Hi there,

Please find attached a patch for IPv6 support in netselect.  The patch
is against r26676 of

  svn://svn.debian.org/svn/collab-maint/deb-maint/netselect/trunk

Regards,

Bob Ham

-- 
Bob Ham <bob....@collabora.com>
Software Engineer

>>>>>>>>
Open First 
Collabora is hiring!
Please check out our latest opportunities here:
http://bit.ly/Collabora-Careers
<<<<<<<<


Index: netinet/icmp6.h
===================================================================
--- netinet/icmp6.h	(revision 0)
+++ netinet/icmp6.h	(working copy)
@@ -0,0 +1,1011 @@
+/*	$KAME: icmp6.h,v 1.107 2007/06/14 12:09:42 itojun Exp $	*/
+
+/*
+ * Copyright (c) 2002 INRIA. All rights reserved.
+ *
+ * Implementation of Multicast Listener Discovery, Version 2.
+ * Developed by Hitoshi Asaeda, INRIA, February 2002.
+ *
+ * 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 INRIA 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 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.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ *	The Regents of the University of California.  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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ *	@(#)ip_icmp.h	8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _NETINET_ICMP6_H_
+#define _NETINET_ICMP6_H_
+#ifdef __APPLE__
+#include <sys/appleapiopts.h>
+#endif /* __APPLE__ */
+
+
+#define ICMPV6_PLD_MAXLEN	1232	/* IPV6_MMTU - sizeof(struct ip6_hdr)
+					   - sizeof(struct icmp6_hdr) */
+
+struct icmp6_hdr {
+	u_int8_t	icmp6_type;	/* type field */
+	u_int8_t	icmp6_code;	/* code field */
+	u_int16_t	icmp6_cksum;	/* checksum field */
+	union {
+		u_int32_t	icmp6_un_data32[1]; /* type-specific field */
+		u_int16_t	icmp6_un_data16[2]; /* type-specific field */
+		u_int8_t	icmp6_un_data8[4];  /* type-specific field */
+	} icmp6_dataun;
+} __attribute__((__packed__));
+
+#define icmp6_data32	icmp6_dataun.icmp6_un_data32
+#define icmp6_data16	icmp6_dataun.icmp6_un_data16
+#define icmp6_data8	icmp6_dataun.icmp6_un_data8
+#define icmp6_pptr	icmp6_data32[0]		/* parameter prob */
+#define icmp6_mtu	icmp6_data32[0]		/* packet too big */
+#define icmp6_id	icmp6_data16[0]		/* echo request/reply */
+#define icmp6_seq	icmp6_data16[1]		/* echo request/reply */
+#define icmp6_maxdelay	icmp6_data16[0]		/* mcast group membership */
+
+#define ICMP6_DST_UNREACH		1	/* dest unreachable, codes: */
+#define ICMP6_PACKET_TOO_BIG		2	/* packet too big */
+#define ICMP6_TIME_EXCEEDED		3	/* time exceeded, code: */
+#define ICMP6_PARAM_PROB		4	/* ip6 header bad */
+
+#define ICMP6_ECHO_REQUEST		128	/* echo service */
+#define ICMP6_ECHO_REPLY		129	/* echo reply */
+#define MLD_LISTENER_QUERY		130 	/* multicast listener query */
+#define MLD_LISTENER_REPORT		131	/* multicast listener report */
+#define MLD_LISTENER_DONE		132	/* multicast listener done */
+#define MLD_LISTENER_REDUCTION MLD_LISTENER_DONE /* RFC3542 definition */
+
+/* RFC2292 decls */
+#define ICMP6_MEMBERSHIP_QUERY		130	/* group membership query */
+#define ICMP6_MEMBERSHIP_REPORT		131	/* group membership report */
+#define ICMP6_MEMBERSHIP_REDUCTION	132	/* group membership termination */
+
+#if (!defined(__APPLE__) && !defined(_KERNEL)) || defined(__APPLE__)
+/* the followings are for backward compatibility to old KAME apps. */
+#define MLD6_LISTENER_QUERY MLD_LISTENER_QUERY
+#define MLD6_LISTENER_REPORT MLD_LISTENER_REPORT
+#define MLD6_LISTENER_DONE MLD_LISTENER_DONE
+#endif
+
+#define ND_ROUTER_SOLICIT		133	/* router solicitation */
+#define ND_ROUTER_ADVERT		134	/* router advertisement */
+#define ND_NEIGHBOR_SOLICIT		135	/* neighbor solicitation */
+#define ND_NEIGHBOR_ADVERT		136	/* neighbor advertisement */
+#define ND_REDIRECT			137	/* redirect */
+
+#define ICMP6_ROUTER_RENUMBERING	138	/* router renumbering */
+
+#define ICMP6_WRUREQUEST		139	/* who are you request */
+#define ICMP6_WRUREPLY			140	/* who are you reply */
+#define ICMP6_FQDN_QUERY		139	/* FQDN query */
+#define ICMP6_FQDN_REPLY		140	/* FQDN reply */
+#define ICMP6_NI_QUERY			139	/* node information request */
+#define ICMP6_NI_REPLY			140	/* node information reply */
+
+/* The belows are not yet defined in 2292bis. They will be renamed */
+#define IND_SOLICIT			141	/* inverse neighbor solicitation */
+#define IND_ADVERT			142	/* inverse neighbor advertisement */
+#define MLDV2_LISTENER_REPORT		143	/* MLDv2 report */
+
+/* Folloing numbers are defined in the mobile-ip draft. */
+#define MIP6_HA_DISCOVERY_REQUEST	144	/* home agent address discovery request */
+#define MIP6_HA_DISCOVERY_REPLY		145	/* home agent address discovery reply */
+#define MIP6_PREFIX_SOLICIT		146	/* mobile prefix solicitation */
+#define MIP6_PREFIX_ADVERT		147	/* mobile prefix advertisement */
+
+/* The definitions below are experimental. TBA */
+#define MLD_MTRACE_RESP			200	/* mtrace resp (to sender) */
+#define MLD_MTRACE			201	/* mtrace messages */
+
+/* backward compatibility for applications using old macro names */
+#if (!defined(__APPLE__) && !defined(_KERNEL)) || defined(__APPLE__)
+#define MLD6_MTRACE_RESP	MLD_MTRACE_RESP
+#define MLD6_MTRACE		MLD_MTRACE
+#define MLD6V2_LISTENER_REPORT	MLDV2_LISTENER_REPORT
+#endif
+
+#define ICMP6_MAXTYPE			201
+
+#define ICMP6_DST_UNREACH_NOROUTE	0	/* no route to destination */
+#define ICMP6_DST_UNREACH_ADMIN	 	1	/* administratively prohibited */
+#define ICMP6_DST_UNREACH_NOTNEIGHBOR	2	/* not a neighbor(obsolete) */
+#define ICMP6_DST_UNREACH_BEYONDSCOPE	2	/* beyond scope of source address */
+#define ICMP6_DST_UNREACH_ADDR		3	/* address unreachable */
+#define ICMP6_DST_UNREACH_NOPORT	4	/* port unreachable */
+
+#define ICMP6_TIME_EXCEED_TRANSIT 	0	/* ttl==0 in transit */
+#define ICMP6_TIME_EXCEED_REASSEMBLY	1	/* ttl==0 in reass */
+
+#define ICMP6_PARAMPROB_HEADER 	 	0	/* erroneous header field */
+#define ICMP6_PARAMPROB_NEXTHEADER	1	/* unrecognized next header */
+#define ICMP6_PARAMPROB_OPTION		2	/* unrecognized option */
+
+#define ICMP6_INFOMSG_MASK		0x80	/* all informational messages */
+
+#define ICMP6_NI_SUBJ_IPV6	0	/* Query Subject is an IPv6 address */
+#define ICMP6_NI_SUBJ_FQDN	1	/* Query Subject is a Domain name */
+#define ICMP6_NI_SUBJ_IPV4	2	/* Query Subject is an IPv4 address */
+
+#define ICMP6_NI_SUCCESS	0	/* node information successful reply */
+#define ICMP6_NI_REFUSED	1	/* node information request is refused */
+#define ICMP6_NI_UNKNOWN	2	/* unknown Qtype */
+
+#define ICMP6_ROUTER_RENUMBERING_COMMAND  0	/* rr command */
+#define ICMP6_ROUTER_RENUMBERING_RESULT   1	/* rr result */
+#define ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET   255	/* rr seq num reset */
+
+/* Used in kernel only */
+#define ND_REDIRECT_ONLINK	0	/* redirect to an on-link node */
+#define ND_REDIRECT_ROUTER	1	/* redirect to a better router */
+
+/*
+ * Multicast Listener Discovery
+ */
+struct mld_hdr {
+	struct icmp6_hdr	mld_icmp6_hdr;
+	struct in6_addr		mld_addr; /* multicast address */
+} __attribute__((__packed__));
+
+/* definitions to provide backward compatibility to old KAME applications */
+#if (!defined(__APPLE__) && !defined(_KERNEL)) || defined(__APPLE__)
+#define mld6_hdr	mld_hdr
+#define mld6_type	mld_type
+#define mld6_code	mld_code
+#define mld6_cksum	mld_cksum
+#define mld6_maxdelay	mld_maxdelay
+#define mld6_reserved	mld_reserved
+#define mld6_addr	mld_addr
+#endif
+
+/* shortcut macro definitions */
+#define mld_type	mld_icmp6_hdr.icmp6_type
+#define mld_code	mld_icmp6_hdr.icmp6_code
+#define mld_cksum	mld_icmp6_hdr.icmp6_cksum
+#define mld_maxdelay	mld_icmp6_hdr.icmp6_data16[0]
+#define mld_reserved	mld_icmp6_hdr.icmp6_data16[1]
+
+/*
+ * Multicast Listener Discovery Version 2
+ */
+struct mldv2_hdr {
+	struct icmp6_hdr	mld_icmp6_hdr;
+	struct in6_addr		mld_addr;	/* multicast address */
+	u_int8_t		mld_rtval;	/* Reserved, S Flag and QRV */
+	u_int8_t	 	mld_qqi;	/* querier's query interval (QQI) */
+	u_int16_t		mld_numsrc;	/* number of sources (0 for general */
+						/* and group-specific queries) */
+	struct in6_addr		mld_src[1];	/* source address list */
+} __attribute__((__packed__));
+
+#define MLD_MRC_EXP(x)	((ntohs(x) >> 12) & 0x0007)
+#define MLD_MRC_MANT(x)	(ntohs(x) & 0x0fff)
+#define MLD_QQIC_EXP(x)	(((x) >> 4) & 0x07)
+#define MLD_QQIC_MANT(x)	((x) & 0x0f)
+#define MLD_QRESV(x)	(((x) >> 4) & 0x0f)
+#define MLD_SFLAG(x)	(((x) >> 3) & 0x01)
+#define MLD_QRV(x)	((x) & 0x07)	/* querier's robustness variable   */
+
+/*
+ * MLDv2 Membership Report Message header.
+ */
+struct mld_report_hdr {
+	struct icmp6_hdr	mld_icmp6_hdr;	/* version & type of MLD message */
+} __attribute__((__packed__));
+
+/* shortcut macro definition */
+#define mld_grpnum	mld_icmp6_hdr.icmp6_data16[1]
+
+/*
+ * MLDv2 Group Record header.
+ */
+struct mld_group_record_hdr {
+	u_int8_t	record_type;	/* record types for membership report */
+	u_int8_t	auxlen;		/* aux data length (must be zero)     */
+	u_int16_t               numsrc;         /* number of sources        */
+        struct in6_addr         group;          /* group address            */
+        struct in6_addr         src[1];         /* source address list      */
+} __attribute__((__packed__));
+
+#define MLD_V1_QUERY			0
+#define MLD_V2_GENERAL_QUERY		1
+#define MLD_V2_GROUP_QUERY		2
+#define MLD_V2_GROUP_SOURCE_QUERY	3
+
+#define MLD_MINLEN			24
+#define MLD_V2_QUERY_MINLEN		28
+
+
+/*
+ * Group Record Types in the MLD Membership Report
+ */
+#ifndef MODE_IS_INCLUDE
+#define MODE_IS_INCLUDE                 1
+#define MODE_IS_EXCLUDE                 2
+#define CHANGE_TO_INCLUDE_MODE          3
+#define CHANGE_TO_EXCLUDE_MODE          4
+#define ALLOW_NEW_SOURCES               5
+#define BLOCK_OLD_SOURCES               6
+#endif
+
+/*
+ * Neighbor Discovery
+ */
+
+struct nd_router_solicit {	/* router solicitation */
+	struct icmp6_hdr 	nd_rs_hdr;
+	/* could be followed by options */
+} __attribute__((__packed__));
+
+#define nd_rs_type	nd_rs_hdr.icmp6_type
+#define nd_rs_code	nd_rs_hdr.icmp6_code
+#define nd_rs_cksum	nd_rs_hdr.icmp6_cksum
+#define nd_rs_reserved	nd_rs_hdr.icmp6_data32[0]
+
+struct nd_router_advert {	/* router advertisement */
+	struct icmp6_hdr	nd_ra_hdr;
+	u_int32_t		nd_ra_reachable;	/* reachable time */
+	u_int32_t		nd_ra_retransmit;	/* retransmit timer */
+	/* could be followed by options */
+} __attribute__((__packed__));
+
+#define nd_ra_type		nd_ra_hdr.icmp6_type
+#define nd_ra_code		nd_ra_hdr.icmp6_code
+#define nd_ra_cksum		nd_ra_hdr.icmp6_cksum
+#define nd_ra_curhoplimit	nd_ra_hdr.icmp6_data8[0]
+#define nd_ra_flags_reserved	nd_ra_hdr.icmp6_data8[1]
+#define ND_RA_FLAG_MANAGED	0x80
+#define ND_RA_FLAG_OTHER	0x40
+#define ND_RA_FLAG_HOME_AGENT	0x20
+
+/*
+ * Router preference values based on draft-draves-ipngwg-router-selection-01.
+ * These are non-standard definitions.
+ */
+#define ND_RA_FLAG_RTPREF_MASK	0x18 /* 00011000 */
+
+#define ND_RA_FLAG_RTPREF_HIGH	0x08 /* 00001000 */
+#define ND_RA_FLAG_RTPREF_MEDIUM	0x00 /* 00000000 */
+#define ND_RA_FLAG_RTPREF_LOW	0x18 /* 00011000 */
+#define ND_RA_FLAG_RTPREF_RSV	0x10 /* 00010000 */
+
+#define nd_ra_router_lifetime	nd_ra_hdr.icmp6_data16[1]
+
+struct nd_neighbor_solicit {	/* neighbor solicitation */
+	struct icmp6_hdr	nd_ns_hdr;
+	struct in6_addr		nd_ns_target;	/*target address */
+	/* could be followed by options */
+} __attribute__((__packed__));
+
+#define nd_ns_type		nd_ns_hdr.icmp6_type
+#define nd_ns_code		nd_ns_hdr.icmp6_code
+#define nd_ns_cksum		nd_ns_hdr.icmp6_cksum
+#define nd_ns_reserved		nd_ns_hdr.icmp6_data32[0]
+
+struct nd_neighbor_advert {	/* neighbor advertisement */
+	struct icmp6_hdr	nd_na_hdr;
+	struct in6_addr		nd_na_target;	/* target address */
+	/* could be followed by options */
+} __attribute__((__packed__));
+
+#define nd_na_type		nd_na_hdr.icmp6_type
+#define nd_na_code		nd_na_hdr.icmp6_code
+#define nd_na_cksum		nd_na_hdr.icmp6_cksum
+#define nd_na_flags_reserved	nd_na_hdr.icmp6_data32[0]
+#if BYTE_ORDER == BIG_ENDIAN
+#define ND_NA_FLAG_ROUTER		0x80000000
+#define ND_NA_FLAG_SOLICITED		0x40000000
+#define ND_NA_FLAG_OVERRIDE		0x20000000
+#else
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define ND_NA_FLAG_ROUTER		0x80
+#define ND_NA_FLAG_SOLICITED		0x40
+#define ND_NA_FLAG_OVERRIDE		0x20
+#endif
+#endif
+
+struct nd_redirect {		/* redirect */
+	struct icmp6_hdr	nd_rd_hdr;
+	struct in6_addr		nd_rd_target;	/* target address */
+	struct in6_addr		nd_rd_dst;	/* destination address */
+	/* could be followed by options */
+} __attribute__((__packed__));
+
+#define nd_rd_type		nd_rd_hdr.icmp6_type
+#define nd_rd_code		nd_rd_hdr.icmp6_code
+#define nd_rd_cksum		nd_rd_hdr.icmp6_cksum
+#define nd_rd_reserved		nd_rd_hdr.icmp6_data32[0]
+
+struct ind_neighbor_solicit {	/* inverse neighbor solicitation */
+	struct icmp6_hdr	ind_ns_hdr;
+	/* could be followed by options */
+} __attribute__((__packed__));
+
+#define ind_ns_type		ind_ns_hdr.icmp6_type
+#define ind_ns_code		ind_ns_hdr.icmp6_code
+#define ind_ns_cksum		ind_ns_hdr.icmp6_cksum
+#define ind_ns_reserved		ind_ns_hdr.icmp6_data32[0]
+
+struct ind_neighbor_advert {	/* inverse neighbor advertisement */
+	struct icmp6_hdr	ind_na_hdr;
+	/* could be followed by options */
+} __attribute__((__packed__));
+
+#define ind_na_type		ind_na_hdr.icmp6_type
+#define ind_na_code		ind_na_hdr.icmp6_code
+#define ind_na_cksum		ind_na_hdr.icmp6_cksum
+#define ind_na_flags_reserved	ind_na_hdr.icmp6_data32[0]
+
+struct mip6_dhaad_req {		/* HA Address Discovery Request */
+	struct icmp6_hdr	mip6_dhreq_hdr;
+} __attribute__((__packed__));
+
+#define mip6_dhreq_type		mip6_dhreq_hdr.icmp6_type
+#define mip6_dhreq_code		mip6_dhreq_hdr.icmp6_code
+#define mip6_dhreq_cksum	mip6_dhreq_hdr.icmp6_cksum
+#define mip6_dhreq_id		mip6_dhreq_hdr.icmp6_data16[0]
+#define mip6_dhreq_reserved	mip6_dhreq_hdr.icmp6_data16[1]
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define MIP6_DHREQ_FLAG_MR	0x8000
+#endif /* BIG_ENDIAN */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define MIP6_DHREQ_FLAG_MR	0x0080
+#endif /* LITTLE_ENDIAN */
+
+
+struct mip6_dhaad_rep {		/* HA Address Discovery Reply */
+	struct icmp6_hdr	mip6_dhrep_hdr;
+	/* could be followed by home agent addresses */
+} __attribute__((__packed__));
+
+#define mip6_dhrep_type		mip6_dhrep_hdr.icmp6_type
+#define mip6_dhrep_code		mip6_dhrep_hdr.icmp6_code
+#define mip6_dhrep_cksum	mip6_dhrep_hdr.icmp6_cksum
+#define mip6_dhrep_id		mip6_dhrep_hdr.icmp6_data16[0]
+#define mip6_dhrep_reserved	mip6_dhrep_hdr.icmp6_data16[1]
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define MIP6_DHREP_FLAG_MR	0x8000
+#endif /* BIG_ENDIAN */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define MIP6_DHREP_FLAG_MR	0x0080
+#endif /* LITTLE_ENDIAN */
+
+struct mip6_prefix_solicit {	/* Mobile Prefix Solicitation */
+	struct icmp6_hdr	mip6_ps_hdr;
+} __attribute__((__packed__));
+
+#define mip6_ps_type		mip6_ps_hdr.icmp6_type
+#define mip6_ps_code		mip6_ps_hdr.icmp6_code
+#define mip6_ps_cksum		mip6_ps_hdr.icmp6_cksum
+#define mip6_ps_id		mip6_ps_hdr.icmp6_data16[0]
+#define mip6_ps_reserved	mip6_ps_hdr.icmp6_data16[1]
+
+struct mip6_prefix_advert {	/* Mobile Prefix Advertisement */
+	struct icmp6_hdr	mip6_pa_hdr;
+	/* followed by options */
+} __attribute__((__packed__));
+
+#define mip6_pa_type		mip6_pa_hdr.icmp6_type
+#define mip6_pa_code		mip6_pa_hdr.icmp6_code
+#define mip6_pa_cksum		mip6_pa_hdr.icmp6_cksum
+#define mip6_pa_id		mip6_pa_hdr.icmp6_data16[0]
+#define mip6_pa_flags_reserved	mip6_pa_hdr.icmp6_data16[1]
+#if BYTE_ORDER == BIG_ENDIAN
+#define MIP6_PA_FLAG_MANAGED	0x8000
+#define MIP6_PA_FLAG_OTHER	0x4000
+#endif /* BIG_ENDIAN */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define MIP6_PA_FLAG_MANAGED	0x0080
+#define MIP6_PA_FLAG_OTHER	0x0040
+#endif /* LITTLE_ENDIAN */
+
+struct nd_opt_hdr {		/* Neighbor discovery option header */
+	u_int8_t	nd_opt_type;
+	u_int8_t	nd_opt_len;
+	/* followed by option specific data*/
+} __attribute__((__packed__));
+
+#define ND_OPT_SOURCE_LINKADDR		1
+#define ND_OPT_TARGET_LINKADDR		2
+#define ND_OPT_PREFIX_INFORMATION	3
+#define ND_OPT_REDIRECTED_HEADER	4
+#define ND_OPT_MTU			5
+#define ND_OPT_ADV_INTERVAL		7	/* RFC3775 */
+#define ND_OPT_HA_INFORMATION		8	/* RFC3775 */
+#define ND_OPT_SOURCE_ADDRLIST		9	/* will be renamed */
+#define ND_OPT_TARGET_ADDRLIST		10	/* will be renamed */
+
+#define ND_OPT_ROUTE_INFO		200	/* draft-ietf-ipngwg-router-preference, not officially assigned yet */
+
+struct nd_opt_prefix_info {	/* prefix information */
+	u_int8_t	nd_opt_pi_type;
+	u_int8_t	nd_opt_pi_len;
+	u_int8_t	nd_opt_pi_prefix_len;
+	u_int8_t	nd_opt_pi_flags_reserved;
+	u_int32_t	nd_opt_pi_valid_time;
+	u_int32_t	nd_opt_pi_preferred_time;
+	u_int32_t	nd_opt_pi_reserved2;
+	struct in6_addr	nd_opt_pi_prefix;
+} __attribute__((__packed__));
+
+#define ND_OPT_PI_FLAG_ONLINK		0x80
+#define ND_OPT_PI_FLAG_AUTO		0x40
+#define ND_OPT_PI_FLAG_ROUTER		0x20	/* RFC3775 */
+
+struct nd_opt_rd_hdr {		/* redirected header */
+	u_int8_t	nd_opt_rh_type;
+	u_int8_t	nd_opt_rh_len;
+	u_int16_t	nd_opt_rh_reserved1;
+	u_int32_t	nd_opt_rh_reserved2;
+	/* followed by IP header and data */
+} __attribute__((__packed__));
+
+struct nd_opt_mtu {		/* MTU option */
+	u_int8_t	nd_opt_mtu_type;
+	u_int8_t	nd_opt_mtu_len;
+	u_int16_t	nd_opt_mtu_reserved;
+	u_int32_t	nd_opt_mtu_mtu;
+} __attribute__((__packed__));
+
+struct nd_opt_adv_interval {	/* Advertisement interval option */
+	u_int8_t	nd_opt_ai_type;
+	u_int8_t	nd_opt_ai_len;
+	u_int16_t	nd_opt_ai_reserved;
+	u_int32_t	nd_opt_ai_interval;
+} __attribute__((__packed__));
+
+struct nd_opt_homeagent_info {	/* Home Agent info */
+	u_int8_t	nd_opt_hai_type;
+	u_int8_t	nd_opt_hai_len;
+	u_int16_t	nd_opt_hai_reserved;
+	u_int16_t	nd_opt_hai_preference;
+	u_int16_t	nd_opt_hai_lifetime;
+} __attribute__((__packed__));
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define MIP6_HAINFO_FLAG_MR	0x8000
+#endif /* BIG_ENDIAN */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define MIP6_HAINFO_FLAG_MR	0x0080
+#endif /* LITTLE_ENDIAN */
+
+struct nd_opt_route_info {	/* route info */
+	u_int8_t	nd_opt_rti_type;
+	u_int8_t	nd_opt_rti_len;
+	u_int8_t	nd_opt_rti_prefixlen;
+	u_int8_t	nd_opt_rti_flags;
+	u_int32_t	nd_opt_rti_lifetime;
+	/* prefix follows */
+} __attribute__((__packed__));
+
+/*
+ * icmp6 namelookup
+ */
+
+struct icmp6_namelookup {
+	struct icmp6_hdr 	icmp6_nl_hdr;
+	u_int8_t	icmp6_nl_nonce[8];
+	int32_t		icmp6_nl_ttl;
+#if 0
+	u_int8_t	icmp6_nl_len;
+	u_int8_t	icmp6_nl_name[3];
+#endif
+	/* could be followed by options */
+} __attribute__((__packed__));
+
+/*
+ * icmp6 node information
+ */
+struct icmp6_nodeinfo {
+	struct icmp6_hdr icmp6_ni_hdr;
+	u_int8_t icmp6_ni_nonce[8];
+	/* could be followed by reply data */
+} __attribute__((__packed__));
+
+#define ni_type		icmp6_ni_hdr.icmp6_type
+#define ni_code		icmp6_ni_hdr.icmp6_code
+#define ni_cksum	icmp6_ni_hdr.icmp6_cksum
+#define ni_qtype	icmp6_ni_hdr.icmp6_data16[0]
+#define ni_flags	icmp6_ni_hdr.icmp6_data16[1]
+
+#define NI_QTYPE_NOOP		0 /* NOOP  */
+#define NI_QTYPE_SUPTYPES	1 /* Supported Qtypes */
+#define NI_QTYPE_FQDN		2 /* FQDN (draft 04) */
+#define NI_QTYPE_DNSNAME	2 /* DNS Name (draft 05-07) */
+#define NI_QTYPE_NODENAME	2 /* Node Name (draft 08) */
+#define NI_QTYPE_NODEADDR	3 /* Node Addresses */
+#define NI_QTYPE_IPV4ADDR	4 /* IPv4 Addresses */
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define NI_SUPTYPE_FLAG_COMPRESS	0x1
+#define NI_FQDN_FLAG_VALIDTTL		0x1
+#define NI_NODENAME_FLAG_VALIDTTL	0x1
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define NI_SUPTYPE_FLAG_COMPRESS	0x0100
+#define NI_FQDN_FLAG_VALIDTTL		0x0100
+#define NI_NODENAME_FLAG_VALIDTTL	0x0100
+#endif
+
+#ifdef NAME_LOOKUPS_04
+#if BYTE_ORDER == BIG_ENDIAN
+#define NI_NODEADDR_FLAG_LINKLOCAL	0x1
+#define NI_NODEADDR_FLAG_SITELOCAL	0x2
+#define NI_NODEADDR_FLAG_GLOBAL		0x4
+#define NI_NODEADDR_FLAG_ALL		0x8
+#define NI_NODEADDR_FLAG_TRUNCATE	0x10
+#define NI_NODEADDR_FLAG_ANYCAST	0x20 /* just experimental. not in spec */
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define NI_NODEADDR_FLAG_LINKLOCAL	0x0100
+#define NI_NODEADDR_FLAG_SITELOCAL	0x0200
+#define NI_NODEADDR_FLAG_GLOBAL		0x0400
+#define NI_NODEADDR_FLAG_ALL		0x0800
+#define NI_NODEADDR_FLAG_TRUNCATE	0x1000
+#define NI_NODEADDR_FLAG_ANYCAST	0x2000 /* just experimental. not in spec */
+#endif
+#else  /* draft-ietf-ipngwg-icmp-name-lookups-05 (and later?) */
+#if BYTE_ORDER == BIG_ENDIAN
+#define NI_NODEADDR_FLAG_TRUNCATE	0x1
+#define NI_NODEADDR_FLAG_ALL		0x2
+#define NI_NODEADDR_FLAG_COMPAT		0x4
+#define NI_NODEADDR_FLAG_LINKLOCAL	0x8
+#define NI_NODEADDR_FLAG_SITELOCAL	0x10
+#define NI_NODEADDR_FLAG_GLOBAL		0x20
+#define NI_NODEADDR_FLAG_ANYCAST	0x40 /* just experimental. not in spec */
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define NI_NODEADDR_FLAG_TRUNCATE	0x0100
+#define NI_NODEADDR_FLAG_ALL		0x0200
+#define NI_NODEADDR_FLAG_COMPAT		0x0400
+#define NI_NODEADDR_FLAG_LINKLOCAL	0x0800
+#define NI_NODEADDR_FLAG_SITELOCAL	0x1000
+#define NI_NODEADDR_FLAG_GLOBAL		0x2000
+#define NI_NODEADDR_FLAG_ANYCAST	0x4000 /* just experimental. not in spec */
+#endif
+#endif
+
+struct ni_reply_fqdn {
+	u_int32_t ni_fqdn_ttl;	/* TTL */
+	u_int8_t ni_fqdn_namelen; /* length in octets of the FQDN */
+	u_int8_t ni_fqdn_name[3]; /* XXX: alignment */
+} __attribute__((__packed__));
+#define ni_reply_nodename ni_reply_fqdn
+#define ni_nodename_ttl ni_fqdn_ttl
+#define ni_nodename_namelen ni_fqdn_namelen
+#define ni_nodename_name ni_fqdn_name
+
+/*
+ * Router Renumbering. as router-renum-08.txt
+ */
+struct icmp6_router_renum {	/* router renumbering header */
+	struct icmp6_hdr	rr_hdr;
+	u_int8_t	rr_segnum;
+	u_int8_t	rr_flags;
+	u_int16_t	rr_maxdelay;
+	u_int32_t	rr_reserved;
+} __attribute__((__packed__));
+
+#define ICMP6_RR_FLAGS_TEST		0x80
+#define ICMP6_RR_FLAGS_REQRESULT	0x40
+#define ICMP6_RR_FLAGS_FORCEAPPLY	0x20
+#define ICMP6_RR_FLAGS_SPECSITE		0x10
+#define ICMP6_RR_FLAGS_PREVDONE		0x08
+
+#define rr_type		rr_hdr.icmp6_type
+#define rr_code		rr_hdr.icmp6_code
+#define rr_cksum	rr_hdr.icmp6_cksum
+#define rr_seqnum 	rr_hdr.icmp6_data32[0]
+
+struct rr_pco_match {		/* match prefix part */
+	u_int8_t	rpm_code;
+	u_int8_t	rpm_len;
+	u_int8_t	rpm_ordinal;
+	u_int8_t	rpm_matchlen;
+	u_int8_t	rpm_minlen;
+	u_int8_t	rpm_maxlen;
+	u_int16_t	rpm_reserved;
+	struct	in6_addr	rpm_prefix;
+} __attribute__((__packed__));
+
+#define RPM_PCO_ADD		1
+#define RPM_PCO_CHANGE		2
+#define RPM_PCO_SETGLOBAL	3
+#define RPM_PCO_MAX		4
+
+struct rr_pco_use {		/* use prefix part */
+	u_int8_t	rpu_uselen;
+	u_int8_t	rpu_keeplen;
+	u_int8_t	rpu_ramask;
+	u_int8_t	rpu_raflags;
+	u_int32_t	rpu_vltime;
+	u_int32_t	rpu_pltime;
+	u_int32_t	rpu_flags;
+	struct	in6_addr rpu_prefix;
+} __attribute__((__packed__));
+#define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK	0x80
+#define ICMP6_RR_PCOUSE_RAFLAGS_AUTO	0x40
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME	0x80000000
+#define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME	0x40000000
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME	0x80
+#define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME	0x40
+#endif
+
+struct rr_result {		/* router renumbering result message */
+	u_int16_t	rrr_flags;
+	u_int8_t	rrr_ordinal;
+	u_int8_t	rrr_matchedlen;
+	u_int32_t	rrr_ifid;
+	struct	in6_addr rrr_prefix;
+} __attribute__((__packed__));
+#if BYTE_ORDER == BIG_ENDIAN
+#define ICMP6_RR_RESULT_FLAGS_OOB		0x0002
+#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN		0x0001
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define ICMP6_RR_RESULT_FLAGS_OOB		0x0200
+#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN		0x0100
+#endif
+
+/*
+ * icmp6 filter structures.
+ */
+
+struct icmp6_filter {
+	u_int32_t icmp6_filt[8];
+};
+
+#ifdef _KERNEL
+#define	ICMP6_FILTER_SETPASSALL(filterp) \
+do {								\
+	int i; u_char *p;					\
+	p = (u_char *)filterp;					\
+	for (i = 0; i < sizeof(struct icmp6_filter); i++)	\
+		p[i] = 0xff;					\
+} while (/*CONSTCOND*/ 0)
+#define	ICMP6_FILTER_SETBLOCKALL(filterp) \
+	bzero(filterp, sizeof(struct icmp6_filter))
+#else /* _KERNEL */
+#define	ICMP6_FILTER_SETPASSALL(filterp) \
+	memset(filterp, 0xff, sizeof(struct icmp6_filter))
+#define	ICMP6_FILTER_SETBLOCKALL(filterp) \
+	memset(filterp, 0x00, sizeof(struct icmp6_filter))
+#endif /* _KERNEL */
+
+#define	ICMP6_FILTER_SETPASS(type, filterp) \
+	(((filterp)->icmp6_filt[(type) >> 5]) |= (1 << ((type) & 31)))
+#define	ICMP6_FILTER_SETBLOCK(type, filterp) \
+	(((filterp)->icmp6_filt[(type) >> 5]) &= ~(1 << ((type) & 31)))
+#define	ICMP6_FILTER_WILLPASS(type, filterp) \
+	((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) != 0)
+#define	ICMP6_FILTER_WILLBLOCK(type, filterp) \
+	((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) == 0)
+
+/*
+ * Variables related to this implementation
+ * of the internet control message protocol version 6.
+ */
+struct icmp6errstat {
+	u_quad_t icp6errs_dst_unreach_noroute;
+	u_quad_t icp6errs_dst_unreach_admin;
+	u_quad_t icp6errs_dst_unreach_beyondscope;
+	u_quad_t icp6errs_dst_unreach_addr;
+	u_quad_t icp6errs_dst_unreach_noport;
+	u_quad_t icp6errs_packet_too_big;
+	u_quad_t icp6errs_time_exceed_transit;
+	u_quad_t icp6errs_time_exceed_reassembly;
+	u_quad_t icp6errs_paramprob_header;
+	u_quad_t icp6errs_paramprob_nextheader;
+	u_quad_t icp6errs_paramprob_option;
+	u_quad_t icp6errs_redirect; /* we regard redirect as an error here */
+	u_quad_t icp6errs_unknown;
+};
+
+struct icmp6stat {
+/* statistics related to icmp6 packets generated */
+	u_quad_t icp6s_error;		/* # of calls to icmp6_error */
+	u_quad_t icp6s_canterror;	/* no error 'cuz old was icmp */
+	u_quad_t icp6s_toofreq;		/* no error 'cuz rate limitation */
+	u_quad_t icp6s_outhist[256];
+/* statistics related to input message processed */
+	u_quad_t icp6s_badcode;		/* icmp6_code out of range */
+	u_quad_t icp6s_tooshort;	/* packet < sizeof(struct icmp6_hdr) */
+	u_quad_t icp6s_checksum;	/* bad checksum */
+	u_quad_t icp6s_badlen;		/* calculated bound mismatch */
+	/*
+	 * number of responses: this member is inherited from netinet code, but
+	 * for netinet6 code, it is already available in icp6s_outhist[].
+	 */
+	u_quad_t icp6s_reflect;
+	u_quad_t icp6s_inhist[256];
+	u_quad_t icp6s_nd_toomanyopt;	/* too many ND options */
+	struct icmp6errstat icp6s_outerrhist;
+#define icp6s_odst_unreach_noroute \
+	icp6s_outerrhist.icp6errs_dst_unreach_noroute
+#define icp6s_odst_unreach_admin icp6s_outerrhist.icp6errs_dst_unreach_admin
+#define icp6s_odst_unreach_beyondscope \
+	icp6s_outerrhist.icp6errs_dst_unreach_beyondscope
+#define icp6s_odst_unreach_addr icp6s_outerrhist.icp6errs_dst_unreach_addr
+#define icp6s_odst_unreach_noport icp6s_outerrhist.icp6errs_dst_unreach_noport
+#define icp6s_opacket_too_big icp6s_outerrhist.icp6errs_packet_too_big
+#define icp6s_otime_exceed_transit \
+	icp6s_outerrhist.icp6errs_time_exceed_transit
+#define icp6s_otime_exceed_reassembly \
+	icp6s_outerrhist.icp6errs_time_exceed_reassembly
+#define icp6s_oparamprob_header icp6s_outerrhist.icp6errs_paramprob_header
+#define icp6s_oparamprob_nextheader \
+	icp6s_outerrhist.icp6errs_paramprob_nextheader
+#define icp6s_oparamprob_option icp6s_outerrhist.icp6errs_paramprob_option
+#define icp6s_oredirect icp6s_outerrhist.icp6errs_redirect
+#define icp6s_ounknown icp6s_outerrhist.icp6errs_unknown
+	u_quad_t icp6s_pmtuchg;		/* path MTU changes */
+	u_quad_t icp6s_nd_badopt;	/* bad ND options */
+	u_quad_t icp6s_badns;		/* bad neighbor solicitation */
+	u_quad_t icp6s_badna;		/* bad neighbor advertisement */
+	u_quad_t icp6s_badrs;		/* bad router advertisement */
+	u_quad_t icp6s_badra;		/* bad router advertisement */
+	u_quad_t icp6s_badredirect;	/* bad redirect message */
+};
+
+/*
+ * Names for ICMP sysctl objects
+ */
+#define ICMPV6CTL_STATS		1
+#define ICMPV6CTL_REDIRACCEPT	2	/* accept/process redirects */
+#define ICMPV6CTL_REDIRTIMEOUT	3	/* redirect cache time */
+#if 0	/*obsoleted*/
+#define ICMPV6CTL_ERRRATELIMIT	5	/* ICMPv6 error rate limitation */
+#endif
+#define ICMPV6CTL_ND6_PRUNE	6
+#define ICMPV6CTL_ND6_DELAY	8
+#define ICMPV6CTL_ND6_UMAXTRIES	9
+#define ICMPV6CTL_ND6_MMAXTRIES		10
+#define ICMPV6CTL_ND6_USELOOPBACK	11
+/*#define ICMPV6CTL_ND6_PROXYALL	12	obsoleted, do not reuse here */
+#define ICMPV6CTL_NODEINFO	13
+#define ICMPV6CTL_ERRPPSLIMIT	14	/* ICMPv6 error pps limitation */
+#define ICMPV6CTL_ND6_MAXNUDHINT	15
+#define ICMPV6CTL_MTUDISC_HIWAT	16
+#define ICMPV6CTL_MTUDISC_LOWAT	17
+#define ICMPV6CTL_ND6_DEBUG	18
+#define ICMPV6CTL_ND6_DRLIST	19
+#define ICMPV6CTL_ND6_PRLIST	20
+#define ICMPV6CTL_MLD_MAXSRCFILTER	21
+#define ICMPV6CTL_MLD_SOMAXSRC	22
+#define ICMPV6CTL_MLD_VERSION	23
+#define ICMPV6CTL_ND6_MAXQLEN	24
+#define ICMPV6CTL_MAXID		25
+
+#if !defined(__APPLE__) || (defined(__APPLE__) && defined(KERNEL_PRIVATE))
+#define ICMPV6CTL_NAMES { \
+	{ 0, 0 }, \
+	{ 0, 0 }, \
+	{ "rediraccept", CTLTYPE_INT }, \
+	{ "redirtimeout", CTLTYPE_INT }, \
+	{ 0, 0 }, \
+	{ 0, 0 }, \
+	{ "nd6_prune", CTLTYPE_INT }, \
+	{ 0, 0 }, \
+	{ "nd6_delay", CTLTYPE_INT }, \
+	{ "nd6_umaxtries", CTLTYPE_INT }, \
+	{ "nd6_mmaxtries", CTLTYPE_INT }, \
+	{ "nd6_useloopback", CTLTYPE_INT }, \
+	{ 0, 0 }, \
+	{ "nodeinfo", CTLTYPE_INT }, \
+	{ "errppslimit", CTLTYPE_INT }, \
+	{ "nd6_maxnudhint", CTLTYPE_INT }, \
+	{ "mtudisc_hiwat", CTLTYPE_INT }, \
+	{ "mtudisc_lowat", CTLTYPE_INT }, \
+	{ "nd6_debug", CTLTYPE_INT }, \
+	{ 0, 0 }, \
+	{ 0, 0 }, \
+	{ "mldmaxsrcfilter", CTLTYPE_INT }, \
+	{ "mldsomaxsrc", CTLTYPE_INT }, \
+	{ "mldalwaysv2", CTLTYPE_INT }, \
+	{ "nd6_maxqueuelen", CTLTYPE_INT }, \
+}
+
+#define RTF_PROBEMTU	RTF_PROTO1
+
+#ifdef _KERNEL
+# ifdef __STDC__
+struct	rtentry;
+struct	rttimer;
+struct	in6_multi;
+# endif
+void	icmp6_init(void);
+void	icmp6_paramerror(struct mbuf *, int);
+void	icmp6_error(struct mbuf *, int, int, int);
+#ifdef __APPLE__
+int	icmp6_input(struct mbuf **, int *);
+void	icmp6_fasttimo(void);
+#else
+void	icmp6_error2(struct mbuf *, int, int, int, struct ifnet *);
+int	icmp6_input(struct mbuf **, int *, int);
+#endif
+void	icmp6_reflect(struct mbuf *, size_t);
+void	icmp6_prepare(struct mbuf *);
+#ifdef __APPLE__
+void	icmp6_redirect_input(struct mbuf *, int);
+#else
+void	icmp6_redirect_input(struct mbuf *, int, int);
+#endif
+void	icmp6_redirect_output(struct mbuf *, struct rtentry *);
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+int	icmp6_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+#endif
+
+struct	ip6ctlparam;
+#ifdef __APPLE__
+void	icmp6_mtudisc_update(struct ip6ctlparam *, int);
+#else /* __APPLE__ */
+void	icmp6_mtudisc_update(struct ip6ctlparam *, struct sockaddr_in6 *, int);
+#endif /* __APPLE__ */
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+void	icmp6_mtudisc_callback_register(void (*)(struct in6_addr *));
+#endif
+
+/* XXX: is this the right place for these macros? */
+#ifdef __APPLE__
+#define icmp6_ifstat_inc(ifp, tag) \
+do {								\
+	if ((ifp) && (ifp)->if_index <= if_index			\
+	 && (ifp)->if_index < icmp6_ifstatmax			\
+	 && icmp6_ifstat && icmp6_ifstat[(ifp)->if_index]) {	\
+		icmp6_ifstat[(ifp)->if_index]->tag++;		\
+	}							\
+} while (0)
+#else
+#define icmp6_ifstat_inc(ifp, tag) \
+do {								\
+	if (ifp)						\
+		((struct in6_ifextra *)((ifp)->if_afdata[AF_INET6]))->icmp6_ifstat->tag++; \
+} while (/*CONSTCOND*/ 0)
+#endif
+
+#define icmp6_ifoutstat_inc(ifp, type, code) \
+do { \
+		icmp6_ifstat_inc(ifp, ifs6_out_msg); \
+		switch(type) { \
+		 case ICMP6_DST_UNREACH: \
+			 icmp6_ifstat_inc(ifp, ifs6_out_dstunreach); \
+			 if (code == ICMP6_DST_UNREACH_ADMIN) \
+				 icmp6_ifstat_inc(ifp, ifs6_out_adminprohib); \
+			 break; \
+		 case ICMP6_PACKET_TOO_BIG: \
+			 icmp6_ifstat_inc(ifp, ifs6_out_pkttoobig); \
+			 break; \
+		 case ICMP6_TIME_EXCEEDED: \
+			 icmp6_ifstat_inc(ifp, ifs6_out_timeexceed); \
+			 break; \
+		 case ICMP6_PARAM_PROB: \
+			 icmp6_ifstat_inc(ifp, ifs6_out_paramprob); \
+			 break; \
+		 case ICMP6_ECHO_REQUEST: \
+			 icmp6_ifstat_inc(ifp, ifs6_out_echo); \
+			 break; \
+		 case ICMP6_ECHO_REPLY: \
+			 icmp6_ifstat_inc(ifp, ifs6_out_echoreply); \
+			 break; \
+		 case MLD_LISTENER_QUERY: \
+			 icmp6_ifstat_inc(ifp, ifs6_out_mldquery); \
+			 break; \
+		 case MLD_LISTENER_REPORT: \
+		 case MLDV2_LISTENER_REPORT: \
+			 icmp6_ifstat_inc(ifp, ifs6_out_mldreport); \
+			 break; \
+		 case MLD_LISTENER_DONE: \
+			 icmp6_ifstat_inc(ifp, ifs6_out_mlddone); \
+			 break; \
+		 case ND_ROUTER_SOLICIT: \
+			 icmp6_ifstat_inc(ifp, ifs6_out_routersolicit); \
+			 break; \
+		 case ND_ROUTER_ADVERT: \
+			 icmp6_ifstat_inc(ifp, ifs6_out_routeradvert); \
+			 break; \
+		 case ND_NEIGHBOR_SOLICIT: \
+			 icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit); \
+			 break; \
+		 case ND_NEIGHBOR_ADVERT: \
+			 icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert); \
+			 break; \
+		 case ND_REDIRECT: \
+			 icmp6_ifstat_inc(ifp, ifs6_out_redirect); \
+			 break; \
+		} \
+} while (/*CONSTCOND*/ 0)
+
+extern int	icmp6_rediraccept;	/* accept/process redirects */
+extern int	icmp6_redirtimeout;	/* cache time for redirect routes */
+
+#define ICMP6_NODEINFO_FQDNOK		0x1
+#define ICMP6_NODEINFO_NODEADDROK	0x2
+#define ICMP6_NODEINFO_TMPADDROK	0x4
+#define ICMP6_NODEINFO_GLOBALOK		0x8
+#endif /* _KERNEL */
+#endif /* !__APPLE__ || (__APPLE__ && KERNEL_PRIVATE) */
+
+#endif /* not _NETINET_ICMP6_H_ */
Index: netinet/ip6.h
===================================================================
--- netinet/ip6.h	(revision 0)
+++ netinet/ip6.h	(working copy)
@@ -0,0 +1,380 @@
+/*	$KAME: ip6.h,v 1.59 2004/07/09 09:15:19 itojun Exp $	*/
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 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.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ *	The Regents of the University of California.  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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ *	@(#)ip.h	8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _NETINET_IP6_H_
+#define _NETINET_IP6_H_
+
+/*
+ * Definition for internet protocol version 6.
+ * RFC 2460
+ */
+
+struct ip6_hdr {
+	union {
+		struct ip6_hdrctl {
+			u_int32_t ip6_un1_flow;	/* 20 bits of flow-ID */
+			u_int16_t ip6_un1_plen;	/* payload length */
+			u_int8_t  ip6_un1_nxt;	/* next header */
+			u_int8_t  ip6_un1_hlim;	/* hop limit */
+		} ip6_un1;
+		u_int8_t ip6_un2_vfc;	/* 4 bits version, top 4 bits class */
+	} ip6_ctlun;
+	struct in6_addr ip6_src;	/* source address */
+	struct in6_addr ip6_dst;	/* destination address */
+} __attribute__((__packed__));
+
+#define ip6_vfc		ip6_ctlun.ip6_un2_vfc
+#define ip6_flow	ip6_ctlun.ip6_un1.ip6_un1_flow
+#define ip6_plen	ip6_ctlun.ip6_un1.ip6_un1_plen
+#define ip6_nxt		ip6_ctlun.ip6_un1.ip6_un1_nxt
+#define ip6_hlim	ip6_ctlun.ip6_un1.ip6_un1_hlim
+#define ip6_hops	ip6_ctlun.ip6_un1.ip6_un1_hlim
+
+#define IPV6_VERSION		0x60
+#define IPV6_VERSION_MASK	0xf0
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define IPV6_FLOWINFO_MASK	0x0fffffff	/* flow info (28 bits) */
+#define IPV6_FLOWLABEL_MASK	0x000fffff	/* flow label (20 bits) */
+#else
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define IPV6_FLOWINFO_MASK	0xffffff0f	/* flow info (28 bits) */
+#define IPV6_FLOWLABEL_MASK	0xffff0f00	/* flow label (20 bits) */
+#endif /* LITTLE_ENDIAN */
+#endif
+#if 1
+/* ECN bits proposed by Sally Floyd */
+#define IP6TOS_CE		0x01	/* congestion experienced */
+#define IP6TOS_ECT		0x02	/* ECN-capable transport */
+#endif
+
+#ifdef _KERNEL
+/*
+ * for IPv6 pseudo header checksum
+ * XXX nonstandard
+ */
+struct ip6_hdr_pseudo {
+	struct in6_addr ip6ph_src;
+	struct in6_addr ip6ph_dst;
+	u_int32_t	ip6ph_len;
+	u_int8_t	ip6ph_zero[3];
+	u_int8_t	ip6ph_nxt;
+} __packed;
+#endif
+
+/*
+ * Extension Headers
+ */
+
+struct	ip6_ext {
+	u_int8_t ip6e_nxt;
+	u_int8_t ip6e_len;
+} __attribute__((__packed__));
+
+/* Hop-by-Hop options header */
+/* XXX should we pad it to force alignment on an 8-byte boundary? */
+struct ip6_hbh {
+	u_int8_t ip6h_nxt;	/* next header */
+	u_int8_t ip6h_len;	/* length in units of 8 octets */
+	/* followed by options */
+} __attribute__((__packed__));
+
+/* Destination options header */
+/* XXX should we pad it to force alignment on an 8-byte boundary? */
+struct ip6_dest {
+	u_int8_t ip6d_nxt;	/* next header */
+	u_int8_t ip6d_len;	/* length in units of 8 octets */
+	/* followed by options */
+} __attribute__((__packed__));
+
+/* Option types and related macros */
+#define IP6OPT_PAD1		0x00	/* 00 0 00000 */
+#define IP6OPT_PADN		0x01	/* 00 0 00001 */
+#define IP6OPT_JUMBO		0xC2	/* 11 0 00010 = 194 */
+#define IP6OPT_NSAP_ADDR	0xC3	/* 11 0 00011 */
+#define IP6OPT_TUNNEL_LIMIT	0x04	/* 00 0 00100 */
+#ifndef _KERNEL
+#define IP6OPT_RTALERT		0x05	/* 00 0 00101 (KAME definition) */
+#endif
+#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 */
+#define IP6OPT_RTALERT_ACTNET	2 	/* contains an Active Networks msg */
+#define IP6OPT_MINLEN		2
+
+#define IP6OPT_HOME_ADDRESS	0xc9	/* 11 0 01001 */
+#define IP6OPT_EID		0x8a	/* 10 0 01010 */
+
+#define IP6OPT_TYPE(o)		((o) & 0xC0)
+#define IP6OPT_TYPE_SKIP	0x00
+#define IP6OPT_TYPE_DISCARD	0x40
+#define IP6OPT_TYPE_FORCEICMP	0x80
+#define IP6OPT_TYPE_ICMP	0xC0
+
+#define IP6OPT_MUTABLE		0x20
+
+/* IPv6 options: common part */
+struct ip6_opt {
+	u_int8_t ip6o_type;
+	u_int8_t ip6o_len;
+} __attribute__((__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];
+} __attribute__((__packed__));
+#define IP6OPT_JUMBO_LEN 6
+
+/* 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
+
+/* Home Address Option */
+struct ip6_opt_home_address {
+	u_int8_t ip6oh_type;
+	u_int8_t ip6oh_len;
+	u_int8_t ip6oh_addr[16];/* Home Address */
+	/* followed by sub-options */
+} __attribute__((__packed__));
+
+/* Routing header */
+struct ip6_rthdr {
+	u_int8_t  ip6r_nxt;	/* next header */
+	u_int8_t  ip6r_len;	/* length in units of 8 octets */
+	u_int8_t  ip6r_type;	/* routing type */
+	u_int8_t  ip6r_segleft;	/* segments left */
+	/* 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_int32_t  ip6r0_reserved;	/* reserved field */
+	/* followed by up to 127 struct in6_addr */
+} __attribute__((__packed__));
+
+/* Type 2 Routing header for Mobile IPv6 */
+struct ip6_rthdr2 {
+	u_int8_t  ip6r2_nxt;		/* next header */
+	u_int8_t  ip6r2_len;		/* always 2 */
+	u_int8_t  ip6r2_type;		/* always 2 */
+	u_int8_t  ip6r2_segleft;	/* 0 or 1 */
+	u_int32_t  ip6r2_reserved;	/* reserved field */
+	/* followed by one struct in6_addr */
+} __attribute__((__packed__));
+
+/* Fragment header */
+struct ip6_frag {
+	u_int8_t  ip6f_nxt;		/* next header */
+	u_int8_t  ip6f_reserved;	/* reserved field */
+	u_int16_t ip6f_offlg;		/* offset, reserved, and flag */
+	u_int32_t ip6f_ident;		/* identification */
+} __attribute__((__packed__));
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define IP6F_OFF_MASK		0xfff8	/* mask out offset from _offlg */
+#define IP6F_RESERVED_MASK	0x0006	/* reserved bits in ip6f_offlg */
+#define IP6F_MORE_FRAG		0x0001	/* more-fragments flag */
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+#define IP6F_OFF_MASK		0xf8ff	/* mask out offset from _offlg */
+#define IP6F_RESERVED_MASK	0x0600	/* reserved bits in ip6f_offlg */
+#define IP6F_MORE_FRAG		0x0100	/* more-fragments flag */
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+/*
+ * Internet implementation parameters.
+ */
+#define IPV6_MAXHLIM	255	/* maximum hoplimit */
+#define IPV6_DEFHLIM	64	/* default hlim */
+#define IPV6_FRAGTTL	120	/* ttl for fragment packets, in slowtimo tick */
+#define IPV6_HLIMDEC	1	/* subtracted when forwarding */
+
+#define IPV6_MMTU	1280	/* minimal MTU and reassembly. 1024 + 256 */
+#define IPV6_MAXPACKET	65535	/* ip6 max packet size without Jumbo payload*/
+#define IPV6_MAXOPTHDR	2048	/* max option header size, 256 64-bit words */
+
+#ifdef _KERNEL
+/*
+ * IP6_EXTHDR_CHECK ensures that region between the IP6 header and the
+ * target header (including IPv6 itself, extension headers and
+ * TCP/UDP/ICMP6 headers) are continuous. KAME requires drivers
+ * to store incoming data into one internal mbuf or one or more external
+ * mbufs(never into two or more internal mbufs). Thus, the third case is
+ * supposed to never be matched but is prepared just in case.
+ */
+
+#define IP6_EXTHDR_CHECK(m, off, hlen, ret)				\
+do {									\
+    if ((m)->m_next != NULL) {						\
+	if ((m)->m_len < (off) + (hlen)) {				\
+		ip6stat.ip6s_exthdrtoolong++;				\
+		m_freem(m);						\
+		return ret;						\
+	}								\
+    } else {								\
+	if ((m)->m_len < (off) + (hlen)) {				\
+		ip6stat.ip6s_tooshort++;				\
+		in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated);	\
+		m_freem(m);						\
+		return ret;						\
+	}								\
+    }									\
+} while (/*CONSTCOND*/ 0)
+
+#ifdef PULLDOWN_STAT
+#define IP6_EXTHDR_STAT(x)	x
+#else
+#define IP6_EXTHDR_STAT(x)
+#endif
+
+/*
+ * IP6_EXTHDR_GET ensures that intermediate protocol header (from "off" to
+ * "len") is located in single mbuf, on contiguous memory region.
+ * The pointer to the region will be returned to pointer variable "val",
+ * with type "typ".
+ * IP6_EXTHDR_GET0 does the same, except that it aligns the structure at the
+ * very top of mbuf.  GET0 is likely to make memory copy than GET.
+ */
+#define IP6_EXTHDR_GET(val, typ, m, off, len) \
+do {									\
+	struct mbuf *t;							\
+	int tmp;							\
+	IP6_EXTHDR_STAT(mbstat.m_exthdrget++);				\
+	if ((m)->m_len >= (off) + (len))				\
+		(val) = (typ)(mtod((m), caddr_t) + (off));		\
+	else {								\
+		t = m_pulldown((m), (off), (len), &tmp);		\
+		if (t) {						\
+			if (t->m_len < tmp + (len))			\
+				panic("m_pulldown malfunction");	\
+			(val) = (typ)(mtod(t, caddr_t) + tmp);		\
+		} else {						\
+			(val) = (typ)NULL;				\
+			(m) = NULL;					\
+		}							\
+	}								\
+} while (/*CONSTCOND*/ 0)
+
+#define IP6_EXTHDR_GET0(val, typ, m, off, len) \
+do {									\
+	struct mbuf *t;							\
+	IP6_EXTHDR_STAT(mbstat.m_exthdrget0++);				\
+	if ((off) == 0 && (m)->m_len >= len)				\
+		(val) = (typ)mtod((m), caddr_t);			\
+	else {								\
+		t = m_pulldown((m), (off), (len), NULL);		\
+		if (t) {						\
+			if (t->m_len < (len))				\
+				panic("m_pulldown malfunction");	\
+			(val) = (typ)mtod(t, caddr_t);			\
+		} else {						\
+			(val) = (typ)NULL;				\
+			(m) = NULL;					\
+		}							\
+	}								\
+} while (/*CONSTCOND*/ 0)
+#endif /*_KERNEL*/
+
+#endif /* not _NETINET_IP6_H_ */
Index: netselect.c
===================================================================
--- netselect.c	(revision 26675)
+++ netselect.c	(working copy)
@@ -59,6 +59,8 @@
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <netinet/ip_icmp.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
 #include <netinet/udp.h>
 #include <arpa/inet.h>
 #include <netdb.h>
