The result of the "RFC3542 support" SoC project by Dashu Huang.
authorHasso Tepper <hasso@dragonflybsd.org>
Thu, 4 Sep 2008 09:08:22 +0000 (09:08 +0000)
committerHasso Tepper <hasso@dragonflybsd.org>
Thu, 4 Sep 2008 09:08:22 +0000 (09:08 +0000)
23 files changed:
lib/libc/net/Makefile.inc
lib/libc/net/inet6_opt_init.3 [new file with mode: 0644]
lib/libc/net/inet6_rth_space.3 [new file with mode: 0644]
lib/libc/net/rthdr.c
lib/libcompat/4.3/rexec.c
sbin/ping6/Makefile
sbin/ping6/ping6.c
sys/net/pf/pf_norm.c
sys/netinet/icmp6.h
sys/netinet/in_pcb.h
sys/netinet/ip6.h
sys/netinet6/icmp6.c
sys/netinet6/in6.h
sys/netinet6/in6_pcb.c
sys/netinet6/ip6_input.c
sys/netinet6/ip6_output.c
sys/netinet6/ip6_var.h
sys/netinet6/raw_ip6.c
sys/netinet6/route6.c
sys/netinet6/udp6_output.c
usr.bin/telnet/commands.c
usr.sbin/traceroute6/Makefile
usr.sbin/traceroute6/traceroute6.c

index d8150f0..1a0edd8 100644 (file)
@@ -1,6 +1,6 @@
 #      from @(#)Makefile.inc   8.2 (Berkeley) 9/5/93
 # $FreeBSD: src/lib/libc/net/Makefile.inc,v 1.36.2.5 2002/07/29 18:33:18 ume Exp $
-# $DragonFly: src/lib/libc/net/Makefile.inc,v 1.4 2005/08/05 23:43:19 swildner Exp $
+# $DragonFly: src/lib/libc/net/Makefile.inc,v 1.5 2008/09/04 09:08:21 hasso Exp $
 
 # machine-independent net sources
 .PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/net ${.CURDIR}/../libc/net
@@ -33,7 +33,8 @@ MAN+= addr2ascii.3 byteorder.3 ethers.3 eui64.3 \
        getifaddrs.3 getipnodebyname.3 \
        getnameinfo.3 getnetent.3 getprotoent.3 getservent.3 if_indextoname.3 \
        inet.3 inet_net.3 \
-       inet6_option_space.3 inet6_rthdr_space.3 linkaddr.3 \
+       inet6_opt_init.3 inet6_option_space.3 inet6_rth_space.3 \
+       inet6_rthdr_space.3 linkaddr.3 \
        rcmd.3 rcmdsh.3 resolver.3
 # not installed: iso_addr.3 ns.3
 
@@ -65,11 +66,22 @@ MLINKS+=inet.3 addr.3 inet.3 inet_addr.3 inet.3 inet_aton.3 \
        inet.3 inet_ntop.3 inet.3 inet_pton.3 \
        inet.3 network.3 inet.3 ntoa.3 
 MLINKS+=inet_net.3 inet_net_ntop.3 inet_net.3 inet_net_pton.3
-MLINKS+=inet6_option_space.3 inet6_option_alloc.3 \
+MLINKS+=inet6_opt_init.3 inet6_opt_append.3 \
+       inet6_opt_init.3 inet6_opt_find.3 \
+       inet6_opt_init.3 inet6_opt_finish.3 \
+       inet6_opt_init.3 inet6_opt_get_val.3 \
+       inet6_opt_init.3 inet6_opt_next.3 \
+       inet6_opt_init.3 inet6_opt_set_val.3 \
+       inet6_option_space.3 inet6_option_alloc.3 \
        inet6_option_space.3 inet6_option_append.3 \
        inet6_option_space.3 inet6_option_find.3 \
        inet6_option_space.3 inet6_option_init.3 \
        inet6_option_space.3 inet6_option_next.3 \
+       inet6_rth_space.3 inet6_rth_add.3 \
+       inet6_rth_space.3 inet6_rth_getaddr.3 \
+       inet6_rth_space.3 inet6_rth_init.3 \
+       inet6_rth_space.3 inet6_rth_reverse.3 \
+       inet6_rth_space.3 inet6_rth_segments.3 \
        inet6_rthdr_space.3 inet6_rthdr_add.3 \
        inet6_rthdr_space.3 inet6_rthdr_getaddr.3 \
        inet6_rthdr_space.3 inet6_rthdr_getflags.3 \
diff --git a/lib/libc/net/inet6_opt_init.3 b/lib/libc/net/inet6_opt_init.3
new file mode 100644 (file)
index 0000000..29286c3
--- /dev/null
@@ -0,0 +1,338 @@
+.\"    $KAME: inet6_opt_init.3,v 1.7 2004/12/27 05:08:23 itojun Exp $
+.\"
+.\" Copyright (C) 2004 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY/
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc/net/inet6_opt_init.3,v 1.10 2005/11/23 16:07:54 ru Exp $
+.\" $DragonFly: src/lib/libc/net/inet6_opt_init.3,v 1.1 2008/09/04 09:08:21 hasso Exp $
+.\"
+.Dd December 23, 2004
+.Dt INET6_OPT_INIT 3
+.Os
+.\"
+.Sh NAME
+.Nm inet6_opt_init ,
+.Nm inet6_opt_append ,
+.Nm inet6_opt_finish ,
+.Nm inet6_opt_set_val ,
+.Nm inet6_opt_next ,
+.Nm inet6_opt_find ,
+.Nm inet6_opt_get_val
+.Nd IPv6 Hop-by-Hop and Destination Options manipulation
+.\"
+.Sh SYNOPSIS
+.In netinet/in.h
+.Ft "int"
+.Fn inet6_opt_init "void *extbuf" "socklen_t extlen"
+.Ft "int"
+.Fn inet6_opt_append "void *extbuf" "socklen_t extlen" "int offset" "u_int8_t type" "socklen_t len" "u_int8_t align" "void **databufp"
+.Ft "int"
+.Fn inet6_opt_finish "void *extbuf" "socklen_t extlen" "int offset"
+.Ft "int"
+.Fn inet6_opt_set_val "void *databuf" "int offset" "void *val" "socklen_t vallen"
+.Ft "int"
+.Fn inet6_opt_next "void *extbuf" "socklen_t extlen" "int offset" "u_int8_t *typep" "socklen_t *lenp" "void **databufp"
+.Ft "int"
+.Fn inet6_opt_find "void *extbuf" "socklen_t extlen" "int offset" "u_int8_t type" "socklen_t *lenp" "void **databufp"
+.Ft "int"
+.Fn inet6_opt_get_val "void *databuf" "int offset" "void *val" "socklen_t vallen"
+.\"
+.Sh DESCRIPTION
+Building and parsing the Hop-by-Hop and Destination options is
+complicated.
+The advanced sockets API defines a set of functions to
+help applications create and manipulate Hop-by-Hop and Destination
+options.
+This man page describes the functions specified in
+IETF Draft RFC3542.
+These functions use the
+formatting rules specified in Appendix B in RFC2460, i.e., that the
+largest field is placed last in the option.
+The function prototypes
+for these functions are all contained in the
+.In netinet/in.h
+header file.
+.\"
+.Ss inet6_opt_init
+The
+.Fn inet6_opt_init
+function
+returns the number of bytes needed for an empty
+extension header, one without any options.
+If the
+.Fa extbuf
+argument points to a valid section of memory
+then the
+.Fn inet6_opt_init
+function also initializes the extension header's length field.
+When attempting to initialize an extension buffer passed in the
+.Fa extbuf
+argument,
+.Fa extlen
+must be a positive multiple of 8 or else the function fails and
+returns \-1 to the caller.
+.\"
+.Ss inet6_opt_append
+The
+.Fn inet6_opt_append
+function can perform two different jobs.
+When a valid
+.Fa extbuf
+argument is supplied it appends an option to the extension buffer and
+returns the updated total length as well as a pointer to the newly
+created option in
+.Fa databufp .
+If the value
+of
+.Fa extbuf
+is
+.Dv NULL
+then the
+.Fn inet6_opt_append
+function only reports what the total length would
+be if the option were actually appended.
+The
+.Fa len
+and
+.Fa align
+arguments specify the length of the option and the required data
+alignment which must be used when appending the option.
+The
+.Fa offset
+argument should be the length returned by the
+.Fn inet6_opt_init
+function or a previous call to
+.Fn inet6_opt_append .
+.Pp
+The
+.Fa type
+argument is the 8-bit option type.
+.Pp
+After
+.Fn inet6_opt_append
+has been called, the application can use the buffer pointed to by
+.Fa databufp
+directly, or use
+.Fn inet6_opt_set_val
+to specify the data to be contained in the option.
+.Pp
+Option types of
+.Li 0
+and
+.Li 1
+are reserved for the
+.Li Pad1
+and
+.Li PadN
+options.
+All other values from 2 through 255 may be used by applications.
+.Pp
+The length of the option data is contained in an 8-bit value and so
+may contain any value from 0 through 255.
+.Pp
+The
+.Fa align
+parameter must have a value of 1, 2, 4, or 8 and cannot exceed the
+value of
+.Fa len .
+The alignment values represent no alignment, 16 bit, 32 bit and 64 bit
+alignments, respectively.
+.\"
+.Ss inet6_opt_finish
+The
+.Fn inet6_opt_finish
+function
+calculates the final padding necessary to make the extension header a
+multiple of 8 bytes, as required by the IPv6 extension header
+specification, and returns the extension header's updated total
+length.
+The
+.Fa offset
+argument should be the length returned by
+.Fn inet6_opt_init
+or
+.Fn inet6_opt_append .
+When
+.Fa extbuf
+is not
+.Dv NULL
+the function also sets up the appropriate padding bytes by inserting a
+Pad1 or PadN option of the proper length.
+.Pp
+If the extension header is too small to contain the proper padding
+then an error of \-1 is returned to the caller.
+.\"
+.Ss inet6_opt_set_val
+The
+.Fn inet6_opt_set_val
+function inserts data items of various sizes into the data portion of
+the option.
+The
+.Fa databuf
+argument is a pointer to memory that was returned by the
+.Fn inet6_opt_append
+call and the
+.Fa offset
+argument specifies where the option should be placed in the
+data buffer.
+The
+.Fa val
+argument points to an area of memory containing the data to be
+inserted into the extension header, and the
+.Fa vallen
+argument indicates how much data to copy.
+.Pp
+The caller should ensure that each field is aligned on its natural
+boundaries as described in Appendix B of RFC2460.
+.Pp
+The function returns the offset for the next field which is calculated as
+.Fa offset
++
+.Fa vallen
+and is used when composing options with multiple fields.
+.\"
+.Ss inet6_opt_next
+The
+.Fn inet6_opt_next
+function parses received extension headers.
+The
+.Fa extbuf
+and
+.Fa extlen
+arguments specify the location and length of the extension header
+being parsed.
+The
+.Fa offset
+argument should either be zero, for the first option, or the length value
+returned by a previous call to
+.Fn inet6_opt_next
+or
+.Fn inet6_opt_find .
+The return value specifies the position where to continue scanning the
+extension buffer.
+The option is returned in the arguments
+.Fa typep , lenp ,
+and
+.Fa databufp ,
+which
+point to the 8-bit option type, the 8-bit option length and the option
+data, respectively.
+This function does not return any PAD1 or PADN options.
+When an error occurs or there are no more options, the return
+value is \-1.
+.\"
+.Ss inet6_opt_find
+The
+.Fn inet6_opt_find
+function searches the extension buffer for a particular option type,
+passed in through the
+.Fa type
+argument.
+If the option is found then the
+.Fa lenp
+and
+.Fa databufp
+arguments are updated to point to the option's length and data,
+respectively.
+The
+.Fa extbuf
+and
+.Fa extlen
+arguments
+must point to a valid extension buffer and give its length.
+The
+.Fa offset
+argument can be used to search from a location anywhere in the
+extension header.
+.Ss inet6_opt_get_val
+The
+.Fn inet6_opt_get_val
+function extracts data items of various sizes in the data portion of
+the option.
+The
+.Fa databuf
+is a pointer returned by the
+.Fn inet6_opt_next
+or
+.Fn inet6_opt_find
+functions.
+The
+.Fa val
+argument points where the data will be extracted.
+The
+.Fa offset
+argument specifies from where in the data portion of the option the
+value should be extracted; the first byte of option data is specified
+by an offset of zero.
+.Pp
+It is expected that each field is aligned on its natural boundaries as
+described in Appendix B of RFC2460.
+.Pp
+The function returns the offset for the next field
+by calculating
+.Fa offset
++
+.Fa vallen
+which can be used when extracting option content with multiple fields.
+Robust receivers must verify alignment before calling this function.
+.\"
+.Sh RETURN VALUES
+All the functions return
+\-1
+on an error.
+.\"
+.Sh EXAMPLES
+RFC3542 gives comprehensive examples in Section 23.
+.Pp
+KAME also provides examples in the
+.Pa advapitest
+directory of its kit.
+.\"
+.Sh SEE ALSO
+.Rs
+.%A W. Stevens
+.%A M. Thomas
+.%A E. Nordmark
+.%A T. Jinmei
+.%T "Advanced Sockets API for IPv6"
+.%N RFC3542
+.%D October 2002
+.Re
+.Rs
+.%A S. Deering
+.%A R. Hinden
+.%T "Internet Protocol, Version 6 (IPv6) Specification"
+.%N RFC2460
+.%D December 1998
+.Re
+.Sh STANDARDS
+The functions are documented in
+.Dq Advanced Sockets API for IPv6
+.Pq RFC3542 .
+.\"
+.Sh HISTORY
+The implementation first appeared in KAME advanced networking kit.
diff --git a/lib/libc/net/inet6_rth_space.3 b/lib/libc/net/inet6_rth_space.3
new file mode 100644 (file)
index 0000000..9339a0b
--- /dev/null
@@ -0,0 +1,225 @@
+.\"    $KAME: inet6_rth_space.3,v 1.7 2005/01/05 03:00:44 itojun Exp $
+.\"
+.\" Copyright (C) 2004 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc/net/inet6_rth_space.3,v 1.10 2005/07/31 03:30:44 keramida Exp $
+.\" $DragonFly: src/lib/libc/net/inet6_rth_space.3,v 1.1 2008/09/04 09:08:21 hasso Exp $
+.\"
+.Dd December 24, 2004
+.Dt INET6_RTH_SPACE 3
+.Os
+.\"
+.Sh NAME
+.Nm inet6_rth_space ,
+.Nm inet6_rth_init ,
+.Nm inet6_rth_add ,
+.Nm inet6_rth_reverse ,
+.Nm inet6_rth_segments ,
+.Nm inet6_rth_getaddr
+.Nd IPv6 Routing Header Options manipulation
+.\"
+.Sh SYNOPSIS
+.In netinet/in.h
+.Ft socklen_t
+.Fn inet6_rth_space "int" "int"
+.Ft "void *"
+.Fn inet6_rth_init "void *" "socklen_t" "int" "int"
+.Ft int
+.Fn inet6_rth_add "void *" "const struct in6_addr *"
+.Ft int
+.Fn inet6_rth_reverse "const void *" "void *"
+.Ft int
+.Fn inet6_rth_segments "const void *"
+.Ft "struct in6_addr *"
+.Fn inet6_rth_getaddr "const void *" "int"
+.\"
+.Sh DESCRIPTION
+The IPv6 Advanced API, RFC 3542, defines the functions that an
+application calls to build and examine IPv6 Routing headers.
+Routing headers are used to perform source routing in IPv6 networks.
+The RFC uses the word
+.Dq segments
+to describe addresses and that is the term used here as well.
+All of the functions are defined in the
+.In netinet/in.h
+header file.
+The functions described in this manual page all operate
+on routing header structures which are defined in
+.In netinet/ip6.h
+but which should not need to be modified outside the use of this API.
+The size and shape of the route header structures may change, so using
+the APIs is a more portable, long term, solution.
+.Pp
+The functions in the API are split into two groups, those that build a
+routing header and those that parse a received routing header.
+We will describe the builder functions followed by the parser functions.
+.Ss inet6_rth_space
+The
+.Fn inet6_rth_space
+function returns the number of bytes required to hold a Routing Header
+of the type, specified in the
+.Fa type
+argument and containing the number of addresses specified in the
+.Fa segments
+argument.
+When the type is
+.Dv IPV6_RTHDR_TYPE_0
+the number of segments must be from 0 through 127.
+Routing headers of type
+.Dv IPV6_RTHDR_TYPE_2
+contain only one segment, and are only used with Mobile IPv6.
+The return value from this function is the number of bytes required to
+store the routing header.
+If the value 0 is returned then either the
+route header type was not recognized or another error occurred.
+.Ss inet6_rth_init
+The
+.Fn inet6_rth_init
+function initializes the pre-allocated buffer pointed to by
+.Fa bp
+to contain a routing header of the specified type The
+.Fa bp_len
+argument is used to verify that the buffer is large enough.
+The caller must allocate the buffer pointed to by bp.
+The necessary buffer size should be determined by calling
+.Fn inet6_rth_space
+described in the previous sections.
+.Pp
+The
+.Fn inet6_rth_init
+function returns a pointer to
+.Fa bp
+on success and
+.Dv NULL
+when there is an error.
+.Ss inet6_rth_add
+The
+.Fn inet6_rth_add
+function adds the IPv6 address pointed to by
+.Fa addr
+to the end of the routing header being constructed.
+.Pp
+A successful addition results in the function returning 0, otherwise
+\-1 is returned.
+.Ss inet6_rth_reverse
+The
+.Fn inet6_rth_reverse
+function takes a routing header, pointed to by the
+argument
+.Fa in ,
+and writes a new routing header into the argument pointed to by
+.Fa out .
+The routing header at that sends datagrams along the reverse of that
+route.
+Both arguments are allowed to point to the same buffer meaning
+that the reversal can occur in place.
+.Pp
+The return value of the function is 0 on success, or \-1 when
+there is an error.
+.\"
+.Pp
+The next set of functions operate on a routing header that the
+application wants to parse.
+In the usual case such a routing header
+is received from the network, although these functions can also be
+used with routing headers that the application itself created.
+.Ss inet6_rth_segments
+The
+.Fn inet6_rth_segments
+function returns the number of segments contained in the
+routing header pointed to by
+.Fa bp .
+The return value is the number of segments contained in the routing
+header, or \-1 if an error occurred.
+It is not an error for 0 to be
+returned as a routing header may contain 0 segments.
+.\"
+.Ss inet6_rth_getaddr
+The
+.Fn inet6_rth_getaddr
+function is used to retrieve a single address from a routing header.
+The
+.Fa index
+is the location in the routing header from which the application wants
+to retrieve an address.
+The
+.Fa index
+parameter must have a value between 0 and one less than the number of
+segments present in the routing header.
+The
+.Fn inet6_rth_segments
+function, described in the last section, should be used to determine
+the total number of segments in the routing header.
+The
+.Fn inet6_rth_getaddr
+function returns a pointer to an IPv6 address on success or
+.Dv NULL
+when an error has occurred.
+.\"
+.Sh EXAMPLES
+RFC 3542 gives extensive examples in Section 21, Appendix B.
+.Pp
+KAME also provides examples in the advapitest directory of its kit.
+.\"
+.Sh DIAGNOSTICS
+The
+.Fn inet6_rth_space
+and
+.Fn inet6_rth_getaddr
+functions return 0 on errors.
+.Pp
+The
+.Fn inet6_rthdr_init
+function returns
+.Dv NULL
+on error.
+The
+.Fn inet6_rth_add
+and
+.Fn inet6_rth_reverse
+functions return 0 on success, or \-1 upon an error.
+.\"
+.Sh SEE ALSO
+.Rs
+.%A W. Stevens
+.%A M. Thomas
+.%A E. Nordmark
+.%A T. Jinmei
+.%T "Advanced Sockets API for IPv6"
+.%N RFC 3542
+.%D May 2003
+.Re
+.Rs
+.%A S. Deering
+.%A R. Hinden
+.%T "Internet Protocol, Version 6 (IPv6) Specification"
+.%N RFC2460
+.%D December 1998
+.Re
+.Sh HISTORY
+The implementation first appeared in KAME advanced networking kit.
index 8e673e4..c4add50 100644 (file)
@@ -29,7 +29,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/lib/libc/net/rthdr.c,v 1.2.2.1 2002/04/28 05:40:24 suz Exp $
- * $DragonFly: src/lib/libc/net/rthdr.c,v 1.5 2007/05/29 10:58:11 hasso Exp $
+ * $DragonFly: src/lib/libc/net/rthdr.c,v 1.6 2008/09/04 09:08:21 hasso Exp $
  */
 
 #include <sys/param.h>
 #include <string.h>
 #include <stdio.h>
 
+/* 
+ * RFC5095 deprecated Type 0 routing header and we don't support any other
+ * routing header type yet.
+ */
 size_t
-inet6_rthdr_space(int type, int seg)
+inet6_rthdr_space(int type __unused, int seg __unused)
 {
-    switch(type) {
-     case IPV6_RTHDR_TYPE_0:
-        if (seg < 1 || seg > 23)
-            return(0);
-        return(CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1)
-                          + sizeof(struct ip6_rthdr0)));
-     default:
-#ifdef DEBUG
-        fprintf(stderr, "inet6_rthdr_space: unknown type(%d)\n", type);
-#endif 
-        return(0);
-    }
+       return(0); /* type not suppported */
 }
 
 struct cmsghdr *
-inet6_rthdr_init(void *bp, int type)
+inet6_rthdr_init(void *bp __unused, int type __unused)
 {
-    struct cmsghdr *ch = (struct cmsghdr *)bp;
-    struct ip6_rthdr *rthdr;
-
-    rthdr = (struct ip6_rthdr *)CMSG_DATA(ch);
-
-    ch->cmsg_level = IPPROTO_IPV6;
-    ch->cmsg_type = IPV6_RTHDR;
-
-    switch(type) {
-     case IPV6_RTHDR_TYPE_0:
-        ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) - sizeof(struct in6_addr));
-        bzero(rthdr, sizeof(struct ip6_rthdr0));
-        rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
-        return(ch);
-     default:
-#ifdef DEBUG
-        fprintf(stderr, "inet6_rthdr_init: unknown type(%d)\n", type);
-#endif 
-        return(NULL);
-    }
+       return(NULL); /* type not suppported */
 }
 
 int
-inet6_rthdr_add(struct cmsghdr *cmsg, const struct in6_addr *addr, u_int flags)
+inet6_rthdr_add(struct cmsghdr *cmsg __unused, const struct in6_addr *addr __unused, u_int flags __unused)
 {
-    struct ip6_rthdr *rthdr;
-
-    rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
-
-    switch(rthdr->ip6r_type) {
-     case IPV6_RTHDR_TYPE_0:
-     {
-        struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
-        if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) {
-#ifdef DEBUG
-            fprintf(stderr, "inet6_rthdr_add: unsupported flag(%d)\n", flags);
-#endif 
-            return(-1);
-        }
-        if (rt0->ip6r0_segleft == 23) {
-#ifdef DEBUG
-            fprintf(stderr, "inet6_rthdr_add: segment overflow\n");
-#endif 
-            return(-1);
-        }
-        if (flags == IPV6_RTHDR_STRICT) {
-            int c, b;
-            c = rt0->ip6r0_segleft / 8;
-            b = rt0->ip6r0_segleft % 8;
-            rt0->ip6r0_slmap[c] |= (1 << (7 - b));
-        }
-        rt0->ip6r0_segleft++;
-        bcopy(addr, (caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3),
-              sizeof(struct in6_addr));
-        rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
-        cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
-        break;
-     }
-     default:
-#ifdef DEBUG
-        fprintf(stderr, "inet6_rthdr_add: unknown type(%d)\n",
-                rthdr->ip6r_type);
-#endif 
-        return(-1);
-    }
-
-    return(0);
+       return(-1); /* type not suppported */
 }
 
 int
-inet6_rthdr_lasthop(struct cmsghdr *cmsg, unsigned int flags)
+inet6_rthdr_lasthop(struct cmsghdr *cmsg __unused, unsigned int flags __unused)
 {
-    struct ip6_rthdr *rthdr;
-
-    rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
-
-    switch(rthdr->ip6r_type) {
-     case IPV6_RTHDR_TYPE_0:
-     {
-        struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
-        if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) {
-#ifdef DEBUG
-            fprintf(stderr, "inet6_rthdr_lasthop: unsupported flag(%d)\n", flags);
-#endif 
-            return(-1);
-        }
-        if (rt0->ip6r0_segleft > 23) {
-#ifdef DEBUG
-            fprintf(stderr, "inet6_rthdr_add: segment overflow\n");
-#endif 
-            return(-1);
-        }
-        if (flags == IPV6_RTHDR_STRICT) {
-            int c, b;
-            c = rt0->ip6r0_segleft / 8;
-            b = rt0->ip6r0_segleft % 8;
-            rt0->ip6r0_slmap[c] |= (1 << (7 - b));
-        }
-        break;
-     }
-     default:
-#ifdef DEBUG
-        fprintf(stderr, "inet6_rthdr_lasthop: unknown type(%d)\n",
-                rthdr->ip6r_type);
-#endif 
-        return(-1);
-    }
-
-    return(0);
+       return (-1); /* type not suppported */
 }
 
-#if 0
 int
-inet6_rthdr_reverse(const struct cmsghdr *in, struct cmsghdr *out)
+inet6_rthdr_reverse(const struct cmsghdr *in __unused, struct cmsghdr *out __unused)
 {
-#ifdef DEBUG
-    fprintf(stderr, "inet6_rthdr_reverse: not implemented yet\n");
-#endif 
-    return -1;
+       return -1; /* type not suppported */
 }
-#endif
 
 int
-inet6_rthdr_segments(const struct cmsghdr *cmsg)
+inet6_rthdr_segments(const struct cmsghdr *cmsg __unused)
 {
-    struct ip6_rthdr *rthdr;
-
-    rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
-
-    switch(rthdr->ip6r_type) {
-    case IPV6_RTHDR_TYPE_0:
-      {
-       struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
-
-       if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
-#ifdef DEBUG
-           fprintf(stderr, "inet6_rthdr_segments: invalid size(%d)\n",
-               rt0->ip6r0_len);
-#endif 
-           return -1;
-       }
-
-       return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
-      }
-
-    default:
-#ifdef DEBUG
-       fprintf(stderr, "inet6_rthdr_segments: unknown type(%d)\n",
-           rthdr->ip6r_type);
-#endif 
-       return -1;
-    }
+       return -1; /* type not suppported */
 }
 
 struct in6_addr *
-inet6_rthdr_getaddr(struct cmsghdr *cmsg, int idx)
+inet6_rthdr_getaddr(struct cmsghdr *cmsg __unused, int idx __unused)
 {
-    struct ip6_rthdr *rthdr;
-
-    rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
-
-    switch(rthdr->ip6r_type) {
-    case IPV6_RTHDR_TYPE_0:
-      {
-       struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
-       int naddr;
-
-       if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
-#ifdef DEBUG
-           fprintf(stderr, "inet6_rthdr_getaddr: invalid size(%d)\n",
-               rt0->ip6r0_len);
-#endif 
-           return NULL;
-       }
-       naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
-       if (idx <= 0 || naddr < idx) {
-#ifdef DEBUG
-           fprintf(stderr, "inet6_rthdr_getaddr: invalid idx(%d)\n", idx);
-#endif 
-           return NULL;
-       }
-       return &rt0->ip6r0_addr[idx - 1];
-      }
-
-    default:
-#ifdef DEBUG
-       fprintf(stderr, "inet6_rthdr_getaddr: unknown type(%d)\n",
-           rthdr->ip6r_type);
-#endif 
-       return NULL;
-    }
+       return NULL; /* type not suppported */
 }
 
 int
-inet6_rthdr_getflags(const struct cmsghdr *cmsg, int idx)
+inet6_rthdr_getflags(const struct cmsghdr *cmsg __unused, int idx __unused)
 {
-    struct ip6_rthdr *rthdr;
-
-    rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
-
-    switch(rthdr->ip6r_type) {
-    case IPV6_RTHDR_TYPE_0:
-      {
-       struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
-       int naddr;
-
-       if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
-#ifdef DEBUG
-           fprintf(stderr, "inet6_rthdr_getflags: invalid size(%d)\n",
-               rt0->ip6r0_len);
-#endif 
-           return -1;
-       }
-       naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
-       if (idx < 0 || naddr < idx) {
-#ifdef DEBUG
-           fprintf(stderr, "inet6_rthdr_getflags: invalid idx(%d)\n", idx);
-#endif 
-           return -1;
-       }
-       if (rt0->ip6r0_slmap[idx / 8] & (0x80 >> (idx % 8)))
-           return IPV6_RTHDR_STRICT;
-       else
-           return IPV6_RTHDR_LOOSE;
-      }
-
-    default:
-#ifdef DEBUG
-       fprintf(stderr, "inet6_rthdr_getflags: unknown type(%d)\n",
-           rthdr->ip6r_type);
-#endif 
-       return -1;
-    }
+       return -1; /* type not suppported */
 }
 
 /*
  * RFC3542 (2292bis) API
  */
-
 socklen_t
 inet6_rth_space(int type __unused, int segments __unused)
 {
index 2c871f1..10b9068 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/lib/libcompat/4.3/rexec.c,v 1.5.8.3 2000/11/22 13:36:00 ben Exp $
- * $DragonFly: src/lib/libcompat/4.3/rexec.c,v 1.3 2006/07/30 07:50:28 swildner Exp $
+ * $DragonFly: src/lib/libcompat/4.3/rexec.c,v 1.4 2008/09/04 09:08:22 hasso Exp $
  *
  * @(#)rexec.c 8.1 (Berkeley) 6/4/93
  */
@@ -294,6 +294,147 @@ bad:
        return (-1);
 }
 
+int
+rexec_af(ahost, rport, name, pass, cmd, fd2p, af)
+       char **ahost;
+       int rport;
+       const char *name, *pass, *cmd;
+       int *fd2p;
+       sa_family_t af;
+{
+       struct sockaddr_storage sa2, from;
+       struct addrinfo hints, *res0;
+       const char *orig_name = name;
+       const char *orig_pass = pass;
+       static char *ahostbuf;
+       u_short port = 0;
+       int s, timo = 1, s3;
+       char c;
+       int gai;
+       char servbuff[NI_MAXSERV];
+
+       sprintf(servbuff, sizeof(servbuff), "%d", ntohs(rport));
+       servbuff[sizeof(servbuff) - 1] = '\0';
+
+       memset(&hints, '\0', sizeof(hints));
+       hints.ai_family = af;
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_flags = AI_CANONNAME;
+       gai = getaddrinfo(*ahost, servbuff, &hints, &res0);
+       if (gai){
+               /* XXX: set errno? */
+               return -1;
+       }
+
+       if (res0->ai_canonname){
+               free (ahostbuf);
+               ahostbuf = strdup (res0->ai_canonname);
+               if (ahostbuf == NULL) {
+                       perror ("rexec: strdup");
+                       return (-1);
+               }
+               *ahost = ahostbuf;
+       } else {
+               *ahost = NULL;
+               __set_errno (ENOENT);
+               return -1;
+       }
+       ruserpass(res0->ai_canonname, &name, &pass);
+retry:
+       s = socket(res0->ai_family, res0->ai_socktype, 0);
+       if (s < 0) {
+               perror("rexec: socket");
+               return (-1);
+       }
+       if (connect(s, res0->ai_addr, res0->ai_addrlen) < 0) {
+               if (errno == ECONNREFUSED && timo <= 16) {
+                       (void) close(s);
+                       sleep(timo);
+                       timo *= 2;
+                       goto retry;
+               }
+               perror(res0->ai_canonname);
+               return (-1);
+       }
+       if (fd2p == 0) {
+               (void) write(s, "", 1);
+               port = 0;
+       } else {
+               char num[32];
+               int s2;
+               socklen_t sa2len;
+
+               s2 = socket(res0->ai_family, res0->ai_socktype, 0);
+               if (s2 < 0) {
+                       (void) close(s);
+                       return (-1);
+               }
+               listen(s2, 1);
+               sa2len = sizeof (sa2);
+               if (getsockname(s2, (struct sockaddr *)&sa2, &sa2len) < 0) {
+                       perror("getsockname");
+                       (void) close(s2);
+                       goto bad;
+               } else if (sa2len != SA_LEN((struct sockaddr *)&sa2)) {
+                       __set_errno(EINVAL);
+                       (void) close(s2);
+                       goto bad;
+               }
+               port = 0;
+               if (!getnameinfo((struct sockaddr *)&sa2, sa2len,
+                                NULL, 0, servbuff, sizeof(servbuff),
+                                NI_NUMERICSERV))
+                       port = atoi(servbuff);
+               (void) sprintf(num, "%u", port);
+               (void) write(s, num, strlen(num)+1);
+               { socklen_t len = sizeof (from);
+                 s3 = accept(s2, (struct sockaddr *)&from,
+                                                 &len);
+                 close(s2);
+                 if (s3 < 0) {
+                       perror("accept");
+                       port = 0;
+                       goto bad;
+                 }
+               }
+               *fd2p = s3;
+       }
+
+       (void) write(s, name, strlen(name) + 1);
+       /* should public key encypt the password here */
+       (void) write(s, pass, strlen(pass) + 1);
+       (void) write(s, cmd, strlen(cmd) + 1);
+
+       /* We don't need the memory allocated for the name and the password
+          in ruserpass anymore.  */
+       if (name != orig_name)
+         free ((char *) name);
+       if (pass != orig_pass)
+         free ((char *) pass);
+
+       if (read(s, &c, 1) != 1) {
+               perror(*ahost);
+               goto bad;
+       }
+       if (c != 0) {
+               while (read(s, &c, 1) == 1) {
+                       (void) write(2, &c, 1);
+                       if (c == '\n')
+                               break;
+               }
+               goto bad;
+       }
+       freeaddrinfo(res0);
+       return (s);
+bad:
+       if (port)
+               (void) close(*fd2p);
+       (void) close(s);
+       freeaddrinfo(res0);
+       return (-1);
+}
+
+
 int
 rexec(ahost, rport, name, pass, cmd, fd2p)
        char **ahost;
index 996e4b1..82a504e 100644 (file)
@@ -1,10 +1,10 @@
 # $FreeBSD: src/sbin/ping6/Makefile,v 1.1.2.4 2002/03/08 09:18:59 ume Exp $
-# $DragonFly: src/sbin/ping6/Makefile,v 1.4 2006/10/17 00:55:43 pavalos Exp $
+# $DragonFly: src/sbin/ping6/Makefile,v 1.5 2008/09/04 09:08:22 hasso Exp $
 
 PROG=  ping6
 MAN=   ping6.8
 
-CFLAGS+=-DINET6 -DIPSEC
+CFLAGS+=-DINET6 -DIPSEC -DUSE_RFC3542
 
 BINOWN=        root
 BINMODE=4555
index 0251423..058ae56 100644 (file)
@@ -31,7 +31,7 @@
  * @(#) Copyright (c) 1989, 1993 The Regents of the University of California.  All rights reserved.
  * @(#)ping.c  8.1 (Berkeley) 6/5/93
  * $FreeBSD: src/sbin/ping6/ping6.c,v 1.4.2.10 2002/12/09 03:04:44 suz Exp $
- * $DragonFly: src/sbin/ping6/ping6.c,v 1.8 2005/03/05 22:27:08 cpressey Exp $
+ * $DragonFly: src/sbin/ping6/ping6.c,v 1.9 2008/09/04 09:08:22 hasso Exp $
  */
 
 /*     BSDI    ping.c,v 2.3 1996/01/21 17:56:50 jch Exp        */
@@ -296,15 +296,17 @@ main(int argc, char **argv)
        int sockbufsize = 0;
        int usepktinfo = 0;
        struct in6_pktinfo *pktinfo = NULL;
-#ifdef USE_RFC2292BIS
+#ifdef USE_RFC3542
        struct ip6_rthdr *rthdr = NULL;
 #endif
 #ifdef IPSEC_POLICY_IPSEC
        char *policy_in = NULL;
        char *policy_out = NULL;
+#endif
+#ifdef IPV6_USE_MIN_MTU
+       int mflag = 0;
 #endif
        double intval;
-       size_t rthlen;
 
        /* just to be sure */
        memset(&smsghdr, 0, sizeof(smsghdr));
@@ -440,7 +442,7 @@ main(int argc, char **argv)
                        break;
                case 'm':
 #ifdef IPV6_USE_MIN_MTU
-                       options |= F_NOMINMTU;
+                       mflag++;
                        break;
 #else
                        errx(1, "-%c is not supported on this platform", ch);
@@ -532,19 +534,9 @@ main(int argc, char **argv)
                usage();
                /*NOTREACHED*/
        }
-
        if (argc > 1) {
-#ifdef IPV6_RECVRTHDR  /* 2292bis */
-               rthlen = CMSG_SPACE(inet6_rth_space(IPV6_RTHDR_TYPE_0,
-                   argc - 1));
-#else  /* RFC2292 */
-               rthlen = inet6_rthdr_space(IPV6_RTHDR_TYPE_0, argc - 1);
-#endif
-               if (rthlen == 0) {
-                       errx(1, "too many intermediate hops");
-                       /*NOTREACHED*/
-               }
-               ip6optlen += rthlen;
+               errx(1, "too many arguments");
+               /*NOTREACHED*/
        }
 
        if (options & F_NIGROUP) {
@@ -669,8 +661,8 @@ main(int argc, char **argv)
                    &optval, sizeof(optval)) == -1)
                        err(1, "IPV6_MULTICAST_HOPS");
 #ifdef IPV6_USE_MIN_MTU
-       if ((options & F_NOMINMTU) == 0) {
-               optval = 1;
+       if (mflag != 1) {
+               optval = mflag > 1 ? 0 : 1;
                if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
                    &optval, sizeof(optval)) == -1)
                        err(1, "setsockopt(IPV6_USE_MIN_MTU)");
@@ -818,60 +810,6 @@ main(int argc, char **argv)
                scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
        }
 #endif
-
-       if (argc > 1) { /* some intermediate addrs are specified */
-               int hops, error;
-#ifdef USE_RFC2292BIS
-               int rthdrlen;
-#endif
-
-#ifdef USE_RFC2292BIS
-               rthdrlen = inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1);
-               scmsgp->cmsg_len = CMSG_LEN(rthdrlen);
-               scmsgp->cmsg_level = IPPROTO_IPV6;
-               scmsgp->cmsg_type = IPV6_RTHDR;
-               rthdr = (struct ip6_rthdr *)CMSG_DATA(scmsgp);
-               rthdr = inet6_rth_init((void *)rthdr, rthdrlen,
-                   IPV6_RTHDR_TYPE_0, argc - 1);
-               if (rthdr == NULL)
-                       errx(1, "can't initialize rthdr");
-#else  /* old advanced API */
-               if ((scmsgp = (struct cmsghdr *)inet6_rthdr_init(scmsgp,
-                   IPV6_RTHDR_TYPE_0)) == 0)
-                       errx(1, "can't initialize rthdr");
-#endif /* USE_RFC2292BIS */
-
-               for (hops = 0; hops < argc - 1; hops++) {
-                       struct addrinfo *iaip;
-
-                       if ((error = getaddrinfo(argv[hops], NULL, &hints,
-                           &iaip)))
-                               errx(1, "%s", gai_strerror(error));
-                       if (SIN6(iaip->ai_addr)->sin6_family != AF_INET6)
-                               errx(1,
-                                   "bad addr family of an intermediate addr");
-
-#ifdef USE_RFC2292BIS
-                       if (inet6_rth_add(rthdr,
-                           &(SIN6(iaip->ai_addr))->sin6_addr))
-                               errx(1, "can't add an intermediate node");
-#else  /* old advanced API */
-                       if (inet6_rthdr_add(scmsgp,
-                           &(SIN6(iaip->ai_addr))->sin6_addr,
-                           IPV6_RTHDR_LOOSE))
-                               errx(1, "can't add an intermediate node");
-#endif /* USE_RFC2292BIS */
-                       freeaddrinfo(iaip);
-               }
-
-#ifndef USE_RFC2292BIS
-               if (inet6_rthdr_lasthop(scmsgp, IPV6_RTHDR_LOOSE))
-                       errx(1, "can't set the last flag");
-#endif
-
-               scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
-       }
-
        {
                /*
                 * source selection
@@ -886,17 +824,19 @@ main(int argc, char **argv)
                src.sin6_port = ntohs(DUMMY_PORT);
                src.sin6_scope_id = dst.sin6_scope_id;
 
-#ifdef USE_RFC2292BIS
+#ifdef USE_RFC3542
                if (pktinfo &&
                    setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTINFO,
                    (void *)pktinfo, sizeof(*pktinfo)))
                        err(1, "UDP setsockopt(IPV6_PKTINFO)");
-
                if (hoplimit != -1 &&
-                   setsockopt(dummy, IPPROTO_IPV6, IPV6_HOPLIMIT,
+                   setsockopt(dummy, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
                    (void *)&hoplimit, sizeof(hoplimit)))
-                       err(1, "UDP setsockopt(IPV6_HOPLIMIT)");
-
+                       err(1, "UDP setsockopt(IPV6_UNICAST_HOPS)");
+               if (hoplimit != -1 &&
+                   setsockopt(dummy, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+                   (void *)&hoplimit, sizeof(hoplimit)))
+                       err(1, "UDP setsockopt(IPV6_MULTICAST_HOPS)");
                if (rthdr &&
                    setsockopt(dummy, IPPROTO_IPV6, IPV6_RTHDR,
                    (void *)rthdr, (rthdr->ip6r_len + 1) << 3))
@@ -1664,7 +1604,7 @@ pr_exthdrs(struct msghdr *mhdr)
        }
 }
 
-#ifdef USE_RFC2292BIS
+#ifdef USE_RFC3542
 void
 pr_ip6opt(void *extbuf)
 {
@@ -1715,7 +1655,7 @@ pr_ip6opt(void *extbuf)
        }
        return;
 }
-#else  /* !USE_RFC2292BIS */
+#else  /* !USE_RFC3542 */
 /* ARGSUSED */
 void
 pr_ip6opt(void *extbuf __unused)
@@ -1723,9 +1663,9 @@ pr_ip6opt(void *extbuf __unused)
        putchar('\n');
        return;
 }