@@ -100,7 +102,26 @@
     struct timeval tv;		/* time packet left */
 }__attribute__((packed)) IPacket;
 
+/*
+ * format of a (headerless udp) probe packet.
+ */
+typedef struct
+{
+    struct udphdr udp;
+    u_char seq;			/* sequence number of this packet */
+    u_char ttl;			/* ttl packet left with */
+    struct timeval tv;		/* time packet left */
+} OPacket6;
 
+/*
+ * format of a (icmpv6) probe packet.
+ */
+typedef struct
+{
+    struct icmp6_hdr icmp6;	/* icmp6 contains seq (id) and ttl (seq)
+                                 * fields already */
+    struct timeval tv;		/* time packet left */
+}__attribute__((packed)) I6Packet;
 
 /* 
  * currently-known information about a host
@@ -114,7 +135,7 @@
     char *dnsname;		/* DNS name of the host, matches hostname
                                  * unless a host resolves to multiple IP
                                  * addresses */
-    struct sockaddr_in addr;	/* remote address */
+    struct sockaddr_storage addr;	/* remote address */
 
     int invalid;		/* !=0 if we discard this host */
     int done;			/* !=0 if host testing is done */
@@ -132,23 +153,30 @@
 
 /* prototypes for functions in this file */
 static HostData *add_host(HostData *host, int *numhosts,
-			  char *hostname, struct sockaddr_in *addr,
+			  char *hostname, struct sockaddr *addr,
                           char *dnsname, int max_ttl);
 static char *un_url(char *orig);