-#endif /* USE_RFC2292BIS */
+#endif /* USE_RFC3542 */
 
-#ifdef USE_RFC2292BIS
+#ifdef USE_RFC3542
 void
 pr_rthdr(void *extbuf)
 {
@@ -1737,29 +1677,13 @@ pr_rthdr(void *extbuf)
        /* print fixed part of the header */
        printf("nxt %u, len %u (%d bytes), type %u, ", rh->ip6r_nxt,
            rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type);
-       if ((segments = inet6_rth_segments(extbuf)) >= 0)
-               printf("%d segments, ", segments);
-       else
-               printf("segments unknown, ");
+       printf("segments unknown, ");
        printf("%d left\n", rh->ip6r_segleft);
-
-       for (i = 0; i < segments; i++) {
-               in6 = inet6_rth_getaddr(extbuf, i);
-               if (in6 == NULL)
-                       printf("   [%d]<NULL>\n", i);
-               else {
-                       if (!inet_ntop(AF_INET6, in6, ntopbuf,
-                           sizeof(ntopbuf)))
-                               strncpy(ntopbuf, "?", sizeof(ntopbuf));
-                       printf("   [%d]%s\n", i, ntopbuf);
-               }
-       }
-
        return;
 
 }
 
-#else  /* !USE_RFC2292BIS */
+#else  /* !USE_RFC3542 */
 /* ARGSUSED */
 void
 pr_rthdr(void *extbuf __unused)
@@ -1767,7 +1691,7 @@ pr_rthdr(void *extbuf __unused)
        putchar('\n');
        return;
 }
-#endif /* USE_RFC2292BIS */
+#endif /* USE_RFC3542 */
 
 int
 pr_bitrange(u_int32_t v, int ss, int ii)
index 77b020e..b02b364 100644 (file)
@@ -1,7 +1,7 @@
 /*     $FreeBSD: src/sys/contrib/pf/net/pf_norm.c,v 1.10 2004/08/14 15:32:40 dwmalone Exp $    */
 /*     $OpenBSD: pf_norm.c,v 1.80.2.1 2004/04/30 21:46:33 brad Exp $ */
 /* add $OpenBSD: pf_norm.c,v 1.87 2004/05/11 07:34:11 dhartmei Exp $ */
-/*     $DragonFly: src/sys/net/pf/pf_norm.c,v 1.9 2007/08/11 18:53:31 dillon Exp $ */
+/*     $DragonFly: src/sys/net/pf/pf_norm.c,v 1.10 2008/09/04 09:08:22 hasso Exp $ */
 
 /*
  * Copyright (c) 2004 The DragonFly Project.  All rights reserved.
 /*
  * XXX: This should go to netinet/ip6.h (KAME)
  */
-/* IPv6 options: common part */
-struct ip6_opt {
-       u_int8_t ip6o_type;
-       u_int8_t ip6o_len;
-} __packed;
-
-/* Jumbo Payload Option */
-struct ip6_opt_jumbo {
-       u_int8_t ip6oj_type;
-       u_int8_t ip6oj_len;
-       u_int8_t ip6oj_jumbo_len[4];
-} __packed;
-
-/* NSAP Address Option */
-struct ip6_opt_nsap {
-       u_int8_t ip6on_type;
-       u_int8_t ip6on_len;
-       u_int8_t ip6on_src_nsap_len;
-       u_int8_t ip6on_dst_nsap_len;
-       /* followed by source NSAP */
-       /* followed by destination NSAP */
-} __packed;
-
-/* Tunnel Limit Option */
-struct ip6_opt_tunnel {
-       u_int8_t ip6ot_type;
-       u_int8_t ip6ot_len;
-       u_int8_t ip6ot_encap_limit;
-} __packed;
-
-/* Router Alert Option */
-struct ip6_opt_router {
-       u_int8_t ip6or_type;
-       u_int8_t ip6or_len;
-       u_int8_t ip6or_value[2];
-} __packed;
 #endif /* INET6 */
 
 #define PFFRAG_SEENLAST        0x0001          /* Seen the last fragment for this */
index e1dc911..e9ded24 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet/icmp6.h,v 1.2.2.5 2002/06/29 18:31:11 ume Exp $       */
-/*     $DragonFly: src/sys/netinet/icmp6.h,v 1.7 2006/05/20 02:42:12 dillon Exp $      */
+/*     $DragonFly: src/sys/netinet/icmp6.h,v 1.8 2008/09/04 09:08:22 hasso Exp $       */
 /*     $KAME: icmp6.h,v 1.46 2001/04/27 15:09:48 itojun Exp $  */
 
 /*
@@ -115,6 +115,7 @@ struct icmp6_hdr {
 #define MLD_LISTENER_REPORT            131     /* multicast listener report */
 #define ICMP6_MEMBERSHIP_REDUCTION     132     /* group membership termination */
 #define MLD_LISTENER_DONE              132     /* multicast listener done */
+#define MLD_LISTENER_REDUCTION MLD_LISTENER_DONE /* defined in RFC3542 */
 
 #ifndef _KERNEL
 /* the followings are for backward compatibility to old KAME apps. */
index 5c9528b..b8a75ac 100644 (file)
@@ -65,7 +65,7 @@
  *
  *     @(#)in_pcb.h    8.1 (Berkeley) 6/10/93
  * $FreeBSD: src/sys/netinet/in_pcb.h,v 1.32.2.7 2003/01/24 05:11:34 sam Exp $
- * $DragonFly: src/sys/netinet/in_pcb.h,v 1.23 2007/04/04 06:13:26 dillon Exp $
+ * $DragonFly: src/sys/netinet/in_pcb.h,v 1.24 2008/09/04 09:08:22 hasso Exp $
  */
 
 #ifndef _NETINET_IN_PCB_H_
@@ -327,16 +327,24 @@ struct inpcbinfo {                /* XXX documentation, prefixes */
 #define        IN6P_RTHDR              0x100000 /* receive routing header */
 #define        IN6P_RTHDRDSTOPTS       0x200000 /* receive dstoptions before rthdr */
 #define IN6P_AUTOFLOWLABEL     0x800000 /* attach flowlabel automatically */
+/* 
+ * RFC3542 Definition 
+ */
+#define        IN6P_TCLASS             0x400000 /* receive traffic class value */
+#define        IN6P_RFC2292            0x40000000 /* used RFC2292 API on the socket */
+#define        IN6P_MTU                0x80000000 /* receive path MTU */
 
 #define        INP_RECVTTL             0x80000000 /* receive incoming IP TTL */
 
 #define        INP_CONTROLOPTS         (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\
-                                       INP_RECVIF|INP_RECVTTL|\
+                                INP_RECVIF|INP_RECVTTL|\
                                 IN6P_PKTINFO|IN6P_HOPLIMIT|IN6P_HOPOPTS|\
                                 IN6P_DSTOPTS|IN6P_RTHDR|IN6P_RTHDRDSTOPTS|\
-                                IN6P_AUTOFLOWLABEL)
+                                IN6P_TCLASS|IN6P_AUTOFLOWLABEL|IN6P_RFC2292|\
+                                IN6P_MTU)
+                                
 #define        INP_UNMAPPABLEOPTS      (IN6P_HOPOPTS|IN6P_DSTOPTS|IN6P_RTHDR|\
-                                IN6P_AUTOFLOWLABEL)
+                                IN6P_TCLASS|IN6P_AUTOFLOWLABEL)
 
  /* for KAME src sync over BSD*'s */
 #define        IN6P_HIGHPORT           INP_HIGHPORT
index f0f1857..5945737 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet/ip6.h,v 1.2.2.2 2001/07/03 11:01:46 ume Exp $ */
-/*     $DragonFly: src/sys/netinet/ip6.h,v 1.7 2007/05/23 08:57:09 dillon Exp $        */
+/*     $DragonFly: src/sys/netinet/ip6.h,v 1.8 2008/09/04 09:08:22 hasso Exp $ */
 /*     $KAME: ip6.h,v 1.18 2001/03/29 05:34:30 itojun Exp $    */
 
 /*
@@ -157,6 +157,7 @@ struct ip6_dest {
 #define IP6OPT_TUNNEL_LIMIT    0x04    /* 00 0 00100 */
 #define IP6OPT_RTALERT         0x05    /* 00 0 00101 (KAME definition) */
 
+#define IP6OPT_ROUTER_ALERT    0x05    /* 00 0 00101 (RFC3542, recommended) */
 #define IP6OPT_RTALERT_LEN     4
 #define IP6OPT_RTALERT_MLD     0       /* Datagram contains an MLD message */
 #define IP6OPT_RTALERT_RSVP    1       /* Datagram contains an RSVP message */
@@ -177,8 +178,58 @@ struct ip6_dest {
 
 #define IP6OPT_MUTABLE         0x20
 
+/* Jumbo Payload Option */
+struct ip6_opt_jumbo {
+       u_int8_t ip6oj_type;
+       u_int8_t ip6oj_len;
+       u_int8_t ip6oj_jumbo_len[4];
+} __attribute__((__packed__));
 #define IP6OPT_JUMBO_LEN       6
 
+/* IPv6 options: common part */
+struct ip6_opt {
+       u_int8_t ip6o_type;
+       u_int8_t ip6o_len;
+} __attribute__((__packed__));
+
+
+/* NSAP Address Option */
+struct ip6_opt_nsap {
+       u_int8_t ip6on_type;
+       u_int8_t ip6on_len;
+       u_int8_t ip6on_src_nsap_len;
+       u_int8_t ip6on_dst_nsap_len;
+       /* followed by source NSAP */
+       /* followed by destination NSAP */
+} __attribute__((__packed__));
+
+/* Tunnel Limit Option */
+struct ip6_opt_tunnel {
+       u_int8_t ip6ot_type;
+       u_int8_t ip6ot_len;
+       u_int8_t ip6ot_encap_limit;
+} __attribute__((__packed__));
+
+/* Router Alert Option */
+struct ip6_opt_router {
+       u_int8_t ip6or_type;
+       u_int8_t ip6or_len;
+       u_int8_t ip6or_value[2];
+} __attribute__((__packed__));
+
+/* Router alert values (in network byte order) */
+#if BYTE_ORDER == BIG_ENDIAN
+#define IP6_ALERT_MLD  0x0000
+#define IP6_ALERT_RSVP 0x0001
+#define IP6_ALERT_AN   0x0002
+#else
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define IP6_ALERT_MLD  0x0000
+#define IP6_ALERT_RSVP 0x0100
+#define IP6_ALERT_AN   0x0200
+#endif /* LITTLE_ENDIAN */
+#endif
+
 /* Routing header */
 struct ip6_rthdr {
        u_int8_t  ip6r_nxt;     /* next header */
@@ -188,17 +239,6 @@ struct ip6_rthdr {
        /* followed by routing type specific data */
 } __attribute__((__packed__));
 
-/* Type 0 Routing header */
-struct ip6_rthdr0 {
-       u_int8_t  ip6r0_nxt;            /* next header */
-       u_int8_t  ip6r0_len;            /* length in units of 8 octets */
-       u_int8_t  ip6r0_type;           /* always zero */
-       u_int8_t  ip6r0_segleft;        /* segments left */
-       u_int8_t  ip6r0_reserved;       /* reserved field */
-       u_int8_t  ip6r0_slmap[3];       /* strict/loose bit map */
-       struct in6_addr  ip6r0_addr[1]; /* up to 23 addresses */
-} __attribute__((__packed__));
-
 /* Fragment header */
 struct ip6_frag {
        u_int8_t  ip6f_nxt;             /* next header */
index 3a8b47b..b94d0de 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet6/icmp6.c,v 1.6.2.13 2003/05/06 06:46:58 suz Exp $     */
-/*     $DragonFly: src/sys/netinet6/icmp6.c,v 1.29 2008/06/21 12:30:19 aggelos Exp $   */
+/*     $DragonFly: src/sys/netinet6/icmp6.c,v 1.30 2008/09/04 09:08:22 hasso Exp $     */
 /*     $KAME: icmp6.c,v 1.211 2001/04/04 05:56:20 itojun Exp $ */
 
 /*
@@ -889,7 +889,6 @@ icmp6_notify_error(struct mbuf *m, int off, int icmp6len, int code)
                int icmp6type = icmp6->icmp6_type;
                struct ip6_frag *fh;
                struct ip6_rthdr *rth;
-               struct ip6_rthdr0 *rth0;
                int rthlen;
 
                while (1) { /* XXX: should avoid infinite loop explicitly? */
@@ -943,36 +942,6 @@ icmp6_notify_error(struct mbuf *m, int off, int icmp6len, int code)
                                }
 #endif
                                rthlen = (rth->ip6r_len + 1) << 3;
-                               /*
-                                * XXX: currently there is no
-                                * officially defined type other
-                                * than type-0.
-                                * Note that if the segment left field
-                                * is 0, all intermediate hops must
-                                * have been passed.
-                                */
-                               if (rth->ip6r_segleft &&
-                                   rth->ip6r_type == IPV6_RTHDR_TYPE_0) {
-                                       int hops;
-
-#ifndef PULLDOWN_TEST
-                                       IP6_EXTHDR_CHECK(m, 0, eoff + rthlen,
-                                                        -1);
-                                       rth0 = (struct ip6_rthdr0 *)(mtod(m, caddr_t) + eoff);
-#else
-                                       IP6_EXTHDR_GET(rth0,
-                                                      struct ip6_rthdr0 *, m,
-                                                      eoff, rthlen);
-                                       if (rth0 == NULL) {
-                                               icmp6stat.icp6s_tooshort++;
-                                               return (-1);
-                                       }
-#endif
-                                       /* just ignore a bogus header */
-                                       if ((rth0->ip6r0_len % 2) == 0 &&
-                                           (hops = rth0->ip6r0_len/2))
-                                               finaldst = (struct in6_addr *)(rth0 + 1) + (hops - 1);
-                               }
                                eoff += rthlen;
                                nxt = rth->ip6r_nxt;
                                break;
index 427b9c1..2394c5b 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet6/in6.h,v 1.7.2.7 2002/08/01 19:38:50 ume Exp $        */
-/*     $DragonFly: src/sys/netinet6/in6.h,v 1.10 2007/08/21 20:03:20 corecode Exp $    */
+/*     $DragonFly: src/sys/netinet6/in6.h,v 1.11 2008/09/04 09:08:22 hasso Exp $       */
 /*     $KAME: in6.h,v 1.89 2001/05/27 13:28:35 itojun Exp $    */
 
 /*
@@ -395,13 +395,15 @@ struct route_in6 {
 #define IPV6_PORTRANGE         14 /* int; range to choose for unspec port */
 #define ICMP6_FILTER           18 /* icmp6_filter; icmp6 filter */
 /* RFC2292 options */
-#define IPV6_PKTINFO           19 /* bool; send/recv if, src/dst addr */
-#define IPV6_HOPLIMIT          20 /* bool; hop limit */
-#define IPV6_NEXTHOP           21 /* bool; next hop addr */
-#define IPV6_HOPOPTS           22 /* bool; hop-by-hop option */
-#define IPV6_DSTOPTS           23 /* bool; destination option */
-#define IPV6_RTHDR             24 /* bool; routing header */
-#define IPV6_PKTOPTIONS                25 /* buf/cmsghdr; set/get IPv6 options */
+#ifdef _KERNEL
+#define IPV6_2292PKTINFO       19 /* bool; send/recv if, src/dst addr */
+#define IPV6_2292HOPLIMIT      20 /* bool; hop limit */
+#define IPV6_2292NEXTHOP       21 /* bool; next hop addr */
+#define IPV6_2292HOPOPTS       22 /* bool; hop-by-hop option */
+#define IPV6_2292DSTOPTS       23 /* bool; destinaion option */
+#define IPV6_2292RTHDR         24 /* bool; routing header */
+#define IPV6_2292PKTOPTIONS    25 /* buf/cmsghdr; set/get IPv6 options */
+#endif
 
 #define IPV6_CHECKSUM          26 /* int; checksum offset for raw socket */
 #define IPV6_V6ONLY            27 /* bool; only bind INET6 at wildcard bind */
@@ -422,11 +424,58 @@ struct route_in6 {
 #define IPV6_FW_GET            34 /* get entire firewall rule chain */
 #endif
 
+/* 
+ * new socket options introduced in RFC3542 
+ */
+#define IPV6_RTHDRDSTOPTS      35 /* ip6_dest; send dst option before rthdr */
+#define IPV6_RECVPKTINFO       36 /* bool; recv if, dst addr */
+#define IPV6_RECVHOPLIMIT      37 /* bool; recv hop limit */
+#define IPV6_RECVRTHDR         38 /* bool; recv routing header */
+#define IPV6_RECVHOPOPTS       39 /* bool; recv hop-by-hop option */
+#define IPV6_RECVDSTOPTS       40 /* bool; recv dst option after rthdr */
+#ifdef _KERNEL
+#define IPV6_RECVRTHDRDSTOPTS  41 /* bool; recv dst option before rthdr */
+#endif
+#define IPV6_USE_MIN_MTU       42 /* bool; send packets at the minimum MTU */
+#define IPV6_RECVPATHMTU       43 /* bool; notify an according MTU */
+
+/* mtuinfo; get the current path MTU (sopt),
+ * 4 bytes int; MTU notification (cmsg) 
+ */
+#define IPV6_PATHMTU           44 
+#if 0 /*obsoleted during 2292bis -> 3542*/
+#define IPV6_REACHCONF         45 /* no data; ND reachability confirm
+                                     (cmsg only/not in of RFC3542) */
+#endif
+#define IPV6_PKTINFO           46 /* in6_pktinfo; send if, src addr */
+#define IPV6_HOPLIMIT          47 /* int; send hop limit */
+#define IPV6_NEXTHOP           48 /* sockaddr; next hop addr */
+#define IPV6_HOPOPTS           49 /* ip6_hbh; send hop-by-hop option */
+#define IPV6_DSTOPTS           50 /* ip6_dest; send dst option befor rthdr */
+#define IPV6_RTHDR             51 /* ip6_rthdr; send routing header */
+#define IPV6_PKTOPTIONS                52 /* buf/cmsghdr; set/get IPv6 options, this is obsoleted by RFC3542 */
+
+#define IPV6_RECVTCLASS                57 /* bool; recv traffic class values */
+
+#define IPV6_AUTOFLOWLABEL     59 /* bool; attach flowlabel automagically */
+
+#define IPV6_TCLASS            61 /* int; send traffic class value */
+#define IPV6_DONTFRAG          62 /* bool; disable IPv6 fragmentation */
+
+#define IPV6_PREFER_TEMPADDR   63 /* int; prefer temporary addresses as
+                                   * the source address.
+                                   */
+/*
+ * The following option is private; do not use it from user applications.
+ * It is deliberately defined to the same value as IP_MSFILTER.
+ */
+#define        IPV6_MSFILTER           74 /* struct __msfilterreq;
+                                   * set/get multicast source filter list.
+                                   */ 
 /* to define items, should talk with KAME guys first, for *BSD compatibility */
 
 #define IPV6_RTHDR_LOOSE     0 /* this hop need not be a neighbor. XXX old spec */
 #define IPV6_RTHDR_STRICT    1 /* this hop must be a neighbor. XXX old spec */
-#define IPV6_RTHDR_TYPE_0    0 /* IPv6 routing header type 0 */
 
 /*
  * Defaults and limits for options
@@ -450,6 +499,14 @@ struct in6_pktinfo {
        unsigned int    ipi6_ifindex;   /* send/recv interface index */
 };
 
+/*
+ * New Control structure for IPV6_RECVPATHMTU socket option introduced in RFC3542.
+ */
+struct ip6_mtuinfo {
+       struct sockaddr_in6 ip6m_addr;  /* or sockaddr_storage? */
+       uint32_t ip6m_mtu;
+};
+
 /*
  * Argument for IPV6_PORTRANGE:
  * - which range to search when port is unspecified at bind() or connect()
index 65a5a06..3fa30a6 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet6/in6_pcb.c,v 1.10.2.9 2003/01/24 05:11:35 sam Exp $   */
-/*     $DragonFly: src/sys/netinet6/in6_pcb.c,v 1.34 2008/01/05 14:02:40 swildner Exp $        */
+/*     $DragonFly: src/sys/netinet6/in6_pcb.c,v 1.35 2008/09/04 09:08:22 hasso Exp $   */
 /*     $KAME: in6_pcb.c,v 1.31 2001/05/21 05:45:10 jinmei Exp $        */
 
 /*
@@ -879,6 +879,20 @@ in6_pcbnotify(struct inpcbhead *head, struct sockaddr *dst, in_port_t fport,
 
                if ((inp->inp_vflag & INP_IPV6) == 0)
                        continue;
+               /*
+                * If the error designates a new path MTU for a destination
+                * and the application (associated with this socket) wanted to
+                * know the value, notify. Note that we notify for all
+                * disconnected sockets if the corresponding application
+                * wanted. This is because some UDP applications keep sending
+                * sockets disconnected.
+                * XXX: should we avoid to notify the value to TCP sockets?
+                */
+               if (cmd == PRC_MSGSIZE && (inp->inp_flags & IN6P_MTU) != 0 &&
+                   (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) ||
+                    IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, &sa6_dst->sin6_addr))) {
+                       ip6_notify_pmtu(inp, (struct sockaddr_in6 *)dst, arg);
+               }
 
                /*
                 * Detect if we should notify the error. If no source and
index fc12beb..a89dc38 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet6/ip6_input.c,v 1.11.2.15 2003/01/24 05:11:35 sam Exp $        */
-/*     $DragonFly: src/sys/netinet6/ip6_input.c,v 1.35 2007/10/14 18:15:19 hasso Exp $ */
+/*     $DragonFly: src/sys/netinet6/ip6_input.c,v 1.36 2008/09/04 09:08:22 hasso Exp $ */
 /*     $KAME: ip6_input.c,v 1.259 2002/01/21 04:58:09 jinmei Exp $     */
 
 /*
@@ -1123,6 +1123,7 @@ void
 ip6_savecontrol(struct inpcb *in6p, struct mbuf **mp, struct ip6_hdr *ip6,
                struct mbuf *m)
 {
+       #define IS2292(x, y)    ((in6p->in6p_flags & IN6P_RFC2292) ? (x) : (y))
        struct thread *td = curthread;  /* XXX */
        int privileged = 0;
        int rthdr_exist = 0;
@@ -1154,7 +1155,7 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf **mp, struct ip6_hdr *ip6,
                                        ? m->m_pkthdr.rcvif->if_index
                                        : 0;
                *mp = sbcreatecontrol((caddr_t) &pi6,
-                       sizeof(struct in6_pktinfo), IPV6_PKTINFO,
+                       sizeof(struct in6_pktinfo), IS2292(IPV6_2292PKTINFO, IPV6_PKTINFO),
                        IPPROTO_IPV6);
                if (*mp)
                        mp = &(*mp)->m_next;
@@ -1163,7 +1164,21 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf **mp, struct ip6_hdr *ip6,
        if (in6p->in6p_flags & IN6P_HOPLIMIT) {
                int hlim = ip6->ip6_hlim & 0xff;
                *mp = sbcreatecontrol((caddr_t) &hlim,
-                       sizeof(int), IPV6_HOPLIMIT, IPPROTO_IPV6);
+                       sizeof(int), IS2292(IPV6_2292HOPLIMIT, IPV6_HOPLIMIT), IPPROTO_IPV6);
+               if (*mp)
+                       mp = &(*mp)->m_next;
+       }
+
+       if ((in6p->in6p_flags & IN6P_TCLASS) != 0) {
+               u_int32_t flowinfo;
+               int tclass;
+
+               flowinfo = (u_int32_t)ntohl(ip6->ip6_flow & IPV6_FLOWINFO_MASK);
+               flowinfo >>= 20;
+
+               tclass = flowinfo & 0xff;
+               *mp = sbcreatecontrol((caddr_t) &tclass, sizeof(tclass),
+                   IPV6_TCLASS, IPPROTO_IPV6);
                if (*mp)
                        mp = &(*mp)->m_next;
        }
@@ -1216,7 +1231,7 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf **mp, struct ip6_hdr *ip6,
                         * Note: this constraint is removed in 2292bis.
                         */
                        *mp = sbcreatecontrol((caddr_t)hbh, hbhlen,
-                                             IPV6_HOPOPTS, IPPROTO_IPV6);
+                                IS2292(IPV6_2292HOPOPTS, IPV6_HOPOPTS), IPPROTO_IPV6);
                        if (*mp)
                                mp = &(*mp)->m_next;
 #ifdef PULLDOWN_TEST
@@ -1331,7 +1346,7 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf **mp, struct ip6_hdr *ip6,
                                        break;
 
                                *mp = sbcreatecontrol((caddr_t)ip6e, elen,
-                                                     IPV6_DSTOPTS,
+                                                     IS2292(IPV6_2292DSTOPTS, IPV6_DSTOPTS),
                                                      IPPROTO_IPV6);
                                if (*mp)
                                        mp = &(*mp)->m_next;
@@ -1341,7 +1356,7 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf **mp, struct ip6_hdr *ip6,
                                        break;
 
                                *mp = sbcreatecontrol((caddr_t)ip6e, elen,
-                                                     IPV6_RTHDR,
+                                                     IS2292(IPV6_2292RTHDR, IPV6_RTHDR),
                                                      IPPROTO_IPV6);
                                if (*mp)
                                        mp = &(*mp)->m_next;
@@ -1376,7 +1391,42 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf **mp, struct ip6_hdr *ip6,
          loopend:
                ;
        }
+#undef IS2292
+}
+
+void
+ip6_notify_pmtu(struct inpcb *in6p, struct sockaddr_in6 *dst, u_int32_t *mtu)
+{
+       struct socket *so;
+       struct mbuf *m_mtu;
+       struct ip6_mtuinfo mtuctl;
+
+       so =  in6p->inp_socket;
+
+       if (mtu == NULL)
+               return;
+
+#ifdef DIAGNOSTIC
+       if (so == NULL)         /* I believe this is impossible */
+               panic("ip6_notify_pmtu: socket is NULL");
+#endif
+
+       bzero(&mtuctl, sizeof(mtuctl)); /* zero-clear for safety */
+       mtuctl.ip6m_mtu = *mtu;
+       mtuctl.ip6m_addr = *dst;
+
+       if ((m_mtu = sbcreatecontrol((caddr_t)&mtuctl, sizeof(mtuctl),
+           IPV6_PATHMTU, IPPROTO_IPV6)) == NULL)
+               return;
+
+       if (sbappendaddr(&so->so_rcv, (struct sockaddr *)dst, NULL, m_mtu)
+           == 0) {
+               m_freem(m_mtu);
+               /* XXX: should count statistics */
+       } else
+               sorwakeup(so);
 
+       return;
 }
 
 #ifdef PULLDOWN_TEST
index c8e54ef..111e5c3 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet6/ip6_output.c,v 1.13.2.18 2003/01/24 05:11:35 sam Exp $       */
-/*     $DragonFly: src/sys/netinet6/ip6_output.c,v 1.36 2008/06/18 11:38:37 swildner Exp $     */
+/*     $DragonFly: src/sys/netinet6/ip6_output.c,v 1.37 2008/09/04 09:08:22 hasso Exp $        */
 /*     $KAME: ip6_output.c,v 1.279 2002/01/26 06:12:30 jinmei Exp $    */
 
 /*
@@ -94,6 +94,7 @@
 #include <netinet6/ip6_var.h>
 #include <netinet/in_pcb.h>
 #include <netinet6/nd6.h>
+#include <netinet6/ip6protosw.h>
 
 #ifdef IPSEC
 #include <netinet6/ipsec.h>
@@ -123,15 +124,22 @@ struct ip6_exthdrs {
        struct mbuf *ip6e_dest2;
 };
 
+static int ip6_pcbopt (int, u_char *, int, struct ip6_pktopts **, int);
+static int ip6_setpktoption (int, u_char *, int, struct ip6_pktopts *,
+        int, int, int, int);
 static int ip6_pcbopts (struct ip6_pktopts **, struct mbuf *,
-                           struct socket *, struct sockopt *sopt);
+                           struct socket *, struct sockopt *);
+static int ip6_getpcbopt(struct ip6_pktopts *, int, struct sockopt *);
 static int ip6_setmoptions (int, struct ip6_moptions **, struct mbuf *);
 static int ip6_getmoptions (int, struct ip6_moptions *, struct mbuf **);
+static int ip6_getpmtu(struct route_in6 *, struct route_in6 *,
+       struct ifnet *, struct in6_addr *, u_long *, int *);
 static int copyexthdr (void *, struct mbuf **);
 static int ip6_insertfraghdr (struct mbuf *, struct mbuf *, int,
                                  struct ip6_frag **);
 static int ip6_insert_jumboopt (struct ip6_exthdrs *, u_int32_t);
 static struct mbuf *ip6_splithdr (struct mbuf *);
+static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int);
 
 /*
  * IP6 output. The packet in mbuf chain m contains a skeletal IP6
@@ -161,6 +169,7 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, struct route_in6 *ro,
        int error = 0;
        struct in6_ifaddr *ia = NULL;
        u_long mtu;
+       int alwaysfrag, dontfrag;
        u_int32_t optlen, plen = 0, unfragpartlen;
        struct ip6_exthdrs exthdrs;
        struct in6_addr finaldst;
@@ -447,18 +456,10 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, struct route_in6 *ro,
         */
        if (exthdrs.ip6e_rthdr) {
                struct ip6_rthdr *rh;
-               struct ip6_rthdr0 *rh0;
 
                finaldst = ip6->ip6_dst;
                rh = mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *);
                switch (rh->ip6r_type) {
-               case IPV6_RTHDR_TYPE_0:
-                        rh0 = (struct ip6_rthdr0 *)rh;
-                        ip6->ip6_dst = rh0->ip6r0_addr[0];
-                        bcopy(&rh0->ip6r0_addr[1], &rh0->ip6r0_addr[0],
-                            sizeof(struct in6_addr)*(rh0->ip6r0_segleft - 1));
-                        rh0->ip6r0_addr[rh0->ip6r0_segleft - 1] = finaldst;
-                        break;
                default:        /* is it possible? */
                         error = EINVAL;
                         goto bad;
@@ -745,59 +746,35 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, struct route_in6 *ro,
        if (ifpp)
                *ifpp = ifp;
 
+       /* Determine path MTU. */
+       if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu,
+           &alwaysfrag)) != 0)
+               goto bad;
+
        /*
-        * Determine path MTU.
+        * The caller of this function may specify to use the minimum MTU
+        * in some cases.
+        * An advanced API option (IPV6_USE_MIN_MTU) can also override MTU
+        * setting.  The logic is a bit complicated; by default, unicast
+        * packets will follow path MTU while multicast packets will be sent at
+        * the minimum MTU.  If IP6PO_MINMTU_ALL is specified, all packets
+        * including unicast ones will be sent at the minimum MTU.  Multicast
+        * packets will always be sent at the minimum MTU unless
+        * IP6PO_MINMTU_DISABLE is explicitly specified.
+        * See RFC 3542 for more details.
         */
-       if (ro_pmtu != ro) {
-               /* The first hop and the final destination may differ. */
-               struct sockaddr_in6 *sin6_fin =
-                       (struct sockaddr_in6 *)&ro_pmtu->ro_dst;
-
-               if (ro_pmtu->ro_rt != NULL &&
-                   (!(ro->ro_rt->rt_flags & RTF_UP) ||
-                    !IN6_ARE_ADDR_EQUAL(&sin6_fin->sin6_addr, &finaldst))) {
-                       RTFREE(ro_pmtu->ro_rt);
-                       ro_pmtu->ro_rt = NULL;
-               }
-               if (ro_pmtu->ro_rt == NULL) {
-                       bzero(sin6_fin, sizeof(*sin6_fin));
-                       sin6_fin->sin6_family = AF_INET6;
-                       sin6_fin->sin6_len = sizeof(struct sockaddr_in6);
-                       sin6_fin->sin6_addr = finaldst;
-
-                       rtalloc((struct route *)ro_pmtu);
-               }
-       }
-       if (ro_pmtu->ro_rt != NULL) {
-               u_int32_t ifmtu = ND_IFINFO(ifp)->linkmtu;
-
-               mtu = ro_pmtu->ro_rt->rt_rmx.rmx_mtu;
-               if (mtu > ifmtu || mtu == 0) {
-                       /*
-                        * The MTU on the route is larger than the MTU on
-                        * the interface!  This shouldn't happen, unless the
-                        * MTU of the interface has been changed after the
-                        * interface was brought up.  Change the MTU in the
-                        * route to match the interface MTU (as long as the
-                        * field isn't locked).
-                        *
-                        * if MTU on the route is 0, we need to fix the MTU.
-                        * this case happens with path MTU discovery timeouts.
-                        */
-                        mtu = ifmtu;
-                        if (!(ro_pmtu->ro_rt->rt_rmx.rmx_locks & RTV_MTU))
-                                ro_pmtu->ro_rt->rt_rmx.rmx_mtu = mtu; /* XXX */
+       if (mtu > IPV6_MMTU) {
+               if ((flags & IPV6_MINMTU))
+                       mtu = IPV6_MMTU;
+               else if (opt && opt->ip6po_minmtu == IP6PO_MINMTU_ALL)
+                       mtu = IPV6_MMTU;
+               else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
+                        (opt == NULL ||
+                         opt->ip6po_minmtu != IP6PO_MINMTU_DISABLE)) {
+                       mtu = IPV6_MMTU;
                }
-       } else {
-               mtu = ND_IFINFO(ifp)->linkmtu;
        }
 
-       /*
-        * advanced API (IPV6_USE_MIN_MTU) overrides mtu setting
-        */
-       if ((flags & IPV6_MINMTU) != 0 && mtu > IPV6_MMTU)
-               mtu = IPV6_MMTU;
-
        /* Fake scoped addresses */
        if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
                /*
@@ -909,36 +886,80 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, struct route_in6 *ro,
        /*
         * Send the packet to the outgoing interface.
         * If necessary, do IPv6 fragmentation before sending.
+        *
+        * the logic here is rather complex:
+        * 1: normal case (dontfrag == 0, alwaysfrag == 0)
+        * 1-a: send as is if tlen <= path mtu
+        * 1-b: fragment if tlen > path mtu
+        *
+        * 2: if user asks us not to fragment (dontfrag == 1)
+        * 2-a: send as is if tlen <= interface mtu
+        * 2-b: error if tlen > interface mtu
+        *
+        * 3: if we always need to attach fragment header (alwaysfrag == 1)
+        *      always fragment
+        *
+        * 4: if dontfrag == 1 && alwaysfrag == 1
+        *      error, as we cannot handle this conflicting request
         */
        tlen = m->m_pkthdr.len;
-       if (tlen <= mtu
-#ifdef notyet
-           /*
-            * On any link that cannot convey a 1280-octet packet in one piece,
-            * link-specific fragmentation and reassembly must be provided at
-            * a layer below IPv6. [RFC 2460, sec.5]
-            * Thus if the interface has ability of link-level fragmentation,
-            * we can just send the packet even if the packet size is
-            * larger than the link's MTU.
-            * XXX: IFF_FRAGMENTABLE (or such) flag has not been defined yet...
-            */
-
-           || ifp->if_flags & IFF_FRAGMENTABLE
-#endif
-           )
-       {
-               /* Record statistics for this interface address. */
-               if (ia && !(flags & IPV6_FORWARDING)) {
-                       ia->ia_ifa.if_opackets++;
-                       ia->ia_ifa.if_obytes += m->m_pkthdr.len;
-               }
+
+       if (opt && (opt->ip6po_flags & IP6PO_DONTFRAG))
+               dontfrag = 1;
+       else
+               dontfrag = 0;
+       if (dontfrag && alwaysfrag) {   /* case 4 */
+               /* conflicting request - can't transmit */
+               error = EMSGSIZE;
+               goto bad;
+       }
+       if (dontfrag && tlen > IN6_LINKMTU(ifp)) {      /* case 2-b */
+               /*
+                * Even if the DONTFRAG option is specified, we cannot send the
+                * packet when the data length is larger than the MTU of the
+                * outgoing interface.
+                * Notify the error by sending IPV6_PATHMTU ancillary data as
+                * well as returning an error code (the latter is not described
+                * in the API spec.)
+                */
+               u_int32_t mtu32;
+               struct ip6ctlparam ip6cp;
+
+               mtu32 = (u_int32_t)mtu;
+               bzero(&ip6cp, sizeof(ip6cp));
+               ip6cp.ip6c_cmdarg = (void *)&mtu32;
+               kpfctlinput2(PRC_MSGSIZE, (struct sockaddr *)&ro_pmtu->ro_dst,
+                   (void *)&ip6cp);
+
+               error = EMSGSIZE;
+               goto bad;
+       }
+
+       /*
+        * transmit packet without fragmentation
+        */
+       if (dontfrag || (!alwaysfrag && tlen <= mtu)) { /* case 1-a and 2-a */
+               struct in6_ifaddr *ia6;
+
+               ip6 = mtod(m, struct ip6_hdr *);
+               ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
+               if (ia6) {
+                       /* Record statistics for this interface address. */
+                       ia6->ia_ifa.if_opackets++;
+                       ia6->ia_ifa.if_obytes += m->m_pkthdr.len;
+               }
 #ifdef IPSEC
                /* clean ipsec history once it goes out of the node */
                ipsec_delaux(m);
 #endif
                error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
                goto done;
-       } else if (mtu < IPV6_MMTU) {
+       } 
+
+       /*
+        * try to fragment the packet.  case 1-b and 3
+        */
+       if (mtu < IPV6_MMTU) {
                /*
                 * note that path MTU is never less than IPV6_MMTU
                 * (see icmp6_input).
@@ -954,6 +975,7 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, struct route_in6 *ro,
                struct mbuf **mnext, *m_frgpart;
                struct ip6_frag *ip6f;
                u_int32_t id = htonl(ip6_id++);
+               int qslots = ifp->if_snd.ifq_maxlen - ifp->if_snd.ifq_len;
                u_char nextproto;
 
                /*
@@ -972,6 +994,17 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, struct route_in6 *ro,
                        goto bad;
                }
 
+               /*
+                * Verify that we have any chance at all of being able to queue
+                *      the packet or packet fragments
+                */
+               if (qslots <= 0 || ((u_int)qslots * (mtu - hlen)
+                   < tlen  /* - hlen */)) {
+                       error = ENOBUFS;
+                       ip6stat.ip6s_odropped++;
+                       goto bad;
+               }
+
                mnext = &m->m_nextpkt;
 
                /*
@@ -1257,14 +1290,92 @@ ip6_insertfraghdr(struct mbuf *m0, struct mbuf *m, int hlen,
        return (0);
 }
 
+static int
+ip6_getpmtu(struct route_in6 *ro_pmtu, struct route_in6 *ro,
+    struct ifnet *ifp, struct in6_addr *dst, u_long *mtup,
+    int *alwaysfragp)
+{
+       u_int32_t mtu = 0;
+       int alwaysfrag = 0;
+       int error = 0;
+
+       if (ro_pmtu != ro) {
+               /* The first hop and the final destination may differ. */
+               struct sockaddr_in6 *sa6_dst =
+                   (struct sockaddr_in6 *)&ro_pmtu->ro_dst;
+               if (ro_pmtu->ro_rt &&
+                   ((ro_pmtu->ro_rt->rt_flags & RTF_UP) == 0 ||
+                    !IN6_ARE_ADDR_EQUAL(&sa6_dst->sin6_addr, dst))) {
+                       RTFREE(ro_pmtu->ro_rt);
+                       ro_pmtu->ro_rt = (struct rtentry *)NULL;
+               }
+               if (ro_pmtu->ro_rt == NULL) {
+                       bzero(sa6_dst, sizeof(*sa6_dst));
+                       sa6_dst->sin6_family = AF_INET6;
+                       sa6_dst->sin6_len = sizeof(struct sockaddr_in6);
+                       sa6_dst->sin6_addr = *dst;
+
+                       rtalloc((struct route *)ro_pmtu);
+               }
+       }
+       if (ro_pmtu->ro_rt) {
+               u_int32_t ifmtu;
+               struct in_conninfo inc;
+
+               bzero(&inc, sizeof(inc));
+               inc.inc_flags = 1; /* IPv6 */
+               inc.inc6_faddr = *dst;
+
+               if (ifp == NULL)
+                       ifp = ro_pmtu->ro_rt->rt_ifp;
+               ifmtu = IN6_LINKMTU(ifp);
+               mtu = ro_pmtu->ro_rt->rt_rmx.rmx_mtu;
+               if (mtu == 0)
+                       mtu = ifmtu;
+               else if (mtu < IPV6_MMTU) {
+                       /*
+                        * RFC2460 section 5, last paragraph:
+                        * if we record ICMPv6 too big message with
+                        * mtu < IPV6_MMTU, transmit packets sized IPV6_MMTU
+                        * or smaller, with framgent header attached.
+                        * (fragment header is needed regardless from the
+                        * packet size, for translators to identify packets)
+                        */
+                       alwaysfrag = 1;
+                       mtu = IPV6_MMTU;
+               } else if (mtu > ifmtu) {
+                       /*
+                        * The MTU on the route is larger than the MTU on
+                        * the interface!  This shouldn't happen, unless the
+                        * MTU of the interface has been changed after the
+                        * interface was brought up.  Change the MTU in the
+                        * route to match the interface MTU (as long as the
+                        * field isn't locked).
+                        */
+                       mtu = ifmtu;
+                       ro_pmtu->ro_rt->rt_rmx.rmx_mtu = mtu;
+               }
+       } else if (ifp) {
+               mtu = IN6_LINKMTU(ifp);
+       } else
+               error = EHOSTUNREACH; /* XXX */
+
+       *mtup = mtu;
+       if (alwaysfragp)
+               *alwaysfragp = alwaysfrag;
+       return (error);
+}
+
 /*
  * IP6 socket option processing.
  */
 int
 ip6_ctloutput(struct socket *so, struct sockopt *sopt)
 {
+       int optdatalen,uproto;
        int privileged;
        struct inpcb *in6p = so->so_pcb;
+       void *optdata;
        int error, optval;
        int level, op, optname;
        int optlen;
@@ -1283,6 +1394,7 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt)
        }
        error = optval = 0;
 