-static char *fix_url(char *orig, char *hostname);
+static char *fix_url(char *orig, struct sockaddr *addr);
 static HostData *name_resolver(int *numhosts, int numnames, char **names,
 			       int max_ttl);
 
 static void send_probe(int seq, int ttl, OPacket *op,
 		       HostData *host);
+static void send_probe6(int seq, int ttl, OPacket6 *op,
+		       HostData *host);
 static void send_icmp_probe(int seq, int ttl, IPacket *op,
 		       HostData *host);
+static void send_icmp6_probe(int seq, int ttl, I6Packet *op,
+		       HostData *host);
 static time_t deltaT(struct timeval *t1p, struct timeval *t2p);
 static HostData *wait_for_reply(HostData *hosts, int numhosts,
-				       int sock, int msec_timeout);
+				       int msec_timeout);
 static HostData *packet_ok(HostData *hosts, int numhosts,
 				  u_char *buf, int cc,
 				  struct sockaddr_in *from);
+static HostData *packet6_ok(HostData *hosts, int numhosts,
+				  u_char *buf, int cc,
+				  struct sockaddr_in6 *from);
 static int choose_ttl(HostData *host);
 static void usage();
 static int results(HostData *hosts, int numhosts, int num_score, int use_dns);
@@ -159,7 +187,9 @@
 
 /* global variables */
 static int rcvsock;		/* receive (icmp) socket file descriptor */