+       uproto = (int)so->so_proto->pr_protocol;
        privileged = (td == NULL || suser(td)) ? 0 : 1;
 
        if (level == IPPROTO_IPV6) {
@@ -1290,7 +1402,10 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt)
 
                case SOPT_SET:
                        switch (optname) {
+                       case IPV6_2292PKTOPTIONS:
+#ifdef IPV6_PKTOPTIONS
                        case IPV6_PKTOPTIONS:
+#endif
                        {
                                struct mbuf *m;
 
@@ -1317,8 +1432,20 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt)
                         *  receiving ANY hbh/dst options in order to avoid
                         *  overhead of parsing options in the kernel.
                         */
+                       case IPV6_RECVHOPOPTS:
+                       case IPV6_RECVDSTOPTS:
+                       case IPV6_RECVRTHDRDSTOPTS:
+                               if (!privileged)
+                                       return (EPERM);
+                       case IPV6_RECVPKTINFO:
+                       case IPV6_RECVHOPLIMIT:
+                       case IPV6_RECVRTHDR:
+                       case IPV6_RECVPATHMTU:
+                       case IPV6_RECVTCLASS:
+                       case IPV6_AUTOFLOWLABEL:
+                       case IPV6_HOPLIMIT:
+                       /* FALLTHROUGH */
                        case IPV6_UNICAST_HOPS:
-                       case IPV6_CHECKSUM:
                        case IPV6_FAITH:
 
                        case IPV6_V6ONLY:
@@ -1352,9 +1479,110 @@ do { \
                in6p->in6p_flags &= ~(bit); \
 } while (0)
 #define OPTBIT(bit) (in6p->in6p_flags & (bit) ? 1 : 0)
+/* 
+ * Although changed to RFC3542, It's better to also support RFC2292 API 
+ */
+#define OPTSET2292(bit) \
+do { \
+       in6p->in6p_flags |= IN6P_RFC2292; \
+       if (optval) \
+               in6p->in6p_flags |= (bit); \
+       else \
+               in6p->in6p_flags &= ~(bit); \
+} while (/*CONSTCOND*/ 0)
+
+                               case IPV6_RECVPKTINFO:
+                                       /* cannot mix with RFC2292 */
+                                       if (OPTBIT(IN6P_RFC2292)) {
+                                               error = EINVAL;
+                                               break;
+                                       }
+                                       OPTSET(IN6P_PKTINFO);
+                                       break;
+
+                               case IPV6_HOPLIMIT:
+                               {
+                                       struct ip6_pktopts **optp;
+
+                                       /* cannot mix with RFC2292 */
+                                       if (OPTBIT(IN6P_RFC2292)) {
+                                               error = EINVAL;
+                                               break;
+                                       }
+                                       optp = &in6p->in6p_outputopts;
+                                       error = ip6_pcbopt(IPV6_HOPLIMIT,
+                                           (u_char *)&optval, sizeof(optval),
+                                           optp, uproto);
+                                       break;
+                               }
+
+                               case IPV6_RECVHOPLIMIT:
+                                       /* cannot mix with RFC2292 */
+                                       if (OPTBIT(IN6P_RFC2292)) {
+                                               error = EINVAL;
+                                               break;
+                                       }
+                                       OPTSET(IN6P_HOPLIMIT);
+                                       break;
+
+                               case IPV6_RECVHOPOPTS:
+                                       /* cannot mix with RFC2292 */
+                                       if (OPTBIT(IN6P_RFC2292)) {
+                                               error = EINVAL;
+                                               break;
+                                       }
+                                       OPTSET(IN6P_HOPOPTS);
+                                       break;
 
-                               case IPV6_CHECKSUM:
-                                       in6p->in6p_cksum = optval;
+                               case IPV6_RECVDSTOPTS:
+                                       /* cannot mix with RFC2292 */
+                                       if (OPTBIT(IN6P_RFC2292)) {
+                                               error = EINVAL;
+                                               break;
+                                       }
+                                       OPTSET(IN6P_DSTOPTS);
+                                       break;
+
+                               case IPV6_RECVRTHDRDSTOPTS:
+                                       /* cannot mix with RFC2292 */
+                                       if (OPTBIT(IN6P_RFC2292)) {
+                                               error = EINVAL;
+                                               break;
+                                       }
+                                       OPTSET(IN6P_RTHDRDSTOPTS);
+                                       break;
+
+                               case IPV6_RECVRTHDR:
+                                       /* cannot mix with RFC2292 */
+                                       if (OPTBIT(IN6P_RFC2292)) {
+                                               error = EINVAL;
+                                               break;
+                                       }
+                                       OPTSET(IN6P_RTHDR);
+                                       break;
+
+                               case IPV6_RECVPATHMTU:
+                                       /*
+                                        * We ignore this option for TCP
+                                        * sockets.
+                                        * (RFC3542 leaves this case
+                                        * unspecified.)
+                                        */
+                                       if (uproto != IPPROTO_TCP)
+                                               OPTSET(IN6P_MTU);
+                                       break;
+
+                               case IPV6_RECVTCLASS:
+                                       /* cannot mix with RFC2292 XXX */
+                                       if (OPTBIT(IN6P_RFC2292)) {
+                                               error = EINVAL;
+                                               break;
+                                       }
+                                       OPTSET(IN6P_TCLASS);
+                                       break;
+
+                               case IPV6_AUTOFLOWLABEL:
+                                       OPTSET(IN6P_AUTOFLOWLABEL);
                                        break;
 
                                case IPV6_FAITH:
@@ -1365,7 +1593,6 @@ do { \
                                        /*
                                         * make setsockopt(IPV6_V6ONLY)
                                         * available only prior to bind(2).
-                                        * see ipng mailing list, Jun 22 2001.
                                         */
                                        if (in6p->in6p_lport ||
                                            !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
@@ -1382,11 +1609,32 @@ do { \
                                }
                                break;
 
-                       case IPV6_PKTINFO:
-                       case IPV6_HOPLIMIT:
-                       case IPV6_HOPOPTS:
-                       case IPV6_DSTOPTS:
-                       case IPV6_RTHDR:
+                       case IPV6_TCLASS:
+                       case IPV6_DONTFRAG:
+                       case IPV6_USE_MIN_MTU:
+                       case IPV6_PREFER_TEMPADDR:
+                               if (optlen != sizeof(optval)) {
+                                       error = EINVAL;
+                                       break;
+                               }
+                               error = soopt_to_kbuf(sopt, &optval,
+                                       sizeof optval, sizeof optval);
+                               if (error)
+                                       break;
+                               {
+                                       struct ip6_pktopts **optp;
+                                       optp = &in6p->in6p_outputopts;
+                                       error = ip6_pcbopt(optname,
+                                           (u_char *)&optval, sizeof(optval),
+                                           optp, uproto);
+                                       break;
+                               }
+
+                       case IPV6_2292PKTINFO:
+                       case IPV6_2292HOPLIMIT:
+                       case IPV6_2292HOPOPTS:
+                       case IPV6_2292DSTOPTS:
+                       case IPV6_2292RTHDR:
                                /* RFC 2292 */
                                if (optlen != sizeof(int)) {
                                        error = EINVAL;
@@ -1397,31 +1645,69 @@ do { \
                                if (error)
                                        break;
                                switch (optname) {
-                               case IPV6_PKTINFO:
-                                       OPTSET(IN6P_PKTINFO);
+                               case IPV6_2292PKTINFO:
+                                       OPTSET2292(IN6P_PKTINFO);
                                        break;
-                               case IPV6_HOPLIMIT:
-                                       OPTSET(IN6P_HOPLIMIT);
+                               case IPV6_2292HOPLIMIT:
+                                       OPTSET2292(IN6P_HOPLIMIT);
                                        break;
-                               case IPV6_HOPOPTS:
+                               case IPV6_2292HOPOPTS:
                                        /*
                                         * Check super-user privilege.
                                         * See comments for IPV6_RECVHOPOPTS.
                                         */
                                        if (!privileged)
                                                return (EPERM);
-                                       OPTSET(IN6P_HOPOPTS);
+                                       OPTSET2292(IN6P_HOPOPTS);
                                        break;
-                               case IPV6_DSTOPTS:
+                               case IPV6_2292DSTOPTS:
                                        if (!privileged)
                                                return (EPERM);
-                                       OPTSET(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); /* XXX */
+                                       OPTSET2292(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); /* XXX */
                                        break;
-                               case IPV6_RTHDR:
-                                       OPTSET(IN6P_RTHDR);
+                               case IPV6_2292RTHDR:
+                                       OPTSET2292(IN6P_RTHDR);
+                                       break;
+                               }
+                               break;
+
+                       case IPV6_PKTINFO:
+                       case IPV6_HOPOPTS:
+                       case IPV6_RTHDR:
+                       case IPV6_DSTOPTS:
+                       case IPV6_RTHDRDSTOPTS:
+                       case IPV6_NEXTHOP:
+                       {
+                               /* 
+                                * New advanced API (RFC3542) 
+                                */
+                               u_char *optbuf;
+                               u_char optbuf_storage[MCLBYTES];
+                               int optlen;
+                               struct ip6_pktopts **optp;
+
+                               /* cannot mix with RFC2292 */
+                               if (OPTBIT(IN6P_RFC2292)) {
+                                       error = EINVAL;
                                        break;
                                }
+
+                               /*
+                                * We only ensure valsize is not too large
+                                * here.  Further validation will be done
+                                * later.
+                                */
+                               error = soopt_to_kbuf(sopt, optbuf_storage,
+                                   sizeof(optbuf_storage), 0);
+                               if (error)
+                                       break;
+                               optlen = sopt->sopt_valsize;
+                               optbuf = optbuf_storage;
+                               optp = &in6p->in6p_outputopts;
+                               error = ip6_pcbopt(optname, optbuf, optlen,
+                                   optp, uproto);
                                break;
+                       }       
 #undef OPTSET
 
                        case IPV6_MULTICAST_IF:
@@ -1528,8 +1814,19 @@ do { \
 
                case SOPT_GET:
                        switch (optname) {
-
+                       case IPV6_2292PKTOPTIONS:
+#ifdef IPV6_PKTOPTIONS
                        case IPV6_PKTOPTIONS:
+#endif
+                               /*
+                                * RFC3542 (effectively) deprecated the
+                                * semantics of the 2292-style pktoptions.
+                                * Since it was not reliable in nature (i.e.,
+                                * applications had to expect the lack of some
+                                * information after all), it would make sense
+                                * to simplify this part by always returning
+                                * empty data.
+                                */
                                if (in6p->in6p_options) {
                                        struct mbuf *m;
                                        m = m_copym(in6p->in6p_options,
@@ -1540,21 +1837,61 @@ do { \
                                } else
                                        sopt->sopt_valsize = 0;
                                break;
-
+               
+                       case IPV6_RECVHOPOPTS:
+                       case IPV6_RECVDSTOPTS:
+                       case IPV6_RECVRTHDRDSTOPTS:
                        case IPV6_UNICAST_HOPS:
-                       case IPV6_CHECKSUM:
-
+                       case IPV6_RECVPKTINFO:
+                       case IPV6_RECVHOPLIMIT:
+                       case IPV6_RECVRTHDR:
+                       case IPV6_RECVPATHMTU:
+                       case IPV6_RECVTCLASS:
+                       case IPV6_AUTOFLOWLABEL:
                        case IPV6_FAITH:
                        case IPV6_V6ONLY:
                        case IPV6_PORTRANGE:
                                switch (optname) {
 
-                               case IPV6_UNICAST_HOPS:
-                                       optval = in6p->in6p_hops;
+                               case IPV6_RECVHOPOPTS:
+                                       optval = OPTBIT(IN6P_HOPOPTS);
+                                       break;
+
+                               case IPV6_RECVDSTOPTS:
+                                       optval = OPTBIT(IN6P_DSTOPTS);
+                                       break;
+
+                               case IPV6_RECVRTHDRDSTOPTS:
+                                       optval = OPTBIT(IN6P_RTHDRDSTOPTS);
+                                       break;
+
+                               case IPV6_RECVPKTINFO:
+                                       optval = OPTBIT(IN6P_PKTINFO);
+                                       break;
+
+                               case IPV6_RECVHOPLIMIT:
+                                       optval = OPTBIT(IN6P_HOPLIMIT);
+                                       break;
+
+                               case IPV6_RECVRTHDR:
+                                       optval = OPTBIT(IN6P_RTHDR);
+                                       break;
+
+                               case IPV6_RECVPATHMTU:
+                                       optval = OPTBIT(IN6P_MTU);
+                                       break;
+
+                               case IPV6_RECVTCLASS:
+                                       optval = OPTBIT(IN6P_TCLASS);
+                                       break;
+
+                               case IPV6_AUTOFLOWLABEL:
+                                       optval = OPTBIT(IN6P_AUTOFLOWLABEL);
                                        break;
 
-                               case IPV6_CHECKSUM:
-                                       optval = in6p->in6p_cksum;
+
+                               case IPV6_UNICAST_HOPS:
+                                       optval = in6p->in6p_hops;
                                        break;
 
                                case IPV6_FAITH:
@@ -1579,41 +1916,88 @@ do { \
                                    }
                                }
                                soopt_from_kbuf(sopt, &optval,
-                                       sizeof optval);
+                                       sizeof optval);
                                break;
 
-                       case IPV6_PKTINFO:
-                       case IPV6_HOPLIMIT:
-                       case IPV6_HOPOPTS:
-                       case IPV6_RTHDR:
-                       case IPV6_DSTOPTS:
-                               if (optname == IPV6_HOPOPTS ||
-                                   optname == IPV6_DSTOPTS ||
+                       case IPV6_PATHMTU:
+                       {
+                               u_long pmtu = 0;
+                               struct ip6_mtuinfo mtuinfo;
+                               struct route_in6 sro;
+
+                               bzero(&sro, sizeof(sro));
+
+                               if (!(so->so_state & SS_ISCONNECTED))
+                                       return (ENOTCONN);
+                               /*
+                                * XXX: we dot not consider the case of source
+                                * routing, or optional information to specify
+                                * the outgoing interface.
+                                */
+                               error = ip6_getpmtu(&sro, NULL, NULL,
+                                   &in6p->in6p_faddr, &pmtu, NULL);
+                               if (sro.ro_rt)
+                                       RTFREE(sro.ro_rt);
+                               if (error)
+                                       break;
+                               if (pmtu > IPV6_MAXPACKET)
+                                       pmtu = IPV6_MAXPACKET;
+
+                               bzero(&mtuinfo, sizeof(mtuinfo));
+                               mtuinfo.ip6m_mtu = (u_int32_t)pmtu;
+                               optdata = (void *)&mtuinfo;
+                               optdatalen = sizeof(mtuinfo);
+                               soopt_from_kbuf(sopt, optdata,
+                                   optdatalen);
+                               break;
+                       }
+
+                       case IPV6_2292PKTINFO:
+                       case IPV6_2292HOPLIMIT:
+                       case IPV6_2292HOPOPTS:
+                       case IPV6_2292RTHDR:
+                       case IPV6_2292DSTOPTS:
+                               if (optname == IPV6_2292HOPOPTS ||
+                                   optname == IPV6_2292DSTOPTS ||
                                    !privileged)
                                        return (EPERM);
                                switch (optname) {
-                               case IPV6_PKTINFO:
+                               case IPV6_2292PKTINFO:
                                        optval = OPTBIT(IN6P_PKTINFO);
                                        break;
-                               case IPV6_HOPLIMIT:
+                               case IPV6_2292HOPLIMIT:
                                        optval = OPTBIT(IN6P_HOPLIMIT);
                                        break;
-                               case IPV6_HOPOPTS:
+                               case IPV6_2292HOPOPTS:
                                        if (!privileged)
                                                return (EPERM);
                                        optval = OPTBIT(IN6P_HOPOPTS);
                                        break;
-                               case IPV6_RTHDR:
+                               case IPV6_2292RTHDR:
                                        optval = OPTBIT(IN6P_RTHDR);
                                        break;
-                               case IPV6_DSTOPTS:
+                               case IPV6_2292DSTOPTS:
                                        if (!privileged)
                                                return (EPERM);
                                        optval = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS);
                                        break;
                                }
                                soopt_from_kbuf(sopt, &optval,
-                                       sizeof optval);
+                                       sizeof optval);
+                               break;
+
+                       case IPV6_PKTINFO:
+                       case IPV6_HOPOPTS:
+                       case IPV6_RTHDR:
+                       case IPV6_DSTOPTS:
+                       case IPV6_RTHDRDSTOPTS:
+                       case IPV6_NEXTHOP:
+                       case IPV6_TCLASS:
+                       case IPV6_DONTFRAG:
+                       case IPV6_USE_MIN_MTU:
+                       case IPV6_PREFER_TEMPADDR:
+                               error = ip6_getpcbopt(in6p->in6p_outputopts,
+                                   optname, sopt);
                                break;
 
                        case IPV6_MULTICAST_IF:
@@ -1627,7 +2011,7 @@ do { \
                                                in6p->in6p_moptions, &m);
                                if (error == 0)
                                        soopt_from_kbuf(sopt,
-                                               mtod(m, char *), m->m_len);
+                                               mtod(m, char *), m->m_len);
                                m_freem(m);
                            }
                                break;
@@ -1686,33 +2070,106 @@ do { \
        return (error);
 }
 
-/*
- * Set up IP6 options in pcb for insertion in output packets or
- * specifying behavior of outgoing packets.
- */
-static int
-ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m, struct socket *so,
-           struct sockopt *sopt)
+int
+ip6_raw_ctloutput(struct socket *so, struct sockopt *sopt)
 {
-       struct ip6_pktopts *opt = *pktopt;
-       int error = 0;
-       struct thread *td = sopt->sopt_td;
-       int priv = 0;
-
-       /* turn off any old options. */
-       if (opt) {
-#ifdef DIAGNOSTIC
-               if (opt->ip6po_pktinfo || opt->ip6po_nexthop ||
-                   opt->ip6po_hbh || opt->ip6po_dest1 || opt->ip6po_dest2 ||
-                   opt->ip6po_rhinfo.ip6po_rhi_rthdr)
-                       kprintf("ip6_pcbopts: all specified options are cleared.\n");
-#endif
-               ip6_clearpktopts(opt, 1, -1);
-       } else
-               opt = kmalloc(sizeof(*opt), M_IP6OPT, M_WAITOK);
-       *pktopt = NULL;
+       int error = 0, optval, optlen;
+       const int icmp6off = offsetof(struct icmp6_hdr, icmp6_cksum);
+       struct in6pcb *in6p = sotoin6pcb(so);
+       int level, op, optname;
 
-       if (m == NULL || m->m_len == 0) {
+       if (sopt) {
+               level = sopt->sopt_level;
+               op = sopt->sopt_dir;
+               optname = sopt->sopt_name;
+               optlen = sopt->sopt_valsize;
+       } else
+               panic("ip6_raw_ctloutput: arg soopt is NULL");
+
+       if (level != IPPROTO_IPV6) {
+               return (EINVAL);
+       }
+
+       switch (optname) {
+       case IPV6_CHECKSUM:
+               /*
+                * For ICMPv6 sockets, no modification allowed for checksum
+                * offset, permit "no change" values to help existing apps.
+                *
+                * RFC3542 says: "An attempt to set IPV6_CHECKSUM
+                * for an ICMPv6 socket will fail."
+                * The current behavior does not meet RFC3542.
+                */
+               switch (op) {
+               case SOPT_SET:
+                       if (optlen != sizeof(int)) {
+                               error = EINVAL;
+                               break;
+                       }
+                       error = soopt_to_kbuf(sopt, &optval,
+                                   sizeof optval, sizeof optval);
+                       if (error)
+                               break;
+                       if ((optval % 2) != 0) {
+                               /* the API assumes even offset values */
+                               error = EINVAL;
+                       } else if (so->so_proto->pr_protocol ==
+                           IPPROTO_ICMPV6) {
+                               if (optval != icmp6off)
+                                       error = EINVAL;
+                       } else
+                               in6p->in6p_cksum = optval;
+                       break;
+
+               case SOPT_GET:
+                       if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
+                               optval = icmp6off;
+                       else
+                               optval = in6p->in6p_cksum;
+
+                       soopt_from_kbuf(sopt, &optval, sizeof(optval));
+                       break;
+
+               default:
+                       error = EINVAL;
+                       break;
+               }
+               break;
+
+       default:
+               error = ENOPROTOOPT;
+               break;
+       }
+
+       return (error);
+}
+
+/*
+ * Set up IP6 options in pcb for insertion in output packets or
+ * specifying behavior of outgoing packets.
+ */
+static int
+ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m,
+    struct socket *so, struct sockopt *sopt)
+{
+       int priv = 0;
+       struct ip6_pktopts *opt = *pktopt;
+       int error = 0;
+
+       /* turn off any old options. */
+       if (opt) {
+#ifdef DIAGNOSTIC
+               if (opt->ip6po_pktinfo || opt->ip6po_nexthop ||
+                   opt->ip6po_hbh || opt->ip6po_dest1 || opt->ip6po_dest2 ||
+                   opt->ip6po_rhinfo.ip6po_rhi_rthdr)
+                       kprintf("ip6_pcbopts: all specified options are cleared.\n");
+#endif
+               ip6_clearpktopts(opt, -1);
+       } else
+               opt = kmalloc(sizeof(*opt), M_IP6OPT, M_WAITOK);
+       *pktopt = NULL;
+
+       if (!m || m->m_len == 0) {
                /*
                 * Only turning off any previous options, regardless of
                 * whether the opt is just created or given.
@@ -1722,10 +2179,8 @@ ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m, struct socket *so,
        }
 
        /*  set options specified by user. */
-       if (suser(td) == 0)
-               priv = 1;
-       if ((error = ip6_setpktoptions(m, opt, priv, 1)) != 0) {
-               ip6_clearpktopts(opt, 1, -1); /* XXX: discard all options */
+       if ((error = ip6_setpktoptions(m, opt, NULL, so->so_proto->pr_protocol, priv)) != 0) {
+               ip6_clearpktopts(opt, -1); /* XXX: discard all options */
                kfree(opt, M_IP6OPT);
                return (error);
        }
@@ -1733,6 +2188,128 @@ ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m, struct socket *so,
        return (0);
 }
 
+
+/*
+ * Below three functions are introduced by merge to RFC3542
+ */
+
+static int
+ip6_getpcbopt(struct ip6_pktopts *pktopt, int optname, struct sockopt *sopt)
+{
+       void *optdata = NULL;
+       int optdatalen = 0;
+       struct ip6_ext *ip6e;
+       int error = 0;
+       struct in6_pktinfo null_pktinfo;
+       int deftclass = 0, on;
+       int defminmtu = IP6PO_MINMTU_MCASTONLY;
+       int defpreftemp = IP6PO_TEMPADDR_SYSTEM;
+
+       switch (optname) {
+       case IPV6_PKTINFO:
+               if (pktopt && pktopt->ip6po_pktinfo)
+                       optdata = (void *)pktopt->ip6po_pktinfo;
+               else {
+                       /* XXX: we don't have to do this every time... */
+                       bzero(&null_pktinfo, sizeof(null_pktinfo));
+                       optdata = (void *)&null_pktinfo;
+               }
+               optdatalen = sizeof(struct in6_pktinfo);
+               break;
+       case IPV6_TCLASS:
+               if (pktopt && pktopt->ip6po_tclass >= 0)
+                       optdata = (void *)&pktopt->ip6po_tclass;
+               else
+                       optdata = (void *)&deftclass;
+               optdatalen = sizeof(int);
+               break;
+       case IPV6_HOPOPTS:
+               if (pktopt && pktopt->ip6po_hbh) {
+                       optdata = (void *)pktopt->ip6po_hbh;
+                       ip6e = (struct ip6_ext *)pktopt->ip6po_hbh;
+                       optdatalen = (ip6e->ip6e_len + 1) << 3;
+               }
+               break;
+       case IPV6_RTHDR:
+               if (pktopt && pktopt->ip6po_rthdr) {
+                       optdata = (void *)pktopt->ip6po_rthdr;
+                       ip6e = (struct ip6_ext *)pktopt->ip6po_rthdr;
+                       optdatalen = (ip6e->ip6e_len + 1) << 3;
+               }
+               break;
+       case IPV6_RTHDRDSTOPTS:
+               if (pktopt && pktopt->ip6po_dest1) {
+                       optdata = (void *)pktopt->ip6po_dest1;
+                       ip6e = (struct ip6_ext *)pktopt->ip6po_dest1;
+                       optdatalen = (ip6e->ip6e_len + 1) << 3;
+               }
+               break;
+       case IPV6_DSTOPTS:
+               if (pktopt && pktopt->ip6po_dest2) {
+                       optdata = (void *)pktopt->ip6po_dest2;
+                       ip6e = (struct ip6_ext *)pktopt->ip6po_dest2;
+                       optdatalen = (ip6e->ip6e_len + 1) << 3;
+               }
+               break;
+       case IPV6_NEXTHOP:
+               if (pktopt && pktopt->ip6po_nexthop) {
+                       optdata = (void *)pktopt->ip6po_nexthop;
+                       optdatalen = pktopt->ip6po_nexthop->sa_len;
+               }
+               break;
+       case IPV6_USE_MIN_MTU:
+               if (pktopt)
+                       optdata = (void *)&pktopt->ip6po_minmtu;
+               else
+                       optdata = (void *)&defminmtu;
+               optdatalen = sizeof(int);
+               break;
+       case IPV6_DONTFRAG:
+               if (pktopt && ((pktopt->ip6po_flags) & IP6PO_DONTFRAG))
+                       on = 1;
+               else
+                       on = 0;
+               optdata = (void *)&on;
+               optdatalen = sizeof(on);
+               break;
+       case IPV6_PREFER_TEMPADDR:
+               if (pktopt)
+                       optdata = (void *)&pktopt->ip6po_prefer_tempaddr;
+               else
+                       optdata = (void *)&defpreftemp;
+               optdatalen = sizeof(int);
+               break;
+       default:                /* should not happen */
+#ifdef DIAGNOSTIC
+               panic("ip6_getpcbopt: unexpected option\n");
+#endif
+               return (ENOPROTOOPT);
+       }
+
+       soopt_from_kbuf(sopt, optdata, optdatalen);
+
+       return (error);
+}
+
+/*
+ * initialize ip6_pktopts.  beware that there are non-zero default values in
+ * the struct.
+ */
+
+static int
+ip6_pcbopt(int optname, u_char *buf, int len, struct ip6_pktopts **pktopt, int uproto)
+{
+       struct ip6_pktopts *opt;
+       int priv =0;
+       if (*pktopt == NULL) {
+               *pktopt = kmalloc(sizeof(*opt), M_IP6OPT, M_WAITOK);
+               init_ip6pktopts(*pktopt);
+       }
+       opt = *pktopt;
+
+       return (ip6_setpktoption(optname, buf, len, opt, 1, 0, uproto, priv));
+}
+
 /*
  * initialize ip6_pktopts.  beware that there are non-zero default values in
  * the struct.
@@ -1743,38 +2320,47 @@ init_ip6pktopts(struct ip6_pktopts *opt)
 
        bzero(opt, sizeof(*opt));
        opt->ip6po_hlim = -1;   /* -1 means default hop limit */
+       opt->ip6po_tclass = -1; /* -1 means default traffic class */
+       opt->ip6po_minmtu = IP6PO_MINMTU_MCASTONLY;
+       opt->ip6po_prefer_tempaddr = IP6PO_TEMPADDR_SYSTEM;
 }
 
 void
-ip6_clearpktopts(struct ip6_pktopts *pktopt, int needfree, int optname)
+ip6_clearpktopts(struct ip6_pktopts *pktopt, int optname)
 {
        if (pktopt == NULL)
                return;
 
-       if (optname == -1) {
-               if (needfree && pktopt->ip6po_pktinfo)
+       if (optname == -1 || optname == IPV6_PKTINFO) {
+               if (pktopt->ip6po_pktinfo)
                        kfree(pktopt->ip6po_pktinfo, M_IP6OPT);
                pktopt->ip6po_pktinfo = NULL;
        }
-       if (optname == -1)
+       if (optname == -1 || optname == IPV6_HOPLIMIT)
                pktopt->ip6po_hlim = -1;
-       if (optname == -1) {
-               if (needfree && pktopt->ip6po_nexthop)
+       if (optname == -1 || optname == IPV6_TCLASS)
+               pktopt->ip6po_tclass = -1;
+       if (optname == -1 || optname == IPV6_NEXTHOP) {
+               if (pktopt->ip6po_nextroute.ro_rt) {
+                       RTFREE(pktopt->ip6po_nextroute.ro_rt);
+                       pktopt->ip6po_nextroute.ro_rt = NULL;
+               }
+               if (pktopt->ip6po_nexthop)
                        kfree(pktopt->ip6po_nexthop, M_IP6OPT);
                pktopt->ip6po_nexthop = NULL;
        }
-       if (optname == -1) {
-               if (needfree && pktopt->ip6po_hbh)
+       if (optname == -1 || optname == IPV6_HOPOPTS) {
+               if (pktopt->ip6po_hbh)
                        kfree(pktopt->ip6po_hbh, M_IP6OPT);
                pktopt->ip6po_hbh = NULL;
        }
-       if (optname == -1) {
-               if (needfree && pktopt->ip6po_dest1)
+       if (optname == -1 || optname == IPV6_RTHDRDSTOPTS) {
+               if (pktopt->ip6po_dest1)
                        kfree(pktopt->ip6po_dest1, M_IP6OPT);
                pktopt->ip6po_dest1 = NULL;
        }
-       if (optname == -1) {
-               if (needfree && pktopt->ip6po_rhinfo.ip6po_rhi_rthdr)
+       if (optname == -1 || optname == IPV6_RTHDR) {
+               if (pktopt->ip6po_rhinfo.ip6po_rhi_rthdr)
                        kfree(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT);
                pktopt->ip6po_rhinfo.ip6po_rhi_rthdr = NULL;
                if (pktopt->ip6po_route.ro_rt) {
@@ -1782,8 +2368,8 @@ ip6_clearpktopts(struct ip6_pktopts *pktopt, int needfree, int optname)
                        pktopt->ip6po_route.ro_rt = NULL;
                }
        }
-       if (optname == -1) {
-               if (needfree && pktopt->ip6po_dest2)
+       if (optname == -1 || optname == IPV6_DSTOPTS) {
+               if (pktopt->ip6po_dest2)
                        kfree(pktopt->ip6po_dest2, M_IP6OPT);
                pktopt->ip6po_dest2 = NULL;
        }
@@ -1847,6 +2433,45 @@ bad:
        kfree(dst, M_IP6OPT);
        return (NULL);
 }
+
+static int
+copypktopts(struct ip6_pktopts *dst, struct ip6_pktopts *src, int canwait)
+{
+       if (dst == NULL || src == NULL)  {
+#ifdef DIAGNOSTIC
+               kprintf("ip6_clearpktopts: invalid argument\n");
+#endif
+               return (EINVAL);
+       }
+
+       dst->ip6po_hlim = src->ip6po_hlim;
+       dst->ip6po_tclass = src->ip6po_tclass;
+       dst->ip6po_flags = src->ip6po_flags;
+       if (src->ip6po_pktinfo) {
+               dst->ip6po_pktinfo = kmalloc(sizeof(*dst->ip6po_pktinfo),
+                   M_IP6OPT, canwait);
+               if (dst->ip6po_pktinfo == NULL)
+                       goto bad;
+               *dst->ip6po_pktinfo = *src->ip6po_pktinfo;
+       }
+       if (src->ip6po_nexthop) {
+               dst->ip6po_nexthop = kmalloc(src->ip6po_nexthop->sa_len,
+                   M_IP6OPT, canwait);
+               if (dst->ip6po_nexthop == NULL)
+                       goto bad;
+               bcopy(src->ip6po_nexthop, dst->ip6po_nexthop,
+                   src->ip6po_nexthop->sa_len);
+       }
+       PKTOPT_EXTHDRCPY(ip6po_hbh);
+       PKTOPT_EXTHDRCPY(ip6po_dest1);
+       PKTOPT_EXTHDRCPY(ip6po_dest2);
+       PKTOPT_EXTHDRCPY(ip6po_rthdr); /* not copy the cached route */
+       return (0);
+
+  bad:
+       ip6_clearpktopts(dst, -1);
+       return (ENOBUFS);
+}
 #undef PKTOPT_EXTHDRCPY
 
 void
@@ -1855,7 +2480,7 @@ ip6_freepcbopts(struct ip6_pktopts *pktopt)
        if (pktopt == NULL)
                return;
 
-       ip6_clearpktopts(pktopt, 1, -1);
+       ip6_clearpktopts(pktopt, -1);
 
        kfree(pktopt, M_IP6OPT);
 }
@@ -2205,213 +2830,448 @@ ip6_freemoptions(struct ip6_moptions *im6o)
 }
 
 /*
- * Set IPv6 outgoing packet options based on advanced API.
+ * Set a particular packet option, as a sticky option or an ancillary data
+ * item.  "len" can be 0 only when it's a sticky option.
+ * We have 4 cases of combination of "sticky" and "cmsg":
+ * "sticky=0, cmsg=0": impossible
+ * "sticky=0, cmsg=1": RFC2292 or RFC3542 ancillary data
+ * "sticky=1, cmsg=0": RFC3542 socket option
+ * "sticky=1, cmsg=1": RFC2292 socket option
  */
-int
-ip6_setpktoptions(struct mbuf *control, struct ip6_pktopts *opt, int priv,
-                 int needcopy)
+static int
+ip6_setpktoption(int optname, u_char *buf, int len, struct ip6_pktopts *opt,
+     int sticky, int cmsg, int uproto, int priv)
 {
-       struct cmsghdr *cm = NULL;
+       int minmtupolicy, preftemp;
+       //int error;
 
-       if (control == NULL || opt == NULL)
+       if (!sticky && !cmsg) {
+               kprintf("ip6_setpktoption: impossible case\n");
                return (EINVAL);
-
-       init_ip6pktopts(opt);
+       }
 
        /*
-        * XXX: Currently, we assume all the optional information is stored
-        * in a single mbuf.
+        * IPV6_2292xxx is for backward compatibility to RFC2292, and should
+        * not be specified in the context of RFC3542.  Conversely,
+        * RFC3542 types should not be specified in the context of RFC2292.
         */
-       if (control->m_next)
-               return (EINVAL);
+       if (!cmsg) {
+               switch (optname) {
+               case IPV6_2292PKTINFO:
+               case IPV6_2292HOPLIMIT:
+               case IPV6_2292NEXTHOP:
+               case IPV6_2292HOPOPTS:
+               case IPV6_2292DSTOPTS:
+               case IPV6_2292RTHDR:
+               case IPV6_2292PKTOPTIONS:
+                       return (ENOPROTOOPT);
+               }
+       }
+       if (sticky && cmsg) {
+               switch (optname) {
+               case IPV6_PKTINFO:
+               case IPV6_HOPLIMIT:
+               case IPV6_NEXTHOP:
+               case IPV6_HOPOPTS:
+               case IPV6_DSTOPTS:
+               case IPV6_RTHDRDSTOPTS:
+               case IPV6_RTHDR:
+               case IPV6_USE_MIN_MTU:
+               case IPV6_DONTFRAG:
+               case IPV6_TCLASS:
+               case IPV6_PREFER_TEMPADDR: /* XXX: not an RFC3542 option */
+                       return (ENOPROTOOPT);
+               }
+       }
 
-       for (; control->m_len; control->m_data += CMSG_ALIGN(cm->cmsg_len),
-                    control->m_len -= CMSG_ALIGN(cm->cmsg_len)) {
-               cm = mtod(control, struct cmsghdr *);
-               if (cm->cmsg_len == 0 || cm->cmsg_len > control->m_len)
+       switch (optname) {
+       case IPV6_2292PKTINFO:
+       case IPV6_PKTINFO:
+       {
+               struct in6_pktinfo *pktinfo;
+               if (len != sizeof(struct in6_pktinfo))
                        return (EINVAL);
-               if (cm->cmsg_level != IPPROTO_IPV6)
-                       continue;
+               pktinfo = (struct in6_pktinfo *)buf;
 
                /*
-                * XXX should check if RFC2292 API is mixed with 2292bis API
+                * An application can clear any sticky IPV6_PKTINFO option by
+                * doing a "regular" setsockopt with ipi6_addr being
+                * in6addr_any and ipi6_ifindex being zero.
+                * [RFC 3542, Section 6]
                 */
-               switch (cm->cmsg_type) {
-               case IPV6_PKTINFO:
-                       if (cm->cmsg_len != CMSG_LEN(sizeof(struct in6_pktinfo)))
-                               return (EINVAL);
-                       if (needcopy) {
-                               /* XXX: Is it really WAITOK? */
-                               opt->ip6po_pktinfo =
-                                       kmalloc(sizeof(struct in6_pktinfo),
-                                              M_IP6OPT, M_WAITOK);
-                               bcopy(CMSG_DATA(cm), opt->ip6po_pktinfo,
-                                   sizeof(struct in6_pktinfo));
-                       } else
-                               opt->ip6po_pktinfo =
-                                       (struct in6_pktinfo *)CMSG_DATA(cm);
-                       if (opt->ip6po_pktinfo->ipi6_ifindex &&
-                           IN6_IS_ADDR_LINKLOCAL(&opt->ip6po_pktinfo->ipi6_addr))
-                               opt->ip6po_pktinfo->ipi6_addr.s6_addr16[1] =
-                                       htons(opt->ip6po_pktinfo->ipi6_ifindex);
-
-                       if (opt->ip6po_pktinfo->ipi6_ifindex > if_index
-                        || opt->ip6po_pktinfo->ipi6_ifindex < 0) {
-                               return (ENXIO);
-                       }
-
-                       /*
-                        * Check if the requested source address is indeed a
-                        * unicast address assigned to the node, and can be
-                        * used as the packet's source address.
-                        */
-                       if (!IN6_IS_ADDR_UNSPECIFIED(&opt->ip6po_pktinfo->ipi6_addr)) {
-                               struct in6_ifaddr *ia6;
-                               struct sockaddr_in6 sin6;
-
-                               bzero(&sin6, sizeof(sin6));
-                               sin6.sin6_len = sizeof(sin6);
-                               sin6.sin6_family = AF_INET6;
-                               sin6.sin6_addr =
-                                       opt->ip6po_pktinfo->ipi6_addr;
-                               ia6 = (struct in6_ifaddr *)ifa_ifwithaddr(sin6tosa(&sin6));
-                               if (ia6 == NULL ||
-                                   (ia6->ia6_flags & (IN6_IFF_ANYCAST |
-                                                      IN6_IFF_NOTREADY)) != 0)
-                                       return (EADDRNOTAVAIL);
-                       }
+               if (optname == IPV6_PKTINFO && opt->ip6po_pktinfo &&
+                   pktinfo->ipi6_ifindex == 0 &&
+                   IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) {
+                       ip6_clearpktopts(opt, optname);
                        break;
+               }
 
-               case IPV6_HOPLIMIT:
-                       if (cm->cmsg_len != CMSG_LEN(sizeof(int)))
-                               return (EINVAL);
+               if (uproto == IPPROTO_TCP && optname == IPV6_PKTINFO &&
+                   sticky && !IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) {
+                       return (EINVAL);
+               }
 
-                       opt->ip6po_hlim = *(int *)CMSG_DATA(cm);
-                       if (opt->ip6po_hlim < -1 || opt->ip6po_hlim > 255)
-                               return (EINVAL);
-                       break;
+               /* validate the interface index if specified. */
+               if (pktinfo->ipi6_ifindex > if_index ||
+                   pktinfo->ipi6_ifindex < 0) {
+                        return (ENXIO);
+               }
+               /*
+                       * Check if the requested source address is indeed a
+                       * unicast address assigned to the node, and can be
+                       * used as the packet's source address.
+               */
+               if (!IN6_IS_ADDR_UNSPECIFIED(&opt->ip6po_pktinfo->ipi6_addr)) {
+                       struct in6_ifaddr *ia6;
+                       struct sockaddr_in6 sin6;
+
+                       bzero(&sin6, sizeof(sin6));
+                       sin6.sin6_len = sizeof(sin6);
+                       sin6.sin6_family = AF_INET6;
+                       sin6.sin6_addr =
+                       opt->ip6po_pktinfo->ipi6_addr;
+                       ia6 = (struct in6_ifaddr *)ifa_ifwithaddr(sin6tosa(&sin6));
+                       if (ia6 == NULL ||
+                               (ia6->ia6_flags & (IN6_IFF_ANYCAST |
+                                       IN6_IFF_NOTREADY)) != 0)
+                       return (EADDRNOTAVAIL);
+               }
 
-               case IPV6_NEXTHOP:
-                       if (!priv)
-                               return (EPERM);
+               /*
+                * We store the address anyway, and let in6_selectsrc()
+                * validate the specified address.  This is because ipi6_addr
+                * may not have enough information about its scope zone, and
+                * we may need additional information (such as outgoing
+                * interface or the scope zone of a destination address) to
+                * disambiguate the scope.
+                * XXX: the delay of the validation may confuse the
+                * application when it is used as a sticky option.
+                */
+               if (opt->ip6po_pktinfo == NULL) {
+                       opt->ip6po_pktinfo = kmalloc(sizeof(*pktinfo),
+                           M_IP6OPT, M_NOWAIT);
+                       if (opt->ip6po_pktinfo == NULL)
+                               return (ENOBUFS);
+               }
+               bcopy(pktinfo, opt->ip6po_pktinfo, sizeof(*pktinfo));
+               break;
+       }
 
-                       if (cm->cmsg_len < sizeof(u_char) ||
-                           /* check if cmsg_len is large enough for sa_len */
-                           cm->cmsg_len < CMSG_LEN(*CMSG_DATA(cm)))
-                               return (EINVAL);
+       case IPV6_2292HOPLIMIT:
+       case IPV6_HOPLIMIT:
+       {
+               int *hlimp;
 
-                       if (needcopy) {
-                               opt->ip6po_nexthop =
-                                       kmalloc(*CMSG_DATA(cm),
-                                              M_IP6OPT, M_WAITOK);
-                               bcopy(CMSG_DATA(cm),
-                                     opt->ip6po_nexthop,
-                                     *CMSG_DATA(cm));
-                       } else
-                               opt->ip6po_nexthop =
-                                       (struct sockaddr *)CMSG_DATA(cm);
-                       break;
+               /*
+                * RFC 3542 deprecated the usage of sticky IPV6_HOPLIMIT
+                * to simplify the ordering among hoplimit options.
+                */
+               if (optname == IPV6_HOPLIMIT && sticky)
+                       return (ENOPROTOOPT);
 
-               case IPV6_HOPOPTS:
-               {
-                       struct ip6_hbh *hbh;
-                       int hbhlen;
+               if (len != sizeof(int))
+                       return (EINVAL);
+               hlimp = (int *)buf;
+               if (*hlimp < -1 || *hlimp > 255)
+                       return (EINVAL);
 
-                       if (cm->cmsg_len < CMSG_LEN(sizeof(struct ip6_hbh)))
-                               return (EINVAL);
-                       hbh = (struct ip6_hbh *)CMSG_DATA(cm);
-                       hbhlen = (hbh->ip6h_len + 1) << 3;
-                       if (cm->cmsg_len != CMSG_LEN(hbhlen))
-                               return (EINVAL);
+               opt->ip6po_hlim = *hlimp;
+               break;
+       }
 
-                       if (needcopy) {
-                               opt->ip6po_hbh =
-                                       kmalloc(hbhlen, M_IP6OPT, M_WAITOK);
-                               bcopy(hbh, opt->ip6po_hbh, hbhlen);
-                       } else
-                               opt->ip6po_hbh = hbh;
+       case IPV6_TCLASS:
+       {
+               int tclass;
+
+               if (len != sizeof(int))
+                       return (EINVAL);
+               tclass = *(int *)buf;
+               if (tclass < -1 || tclass > 255)
+                       return (EINVAL);
+
+               opt->ip6po_tclass = tclass;
+               break;
+       }
+
+       case IPV6_2292NEXTHOP:
+       case IPV6_NEXTHOP:
+               if (!priv)
+                       return (EPERM);
+
+               if (len == 0) { /* just remove the option */
+                       ip6_clearpktopts(opt, IPV6_NEXTHOP);
                        break;
                }
 
-               case IPV6_DSTOPTS:
+               /* check if cmsg_len is large enough for sa_len */
+               if (len < sizeof(struct sockaddr) || len < *buf)
+                       return (EINVAL);
+
+               switch (((struct sockaddr *)buf)->sa_family) {
+               case AF_INET6:
                {
-                       struct ip6_dest *dest, **newdest;
-                       int destlen;
+                       struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)buf;
+                       //int error;
 
-                       if (cm->cmsg_len < CMSG_LEN(sizeof(struct ip6_dest)))
+                       if (sa6->sin6_len != sizeof(struct sockaddr_in6))
                                return (EINVAL);
-                       dest = (struct ip6_dest *)CMSG_DATA(cm);
-                       destlen = (dest->ip6d_len + 1) << 3;
-                       if (cm->cmsg_len != CMSG_LEN(destlen))
+
+                       if (IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr) ||
+                           IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
                                return (EINVAL);
+                       }
+                       break;
+               }
+               case AF_LINK:   /* should eventually be supported */
+               default:
+                       return (EAFNOSUPPORT);
+               }
+
+               /* turn off the previous option, then set the new option. */
+               ip6_clearpktopts(opt, IPV6_NEXTHOP);
+               opt->ip6po_nexthop = kmalloc(*buf, M_IP6OPT, M_NOWAIT);
+               if (opt->ip6po_nexthop == NULL)
+                       return (ENOBUFS);
+               bcopy(buf, opt->ip6po_nexthop, *buf);
+               break;
 
+       case IPV6_2292HOPOPTS:
+       case IPV6_HOPOPTS:
+       {
+               struct ip6_hbh *hbh;
+               int hbhlen;
+
+               /*
+                * XXX: We don't allow a non-privileged user to set ANY HbH
+                * options, since per-option restriction has too much
+                * overhead.
+                */
+               if (!priv)
+                       return (EPERM);
+               if (len == 0) {
+                       ip6_clearpktopts(opt, IPV6_HOPOPTS);
+                       break;  /* just remove the option */
+               }
+
+               /* message length validation */
+               if (len < sizeof(struct ip6_hbh))
+                       return (EINVAL);
+               hbh = (struct ip6_hbh *)buf;
+               hbhlen = (hbh->ip6h_len + 1) << 3;
+               if (len != hbhlen)
+                       return (EINVAL);
+
+               /* turn off the previous option, then set the new option. */
+               ip6_clearpktopts(opt, IPV6_HOPOPTS);
+               opt->ip6po_hbh = kmalloc(hbhlen, M_IP6OPT, M_NOWAIT);
+               if (opt->ip6po_hbh == NULL)
+                       return (ENOBUFS);
+               bcopy(hbh, opt->ip6po_hbh, hbhlen);
+
+               break;
+       }
+
+       case IPV6_2292DSTOPTS:
+       case IPV6_DSTOPTS:
+       case IPV6_RTHDRDSTOPTS:
+       {
+               struct ip6_dest *dest, **newdest = NULL;
+               int destlen;
+               if (!priv)
+                       return (EPERM);
+
+               if (len == 0) {
+                       ip6_clearpktopts(opt, optname);
+                       break;  /* just remove the option */
+               }
+
+               /* message length validation */
+               if (len < sizeof(struct ip6_dest))
+                       return (EINVAL);
+               dest = (struct ip6_dest *)buf;
+               destlen = (dest->ip6d_len + 1) << 3;
+               if (len != destlen)
+                       return (EINVAL);
+
+               /*
+                * Determine the position that the destination options header
+                * should be inserted; before or after the routing header.
+                */
+               switch (optname) {
+               case IPV6_2292DSTOPTS:
                        /*
-                        * The old advacned API is ambiguous on this
-                        * point. Our approach is to determine the
-                        * position based according to the existence
-                        * of a routing header. Note, however, that
-                        * this depends on the order of the extension
-                        * headers in the ancillary data; the 1st part
-                        * of the destination options header must
-                        * appear before the routing header in the
-                        * ancillary data, too.
-                        * RFC2292bis solved the ambiguity by
-                        * introducing separate cmsg types.
+                        * The old advacned API is ambiguous on this point.
+                        * Our approach is to determine the position based
+                        * according to the existence of a routing header.
+                        * Note, however, that this depends on the order of the
+                        * extension headers in the ancillary data; the 1st
+                        * part of the destination options header must appear
+                        * before the routing header in the ancillary data,
+                        * too.
+                        * RFC3542 solved the ambiguity by introducing
+                        * separate ancillary data or option types.
                         */
                        if (opt->ip6po_rthdr == NULL)
                                newdest = &opt->ip6po_dest1;
                        else
                                newdest = &opt->ip6po_dest2;
+                       break;
+               case IPV6_RTHDRDSTOPTS:
+                       newdest = &opt->ip6po_dest1;
+                       break;
+               case IPV6_DSTOPTS:
+                       newdest = &opt->ip6po_dest2;
+                       break;
+               }
 
-                       if (needcopy) {
-                               *newdest = kmalloc(destlen, M_IP6OPT, M_WAITOK);
-                               bcopy(dest, *newdest, destlen);
-                       } else
-                               *newdest = dest;
+               /* turn off the previous option, then set the new option. */
+               ip6_clearpktopts(opt, optname);
+               *newdest = kmalloc(destlen, M_IP6OPT, M_NOWAIT);
+               if (*newdest == NULL)
+                       return (ENOBUFS);
+               bcopy(dest, *newdest, destlen);
 
-                       break;
+               break;
+       }
+
+       case IPV6_2292RTHDR:
+       case IPV6_RTHDR:
+       {
+               struct ip6_rthdr *rth;
+               int rthlen;
+
+               if (len == 0) {
+                       ip6_clearpktopts(opt, IPV6_RTHDR);
+                       break;  /* just remove the option */
                }
 
-               case IPV6_RTHDR:
-               {
-                       struct ip6_rthdr *rth;
-                       int rthlen;
+               /* message length validation */
+               if (len < sizeof(struct ip6_rthdr))
+                       return (EINVAL);
+               rth = (struct ip6_rthdr *)buf;
+               rthlen = (rth->ip6r_len + 1) << 3;
+               if (len != rthlen)
+                       return (EINVAL);
 
-                       if (cm->cmsg_len < CMSG_LEN(sizeof(struct ip6_rthdr)))
-                               return (EINVAL);
-                       rth = (struct ip6_rthdr *)CMSG_DATA(cm);
-                       rthlen = (rth->ip6r_len + 1) << 3;
-                       if (cm->cmsg_len != CMSG_LEN(rthlen))
-                               return (EINVAL);
+               switch (rth->ip6r_type) {
+               default:
+                       return (EINVAL);        /* not supported */
+               }
 
-                       switch (rth->ip6r_type) {
-                       case IPV6_RTHDR_TYPE_0:
-                               /* must contain one addr */
-                               if (rth->ip6r_len == 0)
-                                       return (EINVAL);
-                               /* length must be even */
-                               if (rth->ip6r_len % 2)
-                                       return (EINVAL);
-                               if (rth->ip6r_len / 2 != rth->ip6r_segleft)
-                                       return (EINVAL);
-                               break;
-                       default:
-                               return (EINVAL);        /* not supported */
-                       }
+               /* turn off the previous option */
+               ip6_clearpktopts(opt, IPV6_RTHDR);
+               opt->ip6po_rthdr = kmalloc(rthlen, M_IP6OPT, M_NOWAIT);
+               if (opt->ip6po_rthdr == NULL)
+                       return (ENOBUFS);
+               bcopy(rth, opt->ip6po_rthdr, rthlen);
 
-                       if (needcopy) {
-                               opt->ip6po_rthdr = kmalloc(rthlen, M_IP6OPT,
-                                                         M_WAITOK);
-                               bcopy(rth, opt->ip6po_rthdr, rthlen);
-                       } else
-                               opt->ip6po_rthdr = rth;
+               break;
+       }
 
-                       break;
+       case IPV6_USE_MIN_MTU:
+               if (len != sizeof(int))
+                       return (EINVAL);
+               minmtupolicy = *(int *)buf;
+               if (minmtupolicy != IP6PO_MINMTU_MCASTONLY &&
+                   minmtupolicy != IP6PO_MINMTU_DISABLE &&
+                   minmtupolicy != IP6PO_MINMTU_ALL) {
+                       return (EINVAL);
                }
+               opt->ip6po_minmtu = minmtupolicy;
+               break;
 
-               default:
-                       return (ENOPROTOOPT);
+       case IPV6_DONTFRAG:
+               if (len != sizeof(int))
+                       return (EINVAL);
+
+               if (uproto == IPPROTO_TCP || *(int *)buf == 0) {
+                       /*
+                        * we ignore this option for TCP sockets.
+                        * (RFC3542 leaves this case unspecified.)
+                        */
+                       opt->ip6po_flags &= ~IP6PO_DONTFRAG;
+               } else
+                       opt->ip6po_flags |= IP6PO_DONTFRAG;
+               break;
+
+       case IPV6_PREFER_TEMPADDR:
+               if (len != sizeof(int))
+                       return (EINVAL);
+               preftemp = *(int *)buf;
+               if (preftemp != IP6PO_TEMPADDR_SYSTEM &&
+                   preftemp != IP6PO_TEMPADDR_NOTPREFER &&
+                   preftemp != IP6PO_TEMPADDR_PREFER) {
+                       return (EINVAL);
                }
+               opt->ip6po_prefer_tempaddr = preftemp;
+               break;
+
+       default:
+               return (ENOPROTOOPT);
+       } /* end of switch */
+
+       return (0);
+}
+
+
+/*
+ * Set IPv6 outgoing packet options based on advanced API.
+ */
+int
+ip6_setpktoptions(struct mbuf *control, struct ip6_pktopts *opt,
+    struct ip6_pktopts *stickyopt, int uproto, int priv)
+{
+       struct cmsghdr *cm = NULL;
+
+       if (control == NULL || opt == NULL)
+               return (EINVAL);
+
+       init_ip6pktopts(opt);
+
+       /*
+        * XXX: Currently, we assume all the optional information is stored
+        * in a single mbuf.
+        */
+       if (stickyopt) {
+               int error;
+
+               /*
+                * If stickyopt is provided, make a local copy of the options
+                * for this particular packet, then override them by ancillary
+                * objects.
+                * XXX: copypktopts() does not copy the cached route to a next
+                * hop (if any).  This is not very good in terms of efficiency,
+                * but we can allow this since this option should be rarely
+                * used.
+                */
+               if ((error = copypktopts(opt, stickyopt, M_NOWAIT)) != 0)
+                       return (error);
+       }
+
+       /*
+        * XXX: Currently, we assume all the optional information is stored
+        * in a single mbuf.
+        */
+       if (control->m_next)
+               return (EINVAL);
+
+       for (; control->m_len; control->m_data += CMSG_ALIGN(cm->cmsg_len),
+           control->m_len -= CMSG_ALIGN(cm->cmsg_len)) {
+               int error;
+
+               if (control->m_len < CMSG_LEN(0))
+                       return (EINVAL);
+
+               cm = mtod(control, struct cmsghdr *);
+               if (cm->cmsg_len == 0 || cm->cmsg_len > control->m_len)
+                       return (EINVAL);
+               if (cm->cmsg_level != IPPROTO_IPV6)
+                       continue;
+
+               error = ip6_setpktoption(cm->cmsg_type, CMSG_DATA(cm),
+                   cm->cmsg_len - CMSG_LEN(0), opt, 0, 1, uproto, priv);
+               if (error)
+                       return (error);
        }
 
        return (0);
index bd9f9dd..5837810 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet6/ip6_var.h,v 1.2.2.4 2003/01/23 21:06:47 sam Exp $    */
-/*     $DragonFly: src/sys/netinet6/ip6_var.h,v 1.12 2007/05/07 12:40:30 hasso Exp $   */
+/*     $DragonFly: src/sys/netinet6/ip6_var.h,v 1.13 2008/09/04 09:08:22 hasso Exp $   */
 /*     $KAME: ip6_var.h,v 1.62 2001/05/03 14:51:48 itojun Exp $        */
 
 /*
@@ -138,6 +138,14 @@ struct     ip6po_rhinfo {
 #define ip6po_rthdr    ip6po_rhinfo.ip6po_rhi_rthdr
 #define ip6po_route    ip6po_rhinfo.ip6po_rhi_route
 
+/* Nexthop related info */
+struct ip6po_nhinfo {
+       struct  sockaddr *ip6po_nhi_nexthop;
+       struct  route_in6 ip6po_nhi_route; /* Route to the nexthop */
+};
+#define ip6po_nexthop  ip6po_nhinfo.ip6po_nhi_nexthop
+#define ip6po_nextroute        ip6po_nhinfo.ip6po_nhi_route
+
 struct ip6_pktopts {
        struct  mbuf *ip6po_m;  /* Pointer to mbuf storing the data */
        int     ip6po_hlim;     /* Hoplimit for outgoing packets */
@@ -145,7 +153,8 @@ struct      ip6_pktopts {
        /* Outgoing IF/address information */
        struct  in6_pktinfo *ip6po_pktinfo;
 
-       struct  sockaddr *ip6po_nexthop; /* Next-hop address */
+       /* Next-hop address information */
+       struct  ip6po_nhinfo ip6po_nhinfo;
        
        struct  ip6_hbh *ip6po_hbh; /* Hop-by-Hop options header */
 
@@ -157,12 +166,32 @@ struct    ip6_pktopts {
 
        /* Destination options header (after a routing header) */
        struct  ip6_dest *ip6po_dest2;
+       /*
+        * below fields are introduced in RFC3542
+        */
+       int     ip6po_tclass;   /* traffic class */
+       int     ip6po_minmtu;  /* fragment vs PMTU discovery policy */
+#define IP6PO_MINMTU_MCASTONLY -1 /* default; send at min MTU for multicast*/
+#define IP6PO_MINMTU_DISABLE    0 /* always perform pmtu disc */
+#define IP6PO_MINMTU_ALL        1 /* always send at min MTU */
+       int     ip6po_prefer_tempaddr;  /* whether temporary addresses are
+                                          preferred as source address */
+#define IP6PO_TEMPADDR_SYSTEM  -1 /* follow the system default */
+#define IP6PO_TEMPADDR_NOTPREFER 0 /* not prefer temporary address */
+#define IP6PO_TEMPADDR_PREFER   1 /* prefer temporary address */
+
+       int ip6po_flags;
+#if 0  /* Parameters in this block are obsolete. Do not reuse the values. */
+#define IP6PO_REACHCONF        0x01    /* upper-layer reachability confirmation. */
+#define IP6PO_MINMTU   0x02    /* use minimum MTU (IPV6_USE_MIN_MTU) */
+#endif
+#define IP6PO_DONTFRAG 0x04    /* disable fragmentation (IPV6_DONTFRAG) */
+#define IP6PO_USECOA   0x08    /* use care of address */
 };
 
 /*
  * Control options for incoming packets
  */
-
 struct ip6stat {
        u_quad_t ip6s_total;            /* total packets received */
        u_quad_t ip6s_tooshort;         /* packet too short */
@@ -341,9 +370,12 @@ int        ip6_output (struct mbuf *, struct ip6_pktopts *,
                        struct ip6_moptions *, struct ifnet **,
                        struct inpcb *);
 int    ip6_ctloutput (struct socket *, struct sockopt *sopt);
+int    ip6_raw_ctloutput (struct socket *, struct sockopt *);
 void   init_ip6pktopts (struct ip6_pktopts *);
-int    ip6_setpktoptions (struct mbuf *, struct ip6_pktopts *, int, int);
-void   ip6_clearpktopts (struct ip6_pktopts *, int, int);
+int
+ip6_setpktoptions(struct mbuf *, struct ip6_pktopts *,
+    struct ip6_pktopts *, int , int);
+void   ip6_clearpktopts (struct ip6_pktopts *, int);
 struct ip6_pktopts *ip6_copypktopts (struct ip6_pktopts *, int);
 int    ip6_optlen (struct inpcb *);
 
index 0293864..34db51b 100644 (file)
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/netinet6/raw_ip6.c,v 1.7.2.7 2003/01/24 05:11:35 sam Exp $
- * $DragonFly: src/sys/netinet6/raw_ip6.c,v 1.26 2008/05/17 20:33:36 dillon Exp $
+ * $DragonFly: src/sys/netinet6/raw_ip6.c,v 1.27 2008/09/04 09:08:22 hasso Exp $
  */
 
 /*
@@ -338,7 +338,9 @@ rip6_output(struct mbuf *m, struct socket *so, ...)
                priv = 1;
        dst = &dstsock->sin6_addr;
        if (control) {
-               if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0)
+               if ((error = ip6_setpktoptions(control, &opt,
+                   in6p->in6p_outputopts, 
+                   so->so_proto->pr_protocol, priv)) != 0)
                        goto bad;
                optp = &opt;
        } else
@@ -477,7 +479,7 @@ freectl:
                RTFREE(optp->ip6po_route.ro_rt);
        if (control) {
                if (optp == &opt)
-                       ip6_clearpktopts(optp, 0, -1);
+                       ip6_clearpktopts(optp, -1);
                m_freem(control);
        }
        return (error);
@@ -514,6 +516,9 @@ rip6_ctloutput(struct socket *so, struct sockopt *sopt)
                case MRT6_PIM:
                        error = ip6_mrouter_get(so, sopt);
                        break;
+               case IPV6_CHECKSUM:
+                       error = ip6_raw_ctloutput(so, sopt);
+                       break;
                default:
                        error = ip6_ctloutput(so, sopt);
                        break;
@@ -531,6 +536,9 @@ rip6_ctloutput(struct socket *so, struct sockopt *sopt)
                case MRT6_PIM:
                        error = ip6_mrouter_set(so, sopt);
                        break;
+               case IPV6_CHECKSUM:
+                       error = ip6_raw_ctloutput(so, sopt);
+                       break;
                default:
                        error = ip6_ctloutput(so, sopt);
                        break;
index a912b59..4c993b8 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet6/route6.c,v 1.1.2.5 2003/01/23 21:06:47 sam Exp $     */
-/*     $DragonFly: src/sys/netinet6/route6.c,v 1.9 2007/05/07 13:00:16 hasso Exp $     */
+/*     $DragonFly: src/sys/netinet6/route6.c,v 1.10 2008/09/04 09:08:22 hasso Exp $    */
 /*     $KAME: route6.c,v 1.24 2001/03/14 03:07:05 itojun Exp $ */
 
 /*
 
 #include <netinet/icmp6.h>
 
-#if 0
-static int ip6_rthdr0 (struct mbuf *, struct ip6_hdr *,
-    struct ip6_rthdr0 *);
-#endif
-
 int
 route6_input(struct mbuf **mp, int *offp, int proto) /* proto is unused */
 {
@@ -76,50 +71,6 @@ route6_input(struct mbuf **mp, int *offp, int proto) /* proto is unused */
 #endif
 
        switch (rh->ip6r_type) {
-#if 0
-       /*
-        * See http://www.secdev.org/conf/IPv6_RH_security-csw07.pdf
-        * for why IPV6_RTHDR_TYPE_0 is baned here.
-        *
-        * We return ICMPv6 parameter problem so that innocent people
-        * (not an attacker) would notice about the use of IPV6_RTHDR_TYPE_0.
-        * Since there's no amplification, and ICMPv6 error will be rate-
-        * controlled, it shouldn't cause any problem.
-        * If you are concerned about this, you may want to use the following
-        * code fragment:
-        *
-        * case IPV6_RTHDR_TYPE_0:
-        *      m_freem(m);
-        *      return (IPPROTO_DONE);
-        */
-       case IPV6_RTHDR_TYPE_0:
-               rhlen = (rh->ip6r_len + 1) << 3;
-#ifndef PULLDOWN_TEST
-               /*
-                * note on option length:
-                * due to IP6_EXTHDR_CHECK assumption, we cannot handle
-                * very big routing header (max rhlen == 2048).
-                */
-               IP6_EXTHDR_CHECK(m, off, rhlen, IPPROTO_DONE);
-#else
-               /*
-                * note on option length:
-                * maximum rhlen: 2048
-                * max mbuf m_pulldown can handle: MCLBYTES == usually 2048
-                * so, here we are assuming that m_pulldown can handle
-                * rhlen == 2048 case.  this may not be a good thing to
-                * assume - we may want to avoid pulling it up altogether.
-                */
-               IP6_EXTHDR_GET(rh, struct ip6_rthdr *, m, off, rhlen);
-               if (rh == NULL) {
-                       ip6stat.ip6s_tooshort++;
-                       return IPPROTO_DONE;
-               }
-#endif
-               if (ip6_rthdr0(m, ip6, (struct ip6_rthdr0 *)rh))
-                       return (IPPROTO_DONE);
-               break;
-#endif
        default:
                /* unknown routing type */
                if (rh->ip6r_segleft == 0) {
@@ -135,93 +86,3 @@ route6_input(struct mbuf **mp, int *offp, int proto) /* proto is unused */
        *offp += rhlen;
        return (rh->ip6r_nxt);
 }
-
-#if 0
-/*
- * Type0 routing header processing
- *
- * RFC2292 backward compatibility warning: no support for strict/loose bitmap,
- * as it was dropped between RFC1883 and RFC2460.
- */
-static int
-ip6_rthdr0(struct mbuf *m, struct ip6_hdr *ip6, struct ip6_rthdr0 *rh0)
-{
-       int addrs, index;
-       struct in6_addr *nextaddr, tmpaddr;
-
-       if (rh0->ip6r0_segleft == 0)
-               return (0);
-
-       if (rh0->ip6r0_len % 2
-#ifdef COMPAT_RFC1883
-           || rh0->ip6r0_len > 46
-#endif
-               ) {
-               /*
-                * Type 0 routing header can't contain more than 23 addresses.
-                * RFC 2462: this limitation was removed since strict/loose
-                * bitmap field was deleted.
-                */
-               ip6stat.ip6s_badoptions++;
-               icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
-                           (caddr_t)&rh0->ip6r0_len - (caddr_t)ip6);
-               return (-1);
-       }
-
-       if ((addrs = rh0->ip6r0_len / 2) < rh0->ip6r0_segleft) {
-               ip6stat.ip6s_badoptions++;
-               icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
-                           (caddr_t)&rh0->ip6r0_segleft - (caddr_t)ip6);
-               return (-1);
-       }
-
-       index = addrs - rh0->ip6r0_segleft;
-       rh0->ip6r0_segleft--;
-       /* note that ip6r0_addr does not exist in RFC2292bis */
-       nextaddr = rh0->ip6r0_addr + index;
-
-       /*
-        * reject invalid addresses.  be proactive about malicious use of
-        * IPv4 mapped/compat address.
-        * XXX need more checks?
-        */
-       if (IN6_IS_ADDR_MULTICAST(nextaddr) ||
-           IN6_IS_ADDR_UNSPECIFIED(nextaddr) ||
-           IN6_IS_ADDR_V4MAPPED(nextaddr) ||
-           IN6_IS_ADDR_V4COMPAT(nextaddr)) {
-               ip6stat.ip6s_badoptions++;
-               m_freem(m);
-               return (-1);
-       }
-       if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
-           IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst) ||
-           IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst) ||
-           IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) {
-               ip6stat.ip6s_badoptions++;
-               m_freem(m);
-               return (-1);
-       }
-
-       /*
-        * Swap the IPv6 destination address and nextaddr. Forward the packet.
-        */
-       tmpaddr = *nextaddr;
-       *nextaddr = ip6->ip6_dst;
-       if (IN6_IS_ADDR_LINKLOCAL(nextaddr))
-               nextaddr->s6_addr16[1] = 0;
-       ip6->ip6_dst = tmpaddr;
-       if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst))
-               ip6->ip6_dst.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
-
-#ifdef COMPAT_RFC1883
-       if (rh0->ip6r0_slmap[index / 8] & (1 << (7 - (index % 8))))
-               ip6_forward(m, IPV6_SRCRT_NEIGHBOR);
-       else
-               ip6_forward(m, IPV6_SRCRT_NOTNEIGHBOR);
-#else
-       ip6_forward(m, 1);
-#endif
-
-       return (-1);                    /* m would be freed in ip6_forward() */
-}
-#endif
index b5a40af..bdb93c0 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet6/udp6_output.c,v 1.1.2.6 2003/01/23 21:06:47 sam Exp $        */
-/*     $DragonFly: src/sys/netinet6/udp6_output.c,v 1.8 2006/12/29 18:02:56 victor Exp $       */
+/*     $DragonFly: src/sys/netinet6/udp6_output.c,v 1.9 2008/09/04 09:08:22 hasso Exp $        */
 /*     $KAME: udp6_output.c,v 1.31 2001/05/21 16:39:15 jinmei Exp $    */
 
 /*
@@ -139,7 +139,9 @@ udp6_output(struct in6pcb *in6p, struct mbuf *m, struct sockaddr *addr6,
 
        priv = !suser(td);      /* 1 if privilaged, 0 if not */
        if (control) {
-               if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0)
+               if ((error = ip6_setpktoptions(control, &opt,
+                   in6p->in6p_outputopts, 
+                   IPPROTO_UDP, priv)) != 0)
                        goto release;
                in6p->in6p_outputopts = &opt;
        }
@@ -304,7 +306,7 @@ release:
 
 releaseopt:
        if (control) {
-               ip6_clearpktopts(in6p->in6p_outputopts, 0, -1);
+               ip6_clearpktopts(in6p->in6p_outputopts, -1);
                in6p->in6p_outputopts = stickyopt;
                m_freem(control);
        }
index c6eafbc..e17a487 100644 (file)
@@ -32,7 +32,7 @@
  *
  * @(#)commands.c      8.4 (Berkeley) 5/30/95
  * $FreeBSD: src/usr.bin/telnet/commands.c,v 1.21.2.6 2002/11/30 05:35:13 eric Exp $
- * $DragonFly: src/usr.bin/telnet/commands.c,v 1.6 2007/05/18 17:05:12 dillon Exp $
+ * $DragonFly: src/usr.bin/telnet/commands.c,v 1.7 2008/09/04 09:08:22 hasso Exp $
  */
 
 #include <sys/param.h>
@@ -2568,6 +2568,7 @@ sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *lenp, int *protop,
 #ifdef INET6
        struct sockaddr_in6 *sin6;
        struct cmsghdr *cmsg;
+       struct ip6_rthdr *rth;
 #endif
        struct addrinfo hints, *res;
        int error;
@@ -2610,11 +2611,18 @@ sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *lenp, int *protop,
 
 #ifdef INET6
        if (ai->ai_family == AF_INET6) {
-               cmsg = inet6_rthdr_init(*cpp, IPV6_RTHDR_TYPE_0);
+       /* 
+        *RFC3542 has obsoleted IPV6_PKTOPTIONS socket option. 
+        */
+#ifdef COMPAT_RFC1883          /* XXX */
+               cmsg = NULL;
                if (*cp != '@')
                        return -1;
                *protop = IPPROTO_IPV6;
                *optp = IPV6_PKTOPTIONS;
+#else
+               return -1;
+#endif /* COMPAT_RFC1883 */
        } else
 #endif
       {
@@ -2685,9 +2693,7 @@ sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *lenp, int *protop,
                }
 #ifdef INET6
                if (res->ai_family == AF_INET6) {
-                       sin6 = (struct sockaddr_in6 *)res->ai_addr;
-                       inet6_rthdr_add(cmsg, &sin6->sin6_addr,
-                                       IPV6_RTHDR_LOOSE);
+                       return(0);
                } else
 #endif
              {
@@ -2703,13 +2709,13 @@ sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *lenp, int *protop,
                 * Check to make sure there is space for next address
                 */
 #ifdef INET6
+#ifdef COMPAT_RFC1883          /* XXX */
                if (res->ai_family == AF_INET6) {
                        if (((char *)CMSG_DATA(cmsg) +
-                            sizeof(struct ip6_rthdr) +
-                            ((inet6_rthdr_segments(cmsg) + 1) *
-                             sizeof(struct in6_addr))) > ep)
+                            sizeof(struct ip6_rthdr)) > ep)
                        return -1;
                } else
+#endif /* COMPAT_RFC1883 */
 #endif
                if (lsrp + 4 > ep)
                        return -1;
@@ -2717,8 +2723,9 @@ sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *lenp, int *protop,
        }
 #ifdef INET6
        if (res->ai_family == AF_INET6) {
-               inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
-               *lenp = cmsg->cmsg_len;
+#ifdef COMPAT_RFC1883          /* XXX */
+               *lenp = 0;
+#endif /* COMPAT_RFC1883 */
        } else
 #endif
       {
index b06bcf3..f4e0537 100644 (file)
 # LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 # A PARTICULAR PURPOSE.
 # $FreeBSD: src/usr.sbin/traceroute6/Makefile,v 1.2.2.3 2002/07/23 07:48:27 ru Exp $
-# $DragonFly: src/usr.sbin/traceroute6/Makefile,v 1.2 2003/06/17 04:30:03 dillon Exp $
+# $DragonFly: src/usr.sbin/traceroute6/Makefile,v 1.3 2008/09/04 09:08:22 hasso Exp $
 
 PROG=  traceroute6
 MAN=   traceroute6.8
 BINOWN=        root
 BINMODE=4555
 
-CFLAGS+=-DINET6 -DIPSEC -DHAVE_POLL
+CFLAGS+=-DINET6 -DIPSEC -DHAVE_POLL -DUSE_RFC3542
 
 DPADD= ${LIBIPSEC}
 LDADD= -lipsec
index 4ee1f81..57ae5b1 100644 (file)
@@ -68,7 +68,7 @@
  *     The Regents of the University of California.  All rights reserved.
  *
  * $FreeBSD: src/usr.sbin/traceroute6/traceroute6.c,v 1.22 2008/02/10 21:06:38 dwmalone Exp $
- * $DragonFly: src/usr.sbin/traceroute6/traceroute6.c,v 1.8 2008/05/20 12:14:10 hasso Exp $
+ * $DragonFly: src/usr.sbin/traceroute6/traceroute6.c,v 1.9 2008/09/04 09:08:22 hasso Exp $
  */
 
 /*
@@ -331,10 +331,6 @@ u_long datalen;                    /* How much data */
 #define        ICMP6ECHOLEN    8
 /* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */
 char rtbuf[2064];
-#ifdef USE_RFC2292BIS
-struct ip6_rthdr *rth;
-#endif
-struct cmsghdr *cmsg;
 
 char *source = 0;
 char *hostname;
@@ -423,33 +419,6 @@ main(int argc, char **argv)
                                    "traceroute6: unknown host %s\n", optarg);
                                exit(1);
                        }
-#ifdef USE_RFC2292BIS
-                       if (rth == NULL) {
-                               /*
-                                * XXX: We can't detect the number of
-                                * intermediate nodes yet.
-                                */
-                               if ((rth = inet6_rth_init((void *)rtbuf,
-                                   sizeof(rtbuf), IPV6_RTHDR_TYPE_0,
-                                   0)) == NULL) {
-                                       fprintf(stderr,
-                                           "inet6_rth_init failed.\n");
-                                       exit(1);
-                               }
-                       }
-                       if (inet6_rth_add((void *)rth,
-                           (struct in6_addr *)hp->h_addr)) {
-                               fprintf(stderr,
-                                   "inet6_rth_add failed for %s\n",
-                                   optarg);
-                               exit(1);
-                       }
-#else  /* old advanced API */
-                       if (cmsg == NULL)
-                               cmsg = inet6_rthdr_init(rtbuf, IPV6_RTHDR_TYPE_0);
-                       inet6_rthdr_add(cmsg, (struct in6_addr *)hp->h_addr,
-                           IPV6_RTHDR_LOOSE);
-#endif
                        freehostent(hp);
                        break;
                case 'I':
@@ -729,27 +698,6 @@ main(int argc, char **argv)
        if (options & SO_DONTROUTE)
                (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
                    (char *)&on, sizeof(on));
-#ifdef USE_RFC2292BIS
-       if (rth) {/* XXX: there is no library to finalize the header... */
-               rth->ip6r_len = rth->ip6r_segleft * 2;
-               if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR,
-                   (void *)rth, (rth->ip6r_len + 1) << 3)) {
-                       fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n",
-                           strerror(errno));
-                       exit(1);
-               }
-       }
-#else  /* old advanced API */
-       if (cmsg != NULL) {
-               inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
-               if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_PKTOPTIONS,
-                   rtbuf, cmsg->cmsg_len) < 0) {
-                       fprintf(stderr, "setsockopt(IPV6_PKTOPTIONS): %s\n",
-                           strerror(errno));
-                       exit(1);
-               }
-       }
-#endif /* USE_RFC2292BIS */
 #ifdef IPSEC
 #ifdef IPSEC_POLICY_IPSEC
        /*
@@ -815,9 +763,6 @@ main(int argc, char **argv)
 
                Nxt = Dst;
                Nxt.sin6_port = htons(DUMMY_PORT);
-               if (cmsg != NULL)
-                       bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr,
-                           sizeof(Nxt.sin6_addr));
                if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                        perror("socket");
                        exit(1);