+static int rcvsock6;		/* IPv6 receive (icmp) socket file descriptor */
 static int sndsock;		/* send (udp) socket file descriptor */
+static int sndsock6;		/* IPv6 send socket file descriptor */
 
 static int verbose = 0;
 static u_short ident;
@@ -167,6 +197,8 @@
 
 static int validhosts;
 
+static int addr_fam = AF_UNSPEC;
+
 int main(int argc, char **argv)
 {
     extern char *optarg;
@@ -173,15 +205,18 @@
     extern int optind;
     int hostcount, startcount, endcount = 0, sent_one, lag, min_lag = 100;
     int ch, seq, ttl, max_ttl = 30, num_score = 1;
-    int use_icmp, use_dns, found = 0;
+    int use_icmp = 0, use_dns = 0, found = 0;
+    int sock_v6_only = 1;
     unsigned int min_tries = 10;
     struct timeval now;
     struct timezone tz;
     OPacket udppacket;          /* last output (udp) packet */
-    IPacket icmppacket;          /* last output (udp) packet */
+    IPacket icmppacket;         /* last output (icmp) packet */
+    OPacket6 udppacket6;        /* last output (headerless udp) packet */
+    I6Packet icmp6packet;       /* last output (icmp6) packet */
     
     HostData *host, *hosts;
-    int numhosts, delay, must_continue, count;
+    int numhosts, delay, must_continue, count, port_unreachable, other_unreachable;
     int socket_errno = 0;
 
     /* we might have cap_net_raw on linux, instead print a tip if and when
@@ -190,8 +225,9 @@
         fprintf (stderr, "%s: root privileges required\n", argv[0]);
     */
 
-    if ((rcvsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0
-     || (sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW )) < 0)
+    if ((rcvsock  = socket(AF_INET,  SOCK_RAW, IPPROTO_ICMP)) < 0
+     || (sndsock  = socket(AF_INET,  SOCK_RAW, IPPROTO_RAW )) < 0
+     || (rcvsock6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
     {
 	/* Capture errno so that command-line options can be parsed.
 	   We delay reporting an error until this has happened. */
@@ -206,7 +242,7 @@
 #ifdef __EMX__
     _response(&argc,&argv);
 #endif
-    while ((ch = getopt(argc, argv, "s:t:m:IDv?")) != EOF)
+    while ((ch = getopt(argc, argv, "s:t:m:IDv?46")) != EOF)
     {
 	switch (ch)
 	{
@@ -240,6 +276,14 @@
             use_dns = 1;
 	    break;
 
+	case '4':
+            addr_fam = AF_INET;
+	    break;
+
+	case '6':
+            addr_fam = AF_INET6;
+	    break;
+
 	case 'v':
 	    verbose++;
 	    break;
@@ -272,6 +316,19 @@
 	return 5;
     }
 
+    if (addr_fam == AF_INET)
+    {
+	close(rcvsock6);
+	rcvsock6 = -1;
+    }
+    else if (addr_fam == AF_INET6)
+    {
+	close(rcvsock);
+	rcvsock = -1;
+    }
+
+    ident = (getpid() & 0xffff) | 0x8000;
+
     if ( use_icmp )  
     {
         memset(&icmppacket, 0, sizeof(IPacket));
@@ -278,6 +335,8 @@
         icmppacket.ip.ip_tos = 0;
         icmppacket.ip.ip_v = IPVERSION;
         icmppacket.ip.ip_id = 0;
+
+        sndsock6 = rcvsock6;
     } 
     else 
     {
@@ -285,10 +344,41 @@
         udppacket.ip.ip_tos = 0;
         udppacket.ip.ip_v = IPVERSION;
         udppacket.ip.ip_id = 0;
+
+	if (addr_fam != AF_INET)
+	{
+	    struct sockaddr_in6 source;
+
+	    if ((sndsock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+	    {
+		perror("netselect: socket");
+		if (errno == EPERM) {
+		    fprintf(stderr, "You should be root to run netselect.\n");
+		    return 6;
+		}
+		return 5;
+	    }
+
+	    if (setsockopt(sndsock6, IPPROTO_IPV6, IPV6_V6ONLY,
+			   &sock_v6_only, sizeof(int)) < 0)
+	    {
+		perror("setsockopt with IPV6_V6ONLY");
+		return 1;
+	    }
+
+	    memset(&source, 0, sizeof(struct sockaddr_in6));
+	    source.sin6_family = AF_INET6;
+	    source.sin6_port = htons(ident);
+	    memcpy(&source.sin6_addr, &in6addr_any, sizeof(struct in6_addr));
+
+	    if (bind(sndsock6, (struct sockaddr *)&source, sizeof(source)) < 0)
+	    {
+		perror("bind");
+		return 1;
+	    }
+	}
     }
 
-    ident = (getpid() & 0xffff) | 0x8000;
-    
     validhosts = numhosts = 0;
     
     hosts = name_resolver(&numhosts, argc, argv, max_ttl);
@@ -350,12 +440,26 @@
 		    host->retries++;
 		    
 		    host->num_out++;
-                    if ( use_icmp ) 
-                        send_icmp_probe(host->seq, ttl, &icmppacket, host);
-                    else
-                        send_probe(host->seq, ttl, &udppacket, host);
-		    endcount = hostcount;
-		    sent_one = 1;
+		    if (host->addr.ss_family == AF_INET
+		     || host->addr.ss_family == AF_INET6)
+		    {
+			if (host->addr.ss_family == AF_INET)
+			{
+			    if ( use_icmp ) 
+				send_icmp_probe(host->seq, ttl, &icmppacket, host);
+			    else
+				send_probe(host->seq, ttl, &udppacket, host);
+			}
+			else
+			{
+			    if ( use_icmp ) 
+				send_icmp6_probe(host->seq, ttl, &icmp6packet, host);
+			    else
+				send_probe6(host->seq, ttl, &udppacket6, host);
+			}
+			endcount = hostcount;
+			sent_one = 1;
+		    }
 		}
 	    }
 	    else if (host->hops_less_than - host->hops_more_than > 2)
@@ -374,7 +478,7 @@
 	} while (hostcount != startcount);
 	
 	delay = min_lag/2; /* transmit time must be <= min_lag / 2 */
-	if ((host = wait_for_reply(hosts, numhosts, rcvsock, delay)) != NULL)
+	if ((host = wait_for_reply(hosts, numhosts, delay)) != NULL)
 	{
 	    gettimeofday(&now, &tz);
 	    delay = 0;
@@ -383,10 +487,11 @@
 		fprintf(stderr, "%-35s  %5u ms  %3d hops - ", host->shortname,
 		       (unsigned)deltaT(&host->send_time, &now),
 		       choose_ttl(host));
-	    
-	    switch (host->code - 1)
+
+	    port_unreachable = 0;
+	    other_unreachable = 0;
+	    if (host->code == -1)
 	    {
-	    case -2:
 		if (verbose >= 3)
 		    fprintf(stderr, "HIGHER");
 		else if (verbose >= 1)
@@ -396,9 +501,51 @@
 		host->hops_more_than = choose_ttl(host);
 		host->retries = 0;
 		host->num_out--;
-		break;
-		
-	    case ICMP_UNREACH_PORT:
+	    }
+	    else if (host->addr.ss_family == AF_INET)
+	    {
+		switch (host->code - 1)
+		{
+		case ICMP_UNREACH_PORT:
+		    port_unreachable = 1;
+		    break;
+
+		case ICMP_UNREACH_NET:
+		case ICMP_UNREACH_HOST:
+		case ICMP_UNREACH_PROTOCOL:
+		case ICMP_UNREACH_NEEDFRAG:
+		case ICMP_UNREACH_SRCFAIL:
+		case ICMP_UNREACH_FILTER_PROHIB:
+		case ICMP_UNREACH_NET_PROHIB:	/* misuse */
+		case ICMP_UNREACH_HOST_PROHIB:
+		case ICMP_UNREACH_NET_UNKNOWN:
+		case ICMP_UNREACH_HOST_UNKNOWN:
+		case ICMP_UNREACH_ISOLATED:
+		case ICMP_UNREACH_TOSNET:
+		case ICMP_UNREACH_TOSHOST:
+		    other_unreachable = 1;
+		    break;
+		}
+	    }
+	    else if (host->addr.ss_family == AF_INET6)
+	    {
+		switch (host->code - 1)
+		{
+		case ICMP6_DST_UNREACH_NOPORT:
+		    port_unreachable = 1;
+		    break;
+
+		case ICMP6_DST_UNREACH_NOROUTE:
+		case ICMP6_DST_UNREACH_ADMIN:
+		case ICMP6_DST_UNREACH_BEYONDSCOPE:
+		case ICMP6_DST_UNREACH_ADDR:
+		    other_unreachable = 1;
+		    break;
+		}
+	    }
+
+	    if (port_unreachable)
+	    {
 		if (verbose >= 3)
 		    fprintf(stderr, "OK");
 		else if (verbose >= 1)
@@ -414,27 +561,14 @@
 			fprintf(stderr, "\nmin_lag is now %d", min_lag);
 		}
 		host->total_lag += lag;
-		break;
-
-	    case ICMP_UNREACH_NET:
-	    case ICMP_UNREACH_HOST:
-	    case ICMP_UNREACH_PROTOCOL:
-	    case ICMP_UNREACH_NEEDFRAG:
-	    case ICMP_UNREACH_SRCFAIL:
-	    case ICMP_UNREACH_FILTER_PROHIB:
-	    case ICMP_UNREACH_NET_PROHIB:	/* misuse */
-	    case ICMP_UNREACH_HOST_PROHIB:
-	    case ICMP_UNREACH_NET_UNKNOWN:
-	    case ICMP_UNREACH_HOST_UNKNOWN:
-	    case ICMP_UNREACH_ISOLATED:
-	    case ICMP_UNREACH_TOSNET:
-	    case ICMP_UNREACH_TOSHOST:
+	    }
+	    else if (other_unreachable)
+	    {
 		if (verbose >= 3)
 		    fprintf(stderr, "unreachable! (blocking probes?)\n");
 		if (!host->invalid)
 		    validhosts--;
 		host->invalid = 1;
-		break;
 	    }
 
 	    if (verbose >= 3)
@@ -463,6 +597,10 @@
     return 0;
 }
 
+static inline int in6_addr_cmp(struct in6_addr *a, struct in6_addr *b)
+{
+    return memcmp(&a->s6_addr, &b->s6_addr, 16);
+}
 
 /* 
  * when the newly-created objects are freed, we try to free(hostname)...
@@ -470,7 +608,7 @@
  * function!
  */
 static HostData *add_host(HostData *hosts, int *numhosts,
-			  char *hostname, struct sockaddr_in *addr,
+			  char *hostname, struct sockaddr *addr,
 			  char *dnsname, int max_ttl)
 {
     HostData *host;
@@ -477,14 +615,51 @@
     
     if (addr)
     {
-      int hcount;
-      for (hcount = 0, host = hosts; hcount < *numhosts; hcount++, host++)
-	if (host->addr.sin_addr.s_addr == addr->sin_addr.s_addr)
+	int hcount;
+	sa_family_t family = ((struct sockaddr_storage *)addr)->ss_family;
+	struct in_addr *addr4, *haddr4;
+	struct in6_addr *addr6, *haddr6;
+	
+	
+	if ((family != AF_INET  && family   != AF_INET6)
+	 || (family == AF_INET  && addr_fam == AF_INET6)
+	 || (family == AF_INET6 && addr_fam == AF_INET ))
+        {
+	    if (verbose >= 1)
+		fprintf(stderr, "\nUnsupported address family %hu for host %s address\n",
+			family, hostname);
+	    return hosts;
+        }
+
+	if (family == AF_INET)
+	    addr4 = &((struct sockaddr_in  *)addr)->sin_addr;
+	else
+	    addr6 = &((struct sockaddr_in6 *)addr)->sin6_addr;
+	
+	for (hcount = 0, host = hosts; hcount < *numhosts; hcount++, host++)
 	{
-	  if (verbose >= 1)
-	    fprintf(stderr, "\nDuplicate address %s (%s, %s); keeping only under first name.\n",
-		    inet_ntoa(addr->sin_addr), host->hostname, hostname);
-	  return hosts;
+	    if (host->invalid || host->addr.ss_family != family)
+		continue;
+	    
+	    if (family == AF_INET)
+		haddr4 = &((struct sockaddr_in  *)&host->addr)->sin_addr;
+	    else
+		haddr6 = &((struct sockaddr_in6 *)&host->addr)->sin6_addr;
+
+	    if ((family == AF_INET  && haddr4->s_addr == addr4->s_addr)
+	     || (family == AF_INET6 && in6_addr_cmp(haddr6, addr6) == 0))
+	    {
+		if (verbose >= 1)
+		{
+		    char txt[INET6_ADDRSTRLEN];
+		    fprintf(stderr, "\nDuplicate address %s (%s, %s); keeping only under first name.\n",
+			    inet_ntop(family,
+				      family == AF_INET ? (void *)addr4 : (void *)addr6,
+				      txt, sizeof(txt)),
+			    host->hostname, hostname);
+		}
+		return hosts;
+	    }
 	}
     }
     
@@ -502,7 +677,7 @@
     host->dnsname = dnsname;
     host->shortname = un_url(hostname);
     if (addr)
-	memcpy(&host->addr, addr, sizeof(*addr));
+	memcpy(&host->addr, addr, sizeof(struct sockaddr_storage));
     else
 	host->invalid = 1;
     host->hops_less_than = max_ttl;
@@ -513,62 +688,132 @@
 
 static char *un_url(char *orig)
 {
-    char *sptr, *eptr, *newbuf;
+    char *sptr, *eptr = NULL, *newbuf;
     
     if ((sptr = strstr(orig, "://")) != NULL)
     {
 	/* URL formatted, like: http://hostname:port/dir/file */
 	sptr += 3; /* skip :// */
-	eptr = strchr(sptr, ':');
+	if (*sptr == '[') /* v6 literal address */
+	{
+	    eptr = strchr(sptr, ']');
+	    if (eptr)
+		++sptr;
+	}
+	if (!eptr) eptr = strchr(sptr, ':');
 	if (!eptr) eptr = strchr(sptr, '/');
 	if (!eptr) eptr = strchr(sptr, 0);
-	
+    }
+    else
+    {
+	if (*orig == '[')
+	{
+	    /* quoted v6 literal address in non-URL format */
+	    eptr = strchr(orig, ']');
+	    if (eptr)
+		sptr = orig + 1;
+	}
+
+	if (!sptr && (eptr = strchr(orig, ':')) != NULL)
+	{
+	    /* Could be an IPv6 address */
+	    struct sockaddr_storage ss;
+	    if (inet_pton(AF_INET6, orig, &ss) != 1)
+	    {
+		/* FTP formatted, like: ftp.debian.org:/debian/foo */
+		sptr = orig;
+	    }
+	}
+    }
+
+    if (sptr)
+    {
 	newbuf = (char *)malloc(eptr-sptr+1);
 	strncpy(newbuf, sptr, eptr-sptr);
 	newbuf[eptr-sptr] = 0;
 	return newbuf;
     }
-    else if ((sptr = strchr(orig, ':')) != NULL)
-    {
-	/* FTP formatted, like: ftp.debian.org:/debian/foo */
-	newbuf = (char *)malloc(sptr-orig+1);
-	strncpy(newbuf, orig, sptr-orig);
-	newbuf[sptr-orig] = 0;
-	return newbuf;
-    }
     else /* just plain */
 	return strdup(orig);
 }
 
+static char *fix_url(char *orig, struct sockaddr *addr)
+{
+    char *pree = NULL, *posts = NULL;
+    char addrstr[INET6_ADDRSTRLEN + 2];
+    void *src;
 
-static char *fix_url(char *orig, char *hostname)
-{
-    char *sptr, *eptr, *newbuf;
-    
-    if ((sptr = strstr(orig, "://")) != NULL)
+    if ((pree = strstr(orig, "://")) != NULL)
     {
 	/* URL formatted, like: http://hostname:port/dir/file */
-	sptr += 3; /* skip :// */
-	eptr = strchr(sptr, ':');
-	if (!eptr) eptr = strchr(sptr, '/');
-	if (!eptr) eptr = strchr(sptr, 0);
+	pree += 3; /* skip :// */
+	if (*pree == '[') /* v6 literal address */
+	{
+	    posts = strchr(pree, ']');
+	    if (posts)
+		++posts;
+	}
+	if (!posts) posts = strchr(pree, ':');
+	if (!posts) posts = strchr(pree, '/');
+	if (!posts) posts = strchr(pree, 0);
+    }
+    else
+    {
+	pree = orig;
+	if (*pree == '[')
+	{
+	    /* quoted v6 literal address in non-URL format */
+	    posts = strchr(pree, ']');
+	    if (posts)
+		++posts;
+	}
 	
-	newbuf = (char *)malloc(strlen(orig) + strlen(hostname) + 1);
-	strncpy(newbuf, orig, sptr-orig);
-	strcpy(newbuf+(sptr-orig), hostname);
-	strcat(newbuf, eptr);
-	return newbuf;
+	if (!posts)
+	{
+	    struct sockaddr_storage ss;
+	    if (inet_pton(AF_INET6, orig, &ss) != 1)
+	    {
+		/* FTP formatted, like: ftp.debian.org:/debian/foo */
+		posts = strchr(orig, ':');
+	    }
+	}
     }
-    else if ((sptr = strchr(orig, ':')) != NULL)
+
+    if (addr->sa_family == AF_INET)
+	src = &((struct sockaddr_in  *)addr)->sin_addr;
+    else
+	src = &((struct sockaddr_in6 *)addr)->sin6_addr;
+
+    inet_ntop(addr->sa_family, src, addrstr, sizeof(addrstr));
+
+    if (posts)
     {
-	/* FTP formatted, like: ftp.debian.org:/debian/foo */
-	newbuf = (char *)malloc(strlen(orig) + strlen(hostname) + 1);
-	strcpy(newbuf, hostname);
-	strcat(newbuf, sptr);
+	char *newbuf;
+	size_t addrlen;
+	size_t prelen = pree - orig;
+	size_t postlen = strlen(posts);
+
+	/* We want to quote a v6 address in this case */
+	if (addr->sa_family == AF_INET6)
+	{
+	    char quoted_addr[sizeof(addrstr)];
+	    sprintf(quoted_addr, "[%s]", addrstr);
+	    strcpy(addrstr, quoted_addr);
+	}
+
+	addrlen = strlen(addrstr);
+
+	newbuf = (char *)malloc(prelen + addrlen + postlen + 1);
+
+	if (prelen > 0)
+	    strncpy(newbuf, orig, prelen);
+	strncpy(newbuf + prelen, addrstr, addrlen);
+	strncpy(newbuf + prelen + addrlen, posts, postlen);
+
 	return newbuf;
     }
     else /* just plain */
-	return strdup(hostname);
+	return strdup(addrstr);
 }
 
 
@@ -582,7 +827,7 @@
     struct {
 	char *hostname;
 	int broken, multi;
-	struct sockaddr_in addr;
+	struct sockaddr_storage addr;
     } result;
     
     HostData *hosts = NULL;
@@ -591,8 +836,9 @@
     time_t start = time(NULL);
     fd_set rfd, wfd, efd;
     struct timeval tv;
-    struct hostent *hp;
+    struct addrinfo *hp, hints;
     pid_t pid;
+    int err;
     
     if (pipe(pipes))
     {
@@ -605,6 +851,10 @@
     setmode(pipes[0],O_BINARY);
     setmode(pipes[1],O_BINARY);
 #endif
+
+    memset(&hints, 0, sizeof(struct addrinfo));
+    hints.ai_family = addr_fam;
+    hints.ai_flags  = AI_ADDRCONFIG;
     
     while (time(NULL) < start + 20)
     {
@@ -628,45 +878,52 @@
 		result.multi = result.broken = 0;
 		
 		/* child task -- actually do name lookup */
-		result.addr.sin_family = AF_INET;
-		result.addr.sin_addr.s_addr = inet_addr(names[count]);
+
+		/* try simple IPv4 dotted-quad conversion */
+		if (addr_fam != AF_INET6)
+		{
+		    struct sockaddr_in *addr4 = (struct sockaddr_in *) &result.addr;
+		    addr4->sin_family = AF_INET;
+		    addr4->sin_addr.s_addr = inet_addr(names[count]);
 		
-		if (result.addr.sin_addr.s_addr != INADDR_NONE)
-		{
-		    write(pipes[1], &result, sizeof(result));
+		    if (addr4->sin_addr.s_addr != INADDR_NONE)
+		    {
+			write(pipes[1], &result, sizeof(result));
+			/* Use this as a flag to not do a lookup */
+			result.multi = 1;
+		    }
 		}
-		else
+
+		if (result.multi == 0);
 		{
 		    /* must actually do the name lookup */
 		    char *simplename = un_url(result.hostname);
-		    hp = gethostbyname(simplename);
+		    err = getaddrinfo(simplename, NULL, &hints, &hp);
 		    free(simplename);
 		    
-		    if (hp)
+		    if (!err)
 		    {
-			if (hp->h_addrtype != AF_INET 
-			    || hp->h_length != sizeof(struct in_addr))
+			struct addrinfo *ptr;
+			int already_seen_one = 0;
+
+			result.broken = 0;
+			for (ptr = hp; ptr; ptr = ptr->ai_next)
 			{
-			    result.broken = 1;
+			    if ((ptr->ai_family != AF_INET  && ptr->ai_family != AF_INET6)
+			     || (ptr->ai_family == AF_INET  && addr_fam == AF_INET6)
+			     || (ptr->ai_family == AF_INET6 && addr_fam == AF_INET))
+				continue;
+
+			    if (already_seen_one)
+				result.multi = 1;
+
+			    memcpy(&result.addr, ptr->ai_addr, ptr->ai_addrlen);
 			    write(pipes[1], &result, sizeof(result));
+			    if (!already_seen_one)
+				already_seen_one = 1;
 			}
-			else
-			{
-			    char **ptr = hp->h_addr_list;
-			    
-			    result.broken = 0;
-			    if (ptr[1])
-				result.multi = 1;
-			    result.addr.sin_family = AF_INET;
-			    
-			    while (*ptr)
-			    {
-				memcpy(&result.addr.sin_addr,
-				       *ptr, hp->h_length);
-				write(pipes[1], &result, sizeof(result));
-				ptr++;
-			    }
-			}
+
+			freeaddrinfo(hp);
 		    }
 		    else
 		    {
@@ -747,12 +1004,12 @@
 		    
 		    if (result.multi)
 			newhostname = fix_url(result.hostname,
-					      inet_ntoa(result.addr.sin_addr));
+					      (struct sockaddr *)&result.addr);
 		    else
 			newhostname = strdup(result.hostname);
 		    
 		    hosts = add_host(hosts, numhosts, newhostname,
-				     &result.addr, dnsname, max_ttl);
+				     (struct sockaddr *)&result.addr, dnsname, max_ttl);
 		}
 	    }
 	}
@@ -779,6 +1036,35 @@
     return hosts;
 }
 
+static void do_sendto(int sockfd, const void *buf, size_t len, HostData *host)
+{
+    int i;
+    i = sendto(sockfd, buf, len, 0, (struct sockaddr *)&host->addr,
+	       sizeof(struct sockaddr_storage));
+    if (i < 0 || i != len)
+    {
+	if (i < 0)
+	{
+	    switch (errno)
+	    {
+	    case ENETDOWN:
+	    case ENETUNREACH:
+	    case EHOSTDOWN:
+	    case EHOSTUNREACH:
+		if (verbose >= 3)
+		    fprintf(stderr, "unreachable or down!\n");
+		if (!host->invalid)
+		    validhosts--;
+		host->invalid = 1;
+		break;
+		
+	    default:
+		perror("sendto");
+	    }
+	}
+	fflush(stdout);
+    }
+}
 
 static void send_probe(int seq, int ttl, OPacket *op, HostData *host)
 {
@@ -785,9 +1071,8 @@
     struct ip *ip = &op->ip;
     struct udphdr *up = &op->udp;
     struct timezone tz;
-    int i;
 
-    op->ip.ip_dst = host->addr.sin_addr;
+    op->ip.ip_dst = ((struct sockaddr_in *)&host->addr)->sin_addr;
     op->seq = seq;
     op->ttl = ttl;
     gettimeofday(&op->tv, &tz);
@@ -808,31 +1093,30 @@
     if (verbose >= 4)
     	fprintf(stderr, "%-35s(UDP)>>\n", host->shortname);
 
-    i = sendto(sndsock, op, sizeof(OPacket), 0,
-	       (struct sockaddr *)&host->addr, sizeof(host->addr));
-    if (i < 0 || i != sizeof(OPacket))
+    do_sendto(sndsock, op, sizeof(OPacket), host);
+}
+
+static void send_probe6(int seq, int ttl, OPacket6 *op, HostData *host)
+{
+    struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&host->addr;
+    struct timezone tz;
+
+    op->seq = seq;
+    op->ttl = ttl;
+    gettimeofday(&op->tv, &tz);
+
+    addr->sin6_port = htons(port + seq);
+    
+    if (verbose >= 4)
+    	fprintf(stderr, "%-35s(UDP6)>>\n", host->shortname);
+
+    if (setsockopt(sndsock6, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0)
     {
-	if (i < 0)
-	{
-	    switch (errno)
-	    {
-	    case ENETDOWN:
-	    case ENETUNREACH:
-	    case EHOSTDOWN:
-	    case EHOSTUNREACH:
-		if (verbose >= 3)
-		    fprintf(stderr, "unreachable or down!\n");
-		if (!host->invalid)
-		    validhosts--;
-		host->invalid = 1;
-		break;
-		
-	    default:
-		perror("sendto");
-	    }
-	}
-	fflush(stdout);
+	perror("setsockopt with IPV6_UNICAST_HOPS");
+	return;
     }
+
+    do_sendto(sndsock6, op, sizeof(OPacket6), host);
 }
 
 uint16_t
@@ -852,9 +1136,8 @@
     struct ip *ip = &op->ip;
     struct icmp *icmp = &op->icmp;
     struct timezone tz;
-    int i;
 
-    op->ip.ip_dst = host->addr.sin_addr;
+    op->ip.ip_dst = ((struct sockaddr_in *)&host->addr)->sin_addr;
     op->seq = seq;
     op->ttl = ttl;
     gettimeofday(&op->tv, &tz);
@@ -879,31 +1162,34 @@
     if (verbose >= 5)
         fprintf(stderr, "ICMP sequence: %i, identifier: %i\n", icmp->icmp_seq, icmp->icmp_id);
 
-    i = sendto(sndsock, op, sizeof(IPacket), 0,
-	       (struct sockaddr *)&host->addr, sizeof(host->addr));
-    if (i < 0 || i != sizeof(IPacket))
+    do_sendto(sndsock, op, sizeof(IPacket), host);
+}
+
+static void send_icmp6_probe(int seq, int ttl, I6Packet *op, HostData *host)
+{
+    struct icmp6_hdr *icmp = &op->icmp6;
+    struct timezone tz;
+
+    gettimeofday(&op->tv, &tz);
+
+    icmp->icmp6_type = ICMP6_ECHO_REQUEST;
+    icmp->icmp6_code = 0;
+    icmp->icmp6_cksum = 0;
+    icmp->icmp6_id = htons (ident);
+    icmp->icmp6_seq = htons (seq);
+
+    if (verbose >= 4)
+    	fprintf(stderr, "%-35s(ICMP6)>>\n", host->shortname);
+    if (verbose >= 5)
+        fprintf(stderr, "ICMP6 sequence: %i, identifier: %i\n", icmp->icmp6_seq, icmp->icmp6_id);
+
+    if (setsockopt(sndsock6, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0)
     {
-	if (i < 0)
-	{
-	    switch (errno)
-	    {
-	    case ENETDOWN:
-	    case ENETUNREACH:
-	    case EHOSTDOWN:
-	    case EHOSTUNREACH:
-		if (verbose >= 3)
-		    fprintf(stderr, "unreachable or down!\n");
-		if (!host->invalid)
-		    validhosts--;
-		host->invalid = 1;
-		break;
-		
-	    default:
-		perror("sendto");
-	    }
-	}
-	fflush(stdout);
+	perror("setsockopt with IPV6_UNICAST_HOPS");
+	return;
     }
+
+    do_sendto(sndsock6, op, sizeof(I6Packet), host);
 }
 
 
@@ -913,27 +1199,59 @@
 	 + (t2p->tv_usec - t1p->tv_usec) / 1000;
 }
 
+static HostData * receive(HostData *hosts, int numhosts, int sock)
+{
+    u_char inpacket[INPACKET_SIZE];
+    struct sockaddr_storage from;
+    int cc = 0;
+    HostData *host = NULL;
 
+#if !defined(__GLIBC__)
+    int fromlen = sizeof(from);
+#else				/* __GLIBC__ */
+    socklen_t fromlen = sizeof(from);
+#endif				/* __GLIBC__ */
+
+    cc = recvfrom(sock, inpacket, INPACKET_SIZE, 0,
+		  (struct sockaddr *) &from, &fromlen);
+    if (cc > 0 &&
+	(addr_fam == AF_UNSPEC || from.ss_family == addr_fam))
+    {
+	if (from.ss_family == AF_INET)
+	    host = packet_ok(hosts, numhosts, inpacket, cc,
+			     (struct sockaddr_in *)&from);
+	else
+	    host = packet6_ok(hosts, numhosts, inpacket, cc,
+			      (struct sockaddr_in6 *)&from);
+    }
+
+    return host;
+}
+
 static HostData *wait_for_reply(HostData *hosts, int numhosts,
-				       int sock, int msec_timeout)
+				       int msec_timeout)
 {
     fd_set fds;
     struct timeval wait, start_time;
     struct timezone tz;
-    u_char inpacket[INPACKET_SIZE];
-    struct sockaddr_in from;
-    int cc = 0;
     time_t msec_used;
     HostData *host;
+    int nfds = -1;
+    int sock;
     
-#if !defined(__GLIBC__)
-    int fromlen = sizeof(from);
-#else				/* __GLIBC__ */
-    socklen_t fromlen = sizeof(from);
-#endif				/* __GLIBC__ */
-
     FD_ZERO(&fds);
-    FD_SET(sock, &fds);
+    if (addr_fam != AF_INET6)
+    {
+	FD_SET(rcvsock,  &fds);
+	nfds = rcvsock;
+    }
+    if (addr_fam != AF_INET)
+    {
+	FD_SET(rcvsock6, &fds);
+	if (nfds < rcvsock6)
+	    nfds = rcvsock6;
+    }
+    ++nfds;
     
     gettimeofday(&start_time, &tz);
 
@@ -947,16 +1265,19 @@
 	wait.tv_usec = (msec_timeout - msec_used) * 1000;
 	wait.tv_sec = 0;
 	
-	if (select(sock + 1, &fds, NULL, NULL, &wait) > 0)
+	if (select(nfds, &fds, NULL, NULL, &wait) > 0)
 	{
-	    cc = recvfrom(rcvsock, inpacket, INPACKET_SIZE, 0,
-			  (struct sockaddr *) &from, &fromlen);
-	    if (cc > 0)
-	    {
-		if ((host = packet_ok(hosts, numhosts, inpacket, cc, &from))
-		            != NULL)
-		    return host;
-	    }
+	    if (addr_fam == AF_INET)
+		sock = rcvsock;
+	    else if (addr_fam == AF_INET6)
+		sock = rcvsock6;
+	    else if (FD_ISSET(rcvsock, &fds))
+		sock = rcvsock;
+	    else
+		sock = rcvsock6;
+
+	    if ((host = receive(hosts, numhosts, sock)) != NULL)
+		return host;
 	}
     }
     
@@ -974,6 +1295,7 @@
     struct icmp *icp;
     HostData *host;
     int hcount;
+    struct sockaddr_in *haddr;
 
     ip = (struct ip *) buf;
     hlen = ip->ip_hl << 2;
@@ -1001,11 +1323,13 @@
 	
 	for (hcount = 0, host = hosts; hcount < numhosts; hcount++, host++)
 	{
-	    if (host->invalid) continue;
+	    if (host->invalid || host->addr.ss_family != AF_INET) continue;
 
+	    haddr = (struct sockaddr_in *)&host->addr;
+
             /* Valid ICMP echo reply packet */
             if ( type == ICMP_ECHOREPLY &&
-                 ip->ip_src.s_addr == host->addr.sin_addr.s_addr &&
+                 ip->ip_src.s_addr == haddr->sin_addr.s_addr &&
                  icp->icmp_id == htons(ident) && 
                  icp->icmp_seq == htons(host->seq) )
             {
@@ -1014,7 +1338,7 @@
             }
             /* Time exceeded reply to an ICMP echo request */
             if ( type == ICMP_TIMXCEED &&
-                 hip->ip_dst.s_addr == host->addr.sin_addr.s_addr &&
+                 hip->ip_dst.s_addr == haddr->sin_addr.s_addr &&
                  hip->ip_id == htons(ident+host->seq) )
             {
 		host->code = -1; 
@@ -1025,7 +1349,7 @@
 	    if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
 		up->uh_sport == htons(ident) &&
 		up->uh_dport == htons(port + host->seq) &&
-		hip->ip_dst.s_addr == host->addr.sin_addr.s_addr)
+		hip->ip_dst.s_addr == haddr->sin_addr.s_addr)
 	    {
 		host->code = (type == ICMP_TIMXCEED ? -1 : code + 1);
 		return host;
@@ -1038,7 +1362,106 @@
     return NULL;
 }
 
+static HostData *packet6_ok(HostData *hosts, int numhosts,
+				  u_char * buf, int cc,
+				  struct sockaddr_in6 *from)
+{
+    u_char type, code;
+    struct icmp6_hdr *icp;
+    HostData *host;
+    int hcount;
 
+    if (cc < sizeof(struct icmp6_hdr))
+	return NULL;
+
+    icp = (struct icmp6_hdr *) buf;
+
+    type = icp->icmp6_type;
+    code = icp->icmp6_code;
+
+    if (verbose >= 5)
+    {
+	char txt[INET6_ADDRSTRLEN];
+        fprintf(stderr, "Received ICMP6 type: %i, code: %i, from %s\n", type, code,
+		inet_ntop(AF_INET6, &from->sin6_addr, txt, sizeof(txt)) );
+    }
+
+    if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
+	|| type == ICMP6_DST_UNREACH || type == ICMP6_ECHO_REPLY )
+    {
+	struct ip6_hdr *hip;
+	int invoke_len;
+
+	hip = (struct ip6_hdr *) (icp + 1);
+
+	if (type != ICMP6_ECHO_REPLY)
+	{
+	    if (cc < (sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)))
+		return NULL;
+
+	    /* Check packet is as big as the following code assumes */
+	    switch (hip->ip6_nxt)
+	    {
+	    case IPPROTO_ICMPV6:
+		invoke_len = sizeof(struct icmp6_hdr);
+		break;
+	    case IPPROTO_UDP:
+		invoke_len = sizeof(struct udphdr);
+		break;
+	    default:
+		return NULL;
+	    };
+
+	    if (cc < (sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr) + invoke_len))
+		return NULL;
+	}
+
+	
+	for (hcount = 0, host = hosts; hcount < numhosts; hcount++, host++)
+	{
+	    struct sockaddr_in6 *haddr;
+
+	    if (host->invalid || host->addr.ss_family != AF_INET6) continue;
+
+	    haddr = (struct sockaddr_in6 *)&host->addr;
+
+            /* Valid ICMP echo reply packet */
+            if ( type == ICMP6_ECHO_REPLY &&
+		 in6_addr_cmp(&from->sin6_addr, &haddr->sin6_addr) == 0 &&
+                 icp->icmp6_id == htons(ident) && 
+                 icp->icmp6_seq == htons(host->seq) )
+            {
+		host->code = ICMP6_DST_UNREACH_NOPORT + 1; /* Behave like if a UDP packet was received even though we used ICMP */
+		return host;
+            }
+            /* Time exceeded reply to an ICMP echo request */
+            if ( type == ICMP6_TIME_EXCEEDED &&
+		 hip->ip6_nxt == IPPROTO_ICMPV6 &&
+                 in6_addr_cmp(&hip->ip6_dst, &haddr->sin6_addr) == 0 &&
+		 ((struct icmp6_hdr *)(hip + 1))->icmp6_id == htons(ident+host->seq) )
+	    {
+		host->code = -1;
+		return host;
+	    }
+	    
+            /* Valid reply to an UDP probe packet */
+	    if ( hip->ip6_nxt == IPPROTO_UDP &&
+		 in6_addr_cmp(&hip->ip6_dst, &haddr->sin6_addr) == 0 &&
+		 ((struct udphdr *)(hip + 1))->uh_sport == htons(ident) &&
+		 ((struct udphdr *)(hip + 1))->uh_dport == htons(port + host->seq) )
+	    {
+		host->code = (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1);
+		return host;
+	    }
+	}
+    }
+
+    if (verbose >= 3)
+        fprintf(stderr, "received an unknown v6 packet!\n"); 
+    return NULL;
+}
+
+
 static int choose_ttl(HostData *host)
 {
     if (!host || host->invalid)
Index: netselect.1
===================================================================
--- netselect.1	(revision 26675)
+++ netselect.1	(working copy)
@@ -17,6 +17,7 @@
 .IR PACKETS\| 
 .RB [ \|\-I ]
 .RB [ \|\-D ]
+.RB [ \|\-4 | \|\-6 ]
 .IR host \ ...
 
 .SH DESCRIPTION
@@ -248,7 +249,14 @@
 to present the final server list using the original DNS name instead
 of the IP address if the DNS name resolves to more than one IP address.
 
+.TP
+.BI \-4
+Restrict address lookups to IPv4 only.
 
+.TP
+.BI \-6
+Restrict address lookups to IPv6 only.
+
 .SH SEE ALSO
 .BR ping (8),
 .BR traceroute (8),

Reply via email to