diff -uN src-current/bin/rcp/rcp.c src-current-ipv6/bin/rcp/rcp.c
--- src-current/bin/rcp/rcp.c
+++ src-current-ipv6/bin/rcp/rcp.c
@@ -66,6 +66,7 @@
 #include <string.h>
 #include <string.h>
 #include <unistd.h>
+#include <resolv.h>
 
 #include "pathnames.h"
 #include "extern.h"
@@ -186,6 +187,14 @@
 		}
 	argc -= optind;
 	argv += optind;
+
+#ifdef RES_USE_INET6
+	(void) res_init();
+#ifdef KERBEROS
+	if (!use_kerberos)	/* kerberos not yet IPv6 */
+#endif
+		_res.options |= RES_USE_INET6;
+#endif
 
 #ifdef KERBEROS
 	if (use_kerberos) {
diff -uN src-current/etc/protocols src-current-ipv6/etc/protocols
--- src-current/etc/protocols
+++ src-current-ipv6/etc/protocols
@@ -7,7 +7,7 @@
 # See also http://www.iana.org/in-notes/iana/assignments/protocol-numbers
 #
 ip	0	IP		# internet protocol, pseudo protocol number
-#hopopt	0	HOPOPT		# hop-by-hop options for ipv6
+hopopt	0	HOPOPT		# hop-by-hop options for ipv6
 icmp	1	ICMP		# internet control message protocol
 igmp	2	IGMP		# Internet Group Management
 ggp	3	GGP		# gateway-gateway protocol
@@ -38,4 +38,6 @@
 ospf	89	OSPFIGP		# Open Shortest Path First IGP
 ipip	94	IPIP		# Yet Another IP encapsulation
 encap	98	ENCAP		# Yet Another IP encapsulation
+pim	103	PIMv4		# Protocol Independent Multicast
+ipv6-pim	104	pim6 PIMv6	# Protocol Independent Multicast (IPv6)
 divert	254	DIVERT		# Divert pseudo-protocol
diff -uN src-current/etc/services src-current-ipv6/etc/services
--- src-current/etc/services
+++ src-current-ipv6/etc/services
@@ -1652,6 +1652,7 @@
 ricardo-lm	6148/udp   #Ricardo North America License Manager
 xdsxdm		6558/tcp	
 xdsxdm		6558/udp	
+atmsig		6666/tcp   #Mohsen Souissi ATM signaling daemon
 natd		6668/divert # Network Address Translation
 acmsoda		6969/tcp
 acmsoda		6969/udp
@@ -1688,9 +1689,11 @@
 man		9535/udp
 sd		9876/tcp   #Session Director
 sd		9876/udp   #Session Director
+ipatm		9999/tcp   # ip/atm test,  Mohsen Souissi
 amanda		10080/udp  #Dump server control
 amandaidx	10082/tcp  #Amanda indexing
 amidxtape	10083/tcp  #Amanda tape indexing
+netperf		12865/tcp
 isode-dua	17007/tcp
 isode-dua	17007/udp
 biimenu		18000/tcp #Beckman Instruments, Inc.
diff -uN src-current/include/arpa/inet.h src-current-ipv6/include/arpa/inet.h
--- src-current/include/arpa/inet.h
+++ src-current-ipv6/include/arpa/inet.h
@@ -80,6 +80,7 @@
 const char	*inet_ntop __P((int, const void *, char *, size_t));
 u_int		 inet_nsap_addr __P((const char *, u_char *, int));
 char		*inet_nsap_ntoa __P((int, const u_char *, char *));
+int		 inet6_isipv4mapped __P((const struct in6_addr *));
 __END_DECLS
 
 #endif /* !_INET_H_ */
diff -uN src-current/include/rpc/clnt.h src-current-ipv6/include/rpc/clnt.h
--- src-current/include/rpc/clnt.h
+++ src-current-ipv6/include/rpc/clnt.h
@@ -302,7 +302,7 @@
  * TCP based rpc
  * CLIENT *
  * clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
- *	struct sockaddr_in *raddr;
+ *	RPC_SOCKADDR_IN *raddr;
  *	u_long prog;
  *	u_long version;
  *	register int *sockp;
@@ -310,7 +310,7 @@
  *	u_int recvsz;
  */
 __BEGIN_DECLS
-extern CLIENT *clnttcp_create	__P((struct sockaddr_in *,
+extern CLIENT *clnttcp_create	__P((RPC_SOCKADDR_IN *,
 				     u_long,
 				     u_long,
 				     int *,
@@ -323,7 +323,7 @@
  * UDP based rpc.
  * CLIENT *
  * clntudp_create(raddr, program, version, wait, sockp)
- *	struct sockaddr_in *raddr;
+ *	RPC_SOCKADDR_IN *raddr;
  *	u_long program;
  *	u_long version;
  *	struct timeval wait;
@@ -332,7 +332,7 @@
  * Same as above, but you specify max packet sizes.
  * CLIENT *
  * clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz)
- *	struct sockaddr_in *raddr;
+ *	RPC_SOCKADDR_IN *raddr;
  *	u_long program;
  *	u_long version;
  *	struct timeval wait;
@@ -341,12 +341,12 @@
  *	u_int recvsz;
  */
 __BEGIN_DECLS
-extern CLIENT *clntudp_create	__P((struct sockaddr_in *,
+extern CLIENT *clntudp_create	__P((RPC_SOCKADDR_IN *,
 				     u_long,
 				     u_long,
 				     struct timeval,
 				     int *));
-extern CLIENT *clntudp_bufcreate __P((struct sockaddr_in *,
+extern CLIENT *clntudp_bufcreate __P((RPC_SOCKADDR_IN *,
 				     u_long,
 				     u_long,
 				     struct timeval,
diff -uN src-current/include/rpc/pmap_clnt.h src-current-ipv6/include/rpc/pmap_clnt.h
--- src-current/include/rpc/pmap_clnt.h
+++ src-current-ipv6/include/rpc/pmap_clnt.h
@@ -55,7 +55,7 @@
  *	done = eachresult(resp, raddr)
  *		bool_t done;
  *		caddr_t resp;
- *		struct sockaddr_in raddr;
+ *		RPC_SOCKADDR_IN *raddr;
  *		where resp points to the results of the call and raddr is the
  *		address if the responder to the broadcast.
  */
@@ -67,8 +67,8 @@
 __BEGIN_DECLS
 extern bool_t		pmap_set	__P((u_long, u_long, int, int));
 extern bool_t		pmap_unset	__P((u_long, u_long));
-extern struct pmaplist	*pmap_getmaps	__P((struct sockaddr_in *));
-extern enum clnt_stat	pmap_rmtcall	__P((struct sockaddr_in *,
+extern struct pmaplist	*pmap_getmaps	__P((RPC_SOCKADDR_IN *));
+extern enum clnt_stat	pmap_rmtcall	__P((RPC_SOCKADDR_IN *,
 					     u_long, u_long, u_long,
 					     xdrproc_t, caddr_t,
 					     xdrproc_t, caddr_t,
@@ -77,8 +77,8 @@
 					     xdrproc_t, char *,
 					     xdrproc_t, char *,
 					     bool_t (*) __P((caddr_t,
-						 struct sockaddr_in *))));
-extern u_short		pmap_getport	__P((struct sockaddr_in *,
+						 RPC_SOCKADDR_IN *))));
+extern u_short		pmap_getport	__P((RPC_SOCKADDR_IN *,
 					     u_long, u_long, u_int));
 __END_DECLS
 
diff -uN src-current/include/rpc/svc.h src-current-ipv6/include/rpc/svc.h
--- src-current/include/rpc/svc.h
+++ src-current-ipv6/include/rpc/svc.h
@@ -96,7 +96,7 @@
 	    void	(*xp_destroy) __P((struct __rpc_svcxprt *));
 	} *xp_ops;
 	int		xp_addrlen;	 /* length of remote address */
-	struct sockaddr_in xp_raddr;	 /* remote address */
+	RPC_SOCKADDR_IN	xp_raddr;	 /* remote address */
 	struct opaque_auth xp_verf;	 /* raw response verifier */
 	caddr_t		xp_p1;		 /* private */
 	caddr_t		xp_p2;		 /* private */
@@ -105,7 +105,7 @@
 /*
  *  Approved way of getting address of caller
  */
-#define svc_getcaller(x) (&(x)->xp_raddr)
+#define svc_getcaller(x) ((RPC_SOCKADDR_IN *)(&(x)->xp_raddr))
 
 /*
  * Operations defined on an SVCXPRT handle
diff -uN src-current/include/rpc/types.h src-current-ipv6/include/rpc/types.h
--- src-current/include/rpc/types.h
+++ src-current-ipv6/include/rpc/types.h
@@ -59,4 +59,47 @@
 #endif
 #include <sys/time.h>
 
+#if defined(RPC_USE_INET6) || defined(RPC_USE_INET_ANY)
+/*
+ * IPv6 Support.
+ */
+#include <sys/socket.h>
+#include <netinet/in.h>
+/*
+ * We need to define a preferred family, AF_INET or AF_INET6.
+ * For this we use the same flag that for rcmd and gethostbyname,
+ * the RES_USE_INET6 flag in the _res resolver structure
+ */
+#ifdef RPC_USE_INET_ANY
+#include <resolv.h>
+#define AF_INETX ((_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET)
+#endif
+/*
+ * the real address structure, can contain any address
+ */
+union sockaddr_u {		/*_len, _family, _port are at same offset */
+	struct sockaddr_in s4; 
+	struct sockaddr_in6 s6; 
+};
+#ifdef RPC_USE_INET_ANY
+#define RPC_SOCKADDR_IN	union sockaddr_u
+#define TOSINS(sa)	((sa).s4)
+#define TOSINS6(sa)	((sa).s6)
+#else
+#define RPC_SOCKADDR_IN	struct sockaddr_in6
+#endif
+/*
+ * the visible address structure, for argument.
+ * Should be a generic struct sockaddr, or an union sockaddr_u,
+ * but it causes compiler warnings for non ipv6 programs.
+ */
+#ifdef RPC_USE_INET_ANY
+#define TOSINP(sa)	((struct sockaddr_in *)(sa))
+#define TOSINP6(sa)	((struct sockaddr_in6 *)(sa))
+#endif
+
+#else /* not INET6 : try to be compatible in includes */
+#define RPC_SOCKADDR_IN		struct sockaddr_in
+#endif
+
 #endif /* !_RPC_TYPES_H */
diff -uN src-current/include/rpc/rpc.h src-current-ipv6/include/rpc/rpc.h
--- src-current/include/rpc/rpc.h
+++ src-current-ipv6/include/rpc/rpc.h
@@ -86,8 +86,8 @@
 extern void setrpcent __P((int));
 extern void endrpcent __P((void));
 
-extern int bindresvport __P((int, struct sockaddr_in *));
-extern int get_myaddress __P((struct sockaddr_in *));
+extern int bindresvport __P((int, RPC_SOCKADDR_IN *));
+extern int get_myaddress __P((RPC_SOCKADDR_IN *));
 __END_DECLS
 
 #endif /* !_RPC_RPC_H */
diff -uN src-current/include/Makefile src-current-ipv6/include/Makefile
--- src-current/include/Makefile
+++ src-current-ipv6/include/Makefile
@@ -40,6 +40,7 @@
 
 LFILES=	errno.h fcntl.h poll.h syslog.h termios.h
 
+#LDIRS=	msdosfs net netns netatalk netatm netinet netipx netkey nfs
 LDIRS=	msdosfs net netns netatalk netinet netipx netkey nfs \
 		pccard posix4 sys vm \
 		# netccitt netiso
diff -uN src-current/include/netdb.h src-current-ipv6/include/netdb.h
--- src-current/include/netdb.h
+++ src-current-ipv6/include/netdb.h
@@ -107,6 +107,64 @@
 };
 
 /*
+ * a la POSIX new IPv6 API addrinfo structure.
+ */
+/* to be fixed */
+#ifdef _SYS_SOCKET_H_
+struct addrinfo {
+	int	 ai_flags;		/* AI_PASSIVE, AI_CANONNAME */
+	int	 ai_family;		/* PF_xxx */
+	int	 ai_socktype;		/* SOCK_xxx */
+	int	 ai_protocol;		/* 0 or IPPROTO_xxx for IP */
+	size_t	 ai_addrlen;		/* length of ai_addr */
+	char	*ai_canonname;		/* canonical name */
+	struct sockaddr *ai_addr;	/* binary address */
+	struct addrinfo *ai_next;	/* next struct in linked list */
+};
+#endif
+
+/* addrinfo flags */
+
+#define	AI_NOALIAS	0x0001	/* don't use MX agents or aliases (UNIMP) */
+#define	AI_THISAF	0x0002	/* only retrieve this address family */
+#define	AI_THISTYPE	0x0004	/* only retrieve this socktype */
+#define	AI_THISPROTO	0x0008	/* only retrieve this proto (UNIMP) */
+#define	AI_REUSE	0x0010	/* overwrite this entry (UNIMP) */
+#define	AI_DYNADDR	0x0020	/* can free or re-malloc sockaddr */
+#define	AI_DYNSTRUCT	0x0040	/* can free or re-alloc this struct */
+#define	AI_PASSIVE	0x0080	/* intended for bind() + listen() */
+#define	AI_CANONNAME	0x0100	/* return canonical version of host (UNIMP) */
+/* internally used flags */
+#define	AI_GOTSERVICE	0x1000	/* service field has been filled in */
+
+/* addrinfo errors */
+
+#define	EAI_ADDRFAMILY	1	/* address family not supported */
+#define	EAI_AGAIN	2	/* DNS temporary failure */
+#define	EAI_BADFLAGS	3	/* invalid ai_flags */
+#define	EAI_FAIL	4	/* DNS non-recoverable failure */
+#define	EAI_FAMILY	5	/* ai_family not supported */
+#define	EAI_MEMORY	6	/* memory allocation failure */
+#define	EAI_NODATA	7	/* no address */
+#define	EAI_NONAME	8	/* host/servname not known */
+#define	EAI_SERVICE	9	/* servname not supported for ai_socktype */
+#define	EAI_SOCKTYPE	10	/* ai_socktype not supported */
+#define	EAI_SYSTEM	11	/* system error in errno */
+
+/* nameinfo maximum sizes */
+
+#define	NI_MAXHOST	1025
+#define	NI_MAXSERV	32
+
+/* nameinfo flags */
+
+#define	NI_NOFQDN	0x0001	/* strip domain name */
+#define	NI_NUMERICHOST	0x0002	/* return numeric form of address */
+#define	NI_NAMEREQD	0x0004	/* request DNS name */
+#define	NI_NUMERICSERV	0x0008	/* return port number */
+#define	NI_DGRAM	0x0010	/* UDP based service */
+
+/*
  * Error return codes from gethostbyname() and gethostbyaddr()
  * (left in extern int h_errno).
  */
@@ -172,6 +230,15 @@
 struct netent *  _getnetbynisaddr __P((unsigned long, int));
 void _map_v4v6_address __P((const char *src, char *dst));
 void _map_v4v6_hostent __P((struct hostent *hp, char **bp, int *len));
+
+#ifdef _SYS_SOCKET_H_
+int		getaddrinfo __P((const char *, const char *,
+			const struct addrinfo *, struct addrinfo **));
+void		freeaddrinfo __P((struct addrinfo *));
+char		*gai_strerror __P((int));
+int		getnameinfo __P((const struct sockaddr *, size_t,
+			char *, size_t, char *, size_t, int));
+#endif
 __END_DECLS
 
 #endif /* !_NETDB_H_ */
diff -uN src-current/include/resolv.h src-current-ipv6/include/resolv.h
--- src-current/include/resolv.h
+++ src-current-ipv6/include/resolv.h
@@ -136,6 +136,9 @@
 #define	RES_NOALIASES	0x00001000	/* shuts off HOSTALIASES feature */
 #define	RES_USE_INET6	0x00002000	/* use/map IPv6 in gethostbyname() */
 #define	RES_NOTLDQUERY	0x00004000	/* Don't query TLD names */
+#define	RES_MAPINET6	0x00008000	/* map AF_INET6 to AF_INET4 */
+#define	RES_MAPSIT	0x00010000	/* map IPv4 compatible to IPv4 */
+#define	RES_NOFALL6	0x00020000	/* don't try IPv4 if IPv6 fails */
 
 #define RES_DEFAULT	(RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
 
diff -uN src-current/include/unistd.h src-current-ipv6/include/unistd.h
--- src-current/include/unistd.h
+++ src-current-ipv6/include/unistd.h
@@ -138,6 +138,7 @@
 char	*getwd __P((char *));			/* obsoleted by getcwd() */
 int	 initgroups __P((const char *, int));
 int	 iruserok __P((unsigned long, int, const char *, const char *));
+int	 iruserok2 __P((int, const char *, int, int, const char *, const char *));
 int	 issetugid __P((void));
 int	 lchown __P((const char *, uid_t, gid_t));
 char	*mkdtemp __P((char *));
@@ -156,6 +157,7 @@
 int	 revoke __P((const char *));
 pid_t	 rfork __P((int));
 int	 rresvport __P((int *));
+int	 rresvport_af __P((int *, int));
 int	 ruserok __P((const char *, int, const char *, const char *));
 char	*sbrk __P((int));
 int	 select __P((int, fd_set *, fd_set *, fd_set *, struct timeval *));
diff -uN src-current/lib/libc/gen/errlst.c src-current-ipv6/lib/libc/gen/errlst.c
--- src-current/lib/libc/gen/errlst.c
+++ src-current-ipv6/lib/libc/gen/errlst.c
@@ -136,6 +136,12 @@
 	"No locks available",			/* 77 - ENOLCK */
 	"Function not implemented",		/* 78 - ENOSYS */
 	"Inappropriate file type or format",	/* 79 - EFTYPE */
+	"NFS authentication error",		/* 80 - EAUTH */
+	"NFS needs authenticator",		/* 81 - ENEEDAUTH */
+
+/* IPSec */
+	"IPsec error",				/* 82 - EIPSEC */
+
 };
 int errno;
 const int sys_nerr = sizeof(sys_errlist) / sizeof(sys_errlist[0]);
diff -uN src-current/lib/libc/net/Makefile.inc src-current-ipv6/lib/libc/net/Makefile.inc
--- src-current/lib/libc/net/Makefile.inc
+++ src-current-ipv6/lib/libc/net/Makefile.inc
@@ -14,7 +14,7 @@
 	inet_pton.c linkaddr.c map_v4v6.c ns_addr.c ns_ntoa.c nsap_addr.c \
 	rcmd.c recv.c res_comp.c res_data.c res_debug.c \
 	res_init.c res_mkquery.c res_query.c res_send.c res_stubs.c \
-	send.c
+	send.c getif.c getaddrinfo.c getnameinfo.c
 # not supported: iso_addr.c 
 
 # machine-dependent net sources
@@ -47,7 +47,8 @@
 	inet.3 ntoa.3
 MLINKS+=linkaddr.3 link_addr.3 linkaddr.3 link_ntoa.3 
 #MLINKS+=ns.3 ns_addr.3 ns.3 ns_ntoa.3
-MLINKS+=rcmd.3 iruserok.3 rcmd.3 rresvport.3 rcmd.3 ruserok.3
+MLINKS+=rcmd.3 rresvport.3 rcmd.3 iruserok.3 rcmd.3 ruserok.3 \
+	rcmd.3 iruserok2.3 rcmd.3 rresvport_af.3
 MLINKS+=resolver.3 dn_comp.3 resolver.3 dn_expand.3 resolver.3 res_init.3 \
 	resolver.3 res_mkquery.3 resolver.3 res_query.3 \
 	resolver.3 res_search.3 resolver.3 res_send.3
diff -uN src-current/lib/libc/net/addr2ascii.c src-current-ipv6/lib/libc/net/addr2ascii.c
--- src-current/lib/libc/net/addr2ascii.c
+++ src-current-ipv6/lib/libc/net/addr2ascii.c
@@ -62,7 +62,7 @@
 	int len;		/* should be size_t XXX */
 	char *buf;		/* XXX should pass length of buffer */
 {
-	static char staticbuf[64]; /* 64 for AF_LINK > 16 for AF_INET */
+	static char staticbuf[128]; /* 128 should be enough ! */
 
 	if (!buf)
 		buf = staticbuf;
@@ -74,6 +74,14 @@
 			return 0;
 		}
 		strcpy(buf, inet_ntoa(*(const struct in_addr *)addrp));
+		break;
+
+	case AF_INET6:
+		if (len != sizeof(struct in6_addr)) {
+			errno = ENAMETOOLONG;
+			return 0;
+		}
+		buf = (char *)inet_ntop(af, addrp, buf, 64);
 		break;
 
 	case AF_LINK:
diff -uN src-current/lib/libc/net/ascii2addr.c src-current-ipv6/lib/libc/net/ascii2addr.c
--- src-current/lib/libc/net/ascii2addr.c
+++ src-current-ipv6/lib/libc/net/ascii2addr.c
@@ -45,16 +45,24 @@
 	const char *ascii;
 	void *result;
 {
-	struct in_addr *ina;
-	char strbuf[4*sizeof("123")]; /* long enough for V4 only */
-
 	switch(af) {
 	case AF_INET:
+		{
+		struct in_addr *ina;
+		char strbuf[4*sizeof("123")]; /* long enough for V4 only */
+
 		ina = result;
 		strbuf[0] = '\0';
 		strncat(strbuf, ascii, (sizeof strbuf)-1);
 		if (inet_aton(strbuf, ina))
 			return sizeof(struct in_addr);
+		errno = EINVAL;
+		}
+		break;
+
+	case AF_INET6:
+		if (inet_pton(af, ascii, result))
+			return sizeof(struct in6_addr);
 		errno = EINVAL;
 		break;
 
diff -uN src-current/lib/libc/net/getaddrinfo.c src-current-ipv6/lib/libc/net/getaddrinfo.c
--- src-current/lib/libc/net/getaddrinfo.c
+++ src-current-ipv6/lib/libc/net/getaddrinfo.c
@@ -0,0 +1,340 @@
+/*
+ * getaddrinfo a la POSIX function based on Keith Sklower proposal
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <ctype.h>
+#include <errno.h>
+
+#define BITSET(b, w)	(((b) & (w)) != 0)
+
+#define ai2sin(x)	((struct sockaddr_in *)((x)->ai_addr))
+#define ai2sin6(x)	((struct sockaddr_in6 *)((x)->ai_addr))
+
+int
+getaddrinfo(hostname, servname, hints, res)
+	const char *hostname;
+	const char *servname;
+	const struct addrinfo *hints;
+	struct addrinfo **res;
+{
+	register struct addrinfo *ai;
+	struct addrinfo *aihead;
+	int addrlen;
+	register struct hostent *hp = NULL;
+	struct addrinfo **aip;
+	static struct addrinfo null_hints;
+
+	/* always have a "control" address for simplicity */
+	if (hints == NULL) {
+		aihead = &null_hints;
+
+		/* clear out any calls from last time */
+		freeaddrinfo(aihead);
+	} else {
+		aihead = (struct addrinfo *)hints;
+	}
+	for (ai = aihead; ai != NULL; ai = ai->ai_next) {
+		/* reset the chain */
+		ai->ai_flags &= ~(AI_GOTSERVICE);
+	}
+
+	/*
+	**  Select between passive and active addresses.
+	*/
+
+	ai = aihead;
+	if ((hostname == NULL || *hostname == '\0') &&
+	    !BITSET(AI_PASSIVE, ai->ai_flags))
+		hostname = "localhost";
+
+	if (hostname == NULL || *hostname == '\0') {
+		/*
+		**  Wildcard the address
+		*/
+
+		if (!BITSET(AI_THISAF, ai->ai_flags))
+			ai->ai_family = AF_INET;		/*XXX*/
+		switch (ai->ai_family) {
+		  case AF_INET:
+			addrlen = sizeof (struct sockaddr_in);
+			break;
+
+		  case AF_INET6:
+			addrlen = sizeof (struct sockaddr_in6);
+			break;
+
+		  default:
+#ifdef DEBUG
+			fprintf(stderr,
+				"Unknown address family %d",
+				ai->ai_family);
+#endif
+			return EAI_ADDRFAMILY;
+		}
+
+		if (ai->ai_addrlen != addrlen) {
+			if (BITSET(AI_DYNADDR, ai->ai_flags))
+				free(ai->ai_addr);
+			if ((ai->ai_addr = malloc(addrlen)) == NULL)
+				goto nomem;
+			ai->ai_flags |= AI_DYNADDR;
+		}
+		ai->ai_flags |= AI_PASSIVE;
+		ai->ai_addrlen = addrlen;
+		bzero(ai->ai_addr, addrlen);
+		ai->ai_addr->sa_len = addrlen;
+		switch (ai->ai_family) {
+		    case AF_INET:
+			ai2sin(ai)->sin_addr.s_addr = INADDR_ANY;
+			break;
+
+		    case AF_INET6:
+			ai2sin6(ai)->sin6_addr = in6addr_any;
+			break;
+		}
+	} else {
+		register char **ap;
+
+		hp = gethostbyname2(hostname, ai->ai_family);
+		if (hp == NULL) {
+			return EAI_FAIL;
+		}
+		switch (hp->h_addrtype) {
+		  case AF_INET:
+			addrlen = sizeof (struct sockaddr_in);
+			break;
+
+		  case AF_INET6:
+			addrlen = sizeof (struct sockaddr_in6);
+			break;
+		
+		  default:
+			fprintf(stderr,
+				"Unknown address family type %d\n",
+				hp->h_addrtype);
+			return EAI_FAMILY;
+		}
+		aip = &aihead;
+		for (ap = hp->h_addr_list; *ap != NULL; ap++) {
+			if (*aip == NULL) {
+				/* malloc another address structure */
+				if ((ai = malloc(sizeof *ai)) == NULL)
+					goto nomem;
+				bzero(ai, sizeof *ai);
+				ai->ai_flags |= AI_DYNSTRUCT;
+				*aip = ai;
+			}
+			aip = &ai->ai_next;
+
+			if (ai->ai_addr != NULL) {
+				if (ai->ai_addrlen != addrlen) {
+					if (BITSET(AI_DYNADDR, ai->ai_flags))
+						free(ai->ai_addr);
+					ai->ai_addr = NULL;
+				}
+			}
+			if (ai->ai_addr == NULL) {
+				if ((ai->ai_addr = malloc(addrlen)) == NULL)
+					goto nomem;
+				ai->ai_addrlen = addrlen;
+				ai->ai_flags |= AI_DYNADDR;
+			}
+
+			ai->ai_family = hp->h_addrtype;
+			ai->ai_protocol = hp->h_addrtype;
+			ai->ai_addr->sa_family = ai->ai_family;
+			switch (ai->ai_family) {
+			  case AF_INET:
+				bcopy(*ap, &ai2sin(ai)->sin_addr,
+				      hp->h_length);
+				break;
+
+			  case AF_INET6:
+				bcopy(*ap, &ai2sin6(ai)->sin6_addr,
+				      hp->h_length);
+				break;
+			}
+			ai->ai_canonname = hp->h_name;
+		}
+
+		/* free any extra structs handed in */
+		if (*aip != NULL)
+			freeaddrinfo(*aip);
+		*aip = NULL;
+	}
+
+	/*
+	**  Get the service.
+	*/
+
+	if (isdigit(*servname)) {
+		int serv;
+
+		serv = atoi(servname);
+		for (ai = aihead; ai != NULL; ai = ai->ai_next)	{
+			switch (ai->ai_family) {
+			  case AF_INET:
+				ai2sin(ai)->sin_port = serv;
+				break;
+
+			  case AF_INET6:
+				ai2sin6(ai)->sin6_port = serv;
+				break;
+
+			  default:
+				continue;
+			}
+			if (!BITSET(AI_THISTYPE, ai->ai_flags))
+				ai->ai_socktype = SOCK_STREAM /*???*/;
+		}
+	} else {
+		register struct servent *sp;
+
+		sp = getservbyname(servname, "tcp");
+		if (sp != NULL)	{
+			for (ai = aihead; ai != NULL; ai = ai->ai_next) {
+				if (BITSET(AI_THISTYPE, ai->ai_flags) &&
+				    ai->ai_socktype != SOCK_STREAM)
+					continue;
+				switch (ai->ai_family) {
+				  case AF_INET:
+					ai2sin(ai)->sin_port = sp->s_port;
+					break;
+
+				  case AF_INET6:
+					ai2sin6(ai)->sin6_port = sp->s_port;
+					break;
+
+				  default:
+					continue;
+				}
+				ai->ai_socktype = SOCK_STREAM;
+				ai->ai_flags |= AI_GOTSERVICE;
+			}
+		}
+
+		if ((sp = getservbyname(servname, "udp")) != NULL) {
+			for (ai = aihead; ai != NULL; ai = ai->ai_next)	{
+				if (BITSET(AI_THISTYPE, ai->ai_flags) &&
+				    ai->ai_socktype != SOCK_DGRAM)
+					continue;
+				switch (ai->ai_family) {
+				  case AF_INET:
+					if (BITSET(AI_GOTSERVICE, ai->ai_flags)) {
+						struct addrinfo *nai;
+
+						nai = malloc(sizeof *nai);
+						if (nai == NULL)
+							goto nomem;
+						*nai = *ai;
+						nai->ai_flags |= AI_DYNSTRUCT;
+						ai->ai_next = nai;
+						ai = nai;
+					}
+
+					ai2sin(ai)->sin_port = sp->s_port;
+					ai->ai_socktype = SOCK_DGRAM;
+					ai->ai_flags |= AI_GOTSERVICE;
+					break;
+
+				  case AF_INET6:
+					if (BITSET(AI_GOTSERVICE, ai->ai_flags)) {
+						struct addrinfo *nai;
+
+						nai = malloc(sizeof *nai);
+						if (nai == NULL)
+							goto nomem;
+						*nai = *ai;
+						nai->ai_flags |= AI_DYNSTRUCT;
+						ai->ai_next = nai;
+						ai = nai;
+					}
+
+					ai2sin6(ai)->sin6_port = sp->s_port;
+					ai->ai_socktype = SOCK_DGRAM;
+					ai->ai_flags |= AI_GOTSERVICE;
+					break;
+				}
+			}
+		}
+
+		for (aip = &aihead; (ai = *aip) != NULL; ) {
+			if (BITSET(AI_GOTSERVICE, ai->ai_flags)) {
+				aip = &ai->ai_next;
+			} else {
+				/* unlink this (incomplete) entry */
+				*aip = ai->ai_next;
+				if (BITSET(AI_DYNSTRUCT, ai->ai_flags))
+					free(ai);
+				errno = EPROTONOSUPPORT;
+			}
+		}
+	}
+
+	*res = aihead;
+	return 0;
+
+  nomem:
+	perror("no memory");
+	return EAI_MEMORY;
+}
+
+void
+freeaddrinfo(aihead)
+	struct addrinfo *aihead;
+{
+	register struct addrinfo **aip, *ai;
+	struct addrinfo *nai;
+
+	nai = ai = aihead;
+	aip = &aihead;
+	while (ai = nai) {
+		nai = ai->ai_next;
+		if (BITSET(AI_DYNADDR, ai->ai_flags)) {
+			free(ai->ai_addr);
+			ai->ai_addr = NULL;
+			ai->ai_flags &= ~AI_DYNADDR;
+		}
+		if (BITSET(AI_DYNSTRUCT, ai->ai_flags))	{
+			*aip = nai;
+			free(ai);
+		} else {
+			aip = &ai->ai_next;
+		}
+	}
+}
+
+const char *gai_errlist[] = {
+	"Name Translation Error 0 (no error)",
+	"address family not supported",		/* 1 EAI_ADDRFAMILY */
+	"DNS temporary failure",		/* 2 EAI_AGAIN */
+	"invalid ai_flags",			/* 3 EAI_BADFLAGS */
+	"DNS non-recoverable failure",		/* 4 EAI_FAIL */
+	"ai_family not supported",		/* 5 EAI_FAMILY */
+	"memory allocation failure",		/* 6 EAI_MEMORY */
+	"no address",				/* 7 EAI_NODATA */
+	"host/servname not known",		/* 8 EAI_NONAME */
+	"servname not for ai_socktype",		/* 9 EAI_SERVICE */
+	"ai_socktype not supported",		/* 10 EAI_SOCKTYPE */
+	"system error",				/* 11 EAI_SYSTEM */
+};
+int gai_nerr = { sizeof(gai_errlist)/sizeof(gai_errlist[0]) };
+
+char *
+gai_strerror(ecode)
+	int ecode;
+{
+	if (ecode < 0)
+		return ("Name Translation internal error");
+	else if (ecode < gai_nerr)
+		return ((char *)gai_errlist[ecode]);
+	return ("Unknown name translation error");
+}
diff -uN src-current/lib/libc/net/gethostbydns.c src-current-ipv6/lib/libc/net/gethostbydns.c
--- src-current/lib/libc/net/gethostbydns.c
+++ src-current-ipv6/lib/libc/net/gethostbydns.c
@@ -354,16 +354,6 @@
 			break;
 #else
 			host.h_name = bp;
-			if (_res.options & RES_USE_INET6) {
-				n = strlen(bp) + 1;	/* for the \0 */
-				if (n >= MAXHOSTNAMELEN) {
-					had_error++;
-					break;
-				}
-				bp += n;
-				buflen -= n;
-				_map_v4v6_hostent(&host, &bp, &buflen);
-			}
 			h_errno = NETDB_SUCCESS;
 			return (&host);
 #endif
@@ -384,6 +374,10 @@
 
 				host.h_name = bp;
 				nn = strlen(bp) + 1;	/* for the \0 */
+				if (nn >= MAXHOSTNAMELEN) {
+					had_error++;
+					break;
+				}
 				bp += nn;
 				buflen -= nn;
 			}
@@ -441,10 +435,11 @@
 			bp += n;
 			buflen -= n;
 		}
-		if (_res.options & RES_USE_INET6)
-			_map_v4v6_hostent(&host, &bp, &buflen);
 		h_errno = NETDB_SUCCESS;
 		return (&host);
+	} else if (qtype == T_AAAA && type == T_CNAME) {
+		h_errno = NO_DATA;
+		return (NULL);
 	}
  no_recovery:
 	h_errno = NO_RECOVERY;
@@ -473,46 +468,11 @@
 	return(gethostanswer((const querybuf *)answer, anslen, qname, qtype));
 }
 
-struct hostent *
-_gethostbydnsname(name, af)
+static struct hostent *
+_gethostbylit4(name)
 	const char *name;
-	int af;
 {
-	querybuf buf;
 	register const char *cp;
-	char *bp;
-	int n, size, type, len;
-
-	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
-		h_errno = NETDB_INTERNAL;
-		return (NULL);
-	}
-
-	switch (af) {
-	case AF_INET:
-		size = INADDRSZ;
-		type = T_A;
-		break;
-	case AF_INET6:
-		size = IN6ADDRSZ;
-		type = T_AAAA;
-		break;
-	default:
-		h_errno = NETDB_INTERNAL;
-		errno = EAFNOSUPPORT;
-		return (NULL);
-	}
-
-	host.h_addrtype = af;
-	host.h_length = size;
-
-	/*
-	 * if there aren't any dots, it could be a user-level alias.
-	 * this is also done in res_query() since we are not the only
-	 * function that looks up host names.
-	 */
-	if (!strchr(name, '.') && (cp = __hostalias(name)))
-		name = cp;
 
 	/*
 	 * disallow names consisting only of digits/dots, unless
@@ -528,28 +488,38 @@
 				 * Fake up a hostent as if we'd actually
 				 * done a lookup.
 				 */
-				if (inet_pton(af, name, host_addr) <= 0) {
+				if (inet_pton(AF_INET, name, host_addr) <= 0) {
 					h_errno = HOST_NOT_FOUND;
 					return (NULL);
 				}
 				strncpy(hostbuf, name, MAXDNAME);
 				hostbuf[MAXDNAME] = '\0';
-				bp = hostbuf + MAXDNAME;
-				len = sizeof hostbuf - MAXDNAME;
 				host.h_name = hostbuf;
 				host.h_aliases = host_aliases;
 				host_aliases[0] = NULL;
 				h_addr_ptrs[0] = (char *)host_addr;
 				h_addr_ptrs[1] = NULL;
 				host.h_addr_list = h_addr_ptrs;
-				if (_res.options & RES_USE_INET6)
-					_map_v4v6_hostent(&host, &bp, &len);
 				h_errno = NETDB_SUCCESS;
 				return (&host);
 			}
 			if (!isdigit(*cp) && *cp != '.') 
 				break;
 		}
+	return (NULL);
+}
+
+static struct hostent *
+_gethostbylit6(name)
+	const char *name;
+{
+	register const char *cp;
+	int n;
+
+	/*
+	 * disallow names consisting only of hexdigits/colons/dots,
+	 * unless they end in a dot.
+	 */
 	if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
 	    name[0] == ':')
 		for (cp = name;; ++cp) {
@@ -557,22 +527,21 @@
 				if (*--cp == '.')
 					break;
 				/*
-				 * All-IPv6-legal, no dot at the end.
+				 * All-numeric, no dot at the end.
 				 * Fake up a hostent as if we'd actually
 				 * done a lookup.
 				 */
-				if (inet_pton(af, name, host_addr) <= 0) {
+				n = inet_pton(AF_INET6, name, host_addr);
+				if (n <= 0) {
 					h_errno = HOST_NOT_FOUND;
 					return (NULL);
 				}
 				strncpy(hostbuf, name, MAXDNAME);
 				hostbuf[MAXDNAME] = '\0';
-				bp = hostbuf + MAXDNAME;
-				len = sizeof hostbuf - MAXDNAME;
 				host.h_name = hostbuf;
 				host.h_aliases = host_aliases;
 				host_aliases[0] = NULL;
-				h_addr_ptrs[0] = (char *)host_addr;
+				h_addr_ptrs[0] = (char *)&host_addr;
 				h_addr_ptrs[1] = NULL;
 				host.h_addr_list = h_addr_ptrs;
 				h_errno = NETDB_SUCCESS;
@@ -581,6 +550,54 @@
 			if (!isxdigit(*cp) && *cp != ':' && *cp != '.') 
 				break;
 		}
+	return (NULL);
+}
+
+struct hostent *
+_gethostbydnsname(name, af)
+	const char *name;
+	int af;
+{
+	querybuf buf;
+	register const char *cp;
+	int n, size, type;
+	register struct hostent *hp = NULL;
+
+	switch (af) {
+	case AF_INET:
+		size = INADDRSZ;
+		type = T_A;
+		break;
+	case AF_INET6:
+		size = IN6ADDRSZ;
+		type = T_AAAA;
+		break;
+	default:
+		h_errno = NETDB_INTERNAL;
+		errno = EAFNOSUPPORT;
+		return (NULL);
+	}
+
+	host.h_addrtype = af;
+	host.h_length = size;
+
+	/*
+	 * if there aren't any dots, it could be a user-level alias.
+	 * this is also done in res_query() since we are not the only
+	 * function that looks up host names.
+	 */
+	if (!strchr(name, '.') && (cp = __hostalias(name)))
+		name = cp;
+
+	/*
+	 * the name can be a litteral address.
+	 */
+	if (af == AF_INET)
+		hp = _gethostbylit4(name);
+	else if (af == AF_INET6)
+		hp = _gethostbylit6(name);
+	if (hp)
+		return (hp);
 
 	if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf))) < 0) {
 		dprintf("res_search failed (%d)\n", n);
@@ -595,8 +612,6 @@
 	int len, af;
 {
 	const u_char *uaddr = (const u_char *)addr;
-	static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
-	static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
 	int n, size;
 	querybuf buf;
 	register struct hostent *hp;
@@ -608,19 +623,6 @@
 	char hname2[MAXDNAME+1];
 #endif /*SUNSECURITY*/
 	
-	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
-		h_errno = NETDB_INTERNAL;
-		return (NULL);
-	}
-	if (af == AF_INET6 && len == IN6ADDRSZ &&
-	    (!bcmp(uaddr, mapped, sizeof mapped) ||
-	     !bcmp(uaddr, tunnelled, sizeof tunnelled))) {
-		/* Unmap. */
-		addr += sizeof mapped;
-		uaddr += sizeof mapped;
-		af = AF_INET;
-		len = INADDRSZ;
-	}
 	switch (af) {
 	case AF_INET:
 		size = INADDRSZ;
@@ -674,7 +676,7 @@
 	    strncpy(hname2, hp->h_name, MAXDNAME);
 	    hname2[MAXDNAME] = '\0';
 	    old_options = _res.options;
-	    _res.options &= ~RES_DNSRCH;
+	    _res.options &= ~(RES_DNSRCH|RES_USE_INET6);
 	    _res.options |= RES_DEFNAMES;
 	    if (!(rhp = gethostbyname(hname2))) {
 		syslog(LOG_NOTICE|LOG_AUTH,
@@ -702,11 +704,6 @@
 	bcopy(addr, host_addr, len);
 	h_addr_ptrs[0] = (char *)host_addr;
 	h_addr_ptrs[1] = NULL;
-	if (af == AF_INET && (_res.options & RES_USE_INET6)) {
-		_map_v4v6_address((char*)host_addr, (char*)host_addr);
-		hp->h_addrtype = AF_INET6;
-		hp->h_length = IN6ADDRSZ;
-	}
 	h_errno = NETDB_SUCCESS;
 	return (hp);
 }
diff -uN src-current/lib/libc/net/gethostbyht.c src-current-ipv6/lib/libc/net/gethostbyht.c
--- src-current/lib/libc/net/gethostbyht.c
+++ src-current-ipv6/lib/libc/net/gethostbyht.c
@@ -126,14 +126,8 @@
 		af = AF_INET6;
 		len = IN6ADDRSZ;
 	} else if (inet_pton(AF_INET, p, host_addr) > 0) {
-		if (_res.options & RES_USE_INET6) {
-			_map_v4v6_address((char*)host_addr, (char*)host_addr);
-			af = AF_INET6;
-			len = IN6ADDRSZ;
-		} else {
-			af = AF_INET;
-			len = INADDRSZ;
-		}
+		af = AF_INET;
+		len = INADDRSZ;
 	} else {
 		goto again;
 	}
diff -uN src-current/lib/libc/net/gethostbyname.3 src-current-ipv6/lib/libc/net/gethostbyname.3
--- src-current/lib/libc/net/gethostbyname.3
+++ src-current-ipv6/lib/libc/net/gethostbyname.3
@@ -137,6 +137,8 @@
 .Fa af
 argument must be specified as
 .Dv AF_INET
+or
+.Dv AF_INET6
 else the fuction will return
 .Dv NULL
 after having set
@@ -216,6 +218,9 @@
 .Va h_errno
 can have the following values:
 .Bl -tag -width HOST_NOT_FOUND
+.It Dv NETDB_INTERNAL
+This indicates an internal error in the library, unrelated to the network
+or name service.
 .It Dv HOST_NOT_FOUND
 No such host is known.
 .It Dv TRY_AGAIN
diff -uN src-current/lib/libc/net/gethostnamadr.c src-current-ipv6/lib/libc/net/gethostnamadr.c
--- src-current/lib/libc/net/gethostnamadr.c
+++ src-current-ipv6/lib/libc/net/gethostnamadr.c
@@ -42,6 +42,21 @@
 
 #define _PATH_HOSTCONF	"/etc/host.conf"
 
+const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
+
+/*
+ * function form of the macro IN6_IS_ADDR_V4MAPPED
+ */
+int inet6_isipv4mapped(register const struct in6_addr *addr)
+{
+	return (IN6_IS_ADDR_V4MAPPED(addr));
+}
+
+static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
+static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
+static char hostbuf[BUFSIZ+1];
+
 enum service_type {
   SERVICE_NONE = 0,
   SERVICE_BIND,
@@ -121,13 +136,18 @@
 struct hostent *
 gethostbyname(const char *name)
 {
-	struct hostent *hp;
+	struct hostent *hp = NULL;
 
-	if (_res.options & RES_USE_INET6) {		/* XXX */
-		hp = gethostbyname2(name, AF_INET6);	/* XXX */
-		if (hp)					/* XXX */
-			return (hp);			/* XXX */
-	}						/* XXX */
+	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+		h_errno = NETDB_INTERNAL;
+		return (NULL);
+	}
+	if (_res.options & RES_USE_INET6) {
+		if ((_res.options & RES_MAPINET6) == 0)
+			hp = gethostbyname2(name, AF_INET6);
+		if (hp || (_res.options & RES_NOFALL6))
+			return (hp);
+	}
 	return (gethostbyname2(name, AF_INET));
 }
 
@@ -140,6 +160,11 @@
 	if (!service_done)
 		init_services();
 
+	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+		h_errno = NETDB_INTERNAL;
+		return (NULL);
+	}
+
 	while (!hp) {
 		switch (service_order[nserv]) {
 		      case SERVICE_NONE:
@@ -156,6 +181,14 @@
 		}
 		nserv++;
 	}
+
+	if (hp && (_res.options & RES_USE_INET6) &&
+	    hp->h_addrtype == AF_INET) {
+		char *bp = hostbuf;
+		int buflen = sizeof hostbuf;
+
+		_map_v4v6_hostent(hp, &bp, &buflen);
+	}
 	return hp;
 }
 
@@ -168,6 +201,21 @@
 	if (!service_done)
 		init_services();
 
+	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+		h_errno = NETDB_INTERNAL;
+		return (NULL);
+	}
+
+	if (type == AF_INET6 && len == IN6ADDRSZ &&
+	    (bcmp(addr, mapped, sizeof mapped) == 0 ||
+	     ((_res.options & RES_MAPSIT) &&
+	      bcmp(addr, tunnelled, sizeof tunnelled) == 0))) {
+		/* IPv4-mapped/compatible IPv6 address */
+		addr += sizeof mapped;
+		len = INADDRSZ;
+		type = AF_INET;
+	}
+
 	while (!hp) {
 		switch (service_order[nserv]) {
 		      case SERVICE_NONE:
@@ -183,6 +231,14 @@
 			break;
 		}
 		nserv++;
+	}
+
+	if (hp && (_res.options & RES_USE_INET6) &&
+	    hp->h_addrtype == AF_INET) {
+		char *bp = hostbuf;
+		int buflen = sizeof hostbuf;
+
+		_map_v4v6_hostent(hp, &bp, &buflen);
 	}
 	return hp;
 }
diff -uN src-current/lib/libc/net/getif.c src-current-ipv6/lib/libc/net/getif.c
--- src-current/lib/libc/net/getif.c
+++ src-current-ipv6/lib/libc/net/getif.c
@@ -0,0 +1,376 @@
+/* Get interface name/index via sysctl */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#ifdef DEBUG
+#define static
+#endif
+
+#define ROUNDUP(a) \
+        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sdl_len))
+
+static int mib[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
+static int rsize, rcount;
+static caddr_t buf, rbuf;
+
+static unsigned wanted_index;
+static int wanted_namelen;
+static char *wanted_name;
+
+static int getifs();
+static int ifinfo();
+static void add_ifinfo();
+
+unsigned int
+if_nametoindex(ifname)
+	const char *ifname;
+{
+	if ((ifname == NULL) || (*ifname == '\0'))
+		return(0);
+	wanted_index = 0;
+	wanted_namelen = strlen(ifname);
+	wanted_name = (char *)ifname;
+	if (getifs()) {
+#ifdef DEBUG
+		printf("if_nametoindex(%s)->%u\n",
+		       ifname, wanted_index);
+#endif
+		free(buf);
+		return(wanted_index);
+	}
+#ifdef DEBUG
+	printf("if_nametoindex(%s)->0!\n", ifname);
+#endif
+	return(0);
+}
+
+char *
+if_indextoname(ifindex, ifname)
+	unsigned int ifindex;
+	char *ifname;
+{
+	wanted_index = ifindex;
+	wanted_namelen = 0;
+	if (getifs()) {
+		bzero(ifname, IFNAMSIZ);
+		strncpy(ifname, wanted_name, wanted_namelen);
+#ifdef DEBUG
+		printf("if_indextoname(%d)->%s\n", ifindex, ifname);
+#endif
+		free(buf);
+		return(ifname);
+	}
+#ifdef DEBUG
+	printf("if_indextoname(%d)->NULL\n", ifindex);
+#endif
+	return(NULL);
+}
+
+struct if_nameindex *
+if_nameindex()
+{
+	wanted_index = 0;
+	wanted_namelen = 0;
+	if (getifs()) {
+#ifdef DEBUG
+		printf("if_nameindex->%d\n", rcount);
+#endif
+		free(buf);
+		return((struct if_nameindex *)rbuf);
+	}
+	return((struct if_nameindex *)0);
+}
+
+void
+if_freenameindex(ptr)
+	struct if_nameindex *ptr;
+{
+	free(ptr);
+}
+
+static int
+getifs()
+{
+	struct if_msghdr *ifm;
+	struct if_nameindex *ifni;
+	caddr_t cp, rcp;
+	int size;
+
+	if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0) {
+#ifdef DEBUG
+		perror("sysctl0");
+#endif
+		return(0);
+	}
+#ifdef DEBUG
+	printf("size = %d\n", size);
+#endif
+	if ((buf = malloc(size)) == NULL) {
+#ifdef DEBUG
+		fprintf(stderr, "malloc failed\n");
+#endif
+		return(0);
+	}
+	if (sysctl(mib, 6, buf, &size, NULL, 0) < 0) {
+#ifdef DEBUG
+		perror("sysctl");
+#endif
+		free(buf);
+		return(0);
+	}
+
+	rsize = 0;
+	rcount = 0;
+	for (cp = buf; cp < buf + size; cp += ifm->ifm_msglen) {
+		ifm = (struct if_msghdr *)cp;
+
+		if ((ifm->ifm_type == RTM_IFINFO) && ifinfo(ifm))
+			return(1);
+	}
+	if (rsize) {
+		rsize += sizeof(struct if_nameindex);
+		if ((rbuf = malloc(rsize)) == NULL) {
+#ifdef DEBUG
+			fprintf(stderr, "malloc failed\n");
+#endif
+			return(0);
+		}
+		bzero(rbuf, rsize);
+		ifni = (struct if_nameindex *)rbuf;
+		rcp = (caddr_t)(ifni + rcount + 1);
+		for (cp = buf; cp < buf + size; cp += ifm->ifm_msglen) {
+			ifm = (struct if_msghdr *)cp;
+
+			if (ifm->ifm_type == RTM_IFINFO) {
+				add_ifinfo(ifm, ifni, rcp);
+				ifni++;
+				rcp += IFNAMSIZ;
+			}
+		}
+		return(1);
+	}
+	free(buf);
+	return(0);
+}
+
+static int
+ifinfo(ifm)
+	struct if_msghdr *ifm;
+{
+	struct sockaddr_dl *sdl;
+	caddr_t cp;
+	int len;
+
+	cp = (caddr_t)(ifm + 1);
+	len = ifm->ifm_msglen;
+
+#ifdef DEBUG
+	printf("Interface Info #%d\n", ifm->ifm_index);
+	printf("\t%x addresses\n", ifm->ifm_addrs);
+#endif
+	if (ifm->ifm_addrs != (1 << RTAX_IFP)) {
+#ifdef DEBUG
+		fprintf(stderr, "bad ifm_addrs\n");
+#endif
+		return(0);
+	}
+	sdl = (struct sockaddr_dl *)cp;
+	if (sdl->sdl_family != AF_LINK) {
+#ifdef DEBUG
+		printf("bad family: %d?: ", sdl->sdl_family);
+#endif
+		return(0);
+	}
+		
+#ifdef DEBUG
+      	printf("LL#%d/%d: %*s\n",
+	       sdl->sdl_index,
+	       sdl->sdl_type,
+	       sdl->sdl_nlen,
+	       sdl->sdl_data);
+#endif
+	if (sdl->sdl_nlen >= IFNAMSIZ) {
+#ifdef DEBUG
+		fprintf(stderr, "ifnamelen too large(%d)\n", sdl->sdl_nlen);
+#endif
+		return(0);
+	}
+	if (wanted_index &&
+	    (wanted_index == (unsigned int)sdl->sdl_index)) {
+		wanted_namelen = (int)sdl->sdl_nlen;
+		wanted_name = sdl->sdl_data;
+		return(1);
+	} else if (wanted_namelen &&
+		   (wanted_namelen == (int)sdl->sdl_nlen) &&
+		   (bcmp(sdl->sdl_data, wanted_name, wanted_namelen) == 0)) {
+		wanted_index = sdl->sdl_index;
+		return(1);
+	} else if ((wanted_index == 0) && (wanted_namelen == 0)) {
+		rsize += sizeof(struct if_nameindex) + IFNAMSIZ;
+		rcount++;
+	}
+#ifdef DEBUG
+	ADVANCE(cp, sdl);
+
+	if (cp != (caddr_t)ifm + len)
+		printf("delta = %d\n", cp - ((caddr_t)ifm + len));
+	printf("\n");
+#endif
+	return(0);
+}
+
+static void
+add_ifinfo(ifm, ifni, rcp)
+	struct if_msghdr *ifm;
+	struct if_nameindex *ifni;
+	caddr_t rcp;
+{
+	struct sockaddr_dl *sdl;
+	caddr_t cp;
+	int len;
+
+	cp = (caddr_t)(ifm + 1);
+	len = ifm->ifm_msglen;
+
+	if (ifm->ifm_addrs != (1 << RTAX_IFP))
+		return;
+
+	sdl = (struct sockaddr_dl *)cp;
+	if (sdl->sdl_family != AF_LINK)
+		return;
+		
+	if (sdl->sdl_nlen >= IFNAMSIZ)
+		return;
+
+	ifni->if_index = (unsigned int)sdl->sdl_index;
+	ifni->if_name = rcp;
+	strncpy(rcp, sdl->sdl_data, (size_t)sdl->sdl_nlen);
+}
+
+#ifdef DEBUG
+void
+print_ifni(ifni)
+	struct if_nameindex *ifni;
+{
+	if (ifni == NULL) {
+		fprintf(stderr, "NULL?\n");
+		return;
+	}
+	if ((ifni->if_index == 0) && (ifni->if_name == NULL))
+		return;
+	printf("%s : %u\n", ifni->if_name, ifni->if_index);
+	print_ifni(++ifni);
+}
+
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	char buf[IFNAMSIZ];
+
+	if (argc == 1) {
+		print_ifni(if_nameindex());
+		exit(0);
+	} else if (argc != 2) {
+		fprintf(stderr, "bad argument count (%d)\n", argc);
+		exit(1);
+	}
+	if (isdigit(*argv[1]))
+		(void)if_indextoname(atoi(argv[1]), buf);
+	else
+		(void)if_nametoindex(argv[1]);
+	exit(0);
+}
+#endif
+
+#include <netinet/in.h>
+#include <netinet/in6_var.h>
+
+int
+get_multi_homed()
+{
+	int mib[4] = { CTL_NET, PF_INET6, 0, IP6CTL_MHLEVEL };
+	int mh, size = sizeof(mh);
+
+	if (sysctl(mib, 4, &mh, &size, NULL, 0) < 0) {
+#ifdef DEBUG
+		perror("get_multi_homed: sysctl");
+#endif
+		return(-1);
+	}
+	if (size != sizeof(mh)) {
+#ifdef DEBUG
+		fprintf(stderr, "get_multi_homed: bad size (%d)\n", size);
+#endif
+		return(-1);
+	}
+	return(mh);
+}
+
+int
+main_interface(p)
+	int *p;
+{
+	int mib[4] = { CTL_NET, PF_INET6, 0, IP6CTL_MAININTF };
+	int midx, size = sizeof(midx);
+
+	if (sysctl(mib, 4, &midx, &size, p, sizeof(*p)) < 0) {
+#ifdef DEBUG
+		perror("main_interface:  sysctl");
+#endif
+		return(-1);
+	}
+	if (size != sizeof(midx)) {
+#ifdef DEBUG
+		fprintf(stderr, "main_interface: bad size (%d)\n", size);
+#endif
+		return(-1);
+	}
+	if (p)
+		*p = midx;
+	return(midx);
+}
+
+int
+main_site(p)
+	int *p;
+{
+	int mib[4] = { CTL_NET, PF_INET6, 0, IP6CTL_MAINSITE };
+	int msite, size = sizeof(msite);
+
+	if (sysctl(mib, 4, &msite, &size, p, sizeof(*p)) < 0) {
+#ifdef DEBUG
+		perror("main_site:  sysctl");
+#endif
+		return(-1);
+	}
+	if (size != sizeof(msite)) {
+#ifdef DEBUG
+		fprintf(stderr, "main_site: bad size (%d)\n", size);
+#endif
+		return(-1);
+	}
+	if (p)
+		*p = msite;
+	return(msite);
+}
+
diff -uN src-current/lib/libc/net/getnameinfo.c src-current-ipv6/lib/libc/net/getnameinfo.c
--- src-current/lib/libc/net/getnameinfo.c
+++ src-current-ipv6/lib/libc/net/getnameinfo.c
@@ -0,0 +1,96 @@
+/*
+ * getnameinfo a la POSIX (but defined by IETF) function.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <errno.h>
+
+#define sa2sin(x)	((struct sockaddr_in *)(x))
+#define sa2sin6(x)	((struct sockaddr_in6 *)(x))
+
+int
+getnameinfo(const struct sockaddr *sa, size_t salen,
+	    char *host, size_t hostlen,
+	    char *serv, size_t servlen,
+	    int flags)
+{
+	struct hostent *hp = NULL;
+	struct servent *sp = NULL;
+	char *addr;
+	int port, alen;
+
+	if (sa == NULL)
+		return EAI_ADDRFAMILY;
+	switch (sa->sa_family) {
+	    case AF_INET:
+		addr = (char *)&sa2sin(sa)->sin_addr;
+		alen = sizeof(struct in_addr);
+		port = (int)(sa2sin(sa)->sin_port);
+		break;
+
+	    case AF_INET6:
+		addr = (char *)&sa2sin6(sa)->sin6_addr;
+		alen = sizeof(struct in6_addr);
+		port = (int)(sa2sin6(sa)->sin6_port);
+		break;
+
+	    default:
+		return EAI_FAMILY;
+	}
+	if (host) {
+		if ((flags & NI_NUMERICHOST) == 0)
+			hp = gethostbyaddr(addr, alen, sa->sa_family);
+		if (hp) {
+			if (flags & NI_NOFQDN) {
+				char *dot = strchr(hp->h_name, '.');
+
+				if (dot)
+					dot[-1] = '\0';
+			}
+			if (strlen(hp->h_name) + 1 > hostlen) {
+				freehostent(hp);
+				return EAI_MEMORY;
+			}
+			bzero(host, hostlen);
+			strcpy(host, hp->h_name);
+			freehostent(hp);
+		} else if (flags & NI_NAMEREQD) {
+			switch (h_errno) {
+			    case HOST_NOT_FOUND:
+				return EAI_NONAME;
+			    case TRY_AGAIN:
+				return EAI_AGAIN;
+			    case NO_RECOVERY:
+				return EAI_FAIL;
+			    case NO_ADDRESS:
+				return EAI_NODATA;
+			    default:
+				return EAI_SYSTEM;
+			}
+		} else if (inet_ntop(sa->sa_family,
+				     addr, host, hostlen) == NULL)
+				return EAI_SYSTEM;
+	}
+	if (serv) {
+		if ((flags & NI_NUMERICSERV) == 0)
+			sp = getservbyport(port,
+				flags & NI_DGRAM ? "udp" : "tcp");
+		if (sp) {
+			if (strlen(sp->s_name) + 1 > servlen)
+				return EAI_MEMORY;
+			bzero(serv, servlen);
+			strcpy(serv, sp->s_name);
+		} else {
+			if (servlen < sizeof("65535"))
+				return EAI_MEMORY;
+			sprintf(serv, "%d", port);
+		}
+	}
+	return 0;
+}
diff -uN src-current/lib/libc/net/iso.3 src-current-ipv6/lib/libc/net/iso.3
--- src-current/lib/libc/net/iso.3
+++ src-current-ipv6/lib/libc/net/iso.3
@@ -0,0 +1,111 @@
+.\" Copyright (c) 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.
+.\"
+.\"     from: @(#)iso_addr.3	8.1 (Berkeley) 6/4/93
+.\"     $Id: iso.3,v 1.1 1995/01/09 12:34:39 dupont Exp $
+.\"
+.Dd June 4, 1993
+.Dt ISO 3
+.Os
+.Sh NAME
+.Nm iso_addr ,
+.Nm iso_ntoa
+.Nd "elementary network address conversion routines for Open System Interconnection
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <netiso/iso.h>
+.Ft struct iso_addr *
+.Fn iso_addr "char *cp"
+.Ft char *
+.Fn iso_ntoa "struct iso_addr *isoa"
+.Sh DESCRIPTION
+The routine
+.Fn iso_addr
+interprets character strings representing
+.Tn OSI
+addresses, returning binary information suitable
+for use in system calls.
+The routine
+.Fn iso_ntoa
+takes
+.Tn OSI
+addresses and returns
+.Tn ASCII
+strings representing NSAPs (network service
+access points) in a
+notation inverse to that accepted by 
+.Fn iso_addr .
+.Pp
+Unfortunately, no universal standard exists for representing
+.Tn OSI
+network addresses.
+.Pp
+The format employed by
+.Fn iso_addr
+is a sequence of hexadecimal
+.Dq digits
+(optionally separated by periods),
+of the form:
+.Bd -filled -offset indent
+<hex digits>.<hex digits>.<hex digits>
+.Ed
+.Pp
+Each pair of hexadecimal digits represents a byte
+with the leading digit indicating the higher-ordered bits.
+A period following an even number of bytes has no
+effect (but may be used to increase legibility).
+A period following an odd number of bytes has the
+effect of causing the byte of address being translated
+to have its higher order bits filled with zeros.
+.Sh RETURN VALUES
+.Fn iso_ntoa
+always returns a null terminated string.
+.Fn iso_addr
+always returns a pointer to a struct iso_addr.
+(See
+.Sx BUGS . )
+.Sh SEE ALSO
+.Xr iso 4
+.Sh HISTORY
+The
+.Fn iso_addr
+and
+.Fn iso_ntoa
+functions appeared in 
+.Bx 4.3 Reno .
+.Sh BUGS
+The returned values
+reside in a static memory area.
+.Pp
+The function
+.Fn iso_addr
+should diagnose improperly formed input, and there should be an unambiguous
+way to recognize this.
diff -uN src-current/lib/libc/net/rcmd.3 src-current-ipv6/lib/libc/net/rcmd.3
--- src-current/lib/libc/net/rcmd.3
+++ src-current-ipv6/lib/libc/net/rcmd.3
@@ -40,6 +40,8 @@
 .Nm rresvport ,
 .Nm iruserok ,
 .Nm ruserok
+.Nm rresvport_af ,
+.Nm iruserok2 ,
 .Nd routines for returning a stream to a remote command
 .Sh SYNOPSIS
 .Fd #include <unistd.h>
@@ -48,8 +50,12 @@
 .Ft int
 .Fn rresvport "int *port"
 .Ft int
+.Fn rresvport_af "int *port" "int af"
+.Ft int
 .Fn iruserok "u_long raddr" "int superuser" "const char *ruser" "const char *luser"
 .Ft int
+.Fn iruserok2 "int af" "const char *addr" "int len" "int superuser" "const char *ruser" "const char *luser"
+.Ft int
 .Fn ruserok "const char *rhost" "int superuser" "const char *ruser" "const char *luser"
 .Sh DESCRIPTION
 The
@@ -73,6 +79,29 @@
 by the
 .Xr rshd 8
 server (among others).
+.Pp
+The
+.Fn rresvport_af
+and
+.Fn iruserok2
+functions are protocol family independent versions of
+.Fn rresvport
+and
+.Fn iruserok .
+The 
+.Fa af
+argument is the protocol family (currently only AF_INET and
+AF_INET6 are supported).
+The other arguments are identical, except for
+.Fn iruserok2 
+in which
+.Fa addr
+is a pointer to an address and
+.Fa len
+is the length of this address.
+The other functions determine the protocol family (AF_INET or AF_INET6) by
+using the result of
+.Xr gethostbyname 3 .
 .Pp
 The
 .Fn rcmd
diff -uN src-current/lib/libc/net/rcmd.c src-current-ipv6/lib/libc/net/rcmd.c
--- src-current/lib/libc/net/rcmd.c
+++ src-current-ipv6/lib/libc/net/rcmd.c
@@ -52,6 +52,7 @@
 #include <ctype.h>
 #include <string.h>
 #ifdef YP
+#undef RPC_USE_INET_ANY
 #include <rpc/rpc.h>
 #include <rpcsvc/yp_prot.h>
 #include <rpcsvc/ypclnt.h>
@@ -61,8 +62,15 @@
 
 #define max(a, b)	((a > b) ? a : b)
 
+extern struct in6_addr in6addr_any;
+union sockaddr_u {		/*_len, _family, _port are at same offset */
+	struct sockaddr_in s4; 
+	struct sockaddr_in6 s6; 
+};
+
 int	__ivaliduser __P((FILE *, u_long, const char *, const char *));
-static int __icheckhost __P((u_long, char *));
+int	__ivaliduser2 __P((int, FILE *, const char *, int, const char *, const char *));
+static int __icheckhost2 __P((const char *, int, const char *));
 
 int
 rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
@@ -72,12 +80,19 @@
 	int *fd2p;
 {
 	struct hostent *hp;
-	struct sockaddr_in sin, from;
+	union sockaddr_u Sin, From;
+#define sin	Sin.s4
+#define sin6	Sin.s6
+#define from	From.s4
+#define from6	From.s6
 	fd_set reads;
 	long oldmask;
 	pid_t pid;
 	int s, lport, timo;
 	char c;
+	int af;
+	char *addr;
+	char vb[INET6_ADDRSTRLEN];       /* buffer for Vixie's inet_ntop */
 
 	pid = getpid();
 	hp = gethostbyname(*ahost);
@@ -85,10 +100,11 @@
 		herror(*ahost);
 		return (-1);
 	}
+	af = hp->h_addrtype;
 	*ahost = hp->h_name;
 	oldmask = sigblock(sigmask(SIGURG));
 	for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
-		s = rresvport(&lport);
+		s = rresvport_af(&lport, af);
 		if (s < 0) {
 			if (errno == EAGAIN)
 				(void)fprintf(stderr,
@@ -101,11 +117,19 @@
 		}
 		fcntl(s, F_SETOWN, pid);
 		bzero(&sin, sizeof sin);
-		sin.sin_len = sizeof(struct sockaddr_in);
 		sin.sin_family = hp->h_addrtype;
+		if (af == AF_INET) {
+			sin.sin_len = sizeof(struct sockaddr_in);
+			addr = (char *)&sin.sin_addr;
+		} else {
+			sin6.sin6_len = sizeof(struct sockaddr_in6);
+			sin6.sin6_flowinfo = IPV6_PRIORITY_UNCHARACTERIZED;
+			addr = (char *)&sin6.sin6_addr;
+		}
+		bcopy(hp->h_addr_list[0], addr,
+		      MIN(hp->h_length, sizeof(sin6.sin6_addr)));
 		sin.sin_port = rport;
-		bcopy(hp->h_addr_list[0], &sin.sin_addr, MIN(hp->h_length, sizeof sin.sin_addr));
-		if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
+		if (connect(s, (struct sockaddr *)&sin, sin.sin_len) >= 0)
 			break;
 		(void)close(s);
 		if (errno == EADDRINUSE) {
@@ -121,13 +145,14 @@
 			int oerrno = errno;
 
 			(void)fprintf(stderr, "connect to address %s: ",
-			    inet_ntoa(sin.sin_addr));
+			    inet_ntop(af, addr, vb, sizeof vb));
 			errno = oerrno;
 			perror(0);
 			hp->h_addr_list++;
-			bcopy(hp->h_addr_list[0], &sin.sin_addr, MIN(hp->h_length, sizeof sin.sin_addr));
+			bcopy(hp->h_addr_list[0], addr,
+			      MIN(hp->h_length, sizeof(sin6.sin6_addr)));
 			(void)fprintf(stderr, "Trying %s...\n",
-			    inet_ntoa(sin.sin_addr));
+			    inet_ntop(af, addr, vb, sizeof vb));
 			continue;
 		}
 		(void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno));
@@ -140,7 +165,7 @@
 		lport = 0;
 	} else {
 		char num[8];
-		int s2 = rresvport(&lport), s3;
+		int s2 = rresvport_af(&lport, af), s3;
 		int len = sizeof(from);
 		int nfds;
 
@@ -161,7 +186,7 @@
 			(void)close(s2);
 			goto bad;
 		}
-again:
+	again:
 		FD_ZERO(&reads);
 		FD_SET(s, &reads);
 		FD_SET(s2, &reads);
@@ -182,7 +207,9 @@
 		 * XXX careful for ftp bounce attacks. If discovered, shut them
 		 * down and check for the real auxiliary channel to connect.
 		 */
-		if (from.sin_family == AF_INET && from.sin_port == htons(20)) {
+		if ((from.sin_family == AF_INET ||
+		     from.sin_family == AF_INET6) &&
+		    from.sin_port == htons(20)) {
 			close(s3);
 			goto again;
 		}
@@ -194,8 +221,9 @@
 			goto bad;
 		}
 		*fd2p = s3;
-		from.sin_port = ntohs((u_short)from.sin_port);
-		if (from.sin_family != AF_INET ||
+		from.sin_port = ntohs(from.sin_port); /*ipv4 and ipv6 */
+		if ( (	(from.sin_family != AF_INET) &&
+			(from.sin_family != AF_INET6)) ||
 		    from.sin_port >= IPPORT_RESERVED ||
 		    from.sin_port < IPPORT_RESERVED / 2) {
 			(void)fprintf(stderr,
@@ -231,28 +259,47 @@
 }
 
 int
-rresvport(alport)
-	int *alport;
+rresvport_af(alport, af)
+	int *alport, af;
 {
-	struct sockaddr_in sin;
+	union sockaddr_u Sin;
+#define sin	Sin.s4
+#define sin6	Sin.s6
 	int s;
 
 	bzero(&sin, sizeof sin);
-	sin.sin_len = sizeof(struct sockaddr_in);
-	sin.sin_family = AF_INET;
-	sin.sin_addr.s_addr = INADDR_ANY;
-	s = socket(AF_INET, SOCK_STREAM, 0);
+	sin.sin_family = af;
+	if (af == AF_INET) {
+		sin.sin_len = sizeof(struct sockaddr_in);
+		sin.sin_addr.s_addr = INADDR_ANY;
+	} else if (af == AF_INET6) {
+		sin6.sin6_len = sizeof(struct sockaddr_in6);
+		sin6.sin6_flowinfo = IPV6_PRIORITY_UNCHARACTERIZED;
+		sin6.sin6_addr = in6addr_any;
+	} else {
+		errno = EAFNOSUPPORT;
+		return (-1);	/* todo: other AF_XX ? */
+	}
+	s = socket(af, SOCK_STREAM, 0);
 	if (s < 0)
 		return (-1);
 #if 0 /* compat_exact_traditional_rresvport_semantics */
-	sin.sin_port = htons((u_short)*alport);
-	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
-		return (s);
-	if (errno != EADDRINUSE) {
-		(void)close(s);
-		return (-1);
+	for (;;) {
+		sin.sin_port = htons((u_short)*alport); /* ipv4 and ipv6 */
+		if (bind(s, (struct sockaddr *)&sin, sin.sin_len) >= 0)
+			return (s);
+		if (errno != EADDRINUSE) {
+			(void)close(s);
+			return (-1);
+		}
+		(*alport)--;
+		if (*alport == IPPORT_RESERVED/2) {
+			(void)close(s);
+			errno = EAGAIN;		/* close */
+			return (-1);
+		}
 	}
-#endif
+#else
 	sin.sin_port = 0;
 	if (bindresvport(s, &sin) == -1) {
 		(void)close(s);
@@ -260,6 +307,14 @@
 	}
 	*alport = (int)ntohs(sin.sin_port);
 	return (s);
+#endif
+}
+
+int
+rresvport(alport)
+	int *alport;
+{
+	return rresvport_af(alport, AF_INET);
 }
 
 int	__check_rhosts_file = 1;
@@ -271,14 +326,13 @@
 	int superuser;
 {
 	struct hostent *hp;
-	u_long addr;
 	char **ap;
 
 	if ((hp = gethostbyname(rhost)) == NULL)
 		return (-1);
 	for (ap = hp->h_addr_list; *ap; ++ap) {
-		bcopy(*ap, &addr, sizeof(addr));
-		if (iruserok(addr, superuser, ruser, luser) == 0)
+		if (iruserok2(hp->h_addrtype, (char *)*ap, hp->h_length,
+			      superuser, ruser, luser) == 0)
 			return (0);
 	}
 	return (-1);
@@ -294,9 +348,9 @@
  * Returns 0 if ok, -1 if not ok.
  */
 int
-iruserok(raddr, superuser, ruser, luser)
-	u_long raddr;
-	int superuser;
+iruserok2(af, raddr, len, superuser, ruser, luser)
+	const char *raddr;
+	int superuser, len, af;
 	const char *ruser, *luser;
 {
 	register char *cp;
@@ -307,11 +361,15 @@
 	int first;
 	char pbuf[MAXPATHLEN];
 
+	if (af != AF_INET && af != AF_INET6) {
+		errno = EAFNOSUPPORT;
+		return (-1);	/* todo: other AF_XX ? */
+	}
 	first = 1;
 	hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r");
 again:
 	if (hostf) {
-		if (__ivaliduser(hostf, raddr, luser, ruser) == 0) {
+		if (__ivaliduser2(af, hostf, raddr, len, luser, ruser) == 0) {
 			(void)fclose(hostf);
 			return (0);
 		}
@@ -362,6 +420,15 @@
 	return (-1);
 }
 
+int
+iruserok(raddr, superuser, ruser, luser)
+	u_long raddr;
+	int superuser;
+	const char *ruser, *luser;
+{
+	return iruserok2(AF_INET, (char *)&raddr, sizeof(u_long), superuser, ruser, luser);
+}
+
 /*
  * XXX
  * Don't make static, used by lpd(8).
@@ -369,10 +436,10 @@
  * Returns 0 if ok, -1 if not ok.
  */
 int
-__ivaliduser(hostf, raddr, luser, ruser)
+__ivaliduser2(af, hostf, raddr, len, luser, ruser)
 	FILE *hostf;
-	u_long raddr;
-	const char *luser, *ruser;
+	const char *luser, *ruser, *raddr;
+	int len, af;
 {
 	register char *user, *p;
 	int ch;
@@ -384,14 +451,17 @@
 #ifdef YP
 	char *ypdomain;
 
-	if (yp_get_default_domain(&ypdomain))
+	if (af != AF_INET || yp_get_default_domain(&ypdomain))
 		ypdomain = NULL;
 #else
 #define	ypdomain NULL
 #endif
+	if (af != AF_INET && af != AF_INET6) {
+		errno = EAFNOSUPPORT;
+		return (-1);	/* todo: other AF_XX ? */
+	}
 	/* We need to get the damn hostname back for netgroup matching. */
-	if ((hp = gethostbyaddr((char *)&raddr, sizeof(u_long),
-							AF_INET)) == NULL)
+	if ((hp = gethostbyaddr(raddr, len, af)) == NULL)
 		return (-1);
 	strncpy(hname, hp->h_name, sizeof(hname));
 	hname[sizeof(hname) - 1] = '\0';
@@ -436,7 +506,7 @@
 				hostok = innetgr((char *)&buf[2],
 					(char *)&hname, NULL, ypdomain);
 			else		/* match a host by addr */
-				hostok = __icheckhost(raddr,(char *)&buf[1]);
+				hostok = __icheckhost2(raddr, len, (char *)&buf[1]);
 			break;
 		case '-':     /* reject '-' hosts and all their users */
 			if (buf[1] == '@') {
@@ -444,12 +514,12 @@
 					      (char *)&hname, NULL, ypdomain))
 					return(-1);
 			} else {
-				if (__icheckhost(raddr,(char *)&buf[1]))
+				if (__icheckhost2(raddr, len,(char *)&buf[1]))
 					return(-1);
 			}
 			break;
 		default:  /* if no '+' or '-', do a simple match */
-			hostok = __icheckhost(raddr, buf);
+			hostok = __icheckhost2(raddr, len, buf);
 			break;
 		}
 		switch(*user) {
@@ -488,29 +558,32 @@
 	return (-1);
 }
 
+int
+__ivaliduser(hostf, raddr, luser, ruser)
+	FILE *hostf;
+	u_long raddr;
+	const char *luser, *ruser;
+{
+	return __ivaliduser2(AF_INET, hostf, (char *)&raddr, sizeof(u_long), luser, ruser);
+}
+
 /*
  * Returns "true" if match, 0 if no match.
  */
 static int
-__icheckhost(raddr, lhost)
-	u_long raddr;
-	register char *lhost;
+__icheckhost2(raddr, len, lhost)
+	const char *lhost, *raddr;
+	int len;
 {
 	register struct hostent *hp;
-	register u_long laddr;
 	register char **pp;
 
-	/* Try for raw ip address first. */
-	if (isdigit(*lhost) && (long)(laddr = inet_addr(lhost)) != -1)
-		return (raddr == laddr);
-
-	/* Better be a hostname. */
-	if ((hp = gethostbyname(lhost)) == NULL)
+	if ((hp = gethostbyname(lhost)) == NULL)	/* also OK if addr */
 		return (0);
 
 	/* Spin through ip addresses. */
 	for (pp = hp->h_addr_list; *pp; ++pp)
-		if (!bcmp(&raddr, *pp, sizeof(u_long)))
+		if (len == hp->h_length && !bcmp(raddr, (char *)*pp, len))
 			return (1);
 
 	/* No match. */
diff -uN src-current/lib/libc/net/res_init.c src-current-ipv6/lib/libc/net/res_init.c
--- src-current/lib/libc/net/res_init.c
+++ src-current-ipv6/lib/libc/net/res_init.c
@@ -422,10 +422,35 @@
 			}
 			printf(";;\tdebug\n");
 #endif
-		} else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
+		} else if (!strncasecmp(cp, "mapipv6", sizeof("mapipv6") - 1)) {
+			_res.options |= RES_MAPINET6;
+#ifdef DEBUG
+			if (_res.options & RES_DEBUG)
+				printf(";;\tIPv6 is mapped to IPv4\n");
+#endif
+		} else if (!strncasecmp(cp, "mapsit", sizeof("mapsit") - 1)) {
+			_res.options |= RES_MAPSIT;
+#ifdef DEBUG
+			if (_res.options & RES_DEBUG)
+				printf(";;\tIPv4-compatible IPv6 is mapped to IPv4\n");
+#endif
+		} else if (!strncasecmp(cp, "strictipv6", sizeof("strictipv6") - 1)) {
+			_res.options |= RES_NOFALL6;
+#ifdef DEBUG
+			if (_res.options & RES_DEBUG)
+				printf(";;\tIPv4 is not tried if IPv6 fails\n");
+#endif
+		} else if (!strncasecmp(cp, "inet6", sizeof("inet6") - 1)) {
+			if (strncasecmp(source, "env", sizeof("env") - 1))
+				fprintf(stderr,
+		    "dangereous use of \"inet6\" resolver global option\n");
 			_res.options |= RES_USE_INET6;
 		} else if (!strncmp(cp, "no_tld_query", sizeof("no_tld_query") - 1)) {
 			_res.options |= RES_NOTLDQUERY;
+#ifdef DEBUG
+		} else if (_res.options & RES_DEBUG) {
+				printf(";;\tnew IPv6 API magic mapping\n");
+#endif
 		} else {
 			/* XXX - print a warning here? */
 		}
diff -uN src-current/lib/libc/net/resolver.3 src-current-ipv6/lib/libc/net/resolver.3
--- src-current/lib/libc/net/resolver.3
+++ src-current-ipv6/lib/libc/net/resolver.3
@@ -173,6 +173,19 @@
 This option turns off the user level aliasing feature controlled by the
 .Dq Ev HOSTALIASES
 environment variable.  Network daemons should set this option.
+.It Dv RES_USE_INET6
+Enable support for IPv6 addresses.
+.It Dv RES_MAPINET6
+This option silently remaps any request for an IPv6 address to
+a request for an IPv4 address, avoiding long timeouts when no IPv6
+informations are available.
+.It Dv RES_MAPSIT
+This option remaps reverse request for an IPv4-compatible IPv6 address to
+the reverse request for the associated IPv4 address.
+.It Dv RES_NOFALL6
+If this option is not set (the default) then when a request for
+an IPv6 address fails a search is done for an IPv4 address
+(which gives an IPv4-mapped IPv6 address).
 .El
 .Pp
 The
diff -uN src-current/lib/libc/rpc/svc_tcp.c src-current-ipv6/lib/libc/rpc/svc_tcp.c
--- src-current/lib/libc/rpc/svc_tcp.c
+++ src-current-ipv6/lib/libc/rpc/svc_tcp.c
@@ -129,21 +129,22 @@
 	bool_t madesock = FALSE;
 	register SVCXPRT *xprt;
 	register struct tcp_rendezvous *r;
-	struct sockaddr_in addr;
-	int len = sizeof(struct sockaddr_in);
+	RPC_SOCKADDR_IN addr;
+	int len;
 
 	if (sock == RPC_ANYSOCK) {
-		if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+		if ((sock = socket(AF_INETX, SOCK_STREAM, IPPROTO_TCP)) < 0) {
 			perror("svctcp_.c - udp socket creation problem");
 			return ((SVCXPRT *)NULL);
 		}
 		madesock = TRUE;
 	}
 	memset(&addr, 0, sizeof (addr));
-	addr.sin_len = sizeof(struct sockaddr_in);
-	addr.sin_family = AF_INET;
+	TOSINP(&addr)->sin_family = AF_INETX;
+	TOSINP(&addr)->sin_len = len = AF_INETX == AF_INET ?
+		sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
 	if (bindresvport(sock, &addr)) {
-		addr.sin_port = 0;
+		TOSINP(&addr)->sin_port = 0;
 		(void)bind(sock, (struct sockaddr *)&addr, len);
 	}
 	if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0)  ||
@@ -169,7 +170,7 @@
 	xprt->xp_p1 = (caddr_t)r;
 	xprt->xp_verf = _null_auth;
 	xprt->xp_ops = &svctcp_rendezvous_op;
-	xprt->xp_port = ntohs(addr.sin_port);
+	xprt->xp_port = ntohs(TOSINP(&addr)->sin_port);
 	xprt->xp_sock = sock;
 	xprt_register(xprt);
 	return (xprt);
@@ -231,12 +232,12 @@
 {
 	int sock;
 	struct tcp_rendezvous *r;
-	struct sockaddr_in addr;
+	RPC_SOCKADDR_IN addr;
 	int len;
 
 	r = (struct tcp_rendezvous *)xprt->xp_p1;
     again:
-	len = sizeof(struct sockaddr_in);
+	len = sizeof (addr);
 	if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr,
 	    &len)) < 0) {
 		if (errno == EINTR)
@@ -247,7 +248,7 @@
 	 * XXX careful for ftp bounce attacks. If discovered, close the
 	 * socket and look for another connection.
 	 */
-	if (addr.sin_port == htons(20)) {
+	if (TOSINP(&addr)->sin_port == htons(20)) {
 		close(sock);
 		goto again;
 	}
diff -uN src-current/lib/libc/rpc/clnt_tcp.c src-current-ipv6/lib/libc/rpc/clnt_tcp.c
--- src-current/lib/libc/rpc/clnt_tcp.c
+++ src-current-ipv6/lib/libc/rpc/clnt_tcp.c
@@ -88,7 +88,10 @@
 	bool_t		ct_closeit;
 	struct timeval	ct_wait;
 	bool_t          ct_waitset;       /* wait set by clnt_control? */
-	struct sockaddr_in ct_addr;
+	RPC_SOCKADDR_IN Ct_addr;
+#define ct_addr		Ct_addr.s4
+#define ct_addr6	Ct_addr.s6
+	int		ct_rlen;
 	struct rpc_err	ct_error;
 	char		ct_mcall[MCALL_MSG_SIZE];	/* marshalled callmsg */
 	u_int		ct_mpos;			/* pos after marshal */
@@ -110,8 +113,9 @@
  * something more useful.
  */
 CLIENT *
-clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
-	struct sockaddr_in *raddr;
+clnttcp_create(Raddr, prog, vers, sockp, sendsz, recvsz)
+	RPC_SOCKADDR_IN *Raddr;
+#define raddr	TOSINP(Raddr)
 	u_long prog;
 	u_long vers;
 	register int *sockp;
@@ -147,23 +151,25 @@
 	 */
 	if (raddr->sin_port == 0) {
 		u_short port;
-		if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) {
+		if ((port = pmap_getport(Raddr, prog, vers, IPPROTO_TCP)) == 0) {
 			mem_free((caddr_t)ct, sizeof(struct ct_data));
 			mem_free((caddr_t)h, sizeof(CLIENT));
 			return ((CLIENT *)NULL);
 		}
 		raddr->sin_port = htons(port);
 	}
+	ct->ct_rlen = (raddr->sin_family == AF_INET6) ?
+			sizeof (ct->ct_addr6) : sizeof (ct->ct_addr);
 
 	/*
 	 * If no socket given, open one
 	 */
 	if (*sockp < 0) {
-		*sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-		(void)bindresvport(*sockp, (struct sockaddr_in *)0);
+		*sockp = socket(raddr->sin_family, SOCK_STREAM, IPPROTO_TCP);
+		(void)bindresvport(*sockp, (RPC_SOCKADDR_IN *)0);
 		if ((*sockp < 0)
 		    || (connect(*sockp, (struct sockaddr *)raddr,
-		    sizeof(*raddr)) < 0)) {
+				ct->ct_rlen) < 0)) {
 			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
 			rpc_createerr.cf_error.re_errno = errno;
 			if (*sockp != -1)
@@ -181,7 +187,7 @@
 	ct->ct_sock = *sockp;
 	ct->ct_wait.tv_usec = 0;
 	ct->ct_waitset = FALSE;
-	ct->ct_addr = *raddr;
+	bcopy(raddr, &ct->ct_addr, ct->ct_rlen);
 
 	/*
 	 * Initialize call message
@@ -389,7 +395,7 @@
 	case CLGET_SERVER_ADDR:
 		if (info == NULL)
 			return(FALSE);
-		*(struct sockaddr_in *)info = ct->ct_addr;
+		memcpy(info, &ct->ct_addr, ct->ct_rlen);
 		break;
 	case CLGET_FD:
 		if (info == NULL)
diff -uN src-current/lib/libc/rpc/Makefile.inc src-current-ipv6/lib/libc/rpc/Makefile.inc
--- src-current/lib/libc/rpc/Makefile.inc
+++ src-current-ipv6/lib/libc/rpc/Makefile.inc
@@ -23,6 +23,8 @@
 
 CLEANFILES+= crypt_clnt.c crypt_xdr.c crypt.h
 
+CFLAGS += -DRPC_USE_INET_ANY
+
 RPCDIR= ${DESTDIR}/usr/include/rpcsvc
 RPCGEN= rpcgen -C
 
diff -uN src-current/lib/libc/rpc/bindresvport.3 src-current-ipv6/lib/libc/rpc/bindresvport.3
--- src-current/lib/libc/rpc/bindresvport.3
+++ src-current-ipv6/lib/libc/rpc/bindresvport.3
@@ -9,7 +9,7 @@
 .Fd #include <sys/types.h>
 .Fd #include <netinet/in.h>
 .Ft int
-.Fn bindresvport "int sd" "struct sockaddr_in **sin"
+.Fn bindresvport "int sd" "RPC_SOCKADDR_IN *sin"
 .Sh DESCRIPTION
 .Nm Bindresvport
 is used to bind a socket descriptor to a privileged
@@ -20,6 +20,10 @@
 otherwise -1 is returned and
 .Va errno
 set to reflect the cause of the error.
+.Pp
+If sd is a
+.Dv AF_INET6
+socket, the sin argument must be a pointer to a sockaddr_in6 structure.
 .Pp
 Only root can bind to a privileged port; this call will fail for any
 other users.
diff -uN src-current/lib/libc/rpc/bindresvport.c src-current-ipv6/lib/libc/rpc/bindresvport.c
--- src-current/lib/libc/rpc/bindresvport.c
+++ src-current-ipv6/lib/libc/rpc/bindresvport.c
@@ -44,6 +44,7 @@
 #include <sys/errno.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <rpc/rpc.h>
 #include <unistd.h>
 #include <string.h>
 
@@ -53,23 +54,35 @@
 int
 bindresvport(sd, sin)
 	int sd;
-	struct sockaddr_in *sin;
+	RPC_SOCKADDR_IN *sin;
 {
 	int on, old, error;
-	struct sockaddr_in myaddr;
-	int sinlen = sizeof(struct sockaddr_in);
+	RPC_SOCKADDR_IN myaddr;
+	int sinfam, sinlen;
 
-	if (sin == (struct sockaddr_in *)0) {
-		sin = &myaddr;
-		memset(sin, 0, sinlen);
-		sin->sin_len = sinlen;
-		sin->sin_family = AF_INET;
-	} else if (sin->sin_family != AF_INET) {
+	if (sin == (RPC_SOCKADDR_IN *)0 ||
+	    TOSINP(sin)->sin_family == AF_UNSPEC) {
+		sinlen = sizeof (myaddr);
+		if (getsockname(sd, (struct sockaddr *)&myaddr, &sinlen) != 0)
+			return (-1);
+		sinfam = TOSINP(&myaddr)->sin_family;
+		if (sin == (RPC_SOCKADDR_IN *)0) {
+			sin = &myaddr;
+			memset(sin, 0, sizeof (myaddr));
+		}
+		TOSINP(sin)->sin_family = sinfam;
+	}
+	if (TOSINP(sin)->sin_family != AF_INET &&
+	    TOSINP(sin)->sin_family != AF_INET6) {
 		errno = EPFNOSUPPORT;
 		return (-1);
 	}
+	sinlen = TOSINP(sin)->sin_family == AF_INET6 ?
+			sizeof (struct sockaddr_in6) :
+			sizeof (struct sockaddr_in);
+	TOSINP(sin)->sin_len = sinlen;
 
-	if (sin->sin_port == 0) {
+	if (TOSINP(sin)->sin_port == 0) {
 		int oldlen = sizeof(old);
 		error = getsockopt(sd, IPPROTO_IP, IP_PORTRANGE,
 				   &old, &oldlen);
@@ -85,7 +98,7 @@
 
 	error = bind(sd, (struct sockaddr *)sin, sinlen);
 
-	if (sin->sin_port == 0) {
+	if (TOSINP(sin)->sin_port == 0) {
 		int saved_errno = errno;
 
 		if (error) {
diff -uN src-current/lib/libc/rpc/clnt_generic.c src-current-ipv6/lib/libc/rpc/clnt_generic.c
--- src-current/lib/libc/rpc/clnt_generic.c
+++ src-current-ipv6/lib/libc/rpc/clnt_generic.c
@@ -40,7 +40,6 @@
 #include <sys/socket.h>
 #include <sys/errno.h>
 #include <netdb.h>
-#include <string.h>
 
 /*
  * Generic client creation: takes (hostname, program-number, protocol) and
@@ -56,7 +55,9 @@
 {
 	struct hostent *h;
 	struct protoent *p;
-	struct sockaddr_in sin;
+	RPC_SOCKADDR_IN Sin;
+#define sin	Sin.s4
+#define sin6	Sin.s6
 	struct sockaddr_un sun;
 	int sock;
 	static struct timeval tv;
@@ -83,19 +84,23 @@
 		rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
 		return (NULL);
 	}
-	if (h->h_addrtype != AF_INET) {
+
+	if (h->h_addrtype == AF_INET6) {
+		sin6.sin6_flowinfo = IPV6_PRIORITY_UNCHARACTERIZED;
+		memcpy((char*)&sin6.sin6_addr, h->h_addr, h->h_length);
+	} else if (h->h_addrtype == AF_INET) {
+		bzero(sin.sin_zero, sizeof(sin.sin_zero));
+		memcpy((char*)&sin.sin_addr, h->h_addr, h->h_length);
+	} else {
 		/*
-		 * Only support INET for now
+		 * Only support INET/INET6 for now
 		 */
 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
 		rpc_createerr.cf_error.re_errno = EAFNOSUPPORT;
 		return (NULL);
 	}
-	memset(&sin, 0, sizeof(sin));
-	sin.sin_len = sizeof(struct sockaddr_in);
 	sin.sin_family = h->h_addrtype;
 	sin.sin_port = 0;
-	memcpy((char*)&sin.sin_addr, h->h_addr, h->h_length);
 	p = getprotobyname(proto);
 	if (p == NULL) {
 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
@@ -107,7 +112,7 @@
 	case IPPROTO_UDP:
 		tv.tv_sec = 5;
 		tv.tv_usec = 0;
-		client = clntudp_create(&sin, prog, vers, tv, &sock);
+		client = clntudp_create(&Sin, prog, vers, tv, &sock);
 		if (client == NULL) {
 			return (NULL);
 		}
@@ -118,7 +123,7 @@
 #endif
 		break;
 	case IPPROTO_TCP:
-		client = clnttcp_create(&sin, prog, vers, &sock, 0, 0);
+		client = clnttcp_create(&Sin, prog, vers, &sock, 0, 0);
 		if (client == NULL) {
 			return (NULL);
 		}
diff -uN src-current/lib/libc/rpc/clnt_simple.c src-current-ipv6/lib/libc/rpc/clnt_simple.c
--- src-current/lib/libc/rpc/clnt_simple.c
+++ src-current-ipv6/lib/libc/rpc/clnt_simple.c
@@ -64,7 +64,9 @@
 	char *in, *out;
 {
 	register struct callrpc_private *crp = callrpc_private;
-	struct sockaddr_in server_addr;
+	RPC_SOCKADDR_IN Server_addr;
+#define server_addr	Server_addr.s4
+#define server_addr6	Server_addr.s6
 	enum clnt_stat clnt_stat;
 	struct hostent *hp;
 	struct timeval timeout, tottimeout;
@@ -97,11 +99,21 @@
 		timeout.tv_usec = 0;
 		timeout.tv_sec = 5;
 		memset(&server_addr, 0, sizeof(server_addr));
-		memcpy((char *)&server_addr.sin_addr, hp->h_addr, hp->h_length);
-		server_addr.sin_len = sizeof(struct sockaddr_in);
-		server_addr.sin_family = AF_INET;
+		if (hp->h_addrtype == AF_INET6) {
+			server_addr6.sin6_len = sizeof(struct sockaddr_in6);
+			server_addr6.sin6_flowinfo = IPV6_PRIORITY_UNCHARACTERIZED;
+			memcpy((char *)&server_addr6.sin6_addr,
+			       hp->h_addr,
+			       hp->h_length);
+		} else {
+			server_addr.sin_len = sizeof(struct sockaddr_in);
+			memcpy((char *)&server_addr.sin_addr,
+			       hp->h_addr,
+			       hp->h_length);
+		}
+		server_addr.sin_family = hp->h_addrtype;
 		server_addr.sin_port =  0;
-		if ((crp->client = clntudp_create(&server_addr, (u_long)prognum,
+		if ((crp->client = clntudp_create(&Server_addr, (u_long)prognum,
 		    (u_long)versnum, timeout, &crp->socket)) == NULL)
 			return ((int) rpc_createerr.cf_stat);
 		crp->valid = 1;
diff -uN src-current/lib/libc/rpc/clnt_udp.c src-current-ipv6/lib/libc/rpc/clnt_udp.c
--- src-current/lib/libc/rpc/clnt_udp.c
+++ src-current-ipv6/lib/libc/rpc/clnt_udp.c
@@ -75,7 +75,9 @@
 struct cu_data {
 	int		   cu_sock;
 	bool_t		   cu_closeit;
-	struct sockaddr_in cu_raddr;
+	RPC_SOCKADDR_IN    Cu_raddr;
+#define cu_raddr	Cu_raddr.s4
+#define cu_raddr6	Cu_raddr.s6
 	int		   cu_rlen;
 	struct timeval	   cu_wait;
 	struct timeval     cu_total;
@@ -105,8 +107,9 @@
  * sent and received.
  */
 CLIENT *
-clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz)
-	struct sockaddr_in *raddr;
+clntudp_bufcreate(Raddr, program, version, wait, sockp, sendsz, recvsz)
+	RPC_SOCKADDR_IN *Raddr;
+#define raddr	TOSINP(Raddr)
 	u_long program;
 	u_long version;
 	struct timeval wait;
@@ -145,15 +148,16 @@
 	if (raddr->sin_port == 0) {
 		u_short port;
 		if ((port =
-		    pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
+		    pmap_getport(Raddr, program, version, IPPROTO_UDP)) == 0) {
 			goto fooy;
 		}
 		raddr->sin_port = htons(port);
 	}
 	cl->cl_ops = &udp_ops;
 	cl->cl_private = (caddr_t)cu;
-	cu->cu_raddr = *raddr;
-	cu->cu_rlen = sizeof (cu->cu_raddr);
+	cu->cu_rlen = (raddr->sin_family == AF_INET6) ?
+			sizeof (cu->cu_raddr6) : sizeof (cu->cu_raddr);
+	bcopy(raddr, &cu->cu_raddr, cu->cu_rlen);
 	cu->cu_wait = wait;
 	cu->cu_total.tv_sec = -1;
 	cu->cu_total.tv_usec = -1;
@@ -173,14 +177,16 @@
 	if (*sockp < 0) {
 		int dontblock = 1;
 
-		*sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+		*sockp = socket(cu->cu_raddr.sin_family,
+				SOCK_DGRAM,
+				IPPROTO_UDP);
 		if (*sockp < 0) {
 			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
 			rpc_createerr.cf_error.re_errno = errno;
 			goto fooy;
 		}
-		/* attempt to bind to priv port */
-		(void)bindresvport(*sockp, (struct sockaddr_in *)0);
+		/* attempt to bind to prov port */
+		(void)bindresvport(*sockp, (RPC_SOCKADDR_IN *)0);
 		/* the sockets rpc controls are non-blocking */
 		(void)ioctl(*sockp, FIONBIO, (char *) &dontblock);
 		cu->cu_closeit = TRUE;
@@ -197,10 +203,11 @@
 		mem_free((caddr_t)cl, sizeof(CLIENT));
 	return ((CLIENT *)NULL);
 }
+#undef raddr
 
 CLIENT *
 clntudp_create(raddr, program, version, wait, sockp)
-	struct sockaddr_in *raddr;
+	RPC_SOCKADDR_IN *raddr;
 	u_long program;
 	u_long version;
 	struct timeval wait;
@@ -227,7 +234,7 @@
 	register int inlen;
 	int fromlen;
 	fd_set *fds, readfds;
-	struct sockaddr_in from;
+	RPC_SOCKADDR_IN from;
 	struct rpc_msg reply_msg;
 	XDR reply_xdrs;
 	struct timeval time_waited, start, after, tmp1, tmp2, tv;
@@ -331,7 +338,7 @@
 		}
 
 		do {
-			fromlen = sizeof(struct sockaddr);
+			fromlen = sizeof from;
 			inlen = recvfrom(cu->cu_sock, cu->cu_inbuf,
 				(int) cu->cu_recvsz, 0,
 				(struct sockaddr *)&from, &fromlen);
@@ -478,7 +485,7 @@
 	case CLGET_SERVER_ADDR:
 		if (info == NULL)
 			return(FALSE);
-		*(struct sockaddr_in *)info = cu->cu_raddr;
+		memcpy(info, &cu->cu_raddr, cu->cu_rlen);
 		break;
 	case CLGET_FD:
 		if (info == NULL)
diff -uN src-current/lib/libc/rpc/get_myaddress.c src-current-ipv6/lib/libc/rpc/get_myaddress.c
--- src-current/lib/libc/rpc/get_myaddress.c
+++ src-current-ipv6/lib/libc/rpc/get_myaddress.c
@@ -40,8 +40,7 @@
  * Copyright (C) 1984, Sun Microsystems, Inc.
  */
 
-#include <rpc/types.h>
-#include <rpc/xdr.h>
+#include <rpc/rpc.h>
 #include <rpc/pmap_prot.h>
 #include <sys/socket.h>
 #include <stdio.h>
@@ -56,16 +55,21 @@
  *
  * Avoid loopback interfaces.  We return information from a loopback
  * interface only if there are no other possible interfaces.
+ *
+ * If asking for IPv6, send back an IPv6 address if possible
+ * If not try for an IPv4 mapped address
  */
 int
 get_myaddress(addr)
-	struct sockaddr_in *addr;
+	RPC_SOCKADDR_IN *addr;
 {
 	int s;
 	char buf[BUFSIZ];
 	struct ifconf ifc;
 	struct ifreq ifreq, *ifr, *end;
 	int loopback = 0, gotit = 0;
+	struct in_addr ad4;
+	int done = 0;
 
 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 		return(-1);
@@ -87,16 +91,21 @@
 			return(-1);
 		}
 		if (((ifreq.ifr_flags & IFF_UP) &&
-		    ifr->ifr_addr.sa_family == AF_INET &&
+		    ifr->ifr_addr.sa_family == AF_INETX &&
 			!(ifreq.ifr_flags & IFF_LOOPBACK)) ||
 		    (loopback == 1 && (ifreq.ifr_flags & IFF_LOOPBACK)
-			&& (ifr->ifr_addr.sa_family == AF_INET)
+			&& (ifr->ifr_addr.sa_family == AF_INETX)
 			&& (ifreq.ifr_flags &  IFF_UP))) {
-			*addr = *((struct sockaddr_in *)&ifr->ifr_addr);
-			addr->sin_port = htons(PMAPPORT);
+			memcpy(addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
 			gotit = 1;
+			done = 1;
 			break;
 		}
+		if ((ifreq.ifr_flags & IFF_UP) && done == 0 &&
+		    ifr->ifr_addr.sa_family == AF_INET) {
+			ad4 = TOSINP(&ifr->ifr_addr)->sin_addr;
+			done = -1;
+		}
 		if (ifr->ifr_addr.sa_len)
 			ifr = (struct ifreq *) ((caddr_t) ifr +
 			      ifr->ifr_addr.sa_len -
@@ -108,5 +117,21 @@
 		goto again;
 	}
 	(void) close(s);
+	if (done == 0)
+		errx(1, "get_myaddress: no address found");
+	if (done < 0) {
+#define OFFAD4	(sizeof(struct in6_addr) - sizeof(struct in_addr))
+#define LGMAP	2
+		memset(addr, 0, sizeof (struct sockaddr_in6));
+		TOSINP6(addr)->sin6_len = sizeof (struct sockaddr_in6);
+		TOSINP6(addr)->sin6_family = AF_INET6;
+		memcpy(((char *)&TOSINP6(addr)->sin6_addr) + OFFAD4,
+		       &ad4,
+		       sizeof(struct in_addr));
+		memset(((char *)&TOSINP6(addr)->sin6_addr)+ OFFAD4 - LGMAP,
+		       -1, LGMAP);
+		gotit = 1;
+	}
+	TOSINP(addr)->sin_port = htons(PMAPPORT);
 	return (gotit ? 0 : -1);
 }
diff -uN src-current/lib/libc/rpc/pmap_clnt.c src-current-ipv6/lib/libc/rpc/pmap_clnt.c
--- src-current/lib/libc/rpc/pmap_clnt.c
+++ src-current-ipv6/lib/libc/rpc/pmap_clnt.c
@@ -68,7 +68,7 @@
 	int protocol;
 	u_short port;
 {
-	struct sockaddr_in myaddress;
+	RPC_SOCKADDR_IN myaddress;
 	int socket = -1;
 	register CLIENT *client;
 	struct pmap parms;
@@ -84,7 +84,11 @@
 	else  {
 		if (get_myaddress(&myaddress) != 0)
 			return (FALSE);
-		myaddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+		if (TOSINP(&myaddress)->sin_family == AF_INET)
+			TOSINP(&myaddress)->sin_addr.s_addr
+				= htonl(INADDR_LOOPBACK);
+		else if (TOSINP(&myaddress)->sin_family == AF_INET6)
+			TOSINP6(&myaddress)->sin6_addr = in6addr_loopback;
 		client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS,
 	    		timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
 	}
@@ -115,7 +119,7 @@
 	u_long program;
 	u_long version;
 {
-	struct sockaddr_in myaddress;
+	RPC_SOCKADDR_IN myaddress;
 	int socket = -1;
 	register CLIENT *client;
 	struct pmap parms;
@@ -131,7 +135,11 @@
 	else {
 		if (get_myaddress(&myaddress) != 0)
 			return (FALSE);
-		myaddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+		if (TOSINP(&myaddress)->sin_family == AF_INET)
+			TOSINP(&myaddress)->sin_addr.s_addr
+				= htonl(INADDR_LOOPBACK);
+		else if (TOSINP(&myaddress)->sin_family == AF_INET6)
+			TOSINP6(&myaddress)->sin6_addr = in6addr_loopback;
 		client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS,
 	    		timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
 	}
diff -uN src-current/lib/libc/rpc/getrpcport.c src-current-ipv6/lib/libc/rpc/getrpcport.c
--- src-current/lib/libc/rpc/getrpcport.c
+++ src-current-ipv6/lib/libc/rpc/getrpcport.c
@@ -44,20 +44,30 @@
 #include <netdb.h>
 #include <sys/socket.h>
 
+u_short pmap_getport(RPC_SOCKADDR_IN *, u_long, u_long, u_int);
+
 int
 getrpcport(host, prognum, versnum, proto)
 	char *host;
 	int prognum, versnum, proto;
 {
-	struct sockaddr_in addr;
+	RPC_SOCKADDR_IN Addr;
+#define addr	Addr.s4
+#define addr6	Addr.s6
 	struct hostent *hp;
 
 	if ((hp = gethostbyname(host)) == NULL)
 		return (0);
 	memset(&addr, 0, sizeof(addr));
-	addr.sin_len = sizeof(struct sockaddr_in);
-	addr.sin_family = AF_INET;
+	if (hp->h_addrtype == AF_INET6) {
+		addr6.sin6_len = sizeof(struct sockaddr_in6);
+		addr6.sin6_flowinfo = IPV6_PRIORITY_UNCHARACTERIZED;
+		memcpy((char*)&addr6.sin6_addr, hp->h_addr, hp->h_length);
+	} else {
+		addr.sin_len = sizeof(struct sockaddr_in);
+		memcpy((char *) &addr.sin_addr, hp->h_addr, hp->h_length);
+	}
+	addr.sin_family = hp->h_addrtype;
 	addr.sin_port =  0;
-	memcpy((char *)&addr.sin_addr, hp->h_addr, hp->h_length);
-	return (pmap_getport(&addr, prognum, versnum, proto));
+	return (pmap_getport(&Addr, prognum, versnum, proto));
 }
diff -uN src-current/lib/libc/rpc/pmap_getmaps.c src-current-ipv6/lib/libc/rpc/pmap_getmaps.c
--- src-current/lib/libc/rpc/pmap_getmaps.c
+++ src-current-ipv6/lib/libc/rpc/pmap_getmaps.c
@@ -60,7 +60,7 @@
  */
 struct pmaplist *
 pmap_getmaps(address)
-	 struct sockaddr_in *address;
+	 RPC_SOCKADDR_IN *address;
 {
 	struct pmaplist *head = (struct pmaplist *)NULL;
 	int socket = -1;
@@ -69,7 +69,7 @@
 
 	minutetimeout.tv_sec = 60;
 	minutetimeout.tv_usec = 0;
-	address->sin_port = htons(PMAPPORT);
+	TOSINP(address)->sin_port = htons(PMAPPORT);
 	client = clnttcp_create(address, PMAPPROG,
 	    PMAPVERS, &socket, 50, 500);
 	if (client != (CLIENT *)NULL) {
@@ -81,6 +81,6 @@
 	}
 	if (socket != -1)
 		(void)close(socket);
-	address->sin_port = 0;
+	TOSINP(address)->sin_port = 0;
 	return (head);
 }
diff -uN src-current/lib/libc/rpc/pmap_getport.c src-current-ipv6/lib/libc/rpc/pmap_getport.c
--- src-current/lib/libc/rpc/pmap_getport.c
+++ src-current-ipv6/lib/libc/rpc/pmap_getport.c
@@ -57,7 +57,7 @@
  */
 u_short
 pmap_getport(address, program, version, protocol)
-	struct sockaddr_in *address;
+	RPC_SOCKADDR_IN *address;
 	u_long program;
 	u_long version;
 	u_int protocol;
@@ -67,7 +67,7 @@
 	register CLIENT *client;
 	struct pmap parms;
 
-	address->sin_port = htons(PMAPPORT);
+	TOSINP(address)->sin_port = htons(PMAPPORT);
 	client = clntudp_bufcreate(address, PMAPPROG,
 	    PMAPVERS, timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
 	if (client != (CLIENT *)NULL) {
@@ -86,6 +86,6 @@
 	}
 	if (socket != -1)
 		(void)close(socket);
-	address->sin_port = 0;
+	TOSINP(address)->sin_port = 0;
 	return (port);
 }
diff -uN src-current/lib/libc/rpc/pmap_rmt.c src-current-ipv6/lib/libc/rpc/pmap_rmt.c
--- src-current/lib/libc/rpc/pmap_rmt.c
+++ src-current-ipv6/lib/libc/rpc/pmap_rmt.c
@@ -67,7 +67,7 @@
 */
 enum clnt_stat
 pmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr)
-	struct sockaddr_in *addr;
+	RPC_SOCKADDR_IN *addr;
 	u_long prog, vers, proc;
 	xdrproc_t xdrargs, xdrres;
 	caddr_t argsp, resp;
@@ -80,7 +80,7 @@
 	struct rmtcallres r;
 	enum clnt_stat stat;
 
-	addr->sin_port = htons(PMAPPORT);
+	TOSINP(addr)->sin_port = htons(PMAPPORT);
 	client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &socket);
 	if (client != (CLIENT *)NULL) {
 		a.prog = prog;
@@ -99,7 +99,7 @@
 	}
 	if (socket != -1)
 		(void)close(socket);
-	addr->sin_port = 0;
+	TOSINP(addr)->sin_port = 0;
 	return (stat);
 }
 
@@ -161,7 +161,6 @@
  * Someday a large, complicated system will replace these trivial
  * routines which only support udp/ip .
  */
-
 static int
 getbroadcastnets(addrs, sock, buf)
 	struct in_addr *addrs;
@@ -248,7 +247,12 @@
 	register u_long xid;
 	u_long port;
 	struct in_addr addrs[20];
-	struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
+	int intf[20], af;
+	RPC_SOCKADDR_IN Baddr, Raddr; /* broadcast and response addresses */
+#define baddr	Baddr.s4
+#define baddr6	Baddr.s6
+#define raddr	Raddr.s4
+#define raddr6	Raddr.s6
 	struct rmtcallargs a;
 	struct rmtcallres r;
 	struct rpc_msg msg;
@@ -263,17 +267,20 @@
 	 * initialization: create a socket, a broadcast address, and
 	 * preserialize the arguments into a send buffer.
 	 */
-	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+	af = AF_INETX;
+	if ((sock = socket(af, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
 		perror("Cannot create socket for broadcast rpc");
 		stat = RPC_CANTSEND;
 		goto done_broad;
 	}
 #ifdef SO_BROADCAST
-	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
-		perror("Cannot set socket option SO_BROADCAST");
-		stat = RPC_CANTSEND;
-		goto done_broad;
-	}
+	if (af == AF_INET)
+		if (setsockopt(sock, SOL_SOCKET,
+			       SO_BROADCAST, &on, sizeof (on)) < 0) {
+			perror("Cannot set socket option SO_BROADCAST");
+			stat = RPC_CANTSEND;
+			goto done_broad;
+		}
 #endif /* def SO_BROADCAST */
 	if (sock + 1 > FD_SETSIZE) {
 		int bytes = howmany(sock + 1, NFDBITS) * sizeof(fd_mask);
@@ -288,12 +295,26 @@
 		FD_ZERO(fds);
 	}
 
-	nets = getbroadcastnets(addrs, sock, inbuf);
-	memset(&baddr, 0, sizeof (baddr));
-	baddr.sin_len = sizeof(struct sockaddr_in);
-	baddr.sin_family = AF_INET;
+	memset(&Baddr, 0, sizeof (Baddr));
+	baddr.sin_family = af;
 	baddr.sin_port = htons(PMAPPORT);
-	baddr.sin_addr.s_addr = htonl(INADDR_ANY);
+	if (af == AF_INET) {
+		nets = getbroadcastnets(addrs, sock, inbuf);
+		baddr.sin_addr.s_addr = htonl(INADDR_ANY);
+		baddr.sin_len = sizeof (baddr);
+	} else {
+		struct if_nameindex *all = if_nameindex(), *p;
+		nets = 0;
+
+		for (p = all; p->if_index; p++)
+			intf[nets++] = p->if_index;
+		if_freenameindex(all);
+		baddr6.sin6_flowinfo = IPV6_PRIORITY_UNCHARACTERIZED;
+		baddr6.sin6_addr.s6_addr[0] = 0xff;
+		baddr6.sin6_addr.s6_addr[1] = MADDR6_SCP_LINK;
+		baddr6.sin6_addr.s6_addr[15] = MADDR6_ALLNODES;
+		baddr6.sin6_len = sizeof (baddr6);
+	}
 	(void)gettimeofday(&t, (struct timezone *)0);
 	msg.rm_xid = xid = (++disrupt) ^ getpid() ^ t.tv_sec ^ t.tv_usec;
 	t.tv_usec = 0;
@@ -331,10 +352,23 @@
 	 */
 	for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) {
 		for (i = 0; i < nets; i++) {
-			baddr.sin_addr = addrs[i];
+			if (af == AF_INET)
+				baddr.sin_addr = addrs[i];
+			else {
+				if (!intf[i])
+					continue;
+				if (setsockopt(sock,
+					       IPPROTO_IPV6,
+					       IPV6_MULTICAST_IF,
+					       &intf[i],
+					       sizeof (intf[i])) < 0) {
+					intf[i] = 0;
+					continue;
+				}
+			}
 			if (sendto(sock, outbuf, outlen, 0,
-				(struct sockaddr *)&baddr,
-				sizeof (struct sockaddr)) != outlen) {
+				   (struct sockaddr *)&baddr,
+				   baddr.sin_len) != outlen) {
 				perror("Cannot send broadcast packet");
 				stat = RPC_CANTSEND;
 				goto done_broad;
@@ -366,7 +400,7 @@
 
 		}  /* end of select results switch */
 	try_again:
-		fromlen = sizeof(struct sockaddr);
+		fromlen = sizeof(Raddr);
 		inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0,
 			(struct sockaddr *)&raddr, &fromlen);
 		if (inlen < 0) {
diff -uN src-current/lib/libc/rpc/rpc.3 src-current-ipv6/lib/libc/rpc/rpc.3
--- src-current/lib/libc/rpc/rpc.3
+++ src-current-ipv6/lib/libc/rpc/rpc.3
@@ -725,7 +725,7 @@
 The total time for the call to time out is specified by
 .BR clnt_call(\|) .
 .IP
-This allows the user to specify the maximum packet size for sending and receiving 
+This allows the user to specify the maximum packet size for sending and receiving
 .SM UDP\s0-based
 .SM RPC
 messages.
@@ -735,9 +735,9 @@
 .ft B
 .nf
 .sp .5
-int
+void
 get_myaddress(addr)
-struct sockaddr_in *addr;
+RPC_SOCKADDR_IN *addr;
 .fi
 .ft R
 .IP
@@ -1716,6 +1716,41 @@
 This routine modifies the global variable
 .BR svc_fds(\|) .
 Service implementors usually do not need this routine.
+.SH IPv6 SUPPPORT
+The rpc library has been ported to IPv6.
+All input sockets parameters can be either AF_INET or AF_INET6 sockets.
+All input parameters which are pointers to sockaddr_in structures can also
+point to sockaddr_in6 structures (with a sa_family field of AF_INET6).
+To avoid compiler warnings, the pointer should be casted to
+(struct sockaddr_in*).
+One can also add a #define RPC_USE_INET6 before including the rpc includes.
+In that case all address arguments are of type struct sockaddr_in6 *.
+.LP
+If there is a input sockaddr argument (as in function
+.BR clntudp_create ),
+the family of any created socket is derived from the family of the sockaddr
+argument.
+If there is a no sockaddr argument (as in function
+.BR clnt_create ),
+the family of any created socket is derived from the DNS environement: 
+if the RES_USE_INET6 resolver option is set, all created sockets are IPv6.
+Otherwise they are IPv4.
+.LP
+If the RES_USE_INET6 resolver option is set, the function
+.B clnt_broadcast
+sends its messages on all the interfaces, with as destination the multicast
+IPv6 address ALL_NODES (ff02::1).
+.LP
+A sockaddr structure returned by functions
+.B clnttcp_control
+and
+.B clntudp_control
+can be a sockaddr_in6 structure if the associated connection is an IPv6 one.
+Therefore the allocated space for the returned value must be big enough.
+A sockaddr structure returned by the function
+.BR get_myaddress
+is a sockaddr_in6 structure if the RES_USE_INET6 resolver option is set.
+Therefore the allocated space for the returned value must be big enough.
 .SH SEE ALSO
 .BR rpc_secure (3),
 .BR xdr (3)
diff -uN src-current/lib/libc/rpc/svc_udp.c src-current-ipv6/lib/libc/rpc/svc_udp.c
--- src-current/lib/libc/rpc/svc_udp.c
+++ src-current-ipv6/lib/libc/rpc/svc_udp.c
@@ -50,6 +50,7 @@
 #include <errno.h>
 
 #define rpc_buffer(xprt) ((xprt)->xp_p1)
+#undef MAX
 #define MAX(a, b)     ((a > b) ? a : b)
 
 static bool_t		svcudp_recv();
@@ -103,21 +104,22 @@
 	bool_t madesock = FALSE;
 	register SVCXPRT *xprt;
 	register struct svcudp_data *su;
-	struct sockaddr_in addr;
-	int len = sizeof(struct sockaddr_in);
+	RPC_SOCKADDR_IN addr;
+	int len;
 
 	if (sock == RPC_ANYSOCK) {
-		if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+		if ((sock = socket(AF_INETX, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
 			perror("svcudp_create: socket creation problem");
 			return ((SVCXPRT *)NULL);
 		}
 		madesock = TRUE;
 	}
 	memset((char *)&addr, 0, sizeof (addr));
-	addr.sin_len = sizeof(struct sockaddr_in);
-	addr.sin_family = AF_INET;
+	TOSINP(&addr)->sin_family = AF_INETX;
+	TOSINP(&addr)->sin_len = len = AF_INETX == AF_INET ?
+		sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
 	if (bindresvport(sock, &addr)) {
-		addr.sin_port = 0;
+		TOSINP(&addr)->sin_port = 0;
 		(void)bind(sock, (struct sockaddr *)&addr, len);
 	}
 	if (getsockname(sock, (struct sockaddr *)&addr, &len) != 0) {
@@ -147,7 +149,7 @@
 	xprt->xp_p2 = (caddr_t)su;
 	xprt->xp_verf.oa_base = su->su_verfbody;
 	xprt->xp_ops = &svcudp_op;
-	xprt->xp_port = ntohs(addr.sin_port);
+	xprt->xp_port = ntohs(TOSINP(&addr)->sin_port);
 	xprt->xp_sock = sock;
 	xprt_register(xprt);
 	return (xprt);
@@ -181,7 +183,7 @@
 	u_long replylen;
 
     again:
-	xprt->xp_addrlen = sizeof(struct sockaddr_in);
+	xprt->xp_addrlen = sizeof(xprt->xp_raddr);
 	rlen = recvfrom(xprt->xp_sock, rpc_buffer(xprt), (int) su->su_iosz,
 	    0, (struct sockaddr *)&(xprt->xp_raddr), &(xprt->xp_addrlen));
 	if (rlen == -1 && errno == EINTR)
@@ -298,7 +300,7 @@
 	u_long cache_proc;
 	u_long cache_vers;
 	u_long cache_prog;
-	struct sockaddr_in cache_addr;
+	RPC_SOCKADDR_IN cache_addr;
 	/*
 	 * The cached reply and length
 	 */
@@ -323,7 +325,7 @@
 	u_long uc_prog;		/* saved program number */
 	u_long uc_vers;		/* saved version number */
 	u_long uc_proc;		/* saved procedure number */
-	struct sockaddr_in uc_addr; /* saved caller's address */
+	RPC_SOCKADDR_IN uc_addr; /* saved caller's address */
 };
 
 
@@ -453,7 +455,7 @@
 	register struct svcudp_data *su = su_data(xprt);
 	register struct udp_cache *uc = (struct udp_cache *) su->su_cache;
 
-#	define EQADDR(a1, a2)	(memcmp(&a1, &a2, sizeof(a1)) == 0)
+#	define EQADDR(a1, a2)	(memcmp(&a1, &a2, TOSINP(&a2)->sin_len) == 0)
 
 	loc = CACHE_LOC(xprt, su->su_xid);
 	for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) {
@@ -474,6 +476,8 @@
 	uc->uc_proc = msg->rm_call.cb_proc;
 	uc->uc_vers = msg->rm_call.cb_vers;
 	uc->uc_prog = msg->rm_call.cb_prog;
+	if (TOSINP6(&xprt->xp_raddr)->sin6_family == AF_INET6)
+		TOSINP6(&xprt->xp_raddr)->sin6_flowinfo = 0;
 	uc->uc_addr = xprt->xp_raddr;
 	return(0);
 }
diff -uN src-current/lib/libc/yp/yplib.c src-current-ipv6/lib/libc/yp/yplib.c
--- src-current/lib/libc/yp/yplib.c
+++ src-current-ipv6/lib/libc/yp/yplib.c
@@ -42,6 +42,8 @@
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
+#undef RPC_USE_INET6		/* Not ported to IPv6 - Yet */
+#undef RPC_USE_INET_ANY		/* Not ported to IPv6 - Yet */
 #include <rpc/rpc.h>
 #include <rpc/xdr.h>
 #include <rpcsvc/yp.h>
diff -uN src-current/lib/libcompat/4.3/rexec.c src-current-ipv6/lib/libcompat/4.3/rexec.c
--- src-current/lib/libcompat/4.3/rexec.c
+++ src-current-ipv6/lib/libcompat/4.3/rexec.c
@@ -53,6 +53,11 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+union sockaddr_u {		/*_len, _family, _port are at same offset */
+	struct sockaddr_in s4; 
+	struct sockaddr_in6 s6; 
+};
+
 int	rexecoptions;
 char	*getpass(), *getlogin();
 
@@ -298,7 +303,11 @@
 	char *name, *pass, *cmd;
 	int *fd2p;
 {
-	struct sockaddr_in sin, sin2, from;
+	union sockaddr_u Sin, from, Sin2;
+#define sin	Sin.s4
+#define sin6	Sin.s6
+#define sin2	Sin2.s4
+#define sin26	Sin2.s6
 	struct hostent *hp;
 	u_short port;
 	int s, timo = 1, s3;
@@ -312,15 +321,22 @@
 	*ahost = hp->h_name;
 	ruserpass(hp->h_name, &name, &pass);
 retry:
-	s = socket(AF_INET, SOCK_STREAM, 0);
+	s = socket(hp->h_addrtype, SOCK_STREAM, 0);
 	if (s < 0) {
 		perror("rexec: socket");
 		return (-1);
 	}
 	sin.sin_family = hp->h_addrtype;
 	sin.sin_port = rport;
-	bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
-	if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+	if (sin.sin_family == AF_INET) {
+		sin.sin_len = sizeof(struct sockaddr_in);
+		bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
+	} else {
+		sin6.sin6_len = sizeof(struct sockaddr_in6);
+		sin6.sin6_flowinfo = IPV6_PRIORITY_UNCHARACTERIZED;
+		bcopy(hp->h_addr, (caddr_t)&sin6.sin6_addr, hp->h_length);
+	}
+	if (connect(s, (struct sockaddr *)&sin, sin.sin_len) < 0) {
 		if (errno == ECONNREFUSED && timo <= 16) {
 			(void) close(s);
 			sleep(timo);
@@ -337,15 +353,15 @@
 		char num[8];
 		int s2, sin2len;
 
-		s2 = socket(AF_INET, SOCK_STREAM, 0);
+		s2 = socket(sin.sin_family, SOCK_STREAM, 0);
 		if (s2 < 0) {
 			(void) close(s);
 			return (-1);
 		}
 		listen(s2, 1);
-		sin2len = sizeof (sin2);
+		sin2len = sizeof (Sin2);
 		if (getsockname(s2, (struct sockaddr *)&sin2, &sin2len) < 0 ||
-		  sin2len != sizeof (sin2)) {
+		    (sin2len != sizeof (sin2) && sin2len != sizeof (sin26))) {
 			perror("getsockname");
 			(void) close(s2);
 			goto bad;
diff -uN src-current/libexec/fingerd/fingerd.c src-current-ipv6/libexec/fingerd/fingerd.c
--- src-current/libexec/fingerd/fingerd.c
+++ src-current-ipv6/libexec/fingerd/fingerd.c
@@ -55,6 +55,7 @@
 #include <unistd.h>
 #include <syslog.h>
 #include <netdb.h>
+#include <resolv.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <strings.h>
@@ -71,10 +72,10 @@
 	register int ch;
 	register char *lp;
 	struct hostent *hp;
-	struct sockaddr_in sin;
+	struct sockaddr_in6 sin;
 	int p[2], logging, secure, sval;
 #define	ENTRIES	50
-	char **ap, *av[ENTRIES + 1], **comp, line[1024], *prog;
+	char **ap, *av[ENTRIES + 1], **comp, line[1024], hname[64], *prog;
 
 	prog = _PATH_FINGER;
 	logging = secure = 0;
@@ -127,14 +128,18 @@
 		for (end = t; *end; end++)
 			if (*end == '\n' || *end == '\r')
 				*end = ' ';
+		(void) res_init();
+		_res.options |= RES_USE_INET6;
 		sval = sizeof(sin);
 		if (getpeername(0, (struct sockaddr *)&sin, &sval) < 0)
 			logerr("getpeername: %s", strerror(errno));
-		if (hp = gethostbyaddr((char *)&sin.sin_addr.s_addr,
-		    sizeof(sin.sin_addr.s_addr), AF_INET))
+		if (hp = gethostbyaddr((char *)&sin.sin6_addr,
+		    sizeof(sin.sin6_addr), AF_INET6))
 			lp = hp->h_name;
 		else
-			lp = inet_ntoa(sin.sin_addr);
+			lp = (char *)inet_ntop(sin.sin6_family,
+					       &sin.sin6_addr,
+					       hname, 64);
 		syslog(LOG_NOTICE, "query from %s: `%s'", lp, t);
 	}
 
diff -uN src-current/libexec/ftpd/ftpd.c src-current-ipv6/libexec/ftpd/ftpd.c
--- src-current/libexec/ftpd/ftpd.c
+++ src-current-ipv6/libexec/ftpd/ftpd.c
@@ -60,6 +60,7 @@
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <netinet/tcp.h>
 
 #define	FTP_NAMES
@@ -75,6 +76,7 @@
 #include <glob.h>
 #include <limits.h>
 #include <netdb.h>
+#include <resolv.h>
 #include <pwd.h>
 #include <grp.h>
 #include <setjmp.h>
@@ -113,12 +115,12 @@
 extern	off_t restart_point;
 extern	char cbuf[];
 
-struct	sockaddr_in server_addr;
-struct	sockaddr_in ctrl_addr;
-struct	sockaddr_in data_source;
-struct	sockaddr_in data_dest;
-struct	sockaddr_in his_addr;
-struct	sockaddr_in pasv_addr;
+struct	sockaddr_in6 server_addr;
+struct	sockaddr_in6 ctrl_addr;
+struct	sockaddr_in6 data_source;
+struct	sockaddr_in6 data_dest;
+struct	sockaddr_in6 his_addr;
+struct	sockaddr_in6 pasv_addr;
 
 int	daemon_mode;
 int	data;
@@ -157,7 +159,7 @@
 
 static struct ftphost {
 	struct ftphost	*next;
-	struct in_addr	hostaddr;
+	struct in6_addr	hostaddr;
 	char		*hostname;
 	char		*anonuser;
 	char		*statfile;
@@ -176,7 +178,7 @@
 int	 klogin __P((struct passwd *, char *, char *, char *));
 #endif
 
-struct	in_addr bind_address;
+struct	in6_addr bind_address;
 char	*pid_file = NULL;
 
 #if defined(KERBEROS)
@@ -206,7 +208,7 @@
 
 #ifdef SKEY
 int	pwok = 0;
-char	addr_string[20];	/* XXX */
+char	addr_string[64];	/* XXX */
 #endif
 
 #define LOGCMD(cmd, file) \
@@ -230,13 +232,13 @@
 
 #ifdef VIRTUAL_HOSTING
 static void	 inithosts __P((void));
-static void	selecthost __P((struct in_addr *));
+static void	selecthost __P((struct in6_addr *));
 #endif
 static void	 ack __P((char *));
 static void	 myoob __P((int));
 static int	 checkuser __P((char *, char *, int));
 static FILE	*dataconn __P((char *, off_t, char *));
-static void	 dolog __P((struct sockaddr_in *));
+static void	 dolog __P((struct sockaddr_in6 *));
 static char	*curdir __P((void));
 static void	 end_login __P((void));
 static FILE	*getdatasock __P((char *));
@@ -274,6 +276,8 @@
 	FILE *fd;
 
 	tzset();		/* in case no timezone database in ~ftp */
+	(void) res_init();
+	_res.options |= RES_USE_INET6;
 
 #ifdef OLD_SETPROCTITLE
 	/*
@@ -286,7 +290,7 @@
 #endif /* OLD_SETPROCTITLE */
 
 
-	bind_address.s_addr = htonl(INADDR_ANY);
+	bind_address = in6addr_any;
 	while ((ch = getopt(argc, argv, "AdlDSURt:T:u:va:p:")) != -1) {
 		switch (ch) {
 		case 'D':
@@ -326,7 +330,7 @@
 			break;
 
 		case 'a':
-			if (!inet_aton(optarg, &bind_address))
+			if (inet_pton(AF_INET6, optarg, &bind_address) <= 0)
 				errx(1, "invalid address for -a");
 			break;
 
@@ -394,7 +398,7 @@
 		 * Open a socket, bind it to the FTP port, and start
 		 * listening.
 		 */
-		ctl_sock = socket(AF_INET, SOCK_STREAM, 0);
+		ctl_sock = socket(AF_INET6, SOCK_STREAM, 0);
 		if (ctl_sock < 0) {
 			syslog(LOG_ERR, "control socket: %m");
 			exit(1);
@@ -402,9 +406,13 @@
 		if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR,
 		    (char *)&on, sizeof(on)) < 0)
 			syslog(LOG_ERR, "control setsockopt: %m");;
-		server_addr.sin_family = AF_INET;
-		server_addr.sin_addr = bind_address;
-		server_addr.sin_port = sv->s_port;
+#ifdef SIN6_LEN
+		server_addr.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+		server_addr.sin6_family = AF_INET6;
+		server_addr.sin6_flowinfo = IPV6_PRIORITY_INTERACTIVE;
+		server_addr.sin6_addr = bind_address;
+		server_addr.sin6_port = sv->s_port;
 		if (bind(ctl_sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) {
 			syslog(LOG_ERR, "control bind: %m");
 			exit(1);
@@ -464,7 +472,8 @@
 		syslog(LOG_ERR, "signal: %m");
 
 #ifdef SKEY
-	strncpy(addr_string, inet_ntoa(his_addr.sin_addr), sizeof(addr_string));
+	inet_ntop(AF_INET6, &his_addr.sin6_addr,
+		  addr_string, sizeof(addr_string));
 #endif
 	addrlen = sizeof(ctrl_addr);
 	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
@@ -473,12 +482,15 @@
 	}
 #ifdef VIRTUAL_HOSTING
 	/* select our identity from virtual host table */
-	selecthost(&ctrl_addr.sin_addr);
+	selecthost(&ctrl_addr.sin6_addr);
 #endif
 #ifdef IP_TOS
-	tos = IPTOS_LOWDELAY;
-	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
-		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+	if (IN6_IS_ADDR_V4MAPPED(&his_addr.sin6_addr)) {
+		tos = IPTOS_LOWDELAY;
+		if (setsockopt(0, IPPROTO_IP, IP_TOS,
+			       (char *)&tos, sizeof(int)) < 0)
+			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+	}
 #endif
 	/*
 	 * Disable Nagle on the control channel so that we don't have to wait
@@ -487,7 +499,7 @@
 	if (setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
 		syslog(LOG_WARNING, "control setsockopt TCP_NODELAY: %m");
 
-	data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
+	data_source.sin6_port = htons(ntohs(ctrl_addr.sin6_port) - 1);
 
 	/* set this here so klogin can use it... */
 	(void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
@@ -641,7 +653,7 @@
 			 */
 			if ((hp = gethostbyaddr((char*)&hrp->hostaddr,
 						sizeof(hrp->hostaddr),
-						AF_INET)) != NULL) {
+						AF_INET6)) != NULL) {
 				if (strcmp(cp, hp->h_name) != 0) {
 					if (hp->h_aliases == NULL)
 						cp = hp->h_name;
@@ -684,7 +696,7 @@
 
 static void
 selecthost(a)
-	struct in_addr *a;
+	struct in6_addr *a;
 {
 	struct ftphost	*hrp;
 
@@ -986,8 +998,8 @@
 	if ((lc = login_getpwclass(pw)) != NULL) {
 		char	remote_ip[MAXHOSTNAMELEN];
 
-		strncpy(remote_ip, inet_ntoa(his_addr.sin_addr),
-			sizeof(remote_ip) - 1);
+		inet_ntop(AF_INET6, &his_addr.sin6_addr,
+			  remote_ip, sizeof(remote_ip) - 1);
 		remote_ip[sizeof(remote_ip) - 1] = 0;
 		if (!auth_hostok(lc, remotehost, remote_ip)) {
 			syslog(LOG_INFO|LOG_AUTH,
@@ -1285,16 +1297,19 @@
 	if (data >= 0)
 		return (fdopen(data, mode));
 	(void) seteuid((uid_t)0);
-	s = socket(AF_INET, SOCK_STREAM, 0);
+	s = socket(AF_INET6, SOCK_STREAM, 0);
 	if (s < 0)
 		goto bad;
 	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
 	    (char *) &on, sizeof(on)) < 0)
 		goto bad;
 	/* anchor socket to avoid multi-homing problems */
-	data_source.sin_len = sizeof(struct sockaddr_in);
-	data_source.sin_family = AF_INET;
-	data_source.sin_addr = ctrl_addr.sin_addr;
+#ifdef SIN6_LEN
+	data_source.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+	data_source.sin6_family = AF_INET6;
+	data_source.sin6_flowinfo = IPV6_PRIORITY_BULK;
+	data_source.sin6_addr = ctrl_addr.sin6_addr;
 	for (tries = 1; ; tries++) {
 		if (bind(s, (struct sockaddr *)&data_source,
 		    sizeof(data_source)) >= 0)
@@ -1304,11 +1319,6 @@
 		sleep(tries);
 	}
 	(void) seteuid((uid_t)pw->pw_uid);
-#ifdef IP_TOS
-	on = IPTOS_THROUGHPUT;
-	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
-		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
-#endif
 #ifdef TCP_NOPUSH
 	/*
 	 * Turn off push flag to keep sender TCP from sending short packets
@@ -1343,6 +1353,7 @@
 	char *mode;
 {
 	char sizebuf[32];
+	char hbuf[64];
 	FILE *file;
 	int retry = 0, tos;
 
@@ -1353,7 +1364,7 @@
 	else
 		*sizebuf = '\0';
 	if (pdata >= 0) {
-		struct sockaddr_in from;
+		struct sockaddr_in6 from;
 		int s, fromlen = sizeof(from);
 		struct timeval timeout;
 		fd_set set;
@@ -1374,9 +1385,11 @@
 		(void) close(pdata);
 		pdata = s;
 #ifdef IP_TOS
-		tos = IPTOS_THROUGHPUT;
-		(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
-		    sizeof(int));
+		if (IN6_IS_ADDR_V4MAPPED(&from.sin6_addr)) {
+			tos = IPTOS_THROUGHPUT;
+			(void) setsockopt(s, IPPROTO_IP, IP_TOS,
+					  (char *)&tos, sizeof(int));
+		}
 #endif
 		reply(150, "Opening %s mode data connection for '%s'%s.",
 		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
@@ -1394,8 +1407,8 @@
 	file = getdatasock(mode);
 	if (file == NULL) {
 		reply(425, "Can't create data socket (%s,%d): %s.",
-		    inet_ntoa(data_source.sin_addr),
-		    ntohs(data_source.sin_port), strerror(errno));
+		    inet_ntop(AF_INET6, &data_source.sin6_addr, hbuf, 64),
+		    ntohs(data_source.sin6_port), strerror(errno));
 		return (NULL);
 	}
 	data = fileno(file);
@@ -1651,14 +1664,16 @@
 void
 statcmd()
 {
-	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin;
+	char hbuf[64];
 	u_char *a, *p;
 
 	lreply(211, "%s FTP server status:", hostname, version);
 	printf("     %s\r\n", version);
 	printf("     Connected to %s", remotehost);
-	if (!isdigit(remotehost[0]))
-		printf(" (%s)", inet_ntoa(his_addr.sin_addr));
+	if (!isxdigit(remotehost[0]) || (remotehost[0] == ':'))
+		printf(" (%s)", inet_ntop(AF_INET6, &his_addr.sin6_addr,
+					  hbuf, 64));
 	printf("\r\n");
 	if (logged_in) {
 		if (guest)
@@ -1687,14 +1702,26 @@
 		sin = &pasv_addr;
 		goto printaddr;
 	} else if (usedefault == 0) {
-		printf("     PORT");
 		sin = &data_dest;
+		printf(IN6_IS_ADDR_V4MAPPED(&sin->sin6_addr) ?
+		           "     PORT" : "     LPRT");
 printaddr:
-		a = (u_char *) &sin->sin_addr;
-		p = (u_char *) &sin->sin_port;
+		a = (u_char *) &sin->sin6_addr;
+		p = (u_char *) &sin->sin6_port;
 #define UC(b) (((int) b) & 0xff)
-		printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
-			UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
+		if (IN6_IS_ADDR_V4MAPPED(&sin->sin6_addr))
+			printf(" (%d,%d,%d,%d,%d,%d)\r\n",
+			       UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
+			       UC(p[0]), UC(p[1]));
+		else
+			printf(
+" (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)\r\n",
+6, 16,
+UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
+UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
+UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
+UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
+2, UC(p[0]), UC(p[1]));
 #undef UC
 	} else
 		printf("     No data connection\r\n");
@@ -1899,16 +1926,16 @@
 
 static void
 dolog(sin)
-	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin;
 {
-	struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
-		sizeof(struct in_addr), AF_INET);
+	struct hostent *hp = gethostbyaddr((char *)&sin->sin6_addr,
+		sizeof(struct in6_addr), AF_INET6);
 
 	if (hp)
 		(void) strncpy(remotehost, hp->h_name, sizeof(remotehost));
 	else
-		(void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
-		    sizeof(remotehost));
+		(void) inet_ntop(AF_INET6, &sin->sin6_addr,
+				 remotehost, sizeof(remotehost));
 #ifdef SETPROCTITLE
 #ifdef VIRTUAL_HOSTING
 	if (thishost != firsthost)
@@ -1929,7 +1956,8 @@
 		else
 #endif
 			syslog(LOG_INFO, "connection from %s (%s)", remotehost,
-				inet_ntoa(sin->sin_addr));
+				inet_ntop(AF_INET6, &sin->sin6_addr,
+					  remotehost, sizeof(remotehost)));
 	}
 }
 
@@ -1996,19 +2024,21 @@
  *	with Rick Adams on 25 Jan 89.
  */
 void
-passive()
+passive(mode)
+	int mode;
 {
 	int len;
-	char *p, *a;
+	char hbuf[64], *p, *a;
 
 	if (pdata >= 0)		/* close old port if one set */
 		close(pdata);
 
-	pdata = socket(AF_INET, SOCK_STREAM, 0);
+	pdata = socket(AF_INET6, SOCK_STREAM, 0);
 	if (pdata < 0) {
 		perror_reply(425, "Can't open passive connection");
 		return;
 	}
+	pasv_addr.sin6_flowinfo = IPV6_PRIORITY_BULK;
 
 	(void) seteuid((uid_t)0);
 
@@ -2024,7 +2054,7 @@
 #endif
 
 	pasv_addr = ctrl_addr;
-	pasv_addr.sin_port = 0;
+	pasv_addr.sin6_port = 0;
 	if (bind(pdata, (struct sockaddr *)&pasv_addr,
 		 sizeof(pasv_addr)) < 0)
 		goto pasv_error;
@@ -2034,16 +2064,53 @@
 	len = sizeof(pasv_addr);
 	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
 		goto pasv_error;
+	if (mode == 1) {
+		/* IPv4 only */
+		if (!IN6_IS_ADDR_V4MAPPED(&pasv_addr.sin6_addr))
+			goto pasv_error;
+	} else if (mode == 0) {
+		/* extended or long */
+		if (IN6_IS_ADDR_V4MAPPED(&pasv_addr.sin6_addr))
+			goto pasv_error;
+	}
 	if (listen(pdata, 1) < 0)
 		goto pasv_error;
-	a = (char *) &pasv_addr.sin_addr;
-	p = (char *) &pasv_addr.sin_port;
+	a = (char *) &pasv_addr.sin6_addr;
+	p = (char *) &pasv_addr.sin6_port;
 
 #define UC(b) (((int) b) & 0xff)
 
-	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
-		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
-	return;
+	switch (mode) {
+	    case 1:
+		reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)",
+		      UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
+		      UC(p[0]), UC(p[1]));
+		return;
+
+	    case 0:
+		reply(228,
+		      "Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",
+		      6, 16,
+		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
+		      UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
+		      UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
+		      UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
+		      2, UC(p[0]), UC(p[1]));
+		return;
+
+	    case -1:
+		reply(229,
+		      "(%s|%s|%s|%d) Entering Extended Passive Mode",
+		      "IP6", "TCP",
+		      inet_ntop(AF_INET6, a, hbuf, sizeof(hbuf)),
+		      pasv_addr.sin6_port);
+		return;
+	    case 2:
+		reply(229,
+		      "Entering Passive Mode (%d,%d)",
+		      UC(p[0]), UC(p[1]));
+		return;
+	}
 
 pasv_error:
 	(void) seteuid((uid_t)pw->pw_uid);
diff -uN src-current/libexec/ftpd/extern.h src-current-ipv6/libexec/ftpd/extern.h
--- src-current/libexec/ftpd/extern.h
+++ src-current-ipv6/libexec/ftpd/extern.h
@@ -48,7 +48,7 @@
 void	makedir __P((char *));
 void	nack __P((char *));
 void	pass __P((char *));
-void	passive __P((void));
+void	passive __P((int));
 void	perror_reply __P((int, char *));
 void	pwd __P((void));
 void	removedir __P((char *));
diff -uN src-current/libexec/ftpd/ftpcmd.y src-current-ipv6/libexec/ftpd/ftpcmd.y
--- src-current/libexec/ftpd/ftpcmd.y
+++ src-current-ipv6/libexec/ftpd/ftpcmd.y
@@ -53,6 +53,7 @@
 #include <sys/stat.h>
 
 #include <netinet/in.h>
+#include <arpa/inet.h>
 #include <arpa/ftp.h>
 
 #include <ctype.h>
@@ -71,11 +72,11 @@
 
 #include "extern.h"
 
-extern	struct sockaddr_in data_dest, his_addr;
+extern	struct sockaddr_in6 data_dest, his_addr;
 extern	int logged_in;
 extern	struct passwd *pw;
 extern	int guest;
-extern 	int paranoid;
+extern	int paranoid;
 extern	int logging;
 extern	int type;
 extern	int form;
@@ -111,8 +112,8 @@
 
 	SP	CRLF	COMMA
 
-	USER	PASS	ACCT	REIN	QUIT	PORT
-	PASV	TYPE	STRU	MODE	RETR	STOR
+	USER	PASS	ACCT	REIN	QUIT	PORT	EPRT	EPSV	SPORT
+	LPRT	LPSV	PASV	TYPE	STRU	MODE	RETR	STOR	SPASV
 	APPE	MLFL	MAIL	MSND	MSOM	MSAM
 	MRSQ	MRCP	ALLO	REST	RNFR	RNTO
 	ABOR	DELE	CWD	LIST	NLST	SITE
@@ -155,15 +156,37 @@
 			pass($3);
 			free($3);
 		}
+	| EPRT check_login SP host_ext_port CRLF
+		{
+			if ($2) {
+				if (paranoid &&
+				    ((ntohs(data_dest.sin6_port) <
+				      IPPORT_RESERVED) ||
+				     memcmp(&data_dest.sin6_addr,
+					    &his_addr.sin6_addr,
+					    sizeof(data_dest.sin6_addr)))) {
+					usedefault = 1;
+					reply(500,
+					      "Illegal EPRT range rejected.");
+				} else {
+					usedefault = 0;
+					if (pdata >= 0) {
+						(void) close(pdata);
+						pdata = -1;
+					}
+					reply(200, "EPRT command successful.");
+				}
+			}
+		}
 	| PORT check_login SP host_port CRLF
 		{
 			if ($2) {
 				if (paranoid &&
-				    ((ntohs(data_dest.sin_port) <
+				    ((ntohs(data_dest.sin6_port) <
 				      IPPORT_RESERVED) ||
-				     memcmp(&data_dest.sin_addr,
-					    &his_addr.sin_addr,
-					    sizeof(data_dest.sin_addr)))) {
+				     memcmp(&data_dest.sin6_addr,
+					    &his_addr.sin6_addr,
+					    sizeof(data_dest.sin6_addr)))) {
 					usedefault = 1;
 					reply(500,
 					      "Illegal PORT range rejected.");
@@ -177,10 +200,67 @@
 				}
 			}
 		}
+	| LPRT check_login SP host_long_port CRLF
+		{
+			if ($2) {
+				if (paranoid &&
+				    ((ntohs(data_dest.sin6_port) <
+				      IPPORT_RESERVED) ||
+				     memcmp(&data_dest.sin6_addr,
+					    &his_addr.sin6_addr,
+					    sizeof(data_dest.sin6_addr)))) {
+					usedefault = 1;
+					reply(500,
+					      "Illegal LPRT range rejected.");
+				} else {
+					usedefault = 0;
+					if (pdata >= 0) {
+						(void) close(pdata);
+						pdata = -1;
+					}
+					reply(200, "LPRT command successful.");
+				}
+			}
+		}
+	| SPORT check_login SP short_port CRLF
+		{
+			if ($2) {
+				if (paranoid &&
+				    (ntohs(data_dest.sin6_port) <
+				     IPPORT_RESERVED)) {
+					usedefault = 1;
+					reply(500,
+					      "Illegal SPORT range rejected.");
+				} else {
+					usedefault = 0;
+					if (pdata >= 0) {
+						(void) close(pdata);
+						pdata = -1;
+					}
+					reply(200,
+					      "SPORT command successful.");
+				}
+			}
+		}
+	| EPSV check_login CRLF
+		{
+			if ($2)
+				passive(-1);
+		}
+	| LPSV check_login CRLF
+		{
+			if ($2)
+				passive(0);
+		}
 	| PASV check_login CRLF
 		{
 			if ($2)
-				passive();
+				passive(1);
+		}
+	| SPASV check_login CRLF
+		{
+			if ($2)
+				passive(2);
 		}
 	| TYPE SP type_code CRLF
 		{
@@ -576,12 +656,96 @@
 		{
 			char *a, *p;
 
-			data_dest.sin_len = sizeof(struct sockaddr_in);
-			data_dest.sin_family = AF_INET;
-			p = (char *)&data_dest.sin_port;
+#ifdef SIN6_LEN
+			data_dest.sin6_len = sizeof(data_dest);
+#endif
+			data_dest.sin6_family = AF_INET6;
+			p = (char *)&data_dest.sin6_port;
 			p[0] = $9; p[1] = $11;
-			a = (char *)&data_dest.sin_addr;
-			a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;
+			a = (char *)&data_dest.sin6_addr;
+			memset(a, 0, 10);
+			a[11] = a[10] = 0xff;
+			a[12] = $1; a[13] = $3; a[14] = $5; a[15] = $7;
+		}
+	;
+
+host_long_port
+	: NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER
+		{
+			char *a, *p;
+
+			if ($1 != 6) {
+				reply(521, "Supported address family is 6.");
+				goto bad;
+			}
+			if (($3 != sizeof(struct in6_addr)) || ($37 != 2)) {
+				reply(500, "Bad length.");
+				goto bad;
+			}
+#ifdef SIN6_LEN
+			data_dest.sin6_len = sizeof(data_dest);
+#endif
+			data_dest.sin6_family = AF_INET6;
+			p = (char *)&data_dest.sin6_port;
+			p[0] = $39; p[1] = $41;
+			a = (char *)&data_dest.sin6_addr;
+			a[0] = $5; a[1] = $7; a[2] = $9; a[3] = $11;
+			a[4] = $13; a[5] = $15; a[6] = $17; a[7] = $19;
+			a[8] = $21; a[9] = $23; a[10] = $25; a[11] = $27;
+			a[12] = $29; a[13] = $31; a[14] = $33; a[15] = $35;
+		bad:
+		}
+	;
+
+host_ext_port
+	: STRING
+		{
+		char np[16], tp[16], name[64];
+		int port;
+
+		if (sscanf($1, "%16[^|]|%16[^|]|%64[^|]|%d",
+			   np, tp, name, &port) != 4) {
+			reply(500, "EPRT bad format");
+			goto xbad;
+		}
+		if (strcasecmp(np, "ip6") != 0) {
+			reply(522, "(IP6) Supported network protocol");
+			goto xbad;
+		}
+		if (strcasecmp(tp, "tcp") != 0) {
+			reply(523, "(TCP) Supported transport protocol");
+			goto xbad;
+		}
+		if (inet_pton(AF_INET6, name, &data_dest.sin6_addr) <= 0) {
+			reply(500, "Bad address %s", name);
+			goto xbad;
+		}				       
+#ifdef SIN6_LEN
+		data_dest.sin6_len = sizeof(data_dest);
+#endif
+		data_dest.sin6_family = AF_INET6;
+		data_dest.sin6_port = port;
+		xbad:
+		}
+	;
+
+short_port
+	: NUMBER COMMA NUMBER
+		{
+			char *p;
+
+#ifdef SIN6_LEN
+			data_dest.sin6_len = sizeof(data_dest);
+#endif
+			data_dest.sin6_family = AF_INET6;
+			data_dest.sin6_addr = his_addr.sin6_addr;
+			p = (char *)&data_dest.sin6_port;
+			p[0] = $1; p[1] = $3;
 		}
 	;
 
@@ -773,8 +937,14 @@
 	{ "SMNT", SMNT, ARGS, 0,	"(structure mount)" },
 	{ "REIN", REIN, ARGS, 0,	"(reinitialize server state)" },
 	{ "QUIT", QUIT, ARGS, 1,	"(terminate service)", },
+	{ "EPRT", EPRT, STR1, 1,	"<sp> IP6|TCP|address|port", },
 	{ "PORT", PORT, ARGS, 1,	"<sp> b0, b1, b2, b3, b4" },
+	{ "LPRT", LPRT, ARGS, 1,	"<sp> af, hal, h1, h2, ..." },
+	{ "SPORT", SPORT, ARGS, 1,	"<sp> p0, p1" },
+	{ "EPSV", EPSV, ARGS, 1,	"(set server in extended passive mode)" },
+	{ "LPSV", LPSV, ARGS, 1,	"(set server in long passive mode)" },
 	{ "PASV", PASV, ARGS, 1,	"(set server in passive mode)" },
+	{ "SPASV", SPASV, ARGS, 1,	"(set server in short passive mode)" },
 	{ "TYPE", TYPE, ARGS, 1,	"<sp> [ A | E | I | L ]" },
 	{ "STRU", STRU, ARGS, 1,	"(specify file structure)" },
 	{ "MODE", MODE, ARGS, 1,	"(specify transfer mode)" },
@@ -1144,7 +1314,6 @@
 			case 'T':
 			case 't':
 				return (T);
-
 			}
 			break;
 
diff -uN src-current/libexec/ftpd/ftpd.8 src-current-ipv6/libexec/ftpd/ftpd.8
--- src-current/libexec/ftpd/ftpd.8
+++ src-current-ipv6/libexec/ftpd/ftpd.8
@@ -92,12 +92,13 @@
 With this option set,
 .Nm
 will revert to historical behavior with regard to security checks on
-user operations and restrictions on PORT requests.
+user operations and restrictions on PORT/EPRT/LPRT/SPORT requests.
 Currently,
 .Nm
-will only honor PORT commands directed to unprivileged ports on the 
-remote user's host (which violates the FTP protocol specification but
-closes some security holes).
+will only honor PORT/EPRT/LPRT/SPORT commands directed to unprivileged
+ports on the remote user's host (which violates the FTP protocol
+specification but closes some security holes).
+.
 .It Fl S
 With this option set,
 .Nm
@@ -170,8 +171,12 @@
 .It CDUP Ta "change to parent of current working directory"
 .It CWD Ta "change working directory"
 .It DELE Ta "delete a file"
+.It EPRT Ta "specify data connection (extended) port"
+.It EPSV Ta "prepare for server-to-server (extended) transfer"
 .It HELP Ta "give help information"
 .It LIST Ta "give list files in a directory" Pq Dq Li "ls -lgA"
+.It LPRT Ta "specify data connection (long) port"
+.It LPSV Ta "prepare for server-to-server (long) transfer"
 .It MKD Ta "make a directory"
 .It MDTM Ta "show last modification time of file"
 .It MODE Ta "specify data transfer" Em mode
@@ -189,6 +194,8 @@
 .It RNTO Ta "specify rename-to file name"
 .It SITE Ta "non-standard commands (see next section)"
 .It SIZE Ta "return size of file"
+.It SPASV Ta "prepare for server-to-server (short) transfer"
+.It SPORT Ta "specify data connetion (short) port"
 .It STAT Ta "return status of server"
 .It STOR Ta "store a file"
 .It STOU Ta "store a file with a unique name"
@@ -358,7 +365,7 @@
 account in this directory.
 .El
 .Pp
-If the system has multiple IP addresses,
+If the system has multiple IP (IPv6 or IPv4) addresses,
 .Nm
 supports the idea of virtual hosts, which provides the ability to
 define multiple anonymous ftp areas, each one allocated to a different
@@ -370,7 +377,7 @@
 fields separated by whitespace:
 .Bl -tag -offset indent -width hostname
 .It hostname
-Contains the hostname or IP address of the virtual host.
+Contains the hostname or IPv6 address of the virtual host.
 .It user
 Contains a user record in the system password file.
 As with normal anonymous ftp, this user's access uid, gid and group
@@ -394,7 +401,7 @@
 .Pa /etc/ftpmotd .
 .El
 .Pp
-Defining a virtual host for the primary IP address or hostname
+Defining a virtual host for the primary IPv6 address or hostname
 changes the default for ftp logins to that address.
 The 'user', 'statfile', 'welcome' and 'motd' fields may be left
 blank, or a single hypen '-' used to indicate that the default
diff -uN src-current/libexec/ftpd/logwtmp.c src-current-ipv6/libexec/ftpd/logwtmp.c
--- src-current/libexec/ftpd/logwtmp.c
+++ src-current-ipv6/libexec/ftpd/logwtmp.c
@@ -67,6 +67,7 @@
 	struct utmp ut;
 	struct stat buf;
 
+#ifdef bad_plan
 	if (strlen(host) > UT_HOSTSIZE) {
 		struct hostent *hp = gethostbyname(host);
 
@@ -78,7 +79,7 @@
 		} else
 			host = "invalid hostname";
 	}
-
+#endif
 	if (fd < 0 && (fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0)
 		return;
 	if (fstat(fd, &buf) == 0) {
diff -uN src-current/libexec/rexecd/rexecd.c src-current-ipv6/libexec/rexecd/rexecd.c
--- src-current/libexec/rexecd/rexecd.c
+++ src-current-ipv6/libexec/rexecd/rexecd.c
@@ -64,6 +64,7 @@
 #include <string.h>
 #include <syslog.h>
 #include <unistd.h>
+#include <resolv.h>
 
 char	username[MAXLOGNAME + 5 + 1] = "USER=";
 char	homedir[MAXPATHLEN + 5 + 1] = "HOME=";
@@ -74,9 +75,13 @@
 char	**environ;
 char	*remote;
 
-struct	sockaddr_in asin = { AF_INET };
+#ifdef SIN6_LEN
+struct	sockaddr_in6 asin = { sizeof asin, AF_INET6 };
+#else
+struct	sockaddr_in6 asin = { AF_INET6 };
+#endif
 
-void doit __P((int, struct sockaddr_in *));
+void doit __P((int, struct sockaddr_in6 *));
 void getstr __P((char *, int, char *));
 /*VARARGS1*/
 void error __P(());
@@ -94,19 +99,23 @@
 	int argc;
 	char **argv;
 {
-	struct sockaddr_in from;
+	struct sockaddr_in6 from;
 	int fromlen;
 	struct hostent *hp;
+	char hname[64];
 
 	openlog(argv[0], LOG_PID, LOG_AUTH);
+	(void) res_init();
+	_res.options |= RES_USE_INET6;
 	fromlen = sizeof (from);
 	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0)
 		err(1, "getpeername");
 
-	hp = gethostbyaddr((char *) &from.sin_addr, sizeof(from.sin_addr),
-			   from.sin_family);
-		remote = inet_ntoa(from.sin_addr);
-	remote = (hp != NULL) ? hp->h_name : inet_ntoa(from.sin_addr);
+	hp = gethostbyaddr((char *) &from.sin6_addr,
+			   sizeof(from.sin6_addr),
+			   from.sin6_family);
+	remote = (hp != NULL) ? hp->h_name :
+	  (char *)inet_ntop(from.sin6_family, &from.sin6_addr, hname, 64);
 
 	doit(0, &from);
 	return(0);
@@ -115,7 +124,7 @@
 void
 doit(f, fromp)
 	int f;
-	struct sockaddr_in *fromp;
+	struct sockaddr_in6 *fromp;
 {
 	FILE *fp;
 	char cmdbuf[NCARGS+1], *cp, *namep;
@@ -157,13 +166,13 @@
 	}
 	(void) alarm(0);
 	if (port != 0) {
-		s = socket(AF_INET, SOCK_STREAM, 0);
+		s = socket(AF_INET6, SOCK_STREAM, 0);
 		if (s < 0)
 			exit(1);
 		if (bind(s, (struct sockaddr *)&asin, sizeof (asin)) < 0)
 			exit(1);
 		(void) alarm(60);
-		fromp->sin_port = htons(port);
+		fromp->sin6_port = htons(port);
 		if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0)
 			exit(1);
 		(void) alarm(0);
diff -uN src-current/libexec/rlogind/rlogind.c src-current-ipv6/libexec/rlogind/rlogind.c
--- src-current/libexec/rlogind/rlogind.c
+++ src-current-ipv6/libexec/rlogind/rlogind.c
@@ -69,6 +69,7 @@
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <resolv.h>
 
 #include <errno.h>
 #include <libutil.h>
@@ -112,12 +113,12 @@
 
 struct	passwd *pwd;
 
-void	doit __P((int, struct sockaddr_in *));
+void	doit __P((int, struct sockaddr_in6 *));
 int	control __P((int, char *, int));
 void	protocol __P((int, int));
 void	cleanup __P((int));
 void	fatal __P((int, char *, int));
-int	do_rlogin __P((struct sockaddr_in *));
+int	do_rlogin __P((struct sockaddr_in6 *));
 void	getstr __P((char *, int, char *));
 void	setup_term __P((int));
 int	do_krb_login __P((struct sockaddr_in *));
@@ -131,7 +132,7 @@
 	char *argv[];
 {
 	extern int __check_rhosts_file;
-	struct sockaddr_in from;
+	struct sockaddr_in6 from;	/* IPv6 */
 	int ch, fromlen, on;
 
 	openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
@@ -178,6 +179,10 @@
 		fatal(STDERR_FILENO, "only one of -k and -v allowed", 0);
 	}
 #endif
+
+	(void) res_init();
+	_res.options |= RES_USE_INET6;
+
 	fromlen = sizeof (from);
 	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
 		syslog(LOG_ERR,"Can't get peer name of remote host: %m");
@@ -193,7 +198,7 @@
 	on = IPTOS_LOWDELAY;
 	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
-
+		/* should be IPV6_PRIORITY_INTERACTIVE in IPv6 */
 	doit(0, &from);
 	return 0;
 }
@@ -209,7 +214,7 @@
 void
 doit(f, fromp)
 	int f;
-	struct sockaddr_in *fromp;
+	struct sockaddr_in6 *fromp;
 {
 	int master, pid, on = 1;
 	int authenticated = 0;
@@ -228,13 +233,14 @@
 #endif
 
 	alarm(0);
-	fromp->sin_port = ntohs((u_short)fromp->sin_port);
-	hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(struct in_addr),
-	    fromp->sin_family);
+	fromp->sin6_port = ntohs((u_short)fromp->sin6_port);	/* IPv6 */
+	hp = gethostbyaddr((char *)&fromp->sin6_addr, sizeof(struct in6_addr),
+	    fromp->sin6_family);
 	if (hp) {
 		(void)strncpy(hostname, hp->h_name, sizeof(hostname));
 	} else {
-		(void)strncpy(hostname, inet_ntoa(fromp->sin_addr), sizeof(hostname));
+		(void)inet_ntop(fromp->sin6_family, &fromp->sin6_addr,
+				hostname, sizeof(hostname));
 	}
 	hostname[sizeof(hostname) - 1] = '\0';
 
@@ -250,14 +256,19 @@
 	} else
 #endif
 	{
-		if (fromp->sin_family != AF_INET ||
-		    fromp->sin_port >= IPPORT_RESERVED ||
-		    fromp->sin_port < IPPORT_RESERVED/2) {
+		if (fromp->sin6_family != AF_INET6 ||
+		    fromp->sin6_port >= IPPORT_RESERVED ||
+		    fromp->sin6_port < IPPORT_RESERVED/2) {	/* ipv6 */
+			char hbuf[64];
+
 			syslog(LOG_NOTICE, "Connection from %s on illegal port",
-				inet_ntoa(fromp->sin_addr));
+				inet_ntop(fromp->sin6_family,
+					  &fromp->sin6_addr,
+					  hbuf, 64));
 			fatal(f, "Permission denied", 0);
 		}
-#ifdef IP_OPTIONS
+/* should be IPV6_* options in IPv6 */
+#if defined(IP_OPTIONS) && defined(notyet)
 		{
 		u_char optbuf[BUFSIZ/3];
 		int optsize = sizeof(optbuf), ipproto, i;
@@ -592,7 +603,7 @@
 
 int
 do_rlogin(dest)
-	struct sockaddr_in *dest;
+	struct sockaddr_in6 *dest;
 {
 	getstr(rusername, sizeof(rusername), "remuser too long");
 	getstr(lusername, sizeof(lusername), "locuser too long");
@@ -602,8 +613,9 @@
 	if (pwd == NULL)
 		return (-1);
 	/* XXX why don't we syslog() failure? */
-	return (iruserok(dest->sin_addr.s_addr, pwd->pw_uid == 0,
-		rusername, lusername));
+	return (iruserok2(AF_INET6, (char *)&dest->sin6_addr,
+			  sizeof(dest->sin6_addr), pwd->pw_uid == 0,
+			  rusername, lusername));
 }
 
 void
diff -uN src-current/libexec/rpc.rquotad/rquotad.c src-current-ipv6/libexec/rpc.rquotad/rquotad.c
--- src-current/libexec/rpc.rquotad/rquotad.c
+++ src-current-ipv6/libexec/rpc.rquotad/rquotad.c
@@ -30,11 +30,16 @@
 #include <syslog.h>
 #include <varargs.h>
 
+/*
+ * ipv6 rpc : use base address type struct sockaddr_in6 *  in rpc includes
+ */
+#define RPC_USE_INET6	/*  address type is struct sockaddr_in6 *  */
 #include <ufs/ufs/quota.h>
 #include <rpc/rpc.h>
 #include <rpc/pmap_clnt.h>
 #include <rpcsvc/rquota.h>
 #include <arpa/inet.h>
+#include <resolv.h>
 
 void rquota_service __P((struct svc_req *request, SVCXPRT *transp));
 void sendquota __P((struct svc_req *request, SVCXPRT *transp));
@@ -72,9 +77,12 @@
 	SVCXPRT *transp;
 	int sock = 0;
 	int proto = 0;
-	struct sockaddr_in from;
+	struct sockaddr_in6 from;
 	int fromlen;
 
+	(void)res_init();
+	_res.options |= RES_USE_INET6;
+
 	fromlen = sizeof(from);
 	if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
 		from_inetd = 0;
@@ -191,14 +199,15 @@
 printerr_reply(transp)	/* when a reply to a request failed */
 	SVCXPRT *transp;
 {
-	char   *name;
-	struct sockaddr_in *caller;
+	char   name[64];
+	struct sockaddr_in6 *caller;
 	int     save_errno;
 
 	save_errno = errno;
 
 	caller = svc_getcaller(transp);
-	name = (char *)inet_ntoa(caller->sin_addr);
+	inet_ntop(AF_INET6, &caller->sin6_addr, name, sizeof(name) - 1);
+	name[sizeof(name) - 1] = 0;
 	errno = save_errno;
 	if (errno == 0)
 		syslog(LOG_ERR, "couldn't send reply to %s", name);
diff -uN src-current/libexec/rpc.rstatd/rstatd.c src-current-ipv6/libexec/rpc.rstatd/rstatd.c
--- src-current/libexec/rpc.rstatd/rstatd.c
+++ src-current-ipv6/libexec/rpc.rstatd/rstatd.c
@@ -37,10 +37,15 @@
 #endif /* not lint */
 
 #include <stdlib.h>
+/*
+ * ipv6 rpc : use base address type struct sockaddr_in6 *  in rpc includes
+ */
+#define RPC_USE_INET6	/*  address type is struct sockaddr_in6 *  */
 #include <rpc/rpc.h>
 #include <signal.h>
 #include <syslog.h>
 #include <rpc/pmap_clnt.h>
+#include <resolv.h>
 #include <rpcsvc/rstat.h>
 
 extern void rstat_service();
@@ -65,13 +70,16 @@
 	SVCXPRT *transp;
         int sock = 0;
         int proto = 0;
-	struct sockaddr_in from;
+	struct sockaddr_in6 from;
 	int fromlen;
 
         if (argc == 2)
                 closedown = atoi(argv[1]);
         if (closedown <= 0)
                 closedown = 20;
+
+	(void)res_init();
+	_res.options |= RES_USE_INET6;
 
         /*
          * See if inetd started us
diff -uN src-current/libexec/rpc.rusersd/rusersd.c src-current-ipv6/libexec/rpc.rusersd/rusersd.c
--- src-current/libexec/rpc.rusersd/rusersd.c
+++ src-current-ipv6/libexec/rpc.rusersd/rusersd.c
@@ -37,6 +37,10 @@
 #endif /* not lint */
 
 #include <stdlib.h>
+/*
+ * ipv6 rpc : use base address type struct sockaddr_in6 *  in rpc includes
+ */
+#define RPC_USE_INET6	/*  address type is struct sockaddr_in6 *  */
 #include <rpc/rpc.h>
 #include <rpc/pmap_clnt.h>
 #include <signal.h>
@@ -44,6 +48,7 @@
 #define utmp rutmp
 #include <rpcsvc/rnusers.h>
 #undef utmp
+#include <resolv.h>
 
 extern void rusers_service();
 
@@ -65,7 +70,7 @@
 	SVCXPRT *transp;
         int sock = 0;
         int proto = 0;
-	struct sockaddr_in from;
+	struct sockaddr_in6 from;
 	int fromlen;
 
         /*
@@ -78,6 +83,10 @@
                 proto = IPPROTO_UDP;
         }
 
+	(void)res_init();
+	_res.options |= RES_USE_INET6;
+        openlog("rpc.rusersd", LOG_CONS|LOG_PID, LOG_DAEMON);
+
         if (!from_inetd) {
                 daemon(0, 0);
 
@@ -88,8 +97,6 @@
 		(void) signal(SIGTERM, cleanup);
 		(void) signal(SIGHUP, cleanup);
         }
-
-        openlog("rpc.rusersd", LOG_CONS|LOG_PID, LOG_DAEMON);
 
 	transp = svcudp_create(sock);
 	if (transp == NULL) {
diff -uN src-current/libexec/rpc.rwalld/rwalld.c src-current-ipv6/libexec/rpc.rwalld/rwalld.c
--- src-current/libexec/rpc.rwalld/rwalld.c
+++ src-current-ipv6/libexec/rpc.rwalld/rwalld.c
@@ -46,6 +46,11 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
+/*
+ * ipv6 rpc : use base address type struct sockaddr_in6 *  in rpc includes
+ */
+#define RPC_USE_INET6	/*  address type is struct sockaddr_in6 *  */
+#include <resolv.h>
 
 #ifdef OSF
 #define WALL_CMD "/usr/sbin/wall"
@@ -68,7 +73,7 @@
 {
 	SVCXPRT *transp;
 	int s, salen;
-	struct sockaddr_in sa;
+	struct sockaddr_in6 sa;
         int sock = 0;
         int proto = 0;
 
@@ -85,6 +90,9 @@
 			setuid(getuid());
 	}
 
+	(void)res_init();
+	_res.options |= RES_USE_INET6;
+
         /*
          * See if inetd started us
          */
@@ -110,7 +118,7 @@
                 if (getsockname(s, (struct sockaddr *)&sa, &salen))
                         err(1, "getsockname");
 
-                pmap_set(WALLPROG, WALLVERS, IPPROTO_UDP, ntohs(sa.sin_port));
+                pmap_set(WALLPROG, WALLVERS, IPPROTO_UDP, ntohs(sa.sin6_port));
                 if (dup2(s, 0) < 0)
                         err(1, "dup2");
                 (void)pmap_unset(WALLPROG, WALLVERS);
diff -uN src-current/libexec/rpc.sprayd/sprayd.c src-current-ipv6/libexec/rpc.sprayd/sprayd.c
--- src-current/libexec/rpc.sprayd/sprayd.c
+++ src-current-ipv6/libexec/rpc.sprayd/sprayd.c
@@ -39,10 +39,14 @@
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
+/*
+ * ipv6 rpc : use base address type struct sockaddr_in6 *  in rpc includes
+ */
+#define RPC_USE_INET6	/*  address type is struct sockaddr_in6 *  */
 #include <sys/time.h>
 #include <sys/socket.h>
 #include <syslog.h>
-#include <unistd.h>
+#include <resolv.h>
 
 static void spray_service __P((struct svc_req *, SVCXPRT *));
 
@@ -81,8 +85,11 @@
 	SVCXPRT *transp;
 	int sock = 0;
 	int proto = 0;
-	struct sockaddr_in from;
+	struct sockaddr_in6 from;
 	int fromlen;
+
+	(void)res_init();
+	_res.options |= RES_USE_INET6;
 
 	/*
 	 * See if inetd started us
diff -uN src-current/libexec/rshd/rshd.c src-current-ipv6/libexec/rshd/rshd.c
--- src-current/libexec/rshd/rshd.c
+++ src-current-ipv6/libexec/rshd/rshd.c
@@ -63,6 +63,7 @@
 #include <netinet/ip.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <resolv.h>
 
 #include <errno.h>
 #include <fcntl.h>
@@ -83,7 +84,7 @@
 int	log_success;		/* If TRUE, log all successful accesses */
 int	sent_null;
 
-void	 doit __P((struct sockaddr_in *));
+void	 doit __P((struct sockaddr_in6 *));
 void	 error __P((const char *, ...));
 void	 getstr __P((char *, int, char *));
 int	 local_domain __P((char *));
@@ -112,7 +113,7 @@
 	extern int __check_rhosts_file;
 	struct linger linger;
 	int ch, on = 1, fromlen;
-	struct sockaddr_in from;
+	struct sockaddr_in6 from;
 
 	openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
 
@@ -168,6 +169,9 @@
 #endif
 #endif
 
+	(void) res_init();
+	_res.options |= RES_USE_INET6;
+
 	fromlen = sizeof (from);
 	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
 		syslog(LOG_ERR, "getpeername: %m");
@@ -197,7 +201,7 @@
 
 void
 doit(fromp)
-	struct sockaddr_in *fromp;
+	struct sockaddr_in6 *fromp;
 {
 	extern char *__rcmd_errstr;	/* syslog hook from libc/net/rcmd.c. */
 	struct hostent *hp;
@@ -211,6 +215,7 @@
 	char cmdbuf[NCARGS+1], locuser[16], remuser[16];
 	char remotehost[2 * MAXHOSTNAMELEN + 1];
 	char fromhost[2 * MAXHOSTNAMELEN + 1];
+	char hname[MAXHOSTNAMELEN];
 #ifdef	LOGIN_CAP
 	login_cap_t *lc;
 #endif
@@ -239,13 +244,14 @@
 	  }
 	}
 #endif
-	fromp->sin_port = ntohs((u_short)fromp->sin_port);
-	if (fromp->sin_family != AF_INET) {
-		syslog(LOG_ERR, "malformed \"from\" address (af %d)",
-		    fromp->sin_family);
+	fromp->sin6_port = ntohs((u_short)fromp->sin6_port);
+	if (fromp->sin6_family != AF_INET6) {
+		syslog(LOG_ERR, "malformed \"from\" address (af %d)\n",
+		    fromp->sin6_family);
 		exit(1);
 	}
-#ifdef IP_OPTIONS
+/* should be IPV6_* options in IPv6 */
+#if defined(IP_OPTIONS) && defined(notyet)
       {
 	u_char optbuf[BUFSIZ/3];
 	int optsize = sizeof(optbuf), ipproto, i;
@@ -262,7 +268,9 @@
 			if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
 				syslog(LOG_NOTICE,
 					"connection refused from %s with IP option %s",
-					inet_ntoa(fromp->sin_addr),
+					inet_ntop(AF_INET6, &fromp->sin6_addr,
+						  fromhost,
+						  sizeof(fromhost) - 1));
 					c == IPOPT_LSRR ? "LSRR" : "SSRR");
 				exit(1);
 			}
@@ -277,12 +285,15 @@
 #ifdef	KERBEROS
 	if (!use_kerberos)
 #endif
-		if (fromp->sin_port >= IPPORT_RESERVED ||
-		    fromp->sin_port < IPPORT_RESERVED/2) {
+		if (fromp->sin6_port >= IPPORT_RESERVED ||
+		    fromp->sin6_port < IPPORT_RESERVED/2) {
+			char hbuf[64];
+
 			syslog(LOG_NOTICE|LOG_AUTH,
-			    "connection from %s on illegal port %u",
-			    inet_ntoa(fromp->sin_addr),
-			    fromp->sin_port);
+			       "connection from %s on illegal port %u",
+			       inet_ntop(fromp->sin6_family,
+					 &fromp->sin6_addr, hbuf, 64),
+					 fromp->sin6_port);
 			exit(1);
 		}
 
@@ -304,7 +315,7 @@
 	(void) alarm(0);
 	if (port != 0) {
 		int lport = IPPORT_RESERVED - 1;
-		s = rresvport(&lport);
+		s = rresvport_af(&lport, AF_INET6);
 		if (s < 0) {
 			syslog(LOG_ERR, "can't get stderr port: %m");
 			exit(1);
@@ -316,11 +327,12 @@
 			    port < IPPORT_RESERVED/2) {
 				syslog(LOG_NOTICE|LOG_AUTH,
 				    "2nd socket from %s on unreserved port %u",
-				    inet_ntoa(fromp->sin_addr),
+				    inet_ntop(AF_INET6, &fromp->sin6_addr,
+					      fromhost, sizeof(fromhost) - 1),
 				    port);
 				exit(1);
 			}
-		fromp->sin_port = htons(port);
+		fromp->sin6_port = htons(port);
 		if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) {
 			syslog(LOG_INFO, "connect second port %d: %m", port);
 			exit(1);
@@ -341,8 +353,8 @@
 	dup2(f, 2);
 #endif
 	errorstr = NULL;
-	hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr),
-		fromp->sin_family);
+	hp = gethostbyaddr((char *)&fromp->sin6_addr, sizeof(struct in6_addr),
+		fromp->sin6_family);
 	if (hp) {
 		/*
 		 * If name returned by gethostbyaddr is in our domain,
@@ -367,39 +379,43 @@
 				    remotehost);
 				errorstr =
 				"Couldn't look up address for your host (%s)\n";
-				strncpy(fromhost, inet_ntoa(fromp->sin_addr),
-					sizeof(fromhost) - 1);
+				inet_ntop(AF_INET6, &fromp->sin6_addr,
+					  fromhost, sizeof(fromhost) - 1);
 				fromhost[sizeof(fromhost) - 1] = 0;
 				hostname = fromhost;
 			} else for (; ; hp->h_addr_list++) {
 				if (hp->h_addr_list[0] == NULL) {
 					syslog(LOG_NOTICE,
 					  "host addr %s not listed for host %s",
-					    inet_ntoa(fromp->sin_addr),
+					    inet_ntop(AF_INET6,
+						      &fromp->sin6_addr,
+						      hname,
+						      MAXHOSTNAMELEN),
 					    hp->h_name);
 					errorstr =
 					    "Host address mismatch for %s\n";
-					strncpy(fromhost, inet_ntoa(fromp->sin_addr),
-						sizeof(fromhost) - 1);
+					inet_ntop(AF_INET6,
+						  &fromp->sin6_addr,
+						  fromhost,
+						  sizeof(fromhost) - 1);
 					fromhost[sizeof(fromhost) - 1] = 0;
 					hostname = fromhost;
 					break;
 				}
 				if (!bcmp(hp->h_addr_list[0],
-				    (caddr_t)&fromp->sin_addr,
-				    sizeof(fromp->sin_addr))) {
+				    (caddr_t)&fromp->sin6_addr,
+				    sizeof(fromp->sin6_addr))) {
 					hostname = remotehost;
 					break;
 				}
 			}
 		}
 	} else {
-		strncpy(fromhost, inet_ntoa(fromp->sin_addr),
-			sizeof(fromhost) - 1);
+		inet_ntop(AF_INET6, &fromp->sin6_addr,
+			  fromhost, sizeof(fromhost) - 1);
 		fromhost[sizeof(fromhost) - 1] = 0;
 		errorhost = hostname = fromhost;
 	}
-
 #ifdef	KERBEROS
 	if (use_kerberos) {
 		kdata = (AUTH_DAT *) authbuf;
@@ -493,8 +509,9 @@
 		if (errorstr ||
 		    (pwd->pw_expire && time(NULL) >= pwd->pw_expire) ||
 		    (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
-		    iruserok(fromp->sin_addr.s_addr, pwd->pw_uid == 0,
-		    remuser, locuser) < 0)) {
+		     iruserok2(AF_INET6, (char *)&fromp->sin6_addr,
+			       sizeof(fromp->sin6_addr), pwd->pw_uid == 0,
+			       remuser, locuser) < 0)) {
 			if (__rcmd_errstr)
 				syslog(LOG_INFO|LOG_AUTH,
 			    "%s@%s as %s: permission denied (%s). cmd='%.80s'",
@@ -519,8 +536,8 @@
 	if (lc != NULL) {
 		char	remote_ip[MAXHOSTNAMELEN];
 
-		strncpy(remote_ip, inet_ntoa(fromp->sin_addr),
-			sizeof(remote_ip) - 1);
+		inet_ntop(fromp->sin6_family, &fromp->sin6_addr,
+			  remote_ip, sizeof(remote_ip) - 1);
 		remote_ip[sizeof(remote_ip) - 1] = 0;
 		if (!auth_hostok(lc, fromhost, remote_ip)) {
 			syslog(LOG_INFO|LOG_AUTH,
diff -uN src-current/libexec/telnetd/telnetd.c src-current-ipv6/libexec/telnetd/telnetd.c
--- src-current/libexec/telnetd/telnetd.c
+++ src-current-ipv6/libexec/telnetd/telnetd.c
@@ -46,6 +46,8 @@
 #endif /* not lint */
 
 #include "telnetd.h"
+#include <netinet/ip6.h>
+#include <resolv.h>
 #include "pathnames.h"
 
 #if	defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY)
@@ -134,7 +136,7 @@
 int keepalive = 1;
 char *altlogin;
 
-void doit __P((struct sockaddr_in *));
+void doit __P((struct sockaddr_in6 *));
 int terminaltypeok __P((char *));
 void startslave __P((char *, int, char *));
 extern void usage P((void));
@@ -174,7 +176,7 @@
 main(argc, argv)
 	char *argv[];
 {
-	struct sockaddr_in from;
+	struct sockaddr_in6 from;
 	int on = 1, fromlen;
 	register int ch;
 #if	defined(IPPROTO_IP) && defined(IP_TOS)
@@ -386,34 +388,42 @@
 	argc -= optind;
 	argv += optind;
 
+	(void) res_init();
+	_res.options |= RES_USE_INET6;
+
 	if (debug) {
 	    int s, ns, foo;
 	    struct servent *sp;
-	    static struct sockaddr_in sin = { AF_INET };
+	    static struct sockaddr_in6 sin;
 
+#ifdef SIN6_LEN
+	    sin.sin6_len = sizeof(sin);
+#endif
+	    sin.sin6_family = AF_INET6;
 	    if (argc > 1) {
 		usage();
 		/* NOT REACHED */
 	    } else if (argc == 1) {
-		    if ((sp = getservbyname(*argv, "tcp"))) {
-			sin.sin_port = sp->s_port;
+		    if (sp = getservbyname(*argv, "tcp")) {
+			sin.sin6_port = sp->s_port;
 		    } else {
-			sin.sin_port = atoi(*argv);
-			if ((int)sin.sin_port <= 0) {
-			    warnx("%s: bad port #", *argv);
+			sin.sin6_port = atoi(*argv);
+			if ((int)sin.sin6_port <= 0) {
+			    warnx("telnetd: %s: bad port #", *argv);
 			    usage();
 			    /* NOT REACHED */
 			}
-			sin.sin_port = htons((u_short)sin.sin_port);
+			sin.sin6_port = htons((u_short)sin.sin6_port);
 		   }
 	    } else {
 		sp = getservbyname("telnet", "tcp");
 		if (sp == 0)
 		    errx(1, "tcp/telnet: unknown service");
-		sin.sin_port = sp->s_port;
+		sin.sin6_port = sp->s_port;
 	    }
+	    sin.sin6_flowinfo = IPV6_PRIORITY_INTERACTIVE;
 
-	    s = socket(AF_INET, SOCK_STREAM, 0);
+	    s = socket(AF_INET6, SOCK_STREAM, 0);
 	    if (s < 0)
 		    err(1, "socket");
 	    (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
@@ -504,22 +514,6 @@
 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
 	}
 
-#if	defined(IPPROTO_IP) && defined(IP_TOS)
-	{
-# if	defined(HAS_GETTOS)
-		struct tosent *tp;
-		if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
-			tos = tp->t_tos;
-# endif
-		if (tos < 0)
-			tos = 020;	/* Low Delay bit */
-		if (tos
-		   && (setsockopt(0, IPPROTO_IP, IP_TOS,
-				  (char *)&tos, sizeof(tos)) < 0)
-		   && (errno != ENOPROTOOPT) )
-			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
-	}
-#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
 	net = 0;
 	doit(&from);
 	/* NOTREACHED */
@@ -561,9 +555,6 @@
 #ifdef	SecurID
 	fprintf(stderr, " [-s]");
 #endif
-#ifdef	HAS_GETTOS
-	fprintf(stderr, " [-S tos]");
-#endif
 #ifdef	AUTHENTICATION
 	fprintf(stderr, " [-X auth-type]");
 #endif
@@ -767,9 +758,9 @@
  */
 	void
 doit(who)
-	struct sockaddr_in *who;
+	struct sockaddr_in6 *who;
 {
-	char *host = NULL;
+	char *host = NULL, host_buf[64];
 	struct hostent *hp;
 	int ptynum;
 
@@ -813,8 +804,8 @@
 #endif	/* _SC_CRAY_SECURE_SYS */
 
 	/* get name of connected client */
-	hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
-		who->sin_family);
+	hp = gethostbyaddr((char *)&who->sin6_addr, sizeof (struct in6_addr),
+		who->sin6_family);
 
 	if (hp == NULL && registerd_host_only) {
 		fatal(net, "Couldn't resolve your address into a host name.\r\n\
@@ -823,7 +814,8 @@
 	    (strlen(hp->h_name) <= ((utmp_len < 0) ? -utmp_len : utmp_len))) {
 		host = hp->h_name;
 	} else {
-		host = inet_ntoa(who->sin_addr);
+		host = inet_ntop(who->sin6_family, &who->sin6_addr,
+				 host_buf, 64);
 	}
 	/*
 	 * We must make a copy because Kerberos is probably going
diff -uN src-current/libexec/tftpd/tftpd.c src-current-ipv6/libexec/tftpd/tftpd.c
--- src-current/libexec/tftpd/tftpd.c
+++ src-current-ipv6/libexec/tftpd/tftpd.c
@@ -57,6 +57,7 @@
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <sys/types.h>
+#include <sys/uio.h>
 
 #include <netinet/in.h>
 #include <arpa/tftp.h>
@@ -67,6 +68,7 @@
 #include <fcntl.h>
 #include <netdb.h>
 #include <pwd.h>
+#include <resolv.h>
 #include <setjmp.h>
 #include <signal.h>
 #include <stdio.h>
@@ -86,8 +88,12 @@
 #define	PKTSIZE	SEGSIZE+4
 char	buf[PKTSIZE];
 char	ackbuf[PKTSIZE];
-struct	sockaddr_in from;
+struct	msghdr msg;
+struct	iovec iov;
+char	c_cmsg[100];
+struct	sockaddr_in6 from;
 int	fromlen;
+int	ismapped = 0;
 
 void	tftp __P((struct tftphdr *, int));
 
@@ -108,7 +114,7 @@
 
 static char *errtomsg __P((int));
 static void  nak __P((int));
-static char *verifyhost __P((struct sockaddr_in *));
+static char *verifyhost __P((struct sockaddr_in6 *));
 
 int
 main(argc, argv)
@@ -118,7 +124,9 @@
 	register struct tftphdr *tp;
 	register int n;
 	int ch, on;
-	struct sockaddr_in sin;
+	struct sockaddr_in6 sin;
+	struct in6_pktinfo pi;
+	struct cmsghdr *cmsgp;
 	char *chroot_dir = NULL;
 	struct passwd *nobody;
 
@@ -161,11 +169,18 @@
 		syslog(LOG_ERR, "ioctl(FIONBIO): %m");
 		exit(1);
 	}
-	fromlen = sizeof (from);
-	n = recvfrom(0, buf, sizeof (buf), 0,
-	    (struct sockaddr *)&from, &fromlen);
+	msg.msg_name = (char *)&from;
+	msg.msg_namelen = sizeof (from);
+	msg.msg_iov = &iov;
+	iov.iov_base = buf;
+	iov.iov_len = sizeof (buf);
+	msg.msg_iovlen = 1;
+	msg.msg_control = c_cmsg;
+	msg.msg_controllen = sizeof (c_cmsg);
+	msg.msg_flags = 0;
+	n = recvmsg(0, &msg, 0);
 	if (n < 0) {
-		syslog(LOG_ERR, "recvfrom: %m");
+		syslog(LOG_ERR, "recvmsg: %m");
 		exit(1);
 	}
 	/*
@@ -184,7 +199,7 @@
 	 */
 	{
 		int pid;
-		int i, j;
+		int i;
 
 		for (i = 1; i < 20; i++) {
 		    pid = fork();
@@ -200,12 +215,18 @@
 				 * than one tftpd being started up to service
 				 * a single request from a single client.
 				 */
-				j = sizeof from;
-				i = recvfrom(0, buf, sizeof (buf), 0,
-				    (struct sockaddr *)&from, &j);
+				msg.msg_name = (char *)&from;
+				msg.msg_namelen = sizeof (from);
+				msg.msg_iov = &iov;
+				iov.iov_base = buf;
+				iov.iov_len = sizeof (buf);
+				msg.msg_iovlen = 1;
+				msg.msg_control = c_cmsg;
+				msg.msg_controllen = sizeof (c_cmsg);
+				msg.msg_flags = 0;
+				i = recvmsg(0, &msg, 0);
 				if (i > 0) {
 					n = i;
-					fromlen = j;
 				}
 		    } else {
 				break;
@@ -238,19 +259,55 @@
 		setuid(nobody->pw_uid);
 	}
 
-	from.sin_family = AF_INET;
+	if (from.sin6_family != AF_INET6) {
+		syslog(LOG_ERR, "bad address family: %d", from.sin6_family);
+		exit(1);
+	}
+	if (msg.msg_flags & MSG_TRUNC) {
+		syslog(LOG_ERR, "message data truncated");
+		exit(1);
+	}
+	if (msg.msg_flags & MSG_CTRUNC) {
+		syslog(LOG_ERR, "message control truncated");
+		exit(1);
+	}
+	if (IN6_IS_ADDR_V4MAPPED(&from.sin6_addr)) {
+		ismapped = 1;
+	} else {
+		cmsgp = (struct cmsghdr *)c_cmsg;
+		for (; cmsgp; cmsgp = CMSG_NXTHDR(&msg, cmsgp))
+			if ((cmsgp->cmsg_level == IPPROTO_IPV6) &&
+			    (cmsgp->cmsg_type == IPV6_PKTINFO) &&
+			    (cmsgp->cmsg_len == sizeof (*cmsgp) + sizeof (pi)))
+				bcopy(CMSG_DATA(cmsgp), &pi, sizeof (pi));
+		if (pi.ipi6_ifindex <= 0) {
+			syslog(LOG_ERR, "no usable in6_pktinfo structure");
+			exit(1);
+		}
+	}
+
 	alarm(0);
 	close(0);
 	close(1);
-	peer = socket(AF_INET, SOCK_DGRAM, 0);
+	peer = socket(AF_INET6, SOCK_DGRAM, 0);
 	if (peer < 0) {
 		syslog(LOG_ERR, "socket: %m");
 		exit(1);
 	}
-	memset(&sin, 0, sizeof(sin));
-	sin.sin_family = AF_INET;
-	if (bind(peer, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
-		syslog(LOG_ERR, "bind: %m");
+	if (ismapped) {
+		memset(&sin, 0, sizeof(sin));
+#ifdef SIN6_LEN
+		sin.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+		sin.sin6_family = AF_INET6;
+		sin.sin6_addr = in6addr_any;
+		if (bind(peer, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
+			syslog(LOG_ERR, "bind: %m");
+			exit(1);
+		}
+	} else if (setsockopt(peer, IPPROTO_IPV6, IPV6_PKTINFO,
+		       (char *)&pi, sizeof (pi)) < 0) {
+		syslog(LOG_ERR, "setsockopt IPV6_PKTINFO: %m");
 		exit(1);
 	}
 	if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
@@ -297,6 +354,9 @@
 	register struct formats *pf;
 	char *filename, *mode;
 
+	(void) res_init();
+	_res.options |= RES_USE_INET6;
+
 	filename = cp = tp->th_stuff;
 again:
 	while (cp < buf + size) {
@@ -673,14 +733,17 @@
 
 static char *
 verifyhost(fromp)
-	struct sockaddr_in *fromp;
+	struct sockaddr_in6 *fromp;
 {
 	struct hostent *hp;
+	static char name[64 + 1];
 
-	hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (fromp->sin_addr),
-			    fromp->sin_family);
+	hp = gethostbyaddr((char *)&fromp->sin6_addr,
+			   sizeof (fromp->sin6_addr),
+			   fromp->sin6_family);
 	if (hp)
-		return hp->h_name;
+		strncpy(name, hp->h_name, 64);
 	else
-		return inet_ntoa(fromp->sin_addr);
+		inet_ntop(fromp->sin6_family, &fromp->sin6_addr, name, 64);
+	return name;
 }
diff -uN src-current/lkm/if_disc/Makefile src-current-ipv6/lkm/if_disc/Makefile
--- src-current/lkm/if_disc/Makefile
+++ src-current-ipv6/lkm/if_disc/Makefile
@@ -2,19 +2,22 @@
 
 .PATH:  ${.CURDIR}/../../sys/net
 KMOD=   if_disc_mod
-SRCS=   if_disc.c bpfilter.h	opt_inet.h
+SRCS=   if_disc.c bpfilter.h	opt_inet.h	opt_inet6.h
 NOMAN=
 PSEUDO_LKM=
 
 NBPFILTER?=	0
 
 CFLAGS+= ${PROTOS}
-CLEANFILES+=	bpfilter.h	opt_inet.h
+CLEANFILES+=	bpfilter.h	opt_inet.h	opt_inet6.h
 
 bpfilter.h:
 	echo "#define NBPFILTER ${NBPFILTER}" > bpfilter.h
 
 opt_inet.h:
 	echo "#define INET 1" > opt_inet.h
+
+opt_inet6.h:
+	echo "#define INET6 1" > opt_inet6.h
 
 .include <bsd.kmod.mk>
diff -uN src-current/lkm/if_ppp/Makefile src-current-ipv6/lkm/if_ppp/Makefile
--- src-current/lkm/if_ppp/Makefile
+++ src-current-ipv6/lkm/if_ppp/Makefile
@@ -3,7 +3,8 @@
 .PATH:  ${.CURDIR}/../../sys/net
 KMOD=   if_ppp_mod
 SRCS=	if_ppp.c ppp_tty.c slcompress.c \
-	bpfilter.h ppp.h opt_inet.h opt_ipx.h opt_ppp.h
+	bpfilter.h ppp.h opt_inet.h opt_ipflow.h opt_ipx.h opt_ppp.h \
+	opt_inet6.h
 NOMAN=
 PSEUDO_LKM=
 
@@ -12,6 +13,8 @@
 PPP_DEFLATE?=	1	# 0/1
 PPP_FILTER?=	0	# 0/1 - requires bpf to be configured in kernel
 PPP_INET?=	1	# 0/1 - requires INET to be configured in kernel
+PPP_INET6?=	1	# 0/1 - requires INET6 to be configured in kernel
+PPP_IPFLOW?=	0	# 0/1 - requires IPFLOW to be configured in kernel
 PPP_IPX?=	0	# 0/1 - requires IPX to be configured in kernel
 
 CFLAGS+= ${PROTOS}
@@ -23,7 +26,8 @@
 SRCS+=	ppp_deflate.c zlib.c
 .endif
 
-CLEANFILES+=	bpfilter.h opt_inet.h opt_ipx.h opt_ppp.h ppp.h
+CLEANFILES+=	bpfilter.h opt_inet.h opt_inet6.h opt_ipflow.h \
+		opt_ipx.h opt_ppp.h ppp.h
 
 bpfilter.h:
 	echo "#define NBPFILTER ${PPP_FILTER}" > bpfilter.h
@@ -35,6 +39,18 @@
 	touch opt_inet.h
 .if ${PPP_INET} > 0
 	echo "#define INET 1" > opt_inet.h
+.endif
+
+opt_inet6.h:
+	touch opt_inet6.h
+.if ${PPP_INET6} > 0
+	echo "#define INET 1" > opt_inet6.h
+.endif
+
+opt_ipflow.h:
+	touch opt_ipflow.h
+.if ${PPP_IPFLOW} > 0
+	echo "#define IPFLOW 1" > opt_ipflow.h
 .endif
 
 opt_ipx.h:
diff -uN src-current/lkm/if_tun/Makefile src-current-ipv6/lkm/if_tun/Makefile
--- src-current/lkm/if_tun/Makefile
+++ src-current-ipv6/lkm/if_tun/Makefile
@@ -2,7 +2,7 @@
 
 .PATH:  ${.CURDIR}/../../sys/net
 KMOD=   if_tun_mod
-SRCS=   if_tun.c bpfilter.h opt_devfs.h opt_inet.h tun.h
+SRCS=   if_tun.c bpfilter.h opt_devfs.h opt_inet.h opt_inet6.h tun.h
 NOMAN=
 PSEUDO_LKM=
 
@@ -10,7 +10,7 @@
 NTUN?=		2
 
 CFLAGS+= ${PROTOS}
-CLEANFILES+=	bpfilter.h opt_devfs.h opt_inet.h tun.h
+CLEANFILES+=	bpfilter.h opt_devfs.h opt_inet.h opt_inet6.h tun.h
 
 bpfilter.h:
 	echo "#define NBPFILTER ${NBPFILTER}" > bpfilter.h
@@ -20,6 +20,9 @@
 
 opt_inet.h:
 	echo "#define INET 1" > opt_inet.h
+
+opt_inet6.h:
+	echo "#define INET6 1" > opt_inet6.h
 
 tun.h:
 	echo "#define NTUN ${NTUN}" > tun.h
diff -uN src-current/lkm/nfs/Makefile src-current-ipv6/lkm/nfs/Makefile
--- src-current/lkm/nfs/Makefile
+++ src-current-ipv6/lkm/nfs/Makefile
@@ -4,18 +4,25 @@
 KMOD=   nfs_mod
 SRCS=   nfs_bio.c nfs_node.c nfs_nqlease.c nfs_serv.c nfs_socket.c \
         nfs_srvcache.c nfs_subs.c nfs_syscalls.c nfs_vfsops.c \
-	nfs_vnops.c opt_inet.h
+	nfs_vnops.c opt_inet.h opt_inet6.h
 NFS_INET?=	1	# 0/1 - requires INET to be configured in kernel
+NFS_INET6?=	1
 NOMAN=
 VFS_LKM=
 
 CFLAGS+= -DNFS
-CLEANFILES+=	opt_inet.h
+CLEANFILES+=	opt_inet.h opt_inet6.h
 
 opt_inet.h:
 	touch opt_inet.h
 .if ${NFS_INET} > 0
 	echo "#define INET 1" > opt_inet.h
+.endif
+
+opt_inet6.h:
+	touch opt_inet6.h
+.if ${NFS_INET6} > 0
+	echo "#define INET6 1" > opt_inet6.h
 .endif
 
 .include <bsd.kmod.mk>
diff -uN src-current/sbin/dump/dumprmt.c src-current-ipv6/sbin/dump/dumprmt.c
--- src-current/sbin/dump/dumprmt.c
+++ src-current-ipv6/sbin/dump/dumprmt.c
@@ -58,6 +58,7 @@
 #include <ctype.h>
 #include <err.h>
 #include <netdb.h>
+#include <resolv.h>
 #include <pwd.h>
 #include <signal.h>
 #include <stdio.h>
@@ -147,6 +148,10 @@
 	int size;
 	int throughput;
 	int on;
+
+	(void) res_init();
+	if (!dokerberos)
+		_res.options |= RES_USE_INET6;
 
 	if (sp == NULL) {
 		sp = getservbyname(dokerberos ? "kshell" : "shell", "tcp");
diff -uN src-current/sbin/ifconfig/ifconfig.8 src-current-ipv6/sbin/ifconfig/ifconfig.8
--- src-current/sbin/ifconfig/ifconfig.8
+++ src-current-ipv6/sbin/ifconfig/ifconfig.8
@@ -47,6 +47,20 @@
 .Oc
 .Op Ar parameters
 .Nm ifconfig
+.Ar interface
+.Cm inet6 first
+.Ar address
+.Nm ifconfig
+.Ar interface
+.Cm inet6 firstalias
+.Ar address
+.Op Ar dest_address
+.Op Ar parameters
+.Nm ifconfig
+.Ar interface
+.Cm site6
+.Ar site_number
+.Nm ifconfig
 .Fl a
 .Op Fl d
 .Op Fl u
@@ -100,6 +114,8 @@
 .\" as in the Xerox family.  However, two consecutive dots imply a zero
 .\" byte, and the dots are optional, if the user wishes to (carefully)
 .\" count out long strings of digits in network byte order.
+For the IPv6 family, addresses can be followed by prefix length like
+.Ar address/length .
 .It Ar address_family
 Specifies the
 .Ar address family
@@ -109,6 +125,7 @@
 The address or protocol families currently
 supported are
 .Dq inet ,
+.Dq inet6 ,
 .Dq atalk ,
 .\" .Dq iso ,
 and
@@ -145,6 +162,8 @@
 Specify the address to use to represent broadcasts to the
 network.
 The default broadcast address is the address with a host part of all 1's.
+.It Fl dad
+(inet6 only) Do not perform duplicate IPv6 address detection.
 .It Cm debug
 Enable driver dependent debugging code; usually, this turns on
 extra console error logging.
@@ -166,6 +185,18 @@
 transmit messages through that interface. 
 If possible, the interface will be reset to disable reception as well.
 This action does not automatically disable routes using the interface.
+.It Cm eui64
+(inet6 only)
+The real IPv6 address is computed by replacing the last 64 bytes of
+the given address with the Interface Identifier.
+.It Cm first
+Put an IPv6 address at the first place on an interface in order
+to select it as the source for unbound sockets.
+.It Cm firstalias
+(inet6 only) Same as
+.Cm alias ,
+but set the address in front of the interface address list
+in order to select it as the source for unbound sockets.
 .\" .It Cm ipdst
 .\" This is used to specify an Internet host who is willing to receive
 .\" ip packets encapsulating NS packets bound for a remote network.
@@ -175,6 +206,15 @@
 .\" IP encapsulation of
 .\" .Tn CLNP
 .\" packets is done differently.
+.It Cm ipv6src
+This is used to specified an IPv6 node who is willing to send
+IPv6 packets encapsulating IPv4 packets through a tunnel.
+.It Cm ipv6dst
+This is used to specified an IPv6 node who is willing to receive
+IPv6 packets encapsulating IPv6 or IPv4 packets through a tunnel.
+The apparent destination of the point to point tunnel interface
+cannot be the real destination of the packets because of route
+looping.
 .It Cm media Ar type
 If the driver supports the media selection system, set the media type
 of the interface to
@@ -285,6 +325,9 @@
 It happens automatically when setting the first address on an interface.
 If the interface was reset when previously marked down,
 the hardware will be re-initialized.
+.It Cm site6
+Set the IPv6 site number (default is zero).
+This should be used only with site-local addresses on a multi-sited node.
 .El
 .Pp
 .Nm
diff -uN src-current/sbin/ifconfig/ifconfig.c src-current-ipv6/sbin/ifconfig/ifconfig.c
--- src-current/sbin/ifconfig/ifconfig.c
+++ src-current-ipv6/sbin/ifconfig/ifconfig.c
@@ -86,6 +86,15 @@
 #include <netiso/iso_var.h>
 #endif
 
+/* IPv6 */
+#define INET6
+#include <sys/uio.h>
+#include <netinet/in6_var.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip6.h>
+#include <netinet/ip6_var.h>
+#include <netinet/ip6_icmp.h>
+
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
@@ -103,6 +112,8 @@
 struct	iso_ifreq	iso_ridreq;
 struct	iso_aliasreq	iso_addreq;
 #endif
+struct	in6_ifreq	in6_ridreq;
+struct	in6_aliasreq	in6_addreq;
 struct	sockaddr_in	netmask;
 struct	netrange	at_nr;		/* AppleTalk net range */
 
@@ -115,9 +126,14 @@
 #endif
 int	setaddr;
 int	setipdst;
+int	setipv6src;
+int	setipv6dst;
 int	doalias;
 int	clearaddr;
 int	newaddr = 1;
+int	first;
+int	ismask, ifindex, eui64, nodad;
+int	site6 = -1;
 
 struct	afswtch;
 
@@ -142,6 +158,12 @@
 c_func	setsnpaoffset, setnsellength;
 #endif
 
+c_func	setifprefixlen, setiffirst, setifsite6, setifipv6src, setifipv6dst;
+c_func	noteeui64, notefirstalias, notenodad;
+void	gettoken __P((u_char *, int));
+int	prefix __P((void *, int));
+int	dad_ipv6 __P((int, u_int, struct in6_aliasreq *));
+
 #define	NEXTARG		0xffffff
 
 const
@@ -165,11 +187,14 @@
 	{ "-swabips",	-EN_SWABIPS,	setifflags },
 #endif
 	{ "netmask",	NEXTARG,	setifnetmask },
+	{ "prefixlen",	NEXTARG,	setifprefixlen },
 	{ "range",	NEXTARG,	setatrange },
 	{ "phase",	NEXTARG,	setatphase },
 	{ "metric",	NEXTARG,	setifmetric },
 	{ "broadcast",	NEXTARG,	setifbroadaddr },
 	{ "ipdst",	NEXTARG,	setifipdst },
+	{ "ipv6src",	NEXTARG,	setifipv6src },
+	{ "ipv6dst",	NEXTARG,	setifipv6dst },
 #ifdef ISO
 	{ "snpaoffset",	NEXTARG,	setsnpaoffset },
 	{ "nsellength",	NEXTARG,	setnsellength },
@@ -189,6 +214,12 @@
 	{ "compress",	IFF_LINK0,	setifflags },
 	{ "noicmp",	IFF_LINK1,	setifflags },
 	{ "mtu",	NEXTARG,	setifmtu },
+	{ "first",	NEXTARG,	setiffirst },
+	{ "site6",	NEXTARG,	setifsite6 },
+	{ "eui64",	1,		noteeui64 },
+	{ "eui-64",	1,		noteeui64 },
+	{ "firstalias",	IFF_UP,		notefirstalias },
+	{ "-dad",	1,		notenodad },
 	{ 0,		0,		setifaddr },
 	{ 0,		0,		setifdstaddr },
 };
@@ -212,6 +243,9 @@
 af_getaddr	iso_getaddr;
 #endif
 
+af_status	in6_status;
+af_getaddr	in6_getaddr, in6_getprefix;
+
 /* Known address families */
 const
 struct	afswtch {
@@ -219,33 +253,36 @@
 	short af_af;
 	af_status *af_status;
 	af_getaddr *af_getaddr;
+	af_getaddr *af_getprefix;
 	int af_difaddr;
 	int af_aifaddr;
 	caddr_t af_ridreq;
 	caddr_t af_addreq;
 } afs[] = {
 #define C(x) ((caddr_t) &x)
-	{ "inet", AF_INET, in_status, in_getaddr,
+	{ "inet", AF_INET, in_status, in_getaddr, 0,
 	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
-	{ "ipx", AF_IPX, ipx_status, ipx_getaddr,
+	{ "ipx", AF_IPX, ipx_status, ipx_getaddr, 0,
 	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
-	{ "atalk", AF_APPLETALK, at_status, at_getaddr,
+	{ "atalk", AF_APPLETALK, at_status, at_getaddr, 0,
 	     SIOCDIFADDR, SIOCAIFADDR, C(addreq), C(addreq) },
 #ifdef NS
-	{ "ns", AF_NS, xns_status, xns_getaddr,
+	{ "ns", AF_NS, xns_status, xns_getaddr, 0,
 	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
 #endif
 #ifdef ISO
-	{ "iso", AF_ISO, iso_status, iso_getaddr,
+	{ "iso", AF_ISO, iso_status, iso_getaddr, 0,
 	     SIOCDIFADDR_ISO, SIOCAIFADDR_ISO, C(iso_ridreq), C(iso_addreq) },
 #endif
-	{ "ether", AF_INET, ether_status, NULL },	/* XXX not real!! */
+	{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
+	     SIOCDIFADDR6, SIOCAIFADDR6, C(in6_ridreq), C(in6_addreq) },
+	{ "ether", AF_INET, ether_status, NULL, NULL },	/* XXX not real!! */
 #if 0	/* XXX conflicts with the media command */
 #ifdef USE_IF_MEDIA
-	{ "media", AF_INET, media_status, NULL },	/* XXX not real!! */
+	{ "media", AF_INET, media_status, NULL, NULL },	/* XXX not real!! */
 #endif
 #endif
-	{ 0,	0,	    0,		0 }
+	{ 0,	0,	    0,		0,	0 }
 };
 
 /*
@@ -283,6 +320,8 @@
 	fputs("        [ af [ address [ dest_addr ] ] [ netmask mask ] [ broadcast addr ]\n", stderr);
 	fputs("             [ alias ] [ delete ] ]\n", stderr);
 	fputs("        [ up ] [ down ]\n", stderr);
+	fputs("        [ af first[alias] address [ ... ] ]\n", stderr);
+	fputs("        [ site6 site_number ]\n", stderr);
 	fputs("        [ metric n ]\n", stderr);
 	fputs("        [ mtu n ]\n", stderr);
 	fputs("        [ arp | -arp ]\n", stderr);
@@ -411,6 +450,7 @@
 		if (ifm->ifm_type == RTM_IFINFO) {
 			sdl = (struct sockaddr_dl *)(ifm + 1);
 			flags = ifm->ifm_flags;
+			ifindex = ifm->ifm_index;
 		} else {
 			fprintf(stderr, "out of sync parsing NET_RT_IFLIST\n");
 			fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO,
@@ -527,7 +567,7 @@
 		argc--, argv++;
 	}
 #ifdef ISO
-	if (af == AF_ISO)
+	if (ifr.ifr_addr.sa_family == AF_ISO)
 		adjust_nsellength();
 #endif
 	if (setipdst && ifr.ifr_addr.sa_family == AF_IPX) {
@@ -554,6 +594,49 @@
 			Perror("Encapsulation Routing");
 	}
 #endif
+
+	if (ifr.ifr_addr.sa_family == AF_INET6 && newaddr >0 && !ismask)
+		if (flags & IFF_POINTOPOINT)
+			bzero (&in6_addreq.ifra_mask,
+			       sizeof (in6_addreq.ifra_mask));
+		else
+			errx(1, "inet6 needs prefixlen");
+#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
+	if (eui64) {
+		u_char token[IPV6_TOKEN_LENGTH/8];
+
+		gettoken(token, sizeof token);
+#define AD6(x)	(((struct sockaddr_in6 *)rqtosa(x))->sin6_addr)
+		if (rqtosa(af_ridreq)->sa_family == AF_INET6)
+			bcopy((caddr_t)token,
+			      (caddr_t)&(AD6(af_ridreq).s6_addr[
+						sizeof (struct in6_addr) -
+						sizeof token]),
+			      sizeof token);
+		if (rqtosa(af_addreq)->sa_family == AF_INET6)
+			bcopy((caddr_t)token,
+			      (caddr_t)&(AD6(af_addreq).s6_addr[
+						sizeof (struct in6_addr) -
+						sizeof token]),
+			      sizeof token);
+#undef AD6
+	}
+	if (site6 != -1) {
+		strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+		ifr.ifr_site6 = site6;
+		if (ioctl(s, SIOCSIFSITE6, (caddr_t)&ifr) < 0)
+			Perror("ioctl (SIOCSIFSITE6)");
+	}
+	if (setipv6dst && !setipv6src) {
+		strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
+		if (ioctl(s, SIOCSTUGADDR6, afp->af_ridreq) < 0)
+			Perror("ioctl (SIOCSTUGADDR6)");
+	}
+	if (setipv6dst && setipv6src) {
+		strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
+		if (ioctl(s, SIOCSBTIADDR6, afp->af_addreq) < 0)
+			Perror("ioctl (SIOCSBTIADDR6)");
+	}
 	if (clearaddr) {
 		if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
 			warnx("interface %s cannot change %s addresses!",
@@ -578,10 +661,34 @@
 			newaddr = NULL;
 		}
 	}
+	if (ifr.ifr_addr.sa_family == AF_INET6 && clearaddr && newaddr)
+		first = 1;
 	if (newaddr) {
 		strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
+		if (ifr.ifr_addr.sa_family == AF_INET6 && !nodad) {
+			int ret;
+
+			ret = dad_ipv6(s, ifindex,
+				       (struct in6_aliasreq *)afp->af_addreq);
+			if (ret > 0)
+				goto addr_set;
+			if (ret < 0)
+				exit (1);
+		}
 		if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
 			Perror("ioctl (SIOCAIFADDR)");
+	addr_set:
+		if (first && !rqtosa(af_ridreq)->sa_family) {
+			bcopy((caddr_t)rqtosa(af_addreq),
+			      (caddr_t)rqtosa(af_ridreq),
+			      rqtosa(af_addreq)->sa_len);
+		}
+#undef rqtosa
+	}
+	if (first) {
+		strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
+		if (ioctl(s, SIOCFIFADDR6, afp->af_ridreq) < 0)
+			Perror("ioctl (SIOCFIFADDR6)");
 	}
 	close(s);
 	return(0);
@@ -621,6 +728,18 @@
 }
 
 void
+setifprefixlen(addr, dummy, s, afp)
+	const char *addr;
+	int dummy __unused;
+	int s;
+	const struct afswtch *afp;
+{
+	ismask = 1;
+	if (*afp->af_getprefix)
+		(*afp->af_getprefix)(addr, MASK);
+}
+
+void
 setifbroadaddr(addr, dummy, s, afp)
 	const char *addr;
 	int dummy __unused;
@@ -642,6 +761,113 @@
 	clearaddr = 0;
 	newaddr = 0;
 }
+
+void
+setiffirst(addr, dummy, s, afp)
+	const char *addr;
+	int dummy __unused;
+	int s;
+	const struct afswtch *afp;
+{
+	if (afp->af_af != AF_INET6)
+		errx(1, "%s: inet6 only option", addr);
+	(*afp->af_getaddr)(addr, RIDADDR);
+	first++;
+	clearaddr = 0;
+	newaddr = 0;
+}
+
+void
+notefirstalias(addr, param, s, afp)
+	const char *addr;
+	int param;
+	int s;
+	const struct afswtch *afp;
+{
+	if (afp->af_af != AF_INET6)
+		errx(1, "%s: inet6 only option", addr);
+	first++;
+	notealias(addr, param, s, afp);
+}
+
+void
+noteeui64(addr, param, s, afp)
+	const char *addr;
+	int param;
+	int s;
+	const struct afswtch *afp;
+{
+	if (afp->af_af != AF_INET6)
+		errx(1, "%s: inet6 only option", addr);
+	eui64 = param;
+}
+
+void
+notenodad(addr, param, s, afp)
+	const char *addr;
+	int param;
+	int s;
+	const struct afswtch *afp;
+{
+	if (afp->af_af != AF_INET6)
+		errx(1, "%s: inet6 only option", addr);
+	nodad = param;
+}
+
+void
+setifsite6(addr, dummy, s, afp)
+	const char *addr;
+	int dummy __unused;
+	int s;
+	const struct afswtch *afp;
+{
+	register int ns;
+
+	site6 = atoi(addr);
+	clearaddr = 0;
+	newaddr = 0;
+	ns = socket(AF_INET6, SOCK_DGRAM, 0);
+	if (ns < 0) {
+		if (errno == EPROTONOSUPPORT)
+			return;
+		perror("ifconfig: socket");
+		exit(1);
+	}
+	dup2(ns, s);
+	close(ns);
+}
+
+void
+setifipv6src(addr, dummy, s, afp)
+	const char *addr;
+	int dummy __unused;
+	int s;
+	const struct afswtch *afp;
+{
+	if (afp->af_af != AF_INET6)
+		errx(1, "%s: inet6 only option", addr);
+	(*afp->af_getaddr)(addr, ADDR);
+	setipv6src++;
+	clearaddr = 0;
+	newaddr = 0;
+}
+
+void
+setifipv6dst(addr, dummy, s, afp)
+	const char *addr;
+	int dummy __unused;
+	int s;
+	const struct afswtch *afp;
+{
+	if (afp->af_af != AF_INET6)
+		errx(1, "%s: inet6 only option", addr);
+	(*afp->af_getaddr)(addr, RIDADDR);
+	(*afp->af_getaddr)(addr, DSTADDR);
+	setipv6dst++;
+	clearaddr = 0;
+	newaddr = 0;
+}
+
 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
 
 void
@@ -835,6 +1061,123 @@
 	return;
 }
 
+/*
+ * Get IPv6 interface ID
+ * Try first an Link-Local address, then a Link Layer address if MAC
+ */
+void
+gettoken(token, len)
+	u_char *token;
+	int len;
+{
+	struct	if_msghdr *ifm, *nextifm;
+	struct	ifa_msghdr *ifam;
+	struct	sockaddr_dl *sdl;
+	struct	rt_addrinfo info;
+	char	*buf, *lim, *next;
+	size_t needed;
+	int mib[6];
+
+	mib[0] = CTL_NET;
+	mib[1] = PF_ROUTE;
+	mib[2] = 0;
+	mib[3] = 0;
+	mib[4] = NET_RT_IFLIST;
+	mib[5] = 0;
+
+	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+		errx(1, "gettoken: iflist-sysctl-estimate");
+	if ((buf = malloc(needed)) == NULL)
+		errx(1, "gettoken: malloc");
+	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+		errx(1, "gettoken: retrieval");
+	lim = buf + needed;
+
+	next = buf;
+	while (next < lim) {
+
+		ifm = (struct if_msghdr *)next;
+		
+		if (ifm->ifm_type == RTM_IFINFO)
+			sdl = (struct sockaddr_dl *)(ifm + 1);
+		else
+			errx(1, "gettoken: out of sync");
+
+		next += ifm->ifm_msglen;
+		ifam = NULL;
+		while (next < lim) {
+
+			nextifm = (struct if_msghdr *)next;
+
+			if (nextifm->ifm_type != RTM_NEWADDR)
+				break;
+
+			if (ifam == NULL)
+				ifam = (struct ifa_msghdr *)nextifm;
+
+			next += nextifm->ifm_msglen;
+		}
+
+		if (strlen(name) != sdl->sdl_nlen)
+			continue;	/* not same len */
+		if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) == 0)
+			goto found;	/* same name */
+	}
+
+	errx(1, "gettoken: interface not found");
+
+    found:
+
+	nextifm = ifm;
+	next = (char *)ifm;
+
+	while (1) {
+
+		next += nextifm->ifm_msglen;
+
+		if (next >= lim)
+			break;
+
+		nextifm = (struct if_msghdr *)next;
+
+		if (nextifm->ifm_type != RTM_NEWADDR)
+			break;
+
+		ifam = (struct ifa_msghdr *)nextifm;
+		info.rti_addrs = ifam->ifam_addrs;
+
+		/* Expand the compacted addresses */
+		rt_xaddrs((char *)(ifam + 1),
+			  ifam->ifam_msglen + (char *)ifam,
+			  &info);
+
+#define AD6	(((struct sockaddr_in6 *)info.rti_info[RTAX_IFA])->sin6_addr)
+		if (info.rti_info[RTAX_IFA]->sa_family == AF_INET6 &&
+		    IS_LOCALADDR6(AD6)) {
+			bcopy((caddr_t)&(AD6.s6_addr[
+					sizeof (struct in6_addr)-len]),
+			      (caddr_t)token,
+			      len);
+			return;
+		}
+#undef AD6
+	}
+	/* Heuristic from autoconf6 */
+	if ((ifm->ifm_flags & IFF_BROADCAST) &&
+	    (ifm->ifm_flags & IFF_MULTICAST) &&
+	    sdl->sdl_alen == 6) {
+		bcopy(LLADDR(sdl), token, 6);
+#if IPV6_TOKEN_LENGTH == 64
+		token[0] ^= 0x02;
+		token[3] = 0xff;
+		token[4] = 0xfe;
+		bcopy(LLADDR(sdl) + 3, token + 5, 3);
+#endif
+		return;
+	}
+	errx(1, "%s: no eui-64", name);
+}
+
 void
 in_status(s, info)
 	int s __unused;
@@ -957,12 +1300,22 @@
 	struct rt_addrinfo * info;
 {
 	struct sockaddr_iso *siso, null_siso;
+	int plen;
 
 	memset(&null_siso, 0, sizeof(null_siso));
 
 	siso = (struct sockaddr_iso *)info->rti_info[RTAX_IFA];
 	printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
 
+	siso = (struct sockaddr_iso *)info->rti_info[RTAX_NETMASK];
+	if (siso) {
+		if ((plen = prefix(siso->siso_data, siso->siso_nlen)) >= 0)
+			printf("/%d ", plen);
+		else
+			printf(" netmask %s ", iso_ntoa(&siso->siso_addr));
+	} else
+		printf(" ");
+
 	if (flags & IFF_POINTOPOINT) {
 		siso = (struct sockaddr_iso *)info->rti_info[RTAX_BRD];
 		if (!siso)
@@ -979,6 +1332,66 @@
 #endif
 
 void
+in6_status(s, info)
+	int s;
+	struct rt_addrinfo * info;
+
+{
+	struct sockaddr_in6 *sin, null_sin;
+	char hbuf[64];
+	int plen, dosite = 0;
+
+	memset(&null_sin, 0, sizeof(null_sin));
+
+	sin = (struct sockaddr_in6 *)info->rti_info[RTAX_IFA];
+	if (IN6_IS_ADDR_SITELOCAL(&sin->sin6_addr))
+		dosite = 1;
+	printf("\tinet6 %s",
+	       inet_ntop(AF_INET6, &sin->sin6_addr, hbuf, sizeof(hbuf)));
+
+	sin = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK];
+	if (sin) {
+		plen = prefix(&sin->sin6_addr, sizeof(struct in6_addr));
+		if (plen >= 0)
+			printf("/%d ", plen);
+		else
+			printf(" netmask %s ",
+			       inet_ntop(AF_INET6, &sin->sin6_addr,
+					 hbuf, sizeof(hbuf)));
+	} else
+		printf(" ");
+
+	if (flags & IFF_POINTOPOINT) {
+		sin = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD];
+		if (!sin)
+			sin = &null_sin;
+		printf("--> %s ",
+		       inet_ntop(AF_INET6, &sin->sin6_addr,
+				 hbuf, sizeof(hbuf)));
+	}
+
+	if (dosite) {
+		register int ns;
+
+		ns = socket(AF_INET6, SOCK_DGRAM, 0);
+		if (ns < 0) {
+			if (errno != EPROTONOSUPPORT)
+				perror("dosite socket");
+			goto done;
+		}
+		strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+		ifr.ifr_site6 = 0;
+		if (ioctl(ns, SIOCGIFSITE6, (caddr_t)&ifr) < 0)
+			perror("ioctl (SIOCGIFSITE6)");
+		if (ifr.ifr_site6)
+			printf("site6 %d", (int)ifr.ifr_site6);
+		(void) close(ns);
+	}
+    done:
+	putchar('\n');
+}
+
+void
 ether_status(s, info)
 	int s __unused;
 	struct rt_addrinfo *info;
@@ -993,7 +1406,7 @@
 			printf ("\tether ");
 		else
 			printf ("\tlladdr ");
-             	while (--n >= 0)
+		while (--n >= 0)
 			printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' ');
 		putchar('\n');
 	}
@@ -1243,3 +1656,439 @@
 	fixnsel(sisotab[DSTADDR]);
 }
 #endif
+
+#define SIN6(x) ((struct sockaddr_in6 *) &(x))
+struct sockaddr_in6 *sin6tab[] = {
+SIN6(in6_ridreq.ifr_Addr), SIN6(in6_addreq.ifra_addr),
+SIN6(in6_addreq.ifra_mask), SIN6(in6_addreq.ifra_dstaddr)};
+
+void
+in6_getaddr(addr, which)
+	const char *addr;
+	int which;
+{
+	register struct sockaddr_in6 *sin = sin6tab[which];
+	struct hostent *hp;
+	char *plen = strchr(addr, '/');
+
+	sin->sin6_len = sizeof(*sin);
+	if (which != MASK)
+		sin->sin6_family = AF_INET6;
+	if ((which < MASK) && plen) {
+		*plen++ = '\0';
+		ismask = 1;
+		in6_getprefix(plen, MASK);
+	}
+	if (inet_pton(AF_INET6, addr, &sin->sin6_addr) > 0)
+		;
+	else if ((hp = gethostbyname2(addr, AF_INET6)) != NULL)
+		bcopy(hp->h_addr, (char *)&sin->sin6_addr, hp->h_length);
+	else
+		errx(1, "%s: bad value", addr);
+}
+
+void
+in6_getprefix(plen, which)
+	const char *plen;
+	int which;
+{
+	register struct sockaddr_in6 *sin = sin6tab[which];
+	register u_char *cp;
+	int len = atoi(plen);
+
+	if ((len < 0) || (len > 128))
+		errx(1, "%s: bad value", plen);
+	sin->sin6_len = sizeof(*sin);
+	if (which != MASK)
+		sin->sin6_family = AF_INET6;
+	if ((len == 0) || (len == 128)) {
+		memset(&sin->sin6_addr, -1, sizeof(struct in6_addr));
+		return;
+	}
+	for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
+		*cp++ = -1;
+	*cp = (-1) << (8 - len);
+}
+
+int
+prefix(val, size)
+	void *val;
+	int size;
+{
+	register u_char *name = (u_char *)val;
+	register int byte, bit, plen = 0;
+
+	for (byte = 0; byte < size; byte++, plen += 8)
+		if (name[byte] != 0xff)
+			break;
+	if (byte >= size)
+		return (plen);
+	for (bit = 7; bit != 0; bit--, plen++)
+		if (!(name[byte] & (1 << bit)))
+			break;
+	for (; bit != 0; bit--)
+		if (name[byte] & (1 << bit))
+			return(-1);
+	byte++;
+	for (; byte < size; byte++)
+		if (name[byte])
+			return(-1);
+	return (plen);
+}
+
+#include <signal.h>
+#define MAX_RTR_SOLICITATION_DELAY	1
+#define RETRANS_TIMER			1
+#define DupAddrDetectTransmits		2
+#define MAXPACKET	576	/* max packet size */
+
+int dring = 0;			/* timeout expired */
+u_int delay;			/* initial timeout in seconds */
+u_int reload;			/* retrans timeout in seconds */
+int ntosend = 0;		/* packet to send counter */
+int ninflow = 0;		/* packet on the cable counter */
+
+void intr_dad __P((int));
+void setsig_dad __P((void (*) __P((int))));
+int recv_icmp6 __P((char *, int, struct in6_addr *));
+int in_cksum __P((u_short *, int));
+
+int
+dad_ipv6(u, ifp, req)
+	int u;
+	u_int ifp;
+	struct in6_aliasreq *req;
+{
+	u_int val;
+	int cc, si = -1, ret = -1; /* < 0: err, 0: not done, > 0: OK */
+	struct msghdr msg;
+	struct iovec iov;
+	u_char packet[MAXPACKET];
+	u_char msgndsol[sizeof (struct ipv6) + ICMP6_NSLEN];
+	register struct ipv6 *ip = (struct ipv6 *)msgndsol;
+	register struct icmpv6 *icp = (struct icmpv6 *)(ip + 1);
+	struct sockaddr_in6 dst;
+	int lgsol;
+	struct { 
+		struct cmsghdr c_cm;
+		union {
+			struct in6_pktinfo c_pi;
+			u_char c_uspace[64];
+		} c_space;
+	} c_cmsg;
+#define pi	c_cmsg.c_space.c_pi
+#define cm	c_cmsg.c_cm
+
+	if ((flags & IFF_MULTICAST) == 0) {
+		warnx("Warning: address set without test for dad (no multicast support)");
+		return (0);
+	}
+	if ((flags & IFF_UP) == 0) {
+		warnx("Warning: address set without test for dad (interface down)");
+		return (0);
+	}
+	/* force EINTR on ICMP reads */
+	setsig_dad(intr_dad);
+
+	if (ioctl(u, SIOCAIFADDR6, (caddr_t)req) < 0) {
+		warn("dad ioctl (SIOCAIFADDR6)");
+		goto done;
+	}
+	/* 
+	 * set the adress as tentative; 
+	 * To be corrected : between the two ioctl the address is valid !!
+	 */
+	memset((caddr_t)&req->ifra_mask, -1,
+	       sizeof(struct sockaddr_in6));
+	if (ioctl(u, SIOCVIFADDR6, (caddr_t)req) < 0) {
+		warn("dad ioctl (SIOCVIFADDR6)");
+		goto errdel;
+	}
+		
+	/* Open ICMPv6 "si" socket */
+	if ((si = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
+		warn("dad socket");
+		goto errdel;
+	}
+
+	val = 1;
+	if (setsockopt(si, IPPROTO_IPV6, IP_HDRINCL,
+		       &val, sizeof(val)) < 0) {
+		warn("dad setsockopt(IP_HDRINCL)");
+		goto errdel;
+	}
+
+	val = 1;
+	if (setsockopt(si, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
+		       &val, sizeof(val)) < 0) {
+		warn("dad setsockopt(IPV6_MULTICAST_LOOP)");
+		goto errdel;
+	}
+
+	val = 1;
+	if (setsockopt(si, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+		       &val, sizeof(val)) < 0) {
+		perror("dad setsockopt(IPV6_RECVPKTINFO)");
+		goto errdel;
+	}
+
+	/* needed, even with IP_HDRINCL ?! */
+	val = ICMP6_ND_HOPS;
+	if (setsockopt(si, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+		       &val, sizeof(val)) < 0) {
+		warn("dad setsockopt (IPV6_MULTICAST_HOPS)");
+		goto done;
+	}
+
+	val = ifp;
+	if (setsockopt(si, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+		       &val, sizeof(val)) < 0) {
+		warn("dad setsockopt (IPV6_MULTICAST_IF)");
+		goto done;
+	}
+
+	/* ICMPv6 Neighbor Solicitation packet */
+	lgsol = ICMP6_NSLEN + sizeof(struct ipv6);
+	bzero((caddr_t)msgndsol, lgsol);
+
+	icp->icmp6_type = ICMP6_SOLICITATION_ND;
+	COPY_ADDR6(req->ifra_addr.sin6_addr, icp->icmp6_tgt);
+
+	/* solicited-node multicast address */
+	ip->ip6_dst.s6_addr[0] = 0xff;
+	ip->ip6_dst.s6_addr[1] = 2;
+	ip->ip6_dst.s6_addr[11] = 1;
+#if IPV6_TOKEN_LENGTH ==  64
+	ip->ip6_dst.s6_addr[12] = 0xff;
+#define LENSOL 3
+#else
+#define LENSOL 4
+#endif
+	bcopy(&icp->icmp6_tgt.s6_addr[sizeof(struct in6_addr)-LENSOL],
+	      &ip->ip6_dst.s6_addr[sizeof(struct in6_addr)-LENSOL],
+	      LENSOL);
+
+	((struct ip6ovck *)ip)->ih6_pr = IPPROTO_ICMPV6;
+	((struct ip6ovck *)ip)->ih6_len = htons(lgsol-sizeof(struct ipv6));
+
+	/* other fields are 0 */
+
+	icp->icmp6_cksum = in_cksum((u_short *)ip, lgsol);
+
+	/* finish IPv6 header */
+	ip->ip6_head = IPV6_VERSION | ICMP6_ND_PRIORITY;
+	ip->ip6_len = htons(lgsol - sizeof(struct ipv6));
+	ip->ip6_nh = IPPROTO_ICMPV6;
+	ip->ip6_hlim = ICMP6_ND_HOPS;
+
+	/*
+	 * Perform duplicate address detection.
+	 */
+	ntosend = DupAddrDetectTransmits;
+	ninflow = 0;
+	reload = RETRANS_TIMER * 1000000;
+	/*
+	 * start sending NDsol immediately, autoconf6 should have
+	 * done the initial random wait
+	 */
+#ifdef WAIT_BEFORE_ND
+	{
+		struct timeval tv;
+
+		gettimeofday(&tv, NULL);
+		srandom((int)tv.tv_sec+tv.tv_usec);
+		delay = MAX_RTR_SOLICITATION_DELAY * 1000000;
+		delay -= random() % 1000000;
+	}
+#else
+	delay = reload;
+#endif
+	(void)ualarm(delay, reload);
+
+#ifndef WAIT_BEFORE_ND
+	goto firsttime;
+#endif
+	for (;;) {
+		bzero((caddr_t)&msg, sizeof(struct msghdr));
+		msg.msg_iov = &iov;
+		msg.msg_iov->iov_base = packet;
+		msg.msg_iov->iov_len = MAXPACKET;
+		msg.msg_iovlen = 1;
+		msg.msg_control = (caddr_t)&c_cmsg;
+		msg.msg_controllen = sizeof(c_cmsg);
+		cc = recvmsg(si, &msg, 0);
+
+		if (cc >= 0) {
+			if (cc == 0 || (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)))
+				continue;
+			if ((msg.msg_controllen == 0) ||
+			    (cm.cmsg_len != (sizeof(struct cmsghdr) +
+					    sizeof(pi))) ||
+			    (cm.cmsg_level != IPPROTO_IPV6) ||
+			    (cm.cmsg_type != IPV6_PKTINFO) ||
+			    (pi.ipi6_ifindex != ifp))
+				continue;
+
+			if (recv_icmp6((char *)packet, cc,
+					&req->ifra_addr.sin6_addr) < 0) {
+				warnx("Duplicate address detected");
+				ualarm(0, 0);
+				goto errdel;
+			}
+			continue;
+		}
+		if (errno != EINTR || dring == 0)
+			continue;
+		if (dring < 0) {
+			warn("dad recvmsg interrupt");
+			goto errdel;
+		}
+		dring = 0;
+	firsttime:
+		if (--ntosend < 0) {
+			ualarm(0, 0);
+			break;
+		}
+
+		dst.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+		dst.sin6_len = sizeof dst;
+#endif
+		dst.sin6_flowinfo = 0;
+		COPY_ADDR6(ip->ip6_dst, dst.sin6_addr);
+
+		cc = sendto(si, (char *)msgndsol, lgsol, 0,
+			    (struct sockaddr *)&dst, sizeof dst);
+		if (cc < 0 || cc != lgsol)  {
+			if (cc < 0)
+				warn("dad sendto NDsol");
+			else
+				warnx("dad NDsol: wrote %d chars, ret=%d",
+				      lgsol, cc);
+			ualarm(0, 0);
+			goto errdel;
+		}
+		ninflow++;
+	}
+	memset((caddr_t)&req->ifra_mask, 0,
+	       sizeof(struct sockaddr_in6));
+	if (ioctl(u, SIOCVIFADDR6, (caddr_t)req) < 0) {
+		warn("dad ioctl (SIOCVIFADDR6)");
+		goto errdel;
+	}
+	ret = 1;
+	goto done;
+
+    errdel:
+	(void) ioctl(u, SIOCDIFADDR6, (caddr_t)req);
+
+    done:
+	setsig_dad(SIG_DFL);
+	close(si);
+	return(ret);
+}
+
+void
+setsig_dad(handler)
+	void (*handler) __P((int));
+{
+	struct sigaction sa, osa;
+
+	sa.sa_handler = handler;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = 0;
+	sigaction(SIGALRM, &sa, (struct sigaction *)NULL);
+
+#define SETSIG(sig, sa, osa)	{					\
+	if (sigaction((sig), (struct sigaction *)NULL, (osa)) == 0 &&	\
+	    (osa)->sa_handler != SIG_IGN)				\
+		sigaction((sig), (sa), (struct sigaction *)NULL);	\
+	}
+	SETSIG(SIGINT, &sa, &osa);
+	SETSIG(SIGTERM, &sa, &osa);
+	SETSIG(SIGHUP, &sa, &osa);
+#undef SETSIG
+}
+
+void
+intr_dad(s)
+	int s;
+{
+	dring++;
+	if (s != SIGALRM)
+		dring = -1;
+}
+
+/* Receive an ICMPv6 packet */
+int
+recv_icmp6(buf, cc, addr)
+	char *buf;
+	int cc;
+	struct in6_addr *addr;
+{
+	register struct ipv6 *ip = (struct ipv6 *)buf;
+	register struct icmpv6 *icp = (struct icmpv6 *)(ip + 1);
+
+	if (cc < sizeof(*ip) + ICMP6_MINLEN ||
+	    ip->ip6_hlim != ICMP6_ND_HOPS ||
+	    icp->icmp6_code != 0)
+		return(0);
+
+	cc -= sizeof(*ip);
+	switch (icp->icmp6_type) {
+	    case ICMP6_ADVERTISEMENT_ND:
+		if ((unsigned)cc < ICMP6_NALEN)
+			return(0);
+		if (!SAME_ADDR6(icp->icmp6_tgt, *addr))
+			return(0);
+		return(-1);
+
+	    case ICMP6_SOLICITATION_ND:
+		if ((unsigned)cc < ICMP6_NSLEN)
+			return(0);
+		if (!SAME_ADDR6(icp->icmp6_tgt, *addr) ||
+		    !IS_ANYADDR6(ip->ip6_src) ||
+		    --ninflow >= 0)
+			return(0);
+		return(-1);
+	}
+	return(0);
+}
+
+/* Internet checksum */
+int
+in_cksum(addr, len)
+	u_short *addr;
+	int len;
+{
+	register int nleft = len;
+	register u_short *w = addr;
+	register u_short answer;
+	u_short odd_byte = 0;
+	register int sum = 0;
+
+	/*
+	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
+	 *  we add sequential 16 bit words to it, and at the end, fold
+	 *  back all the carry bits from the top 16 bits into the lower
+	 *  16 bits.
+	 */
+	while( nleft > 1 )  {
+		sum += *w++;
+		nleft -= 2;
+	}
+
+	/* mop up an odd byte, if necessary */
+	if ( nleft == 1 ) {
+		*(u_char *)(&odd_byte) = *(u_char *)w;
+		sum += odd_byte;
+	}
+
+	/*
+	 * add back carry outs from top 16 bits to low 16 bits
+	 */
+	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
+	sum += (sum >> 16);			/* add carry */
+	answer = ~sum;				/* truncate to 16 bits */
+	return(answer);
+}
diff -uN src-current/sbin/Makefile src-current-ipv6/sbin/Makefile
--- src-current/sbin/Makefile
+++ src-current-ipv6/sbin/Makefile
@@ -12,6 +12,7 @@
 	mount_nfs mount_null mount_portal mount_std mount_umap \
 	mount_union mountd newfs nfsd nfsiod nos-tun quotacheck \
 	restore savecore scsi slattach startslip spppcontrol swapon \
+	autoconf6 cticonfig key6 ping6 probe6 \
 	tunefs umount
 .endif
 
diff -uN src-current/sbin/mount_nfs/Makefile src-current-ipv6/sbin/mount_nfs/Makefile
--- src-current/sbin/mount_nfs/Makefile
+++ src-current-ipv6/sbin/mount_nfs/Makefile
@@ -5,7 +5,7 @@
 MAN8=	mount_nfs.8
 
 MOUNT=	${.CURDIR}/../mount
-CFLAGS+= -DNFS -I${MOUNT}
+CFLAGS+= -DNFS -DRPC_USE_INET_ANY -I${MOUNT}
 .PATH:	${MOUNT}
 
 .if exists(${DESTDIR}/usr/lib/libkrb.a) && (defined(MAKE_KERBEROS) \
diff -uN src-current/sbin/mount_nfs/mount_nfs.8 src-current-ipv6/sbin/mount_nfs/mount_nfs.8
--- src-current/sbin/mount_nfs/mount_nfs.8
+++ src-current-ipv6/sbin/mount_nfs/mount_nfs.8
@@ -41,7 +41,7 @@
 .Nd mount nfs file systems
 .Sh SYNOPSIS
 .Nm mount_nfs
-.Op Fl 23KNPTUbcdilqs
+.Op Fl 234KNPTUbcdilqs
 .Op Fl D Ar deadthresh
 .Op Fl I Ar readdirsize
 .Op Fl L Ar leaseterm
@@ -54,14 +54,17 @@
 .Op Fl t Ar timeout
 .Op Fl w Ar writesize
 .Op Fl x Ar retrans
-.Ar rhost:path node
+.Ar (rhost:path|path@rhost) node
 .Sh DESCRIPTION
 The
 .Nm mount_nfs
 command
 calls the
 .Xr mount 2
-system call to prepare and graft a remote nfs file system (rhost:path)
+system call to prepare and graft a remote nfs file system
+.Ar ( path@rhost
+or
+.Ar rhost:path )
 on to the file system tree at the point
 .Ar node.
 This command is normally executed by
@@ -78,6 +81,8 @@
 gigabytes.
 .It Fl 3
 Use the NFS Version 3 protocol.
+.It Fl 4
+Use only IPv4 transport.
 .It Fl D
 Used with NQNFS to set the
 .Dq "dead server threshold"
@@ -101,6 +106,9 @@
 (Refer to the INTERNET-DRAFT titled
 .%T "Authentication Mechanisms for ONC RPC" ,
 for more information.)
+This option forces the
+.Fl 4
+option.
 .It Fl L
 Used with NQNFS to set the lease term to the specified number of seconds.
 Only use this argument for mounts with a large round trip delay.
diff -uN src-current/sbin/mount_nfs/mount_nfs.c src-current-ipv6/sbin/mount_nfs/mount_nfs.c
--- src-current/sbin/mount_nfs/mount_nfs.c
+++ src-current-ipv6/sbin/mount_nfs/mount_nfs.c
@@ -80,6 +80,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <netdb.h>
+#include <resolv.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -178,6 +179,7 @@
 #define	ISBGRND	2
 int retrycnt = DEF_RETRY;
 int opflags = 0;
+int inet4flag = 0;
 int nfsproto = IPPROTO_UDP;
 int mnttcp_ok = 1;
 u_short port_no = 0;
@@ -280,7 +282,7 @@
 	nfsargs = nfsdefargs;
 	nfsargsp = &nfsargs;
 	while ((c = getopt(argc, argv,
-	    "23a:bcdD:g:I:iKL:lm:No:PpqR:r:sTt:w:x:U")) != -1)
+	    "234a:bcdD:g:I:iKL:lm:No:PpqR:r:sTt:w:x:U")) != -1)
 		switch (c) {
 		case '2':
 			mountmode = V2;
@@ -288,6 +290,9 @@
 		case '3':
 			mountmode = V3;
 			break;
+		case '4':
+			inet4flag = 1;
+			break;
 		case 'a':
 			num = strtol(optarg, &p, 10);
 			if (*p || num < 0)
@@ -600,11 +605,11 @@
  */
 enum clnt_stat
 pingnfsserver(addr, version, sotype)
-	struct sockaddr_in *addr;
+	RPC_SOCKADDR_IN *addr;
 	int version;
 	int sotype;
 {
-	struct sockaddr_in sin;
+	RPC_SOCKADDR_IN sin;
 	int tport;
 	CLIENT *clp;
 	int so = RPC_ANYSOCK;
@@ -618,7 +623,7 @@
 		return rpc_createerr.cf_stat;
 	}
 
-	sin.sin_port = htons(tport);
+	TOSINP(&sin)->sin_port = htons(tport);
 
 	pertry.tv_sec = 10;
 	pertry.tv_usec = 0;
@@ -648,7 +653,9 @@
 {
 	register CLIENT *clp;
 	struct hostent *hp;
-	static struct sockaddr_in saddr;
+	static RPC_SOCKADDR_IN Saddr;
+#define saddr	Saddr.s4
+#define saddr6	Saddr.s6
 #ifdef ISO
 	static struct sockaddr_iso isoaddr;
 	struct iso_addr *isop;
@@ -670,6 +677,16 @@
 	if ((delimp = strchr(spec, '@')) != NULL) {
 		hostp = delimp + 1;
 	} else if ((delimp = strchr(spec, ':')) != NULL) {
+		/* IPv6 special case: look for adv6:spec */
+		char *p = spec + strspn(spec, "0123456789abcdefABCDEF:.");
+		struct in6_addr ad;
+
+		if (p > spec && p[-1] == ':') {
+			*--p = 0;
+			if (inet_pton(AF_INET6, spec, &ad) == 1)
+				delimp = p;
+			*p = ':';
+		}
 		hostp = spec;
 		spec = delimp + 1;
 	} else {
@@ -707,6 +724,21 @@
 	}
 #endif /* ISO */
 
+#ifdef NFSKERB
+	if ((nfsargsp->flags & NFSMNT_KERB))
+		inet4flag = 1;		/* Kerberos ip4 only */
+#endif
+	if (!inet4flag) {
+		(void)res_init(); 
+		_res.options |= RES_USE_INET6;
+		if ((hp = gethostbyname(hostp)) == NULL) {
+			warnx("can't get net id for host");
+			return (0);
+		}
+		bcopy(hp->h_addr, (caddr_t)&saddr6.sin6_addr, hp->h_length);
+		goto com;
+	}
+
 	/*
 	 * Handle an internet host address and reverse resolve it if
 	 * doing Kerberos.
@@ -739,7 +771,16 @@
 	}
 #endif /* NFSKERB */
 
+com:
 	orgcnt = retrycnt;
+	if (!inet4flag) {
+#ifdef SIN6_LEN
+		saddr6.sin6_len = sizeof(saddr6);
+#endif
+		saddr6.sin6_family = AF_INET6;
+		saddr6.sin6_flowinfo = 0;
+	} else
+		saddr.sin_family = AF_INET;
 tryagain:
 	if (mountmode == ANY || mountmode == V3) {
 		nfsvers = 3;
@@ -752,10 +793,9 @@
 	}
 	nfhret.stat = EACCES;	/* Mark not yet successful */
 	while (retrycnt > 0) {
-		saddr.sin_family = AF_INET;
 		saddr.sin_port = htons(PMAPPORT);
 		if ((tport = port_no ? port_no :
-		     pmap_getport(&saddr, RPCPROG_NFS,
+		     pmap_getport(&Saddr, RPCPROG_NFS,
 		    		  nfsvers, nfsproto)) == 0) {
 			if ((opflags & ISBGRND) == 0)
 				clnt_pcreateerror("NFS Portmap");
@@ -764,7 +804,7 @@
 			 * First ping the nfs server to see if it supports
 			 * the version of the protocol we want to use.
 			 */
-			clnt_stat = pingnfsserver(&saddr, nfsvers,
+			clnt_stat = pingnfsserver(&Saddr, nfsvers,
 						  nfsargsp->sotype);
 			if (clnt_stat == RPC_PROGVERSMISMATCH) {
 				if (mountmode == ANY) {
@@ -778,10 +818,10 @@
 			pertry.tv_sec = 10;
 			pertry.tv_usec = 0;
 			if (mnttcp_ok && nfsargsp->sotype == SOCK_STREAM)
-			    clp = clnttcp_create(&saddr, RPCPROG_MNT, mntvers,
+			    clp = clnttcp_create(&Saddr, RPCPROG_MNT, mntvers,
 				&so, 0, 0);
 			else
-			    clp = clntudp_create(&saddr, RPCPROG_MNT, mntvers,
+			    clp = clntudp_create(&Saddr, RPCPROG_MNT, mntvers,
 				pertry, &so);
 			if (clp == NULL) {
 				if ((opflags & ISBGRND) == 0)
@@ -851,6 +891,8 @@
 	{
 		nfsargsp->addr = (struct sockaddr *) &saddr;
 		nfsargsp->addrlen = sizeof (saddr);
+		if (!inet4flag)
+			nfsargsp->addrlen = sizeof (saddr6);
 	}
 	nfsargsp->fh = nfhret.nfh;
 	nfsargsp->fhsize = nfhret.fhsize;
@@ -918,6 +960,6 @@
 usage: mount_nfs [-23KPTUbcdilqs] [-D deadthresh] [-I readdirsize]\n\
        [-L leaseterm] [-R retrycnt] [-a maxreadahead] [-g maxgroups]\n\
        [-m realm] [-o options] [-r readsize] [-t timeout] [-w writesize]\n\
-       [-x retrans] rhost:path node\n");
+       [-x retrans] (rhost:path|path@rhost) node\n");
 	exit(1);
 }
diff -uN src-current/sbin/mountd/exports.5 src-current-ipv6/sbin/mountd/exports.5
--- src-current/sbin/mountd/exports.5
+++ src-current-ipv6/sbin/mountd/exports.5
@@ -147,6 +147,7 @@
 option specifies that the Kerberos authentication server should be
 used to authenticate and map client credentials.
 This option requires that the kernel be built with the NFSKERB option.
+This option is incompatible with IPv6 addresses.
 .Pp
 The
 .Fl ro
@@ -195,7 +196,8 @@
 The third component of a line specifies the host set to which the line applies.
 The set may be specified in three ways.
 The first way is to list the host name(s) separated by white space.
-(Standard internet ``dot'' addresses may be used in place of names.)
+(Standard internet ``dot'' addresses or IPv6 ``colon'' addresses may be
+used in place of names.)
 The second way is to specify a ``netgroup'' as defined in the netgroup file (see
 .Xr netgroup 5 ).
 The third way is to specify an internet subnetwork using a network and
@@ -211,7 +213,7 @@
 first and are assumed to be hostnames otherwise.
 Using the full domain specification for a hostname can normally
 circumvent the problem of a host that has the same name as a netgroup.
-The third case is specified by the flag
+For IPv4, the third case is specified by the flag
 .Sm off
 .Fl network No = Sy netname
 .Sm on
@@ -222,6 +224,15 @@
 If the mask is not specified, it will default to the mask for that network
 class (A, B or C; see
 .Xr inet 4 ).
+For IPv6, the third case is specified by the flag
+.Sm off
+.Fl network No = Sy prefix .
+.Sm on
+Prefix is a IPv6 prefix, using the normal syntax
+.Sm off
+.Sy address / Sy prefix_len
+.Sm on
+where address is a numeric ``colon'' adress or a host name.
 .Pp
 For example:
 .Bd -literal -offset indent
@@ -231,6 +242,7 @@
 /u -maproot=bin: -network 131.104.48 -mask 255.255.255.0
 /u2 -maproot=root friends
 /u2 -alldirs -kerb -network cis-net -mask cis-mask
+/u2 -alldirs -network 3f25:33:1:2::/64
 .Ed
 .Pp
 Given that
diff -uN src-current/sbin/mountd/mountd.c src-current-ipv6/sbin/mountd/mountd.c
--- src-current/sbin/mountd/mountd.c
+++ src-current-ipv6/sbin/mountd/mountd.c
@@ -56,6 +56,10 @@
 #include <sys/ucred.h>
 #include <sys/sysctl.h>
 
+/*
+ * ipv6 rpc : use base address type struct sockaddr_in6 *  in rpc includes
+ */
+#define RPC_USE_INET6	/* address type is struct sockaddr_in6 * */
 #include <rpc/rpc.h>
 #include <rpc/pmap_clnt.h>
 #include <rpc/pmap_prot.h>
@@ -76,6 +80,7 @@
 #include <grp.h>
 #include <netdb.h>
 #include <pwd.h>
+#include <resolv.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -121,8 +126,8 @@
 #define	EX_LINKED	0x1
 
 struct netmsk {
-	u_long	nt_net;
-	u_long	nt_mask;
+	struct in6_addr	nt_net;
+	struct in6_addr	nt_mask;
 	char *nt_name;
 };
 
@@ -165,7 +170,7 @@
 void	add_mlist __P((char *, char *));
 int	check_dirpath __P((char *));
 int	check_options __P((struct dirlist *));
-int	chk_host __P((struct dirlist *, u_long, int *, int *));
+int	chk_host __P((struct dirlist *, struct in6_addr *, int *, int *));
 void	del_mlist __P((char *, char *));
 struct dirlist *dirp_search __P((struct dirlist *, char *));
 int	do_mount __P((struct exportlist *, struct grouplist *, int,
@@ -185,6 +190,7 @@
 int	get_line __P((void));
 void	get_mountlist __P((void));
 int	get_net __P((char *, struct netmsk *, int));
+int	get_net4 __P((char *, struct netmsk *, int));
 void	getexp_err __P((struct exportlist *, struct grouplist *));
 struct grouplist *get_grp __P((void));
 void	hang_dirp __P((struct dirlist *, struct grouplist *,
@@ -194,9 +200,9 @@
 void	out_of_mem __P((void));
 void	parsecred __P((char *, struct ucred *));
 int	put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *));
-int	scan_tree __P((struct dirlist *, u_long));
+int	scan_tree __P((struct dirlist *, struct in6_addr *));
 void	send_umntall __P((void));
-int	umntall_each __P((caddr_t, struct sockaddr_in *));
+int	umntall_each __P((caddr_t, RPC_SOCKADDR_IN *));
 int	xdr_dir __P((XDR *, char *));
 int	xdr_explist __P((XDR *, caddr_t));
 int	xdr_fhs __P((XDR *, caddr_t));
@@ -234,6 +240,7 @@
 #define	OP_NET		0x10
 #define	OP_ISO		0x20
 #define	OP_ALLDIRS	0x40
+#define	OP_IPV6		0x80
 
 #ifdef DEBUG
 int debug = 1;
@@ -293,6 +300,10 @@
 		};
 	argc -= optind;
 	argv += optind;
+
+	(void)res_init();
+	_res.options |= RES_USE_INET6;
+
 	grphead = (struct grouplist *)NULL;
 	exphead = (struct exportlist *)NULL;
 	mlhead = (struct mountlist *)NULL;
@@ -370,18 +381,19 @@
 	struct stat stb;
 	struct statfs fsb;
 	struct hostent *hp;
-	struct in_addr saddrin;
-	u_long saddr;
+	struct in6_addr saddrin;
+	struct in6_addr *saddr;
 	u_short sport;
 	char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN];
 	int bad = 0, defset, hostset;
 	sigset_t sighup_mask;
+	char vb[INET6_ADDRSTRLEN];
 
 	sigemptyset(&sighup_mask);
 	sigaddset(&sighup_mask, SIGHUP);
-	saddr = transp->xp_raddr.sin_addr.s_addr;
-	saddrin = transp->xp_raddr.sin_addr;
-	sport = ntohs(transp->xp_raddr.sin_port);
+	saddr = &transp->xp_raddr.sin6_addr;
+	saddrin = transp->xp_raddr.sin6_addr;
+	sport = ntohs(transp->xp_raddr.sin6_port);
 	hp = (struct hostent *)NULL;
 	switch (rqstp->rq_proc) {
 	case NULLPROC:
@@ -392,13 +404,13 @@
 		if (sport >= IPPORT_RESERVED && resvport_only) {
 			syslog(LOG_NOTICE,
 			    "mount request from %s from unprivileged port",
-			    inet_ntoa(saddrin));
+			    inet_ntop(AF_INET6, &saddrin, vb, sizeof(vb)));
 			svcerr_weakauth(transp);
 			return;
 		}
 		if (!svc_getargs(transp, xdr_dir, rpcpath)) {
 			syslog(LOG_NOTICE, "undecodable mount request from %s",
-			    inet_ntoa(saddrin));
+			    inet_ntop(AF_INET6, &saddrin, vb, sizeof(vb)));
 			svcerr_decode(transp);
 			return;
 		}
@@ -416,7 +428,8 @@
 			chdir("/");	/* Just in case realpath doesn't */
 			syslog(LOG_NOTICE,
 			    "mount request from %s for non existant path %s",
-			    inet_ntoa(saddrin), dirpath);
+			    inet_ntop(AF_INET6, &saddrin, vb, sizeof(vb)),
+			    dirpath);
 			if (debug)
 				fprintf(stderr, "stat failed on %s\n", dirpath);
 			bad = ENOENT;	/* We will send error reply later */
@@ -457,24 +470,29 @@
 			if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr))
 				syslog(LOG_ERR, "Can't send reply");
 			if (hp == NULL)
-				hp = gethostbyaddr((caddr_t)&saddr,
-				    sizeof(saddr), AF_INET);
+				hp = gethostbyaddr((caddr_t)saddr,
+				    sizeof(*saddr), AF_INET6);
 			if (hp)
 				add_mlist(hp->h_name, dirpath);
 			else
-				add_mlist(inet_ntoa(saddrin),
-					dirpath);
+				add_mlist((char *)inet_ntop(AF_INET6,
+						&saddrin,
+						vb, sizeof(vb)),
+					  dirpath);
 			if (debug)
 				fprintf(stderr,"Mount successfull.\n");
 			if (log)
 				syslog(LOG_NOTICE,
 				    "mount request succeeded from %s for %s",
-				    inet_ntoa(saddrin), dirpath);
+				    inet_ntop(AF_INET6, &saddrin,
+					      vb, sizeof(vb)),
+				    dirpath);
 		} else {
 			bad = EACCES;
 			syslog(LOG_NOTICE,
 			    "mount request denied from %s for %s",
-			    inet_ntoa(saddrin), dirpath);
+			    inet_ntop(AF_INET6, &saddrin, vb, sizeof(vb)),
+			    dirpath);
 		}
 
 		if (bad && !svc_sendreply(transp, xdr_long, (caddr_t)&bad))
@@ -487,51 +505,57 @@
 		else if (log)
 			syslog(LOG_NOTICE,
 			    "dump request succeeded from %s",
-			    inet_ntoa(saddrin), dirpath);
+			    inet_ntop(AF_INET6, &saddrin, vb, sizeof(vb)),
+			    dirpath);
 		return;
 	case RPCMNT_UMOUNT:
 		if (sport >= IPPORT_RESERVED && resvport_only) {
 			syslog(LOG_NOTICE,
 			    "umount request from %s from unprivileged port",
-			    inet_ntoa(saddrin));
+			    inet_ntop(AF_INET6, &saddrin, vb, sizeof(vb)));
 			svcerr_weakauth(transp);
 			return;
 		}
 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
 			syslog(LOG_NOTICE, "undecodable umount request from %s",
-			    inet_ntoa(saddrin));
+			    inet_ntop(AF_INET6, &saddrin, vb, sizeof(vb)));
 			svcerr_decode(transp);
 			return;
 		}
 		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
 			syslog(LOG_ERR, "Can't send reply");
-		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
+		hp = gethostbyaddr((caddr_t)saddr, sizeof(*saddr), AF_INET6);
 		if (hp)
 			del_mlist(hp->h_name, dirpath);
-		del_mlist(inet_ntoa(saddrin), dirpath);
+		del_mlist((char *)inet_ntop(AF_INET6, &saddrin,
+					    vb, sizeof(vb)),
+			  dirpath);
 		if (log)
 			syslog(LOG_NOTICE,
 			    "umount request succeeded from %s for %s",
-			    inet_ntoa(saddrin), dirpath);
+			    inet_ntop(AF_INET6, &saddrin, vb, sizeof(vb)),
+			    dirpath);
 		return;
 	case RPCMNT_UMNTALL:
 		if (sport >= IPPORT_RESERVED && resvport_only) {
 			syslog(LOG_NOTICE,
 			    "umountall request from %s from unprivileged port",
-			    inet_ntoa(saddrin));
+			    inet_ntop(AF_INET6, &saddrin, vb, sizeof(vb)));
 			svcerr_weakauth(transp);
 			return;
 		}
 		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
 			syslog(LOG_ERR, "Can't send reply");
-		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
+		hp = gethostbyaddr((caddr_t)saddr, sizeof(*saddr), AF_INET6);
 		if (hp)
 			del_mlist(hp->h_name, (char *)NULL);
-		del_mlist(inet_ntoa(saddrin), (char *)NULL);
+		del_mlist((char *)inet_ntop(AF_INET6, &saddrin,
+					    vb, sizeof(vb)),
+			  (char *)NULL);
 		if (log)
 			syslog(LOG_NOTICE,
 			    "umountall request succeeded from %s",
-			    inet_ntoa(saddrin));
+			    inet_ntop(AF_INET6, &saddrin, vb, sizeof(vb)));
 		return;
 	case RPCMNT_EXPORT:
 		if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL))
@@ -539,7 +563,7 @@
 		if (log)
 			syslog(LOG_NOTICE,
 			    "export request succeeded from %s",
-			    inet_ntoa(saddrin));
+			    inet_ntop(AF_INET6, &saddrin, vb, sizeof(vb)));
 		return;
 	default:
 		svcerr_noproc(transp);
@@ -943,8 +967,8 @@
 			if (hpe == (struct hostent *)NULL)
 				out_of_mem();
 			hpe->h_name = strdup("Default");
-			hpe->h_addrtype = AF_INET;
-			hpe->h_length = sizeof (u_long);
+			hpe->h_addrtype = AF_INET6;
+			hpe->h_length = sizeof (struct in6_addr);
 			hpe->h_addr_list = (char **)NULL;
 			grp->gr_ptr.gt_hostent = hpe;
 
@@ -1237,13 +1261,13 @@
 int
 chk_host(dp, saddr, defsetp, hostsetp)
 	struct dirlist *dp;
-	u_long saddr;
+	struct in6_addr *saddr;
 	int *defsetp;
 	int *hostsetp;
 {
 	struct hostlist *hp;
 	struct grouplist *grp;
-	u_long **addrp;
+	struct in6_addr **addrp;
 
 	if (dp) {
 		if (dp->dp_flag & DP_DEFSET)
@@ -1253,10 +1277,10 @@
 			grp = hp->ht_grp;
 			switch (grp->gr_type) {
 			case GT_HOST:
-			    addrp = (u_long **)
+			    addrp = (struct in6_addr **)
 				grp->gr_ptr.gt_hostent->h_addr_list;
 			    while (*addrp) {
-				if (**addrp == saddr) {
+				if (IN6_ARE_ADDR_EQUAL(*addrp, saddr)) {
 				    *hostsetp = (hp->ht_flag | DP_HOSTSET);
 				    return (1);
 				}
@@ -1264,10 +1288,18 @@
 			    }
 			    break;
 			case GT_NET:
-			    if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
-				grp->gr_ptr.gt_net.nt_net) {
-				*hostsetp = (hp->ht_flag | DP_HOSTSET);
-				return (1);
+			    {
+				int i;
+
+#define GN(i)	grp->gr_ptr.gt_net.nt_net.s6_addr[i]
+#define GM(i)	grp->gr_ptr.gt_net.nt_mask.s6_addr[i]
+				for (i = 0; i < 16; i++)
+				    if ((saddr->s6_addr[i] & GM(i)) != GN(i))
+					break;
+				if (i == 16) {
+				    *hostsetp = (hp->ht_flag | DP_HOSTSET);
+				    return (1);
+				}
 			    }
 			    break;
 			};
@@ -1283,7 +1315,7 @@
 int
 scan_tree(dp, saddr)
 	struct dirlist *dp;
-	u_long saddr;
+	struct in6_addr *saddr;
 {
 	int defset, hostset;
 
@@ -1448,31 +1480,29 @@
 	char **addrp, **naddrp;
 	struct hostent t_host;
 	int i;
-	u_long saddr;
+	struct in6_addr saddr;
 	char *aptr[2];
 
 	if (grp->gr_type != GT_NULL)
 		return (1);
 	if ((hp = gethostbyname(cp)) == NULL) {
-		if (isdigit(*cp)) {
-			saddr = inet_addr(cp);
-			if (saddr == -1) {
- 				syslog(LOG_ERR, "Inet_addr failed for %s", cp);
-				return (1);
-			}
-			if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
-				AF_INET)) == NULL) {
-				hp = &t_host;
-				hp->h_name = cp;
-				hp->h_addrtype = AF_INET;
-				hp->h_length = sizeof (u_long);
-				hp->h_addr_list = aptr;
-				aptr[0] = (char *)&saddr;
-				aptr[1] = (char *)NULL;
-			}
-		} else {
- 			syslog(LOG_ERR, "Gethostbyname failed for %s", cp);
-			return (1);
+		syslog(LOG_ERR, "Gethostbyname failed for %s", cp);
+		return (1);
+	}
+	/*
+	 * for gethostbyname IPv6, gethostbyname do the inet_ conversion
+	 */
+	if (index(cp, ':') || cp[strspn(cp, ".0123456789")] == '\0') {
+		bcopy(hp->h_addr, &saddr, sizeof (saddr));
+		if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
+					AF_INET6)) == NULL) {
+			hp = &t_host;
+			hp->h_name = cp;
+			hp->h_addrtype = AF_INET6;
+			hp->h_length = sizeof (struct in6_addr);
+			hp->h_addr_list = aptr;
+			aptr[0] = (char *)&saddr;
+			aptr[1] = (char *)NULL;
 		}
 	}
         /*
@@ -1632,10 +1662,10 @@
 	struct statfs *fsb;
 {
 	char *cp = (char *)NULL;
-	u_long **addrp;
+	struct in6_addr **addrp;
 	int done;
 	char savedc = '\0';
-	struct sockaddr_in sin, imask;
+	struct sockaddr_in6 sin, imask;
 	union {
 		struct ufs_args ua;
 		struct iso_args ia;
@@ -1652,20 +1682,20 @@
 	args.ua.export.ex_indexfile = ep->ex_indexfile;
 	memset(&sin, 0, sizeof(sin));
 	memset(&imask, 0, sizeof(imask));
-	sin.sin_family = AF_INET;
-	sin.sin_len = sizeof(sin);
-	imask.sin_family = AF_INET;
-	imask.sin_len = sizeof(sin);
+	sin.sin6_family = AF_INET6;
+	sin.sin6_len = sizeof(sin);
+	imask.sin6_family = AF_INET6;
+	imask.sin6_len = sizeof(sin);
 	if (grp->gr_type == GT_HOST)
-		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
+		addrp = (struct in6_addr **)grp->gr_ptr.gt_hostent->h_addr_list;
 	else
-		addrp = (u_long **)NULL;
+		addrp = (struct in6_addr **)NULL;
 	done = FALSE;
 	while (!done) {
 		switch (grp->gr_type) {
 		case GT_HOST:
 			if (addrp) {
-				sin.sin_addr.s_addr = **addrp;
+				sin.sin6_addr = **addrp;
 				args.ua.export.ex_addrlen = sizeof(sin);
 			} else
 				args.ua.export.ex_addrlen = 0;
@@ -1673,21 +1703,8 @@
 			args.ua.export.ex_masklen = 0;
 			break;
 		case GT_NET:
-			if (grp->gr_ptr.gt_net.nt_mask)
-			    imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
-			else {
-			    net = ntohl(grp->gr_ptr.gt_net.nt_net);
-			    if (IN_CLASSA(net))
-				imask.sin_addr.s_addr = inet_addr("255.0.0.0");
-			    else if (IN_CLASSB(net))
-				imask.sin_addr.s_addr =
-				    inet_addr("255.255.0.0");
-			    else
-				imask.sin_addr.s_addr =
-				    inet_addr("255.255.255.0");
-			    grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
-			}
-			sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
+			imask.sin6_addr = grp->gr_ptr.gt_net.nt_mask;
+			sin.sin6_addr = grp->gr_ptr.gt_net.nt_net;
 			args.ua.export.ex_addr = (struct sockaddr *)&sin;
 			args.ua.export.ex_addrlen = sizeof (sin);
 			args.ua.export.ex_mask = (struct sockaddr *)&imask;
@@ -1751,7 +1768,7 @@
 		}
 		if (addrp) {
 			++addrp;
-			if (*addrp == (u_long *)NULL)
+			if (*addrp == (struct in6_addr *)NULL)
 				done = TRUE;
 		} else
 			done = TRUE;
@@ -1770,10 +1787,59 @@
 	struct netmsk *net;
 	int maskflg;
 {
+	char *p;
+	struct hostent *hp;
+	int i, j, k;
+
+    /* do not know how to define named prefixes for IPv6 !! */
+	if (!(p = index(cp, '/')))
+		return get_net4(cp, net, maskflg);
+	if (maskflg || !isdigit(p[1]))
+		return 1;
+	opt_flags |= OP_IPV6;
+	*p = 0;
+	/*
+	 * for gethostbyname IPv6, gethostbyname do the inet_ conversion
+	 */
+	if ((hp = gethostbyname(cp)) == NULL || hp->h_addrtype != AF_INET6)
+		return (1);
+	bcopy(hp->h_addr_list[0], &net->nt_net, hp->h_length);
+	*p = '/';
+	i = atoi(p+1);
+	if (i < 0 || i > 128)
+		return 1;
+	bzero(&net->nt_mask, sizeof net->nt_mask);
+	j = 0;
+	k = 0x80;
+	while (i >= 8) {
+		i -= 8;
+		net->nt_mask.s6_addr[j++] = 0xff;
+	}
+	while (i >= 1) {
+		net->nt_mask.s6_addr[j] |= k;
+		k >>= 1;
+		i--;
+	}
+	for(i = 0; i < 16; i++)
+		net->nt_net.s6_addr[i] &= net->nt_mask.s6_addr[i];
+	net->nt_name = (char *)malloc(strlen(cp) + 1);
+	if (net->nt_name == (char *)NULL)
+		out_of_mem();
+	strcpy(net->nt_name, cp);
+	return (0);
+}
+
+int
+get_net4(cp, net, maskflg)
+	char *cp;
+	struct netmsk *net;
+	int maskflg;
+{
 	struct netent *np;
 	long netaddr;
 	struct in_addr inetaddr, inetaddr2;
 	char *name;
+	u_long addr;
 
 	if (isdigit(*cp) && ((netaddr = inet_network(cp)) != -1)) {
 		inetaddr = inet_makeaddr(netaddr, 0);
@@ -1798,9 +1864,10 @@
 	} else
 		return (1);
 
-	if (maskflg)
-		net->nt_mask = inetaddr.s_addr;
-	else {
+	if (maskflg) {
+		memset(&net->nt_mask, -1, sizeof net->nt_mask);
+		bcopy(&inetaddr, &net->nt_mask.s6_addr[12], sizeof inetaddr);
+	} else {
 		if (np)
 			name = np->n_name;
 		else
@@ -1809,7 +1876,21 @@
 		if (net->nt_name == (char *)NULL)
 			out_of_mem();
 		strcpy(net->nt_name, name);
-		net->nt_net = inetaddr.s_addr;
+		bzero(&net->nt_net, sizeof net->nt_net);
+		memset(&net->nt_net.s6_addr[10], -1, 2);
+		bcopy(&inetaddr, &net->nt_net.s6_addr[12], sizeof inetaddr);
+		if (!(opt_flags & OP_MASK)) {
+			addr = ntohl(inetaddr.s_addr);
+			if (IN_CLASSA(addr))
+				inetaddr2.s_addr = inet_addr("255.0.0.0");
+			else if (IN_CLASSB(addr))
+				inetaddr2.s_addr = inet_addr("255.255.0.0");
+			else
+				inetaddr2.s_addr = inet_addr("255.255.255.0");
+			memset(&net->nt_mask, -1, sizeof net->nt_mask);
+			bcopy(&inetaddr2, &net->nt_mask.s6_addr[12],
+				sizeof inetaddr2);
+		}
 	}
 	return (0);
 }
@@ -2078,7 +2159,7 @@
 int
 umntall_each(resultsp, raddr)
 	caddr_t resultsp;
-	struct sockaddr_in *raddr;
+	RPC_SOCKADDR_IN *raddr;
 {
 	return (1);
 }
@@ -2142,6 +2223,10 @@
 	}
 	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
 	    syslog(LOG_ERR, "-mask requires -net");
+	    return (1);
+	}
+	if ((opt_flags & (OP_MASK | OP_IPV6)) == (OP_MASK | OP_IPV6)) {
+	    syslog(LOG_ERR, "-mask and IPv6 -net mutually exclusive");
 	    return (1);
 	}
 	if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
diff -uN src-current/sbin/nfsd/Makefile src-current-ipv6/sbin/nfsd/Makefile
--- src-current/sbin/nfsd/Makefile
+++ src-current-ipv6/sbin/nfsd/Makefile
@@ -1,7 +1,7 @@
 #	@(#)Makefile	8.1 (Berkeley) 6/5/93
 
 PROG=	nfsd
-CFLAGS+=-DNFS
+CFLAGS+=-DNFS -DRPC_USE_INET6
 MAN8=	nfsd.8
 DPADD+=	${LIBUTIL}
 LDADD+=	-lutil
diff -uN src-current/sbin/nfsd/nfsd.c src-current-ipv6/sbin/nfsd/nfsd.c
--- src-current/sbin/nfsd/nfsd.c
+++ src-current-ipv6/sbin/nfsd/nfsd.c
@@ -147,7 +147,7 @@
 	struct nfsd_args nfsdargs;
 	struct passwd *pwd;
 	struct ucred *cr;
-	struct sockaddr_in inetaddr, inetpeer;
+	struct sockaddr_in6 inetaddr, inetpeer;
 #ifdef ISO
 	struct sockaddr_iso isoaddr, isopeer;
 #endif
@@ -377,14 +377,15 @@
 
 	/* If we are serving udp, set up the socket. */
 	if (udpflag) {
-		if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+		if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
 			syslog(LOG_ERR, "can't create udp socket");
 			exit(1);
 		}
-		inetaddr.sin_family = AF_INET;
-		inetaddr.sin_addr.s_addr = INADDR_ANY;
-		inetaddr.sin_port = htons(NFS_PORT);
-		inetaddr.sin_len = sizeof(inetaddr);
+		inetaddr.sin6_family = AF_INET6;
+		inetaddr.sin6_addr = in6addr_any;
+		inetaddr.sin6_flowinfo = 0;
+		inetaddr.sin6_port = htons(NFS_PORT);
+		inetaddr.sin6_len = sizeof(inetaddr);
 		if (bind(sock,
 		    (struct sockaddr *)&inetaddr, sizeof(inetaddr)) < 0) {
 			syslog(LOG_ERR, "can't bind udp addr");
@@ -451,17 +452,18 @@
 	FD_ZERO(&sockbits);
 	connect_type_cnt = 0;
 	if (tcpflag) {
-		if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		if ((tcpsock = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
 			syslog(LOG_ERR, "can't create tcp socket");
 			exit(1);
 		}
 		if (setsockopt(tcpsock,
 		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
 			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
-		inetaddr.sin_family = AF_INET;
-		inetaddr.sin_addr.s_addr = INADDR_ANY;
-		inetaddr.sin_port = htons(NFS_PORT);
-		inetaddr.sin_len = sizeof(inetaddr);
+		inetaddr.sin6_family = AF_INET6;
+		inetaddr.sin6_addr = in6addr_any;
+		inetaddr.sin6_flowinfo = 0;
+		inetaddr.sin6_port = htons(NFS_PORT);
+		inetaddr.sin6_len = sizeof(inetaddr);
 		if (bind(tcpsock,
 		    (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
 			syslog(LOG_ERR, "can't bind tcp addr");
@@ -583,7 +585,7 @@
 				syslog(LOG_ERR, "accept failed: %m");
 				exit(1);
 			}
-			memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero));
+			inetpeer.sin6_flowinfo = 0;
 			if (setsockopt(msgsock, SOL_SOCKET,
 			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
 				syslog(LOG_ERR,
diff -uN src-current/sbin/route/keywords src-current-ipv6/sbin/route/keywords
--- src-current/sbin/route/keywords
+++ src-current-ipv6/sbin/route/keywords
@@ -2,16 +2,19 @@
 
 add
 atalk
+author
 blackhole
 change
 cloning
 delete
+downstream
 dst
 expire
 flush
 gateway
 genmask
 get
+getnext
 host
 hopcount
 iface
@@ -19,18 +22,23 @@
 ifa
 ifp
 inet
+inet6
 iso
 link
 llinfo
+local
 lock
 lockrest
 mask
+metric
 monitor
 mtu
+multicast
 net
 netmask
 nostatic
 osi
+prefixlen
 proto1
 proto2
 recvpipe
diff -uN src-current/sbin/route/route.8 src-current-ipv6/sbin/route/route.8
--- src-current/sbin/route/route.8
+++ src-current-ipv6/sbin/route/route.8
@@ -90,6 +90,8 @@
 Change aspects of a route (such as its gateway).
 .It Cm get
 Lookup and display the route for a destination.
+.It Cm getnext
+Lookup the route for a destination and display the next route in the table.
 .It Cm monitor
 Continuously report any changes to the routing information base,
 routing lookup misses, or suspected network partitionings.
@@ -198,6 +200,14 @@
 and the names must be numeric specifications rather than
 symbolic names.
 .Pp
+For the IPv6 address family
+.Fl inet6
+must be used. The length of a destination prefix can be
+specified with the syntax
+.Ar prefix/length
+or with the option
+.Fl prefixlen .
+.Pp
 The optional
 .Fl netmask
 modifier is intended
@@ -225,6 +235,7 @@
 -nostatic ~RTF_STATIC     - pretend route added by kernel or daemon
 -reject    RTF_REJECT     - emit an ICMP unreachable when matched
 -blackhole RTF_BLACKHOLE  - silently discard pkts (during updates)
+-local     RTF_LOCAL      - should use the loopback interface
 -proto1    RTF_PROTO1     - set protocol specific routing flag #1
 -proto2    RTF_PROTO2     - set protocol specific routing flag #2
 -llinfo    RTF_LLINFO     - validly translates proto addr to link addr
@@ -259,7 +270,9 @@
 the route (as in the
 .Tn ISO
 case where several interfaces may have the
-same address), the
+same address and in the
+.Tn IPv6
+case an interface may have several addresses), the
 .Fl ifp
 or
 .Fl ifa
@@ -280,6 +293,7 @@
 RTM_ADD,
 RTM_DELETE,
 RTM_GET,
+RTM_GETNEXT,
 and
 RTM_CHANGE.
 As such, only the super-user may modify
diff -uN src-current/sbin/route/route.c src-current-ipv6/sbin/route/route.c
--- src-current/sbin/route/route.c
+++ src-current-ipv6/sbin/route/route.c
@@ -87,12 +87,14 @@
 union	sockunion {
 	struct	sockaddr sa;
 	struct	sockaddr_in sin;
+	struct	sockaddr_in6 sin6;
 	struct	sockaddr_at sat;
 #ifdef NS
 	struct	sockaddr_ns sns;
 #endif
 	struct	sockaddr_dl sdl;
-} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
+} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp, so_src;
+struct	sockaddr_inds *so_down;
 
 typedef union sockunion *sup;
 int	pid, rtm_addrs, uid;
@@ -109,6 +111,7 @@
 void	flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
 void	print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
 int	getaddr(), rtmsg(), x25_makemask();
+void	getprefixlen();
 extern	char *inet_ntoa(), *iso_ntoa(), *link_ntoa();
 
 void usage __P((const char *)) __dead2;
@@ -172,10 +175,15 @@
 		s = socket(PF_ROUTE, SOCK_RAW, 0);
 	if (s < 0)
 		err(EX_OSERR, "socket");
+	/* At most 10 downstream interface can be present */
+	so_down = (struct sockaddr_inds *) malloc(sizeof(struct sockaddr_inds)
+			+ 10 * sizeof(struct ds_in6addr));
+	so_down->sin_num = 0;
 	setuid(uid);
 	if (*argv)
 		switch (keyword(*argv)) {
 		case K_GET:
+		case K_GETNEXT:
 			uid = 0;
 			/* FALLTHROUGH */
 
@@ -208,6 +216,7 @@
 	int argc;
 	char *argv[];
 {
+	int flags = 0;
 	size_t needed;
 	int mib[6], rlen, seqno;
 	char *buf, *next, *lim;
@@ -218,12 +227,14 @@
 	}
 	shutdown(s, 0); /* Don't want to read back our messages */
 	if (argc > 1) {
-		argv++;
-		if (argc == 2 && **argv == '-')
+		while (--argc && **++argv == '-')
 		    switch (keyword(*argv + 1)) {
 			case K_INET:
 				af = AF_INET;
 				break;
+			case K_INET6:
+				af = AF_INET6;
+				break;
 			case K_ATALK:
 				af = AF_APPLETALK;
 				break;
@@ -235,17 +246,21 @@
 			case K_LINK:
 				af = AF_LINK;
 				break;
+			case K_MULTICAST:
+				flags = RTF_MULTICAST;
+				break;
 			default:
 				goto bad;
-		} else
+		}
+		if (argc)
 bad:			usage(*argv);
 	}
 	mib[0] = CTL_NET;
 	mib[1] = PF_ROUTE;
 	mib[2] = 0;		/* protocol */
-	mib[3] = 0;		/* wildcard address family */
+	mib[3] = af;
 	mib[4] = NET_RT_DUMP;
-	mib[5] = 0;		/* no flags */
+	mib[5] = flags;
 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
 		err(EX_OSERR, "route-sysctl-estimate");
 	if ((buf = malloc(needed)) == NULL)
@@ -260,7 +275,7 @@
 		rtm = (struct rt_msghdr *)next;
 		if (verbose)
 			print_rtmsg(rtm, rtm->rtm_msglen);
-		if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
+		if ((rtm->rtm_flags & (RTF_GATEWAY|RTF_MULTICAST)) == 0)
 			continue;
 		if (af) {
 			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
@@ -306,6 +321,7 @@
 #ifdef NS
 	char *ns_print();
 #endif
+	char *ipv6_print();
 
 	if (first) {
 		first = 0;
@@ -351,6 +367,9 @@
 		break;
 	    }
 
+	case AF_INET6:
+		return (ipv6_print((struct sockaddr_in6 *)sa));
+
 	case AF_APPLETALK:
 		(void) snprintf(line, sizeof(line), "atalk %s",
 			atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
@@ -362,8 +381,16 @@
 #endif
 
 	case AF_LINK:
-		return (link_ntoa((struct sockaddr_dl *)sa));
+	    {	struct sockaddr_dl *sdl;
+		sdl = (struct sockaddr_dl *)sa;
 
+		if (sdl->sdl_index == 0)
+			return (link_ntoa(sdl));
+		(void) snprintf(line, sizeof(line), "%d#%s",
+				(int)sdl->sdl_index,
+				link_ntoa(sdl));
+		break;
+	    }
 	default:
 	    {	u_short *s = (u_short *)sa;
 		u_short *slim = s + ((sa->sa_len + 1) >> 1);
@@ -395,6 +422,7 @@
 #ifdef NS
 	char *ns_print();
 #endif
+	char *ipv6_print();
 
 	switch (sa->sa_family) {
 
@@ -448,6 +476,9 @@
 		break;
 	    }
 
+	case AF_INET6:
+		return (ipv6_print((struct sockaddr_in6 *)sa));
+
 	case AF_APPLETALK:
 		(void) snprintf(line, sizeof(line), "atalk %s",
 			atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
@@ -456,12 +487,19 @@
 #ifdef NS
 	case AF_NS:
 		return (ns_print((struct sockaddr_ns *)sa));
-		break;
 #endif
 
 	case AF_LINK:
-		return (link_ntoa((struct sockaddr_dl *)sa));
+	    {	struct sockaddr_dl *sdl;
+		sdl = (struct sockaddr_dl *)sa;
 
+		if (sdl->sdl_index == 0)
+			return (link_ntoa(sdl));
+		(void) snprintf(line, sizeof(line), "%d#%s",
+				(int)sdl->sdl_index,
+				link_ntoa(sdl));
+		break;
+	    }
 
 	default:
 	    {	u_short *s = (u_short *)sa->sa_data;
@@ -489,6 +527,7 @@
 #define caseof(x, y, z)	case x: valp = &rt_metrics.z; flag = y; break
 	caseof(K_MTU, RTV_MTU, rmx_mtu);
 	caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
+	caseof(K_METRIC, RTV_HOPCOUNT, rmx_hopcount);
 	caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
 	caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
 	caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
@@ -513,6 +552,8 @@
 	int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC;
 	int key;
 	struct hostent *hp = 0;
+	struct ds_in6addr *ds;
+	struct in6_addr v6addr;
 
 	if (uid) {
 		errx(EX_NOPERM, "must be root to alter routing table");
@@ -531,6 +572,10 @@
 				af = AF_INET;
 				aflen = sizeof(struct sockaddr_in);
 				break;
+			case K_INET6:
+				af = AF_INET6;
+				aflen = sizeof(struct sockaddr_in6);
+				break;
 			case K_ATALK:
 				af = AF_APPLETALK;
 				aflen = sizeof(struct sockaddr_at);
@@ -570,6 +615,9 @@
 			case K_BLACKHOLE:
 				flags |= RTF_BLACKHOLE;
 				break;
+			case K_LOCAL:
+				flags |= RTF_LOCAL;
+				break;
 			case K_PROTO1:
 				flags |= RTF_PROTO1;
 				break;
@@ -593,6 +641,31 @@
 				argc--;
 				(void) getaddr(RTA_IFP, *++argv, 0);
 				break;
+			case K_MULTICAST:
+				flags |= RTF_MULTICAST;
+				iflag = 1;
+				forcehost++;
+				break;
+			case K_DOWNSTREAM:
+				ds = (struct ds_in6addr *)
+    (&so_down->sin_data[0] + so_down->sin_num * sizeof(struct ds_in6addr));
+				argc--; argc--;
+				rtm_addrs |= RTA_DOWNSTREAM;
+				if (inet_pton(AF_INET6,
+					      *++argv,
+					      &v6addr) > 0) {
+					ds->sin6_addr = v6addr;
+					ds->hoplimit = atoi(*++argv);
+					so_down->sin_num++;
+				}
+				so_down->sin_len =
+				  so_down->sin_num * sizeof(struct ds_in6addr)
+				  + 2 * sizeof(u_char) + sizeof(u_short);
+				break;
+			case K_AUTHOR:
+				argc--;
+				(void) getaddr(RTA_AUTHOR, *++argv, 0);
+				break;
 			case K_GENMASK:
 				argc--;
 				(void) getaddr(RTA_GENMASK, *++argv, 0);
@@ -609,12 +682,18 @@
 			case K_NETMASK:
 				argc--;
 				(void) getaddr(RTA_NETMASK, *++argv, 0);
+				forcenet++;
+				break;
+			case K_PREFIXLEN:
+				argc--;
+				getprefixlen(*++argv);
 				/* FALLTHROUGH */
 			case K_NET:
 				forcenet++;
 				break;
 			case K_MTU:
 			case K_HOPCOUNT:
+			case K_METRIC:
 			case K_EXPIRE:
 			case K_RECVPIPE:
 			case K_SENDPIPE:
@@ -650,7 +729,7 @@
 		flags |= RTF_GATEWAY;
 	for (attempts = 1; ; attempts++) {
 		errno = 0;
-		if ((ret = rtmsg(*cmd, flags)) == 0)
+		if ((ret = rtmsg(cmd, flags)) == 0)
 			break;
 		if (errno != ENETUNREACH && errno != ESRCH)
 			break;
@@ -754,7 +833,8 @@
 	struct hostent *hp;
 	struct netent *np;
 	u_long val;
-	char *q,qs;
+	char *q = NULL, qs;
+	int plen = -1;
 
 	if (af == 0) {
 		af = AF_INET;
@@ -764,6 +844,20 @@
 	switch (which) {
 	case RTA_DST:
 		su = &so_dst;
+		q = index(s, '/');
+		if (q && (plen = atoi(q + 1)) >= 0) {
+			*q = '\0';
+			getprefixlen(q+1);
+			forcenet++;
+			*q = '/';
+		}			
+#ifdef notdef
+		/* bug fix (signaled by Michael Clay) */
+		if ((af == AF_INET6) && !(rtm_addrs & RTA_NETMASK)) {
+			plen = 128;
+			getprefixlen("128");
+		}
+#endif
 		break;
 	case RTA_GATEWAY:
 		su = &so_gate;
@@ -822,6 +916,12 @@
 	case RTA_IFA:
 		su = &so_ifa;
 		break;
+	case RTA_AUTHOR:
+		su = &so_src;
+		break;
+	case RTA_DOWNSTREAM:
+		su = (sup)&so_down;
+		break;
 	default:
 		usage("Internal Error");
 		/*NOTREACHED*/
@@ -860,7 +960,6 @@
 		return (!ns_nullhost(su->sns.sns_addr));
 #endif
 
-
 	case AF_APPLETALK:
 		if (!atalk_aton(s, &su->sat.sat_addr))
 			errx(EX_NOHOST, "bad address: %s", s);
@@ -869,8 +968,22 @@
 
 	case AF_LINK:
 		link_addr(s, &su->sdl);
+		q = index(s, ':');
+		if (q) {
+			*q = '\0';
+			su->sdl.sdl_index = if_nametoindex(s);
+		}
 		return (1);
 
+	case AF_INET6:
+		if (((plen < 0) || (plen != 128)) &&
+		    (hp = gethostbyname2(s, AF_INET6)))
+			bcopy(hp->h_addr,
+			      (char *)&su->sin6.sin6_addr,
+			      hp->h_length);
+		else
+			inet_pton(AF_INET6, s, &su->sin6.sin6_addr);
+		return (plen == 128);
 
 	case PF_ROUTE:
 		su->sa.sa_len = sizeof(*su);
@@ -886,7 +999,7 @@
 		hpp = &hp;
 	*hpp = NULL;
 
-	q = strchr(s,'/');
+	q = strchr(s, '/');
 	if (q && which == RTA_DST) {
 		qs = *q;
 		*q = '\0';
@@ -895,7 +1008,7 @@
 				htonl(val), &su->sin, strtoul(q+1, 0, 0));
 			return (0);
 		}
-		*q =qs;
+		*q = qs;
 	}
 	if (((val = inet_addr(s)) != INADDR_NONE) &&
 	    (which != RTA_DST || forcenet == 0)) {
@@ -926,6 +1039,63 @@
 	errx(EX_NOHOST, "bad address: %s", s);
 }
 
+/*
+ * Build the prefix netmask with argument one bits.
+ */
+void
+getprefixlen(s)
+	char *s;
+{
+	register sup su = &so_mask;
+	struct ns_addr ns_addr();
+	struct iso_addr *iso_addr();
+	register char *cp;
+	register int len, max, i;
+
+	len = atoi(s);
+	if (len < 0)
+		goto bad;
+	if (af == 0) {
+		af = AF_INET;
+		aflen = sizeof(struct sockaddr_in);
+	}
+	rtm_addrs |= RTA_NETMASK;
+	su->sa.sa_len = aflen;
+	switch (af) {
+#ifdef NS
+	case AF_NS:
+		cp = (char *)&su->sns.sns_addr;
+		max = sizeof(union ns_net) + sizeof(union ns_host);
+		len = MIN(len, max * 8);
+		su->sns.sns_addr = ns_addr(s);
+		break;
+#endif
+	case AF_INET6:
+		cp = (char *)&su->sin6.sin6_addr;
+		max = sizeof(struct in6_addr);
+		len = MIN(len, max * 8);
+		break;
+
+	case AF_INET:
+		cp = (char *)&su->sin.sin_addr;
+		max = sizeof(struct in_addr);
+		len = MIN(len, max * 8);
+		break;
+
+	default:
+		goto bad;
+	}
+	for (i = 0; i < (len / 8); i++)
+		*cp++ = 0xff;
+	if (len < (max * 8))
+		*cp++ = 0xff << (8 - (len & 7));
+	for (i += 1; i < max; i++)
+		*cp++ = 0;
+	return;
+bad:
+	(void) fprintf(stderr, "%s: bad value\n", s);
+	exit(1);
+}
 
 #ifdef NS
 short ns_nullh[] = {0,0,0};
@@ -978,6 +1148,26 @@
 }
 #endif
 
+char *
+ipv6_print(sin)
+	struct sockaddr_in6 *sin;
+{
+	static struct in6_addr ina;
+	static char hbuf[64];
+	register int i;
+	register u_char *p = (u_char *)&ina;
+
+	COPY_ADDR6(sin->sin6_addr, ina);
+	if (sin->sin6_len < sizeof(*sin)) {
+		i = (caddr_t)sin + sin->sin6_len - (caddr_t)&sin->sin6_addr;
+		if (i < 0)
+			i = 0;
+		for (; i < sizeof(struct in6_addr); i++)
+			p[i] = 0;
+	}
+	return ((char *)inet_ntop(AF_INET6, &ina, hbuf, sizeof(hbuf)));
+}
+
 void
 interfaces()
 {
@@ -1030,8 +1220,10 @@
 
 int
 rtmsg(cmd, flags)
-	int cmd, flags;
+	char *cmd;
+	int flags;
 {
+	int type;
 	static int seq;
 	int rlen;
 	register char *cp = m_rtmsg.m_space;
@@ -1045,21 +1237,24 @@
 
 	errno = 0;
 	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
-	if (cmd == 'a')
-		cmd = RTM_ADD;
-	else if (cmd == 'c')
-		cmd = RTM_CHANGE;
-	else if (cmd == 'g') {
-		cmd = RTM_GET;
+	if (*cmd == 'a')
+		type = RTM_ADD;
+	else if (*cmd == 'c')
+		type = RTM_CHANGE;
+	else if (*cmd == 'g') {
+		if (strcmp(cmd, "getnext") == 0)
+			type = RTM_GETNEXT;
+		else
+			type = RTM_GET;
 		if (so_ifp.sa.sa_family == 0) {
 			so_ifp.sa.sa_family = AF_LINK;
 			so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
 			rtm_addrs |= RTA_IFP;
 		}
 	} else
-		cmd = RTM_DELETE;
+		type = RTM_DELETE;
 #define rtm m_rtmsg.m_rtm
-	rtm.rtm_type = cmd;
+	rtm.rtm_type = type;
 	rtm.rtm_flags = flags;
 	rtm.rtm_version = RTM_VERSION;
 	rtm.rtm_seq = ++seq;
@@ -1075,6 +1270,24 @@
 	NEXTADDR(RTA_GENMASK, so_genmask);
 	NEXTADDR(RTA_IFP, so_ifp);
 	NEXTADDR(RTA_IFA, so_ifa);
+	NEXTADDR(RTA_AUTHOR, so_src);
+	if (rtm_addrs & RTA_DOWNSTREAM) {
+		int i;
+		struct ds_in6addr *ds;
+		char v[64];
+
+		ds = (struct ds_in6addr *) &so_down->sin_data[0];
+		bcopy((char *)so_down, cp, so_down->sin_len);
+		cp += so_down->sin_len;
+		(void) printf("so_downstream: inet ");
+		for (i = 0; i < so_down->sin_num; i++) {
+			(void) printf("addr %s hops %d ",
+				      inet_ntop(AF_INET6, &(ds->sin6_addr),
+						v, sizeof(v)),
+				      ds->hoplimit);
+			ds++;
+		}
+	}
 	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
 	if (verbose)
 		print_rtmsg(&rtm, l);
@@ -1084,7 +1297,7 @@
 		perror("writing to routing socket");
 		return (-1);
 	}
-	if (cmd == RTM_GET) {
+	if ((type == RTM_GET) || (type == RTM_GETNEXT)) {
 		do {
 			l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
 		} while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
@@ -1115,6 +1328,7 @@
 	case AF_NS:
 #endif
 	case AF_INET:
+	case AF_INET6:
 	case AF_APPLETALK:
 	case 0:
 		return;
@@ -1146,6 +1360,9 @@
 	"RTM_IFINFO: iface status change",
 	"RTM_NEWMADDR: new multicast group membership on iface",
 	"RTM_DELMADDR: multicast group membership removed from iface",
+	"RTM_EXPIR: route has expired",
+	"RTM_RTLOST: router has been lost",
+	"RTM_GETNEXT: get next route",
 	0,
 };
 
@@ -1154,15 +1371,15 @@
 "\1mtu";
 char routeflags[] =
 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
-"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
-"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE"
+"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016BNDUPDLST"
+"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024BNDCENT"
 "\025PINNED\026LOCAL\027BROADCAST\030MULTICAST";
 char ifnetflags[] =
 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
 "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
 "\017LINK2\020MULTICAST";
 char addrnames[] =
-"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
+"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011DOWNSTREAM";
 
 void
 print_rtmsg(rtm, msglen)
@@ -1218,12 +1435,17 @@
 	int msglen;
 {
 	struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
+	struct sockaddr *ifa = NULL;
 	struct sockaddr_dl *ifp = NULL;
 	register struct sockaddr *sa;
+	struct sockaddr *src = NULL;
+	struct sockaddr_inds *downstream = NULL;
 	register char *cp;
 	register int i;
 
-	(void) printf("   route to: %s\n", routename(&so_dst));
+	(void) printf("%s route to: %s\n",
+		      rtm->rtm_type == RTM_GETNEXT ? "next" : "  ",
+		      routename(&so_dst));
 	if (rtm->rtm_version != RTM_VERSION) {
 		warnx("routing message version %d not understood",
 		     rtm->rtm_version);
@@ -1253,11 +1475,20 @@
 				case RTA_NETMASK:
 					mask = sa;
 					break;
+				case RTA_IFA:
+					ifa = sa;
+					break;
 				case RTA_IFP:
 					if (sa->sa_family == AF_LINK &&
 					   ((struct sockaddr_dl *)sa)->sdl_nlen)
 						ifp = (struct sockaddr_dl *)sa;
 					break;
+				case RTA_AUTHOR:
+					src = sa;
+					break;
+				case RTA_DOWNSTREAM:
+					downstream = (struct sockaddr_inds *) sa;
+					break;
 				}
 				ADVANCE(cp, sa);
 			}
@@ -1277,13 +1508,37 @@
 	if (ifp)
 		(void)printf("  interface: %.*s\n",
 		    ifp->sdl_nlen, ifp->sdl_data);
+	if (src)
+		(void)printf("     source: %s\n", routename(src));
+	if (downstream) {
+		int i;
+		struct ds_in6addr *ds;
+		char v[64];
+
+		ds = (struct ds_in6addr *) &downstream->sin_data[0];
+		for (i = 0; i < downstream->sin_num; i++) {
+			(void) printf(" downstream: addr %s hoplimit %d\n",
+				      inet_ntop(AF_INET6, &(ds->sin6_addr),
+						v, sizeof(v)),
+				      ds->hoplimit);
+			ds++;
+		}
+	}
+	if (ifa)
+		(void)printf("interf addr: %s\n", routename(ifa));
 	(void)printf("      flags: ");
 	bprintf(stdout, rtm->rtm_flags, routeflags);
-
+	if (rtm->rtm_flags & RTF_MULTICAST) {
+		(void)printf("\n");
+	} else {
 #define lock(f)	((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
 #define msec(u)	(((u) + 500) / 1000)		/* usec to msec */
 
-	(void) printf("\n%s\n", "\
+	if (dst && dst->sa_family == AF_INET6)
+		(void) printf("\n%s\n", "\
+ recvpipe  sendpipe  ssthresh  rtt,msec    rttvar    metric      mtu     expire");
+	else
+		(void) printf("\n%s\n", "\
  recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu     expire");
 	printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
 	printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
@@ -1297,7 +1552,9 @@
 	printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
 #undef lock
 #undef msec
-#define	RTA_IGN	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
+	}
+#define	RTA_IGN	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|\
+		 RTA_IFA|RTA_BRD|RTA_AUTHOR|RTA_DOWNSTREAM)
 	if (verbose)
 		pmsg_common(rtm);
 	else if (rtm->rtm_addrs &~ RTA_IGN) {
@@ -1387,15 +1644,22 @@
 	register sup su;
 	char *which;
 {
+	static char sbuf[64];
+
 	switch (su->sa.sa_family) {
 	case AF_LINK:
-		(void) printf("%s: link %s; ",
-		    which, link_ntoa(&su->sdl));
+		(void) printf("%s: link#%d %s; ",
+		    which, (int)su->sdl.sdl_index, link_ntoa(&su->sdl));
 		break;
 	case AF_INET:
 		(void) printf("%s: inet %s; ",
 		    which, inet_ntoa(su->sin.sin_addr));
 		break;
+	case AF_INET6:
+		(void) printf("%s: inet6 %s; ", which,
+			      inet_ntop(AF_INET6, &su->sin6.sin6_addr,
+					sbuf, sizeof(sbuf)));
+		break;
 	case AF_APPLETALK:
 		(void) printf("%s: atalk %s; ",
 		    which, atalk_ntoa(su->sat.sat_addr));
@@ -1427,7 +1691,7 @@
 	register char *cp = (char *)sa;
 	int size = sa->sa_len;
 	char *cplim = cp + size;
-	register int byte = 0, state = VIRGIN, new = 0 /* foil gcc */;
+	register int byte = 0, state = VIRGIN, new = 0;
 
 	bzero(cp, size);
 	cp++;
diff -uN src-current/sbin/umount/umount.c src-current-ipv6/sbin/umount/umount.c
--- src-current/sbin/umount/umount.c
+++ src-current-ipv6/sbin/umount/umount.c
@@ -49,6 +49,7 @@
 #include <sys/socketvar.h>
 
 #include <netdb.h>
+#define RPC_USE_INET6	/*  address type is struct sockaddr_in6 *  */
 #include <rpc/rpc.h>
 #include <rpc/pmap_clnt.h>
 #include <rpc/pmap_prot.h>
@@ -60,6 +61,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <arpa/inet.h>
+#include <resolv.h>
 
 typedef enum { MNTON, MNTFROM } mntwhat;
 
@@ -122,6 +125,9 @@
 	argc -= optind;
 	argv += optind;
 
+	(void)res_init(); 
+	_res.options &= ~RES_USE_INET6;
+
 	if (argc == 0 && !all || argc != 0 && all)
 		usage();
 
@@ -207,7 +213,8 @@
 {
 	enum clnt_stat clnt_stat;
 	struct hostent *hp;
-	struct sockaddr_in saddr;
+	struct sockaddr_in6 saddr;
+	int af = AF_INET6, ch;
 	struct stat sb;
 	struct timeval pertry, try;
 	CLIENT *clp;
@@ -251,15 +258,29 @@
 	if (!strcmp(type, "nfs")) {
 		if ((delimp = strchr(name, '@')) != NULL) {
 			hostp = delimp + 1;
-			*delimp = '\0';
-			hp = gethostbyname(hostp);
-			*delimp = '@';
 		} else if ((delimp = strchr(name, ':')) != NULL) {
-			*delimp = '\0';
-			hostp = name;
-			hp = gethostbyname(hostp);
+			/* IPv6 special case: look for adv6:spec */
+			char *p = name
+				  + strspn(name, "0123456789abcdefABCDEF:.");
+			struct in6_addr ad;
+
+			if (p > name && p[-1] == ':') {
+				*--p = 0;
+				if (inet_pton(AF_INET6, name, &ad) == 1)
+					delimp = p;
+				*p = ':';
+			}
 			name = delimp + 1;
-			*delimp = ':';
+		}
+		if (delimp) {
+			ch = *delimp;
+			*delimp = '\0';
+			hp = gethostbyname2(hostp, af);
+			if (!hp) {
+				af = AF_INET;
+				hp = gethostbyname2(hostp, af);
+			}
+			*delimp = ch;
 		}
 	}
 
@@ -276,18 +297,35 @@
 		return (1);
 	}
 
+    restart4:
 	if ((hp != NULL) && !(fflag & MNT_FORCE)) {
 		*delimp = '\0';
 		memset(&saddr, 0, sizeof(saddr));
-		saddr.sin_family = AF_INET;
-		saddr.sin_port = 0;
-		memmove(&saddr.sin_addr, hp->h_addr, 
-		    MIN(hp->h_length, sizeof(saddr.sin_addr)));
+		saddr.sin6_port = 0;
+		if (af == AF_INET6) {
+			saddr.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+			saddr.sin6_len = sizeof saddr;
+#endif
+			memmove(&saddr.sin6_addr, hp->h_addr,
+				MIN(hp->h_length, sizeof(saddr.sin6_addr)));
+		} else {
+#define TOSIN(x) ((struct sockaddr_in *)(x))
+			saddr.sin6_family = AF_INET;
+			memmove(&TOSIN(&saddr)->sin_addr, hp->h_addr,
+				MIN(hp->h_length,
+				sizeof(&TOSIN(&saddr)->sin_addr)));
+		}
 		pertry.tv_sec = 3;
 		pertry.tv_usec = 0;
 		so = RPC_ANYSOCK;
 		if ((clp = clntudp_create(&saddr,
 		    RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
+			if (af == AF_INET6) {
+				af = AF_INET;
+				if ((hp = gethostbyname2(hostp, af)))
+					goto restart4;
+			}
 			clnt_pcreateerror("Cannot MNT PRC");
 			return (1);
 		}
@@ -297,7 +335,17 @@
 		clnt_stat = clnt_call(clp,
 		    RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
 		if (clnt_stat != RPC_SUCCESS) {
+			if (af == AF_INET6) {
+				af = AF_INET;
+				if ((hp = gethostbyname2(hostp, af))) {
+					auth_destroy(clp->cl_auth);
+					clnt_destroy(clp);
+					goto restart4;
+				}
+			}
 			clnt_perror(clp, "Bad MNT RPC");
+			auth_destroy(clp->cl_auth);
+			clnt_destroy(clp);
 			return (1);
 		}
 		auth_destroy(clp->cl_auth);
diff -uN src-current/share/man/man4/Makefile src-current-ipv6/share/man/man4/Makefile
--- src-current/share/man/man4/Makefile
+++ src-current-ipv6/share/man/man4/Makefile
@@ -6,11 +6,15 @@
 	null.4 od.4 ppi.4 ppp.4 pt.4 pty.4 route.4 \
 	scsi.4 sd.4 sl.4 smp.4 snp.4 sppp.4 ssc.4 st.4 su.4 tcp.4 \
 	ttcp.4 termios.4 tty.4 tun.4  udp.4 uk.4 update.4 unix.4 vn.4 \
-	worm.4 yp.4 zero.4
+	worm.4 yp.4 zero.4 \
+	inet6.4 ipsec.4 ipv6.4 icmpv6.4 sit.4 cti.4 ip6firewall.4 \
+	en.4 natm.4 # pvc.4
 
 MLINKS+=fd.4 stderr.4 fd.4 stdin.4 fd.4 stdout.4
 MLINKS+=netintro.4 networking.4
 MLINKS+=ipfirewall.4 ipacct.4 ipfirewall.4 ipfw.4 ipfirewall.4 ipaccounting.4
+MLINKS+=ip6firewall.4 ip6acct.4 ip6firewall.4 ip6fw.4
+MLINKS+=ip6firewall.4 ip6accounting.4
 MLINKS+=fpa.4 fea.4
 MLINKS+=yp.4 YP.4 yp.4 nis.4 yp.4 NIS.4
 MLINKS+=smp.4 SMP.4
diff -uN src-current/share/man/man4/cti.4 src-current-ipv6/share/man/man4/cti.4
--- src-current/share/man/man4/cti.4
+++ src-current-ipv6/share/man/man4/cti.4
@@ -0,0 +1,78 @@
+.\" Copyright (c) 1983, 1991, 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.
+.\"
+.\"     @(#)lo.4	8.1 (Berkeley) 6/5/93
+.\"
+.Dd June 5, 1993
+.Dt CTI 4
+.Os BSD 4.2
+.Sh NAME
+.Nm cti
+.Nd software Configured Tunnel Interfaces
+.Sh SYNOPSIS
+.Nm pseudo-device cti
+.Op Ar count
+.Sh DESCRIPTION
+The
+.Nm CTI
+interfaces are a software mechanism which encapsulate
+.Tn IPv6
+packets over IP (version 4) configured tunnels
+(automatic tunnels are 
+.Nm SIT
+interfaces).
+.Pp
+The IPv4 addresses of both ends are taken from the IPv4-compatible
+IPv6 addresses of interfaces. The IPv4 source address must be used by
+another interface in order to not mess the IPv4 routing.
+.Pp
+A
+.Nm CTI
+interface is point-to-point, supports multicast
+and should have an host source address.
+.Pp
+It is possible to add new
+.Nm CTI
+interfaces with the ``net.inet6.ipv6.cti_count''
+variable accessible by sysctl.
+.Sh SEE ALSO
+.Xr intro 4 ,
+.Xr inet 4 ,
+.Xr inet6 4 ,
+.Xr ipv6 4 ,
+.Xr sit 4 ,
+.Xr autoconf6 8 ,
+.Xr cticonfig 8 ,
+.Xr ifconfig 8 ,
+.Xr sysctl 8
+.Sh BUGS
+The don't fragment flag is not used because IPv4 Path MTU discovery
+is currently too broken then ICMP errors are ignored.
diff -uN src-current/share/man/man4/icmpv6.4 src-current-ipv6/share/man/man4/icmpv6.4
--- src-current/share/man/man4/icmpv6.4
+++ src-current-ipv6/share/man/man4/icmpv6.4
@@ -0,0 +1,117 @@
+.\" Copyright (c) 1986, 1991, 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.
+.\"
+.\"     @(#)icmp.4	8.1 (Berkeley) 6/5/93
+.\"
+.Dd June 5, 1993
+.Dt ICMPV6 4
+.Os BSD 4.3
+.Sh NAME
+.Nm icmpv6
+.Nd Internet Control Message Protocol version 6
+.Sh SYNOPSIS
+.Fd #include <sys/socket.h>
+.Fd #include <netinet/in.h>
+.Ft int
+.Fn socket AF_INET6 SOCK_RAW proto
+.Sh DESCRIPTION
+.Tn ICMPv6
+is the error and control message protocol used
+by
+.Tn IPv6
+and the version 6 of the Internet protocol family.
+.Tn ICMPv6
+replaces IGMP (Internet Group Management Protocol) and ARP
+(Address Resolution Protocol), named
+.Tn NDP
+(Neighbor Discovery Protocol) in version 6, too.
+It may be accessed through a
+.Dq raw socket
+for network monitoring
+and diagnostic functions.
+The
+.Fa proto
+parameter to the socket call to create an
+.Tn ICMPv6
+socket
+is obtained from
+.Xr getprotobyname 3 .
+.Tn ICMPv6
+sockets are connectionless,
+and are normally used with the
+.Xr sendto 2
+and
+.Xr recvfrom 2
+calls, though the
+.Xr connect 2
+call may also be used to fix the destination for future
+packets (in which case the 
+.Xr read 2
+or
+.Xr recv 2
+and 
+.Xr write 2
+or
+.Xr send 2
+system calls may be used).
+.Pp
+Outgoing packets automatically have an
+.Tn IPv6
+header prepended to
+them (based on the destination address).
+Incoming packets are received with the
+.Tn IPv6
+header and extra headers intact.
+.Sh DIAGNOSTICS
+A socket operation may fail with one of the following errors returned:
+.Bl -tag -width [EADDRNOTAVAIL]
+.It Bq Er EISCONN
+when trying to establish a connection on a socket which
+already has one, or when trying to send a datagram with the destination
+address specified and the socket is already connected;
+.It Bq Er ENOTCONN
+when trying to send a datagram, but
+no destination address is specified, and the socket hasn't been
+connected;
+.It Bq Er ENOBUFS
+when the system runs out of memory for
+an internal data structure;
+.It Bq Er EADDRNOTAVAIL
+when an attempt is made to create a 
+socket with a network address for which no network interface
+exists.
+.El
+.Sh SEE ALSO
+.Xr recv 2 ,
+.Xr send 2 ,
+.Xr inet6 4 ,
+.Xr netintro 4 ,
+.Xr ipv6 4
diff -uN src-current/share/man/man4/inet6.4 src-current-ipv6/share/man/man4/inet6.4
--- src-current/share/man/man4/inet6.4
+++ src-current-ipv6/share/man/man4/inet6.4
@@ -0,0 +1,142 @@
+.\" Copyright (c) 1983, 1991, 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.
+.\"
+.\"     From: @(#)inet.4	8.1 (Berkeley) 6/5/93
+.\"	$Id: inet.4,v 1.3 1995/03/16 18:24:19 wollman Exp $
+.\"
+.Dd February 14, 1995
+.Dt INET6 4
+.Os BSD 4.2
+.Sh NAME
+.Nm inet6
+.Nd Internet protocol version 6 family
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <netinet/in.h>
+.Sh DESCRIPTION
+The Version 6 of the Internet protocol (named IPv6)
+is a new version of the 
+.Em Internet  Protocol 
+utilizing a 16-octet address format.
+The version 6 Internet family provides protocol support for the
+.Dv SOCK_STREAM , SOCK_DGRAM ,
+and
+.Dv SOCK_RAW
+socket types; the
+.Dv SOCK_RAW
+interface provides access to the
+.Tn IPv6
+protocol.
+.Sh ADDRESSING
+IPv6 addresses are 16 octet quantities, stored in
+network standard format (on little endian hosts
+these are word and byte
+reversed).  The include file
+.Aq Pa netinet/in.h
+defines this address as a structure.
+.Pp
+Sockets bound to the IPv6 family utilize
+the following addressing structure,
+.Bd -literal -offset indent
+struct sockaddr_in6 {
+	u_int8_t  sin6_len;
+	u_int8_t  sin6_family;
+	u_int16_t sin6_port;
+	u_int32_t sin6_flowinfo;
+	struct    in6_addr sin6_addr;
+};
+.Ed
+.Pp
+Sockets may be created with the all-zeroes local address
+to effect
+.Dq wildcard
+matching on incoming messages for both IPv4 and IPv6.
+The address in a
+.Xr connect 2
+or
+.Xr sendto 2
+call may be given as all-zeros to mean
+.Dq this host .
+Version 4 Internet protocols can be accessed using
+``IPv4-mapped IPv6 addresses'' of the form
+.Bd -literal -offset indent
+::FFFF:<IPv4-address>
+.Ed
+.Sh PROTOCOLS
+The Internet protocol family is comprised of
+the
+.Tn IPv6
+network protocol, Internet Control
+Message Protocol
+.Pq Tn ICMPv6 ,
+Transmission Control Protocol
+.Pq Tn TCP ,
+and User Datagram Protocol
+.Pq Tn UDP .
+.Tn TCP
+is used to support the
+.Dv SOCK_STREAM
+abstraction while
+.Tn UDP
+is used to support the
+.Dv SOCK_DGRAM
+abstraction.  A raw interface to
+.Tn IPv6
+is available
+by creating an Internet socket of type
+.Dv SOCK_RAW .
+The
+.Tn ICMPv6
+message protocol is accessible from a raw socket.
+.Sh MIB VARIABLES
+A number of variables are implemented in the net.inet6 branch of the
+.Xr sysctl 3
+MIB and should be documented here.
+.Sh SEE ALSO
+.Xr ioctl 2 ,
+.Xr socket 2 ,
+.Xr sysctl 3 ,
+.Xr icmpv6 4 ,
+.Xr intro 4 ,
+.Xr ipv6 4 ,
+.Xr tcp 4 ,
+.Xr ttcp 4 ,
+.Xr udp 4 ,
+.Rs
+.%T "An Introductory 4.3 BSD Interprocess Communication Tutorial"
+.%B PS1
+.%N 7
+.Re
+.Rs
+.%T "An Advanced 4.3 BSD Interprocess Communication Tutorial"
+.%B PS1
+.%N 8
+.Re
diff -uN src-current/share/man/man4/ip6firewall.4 src-current-ipv6/share/man/man4/ip6firewall.4
--- src-current/share/man/man4/ip6firewall.4
+++ src-current-ipv6/share/man/man4/ip6firewall.4
@@ -0,0 +1,211 @@
+.Dd November 16, 1994
+.Dt IP6FIREWALL 4
+.Os
+.Sh NAME
+.Nm ip6firewall ,
+.Nm ip6fw ,
+.Nm ip6accounting ,
+.Nm ip6acct
+.Nd IPv6 packet filter and traffic accounting.
+.Sh SYNOPSIS
+.Fd #include <netinet/ip6_fw.h>
+.Ft int
+.Fn setsockopt raw_socket IPPROTO_IPV6 "ip6fw/ip6acct  option" "struct ipv6 | struct ip6fw" size
+
+Ip6fw options:
+  IP6_FW_ADD_BLK   - add entry to blocking chain. 
+  IP6_FW_ADD_FWD   - add entry to forwarding chain. 
+  IP6_FW_CHK_BLK   - check ipv6 packet against blocking chain.
+  IP6_FW_CHK_FWD   - check ipv6 packet against forwarding chain.
+  IP6_FW_DEL_BLK   - delete entry from blocking chain.
+  IP6_FW_DEL_FWD   - delete entry from forwarding chain.
+  IP6_FW_FLUSH     - flush all blocking & forwarding chain entries.
+  IP6_FW_POLICY    - define default ip6fw policy.
+
+Ip6acct options:
+  IP6_ACCT_ADD     - add entry to accounting chain.
+  IP6_ACCT_DEL     - delete entry from accounting chain.
+  IP6_ACCT_FLUSH   - flush all accounting chain entries.
+  IP6_ACCT_ZERO    - zero all accounting chain entries.
+
+Ip6fw/ip6acct entry structure:
+  #define IP6_FW_MAX_PORTS 10             
+
+struct ip6_fw {
+  struct ip_fw *next;       
+  struct in6_addr src, dst; 
+  struct in6_addr src_mask, dst_mask;  
+  u_short flags;                     
+  u_short n_src_p, n_dst_p;  
+  u_short ports[IP6_FW_MAX_PORTS];  
+  u_long p_cnt, b_cnt;  
+}
+
+Flags values for "flags" field:
+  IP6_FW_F_ALL     - The entry should match all IPv6 packets. 
+  IP6_FW_F_TCP     - The entry should match TCP packets.
+  IP6_FW_F_UDP     - The entry should match UDP packets.
+  IP6_FW_F_ICMP    - The entry should match ICMPv6 packets.
+  IP6_FW_F_KIND    - Mask value to separate protocol kind.
+  IP6_FW_F_ACCEPT  - This entry is accepting ( see below )
+  IP6_FW_F_SRNG    - Source ports are range ( see below )
+  IP6_FW_F_DRNG    - Destination ports are range ( see below )
+  IP6_FW_F_PRN     - Print this entry ( see below )
+  IP6_FW_F_BIDIR   - This acct entry is bidirectional ( see below )
+  IP6_FW_F_MASK    - Mask to match all valid flag bits.
+
+Kernel symbols to kvm_nlist():
+  struct ip6_fw *ip6_fw_blk_chain - chain of forwarding entries.
+  struct ip6_fw *ip6_fw_fwd_chain - chain of blocking entries.
+  int           ip6_fw_policy    - default policy.
+  struct ip6_fw *ip6_acct_chain   - chain of accounting entries.
+
+Options in the kernel configuration file:
+  IPFIREWALL	   - enable ipfirewall.
+  IPFIREWALL_VERBOSE - enable firewall output ( see below )
+  DEBUG_IPFIREWALL   - enable extensive debugging output.
+  IP6ACCT		   - enable ip6accounting.
+
+.Sh DESCRIPTION
+Ip6firewall (later ip6fw) is a system facility, which allows filtering
+of incoming and/or forwarding packets on the protocol+source/destination
+address/ports base.
+Ip6accounting (later ip6acct) is a system facility, which allows counting
+of incoming, outgoing and forwarding traffic by packet/byte count.
+.Pp
+Basic idea is that every packet checked against number of entries
+in several chains. There are 3 chains:
+  Blocking - this chain defines whenever packet should be accepted
+             ever for local delivery or for forwarding.
+  Forwarding - this chain defines whenever packet should be accepted
+               for forwarding only.
+  Accounting - this chain defines types of packets , which should be
+               counted.
+.Pp
+Options to add/remove specific entries or to flush all entries described
+above. Value passed to
+.Fn setsockopt
+is a value of struct ip6fw for
+entry. If an entry is added, it checked by such rules that when we start
+searching chain for matching entry the first matching is the best match,
+[ or at least one of them :^) ].
+ That means:
+  * First in chain entries with specific protocol and small ranges
+    of src/dst addresses and ports. 
+  * Later go entries with wider ranges of ports and addresses.
+  * Later entries matching every port for some address range.
+  * Later universal entries matching any protocol.
+.Pp
+While deleting entry, every entry which is equal to that passed to 
+.Fn setsockopt
+will be removed. Flush removes all entries.
+Each entry has several fields, by which packets matched:
+
+
+   struct ip6_fw *next - next entry in chain.(Set internally)
+
+   struct in6_addr src - source address to be matched.
+   struct in6_addr src_mask  - source address mask.
+           To match whole networks/subnets or address groups
+           mask bits should be zeroed here and also
+           in src_mask field. Valuable bits should be set
+           in src_mask field.
+   struct in6_addr dst - destination address to be matched.
+   struct in6_addr dst_mask - destination address mask. 
+
+   u_short flags  - flags field. See exact description of flags meaning
+                    in description later.
+
+   u_short n_src_p - number of source ports in "ports" array.
+   u_short n_dst_p - number of destination ports in "ports" array. 
+   u_short ports[] - ports array. Overall length currently defined
+                     to reasonable maximum - 10, and could be changed.
+                     The packet's src port can ever match one of
+                     ports[0] ... ports[--n_src_p] numbers, or if
+                     flag IP6_FW_F_SRNG set take port[0] as bottom 
+                     range value and ports[1] as top one. n_src_p should
+                     be set to 2 then. If n_src_p equal to 0 , every port
+                     match. The same rules apply to packet's dst port,
+                     except that it matched against ports[n_src_p] ...
+                     ... ports[n_src_p+n_dst_p--], or if IP6_FW_F_DRNG
+                     set, range is ports[n_src_p] to ports[n_srcp++].
+
+   u_long p_cnt - packets count for ip6acct entries.
+   u_long b_cnt - bytes count for ip6acct entries.
+
+Packet matching proceeds in following manner:
+
+a) If packet entry protocol set to ALL, see c).
+
+b) If entry protocol set to TCP/UDP/ICMPv6 and packet protocol 
+   different - no match, if packet protocol and entry protocol
+   same - continue.
+     
+c) If source address pattern does not equal to packets sources address
+   masked with src_mask, or destination pattern not equal to packets
+   destination address masked with dst_mask - no match.
+   If they does and protocol set to ALL/ICMPv6 - got match.
+   If they does and protocol set to TCP/UDP - continue.
+
+d) If src port doesn't match or dst port doesn't match - all
+   packet don't match. If they do - got match.
+.Pp
+In ip6fw packet matched consequently against every chain entry.
+Search continues untill first matching entry found. If IP6_FW_F_ACCEPT
+flag set - packet accepted. If it is not set - packet denied.
+If no matching entry found , all unmatched packets ever accepted or
+denied depending on global policy value. It can be set with
+IP6_FW_POLICY raw socket option. The value for deny is 0,
+and 1 for accept.
+.Pp
+Entries can be added with IP6_FW_F_PRN flag set. If kernel compiled
+with IP6FIREWALL_VERBOSE option, packets matching this entries will
+be printed by kernel printf's.
+.Pp
+If some chain is empty, every packet accepted by this chain no
+matter what default policy is.
+.Pp
+To check whenever or not packet denied by some chain , checking
+options to setsockopt() can be issued. Then the argument is 
+a buffer representing ipv6 packet, thus it has to be 
+struct ipv6 + struct tcphdr .
+Then setsockopt() return value 0 on accept or another on deny.
+.Pp   
+Ip6accounting entries added the same way as ip6fw ones. Packet checked
+against all entries in chain and values of p_cnt and b_cnt in matching
+entries rised. p_cnt rises by 1 and b_cnt by ip6_len value of ipv6 packet
+plus the size of the ipv6 header. Thus all traffic size counted including
+IPv6 headers.
+.Pp
+If IP6_FW_F_BIDIR flag is set in accounting entry, packets counted are
+those which match entry in standard way along with packets which match
+entry while their source and destination addr/port pairs swapped.
+.Pp
+Zero option allows all accounting to be cleared.
+.Sh DIAGNOSTICS
+
+[EINVAL]  The IPv6 option field was improperly formed; an option
+          field was shorter than the minimum value or longer than
+          the option buffer provided. An structural error in 
+          ip6_fw structure occurred (n_src_p+n_dst_p too big,
+          ports set for ALL/ICMPv6 protocols etc.)
+.Sh SEE ALSO
+.Xr setsockopt 2 ,
+.Xr kvm_nlist 3 ,
+.Xr kvm_read 3 ,
+.Xr ipv6 4
+.Sh BUGS
+The ip6fw/ip6acct facilities are new and, although serious bugs have
+been tracked, some less important ones are expected.
+.Pp
+This man page is mostly out of date and should be rewritten. 
+.Sh HISTORY
+ Ipfw facility has been initially written as package to BSDI
+by Daniel Boulet <danny@BouletFermat.ab.ca>.
+ It has been heavily modified and ported to
+.Fx 2.0 
+by Ugen J.S.Antsilevich <ugen@NetVision.net.il>
+ Ipacct facility written for
+.Fx 2.0 
+by Ugen J.S.Antsilevich <ugen@NetVision.net.il>
+ Both have been v6fied by Francis Dupont <Francis.Dupont@inria.fr>
diff -uN src-current/share/man/man4/ipsec.4 src-current-ipv6/share/man/man4/ipsec.4
--- src-current/share/man/man4/ipsec.4
+++ src-current-ipv6/share/man/man4/ipsec.4
@@ -0,0 +1,77 @@
+.Dd April 17, 1996
+.Dt IPSEC 4
+.Os BSD 4.2
+.Sh NAME
+.Nm ipsec
+.Nd IPv6 network layer security
+.Sh SYNOPSIS
+.Fd #include <netinet/ipsec.h>
+.Sh DESCRIPTION
+The IPv6 implements authentication and confidentiality
+with two optional headers. An one way Security Association
+can be bound to a destination address and a Security
+Parameter Index pair and can be manually managed by
+the
+.Xr key6 8
+utility.
+.Pp
+Each socket has a list of attached Security Associations
+which can be used of incoming or outgoing packets.
+.Sh OPTIONS
+The
+.Xr getsockopt 2
+and
+.Xr setsockopt 2
+system calls with level
+.Ar IP6_NHDR_AUTH
+(51) or
+.Ar IP6_NHDR_ESP
+(50) can create, change or delete Security Associations,
+attach or detach them to/from sockets.
+.Pp
+Available options are :
+.Bl -tag -width IPSEC_WANTCRYPT__
+.It IPSEC_WANTAUTH
+packets are delivered to the socket only when they are
+authentic with a matching Security Association.
+.It IPSEC_WANTCRYPT
+packets are delivered to the socket only when they are
+crypted with a matching Security Association.
+.It IPSEC_CREATE
+create a new Security Association with the given parameters.
+.It IPSEC_CHANGE
+change a Security Association parameters.
+.It IPSEC_DELETE
+delete a Security Association.
+.It IPSEC_ATTACH
+attach a Security Association to a socket.
+.It IPSEC_ATTACHX
+attach a Security Association without references to a socket.
+.It IPSEC_ATTACHW
+attach the wildcard Security Association to a socket
+(any known Security Association will match).
+.It IPSEC_DETACH
+detach a Security Association from a socket.
+.It IPSEC_DETACHX
+detach a Security Association without other references from a socket.
+.It IPSEC_DETACHW
+detach the wildcard Security Association from a socket.
+.El
+.Sh ERRORS
+Some error codes have special meanings :
+.Bl -tag -width ENOPROTOOPTAA
+.It Bq Er ENOENT
+no Security Association can be found.
+.It Bq Er ESRCH
+the given algorithm is not available.
+.It Bq Er EEXIST
+the entry already exists or has extra references.
+.It Bq Er EBUSY
+the entry is still used and can't be deleted.
+.It Bq Er EIPSEC
+a packet can't be sent because a security header
+is provided with an inexistant SPI.
+.El
+.Sh SEE ALSO
+.Xr ipv6 4 ,
+.Xr key6 8
diff -uN src-current/share/man/man4/ipv6.4 src-current-ipv6/share/man/man4/ipv6.4
--- src-current/share/man/man4/ipv6.4
+++ src-current-ipv6/share/man/man4/ipv6.4
@@ -0,0 +1,157 @@
+.\" Copyright (c) 1983, 1991, 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.4	8.2 (Berkeley) 11/30/93
+.\"
+.Dd November 30, 1993
+.Dt IPC6 4
+.Os BSD 4.2
+.Sh NAME
+.Nm ipv6
+.Nd Internet Protocol version 6
+.Sh SYNOPSIS
+.Fd #include <sys/socket.h>
+.Fd #include <netinet/in.h>
+.Ft int
+.Fn socket AF_INET6 SOCK_RAW proto
+.Sh DESCRIPTION
+.Tn IPv6
+is the network layer protocol used
+by the version 6 of the Internet protocol family.
+Options may be set at the
+.Tn IPv6
+level
+when using higher-level protocols that are based on
+.Tn IPv6
+(such as
+.Tn TCP
+and
+.Tn UDP ) .
+It may also be accessed
+through a
+.Dq raw socket
+when developing new protocols, or
+special-purpose applications.
+.Pp
+There are several new
+.Tn IPv6-level
+.Xr setsockopt 2
+and
+.Xr getsockopt 2
+options which should be described here.
+.Ss "Raw IPv6 Sockets"
+.Pp
+Raw
+.Tn IPv6
+sockets are connectionless,
+and are normally used with the
+.Xr sendto 2
+and
+.Xr recvfrom 2
+calls, though the
+.Xr connect 2
+call may also be used to fix the destination for future
+packets (in which case the 
+.Xr read 2
+or
+.Xr recv 2
+and 
+.Xr write 2
+or
+.Xr send 2
+system calls may be used).
+.Pp
+The protocol number
+.Fa proto
+is used on outgoing packets
+and to filter incoming packets.
+.Pp
+Outgoing packets automatically have an
+.Tn IPv6
+header prepended to
+them (based on the destination address and the protocol
+number the socket is created with),
+unless the 
+.Dv IP_HDRINCL 
+option has been set.
+Incoming packets are received with
+.Tn IPv6
+header and extra headers intact.
+.Pp
+.Dv IP_HDRINCL 
+indicates the complete IPv6 header is included with the data
+and may be used only with the 
+.Dv SOCK_RAW 
+type.
+.Sh DIAGNOSTICS
+A socket operation may fail with one of the following errors returned:
+.Bl -tag -width [EADDRNOTAVAIL]
+.It Bq Er EISCONN
+when trying to establish a connection on a socket which
+already has one, or when trying to send a datagram with the destination
+address specified and the socket is already connected;
+.It Bq Er ENOTCONN
+when trying to send a datagram, but
+no destination address is specified, and the socket hasn't been
+connected;
+.It Bq Er ENOBUFS
+when the system runs out of memory for
+an internal data structure;
+.It Bq Er EADDRNOTAVAIL
+when an attempt is made to create a 
+socket with a network address for which no network interface
+exists.
+.It Bq Er EACESS
+when an attempt is made to create
+a raw IP socket by a non-privileged process.
+.El
+.Pp
+The following errors specific to
+.Tn IPv6
+may occur when setting or getting
+.Tn IPv6
+options:
+.Bl -tag -width EADDRNOTAVAILxx
+.It Bq Er EINVAL
+An unknown socket option name was given.
+.It Bq Er EINVAL
+The IPv6 option field was improperly formed;
+an option field was shorter than the minimum value
+or longer than the option buffer provided.
+.El
+.Sh SEE ALSO
+.Xr getsockopt 2 ,
+.Xr recv 2 ,
+.Xr send 2 ,
+.Xr icmpv6 4 ,
+.Xr inet6 4 ,
+.Xr intro 4 ,
+.Xr ip 4
diff -uN src-current/share/man/man4/netintro.4 src-current-ipv6/share/man/man4/netintro.4
--- src-current/share/man/man4/netintro.4
+++ src-current-ipv6/share/man/man4/netintro.4
@@ -151,6 +151,7 @@
 #define    AF_CCITT     10   /* CCITT protocols, X.25 etc */
 #define    AF_HYLINK    15   /* NSC Hyperchannel */
 #define    AF_ISO       18   /* ISO protocols */
+#define    AF_INET6     28   /* IPv6 protocols */
 .Ed
 .Sh ROUTING
 .Tn UNIX
diff -uN src-current/share/man/man4/sit.4 src-current-ipv6/share/man/man4/sit.4
--- src-current/share/man/man4/sit.4
+++ src-current-ipv6/share/man/man4/sit.4
@@ -0,0 +1,72 @@
+.\" Copyright (c) 1983, 1991, 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.
+.\"
+.\"     @(#)lo.4	8.1 (Berkeley) 6/5/93
+.\"
+.Dd June 5, 1993
+.Dt SIT 4
+.Os BSD 4.2
+.Sh NAME
+.Nm sit
+.Nd software Simple Internet Transition interfaces
+.Sh SYNOPSIS
+.Nm pseudo-device sit
+.Op Ar count
+.Sh DESCRIPTION
+The
+.Nm SIT
+interfaces are a software mechanism which encapsulate
+.Tn IPv6
+packets over IP (version 4) automatic tunnels
+(configured tunnels are
+.Nm CTI
+interfaces).
+.Pp
+The IPv4 address of the entry point is taken from the IPv4-compatible
+IPv6 address of the interface. This IPv4 source address must be used by
+another interface in order to not mess the IPv4 routing.
+.Pp
+Usually the first
+.Nm SIT
+interface ``sit0'' is configured for the whole IPv4-compatible
+IPv6 prefix ``::/96'' which gives a cloning route doing
+the IPv4-compatible IPv6 address to IPv4 address automagical mapping.
+.Sh SEE ALSO
+.Xr intro 4 ,
+.Xr inet 4 ,
+.Xr inet6 4 ,
+.Xr ipv6 4 ,
+.Xr cti 4 ,
+.Xr autoconf6 8 ,
+.Xr ifconfig 8
+.Sh BUGS
+The don't fragment flag is not used because IPv4 Path MTU discovery
+is currently too broken then ICMP errors are ignored.
diff -uN src-current/share/man/man4/tcp.4 src-current-ipv6/share/man/man4/tcp.4
--- src-current/share/man/man4/tcp.4
+++ src-current-ipv6/share/man/man4/tcp.4
@@ -44,6 +44,9 @@
 .Fd #include <netinet/in.h>
 .Ft int
 .Fn socket AF_INET SOCK_STREAM 0
+or
+.Ft int
+.Fn socket AF_INET6 SOCK_STREAM 0
 .Sh DESCRIPTION
 The
 .Tn TCP
@@ -52,12 +55,12 @@
 support the
 .Dv SOCK_STREAM
 abstraction.  TCP uses the standard
-Internet address format and, in addition, provides a per-host
+Internet address formats and, in addition, provides a per-host
 collection of
 .Dq port addresses .
 Thus, each address is composed
-of an Internet address specifying the host and network, with
-a specific
+of an Internet (IPv4) address specifying the host and network,
+or an IPv6 address, with a specific
 .Tn TCP
 port on the host identifying the peer entity.
 .Pp
@@ -98,7 +101,13 @@
 To create a socket which listens on all networks, the Internet
 address
 .Dv INADDR_ANY
-must be bound.  The
+must be bound.
+To create a socket which listens on both IPv4 (all networks)
+and
+.Tn IPv6
+protocols, the all-zeros
+.Tn IPv6
+address must be used.  The
 .Tn TCP
 port may still be specified
 at this time; if the port is not specified the system will assign one.
@@ -181,7 +190,9 @@
 transport level may be used with
 .Tn TCP ;
 see
-.Xr ip 4 .
+.Xr ip 4
+and
+.Xr ipv6 4 .
 Incoming connection requests that are source-routed are noted,
 and the reverse source route is used in responding.
 .Sh MIB VARIABLES
@@ -244,8 +255,10 @@
 .Xr socket 2 ,
 .Xr sysctl 3 ,
 .Xr inet 4 ,
+.Xr inet6 4 ,
 .Xr intro 4 ,
 .Xr ip 4 ,
+.Xr ipv6 4 ,
 .Xr ttcp 4
 .Rs
 .%A V. Jacobson, R. Braden, and D. Borman
diff -uN src-current/share/man/man4/udp.4 src-current-ipv6/share/man/man4/udp.4
--- src-current/share/man/man4/udp.4
+++ src-current-ipv6/share/man/man4/udp.4
@@ -44,6 +44,9 @@
 .Fd #include <netinet/in.h>
 .Ft int
 .Fn socket AF_INET SOCK_DGRAM 0
+or
+.Ft int
+.Fn socket AF_INET6 SOCK_DGRAM 0
 .Sh DESCRIPTION
 .Tn UDP
 is a simple, unreliable datagram protocol which is used
@@ -76,7 +79,7 @@
 In particular
 .Tn UDP
 provides a port identifier in addition
-to the normal Internet address format.  Note that the
+to the normal Internet address formats.  Note that the
 .Tn UDP
 port
 space is separate from the
@@ -100,7 +103,9 @@
 transport level may be used with
 .Tn UDP ;
 see
-.Xr ip 4 .
+.Xr ip 4
+and
+.Xr ipv6 4 .
 .Sh DIAGNOSTICS
 A socket operation may fail with one of the following errors returned:
 .Bl -tag -width [EADDRNOTAVAIL]
@@ -130,8 +135,10 @@
 .Xr send 2 ,
 .Xr socket 2 ,
 .Xr inet 4 ,
+.Xr inet6 4 ,
 .Xr intro 4 ,
-.Xr ip 4
+.Xr ip 4 ,
+.Xr ipv6 4
 .Sh HISTORY
 The
 .Nm
diff -uN src-current/share/man/man5/hosts.5 src-current-ipv6/share/man/man5/hosts.5
--- src-current/share/man/man5/hosts.5
+++ src-current-ipv6/share/man/man5/hosts.5
@@ -46,7 +46,7 @@
 For each host a single line should be present
 with the following information:
 .Bd -unfilled -offset indent
-Internet address
+Internet (IPv4 or IPv6) address
 official host name
 aliases
 .Ed
@@ -79,12 +79,14 @@
 .Tn DARPA
 Internet.
 .Pp
-Network addresses are specified in the conventional
+Internet (IPv4) addresses are specified in the conventional
 ``.'' (dot) notation using the
 .Xr inet_addr 3
 routine
 from the Internet address manipulation library,
 .Xr inet 3 .
+IPv6 addresses are specified using ``:'' (colon)
+notation.
 Host names may contain any printable
 character other than a field delimiter, newline,
 or comment character.
@@ -98,6 +100,7 @@
 .El
 .Sh SEE ALSO
 .Xr gethostbyname 3 ,
+.Xr hostname2addr 3 ,
 .Xr ifconfig 8 ,
 .Xr named 8
 .Rs
diff -uN src-current/sys/conf/files src-current-ipv6/sys/conf/files
--- src-current/sys/conf/files
+++ src-current-ipv6/sys/conf/files
@@ -71,6 +71,35 @@
 gnu/ext2fs/ext2_subr.c		optional ext2fs
 gnu/ext2fs/ext2_vfsops.c	optional ext2fs
 gnu/ext2fs/ext2_vnops.c		optional ext2fs
+harp/adapters/eni/eni.c			optional hea device-driver
+harp/adapters/eni/eni_buffer.c		optional hea device-driver
+harp/adapters/eni/eni_globals.c		optional hea device-driver
+harp/adapters/eni/eni_if.c		optional hea device-driver
+harp/adapters/eni/eni_init.c		optional hea device-driver
+harp/adapters/eni/eni_intr.c		optional hea device-driver
+harp/adapters/eni/eni_receive.c		optional hea device-driver
+harp/adapters/eni/eni_transmit.c	optional hea device-driver
+harp/adapters/eni/eni_vcm.c		optional hea device-driver
+harp/adapters/fore/fore_buffer.c	optional hfa device-driver
+harp/adapters/fore/fore_command.c	optional hfa device-driver
+harp/adapters/fore/fore_globals.c	optional hfa device-driver
+harp/adapters/fore/fore_if.c		optional hfa device-driver
+harp/adapters/fore/fore_init.c		optional hfa device-driver
+harp/adapters/fore/fore_intr.c		optional hfa device-driver
+harp/adapters/fore/fore_load.c		optional hfa device-driver
+harp/adapters/fore/fore_output.c	optional hfa device-driver
+harp/adapters/fore/fore_receive.c	optional hfa device-driver
+harp/adapters/fore/fore_stats.c		optional hfa device-driver
+harp/adapters/fore/fore_timer.c		optional hfa device-driver
+harp/adapters/fore/fore_transmit.c	optional hfa device-driver
+harp/adapters/fore/fore_vcm.c		optional hfa device-driver
+harp/netatm/atm_config.c		optional atm
+harp/netatm/atm_device.c		optional atm
+harp/netatm/atm_if.c			optional atm
+harp/netatm/atm_proto.c			optional atm
+harp/netatm/atm_signal.c		optional atm
+harp/netatm/atm_subr.c			optional atm
+harp/netatm/atm_usrreq.c		optional atm
 isofs/cd9660/cd9660_bmap.c	optional cd9660
 isofs/cd9660/cd9660_lookup.c	optional cd9660
 isofs/cd9660/cd9660_node.c	optional cd9660
@@ -199,6 +228,7 @@
 msdosfs/msdosfs_lookup.c	optional msdosfs
 msdosfs/msdosfs_vfsops.c	optional msdosfs
 msdosfs/msdosfs_vnops.c		optional msdosfs
+net/altq.c		optional altq
 net/bpf.c		optional bpfilter
 net/bpf_filter.c	optional bpfilter
 net/bsd_comp.c		optional ppp_bsdcomp
@@ -256,15 +286,37 @@
 #netimp/if_imp.c		optional imp
 #netimp/if_imphost.c	optional imp
 #netimp/raw_imp.c	optional imp
+netinet/afmap.c		optional altq
+netinet/cbq.c		optional altq
+netinet/cbq_class.c	optional altq
+netinet/des.c		optional inet6
+netinet/fifoq.c		optional altq
 netinet/fil.c		optional ipfilter inet
 netinet/if_atm.c	optional atm
+netinet/if_bti6.c	optional bti device-driver
+netinet/if_cti6.c	optional cti device-driver
 netinet/if_ether.c	optional ether
+netinet/if_gre.c	optional gre device-driver
+netinet/if_llink6.c	optional llink device-driver
+netinet/if_ndp6.c	optional inet6
+netinet/if_sit6.c	optional sit device-driver
+netinet/if_sit6.c	optional cti device-driver
+netinet/if_tug6.c	optional tug device-driver
+netinet/if_tug6.c	optional inet6
 netinet/igmp.c		optional inet
 netinet/in.c		optional inet
+netinet/in6.c		optional inet6
+netinet/in6_pcb.c	optional inet6
+netinet/in6_proto.c	optional inet6
 #netinet/in_hostcache.c	optional inet
 netinet/in_pcb.c	optional inet
 netinet/in_proto.c	optional inet
 netinet/in_rmx.c	optional inet
+netinet/ip6_fw.c	optional ip6firewall
+netinet/ip6_icmp.c	optional inet6
+netinet/ip6_input.c	optional inet6
+netinet/ip6_mroute.c	optional inet6
+netinet/ip6_output.c	optional inet6
 netinet/ip_auth.c	optional ipfilter inet
 netinet/ip_divert.c	optional ipdivert
 netinet/ip_fil.c	optional ipfilter inet
@@ -279,15 +331,36 @@
 netinet/ip_output.c	optional inet
 netinet/ip_proxy.c	optional ipfilter inet
 netinet/ip_state.c	optional ipfilter inet
+netinet/ipsec.c		optional inet6
+netinet/ipsec_algo.c	optional inet6
+netinet/md5.c		optional inet6
 netinet/mlf_ipl.c	optional ipfilter inet
 netinet/raw_ip.c	optional inet
+netinet/raw_ip6.c	optional inet6
+netinet/red.c		optional altq
+netinet/rm_class.c	optional altq
+netinet/sha.c		optional inet6
+netinet/tcp6_input.c	optional inet6
+netinet/tcp6_output.c	optional inet6
+netinet/tcp6_subr.c	optional inet6
+netinet/tcp6_timer.c	optional inet6
+netinet/tcp6_usrreq.c	optional inet6
 netinet/tcp_debug.c	optional tcpdebug
 netinet/tcp_input.c	optional inet
 netinet/tcp_output.c	optional inet
 netinet/tcp_subr.c	optional inet
 netinet/tcp_timer.c	optional inet
 netinet/tcp_usrreq.c	optional inet
+netinet/udp6_usrreq.c	optional inet6
 netinet/udp_usrreq.c	optional inet
+netinet/ip_fil.c	optional ipfilter inet
+netinet/fil.c		optional ipfilter inet
+netinet/ip_nat.c	optional ipfilter inet
+netinet/ip_frag.c	optional ipfilter inet
+netinet/ip_state.c	optional ipfilter inet
+netinet/ip_proxy.c	optional ipfilter inet
+netinet/mln_ipl.c	optional ipfilter inet
+netinet/wfq.c		optional altq
 netipx/ipx.c		optional ipx
 netipx/ipx_cksum.c	optional ipx
 netipx/ipx_input.c	optional ipx
@@ -353,6 +426,7 @@
 netnatm/natm.c		optional natm
 netnatm/natm_pcb.c	optional natm
 netnatm/natm_proto.c	optional natm
+netnatm/natm_sif.c	optional sat device-driver
 #netns/idp_usrreq.c	optional ns
 #netns/ns.c		optional ns
 #netns/ns_error.c	optional ns
diff -uN src-current/sys/conf/files.newconf src-current-ipv6/sys/conf/files.newconf
--- src-current/sys/conf/files.newconf
+++ src-current-ipv6/sys/conf/files.newconf
@@ -28,10 +28,23 @@
 pseudo-device cd: disk
 pseudo-device loop
 pseudo-device pty: tty
+pseudo-device sit
+pseudo-device cti
+pseudo-device tug
+pseudo-device bti
+pseudo-device llink
+pseudo-device sat
 pseudo-device sl
 pseudo-device vn: disk
 
 # kernel sources
+file	harp/netatm/atm_config.c	atm
+file	harp/netatm/atm_device.c	atm
+file	harp/netatm/atm_if.c		atm
+file	harp/netatm/atm_proto.c		atm
+file	harp/netatm/atm_signal.c	atm
+file	harp/netatm/atm_subr.c		atm
+file	harp/netatm/atm_usrreq.c	atm
 file	isofs/cd9660/cd9660_bmap.c	cd9660
 file	isofs/cd9660/cd9660_lookup.c	cd9660
 file	isofs/cd9660/cd9660_node.c	cd9660
@@ -119,6 +132,7 @@
 file	miscfs/union/union_subr.c	union
 file	miscfs/union/union_vfsops.c	union
 file	miscfs/union/union_vnops.c	union
+file	net/altq.c		altq
 file	net/bpf.c		bpfilter needs-count
 file	net/bpf_filter.c	bpfilter needs-count
 file	net/if.c
@@ -154,12 +168,33 @@
 file	netimp/if_imp.c		imp needs-count
 file	netimp/if_imphost.c	imp needs-count
 file	netimp/raw_imp.c	imp
+file	netinet/afmap.c		altq
+file	netinet/cbq.c		altq
+file	netinet/cbq_class.c	altq
+file	netinet/des.c		inet6
+file	netinet/fifoq.c		altq
 file	netinet/if_atm.c	atm
+file	netinet/if_bti6.c	bti needs-count
+file	netinet/if_cti6.c	cti needs-count
 file	netinet/if_ether.c	ether
+file	netinet/if_gre.c	gre needs-count
+file	netinet/if_llink6.c	multi_homed
+file	netinet/if_ndp6.c	inet6
+file	netinet/if_sit6.c	cti | sit needs-count
+file	netinet/if_tug6.c	tug needs-count
 file	netinet/igmp.c		inet
 file	netinet/in.c		inet
+file	netinet/in6.c		inet6
+file	netinet/in6_pcb.c	inet6
+file	netinet/in6_proto.c	inet6
 file	netinet/in_pcb.c	inet
 file	netinet/in_proto.c	inet
+file	netinet/ip6_fw.c	ip6firewall
+file	netinet/ip6_icmp.c	inet6
+file	netinet/ip6_input.c	inet6
+file	netinet/ip6_mroute.c	inet6
+file	netinet/ip6_output.c	inet6
+file	netinet/ip_fw.c		ipfirewall
 file	netinet/ip_icmp.c	inet
 file	netinet/ip_input.c	inet
 file	netinet/ip_mroute.c	inet
@@ -170,15 +205,29 @@
 file	netinet/ip_frag.c	ipfilter
 file	netinet/ip_state.c	ipfilter
 file	netinet/ip_proxy.c	ipfilter
+file	netinet/ipsec.c		inet6
+file	netinet/ipsec_algo.c	inet6
+file	netinet/md5.c		inet6
 file	netinet/mln_ipl.c	ipfilter
 file	netinet/raw_ip.c	inet
+file	netinet/raw_ip6.c	inet6
+file	netinet/red.c		altq
+file	netinet/rm_class.c	altq
+file	netinet/sha.c		inet6
+file	netinet/tcp6_input.c	inet6
+file	netinet/tcp6_output.c	inet6
+file	netinet/tcp6_subr.c	inet6
+file	netinet/tcp6_timer.c	inet6
+file	netinet/tcp6_usrreq.c	inet6
 file	netinet/tcp_debug.c	inet
 file	netinet/tcp_input.c	inet
 file	netinet/tcp_output.c	inet
 file	netinet/tcp_subr.c	inet
 file	netinet/tcp_timer.c	inet
 file	netinet/tcp_usrreq.c	inet
+file	netinet/udp6_usrreq.c	inet6
 file	netinet/udp_usrreq.c	inet
+file	netinet/wfq.c		altq
 file	netiso/clnp_debug.c	iso
 file	netiso/clnp_er.c	iso
 file	netiso/clnp_frag.c	iso
@@ -218,6 +267,7 @@
 file	netnatm/natm.c		natm
 file	netnatm/natm_pcb.c	natm
 file	netnatm/natm_proto.c	natm
+file	netnatm/natm_sif.c	sat needs-count
 file	netns/idp_usrreq.c	ns
 file	netns/ns.c		ns
 file	netns/ns_error.c	ns
diff -uN src-current/sys/conf/options src-current-ipv6/sys/conf/options
--- src-current/sys/conf/options
+++ src-current-ipv6/sys/conf/options
@@ -165,10 +165,20 @@
 BOOTP_NFSROOT		opt_bootp.h
 BOOTP_NFSV3		opt_bootp.h
 BOOTP_WIRED_TO		opt_bootp.h
+ALTQ			opt_altq.h
+ALTQ_ECN		opt_altq.h
+CBQ			opt_altq.h
+WFQ			opt_altq.h
+AFMAP			opt_altq.h
+FIFOQ			opt_altq.h
+RED			opt_altq.h
+ALTQ_ACCOUNT		opt_altq.h
 GATEWAY			opt_defunct.h
 MROUTING		opt_mrouting.h
 INET			opt_inet.h
+INET6			opt_inet6.h
 IPDIVERT
+MROUTING6		opt_mrouting6.h
 IPFIREWALL		opt_ipfw.h
 IPFIREWALL_VERBOSE	opt_ipfw.h
 IPFIREWALL_VERBOSE_LIMIT	opt_ipfw.h
@@ -183,6 +193,9 @@
 PPP_DEFLATE		opt_ppp.h
 PPP_FILTER		opt_ppp.h
 TCP_COMPAT_42		opt_compat.h
+IP6FIREWALL		opt_ip6fw.h
+IP6FIREWALL_VERBOSE	opt_ip6fw.h
+IP6FIREWALL_VERBOSE_LIMIT	opt_ip6fw.h
 TCPDEBUG
 IPFILTER		opt_ipfilter.h
 IPFILTER_LOG		opt_ipfilter.h
diff -uN src-current/sys/dev/en/midway.c src-current-ipv6/sys/dev/en/midway.c
--- src-current/sys/dev/en/midway.c
+++ src-current-ipv6/sys/dev/en/midway.c
@@ -1,5 +1,5 @@
-/*	$NetBSD: midway.c,v 1.25 1997/03/20 21:34:42 chuck Exp $	*/
-/*	(sync'd to midway.c 1.67)	*/
+/*	$NetBSD: midway.c,v 1.30 1997/09/29 17:40:38 chuck Exp $	*/
+/*	(sync'd to midway.c 1.68)	*/
 
 /*
  *
@@ -46,7 +46,35 @@
  *   I would also like to thank Werner for promptly answering email and being
  *   generally helpful.
  */
-
+/*
+ *  1997/12/02 kjc
+ *    new features added:
+ *	- support vc/vp shaping
+ *	- integrate IPv6 support.
+ *	- support pvc shadow interface
+ *	  (initial work on per-pvc-interface for ipv6 was done
+ *	  by Katsushi Kobayashi <ikob@cc.uec.ac.jp> of the WIDE Project,
+ *	  extensively modified by kjc.)
+ *    code cleanup:
+ *	- remove WMAYBE related code.  ENI WMAYBE DMA doen't work.
+ *	- drop support of FreeBSD-2.1.x and FreeBSD-3.0-SNAP-970124.
+ *	- remove updating if_lastchange for every packet.
+ *	- BPF related code is moved to midway.c as it should be.
+ *	  (bpfwrite should work if atm_pseudohdr and LLC/SNAP are
+ *	  prepended.)
+ *	- BPF link type is changed to DLT_ATM_RFC1483.
+ *	  BPF now understands only LLC/SNAP!! (because bpf can't
+ *	  handle variable link header length.)
+ *	  It is recommended to use LLC/SNAP instead of NULL
+ *	  encapsulation for various reasons.  (BPF, IPv6,
+ *	  interoperability, etc.)
+ *	- altq queue implementation is moved from the driver internal
+ *	  queue to if_snd.
+ *	- AFMAP related code cleanup.
+ */
+#if defined(__FreeBSD__) && defined(ALTQ)
+#include "opt_altq.h"
+#endif
 
 #undef	EN_DEBUG
 #undef	EN_DEBUG_RANGE		/* check ranges on en_read/en_write's? */
@@ -58,16 +86,35 @@
 #endif
 #define EN_NOTXDMA	0	/* hook to disable tx dma only */
 #define EN_NORXDMA	0	/* hook to disable rx dma only */
-#define EN_NOWMAYBE	1	/* hook to disable word maybe DMA */
-				/* XXX: WMAYBE doesn't work, needs debugging */
 #define EN_DDBHOOK	1	/* compile in ddb functions */
-#ifdef __FreeBSD__
-/* somehow, misaligned DMA doesn't work on FreeBSD with ENI card.
- * not sure if this is specific to FreeBSD.
- * anyway, always fix unaligned or word fragmented mbufs.  --kjc */
-#define EN_FIXMBUF
+#if defined(MIDWAY_ADPONLY)
+#define EN_ENIDMAFIX	0	/* no ENI cards to worry about */
+#else
+#define EN_ENIDMAFIX	1	/* avoid byte DMA on the ENI card (see below) */
 #endif
 
+/*
+ * note on EN_ENIDMAFIX: the byte aligner on the ENI version of the card
+ * appears to be broken.   it works just fine if there is no load... however
+ * when the card is loaded the data get corrupted.   to see this, one only
+ * has to use "telnet" over ATM.   do the following command in "telnet":
+ * 	cat /usr/share/misc/termcap
+ * "telnet" seems to generate lots of 1023 byte mbufs (which make great
+ * use of the byte aligner).   watch "netstat -s" for checksum errors.
+ * 
+ * I further tested this by adding a function that compared the transmit 
+ * data on the card's SRAM with the data in the mbuf chain _after_ the 
+ * "transmit DMA complete" interrupt.   using the "telnet" test I got data
+ * mismatches where the byte-aligned data should have been.   using ddb
+ * and en_dumpmem() I verified that the DTQs fed into the card were 
+ * absolutely correct.   thus, we are forced to concluded that the ENI
+ * hardware is buggy.   note that the Adaptec version of the card works
+ * just fine with byte DMA.
+ *
+ * bottom line: we set EN_ENIDMAFIX to 1 to avoid byte DMAs on the ENI
+ * card.
+ */
+
 #if defined(DIAGNOSTIC) && !defined(EN_DIAG)
 #define EN_DIAG			/* link in with master DIAG option */
 #endif
@@ -89,27 +136,27 @@
 
 #ifdef __FreeBSD__
 #include "en.h"
-#include "opt_inet.h"
-#include "opt_natm.h"
 #endif
 
 #if NEN > 0 || !defined(__FreeBSD__)
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/queue.h>
 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
 #include <sys/device.h>
 #endif
 #include <sys/sockio.h>
 #include <sys/mbuf.h>
 #include <sys/socket.h>
+#include <sys/proc.h>
 
 #include <net/if.h>
 #include <net/if_atm.h>
 
 #include <vm/vm.h>
 
-#ifdef INET
+#if defined(INET) || defined(INET6)
 #include <netinet/if_atm.h>
 #endif
 
@@ -118,6 +165,9 @@
 #include <netnatm/natm.h>
 #endif
 
+#if defined(ALTQ) && defined(AFMAP)
+#include <netinet/afmap.h>
+#endif
 
 #if !defined(sparc) && !defined(__FreeBSD__)
 #include <machine/bus.h>
@@ -137,18 +187,24 @@
 #include <dev/en/midwayvar.h>
 #include <vm/pmap.h>			/* for vtophys proto */
 
-/* 
- * 2.1.x does not have if_softc.   detect this by seeing if IFF_NOTRAILERS
- * is defined, as per kjc.
- */
-#ifdef IFF_NOTRAILERS
-#define MISSING_IF_SOFTC
-#else
+#ifndef IFF_NOTRAILERS
 #define IFF_NOTRAILERS 0
 #endif
 
 #endif	/* __FreeBSD__ */
 
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#ifdef __FreeBSD__
+#define BPFATTACH(ifp, dlt, hlen)	bpfattach((ifp), (dlt), (hlen))
+#define BPF_MTAP(ifp, m)		bpf_mtap((ifp), (m))
+#else
+#define BPFATTACH(ifp, dlt, hlen)	bpfattach(&(ifp)->if_bpf, (ifp), (dlt), (hlen))
+#define BPF_MTAP(ifp, m)		bpf_mtap((ifp)->if_bpf, (m))
+#endif
+#endif /* NBPFILTER > 0 */
+
 /*
  * params
  */
@@ -171,7 +227,7 @@
 #define ENOTHER_RAW	0x04		/* 'raw' access  (aka boodi mode) */
 #define ENOTHER_SWSL	0x08		/* in software service list */
 
-static int en_dma = EN_DMA;		/* use DMA (switch off for dbg) */
+int en_dma = EN_DMA;			/* use DMA (switch off for dbg) */
 
 /*
  * autoconfig attachments
@@ -206,7 +262,7 @@
 /*
  * dma table (index by # of words)
  *
- * plan A: use WMAYBE
+ * plan A: use WMAYBE (obsolete)
  * plan B: avoid WMAYBE
  */
 
@@ -215,18 +271,6 @@
   u_int8_t divshift;		/* byte divisor */
 };
 
-static struct en_dmatab en_dma_planA[] = {
-  { 0, 0 },		/* 0 */		{ MIDDMA_WORD, 2 },	/* 1 */
-  { MIDDMA_2WORD, 3},	/* 2 */		{ MIDDMA_4WMAYBE, 2},	/* 3 */
-  { MIDDMA_4WORD, 4},	/* 4 */		{ MIDDMA_8WMAYBE, 2},	/* 5 */
-  { MIDDMA_8WMAYBE, 2},	/* 6 */		{ MIDDMA_8WMAYBE, 2},	/* 7 */
-  { MIDDMA_8WORD, 5},   /* 8 */		{ MIDDMA_16WMAYBE, 2},	/* 9 */
-  { MIDDMA_16WMAYBE,2},	/* 10 */	{ MIDDMA_16WMAYBE, 2},	/* 11 */
-  { MIDDMA_16WMAYBE,2},	/* 12 */	{ MIDDMA_16WMAYBE, 2},	/* 13 */
-  { MIDDMA_16WMAYBE,2},	/* 14 */	{ MIDDMA_16WMAYBE, 2},	/* 15 */
-  { MIDDMA_16WORD, 6},  /* 16 */
-};
-
 static struct en_dmatab en_dma_planB[] = {
   { 0, 0 },		/* 0 */		{ MIDDMA_WORD, 2},	/* 1 */
   { MIDDMA_2WORD, 3},	/* 2 */		{ MIDDMA_WORD, 2},	/* 3 */
@@ -239,35 +283,56 @@
   { MIDDMA_16WORD, 6},  /* 16 */
 };
 
-static struct en_dmatab *en_dmaplan = en_dma_planA;
-  
+static struct en_dmatab *en_dmaplan = en_dma_planB;
+
 /*
  * prototypes
  */
 
-STATIC	int en_b2sz __P((int));
+STATIC INLINE	int en_b2sz __P((int)) __attribute__ ((unused));
 #ifdef EN_DDBHOOK
-int	en_dump __P((int,int));
-int	en_dumpmem __P((int,int,int));
+		int en_dump __P((int,int));
+		int en_dumpmem __P((int,int,int));
+#endif
+STATIC		void en_dmaprobe __P((struct en_softc *));
+STATIC		int en_dmaprobe_doit __P((struct en_softc *, u_int8_t *, 
+		    u_int8_t *, int));
+STATIC INLINE	int en_dqneed __P((struct en_softc *, caddr_t, u_int,
+		    u_int)) __attribute__ ((unused));
+STATIC		void en_init __P((struct en_softc *));
+STATIC		int en_ioctl __P((struct ifnet *, EN_IOCTL_CMDT, caddr_t));
+STATIC INLINE	int en_k2sz __P((int)) __attribute__ ((unused));
+STATIC		void en_loadvc __P((struct en_softc *, int));
+STATIC		int en_mfix __P((struct en_softc *, struct mbuf **,
+		    struct mbuf *));
+STATIC INLINE	struct mbuf *en_mget __P((struct en_softc *, u_int,
+		    u_int *)) __attribute__ ((unused));
+STATIC INLINE	u_int32_t en_read __P((struct en_softc *,
+		    u_int32_t)) __attribute__ ((unused));
+STATIC		int en_rxctl __P((struct en_softc *, struct atm_pseudoioctl *,
+		    int));
+STATIC		void en_txdma __P((struct en_softc *, int));
+STATIC		void en_txlaunch __P((struct en_softc *, int,
+		    struct en_launch *));
+STATIC		void en_service __P((struct en_softc *));
+STATIC		void en_start __P((struct ifnet *));
+STATIC INLINE	int en_sz2b __P((int)) __attribute__ ((unused));
+STATIC INLINE	void en_write __P((struct en_softc *, u_int32_t,
+		    u_int32_t)) __attribute__ ((unused));
+
+#ifdef ATM_PVCEXT
+static int en_txctl __P((struct en_softc *, int, int, int));
+static int en_pvctx __P((struct en_softc *, struct pvctxreq *));
+static int en_pvctxget __P((struct en_softc *, struct pvctxreq *));
+static int en_pcr2txspeed __P((int));
+static int en_txspeed2pcr __P((int));
+#endif
+
+#if defined(ALTQ) && defined(AFMAP)
+static int en_flowmap_add __P((struct en_softc *, struct atm_flowmap *));
+static int en_flowmap_delete __P((struct en_softc *, int, int));
+static int en_flowmap_get __P((struct en_softc *, struct atm_flowmap *));
 #endif
-STATIC	void en_dmaprobe __P((struct en_softc *));
-STATIC	int en_dmaprobe_doit __P((struct en_softc *, u_int8_t *, 
-							u_int8_t *, int));
-STATIC	int en_dqneed __P((struct en_softc *, caddr_t, u_int, u_int));
-STATIC	void en_init __P((struct en_softc *));
-STATIC	int en_ioctl __P((struct ifnet *, EN_IOCTL_CMDT, caddr_t));
-STATIC	int en_k2sz __P((int));
-STATIC	void en_loadvc __P((struct en_softc *, int));
-STATIC	int en_mfix __P((struct en_softc *, struct mbuf **, struct mbuf *));
-STATIC	struct mbuf *en_mget __P((struct en_softc *, u_int, u_int *));
-STATIC	u_int32_t en_read __P((struct en_softc *, u_int32_t));
-STATIC	int en_rxctl __P((struct en_softc *, struct atm_pseudoioctl *, int));
-STATIC	void en_txdma __P((struct en_softc *, int));
-STATIC	void en_txlaunch __P((struct en_softc *, int, struct en_launch *));
-STATIC	void en_service __P((struct en_softc *));
-STATIC	void en_start __P((struct ifnet *));
-STATIC	int en_sz2b __P((int));
-STATIC	void en_write __P((struct en_softc *, u_int32_t, u_int32_t));
 
 /*
  * macros/inline
@@ -596,10 +661,14 @@
       }
       m->m_len = MLEN;
     }
-    if (top && totlen >= MINCLSIZE) {
+    if (totlen >= MINCLSIZE) {
       MCLGET(m, M_DONTWAIT);
-      if (m->m_flags & M_EXT)
-	m->m_len = MCLBYTES;
+      if ((m->m_flags & M_EXT) == 0) {
+	m_free(m);
+	m_freem(top);
+	return(NULL);	  /* out of mbuf clusters */
+      }
+      m->m_len = MCLBYTES;
     }
     m->m_len = min(totlen, m->m_len);
     totlen -= m->m_len;
@@ -674,7 +743,7 @@
 	(MID_IS_SABRE(reg)) ? "sabre controller, " : "",
 	(MID_IS_SUNI(reg)) ? "SUNI" : "Utopia",
 	(!MID_IS_SUNI(reg) && MID_IS_UPIPE(reg)) ? " (pipelined)" : "",
-	sc->en_obmemsz / 1024);
+	(long)sc->en_obmemsz / 1024);
 
   if (sc->is_adaptec) {
     if (sc->bestburstlen == 64 && sc->alburst == 0)
@@ -687,12 +756,6 @@
 	  sc->bestburstlen, (sc->alburst) ? " (must align)" : "");
   }
 
-#if 0		/* WMAYBE doesn't work, don't complain about it */
-  /* check if en_dmaprobe disabled wmaybe */
-  if (en_dmaplan == en_dma_planB)
-    printf("%s: note: WMAYBE DMA has been disabled\n", sc->sc_dev.dv_xname);
-#endif
-
   /*
    * link into network subsystem and prepare card
    */
@@ -700,13 +763,14 @@
 #if defined(__NetBSD__) || defined(__OpenBSD__)
   bcopy(sc->sc_dev.dv_xname, sc->enif.if_xname, IFNAMSIZ);
 #endif
-#if !defined(MISSING_IF_SOFTC)
   sc->enif.if_softc = sc;
-#endif
   ifp->if_flags = IFF_SIMPLEX|IFF_NOTRAILERS;
   ifp->if_ioctl = en_ioctl;
   ifp->if_output = atm_output;
   ifp->if_start = en_start;
+#ifdef ALTQ
+  ifp->if_altqflags |= ALTQF_READY;
+#endif  /* ALTQ */
 
   /*
    * init softc
@@ -749,11 +813,14 @@
     printf("%s: EN_NTX/EN_TXSZ/EN_RXSZ too big\n", sc->sc_dev.dv_xname);
     return;
   }
-#if 1
-  /* leave one entry in the ringbuf unused to avoid wraparound */
+
+  /* 
+   * ensure that there is always one VC slot on the service list free
+   * so that we can tell the difference between a full and empty list.
+   */
   if (sc->en_nrx >= MID_N_VC)
-      sc->en_nrx = MID_N_VC - 1;
-#endif
+    sc->en_nrx = MID_N_VC - 1;
+
   for (lcv = 0 ; lcv < sc->en_nrx ; lcv++) {
     sc->rxslot[lcv].rxhand = NULL;
     sc->rxslot[lcv].oth_flags = ENOTHER_FREE;
@@ -788,6 +855,9 @@
   printf("%s: %d %dKB receive buffers, %d %dKB transmit buffers allocated\n",
 	sc->sc_dev.dv_xname, sc->en_nrx, EN_RXSZ, EN_NTX, EN_TXSZ);
 
+  printf("%s: End Station Identifier (mac address) %6D\n",
+	 sc->sc_dev.dv_xname, sc->macaddr, ":");
+
   /*
    * final commit
    */
@@ -795,6 +865,12 @@
   if_attach(ifp);
   atm_ifattach(ifp); 
 
+#if NBPFILTER > 0 
+  BPFATTACH(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc));
+#endif
+#if defined(ALTQ) && defined(AFMAP)
+  afm_alloc(ifp);
+#endif
 }
 
 
@@ -812,30 +888,67 @@
  * p166:   bestburstlen=64, alburst=0 
  */
 
+#if 1 /* __FreeBSD__ */
+#define NBURSTS	3	/* number of bursts to use for dmaprobe */
+#define BOUNDARY 1024	/* test misaligned dma crossing the bounday.
+			   should be n * 64.  at least 64*(NBURSTS+1).
+			   dell P6 with EDO DRAM has 1K bounday problem */
+#endif
+
 STATIC void en_dmaprobe(sc)
 
 struct en_softc *sc;
 
 {
+#ifdef NBURSTS
+  /* be careful. kernel stack is only 8K */
+  u_int8_t buffer[BOUNDARY * 2 + 64 * (NBURSTS + 1)]; 
+#else
   u_int32_t srcbuf[64], dstbuf[64];
+#endif
   u_int8_t *sp, *dp;
-  int bestalgn, bestnotalgn, lcv, try, fail;
+  int bestalgn, bestnotalgn, lcv, try;
 
   sc->alburst = 0;
 
+#ifdef NBURSTS
+  /* setup src and dst buf at the end of the boundary */
+  sp = (u_int8_t *)roundup((unsigned long)buffer, 64);
+  while (((unsigned long)sp & (BOUNDARY - 1)) != (BOUNDARY - 64))
+      sp += 64;
+  dp = sp + BOUNDARY;
+
+  /*
+   * we can't dma across page boundary so that, if buf is at a page
+   * boundary, move it to the next page.  but still either src or dst
+   * will be at the boundary, which should be ok.
+   */
+  if ((((unsigned long)sp + 64) & PAGE_MASK) == 0)
+      sp += 64;
+  if ((((unsigned long)dp + 64) & PAGE_MASK) == 0)
+      dp += 64;
+#else /* !NBURSTS */
   sp = (u_int8_t *) srcbuf;
   while ((((unsigned long) sp) % MIDDMA_MAXBURST) != 0)
     sp += 4;
   dp = (u_int8_t *) dstbuf;
   while ((((unsigned long) dp) % MIDDMA_MAXBURST) != 0)
     dp += 4;
+#endif /* !NBURSTS */
 
   bestalgn = bestnotalgn = en_dmaprobe_doit(sc, sp, dp, 0);
 
   for (lcv = 4 ; lcv < MIDDMA_MAXBURST ; lcv += 4) {
     try = en_dmaprobe_doit(sc, sp+lcv, dp+lcv, 0);
+#ifdef NBURSTS
+    if (try < bestnotalgn) {
+      bestnotalgn = try;
+      break;
+    }
+#else
     if (try < bestnotalgn)
       bestnotalgn = try;
+#endif
   }
 
   if (bestalgn != bestnotalgn) 		/* need bursts aligned */
@@ -846,39 +959,21 @@
   sc->bestburstmask = sc->bestburstlen - 1; /* must be power of 2 */
   sc->bestburstcode = en_sz2b(bestalgn);
 
-  if (sc->bestburstlen <= 2*sizeof(u_int32_t))
-    return;				/* won't be using WMAYBE */
-
-  /*
-   * adaptec does not have (or need) wmaybe.   do not bother testing
-   * for it.
-   */
-  if (sc->is_adaptec) {
-    /* XXX, actually don't need a DMA plan: adaptec is smarter than that */
-    en_dmaplan = en_dma_planB; 
-    return;
-  }
-
+#ifdef __FreeBSD__
   /*
-   * test that WMAYBE dma works like we think it should 
-   * (i.e. no alignment restrictions on host address other than alburst)
-   */
-
-  try = sc->bestburstlen - 4;
-  fail = 0;
-  fail += en_dmaprobe_doit(sc, sp, dp, try);
-  for (lcv = 4 ; lcv < sc->bestburstlen ; lcv += 4) {
-    fail += en_dmaprobe_doit(sc, sp+lcv, dp+lcv, try);
-    if (sc->alburst)
-      try -= 4;
-  }
-  if (EN_NOWMAYBE || fail) {
-    if (fail)
-      printf("%s: WARNING: WMAYBE DMA test failed %d time(s)\n", 
-	sc->sc_dev.dv_xname, fail);
-    en_dmaplan = en_dma_planB;		/* fall back to plan B */
+   * correct pci chipsets should be able to handle misaligned-64-byte DMA.
+   * but there are too many broken chipsets around.  we try to work around
+   * by finding the best workable dma size, but still some broken machines
+   * exhibit the problem later. so warn it here.
+   */
+  if (bestalgn != 64 || sc->alburst != 0) {
+    printf("%s: WARNING: DMA test detects a broken PCI chipset!\n", 
+	   sc->sc_dev.dv_xname);
+    printf("     trying to work around the problem...  but if this doesn't\n");
+    printf("     work for you, you'd better switch to a newer motherboard.\n");
   }
-
+#endif /* __FreeBSD__ */
+    return;
 }
 
 
@@ -912,7 +1007,11 @@
   EN_WRITE(sc, MID_DST_RP(0), 0);
   EN_WRITE(sc, MID_WP_ST_CNT(0), 0);
 
+#ifdef NBURSTS
+  for (lcv = 0 ; lcv < 64*NBURSTS; lcv++) 	/* set up sample data */
+#else
   for (lcv = 0 ; lcv < 68 ; lcv++) 		/* set up sample data */
+#endif
     sp[lcv] = lcv+1;
   EN_WRITE(sc, MID_MAST_CSR, MID_MCSR_ENDMA);	/* enable DMA (only) */
 
@@ -934,10 +1033,19 @@
 
   for (lcv = 8 ; lcv <= MIDDMA_MAXBURST ; lcv = lcv * 2) {
 
+#ifdef EN_DEBUG
+    printf("DMA test lcv=%d, sp=0x%x, dp=0x%x, wmtry=%d\n",
+	   lcv, sp, dp, wmtry);
+#endif
+
     /* zero SRAM and dest buffer */
     for (cnt = 0 ; cnt < 1024; cnt += 4) 
       EN_WRITE(sc, MID_BUFOFF+cnt, 0);	/* zero memory */
+#ifdef NBURSTS
+    for (cnt = 0 ; cnt < 64*NBURSTS; cnt++) 
+#else
     for (cnt = 0 ; cnt < 68  ; cnt++) 
+#endif
       dp[cnt] = 0;
 
     if (wmtry) {
@@ -948,6 +1056,29 @@
       bcode = en_sz2b(lcv);
       count = 1;
     }
+#ifdef NBURSTS
+    /* build lcv-byte-DMA x NBURSTS */
+    if (sc->is_adaptec)
+      EN_WRITE(sc, sc->dtq_chip, MID_MK_TXQ_ADP(lcv*NBURSTS, 0, MID_DMA_END, 0));
+    else
+      EN_WRITE(sc, sc->dtq_chip, MID_MK_TXQ_ENI(count*NBURSTS, 0, MID_DMA_END, bcode));
+    EN_WRITE(sc, sc->dtq_chip+4, vtophys(sp));
+    EN_WRAPADD(MID_DTQOFF, MID_DTQEND, sc->dtq_chip, 8);
+    EN_WRITE(sc, MID_DMA_WRTX, MID_DTQ_A2REG(sc->dtq_chip));
+    cnt = 1000;
+    while (EN_READ(sc, MID_DMA_RDTX) != MID_DTQ_A2REG(sc->dtq_chip)) {
+      DELAY(1);
+      cnt--;
+      if (cnt == 0) {
+	printf("%s: unexpected timeout in tx DMA test\n", sc->sc_dev.dv_xname);
+/*
+	printf("  alignment=0x%lx, burst size=%d, dma addr reg=0x%x\n",
+	       (u_long)sp & 63, lcv, EN_READ(sc, MID_DMA_ADDR));
+*/	       
+	return(retval);		/* timeout, give up */
+      }
+    }
+#else /* !NBURSTS */
     if (sc->is_adaptec)
       EN_WRITE(sc, sc->dtq_chip, MID_MK_TXQ_ADP(lcv, 0, MID_DMA_END, 0));
     else
@@ -964,6 +1095,7 @@
       }
     }
     EN_WRAPADD(MID_DTQOFF, MID_DTQEND, sc->dtq_chip, 8);
+#endif /* !NBURSTS */
     reg = EN_READ(sc, MID_INTACK); 
     if ((reg & MID_INT_DMA_TX) != MID_INT_DMA_TX) {
       printf("%s: unexpected status in tx DMA test: 0x%x\n", 
@@ -974,6 +1106,25 @@
 
     /* "return to sender..."  address is known ... */
 
+#ifdef NBURSTS
+    /* build lcv-byte-DMA x NBURSTS */
+    if (sc->is_adaptec)
+      EN_WRITE(sc, sc->drq_chip, MID_MK_RXQ_ADP(lcv*NBURSTS, 0, MID_DMA_END, 0));
+    else
+      EN_WRITE(sc, sc->drq_chip, MID_MK_RXQ_ENI(count*NBURSTS, 0, MID_DMA_END, bcode));
+    EN_WRITE(sc, sc->drq_chip+4, vtophys(dp));
+    EN_WRAPADD(MID_DRQOFF, MID_DRQEND, sc->drq_chip, 8);
+    EN_WRITE(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip));
+    cnt = 1000;
+    while (EN_READ(sc, MID_DMA_RDRX) != MID_DRQ_A2REG(sc->drq_chip)) {
+      DELAY(1);
+      cnt--;
+      if (cnt == 0) {
+	printf("%s: unexpected timeout in rx DMA test\n", sc->sc_dev.dv_xname);
+	return(retval);		/* timeout, give up */
+      }
+    }
+#else /* !NBURSTS */
     if (sc->is_adaptec)
       EN_WRITE(sc, sc->drq_chip, MID_MK_RXQ_ADP(lcv, 0, MID_DMA_END, 0));
     else
@@ -990,6 +1141,7 @@
       }
     }
     EN_WRAPADD(MID_DRQOFF, MID_DRQEND, sc->drq_chip, 8);
+#endif /* !NBURSTS */
     reg = EN_READ(sc, MID_INTACK); 
     if ((reg & MID_INT_DMA_RX) != MID_INT_DMA_RX) {
       printf("%s: unexpected status in rx DMA test: 0x%x\n", 
@@ -1002,8 +1154,15 @@
       return(bcmp(sp, dp, wmtry));  /* wmtry always exits here, no looping */
     }
   
+#ifdef NBURSTS
+    if (bcmp(sp, dp, lcv * NBURSTS)) {
+/*      printf("DMA test failed! lcv=%d, sp=0x%x, dp=0x%x\n", lcv, sp, dp); */
+      return(retval);		/* failed, use last value */
+    }
+#else
     if (bcmp(sp, dp, lcv))
       return(retval);		/* failed, use last value */
+#endif
 
     retval = lcv;
 
@@ -1030,11 +1189,7 @@
 caddr_t data;
 
 {
-#ifdef MISSING_IF_SOFTC
-    struct en_softc *sc = (struct en_softc *) en_cd.cd_devs[ifp->if_unit];
-#else
     struct en_softc *sc = (struct en_softc *) ifp->if_softc;
-#endif
     struct ifaddr *ifa = (struct ifaddr *) data;
     struct ifreq *ifr = (struct ifreq *) data;
     struct atm_pseudoioctl *api = (struct atm_pseudoioctl *)data;
@@ -1079,8 +1234,9 @@
 #endif
 	case SIOCSIFADDR: 
 		ifp->if_flags |= IFF_UP;
-#ifdef INET
-		if (ifa->ifa_addr->sa_family == AF_INET) {
+#if defined(INET) || defined(INET6)
+		if (ifa->ifa_addr->sa_family == AF_INET
+		    || ifa->ifa_addr->sa_family == AF_INET6) {
 			en_reset(sc);
 			en_init(sc);
 			ifa->ifa_rtrequest = atm_rtrequest; /* ??? */
@@ -1121,6 +1277,71 @@
 	    break;
 #endif /* SIOCSIFMTU */
 
+#ifdef ATM_PVCEXT
+	case SIOCSPVCTX:
+		if ((error = suser(curproc->p_ucred, &curproc->p_acflag)) == 0)
+			error = en_pvctx(sc, (struct pvctxreq *)data);
+		break;
+
+	case SIOCGPVCTX:
+		error = en_pvctxget(sc, (struct pvctxreq *)data);
+		break;
+
+	case SIOCSPVCSIF:
+		do {
+			struct ifnet *shadow;
+		    
+			if (error = suser(curproc->p_ucred, &curproc->p_acflag))
+				break;
+		    
+			if ((shadow = pvc_attach(ifp)) != NULL) {
+				sprintf(ifr->ifr_name, "%s%d",
+					shadow->if_name, shadow->if_unit);
+			}
+			else
+				error = ENOBUFS;
+		} while (0);
+		break;
+
+#endif /* ATM_PVCEXT */
+
+#if defined(ALTQ) && defined(AFMAP)
+	case AFM_ADDFMAP:
+		do {
+			struct afm *afm = afm_top(ifp);
+			error = en_flowmap_add(sc, (struct atm_flowmap *)data);
+			if (afm == NULL && error == 0)
+				ifp->if_altqflags |= ALTQF_DRIVER1;
+		} while (0);
+		break;
+		
+	case AFM_DELFMAP:
+		do {
+			struct atm_flowmap *fmap = (struct atm_flowmap *)data;
+			error = en_flowmap_delete(sc, fmap->af_vpi, fmap->af_vci);
+		    
+			if (afm_top(ifp) == NULL)
+				ifp->if_altqflags &= ~ALTQF_DRIVER1;
+
+		} while (0);
+		break;
+		
+	case AFM_CLEANFMAP:
+		do {
+			struct afm *afm;
+			while ((afm = afm_top(ifp)) != NULL)
+				en_flowmap_delete(sc, afm->afm_vpi, afm->afm_vci);
+		
+			ifp->if_altqflags &= ~ALTQF_DRIVER1;
+		} while (0);
+		break;
+
+	case AFM_GETFMAP:
+		error = en_flowmap_get(sc, (struct atm_flowmap *)data);
+		break;
+
+#endif /* ALTQ && AFMAP */
+
 	default: 
 	    error = EINVAL;
 	    break;
@@ -1296,6 +1517,15 @@
 	break;		/* >>> exit 'while(1)' here <<< */
       m_freem(m);
     }
+
+#ifdef ALTQ
+    do {
+	    struct ifnet *ifp = &sc->enif;
+
+	    if (ALTQ_IS_ON(ifp))
+		    (void)(*ifp->if_altqdequeue)(ifp, ALTDQ_FLUSH);
+    } while (0);
+#endif /* ALTQ */
     sc->txslot[lcv].mbsize = 0;
   }
 
@@ -1335,30 +1565,30 @@
 
   /*
    * init obmem data structures: vc tab, dma q's, slist.
+   *
+   * note that we set drq_free/dtq_free to one less than the total number
+   * of DTQ/DRQs present.   we do this because the card uses the condition
+   * (drq_chip == drq_us) to mean "list is empty"... but if you allow the
+   * circular list to be completely full then (drq_chip == drq_us) [i.e.
+   * the drq_us pointer will wrap all the way around].   by restricting
+   * the number of active requests to (N - 1) we prevent the list from
+   * becoming completely full.    note that the card will sometimes give
+   * us an interrupt for a DTQ/DRQ we have already processes... this helps
+   * keep that interrupt from messing us up.
    */
 
   for (vc = 0 ; vc < MID_N_VC ; vc++) 
     en_loadvc(sc, vc);
 
   bzero(&sc->drq, sizeof(sc->drq));
-#if 1
-  /* leave one entry in the ringbuf unused to avoid wraparound */
-  sc->drq_free = MID_DRQ_N - 1;
-#else
-  sc->drq_free = MID_DRQ_N;
-#endif
+  sc->drq_free = MID_DRQ_N - 1;		/* N - 1 */
   sc->drq_chip = MID_DRQ_REG2A(EN_READ(sc, MID_DMA_RDRX));
   EN_WRITE(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip)); 
 						/* ensure zero queue */
   sc->drq_us = sc->drq_chip;
 
   bzero(&sc->dtq, sizeof(sc->dtq));
-#if 1
-  /* leave one entry in the ringbuf unused to avoid wraparound */
-  sc->dtq_free = MID_DTQ_N - 1;
-#else
-  sc->dtq_free = MID_DTQ_N;
-#endif
+  sc->dtq_free = MID_DTQ_N - 1;		/* N - 1 */
   sc->dtq_chip = MID_DTQ_REG2A(EN_READ(sc, MID_DMA_RDTX));
   EN_WRITE(sc, MID_DMA_WRTX, MID_DRQ_A2REG(sc->dtq_chip)); 
 						/* ensure zero queue */
@@ -1443,11 +1673,7 @@
 struct ifnet *ifp;
 
 {
-#ifdef MISSING_IF_SOFTC
-    struct en_softc *sc = (struct en_softc *) en_cd.cd_devs[ifp->if_unit];
-#else
     struct en_softc *sc = (struct en_softc *) ifp->if_softc;
-#endif
     struct ifqueue *ifq = &ifp->if_snd; /* if INPUT QUEUE */
     struct mbuf *m, *lastm, *prev;
     struct atm_pseudohdr *ap, *new_ap;
@@ -1465,6 +1691,33 @@
 
     while (1) {
 
+#ifdef ALTQ
+      if (ALTQ_IS_ON(ifp)) {
+	  struct mbuf *tmp;
+	  /*
+	   * when altq is used, don't dequeue the packet until we
+	   * know we have enough buffer space.  this makes packet
+	   * dropping is done in altq_enqueue.
+	   * also make the internal buffer smaller (20KB instead of 64KB)
+	   * to keep packets remaining in altq.
+	   */
+	  m = (*ifp->if_altqdequeue)(ifp, ALTDQ_PEEK);
+	  if (m != NULL) {
+	      ap = mtod(m, struct atm_pseudohdr *);
+	      atm_vci = ATM_PH_VCI(ap);
+	      txchan = sc->txvc2slot[atm_vci];
+	      if (sc->txslot[txchan].mbsize > 20*1024) {
+	          EN_COUNT(sc->txmbovr); /* this isn't a right stat counter */
+		  return;
+	      }
+
+	      tmp = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+	      if (tmp != m)
+		  panic("en_start: different mbuf dequeued!");
+	  }
+      }
+      else
+#endif
       IF_DEQUEUE(ifq, m);
       if (m == NULL)
 	return;		/* EMPTY: >>> exit here <<< */
@@ -1483,12 +1736,8 @@
       mlen = 0;
       prev = NULL;
       while (1) {
-#ifdef EN_FIXMBUF
-	/* if eni, always fix misaligned mbuf */
-	if (!sc->is_adaptec || EN_NOTXDMA || !en_dma) {
-#else
-        if (EN_NOTXDMA || !en_dma) {		/* no DMA? */
-#endif
+	/* no DMA? */
+        if ((!sc->is_adaptec && EN_ENIDMAFIX) || EN_NOTXDMA || !en_dma) {
 	  if ( (mtod(lastm, unsigned long) % sizeof(u_int32_t)) != 0 ||
 	    ((lastm->m_len % sizeof(u_int32_t)) != 0 && lastm->m_next)) {
 	    first = (lastm == m);
@@ -1502,6 +1751,7 @@
           }
           prev = lastm;
         }
+
 	mlen += lastm->m_len;
 	if (lastm->m_next == NULL)
 	  break;
@@ -1604,6 +1854,49 @@
       txchan = sc->txvc2slot[atm_vci];
 
       if (sc->txslot[txchan].mbsize > EN_TXHIWAT) {
+#ifdef ALTQ_ACCOUNT
+	/*
+	 * special process for altq drop accounting.
+	 * re-extract flow and do drop-accounting here.
+	 */
+	struct pr_hdr pr_hdr;
+	int size;
+
+	pr_hdr.ph_family = AF_INET;  /* XXX */
+	if (ifp->if_altqflags & ALTQF_ACCOUNTING) {
+	    size = sizeof(struct atm_pseudohdr);
+	    if (atm_flags & ATM_PH_LLCSNAP)
+		size += 8; /* sizeof snap == 8 */
+	    if (atm_flags & EN_OBHDR)
+		size += MID_TBD_SIZE;
+	    if (m->m_len >= size + 20) {
+		/* ip header in the first mbuf */
+		pr_hdr.ph_hdr = mtod(m, caddr_t) + size;
+#ifdef INET6
+		if ((pr_hdr.ph_hdr[0] >> 4) == 6) {
+		    pr_hdr.ph_family = AF_INET6;
+		    if (m->m_len < size + 40)
+			pr_hdr.ph_hdr = NULL;
+		}
+#endif
+	    } else if (m->m_len == size && m->m_next->m_len >= 20) {
+		/* ip header is in the second mbuf */
+		pr_hdr.ph_hdr = mtod(m->m_next, caddr_t);
+#ifdef INET6
+		if ((pr_hdr.ph_hdr[0] >> 4) == 6) {
+		    pr_hdr.ph_family = AF_INET6;
+		    if (m->m_next->m_len < 40)
+			pr_hdr.ph_hdr = NULL;
+		}
+#endif
+	    } else
+		/* give up otherwise */
+	        pr_hdr.ph_hdr = NULL;
+	}
+	else
+	    pr_hdr.ph_hdr = NULL;
+	ALTQ_ACCOUNTING(ifp, m, &pr_hdr, ALTEQ_ACCDROP);
+#endif
 	EN_COUNT(sc->txmbovr);
 	m_freem(m);
 #ifdef EN_DEBUG
@@ -1624,6 +1917,7 @@
 #endif
 
       IF_ENQUEUE(&sc->txslot[txchan].q, m);
+
       en_txdma(sc, txchan);
 
   }
@@ -1634,6 +1928,85 @@
 /*
  * en_mfix: fix a stupid mbuf
  */
+
+#ifndef __FreeBSD__
+
+STATIC int en_mfix(sc, mm, prev)
+
+struct en_softc *sc;
+struct mbuf **mm, *prev;
+
+{
+  struct mbuf *m, *new;
+  u_char *d, *cp;
+  int off;
+  struct mbuf *nxt;
+
+  m = *mm;
+
+  EN_COUNT(sc->mfix);			/* count # of calls */
+#ifdef EN_DEBUG
+  printf("%s: mfix mbuf m_data=%p, m_len=%d\n", sc->sc_dev.dv_xname,
+	m->m_data, m->m_len);
+#endif
+
+  d = mtod(m, u_char *);
+  off = ((unsigned long) d) % sizeof(u_int32_t);
+
+  if (off) {
+    if ((m->m_flags & M_EXT) == 0) {
+      bcopy(d, d - off, m->m_len);   /* ALIGN! (with costly data copy...) */
+      d -= off;
+      m->m_data = (caddr_t)d;
+    } else {
+      /* can't write to an M_EXT mbuf since it may be shared */
+      MGET(new, M_DONTWAIT, MT_DATA);
+      if (!new) {
+        EN_COUNT(sc->mfixfail);
+        return(0);
+      }
+      MCLGET(new, M_DONTWAIT);
+      if ((new->m_flags & M_EXT) == 0) {
+        m_free(new);
+        EN_COUNT(sc->mfixfail);
+        return(0);
+      }
+      bcopy(d, new->m_data, m->m_len);	/* ALIGN! (with costly data copy...) */
+      new->m_len = m->m_len;
+      new->m_next = m->m_next;
+      if (prev)
+        prev->m_next = new;
+      m_free(m);
+      *mm = m = new;	/* note: 'd' now invalid */
+    }
+  }
+
+  off = m->m_len % sizeof(u_int32_t);
+  if (off == 0)
+    return(1);
+
+  d = mtod(m, u_char *) + m->m_len;
+  off = sizeof(u_int32_t) - off;
+  
+  nxt = m->m_next;
+  while (off--) {
+    for ( ; nxt != NULL && nxt->m_len == 0 ; nxt = nxt->m_next)
+      /*null*/;
+    if (nxt == NULL) {		/* out of data, zero fill */
+      *d++ = 0;
+      continue;			/* next "off" */
+    }
+    cp = mtod(nxt, u_char *);
+    *d++ = *cp++;
+    m->m_len++;
+    nxt->m_len--; 
+    nxt->m_data = (caddr_t)cp;
+  }
+  return(1);
+}
+
+#else /* __FreeBSD__ */
+
 STATIC int en_makeexclusive(struct en_softc *, struct mbuf **, struct mbuf *);
 
 STATIC int en_makeexclusive(sc, mm, prev)
@@ -1652,7 +2025,11 @@
 	    return (0);
 	}
 	
+#if defined(__FreeBSD__)
 	if (mclrefcnt[mtocl(m->m_ext.ext_buf)] > 1) {
+#else
+	if (m->m_ext.ext_nextref != m) {
+#endif
 	    /* make a real copy of the M_EXT mbuf since it is shared */
 	    MGET(new, M_DONTWAIT, MT_DATA);
 	    if (!new) {
@@ -1761,6 +2138,7 @@
   return(1);
 }
 
+#endif /* __FreeBSD__ */
 
 /*
  * en_txdma: start trasmit DMA, if possible
@@ -1929,7 +2307,27 @@
   }
 
   en_txlaunch(sc, chan, &launch);
-  
+
+#if NBPFILTER > 0
+  if (sc->enif.if_bpf) {
+      /*
+       * adjust the top of the mbuf to skip the pseudo atm header
+       * (and TBD, if present) before passing the packet to bpf,
+       * restore it afterwards.
+       */
+      int size = sizeof(struct atm_pseudohdr);
+      if (launch.atm_flags & EN_OBHDR)
+	  size += MID_TBD_SIZE;
+
+      launch.t->m_data += size;
+      launch.t->m_len -= size;
+
+      BPF_MTAP(&sc->enif, launch.t);
+
+      launch.t->m_data -= size;
+      launch.t->m_len += size;
+  }
+#endif /* NBPFILTER > 0 */
   /*
    * do some housekeeping and get the next packet
    */
@@ -2490,6 +2888,11 @@
 		sc->sc_dev.dv_xname, slot, sc->rxslot[slot].atm_vci, m,
 		EN_DQ_LEN(drq), sc->rxslot[slot].rxhand);
 #endif
+#if NBPFILTER > 0
+	  if (sc->enif.if_bpf)
+	    BPF_MTAP(&sc->enif, m);
+#endif /* NBPFILTER > 0 */
+
 	  sc->enif.if_ipackets++;
 
 	  atm_input(&sc->enif, &ah, m, sc->rxslot[slot].rxhand);
@@ -2575,6 +2978,12 @@
   sc->vtrash += MID_VTRASH(reg);
 #endif
 
+#ifdef ALTQ
+  /* when altq is used, better try to dequeue the next packet. */
+  if (ALTQ_IS_ON(&sc->enif) && kick)
+    en_start(&sc->enif);
+#endif
+
   EN_INTR_RET(1); /* for us */
 }
 
@@ -2688,6 +3097,9 @@
       mlen = 0;			/* we've got trash */
       fill = MID_RBD_SIZE;
       EN_COUNT(sc->ttrash);
+#ifdef EN_DEBUG
+      printf("RX overflow lost %d cells!\n", MID_RBD_CNT(rbd));
+#endif
     } else if (!aal5) {
       mlen = MID_RBD_SIZE + MID_CHDR_SIZE + MID_ATMDATASZ; /* 1 cell (ick!) */
       fill = 0;
@@ -2699,11 +3111,11 @@
       pdu = EN_READ(sc, pdu);	/* get PDU in correct byte order */
       fill = tlen - MID_RBD_SIZE - MID_PDU_LEN(pdu);
       if (fill < 0 || (rbd & MID_RBD_CRCERR) != 0) {
-        printf("%s: invalid AAL5 PDU length or CRC detected, dropping frame\n", 
-						sc->sc_dev.dv_xname);
-        printf("%s: got %d cells (%d bytes), AAL5 len is %d bytes (pdu=0x%x) CRCERR=%d\n",
-	  sc->sc_dev.dv_xname, MID_RBD_CNT(rbd), tlen - MID_RBD_SIZE,
-		MID_PDU_LEN(pdu), pdu, (rbd & MID_RBD_CRCERR)?1:0);
+        printf("%s: %s, dropping frame\n", sc->sc_dev.dv_xname,
+	    (rbd & MID_RBD_CRCERR) ? "CRC error" : "invalid AAL5 PDU length");
+        printf("%s: got %d cells (%d bytes), AAL5 len is %d bytes (pdu=0x%x)\n",
+ 	  sc->sc_dev.dv_xname, MID_RBD_CNT(rbd), tlen - MID_RBD_SIZE,
+ 		MID_PDU_LEN(pdu), pdu);
 	fill = tlen;
       }
       mlen = tlen - fill;
@@ -3162,7 +3574,6 @@
         printf("0x%x ", sc->swslist[cnt]);
       printf("\n");
     }
-
   }
   return(0);
 }
@@ -3199,5 +3610,311 @@
 }
 #endif
 
+#ifdef ATM_PVCEXT
+/*
+ * ATM PVC extention: shaper control and pvc shadow interfaces
+ */
+
+/* txspeed conversion derived from linux drivers/atm/eni.c
+   by Werner Almesberger, EPFL LRC */
+static const int pre_div[] = { 4,16,128,2048 };
+
+static int en_pcr2txspeed(pcr)
+	int pcr;
+{
+	int pre, res, div;
+
+	if (pcr == 0)
+		pre = res = 0;	/* max rate */
+	else {
+		for (pre = 0; pre < 3; pre++)
+			if (25000000/pre_div[pre]/64 <= pcr)
+				break;
+		div = pre_div[pre]*(pcr);
+		res = 25000000/div-1;
+		if (res < 0)
+			res = 0;
+		if (res > 63)
+			res = 63;
+	}
+	return ((pre << 6) + res);
+}
+
+static int en_txspeed2pcr(txspeed)
+	int txspeed;
+{
+	int pre, res, pcr;
+
+	pre = (txspeed >> 6) & 0x3;
+	res = txspeed & 0x3f;
+	pcr = 25000000 / pre_div[pre] / (res+1);
+	return (pcr);
+}
+
+/*
+ * en_txctl selects a hardware transmit channel and sets the shaper value.
+ * en_txctl should be called after enabling the vc by en_rxctl
+ * since it assumes a transmit channel is already assigned by en_rxctl
+ * to the vc.
+ */
+static int en_txctl(sc, vci, joint_vci, pcr)
+	struct en_softc *sc;
+	int vci;
+	int joint_vci;
+	int pcr;
+{
+	int txspeed, txchan, c, s;
+
+	if (pcr)
+		txspeed = en_pcr2txspeed(pcr);
+
+	s = splimp();
+	txchan = sc->txvc2slot[vci];
+	sc->txslot[txchan].nref--;
+    
+	/* select a slot */
+	if (joint_vci != 0)
+		/* use the same channel */
+		txchan = sc->txvc2slot[joint_vci];
+	if (pcr == 0)
+		txchan = 0;
+	else {
+		for (c = 1, txchan = 1; c < EN_NTX; c++) {
+			if (sc->txslot[c].nref < sc->txslot[txchan].nref)
+				txchan = c;
+			if (sc->txslot[txchan].nref == 0)
+				break;
+		}
+	}
+	sc->txvc2slot[vci] = txchan;
+	sc->txslot[txchan].nref++;
+
+	/* set the shaper parameter */
+	if (pcr)
+		sc->txspeed[vci] = (u_int8_t)txspeed;
+	else
+		sc->txspeed[vci] = 0;
+
+	splx(s);
+#ifdef EN_DEBUG
+	printf("VCI:%d PCR set to %d, tx channel %d\n", vci, pcr, txchan);
+	if (joint_vci != 0)
+		printf("  slot shared with VCI:%d\n", joint_vci);
+#endif
+	return (0);
+}
+
+static int en_pvctx(sc, pvcreq)
+	struct en_softc *sc;
+	struct pvctxreq *pvcreq;
+{
+	struct ifnet *ifp;
+	struct atm_pseudoioctl api;
+	struct atm_pseudohdr *pvc_aph, *pvc_joint;
+	int vci, joint_vci, pcr;
+	int error = 0;
+
+	/* check vpi:vci values */
+	pvc_aph = &pvcreq->pvc_aph;
+	pvc_joint = &pvcreq->pvc_joint;
+
+	vci = ATM_PH_VCI(pvc_aph);
+	joint_vci = ATM_PH_VCI(pvc_joint);
+	pcr = pvcreq->pvc_pcr;
+
+	if (ATM_PH_VPI(pvc_aph) != 0 || vci >= MID_N_VC ||
+	    ATM_PH_VPI(pvc_joint) != 0 || joint_vci >= MID_N_VC)
+		return (EADDRNOTAVAIL);
+
+	if ((ifp = ifunit(pvcreq->pvc_ifname)) == NULL)
+		return (ENXIO);
+
+	if (pcr < 0) {
+		/* negative pcr means disable the vc. */
+		if (sc->rxvc2slot[vci] == RX_NONE)
+			/* already disabled */
+			return 0;
+
+		ATM_PH_FLAGS(&api.aph) = 0;
+		ATM_PH_VPI(&api.aph) = 0;
+		ATM_PH_SETVCI(&api.aph, vci);
+		api.rxhand = NULL;
+
+		error = en_rxctl(sc, &api, 0);
+		
+		if (error == 0 && &sc->enif != ifp) {
+			/* clear vc info of shadow interface */
+			ATM_PH_SETVCI(&api.aph, 0);
+			pvc_setaph(ifp, &api.aph);
+		}
+		return (error);
+	}
+
+	if (&sc->enif == ifp) {
+		/* called for an en interface */
+		if (sc->rxvc2slot[vci] == RX_NONE) {
+			/* vc is not active */
+			printf("%s%d: en_pvctx: rx not active! vci=%d\n",
+			       ifp->if_name, ifp->if_unit, vci);
+			return (EINVAL);
+		}
+	}
+	else {
+		/* called for a shadow interface */
+		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
+			printf("en_pvctx: if %s is not point-to-point!\n",
+			       pvcreq->pvc_ifname);
+			return (EINVAL);
+		}
+    		sprintf(pvcreq->pvc_ifname, "%s%d",
+			sc->enif.if_name, sc->enif.if_unit);
+		
+		ATM_PH_FLAGS(&api.aph) = ATM_PH_PVCSIF |
+			(ATM_PH_FLAGS(pvc_aph) & (ATM_PH_AAL5|ATM_PH_LLCSNAP));
+		ATM_PH_VPI(&api.aph) = 0;
+		ATM_PH_SETVCI(&api.aph, vci);
+		api.rxhand = ifp;
+		pvc_setaph(ifp, &api.aph);
+
+		if (sc->rxvc2slot[vci] == RX_NONE) {
+			/* vc is not active, enable rx */
+			error = en_rxctl(sc, &api, 1);
+			if (error)
+				return error;
+		}
+		else {
+			/* vc is already active, update aph in softc */
+			sc->rxslot[sc->rxvc2slot[vci]].atm_flags =
+				ATM_PH_FLAGS(&api.aph);
+		}
+
+	}
+
+	error = en_txctl(sc, vci, joint_vci, pcr);
+
+	if (error == 0) {
+		if (sc->txspeed[vci] != 0)
+			pvcreq->pvc_pcr = en_txspeed2pcr(sc->txspeed[vci]);
+		else
+			pvcreq->pvc_pcr = 0;
+	}
+
+	return error;
+}
+
+static int en_pvctxget(sc, pvcreq)
+	struct en_softc *sc;
+	struct pvctxreq *pvcreq;
+{
+	struct atm_pseudohdr *pvc_aph;
+	int vci, slot;
+
+	pvc_aph = &pvcreq->pvc_aph;
+	vci = ATM_PH_VCI(pvc_aph);
+
+	if ((slot = sc->rxvc2slot[vci]) == RX_NONE) {
+		/* vc is not active */
+		ATM_PH_FLAGS(pvc_aph) = 0;
+		ATM_PH_VPI(pvc_aph) = 0;
+		ATM_PH_SETVCI(pvc_aph, vci);
+		pvcreq->pvc_pcr = -1;
+	}
+	else {
+		ATM_PH_FLAGS(pvc_aph) = sc->rxslot[slot].atm_flags;
+		ATM_PH_VPI(pvc_aph) = 0;
+		ATM_PH_SETVCI(pvc_aph, vci);
+		if (sc->txspeed[vci])
+			pvcreq->pvc_pcr = en_txspeed2pcr(sc->txspeed[vci]);
+		else
+			pvcreq->pvc_pcr = 0;
+	}
+
+	return (0);
+}
+
+#endif /* ATM_PVCEXT */
+
+#if defined(ALTQ) && defined(AFMAP)
+
+static int en_flowmap_add(sc, fmap)
+	struct en_softc *sc;
+	struct atm_flowmap *fmap;
+{
+	struct afm *afm;
+	struct atm_pseudoioctl api;
+	int error = 0;
+
+	afm = afm_lookup(&sc->enif, fmap->af_vpi, fmap->af_vci);
+	if (afm)
+		/* already in use */
+		return (EEXIST);
+
+	if ((error = afm_add(&sc->enif, fmap)))
+		return error;
+
+	/* enable rx */
+	ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5 | ATM_PH_LLCSNAP;
+	ATM_PH_VPI(&api.aph) = fmap->af_vpi;
+	ATM_PH_SETVCI(&api.aph, fmap->af_vci);
+	api.rxhand = NULL;
+	error = en_rxctl(sc, &api, 1);
+	if (error)
+		return error;
+	error = en_txctl(sc, fmap->af_vci, 0, fmap->af_pcr);
+	return error;
+}
+
+static int en_flowmap_delete(sc, vpi, vci)
+	struct en_softc *sc;
+	int vpi, vci;
+{
+	struct afm *afm;
+	struct atm_pseudoioctl api;
+	int txchan, error = 0;
+
+	afm = afm_lookup(&sc->enif, vpi, vci);
+	if (afm == NULL)
+		return (ENOENT);
+    
+	afm_remove(afm);
+
+	/* disable rx */
+	ATM_PH_FLAGS(&api.aph) = 0;
+	ATM_PH_VPI(&api.aph) = vpi;
+	ATM_PH_SETVCI(&api.aph, vci);
+	api.rxhand = NULL;
+	error = en_rxctl(sc, &api, 0);
+
+	return error;
+}
+
+static int en_flowmap_get(sc, fmap)
+	struct en_softc *sc;
+	struct atm_flowmap *fmap;
+{
+	struct afm *afm;
+	struct atm_pseudoioctl api;
+	int error = 0;
+
+	afm = afm_lookup(&sc->enif, fmap->af_vpi, fmap->af_vci);
+	if (afm == NULL)
+		return (ENOENT);
+
+	bcopy(&afm->afm_flowinfo, &fmap->af_flowinfo, sizeof(struct flowinfo));
+
+	/* get pcr value */
+	if (sc->txspeed[fmap->af_vci] != 0)
+		fmap->af_pcr = en_txspeed2pcr(sc->txspeed[fmap->af_vci]);
+	else
+		fmap->af_pcr = 0;
+
+	/* get stats */
+	fmap->afs_packets = afm->afms_packets;
+	fmap->afs_bytes = afm->afms_bytes;
+
+	return error;
+}
+
+#endif /* ALTQ && AFMAP */
 
 #endif /* NEN > 0 || !defined(__FreeBSD__) */
diff -uN src-current/sys/dev/en/midwayreg.h src-current-ipv6/sys/dev/en/midwayreg.h
--- src-current/sys/dev/en/midwayreg.h
+++ src-current-ipv6/sys/dev/en/midwayreg.h
@@ -68,6 +68,7 @@
 /*
  * prom & phy: not defined here
  */
+#define MID_ADPMACOFF	0xffc0		/* mac address offset (adaptec only) */
 
 /*
  * midway regs  (byte offsets from en_base)
diff -uN src-current/sys/dev/en/midwayvar.h src-current-ipv6/sys/dev/en/midwayvar.h
--- src-current/sys/dev/en/midwayvar.h
+++ src-current-ipv6/sys/dev/en/midwayvar.h
@@ -90,7 +90,6 @@
 
 #endif
 
-
 /*
  * softc
  */
@@ -99,6 +98,10 @@
   /* bsd glue */
   struct device sc_dev;		/* system device */
   struct ifnet enif;		/* network ifnet handle */
+
+  /* ESI/MAC address (must be just after the ifnet structure */
+  u_int8_t macaddr[6];		/* End System Identifier == MAC address */
+  u_int8_t pad[2];
 
   /* bus glue */
   bus_space_tag_t en_memt;	/* for EN_READ/EN_WRITE */
diff -uN src-current/sys/dev/pdq/pdq_ifsubr.c src-current-ipv6/sys/dev/pdq/pdq_ifsubr.c
--- src-current/sys/dev/pdq/pdq_ifsubr.c
+++ src-current-ipv6/sys/dev/pdq/pdq_ifsubr.c
@@ -54,7 +54,13 @@
 #ifdef INET
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
+#ifdef INET6
+#include <netinet/if_ether6.h>
+#include <netinet/if_ndp6.h>
 #endif
+#endif
+#endif
+#if defined(__FreeBSD__)
 #include <netinet/if_fddi.h>
 #else
 #include <net/if_fddi.h>
@@ -133,6 +139,11 @@
 
     ifp->if_flags &= ~IFF_OACTIVE;
     ifp->if_timer = 0;
+#ifdef ALTQ
+    if (ALTQ_IS_ON(ifp))
+	(void)(*ifp->if_altqdequeue)(ifp, ALTDQ_FLUSH);
+    else
+#endif
     for (;;) {
 	struct mbuf *m;
 	IF_DEQUEUE(&ifp->if_snd, m);
@@ -162,15 +173,29 @@
 	return;
     }
     for (;; tx = 1) {
-	IF_DEQUEUE(ifq, m);
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp))
+	    m = (*ifp->if_altqdequeue)(ifp, ALTDQ_PEEK);
+	else
+#endif
+	m = ifp->if_snd.ifq_head;
 	if (m == NULL)
 	    break;
 
 	if (pdq_queue_transmit_data(sc->sc_pdq, m) == PDQ_FALSE) {
 	    ifp->if_flags |= IFF_OACTIVE;
-	    IF_PREPEND(ifq, m);
 	    break;
 	}
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp)) {
+	    struct mbuf *tmp = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+
+	    if (tmp != m)
+		panic("pdqstart:  different mbuf dequeued!");
+	}
+	else
+#endif
+	IF_DEQUEUE(ifq, m);
     }
     if (tx)
 	PDQ_DO_TYPE2_PRODUCER(sc->sc_pdq);
@@ -208,6 +233,17 @@
 {
     pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
     sc->sc_if.if_flags &= ~IFF_OACTIVE;
+#ifdef ALTQ
+    if (ALTQ_IS_ON(&sc->sc_if)) {
+	if ((*sc->sc_if.if_altqdequeue)(&sc->sc_if, ALTDQ_PEEK) != NULL) {
+	    sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
+	    pdq_ifstart(&sc->sc_if);
+	} else {
+	    sc->sc_if.if_timer = 0;
+	}
+    }
+    else
+#endif
     if (sc->sc_if.if_snd.ifq_head != NULL) {
 	sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
 	pdq_ifstart(&sc->sc_if);
@@ -278,6 +314,14 @@
 		}
 #endif /* INET */
 
+#if defined(INET6)
+		case AF_INET6: {
+		    pdq_ifinit(sc);
+		    ndp6_ifinit(ifp, ifa);
+		    break;
+		}
+#endif /* INET6 */
+
 #if defined(NS)
 		/* This magic copied from if_is.c; I don't use XNS,
 		 * so I have no way of telling if this actually
@@ -381,6 +425,9 @@
     ifp->if_start = pdq_ifstart;
 #warning "Implement fddi_resolvemulti!"
 /*    ifp->if_resolvemulti = ether_resolvemulti; XXX */
+#ifdef ALTQ
+    ifp->if_altqflags |= ALTQF_READY;
+#endif
   
     if_attach(ifp);
     fddi_ifattach(ifp);
diff -uN src-current/sys/dev/vx/if_vx.c src-current-ipv6/sys/dev/vx/if_vx.c
--- src-current/sys/dev/vx/if_vx.c
+++ src-current-ipv6/sys/dev/vx/if_vx.c
@@ -62,6 +62,9 @@
 #define NVX 4
 #endif
 
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
 #include "bpfilter.h"
 
 #include <sys/param.h>
@@ -71,6 +74,10 @@
 #include <sys/mbuf.h>
 #include <sys/socket.h>
 
+#ifdef INET
+#include <netinet/in.h>
+#endif
+
 #include <net/if.h>
 
 #include <net/ethernet.h>
@@ -213,6 +220,9 @@
     ifp->if_init = vxinit;
     ifp->if_watchdog = vxwatchdog;
     ifp->if_softc = sc;
+#ifdef ALTQ
+    ifp->if_altqflags |= ALTQF_READY;
+#endif
 
     if_attach(ifp);
     ether_ifattach(ifp);
@@ -454,6 +464,11 @@
 
 startagain:
     /* Sneak a peek at the next packet */
+#ifdef ALTQ
+    if (ALTQ_IS_ON(ifp))
+	m0 = (*ifp->if_altqdequeue)(ifp, ALTDQ_PEEK);
+    else
+#endif
     m0 = ifp->if_snd.ifq_head;
     if (m0 == 0) {
 	return;
@@ -473,6 +488,14 @@
     if (len + pad > ETHER_MAX_LEN) {
 	/* packet is obviously too large: toss it */
 	++ifp->if_oerrors;
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp)) {
+	    struct mbuf *tmp = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+	    if (tmp != m0)
+		panic("vxstart: different mbuf dequeued!");
+	}
+	else
+#endif
 	IF_DEQUEUE(&ifp->if_snd, m0);
 	m_freem(m0);
 	goto readcheck;
@@ -488,6 +511,14 @@
 	}
     }
     outw(BASE + VX_COMMAND, SET_TX_AVAIL_THRESH | (8188 >> 2));
+#ifdef ALTQ
+    if (ALTQ_IS_ON(ifp)) {
+	struct mbuf *tmp = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+	if (tmp != m0)
+	    panic("vxstart: different mbuf dequeued!");
+    }
+    else
+#endif
     IF_DEQUEUE(&ifp->if_snd, m0);
     if (m0 == 0) {		/* not really needed */
 	return;
@@ -875,10 +906,10 @@
         len = min(totlen, len);
         if (len > 3)
             insl(BASE + VX_W1_RX_PIO_RD_1, mtod(m, u_int32_t *), len / 4);
-	if (len & 3) {
-	    insb(BASE + VX_W1_RX_PIO_RD_1, mtod(m, u_int8_t *) + (len & ~3),
-		len & 3);
-	}
+        if (len & 3) {
+            insb(BASE + VX_W1_RX_PIO_RD_1, mtod(m, u_int8_t *) + (len & ~3),
+                len & 3);
+        }
         m->m_len = len;
         totlen -= len;
         *mp = m;
diff -uN src-current/sys/i386/conf/LINT src-current-ipv6/sys/i386/conf/LINT
--- src-current/sys/i386/conf/LINT
+++ src-current-ipv6/sys/i386/conf/LINT
@@ -434,6 +434,60 @@
 #options	IPFILTER_LKM		#kernel support for ip_fil.o LKM
 options		TCPDEBUG
 
+#
+# IPv6 options and pseudo-device
+#
+options		"INET6"			# IPv6 (don't forget the quotes)
+options		MULTI_HOMED		# multiple interfaces with ND
+
+# UNTESTED options (ie don't use)
+
+options		"MROUTING6"		# multicast routing (quotes!)
+options		"IP6FIREWALL"		# filter/accounting
+
+# IPv6 over IPv4 tunnels
+
+pseudo-device	sit	2		# as many as physical interfaces
+pseudo-device	cti	2		# configured mode
+
+# link-local stuff for multihomed nodes
+
+pseudo-device	llink
+
+# IPv6 over IPv6 (UNTESTED)
+
+pseudo-device	tug	2
+
+# ATM (Chuck Cranor)
+#
+# The `en' device provides support for Efficient Networks (ENI)
+# ENI-155 PCI midway cards, and the Adaptec 155Mbps PCI ATM cards (ANA-59x0).
+#
+# ifatm pseudo-device provides generic atm functions and
+# is required for atm devices.
+# NATM enables the netnatm protocol family that can be used to
+# bypass TCP/IP.
+
+#options		NATM			# native ATM support
+#pseudo-device	ifatm			# same than ether !
+
+# ATM (HARP)
+#
+#options		ATM			# HARP ATM support
+#device		hea0			# HARP Efficient ATM device support
+#device		hfa0			# HARP Fore ATM device support
+
+# ALTQ
+
+options		ALTQ			#alternate queueing
+options		CBQ			#class based queueing
+options		WFQ			#weighted fair queueing
+options		AFMAP			#atm flow mapping
+options		FIFOQ			#fifo queueing
+options		RED			#random early detection
+options		ALTQ_ACCOUNT		#altq accounting
+options		ALTQ_ECN		#ecn extention to tcp
+
 
 #####################################################################
 # FILESYSTEM OPTIONS
@@ -1033,10 +1087,10 @@
 # for more details, please read the original documents at 
 # http://www.ccrc.wustl.edu/pub/chuck/bsdatm/wucs.html
 #
-pseudo-device	atm
-device en0
-device en1
-options		NATM			#native ATM
+#pseudo-device	atm
+#device en0
+#device en1
+#options		NATM			#native ATM
 
 #
 # Audio drivers: `snd', `sb', `pas', `gus', `pca'
@@ -1367,6 +1421,10 @@
 device		meteor0
 device		bktr0
 
+# ENI ATM driver
+
+device		en0
+device		en1
 
 #
 # PCCARD/PCMCIA
diff -uN src-current/sys/i386/conf/majors.i386 src-current-ipv6/sys/i386/conf/majors.i386
--- src-current/sys/i386/conf/majors.i386
+++ src-current-ipv6/sys/i386/conf/majors.i386
@@ -1,4 +1,4 @@
-$Id: majors.i386,v 1.39 1998/04/22 05:10:51 msmith Exp $
+$Id: majors.i386,v 1.42 1998/05/13 12:38:26 jkh Exp $
 
 Hopefully, this list will one day be obsoleted by DEVFS, but for now
 this is the current allocation of device major numbers.
@@ -140,3 +140,5 @@
 95	gd		Geometry disk
 96	altq		alternate queueing (including cbq, red, wfq)
 97	myx		Mylex RAID controller (ulf@alameda.net)
+98	loe		Loopback pseudo-ethernet (sbabkin@dcn.att.com)
+99	ct		Cronyx/Tau serial adaptor
diff -uN src-current/sys/i386/isa/if_ie.c src-current-ipv6/sys/i386/isa/if_ie.c
--- src-current/sys/i386/isa/if_ie.c
+++ src-current-ipv6/sys/i386/isa/if_ie.c
@@ -130,6 +130,10 @@
 #ifdef INET
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
+#ifdef INET6
+#include <netinet/if_ether6.h>
+#include <netinet/if_ndp6.h>
+#endif
 #endif
 
 #ifdef IPX
@@ -842,6 +846,9 @@
 #if NBPFILTER > 0
 	bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
 #endif
+#ifdef ALTQ
+	ifp->if_altqflags |= ALTQF_READY;
+#endif
 
 	if_attach(ifp);
 	ether_ifattach(ifp);
@@ -1559,6 +1566,13 @@
 		return;
 
 	do {
+#ifdef ALTQ
+		if (ALTQ_IS_ON(ifp)) {
+			m = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+		}
+		else
+#endif
+
 		IF_DEQUEUE(&ie->arpcom.ac_if.if_snd, m);
 		if (!m)
 			break;
@@ -2271,6 +2285,13 @@
 			arp_ifinit((struct arpcom *) ifp, ifa);
 			break;
 #endif				/* INET */
+
+#ifdef INET6
+		case AF_INET6:
+			ieinit(ifp->if_unit);
+			ndp6_ifinit(ifp, ifa);
+			break;
+#endif /* INET6 */
 
 #ifdef IPX
 			/*
diff -uN src-current/sys/i386/isa/if_zp.c src-current-ipv6/sys/i386/isa/if_zp.c
--- src-current/sys/i386/isa/if_zp.c
+++ src-current-ipv6/sys/i386/isa/if_zp.c
@@ -99,6 +99,9 @@
  * Very small patch for IBM Ethernet PCMCIA Card II and IBM ThinkPad230Cs.
  *			ETO, Toshihisa <eto@osl.fujitsu.co.jp>
  */
+/*
+ * IPv6 patches tested by Alain Durand & Jean-Luc Richier of IMAG.
+ */
 
 /* XXX don't mix different PCCARD support code. */
 #include "card.h"
@@ -133,6 +136,10 @@
 #ifdef INET
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
+#ifdef INET6
+#include <netinet/if_ether6.h>
+#include <netinet/if_ndp6.h>
+#endif
 #endif
 
 #ifdef IPX
@@ -551,7 +558,7 @@
 
 	ifp->if_softc = sc;
 	ifp->if_mtu = ETHERMTU;
-	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_unit = isa_dev->id_unit;
 	ifp->if_name = "zp";
 	ifp->if_output = ether_output;
@@ -560,6 +567,9 @@
 	ifp->if_watchdog = zpwatchdog;
 	/* Select connector according to board setting. */
 	ifp->if_flags |= IFF_LINK0;
+#ifdef ALTQ
+	ifp->if_altqflags |= ALTQF_READY;
+#endif
 
 	if_attach(ifp);
 	ether_ifattach(ifp);
@@ -699,6 +709,11 @@
 startagain:
 
 	/* Sneak a peek at the next packet */
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp))
+		m = (*ifp->if_altqdequeue)(ifp, ALTDQ_PEEK);
+	else
+#endif
 	m = sc->arpcom.ac_if.if_snd.ifq_head;
 	if (m == 0) {
 		splx(s);
@@ -715,6 +730,14 @@
 	if (len + pad > ETHER_MAX_LEN) {
 		/* packet is obviously too large: toss it */
 		++sc->arpcom.ac_if.if_oerrors;
+#ifdef ALTQ
+		if (ALTQ_IS_ON(ifp)) {
+			m = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+			if (m != top)
+				panic("zpstart: different mbuf dequeued!");
+		}
+		else
+#endif
 		IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
 		m_freem(m);
 		goto readcheck;
@@ -727,6 +750,14 @@
 
 		return;
 	}
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp)) {
+		m = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+		if (m != top)
+			panic("zpstart: different mbuf dequeued!");
+	}
+	else
+#endif
 	IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
 
 	if (m == 0) {		/* not really needed */
@@ -989,6 +1020,16 @@
 		}
 	}
 #endif
+
+	/* Check extra multicast packets */
+	if ((eh->ether_dhost[0] & 1) &&
+	    bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
+		 sizeof(etherbroadcastaddr)) &&
+	    !ether_matchmulti(&sc->arpcom, eh->ether_dhost)) {
+		m_freem(top);
+		return;
+	}
+
 	m_adj(top, sizeof(struct ether_header));
 	ether_input(&sc->arpcom.ac_if, eh, top);
 	return;
@@ -1025,6 +1066,12 @@
 			arp_ifinit((struct arpcom *) ifp, ifa);
 			break;
 #endif
+#ifdef INET6
+		case AF_INET6:
+			zpinit(ifp->if_unit);
+			ndp6_ifinit(ifp, ifa);
+			break;
+#endif
 #ifdef IPX
 		case AF_IPX:
 			{
@@ -1074,6 +1121,24 @@
 			break;
 		}
 		zpinit(ifp->if_unit);
+		break;
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		/* 
+		 * Update multicast listener list
+		 */
+		if (cmd == SIOCADDMULTI)
+			error = ether_addmulti((struct ifreq *) data,
+					       &sc->arpcom);
+		else 
+			error = ether_delmulti((struct ifreq *) data,
+					       &sc->arpcom);
+		if (error == ENETRESET) {
+			/* reset hard filter?? */
+			/* oh god! it is a 3Com chipset... */
+			/* zpinit() */;
+			error = 0;
+		}
 		break;
 	default:
 		error = EINVAL;
diff -uN src-current/sys/i386/isa/if_ar.c src-current-ipv6/sys/i386/isa/if_ar.c
--- src-current/sys/i386/isa/if_ar.c
+++ src-current-ipv6/sys/i386/isa/if_ar.c
@@ -345,6 +345,9 @@
 		ifp->if_ioctl = arioctl;
 		ifp->if_start = arstart;
 		ifp->if_watchdog = arwatchdog;
+#ifdef ALTQ
+		ifp->if_altqflags |= ALTQF_READY;
+#endif
 
 		sc->ifsppp.pp_flags = PP_KEEPALIVE;
 
diff -uN src-current/sys/i386/isa/if_cx.c src-current-ipv6/sys/i386/isa/if_cx.c
--- src-current/sys/i386/isa/if_cx.c
+++ src-current-ipv6/sys/i386/isa/if_cx.c
@@ -278,6 +278,9 @@
 			c->ifp->if_ioctl = cxsioctl;
 			c->ifp->if_start = (start_func_t) cxstart;
 			c->ifp->if_watchdog = (watchdog_func_t) cxwatchdog;
+#ifdef ALTQ
+			c->ifp->if_altqflags |= ALTQF_READY;
+#endif
 			/* Init routine is never called by upper level? */
 			sppp_attach (c->ifp);
 			if_attach (c->ifp);
diff -uN src-current/sys/i386/isa/if_ed.c src-current-ipv6/sys/i386/isa/if_ed.c
--- src-current/sys/i386/isa/if_ed.c
+++ src-current-ipv6/sys/i386/isa/if_ed.c
@@ -39,6 +39,8 @@
 
 #include "ed.h"
 #include "bpfilter.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
 #include "pnp.h"
 
 #ifndef EXTRA_ED
@@ -60,6 +62,10 @@
 #include <sys/socket.h>
 #include <sys/syslog.h>
 
+#ifdef INET
+#include <netinet/in.h>
+#endif
+
 #include <net/ethernet.h>
 #include <net/if.h>
 #include <net/if_arp.h>
@@ -1693,6 +1699,9 @@
 			ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX |
 			    IFF_MULTICAST);
 
+#ifdef ALTQ
+		ifp->if_altqflags |= ALTQF_READY;
+#endif
 		/*
 		 * Attach the interface
 		 */
@@ -2079,6 +2088,12 @@
 		ifp->if_flags |= IFF_OACTIVE;
 		return;
 	}
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp)) {
+	    m = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+	}
+	else
+#endif
 	IF_DEQUEUE(&ifp->if_snd, m);
 	if (m == 0) {
 
@@ -3471,6 +3486,7 @@
 	dev->id_iobase = d.port[0];
 	dev->id_irq = (1 << d.irq[0]);
 	dev->id_intr = edintr;
+	dev->id_ri_flags = RI_FAST;
 	dev->id_drq = -1;
 
 	if (dev->id_driver == NULL) {
diff -uN src-current/sys/i386/isa/if_ep.c src-current-ipv6/sys/i386/isa/if_ep.c
--- src-current/sys/i386/isa/if_ep.c
+++ src-current-ipv6/sys/i386/isa/if_ep.c
@@ -82,6 +82,10 @@
 #ifdef INET
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
+#ifdef INET6
+#include <netinet/if_ether6.h>
+#include <netinet/if_ndp6.h>
+#endif
 #endif
 
 #ifdef IPX
@@ -133,6 +137,7 @@
 static	struct ep_softc* ep_softc[NEP];
 static	int ep_current_tag = EP_LAST_TAG + 1;
 static	char *ep_conn_type[] = {"UTP", "AUI", "???", "BNC"};
+static	u_short ep_index[NEP];
 
 #define ep_ftst(f) (sc->stat&(f))
 #define ep_fset(f) (sc->stat|=(f))
@@ -477,6 +482,17 @@
     struct ep_board *epb;
     u_short k;
 
+#if NCRD > 0
+    static int ep_pccard_unit = 0;
+    extern int if_index;
+
+    pccard_add_driver(&ep_info);
+    if (ep_pccard_unit + ep_unit > NEP)
+	panic("ep_isa_probe");
+    ep_index[ep_unit + ep_pccard_unit] = ++if_index;
+    ep_pccard_unit++;
+#endif /* NCRD > 0 */
+
     if ((epb = ep_look_for_board_at(is)) == 0)
 	return (0);
 
@@ -622,8 +638,12 @@
     ifp->if_start = epstart;
     ifp->if_ioctl = epioctl;
     ifp->if_watchdog = epwatchdog;
+#ifdef ALTQ
+    ifp->if_altqflags |= ALTQF_READY;
+#endif
 
     if (!attached) {
+	ifp->if_index = ep_index[ifp->if_unit];
 	if_attach(ifp);
 	ether_ifattach(ifp);
     }
@@ -817,6 +837,11 @@
     }
 startagain:
     /* Sneak a peek at the next packet */
+#ifdef ALTQ
+    if (ALTQ_IS_ON(ifp))
+	m = (*ifp->if_altqdequeue)(ifp, ALTDQ_PEEK);
+    else
+#endif
     m = ifp->if_snd.ifq_head;
     if (m == 0) {
 	splx(s);
@@ -835,6 +860,14 @@
     if (len + pad > ETHER_MAX_LEN) {
 	/* packet is obviously too large: toss it */
 	++ifp->if_oerrors;
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp)) {
+	    m = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+	    if (m != top)
+		panic("epstart: different mbuf dequeued!");
+	}
+	else
+#endif
 	IF_DEQUEUE(&ifp->if_snd, m);
 	m_freem(m);
 	goto readcheck;
@@ -849,6 +882,14 @@
 	    return;
 	}
     }
+#ifdef ALTQ
+    if (ALTQ_IS_ON(ifp)) {
+	m = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+	if (m != top)
+	    panic("epstart: different mbuf dequeued!");
+    }
+    else
+#endif
     IF_DEQUEUE(&ifp->if_snd, m);
 
     outw(BASE + EP_W1_TX_PIO_WR_1, len); 
@@ -1220,6 +1261,12 @@
 	    arp_ifinit((struct arpcom *)ifp, ifa);
 	    break;
 #endif
+#ifdef INET6
+	  case AF_INET6:
+	    epinit(sc);
+	    ndp6_ifinit(ifp, ifa);
+	    break;
+#endif
 #ifdef IPX
 	  case AF_IPX:
 	    {
@@ -1303,6 +1350,10 @@
 		break; 
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
+	    if (cmd == SIOCADDMULTI)
+		error = ether_addmulti(ifr, (struct arpcom *)ifp);
+	    else
+		error = ether_delmulti(ifr, (struct arpcom *)ifp);
 	    /*
 	     * The Etherlink III has no programmable multicast
 	     * filter.  We always initialize the card to be
diff -uN src-current/sys/i386/isa/if_fe.c src-current-ipv6/sys/i386/isa/if_fe.c
--- src-current/sys/i386/isa/if_fe.c
+++ src-current-ipv6/sys/i386/isa/if_fe.c
@@ -104,6 +104,7 @@
 #ifdef INET6
 /* IPv6 added by shin 96.2.6 */
 #include <netinet/if_ether6.h>
+#include <netinet/if_ndp6.h>
 #endif
 
 /* XNS code is not tested.  FIXME.  */
@@ -1481,6 +1482,10 @@
 		sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen;
 	}
 
+#ifdef ALTQ
+	sc->sc_if.if_altqflags |= ALTQF_READY;
+#endif
+
 #if FE_DEBUG >= 3
 	fe_dump( LOG_INFO, sc, "attach()" );
 #endif
@@ -1973,6 +1978,12 @@
 		/*
 		 * Get the next mbuf chain for a packet to send.
 		 */
+#ifdef ALTQ
+		if (ALTQ_IS_ON(ifp)) {
+			m = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+		}
+		else
+#endif
 		IF_DEQUEUE( &sc->sc_if.if_snd, m );
 		if ( m == NULL ) {
 			/* No more packets to send.  */
@@ -2525,7 +2536,7 @@
 		  case AF_INET6:
 			/* IPV6 added by shin 96.2.6 */
 			fe_init(sc->sc_unit);
-			ndp6_ifinit(&sc->arpcom, ifa);
+			ndp6_ifinit(ifp, ifa);
 			break;
 #endif
 #ifdef NS
diff -uN src-current/sys/i386/isa/if_le.c src-current-ipv6/sys/i386/isa/if_le.c
--- src-current/sys/i386/isa/if_le.c
+++ src-current-ipv6/sys/i386/isa/if_le.c
@@ -57,6 +57,10 @@
 #ifdef INET
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
+#ifdef INET6
+#include <netinet/if_ether6.h>
+#include <netinet/if_ndp6.h>
+#endif
 #endif
 
 #ifdef IPX
@@ -528,6 +532,13 @@
 		    break;
 		}
 #endif /* INET */
+#ifdef INET6
+		case AF_INET6: {
+		    (*sc->if_init)(ifp->if_unit);
+		    ndp6_ifinit(ifp, ifa);
+		    break;
+		}
+#endif /* INET6 */
 #ifdef IPX
 		/* This magic copied from if_is.c; I don't use XNS,
 		 * so I have no way of telling if this actually
diff -uN src-current/sys/i386/isa/if_lnc.c src-current-ipv6/sys/i386/isa/if_lnc.c
--- src-current/sys/i386/isa/if_lnc.c
+++ src-current-ipv6/sys/i386/isa/if_lnc.c
@@ -32,6 +32,7 @@
  *
  */
 
+#define LNC_MULTICAST
 /*
 #define LNC_MULTICAST
 #define DIAGNOSTIC
@@ -82,9 +83,14 @@
 
 #include <net/if.h>
 #include <net/if_types.h>
+#include <net/if_dl.h>
 #ifdef INET
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
+#ifdef INET6
+#include <netinet/if_ether6.h>
+#include <netinet/if_ndp6.h>
+#endif
 #endif
 
 #if NBPFILTER > 0
@@ -256,7 +262,9 @@
 	     ifma = ifma->ifma_link.le_next) {
 		if (ifma->ifma_addr->sa_family != AF_LINK)
 			continue;
-		index = ether_crc(enm->enm_addrlo) >> 26;
+		/* index = ether_crc(enm->enm_addrlo) >> 26; */
+		index = ether_crc(LLADDR((struct sockaddr_dl *)ifma->ifma_addr))
+			>> 26;
 		sc->init_block->ladrf[index >> 3] |= 1 << (index & 7);
 	}
 }
@@ -1217,6 +1225,9 @@
 	sc->arpcom.ac_if.if_type = IFT_ETHER;
 	sc->arpcom.ac_if.if_addrlen = ETHER_ADDR_LEN;
 	sc->arpcom.ac_if.if_hdrlen = ETHER_HDR_LEN;
+#ifdef ALTQ
+	sc->arpcom.ac_if.if_altqflags |= ALTQF_READY;
+#endif
 
 	/*
 	 * XXX -- should check return status of if_attach
@@ -1604,6 +1615,12 @@
 
 	do {
 
+#ifdef ALTQ
+		if (ALTQ_IS_ON(ifp)) {
+			head = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+		}
+		else
+#endif
 		IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, head);
 		if (!head)
 			return;
@@ -1767,6 +1784,12 @@
 		case AF_INET:
 			lnc_init(sc);
 			arp_ifinit((struct arpcom *)ifp, ifa);
+			break;
+#endif
+#ifdef INET6
+		case AF_INET6:
+			lnc_init(sc);
+			ndp6_ifinit(ifp, ifa);
 			break;
 #endif
 		default:
diff -uN src-current/sys/i386/isa/if_sr.c src-current-ipv6/sys/i386/isa/if_sr.c
--- src-current/sys/i386/isa/if_sr.c
+++ src-current-ipv6/sys/i386/isa/if_sr.c
@@ -823,6 +823,9 @@
 		ifp->if_ioctl = srioctl;
 		ifp->if_start = srstart;
 		ifp->if_watchdog = srwatchdog;
+#ifdef ALTQ
+		ifp->if_altqflags |= ALTQF_READY;
+#endif
 
 		printf("sr%d: Adapter %d, port %d.\n",
 		       sc->unit, hc->cunit, sc->subunit);
diff -uN src-current/sys/i386/isa/if_wl.c src-current-ipv6/sys/i386/isa/if_wl.c
--- src-current/sys/i386/isa/if_wl.c
+++ src-current-ipv6/sys/i386/isa/if_wl.c
@@ -212,6 +212,10 @@
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
 #include <netinet/if_ether.h>
+#ifdef INET6
+#include <netinet/if_ether6.h>
+#include <netinet/if_ndp6.h>
+#endif
 #endif
 
 #if NBPFILTER > 0
@@ -508,6 +512,9 @@
        ifp->if_done
        ifp->if_reset
        */
+#ifdef ALTQ
+  ifp->if_altqflags |= ALTQF_READY;
+#endif
     if_attach(ifp);
     ether_ifattach(ifp);
 
@@ -896,6 +903,12 @@
 
     /* get ourselves some data */
     ifp = &(sc->wl_if);
+#ifdef ALTQ
+    if (ALTQ_IS_ON(ifp)) {
+      m = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+    }
+    else
+#endif
     IF_DEQUEUE(&ifp->if_snd, m);
     if (m != (struct mbuf *)0) {
 #if NBPFILTER > 0
@@ -1135,6 +1148,14 @@
 	    m_freem(m);
 	    return 1;
 	}
+	/* extra check for multicasts */
+	if ((eh.ether_dhost[0] & 1) &&
+	    bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh.ether_dhost,
+		 sizeof(etherbroadcastaddr)) &&
+	    !ether_matchmulti(&sc->wl_ac, eh.ether_dhost)) {
+	    m_freem(m);
+	    return 1;
+	}
     }
 #endif
 
@@ -1201,6 +1222,14 @@
 	    arp_ifinit((struct arpcom *)ifp, ifa);
 	    break;
 #endif
+
+#ifdef INET6
+	case AF_INET6:
+	    wlinit(sc);
+	    ndp6_ifinit(ifp, ifa);
+	    break;
+#endif /* INET6 */
+
 #ifdef NS
 	case AF_NS:
 	{
diff -uN src-current/sys/kern/uipc_mbuf.c src-current-ipv6/sys/kern/uipc_mbuf.c
--- src-current/sys/kern/uipc_mbuf.c
+++ src-current-ipv6/sys/kern/uipc_mbuf.c
@@ -730,6 +730,56 @@
 }
 
 /*
+ * m_clpullup: like m_pullup but allocates a cluster.
+ */
+struct mbuf *
+m_clpullup(n, len)
+	register struct mbuf *n;
+	int len;
+{
+	register struct mbuf *m;
+	register int count;
+
+	if (len > MCLBYTES)
+		goto bad;
+	MGET(m, M_DONTWAIT, n->m_type);
+	if (m == 0)
+		goto bad;
+	if (n->m_flags & M_PKTHDR) {
+		M_COPY_PKTHDR(m, n);
+		n->m_flags &= ~M_PKTHDR;
+	}
+	MCLGET(m, M_DONTWAIT);
+	if ((m->m_flags & M_EXT) == 0) {
+		m_free(m);
+		goto bad;
+	}
+	m->m_len = 0;
+	do {
+		count = min(len, n->m_len);
+		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
+		  (unsigned)count);
+		len -= count;
+		m->m_len += count;
+		n->m_len -= count;
+		if (n->m_len)
+			n->m_data += count;
+		else
+			n = m_free(n);
+	} while (len > 0 && n);
+	if (len > 0) {
+		(void) m_free(m);
+		goto bad;
+	}
+	m->m_next = n;
+	return (m);
+bad:
+	m_freem(n);
+	MPFail++;
+	return (0);
+}
+
+/*
  * Partition an mbuf chain in two pieces, returning the tail --
  * all but the first len0 bytes.  In case of failure, it returns NULL and
  * attempts to restore the chain to its original state.
diff -uN src-current/sys/kern/uipc_socket.c src-current-ipv6/sys/kern/uipc_socket.c
--- src-current/sys/kern/uipc_socket.c
+++ src-current-ipv6/sys/kern/uipc_socket.c
@@ -475,6 +475,10 @@
 			if (flags & MSG_EOR)
 				top->m_flags |= M_EOR;
 		    } else do {
+			if (!atomic)
+				/* reasonable amount of job */
+#define	LOMTU	(16384)
+				space = min(space, LOMTU);
 			if (top == 0) {
 				MGETHDR(m, M_WAIT, MT_DATA);
 				mlen = MHLEN;
@@ -514,7 +518,7 @@
 					top->m_flags |= M_EOR;
 				break;
 			}
-		    } while (space > 0 && atomic);
+		    } while (space > 0);
 		    if (dontroute)
 			    so->so_options |= SO_DONTROUTE;
 		    s = splnet();				/* XXX */
diff -uN src-current/sys/kern/vfs_subr.c src-current-ipv6/sys/kern/vfs_subr.c
--- src-current/sys/kern/vfs_subr.c
+++ src-current-ipv6/sys/kern/vfs_subr.c
@@ -44,6 +44,7 @@
  */
 #include "opt_ddb.h"
 #include "opt_devfs.h"
+#include "opt_inet6.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -70,6 +71,9 @@
 #include <vm/vnode_pager.h>
 #include <vm/vm_zone.h>
 #include <sys/sysctl.h>
+#ifdef INET6
+#include <netinet/in.h>
+#endif
 
 #if defined(DEVFS)
 #include <sys/devfsext.h>
@@ -2177,6 +2181,21 @@
  * Build hash lists of net addresses and hang them off the mount point.
  * Called by ufs_mount() to set up the lists of export addresses.
  */
+#ifdef INET6
+static struct sockaddr_in6 addr6 = { sizeof(addr6), AF_INET6, 0, 0,
+#if BYTE_ORDER == BIG_ENDIAN
+	{ { {0, 0, 0x0000ffff, 0} } }
+#elif BYTE_ORDER == LITTLE_ENDIAN
+	{ { {0, 0, 0xffff0000, 0} } }
+#else
+	XXX
+#endif
+};
+static struct sockaddr_in6 msk6 = { sizeof(msk6), AF_INET6, 0, 0,
+	{ { {0xffffffff, 0xffffffff, 0xffffffff, 0} } }
+};
+#endif	/* INET6 */
+
 static int
 vfs_hang_addrlist(mp, nep, argp)
 	struct mount *mp;
@@ -2188,6 +2207,10 @@
 	register int i;
 	struct radix_node *rn;
 	struct sockaddr *saddr, *smask = 0;
+#ifdef INET6
+	struct sockaddr_in sin, smsk;
+	int doconv = 0;
+#endif
 	struct domain *dom;
 	int error;
 
@@ -2201,18 +2224,50 @@
 		mp->mnt_flag |= MNT_DEFEXPORTED;
 		return (0);
 	}
+#ifdef INET6
+#define MINSZ (((char *)&sin.sin_zero)-((char*)&sin))
+	/* convert all AF_INET to AF_INET6 */
+	if (argp->ex_addrlen >= sizeof MINSZ) {
+		if ((error = copyin(argp->ex_addr, (caddr_t) &sin, MINSZ)))
+			goto out;
+		if (sin.sin_family == AF_INET) {
+			doconv = 1;
+			argp->ex_addrlen = sizeof (struct sockaddr_in6);
+			if (argp->ex_masklen >= MINSZ) {
+				if ((error = copyin(argp->ex_mask,
+					(caddr_t) &smsk, MINSZ)))
+					goto out;
+				doconv = 2;
+				argp->ex_masklen = sizeof (struct sockaddr_in6);
+			}
+		}
+	}
+#endif
 	i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen;
 	np = (struct netcred *) malloc(i, M_NETADDR, M_WAITOK);
 	bzero((caddr_t) np, i);
 	saddr = (struct sockaddr *) (np + 1);
+#ifdef INET6
+	if (doconv) {
+		bcopy(&addr6, (caddr_t) saddr, sizeof addr6);
+		((struct sockaddr_in6 *)saddr)->sin6_addr.s6_addr32[3] =
+			sin.sin_addr.s_addr;
+	} else
+#endif
 	if ((error = copyin(argp->ex_addr, (caddr_t) saddr, argp->ex_addrlen)))
 		goto out;
 	if (saddr->sa_len > argp->ex_addrlen)
 		saddr->sa_len = argp->ex_addrlen;
 	if (argp->ex_masklen) {
 		smask = (struct sockaddr *) ((caddr_t) saddr + argp->ex_addrlen);
-		error = copyin(argp->ex_mask, (caddr_t) smask, argp->ex_masklen);
-		if (error)
+#ifdef INET6
+		if (doconv > 1) {
+			bcopy(&msk6, (caddr_t) smask, sizeof msk6);
+			((struct sockaddr_in6 *)smask)->
+				sin6_addr.s6_addr32[3] = smsk.sin_addr.s_addr;
+		} else
+#endif
+		if ((error = copyin(argp->ex_mask, (caddr_t) smask, argp->ex_masklen)))
 			goto out;
 		if (smask->sa_len > argp->ex_masklen)
 			smask->sa_len = argp->ex_masklen;
@@ -2408,6 +2463,13 @@
 		 */
 		if (nam != NULL) {
 			saddr = nam;
+#ifdef INET6
+			if (saddr->sa_family == AF_INET) {
+				addr6.sin6_addr.s6_addr32[3] =
+					((struct sockaddr_in *)saddr)->sin_addr.s_addr;
+				saddr = (struct sockaddr *)&addr6;
+			}
+#endif
 			rnh = nep->ne_rtable[saddr->sa_family];
 			if (rnh != NULL) {
 				np = (struct netcred *)
diff -uN src-current/sys/kern/uipc_syscalls.c src-current-ipv6/sys/kern/uipc_syscalls.c
--- src-current/sys/kern/uipc_syscalls.c
+++ src-current-ipv6/sys/kern/uipc_syscalls.c
@@ -35,6 +35,7 @@
  */
 
 #include "opt_compat.h"
+#include "opt_inet6.h"
 #include "opt_ktrace.h"
 
 #include <sys/param.h>
@@ -754,6 +755,7 @@
 		m = control;
 		mp->msg_controllen = 0;
 		ctlbuf = (caddr_t) mp->msg_control;
+		i = 0;
 
 		while (m && len > 0) {
 			unsigned int tocopy;
@@ -764,13 +766,17 @@
 				mp->msg_flags |= MSG_CTRUNC;
 				tocopy = len;
 			}
-		
+			if (len <= 0)
+				break;
+			ctlbuf += i;
+
 			if (error = copyout((caddr_t)mtod(m, caddr_t),
 					ctlbuf, tocopy))
 				goto out;
 
 			ctlbuf += tocopy;
-			len -= tocopy;
+			i = ALIGN(tocopy) - tocopy;
+			len -= tocopy + i;
 			m = m->m_next;
 		}
 		mp->msg_controllen = ctlbuf - mp->msg_control;
@@ -998,6 +1004,10 @@
 				return (ENOBUFS);
 			}
 		}
+#ifdef INET6
+		else if (uap->valsize <= MHLEN)
+			MH_ALIGN(m, uap->valsize);
+#endif
 		error = copyin(uap->val, mtod(m, caddr_t), (u_int)uap->valsize);
 		if (error) {
 			(void) m_free(m);
@@ -1222,6 +1232,10 @@
 	if (m == NULL)
 		return (ENOBUFS);
 	m->m_len = buflen;
+#ifdef INET6
+	if (type == MT_SONAME && buflen <= MHLEN)
+		MH_ALIGN(m, buflen);
+#endif
 	error = copyin(buf, mtod(m, caddr_t), (u_int)buflen);
 	if (error)
 		(void) m_free(m);
diff -uN src-current/sys/net/if_spppsubr.c src-current-ipv6/sys/net/if_spppsubr.c
--- src-current/sys/net/if_spppsubr.c
+++ src-current-ipv6/sys/net/if_spppsubr.c
@@ -23,6 +23,10 @@
 #include "opt_inet.h"
 #include "opt_ipx.h"
 
+#if defined(__FreeBSD__)
+#include "opt_altq.h"
+#endif
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
@@ -578,7 +582,10 @@
 	struct ifqueue *ifq;
 	int s, rv = 0;
 
-	s = splimp();
+#ifdef ALTQ
+	struct pr_hdr pr_hdr;
+#endif
+	s = splimp ();
 
 	if ((ifp->if_flags & IFF_UP) == 0 ||
 	    (ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == 0) {
@@ -598,6 +605,18 @@
 		s = splimp();
 	}
 
+#ifdef ALTQ
+	/*
+	 * save a pointer to the protocol level header before adding
+	 * link headers.
+	 */
+	pr_hdr.ph_family = dst->sa_family;
+	pr_hdr.ph_hdr = mtod(m, caddr_t);
+#endif /* ALTQ */
+
+#ifdef ALTQ
+	if (!ALTQ_IS_ON(ifp)) {
+#endif
 	ifq = &ifp->if_snd;
 #ifdef INET
 	/*
@@ -617,6 +636,9 @@
 			ifq = &sp->pp_fastq;
 	}
 #endif
+#ifdef ALTQ
+        }
+#endif
 
 	/*
 	 * Prepend general data packet PPP header. For now, IP only.
@@ -687,18 +709,36 @@
 		return (EAFNOSUPPORT);
 	}
 
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp)) {
+	        int error, len;
+	        len = m->m_pkthdr.len;
+	        error = (*ifp->if_altqenqueue)(ifp, m, &pr_hdr, ALTEQ_NORMAL);
+	        if (error == 0)
+		        ifp->if_obytes += len + 3;
+	        splx(s);
+	        return (error);
+	}
+#endif /* ALTQ */
+
 	/*
 	 * Queue message on interface, and start output if interface
 	 * not yet active.
 	 */
 	if (IF_QFULL (ifq)) {
 		IF_DROP (&ifp->if_snd);
+#ifdef ALTQ_ACCOUNT
+		ALTQ_ACCOUNTING(ifp, m, &pr_hdr, ALTEQ_ACCDROP);
+#endif
 		m_freem (m);
 		++ifp->if_oerrors;
 		splx (s);
 		return (rv? rv: ENOBUFS);
 	}
 	IF_ENQUEUE (ifq, m);
+#ifdef ALTQ_ACCOUNT
+	ALTQ_ACCOUNTING(ifp, m, &pr_hdr, ALTEQ_ACCOK);
+#endif
 	if (! (ifp->if_flags & IFF_OACTIVE))
 		(*ifp->if_start) (ifp);
 
@@ -773,6 +813,12 @@
 {
 	struct sppp *sp = (struct sppp*) ifp;
 
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp)) {
+	        (void)(*ifp->if_altqdequeue)(ifp, ALTDQ_FLUSH);
+	        return;
+	}
+#endif
 	sppp_qflush (&sp->pp_if.if_snd);
 	sppp_qflush (&sp->pp_fastq);
 	sppp_qflush (&sp->pp_cpq);
@@ -788,6 +834,11 @@
 	int empty, s;
 
 	s = splimp();
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp))
+	        empty = ((*ifp->if_altqdequeue)(ifp, ALTDQ_PEEK) == NULL);
+	else
+#endif
 	empty = !sp->pp_fastq.ifq_head && !sp->pp_cpq.ifq_head &&
 		!sp->pp_if.if_snd.ifq_head;
 	splx(s);
@@ -811,6 +862,13 @@
 	 *
 	 * Do always serve all three queues in Cisco mode.
 	 */
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp)) {
+	        m = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+	        splx(s);
+	        return (m);
+	}
+#endif /* ALTQ */
 	IF_DEQUEUE(&sp->pp_cpq, m);
 	if (m == NULL &&
 	    (sppp_ncp_check(sp) || (sp->pp_flags & PP_CISCO) != 0)) {
@@ -886,6 +944,9 @@
 				lcp.Open(sp);
 		} else if (going_down) {
 			sppp_flush(ifp);
+			if (ALTQ_IS_ON(ifp))
+			        (void)(*ifp->if_altqdequeue)
+				        (ifp, ALTDQ_FLUSH);
 			ifp->if_flags &= ~IFF_RUNNING;
 		}
 
@@ -986,6 +1047,11 @@
 				if (ifp->if_flags & IFF_UP) {
 					if_down (ifp);
 					sppp_qflush (&sp->pp_cpq);
+#ifdef ALTQ
+					if (ALTQ_IS_ON(ifp))
+					        (void)(*ifp->if_altqdequeue)
+						    (ifp, ALTDQ_FLUSH);
+#endif
 				}
 			}
 			++sp->pp_loopcnt;
@@ -1048,6 +1114,19 @@
 			ifp->if_name, ifp->if_unit, ntohl (ch->type), ch->par1,
 			ch->par2, ch->rel, ch->time0, ch->time1);
 
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp)) {
+		struct pr_hdr pr_hdr;
+	        int error, len;
+
+	        len = m->m_pkthdr.len;
+		altq_mkctlhdr(&pr_hdr);	/* fake a control type header */
+	        error = (*ifp->if_altqenqueue)(ifp, m, &pr_hdr, ALTEQ_NORMAL);
+	        if (error == 0)
+		        ifp->if_obytes += len + 3;
+	        return;
+	}
+#endif /* ALTQ */
 	if (IF_QFULL (&sp->pp_cpq)) {
 		IF_DROP (&sp->pp_fastq);
 		IF_DROP (&ifp->if_snd);
@@ -1105,6 +1184,19 @@
 			sppp_print_bytes ((u_char*) (lh+1), len);
 		addlog(">\n");
 	}
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp)) {
+		struct pr_hdr pr_hdr;
+	        int error, len;
+
+	        len = m->m_pkthdr.len;
+		altq_mkctlhdr(&pr_hdr);	/* fake a control type header */
+	        error = (*ifp->if_altqenqueue)(ifp, m, &pr_hdr, ALTEQ_NORMAL);
+	        if (error == 0)
+		        ifp->if_obytes += len + 3;
+	        return;
+	}
+#endif /* ALTQ */
 	if (IF_QFULL (&sp->pp_cpq)) {
 		IF_DROP (&sp->pp_fastq);
 		IF_DROP (&ifp->if_snd);
diff -uN src-current/sys/net/if_ppp.c src-current-ipv6/sys/net/if_ppp.c
--- src-current/sys/net/if_ppp.c
+++ src-current-ipv6/sys/net/if_ppp.c
@@ -67,6 +67,9 @@
  * Added priority queueing for interactive IP packets, following
  * the model of if_sl.c, plus hooks for bpf.
  * Paul Mackerras (paulus@cs.anu.edu.au).
+ *
+ * raw IPv6 support by Eric L'Amoulen of ENST Bretagne
+ *
  */
 
 /* $Id: if_ppp.c,v 1.57 1998/05/19 14:04:09 dg Exp $ */
@@ -77,6 +80,8 @@
 #if NPPP > 0
 
 #include "opt_inet.h"
+#include "opt_inet6.h"
+#include "opt_ipflow.h"
 #include "opt_ipx.h"
 #include "opt_ppp.h"
 
@@ -107,6 +112,11 @@
 #include <netinet/ip.h>
 #endif
 
+#if INET6
+#include <netinet/ip6.h>
+#include <netinet/if_ndp6.h>
+#endif
+
 #if IPX
 #include <netipx/ipx.h>
 #include <netipx/ipx_if.h>
@@ -223,6 +233,9 @@
 	sc->sc_inq.ifq_maxlen = IFQ_MAXLEN;
 	sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN;
 	sc->sc_rawq.ifq_maxlen = IFQ_MAXLEN;
+#ifdef INET6
+	sc->sc_if.if_ndtype = IFND6_PPP;
+#endif
 	if_attach(&sc->sc_if);
 #if NBPFILTER > 0
 	bpfattach(&sc->sc_if, DLT_PPP, PPP_HDRLEN);
@@ -487,6 +500,9 @@
 	npi = (struct npioctl *) data;
 	switch (npi->protocol) {
 	case PPP_IP:
+#ifdef INET6
+	case PPP_IPV6:
+#endif
 	    npx = NP_IP;
 	    break;
 	default:
@@ -589,6 +605,10 @@
 	case AF_INET:
 	    break;
 #endif
+#ifdef INET6
+	case AF_INET6:
+	    break;
+#endif
 #ifdef IPX
 	case AF_IPX:
 	    break;
@@ -605,6 +625,10 @@
 	case AF_INET:
 	    break;
 #endif
+#ifdef INET6
+	case AF_INET6:
+	    break;
+#endif
 #ifdef IPX
 	case AF_IPX:
 	    break;
@@ -642,6 +666,10 @@
 	case AF_INET:
 	    break;
 #endif
+#ifdef INET6
+	case AF_INET6:
+	    break;
+#endif
 	default:
 	    error = EAFNOSUPPORT;
 	    break;
@@ -702,6 +730,9 @@
     u_char *cp;
     int s, error;
     struct ip *ip;
+#ifdef INET6
+    struct ipv6 *ipv6;
+#endif
     struct ifqueue *ifq;
     enum NPmode mode;
     int len;
@@ -734,6 +765,23 @@
 	    m0->m_flags |= M_HIGHPRI;
 	break;
 #endif
+#ifdef INET6
+    case AF_INET6:
+	address = PPP_ALLSTATIONS;
+	control = PPP_UI;
+	protocol = PPP_IPV6;
+	mode = sc->sc_npmode[NP_IP];
+
+	/*
+	 * If this is a packet with an interactive or control flow
+	 * put it on the fastq instead.
+	 */
+	ipv6 = mtod(m0, struct ipv6 *);
+	if ((IPV6_GET_PRIORITY(ipv6->ip6_head) & IPV6_PRIORITY_CONTROL)
+				> IPV6_PRIORITY_INTERACTIVE)
+	    m0->m_flags |= M_HIGHPRI;
+	break;
+#endif
 #ifdef IPX
     case AF_IPX:
 	/*
@@ -890,6 +938,9 @@
     for (mpp = &sc->sc_npqueue; (m = *mpp) != NULL; ) {
 	switch (PPP_PROTOCOL(mtod(m, u_char *))) {
 	case PPP_IP:
+#ifdef INET6
+	case PPP_IPV6:
+#endif
 	    mode = sc->sc_npmode[NP_IP];
 	    break;
 	default:
@@ -1017,6 +1068,15 @@
 #endif	/* VJC */
 	break;
 
+#ifdef INET6
+    case PPP_IPV6:
+	/*
+	 * Update the time we sent the most recent packet.
+	 */
+	sc->sc_last_sent = time_second;
+	break;
+#endif
+
 #ifdef PPP_COMPRESS
     case PPP_CCP:
 	ppp_ccp(sc, m, 0);
@@ -1476,6 +1536,9 @@
     switch (proto) {
 #ifdef INET
     case PPP_IP:
+#ifdef INET6
+    case PPP_IPV6:
+#endif
 	/*
 	 * IP packet - take off the ppp header and pass it up to IP.
 	 */
@@ -1494,7 +1557,6 @@
 	}
 	schednetisr(NETISR_IP);
 	inq = &ipintrq;
-	sc->sc_last_recv = time_second;	/* update time of last pkt rcvd */
 	break;
 #endif
 #ifdef IPX
diff -uN src-current/sys/net/if_ethersubr.c src-current-ipv6/sys/net/if_ethersubr.c
--- src-current/sys/net/if_ethersubr.c
+++ src-current-ipv6/sys/net/if_ethersubr.c
@@ -36,7 +36,12 @@
 
 #include "opt_atalk.h"
 #include "opt_inet.h"
+#include "opt_inet6.h"
+#include "opt_ipflow.h"
 #include "opt_ipx.h"
+#if defined(__FreeBSD__) && defined(ALTQ)
+#include "opt_altq.h"
+#endif
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -57,8 +62,15 @@
 #ifdef INET
 #include <netinet/in.h>
 #include <netinet/in_var.h>
+#ifdef INET6
+#include <netinet/in6_var.h>
+#endif
 #include <netinet/if_ether.h>
 #endif
+#ifdef INET6
+#include <netinet/if_ether6.h>
+#include <netinet/if_ndp6.h>
+#endif
 
 #ifdef IPX
 #include <netipx/ipx.h>
@@ -137,6 +149,9 @@
 #ifdef NETATALK
 	struct at_ifaddr *aa;
 #endif NETATALK
+#ifdef ALTQ
+        struct pr_hdr pr_hdr;
+#endif
 
 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
 		senderr(ENETDOWN);
@@ -165,6 +180,15 @@
 			    time_second < rt->rt_rmx.rmx_expire)
 				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
 	}
+#ifdef ALTQ
+	/*
+	 * save a pointer to the protocol level header before adding
+	 * link headers.
+	 */
+	pr_hdr.ph_family = dst->sa_family;
+	pr_hdr.ph_hdr = mtod(m, caddr_t);
+#endif /* ALTQ */
+
 	switch (dst->sa_family) {
 
 #ifdef INET
@@ -178,6 +202,16 @@
 		type = htons(ETHERTYPE_IP);
 		break;
 #endif
+#ifdef INET6
+	case AF_INET6:
+		if (rt && (rt->rt_flags & RTF_REJECT))
+			senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
+		if (!ndp6_resolve(ifp, rt, m, dst, edst))
+			return (0);	/* if not yet resolved */
+		m->m_flags &= ~M_NOPROBE;
+		type = htons(ETHERTYPE_IPV6);
+		break;
+#endif
 #ifdef IPX
 	case AF_IPX:
 		{
@@ -430,6 +464,19 @@
  	(void)memcpy(eh->ether_dhost, edst, sizeof (edst));
  	(void)memcpy(eh->ether_shost, ac->ac_enaddr,
 	    sizeof(eh->ether_shost));
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp)) {
+	        s = splimp();
+		error = (*ifp->if_altqenqueue)(ifp, m, &pr_hdr, ALTEQ_NORMAL);
+		splx(s);
+		if (!error) {
+		    ifp->if_obytes += len + sizeof (struct ether_header);
+		    if (m->m_flags & M_MCAST)
+		    	ifp->if_omcasts++;
+		}
+		return (error);
+	}
+#endif /* ALTQ */
 	s = splimp();
 	/*
 	 * Queue message on interface, and start output if interface
@@ -437,10 +484,16 @@
 	 */
 	if (IF_QFULL(&ifp->if_snd)) {
 		IF_DROP(&ifp->if_snd);
+#ifdef ALTQ_ACCOUNT
+		ALTQ_ACCOUNTING(ifp, m, &pr_hdr, ALTEQ_ACCDROP);
+#endif
 		splx(s);
 		senderr(ENOBUFS);
 	}
 	IF_ENQUEUE(&ifp->if_snd, m);
+#ifdef ALTQ_ACCOUNT
+	ALTQ_ACCOUNTING(ifp, m, &pr_hdr, ALTEQ_ACCOK);
+#endif
 	if ((ifp->if_flags & IFF_OACTIVE) == 0)
 		(*ifp->if_start)(ifp);
 	splx(s);
@@ -512,6 +565,12 @@
 		inq = &arpintrq;
 		break;
 #endif
+#ifdef INET6
+	case ETHERTYPE_IPV6:
+		schednetisr(NETISR_IP);
+		inq = &ipintrq;
+		break;
+#endif
 #ifdef IPX
 	case ETHERTYPE_IPX:
 		schednetisr(NETISR_IPX);
@@ -601,6 +660,16 @@
 					M_PREPEND(m, sizeof *eh, M_DONTWAIT);
 					if (m == 0)
 						return;
+#ifdef sparc
+					if (mtod(m, u_long) & 3) {
+					    /* force 4-byte alignment */
+					    caddr_t ocp = mtod(m, caddr_t);
+
+					    m->m_data = (caddr_t)((u_long)ocp & ~3);
+					    ovbcopy(ocp, mtod(m, caddr_t),
+						    (unsigned)m->m_len);
+					}
+#endif
 					*mtod(m, struct ether_header *) = *eh;
 					IFDEBUG(D_ETHER)
 						printf("clnp packet");
@@ -709,6 +778,14 @@
 	ifp->if_resolvemulti = ether_resolvemulti;
 	if (ifp->if_baudrate == 0)
 	    ifp->if_baudrate = 10000000;
+#ifdef INET6
+	ifp->if_ndtype = (IFND6_IEEE |
+			  (IFND6_INLL | IFND6_ADDRES) |
+			  (((int)&(((struct arpcom *)0)->ac_llip6) -
+			   sizeof(struct ifnet)) << 8) |
+			   ((int)&(((struct arpcom *)0)->ac_enaddr[0]) -
+			    sizeof(struct ifnet)));
+#endif
 	ifa = ifnet_addrs[ifp->if_index - 1];
 	if (ifa == 0) {
 		printf("ether_ifattach: no lladdr!\n");
@@ -743,6 +820,12 @@
 			arp_ifinit((struct arpcom *)ifp, ifa);
 			break;
 #endif
+#ifdef INET6
+		case AF_INET6:
+			ifp->if_init(ifp->if_softc);
+			ndp6_ifinit(ifp, ifa);
+			break;
+#endif
 #ifdef IPX
 		/*
 		 * XXX - This code is probably wrong
@@ -832,6 +915,7 @@
 {
 	struct sockaddr_dl *sdl;
 	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin6;
 	u_char *e_addr;
 
 	switch(sa->sa_family) {
@@ -865,7 +949,27 @@
 		*llsa = (struct sockaddr *)sdl;
 		return 0;
 #endif
-
+#ifdef INET6
+	case AF_INET6:
+		sin6 = (struct sockaddr_in6 *)sa;
+/*
+		if (!IN_MULTICAST(ntohl(sin6->sin_addr.s_addr)))
+			return EADDRNOTAVAIL;
+*/
+		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
+		       M_WAITOK);
+		sdl->sdl_len = sizeof *sdl;
+		sdl->sdl_family = AF_LINK;
+		sdl->sdl_index = ifp->if_index;
+		sdl->sdl_type = IFT_ETHER;
+		sdl->sdl_nlen = 0;
+		sdl->sdl_alen = ETHER_ADDR_LEN;
+		sdl->sdl_slen = 0;
+		e_addr = LLADDR(sdl);
+		ETHER_MAP_IP6_MULTICAST(&sin6->sin6_addr, e_addr);
+		*llsa = (struct sockaddr *)sdl;
+		return 0;
+#endif
 	default:
 		/* 
 		 * Well, the text isn't quite right, but it's the name
diff -uN src-current/sys/net/if_fddisubr.c src-current-ipv6/sys/net/if_fddisubr.c
--- src-current/sys/net/if_fddisubr.c
+++ src-current-ipv6/sys/net/if_fddisubr.c
@@ -38,6 +38,7 @@
 
 #include "opt_atalk.h"
 #include "opt_inet.h"
+#include "opt_inet6.h"
 #include "opt_ipx.h"
 
 #include <sys/param.h>
@@ -56,8 +57,15 @@
 #ifdef INET
 #include <netinet/in.h>
 #include <netinet/in_var.h>
+#ifdef INET6
+#include <netinet/in6_var.h>
+#endif
 #include <netinet/if_ether.h>
 #endif
+#ifdef INET6
+#include <netinet/if_ether6.h>
+#include <netinet/if_ndp6.h>
+#endif
 #if defined(__FreeBSD__)
 #include <netinet/if_fddi.h>
 #else
@@ -193,6 +201,16 @@
 		break;
 	}
 #endif
+#ifdef INET6
+	case AF_INET6:
+		if (rt && (rt->rt_flags & RTF_REJECT))
+			senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
+		if (!ndp6_resolve(ifp, rt, m, dst, edst))
+			return (0);	/* if not yet resolved */
+		m->m_flags &= ~M_NOPROBE;
+		type = htons(ETHERTYPE_IPV6);
+		break;
+#endif
 #ifdef IPX
 	case AF_IPX:
 		{
@@ -502,7 +520,7 @@
 
 	l = mtod(m, struct llc *);
 	switch (l->llc_dsap) {
-#if defined(INET) || defined(NS) || defined(DECNET) || defined(IPX) || defined(NETATALK)
+#if defined(INET) || defined(INET6) || defined(NS) || defined(DECNET) || defined(IPX) || defined(NETATALK)
 	case LLC_SNAP_LSAP:
 	{
 		u_int16_t type;
@@ -549,6 +567,12 @@
 			return;
 #endif
 #endif
+#ifdef INET6
+		case ETHERTYPE_IPV6:
+			schednetisr(NETISR_IP);
+			inq = &ipintrq;
+			break;
+#endif
 #ifdef IPX      
 		case ETHERTYPE_IPX: 
 			schednetisr(NETISR_IPX);
@@ -704,6 +728,14 @@
 	ifp->if_hdrlen = 21;
 	ifp->if_mtu = FDDIMTU;
 	ifp->if_baudrate = 100000000;
+#ifdef INET6
+	ifp->if_ndtype = (IFND6_IEEE |
+		(IFND6_INLL | IFND6_ADDRES | IFND6_MTU)  |
+		(((int)&(((struct arpcom *)0)->ac_llip6) -
+		  sizeof(struct ifnet)) << 8) |
+		((int)&(((struct arpcom *)0)->ac_enaddr[0]) -
+		  sizeof(struct ifnet)));
+#endif
 #ifdef IFF_NOTRAILERS
 	ifp->if_flags |= IFF_NOTRAILERS;
 #endif
diff -uN src-current/sys/net/altq.c src-current-ipv6/sys/net/altq.c
--- src-current/sys/net/altq.c
+++ src-current-ipv6/sys/net/altq.c
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 1997, 1998
+ *	Sony Computer Science Laboratory Inc.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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.
+ *
+ * $Id: altq.c,v 0.8 1998/01/27 02:50:14 kjc Exp $
+ */
+
+#ifdef ALTQ
+#if defined(__FreeBSD__)
+#include "opt_altq.h"
+#endif
+
+#include "opt_inet6.h"
+
+/*
+static char rcsid[] = "$Id: altq.c,v 0.5 1997/10/27 02:32:42 kjc Exp kjc $";
+*/
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/kernel.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+
+#ifndef TAILQ_EMPTY
+#define	TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
+#define	TAILQ_FIRST(head) ((head)->tqh_first)
+#define	TAILQ_LAST(head) ((head)->tqh_last)
+#define	TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_PREV(elm, field) ((elm)->field.tqe_prev)
+#endif
+
+struct ip4_frag {
+    TAILQ_ENTRY(ip4_frag) ip4f_chain;
+    char    ip4f_valid;
+    u_short ip4f_id;
+    struct flowinfo_in ip4f_info;
+};
+
+static TAILQ_HEAD(ip4f_list, ip4_frag) ip4f_list; /* IPv4 fragment cache */
+
+#define IP4F_TABSIZE		8	/* IPv4 fragment cache size */
+
+/*
+ * internal function prototypes
+ */
+static void ip4f_cache __P((struct ip *, struct flowinfo_in *));
+static int ip4f_lookup __P((struct ip *, struct flowinfo_in *));
+static int ip4f_init __P((void));
+static struct ip4_frag *ip4f_alloc __P((void));
+static void ip4f_free __P((struct ip4_frag *));
+
+/*
+ * alternate queueing support routines
+ */
+/* look up the queue state by the interface name and the queuing type. */
+void *
+altq_lookup(name, type)
+    char *name;
+    int type;
+{
+    struct ifnet *ifp;
+
+    if ((ifp = ifunit(name))) {
+	if (type != ALTQT_NONE && ifp->if_altqtype != type)
+	    return NULL;
+	return (void *)ifp->if_altqp;
+    }
+
+    return NULL;
+}
+
+int
+if_altqattach(ifp, queue_state, enqueue, dequeue, type)
+    struct ifnet *ifp;
+    void *queue_state;
+    int (*enqueue)(struct ifnet *, struct mbuf *, struct pr_hdr *, int);
+    struct mbuf *(*dequeue)(struct ifnet *, int);
+    int type;
+{
+    if (!ALTQ_IS_READY(ifp))
+	return ENXIO;
+    if (ALTQ_IS_ON(ifp))
+	return EBUSY;
+    if (ifp->if_altqp != NULL)
+	return EEXIST;
+
+    ifp->if_altqp = queue_state;
+    ifp->if_altqenqueue = enqueue;
+    ifp->if_altqdequeue = dequeue;
+    ifp->if_altqflags &= ALTQF_CANTCHANGE;
+    ifp->if_altqtype = type;
+    return 0;
+}
+
+int
+if_altqdetach(ifp)
+    struct ifnet *ifp;
+{
+    if (!ALTQ_IS_READY(ifp))
+	return ENXIO;
+    if (ALTQ_IS_ON(ifp))
+	return EBUSY;
+
+    ifp->if_altqp = NULL;
+    ifp->if_altqenqueue = NULL;
+    ifp->if_altqdequeue = NULL;
+    ifp->if_altqflags &= ALTQF_CANTCHANGE;
+    ifp->if_altqtype = ALTQT_NONE;
+    return 0;
+}
+
+int
+if_altqenable(ifp)
+    struct ifnet *ifp;
+{
+    struct mbuf *m;
+    int s;
+    
+    if (!ALTQ_IS_READY(ifp))
+	return ENXIO;
+    if (ALTQ_IS_ON(ifp))
+	return 0;
+
+    s = splimp();
+    do {
+	IF_DEQUEUE(&ifp->if_snd, m);
+	if (m)
+	    m_freem(m);
+    } while (m);
+
+    ifp->if_altqflags |= ALTQF_ENABLE;
+    splx(s);
+
+    return 0;
+}
+
+int
+if_altqdisable(ifp)
+    struct ifnet *ifp;
+{
+    int s;
+    
+    if (!ALTQ_IS_ON(ifp))
+	return 0;
+
+    s = splimp();
+    (void)(*ifp->if_altqdequeue)(ifp, ALTDQ_FLUSH);
+    ifp->if_altqflags &= ~ALTQF_ENABLE;
+    splx(s);
+    return 0;
+}
+
+
+/* 
+ * extract flow information from a given packet.
+ * this is called from if_output routines before adding a link-level header.
+ * currently, only IP (v4 or v6) is supported.
+ * assuming ip header is at the top of the mbuf, the entire ip header
+ * is in the first mbuf, and addresses and ports are in network byte order.
+ */
+
+static int altq_extractflow4 __P((struct mbuf *,
+	struct ip *, struct flowinfo_in *));
+#ifdef INET6
+static int altq_extractflow6 __P((struct mbuf *,
+	struct ipv6 *, struct flowinfo_in6 *));
+#endif
+
+int 
+altq_extractflow(m, pr_hdr, flow)
+    struct mbuf *m;
+    struct pr_hdr *pr_hdr;
+    struct flowinfo *flow;
+{
+    struct ip *ip = 0;
+
+    switch (pr_hdr->ph_family) {
+      case PF_INET:
+	ip = (struct ip *)pr_hdr->ph_hdr;
+#ifdef IP_VHL_V
+	switch (IP_VHL_V(ip->ip_vhl)) {
+#else
+	switch (ip->ip_v) {
+#endif
+	  case 4:
+	    return (altq_extractflow4(m, ip, (struct flowinfo_in *)flow));
+#ifdef INET6
+	  case 6:
+	  ipv6:
+	    return (altq_extractflow6(m,
+				      (struct ipv6 *)ip,
+				      (struct flowinfo_in6 *)flow));
+#endif
+	  default:
+	  unspec:
+#if 0
+	    printf("altq_extractflow: unknown proto family=%d\n",
+		   pr_hdr->ph_family);
+#endif
+	    flow->fi_len = sizeof(struct flowinfo);
+	    flow->fi_family = AF_UNSPEC;
+	    return 0;
+	}
+#ifdef INET6
+      case PF_INET6:
+	goto ipv6;
+#endif
+      default:
+	goto unspec;
+    }
+}
+
+/* IPv4 version */
+static int 
+altq_extractflow4(m, ip, fin)
+    struct mbuf *m;
+    struct ip *ip;
+    struct flowinfo_in *fin;
+{
+    struct udphdr *udp, buf;
+    u_short ip_off;
+    int hlen;
+
+    fin->fi_len = sizeof(struct flowinfo_in);
+    fin->fi_family = AF_INET;
+
+    fin->fi_proto = ip->ip_p;
+    fin->fi_tos = ip->ip_tos;
+
+    fin->fi_src.s_addr = ip->ip_src.s_addr;
+    fin->fi_dst.s_addr = ip->ip_dst.s_addr;
+    
+    /* if TCP or UDP, extract port numbers */
+    if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) {
+
+	ip_off = ntohs(ip->ip_off);
+	if (ip_off & IP_OFFMASK) {
+	    ip4f_lookup(ip, fin);
+	    return (1);
+	}
+
+#ifdef IP_VHL_HL
+	hlen = IP_VHL_HL(ip->ip_vhl) << 2;
+#else	
+	hlen = ip->ip_hl << 2;
+#endif
+
+	/*
+	 * make sure we can access port numbers
+	 * (in the front of transport header)
+	 */
+	if (m->m_len < hlen + 4) {
+	    m_copydata(m, hlen, 4, (caddr_t)&buf);
+	    udp = &buf;
+	} else
+	    udp = (struct udphdr *) (mtod(m, caddr_t) + hlen);
+	fin->fi_sport = udp->uh_sport;
+	fin->fi_dport = udp->uh_dport;
+
+	/* if this is a first fragment, cache it. */
+	if (ip_off & IP_MF)
+	    ip4f_cache(ip, fin);
+    }
+    else {
+	fin->fi_sport = 0;
+	fin->fi_dport = 0;
+    }
+    return (1);
+}
+
+#ifdef INET6
+/* IPv6 version */
+static int 
+altq_extractflow6(m, ip, fin)
+    struct mbuf *m;
+    struct ipv6 *ip;
+    struct flowinfo_in6 *fin;
+{
+    struct udphdr *udp, buf;
+    int hlen = sizeof(struct ipv6);
+
+    ip = mtod(m, struct ipv6 *);
+
+    fin->fi_len = sizeof(struct flowinfo_in6);
+    fin->fi_family = AF_INET6;
+
+    fin->fi_proto = ip->ip6_nh;
+    fin->fi_pri = IPV6_GET_PRIORITY(ip->ip6_head);
+
+    fin->fi_flowlabel = IPV6_GET_FLOWLABEL(ip->ip6_head);
+    COPY_ADDR6(ip->ip6_src, fin->fi_src);
+    COPY_ADDR6(ip->ip6_dst, fin->fi_dst);
+    
+    /* if direct TCP or UDP, and not a fragment, extract port numbers */
+    if ((ip->ip6_nh == IPPROTO_TCP || ip->ip6_nh == IPPROTO_UDP)) {
+
+	/*
+	 * make sure we can access port numbers
+	 * (in the front of transport header)
+	 */
+	if (m->m_len < hlen + 4) {
+	    m_copydata(m, hlen, 4, (caddr_t)&buf);
+	    udp = &buf;
+	} else
+	    udp = (struct udphdr *) (mtod(m, caddr_t) + hlen);
+	fin->fi_sport = udp->uh_sport;
+	fin->fi_dport = udp->uh_dport;
+    }
+    else {
+	fin->fi_sport = 0;
+	fin->fi_dport = 0;
+    }
+    return (1);
+}
+#endif
+
+/*
+ * helper functions to handle IPv4 fragments.
+ * currently only in-sequence fragments are handled.
+ *	- fragment info is cached in a LRU list.
+ *	- when a first fragment is found, cache its flow info.
+ *	- when a non-first fragment is found, lookup the cache.
+ */
+
+static void ip4f_cache(ip, fin)
+    struct ip *ip;
+    struct flowinfo_in *fin;
+{
+    struct ip4_frag *fp;
+
+    if (TAILQ_EMPTY(&ip4f_list)) {
+	/* first time call, allocate fragment cache entries. */
+	if (ip4f_init() < 0)
+	    /* allocation failed! */
+	    return;
+    }
+
+    fp = ip4f_alloc();
+    fp->ip4f_id = ip->ip_id;
+    bcopy(fin, &fp->ip4f_info, sizeof(struct flowinfo_in));
+}
+
+static int ip4f_lookup(ip, fin)
+    struct ip *ip;
+    struct flowinfo_in *fin;
+{
+    struct ip4_frag *fp;
+
+    for (fp = TAILQ_FIRST(&ip4f_list); fp != NULL && fp->ip4f_valid;
+	 fp = TAILQ_NEXT(fp, ip4f_chain))
+	if (ip->ip_id == fp->ip4f_id &&
+	    ip->ip_src.s_addr == fp->ip4f_info.fi_src.s_addr &&
+	    ip->ip_dst.s_addr == fp->ip4f_info.fi_dst.s_addr &&
+	    ip->ip_p == fp->ip4f_info.fi_proto) {
+
+	    /* found the matching entry */
+	    fin->fi_sport = fp->ip4f_info.fi_sport;
+	    fin->fi_dport = fp->ip4f_info.fi_dport;
+
+	    if ((ntohs(ip->ip_off) & IP_MF) == 0)
+		/* this is the last fragment, release the entry. */
+		ip4f_free(fp);
+
+	    return (1);
+	}
+
+    /* no matching entry found */
+    fin->fi_sport = 0;
+    fin->fi_dport = 0;
+    return (0);
+}
+
+static int ip4f_init(void)
+{
+    struct ip4_frag *fp;
+    int i;
+    
+    TAILQ_INIT(&ip4f_list);
+    for (i=0; i<IP4F_TABSIZE; i++) {
+	MALLOC(fp, struct ip4_frag *, sizeof(struct ip4_frag),
+	       M_DEVBUF, M_NOWAIT);
+	if (fp == NULL) {
+	    printf("ip4f_initcache: can't alloc cache entry!\n");
+	    return (-1);
+	}
+	fp->ip4f_valid = 0;
+	TAILQ_INSERT_TAIL(&ip4f_list, fp, ip4f_chain);
+    }
+    return (0);
+}
+
+static struct ip4_frag *ip4f_alloc(void)
+{
+    struct ip4_frag *fp;
+
+    /* reclaim an entry at the tail, put it at the head */
+    fp = (struct ip4_frag *)TAILQ_LAST(&ip4f_list);
+    TAILQ_REMOVE(&ip4f_list, fp, ip4f_chain);
+    fp->ip4f_valid = 1;
+    TAILQ_INSERT_HEAD(&ip4f_list, fp, ip4f_chain);
+    return (fp);
+}
+
+static void ip4f_free(fp)
+    struct ip4_frag *fp;
+{
+    TAILQ_REMOVE(&ip4f_list, fp, ip4f_chain);
+    fp->ip4f_valid = 0;
+    TAILQ_INSERT_TAIL(&ip4f_list, fp, ip4f_chain);
+}
+
+/*
+ * make a control type ip header.  fake an ICMP type for now.
+ */
+int altq_mkctlhdr(pr_hdr)
+    struct pr_hdr *pr_hdr;
+{
+    static struct ip *ip = NULL;
+
+    if (ip == NULL) {
+	MALLOC(ip, struct ip *, sizeof(struct ip), M_DEVBUF, M_WAITOK);
+	ip->ip_len = htons(sizeof(struct ip));
+	ip->ip_v = 4;
+	ip->ip_hl = sizeof(struct ip) >> 2;
+	ip->ip_p = IPPROTO_ICMP;
+	ip->ip_tos = 0;
+	ip->ip_src.s_addr = htonl(0);	/* XXX */
+	ip->ip_dst.s_addr = htonl(0);	/* XXX */
+    }
+    pr_hdr->ph_family = AF_INET;
+    pr_hdr->ph_hdr = (caddr_t)ip;
+    return (0);
+}
+
+/*
+ * altq device interface for FreeBSD.
+ */
+#include <sys/conf.h>
+#ifdef DEVFS
+#include <sys/devfsext.h>
+#endif /*DEVFS*/
+
+#ifdef CBQ
+extern d_open_t cbqopen; extern d_close_t cbqclose; extern d_ioctl_t cbqioctl;
+#endif
+#ifdef WFQ
+extern d_open_t wfqopen; extern d_close_t wfqclose; extern d_ioctl_t wfqioctl;
+#endif
+#ifdef AFMAP
+extern d_open_t afmopen; extern d_close_t afmclose; extern d_ioctl_t afmioctl;
+#endif
+#ifdef FIFOQ
+extern d_open_t fifoqopen; extern d_close_t fifoqclose; extern d_ioctl_t fifoqioctl;
+#endif
+#ifdef RED
+extern d_open_t redopen; extern d_close_t redclose; extern d_ioctl_t redioctl;
+#endif
+
+static struct altqsw {
+        char		*d_name;
+	d_open_t	*d_open;
+	d_close_t	*d_close;
+	d_ioctl_t	*d_ioctl;
+} altqsw[] = {							/* minor */
+#ifdef CBQ
+	{"cbq",	cbqopen,	cbqclose,	cbqioctl},	/* 0 */
+#else
+	{"noq",	noopen,		noclose,	noioctl},	/* 0 */
+#endif
+#ifdef WFQ
+	{"wfq",	wfqopen,	wfqclose,	wfqioctl},	/* 1 */
+#else
+	{"noq",	noopen,		noclose,	noioctl},	/* 1 */
+#endif
+#ifdef AFMAP
+	{"afm",	afmopen,	afmclose,	afmioctl},	/* 2 */
+#else
+	{"noq",	noopen,		noclose,	noioctl},	/* 2 */
+#endif
+#ifdef FIFOQ
+	{"fifoq", fifoqopen,	fifoqclose,	fifoqioctl},	/* 3 */
+#else
+	{"noq",	noopen,		noclose,	noioctl},	/* 3 */
+#endif
+#ifdef RED
+	{"red", redopen,	redclose,	redioctl},	/* 4 */
+#else
+	{"noq",	noopen,		noclose,	noioctl},	/* 4 */
+#endif
+};
+
+int	naltqsw = sizeof (altqsw) / sizeof (altqsw[0]);
+
+static	d_open_t	altqopen;
+static	d_close_t	altqclose;
+static	d_ioctl_t	altqioctl;
+
+#define CDEV_MAJOR 88 /* temporarily */
+
+static struct cdevsw altq_cdevsw = 
+        { altqopen,	altqclose,	noread,	        nowrite,	/*79*/
+	  altqioctl,	nostop,		nullreset,	nodevtotty,  /* altq */
+ 	  seltrue,	nommap,		NULL,	"altq",	NULL,	-1 };
+
+static int
+altqopen(dev_t dev, int flag, int fmt, struct proc *p)
+{
+    int unit = minor(dev);
+
+    if (unit < naltqsw)
+	return (*altqsw[unit].d_open)(dev, flag, fmt, p);
+
+    return ENXIO;
+}
+
+static int
+altqclose(dev_t dev, int flag, int fmt, struct proc *p)
+{
+    int unit = minor(dev);
+
+    if (unit < naltqsw)
+	return (*altqsw[unit].d_close)(dev, flag, fmt, p);
+
+    return ENXIO;
+}
+
+static int
+altqioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
+{
+    int unit = minor(dev);
+
+    if (unit < naltqsw)
+	return (*altqsw[unit].d_ioctl)(dev, cmd, addr, flag, p);
+
+    return ENXIO;
+}
+
+
+static altq_devsw_installed = 0;
+
+#ifdef DEVFS
+static	void *altq_devfs_token[NALTQ];
+#endif
+
+static void
+altq_drvinit(void *unused)
+{
+    dev_t dev;
+    int i;
+
+    if( ! altq_devsw_installed ) {
+	dev = makedev(CDEV_MAJOR,0);
+	cdevsw_add(&dev,&altq_cdevsw,NULL);
+	altq_devsw_installed = 1;
+#ifdef DEVFS
+	for (i=0; i<naltqsw; i++) {
+	    altq_devfs_token[i] = devfs_add_devswf(&altq_cdevsw, i, DV_CHR,
+				      0, 0, 0644, altqsw[i].d_name);
+#endif
+	printf("altq: major number is %d\n", CDEV_MAJOR);
+    }
+}
+
+SYSINIT(altqdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,altq_drvinit,NULL)
+
+#endif /* ALTQ */
diff -uN src-current/sys/net/if.c src-current-ipv6/sys/net/if.c
--- src-current/sys/net/if.c
+++ src-current-ipv6/sys/net/if.c
@@ -35,6 +35,7 @@
  */
 
 #include "opt_compat.h"
+#include "opt_inet6.h"
 
 #include <sys/param.h>
 #include <sys/malloc.h>
@@ -162,7 +163,7 @@
 		sdl->sdl_nlen = namelen;
 		sdl->sdl_index = ifp->if_index;
 		sdl->sdl_type = ifp->if_type;
-		ifnet_addrs[if_index - 1] = ifa;
+		ifnet_addrs[ifp->if_index - 1] = ifa;
 		ifa->ifa_ifp = ifp;
 		ifa->ifa_rtrequest = link_rtrequest;
 		ifa->ifa_addr = (struct sockaddr *)sdl;
@@ -195,7 +196,7 @@
 		if (equal(addr, ifa->ifa_addr))
 			return (ifa);
 		if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
-		    equal(ifa->ifa_broadaddr, addr))
+		    equal(addr, ifa->ifa_broadaddr))
 			return (ifa);
 	}
 	return ((struct ifaddr *)0);
@@ -215,7 +216,8 @@
 	    if (ifp->if_flags & IFF_POINTOPOINT)
 		for (ifa = ifp->if_addrhead.tqh_first; ifa; 
 		     ifa = ifa->ifa_link.tqe_next) {
-			if (ifa->ifa_addr->sa_family != addr->sa_family)
+			if (ifa->ifa_addr->sa_family != addr->sa_family ||
+			    ifa->ifa_dstaddr == NULL)
 				continue;
 			if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))
 				return (ifa);
@@ -270,7 +272,10 @@
 				if (ifa->ifa_dstaddr != 0
 				    && equal(addr, ifa->ifa_dstaddr))
  					return (ifa);
-			} else {
+			}
+#ifndef INET6
+			else {
+#endif
 				/*
 				 * if we have a special address handler,
 				 * then use it instead of the generic one.
@@ -311,7 +316,9 @@
 				    rn_refines((caddr_t)ifa->ifa_netmask,
 				    (caddr_t)ifa_maybe->ifa_netmask))
 					ifa_maybe = ifa;
+#ifndef INET6
 			}
+#endif
 		}
 	}
 	return (ifa_maybe);
@@ -347,9 +354,13 @@
 			continue;
 		}
 		if (ifp->if_flags & IFF_POINTOPOINT) {
-			if (equal(addr, ifa->ifa_dstaddr))
+			if (ifa->ifa_dstaddr != 0
+			    && equal(addr, ifa->ifa_dstaddr))
 				return (ifa);
-		} else {
+		}
+#ifndef INET6
+		 else {
+#endif
 			cp = addr->sa_data;
 			cp2 = ifa->ifa_addr->sa_data;
 			cp3 = ifa->ifa_netmask->sa_data;
@@ -359,7 +370,9 @@
 					break;
 			if (cp3 == cplim)
 				return (ifa);
+#ifndef INET6
 		}
+#endif
 	}
 	return (ifa_maybe);
 }
@@ -397,7 +410,7 @@
 /*
  * Mark an interface down and notify protocols of
  * the transition.
- * NOTE: must be called at splnet or eqivalent.
+ * NOTE: must be called at splnet or equivalent.
  */
 void
 if_down(ifp)
diff -uN src-current/sys/net/if.h src-current-ipv6/sys/net/if.h
--- src-current/sys/net/if.h
+++ src-current-ipv6/sys/net/if.h
@@ -57,9 +57,11 @@
 	u_char	ifi_hdrlen;		/* media header length */
 	u_char	ifi_recvquota;		/* polling quota for receive intrs */
 	u_char	ifi_xmitquota;		/* polling quota for xmit intrs */
+	u_short	ifi_site6;		/* IPv6 site index */
 	u_long	ifi_mtu;		/* maximum transmission unit */
 	u_long	ifi_metric;		/* routing metric (external only) */
 	u_long	ifi_baudrate;		/* linespeed */
+	u_long	ifi_ndtype;		/* IPv6 neighbor discovery type */
 	/* volatile statistics */
 	u_long	ifi_ipackets;		/* packets received on interface */
 	u_long	ifi_ierrors;		/* input errors on interface */
@@ -162,6 +164,7 @@
 		int	ifru_mtu;
 		int	ifru_phys;
 		int	ifru_media;
+		u_short	ifru_site6;
 		caddr_t	ifru_data;
 	} ifr_ifru;
 #define	ifr_addr	ifr_ifru.ifru_addr	/* address */
@@ -172,6 +175,7 @@
 #define	ifr_mtu		ifr_ifru.ifru_mtu	/* mtu */
 #define ifr_phys	ifr_ifru.ifru_phys	/* physical wire */
 #define ifr_media	ifr_ifru.ifru_media	/* physical media */
+#define ifr_site6	ifr_ifru.ifru_site6	/* IPv6 site index */
 #define	ifr_data	ifr_ifru.ifru_data	/* for use by interface */
 };
 
@@ -218,6 +222,22 @@
 MALLOC_DECLARE(M_IFMADDR);
 #endif
 #endif
+
+/* for IPv6 advanced API */
+
+struct if_nameindex {
+	unsigned int	 if_index;	/* 1, 2, ... */
+	char		*if_name;	/* null terminated name */
+};
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+unsigned int	if_nametoindex __P((const char *));
+char	*if_indextoname __P((unsigned int, char *));
+struct if_nameindex	*if_nameindex __P((void));
+void	if_freenameindex __P((struct if_nameindex *));
+__END_DECLS
 
 /* XXX - this should go away soon */
 #ifdef KERNEL
diff -uN src-current/sys/net/if_altq.h src-current-ipv6/sys/net/if_altq.h
--- src-current/sys/net/if_altq.h
+++ src-current-ipv6/sys/net/if_altq.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 1997, 1998
+ *	Sony Computer Science Laboratory Inc.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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.
+ *
+ * $Id: if_altq.h,v 0.6 1998/01/27 02:50:14 kjc Exp $
+ */
+#ifndef _NET_IF_ALTQ_H_
+#define _NET_IF_ALTQ_H_
+
+/*
+ * common network flow info structure
+ */
+struct flowinfo {
+	u_char		fi_len;		/* total length */
+	u_char		fi_family;	/* address family */
+	u_int8_t	fi_data[46];	/* actually longer; address family
+					   specific flow info. */
+};
+
+/* protocol header info is passed to an enqueue routine */
+struct pr_hdr {
+	u_int8_t	ph_family;	/* protocol family (e,g, PF_INET) */
+	caddr_t		ph_hdr;		/* pointer to a protocol header */
+};
+
+#ifdef KERNEL
+
+/* if_altqflags */
+#define ALTQF_READY	 0x01	/* driver supports alternate queueing */
+#define ALTQF_ENABLE	 0x02	/* altq is in use */
+#define ALTQF_ACCOUNTING 0x04	/* altq accounting is enabled */
+#define ALTQF_DRIVER1	 0x40	/* driver specific */
+
+/* if_altqtype */
+#define ALTQT_NONE	0	/* reserved */
+#define ALTQT_CBQ	1	/* cbq */
+#define ALTQT_WFQ	2	/* wfq */
+#define ALTQT_AFMAP	3	/* afmap */
+#define ALTQT_FIFOQ	4	/* fifoq */
+#define ALTQT_RED	5	/* red */
+
+/* if_altqflags set internally only: */
+#define	ALTQF_CANTCHANGE 	(ALTQF_READY)
+
+#define ALTQ_IS_READY(ifp)	((ifp)->if_altqflags & ALTQF_READY)
+#define ALTQ_IS_ON(ifp)		((ifp)->if_altqflags & ALTQF_ENABLE)
+
+#define SET_ACCOUNTING(ifp)	((ifp)->if_altqflags |= ALTQF_ACCOUNTING)
+#define CLEAR_ACCOUNTING(ifp)	((ifp)->if_altqflags &= ~ALTQF_ACCOUNTING)
+
+
+/* if_altqenqueue 4th arg */
+#define ALTEQ_NORMAL	0	/* normal queueing */
+#define ALTEQ_ACCOK	1	/* accounting successful queueing */
+#define ALTEQ_ACCDROP	2	/* accounting packet drop */
+
+/* if_altqdequeue 2nd arg */	
+#define ALTDQ_DEQUEUE	0	/* dequeue mbuf from the queue */
+#define ALTDQ_PEEK	1	/* don't dequeue mbuf from the queue */
+#define ALTDQ_FLUSH	2	/* discard all the queued packets */
+
+#define ALTQ_ACCOUNTING(ifp, m, h, mode) \
+		if ((ifp)->if_altqflags & ALTQF_ACCOUNTING) \
+			(ifp)->if_altqenqueue((ifp), (m), (h), (mode));
+
+
+struct ifnet; struct mbuf;	/* forward declarations for Standard C */
+
+void *altq_lookup __P((char *, int));
+int if_altqattach __P((struct ifnet *, void *,
+		       int (*)(struct ifnet *, struct mbuf *, struct pr_hdr *, int),
+		       struct mbuf *(*)(struct ifnet *, int), int));
+int if_altqdetach __P((struct ifnet *));
+int if_altqenable __P((struct ifnet *));
+int if_altqdisable __P((struct ifnet *));
+int altq_extractflow __P((struct mbuf *, struct pr_hdr *, struct flowinfo *));
+int altq_mkctlhdr __P((struct pr_hdr *));
+#endif /* KERNEL */
+
+#endif /* _NET_IF_ALTQ_H_ */
+
diff -uN src-current/sys/net/if_atm.h src-current-ipv6/sys/net/if_atm.h
--- src-current/sys/net/if_atm.h
+++ src-current-ipv6/sys/net/if_atm.h
@@ -42,6 +42,14 @@
 #endif
 #endif /* freebsd doesn't define _KERNEL */
 
+#ifndef NO_ATM_PVCEXT
+/*
+ * ATM_PVCEXT enables PVC extention: VP/VC shaping
+ * and PVC shadow interfaces.
+ */
+#define ATM_PVCEXT	/* enable pvc extention */
+#endif
+
 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
 #define RTALLOC1(A,B)		rtalloc1((A),(B))
 #elif defined(__FreeBSD__)
@@ -51,7 +59,6 @@
 /*
  * pseudo header for packet transmission
  */
-
 struct atm_pseudohdr {
   u_int8_t atm_ph[4];	/* flags+VPI+VCI1(msb)+VCI2(lsb) */
 };
@@ -67,6 +74,9 @@
 #define ATM_PH_AAL5    0x01	/* use AAL5? (0 == aal0) */
 #define ATM_PH_LLCSNAP 0x02	/* use the LLC SNAP encoding (iff aal5) */
 
+#ifdef ATM_PVCEXT
+#define ATM_PH_INERNAL  0x20	/* reserve for kernel internal use */
+#endif
 #define ATM_PH_DRIVER7  0x40	/* reserve for driver's use */
 #define ATM_PH_DRIVER8  0x80	/* reserve for driver's use */
 
@@ -85,6 +95,33 @@
 #define SIOCATMENA	_IOWR('a', 123, struct atm_pseudoioctl) /* enable */
 #define SIOCATMDIS	_IOWR('a', 124, struct atm_pseudoioctl) /* disable */
 
+/* sub-interface add */
+#define SIOCATMASIF	_IOW('a', 126, struct ifreq)	/* attach sub IF */
+#define SIOCATMDSIF	_IOW('a', 127, struct ifreq)	/* detach sub IF */
+
+#ifdef ATM_PVCEXT
+
+/* structure to control PVC transmitter */
+struct pvctxreq {
+    /* first entry must be compatible with struct ifreq */
+    char pvc_ifname[IFNAMSIZ];		/* if name, e.g. "en0" */
+    struct atm_pseudohdr pvc_aph;	/* (flags) + vpi:vci */
+    struct atm_pseudohdr pvc_joint;	/* for vp shaping: another vc
+					   to share the shaper */
+    int pvc_pcr;			/* peak cell rate (shaper value) */
+};
+
+/* use ifioctl for now */
+#define SIOCSPVCTX	_IOWR('i', 95, struct pvctxreq)
+#define SIOCGPVCTX	_IOWR('i', 96, struct pvctxreq)
+#define SIOCSPVCSIF	_IOWR('i', 97, struct ifreq)
+#define SIOCGPVCSIF	_IOWR('i', 98, struct ifreq)
+
+#ifdef _KERNEL
+#define ATM_PH_PVCSIF	ATM_PH_INERNAL	/* pvc shadow interface */
+#endif
+#endif /* ATM_PVCEXT */
+
 /*
  * XXX forget all the garbage in if_llc.h and do it the easy way
  */
@@ -103,9 +140,18 @@
 }
 
 #ifdef _KERNEL
+extern	u_int atm_hw_if_count, atm_sub_cnt, atm_sub_next;
+
 void	atm_ifattach __P((struct ifnet *));
 void	atm_input __P((struct ifnet *, struct atm_pseudohdr *,
 		struct mbuf *, void *));
 int	atm_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, 
 		struct rtentry *));
+#endif
+#ifdef ATM_PVCEXT
+char *shadow2if __P((char *));
+#ifdef _KERNEL
+struct ifnet *pvc_attach __P((struct ifnet *));
+int pvc_setaph __P((struct ifnet *, struct atm_pseudohdr *));
+#endif
 #endif
diff -uN src-current/sys/net/if_atmsubr.c src-current-ipv6/sys/net/if_atmsubr.c
--- src-current/sys/net/if_atmsubr.c
+++ src-current-ipv6/sys/net/if_atmsubr.c
@@ -37,12 +37,20 @@
  */
 
 #include "opt_inet.h"
+#include "opt_inet6.h"
 #include "opt_natm.h"
 
+#if defined(__FreeBSD__) && defined(ALTQ)
+#include "opt_altq.h"
+#endif
+
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/kernel.h>
 #include <sys/mbuf.h>
 #include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
 
 #include <net/if.h>
 #include <net/netisr.h>
@@ -54,25 +62,25 @@
 #include <netinet/in.h>
 #include <netinet/if_atm.h>
 #include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */
-#ifdef INET
+#if defined(INET) || defined(INET6)
 #include <netinet/in_var.h>
 #endif
+#ifdef INET6
+#include <netinet/in6_var.h>
+#include <netinet/if_ether6.h>
+#include <netinet/if_ndp6.h>
+#endif
 #ifdef NATM
 #include <netnatm/natm.h>
 #endif
 
-#include "bpfilter.h"
-#if NBPFILTER > 0
-/*
- * bpf support.
- * the code is derived from if_loop.c.
- * bpf support should belong to the driver but it's easier to implement
- * it here since we can call bpf_mtap before atm_output adds a pseudo
- * header to the mbuf.
- *			--kjc
- */
-#include <net/bpf.h>
-#endif /* NBPFILTER > 0 */
+#if defined(ALTQ) && defined(AFMAP)
+#include <netinet/afmap.h>
+#endif
+
+#ifndef ETHERTYPE_IPV6
+#define ETHERTYPE_IPV6	0x86dd
+#endif
 
 #define senderr(e) { error = (e); goto bad;}
 
@@ -104,10 +112,27 @@
 	register struct mbuf *m = m0;
 	register struct rtentry *rt;
 	struct atmllc *atmllc;
+	struct atmllc *llc_hdr = NULL;
 	u_int32_t atm_flags;
+#ifdef ALTQ
+	struct pr_hdr pr_hdr;
+#endif
 
 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
 		senderr(ENETDOWN);
+
+#ifdef ALTQ
+	/*
+	 * save a pointer to the protocol level header before adding
+	 * link headers.
+	 */
+	if (dst)
+		pr_hdr.ph_family = dst->sa_family;
+	else
+		pr_hdr.ph_family = AF_UNSPEC;
+	pr_hdr.ph_hdr = mtod(m, caddr_t);
+#endif /* ALTQ */
+
 	getmicrotime(&ifp->if_lastchange);
 
 	/*
@@ -133,8 +158,13 @@
 			}
 		}
 
-		/* XXX: put RTF_REJECT code here if doing ATMARP */
+		if (rt->rt_flags & RTF_REJECT)
+			if (rt->rt_rmx.rmx_expire == 0 ||
+			    time_second < rt->rt_rmx.rmx_expire)
+				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
 
+		if (rt->rt_flags & RTF_XRESOLVE)
+			senderr(0);
 	}
 
 	/*
@@ -142,8 +172,9 @@
 	 */
 	if (dst) {
 		switch (dst->sa_family) {
-#ifdef INET
+#if defined(INET) || defined(INET6)
 		case AF_INET:
+		case AF_INET6:
 			if (!atmresolve(rt, m, dst, &atmdst)) {
 				m = NULL; 
 				/* XXX: atmresolve already free'd it */
@@ -151,10 +182,37 @@
 				/* XXX: put ATMARP stuff here */
 				/* XXX: watch who frees m on failure */
 			}
-			etype = htons(ETHERTYPE_IP);
-			break;
+#ifdef INET6
+			if (dst->sa_family == AF_INET6) {
+				m->m_flags &= ~M_NOPROBE;
+				etype = htons(ETHERTYPE_IPV6);
+			} else
 #endif
+				etype = htons(ETHERTYPE_IP);
+			break;
+#endif /* INET || INET6 */
 
+		case AF_UNSPEC:
+			/*
+			 * XXX: bpfwrite or output from a pvc shadow if.
+			 * assuming dst contains 12 bytes (atm pseudo
+			 * header (4) + LLC/SNAP (8))
+			 */
+			bcopy(dst->sa_data, &atmdst, sizeof(atmdst));
+			llc_hdr = (struct atmllc *)(dst->sa_data + sizeof(atmdst));
+#ifdef ALTQ
+			/* modify pr_hdr to have a correct family */
+			switch (ATM_LLC_TYPE(llc_hdr)) {
+			case ETHERTYPE_IP:
+				pr_hdr.ph_family = AF_INET;
+				break;
+			case ETHERTYPE_IPV6:
+				pr_hdr.ph_family = AF_INET6;
+				break;
+			}
+#endif			
+			break;
+			
 		default:
 #if defined(__NetBSD__) || defined(__OpenBSD__)
 			printf("%s: can't handle af%d\n", ifp->if_xname, 
@@ -166,39 +224,28 @@
 			senderr(EAFNOSUPPORT);
 		}
 
-#if NBPFILTER > 0
-		/* BPF write needs to be handled specially */
-		if (dst && dst->sa_family == AF_UNSPEC) {
-		    dst->sa_family = *(mtod(m, int *));
-		    m->m_len -= sizeof(int);
-		    m->m_pkthdr.len -= sizeof(int);
-		    m->m_data += sizeof(int);
-		}
-
-		if (ifp->if_bpf) {
-		    /*
-		     * We need to prepend the address family as
-		     * a four byte field.  Cons up a dummy header
-		     * to pacify bpf.  This is safe because bpf
-		     * will only read from the mbuf (i.e., it won't
-		     * try to free it or keep a pointer a to it).
-		     */
-		    struct mbuf m1;
-		    u_int af = dst->sa_family;
-
-		    m1.m_next = m;
-		    m1.m_len = 4;
-		    m1.m_data = (char *)&af;
-
-		    s = splimp();
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-		bpf_mtap(&ifp->if_bpf, &m0);
-#elif defined(__FreeBSD__)
-		    bpf_mtap(ifp, &m1);
+#if defined(ALTQ) && defined(AFMAP)
+		if (ifp->if_altqflags & ALTQF_DRIVER1) {
+		        /* try to map flow to vpi/vci. */
+			struct flowinfo flow;
+		        struct afm *afm;
+
+			altq_extractflow(m, &pr_hdr, &flow);
+		        if ((afm = afm_match(ifp, &flow)) != NULL) {
+			        /* matching entry found.  overwrite vpi:vci. */
+#if 0
+				printf("%s%d: atm_output:afmap vci %d -> %d\n",
+				       ifp->if_name, ifp->if_unit,
+				       ATM_PH_VCI(&atmdst), afm->afm_vci);
 #endif
-		    splx(s);
+			        ATM_PH_VPI(&atmdst) = afm->afm_vpi;
+			        ATM_PH_SETVCI(&atmdst, afm->afm_vci);
+
+				afm->afms_packets++;
+				afm->afms_bytes = m->m_pkthdr.len;
+			}
 		}
-#endif /* NBPFILTER > 0 */
+#endif /* ALTQ && AFMAP */
 
 		/*
 		 * must add atm_pseudohdr to data
@@ -213,10 +260,14 @@
 		*ad = atmdst;
 		if (atm_flags & ATM_PH_LLCSNAP) {
 			atmllc = (struct atmllc *)(ad + 1);
-			bcopy(ATMLLC_HDR, atmllc->llchdr, 
-						sizeof(atmllc->llchdr));
-			ATM_LLC_SETTYPE(atmllc, etype); 
+			if (llc_hdr == NULL) {
+			        bcopy(ATMLLC_HDR, atmllc->llchdr, 
+				      sizeof(atmllc->llchdr));
+				ATM_LLC_SETTYPE(atmllc, etype); 
 					/* note: already in network order */
+			}
+			else
+			        bcopy(llc_hdr, atmllc, sizeof(struct atmllc));
 		}
 	}
 
@@ -224,15 +275,34 @@
 	 * Queue message on interface, and start output if interface
 	 * not yet active.
 	 */
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp)) {
+	        s = splimp();
+		error = (*ifp->if_altqenqueue)(ifp, m, &pr_hdr, ALTEQ_NORMAL);
+		splx(s);
+		if (!error) {
+			ifp->if_obytes += m->m_pkthdr.len;
+			if (m->m_flags & M_MCAST)
+				ifp->if_omcasts++;
+		}
+		return (error);
+	}
+#endif /* ALTQ */
 
 	s = splimp();
 	if (IF_QFULL(&ifp->if_snd)) {
 		IF_DROP(&ifp->if_snd);
+#ifdef ALTQ_ACCOUNT
+		ALTQ_ACCOUNTING(ifp, m, &pr_hdr, ALTEQ_ACCDROP);
+#endif
 		splx(s);
 		senderr(ENOBUFS);
 	}
 	ifp->if_obytes += m->m_pkthdr.len;
 	IF_ENQUEUE(&ifp->if_snd, m);
+#ifdef ALTQ_ACCOUNT
+	ALTQ_ACCOUNTING(ifp, m, &pr_hdr, ALTEQ_ACCOK);
+#endif
 	if ((ifp->if_flags & IFF_OACTIVE) == 0)
 		(*ifp->if_start)(ifp);
 	splx(s);
@@ -258,89 +328,108 @@
 	register struct ifqueue *inq;
 	u_int16_t etype = ETHERTYPE_IP; /* default */
 	int s;
+#ifdef NATM
+	struct natmpcb *npcb = rxhand;
+#endif
+	struct atmllc *alc = 0;
 
 	if ((ifp->if_flags & IFF_UP) == 0) {
-		m_freem(m);
-		return;
+	    m_freem(m);
+	    return;
 	}
 	getmicrotime(&ifp->if_lastchange);
 	ifp->if_ibytes += m->m_pkthdr.len;
 
-#if NBPFILTER > 0
-	if (ifp->if_bpf) {
+#ifdef ATM_PVCEXT
+	if (ATM_PH_FLAGS(ah) & ATM_PH_PVCSIF) {
 		/*
-		 * We need to prepend the address family as
-		 * a four byte field.  Cons up a dummy header
-		 * to pacify bpf.  This is safe because bpf
-		 * will only read from the mbuf (i.e., it won't
-		 * try to free it or keep a pointer to it).
+		 * when PVC shadow interface is used, pointer to
+		 * the shadow interface is passed as rxhand.
+		 * override the receive interface of the packet.
 		 */
-		struct mbuf m0;
-		u_int af = AF_INET;
-
-		m0.m_next = m;
-		m0.m_len = 4;
-		m0.m_data = (char *)&af;
-
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-		bpf_mtap(&ifp->if_bpf, &m0);
-#elif defined(__FreeBSD__)
-		bpf_mtap(ifp, &m0);
-#endif
+		m->m_pkthdr.rcvif = (struct ifnet *)rxhand;
+		rxhand = NULL;
 	}
-#endif /* NBPFILTER > 0 */
+#endif /*  ATM_PVCEXT */
 
 	if (rxhand) {
 #ifdef NATM
-	  struct natmpcb *npcb = rxhand;
-	  s = splimp();			/* in case 2 atm cards @ diff lvls */
-	  npcb->npcb_inq++;			/* count # in queue */
-	  splx(s);
-	  schednetisr(NETISR_NATM);
-	  inq = &natmintrq;
-	  m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
+	    if ((npcb->npcb_flags & NPCB_IP) == 0) {
+    for_ntam:
+		s = splimp();		/* in case 2 atm cards @ diff lvls */
+		npcb->npcb_inq++;	/* count # in queue */
+		splx(s);
+		schednetisr(NETISR_NATM);
+		inq = &natmintrq;
+		m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
+		goto enqueue;
+	    } else if (npcb->npcb_sifp)
+		m->m_pkthdr.rcvif = npcb->npcb_sifp;
 #else
-	  printf("atm_input: NATM detected but not configured in kernel\n");
-	  m_freem(m);
-	  return;
-#endif
-	} else {
-	  /*
-	   * handle LLC/SNAP header, if present
-	   */
-	  if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
-	    struct atmllc *alc;
-	    if (m->m_len < sizeof(*alc) && (m = m_pullup(m, sizeof(*alc))) == 0)
-		  return; /* failed */
+	    printf("atm_input: NATM detected but not configured in kernel\n");
+	    m_freem(m);
+	    return;
+#endif
+	}
+
+	/*
+	 * handle LLC/SNAP header, if present
+	 */
+	if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
+	    if (m->m_len < sizeof(*alc)) {
+#ifdef NATM
+		if (rxhand)
+		    goto for_ntam;
+#endif
+		return; /* failed */
+	    }
+	    if (m->m_len < sizeof(*alc) &&
+		(m = m_pullup(m, sizeof(*alc))) == 0)
+		return; /* failed */
 	    alc = mtod(m, struct atmllc *);
 	    if (bcmp(alc, ATMLLC_HDR, 6)) {
+#ifdef NATM
+		if (rxhand)
+		    goto for_ntam;
+#endif
 #if defined(__NetBSD__) || defined(__OpenBSD__)
-	      printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
-		  ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
+		printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
+		       ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
 #elif defined(__FreeBSD__) || defined(__bsdi__)
-	      printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
-		  ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
+		printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
+		       ifp->if_name, ifp->if_unit,
+		       ATM_PH_VPI(ah), ATM_PH_VCI(ah));
 #endif
-	      m_freem(m);
-              return;
+		m_freem(m);
+		return;
 	    }
 	    etype = ATM_LLC_TYPE(alc);
-	    m_adj(m, sizeof(*alc));
-	  }
+	}
 
-	  switch (etype) {
+	switch (etype) {
 #ifdef INET
 	  case ETHERTYPE_IP:
-		  schednetisr(NETISR_IP);
-		  inq = &ipintrq;
-		  break;
+#ifdef INET6
+	  case ETHERTYPE_IPV6:
+#endif
+	    schednetisr(NETISR_IP);
+	    inq = &ipintrq;
+	    if (alc)
+		m_adj(m, sizeof(*alc));
+	    break;
 #endif
 	  default:
-	      m_freem(m);
-	      return;
-	  }
+#ifdef NATM
+	    if (rxhand)
+		goto for_ntam;
+#endif
+	    m_freem(m);
+	    return;
 	}
 
+#ifdef NATM
+    enqueue:
+#endif
 	s = splimp();
 	if (IF_QFULL(inq)) {
 		IF_DROP(inq);
@@ -360,41 +449,337 @@
 	register struct ifaddr *ifa;
 	register struct sockaddr_dl *sdl;
 
+	atm_hw_if_count++;
+
 	ifp->if_type = IFT_ATM;
-	ifp->if_addrlen = 0;
+	ifp->if_addrlen = 6;
 	ifp->if_hdrlen = 0;
 	ifp->if_mtu = ATMMTU;
+#ifdef INET6
+	ifp->if_ndtype = IFND6_ATM;
+#endif
 	ifp->if_output = atm_output;
 
 #if defined(__NetBSD__) || defined(__OpenBSD__)
 	for (ifa = ifp->if_addrlist.tqh_first; ifa != 0;
 	    ifa = ifa->ifa_list.tqe_next)
-#elif defined(__FreeBSD__) && ((__FreeBSD__ > 2) || defined(_NET_IF_VAR_H_))
-/*
- * for FreeBSD-3.0.  3.0-SNAP-970124 still sets -D__FreeBSD__=2!
- * XXX -- for now, use newly-introduced "net/if_var.h" as an identifier.
- * need a better way to identify 3.0.  -- kjc
- */
+#elif defined(__FreeBSD__) && (__FreeBSD__ > 2)
 	for (ifa = ifp->if_addrhead.tqh_first; ifa; 
 	    ifa = ifa->ifa_link.tqe_next)
 #elif defined(__FreeBSD__) || defined(__bsdi__)
 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 
 #endif
-
 		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
 		    sdl->sdl_family == AF_LINK) {
 			sdl->sdl_type = IFT_ATM;
 			sdl->sdl_alen = ifp->if_addrlen;
-#ifdef notyet /* if using ATMARP, store hardware address using the next line */
-			bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen);
+			/* the ESI is just after the ifnet struct */
+			bcopy((caddr_t)(ifp + 1),
+			      LLADDR(sdl),
+			      ifp->if_addrlen);
+			break;
+		}
+}
+
+#ifdef ATM_PVCEXT
+/*
+ * ATM PVC shadow interface: a trick to assign a shadow interface
+ * to a PVC.
+ * with shadow interface, each PVC looks like an individual
+ * Point-to-Point interface.
+ * as oposed to the NBMA model, a shadow interface is inherently
+ * multicast capable (no LANE/MARS required).
+ */
+struct pvcsif {
+	struct ifnet sif_shadow;	/* shadow ifnet structure per pvc */
+	struct atm_pseudohdr sif_aph;	/* flags + vpi:vci */
+	struct ifnet *sif_ifp;		/* pointer to the genuine interface */
+};
+
+static int pvc_output __P((struct ifnet *, struct mbuf *,
+			   struct sockaddr *, struct rtentry *));
+#ifdef __FreeBSD__
+static int pvc_ioctl __P((struct ifnet *, int, caddr_t));
+#else
+static int pvc_ioctl __P((struct ifnet *, u_long, caddr_t));
+#endif
+
+/*
+ * create and attach per pvc shadow interface
+ * (currently detach is not supported)
+ */
+static int pvc_number = 0;
+
+struct ifnet *
+pvc_attach(ifp)
+	struct ifnet *ifp;
+{
+	struct pvcsif *pvcsif;
+	struct ifnet *shadow;
+	struct ifaddr *ifa;
+	struct sockaddr_dl *sdl;
+	int s;
+
+	MALLOC(pvcsif, struct pvcsif *, sizeof(struct pvcsif),
+	       M_DEVBUF, M_WAITOK);
+	bzero(pvcsif, sizeof(struct pvcsif));
+
+	pvcsif->sif_ifp = ifp;
+	shadow = &pvcsif->sif_shadow;
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+	sprintf(shadow->if_xname, "gre%d", pvc_number++);
+#elif defined(__FreeBSD__) || defined(__bsdi__)
+	shadow->if_unit = pvc_number++;
+	shadow->if_name = "pvc";
+#endif
+	shadow->if_flags = ifp->if_flags | (IFF_POINTOPOINT | IFF_MULTICAST);
+	shadow->if_ioctl = pvc_ioctl;
+	shadow->if_output = pvc_output;
+	shadow->if_start = NULL;
+	shadow->if_mtu = ifp->if_mtu;
+	shadow->if_type = ifp->if_type;
+	shadow->if_addrlen = ifp->if_addrlen;
+	shadow->if_hdrlen = ifp->if_hdrlen;
+#ifdef INET6
+	shadow->if_ndtype = ifp->if_ndtype;
+#endif
+	shadow->if_softc = pvcsif;
+	shadow->if_snd.ifq_maxlen = 50;	/* dummy */
+
+	s = splimp();
+	if_attach(shadow);
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+	for (ifa = shadow->if_addrlist.tqh_first; ifa != 0;
+	     ifa = ifa->ifa_list.tqe_next)
+#elif defined(__FreeBSD__) && (__FreeBSD__ > 2)
+	for (ifa = shadow->if_addrhead.tqh_first; ifa; 
+	     ifa = ifa->ifa_link.tqe_next)
+#elif defined(__FreeBSD__) || defined(__bsdi__)
+	for (ifa = shadow->if_addrlist; ifa; ifa = ifa->ifa_next) 
+#endif
+		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
+		    sdl->sdl_family == AF_LINK) {
+			sdl->sdl_type = IFT_ATM;
+			sdl->sdl_alen = shadow->if_addrlen;
+			/* the ESI is just after the ifnet struct */
+			bcopy((caddr_t)(ifp + 1),
+			      LLADDR(sdl),
+			      ifp->if_addrlen);
+			break;
+		}
+	splx(s);
+
+	return (shadow);
+}
+
+/*
+ * pvc_output relays the packet to atm_output along with vpi:vci info.
+ */
+static int
+pvc_output(shadow, m, dst, rt)
+	struct ifnet *shadow;
+	struct mbuf *m;
+	struct sockaddr *dst;
+	struct rtentry *rt;
+{
+	struct pvcsif *pvcsif;
+	struct sockaddr dst_addr;
+	struct atmllc *atmllc;
+	u_int16_t etype = 0;
+	int error = 0;
+
+	if ((shadow->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+		senderr(ENETDOWN);
+
+	pvcsif = shadow->if_softc;
+	if (ATM_PH_VCI(&pvcsif->sif_aph) == 0)
+		senderr(ENETDOWN);
+	
+	/*
+	 * create a dummy sockaddr: (using bpfwrite interface)
+	 * put atm pseudo header and llc/snap into sa_data (12 bytes)
+	 * and mark it as AF_UNSPEC.
+	 */
+	if (dst) {
+		switch (dst->sa_family) {
+#if defined(INET) || defined(INET6)
+		case AF_INET:
+#ifdef INET6
+		case AF_INET6:
+			if (dst->sa_family == AF_INET6) {
+				m->m_flags &= ~M_NOPROBE;
+				etype = htons(ETHERTYPE_IPV6);
+			} else
 #endif
+				etype = htons(ETHERTYPE_IP);
 			break;
+#endif
+
+		default:
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+			printf("%s: can't handle af%d\n",
+			       shadow->if_xname, dst->sa_family);
+#elif defined(__FreeBSD__) || defined(__bsdi__)
+			printf("%s%d: can't handle af%d\n", shadow->if_name, 
+			       shadow->if_unit, dst->sa_family);
+#endif
+			senderr(EAFNOSUPPORT);
 		}
-#if NBPFILTER > 0 
+	}
+
+	dst_addr.sa_family = AF_UNSPEC;
+	bcopy(&pvcsif->sif_aph, dst_addr.sa_data,
+	      sizeof(struct atm_pseudohdr));
+	atmllc = (struct atmllc *)
+		(dst_addr.sa_data + sizeof(struct atm_pseudohdr));
+	bcopy(ATMLLC_HDR, atmllc->llchdr,  sizeof(atmllc->llchdr));
+	ATM_LLC_SETTYPE(atmllc, etype);  /* note: already in network order */
+
+	return atm_output(pvcsif->sif_ifp, m, &dst_addr, rt);
+
+bad:
+	if (m)
+		m_freem(m);
+	return (error);
+}
+
+static int
+pvc_ioctl(shadow, cmd, data)
+	struct ifnet *shadow;
+#ifdef __FreeBSD__
+	int cmd;
+#else
+	u_long cmd;
+#endif
+	caddr_t data;
+{
+	struct ifnet *ifp;
+	struct pvcsif *pvcsif;
+	struct ifreq *ifr = (struct ifreq *) data;
+	void (*ifa_rtrequest)(int, struct rtentry *, struct sockaddr *) = NULL;
+	int error = 0;
+
+	pvcsif = (struct pvcsif *)shadow->if_softc;
+	ifp = pvcsif->sif_ifp;
+	if (ifp == 0 || ifp->if_ioctl == 0)
+		return (EOPNOTSUPP);
+    
+	/*
+	 * pre process
+	 */
+	switch (cmd) {
+	case SIOCGPVCSIF:
 #if defined(__NetBSD__) || defined(__OpenBSD__)
-	bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
-#elif defined(__FreeBSD__)
-	bpfattach(ifp, DLT_NULL, sizeof(u_int));
+		sprintf(ifr->ifr_name, "%s", ifp->if_xname);
+#elif defined(__FreeBSD__) || defined(__bsdi__)
+		sprintf(ifr->ifr_name, "%s%d", ifp->if_name, ifp->if_unit);
 #endif
-#endif /* NBPFILTER > 0 */
+		return (0);
+
+	case SIOCGPVCTX:
+		do {
+			struct pvctxreq *pvcreq = (struct pvctxreq *)data;
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+			sprintf(pvcreq->pvc_ifname, "%s", ifp->if_xname);
+#elif defined(__FreeBSD__) || defined(__bsdi__)
+			sprintf(pvcreq->pvc_ifname, "%s%d",
+				ifp->if_name, ifp->if_unit);
+#endif
+			pvcreq->pvc_aph = pvcsif->sif_aph;
+		} while (0);
+		break;
+
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		if (ifr == 0)
+			return (EAFNOSUPPORT);	/* XXX */
+		switch (ifr->ifr_addr.sa_family) {
+#ifdef INET
+		case AF_INET:
+			return (0);
+#endif
+#ifdef INET6
+		case AF_INET6:
+			return (0);
+#endif
+		default:
+			return (EAFNOSUPPORT);
+		}
+		break;
+	case SIOCSIFADDR:
+		if (ifp->if_flags & IFF_UP) {
+			/* real if is already up */
+			shadow->if_flags = ifp->if_flags |
+				(IFF_POINTOPOINT|IFF_MULTICAST);
+			return (0);
+		}
+		/*
+		 * XXX: save the rtrequest field since the atm driver
+		 * overwrites this field.
+		 */
+		ifa_rtrequest = ((struct ifaddr *)data)->ifa_rtrequest;
+		break;
+		
+	case SIOCSIFFLAGS:
+		if ((shadow->if_flags & IFF_UP) == 0) {
+			/*
+			 * interface down. don't pass this to
+			 * the real interface.
+			 */
+			return (0);
+		}
+		if (shadow->if_flags & IFF_UP) {
+			/*
+			 * interface up. if the real if is already up,
+			 * nothing to do.
+			 */
+			if (ifp->if_flags & IFF_UP) {
+				shadow->if_flags = ifp->if_flags |
+					(IFF_POINTOPOINT|IFF_MULTICAST);
+				return (0);
+			}
+		}
+		break;
+	}
+
+	/*
+	 * pass the ioctl to the genuine interface
+	 */
+	error = (*ifp->if_ioctl)(ifp, cmd, data);
+
+	/*
+	 * post process
+	 */
+	switch (cmd) {
+	case SIOCSIFMTU:
+		shadow->if_mtu = ifp->if_mtu;
+		break;
+	case SIOCSIFADDR:
+		/* restore rtrequest */
+		((struct ifaddr *)data)->ifa_rtrequest = ifa_rtrequest;
+		/* fall into... */
+	case SIOCSIFFLAGS:
+		/* update if_flags */
+		shadow->if_flags = ifp->if_flags
+			| (IFF_POINTOPOINT|IFF_MULTICAST);
+		break;
+	}
+
+	return (error);
 }
+
+int pvc_setaph(shadow, aph)
+	struct ifnet *shadow;
+	struct atm_pseudohdr *aph;
+{
+	struct pvcsif *pvcsif;
+    
+	pvcsif = shadow->if_softc;
+	bcopy(aph, &pvcsif->sif_aph, sizeof(struct atm_pseudohdr));
+	return (0);
+}
+
+#endif /* ATM_PVCEXT */
diff -uN src-current/sys/net/if_disc.c src-current-ipv6/sys/net/if_disc.c
--- src-current/sys/net/if_disc.c
+++ src-current-ipv6/sys/net/if_disc.c
@@ -53,6 +53,7 @@
 
 #include "bpfilter.h"
 #include "opt_inet.h"
+#include "opt_inet6.h"
 
 #ifdef TINY_DSMTU
 #define	DSMTU	(1024+512)
@@ -60,6 +61,16 @@
 #define DSMTU	65532
 #endif
 
+#ifdef  INET
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#ifdef INET6
+#include <netinet/in6_var.h>
+#include <netinet/ip6.h>
+#include <netinet/if_ndp6.h>
+#endif
+#endif
+
 static void discattach __P((void *dummy));
 PSEUDO_SET(discattach, if_disc);
 
@@ -84,6 +95,9 @@
 	ifp->if_type = IFT_LOOP;
 	ifp->if_hdrlen = 0;
 	ifp->if_addrlen = 0;
+#ifdef INET6
+	ifp->if_ndtype = IFND6_LOOP;
+#endif
 	if_attach(ifp);
 #if NBPFILTER > 0
 	bpfattach(ifp, DLT_NULL, sizeof(u_int));
@@ -182,6 +196,9 @@
 
 #ifdef INET
 		case AF_INET:
+#ifdef INET6
+		case AF_INET6:
+#endif
 			break;
 #endif
 
diff -uN src-current/sys/net/if_loop.c src-current-ipv6/sys/net/if_loop.c
--- src-current/sys/net/if_loop.c
+++ src-current-ipv6/sys/net/if_loop.c
@@ -42,6 +42,7 @@
 
 #include "opt_atalk.h"
 #include "opt_inet.h"
+#include "opt_inet6.h"
 #include "opt_ipx.h"
 
 #include <sys/param.h>
@@ -60,6 +61,11 @@
 #ifdef	INET
 #include <netinet/in.h>
 #include <netinet/in_var.h>
+#ifdef INET6
+#include <netinet/in6_var.h>
+#include <netinet/ip6.h>
+#include <netinet/if_ndp6.h>
+#endif
 #endif
 
 #ifdef IPX
@@ -88,6 +94,9 @@
 static void lortrequest __P((int, struct rtentry *, struct sockaddr *));
 
 static void loopattach __P((void *));
+#ifdef ALTQ
+static void lo_altqstart __P((struct ifnet *));
+#endif
 PSEUDO_SET(loopattach, if_loop);
 
 #ifdef TINY_LOMTU
@@ -114,6 +123,13 @@
 	    ifp->if_ioctl = loioctl;
 	    ifp->if_output = looutput;
 	    ifp->if_type = IFT_LOOP;
+#ifdef INET6
+	    ifp->if_ndtype = IFND6_LOOP;
+#endif
+#ifdef ALTQ
+	    ifp->if_start = lo_altqstart;
+	    ifp->if_altqflags |= ALTQF_READY;
+#endif
 	    if_attach(ifp);
 #if NBPFILTER > 0
 	    bpfattach(ifp, DLT_NULL, sizeof(u_int));
@@ -130,9 +146,21 @@
 {
 	int s, isr;
 	register struct ifqueue *ifq = 0;
+#ifdef ALTQ
+	struct pr_hdr pr_hdr;
+#endif
 
 	if ((m->m_flags & M_PKTHDR) == 0)
 		panic("looutput no HDR");
+#ifdef ALTQ
+	/*
+	 * save a pointer to the protocol level header before adding
+	 * link headers.
+	 */
+	pr_hdr.ph_family = dst->sa_family;
+	pr_hdr.ph_hdr = mtod(m, caddr_t);
+#endif /* ALTQ */
+
 #if NBPFILTER > 0
 	/* BPF write needs to be handled specially */
 	if (dst->sa_family == AF_UNSPEC) {
@@ -161,6 +189,8 @@
 	}
 #endif
 	m->m_pkthdr.rcvif = ifp;
+	if (rt && (rt->rt_flags & RTF_LOCAL))
+		m->m_pkthdr.rcvif = rt->rt_ifp;
 
 	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
 		m_freem(m);
@@ -173,6 +203,9 @@
 
 #ifdef INET
 	case AF_INET:
+#ifdef INET6
+	case AF_INET6:
+#endif
 		ifq = &ipintrq;
 		isr = NETISR_IP;
 		break;
@@ -207,6 +240,16 @@
 		m_freem(m);
 		return (EAFNOSUPPORT);
 	}
+#ifdef ALTQ
+	/* altq for loop is just for debugging */
+	if (ALTQ_IS_ON(ifp)) {
+	        int error;
+	        s = splimp();
+		error = (*ifp->if_altqenqueue)(ifp, m, &pr_hdr, ALTEQ_NORMAL);
+		splx(s);
+		return (error);
+	}
+#endif /* ALTQ */
 	s = splimp();
 	if (IF_QFULL(ifq)) {
 		IF_DROP(ifq);
@@ -222,6 +265,47 @@
 	return (0);
 }
 
+#ifdef ALTQ
+static void
+lo_altqstart(ifp)
+    struct ifnet *ifp;
+{
+    struct ifqueue *ifq;
+    struct mbuf *m;
+    int s, isr;
+
+    if (!ALTQ_IS_ON(ifp))
+	return;
+    
+    while (1) {
+	s = splimp();
+	m = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+	splx(s);
+
+	if (!m)
+	    return;
+
+#ifdef INET
+	/* todo: should support other protocols */
+	ifq = &ipintrq;
+	isr = NETISR_IP;
+#endif
+	s = splimp();
+	if (IF_QFULL(ifq)) {
+	    IF_DROP(ifq);
+	    m_freem(m);
+	    splx(s);
+	    return;
+	}
+	IF_ENQUEUE(ifq, m);
+	schednetisr(isr);
+	ifp->if_ipackets++;
+	ifp->if_ibytes += m->m_pkthdr.len;
+	splx(s);
+    }
+}
+#endif /* ALTQ */
+
 /* ARGSUSED */
 static void
 lortrequest(cmd, rt, sa)
@@ -238,6 +322,11 @@
 		 */
 		rt->rt_rmx.rmx_recvpipe = 
 			rt->rt_rmx.rmx_sendpipe = 3 * LOMTU;
+		sa = rt->rt_ifa->ifa_addr;
+		if ((rt->rt_flags & RTF_HOST) &&
+		    (cmd == RTM_ADD) &&
+		    (bcmp(rt_key(rt), sa, sa->sa_len) == 0))
+			rt->rt_flags |= RTF_LOCAL;
 	}
 }
 
@@ -276,6 +365,10 @@
 
 #ifdef INET
 		case AF_INET:
+			break;
+#endif
+#ifdef INET6
+		case AF_INET6:
 			break;
 #endif
 
diff -uN src-current/sys/net/if_tun.c src-current-ipv6/sys/net/if_tun.c
--- src-current/sys/net/if_tun.c
+++ src-current-ipv6/sys/net/if_tun.c
@@ -19,6 +19,7 @@
 
 #include "opt_devfs.h"
 #include "opt_inet.h"
+#include "opt_inet6.h"
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -51,7 +52,15 @@
 
 #ifdef INET
 #include <netinet/in.h>
+#include <netinet/in_systm.h>
 #include <netinet/in_var.h>
+#include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/in6_var.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/if_ndp6.h>
+#endif
 #endif
 
 #ifdef NS
@@ -134,6 +143,9 @@
 		ifp->if_output = tunoutput;
 		ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
 		ifp->if_snd.ifq_maxlen = ifqmaxlen;
+#ifdef INET6
+		ifp->if_ndtype = IFND6_TUN;
+#endif
 		if_attach(ifp);
 #if NBPFILTER > 0
 		bpfattach(ifp, DLT_NULL, sizeof(u_int));
@@ -211,6 +223,13 @@
 			    rtinit(ifa, (int)RTM_DELETE,
 				   tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0);
 			}
+#ifdef INET6
+			else if (ifa->ifa_addr->sa_family == AF_INET6) {
+			    rtinit(ifa, (int)RTM_DELETE,
+				   tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0);
+
+			}
+#endif
 		    }
 		}
 		splx(s);
@@ -250,7 +269,21 @@
 			    tp->tun_flags |= TUN_DSTADDR;
 		}
 #endif
+#ifdef INET6
+		else if (ifa->ifa_addr->sa_family == AF_INET6) {
+		    struct sockaddr_in6 *si;
+
+		    si = (struct sockaddr_in6 *)ifa->ifa_addr;
+		    if (si && !IS_ANYADDR6(si->sin6_addr))
+			    tp->tun_flags |= TUN_IASET;
+
+		    si = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
+		    if (si && !IS_ANYADDR6(si->sin6_addr))
+			    tp->tun_flags |= TUN_DSTADDR;
+		}
+#endif
 	}
+
 	return 0;
 }
 
@@ -349,6 +382,9 @@
 	switch(dst->sa_family) {
 #ifdef INET
 	case AF_INET:
+#ifdef INET6
+	case AF_INET6:
+#endif
 		s = splimp();
 		if (IF_QFULL(&ifp->if_snd)) {
 			IF_DROP(&ifp->if_snd);
@@ -569,8 +605,14 @@
 		 * try to free it or keep a pointer to it).
 		 */
 		struct mbuf m;
-		u_int af = AF_INET;
-
+		u_int af;
+#ifdef INET6
+		struct ip *ip = mtod(top, struct ip *);
+
+		af = ip->ip_v == 6 ? AF_INET6 : AF_INET;
+#else
+		af = AF_INET;
+#endif
 		m.m_next = top;
 		m.m_len = 4;
 		m.m_data = (char *)&af;
diff -uN src-current/sys/net/netisr.h src-current-ipv6/sys/net/netisr.h
--- src-current/sys/net/netisr.h
+++ src-current-ipv6/sys/net/netisr.h
@@ -66,6 +66,7 @@
 #define NETISR_IPX	23		/* same as AF_IPX */
 #define	NETISR_ISDN	26		/* same as AF_E164 */
 #define	NETISR_PPP	27		/* PPP soft interrupt */
+#define	NETISR_IPV6	28		/* same as AF_INET6 (not used) */
 #define	NETISR_NATM	29		/* same as AF_NATM */
 
 #define	schednetisr(anisr)	{ netisr |= 1<<(anisr); setsoftnet(); }
diff -uN src-current/sys/net/ppp_defs.h src-current-ipv6/sys/net/ppp_defs.h
--- src-current/sys/net/ppp_defs.h
+++ src-current-ipv6/sys/net/ppp_defs.h
@@ -59,10 +59,12 @@
 #define PPP_IPX		0x2b	/* IPX Datagram (RFC1552) */
 #define	PPP_VJC_COMP	0x2d	/* VJ compressed TCP */
 #define	PPP_VJC_UNCOMP	0x2f	/* VJ uncompressed TCP */
+#define PPP_IPV6	0x57	/* IPv6 */
 #define PPP_COMP	0xfd	/* compressed packet */
 #define PPP_IPCP	0x8021	/* IP Control Protocol */
 #define PPP_ATCP	0x8029	/* AppleTalk Control Protocol */
 #define PPP_IPXCP	0x802b	/* IPX Control Protocol (RFC1552) */
+#define PPP_IPV6CP	0x8057	/* IPv6 Control Protocol */
 #define PPP_CCP		0x80fd	/* Compression Control Protocol */
 #define PPP_LCP		0xc021	/* Link Control Protocol */
 #define PPP_PAP		0xc023	/* Password Authentication Protocol */
diff -uN src-current/sys/net/radix.c src-current-ipv6/sys/net/radix.c
--- src-current/sys/net/radix.c
+++ src-current-ipv6/sys/net/radix.c
@@ -51,6 +51,9 @@
 #include <net/radix.h>
 #endif
 
+static struct radix_node *
+		rn_genmatch __P((void *v_arg,
+				 struct radix_node_head *head, int));
 static int	rn_walktree_from __P((struct radix_node_head *h, void *a,
 				      void *m, walktree_f_t *f, void *w));
 static int rn_walktree __P((struct radix_node_head *, walktree_f_t *, void *));
@@ -217,11 +220,29 @@
 	return 1;
 }
 
+/* Changes grabbed from Girish's code */
 struct radix_node *
 rn_match(v_arg, head)
 	void *v_arg;
 	struct radix_node_head *head;
 {
+	return rn_genmatch(v_arg, head, 0);
+}
+
+struct radix_node *
+rn_fullmatch(v_arg, head)
+	void *v_arg;
+	struct radix_node_head *head;
+{
+	return rn_genmatch(v_arg, head, 1);
+}
+
+static struct radix_node *
+rn_genmatch(v_arg, head, exact)
+	void *v_arg;
+	struct radix_node_head *head;
+	int exact;
+{
 	caddr_t v = v_arg;
 	register struct radix_node *t = head->rnh_treetop, *x;
 	register caddr_t cp = v, cp2;
@@ -255,8 +276,12 @@
 		vlen = *(u_char *)t->rn_mask;
 	cp += off; cp2 = t->rn_key + off; cplim = v + vlen;
 	for (; cp < cplim; cp++, cp2++)
-		if (*cp != *cp2)
-			goto on1;
+		if (*cp != *cp2) {
+			if (exact)
+				return 0;
+			else
+				goto on1;
+		}
 	/*
 	 * This extra grot is in case we are explicitly asked
 	 * to look up the default.  Ugh!
diff -uN src-current/sys/net/radix.h src-current-ipv6/sys/net/radix.h
--- src-current/sys/net/radix.h
+++ src-current-ipv6/sys/net/radix.h
@@ -164,7 +164,8 @@
 	 *rn_delete __P((void *, void *, struct radix_node_head *)),
 	 *rn_lookup __P((void *v_arg, void *m_arg,
 		        struct radix_node_head *head)),
-	 *rn_match __P((void *, struct radix_node_head *));
+	 *rn_match __P((void *, struct radix_node_head *)),
+	 *rn_fullmatch __P((void *, struct radix_node_head *));
 
 
 #endif /* _RADIX_H_ */
diff -uN src-current/sys/net/route.c src-current-ipv6/sys/net/route.c
--- src-current/sys/net/route.c
+++ src-current-ipv6/sys/net/route.c
@@ -35,6 +35,7 @@
  */
 
 #include "opt_inet.h"
+#include "opt_inet6.h"
 #include "opt_mrouting.h"
 
 #include <sys/param.h>
@@ -48,13 +49,25 @@
 #include <net/route.h>
 
 #include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
 #include <netinet/ip_mroute.h>
 
+#include <netinet/ip6.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/ip6_icmp.h>
+#include <netinet/ip6_opts.h>
+
 #define	SA(p) ((struct sockaddr *)(p))
 
 struct route_cb route_cb;
 static struct rtstat rtstat;
 struct radix_node_head *rt_tables[AF_MAX+1];
+struct radix_node_head *mfc_tables[AF_MAX+1];
 
 static int	rttrash;		/* routes not in table but not freed */
 
@@ -78,6 +91,7 @@
 {
 	rn_init();	/* initialize all zeroes, all ones, mask table */
 	rtable_init((void **)rt_tables);
+	rtable_init((void **)mfc_tables);
 }
 
 /*
@@ -420,6 +434,9 @@
 		if (rt == 0)
 			return (0);
 		rt->rt_refcnt--;
+		/* the gateway must be local... */
+		if (rt->rt_flags & RTF_GATEWAY)
+			return (0);
 		if ((ifa = rt->rt_ifa) == 0)
 			return (0);
 	}
@@ -987,6 +1004,8 @@
 			 * it doesn't exist, we could just return at this point
 			 * with an "ELSE" clause, but apparently not..
 			 */
+			if (m)
+				(void) m_free(m);
 			return (flags & RTF_HOST ? EHOSTUNREACH
 							: ENETUNREACH);
 		}
@@ -1028,8 +1047,10 @@
 		 * have already existed or something. (XXX)
 		 */
 		if (rt->rt_ifa != ifa) {
+#ifdef DIAGNOSTIC
 			printf("rtinit: wrong ifa (%p) was (%p)\n", ifa,
 				rt->rt_ifa);
+#endif
 			/*
 			 * Ask that the protocol in question
 			 * remove anything it has associated with
@@ -1047,6 +1068,7 @@
 			 */
 			rt->rt_ifa = ifa;
 			rt->rt_ifp = ifa->ifa_ifp;
+			rt->rt_flags = RTF_UP | flags | ifa->ifa_flags;
 			ifa->ifa_refcnt++;
 			/*
 			 * Now ask the protocol to check if it needs
@@ -1062,3 +1084,597 @@
 	}
 	return (error);
 }
+
+#ifdef INET6
+
+static void debug_dump_buf __P((void *, int));
+
+/* Grabbed from Girish's code, adapted by Yixin Jin */
+int                     
+mfcrequest(req, dst, ifpaddr, src, downstream, flags)
+        int req;
+        struct sockaddr *dst, *ifpaddr, *src, *downstream;
+	int flags; 
+{   
+        int s = splnet(), len, error = 0;   
+        register struct mfcentry *mfc = 0;
+        register struct radix_node *rn;
+        register struct radix_node_head *rnh;
+        struct ifaddr *ifa = 0;
+        struct sockaddr *key, *nkey;
+        struct ds_ifaddr *cur, *next;
+#define senderr(x) { error = x ; goto bad; }
+        
+        if ((rnh = mfc_tables[dst->sa_family]) == 0)
+                senderr(ESRCH);
+        key = sockmerge(dst, src);
+#ifdef MFC_DEBUG
+	printf("Source: ");
+	debug_dump_buf(src, sizeof(struct sockaddr_in6));
+	printf("Group: ");
+	debug_dump_buf(dst, sizeof(struct sockaddr_in6));
+#endif      
+        switch (req) {
+        case RTM_DELETE:
+#ifdef MFC_DEBUG
+		printf("It is RTM_DELETE for IPv6 multicast forwarding cache\n");
+#endif
+                if ((rn = rnh->rnh_deladdr((caddr_t)key, (caddr_t)0, rnh)) == 0) {
+#ifdef MFC_DEBUG
+			printf("RTM_DELETE doesn't succeed\n");
+#endif
+                        senderr(ESRCH);
+                }
+                if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
+                        panic ("mfcrequest delete");
+                mfc = (struct mfcentry *)rn;
+                mfc->mfc_flags &= ~RTF_UP;  
+		/*
+		 * Free existing downstream interface list
+		 */
+                cur = mfc->ds_list;
+                while (cur) { 
+                        next = cur->ds_next;
+                        Free(cur);
+                        cur = next;
+                }
+		/*
+		 * remove any queued up packets
+		 */
+                while (mfc->packet_q[mfc->mfc_head]) {
+                        (void) m_freem(mfc->packet_q[mfc->mfc_head]);
+                        mfc->packet_q[mfc->mfc_head] = (struct mbuf *) 0;
+                        mfc->mfc_head = (mfc->mfc_head+1) % MFC_PACKET_Q_SIZE;
+                }
+                if ((mfc->mfc_flags & RTF_XRESOLVE) && mfc->un_next) {
+                        unresolved_deq(mfc);
+                }
+                mfcfree(mfc);
+                break;
+
+        case RTM_ADD:   
+#ifdef MFC_DEBUG        
+		printf("It is RTM_ADD for IPv6 multicast forwarding cache\n");
+#endif          
+                if (ifpaddr) {
+                        ifa = ifa_ifwithaddr(ifpaddr);
+                        if (ifa == 0)
+                                senderr(EINVAL);
+                }        
+                len = sizeof (*mfc) + ROUNDUP(key->sa_len);
+                if (downstream) {  
+                        len += ROUNDUP(downstream->sa_len);
+                }       
+                R_Malloc(mfc, struct mfcentry *, len);
+                if (mfc == 0)
+                        senderr(ENOBUFS);
+                Bzero(mfc, len);
+                        
+                if (ifa) 
+                        mfc->upstream_ifp = ifa->ifa_ifp;
+                
+                if (downstream && ifa_locate_down(downstream, mfc)) {
+                        Free(mfc);
+                        senderr(EINVAL);
+                }
+                nkey = (struct sockaddr *)(mfc + 1); 
+                Bcopy(key, nkey, key->sa_len);
+                rn = rnh->rnh_addaddr((caddr_t)nkey, (caddr_t) 0,
+                                        rnh, mfc->rt_nodes);
+                if (rn == 0) {
+#ifdef MFC_DEBUG
+			printf("RTM_ADD doesn't succeed\n");
+#endif  
+                        Free(mfc);
+                        senderr(EEXIST); 
+                }
+                if (downstream) {
+                        mfc->downstream = (struct sockaddr *)
+                                        (rn->rn_key + ROUNDUP(key->sa_len));
+                        Bcopy(downstream, mfc->downstream, downstream->sa_len);
+                }        
+                mfc->mfc_flags = RTF_UP | flags;
+                break;
+                        
+        case RTM_CHANGE:
+                mfc = mfcalloc(dst, src);
+                if (mfc == 0)
+                        senderr(ESRCH);  
+                if (ifpaddr) {  
+                        ifa = ifa_ifwithaddr(ifpaddr);
+			if (ifa == 0)
+				ifa = ifa_ifwithdstaddr(ifpaddr);
+                        if (ifa == 0)
+                                senderr(EINVAL);
+                        mfc->upstream_ifp = ifa->ifa_ifp;
+                }
+		/*
+		 * Free existing downstream interface list
+		 * when anything changes since new entry
+		 * will contain complete list
+		 */
+                cur = mfc->ds_list;
+                while (cur) {
+                        next = cur->ds_next; 
+			Free(cur);
+                        cur = next; 
+                }
+                mfc->ds_list = (struct ds_ifaddr *) 0;
+                if (downstream) {
+                        if (ifa_locate_down(downstream, mfc)) {       
+                                senderr(EINVAL);
+                        }               
+                }       
+		/* entry has been completed. Start using it */
+                if ((mfc->mfc_flags & RTF_XRESOLVE) && ifpaddr) {
+			mfc->mfc_flags &= ~RTF_XRESOLVE;
+			if (mfc->un_next) {
+				/* If it is in unresolved entry queue */
+				unresolved_deq(mfc);
+			}
+                }
+                if (mfc->packet_q[mfc->mfc_head]) {
+                        mfc_requeue(dst->sa_family, &ipintrq, mfc);
+                }       
+                break;  
+        }                       
+bad:            
+        splx(s); 
+        return (error);   
+}                        
+                         
+struct mfcentry *        
+mfcalloc(dst, src)       
+        struct sockaddr *dst, *src;
+{     
+#if 0            
+        register struct radix_node_head *rnh = rt_tables[dst->sa_family];
+#else           
+        register struct radix_node_head *rnh = mfc_tables[dst->sa_family];
+#endif  
+        register struct mfcentry *mfc = (struct mfcentry *) 0;
+        register struct radix_node *rn;
+        register struct sockaddr *key = sockmerge(dst, src); 
+        int  s = splnet();
+                                
+        if (rnh && (rn = rn_fullmatch((caddr_t)key, rnh)) &&
+            ((rn->rn_flags & RNF_ROOT) == 0)) {
+                mfc = (struct mfcentry *) rn;
+        }               
+        splx(s);
+        return (mfc);   
+}               
+                
+int mfcfree(mfc)        
+        register struct mfcentry *mfc;
+{                       
+        if (mfc == 0)   
+                panic("mfcfree");
+        if ((mfc->mfc_flags & RTF_UP) == 0) {
+                if (mfc->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
+                        panic ("mfcfree 2");
+                Free(mfc);
+        }
+	return 1;
+}
+
+#if 0
+/*
+ * Store this packet in the circular buffer in the mfcentry associated
+ * with this group and source. This will be emptied out after the
+ * forwarding cache entry is completely built.
+ */
+
+static int
+mfc_addqueue(m, mfc)
+struct mbuf *m;
+struct mfcentry *mfc;
+{
+	int error = 0;
+	register struct mbuf *mcopy;
+
+	/*
+	 * if packet already there, must drop it before storing new one
+	 */
+	if (mfc->packet_q[mfc->mfc_tail]) {
+		m_freem(mfc->packet_q[mfc->mfc_tail]);
+		mfc->mfc_head = (mfc->mfc_head + 1) % MFC_PACKET_Q_SIZE;
+	}
+	if (mcopy = m_copy(m, 0, M_COPYALL)) {
+		mfc->packet_q[mfc->mfc_tail] = mcopy;
+		mfc->mfc_tail = (mfc->mfc_tail + 1) % MFC_PACKET_Q_SIZE;
+	} else {
+		error = ENOBUFS;
+	}
+	return(error);
+}
+
+/*
+ * Put stored multicast packets back on input queue.
+ * There is a circular buffer in the mfcentry that holds MFC_PACKET_Q_SIZE
+ * packets which is emptied into the protocol input queue if there is room.
+ * Otherwise, we just return and try again later.
+ */
+
+void
+mfc_requeue(fam, ifq, mfc)
+	int fam;	/* Which address family being talked about */ 
+	struct ifqueue *ifq;
+	struct mfcentry *mfc;
+{
+	int s = splimp();
+
+	while (!IF_QFULL(ifq) && mfc->packet_q[mfc->mfc_head]) {
+		register struct mbuf *m = mfc->packet_q[mfc->mfc_head];
+		switch (fam) {
+		case AF_INET: {
+			register struct ip *ip = mtod(m, struct ip *);
+			register int hlen = ip->ip_hl << 2;
+
+			/*
+			 * restore packet to previous state so ip_input
+			 * doesn't choke on it
+			 */
+			HTONS(ip->ip_len);
+			HTONS(ip->ip_id);
+			HTONS(ip->ip_off);
+			ip->ip_sum = in_cksum(m, hlen);
+			break;
+		}
+		case AF_INET6: {
+			register struct ipv6 *ip6 = mtod(m, struct ipv6 *);
+
+			HTONS(ip6->ip6_len);
+			break;
+		}
+		default:
+			printf("Unsupported family for multicasting(%d)\n",
+			       fam);
+			break;
+		}
+		mfc->packet_q[mfc->mfc_head] = (struct mbuf *) 0;
+		mfc->mfc_head = (mfc->mfc_head + 1) % MFC_PACKET_Q_SIZE;
+	    
+		IF_ENQUEUE(ifq, m);
+	}
+	splx(s);
+}
+
+/*
+ * Timeout routine. Age unresolved MFC entries
+ */
+
+static void
+mfctimer()
+{
+	int err;
+	struct mfcentry *mfc;
+
+	mfc = un_head.un_next;
+	while (mfc != &un_head) {
+		if ((mfc->mfc_flags & RTF_XRESOLVE) &&
+		    (mfc->mfc_un_timer++ < MFC_KILLU)) {
+			mfc = mfc->un_next;
+		} else {
+			struct mfcentry *next_mfc = mfc->un_next;
+			/*
+			 * timer has expired or mfc is resolved, clear entry
+			 */
+
+			unresolved_deq(mfc);
+
+			if (mfc->mfc_flags & RTF_XRESOLVE) { 
+				struct sockaddr_in6 sa_dst, sa_src;
+
+				mfc->mfc_flags &= ~RTF_XRESOLVE;
+				sockdata1(mfc_key(mfc), SA(&sa_dst));
+				sockdata2(mfc_key(mfc), SA(&sa_src));
+
+#ifdef MFC_DEBUG
+				printf("Timeout unsolved MFC entry\n");
+#endif
+				if (err = mfcrequest(RTM_DELETE, 
+						SA(&sa_dst), SA(0),
+						SA(&sa_src), SA(0), 
+						RTF_MULTICAST|RTF_HOST))
+				    log(LOG_ERR,
+					"ip_mroute: RTM_DELETE errno %d\n",
+					err);
+			}
+			mfc = next_mfc;
+		}
+	}
+	if (un_head.un_next == &un_head) {
+		restart_timer = 1;
+	} else {
+		timeout((timeout_func_t)mfctimer, (caddr_t) 0, MFC_AGE * hz);
+	}
+}
+
+/*
+ * Put an unresolved mfc in a linked list for easy timeout.
+ * Like insque, but pointers in middle of structure.
+ */
+static void 
+unresolved_enq(p, prev)
+	register struct mfcentry *p, *prev;
+{
+	p->un_prev = prev;
+	p->un_next = prev->un_next;
+	prev->un_next->un_prev = p;
+	prev->un_next = p;
+}
+
+/*
+ * To unresolved_enq as remque is to insque.
+ */
+void
+unresolved_deq(p)
+	register struct mfcentry *p;
+{
+	p->un_prev->un_next = p->un_next;
+	p->un_next->un_prev = p->un_prev;
+
+	p->un_next = (struct mfcentry *) 0;
+	p->un_prev = (struct mfcentry *) 0;
+	p->mfc_un_timer = 0;
+}
+#endif
+
+static struct sockaddr * 
+sockmerge(sa1, sa2)
+	struct sockaddr *sa1, *sa2;
+{       
+        caddr_t cp, cp1, cp2;
+        int len = 0;
+        static unsigned char sockbuf[sizeof(struct sockaddr_in6) * 2];
+        static struct sockaddr *sockdata = SA(sockbuf);
+        
+        bzero(sockbuf, sizeof(sockbuf));
+        sockdata->sa_family = sa1->sa_family;
+        sockdata->sa_len = sizeof(struct sockaddr_in6) * 2;
+        
+        switch (sa1->sa_family) {
+        case AF_INET: 
+                {       
+                        struct sockaddr_in *in;
+
+			in = (struct sockaddr_in *) sockdata;
+                        cp = (caddr_t) &in->sin_addr;
+                        in = (struct sockaddr_in *) sa1;
+                        cp1 = (caddr_t) &in->sin_addr;
+                        in = (struct sockaddr_in *) sa2;
+                        cp2 = (caddr_t) &in->sin_addr;
+                        len = sizeof(struct in_addr);
+                }
+                break;
+        
+        case AF_INET6:
+                {       
+                        struct sockaddr_in6 *in6;
+
+			in6 = (struct sockaddr_in6 *) sockdata;
+                        cp = (caddr_t) &in6->sin6_addr;
+                        in6 = (struct sockaddr_in6 *) sa1;
+                        cp1 = (caddr_t) &in6->sin6_addr;
+                        in6 = (struct sockaddr_in6 *) sa2;
+                        cp2 = (caddr_t) &in6->sin6_addr;
+                        len = sizeof (struct in6_addr);
+                }
+                break;
+        }
+        
+        if (len) {
+                bcopy(cp1, cp, len);
+                cp += len;
+                bcopy(cp2, cp, len);
+                return(sockdata);
+        }
+        return(SA(0));
+}               
+                        
+void                    
+sockdata1(sa, sockdata) 
+	struct sockaddr *sa, *sockdata; 
+{                       
+        int len = 0;    
+        caddr_t cp, cp2;
+                
+        
+        switch (sa->sa_family) {
+        case AF_INET:   
+                {       
+                        struct sockaddr_in *in = (struct sockaddr_in *) sa;
+                        cp2 = (caddr_t) &in->sin_addr;
+
+                        bzero(sockdata, sizeof(struct sockaddr));
+                        sockdata->sa_family = sa->sa_family;
+                        
+                        in = (struct sockaddr_in *) sockdata;
+                        in->sin_len = sizeof(*in);
+                        len = sizeof(struct in_addr);
+                        cp = (caddr_t) &in->sin_addr;
+                }
+                break;
+        case AF_INET6:
+                {
+                        struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) sa;
+                        cp2 = (caddr_t) &in6->sin6_addr;
+        
+                        bzero(sockdata, sizeof(struct sockaddr_in6));
+                        sockdata->sa_family = sa->sa_family;
+                
+                        in6 = (struct sockaddr_in6 *) sockdata;
+                        in6->sin6_len = sizeof(*in6);
+                        len = sizeof(struct in6_addr);
+                        cp = (caddr_t) &in6->sin6_addr;
+                }
+                break;  
+        default:
+                {
+                        bzero(sockdata, sizeof(struct sockaddr));
+                        sockdata->sa_family = sa->sa_family;
+                }
+                break;  
+                
+        }   
+        if (len) {      
+                bcopy(cp2, cp, len);
+        }               
+}                       
+                        
+void                    
+sockdata2(sa, sockdata) 
+	struct sockaddr *sa, *sockdata;
+{
+        int len = 0;
+        caddr_t cp, cp2;
+
+
+        switch (sa->sa_family) {
+        case AF_INET:
+                {
+                        struct sockaddr_in *in = (struct sockaddr_in *) sa;
+                        cp2 = (caddr_t) &in->sin_addr + sizeof(struct in_addr);
+
+                        bzero(sockdata, sizeof(struct sockaddr));
+                        sockdata->sa_family = sa->sa_family;
+
+                        in = (struct sockaddr_in *) sockdata;
+                        in->sin_len = sizeof(*in);
+                        len = sizeof(struct in_addr);
+                        cp = (caddr_t) &in->sin_addr;
+                }
+                break;
+        case AF_INET6:
+                {
+                        struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) sa;
+                        cp2 = (caddr_t) &in6->sin6_addr 
+                                + sizeof(struct in6_addr);
+         
+                        bzero(sockdata, sizeof(struct sockaddr_in6));
+                        sockdata->sa_family = sa->sa_family;
+                        
+                        in6 = (struct sockaddr_in6 *) sockdata;
+                        in6->sin6_len = sizeof(*in6);
+                        len = sizeof(struct in6_addr);
+                        cp = (caddr_t) &in6->sin6_addr;
+                }
+                break;
+        default:
+                {
+                        bzero(sockdata, sizeof(struct sockaddr));
+                        sockdata->sa_family = sa->sa_family;
+                }
+        }       
+        if (len) {      
+                bcopy(cp2, cp, len);
+        }
+}
+
+int
+ifa_locate_down(sa, mfc)
+	struct sockaddr *sa;	
+	struct mfcentry *mfc;	
+{			
+    int i = 0;	 
+    struct ds_ifaddr *cur, *next;
+    struct sockaddr_in6 sin6;
+    struct sockaddr_inds *sa_inds = (struct sockaddr_inds *) sa;
+    struct ds_in6addr *indsap = (struct ds_in6addr *) sa_inds->sin_data;
+	
+    bzero(&sin6, sizeof(sin6));
+    sin6.sin6_len = sizeof(struct sockaddr_in6);
+    sin6.sin6_family = AF_INET6;
+			
+    mfc->ds_list = cur = (struct ds_ifaddr *) 0;
+    while (sa_inds && i < sa_inds->sin_num) {
+	struct ifaddr *ifa = 0;
+	if (cur) {
+	    R_Malloc(cur->ds_next, struct ds_ifaddr *, sizeof(struct ds_ifaddr));
+	    cur = cur->ds_next;
+	} else {
+	    R_Malloc(mfc->ds_list, struct ds_ifaddr *, sizeof(struct ds_ifaddr));		       
+	    cur = mfc->ds_list;
+	}
+	cur->ds_next = 0;  
+	sin6.sin6_addr = indsap->sin6_addr; 
+    
+#ifdef MFC_DEBUG
+	printf("ifa_locate_down: %s\n", ip6_sprintf(&sin6.sin6_addr));
+#endif
+    
+	ifa = ifa_ifwithaddr(SA(&sin6));
+	if (ifa == 0)
+	    ifa = ifa_ifwithdstaddr(SA(&sin6));
+	if (ifa) {
+	    cur->ds_ifp = ifa->ifa_ifp;
+	    cur->min_hoplimit = indsap->hoplimit;
+	} else {
+	    /*
+	     * bad interface, free up current list
+	     */
+	    cur = mfc->ds_list;
+	    while (cur) {
+		next = cur->ds_next;
+		Free(cur);
+		cur = next;
+	    }	
+	    mfc->ds_list = 0;  
+	    return(1);
+	}
+	i++;
+	indsap++;
+    }
+    return(0);
+}		
+		
+/* Grabbed from Girish's code */
+		
+/* Some debug routines, so far only used for IPv6 multicast forwarding
+ * But it is generic enough to be used any where else. Then route.c
+ * may not be the right place to put it in. Yixin */
+static void
+debug_dump_buf(void *buf, int len)
+{
+    int col = 0;
+    int i=0;
+    char *p;
+
+    p = (char *)buf;
+    while(i < len/4){
+	printf("%02x",*p++);
+	printf("%02x",*p++);
+	printf("%02x",*p++);
+	printf("%02x ",*p++);
+	i++;
+	col++;
+	if (col > 7){
+	    col=0;
+	    printf("\n");
+	}
+    }
+    printf("\n\n");
+}
+
+#endif
diff -uN src-current/sys/net/route.h src-current-ipv6/sys/net/route.h
--- src-current/sys/net/route.h
+++ src-current-ipv6/sys/net/route.h
@@ -114,7 +114,7 @@
 				  struct sockaddr *, struct rtentry *));
 					/* output routine for this (rt,if) */
 	struct	rtentry *rt_parent; 	/* cloning parent of this route */
-	void	*rt_filler2;		/* more filler */
+	struct	mbuf *rt_xoptions;	/* extensions */
 };
 
 /*
@@ -139,27 +139,67 @@
 #define	RTF_REJECT	0x8		/* host or net unreachable */
 #define	RTF_DYNAMIC	0x10		/* created dynamically (by redirect) */
 #define	RTF_MODIFIED	0x20		/* modified dynamically (by redirect) */
-#define RTF_DONE	0x40		/* message confirmed */
+#define	RTF_DONE	0x40		/* message confirmed */
 /*			0x80		   unused */
-#define RTF_CLONING	0x100		/* generate new routes on use */
-#define RTF_XRESOLVE	0x200		/* external daemon resolves name */
-#define RTF_LLINFO	0x400		/* generated by link layer (e.g. ARP) */
-#define RTF_STATIC	0x800		/* manually added */
-#define RTF_BLACKHOLE	0x1000		/* just discard pkts (during updates) */
-#define RTF_PROTO2	0x4000		/* protocol specific routing flag */
-#define RTF_PROTO1	0x8000		/* protocol specific routing flag */
-
-#define RTF_PRCLONING	0x10000		/* protocol requires cloning */
-#define RTF_WASCLONED	0x20000		/* route generated through cloning */
-#define RTF_PROTO3	0x40000		/* protocol specific routing flag */
-/*			0x80000		   unused */
-#define RTF_PINNED	0x100000	/* future use */
+#define	RTF_CLONING	0x100		/* generate new routes on use */
+#define	RTF_XRESOLVE	0x200		/* external daemon resolves name */
+#define	RTF_LLINFO	0x400		/* generated by link layer (e.g. ARP) */
+#define	RTF_STATIC	0x800		/* manually added */
+#define	RTF_BLACKHOLE	0x1000		/* just discard pkts (during updates) */
+#define	RTF_BUL		0x2000		/* has a binding update list */
+#define	RTF_PROTO2	0x4000		/* protocol specific routing flag */
+#define	RTF_PROTO1	0x8000		/* protocol specific routing flag */
+#define	RTF_PRCLONING	0x10000		/* protocol requires cloning */
+#define	RTF_WASCLONED	0x20000		/* route generated through cloning */
+#define	RTF_PROTO3	0x40000		/* protocol specific routing flag */
+#define	RTF_BCE		0x80000		/* has a binding cache entry */
+#define	RTF_PINNED	0x100000	/* future use */
 #define	RTF_LOCAL	0x200000 	/* route represents a local address */
 #define	RTF_BROADCAST	0x400000	/* route represents a bcast address */
 #define	RTF_MULTICAST	0x800000	/* route represents a mcast address */
 					/* 0x1000000 and up unassigned */
 
 /*
+ * Extension common header.
+ */
+struct	rt_xohdr {
+    void (*rt_xofree) __P((struct rtentry *, struct mbuf **, void *));
+    struct mbuf *(*rt_xomatch) __P((struct rtentry *, struct mbuf *, void *));
+};
+
+/* Grabbed from Girish's code */
+
+#define MFC_PACKET_Q_SIZE	5	/* must be between 1 and 10 */
+#define MAX_PACKET_Q_SIZE	7	/* fixed for comparison to rtentry */
+
+struct mfcentry {
+        struct  radix_node rt_nodes[2]; /* tree glue, and other values */
+#define mfc_key(r)      ((struct sockaddr *)((r)->rt_nodes->rn_key))
+        struct  ifnet *upstream_ifp;    /* for tree based routing */
+        u_long  mfc_flags;              /* flags */
+        u_short mfc_un_timer;           /* timeout value of unresolved entry */
+        struct  sockaddr *downstream;   /* the answer: interfaces to use */
+        struct  ds_ifaddr *ds_list;     /* the answer: for faster forwarding */
+        struct  mfcentry *un_prev;      /* linked list of unresolved entries */
+        struct  mfcentry *un_next;      /* linked list of unresolved entries */
+        u_long  mfc_use;                /* raw # packets forwarded */
+        u_long  mfc_ctime;              /* time cache entry created */
+        u_long  mfc_utime;              /* last use time */
+        u_short mfc_head;               /* position of first packet in buffer */
+        u_short mfc_tail;               /* position of last packet in buffer */
+        struct  mbuf *packet_q[MFC_PACKET_Q_SIZE];
+        struct  mbuf *unused[MAX_PACKET_Q_SIZE - MFC_PACKET_Q_SIZE];
+};
+
+struct ds_ifaddr {
+        struct  ds_ifaddr *ds_next;     /* next down stream ifaddr */
+        struct  ifnet *ds_ifp;          /* the interface to use */
+        struct  sockaddr ds_nbr;        /* the nbma nbr address */
+        u_short min_hoplimit;           /* min ttl required to forward */
+        u_short ds_flags;               /* downstream flags */
+};
+
+/*
  * Routing statistics.
  */
 struct	rtstat {
@@ -205,6 +245,9 @@
 #define RTM_IFINFO	0xe	/* iface going up/down etc. */
 #define	RTM_NEWMADDR	0xf	/* mcast group membership being added to if */
 #define	RTM_DELMADDR	0x10	/* mcast group membership being deleted */
+#define RTM_EXPIRE	0x11	/* Route has Expired */
+#define RTM_RTLOST	0x12	/* Router has been Lost */
+#define RTM_GETNEXT	0x13	/* get next route */
 
 #define RTV_MTU		0x1	/* init or lock _mtu */
 #define RTV_HOPCOUNT	0x2	/* init or lock _hopcount */
@@ -226,6 +269,7 @@
 #define RTA_IFA		0x20	/* interface addr sockaddr present */
 #define RTA_AUTHOR	0x40	/* sockaddr for author of redirect */
 #define RTA_BRD		0x80	/* for NEWADDR, broadcast or p-p dest addr */
+#define RTA_DOWNSTREAM	0x100	/* multicast downstream sockaddr present */
 
 /*
  * Index offsets for sockaddr array for alternate internal encoding.
@@ -238,7 +282,8 @@
 #define RTAX_IFA	5	/* interface addr sockaddr present */
 #define RTAX_AUTHOR	6	/* sockaddr for author of redirect */
 #define RTAX_BRD	7	/* for NEWADDR, broadcast or p-p dest addr */
-#define RTAX_MAX	8	/* size of array to allocate */
+#define RTAX_DOWNSTREAM	8	/* multicast downstream sockaddr present */
+#define RTAX_MAX	9	/* size of array to allocate */
 
 struct rt_addrinfo {
 	int	rti_addrs;
@@ -262,6 +307,7 @@
 
 extern struct route_cb route_cb;
 extern struct radix_node_head *rt_tables[AF_MAX+1];
+extern struct radix_node_head *mfc_tables[AF_MAX+1];
 
 struct ifmultiaddr;
 struct proc;
@@ -284,6 +330,21 @@
 	    struct sockaddr *, int, struct sockaddr *, struct rtentry **));
 int	 rtrequest __P((int, struct sockaddr *,
 	    struct sockaddr *, struct sockaddr *, int, struct rtentry **));
+
+#ifdef INET6
+struct mfcentry *
+        mfcalloc __P((struct sockaddr *, struct sockaddr *));
+int mfcrequest __P((int, struct sockaddr *, struct sockaddr *,
+            struct sockaddr *, struct sockaddr *, int));
+int mfcfree __P((register struct mfcentry *));
+void mfc_requeue __P((int, struct ifqueue *, struct mfcentry *));
+void unresolved_deq __P((struct mfcentry *));
+static struct sockaddr *
+    sockmerge __P((struct sockaddr *, struct sockaddr *));
+void sockdata1 __P((struct sockaddr *, struct sockaddr *));
+void sockdata2 __P((struct sockaddr *, struct sockaddr *));
+int ifa_locate_down __P((struct sockaddr *, struct mfcentry *));
+#endif
 #endif
 
 #endif
diff -uN src-current/sys/net/rtsock.c src-current-ipv6/sys/net/rtsock.c
--- src-current/sys/net/rtsock.c
+++ src-current-ipv6/sys/net/rtsock.c
@@ -34,6 +34,7 @@
  *	$Id: rtsock.c,v 1.37 1997/10/31 08:53:13 davidg Exp $
  */
 
+#include "opt_inet6.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -83,6 +84,8 @@
 #define ifpaddr	info.rti_info[RTAX_IFP]
 #define ifaaddr	info.rti_info[RTAX_IFA]
 #define brdaddr	info.rti_info[RTAX_BRD]
+#define src	info.rti_info[RTAX_AUTHOR]
+#define dsaddr	info.rti_info[RTAX_DOWNSTREAM]
 
 /*
  * It really doesn't make any sense at all for this code to share much
@@ -131,6 +134,7 @@
 	}
 	switch(rp->rcb_proto.sp_protocol) {
 	case AF_INET:
+	case AF_INET6:
 		route_cb.ip_count++;
 		break;
 	case AF_IPX:
@@ -277,6 +281,9 @@
 {
 	register struct rt_msghdr *rtm = 0;
 	register struct rtentry *rt = 0;
+#ifdef INET6
+	register struct mfcentry *mfc = 0;
+#endif
 	struct rtentry *saved_nrt = 0;
 	struct radix_node_head *rnh;
 	struct rt_addrinfo info;
@@ -323,6 +330,60 @@
 		else
 			senderr(ENOBUFS);
 	}
+#ifdef INET6
+	/* Grabbed from Girish's code, adapted by Yixin Jin */
+	if (rtm->rtm_flags & RTF_MULTICAST) {
+		if (src == 0)
+			senderr(EINVAL);
+		switch (rtm->rtm_type) {
+    
+		case RTM_ADD:
+		case RTM_DELETE:
+		case RTM_CHANGE:
+#ifdef MFC_DEBUG
+			printf("Calling mfcreq: with flags 0x%0x\n",
+			       rtm->rtm_flags);
+#endif 
+			error = mfcrequest(rtm->rtm_type, dst, ifpaddr, src,
+					   dsaddr, rtm->rtm_flags);
+			break;
+		case RTM_GET: 
+			mfc = mfcalloc(dst, src);
+			if (mfc == 0)
+				senderr(ESRCH);
+			ifpaddr = 0;
+			if (mfc->upstream_ifp) {
+				ifa = TAILQ_FIRST(&mfc->upstream_ifp->if_addrhead);
+				if (ifa) {
+					ifpaddr = ifa->ifa_addr;
+				}
+			}
+			dsaddr = mfc->downstream;
+			len = rt_msg2(RTM_GET, &info, (caddr_t)0,
+				      (struct walkarg *)0);
+			if (len > rtm->rtm_msglen) { 
+				struct rt_msghdr *new_rtm;
+				R_Malloc(new_rtm, struct rt_msghdr *, len);
+				if (new_rtm == 0)
+					senderr(ENOBUFS);
+				Bcopy(rtm, new_rtm, rtm->rtm_msglen);
+				Free(rtm);
+				rtm = new_rtm;
+			}
+			(void)rt_msg2(RTM_GET, &info, (caddr_t)rtm,
+				      (struct walkarg *)0);
+			rtm->rtm_use = mfc->mfc_use;
+			rtm->rtm_flags = mfc->mfc_flags;
+			rtm->rtm_addrs = info.rti_addrs;
+
+			break;
+		/* Add GETNEXT ! */
+		default:
+			senderr(EOPNOTSUPP);
+		}	
+		goto flush;   
+	}		
+#endif
 	switch (rtm->rtm_type) {
 
 	case RTM_ADD:
@@ -331,13 +392,39 @@
 		error = rtrequest(RTM_ADD, dst, gate, netmask,
 					rtm->rtm_flags, &saved_nrt);
 		if (error == 0 && saved_nrt) {
-			rt_setmetrics(rtm->rtm_inits,
-				&rtm->rtm_rmx, &saved_nrt->rt_rmx);
-			saved_nrt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
-			saved_nrt->rt_rmx.rmx_locks |=
-				(rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
-			saved_nrt->rt_refcnt--;
-			saved_nrt->rt_genmask = genmask;
+		    register struct ifaddr *oifa = saved_nrt->rt_ifa;
+
+		    if (ifpaddr) {
+			ifa = ifa_ifwithnet(ifpaddr);
+			if (ifa)
+			    ifp = ifa->ifa_ifp;
+			if (ifp)
+			    ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,
+						ifp);
+		    }
+		    if ((ifp == 0) && ifaaddr)
+			ifa = ifa_ifwithaddr(ifaaddr);
+		    if (ifa) {
+			if (oifa != ifa) {
+			    if (oifa && oifa->ifa_rtrequest)
+				oifa->ifa_rtrequest(RTM_DELETE,
+						saved_nrt, gate);
+			    IFAFREE(saved_nrt->rt_ifa);
+			    saved_nrt->rt_ifa = ifa;
+			    ifa->ifa_refcnt++;
+			    saved_nrt->rt_ifp = ifa->ifa_ifp;
+			} else
+			    ifa = 0;
+		    }
+		    rt_setmetrics(rtm->rtm_inits,
+				  &rtm->rtm_rmx, &saved_nrt->rt_rmx);
+		    if (ifa && ifa->ifa_rtrequest)
+			ifa->ifa_rtrequest(RTM_ADD, saved_nrt, gate);
+		    saved_nrt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
+		    saved_nrt->rt_rmx.rmx_locks |=
+			(rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
+		    saved_nrt->rt_refcnt--;
+		    saved_nrt->rt_genmask = genmask;
 		}
 		break;
 
@@ -354,6 +441,7 @@
 	case RTM_GET:
 	case RTM_CHANGE:
 	case RTM_LOCK:
+	case RTM_GETNEXT:
 		if ((rnh = rt_tables[dst->sa_family]) == 0) {
 			senderr(EAFNOSUPPORT);
 		} else if (rt = (struct rtentry *)
@@ -448,6 +536,37 @@
 			rt->rt_rmx.rmx_locks |=
 				(rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
 			break;
+
+		case RTM_GETNEXT: {
+			register struct radix_node *rn;
+			int s = splnet();
+
+			rn = (struct radix_node *)rt;
+			saved_nrt = rt;
+			/* if dupedkey get it */
+			if (rn->rn_dupedkey) {
+				rt = (struct rtentry *)rn->rn_dupedkey;
+				goto found;
+			}
+			/* if right child go back up */
+			while (rn->rn_p->rn_r == rn &&
+			       (rn->rn_flags & RNF_ROOT) == 0)
+				rn = rn->rn_p;
+			/* then goto left */
+			for (rn = rn->rn_p->rn_r; rn->rn_b >= 0;)
+				rn = rn->rn_l;
+			rt = (struct rtentry *)rn;
+		found:
+			if (rn->rn_flags & RNF_ROOT) {
+				rt = saved_nrt;
+				splx(s);
+				senderr(ESRCH);
+			}
+			rt->rt_refcnt++;
+			splx(s);
+			rtfree(saved_nrt);
+			goto report;
+			}
 		}
 		break;
 
@@ -852,24 +971,58 @@
 {
 	register struct walkarg *w = vw;
 	register struct rtentry *rt = (struct rtentry *)rn;
+#ifdef INET6
+	register struct mfcentry *mfc = (struct mfcentry *)rn;
+	char sa1[64], sa2[64];
+	struct ifaddr *ifa = 0;
+#endif
 	int error = 0, size;
 	struct rt_addrinfo info;
 
 	if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
 		return 0;
 	bzero((caddr_t)&info, sizeof(info));
-	dst = rt_key(rt);
-	gate = rt->rt_gateway;
-	netmask = rt_mask(rt);
-	genmask = rt->rt_genmask;
+#ifdef INET6
+	if (w->w_arg & RTF_MULTICAST) {
+		dst = (struct sockaddr *)sa1;
+		src = (struct sockaddr *)sa2;
+		sockdata1(mfc_key(mfc), dst);
+		sockdata2(mfc_key(mfc), src);
+		if (mfc->upstream_ifp &&
+		    (ifa = TAILQ_FIRST(&mfc->upstream_ifp->if_addrhead))) {
+			ifpaddr = ifa->ifa_addr;
+		}
+		dsaddr = mfc->downstream;
+#ifdef MFC_DEBUG
+		printf("sysctl_dumpentry(): ");
+		printf("Dumping IPv6 multicast forwarding cache\n");
+		printf("And it is for RTF_MULTICAST\n");
+#endif
+	} else
+#endif
+	{
+		dst = rt_key(rt);
+		gate = rt->rt_gateway;
+		netmask = rt_mask(rt);
+		genmask = rt->rt_genmask;
+	}
 	size = rt_msg2(RTM_GET, &info, 0, w);
 	if (w->w_req && w->w_tmem) {
 		register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
 
-		rtm->rtm_flags = rt->rt_flags;
-		rtm->rtm_use = rt->rt_use;
-		rtm->rtm_rmx = rt->rt_rmx;
-		rtm->rtm_index = rt->rt_ifp->if_index;
+#ifdef INET6
+		if (w->w_arg & RTF_MULTICAST) {
+			rtm->rtm_flags = mfc->mfc_flags;
+			rtm->rtm_use = mfc->mfc_use;
+			rtm->rtm_index = 0;
+		} else
+#endif
+		{
+			rtm->rtm_flags = rt->rt_flags;
+			rtm->rtm_use = rt->rt_use;
+			rtm->rtm_rmx = rt->rt_rmx;
+			rtm->rtm_index = rt->rt_ifp->if_index;
+		}
 		rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
 		rtm->rtm_addrs = info.rti_addrs;
 		error = SYSCTL_OUT(w->w_req, (caddr_t)rtm, size);
@@ -960,10 +1113,25 @@
 
 	case NET_RT_DUMP:
 	case NET_RT_FLAGS:
+#ifdef INET6
+#ifdef MFC_DEBUG
+		if (w.w_op == NET_RT_DUMP)
+			printf("We got NET_RT_DUMP\n");
+		if (w.w_arg == RTF_MULTICAST)
+			printf("We got RTF_MULTICAST\n");
+		if (af == AF_INET6)
+			printf("It is for AF_INET6\n");
+#endif
+		if ((af == AF_INET6) && (w.w_arg & RTF_MULTICAST)) {
+			rnh = mfc_tables[AF_INET6];
+			error = rnh->rnh_walktree(rnh, sysctl_dumpentry, &w);
+			break;
+		} /* else */
+#endif
 		for (i = 1; i <= AF_MAX; i++)
 			if ((rnh = rt_tables[i]) && (af == 0 || af == i) &&
 			    (error = rnh->rnh_walktree(rnh,
-							sysctl_dumpentry, &w)))
+						       sysctl_dumpentry, &w)))
 				break;
 		break;
 
diff -uN src-current/sys/net/if_arp.h src-current-ipv6/sys/net/if_arp.h
--- src-current/sys/net/if_arp.h
+++ src-current-ipv6/sys/net/if_arp.h
@@ -99,8 +99,8 @@
 	 * The ifnet struct _must_ be at the head of this structure.
 	 */
 	struct 	ifnet ac_if;		/* network-visible interface */
-	u_char	ac_enaddr[6];		/* ethernet hardware address */
-	int	ac_multicnt;		/* length of ac_multiaddrs list */
+	u_char	ac_enaddr[ETHER_ADDR_LEN]; /* ethernet hardware address */
+	struct	in6_addr ac_llip6;	/* link-local address */
 };
 
 extern u_char	etherbroadcastaddr[6];
diff -uN src-current/sys/net/if_var.h src-current-ipv6/sys/net/if_var.h
--- src-current/sys/net/if_var.h
+++ src-current-ipv6/sys/net/if_var.h
@@ -62,6 +62,8 @@
  * interfaces.  These routines live in the files if.c and route.c
  */
 
+#include <net/if_altq.h>
+
 #ifdef __STDC__
 /*
  * Forward structure declarations for function prototypes [sic].
@@ -138,6 +140,16 @@
 		__P((struct ifnet *, struct sockaddr **, struct sockaddr *));
 	struct	ifqueue if_snd;		/* output queue */
 	struct	ifqueue *if_poll_slowq;	/* input queue for slow devices */
+#ifdef ALTQ
+	/* alternate queueing related stuff */
+	int	if_altqtype;		/* queueing scheme id */
+	int	if_altqflags;		/* altq flags (e.g. ready, in-use) */
+	void	*if_altqp;		/* queue state */
+	int	(*if_altqenqueue)
+		__P((struct ifnet *, struct mbuf *, struct pr_hdr *, int));
+	struct mbuf *(*if_altqdequeue)
+		__P((struct ifnet *, int));
+#endif
 };
 typedef void if_init_f_t __P((void *));
 
@@ -148,6 +160,8 @@
 #define	if_hdrlen	if_data.ifi_hdrlen
 #define	if_metric	if_data.ifi_metric
 #define	if_baudrate	if_data.ifi_baudrate
+#define	if_site6	if_data.ifi_site6
+#define	if_ndtype	if_data.ifi_ndtype
 #define	if_ipackets	if_data.ifi_ipackets
 #define	if_ierrors	if_data.ifi_ierrors
 #define	if_opackets	if_data.ifi_opackets
diff -uN src-current/sys/net/bpf.c src-current-ipv6/sys/net/bpf.c
--- src-current/sys/net/bpf.c
+++ src-current-ipv6/sys/net/bpf.c
@@ -197,6 +197,16 @@
 		hlen = 0;
 		break;
 
+#ifdef ALTQ
+	/*
+	 * added for en atm driver.  atm pseudo header isn't standard
+	 * but vpi:vci need to be specified anyway.
+	 */
+	case DLT_ATM_RFC1483:
+		sockp->sa_family = AF_UNSPEC;
+		hlen = 12;	/* XXX 4(ATM_PH) + 3(LLC) + 5(SNAP) */
+		break;
+#endif
 	default:
 		return (EIO);
 	}
diff -uN src-current/sys/netinet/in_rmx.c src-current-ipv6/sys/netinet/in_rmx.c
--- src-current/sys/netinet/in_rmx.c
+++ src-current-ipv6/sys/netinet/in_rmx.c
@@ -55,6 +55,12 @@
 #include <netinet/in.h>
 #include <netinet/in_var.h>
 
+#include <netinet/if_ether.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip6_var.h>
+
 extern int	in_inithead __P((void **head, int off));
 
 #define RTPRF_OURS		RTF_PROTO3	/* set on routes we manage */
@@ -100,11 +106,9 @@
 		if (in_broadcast(sin->sin_addr, rt->rt_ifp)) {
 			rt->rt_flags |= RTF_BROADCAST;
 		} else {
-#define satosin(sa) ((struct sockaddr_in *)sa)
 			if (satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr
 			    == sin->sin_addr.s_addr)
 				rt->rt_flags |= RTF_LOCAL;
-#undef satosin
 		}
 	}
 
@@ -124,9 +128,11 @@
 				RTF_CLONING | RTF_PRCLONING);
 		if (rt2) {
 			if (rt2->rt_flags & RTF_LLINFO &&
-				rt2->rt_flags & RTF_HOST &&
-				rt2->rt_gateway &&
-				rt2->rt_gateway->sa_family == AF_LINK) {
+			    rt2->rt_flags & RTF_HOST &&
+			    rt2->rt_gateway &&
+			    rt2->rt_gateway->sa_family == AF_LINK &&
+			    rt2->rt_ifa &&
+			    rt2->rt_ifa->ifa_rtrequest == arp_rtrequest) {
 				rtrequest(RTM_DELETE,
 					  (struct sockaddr *)rt_key(rt2),
 					  rt2->rt_gateway,
@@ -368,6 +374,7 @@
 struct in_ifadown_arg {
 	struct radix_node_head *rnh;
 	struct ifaddr *ifa;
+	struct rtentry *rt;
 };
 
 static int
diff -uN src-current/sys/netinet/ip_flow.c src-current-ipv6/sys/netinet/ip_flow.c
diff -uN src-current/sys/netinet/ip_var.h src-current-ipv6/sys/netinet/ip_var.h
diff -uN src-current/sys/netinet/ip_fw.c src-current-ipv6/sys/netinet/ip_fw.c
diff -uN src-current/sys/netinet/in_var.h src-current-ipv6/sys/netinet/in_var.h
diff -uN src-current/sys/netinet/ip_flow.h src-current-ipv6/sys/netinet/ip_flow.h
--- src-current/sys/netinet/ip_flow.h
+++ src-current-ipv6/sys/netinet/ip_flow.h
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the 3am Software Foundry ("3am").  It was developed by Matt Thomas.
+ *
+ * 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 NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ *
+ * $Id: ip_flow.h,v 1.1 1998/05/19 15:53:49 pb Exp $
+ */
+
+#ifndef _NETINET_IP_FLOW_H
+#define _NETINET_IP_FLOW_H
+
+struct ipflow {
+	LIST_ENTRY(ipflow) ipf_next;	/* next ipflow in bucket */
+	struct in_addr ipf_dst;		/* destination address */
+	struct in_addr ipf_src;		/* source address */
+
+	u_int8_t ipf_tos;		/* type-of-service */
+	struct route ipf_ro;		/* associated route entry */
+	u_long ipf_uses;		/* number of uses in this period */
+
+	int ipf_timer;			/* remaining lifetime of this entry */
+	u_long ipf_dropped;		/* ENOBUFS returned by if_output */
+	u_long ipf_errors;		/* other errors returned by if_output */
+	u_long ipf_last_uses;		/* number of uses in last period */
+};
+
+#endif
diff -uN src-current/sys/netinet/ip_input.c src-current-ipv6/sys/netinet/ip_input.c
--- src-current/sys/netinet/ip_input.c
+++ src-current-ipv6/sys/netinet/ip_input.c
@@ -38,6 +38,8 @@
 #define	_IP_VHL
 
 #include "opt_bootp.h"
+#include "opt_inet6.h"
+#include "opt_ipflow.h"
 #include "opt_ipfw.h"
 #include "opt_ipdivert.h"
 #include "opt_ipfilter.h"
@@ -65,8 +67,15 @@
 #include <netinet/in_systm.h>
 #include <netinet/in_var.h>
 #include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif
+#include <netinet/ipsec.h>
 #include <netinet/in_pcb.h>
 #include <netinet/ip_var.h>
+#ifdef INET6
+#include <netinet/ip6_var.h>
+#endif
 #include <netinet/ip_icmp.h>
 #include <machine/in_cksum.h>
 
@@ -199,8 +208,8 @@
 void
 ip_init()
 {
-	register struct protosw *pr;
-	register int i;
+	struct protosw *pr;
+	int i;
 
 	TAILQ_INIT(&in_ifaddrhead);
 	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
@@ -279,8 +288,13 @@
 	ip = mtod(m, struct ip *);
 
 	if (IP_VHL_V(ip->ip_vhl) != IPVERSION) {
+#ifdef INET6
+		ip6_input(m, 0);
+		return;
+#else
 		ipstat.ips_badvers++;
 		goto bad;
+#endif
 	}
 
 	hlen = IP_VHL_HL(ip->ip_vhl) << 2;
@@ -648,12 +662,12 @@
  */
 static struct ip *
 ip_reass(ip, fp, where)
-	register struct ipasfrag *ip;
-	register struct ipq *fp;
+	struct ipasfrag *ip;
+	struct ipq *fp;
 	struct   ipq    *where;
 {
-	register struct mbuf *m = dtom(ip);
-	register struct ipasfrag *q;
+	struct mbuf *m = dtom(ip);
+	struct ipasfrag *q;
 	struct mbuf *t;
 	int hlen = ip->ip_hl << 2;
 	int i, next;
@@ -816,7 +830,7 @@
 	m->m_data -= (ip->ip_hl << 2);
 	/* some debugging cruft by sklower, below, will go away soon */
 	if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */
-		register int plen = 0;
+		int plen = 0;
 		for (t = m; m; m = m->m_next)
 			plen += m->m_len;
 		t->m_pkthdr.len = plen;
@@ -837,7 +851,7 @@
 ip_freef(fp)
 	struct ipq *fp;
 {
-	register struct ipasfrag *q, *p;
+	struct ipasfrag *q, *p;
 
 	for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) {
 		p = q->ipf_next;
@@ -855,7 +869,7 @@
  */
 static void
 ip_enq(p, prev)
-	register struct ipasfrag *p, *prev;
+	struct ipasfrag *p, *prev;
 {
 
 	p->ipf_prev = prev;
@@ -869,7 +883,7 @@
  */
 static void
 ip_deq(p)
-	register struct ipasfrag *p;
+	struct ipasfrag *p;
 {
 
 	p->ipf_prev->ipf_next = p->ipf_next;
@@ -884,7 +898,7 @@
 void
 ip_slowtimo()
 {
-	register struct ipq *fp;
+	struct ipq *fp;
 	int s = splnet();
 	int i;
 
@@ -933,10 +947,10 @@
 ip_dooptions(m)
 	struct mbuf *m;
 {
-	register struct ip *ip = mtod(m, struct ip *);
-	register u_char *cp;
-	register struct ip_timestamp *ipt;
-	register struct in_ifaddr *ia;
+	struct ip *ip = mtod(m, struct ip *);
+	u_char *cp;
+	struct ip_timestamp *ipt;
+	struct in_ifaddr *ia;
 	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
 	struct in_addr *sin, dst;
 	n_time ntime;
@@ -1144,7 +1158,7 @@
 ip_rtaddr(dst)
 	 struct in_addr dst;
 {
-	register struct sockaddr_in *sin;
+	struct sockaddr_in *sin;
 
 	sin = (struct sockaddr_in *) &ipforward_rt.ro_dst;
 
@@ -1195,8 +1209,8 @@
 struct mbuf *
 ip_srcroute()
 {
-	register struct in_addr *p, *q;
-	register struct mbuf *m;
+	struct in_addr *p, *q;
+	struct mbuf *m;
 
 	if (ip_nhops == 0)
 		return ((struct mbuf *)0);
@@ -1265,12 +1279,12 @@
  */
 void
 ip_stripoptions(m, mopt)
-	register struct mbuf *m;
+	struct mbuf *m;
 	struct mbuf *mopt;
 {
-	register int i;
+	int i;
 	struct ip *ip = mtod(m, struct ip *);
-	register caddr_t opts;
+	caddr_t opts;
 	int olen;
 
 	olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
@@ -1311,9 +1325,9 @@
 	struct mbuf *m;
 	int srcrt;
 {
-	register struct ip *ip = mtod(m, struct ip *);
-	register struct sockaddr_in *sin;
-	register struct rtentry *rt;
+	struct ip *ip = mtod(m, struct ip *);
+	struct sockaddr_in *sin;
+	struct rtentry *rt;
 	int error, type = 0, code = 0;
 	struct mbuf *mcopy;
 	n_long dest;
@@ -1372,7 +1386,6 @@
 	 * Also, don't send redirect if forwarding using a default route
 	 * or a route modified by a redirect.
 	 */
-#define	satosin(sa)	((struct sockaddr_in *)(sa))
 	if (rt->rt_ifp == m->m_pkthdr.rcvif &&
 	    (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
 	    satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
@@ -1440,19 +1453,23 @@
 		break;
 
 	case ENOBUFS:
-		type = ICMP_SOURCEQUENCH;
-		code = 0;
-		break;
+		/*
+		 * don't generate ICMP_SOURCEQUENCH
+		 * (RFC1812 Requirements for IP Version 4 Routers)
+		 */
+		if (mcopy)
+			m_freem(mcopy);
+		return;
 	}
 	icmp_error(mcopy, type, code, dest, destifp);
 }
 
 void
 ip_savecontrol(inp, mp, ip, m)
-	register struct inpcb *inp;
-	register struct mbuf **mp;
-	register struct ip *ip;
-	register struct mbuf *m;
+	struct inpcb *inp;
+	struct mbuf **mp;
+	struct ip *ip;
+	struct mbuf *m;
 {
 	if (inp->inp_socket->so_options & SO_TIMESTAMP) {
 		struct timeval tv;
@@ -1463,12 +1480,34 @@
 		if (*mp)
 			mp = &(*mp)->m_next;
 	}
+#ifndef INET6
 	if (inp->inp_flags & INP_RECVDSTADDR) {
 		*mp = sbcreatecontrol((caddr_t) &ip->ip_dst,
 		    sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP);
 		if (*mp)
 			mp = &(*mp)->m_next;
 	}
+#else
+	if (inp->inp_flags & INP_RECVDSTADDR) {
+		struct in6_addr addr;
+
+		if (inp->inp_flags & INP_COMPATV6) {
+			addr.s6_addr32[0] = 0;
+			addr.s6_addr32[1] = 0;
+			addr.s6_addr32[2] = htonl(0xffff);
+			addr.s6_addr32[3] = ip->ip_dst.s_addr;
+			*mp = sbcreatecontrol((caddr_t) &addr,
+					      sizeof(struct in6_addr),
+					      IP_RECVDSTADDR, IPPROTO_IP);
+		} else {
+			*mp = sbcreatecontrol((caddr_t) &ip->ip_dst,
+					      sizeof(struct in_addr),
+					      IP_RECVDSTADDR, IPPROTO_IP);
+		}
+		if (*mp)
+			mp = &(*mp)->m_next;
+	}
+#endif
 #ifdef notyet
 	/* XXX
 	 * Moving these out of udp_input() made them even more broken
@@ -1489,6 +1528,23 @@
 			mp = &(*mp)->m_next;
 	}
 #endif
+#ifdef INET6
+	if ((inp->inp_flags & (INP_COMPATV6|INP_RECVPKTINFO)) ==
+			      (INP_COMPATV6|INP_RECVPKTINFO)) {
+		struct in6_pktinfo info;
+
+		info.ipi6_ifindex = m->m_pkthdr.rcvif ?
+		    m->m_pkthdr.rcvif->if_index : 0;
+		info.ipi6_addr.s6_addr32[0] = 0;
+		info.ipi6_addr.s6_addr32[1] = 0;
+		info.ipi6_addr.s6_addr32[2] = htonl(0xffff);
+		info.ipi6_addr.s6_addr32[3] = ip->ip_dst.s_addr;
+		*mp = sbcreatecontrol((caddr_t) &info,
+		    sizeof(struct in6_pktinfo), IPV6_PKTINFO, IPPROTO_IPV6);
+		if (*mp)
+			mp = &(*mp)->m_next;
+	}
+#endif
 	if (inp->inp_flags & INP_RECVIF) {
 		struct ifnet *ifp;
 		struct sdlbuf {
@@ -1520,6 +1576,26 @@
 		}
 		*mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len,
 			IP_RECVIF, IPPROTO_IP);
+		if (*mp)
+			mp = &(*mp)->m_next;
+	}
+#ifdef notyet
+	if (inp->inp_flags & INP_RECVINTERFACE) {
+		int index;
+
+		index = m->m_pkthdr.rcvif ?  m->m_pkthdr.rcvif->if_index : 0;
+		*mp = sbcreatecontrol((caddr_t) &index, sizeof(int),
+		    IP_RECVINTERFACE, IPPROTO_IP);
+		if (*mp)
+			mp = &(*mp)->m_next;
+	}
+#endif
+	if (inp->inp_flags & INP_RECVTTL) {
+		int ttl;
+
+		ttl = ip->ip_ttl;
+		*mp = sbcreatecontrol((caddr_t) &ttl, sizeof(int),
+		    IP_TTL, IPPROTO_IP);
 		if (*mp)
 			mp = &(*mp)->m_next;
 	}
diff -uN src-current/sys/netinet/if_gre.c src-current-ipv6/sys/netinet/if_gre.c
--- src-current/sys/netinet/if_gre.c
+++ src-current-ipv6/sys/netinet/if_gre.c
@@ -0,0 +1,527 @@
+/*
+ * GRE IP/IP (really ANY/IP)
+ * RFC 1701 and 1702
+ *
+ * Francis.Dupont@inria.fr March 1998,
+ * from SunOS implementation, September 1993
+ */
+
+#include "gre.h"
+#include "opt_inet6.h"
+
+#if NGRE > 0
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/sockio.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/if_ether.h>
+
+#include <netinet/if_gre.h>
+
+struct gre_softc gre_softc[NGRE];
+
+SYSCTL_NODE(_net_inet, IPPROTO_GRE, gre, CTLFLAG_RW, 0,
+	    "Generic Routing Encapsulation");
+
+u_int gredebug = 1;
+
+#define GREDEBUG	if (gredebug) printf
+
+SYSCTL_INT(_net_inet_gre, OID_AUTO, debug, CTLFLAG_RW,
+	   &gredebug, 0, "");
+
+static void gre_attach __P((void *));
+static int gre_reset __P((struct ifnet *, int));
+static int gre_ioctl __P((struct ifnet *, int, caddr_t));
+static int gre_output __P((struct ifnet *,
+		struct mbuf *, struct sockaddr *,  struct rtentry *));
+
+PSEUDO_SET(gre_attach, if_gre);
+
+/*
+ * attach an interface
+ */
+static void
+gre_attach(dummy)
+    void *dummy;
+{
+    struct ifnet *ifp;
+    int i;
+
+    for (i = 0; i < NGRE; i++) {
+	ifp = &gre_softc[i].gre_if;
+	ifp->if_softc = &gre_softc[i];
+	ifp->if_name = "gre";
+	ifp->if_unit = i;
+	ifp->if_mtu = ETHERMTU - sizeof(struct gre);
+	ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
+	ifp->if_type = IFT_OTHER;
+	ifp->if_hdrlen = sizeof(struct gre);
+	ifp->if_ioctl = gre_ioctl;
+	ifp->if_output = gre_output;
+	ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+	if_attach(ifp);
+	GREDEBUG("%s%d: attach\n", ifp->if_name, ifp->if_unit);
+    }
+}
+
+/*
+ * Reset interface following a system change
+ */
+static int
+gre_reset(ifp, reset)
+    struct ifnet *ifp;
+    int reset;
+{
+    struct gre_softc *gref = (struct gre_softc *)ifp;
+    struct gre *grep = gref->gre_tpl;
+
+    if (reset && grep) {
+	free(grep, M_IFADDR);
+	grep = (struct gre *)0;
+    }
+
+    if ((gref->gre_flags & GRE_GOOD) == GRE_GOOD) {
+	/* allocate template if needed */
+	if (grep == (struct gre *)0) {
+	    gref->gre_tpltl = sizeof(struct gre);
+	    if (gref->gre_flags & (GRE_HAS_CHKSUM|GRE_HAS_ROUTE)) {
+		gref->gre_tpltcd = gref->gre_tpltl;
+		gref->gre_tpltl += 2 * sizeof(u_int16_t);
+	    }
+	    if (gref->gre_flags & GRE_HAS_KEY) {
+		gref->gre_tpltkd = gref->gre_tpltl;
+		gref->gre_tpltl += sizeof(u_int32_t);
+	    }
+	    if (gref->gre_flags & GRE_HAS_SEQNB) {
+		gref->gre_tpltsd = gref->gre_tpltl;
+		gref->gre_tpltl += sizeof(u_int32_t);
+	    }
+	    gref->gre_tpl = grep = malloc(gref->gre_tpltl, M_IFADDR, M_WAITOK);
+	    if (grep == (struct gre *)0) {
+		GREDEBUG("%s%d: gre_reset no buf\n",
+			 ifp->if_name, ifp->if_unit);
+		return ENOBUFS;
+	    }
+	    GREDEBUG("%s%d: template allocated (len=%d)\n",
+		     ifp->if_name, ifp->if_unit, gref->gre_tpltl);
+	}
+
+	/* fill template */
+	(void) bzero((caddr_t)grep, gref->gre_tpltl);
+	grep->gre_ip_p = IPPROTO_GRE;
+	grep->gre_ip_dst = gref->gre_peer;
+	grep->gre_ip_ttl = ip_defttl;
+	grep->gre_flgver = gref->gre_flags & GRE_CANSET;
+	grep->gre_protyp = gref->gre_ptype;
+	if (gref->gre_flags & GRE_HAS_KEY)
+	    *((u_int32_t *)((caddr_t)grep + gref->gre_tpltkd)) = gref->gre_key;
+
+	/* reset route */
+	if (gref->gre_ro.ro_rt) {
+	    RTFREE(gref->gre_ro.ro_rt);
+	    bzero((caddr_t)&gref->gre_ro, sizeof(struct route));
+	}
+
+	ifp->if_flags |= IFF_RUNNING;
+	ifp->if_mtu = ETHERMTU - gref->gre_tpltl;
+
+	GREDEBUG("%s%d: template filled\n", ifp->if_name, ifp->if_unit);
+    } else {
+	ifp->if_flags &= ~IFF_RUNNING;
+    }
+    GREDEBUG("%s%d: gre_reset -> %s\n", ifp->if_name,
+	     ifp->if_unit, ifp->if_flags & IFF_RUNNING ? "good" : "bad");
+    return 0;
+}
+
+/*
+ * Process an ioctl request
+ */
+static int
+gre_ioctl(ifp, cmd, data)
+    struct ifnet *ifp;
+    int cmd;
+    caddr_t data;
+{
+    struct gre_softc *gref = (struct gre_softc *)ifp;
+    struct ifaddr *ifa;
+    struct ifreq *ifr;
+    struct gre_data *gred;
+    int s = splimp(), error = 0;
+
+    switch (cmd) {
+    case SIOCSIFADDR:
+	ifa = (struct ifaddr *)data;
+	if (ifa->ifa_addr->sa_family != AF_INET) {
+	    error = EAFNOSUPPORT;
+	    break;
+	}
+	if (IA_SIN(ifa)->sin_addr.s_addr == INADDR_ANY)
+	    break;	
+	gref->gre_flags |= GRE_SRC;
+	GREDEBUG("%s%d: set address\n", ifp->if_name, ifp->if_unit);
+	/* fall into */
+
+    case SIOCSIFDSTADDR:
+	ifa = (struct ifaddr *)data;
+	/* set dst address */
+	if ((ifa->ifa_dstaddr->sa_family != AF_INET) ||
+	    IA_DSTSIN(ifa)->sin_addr.s_addr == INADDR_ANY)
+	    break;
+
+	/* set dst address */
+	gref->gre_flags |= GRE_DST;
+	GREDEBUG("%s%d: set dst\n", ifp->if_name, ifp->if_unit);
+
+	/* test if running */
+	error = gre_reset(ifp, 0);
+	break;
+
+    case SIOCSIFFLAGS:
+	if ((ifp->if_flags & IFF_RUNNING) == 0)
+	    ifp->if_flags &= ~IFF_UP;
+	GREDEBUG("%s%d: set flags\n", ifp->if_name, ifp->if_unit);
+
+	/* test if running */
+	error = gre_reset(ifp, 0);
+	break;
+
+    case SIOCSIFMTU:
+	ifr = (struct ifreq *)data;
+	ifp->if_mtu = ifr->ifr_mtu;
+	break;
+
+    case SIOCADDMULTI:
+    case SIOCDELMULTI:
+	ifr = (struct ifreq *)data;
+	if (ifr->ifr_addr.sa_family != AF_INET) {
+	    error = EAFNOSUPPORT;
+	    break;
+	}
+	break;
+
+    case SIOCGIFGRED:
+	/* get parameters */
+	gred = (struct gre_data *)data;
+	gred->gre_peer.s_addr = gref->gre_peer.s_addr;
+	gred->gre_flags = ntohs(gref->gre_flags & GRE_CANSET);
+	gred->gre_ptype = ntohs(gref->gre_ptype);
+	gred->gre_key = ntohl(gref->gre_key);
+	gred->gre_seq = gref->gre_oseq;
+
+	GREDEBUG("%s%d: get data\n", ifp->if_name, ifp->if_unit);
+	break;
+
+    case SIOCSIFGRED:
+	/* set parameters */
+	gred = (struct gre_data *)data;
+	HTONS(gred->gre_flags);
+	HTONS(gred->gre_ptype);
+	if (gred->gre_flags & ~GRE_CANSET) {
+	    GREDEBUG("%s%d: bad flags 0x%x\n",
+		     ifp->if_name, ifp->if_unit, gred->gre_flags);
+	    error = EINVAL;
+	    break;
+	}
+	if (gred->gre_ptype != ntohs(ETHERTYPE_IP)) {
+	    GREDEBUG("%s%d: bad ptype 0x%x\n",
+		     ifp->if_name, ifp->if_unit, gred->gre_ptype);
+	    error = EPROTONOSUPPORT;
+	    break;
+	}
+	gref->gre_peer.s_addr = gred->gre_peer.s_addr;
+	gref->gre_flags &= ~GRE_IMPLEMENTED;
+	gref->gre_flags |= gred->gre_flags & GRE_IMPLEMENTED;
+	if (gref->gre_peer.s_addr != INADDR_ANY)
+	    gref->gre_flags |= GRE_PEER;
+	gref->gre_ptype = gred->gre_ptype;
+	gref->gre_key = htonl(gred->gre_key);
+	gref->gre_oseq = gred->gre_seq;
+	gref->gre_iseq = 0;
+	GREDEBUG("%s%d: set data\n", ifp->if_name, ifp->if_unit);
+
+	/* test if running */
+	error = gre_reset(ifp, 1);
+	break;
+
+    default:
+	error = EINVAL;
+	break;
+
+    }
+    splx(s);
+    return error;
+}
+
+/*
+ * output : encapsulate and give to the good interface
+ */
+static int
+gre_output(ifp, m, dst, rt)
+    struct ifnet *ifp;
+    struct mbuf *m;
+    struct sockaddr *dst;
+    struct rtentry *rt;
+{
+    struct gre_softc *gref = (struct gre_softc *)ifp;
+    struct gre *grep = mtod(m, struct gre *);
+    struct in_ifaddr *ia;
+    int len, tos = 0, error = 0;
+
+    GREDEBUG("%s%d: output\n", ifp->if_name, ifp->if_unit);
+
+    if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+	GREDEBUG("%s%d: not ready\n", ifp->if_name, ifp->if_unit);
+	m_freem(m);
+	return ENETDOWN;
+    }
+
+    if (dst->sa_family != AF_INET) {
+	GREDEBUG("%s%d: un output\n", ifp->if_name, ifp->if_unit);
+	m_freem(m);
+	return EAFNOSUPPORT;
+    }
+
+    if (rt && rt->rt_ifa)
+	ia = (struct in_ifaddr *)(rt->rt_ifa);
+    else {
+	IFP_TO_IA(ifp, ia);
+    }
+    if (ia == NULL) {
+	GREDEBUG("%s%d: no ia\n", ifp->if_name, ifp->if_unit);
+	m_freem(m);
+	ifp->if_oerrors++;
+	return ENETDOWN;
+    }
+
+    if (satosin(dst)->sin_addr.s_addr == gref->gre_peer.s_addr) {
+	GREDEBUG("%s%d: loop\n", ifp->if_name, ifp->if_unit);
+	m_freem (m);
+	ifp->if_collisions++;
+	return ETOOMANYREFS;
+    }
+
+    getmicrotime(&ifp->if_lastchange);
+
+    /* get payload length and TOS */
+    len = ntohs(grep->gre_ip_len);
+    tos = grep->gre_ip_tos;
+
+    /* Make space for IP and GRE headers */
+    M_PREPEND(m, gref->gre_tpltl, M_DONTWAIT);
+    if (m == (struct mbuf *)0) {
+	GREDEBUG("%s%d: no buf\n", ifp->if_name, ifp->if_unit);
+	return ENOBUFS;
+    }
+
+    /* Fill in IP and GRE header */
+    grep = mtod(m, struct gre *);
+    len += gref->gre_tpltl;
+
+    (void) bcopy(gref->gre_tpl, mtod(m, caddr_t), gref->gre_tpltl);
+
+    grep->gre_ip_len = (u_short)len;
+    grep->gre_ip_tos = tos;
+    grep->gre_ip_src.s_addr = ia->ia_addr.sin_addr.s_addr;
+
+    if (gref->gre_flags & GRE_HAS_SEQNB)
+	*((u_int32_t *)((caddr_t)grep + gref->gre_tpltsd)) =
+		htonl(gref->gre_oseq++);
+
+    if (gref->gre_flags & GRE_HAS_CHKSUM) {
+	m->m_data += sizeof(struct ip);
+	m->m_len -= sizeof(struct ip);
+	len -= sizeof(struct ip);
+	*((u_int16_t *)((caddr_t)grep + gref->gre_tpltcd)) = in_cksum(m, len);
+	len += sizeof(struct ip);
+	m->m_len += sizeof(struct ip);
+	m->m_data -= sizeof(struct ip);
+    }
+
+    /* Output final datagram */
+    error = ip_output(m, (struct mbuf *)0, &gref->gre_ro, 0, NULL);
+    ifp->if_opackets++;
+    ifp->if_obytes += len;
+    GREDEBUG("%s%d: ip output\n", ifp->if_name, ifp->if_unit);
+    if (error) {
+	ifp->if_oerrors++;
+	GREDEBUG("%s%d: output error %d\n", ifp->if_name, ifp->if_unit, error);
+    }
+    return error;
+}
+
+/*
+ * input : decapsulate and give to IP
+ */
+void
+gre_input(m, iphlen)
+    struct mbuf *m;
+    int iphlen;
+{
+    struct gre *grep;
+    struct gre_softc *gref;
+    struct ifnet *ifp;
+    struct ifqueue *inq = &ipintrq;
+    int s, len, unit;
+
+    /* get the IP and GRE headers */
+    if ((m->m_len < sizeof(struct gre)) &&
+	((m =  m_pullup(m, sizeof(struct gre))) == (struct mbuf *)0)) {
+	GREDEBUG("gre*: can't pullup\n");
+	return;
+    }
+    grep = mtod(m, struct gre *);
+
+    /* find the matching GRE interface */
+    for (unit = 0; unit < NGRE ; unit++) {
+	gref = &gre_softc[unit];
+	ifp = &gref->gre_if;
+	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+	    continue;
+	if ((gref->gre_flags & GRE_GOOD) != GRE_GOOD)
+	    continue;
+	if (gref->gre_peer.s_addr != grep->gre_ip_src.s_addr)
+	    continue;
+	if (gref->gre_ptype != grep->gre_protyp)
+	    continue;
+	GREDEBUG("%s%d: input\n", ifp->if_name, ifp->if_unit);
+	m->m_pkthdr.rcvif = ifp;
+	break;
+    }
+    if (unit == NGRE) {
+	GREDEBUG("gre*: no input match\n");
+#ifdef nomore
+	m_freem(m);
+	return;
+#else
+	gref = &gre_softc[0];
+	ifp = &gref->gre_if;
+#endif
+    }
+
+    /*
+     * Get the two headers together in first mbuf.
+     */
+    len = gref->gre_tpltl + sizeof(struct ip);
+    if (m->m_len < len) {
+	if ((m = m_pullup(m, len)) == (struct mbuf *)0) {
+	    GREDEBUG("%s%d: can't pullup\n", ifp->if_name, ifp->if_unit);
+	    ifp->if_ierrors++;
+	    return;
+	}
+	grep = mtod(m, struct gre *);
+    }
+
+    if (iphlen > sizeof(struct ip)) {
+	ip_stripoptions(m, (struct mbuf *)0);
+	if (m->m_len < len) {
+	    if ((m = m_pullup(m, len)) == (struct mbuf *)0) {
+		GREDEBUG("%s%d: short input\n", ifp->if_name, ifp->if_unit);
+		ifp->if_ierrors++;
+		return;
+	    }
+	}
+	grep = mtod(m, struct gre *);
+    }
+
+    len = grep->gre_ip_len;
+    if (grep->gre_flgver != (gref->gre_flags & GRE_CANSET)) {
+	GREDEBUG("%s%d: bad flags on input\n", ifp->if_name, ifp->if_unit);
+	goto bad;
+    }
+    if (grep->gre_protyp != gref->gre_ptype) {
+	GREDEBUG("%s%d: bad ptype on input\n", ifp->if_name, ifp->if_unit);
+	goto bad;
+    }
+    if (grep->gre_flgver & GRE_HAS_KEY) {
+	caddr_t kptr = (caddr_t)grep + gref->gre_tpltkd;
+
+	if (*((u_int32_t *)kptr) != gref->gre_key) {
+	    GREDEBUG("%s%d: bad key (%d != %d)\n",
+		     ifp->if_name, ifp->if_unit,
+		     *((u_int32_t *)kptr), gref->gre_key);
+	    goto bad;
+	}
+    }
+    /* TODO: sequence number test */
+    if (grep->gre_flgver & GRE_HAS_CHKSUM) {
+	m->m_data += sizeof(struct ip);
+	m->m_len -= sizeof(struct ip);
+	if (in_cksum(m, len) != 0) {
+	    GREDEBUG("%s%d: bad checksum\n", ifp->if_name, ifp->if_unit);
+	    goto bad;
+	}
+	m->m_data += gref->gre_tpltl - sizeof(struct ip);
+	m->m_len -= gref->gre_tpltl - sizeof(struct ip);
+    } else {
+	m->m_data += gref->gre_tpltl;
+	m->m_len -= gref->gre_tpltl;
+    }
+    m->m_pkthdr.len -= gref->gre_tpltl;
+
+    ifp->if_ipackets++;
+
+    if ((gref->gre_ptype != ntohs(ETHERTYPE_IP))
+#ifdef INET6
+	&& (gref->gre_ptype != ETHERTYPE_IPV6)
+#endif
+       ) {
+	GREDEBUG("%s%d: bad ptype?\n", ifp->if_name, ifp->if_unit);
+	goto bad;
+    }
+
+    /*
+     * Deliver the payload
+     */
+    s = splimp();
+
+    if (IF_QFULL(inq)) {
+	IF_DROP(inq);
+	m_freem(m);
+    } else
+	IF_ENQUEUE(inq, m);
+    /* no schednetisr(NETISR_IP) because we are in ip_input */
+    splx(s);
+    return;
+
+bad:
+    ifp->if_ierrors++;
+    m_freem(m);
+}
+
+/*
+ * input ICMP
+ */
+void
+gre_ctlinput(cmd, sa, vip)
+    int cmd;
+    struct sockaddr *sa;
+    void *vip;
+{
+    if (sa->sa_family != AF_INET)
+	return;
+
+    GREDEBUG("gre*: icmp input %d\n", cmd);
+    /* TODO */
+}
+#endif
diff -uN src-current/sys/netinet/tcp_input.c src-current-ipv6/sys/netinet/tcp_input.c
--- src-current/sys/netinet/tcp_input.c
+++ src-current-ipv6/sys/netinet/tcp_input.c
@@ -34,6 +34,7 @@
  *	$Id: tcp_input.c,v 1.77 1998/05/18 17:11:24 guido Exp $
  */
 
+#include "opt_inet6.h"
 #include "opt_tcpdebug.h"
 
 #include <sys/param.h>
@@ -56,8 +57,11 @@
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
 #include <netinet/in_pcb.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
 #include <netinet/tcp.h>
 #include <netinet/tcp_fsm.h>
 #include <netinet/tcp_seq.h>
@@ -69,7 +73,7 @@
 static struct	tcpiphdr tcp_saveti;
 #endif
 
-static int	tcprexmtthresh = 3;
+int	tcprexmtthresh = 3;
 tcp_seq	tcp_iss;
 tcp_cc	tcp_ccgen;
 
@@ -77,14 +81,43 @@
 SYSCTL_STRUCT(_net_inet_tcp, TCPCTL_STATS, stats,
 	CTLFLAG_RD, &tcpstat , tcpstat, "");
 
-static int log_in_vain = 0;
+int tcp_log_in_vain = 0;
 SYSCTL_INT(_net_inet_tcp, OID_AUTO, log_in_vain, CTLFLAG_RW, 
-	&log_in_vain, 0, "");
+	&tcp_log_in_vain, 0, "");
 
 int tcp_delack_enabled = 1;
 SYSCTL_INT(_net_inet_tcp, OID_AUTO, delayed_ack, CTLFLAG_RW, 
 	&tcp_delack_enabled, 0, "");
 
+/*
+ * experimental ECN support based on 
+ *	draft-kksjf-ecn-00.txt and http://www-nrg.ee.lbl.gov/floyd/ECN-IP.txt
+ *
+ * NOTE: this is just an experimental implementation.  there's still
+ * no consensus on which bits to use in IPv4/v6 and TCP headers.
+ * there are other proposals which use different bits (e.g.,
+ * draft-ellesson-tos-00.txt)
+ * no negotiation mechanism is defined in those drafts.
+ * our implementation:
+ *   - use two bits of the IP TOS field.
+ *   - use one bit of the TCP flag field.
+ *   - simple negotiation mechanism:
+ *	send SYN always with TH_ECN.
+ *	when SYN with TH_ECN is received, use ECN.
+ *   - add "recover" variable (to tcp pcb) used in ns to avoid multiple
+ *     reductions of cwnd in a single window.
+ *     (note: interaction between ECN and fast recovery is not fully studied.)
+ */
+
+int tcp_ecn = 0;
+#ifdef ALTQ_ECN
+SYSCTL_INT(_net_inet_tcp, TCPCTL_ECN, ecn,
+	CTLFLAG_RW, &tcp_ecn , 0, "");
+#else
+SYSCTL_INT(_net_inet_tcp, TCPCTL_ECN, ecn,
+	CTLFLAG_RD, &tcp_ecn , 0, "");
+#endif
+
 u_long	tcp_now;
 struct inpcbhead tcb;
 struct inpcbinfo tcbinfo;
@@ -94,7 +127,6 @@
 static void	 tcp_pulloutofband __P((struct socket *,
 	    struct tcpiphdr *, struct mbuf *));
 static int	 tcp_reass __P((struct tcpcb *, struct tcpiphdr *, struct mbuf *));
-static void	 tcp_xmit_timer __P((struct tcpcb *, int));
 
 
 /*
@@ -254,12 +286,16 @@
 	struct socket *so = 0;
 	int todrop, acked, ourfinisacked, needoutput = 0;
 	struct in_addr laddr;
+	int atype;
 	int dropsocket = 0;
 	int iss = 0;
 	u_long tiwin;
 	struct tcpopt to;		/* options in this segment */
 	struct rmxp_tao *taop;		/* pointer to our TAO cache entry */
 	struct rmxp_tao	tao_noncached;	/* in case there's no cached entry */
+#ifdef ALTQ_ECN
+	u_char ip_tos;
+#endif
 #ifdef TCPDEBUG
 	short ostate = 0;
 #endif
@@ -282,6 +318,10 @@
 		ti = mtod(m, struct tcpiphdr *);
 	}
 
+#ifdef ALTQ_ECN
+	/* save ip_tos before clearing it for checksum */
+	ip_tos = ((struct ip *)ti)->ip_tos;
+#endif
 	/*
 	 * Checksum extended TCP header and data.
 	 */
@@ -349,7 +389,7 @@
 	 * but should either do a listen or a connect soon.
 	 */
 	if (inp == NULL) {
-		if (log_in_vain && tiflags & TH_SYN) {
+		if (tcp_log_in_vain && tiflags & TH_SYN) {
 			char buf[4*sizeof "123"];
 
 			strcpy(buf, inet_ntoa(ti->ti_dst));
@@ -419,7 +459,14 @@
 			 */
 			dropsocket++;
 			inp = (struct inpcb *)so->so_pcb;
+			inp->inp_flags &= ~INP_COMPATV6;
 			inp->inp_laddr = ti->ti_dst;
+#ifdef INET6
+			inp->inp_laddr6.s6_addr32[0] = 0;
+			inp->inp_laddr6.s6_addr32[1] = 0;
+			inp->inp_laddr6.s6_addr32[2] = htonl(0xffff);
+#endif
+			inp->inp_latype = IPATYPE_IPV4;
 			inp->inp_lport = ti->ti_dport;
 			if (in_pcbinshash(inp) != 0) {
 				/*
@@ -457,6 +504,11 @@
 	if (tp->t_state != TCPS_LISTEN)
 		tcp_dooptions(tp, optp, optlen, ti, &to);
 
+#ifdef ALTQ_ECN
+	/* if congestion experienced, set ECN bit in the next output. */
+	if ((ip_tos & (IPTOS_ECT|IPTOS_CE)) == (IPTOS_ECT|IPTOS_CE))
+		tp->t_flags |= TF_RCVD_CE;
+#endif
 	/*
 	 * Header prediction: check for the two common cases
 	 * of a uni-directional data xfer.  If the packet has
@@ -475,7 +527,11 @@
 	 * be TH_NEEDSYN.
 	 */
 	if (tp->t_state == TCPS_ESTABLISHED &&
+#ifdef ALTQ_ECN
+	    (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ECN|TH_ACK)) == TH_ACK &&
+#else
 	    (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&
+#endif
 	    ((tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN)) == 0) &&
 	    ((to.to_flag & TOF_TS) == 0 ||
 	     TSTMP_GEQ(to.to_tsval, tp->ts_recent)) &&
@@ -522,6 +578,11 @@
 				tcpstat.tcps_rcvackbyte += acked;
 				sbdrop(&so->so_snd, acked);
 				tp->snd_una = ti->ti_ack;
+#ifdef ALTQ_ECN
+				/* sync snc_rcvr with snd_una */
+				if (SEQ_GT(tp->snd_una, tp->snd_rcvr))
+					tp->snd_rcvr = tp->snd_una;
+#endif
 				m_freem(m);
 
 				/*
@@ -631,14 +692,24 @@
 		sin->sin_port = ti->ti_sport;
 		bzero((caddr_t)sin->sin_zero, sizeof(sin->sin_zero));
 		laddr = inp->inp_laddr;
-		if (inp->inp_laddr.s_addr == INADDR_ANY)
+		atype = inp->inp_latype;
+		if (atype == IPATYPE_UNBD) {
 			inp->inp_laddr = ti->ti_dst;
+#ifdef INET6
+			inp->inp_laddr6.s6_addr32[0] = 0;
+			inp->inp_laddr6.s6_addr32[1] = 0;
+			inp->inp_laddr6.s6_addr32[2] = htonl(0xffff);
+#endif
+			inp->inp_latype = IPATYPE_IPV4;
+		}
 		if (in_pcbconnect(inp, (struct sockaddr *)sin, &proc0)) {
 			inp->inp_laddr = laddr;
+			inp->inp_latype = atype;
 			FREE(sin, M_SONAME);
 			goto drop;
 		}
 		FREE(sin, M_SONAME);
+		inp->inp_flags &= ~INP_COMPATV6;
 		tp->t_template = tcp_template(tp);
 		if (tp->t_template == 0) {
 			tp = tcp_drop(tp, ENOBUFS);
@@ -658,6 +729,14 @@
 		tp->irs = ti->ti_seq;
 		tcp_sendseqinit(tp);
 		tcp_rcvseqinit(tp);
+#ifdef ALTQ_ECN
+		tp->snd_rcvr = tp->snd_una;
+		/* if ECN flag bit is set, peer is ECN capable */
+		if (tcp_ecn && (tiflags & TH_ECN)) {
+			tp->t_flags |= TF_REQ_ECN;
+			tiflags &= ~TH_ECN;
+		}
+#endif
 		/*
 		 * Initialization of the tcpcb for transaction;
 		 *   set SND.WND = SEG.WND,
@@ -789,6 +868,14 @@
 
 		tp->irs = ti->ti_seq;
 		tcp_rcvseqinit(tp);
+#ifdef ALTQ_ECN
+		tp->snd_rcvr = tp->snd_una;
+		/* if ECN flag bit is set, peer is ECN capable */
+		if (tcp_ecn && (tiflags & TH_ECN)) {
+			tp->t_flags |= TF_REQ_ECN;
+			tiflags &= ~TH_ECN;
+		}
+#endif
 		if (tiflags & TH_ACK) {
 			/*
 			 * Our SYN was acked.  If segment contains CC.ECHO
@@ -1219,6 +1306,30 @@
 	case TCPS_LAST_ACK:
 	case TCPS_TIME_WAIT:
 
+#ifdef ALTQ_ECN
+		/*
+		 * if we receive ECN notify and we are not already in
+		 * receovery phase, reduce cwnd by half but don't slow-
+		 * start.
+		 */
+		if (tcp_ecn && (tiflags & TH_ECN)) {
+			if (SEQ_GEQ(tp->snd_una, tp->snd_rcvr)) {
+				u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 /
+					tp->t_maxseg;
+				if (win < 2)
+					win = 2;
+				tp->snd_ssthresh = win * tp->t_maxseg;
+				tp->snd_cwnd = tp->snd_ssthresh;
+				/*
+				 * advance snd_rcvr to snd_max not to
+				 * reduce cwnd again until all outstanding
+				 * packets are acked.
+				 */
+				tp->snd_rcvr = tp->snd_max;
+			}
+		}
+#endif /* ALTQ_ECN */
+		    
 		if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
 			if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {
 				tcpstat.tcps_rcvdupack++;
@@ -1251,6 +1362,17 @@
 					tp->t_dupacks = 0;
 				else if (++tp->t_dupacks == tcprexmtthresh) {
 					tcp_seq onxt = tp->snd_nxt;
+#ifdef ALTQ_ECN
+					if (SEQ_LT(tp->snd_una, tp->snd_rcvr)) {
+						/*
+						 * we are in recovery phase
+						 * and have already halved
+						 * cwnd within a roundtrip.
+						 * don't reduce cwnd again.
+						 */
+					}
+					else {
+#endif /* ALTQ_ECN */
 					u_int win =
 					    min(tp->snd_wnd, tp->snd_cwnd) / 2 /
 						tp->t_maxseg;
@@ -1258,6 +1380,11 @@
 					if (win < 2)
 						win = 2;
 					tp->snd_ssthresh = win * tp->t_maxseg;
+#ifdef ALTQ_ECN
+					/* mark we are in recovery phase */
+					tp->snd_rcvr = tp->snd_max;
+				        }
+#endif
 					tp->t_timer[TCPT_REXMT] = 0;
 					tp->t_rtt = 0;
 					tp->snd_nxt = ti->ti_ack;
@@ -1376,6 +1503,11 @@
 		if (so->so_snd.sb_flags & SB_NOTIFY)
 			sowwakeup(so);
 		tp->snd_una = ti->ti_ack;
+#ifdef ALTQ_ECN
+		/* sync snc_rcvr with snd_una */
+		if (SEQ_GT(tp->snd_una, tp->snd_rcvr))
+			tp->snd_rcvr = tp->snd_una;
+#endif
 		if (SEQ_LT(tp->snd_nxt, tp->snd_una))
 			tp->snd_nxt = tp->snd_una;
 
@@ -1837,7 +1969,7 @@
  * Collect new round-trip time estimate
  * and update averages and current timeout.
  */
-static void
+void
 tcp_xmit_timer(tp, rtt)
 	register struct tcpcb *tp;
 	short rtt;
diff -uN src-current/sys/netinet/in.h src-current-ipv6/sys/netinet/in.h
--- src-current/sys/netinet/in.h
+++ src-current-ipv6/sys/netinet/in.h
@@ -37,6 +37,9 @@
 #ifndef _NETINET_IN_H_
 #define _NETINET_IN_H_
 
+#define	IPV6_INRIA_VERSION	19980101
+#define	IPV6_TOKEN_LENGTH	64
+
 /*
  * Constants and structures defined by the internet system,
  * Per RFC 790, September 1981, and numerous additions.
@@ -46,6 +49,7 @@
  * Protocols (RFC 1700)
  */
 #define	IPPROTO_IP		0		/* dummy for IP */
+#define	IPPROTO_HOPOPTS		0		/* IPv6 Hop-by-Hop options */
 #define	IPPROTO_ICMP		1		/* control message protocol */
 #define	IPPROTO_IGMP		2		/* group mgmt protocol */
 #define	IPPROTO_GGP		3		/* gateway^2 (deprecated) */
@@ -85,12 +89,12 @@
 #define	IPPROTO_CMTP		38		/* Control Message Transport */
 #define	IPPROTO_TPXX		39		/* TP++ Transport */
 #define	IPPROTO_IL		40		/* IL transport protocol */
-#define	IPPROTO_SIP		41		/* Simple Internet Protocol */
+#define	IPPROTO_IPV6		41		/* IPv6 into IPv4 */
 #define	IPPROTO_SDRP		42		/* Source Demand Routing */
-#define	IPPROTO_SIPSR		43		/* SIP Source Route */
-#define	IPPROTO_SIPFRAG		44		/* SIP Fragment */
+#define	IPPROTO_ROUTING		43		/* IPv6 Routing header */
+#define	IPPROTO_FRAGMENT	44		/* IPv6 fragmentation header */
 #define	IPPROTO_IDRP		45		/* InterDomain Routing*/
-#define IPPROTO_RSVP		46 		/* resource reservation */
+#define	IPPROTO_RSVP		46 		/* resource reservation */
 #define	IPPROTO_GRE		47		/* General Routing Encap. */
 #define	IPPROTO_MHRP		48		/* Mobile Host Routing */
 #define	IPPROTO_BHA		49		/* BHA */
@@ -99,7 +103,10 @@
 #define	IPPROTO_INLSP		52		/* Integ. Net Layer Security */
 #define	IPPROTO_SWIPE		53		/* IP with encryption */
 #define	IPPROTO_NHRP		54		/* Next Hop Resolution */
-/* 55-60: Unassigned */
+/* 55-57: Unassigned */
+#define	IPPROTO_ICMPV6		58		/* ICMPv6/IGMPv6/NDPv6 */
+#define	IPPROTO_NONE		59		/* IPv6 no next header */
+#define	IPPROTO_DSTOPTS		60		/* IPv6 Destination options */
 #define	IPPROTO_AHIP		61		/* any host internal protocol */
 #define	IPPROTO_CFTP		62		/* CFTP */
 #define	IPPROTO_HELLO		63		/* "hello" routing protocol */
@@ -223,6 +230,29 @@
 	u_int32_t s_addr;
 };
 
+#define INET_ADDRSTRLEN		16
+
+/*
+ * IPv6 address (a structure for 64 bit architectures)
+ */
+struct in6_addr {
+	union {
+		u_int32_t u6_addr32[4];
+#ifdef notyet
+		u_int64_t u6_addr64[2];
+#endif
+		u_int8_t  u6_addr8[16];
+	} u6_addr;
+};
+#define s6_addr32	u6_addr.u6_addr32
+#ifdef notyet
+#define s6_addr64	u6_addr.u6_addr64
+#endif
+#define s6_addr8	u6_addr.u6_addr8
+#define s6_addr		u6_addr.u6_addr8
+
+#define INET6_ADDRSTRLEN	46
+
 /*
  * Definitions of bits in internet address integers.
  * On subnets, the decomposition of addresses to host and net parts
@@ -268,6 +298,20 @@
 
 #define	IN_LOOPBACKNET		127			/* official! */
 
+#define IN6ADDR_ANY_INIT	{0, 0, 0, 0}
+#define IPV6ADDR_ANY_INIT	IN6ADDR_ANY_INIT	/* old name */
+#if BYTE_ORDER == BIG_ENDIAN
+#define IN6ADDR_LOOPBACK_INIT	{0, 0, 0, 1}
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define IN6ADDR_LOOPBACK_INIT	{0, 0, 0, 0x01000000}
+#endif
+#define IPV6ADDR_LOOPBACK_INIT	IN6ADDR_LOOPBACK_INIT	/* old name */
+
+#ifndef KERNEL
+extern const struct in6_addr in6addr_any, in6addr_loopback;
+#endif
+
 /*
  * Socket address, internet style.
  */
@@ -280,6 +324,282 @@
 };
 
 /*
+ * IPv6 socket address
+ */
+#define	SIN6_LEN
+
+struct sockaddr_in6 {
+	u_int8_t  sin6_len;
+	u_int8_t  sin6_family;
+	u_int16_t sin6_port;
+	u_int32_t sin6_flowinfo;
+	struct	  in6_addr sin6_addr;
+};
+
+#define IPNGVERSION	6
+
+/*
+ * IPv6 routing socket pseudo-address
+ */
+
+struct sockaddr_rt6 {
+	u_int8_t  sin6_len;
+	u_int8_t  sin6_family;
+	u_int16_t sin6_rtpad1;
+	u_int16_t sin6_rtpad2;
+	u_int16_t sin6_local;
+	struct	  in6_addr sin6_addr;
+};
+
+/*
+ * Definitions for flow labels.
+ */
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define IPV6_FLOWINFO_FLOWLABEL		0x00ffffff
+#define IPV6_FLOWINFO_PRIORITY		0x0f000000
+#define IPV6_FLOWINFO_PRIFLOW		0x0fffffff
+#define IPV6_FLOWINFO_SRFLAG		0x10000000
+#define IPV6_FLOWINFO_VERSION		0xf0000000
+
+#define IPV6_PRIORITY_UNCHARACTERIZED	0x00000000
+#define IPV6_PRIORITY_FILLER		0x01000000
+#define IPV6_PRIORITY_UNATTENDED	0x02000000
+#define IPV6_PRIORITY_RESERVED1		0x03000000
+#define IPV6_PRIORITY_BULK		0x04000000
+#define IPV6_PRIORITY_RESERVED2		0x05000000
+#define IPV6_PRIORITY_INTERACTIVE	0x06000000
+#define IPV6_PRIORITY_CONTROL		0x07000000
+#define IPV6_PRIORITY_8			0x08000000
+#define IPV6_PRIORITY_9			0x09000000
+#define IPV6_PRIORITY_10		0x0a000000
+#define IPV6_PRIORITY_11		0x0b000000
+#define IPV6_PRIORITY_12		0x0c000000
+#define IPV6_PRIORITY_13		0x0d000000
+#define IPV6_PRIORITY_14		0x0e000000
+#define IPV6_PRIORITY_15		0x0f000000
+
+#define IPV6_SRFLAG_STRICT		0x10000000
+#define IPV6_SRFLAG_LOOSE		0x00000000
+
+#define IPV6_VERSION			0x60000000
+
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define IPV6_FLOWINFO_FLOWLABEL		0xffffff00
+#define IPV6_FLOWINFO_PRIORITY		0x0000000f
+#define IPV6_FLOWINFO_PRIFLOW		0xffffff0f
+#define IPV6_FLOWINFO_SRFLAG		0x00000010
+#define IPV6_FLOWINFO_VERSION		0x000000f0
+
+#define IPV6_PRIORITY_UNCHARACTERIZED	0x00000000
+#define IPV6_PRIORITY_FILLER		0x00000001
+#define IPV6_PRIORITY_UNATTENDED	0x00000002
+#define IPV6_PRIORITY_RESERVED1		0x00000003
+#define IPV6_PRIORITY_BULK		0x00000004
+#define IPV6_PRIORITY_RESERVED2		0x00000005
+#define IPV6_PRIORITY_INTERACTIVE	0x00000006
+#define IPV6_PRIORITY_CONTROL		0x00000007
+#define IPV6_PRIORITY_8			0x00000008
+#define IPV6_PRIORITY_9			0x00000009
+#define IPV6_PRIORITY_10		0x0000000a
+#define IPV6_PRIORITY_11		0x0000000b
+#define IPV6_PRIORITY_12		0x0000000c
+#define IPV6_PRIORITY_13		0x0000000d
+#define IPV6_PRIORITY_14		0x0000000e
+#define IPV6_PRIORITY_15		0x0000000f
+
+#define IPV6_SRFLAG_STRICT		0x00000010
+#define IPV6_SRFLAG_LOOSE		0x00000000
+
+#define IPV6_VERSION			0x00000060
+
+#endif
+
+#define IPV6_GET_FLOWLABEL(x)		(ntohl(x) & 0x00ffffff)
+#define IPV6_GET_PRIORITY(x)		((ntohl(x) >> 24) & 0xf)
+#define IPV6_GET_VERSION(x)		((ntohl(x) >> 28) & 0xf)
+#define IPV6_SET_FLOWLABEL(x)		(htonl(x) & IPV6_FLOWINFO_FLOWLABEL)
+#define IPV6_SET_PRIORITY(x)		(htonl((x & 0xf) << 24))
+
+/*
+ * Definitions for IPv6 addresses.
+ */
+
+#define CLR_ADDR6(a) \
+	{ \
+		(a).s6_addr32[0] = 0; \
+		(a).s6_addr32[1] = 0; \
+		(a).s6_addr32[2] = 0; \
+		(a).s6_addr32[3] = 0; \
+	}
+
+#define COPY_ADDR6(from, to) \
+	{ \
+		(to).s6_addr32[0] = (from).s6_addr32[0]; \
+		(to).s6_addr32[1] = (from).s6_addr32[1]; \
+		(to).s6_addr32[2] = (from).s6_addr32[2]; \
+		(to).s6_addr32[3] = (from).s6_addr32[3]; \
+	}
+
+#define SAME_SOCKADDR(a, b) \
+	(((a)->sin6_addr.s6_addr32[0] == (b)->sin6_addr.s6_addr32[0]) && \
+	 ((a)->sin6_addr.s6_addr32[1] == (b)->sin6_addr.s6_addr32[1]) && \
+	 ((a)->sin6_addr.s6_addr32[2] == (b)->sin6_addr.s6_addr32[2]) && \
+	 ((a)->sin6_addr.s6_addr32[3] == (b)->sin6_addr.s6_addr32[3]))
+
+#define SAME_ADDR6(a, b) \
+	(((a).s6_addr32[0] == (b).s6_addr32[0]) && \
+	 ((a).s6_addr32[1] == (b).s6_addr32[1]) && \
+	 ((a).s6_addr32[2] == (b).s6_addr32[2]) && \
+	 ((a).s6_addr32[3] == (b).s6_addr32[3]))
+
+#define IS_ANYSOCKADDR(a) \
+	(((a)->sin6_addr.s6_addr32[0] == 0) && \
+	 ((a)->sin6_addr.s6_addr32[1] == 0) && \
+	 ((a)->sin6_addr.s6_addr32[2] == 0) && \
+	 ((a)->sin6_addr.s6_addr32[3] == 0))
+
+#define IS_ANYADDR6(a) \
+	(((a).s6_addr32[0] == 0) && \
+	 ((a).s6_addr32[1] == 0) && \
+	 ((a).s6_addr32[2] == 0) && \
+	 ((a).s6_addr32[3] == 0))
+
+#define IS_COMPATSOCKADDR(a) \
+	(((a)->sin6_addr.s6_addr32[0] == 0) && \
+	 ((a)->sin6_addr.s6_addr32[1] == 0) && \
+	 ((a)->sin6_addr.s6_addr32[2] == 0) && \
+	 ((a)->sin6_addr.s6_addr8[12] != 0))
+
+#define IS_COMPATADDR6(a) \
+	(((a).s6_addr32[0] == 0) && \
+	 ((a).s6_addr32[1] == 0) && \
+	 ((a).s6_addr32[2] == 0) && \
+	 ((a).s6_addr8[12] != 0))
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define IS_LOOPSOCKADDR(a) \
+	(((a)->sin6_addr.s6_addr32[0] == 0) && \
+	 ((a)->sin6_addr.s6_addr32[1] == 0) && \
+	 ((a)->sin6_addr.s6_addr32[2] == 0) && \
+	 ((a)->sin6_addr.s6_addr32[3] == 1))
+
+#define IS_LOOPADDR6(a) \
+	(((a).s6_addr32[0] == 0) && \
+	 ((a).s6_addr32[1] == 0) && \
+	 ((a).s6_addr32[2] == 0) && \
+	 ((a).s6_addr32[3] == 1))
+
+#define IS_IPV4SOCKADDR(a) \
+	(((a)->sin6_addr.s6_addr32[0] == 0) && \
+	 ((a)->sin6_addr.s6_addr32[1] == 0) && \
+	 ((a)->sin6_addr.s6_addr32[2] == 0x0000ffff))
+
+#define IS_IPV4ADDR6(a) \
+	(((a).s6_addr32[0] == 0) && \
+	 ((a).s6_addr32[1] == 0) && \
+	 ((a).s6_addr32[2] == 0x0000ffff))
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define IS_LOOPSOCKADDR(a) \
+	(((a)->sin6_addr.s6_addr32[0] == 0) && \
+	 ((a)->sin6_addr.s6_addr32[1] == 0) && \
+	 ((a)->sin6_addr.s6_addr32[2] == 0) && \
+	 ((a)->sin6_addr.s6_addr32[3] == 0x1000000))
+
+#define IS_LOOPADDR6(a) \
+	(((a).s6_addr32[0] == 0) && \
+	 ((a).s6_addr32[1] == 0) && \
+	 ((a).s6_addr32[2] == 0) && \
+	 ((a).s6_addr32[3] == 0x1000000))
+
+#define IS_IPV4SOCKADDR(a) \
+	(((a)->sin6_addr.s6_addr32[0] == 0) && \
+	 ((a)->sin6_addr.s6_addr32[1] == 0) && \
+	 ((a)->sin6_addr.s6_addr32[2] == 0xffff0000))
+
+#define IS_IPV4ADDR6(a) \
+	(((a).s6_addr32[0] == 0) && \
+	 ((a).s6_addr32[1] == 0) && \
+	 ((a).s6_addr32[2] == 0xffff0000))
+#endif
+
+#define IS_LOCALADDR6(a)	((a).s6_addr8[0] == 0xfe)
+
+#define IS_LINKLADDR6(a) \
+	(IS_LOCALADDR6(a) && ((a).s6_addr8[1] == 0x80))
+
+#define IS_SITELADDR6(a) \
+	(IS_LOCALADDR6(a) && ((a).s6_addr8[1] == 0xc0))
+
+#define IS_MULTIADDR6(a)	((a).s6_addr8[0] == 0xff)
+
+#define MADDR6_FLAGS(a)		((a).s6_addr8[1] >> 4)
+
+#define MADDR6_FLG_WK		0	/* "well-known" multicast address */
+#define MADDR6_FLG_TS		1	/* "transient" multicast address */
+
+#define MADDR6_SCOPE(a)		((a).s6_addr8[1] & 0x0f)
+
+#define MADDR6_SCP_NODE		0x1	/* node-local scope */
+#define MADDR6_SCP_LINK		0x2	/* link-local scope */
+#define MADDR6_SCP_SITE		0x5	/* site-local scope */
+#define MADDR6_SCP_ORG		0x8	/* organization-local scope */
+#define MADDR6_SCP_GLO		0xe	/* global scope */
+
+#define MADDR6_ALLNODES		1	/* all-nodes groups */
+#define MADDR6_ALLROUTERS	2	/* all-routers groups */
+#define MADDR6_ALLHOSTS		3	/* all-hosts groups */
+
+/*
+ * New IPv6 address macros of BSD API
+ */
+
+#define IN6_IS_ADDR_UNSPECIFIED(p)	IS_ANYADDR6(*p)
+#define IN6_IS_ADDR_LOOPBACK(p)		IS_LOOPADDR6(*p)
+#define IN6_IS_ADDR_MULTICAST(p)	IS_MULTIADDR6(*p)
+#define IN6_IS_ADDR_LINKLOCAL(p)	IS_LINKLADDR6(*p)
+#define IN6_IS_ADDR_SITELOCAL(p)	IS_SITELADDR6(*p)
+#define IN6_IS_ADDR_V4MAPPED(p)		IS_IPV4ADDR6(*p)
+#define IN6_IS_ADDR_V4COMPAT(p)		IS_COMPATADDR6(*p)
+
+#define IN6_IS_ADDR_MC_NODELOCAL(p) \
+	(IS_MULTIADDR6(*p) && (MADDR6_SCOPE(*p) == MADDR6_SCP_NODE))
+#define IN6_IS_ADDR_MC_LINKLOCAL(p) \
+	(IS_MULTIADDR6(*p) && (MADDR6_SCOPE(*p) == MADDR6_SCP_LINK))
+#define IN6_IS_ADDR_MC_SITELOCAL(p) \
+	(IS_MULTIADDR6(*p) && (MADDR6_SCOPE(*p) == MADDR6_SCP_SITE))
+#define IN6_IS_ADDR_MC_ORGLOCAL(p) \
+	(IS_MULTIADDR6(*p) && (MADDR6_SCOPE(*p) == MADDR6_SCP_ORG))
+#define IN6_IS_ADDR_MC_GLOBAL(p) \
+	(IS_MULTIADDR6(*p) && (MADDR6_SCOPE(*p) == MADDR6_SCP_GLO))
+
+#define IN6_ARE_ADDR_EQUAL(pa,pb)	SAME_ADDR6(*pa,*pb)
+
+/* My own extension (:-) */
+
+#define IN6_ADDR_V6_TO_V4(a)	((struct in_addr *)&(a)->s6_addr[12])
+
+/* Grabbed from Girish's, Tom Pusateri's & Yixin Jin's code */
+/*
+ * Multicast downstream destinations
+ */
+
+struct ds_in6addr {
+	struct	in6_addr sin6_addr;	/* downstream destination */
+	u_short	hoplimit;		/* min ttl required to forward */
+	u_short	flags;			/* attributes */
+};
+
+struct sockaddr_inds {
+	u_char	sin_len;
+	u_char	sin_family;
+	u_short	sin_num;
+	char	sin_data[12];
+};
+
+/*
  * Structure used to describe IP options.
  * Used to store options internally, to pass them to a process,
  * or to restore options retrieved earlier.
@@ -299,15 +619,23 @@
 #define	IP_HDRINCL		2    /* int; header is included with data */
 #define	IP_TOS			3    /* int; IP type of service and preced. */
 #define	IP_TTL			4    /* int; IP time to live */
+#define	IP_UNICAST_HOPS		IP_TTL
+#define	IPV6_UNICAST_HOPS	IP_TTL
 #define	IP_RECVOPTS		5    /* bool; receive all IP opts w/dgram */
 #define	IP_RECVRETOPTS		6    /* bool; receive IP opts for response */
 #define	IP_RECVDSTADDR		7    /* bool; receive IP dst addr w/dgram */
 #define	IP_RETOPTS		8    /* ip_opts; set/get IP options */
-#define	IP_MULTICAST_IF		9    /* u_char; set/get IP multicast i/f  */
+#define	IP_MULTICAST_IF		9    /* in_addr; set/get IP multicast i/f  */
+#define	IPV6_MULTICAST_IF	IP_MULTICAST_IF	/* u_int */
 #define	IP_MULTICAST_TTL	10   /* u_char; set/get IP multicast ttl */
+#define IP_MULTICAST_HOPS	IP_MULTICAST_TTL
+#define IPV6_MULTICAST_HOPS	IP_MULTICAST_TTL	/* int */
 #define	IP_MULTICAST_LOOP	11   /* u_char; set/get IP multicast loopback */
+#define	IPV6_MULTICAST_LOOP	IP_MULTICAST_LOOP	/* u_int */
 #define	IP_ADD_MEMBERSHIP	12   /* ip_mreq; add an IP group membership */
+#define	IPV6_ADD_MEMBERSHIP	IP_ADD_MEMBERSHIP
 #define	IP_DROP_MEMBERSHIP	13   /* ip_mreq; drop an IP group membership */
+#define	IPV6_DROP_MEMBERSHIP	IP_DROP_MEMBERSHIP
 #define IP_MULTICAST_VIF	14   /* set/get IP mcast virt. iface */
 #define IP_RSVP_ON		15   /* enable RSVP in kernel */
 #define IP_RSVP_OFF		16   /* disable RSVP in kernel */
@@ -315,6 +643,20 @@
 #define IP_RSVP_VIF_OFF		18   /* unset RSVP per-vif socket */
 #define IP_PORTRANGE		19   /* int; range to choose for unspec port */
 #define	IP_RECVIF		20   /* bool; receive reception if w/dgram */
+#define IPV6_RECVIF		IP_RECVIF   /* int */
+#define	IP_ADDRFORM		22   /* int; get/set form of returned addrs */
+#define	IPV6_ADDRFORM		IP_ADDRFORM
+#define	IPV6_NOPROBE		28   /* int; don't trigger NUD probes */
+#define IPV6_RECVSRCRT		29   /* int; receive source route array */
+#define IPV6_SENDIF		31   /* sockaddr; set outgoing iface */
+#define IPV6_RECVPKTINFO	32   /* int; receive packet info */
+#define IPV6_PKTINFO		33   /* in6_pktinfo; set packet info */
+#define IP_RECVTTL		34   /* int; receive TTL/hlim */
+#define IPV6_RECVHOPS		IP_RECVTTL
+#define ICMPV6_FILTER		35   /* set/get icmpv6 filter */
+#define ICMP6_FILTER		ICMPV6_FILTER
+#define IPV6_PKTOPTIONS		36   /* ancillary data style */
+#define FLOW6_RAND		49   /* random generator for flow IDs */
 
 #define IP_FW_ADD     		50   /* add a firewall rule to chain */
 #define IP_FW_DEL    		51   /* delete a firewall rule from chain */
@@ -329,6 +671,7 @@
 #define	IP_DEFAULT_MULTICAST_TTL  1	/* normally limit m'casts to 1 hop  */
 #define	IP_DEFAULT_MULTICAST_LOOP 1	/* normally hear sends if a member  */
 #define	IP_MAX_MEMBERSHIPS	20	/* per socket */
+#define	IPV6_SR_MAXADDR		25	/* for IPV6_RECVSRCRT array */
 
 /*
  * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP.
@@ -337,6 +680,26 @@
 	struct	in_addr imr_multiaddr;	/* IP multicast address of group */
 	struct	in_addr imr_interface;	/* local IP address of interface */
 };
+struct ipv6_mreq {
+	struct in6_addr ipv6mr_multiaddr; /* IPv6 multicast address of group */
+	unsigned int ipv6mr_interface;	/* local IPv6 address of interface */
+};
+/* old layout */
+struct oipv6_mreq {
+	struct	in6_addr ipv6mr_multiaddr;/* IPv6 multicast address of group */
+	struct	in6_addr ipv6mr_interface;/* local IPv6 address of interface */
+};
+
+/* Print IPv6 address in network order, Yixin */
+#define print_ip6(addr)		printf("%s", ip6_sprintf(&(addr)))
+
+/*
+ * packet information
+ */
+struct in6_pktinfo {
+	struct in6_addr ipi6_addr;	/* src/dst IPv6 address */
+	int		ipi6_ifindex;	/* send/recv interface index */
+};
 
 /*
  * Argument for IP_PORTRANGE:
@@ -419,6 +782,7 @@
 	{ "fastforwarding", CTLTYPE_INT }, \
 }
 
+#include <netinet/in_altq.h>
 
 #ifdef KERNEL
 struct ifnet; struct mbuf;	/* forward declarations for Standard C */
@@ -443,6 +807,27 @@
 extern	ip_nat_ctl_t *ip_nat_ctl_ptr;
 #define	IP_NAT_IN	0x00000001
 #define	IP_NAT_OUT	0x00000002
+
+#define satosin(sa)	((struct sockaddr_in *)(sa))
+#define sintosa(sin)	((struct sockaddr *)(sin))
+#define ifatoia(ifa)	((struct in_ifaddr *)(ifa))
+
+#ifdef INET6
+struct ipv6;
+/* IPv6 Firewall hooks */
+typedef	int ip6_fw_chk_t __P((struct ipv6**, struct ifnet*, int, struct mbuf**));
+typedef	int ip6_fw_ctl_t __P((int, struct mbuf**));
+extern	ip6_fw_chk_t *ip6_fw_chk_ptr;
+extern	ip6_fw_ctl_t *ip6_fw_ctl_ptr;
+
+int	 in6_isanycast __P(( struct in6_addr *));
+char	*ip6_sprintf __P((struct in6_addr *));
+#endif
+
+#define satosin6(sa)	((struct sockaddr_in6 *)(sa))
+#define satosrt6(sa)	((struct sockaddr_rt6 *)(sa))
+#define sin6tosa(sin6)	((struct sockaddr *)(sin6))
+#define ifatoia6(ifa)	((struct in6_ifaddr *)(ifa))
 
 #endif /* KERNEL */
 
diff -uN src-current/sys/netinet/tcp_output.c src-current-ipv6/sys/netinet/tcp_output.c
--- src-current/sys/netinet/tcp_output.c
+++ src-current-ipv6/sys/netinet/tcp_output.c
@@ -45,13 +45,17 @@
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 
+#include <net/if.h>
 #include <net/route.h>
 
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
 #include <netinet/in_pcb.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
 #include <netinet/tcp.h>
 #define	TCPOUTFLAGS
 #include <netinet/tcp_fsm.h>
@@ -541,6 +545,17 @@
 		panic("tcp_output");
 	(void)memcpy(ti, tp->t_template, sizeof (struct tcpiphdr));
 
+#ifdef ALTQ_ECN
+	/*
+	 * if we have received congestion experienced segs
+	 * or this is a SYN seg, set ECN bit.
+	 */
+	if (tcp_ecn &&
+	    ((tp->t_flags & TF_RCVD_CE) || (flags & TH_SYN))) {
+		flags |= TH_ECN;
+		tp->t_flags &= ~TF_RCVD_CE;
+	}
+#endif
 	/*
 	 * Fill in fields, remembering maximum advertised
 	 * window for use in delaying messages about window sizes.
@@ -676,8 +691,16 @@
 	struct rtentry *rt;
 #endif
 	((struct ip *)ti)->ip_len = m->m_pkthdr.len;
-	((struct ip *)ti)->ip_ttl = tp->t_inpcb->inp_ip_ttl;	/* XXX */
-	((struct ip *)ti)->ip_tos = tp->t_inpcb->inp_ip_tos;	/* XXX */
+	((struct ip *)ti)->ip_ttl = tp->t_inpcb->inp_ttl;	/* XXX */
+	((struct ip *)ti)->ip_tos = tp->t_inpcb->inp_tos;	/* XXX */
+#ifdef ALTQ_ECN
+	/*
+	 * if peer is ECN capable and this is not a pure ack seg,
+	 * set ECN capable bit in IP header.
+	 */
+	if ((tp->t_flags & TF_REQ_ECN) && len > 0)
+		((struct ip *)ti)->ip_tos |= IPTOS_ECT;
+#endif
 #if 1
 	/*
 	 * See if we should do MTU discovery.  We do it only if the following
diff -uN src-current/sys/netinet/ip_output.c src-current-ipv6/sys/netinet/ip_output.c
--- src-current/sys/netinet/ip_output.c
+++ src-current-ipv6/sys/netinet/ip_output.c
@@ -36,6 +36,7 @@
 
 #define _IP_VHL
 
+#include "opt_inet6.h"
 #include "opt_ipfw.h"
 #include "opt_ipdivert.h"
 #include "opt_ipfilter.h"
@@ -54,6 +55,10 @@
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif
+#include <netinet/ipsec.h>
 #include <netinet/in_pcb.h>
 #include <netinet/in_var.h>
 #include <netinet/ip_var.h>
@@ -63,7 +68,7 @@
 #endif
 #include <machine/in_cksum.h>
 
-static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options");
+MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options");
 
 #if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1
 #undef COMPAT_IPFW
@@ -160,8 +165,6 @@
 	 * If routing to interface only,
 	 * short circuit routing lookup.
 	 */
-#define ifatoia(ifa)	((struct in_ifaddr *)(ifa))
-#define sintosa(sin)	((struct sockaddr *)(sin))
 	if (flags & IP_ROUTETOIF) {
 		if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
 		    (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
@@ -308,6 +311,12 @@
 	if (ip->ip_src.s_addr == INADDR_ANY)
 		ip->ip_src = IA_SIN(ia)->sin_addr;
 #endif
+#ifdef ALTQ
+	/*
+	 * disable packet drop hack.
+	 * packetdrop should be done by queueing.
+	 */
+#else /* !ALTQ */
 	/*
 	 * Verify that we have any chance at all of being able to queue
 	 *      the packet or packet fragments
@@ -317,6 +326,7 @@
 			error = ENOBUFS;
 			goto bad;
 	}
+#endif /* !ALTQ */
 
 	/*
 	 * Look for broadcast address and
@@ -637,7 +647,11 @@
 	register int optval = 0;
 	int error = 0;
 
-	if (level != IPPROTO_IP) {
+	if ((level != IPPROTO_IP) 
+#ifdef INET6
+	    && (level != IPPROTO_IPV6)
+#endif
+	   ) {
 		error = EINVAL;
 		if (op == PRCO_SETOPT && *mp)
 			(void) m_free(*mp);
@@ -659,6 +673,9 @@
 		case IP_RECVRETOPTS:
 		case IP_RECVDSTADDR:
 		case IP_RECVIF:
+		case IP_ADDRFORM:
+		case IPV6_RECVPKTINFO:
+		case IP_RECVTTL:
 			if (m == 0 || m->m_len != sizeof(int))
 				error = EINVAL;
 			else {
@@ -666,11 +683,32 @@
 				switch (optname) {
 
 				case IP_TOS:
-					inp->inp_ip_tos = optval;
+					inp->inp_tos = optval;
+#if defined(INET6)
+					if (so->so_proto->pr_type != SOCK_STREAM)
+						break;
+					switch (optval) {
+					case IPTOS_LOWDELAY:
+						inp->inp_oflowinfo =
+						  IPV6_PRIORITY_INTERACTIVE;
+						break;
+					case IPTOS_THROUGHPUT:
+						inp->inp_oflowinfo =
+						  IPV6_PRIORITY_BULK;
+						break;
+					}
+#endif
 					break;
 
 				case IP_TTL:
-					inp->inp_ip_ttl = optval;
+					if (optval == -1)
+						optval = ip_defttl;
+					if ((optval < 0) ||
+					    (optval > MAXTTL)) {
+						error = EINVAL;
+						break;
+					}
+					inp->inp_ttl = optval;
 					break;
 #define	OPTSET(bit) \
 	if (optval) \
@@ -693,10 +731,34 @@
 				case IP_RECVIF:
 					OPTSET(INP_RECVIF);
 					break;
+
+				case IPV6_RECVPKTINFO:
+					OPTSET(INP_RECVPKTINFO);
+					break;
+
+				case IP_RECVTTL:
+					OPTSET(INP_RECVTTL);
+					break;
+#undef OPTSET
+				case IP_ADDRFORM:
+					switch (optval) {
+					case PF_INET:
+					    break;
+
+#ifdef INET6
+					case PF_INET6:
+					    error = ip_changeversion(optval,
+								     so,
+								     inp);
+					    break;
+#endif
+					default:
+					    error = EPFNOSUPPORT;
+					}
+					break;
 				}
 			}
 			break;
-#undef OPTSET
 
 		case IP_MULTICAST_IF:
 		case IP_MULTICAST_VIF:
@@ -764,16 +826,19 @@
 		case IP_RECVRETOPTS:
 		case IP_RECVDSTADDR:
 		case IP_RECVIF:
+		case IP_ADDRFORM:
+		case IPV6_RECVPKTINFO:
+		case IP_RECVTTL:
 			*mp = m = m_get(M_WAIT, MT_SOOPTS);
 			m->m_len = sizeof(int);
 			switch (optname) {
 
 			case IP_TOS:
-				optval = inp->inp_ip_tos;
+				optval = inp->inp_tos;
 				break;
 
 			case IP_TTL:
-				optval = inp->inp_ip_ttl;
+				optval = inp->inp_ttl;
 				break;
 
 #define	OPTBIT(bit)	(inp->inp_flags & bit ? 1 : 0)
@@ -793,6 +858,18 @@
 			case IP_RECVIF:
 				optval = OPTBIT(INP_RECVIF);
 				break;
+
+			case IPV6_RECVPKTINFO:
+				optval = OPTBIT(INP_RECVPKTINFO);
+				break;
+
+			case IP_RECVTTL:
+				optval = OPTBIT(INP_RECVTTL);
+				break;
+
+			case IP_ADDRFORM:
+				optval = PF_INET;
+				break;
 			}
 			*mtod(m, int *) = optval;
 			break;
@@ -830,6 +907,56 @@
 }
 
 /*
+ * Translate IPvX to IPvY socket.
+ */
+#ifdef INET6
+int
+ip_changeversion(pf, so, inp)
+	int pf;
+	struct socket *so;
+	struct inpcb *inp;
+{
+	register struct protosw *prp;
+	short type, proto;
+
+	/* get new protosw structure */
+	prp = so->so_proto;
+	type = prp->pr_type;
+	proto = prp->pr_protocol;
+	prp = pffindproto(pf, proto, type);
+	if (prp == 0 || prp->pr_usrreqs == 0)
+		return EPROTONOSUPPORT;
+
+	if ((inp->inp_options) || (inp->inp_moptions))
+		return EADDRNOTAVAIL;
+
+	/* verify address types */
+	switch (pf) {
+	case PF_INET:
+		if (((inp->inp_flags & INP_COMPATV4) == 0) ||
+		    (inp->inp_latype == IPATYPE_IPV6) ||
+		    (inp->inp_fatype == IPATYPE_IPV6)) {
+			/* TODO */
+			return EADDRNOTAVAIL;
+		}
+		inp->inp_flags &= ~INP_COMPATV6;
+		break;
+
+	case PF_INET6:
+		inp->inp_flags |= INP_COMPATV6;
+		break;
+
+	default:
+		return EPROTONOSUPPORT;
+	}
+
+	/* magic! */
+	so->so_proto = prp;
+	return 0;
+}
+#endif
+	
+/*
  * Set up IP options in pcb for insertion in output packets.
  * Store in mbuf with pointer in pcbopt, adding pseudo-option
  * with destination address if source routed.
@@ -870,7 +997,12 @@
 	 * actual options; move other options back
 	 * and clear it when none present.
 	 */
+#ifdef INET6
+	if ((m->m_flags & M_EXT) ||
+	    (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]))
+#else
 	if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
+#endif
 		goto bad;
 	cnt = m->m_len;
 	m->m_len += sizeof(struct in_addr);
diff -uN src-current/sys/netinet/if_ether.c src-current-ipv6/sys/netinet/if_ether.c
--- src-current/sys/netinet/if_ether.c
+++ src-current-ipv6/sys/netinet/if_ether.c
@@ -52,6 +52,7 @@
 #include <sys/syslog.h>
 
 #include <net/if.h>
+#include <net/if_var.h>
 #include <net/if_dl.h>
 #include <net/route.h>
 #include <net/netisr.h>
@@ -67,7 +68,7 @@
 
 /* timer values */
 static int arpt_prune = (5*60*1); /* walk list every 5 minutes */
-static int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */
+int arpt_keep = (20*60);	/* once resolved, good for 20 more minutes */
 static int arpt_down = 20;	/* once declared down, don't send for 20 sec */
 
 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW,
@@ -93,7 +94,7 @@
 static int	arp_inuse, arp_allocated;
 
 static int	arp_maxtries = 5;
-static int	useloopback = 1; /* use loopback interface for local traffic */
+int	useloopback = 1; /* use loopback interface for local traffic */
 static int	arp_proxyall = 0;
 
 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW,
@@ -103,7 +104,6 @@
 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW,
 	   &arp_proxyall, 0, "");
 
-static void	arp_rtrequest __P((int, struct rtentry *, struct sockaddr *));
 static void	arprequest __P((struct arpcom *, u_long *, u_long *, u_char *));
 static void	arpintr __P((void));
 static void	arptfree __P((struct llinfo_arp *));
@@ -139,7 +139,7 @@
 /*
  * Parallel to llc_rtrequest.
  */
-static void
+void
 arp_rtrequest(req, rt, sa)
 	int req;
 	register struct rtentry *rt;
@@ -168,6 +168,13 @@
 		if ((rt->rt_flags & RTF_HOST) == 0 &&
 		    SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
 			rt->rt_flags |= RTF_CLONING;
+		if ((rt->rt_flags & RTF_CLONING) &&
+		    (rt->rt_ifa->ifa_flags & RTF_HOST)) {
+			rt->rt_flags &= ~RTF_CLONING;
+			rt_setgate(rt, rt_key(rt),
+					(struct sockaddr *)&null_sdl);
+			gate = rt->rt_gateway;
+		}
 		if (rt->rt_flags & RTF_CLONING) {
 			/*
 			 * Case 1: This route should come from a route to iface.
diff -uN src-current/sys/netinet/ip_icmp.c src-current-ipv6/sys/netinet/ip_icmp.c
--- src-current/sys/netinet/ip_icmp.c
+++ src-current-ipv6/sys/netinet/ip_icmp.c
@@ -73,7 +73,7 @@
 SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW, &icmpbmcastecho,
 	   0, "");
 
-#ifdef ICMPPRINTFS
+#if defined(ICMPPRINTFS) || defined(DIAGNOSTIC)
 int	icmpprintfs = 0;
 #endif
 
@@ -398,7 +398,6 @@
 		goto reflect;
 
 	case ICMP_MASKREQ:
-#define	satosin(sa)	((struct sockaddr_in *)(sa))
 		if (icmpmaskrepl == 0)
 			break;
 		/*
diff -uN src-current/sys/netinet/ip_divert.c src-current-ipv6/sys/netinet/ip_divert.c
--- src-current/sys/netinet/ip_divert.c
+++ src-current-ipv6/sys/netinet/ip_divert.c
@@ -426,7 +426,7 @@
 
 	s = splnet();
 	inp = sotoinpcb(so);
-	error = in_pcbbind(inp, nam, p);
+	error = in_pcbbind(inp, nam, 0, p);
 	splx(s);
 	return 0;
 }
diff -uN src-current/sys/netinet/afmap.c src-current-ipv6/sys/netinet/afmap.c
--- src-current/sys/netinet/afmap.c
+++ src-current-ipv6/sys/netinet/afmap.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 1997, 1998
+ *	Sony Computer Science Laboratory Inc.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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.
+ *
+ * $Id: afmap.c,v 0.4 1998/01/27 02:50:14 kjc Exp $
+ */
+
+#include "opt_inet6.h"
+
+/*
+ * experimental:
+ * mapping an ip flow to atm vpi/vci.
+ * this module is not related to queueing at all, but uses the altq
+ * flowinfo mechanism.  it's just put in the altq framework since
+ * it is easy to add devices to altq.
+ */
+
+#if defined(__FreeBSD__)
+#include "opt_altq.h"
+#endif
+
+#ifdef AFMAP
+
+#ifndef __NetBSD__
+#ifndef lint
+static char rcsid[] = "$Id: afmap.c,v 0.4 1998/01/27 02:50:14 kjc Exp $";
+#endif
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+
+#include <netinet/in.h>
+#include <netinet/afmap.h>
+
+LIST_HEAD(, afm_head) afhead_chain;
+
+static struct afm *afm_match4 __P((struct afm_head *, struct flowinfo_in *));
+#ifdef INET6
+static struct afm *afm_match6 __P((struct afm_head *, struct flowinfo_in6 *));
+#endif
+
+/*
+ * rules to block interrupts: afm_match can be called from a net
+ * level interrupt so that other routines handling the lists should
+ * be called in splnet().
+ */
+int
+afm_alloc(ifp)
+    struct ifnet *ifp;
+{
+    struct afm_head *head;
+    
+    MALLOC(head, struct afm_head *, sizeof(struct afm_head),
+	   M_DEVBUF, M_WAITOK);
+    bzero(head, sizeof(struct afm_head));
+
+    /* initialize per interface afmap list */
+    LIST_INIT(&head->afh_head);
+
+    head->afh_ifp = ifp;
+    
+    /* add this afm_head to the chain */
+    LIST_INSERT_HEAD(&afhead_chain, head, afh_chain);
+    
+    return (0);
+}
+
+int
+afm_dealloc(ifp)
+    struct ifnet *ifp;
+{
+    struct afm_head *head;
+
+    for (head = afhead_chain.lh_first; head != NULL;
+	 head = head->afh_chain.le_next)
+	if (head->afh_ifp == ifp)
+	    break;
+    if (head == NULL)
+	return (-1);
+
+    afm_removeall(ifp);
+
+    LIST_REMOVE(head, afh_chain);
+
+    FREE(head, M_DEVBUF);
+    return 0;
+}
+
+struct afm *
+afm_top(ifp)
+    struct ifnet *ifp;
+{
+    struct afm_head *head;
+
+    for (head = afhead_chain.lh_first; head != NULL;
+	 head = head->afh_chain.le_next)
+	if (head->afh_ifp == ifp)
+	    break;
+    if (head == NULL)
+	return NULL;
+    
+    return (head->afh_head.lh_first);
+}
+
+int afm_add(ifp, flowmap)
+    struct ifnet *ifp;
+    struct atm_flowmap *flowmap;
+{
+    struct afm_head *head;
+    struct afm *afm;
+
+    for (head = afhead_chain.lh_first; head != NULL;
+	 head = head->afh_chain.le_next)
+	if (head->afh_ifp == ifp)
+	    break;
+    if (head == NULL)
+	return (-1);
+
+    if (flowmap->af_flowinfo.fi_family == AF_INET) {
+	if (flowmap->af_flowinfo.fi_len != sizeof(struct flowinfo_in))
+	    return (EINVAL);
+#ifdef INET6
+    } else if (flowmap->af_flowinfo.fi_family == AF_INET6) {
+	if (flowmap->af_flowinfo.fi_len != sizeof(struct flowinfo_in6))
+	    return (EINVAL);
+#endif
+    } else
+	return (EINVAL);
+
+    MALLOC(afm, struct afm *, sizeof(struct afm),
+	   M_DEVBUF, M_WAITOK);
+    bzero(afm, sizeof(struct afm));
+
+    afm->afm_vci = flowmap->af_vci;
+    afm->afm_vpi = flowmap->af_vpi;
+    bcopy(&flowmap->af_flowinfo, &afm->afm_flowinfo,
+	  flowmap->af_flowinfo.fi_len);
+
+    LIST_INSERT_HEAD(&head->afh_head, afm, afm_list);
+    return 0;
+}
+
+int afm_remove(afm)
+    struct afm *afm;
+{
+    LIST_REMOVE(afm, afm_list);
+    FREE(afm, M_DEVBUF);
+    return (0);
+}
+
+int afm_removeall(ifp)
+    struct ifnet *ifp;
+{
+    struct afm_head *head;
+    struct afm *afm;
+
+    for (head = afhead_chain.lh_first; head != NULL;
+	 head = head->afh_chain.le_next)
+	if (head->afh_ifp == ifp)
+	    break;
+    if (head == NULL)
+	return (-1);
+
+    while ((afm = head->afh_head.lh_first) != NULL)
+	afm_remove(afm);
+    return (0);
+}
+
+struct afm *afm_lookup(ifp, vpi, vci)
+    struct ifnet *ifp;
+    int vpi, vci;
+{
+    struct afm_head *head;
+    struct afm *afm;
+
+    for (head = afhead_chain.lh_first; head != NULL;
+	 head = head->afh_chain.le_next)
+	if (head->afh_ifp == ifp)
+	    break;
+    if (head == NULL)
+	return NULL;
+
+    for (afm = head->afh_head.lh_first; afm != NULL;
+	 afm = afm->afm_list.le_next)
+	if (afm->afm_vpi == vpi && afm->afm_vci == vci)
+	    break;
+    return afm;
+}
+
+/* should be called in splimp() */
+struct afm *afm_match4(head, fp)
+    struct afm_head *head;
+    struct flowinfo_in *fp;
+{
+    struct afm *afm;
+
+    for (afm = head->afh_head.lh_first; afm != NULL; afm = afm->afm_list.le_next) {
+	if (afm->afm_flowinfo4.fi_dst.s_addr != 0 &&
+	    afm->afm_flowinfo4.fi_dst.s_addr != fp->fi_dst.s_addr)
+	    continue;
+	if (afm->afm_flowinfo4.fi_dport != 0 &&
+	    afm->afm_flowinfo4.fi_dport != fp->fi_dport)
+	    continue;
+	if (afm->afm_flowinfo4.fi_src.s_addr != 0 &&
+	    afm->afm_flowinfo4.fi_src.s_addr != fp->fi_src.s_addr)
+	    continue;
+	if (afm->afm_flowinfo4.fi_sport != 0 &&
+	    afm->afm_flowinfo4.fi_sport != fp->fi_sport)
+	    continue;
+	if (afm->afm_flowinfo4.fi_proto != 0 &&
+	    afm->afm_flowinfo4.fi_proto != fp->fi_proto)
+	    continue;
+	/* match found! */
+	return (afm);
+    }
+    return NULL;
+}
+
+#ifdef INET6
+static struct afm *afm_match6(head, fp)
+    struct afm_head *head;
+    struct flowinfo_in6 *fp;
+{
+    struct afm *afm;
+
+    for (afm = head->afh_head.lh_first; afm != NULL; afm = afm->afm_list.le_next) {
+	if (afm->afm_flowinfo6.fi_flowlabel != 0 &&
+	    afm->afm_flowinfo6.fi_flowlabel != fp->fi_flowlabel)
+	    continue;
+#ifdef notyet
+	if (afm->afm_flowinfo6.fi_dport != 0 &&
+	    afm->afm_flowinfo6.fi_dport != fp->fi_dport)
+	    continue;
+	if (!IS_ANYADDR6(afm->afm_flowinfo6.fi_dst) &&
+	    !SAME_ADDR6(afm->afm_flowinfo6.fi_dst, fp->fi_dst))
+	    continue;
+#endif
+	if (!IS_ANYADDR6(afm->afm_flowinfo6.fi_src) &&
+	    !SAME_ADDR6(afm->afm_flowinfo6.fi_src, fp->fi_src))
+	    continue;
+#ifdef notyet
+	if (afm->afm_flowinfo6.fi_sport != 0 &&
+	    afm->afm_flowinfo6.fi_sport != fp->fi_sport)
+	    continue;
+#endif
+	if (afm->afm_flowinfo6.fi_proto != 0 &&
+	    afm->afm_flowinfo6.fi_proto != fp->fi_proto)
+	    continue;
+	/* match found! */
+	return (afm);
+    }
+    return NULL;
+}
+#endif
+
+struct afm *afm_match(ifp, flow)
+    struct ifnet *ifp;
+    struct flowinfo *flow;
+{
+    struct afm_head *head;
+
+    for (head = afhead_chain.lh_first; head != NULL;
+	 head = head->afh_chain.le_next)
+	if (head->afh_ifp == ifp)
+	    break;
+    if (head == NULL)
+	return NULL;
+
+    switch (flow->fi_family) {
+    case AF_INET:
+	return (afm_match4(head, (struct flowinfo_in *)flow));
+
+#ifdef INET6
+    case AF_INET6:
+	return (afm_match6(head, (struct flowinfo_in6 *)flow));
+#endif
+
+    default:
+	return NULL;
+    }
+}
+
+/*
+ * afm device interface
+ */
+#include <sys/sockio.h>
+#include <sys/conf.h>
+
+d_open_t	afmopen;
+d_close_t	afmclose;
+d_ioctl_t	afmioctl;
+
+int
+afmopen(dev, flag, fmt, p)
+    dev_t dev;
+    int flag, fmt;
+    struct proc *p;
+{
+    return 0;
+}
+
+int
+afmclose(dev, flag, fmt, p)
+    dev_t dev;
+    int flag, fmt;
+    struct proc *p;
+{
+    int err, error = 0;
+    struct atm_flowmap fmap;
+    struct afm_head *head;
+
+    for (head = afhead_chain.lh_first; head != NULL;
+	 head = head->afh_chain.le_next) {
+
+	/* call interface to clean up maps */
+#ifdef __FreeBSD__
+	sprintf(fmap.af_ifname, "%s%d",
+		head->afh_ifp->if_name, head->afh_ifp->if_unit);
+#else
+	sprintf(fmap.af_ifname, "%s", head->afh_ifp->if_xname);
+#endif
+	err = afmioctl(dev, AFM_CLEANFMAP, (caddr_t)&fmap, flag, p);
+	if (err && error == 0)
+	    error = err;
+    }
+
+    return error;
+}
+
+int
+afmioctl(dev, cmd, addr, flag, p)
+    dev_t dev;
+    int cmd;
+    caddr_t addr;
+    int flag;
+    struct proc *p;
+{
+    int	error = 0;
+    struct atm_flowmap *flowmap;
+    struct ifnet *ifp;
+
+    /* check cmd for superuser only */
+    switch (cmd) {
+    case AFM_GETFMAP:
+	break;
+    default:
+	error = suser(p->p_ucred, &p->p_acflag);
+	if (error)
+	    return (error);
+	break;
+    }
+
+    /* lookup interface */
+    flowmap = (struct atm_flowmap *)addr;
+    flowmap->af_ifname[IFNAMSIZ-1] = '\0'; 	  
+    ifp = ifunit(flowmap->af_ifname);
+    if (ifp == NULL || ifp->if_ioctl == NULL ||
+	(ifp->if_flags & IFF_RUNNING) == 0)
+	error = ENXIO;
+    else
+	error = ifp->if_ioctl(ifp, cmd, addr);
+
+    return error;
+}
+
+#endif /* AFMAP */
diff -uN src-current/sys/netinet/afmap.h src-current-ipv6/sys/netinet/afmap.h
--- src-current/sys/netinet/afmap.h
+++ src-current-ipv6/sys/netinet/afmap.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 1997, 1998
+ *	Sony Computer Science Laboratory Inc.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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.
+ *
+ * $Id: afmap.h,v 0.4 1998/01/27 02:50:14 kjc Exp $
+ */
+
+#ifndef _NETINET_AFMAP_H_
+#define _NETINET_AFMAP_H_
+
+#include <sys/queue.h>
+
+struct atm_flowmap {
+    char		af_ifname[IFNAMSIZ];	/* if name, e.g. "en0" */
+    u_int8_t		af_vpi;
+    u_int16_t		af_vci;
+    u_int32_t		af_pcr;			/* peek cell rate */
+    union {
+	struct flowinfo	      afu_fi;
+	struct flowinfo_in    afu_fi4;
+#ifdef INET6
+	struct flowinfo_in6   afu_fi6;
+#endif
+    } af_fiu;
+#define af_flowinfo	af_fiu.afu_fi
+#define af_flowinfo4	af_fiu.afu_fi4
+#define af_flowinfo6	af_fiu.afu_fi6
+
+    /* statistics */
+    u_int32_t		afs_packets;		/* total packet count */
+    u_int32_t		afs_bytes;		/* total byte count */
+};
+
+/* set or get flowmap */
+#define AFM_ADDFMAP	_IOWR('F', 1, struct atm_flowmap)
+#define AFM_DELFMAP	_IOWR('F', 2, struct atm_flowmap)
+#define AFM_CLEANFMAP	_IOWR('F', 3, struct atm_flowmap)
+#define AFM_GETFMAP	_IOWR('F', 4, struct atm_flowmap)
+
+#ifdef KERNEL
+
+/* per flow information */
+struct afm {
+    LIST_ENTRY(afm) 	afm_list;
+    u_int16_t		afm_vci;
+    u_int8_t		afm_vpi;
+    union {
+	struct flowinfo      afmu_fi;
+	struct flowinfo_in   afmu_fi4;
+#ifdef INET6
+	struct flowinfo_in6  afmu_fi6;
+#endif
+    } afm_fiu;
+#define afm_flowinfo	afm_fiu.afmu_fi
+#define afm_flowinfo4	afm_fiu.afmu_fi4
+#define afm_flowinfo6	afm_fiu.afmu_fi6
+
+    /* statistics */
+    u_int32_t		afms_packets;		/* total packet count */
+    u_int32_t		afms_bytes;		/* total byte count */
+};
+
+/* per interface */
+struct afm_head {
+    LIST_ENTRY(afm_head) 	afh_chain;
+    LIST_HEAD(, afm)	afh_head;
+    struct ifnet	*afh_ifp;
+};
+
+
+struct afm *afm_top __P((struct ifnet *));
+int afm_alloc __P((struct ifnet *));
+int afm_dealloc __P((struct ifnet *));
+int afm_add __P((struct ifnet *, struct atm_flowmap *));
+int afm_remove __P((struct afm *));
+int afm_removeall __P((struct ifnet *));
+struct afm *afm_lookup __P((struct ifnet *, int, int));
+struct afm *afm_match __P((struct ifnet *, struct flowinfo *));
+
+#endif /* KERNEL */
+
+#endif /* _NETINET_AFMAP_H_ */
diff -uN src-current/sys/netinet/cbq.c src-current-ipv6/sys/netinet/cbq.c
--- src-current/sys/netinet/cbq.c
+++ src-current-ipv6/sys/netinet/cbq.c
@@ -0,0 +1,1312 @@
+/*
+ * Copyright (c) Sun Microsystems, Inc. 1993-1997. All rights reserved.
+ *
+ * License is granted to copy, to use, and to make and to use derivative works
+ * for research and evaluation purposes, provided that Sun Microsystems is
+ * acknowledged in all documentation pertaining to any such copy or
+ * derivative work. Sun Microsystems grants no other licenses expressed or
+ * implied. The Sun Microsystems  trade name should not be used in any
+ * advertising without its written permission.
+ *
+ * SUN MICROSYSTEMS MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS
+ * SOFTWARE FOR ANY PARTICULAR PURPOSE.  The software is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this software.
+ */
+
+/*
+ * Copyright (c) 1993-1997 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 the Network Research Group at
+ *	Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory 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.
+ */
+/*
+ * Copyright (C) 1997, 1998
+ *	Sony Computer Science Laboratory Inc.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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.
+ *
+ * $Id: cbq.c,v 0.9 1998/01/30 09:06:31 kjc Exp kjc $
+ */
+
+#include "opt_inet6.h"
+
+#if defined(__FreeBSD__)
+#include "opt_altq.h"
+#endif
+
+#ifdef CBQ	/* cbq is enabled by CBQ option in opt_altq.h */
+
+/*
+static char rcsid[] = "$Id: cbq.c,v 0.9 1998/01/30 09:06:31 kjc Exp kjc $";
+*/
+#ident "@(#)cbq.c  1.16     97/08/03 SMI"
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+
+#include <netinet/rm_class.h>
+#include <netinet/cbq.h>
+
+#ifdef ALTQ
+#define CBQ_DEBUG
+#endif
+
+#if defined(__NetBSD__)
+typedef void (timeout_t)(void *);
+#endif
+
+/*
+ * Local Data structures.
+ */
+static cbq_state_t *cbq_list = NULL;
+
+/*
+ * Forward Declarations.
+ */
+
+static int		cbq_set_enable(struct cbq_interface *, int);
+static int		cbq_set_accenable(struct cbq_interface *, int);
+static int		cbq_add_filter(struct cbq_add_filter *);
+static int		cbq_delete_filter(struct cbq_delete_filter *);
+static int		cbq_add_class(struct cbq_add_class *);
+static int		cbq_delete_class(struct cbq_delete_class *);
+static int		cbq_clear_hierarchy(struct cbq_interface *);
+
+static int		cbq_clear_interface(cbq_state_t *);
+static void		cbq_dealloc_filter(cbq_state_t *, k_filter_cb_t *);
+static int		is_a_parent_class(cbq_state_t *, struct rm_class *);
+static k_filter_cb_t 	*cbq_filth_to_filtp(cbq_state_t *, u_long, int *);
+static u_long		cbq_alloc_class_handle(cbq_state_t *, int *);
+static void		cbq_free_class_handle(cbq_state_t *, u_long);
+static struct rm_class  *cbq_clh_to_clp(cbq_state_t *, u_long, int *);
+
+static int		cbq_ifattach(struct cbq_interface *);
+static int		cbq_ifdetach(struct cbq_interface *);
+static int		cbq_enqueue(struct ifnet *, struct mbuf *, struct pr_hdr *, int);
+static struct mbuf 	*cbq_dequeue(struct ifnet *, int);
+static void		cbqwatchdog(cbq_state_t *);
+
+static void 		_get_stats(class_stats_t *, struct rm_class *);
+static int 		cbq_getstats(struct cbq_getstats *);
+static void		cbq_flush(cbq_state_t *);
+
+/*
+ * static int
+ * cbq_set_enable(struct cbq_enable *ep) - this function processed the
+ *	ioctl request to enable class based queueing.  It searches the list
+ *	of interfaces for the specified interface and then enables CBQ on
+ *	that interface.
+ *
+ *	Returns:	0, for no error.
+ *			ENXIO, for specified inteface not found.
+ */
+
+static int
+cbq_set_enable(ep, enable)
+    struct cbq_interface *ep;
+    int enable;
+{
+    int 	error = 0;
+    cbq_state_t	*cbqp;
+    char 	*ifacename;
+
+    ifacename = ep->cbq_ifacename;
+    if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
+	return ENXIO;
+	
+    switch (enable) {
+    case ENABLE:
+	if (!cbqp->ifnp.root_ || !cbqp->ifnp.default_ || !cbqp->ifnp.ctl_) {
+	    if (!cbqp->ifnp.root_)
+		printf("No Root Class for %s\n", ifacename);
+	    if (!cbqp->ifnp.default_)
+		printf("No Default Class for %s\n", ifacename);
+	    if (!cbqp->ifnp.ctl_)
+		printf("No Control Class for %s\n", ifacename);
+	    error = ENXIO;
+	}
+	else if ((error = if_altqenable(cbqp->ifnp.ifp)) == 0) {
+	    cbqp->cbq_busy = 0;
+	    timeout((timeout_t *)cbqwatchdog, cbqp, CBQ_TIMEOUT);
+	}
+	break;
+    case DISABLE:
+	untimeout((timeout_t *)cbqwatchdog, cbqp); 
+	error = if_altqdisable(cbqp->ifnp.ifp);
+	break;
+    }
+/*    cbq_satisfied(cbqp);  */
+    return (error);
+}
+
+/*
+ * void
+ * cbq_satisfied(cbqp) - Check CBQ to see how link-sharing is performing.
+ *
+ *	Returns: NONE
+ */
+#ifdef notyet
+static void
+cbq_satisfied(cbq_state_t *cbqp)
+{
+#ifdef USE_HRTIME
+    hrtime_t	now;
+#else
+    struct timeval	now;
+#endif
+    if (cbqp->cbq_enabled) {
+	RM_GETTIME(now);
+	rmc_tl_satisfied(&cbqp->ifnp, &now);
+	cbqp->cbq_tl_timeout_id = timeout(cbq_satisfied,
+					  (caddr_t)cbqp, CBQ_LS_TIMEOUT);
+    } else
+	cbqp->cbq_tl_timeout_id = 0;
+}
+#endif
+
+static int
+cbq_set_accenable(ep, enable)
+    struct cbq_interface *ep;
+    int enable;
+{
+    int 	error = 0;
+    cbq_state_t	*cbqp;
+    char 	*ifacename;
+    struct ifnet *ifp;
+    int		s;
+
+    ifacename = ep->cbq_ifacename;
+    if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
+	return ENXIO;
+
+    ifp = cbqp->ifnp.ifp;
+    s = splimp();
+    switch (enable) {
+    case ENABLE:
+	SET_ACCOUNTING(ifp);
+	break;
+    case DISABLE:
+	CLEAR_ACCOUNTING(ifp);
+	break;
+    }
+    splx(s);
+    return (error);
+}
+
+
+/* copy the stats info in rm_class to class_states_t */
+static void
+_get_stats(statsp, cl)
+    class_stats_t	*statsp;
+    struct rm_class	*cl;
+{
+    statsp->depth 	= cl->depth_;
+
+    statsp->npackets 	= cl->stats_.npackets;
+    statsp->nbytes 	= cl->stats_.nbytes;
+    statsp->over	= cl->stats_.over;
+    statsp->borrows 	= cl->stats_.borrows;
+    statsp->drops 	= cl->stats_.drops;
+#ifdef ALTQ
+    statsp->drop_bytes 	= cl->stats_.drop_bytes;
+#endif
+    statsp->overactions = cl->stats_.overactions;
+    statsp->delays 	= cl->stats_.delays;
+
+#ifdef ALTQ
+    statsp->priority	= cl->pri_;
+    statsp->maxidle	= cl->maxidle_;
+    statsp->minidle	= cl->minidle_;
+    statsp->offtime	= cl->offtime_;
+    statsp->qmax	= qlimit(cl->q_);
+#if RM_DEFAULT_MTU >= 1000
+    statsp->ns_per_byte	= cl->len2time_[1000];
+#else
+#error len2time too small!  rewrite how to get ns_per_byte.
+#endif
+    statsp->wrr_allot	= cl->w_allotment_;
+    statsp->qcnt	= qlen(cl->q_);
+    statsp->avgidle	= cl->avgidle_;
+#endif /* ALTQ */
+}
+
+static int
+cbq_getstats(gsp)
+    struct cbq_getstats *gsp;
+{
+    int			error = 0;
+    char		*ifacename;
+    int			handle, n, nclasses;
+    cbq_state_t		*cbqp;
+    struct rm_class	*cl;
+    class_stats_t	stats, *usp;
+
+    ifacename = gsp->iface.cbq_ifacename;
+    nclasses = gsp->nclasses;
+    usp = gsp->stats;
+
+    if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
+	return ENXIO;
+    if (nclasses <= 0)
+	return EINVAL;
+
+    for (n = 0, handle = 0; n < nclasses && handle < CBQ_MAX_CLASSES; n++) {
+	switch(n) {
+	case 0:
+	    if (!(cl = cbqp->ifnp.root_))
+		return ENXIO;
+	    stats.handle = ROOT_CLASS_HANDLE;
+	    break;
+	case 1:
+	    if (!(cl = cbqp->ifnp.default_))
+		return ENXIO;
+	    stats.handle = DEFAULT_CLASS_HANDLE;
+	    break;
+	case 2:
+	    if ((cl = cbqp->ifnp.ctl_)) {
+		stats.handle = CTL_CLASS_HANDLE;
+		break;
+	    }
+	    /* fall into... */
+	default:
+	    while (!(cl = cbqp->cbq_class_tbl[handle]))
+		if (++handle >= CBQ_MAX_CLASSES)
+		    goto out;
+	    stats.handle = handle++;
+	    break;
+	}
+
+	_get_stats(&stats, cl);
+
+	if ((error = copyout((caddr_t)&stats, (caddr_t)usp++, sizeof(stats))))
+	    return (error);
+    }
+
+ out:
+    gsp->nclasses = n;
+
+    return error;
+}
+
+static u_long get_filt_handle(cbq_state_t *cbqp, int i)
+{
+    static u_long _k_filt_handles = 1;
+    u_long handle;
+    k_filter_cb_t 	*kfp;
+
+    while (1) {
+	handle = _k_filt_handles++ & 0x000fffff;
+
+	if (cbqp->filters[i] == NULL)
+	    return (handle);
+	
+	for (kfp = cbqp->filters[i]; kfp; kfp = kfp->next) {
+	    if ((kfp->handle & 0x000fffff) == handle)
+		break;
+	}
+	if (kfp == NULL)
+	    break;
+	/* this handle is already used, try again */
+    }
+    return (handle);
+}
+
+/* TODO: wildcard handling */
+static int
+cbq_add_filter(afp)
+    struct cbq_add_filter *afp;
+{
+    int			error = 0;
+    char		*ifacename;
+    int			s, i;
+    cbq_state_t		*cbqp;
+    k_filter_cb_t	*kfcbp;
+    struct rm_class	*classp;
+    u_long		handle;
+
+#ifdef INET6
+    if (afp->cbq_filter.family == 0)
+	afp->cbq_filter.family = AF_INET;
+#endif
+
+    ifacename = afp->cbq_iface.cbq_ifacename;
+    if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
+	return ENXIO;
+
+    /* Get the pointer to class. */
+    classp = cbq_clh_to_clp(cbqp, afp->cbq_class_handle, &error);
+    if (error)
+	return error;
+
+    MALLOC(kfcbp, k_filter_cb_t *, sizeof(k_filter_cb_t), M_DEVBUF, M_WAITOK);
+    bzero(kfcbp, sizeof(k_filter_cb_t));
+
+    bcopy(&afp->cbq_filter, &kfcbp->filter, sizeof(cbq_filt_t));
+
+    kfcbp->clp = classp;
+
+#ifdef INET6
+    if (kfcbp->filter.family == AF_INET) {
+#endif
+    /* if address is 0, it's a wildcard.  if address mask isn't set,
+       use full mask.  */
+    if (kfcbp->filter.daddr == 0)
+	kfcbp->filter.dmask = 0;
+    else if (kfcbp->filter.dmask == 0)
+	kfcbp->filter.dmask = 0xffffffff;
+    if (kfcbp->filter.saddr == 0)
+	kfcbp->filter.smask = 0;
+    else if (kfcbp->filter.smask == 0)
+	kfcbp->filter.smask = 0xffffffff;
+
+    /*  if dst address is a wildcard, use hash-entry CBQ_WILDCARD_INDEX. */
+    if (kfcbp->filter.dmask != 0xffffffff)
+	i = CBQ_WILDCARD_INDEX;
+    else
+	i = CBQ_GET_HASH_INDEX(kfcbp->filter.daddr);
+#ifdef INET6
+    } else i = CBQ_GET_HASH_INDEX(kfcbp->filter.flow6);
+#endif
+
+    s = splimp();
+    handle = get_filt_handle(cbqp, i);
+    kfcbp->handle = (i << 20) | handle;
+
+    if (i != CBQ_WILDCARD_INDEX || cbqp->filters[i] == NULL) {
+	/* add filter to the head of the filter list. */
+	kfcbp->prev = NULL;
+	kfcbp->next = cbqp->filters[i];
+	if (cbqp->filters[i])
+	    cbqp->filters[i]->prev = kfcbp;
+	cbqp->filters[i] = kfcbp;
+    }
+    else {
+	/* keep the wildcard list sorted in the mask length order
+	   for wildcard matching.
+	   (assuming dmask is an address prefix)  */
+	k_filter_cb_t 	*kfp;
+
+	for (kfp = cbqp->filters[CBQ_WILDCARD_INDEX]; kfp; kfp = kfp->next)
+	    if ((kfp->filter.dmask &~ kfcbp->filter.dmask) == 0) {
+		/* entry has a shorter mask, insert before it.  */
+		if (kfp->prev)
+		    kfp->prev->next = kfcbp;
+		else
+		    cbqp->filters[CBQ_WILDCARD_INDEX] = kfcbp;
+		kfcbp->prev = kfp->prev;
+		kfcbp->next = kfp;
+		kfp->prev = kfcbp;
+		break;
+	    }
+	    else if (kfp->next == NULL) {
+		/* last entry.  add the new filter at the tail. */
+		kfp->next = kfcbp;
+		kfcbp->prev = kfp;
+		kfcbp->next = NULL;
+		break;
+	    }
+    }
+    splx(s);
+    afp->cbq_filter_handle = kfcbp->handle;
+
+    return (error);
+}
+
+static int
+cbq_delete_filter(dfp)
+    struct cbq_delete_filter *dfp;
+{
+    int			error = 0;
+    char		*ifacename;
+    cbq_state_t		*cbqp;
+    k_filter_cb_t	*kfp;
+    int s;
+
+    ifacename = dfp->cbq_iface.cbq_ifacename;
+    if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
+	return ENXIO;
+    
+    kfp = cbq_filth_to_filtp(cbqp, dfp->cbq_filter_handle, &error);
+    if (error)
+	return error;
+
+    s = splimp();
+    cbq_dealloc_filter(cbqp, kfp);
+    splx(s);
+    return (error);
+}
+
+static int
+cbq_add_class(acp)
+    struct cbq_add_class *acp;
+{
+    int			error = 0;
+    char		*ifacename;
+    struct rm_class	*classp, *borrow, *parent;
+    cbq_state_t		*cbqp;
+    u_long		chandle;
+    int			s;
+
+    ifacename = acp->cbq_iface.cbq_ifacename;
+    if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
+	return ENXIO;
+
+    /* Get pointers to parent and borrow classes.  */
+    parent = cbq_clh_to_clp(cbqp, acp->cbq_class.parent_class_handle, &error);
+    if (error)
+	return error;
+
+    borrow = cbq_clh_to_clp(cbqp, acp->cbq_class.borrow_class_handle, &error);
+    if (error)
+	return error;
+
+    /*
+     * A class must borrow from it's parent or it can not
+     * borrow at all.  Hence, borrow can be null.
+     */
+    if ((borrow != parent)  && (borrow != NULL)) {
+	printf("cbq_add_class: borrow class != parent\n");
+	return (EINVAL);
+    }
+
+    /* Create class.  */
+    if (!parent) {
+	if (cbqp->ifnp.root_)
+	    return (EINVAL);
+	chandle = ROOT_CLASS_HANDLE;
+    }
+    else if (acp->cbq_class.defaultclass) {
+	if (cbqp->ifnp.default_)
+	    return (EINVAL);
+	chandle = DEFAULT_CLASS_HANDLE;
+    }
+    else if (acp->cbq_class.ctlclass) {
+	if (cbqp->ifnp.ctl_)
+	    return EINVAL;
+	chandle = CTL_CLASS_HANDLE;
+    }
+    else {
+	chandle = cbq_alloc_class_handle(cbqp, &error);
+	if (error)
+	    return error;
+    }
+
+    s = splimp();
+    classp = cbq_class_create(cbqp, acp, chandle, parent, borrow);
+    splx(s);
+    if (!classp) {
+#ifdef CBQ_DEBUG
+	printf("cbq_class_create: failed! chandle=%lu\n", chandle);
+#endif
+	cbq_free_class_handle(cbqp, chandle);
+	return (ENOMEM);
+    }
+
+    /* Return handle to user space. */
+    classp->stats_.handle = chandle;
+    classp->stats_.depth = classp->depth_;
+    acp->cbq_class_handle = chandle;
+    return (error);
+}
+
+static int
+cbq_delete_class(dcp)
+    struct cbq_delete_class *dcp;
+{
+    int			error = 0;
+    char		*ifacename;
+    struct rm_class	*classp;
+    cbq_state_t		*cbqp;
+    k_filter_cb_t	*kfp, *tfp;
+    int			s, i;
+
+    ifacename = dcp->cbq_iface.cbq_ifacename;
+    if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
+	return ENXIO;
+
+    classp = cbq_clh_to_clp(cbqp, dcp->cbq_class_handle, &error);
+    if (error || !classp)
+	return error;
+    
+    /*
+     * If we are a parent class, then return an error. 
+     */ 
+    if (is_a_parent_class(cbqp, classp))
+	return (EINVAL);
+
+    s = splimp();
+    /*
+     * If a filter has a reference to this class delete
+     * the filter before deleting the class.
+     */
+    for (i = 0; i < CBQ_FILTER_TBL_SZ; i++)
+	for (kfp = cbqp->filters[i]; kfp; kfp = tfp) {
+	    tfp = kfp->next;
+	    if (kfp->clp == classp)
+		cbq_dealloc_filter(cbqp, kfp);
+	}
+
+    error = cbq_class_destroy(cbqp, classp);
+    splx(s);
+    if (error)
+	return error;
+    
+    cbq_free_class_handle(cbqp, dcp->cbq_class_handle); 
+    return (error);
+}
+
+/*
+ * cbq_clear_hierarchy deletes all classes and their filters on the
+ * given interface.
+ * note that this doesn't affect the enable state and leaves
+ * the root class and the default class intact.  This behavior is
+ * different from Sun's CBQ implementation.
+ */
+static int
+cbq_clear_hierarchy(ifacep)
+    struct cbq_interface *ifacep;
+{
+    int		error = 0;
+    char	*ifacename;
+    cbq_state_t	*cbqp;
+
+    ifacename = ifacep->cbq_ifacename;
+    if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
+	return ENXIO;
+
+    error = cbq_clear_interface(cbqp);
+    return (error);
+}
+
+static int
+cbq_clear_interface(cbqp)
+    cbq_state_t *cbqp;
+{
+    int		again, i, s;
+    k_filter_cb_t	*kfp, *tfp;
+    struct rm_class	*cl;
+
+    s = splimp();
+    /*
+     * Free the filters for this interface.
+     */
+    for (i = 0; i < CBQ_FILTER_TBL_SZ; i++)
+	for (kfp = cbqp->filters[i]; kfp; kfp = tfp) {
+	    tfp = kfp->next;
+	    cbq_dealloc_filter(cbqp, kfp);
+	}
+
+    /*
+     * Clear out the classes now.
+     */
+do_it_again:
+    again = 0;
+    for (i = 0; i < CBQ_MAX_CLASSES; i++) {
+	if ((cl = cbqp->cbq_class_tbl[i]) == NULL)
+	    continue;
+	if (is_a_parent_class(cbqp, cl)) {
+	    again++;
+	    continue;
+	}
+
+	cbq_class_destroy(cbqp, cl);
+	cbqp->cbq_class_tbl[i] = NULL;
+    }
+    if (again)
+	goto do_it_again;
+
+#ifndef ALTQ	/* !!! check this behavior !!! */
+    if (cbqp->ifnp.ctl_) {
+	cbq_class_destroy(cbqp, cbqp->ifnp.ctl_);
+	cbqp->ifnp.ctl_ = NULL;
+    }
+
+    if (cbqp->ifnp.default_) {
+	cbq_class_destroy(cbqp, cbqp->ifnp.default_);
+	cbqp->ifnp.default_ = NULL;
+    }
+
+    if (cbqp->ifnp.root_) {
+	cbq_class_destroy(cbqp, cbqp->ifnp.root_);
+	cbqp->ifnp.root_ = NULL;
+    }
+#endif
+    splx(s);
+    return (0);
+}
+
+static int
+is_a_parent_class(cbqp, cl)
+    cbq_state_t *cbqp;
+    struct rm_class *cl;
+{
+    int	i;
+
+    if (!cl)
+	return (0);
+
+    for (i = 0; i < CBQ_MAX_CLASSES; i++) {
+	if (cbqp->cbq_class_tbl[i]) {
+	    if (cbqp->cbq_class_tbl[i]->parent_ == cl)
+		return (1);
+	}
+    }
+
+    return (0);
+}
+
+static void
+cbq_dealloc_filter(cbqp, kfp)
+    cbq_state_t *cbqp;
+    k_filter_cb_t *kfp;
+{
+    if (!kfp || !cbqp)
+	return;
+    
+    /* Delete from the filter list. */
+    if (kfp->prev && kfp->next) {
+	kfp->prev->next = kfp->next;
+	kfp->next->prev = kfp->prev;
+    } else if (kfp->prev && !kfp->next) {
+	kfp->prev->next = NULL;
+    } else {
+	int i;
+
+	if (kfp->filter.dmask != 0xffffffff)
+	    i = CBQ_WILDCARD_INDEX;
+	else
+	    i = CBQ_GET_HASH_INDEX(kfp->filter.daddr);
+	if (kfp->next && !kfp->prev) {
+	    kfp->next->prev = NULL;
+	    cbqp->filters[i] = kfp->next;
+	} else
+	    cbqp->filters[i] = NULL;
+    }
+
+    kfp->next = kfp->prev = NULL;
+    FREE(kfp, M_DEVBUF);
+}
+
+/* convert filter handle to filter pointer */
+static k_filter_cb_t *
+cbq_filth_to_filtp(cbqp, handle, error)
+    cbq_state_t *cbqp;
+    u_long handle;
+    int *error;
+{
+    k_filter_cb_t 	*kfp;
+
+    int i = CBQ_GET_HINDEX(handle);
+
+    if (cbqp->filters[i]) {
+	for (kfp = cbqp->filters[i]; kfp; kfp = kfp->next) {
+	    if (kfp->handle == handle)
+		return (kfp);
+	}
+    }
+
+    *error = EINVAL;
+    return ((k_filter_cb_t *)NULL);
+}
+
+static u_long
+cbq_alloc_class_handle(cbqp, error)
+    cbq_state_t *cbqp;
+    int *error;
+{
+    int	i;
+    u_long	handle = 0;
+
+    for (i = 0; i < CBQ_MAX_CLASSES; i++) {
+	if (!cbqp->cbq_class_tbl[i])
+	    break;
+    }
+
+    if (i >= CBQ_MAX_CLASSES)
+	*error = ENOSPC;
+
+    handle = (u_long)i;
+    return (handle);	
+}
+
+static void
+cbq_free_class_handle(cbqp, handle)
+    cbq_state_t *cbqp;
+    u_long handle;
+{
+    switch (handle) {
+    case ROOT_CLASS_HANDLE:
+    case DEFAULT_CLASS_HANDLE:
+    case CTL_CLASS_HANDLE:
+    case NULL_CLASS_HANDLE:
+	break;
+
+    default:
+	if (handle >= CBQ_MAX_CLASSES)
+	    return ;
+
+	cbqp->cbq_class_tbl[handle] = NULL;
+    }
+}
+
+/* convert class handle to class pointer */
+static struct rm_class *
+cbq_clh_to_clp(cbqp, handle, error)
+    cbq_state_t *cbqp;
+    u_long handle;
+    int *error;
+{
+    switch (handle) {
+    case NULL_CLASS_HANDLE:
+	return ((struct rm_class *)NULL);
+
+    case ROOT_CLASS_HANDLE:
+	if (!cbqp->ifnp.root_)
+	    *error = EINVAL;
+	return (cbqp->ifnp.root_);
+
+    case DEFAULT_CLASS_HANDLE:
+	if (!cbqp->ifnp.default_)
+	    *error = EINVAL;
+	return (cbqp->ifnp.default_);
+
+    case CTL_CLASS_HANDLE:
+	if (!cbqp->ifnp.ctl_)
+	    *error = EINVAL;
+	return (cbqp->ifnp.ctl_);
+
+    default:
+	if (handle >= CBQ_MAX_CLASSES)
+	    *error = ENXIO;
+	else
+	    return (cbqp->cbq_class_tbl[handle]);
+    }
+    *error = EINVAL;
+    return NULL;
+}
+
+static int
+cbq_ifattach(ifacep)
+    struct cbq_interface *ifacep;
+{
+    int		error = 0;
+    char	*ifacename;
+    cbq_state_t	*new_cbqp;
+    struct ifnet *ifp;
+    int		i;
+
+    ifacename = ifacep->cbq_ifacename;
+    if ((ifp = ifunit(ifacename)) == NULL) {
+#ifdef CBQ_DEBUG
+	printf("cbq_ifattach: no ifp found!\n");
+#endif
+	return (ENXIO);
+    }
+    if (!ALTQ_IS_READY(ifp))
+	return (ENXIO);
+
+    /* allocate and initialize cbq_state_t */
+    MALLOC(new_cbqp, cbq_state_t *, sizeof(cbq_state_t), M_DEVBUF, M_WAITOK);
+    bzero(new_cbqp, sizeof(cbq_state_t));
+    MALLOC(new_cbqp->cbq_class_tbl, struct rm_class **,
+	   sizeof(struct rm_class *) * CBQ_MAX_CLASSES, M_DEVBUF, M_WAITOK);
+    bzero(new_cbqp->cbq_class_tbl, sizeof(struct rm_class *) * CBQ_MAX_CLASSES);
+    new_cbqp->q_full = 0;
+    new_cbqp->qlen = 0;
+    new_cbqp->cbq_busy = 0;
+    for (i = 0; i < CBQ_FILTER_TBL_SZ; i++)
+	new_cbqp->filters[i] = NULL;
+#ifndef ALTQ
+    new_cbqp->threshold = CBQ_VIRTUAL_IF_THRESH;
+#endif
+    new_cbqp->ifnp.ifp = ifp;	    /* keep the ifp */
+       
+    /*
+     * Append to the list of cbq_state_t's.
+     */
+    new_cbqp->cbq_next = NULL;
+    if (cbq_list) {
+	cbq_state_t	*cbqp;
+
+	for (cbqp = cbq_list; cbqp->cbq_next; cbqp = cbqp->cbq_next)
+			    ;
+	cbqp->cbq_next = new_cbqp;
+    } else
+	cbq_list = new_cbqp;
+
+    /*
+     * set CBQ to this ifnet structure.
+     */
+    error = if_altqattach(ifp, new_cbqp, cbq_enqueue, cbq_dequeue, ALTQT_CBQ);
+    if (error)
+	(void)cbq_ifdetach(ifacep);
+
+    return (error);
+}
+
+static int
+cbq_ifdetach(ifacep)
+    struct cbq_interface *ifacep;
+{
+    int		error = 0;
+    char	*ifacename;
+    cbq_state_t *cbqp;
+    int s;
+    
+    ifacename = ifacep->cbq_ifacename;
+    if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
+	return ENXIO;
+
+    error = cbq_set_enable(ifacep, DISABLE);
+    (void)cbq_set_accenable(ifacep, DISABLE);
+    if (error)
+	return error;
+    
+    error = cbq_clear_hierarchy(ifacep);
+#ifdef CBQ_DEBUG
+    if (error)
+	printf("cbq_ifdetach: clear failed!\n");
+#endif
+
+    s = splimp();
+    if (cbqp->ifnp.ctl_) {
+	cbq_class_destroy(cbqp, cbqp->ifnp.ctl_);
+	cbqp->ifnp.ctl_ = NULL;
+    }
+
+    if (cbqp->ifnp.default_) {
+	cbq_class_destroy(cbqp, cbqp->ifnp.default_);
+	cbqp->ifnp.default_ = NULL;
+    }
+
+    if (cbqp->ifnp.root_) {
+	cbq_class_destroy(cbqp, cbqp->ifnp.root_);
+	cbqp->ifnp.root_ = NULL;
+    }
+    splx(s);
+    
+    /* remove CBQ from the ifnet structure. */
+    (void)if_altqdetach(cbqp->ifnp.ifp);
+    
+    /* remove from the list of cbq_state_t's. */
+    if (cbq_list == cbqp)
+	cbq_list = cbqp->cbq_next;
+    else {
+	cbq_state_t *cp;
+	
+	for (cp = cbq_list; cp; cp = cbqp->cbq_next)
+	    if (cp->cbq_next == cbqp) {
+		cp->cbq_next = cbqp->cbq_next;
+		break;
+	    }
+    }
+
+    /* deallocate cbq_state_t */
+    FREE(cbqp->cbq_class_tbl, M_DEVBUF);
+    FREE(cbqp, M_DEVBUF);
+
+    return (error);
+}
+
+/*
+ * int
+ * cbq_enqueue(struct ifnet *ifp, struct mbuf *mp, int mode)
+ *		- Queue data packets.
+ *
+ *	cbq_enqueue is set to ifp->if_altqenqueue and called by an upper
+ *	layer (e.g. ether_output).  cbq_enqueue queues the given packet
+ *	to the cbq, then invokes the driver's start routine.
+ *
+ *	Assumptions:	called in splimp
+ *	Returns:	0 if the queueing is successful.
+ *			ENOBUFS if a packet dropping occured as a result of
+ *			the queueing.
+ */
+
+static int
+cbq_enqueue(ifp, mp, pr_hdr, mode)
+    struct ifnet *ifp;
+    struct mbuf *mp;
+    struct pr_hdr *pr_hdr;
+    int mode;
+{
+    cbq_state_t *cbqp = (cbq_state_t *)ifp->if_altqp;
+    struct flowinfo flow;
+    struct rm_class *cl;
+
+    altq_extractflow(mp, pr_hdr, &flow);
+
+    if (mode == ALTEQ_NORMAL) {
+	if ((cl = cbq_classify(cbqp, &flow)) == NULL) {
+	    /* no class found */
+	    m_freem(mp);
+	    return ENOBUFS;  /* XXX */
+	}
+
+	if (rmc_queue_packet(cl, mp) == 0) {
+	    /* successfully queued. */
+	    ++cbqp->cbq_busy;
+    
+	    /*
+	     * call the driver's start routine.
+	     */
+	    ifp = cbqp->ifnp.ifp;
+	    if (ifp->if_start && (ifp->if_flags & IFF_OACTIVE) == 0)
+		(*ifp->if_start)(ifp);
+	    return (0);
+	}
+    			
+	/* drop occurred.  some mbuf was freed in rm_queue_packet. */
+	return ENOBUFS;
+    }
+
+#ifdef ALTQ_ACCOUNT
+    /* accounting mode */
+    if ((cl = cbq_classify(cbqp, &flow)) != NULL) {
+	/* class found */
+	if (mode == ALTEQ_ACCOK) {
+	    ++cl->stats_.npackets;
+	    cl->stats_.nbytes += mp->m_pkthdr.len;
+	}
+	else {
+	    /* mode == ALTEQ_ACCDROP */
+	    ++cl->stats_.drops;
+	    cl->stats_.drop_bytes += mp->m_pkthdr.len;
+	}
+    }
+#endif /* ALTQ_ACCOUNT */
+
+    return 0;
+}
+
+static struct mbuf *
+cbq_dequeue(ifp, mode)
+    struct ifnet *ifp;
+    int mode;
+{
+    cbq_state_t *cbqp = (cbq_state_t *)ifp->if_altqp;
+    struct mbuf 	*mp;
+
+    if (mode == ALTDQ_FLUSH) {
+	cbq_flush(cbqp);
+	return NULL;
+    }
+
+    mp = rmc_dequeue_next(&cbqp->ifnp, mode);
+
+    if (mp && mode == ALTDQ_DEQUEUE) {
+	--cbqp->cbq_busy;	/* decrement # of packets in the cbq. */
+	
+	/* Update the class. */
+	rmc_update_class_util(&cbqp->ifnp);
+    }
+    return mp;
+}
+
+/*
+ * void
+ * cbqrestart(queue_t *) - Restart sending of data.
+ * called from rmc_restart in splimp via timeout after waking up
+ * a suspended class.
+ *	Returns:	NONE
+ */
+
+void
+cbqrestart(ifp)
+    struct ifnet *ifp;
+{
+    cbq_state_t	*cbqp;
+    
+    if (!ALTQ_IS_ON(ifp))
+	/* cbq must have been detached */
+	return;
+
+    cbqp = (cbq_state_t *)ifp->if_altqp;
+    if (cbqp == NULL) {
+	/* should not happen */
+#ifdef CBQ_DEBUG
+	printf("cbqrestart: null cbqp!\n");
+#endif
+	return;
+    }
+
+    if (ifp->if_start &&
+	cbqp->cbq_busy && (ifp->if_flags & IFF_OACTIVE) == 0) {
+	(*ifp->if_start)(ifp);
+    }
+}
+
+static void cbq_flush(cbqp)
+    cbq_state_t *cbqp;
+{
+    struct rm_class *cl;
+    int i;
+    
+    for (i = 0; i < CBQ_MAX_CLASSES; i++) {
+	cl = cbqp->cbq_class_tbl[i];
+	if (!cl)
+	    continue;
+	rmc_flush(cl);
+    }
+}
+
+/*
+ * void
+ * cbqwatchdog(queue_t *) - this function is called via timeout while the
+ *	interface below is enabled.  This is necessary to flush regulated
+ *	class queues.
+ *
+ *	Returns:	NONE
+ */
+
+static void
+cbqwatchdog(cbqp)
+    cbq_state_t *cbqp;
+{
+    struct ifnet *ifp;
+    int s;
+    
+    /*
+     * If the CBQ is enabled on this interface, make sure
+     * that it is running if there are packets to send.
+     */
+    ifp = cbqp->ifnp.ifp;
+    if (ALTQ_IS_ON(ifp) && ifp->if_start) {
+	s = splimp();
+	if (cbqp->cbq_busy && (ifp->if_flags & IFF_OACTIVE) == 0)
+	    (*ifp->if_start)(ifp);
+	splx(s);
+	timeout((timeout_t *)cbqwatchdog, cbqp, CBQ_TIMEOUT);
+    }
+}
+
+/*
+ * cbq device interface
+ */
+#include <sys/sockio.h>
+#include <sys/conf.h>
+
+d_open_t	cbqopen;
+d_close_t	cbqclose;
+d_ioctl_t	cbqioctl;
+
+int
+cbqopen(dev, flag, fmt, p)
+    dev_t dev;
+    int flag, fmt;
+    struct proc *p;
+{
+    return 0;
+}
+
+int
+cbqclose(dev, flag, fmt, p)
+    dev_t dev;
+    int flag, fmt;
+    struct proc *p;
+{
+    struct ifnet *ifp;
+    struct cbq_interface iface;
+    int err, error = 0;
+
+    while (cbq_list) {
+	ifp = cbq_list->ifnp.ifp;
+#if 1
+	if (!ifp) {
+	    /* should not happen! */
+#ifdef CBQ_DEBUG
+	    printf("cbqclose: no ifp!\n");
+#endif
+	    return (-1);
+	}
+#endif
+	sprintf(iface.cbq_ifacename, "%s%d", ifp->if_name, ifp->if_unit);
+	iface.cbq_ifacelen = strlen(iface.cbq_ifacename);
+
+	err = cbq_ifdetach(&iface);
+	if (err != 0 && error == 0)
+	    error = err;
+    }
+
+    return error;
+}
+
+int
+cbqioctl(dev, cmd, addr, flag, p)
+    dev_t dev;
+    int cmd;
+    caddr_t addr;
+    int flag;
+    struct proc *p;
+{
+    int	error = 0;
+
+    /* check cmd for superuser only */
+    switch (cmd) {
+    case CBQ_GETSTATS:
+	/* currently only command that an ordinary user can call */
+	break;
+    default:
+	error = suser(p->p_ucred, &p->p_acflag);
+	if (error)
+	    return (error);
+	break;
+    }
+
+    switch (cmd) {
+
+    case CBQ_ENABLE:
+	error = cbq_set_enable((struct cbq_interface *)addr, ENABLE);
+	break;
+
+    case CBQ_DISABLE:
+	error = cbq_set_enable((struct cbq_interface *)addr, DISABLE);
+	break;
+
+    case CBQ_ADD_FILTER:
+	error = cbq_add_filter((struct cbq_add_filter *)addr);
+	break;
+
+    case CBQ_DEL_FILTER:
+	error = cbq_delete_filter((struct cbq_delete_filter *)addr);
+	break;
+
+    case CBQ_ADD_CLASS:
+	error = cbq_add_class((struct cbq_add_class *)addr);
+	break;
+
+    case CBQ_DEL_CLASS:
+	error = cbq_delete_class((struct cbq_delete_class *)addr);
+	break;
+
+    case CBQ_CLEAR_HIERARCHY:
+	error = cbq_clear_hierarchy((struct cbq_interface *)addr);
+	break;
+
+    case CBQ_IF_ATTACH:
+	error = cbq_ifattach((struct cbq_interface *)addr);
+	break;
+
+    case CBQ_IF_DETACH:
+	error = cbq_ifdetach((struct cbq_interface *)addr);
+	break;
+
+    case CBQ_GETSTATS:
+	error = cbq_getstats((struct cbq_getstats *)addr);
+	break;
+
+    case CBQ_ACC_ENABLE:
+	error = cbq_set_accenable((struct cbq_interface *)addr, ENABLE);
+	break;
+
+    case CBQ_ACC_DISABLE:
+	error = cbq_set_accenable((struct cbq_interface *)addr, DISABLE);
+	break;
+
+    default:
+	error = EINVAL;
+	break;
+    }
+
+    return error;
+}
+
+#ifdef need_cbq_class_dump
+/* for debug */
+static void cbq_class_dump(int);
+
+static void cbq_class_dump(int i)
+{
+    struct rm_class *cl;
+    rm_class_stats_t *s;
+    struct _class_queue_ *q;
+
+    if (cbq_list == NULL) {
+	printf("cbq_class_dump: no cbq_state found\n");
+	return;
+    }
+    cl = cbq_list->cbq_class_tbl[i];
+    
+    printf("class %d cl=%p\n", i, cl);
+    if (cl != NULL) {
+	s = &cl->stats_;
+	q = cl->q_;
+
+	printf("pri=%d, depth=%d, maxrate=%d, allotment=%d\n",
+	       cl->pri_, cl->depth_, cl->maxrate_, cl->allotment_);
+	printf("w_allotment=%d, bytes_alloc=%d, avgidle=%d, maxidle=%d\n",
+	       cl->w_allotment_, cl->bytes_alloc_, cl->avgidle_, cl->maxidle_);
+	printf("minidle=%d, offtime=%d, sleeping=%d, leaf=%d\n",
+	       cl->minidle_, cl->offtime_, cl->sleeping_, cl->leaf_);
+
+	printf("handle=%d, depth=%d, npackets=%d, nbytes=%d\n",
+	       s->handle, s->depth, s->npackets, s->nbytes);
+	printf("over=%d\n, borrows=%d, drops=%d, overactions=%d, delays=%d\n",
+	       s->over, s->borrows, s->drops, s->overactions, s->delays);
+
+	printf("tail=%p, head=%p, qlen=%d, qlim=%d, qthresh=%d,qtype=%d\n",
+	       q->tail_, q->head_, q->qlen_, q->qlim_, q->qthresh_, q->qtype_);
+    }
+}
+#endif
+
+#endif /* CBQ */
diff -uN src-current/sys/netinet/cbq.h src-current-ipv6/sys/netinet/cbq.h
--- src-current/sys/netinet/cbq.h
+++ src-current-ipv6/sys/netinet/cbq.h
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) Sun Microsystems, Inc.  1995-1997. All rights reserved.
+ *
+ * License is granted to copy, to use, and to make and to use derivative works
+ * for research and evaluation purposes, provided that Sun Microsystems is
+ * acknowledged in all documentation pertaining to any such copy or
+ * derivative work. Sun Microsystems grants no other licenses expressed or
+ * implied. The Sun Microsystems  trade name should not be used in any
+ * advertising without its written permission.
+ *
+ * SUN MICROSYSTEMS MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS
+ * SOFTWARE FOR ANY PARTICULAR PURPOSE.  The software is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this software.
+ */
+#ifndef _NETINET_CBQ_H
+#define	_NETINET_CBQ_H
+
+#include "opt_inet6.h"
+
+#pragma ident "@(#)cbq.h  1.8     97/08/03 SMI"
+
+#include <sys/sockio.h>
+#include <sys/ioccom.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif 
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ	16
+#endif
+
+#define	MAXQ		64	/* Max allowed queue length */
+
+/*
+ * Define filter structure
+ */
+
+#define FILT_SIZE       48
+
+typedef struct _filt cbq_filt_t;
+
+#ifdef INET6
+struct _filt {
+    union {
+	struct {			/* IPv4 filter */
+	    u_int	daddr_4;	/* Destination Address. */
+#if !defined(sun)
+	    u_int	dmask_4;	/* Destination Address Mask */
+#endif
+	    u_int	saddr_4;	/* Source Address */
+#if !defined(sun)
+	    u_int	smask_4;	/* Source Address Mask*/
+#endif
+	    u_short	dport_4;	/* Destination Port. */
+	    u_short	sport_4;	/* Source port. */
+	} _filt_4;
+	struct {			/* IPv6 filter */
+	    u_int	saddr_6[4];	/* Source Address */
+	    u_int	flow_6;		/* Flow Label */
+	    u_char	splen_6;	/* Source Prefix Length */
+	} _filt_6;
+    } _ufilt;
+	u_char		proto;		/* IP protocol Number. */
+	u_char		family;		/* Filter Family */
+};
+#define	daddr		_ufilt._filt_4.daddr_4
+#define	dmask		_ufilt._filt_4.dmask_4
+#define	saddr		_ufilt._filt_4.saddr_4
+#define	smask		_ufilt._filt_4.smask_4
+#define	dport		_ufilt._filt_4.dport_4
+#define	sport		_ufilt._filt_4.sport_4
+#define	saddr6		_ufilt._filt_6.saddr_6
+#define	flow6		_ufilt._filt_6.flow_6
+#define splen6		_ufilt._filt_6.splen_6
+
+#else
+
+struct _filt {
+	u_int		daddr;	/* Destination Address. */
+#if !defined(sun)
+	u_int		dmask;	/* Destination Address Mask */
+#endif
+	u_int		saddr;	/* Source Address */
+#if !defined(sun)
+	u_int		smask;	/* Source Address Mask*/
+#endif
+	u_short		dport;	/* Destination Port. */
+	u_short		sport;	/* Source port. */
+	u_char		proto;	/* IP protocol Number. */
+};
+#endif
+
+/*
+ * Define a well known class handles
+ */
+#define NULL_CLASS_HANDLE	0xffffffff
+#define	ROOT_CLASS_HANDLE	0xfffffffe
+#define	DEFAULT_CLASS_HANDLE	0xfffffffd
+#define	CTL_CLASS_HANDLE	0xfffffffc
+
+/*
+ * Define structures associated with IOCTLS for cbq.
+ */
+
+/*
+ * Define the CBQ interface structure.  This must be included in all
+ * IOCTL's such that the CBQ driver may find the appropriate CBQ module
+ * associated with the network interface to be affected.
+ */
+typedef struct cbq_interface {
+	char	cbq_ifacename[IFNAMSIZ];
+	u_int	cbq_ifacelen;
+} cbq_iface_t;
+
+/* 
+ * Define IOCTLs for CBQ.
+ */
+#define CBQ_ENABLE		_IOW('Q', 1, struct cbq_interface)
+#define CBQ_DISABLE		_IOW('Q', 2, struct cbq_interface)
+
+#define	CBQ_ADD_FILTER		_IOWR('Q', 3, struct cbq_add_filter)
+
+struct cbq_add_filter {
+	cbq_iface_t	cbq_iface;
+	u_long		cbq_class_handle;
+	cbq_filt_t	cbq_filter;
+
+	u_long		cbq_filter_handle;
+};
+
+#define	CBQ_DEL_FILTER		_IOW('Q', 4, struct cbq_delete_filter)
+
+struct cbq_delete_filter {
+	cbq_iface_t	cbq_iface;
+	u_long		cbq_filter_handle;
+};
+
+#define CBQ_ADD_CLASS		_IOWR('Q', 5, struct cbq_add_class)
+
+typedef struct cbq_class_spec {
+	u_int		priority;
+	u_int		nano_sec_per_byte;
+	u_int		maxq;
+	u_int		maxidle;
+	int		minidle;	
+	u_int		offtime;
+	u_long		parent_class_handle;
+	u_long		borrow_class_handle;
+
+	u_int		defaultclass;
+	u_int		ctlclass;
+	u_int		red;	/* not used */
+	u_int		wrr;
+	int		efficient;
+} cbq_class_spec_t;
+
+#if !defined(sun)
+#define CBQ_MAXQSIZE	200
+#endif
+
+struct cbq_add_class {
+	cbq_iface_t		cbq_iface;
+
+	cbq_class_spec_t	cbq_class;	
+	u_long			cbq_class_handle;
+};
+
+#define CBQ_DEL_CLASS		_IOW('Q', 6, struct cbq_delete_class)
+
+struct cbq_delete_class {
+	cbq_iface_t	cbq_iface;
+	u_long		cbq_class_handle;
+};
+
+#define CBQ_CLEAR_HIERARCHY	_IOW('Q', 7, struct cbq_interface)
+#if defined(sun)
+#define	CBQ_ENABLE_STATS	_IOW('Q', 8, struct cbq_interface)
+#define	CBQ_DISABLE_STATS	_IOW('Q', 9, struct cbq_interface)
+#endif
+
+#ifndef _CLASS_STATS
+#define	_CLASS_STATS
+
+typedef struct _class_stats_ {
+	u_int		handle;
+	u_int		depth;
+
+	int		npackets;	/* packets sent in this class */
+	int		nbytes;		/* bytes sent in this class */
+	int		over;		/* # times went over limit */
+	int		borrows;	/* # times tried to borrow */
+	int		drops;		/* # times dropped packets */
+	int		overactions;	/* # times invoked overlimit action */
+	int		delays;		/* # times invoked delay actions */
+#if !defined(sun)
+	int		drop_bytes;	/* bytes dropped in this class */
+#endif
+
+#if !defined(sun)
+	/* other static class parameters useful for debugging */
+	int		priority;
+	int		maxidle;
+	int		minidle;
+	int		offtime;
+	int		qmax;
+	int		ns_per_byte;
+	int		wrr_allot;
+#endif
+#if !defined(sun)
+	int		qcnt;		/* # packets in queue */
+	int		avgidle;
+#endif
+} class_stats_t;
+#endif
+
+struct cbq_getstats {
+	cbq_iface_t	iface;
+	int		nclasses;
+	class_stats_t	*stats;
+};
+
+#if !defined(sun)
+/* number of classes are returned in nclasses field */
+#define	CBQ_GETSTATS		_IOWR('Q', 10, struct cbq_getstats)
+#else
+#define	CBQ_GETSTATS		_IOW('Q', 10, struct cbq_getstats)
+#endif
+
+#if !defined(sun)
+
+#define	CBQ_IF_ATTACH		_IOW('Q', 16, struct cbq_interface)
+#define	CBQ_IF_DETACH		_IOW('Q', 17, struct cbq_interface)
+
+#define	CBQ_ACC_ENABLE		_IOW('Q', 18, struct cbq_interface)
+#define	CBQ_ACC_DISABLE		_IOW('Q', 19, struct cbq_interface)
+
+
+#endif /* !sun */
+
+
+#ifdef KERNEL
+
+/*
+ * Define macros only good for kernel drivers and modules.
+ */
+#if defined(sun)
+#define N_MAX_CBQ_DEVS	1
+#define	CBQ_DEVICE	0x1
+#define CBQ_MODULE	0x2
+#endif
+
+#define ENABLE		0x01
+#define	DISABLE		0x00
+
+#if defined(sun)
+#define	IS_FAST_PATH		0x01
+#define	IS_NOT_FAST_PATH	0x00
+#endif
+
+#define	CBQ_HI_WATER		(192 * 1024)
+#define	CBQ_LO_WATER		(1)
+
+#define CBQ_WATCHDOG    	(HZ / 20)
+#if !defined(sun)
+#define CBQ_TIMEOUT		10
+#define	CBQ_LS_TIMEOUT		(20 * hz / 1000)
+#define CBQ_VIRTUAL_IF_THRESH	1000
+#else
+#define	CBQ_TIMEOUT		1
+#define	CBQ_LS_TIMEOUT		drv_usectohz(20000)
+#define	CBQ_VIRTUAL_IF_THRESH	1000
+#endif
+#define CBQ_ACTIVE      	1
+#define CBQ_INACTIVE    	0
+
+#define CBQ_MAX_CLASSES	256
+#define CBQ_MAX_FILTERS 256
+
+/*
+ * Define State structures.
+ */
+
+typedef struct _k_filter_cb_ {
+	struct rm_class		*clp;
+	cbq_filt_t		filter;
+
+	u_long			handle;
+
+	struct _k_filter_cb_	*next;
+	struct _k_filter_cb_	*prev;
+	int			matches;
+
+#if defined(sun)
+	int			tbfilter;	/* If true, then apply */
+	u_int			rate;	/* bytes/millisecond */
+	u_int			depth;	/* bytes */
+	u_int			bucket;	/* bytes */
+	hrtime_t		last;	/* microsecond timestamp of last byte */
+	u_long			dropped;
+#endif
+} k_filter_cb_t;
+
+typedef struct cbqstate {
+#if !defined(sun)
+	struct cbqstate		*cbq_next;
+#endif
+#if defined(sun)
+	kmutex_t		cbq_lock;
+	kcondvar_t		cv;
+#ifdef DEBUG
+	int			cbqstarts;
+	int			cbqfrees;
+#endif
+	queue_t			*cbq_q;
+
+	int			mac_addr_sz;
+	int			is_pktsched_inited;
+	int			is_pktsched_destroyed;
+	int			use_esballoc;
+	int			cbq_timeout_id;
+	int			cbq_tl_timeout_id;
+#endif /* sun */
+	int			cbq_busy;
+#if defined(sun)
+	int			cbq_enabled;
+#endif
+	int			qlen;
+	int			q_full;
+	u_long			threshold;
+
+#if defined(sun)
+	int			cbqfi;
+	int			cbqfo;
+	mblk_t			*cbq_freeit[RM_MAXQUEUED];
+	frtn_t			cbq_retn;
+#endif
+
+	struct rm_class		**cbq_class_tbl;
+
+#if !defined(sun)
+#define	CBQ_FILTER_TBL_SZ	(256+1)
+/* XXX TBL_SZ can't be larger than 2048 unless we fix the handle assignment */
+#define	CBQ_FILTER_MASK		(CBQ_FILTER_TBL_SZ - 2)
+	k_filter_cb_t		*filters[CBQ_FILTER_TBL_SZ];
+#define CBQ_WILDCARD_INDEX	(CBQ_FILTER_TBL_SZ - 1)
+#else /* sun */
+#define	CBQ_FILTER_TBL_SZ	256
+	k_filter_cb_t		*filters[CBQ_FILTER_TBL_SZ];
+#endif
+#if defined(sun)
+	int			cbq_stats_timeout_id;
+	int			cbq_stats_enabled;
+	int			cbq_filter_debug;
+#endif
+
+	struct rm_ifdat		ifnp;
+
+#ifdef CBQPERF
+#define N_CBQ_PERF		64 * 1024
+	struct cbq_perf		*perf;
+	int			nperf;
+#endif
+#if !defined(sun)
+} cbq_state_t;
+#else
+} cbq_mod_state_t;
+#endif
+
+#if !defined(sun)
+/* have to take care of little-endian machines */
+#define	CBQ_GET_HASH_INDEX(addr) \
+	(((addr) + ((addr)>>8) + ((addr)>>16) + ((addr)>>24)) \
+	 & CBQ_FILTER_MASK)
+#define	CBQ_GET_HINDEX(handle) ((handle) >> 20)
+
+#else /* sun */
+
+#define	CBQ_GET_HASH_INDEX(addr) \
+	(((addr) + (addr >> 8)) & (CBQ_FILTER_TBL_SZ - 1))
+#define	CBQ_GET_HINDEX(handle) ((handle) >> 24)
+
+#endif /* sun */
+
+void 		cbqrestart __P((struct ifnet *));
+int		cbq_class_destroy __P((cbq_state_t *, struct rm_class *));
+struct rm_class *cbq_class_create __P((cbq_state_t *, struct cbq_add_class *,
+			u_long, struct rm_class *, struct rm_class *));
+struct rm_class *cbq_classify __P((cbq_state_t *, struct flowinfo *));
+
+#endif /* KERNEL */
+
+#ifdef __cplusplus
+}
+#endif 
+
+int cbq_debug(void);
+
+#endif /* !_NETINET_CBQ_H */
diff -uN src-current/sys/netinet/cbq_class.c src-current-ipv6/sys/netinet/cbq_class.c
--- src-current/sys/netinet/cbq_class.c
+++ src-current-ipv6/sys/netinet/cbq_class.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) Sun Microsystems, Inc.  1993-1997. All rights reserved.
+ *
+ * License is granted to copy, to use, and to make and to use derivative works
+ * for research and evaluation purposes, provided that Sun Microsystems is
+ * acknowledged in all documentation pertaining to any such copy or
+ * derivative work. Sun Microsystems grants no other licenses expressed or
+ * implied. The Sun Microsystems  trade name should not be used in any
+ * advertising without its written permission.
+ *
+ * SUN MICROSYSTEMS MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS
+ * SOFTWARE FOR ANY PARTICULAR PURPOSE.  The software is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this software.
+ */
+
+/*
+ * Copyright (c) 1993-1997 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 the Network Research Group at
+ *	Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory 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.
+ */
+/*
+ * Copyright (C) 1997, 1998
+ *	Sony Computer Science Laboratory Inc.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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.
+ *
+ * $Id: cbq_class.c,v 0.4 1998/01/27 02:50:14 kjc Exp $
+ */
+
+#include "opt_inet6.h"
+
+#if defined(__FreeBSD__)
+#include "opt_altq.h"
+#endif
+
+#ifdef CBQ	/* cbq is enabled by CBQ option in opt_altq.h */
+/*
+static char rcsid[] = "$Id: cbq_class.c,v 0.4 1998/01/27 02:50:14 kjc Exp $";
+*/
+
+/* static char sccsid[] = "@(#) cbq_class.c 1.10@(#)"; */
+#pragma ident "@(#) cbq_class.c 1.10@(#)"
+#ident "@(#) cbq_class.c 1.10@(#)"
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+
+#include <netinet/rm_class.h>
+#include <netinet/cbq.h>
+
+static int cbq_apply_filter4(cbq_filt_t *, struct flowinfo_in *);
+#ifdef INET6
+static int cbq_apply_filter6(cbq_filt_t *, struct flowinfo_in6 *);
+#endif
+
+/*
+ * int
+ * cbq_class_destroy(cbq_mod_state_t *, struct rm_class *) - This
+ *	function destroys a given traffic class.  Before destorying
+ *	the class, all traffic for that class is released.
+ */
+int
+cbq_class_destroy(cbqp, classp)
+    cbq_state_t *cbqp;
+    struct rm_class *classp;
+{
+    rmc_delete_class(&cbqp->ifnp, classp);
+    return (0);
+}
+
+/*
+ * struct rm_class *
+ * cbq_class_create(cbq_mod_state_t *cbqp, struct cbq_add_class *acp,
+ *		u_long handle, struct rm_class *parent,
+ *		struct rm_class *borrow)
+ *
+ * This function create a new traffic class in the CBQ class hierarchy of
+ * given paramters.  The class that created is either the root, default,
+ * or a new dynamic class.  If CBQ is not initilaized, the the root class
+ * will be created.
+ */
+struct rm_class *
+cbq_class_create(cbqp, acp, handle, parent, borrow)
+    cbq_state_t *cbqp;
+    struct cbq_add_class *acp;
+    u_long handle;
+    struct rm_class *parent, *borrow;
+{
+    struct rm_class	*cl;
+    cbq_class_spec_t	*spec = &acp->cbq_class;
+
+    /* check parameters */
+    if (spec->priority >= RM_MAXPRIO || spec->maxq > CBQ_MAXQSIZE)
+	return NULL;  /* should check other params? */
+    
+    if (!parent) {
+	if (cbqp->ifnp.root_) {
+	    printf("CBQ_ADD_CLASS: Root Class exists\n");
+	    return (NULL);
+	}
+	rmc_init(cbqp->ifnp.ifp, &cbqp->ifnp, spec->nano_sec_per_byte,
+		 cbqrestart, spec->maxq, RM_MAXQUEUED,
+		 spec->maxidle, spec->minidle, spec->offtime,
+		 spec->wrr, spec->efficient);
+	return (cbqp->ifnp.root_);
+    } else if (acp->cbq_class.defaultclass) {
+	if (cbqp->ifnp.default_) {
+	    printf("CBQ_ADD_CLASS: Default Class exists\n");
+	    return (NULL);
+	}
+
+	cbqp->ifnp.default_ = rmc_newclass(spec->priority,
+			&cbqp->ifnp, spec->nano_sec_per_byte,
+			rmc_delay_action, spec->maxq, parent, borrow,
+			spec->maxidle, spec->minidle, spec->offtime);
+
+	return (cbqp->ifnp.default_);
+    } else if (acp->cbq_class.ctlclass) {
+	if (cbqp->ifnp.ctl_) {
+	    printf("CBQ_ADD_CLASS: Ctl Class exists\n");
+	    return (NULL);
+	}
+
+	cbqp->ifnp.ctl_ = rmc_newclass(spec->priority,
+			&cbqp->ifnp, spec->nano_sec_per_byte,
+			rmc_delay_action, spec->maxq, parent, borrow,
+			spec->maxidle, spec->minidle, spec->offtime);
+
+	return (cbqp->ifnp.ctl_);
+    } else {
+	cl = rmc_newclass(spec->priority,
+			&cbqp->ifnp, spec->nano_sec_per_byte,
+			rmc_delay_action, spec->maxq, parent, borrow,
+			spec->maxidle, spec->minidle, spec->offtime);
+	if (!cl)
+	    return((struct rm_class *)NULL);
+
+	cbqp->cbq_class_tbl[handle] = cl;
+	return (cl);
+    }
+}
+
+struct rm_class *
+cbq_classify(cbqp, flow)
+    cbq_state_t *cbqp;
+    struct flowinfo *flow;
+{
+    k_filter_cb_t 	*kfp;
+    int			i;
+
+    if (flow != NULL && flow->fi_family == AF_INET) {
+	struct flowinfo_in *fp = (struct flowinfo_in *)flow;
+	
+	/* first, check if this goes into the ctl class. */
+	if ((fp->fi_proto == IPPROTO_ICMP || fp->fi_proto == IPPROTO_IGMP ||
+	     fp->fi_proto == IPPROTO_RSVP) && cbqp->ifnp.ctl_)
+	    return (cbqp->ifnp.ctl_);
+
+	/* get the filter hash entry from its dest address */
+	i = CBQ_GET_HASH_INDEX(fp->fi_dst.s_addr);
+
+	/* TODO: put some cache code here */
+
+	/* go through this loop twice.  first for dst hash, second for
+	   wildcards. */
+	do {
+	    for (kfp = cbqp->filters[i]; kfp; kfp = kfp->next)
+		if (cbq_apply_filter4(&kfp->filter, fp))
+		    return (kfp->clp);
+
+	    /*
+	     * check again for filters with a daddr wildcard.
+	     * (daddr == 0 || dmask != 0xffffffff).
+	     */
+	    if (i != CBQ_WILDCARD_INDEX)
+		i = CBQ_WILDCARD_INDEX;
+	    else
+		break;
+	} while (1);
+    }
+#ifdef INET6
+     else if (flow != NULL && flow->fi_family == AF_INET6) {
+	struct flowinfo_in6 *fp = (struct flowinfo_in6 *)flow;
+	
+	/* first, check if this goes into the ctl class. */
+	if ((fp->fi_proto == IPPROTO_ICMPV6 || fp->fi_proto == IPPROTO_RSVP)
+	     && cbqp->ifnp.ctl_)
+	    return (cbqp->ifnp.ctl_);
+
+	/* get the filter hash entry from its flow ID */
+	i = CBQ_GET_HASH_INDEX(fp->fi_flowlabel);
+
+	/* TODO: put some cache code here */
+
+	/* go through this loop twice.  first for flow hash, second for
+	   wildcards. */
+	do {
+	    for (kfp = cbqp->filters[i]; kfp; kfp = kfp->next)
+		if (cbq_apply_filter6(&kfp->filter, fp))
+		    return (kfp->clp);
+
+	    /*
+	     * check again for filters with a wildcard.
+	     */
+	    if (i != CBQ_WILDCARD_INDEX)
+		i = CBQ_WILDCARD_INDEX;
+	    else
+		break;
+	} while (1);
+    }
+#endif
+
+    /* no filter matched.  use defaultclass. */
+    return (cbqp->ifnp.default_);
+}
+
+static int
+cbq_apply_filter4(filt, pkt)
+    cbq_filt_t *filt;
+    struct flowinfo_in *pkt;
+{
+#ifdef INET6
+    if (filt->family != AF_INET)
+	return (0);
+#endif
+
+    if (filt->daddr != 0 && filt->daddr != (pkt->fi_dst.s_addr & filt->dmask))
+	return (0);
+
+    if (filt->dport != 0 && filt->dport != pkt->fi_dport)
+	return (0);
+
+    if (filt->proto != 0 && filt->proto != pkt->fi_proto)
+	return (0);
+
+    if (filt->saddr != 0 && filt->saddr != (pkt->fi_src.s_addr & filt->smask))
+	return (0);
+
+    if (filt->sport != 0 && filt->sport != pkt->fi_sport)
+	return (0);
+
+    /* match */
+    return (1);
+}
+
+#ifdef INET6
+static int
+cbq_apply_filter6(filt, pkt)
+    cbq_filt_t *filt;
+    struct flowinfo_in6 *pkt;
+{
+    if (filt->family != AF_INET6)
+	return (0);
+
+    if (filt->flow6 != 0 && filt->flow6 != pkt->fi_flowlabel)
+	return (0);
+
+    if (filt->proto != 0 && filt->proto != pkt->fi_proto)
+	return (0);
+
+    /* TODO: splen6 !!! */
+    if (((filt->saddr6[0] != 0) ||
+	 (filt->saddr6[1] != 0) ||
+	 (filt->saddr6[2] != 0) ||
+	 (filt->saddr6[3] != 0)) &&
+	((filt->saddr6[0] != pkt->fi_src.s6_addr32[0]) ||
+	 (filt->saddr6[1] != pkt->fi_src.s6_addr32[1]) ||
+	 (filt->saddr6[2] != pkt->fi_src.s6_addr32[2]) ||
+	 (filt->saddr6[3] != pkt->fi_src.s6_addr32[3])))
+	return (0);
+
+    /* match */
+    return (1);
+}
+#endif
+
+#endif /* CBQ */
diff -uN src-current/sys/netinet/des.c src-current-ipv6/sys/netinet/des.c
--- src-current/sys/netinet/des.c
+++ src-current-ipv6/sys/netinet/des.c
@@ -0,0 +1,47 @@
+/* lib/des/set_key.c */
+/* Copyright (C) 1995 Eric Young (eay@mincom.oz.au)
+ * All rights reserved.
+ * 
+ * This file is part of an SSL implementation written
+ * by Eric Young (eay@mincom.oz.au).
+ * The implementation was written so as to conform with Netscapes SSL
+ * specification.  This library and applications are
+ * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE
+ * as long as the following conditions are aheared to.
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.  If this code is used in a product,
+ * Eric Young should be given attribution as the author of the parts used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * 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 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 Eric Young (eay@mincom.oz.au)
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
diff -uN src-current/sys/netinet/des.h src-current-ipv6/sys/netinet/des.h
--- src-current/sys/netinet/des.h
+++ src-current-ipv6/sys/netinet/des.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 1995 Eric Young (eay@mincom.oz.au)
+ * All rights reserved.
+ * 
+ * This file is part of an SSL implementation written
+ * by Eric Young (eay@mincom.oz.au).
+ * The implementation was written so as to conform with Netscapes SSL
+ * specification.  This library and applications are
+ * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE
+ * as long as the following conditions are aheared to.
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.  If this code is used in a product,
+ * Eric Young should be given attribution as the author of the parts used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * 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 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 Eric Young (eay@mincom.oz.au)
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef _NETINET_DES_H
+#define _NETINET_DES_H
+
+
+#endif
diff -uN src-current/sys/netinet/fifoq.c src-current-ipv6/sys/netinet/fifoq.c
--- src-current/sys/netinet/fifoq.c
+++ src-current-ipv6/sys/netinet/fifoq.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 1997
+ *	Sony Computer Science Laboratory Inc.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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.
+ *
+ */
+
+#if defined(__FreeBSD__) && defined(ALTQ)
+#include "opt_altq.h"
+#endif
+
+#ifdef FIFOQ	/* fifoq is enabled by FIFOQ option in opt_altq.h */
+
+/*
+ * FIFOQ is an altq sample implementation.  There will be little
+ * need to use FIFOQ as an alternative queueing scheme.
+ * But this code is provided as a template for those who want to
+ * write their own queueing schemes.
+ */
+
+/*
+static char rcsid[] = "$Id: fifoq.c,v 1.2 1998/01/26 11:05:48 kjc Exp $";
+*/
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/ioctl.h>
+#include <sys/conf.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+
+#include <netinet/fifoq.h>
+
+#define FIFOQ_STATS	/* collect statistics */
+
+/* fifoq_list keeps all fifoq_state_t's allocated. */
+static fifoq_state_t *fifoq_list = NULL;
+
+/* internal function prototypes */
+static int		fifoq_enqueue __P((struct ifnet *, struct mbuf *,
+					   struct pr_hdr *, int));
+static struct mbuf 	*fifoq_dequeue __P((struct ifnet *, int));
+static int fifoq_detach __P((fifoq_state_t *));
+static void fifoq_flush __P((fifoq_state_t *));
+
+/*
+ * fifoq device interface
+ */
+d_open_t	fifoqopen;
+d_close_t	fifoqclose;
+d_ioctl_t	fifoqioctl;
+
+int
+fifoqopen(dev, flag, fmt, p)
+    dev_t dev;
+    int flag, fmt;
+    struct proc *p;
+{
+    /* everything will be done when the queueing scheme is attached. */
+    return 0;
+}
+
+/*
+ * there are 2 ways to act on close.
+ *   detach-all-on-close:
+ *	use for the daemon style approach.  if the daemon dies, all the
+ *	resource will be released.
+ *   no-action-on-close:
+ *	use for the command style approach.  (e.g.  fifoq on/off)
+ *
+ * note: close is called not on every close but when the last reference
+ *       is removed (only once with multiple simultaneous references.)
+ */
+int
+fifoqclose(dev, flag, fmt, p)
+    dev_t dev;
+    int flag, fmt;
+    struct proc *p;
+{
+    fifoq_state_t *q;
+    int err, error = 0;
+
+    while ((q = fifoq_list) != NULL) {
+	/* destroy all */
+	err = fifoq_detach(q);
+	if (err != 0 && error == 0)
+	    error = err;
+    }
+
+    return error;
+}
+
+int
+fifoqioctl(dev, cmd, addr, flag, p)
+    dev_t dev;
+    int cmd;
+    caddr_t addr;
+    int flag;
+    struct proc *p;
+{
+    fifoq_state_t *q;
+    struct fifoq_interface *ifacep;
+    struct ifnet *ifp;
+    int	error = 0;
+
+    /* check super-user privilege */
+    switch (cmd) {
+    case FIFOQ_GETSTATS:
+	break;
+    default:
+	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
+	    return (error);
+	break;
+    }
+    
+    switch (cmd) {
+
+    case FIFOQ_ENABLE:
+	ifacep = (struct fifoq_interface *)addr;
+	if ((q = altq_lookup(ifacep->fifoq_ifname, ALTQT_FIFOQ)) == NULL) {
+	    error = EINVAL;
+	    break;
+	}
+    
+	error = if_altqenable(q->q_ifp);
+	break;
+
+    case FIFOQ_DISABLE:
+	ifacep = (struct fifoq_interface *)addr;
+	if ((q = altq_lookup(ifacep->fifoq_ifname, ALTQT_FIFOQ)) == NULL) {
+	    error = EINVAL;
+	    break;
+	}
+    	error = if_altqdisable(q->q_ifp);
+	break;
+
+    case FIFOQ_IF_ATTACH:
+	ifp = ifunit(((struct fifoq_interface *)addr)->fifoq_ifname);
+	if (ifp == NULL) {
+	    error = ENXIO;
+	    break;
+	}
+
+	/* allocate and initialize fifoq_state_t */
+	MALLOC(q, fifoq_state_t *, sizeof(fifoq_state_t), M_DEVBUF, M_WAITOK);
+	bzero(q, sizeof(fifoq_state_t));
+
+	q->q_ifp = ifp;
+	q->q_head = q->q_tail = NULL;
+	q->q_len = 0;
+	q->q_limit = FIFOQ_LIMIT;
+
+	/*
+	 * set FIFOQ to this ifnet structure.
+	 */
+	error = if_altqattach(ifp, q, fifoq_enqueue, fifoq_dequeue,
+			      ALTQT_FIFOQ);
+	if (error) {
+	    FREE(q, M_DEVBUF);
+	    break;
+	}
+
+	/* add this state to the fifoq list */
+	q->q_next = fifoq_list;
+	fifoq_list = q;
+	break;
+
+    case FIFOQ_IF_DETACH:
+	ifacep = (struct fifoq_interface *)addr;
+	if ((q = altq_lookup(ifacep->fifoq_ifname, ALTQT_FIFOQ)) == NULL) {
+	    error = EINVAL;
+	    break;
+	}
+    
+	error = fifoq_detach(q);
+	break;
+
+    case FIFOQ_GETSTATS:
+	do {
+	    struct fifoq_getstats *q_stats;
+
+	    q_stats = (struct fifoq_getstats *)addr;
+	    if ((q = altq_lookup(q_stats->iface.fifoq_ifname,
+				 ALTQT_FIFOQ)) == NULL) {
+		error = EINVAL;
+		break;
+	    }
+
+	    q_stats->q_len 	  = q->q_len;
+	    q_stats->q_limit 	  = q->q_limit;
+	    q_stats->xmit_packets = q->q_stats.xmit_packets;
+	    q_stats->xmit_bytes   = q->q_stats.xmit_bytes;
+	    q_stats->drop_packets = q->q_stats.drop_packets;
+	    q_stats->drop_bytes   = q->q_stats.drop_bytes;
+
+	} while (0);
+	break;
+
+    case FIFOQ_CONFIG:
+	do {
+	    struct fifoq_conf *fc;
+	    int limit;
+
+	    fc = (struct fifoq_conf *)addr;
+	    if ((q = altq_lookup(fc->iface.fifoq_ifname,
+				 ALTQT_FIFOQ)) == NULL) {
+		error = EINVAL;
+		break;
+	    }
+	    limit = fc->fifoq_limit;
+	    if (limit < 0)
+		limit = 0;
+	    q->q_limit = limit;
+	    fc->fifoq_limit = limit;
+	} while (0);
+	break;
+
+    case FIFOQ_ACC_ENABLE:
+	/* enable accounting mode */
+	ifacep = (struct fifoq_interface *)addr;
+	if ((q = altq_lookup(ifacep->fifoq_ifname, ALTQT_FIFOQ)) == NULL) {
+	    error = EINVAL;
+	    break;
+	}
+	SET_ACCOUNTING(q->q_ifp);
+#if 0
+	/* uncomment this if the scheme needs flowinfo */
+	SET_AFLOWINFO(q->q_ifp);
+#endif
+	break;
+
+    case FIFOQ_ACC_DISABLE:
+	/* disable accounting mode */
+	ifacep = (struct fifoq_interface *)addr;
+	if ((q = altq_lookup(ifacep->fifoq_ifname, ALTQT_FIFOQ)) == NULL) {
+	    error = EINVAL;
+	    break;
+	}
+	CLEAR_ACCOUNTING(q->q_ifp);
+#if 0
+	/* uncomment this if the scheme needs flowinfo */
+	CLEAR_AFLOWINFO(q->q_ifp);
+#endif
+	break;
+
+    default:
+	error = EINVAL;
+	break;
+    }
+    return error;
+}
+
+/*
+ * fifoq support routines
+ */
+
+/*
+ * enqueue routine:
+ *
+ *	returns: 0 when successfully queued.
+ *		 ENOBUFS when drop occurs.
+ */
+static int
+fifoq_enqueue(ifp, m, pr_hdr, mode)
+    struct ifnet *ifp;
+    struct mbuf *m;
+    struct pr_hdr *pr_hdr;
+    int mode;
+{
+    fifoq_state_t *q = (fifoq_state_t *)ifp->if_altqp;
+
+    switch (mode) {
+    case ALTEQ_NORMAL:
+	/* if the queue is full, drop the incoming packet (drop-tail). */
+	if (q->q_len >= q->q_limit) {
+#ifdef FIFOQ_STATS
+	    q->q_stats.drop_packets++;
+	    q->q_stats.drop_bytes += m->m_pkthdr.len;
+#endif
+	    m_freem(m);
+	    return (ENOBUFS);
+	}
+
+	/* enqueue the packet at the taile of the queue */
+	m->m_nextpkt = NULL;
+	if (q->q_tail == NULL)
+	    q->q_head = m;
+	else
+	    q->q_tail->m_nextpkt = m;
+	q->q_tail = m;
+	q->q_len++;
+
+	/* start the driver */
+	if (ifp->if_start && (ifp->if_flags & IFF_OACTIVE) == 0)
+	    (*ifp->if_start)(ifp);
+
+	break;
+
+#if defined(ALTQ_ACCOUNT) && defined(FIFOQ_STATS)
+	/*
+	 * altq accounting mode: used just for statistics.
+	 */
+    case ALTEQ_ACCOK:
+	q->q_stats.xmit_packets++;
+	q->q_stats.xmit_bytes += m->m_pkthdr.len;
+	break;
+
+    case ALTEQ_ACCDROP:
+	q->q_stats.drop_packets++;
+	q->q_stats.drop_bytes += m->m_pkthdr.len;
+	break;
+
+#endif /* ALTQ_ACCOUNT && FIFOQ_STATS */
+    }
+    return 0;
+}
+
+/*
+ * dequeue routine:
+ *	must be called in splimp.
+ *
+ *	returns: mbuf dequeued.
+ *		 NULL when no packet is available in the queue.
+ */
+/*
+ * ALTDQ_PEEK is provided for drivers which need to know the next packet
+ * to send in advance.
+ * when ALTDQ_PEEK is specified, the next packet to be dequeued is
+ * returned without dequeueing the packet.
+ * when ALTDQ_DEQUEUE is called *immediately after* an ALTDQ_PEEK
+ * operation, the same packet should be returned.
+ */
+static struct mbuf *
+fifoq_dequeue(ifp, mode)
+    struct ifnet *ifp;
+    int mode;
+{
+    fifoq_state_t *q = (fifoq_state_t *)ifp->if_altqp;
+    struct mbuf *m = 0;
+
+    switch (mode) {
+    case ALTDQ_DEQUEUE:
+	if ((m = q->q_head) == NULL)
+	    break;
+	if ((q->q_head = m->m_nextpkt) == NULL)
+	    q->q_tail = NULL;
+	m->m_nextpkt = NULL;
+	q->q_len--;
+
+#ifdef FIFOQ_STATS
+	q->q_stats.xmit_packets++;
+	q->q_stats.xmit_bytes += m->m_pkthdr.len;
+#endif
+	break;
+    case ALTDQ_PEEK:
+	m = q->q_head;
+	break;
+    case ALTDQ_FLUSH:
+	fifoq_flush(q);
+	m = NULL;
+	break;
+    }
+    return m;
+}
+
+static int fifoq_detach(q)
+    fifoq_state_t *q;
+{
+    fifoq_state_t *tmp;
+    int error = 0;
+
+    if (ALTQ_IS_ON(q->q_ifp))
+	if_altqdisable(q->q_ifp);
+
+    fifoq_flush(q);
+
+    if ((error = if_altqdetach(q->q_ifp)))
+	return (error);
+
+    if (fifoq_list == q)
+	fifoq_list = q->q_next;
+    else {
+	for (tmp = fifoq_list; tmp != NULL; tmp = tmp->q_next)
+	    if (tmp->q_next == q) {
+		tmp->q_next = q->q_next;
+		break;
+	    }
+	if (tmp == NULL)
+	    printf("fifoq_detach: no state found in fifoq_list!\n");
+    }
+
+    FREE(q, M_DEVBUF);
+    return (error);
+}
+
+/*
+ * fifoq_flush
+ * should be called in splimp or after disabling the fifoq.
+ */
+static void fifoq_flush(q)
+    fifoq_state_t *q;
+{
+    struct mbuf *m;
+    
+    while ((m = q->q_head) != NULL) {
+	q->q_head = m->m_nextpkt;
+	m_freem(m);
+    }
+    q->q_tail = NULL;
+    q->q_len = 0;
+}
+
+#endif /* FIFOQ */
diff -uN src-current/sys/netinet/fifoq.h src-current-ipv6/sys/netinet/fifoq.h
--- src-current/sys/netinet/fifoq.h
+++ src-current-ipv6/sys/netinet/fifoq.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 1997
+ *	Sony Computer Science Laboratory Inc.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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.
+ *
+ * $Id: fifoq.h,v 1.1 1997/10/27 02:31:23 kjc Exp $
+ */
+
+#ifndef _NETINET_FIFOQ_H_
+#define _NETINET_FIFOQ_H_
+
+typedef struct fifoq_state {
+    struct fifoq_state *q_next;		/* next fifoq_state in the list */
+    struct ifnet *q_ifp;		/* backpointer to ifnet */
+
+    struct mbuf *q_head;		/* head of queue */
+    struct mbuf *q_tail;		/* tail of queue */
+    int	q_len;				/* queue length */
+    int	q_limit;			/* max queue length */
+
+    /* statistics */
+    struct {
+	quad_t xmit_packets;
+	quad_t xmit_bytes;
+	quad_t drop_packets;
+	quad_t drop_bytes;
+    } q_stats;
+} fifoq_state_t;
+
+struct fifoq_interface {
+	char	fifoq_ifname[IFNAMSIZ];
+};
+
+struct fifoq_getstats {
+    struct fifoq_interface iface;
+    int q_len;
+    int q_limit;
+    quad_t xmit_packets;
+    quad_t xmit_bytes;
+    quad_t drop_packets;
+    quad_t drop_bytes;
+};
+
+struct fifoq_conf {
+    struct fifoq_interface iface;
+    int fifoq_limit;
+};
+
+#define FIFOQ_LIMIT	50	/* default max queue lenght */
+
+/* 
+ * IOCTLs for FIFOQ
+ */
+#define FIFOQ_ENABLE		_IOW('Q', 1, struct fifoq_interface)
+#define FIFOQ_DISABLE		_IOW('Q', 2, struct fifoq_interface)
+#define	FIFOQ_IF_ATTACH		_IOW('Q', 3, struct fifoq_interface)
+#define	FIFOQ_IF_DETACH		_IOW('Q', 4, struct fifoq_interface)
+#define	FIFOQ_ACC_ENABLE	_IOW('Q', 5, struct fifoq_interface)
+#define	FIFOQ_ACC_DISABLE	_IOW('Q', 6, struct fifoq_interface)
+#define	FIFOQ_GETSTATS		_IOWR('Q', 7, struct fifoq_getstats)
+#define	FIFOQ_CONFIG		_IOWR('Q', 8, struct fifoq_conf)
+
+#endif /* _NETINET_FIFOQ_H_ */
diff -uN src-current/sys/netinet/icmp6.h src-current-ipv6/sys/netinet/icmp6.h
--- src-current/sys/netinet/icmp6.h
+++ src-current-ipv6/sys/netinet/icmp6.h
@@ -0,0 +1,195 @@
+#ifndef _NETINET_ICMP6_H_
+#define _NETINET_ICMP6_H_
+
+/*
+ * Header for the BSD advanced API
+ */
+
+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;
+};
+
+#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
+#define ICMP6_PACKET_TOO_BIG		2
+#define ICMP6_TIME_EXCEEDED		3
+#define ICMP6_PARAM_PROB		4
+
+#define ICMP6_INFOMSG_MASK		0x80	/* all information messages */
+
+#define ICMP6_ECHO_REQUEST		128
+#define ICMP6_ECHO_REPLY		129
+#define ICMP6_MEMBERSHIP_QUERY		130
+#define ICMP6_MEMBERSHIP_REPORT		131
+#define ICMP6_MEMBERSHIP_REDUCTION	132
+
+#define ICMP6_DST_UNREACH_NOROUTE	0
+#define ICMP6_DST_UNREACH_ADMIN		1
+#define ICMP6_DST_UNREACH_NOTNEIGHBOR	2
+#define ICMP6_DST_UNREACH_ADDR		3
+#define ICMP6_DST_UNREACH_NOPORT	4
+
+#define ICMP6_TIME_EXCEEDED_TRANSIT	0
+#define ICMP6_TIME_EXCEEDED_REASSEMBLY	1
+
+#define ICMP6_PARAMPROB_HEADER		0
+#define ICMP6_PARAMPROB_NEXTHEADER	1
+#define ICMP6_PARAMPROB_OPTION		2
+
+#define ND_ROUTER_SOLICIT		133
+#define ND_ROUTER_ADVERT		134
+#define ND_NEIGHBOR_SOLICIT		135
+#define ND_NEIGHBOR_ADVERT		136
+#define ND_REDIRECT			137
+
+struct nd_router_solicit {	/* router solicitation */
+    struct icmp6_hdr nd_rs_hdr;
+};
+
+#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 */
+};
+
+#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_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 */
+};
+
+#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 */
+};
+
+#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 /* BYTE_ORDER == LITTLE_ENDIAN */
+#define ND_NA_FLAG_ROUTER	0x00000080
+#define ND_NA_FLAG_SOLICITED	0x00000040
+#define ND_NA_FLAG_OVERRIDE	0x00000020
+#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 */
+};
+
+#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 nd_opt_hdr {	/* Neighbor discovery option header */
+    u_int8_t	nd_opt_type;
+    u_int8_t	nd_opt_len;	/* in units of 8 octets */
+};
+
+#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
+
+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;
+};
+
+#define ND_OPT_PI_FLAG_ONLINK		0x80
+#define ND_OPT_PI_FLAG_AUTO		0x40
+
+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;
+};
+
+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;
+};
+
+#ifndef ICMP6_FILTER_WILLPASS
+
+/*
+ * ICMPv6 filter definition
+ */
+
+struct icmp6_filter {
+	u_int32_t icmp6_filt[8];	/* 8*32 = 256 bits */
+};
+
+#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)
+#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_SETPASSALL(filterp)	\
+    {	\
+	register int i;	\
+	for (i = 0; i < 8; i++)	\
+	    (filterp)->icmp6_filt[i] = 0xffffffff;	\
+    }
+#define ICMP6_FILTER_SETBLOCKALL(filterp)	\
+    {	\
+	register int i;	\
+	for (i = 0; i < 8; i++)	\
+	    (filterp)->icmp6_filt[i] = 0;	\
+    }
+
+#endif
+#endif
diff -uN src-current/sys/netinet/icmp6_var.h src-current-ipv6/sys/netinet/icmp6_var.h
--- src-current/sys/netinet/icmp6_var.h
+++ src-current-ipv6/sys/netinet/icmp6_var.h
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ *
+ *	@(#)icmp_var.h	8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _NETINET_ICMP6_VAR_H_
+#define _NETINET_ICMP6_VAR_H_
+
+/*
+ * Variables related to this implementation
+ * of the IPv6 control message protocol.
+ */
+struct	icmp6stat {
+/* statistics related to IPV6 icmp packets generated */
+	u_long	icp6s_error;		/* # of calls to icmp6_error */
+	u_long	icp6s_ratelim;		/* # beyond error rate limit */
+	u_long	icp6s_oldicmp;		/* no error 'cuz old was icmp */
+	u_long	icp6s_snd_unreach;	/* # of sent unreachables */
+	u_long	icp6s_snd_pkttoobig;	/* # of sent packet too big */
+	u_long	icp6s_snd_timxceed;	/* # of sent time exceeded */
+	u_long	icp6s_snd_paramprob;	/* # of sent parameter problems */
+	u_long	icp6s_snd_redirect;	/* # of sent redirects */
+	u_long	icp6s_snd_echoreq;	/* # of sent echo requests */
+	u_long	icp6s_snd_echorep;	/* # of sent echo replies */
+	u_long	icp6s_snd_grpqry;	/* # of sent group queries */
+	u_long	icp6s_snd_grprep;	/* # of sent group reports */
+	u_long	icp6s_snd_grpterm;	/* # of sent group terminations */
+	u_long	icp6s_snd_rtsol;	/* # of sent router solicitations */
+	u_long	icp6s_snd_rtadv;	/* # of sent router advertisements */
+	u_long	icp6s_snd_ndsol;	/* # of sent neighbor solicitations */
+	u_long	icp6s_snd_ndadv;	/* # of sent neighbor advertisements */
+/* statistics related to input messages processed */
+ 	u_long	icp6s_badcode;		/* icmp6_code out of range */
+	u_long	icp6s_tooshort;		/* packet < ICMP6_MINLEN */
+	u_long	icp6s_checksum;		/* bad checksum */
+	u_long	icp6s_badlen;		/* calculated bound mismatch */
+	u_long	icp6s_reflect;		/* number of responses */
+	u_long	icp6s_rcv_unreach;	/* # of rcvd unreachables */
+	u_long	icp6s_rcv_pkttoobig;	/* # of rcvd packet too big */
+	u_long	icp6s_rcv_timxceed;	/* # of rcvd time exceeded */
+	u_long	icp6s_rcv_paramprob;	/* # of rcvd parameter problems */
+	u_long	icp6s_rcv_echoreq;	/* # of rcvd echo requests */
+	u_long	icp6s_rcv_echorep;	/* # of rcvd echo replies */
+	u_long	icp6s_rcv_grpqry;	/* # of rcvd group queries */
+	u_long	icp6s_rcv_grprep;	/* # of rcvd group reports */
+	u_long	icp6s_rcv_grpterm;	/* # of rcvd group terminations */
+	u_long	icp6s_rcv_bad_grpqry;	/* # of rcvd bad group queries */
+	u_long	icp6s_rcv_bad_grprep;	/* # of rcvd bad group reports */
+	u_long	icp6s_rcv_our_grprep;	/* # of rcvd our groups' reports */
+	u_long	icp6s_rcv_bad_grpterm;	/* # of rcvd bad group terminations */
+	u_long	icp6s_rcv_rtsol;	/* # of rcvd router solicitations */
+	u_long	icp6s_rcv_rtadv;	/* # of rcvd router advertisements */
+	u_long	icp6s_rcv_ndsol;	/* # of rcvd neighbor solicitations */
+	u_long	icp6s_rcv_ndadv;	/* # of rcvd neighbor advertisements */
+	u_long	icp6s_rcv_redirect;	/* # of rcvd redirects */
+	u_long	icp6s_rcv_badrtsol;	/* # of rcvd bad router sol. */
+	u_long	icp6s_rcv_badrtadv;	/* # of rcvd bad router adv. */
+	u_long	icp6s_rcv_badndsol;	/* # of rcvd bad neighbor sol. */
+	u_long	icp6s_rcv_badndadv;	/* # of rcvd bad neighbor adv. */
+	u_long	icp6s_rcv_badredirect;	/* # of rcvd bad redirects */
+};
+
+/*
+ * Names for ICMPv6 sysctl objects
+ */
+#define	ICMP6CTL_STATS		1	/* statistics (read-only) */
+#define	ICMP6CTL_IPSEC		2	/* IPsec for ICMPv6 */
+#define ICMP6CTL_MAXID		3
+
+#define ICMP6CTL_NAMES { \
+	{ 0, 0 }, \
+	{ "stats", CTLTYPE_STRUCT }, \
+	{ "ipsec", CTLTYPE_INT }, \
+}
+
+#ifdef KERNEL
+extern struct	icmp6stat icmp6stat;
+#endif
+
+#endif
diff -uN src-current/sys/netinet/if_atm.c src-current-ipv6/sys/netinet/if_atm.c
--- src-current/sys/netinet/if_atm.c
+++ src-current-ipv6/sys/netinet/if_atm.c
@@ -37,12 +37,14 @@
  */
 
 #include "opt_inet.h"
+#include "opt_inet6.h"
 #include "opt_natm.h"
 
-#ifdef INET
+#if defined(INET) || defined(INET6)
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/queue.h>
 #include <sys/mbuf.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
@@ -79,7 +81,6 @@
 	register struct sockaddr *gate = rt->rt_gateway;
 	struct atm_pseudoioctl api;
 #ifdef NATM
-	struct sockaddr_in *sin;
 	struct natmpcb *npcb = NULL;
 	struct atm_pseudohdr *aph;
 #endif
@@ -91,6 +92,8 @@
 	switch (req) {
 
 	case RTM_RESOLVE: /* resolve: only happens when cloning */
+		if (rt->rt_flags & RTF_XRESOLVE)
+			break;
 		printf("atm_rtrequest: RTM_RESOLVE request detected?\n");
 		break;
 
@@ -122,42 +125,59 @@
 		}
 
 #ifdef DIAGNOSTIC
-		if (rt->rt_ifp->if_ioctl == NULL) panic("atm null ioctl");
+		if (rt->rt_ifp->if_ioctl == NULL)
+			panic("atm null ioctl");
 #endif
 
 #ifdef NATM
+#define RTDST	rt_key(rt)
 		/*
 		 * let native ATM know we are using this VCI/VPI
 		 * (i.e. reserve it)
 		 */
-		sin = (struct sockaddr_in *) rt_key(rt);
-		if (sin->sin_family != AF_INET)
+		if ((RTDST->sa_family != AF_INET) &&
+		    (RTDST->sa_family != AF_INET6))
 			goto failed;
 		aph = (struct atm_pseudohdr *) LLADDR(SDL(gate));
-		npcb = npcb_add(NULL, rt->rt_ifp, ATM_PH_VCI(aph), 
-						ATM_PH_VPI(aph));
+		npcb = npcb_add(NULL, rt->rt_ifp,
+				ATM_PH_VCI(aph), ATM_PH_VPI(aph),
+				ATM_PH_FLAGS(aph));
 		if (npcb == NULL) 
 			goto failed;
-		npcb->npcb_flags |= NPCB_IP;
-		npcb->ipaddr.s_addr = sin->sin_addr.s_addr;
+		if ((npcb->npcb_flags & NPCB_IP) == 0) {
+			npcb->npcb_flags |= NPCB_IP;
+			CLR_ADDR6(npcb->ipaddr6);
+			if (RTDST->sa_family == AF_INET) {
+				npcb->ipaddr6.s6_addr32[2] = htonl(0xffff);
+				npcb->ipaddr.s_addr =
+					satosin(RTDST)->sin_addr.s_addr;
+			} else {
+				COPY_ADDR6(satosin6(RTDST)->sin6_addr,
+					   npcb->ipaddr6);
+			}
+		}
 		/* XXX: move npcb to llinfo when ATM ARP is ready */
 		rt->rt_llinfo = (caddr_t) npcb;
 		rt->rt_flags |= RTF_LLINFO;
+#undef RTDST
 #endif
 		/*
 		 * let the lower level know this circuit is active
 		 */
+		SDL(gate)->sdl_type = rt->rt_ifp->if_type;
+		SDL(gate)->sdl_index = rt->rt_ifp->if_index;
+
+#ifdef NATM
+		if (npcb->npcb_refcnt > 1)
+			break;
+#endif
 		bcopy(LLADDR(SDL(gate)), &api.aph, sizeof(api.aph));
 		api.rxhand = NULL;
 		if (rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMENA, 
-							(caddr_t)&api) != 0) {
+					 (caddr_t)&api) != 0) {
 			printf("atm: couldn't add VC\n");
 			goto failed;
 		}
-
-		SDL(gate)->sdl_type = rt->rt_ifp->if_type;
-		SDL(gate)->sdl_index = rt->rt_ifp->if_index;
-
 		break;
 
 failed:
@@ -169,7 +189,7 @@
 		}
 #endif
 		rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0,
-			rt_mask(rt), 0, (struct rtentry **) 0);
+			  rt_mask(rt), 0, (struct rtentry **) 0);
 		break;
 
 	case RTM_DELETE:
@@ -180,11 +200,13 @@
 		 */
 
 		if (rt->rt_flags & RTF_LLINFO) {
-			npcb_free((struct natmpcb *)rt->rt_llinfo, 
-								NPCB_DESTROY);
+			npcb = (struct natmpcb *)rt->rt_llinfo;
+			npcb_free(npcb, NPCB_DESTROY);
 			rt->rt_llinfo = NULL;
 			rt->rt_flags &= ~RTF_LLINFO;
 		}
+		if (npcb && (npcb->npcb_refcnt >= 1))
+			break;
 #endif
 		/*
 		 * tell the lower layer to disable this circuit
@@ -193,7 +215,7 @@
 		bcopy(LLADDR(SDL(gate)), &api.aph, sizeof(api.aph));
 		api.rxhand = NULL;
 		(void)rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMDIS, 
-							(caddr_t)&api);
+					   (caddr_t)&api);
 
 		break;
 	}
@@ -204,7 +226,7 @@
  *   inputs:
  *     [1] "rt" = the link level route to use (or null if need to look one up)
  *     [2] "m" = mbuf containing the data to be sent
- *     [3] "dst" = sockaddr_in (IP) address of dest.
+ *     [3] "dst" = sockaddr_in(6) (IP) address of dest.
  *   output:
  *     [4] "desten" = ATM pseudo header which we will fill in VPI/VCI info
  *   return: 
diff -uN src-current/sys/netinet/if_atm.h src-current-ipv6/sys/netinet/if_atm.h
--- src-current/sys/netinet/if_atm.h
+++ src-current-ipv6/sys/netinet/if_atm.h
@@ -36,11 +36,6 @@
  * if_atm.h
  */
 
-struct atm_pseudohdr;
-struct mbuf;
-struct rtentry;
-struct sockaddr;
-
 void atm_rtrequest __P((int, struct rtentry *, struct sockaddr *));
 int atmresolve __P((struct rtentry *, struct mbuf *, struct sockaddr *, 
 		struct atm_pseudohdr *));
diff -uN src-current/sys/netinet/if_bti6.c src-current-ipv6/sys/netinet/if_bti6.c
--- src-current/sys/netinet/if_bti6.c
+++ src-current-ipv6/sys/netinet/if_bti6.c
@@ -0,0 +1,404 @@
+/*
+ * IPv4 in IPv6 tunnels.
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#if !defined(INET) || !defined(INET6)
+#error "IPv4 in IPv6 DOES NEED INET and INET6 !!!"
+#endif
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/sockio.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
+#include <net/bpf.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+
+#include "bpfilter.h"
+
+#include "bti.h"
+#if NBTI > 0
+
+/* Maximum packet size */
+#define BTIMTU		(1500-40)
+
+u_int	btinext, bticnt;
+
+struct	bti_softc {
+	struct	ifnet bti_if;
+	struct	ipv6 bti_hdr;
+	union	route_6 bti_ro;
+	STAILQ_ENTRY(bti_softc) bti_list;
+};
+
+STAILQ_HEAD(bti_head, bti_softc);
+struct bti_head bti_head;
+struct bti_softc *last_btiif;
+
+static	void btiattach __P((void *));
+static	void btiadd __P((u_int));
+int	btioutput __P((struct ifnet *, struct mbuf *, struct sockaddr *,
+		       struct rtentry *));
+int	btiioctl __P((struct ifnet *, int, caddr_t));
+void	bti_input __P((struct mbuf *, int));
+
+static int
+sysctl_net_inet6_bticnt SYSCTL_HANDLER_ARGS
+{
+	int error = sysctl_handle_int(oidp,
+		oidp->oid_arg1, oidp->oid_arg2, req);
+
+	if (!error) {
+		if (bticnt > btinext)
+			btiadd(bticnt);
+		bticnt = btinext;
+	}
+	return error;
+}
+
+SYSCTL_PROC(_net_inet6_ipv6, IP6CTL_BTICNT, bti_count,
+	CTLTYPE_INT|CTLFLAG_RW, &bticnt, 0,
+	&sysctl_net_inet6_bticnt, "I", "");
+
+/*
+ * attach BTI interfaces
+ */
+
+static void
+btiattach(dummy)
+	void *dummy;
+{
+	STAILQ_INIT(&bti_head);
+	bticnt = NBTI;
+	btinext = 0;
+	/* add preconfigured BTI interfaces */
+	btiadd(bticnt);
+	last_btiif = bti_head.stqh_first;
+}
+
+PSEUDO_SET(btiattach, if_bti6);
+
+void
+btiadd(cnt)
+	u_int cnt;
+{
+	register int i;
+	register struct bti_softc *sc;
+	register struct ifnet *ifp;
+
+	for (i = btinext; i < cnt; i++) {
+		sc = malloc(sizeof(struct bti_softc), M_DEVBUF, M_NOWAIT);
+		if (sc == NULL)
+			break;
+		bzero(sc, sizeof(struct bti_softc));
+		STAILQ_INSERT_TAIL(&bti_head, sc, bti_list);
+		btinext = i + 1;
+		ifp = &sc->bti_if;
+		ifp->if_softc = sc;
+		ifp->if_unit = i;
+		ifp->if_name = "bti";
+		ifp->if_mtu = BTIMTU;
+		ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
+		ifp->if_snd.ifq_maxlen = ifqmaxlen;
+		ifp->if_ioctl = btiioctl;
+		ifp->if_output = btioutput;
+		ifp->if_type = IFT_OTHER;
+		sc->bti_hdr.ip6_head = IPV6_VERSION;
+		sc->bti_hdr.ip6_nh = IPPROTO_IPIP;
+		sc->bti_hdr.ip6_hlim = ip_defttl;
+		ifp->if_hdrlen = sizeof(struct ipv6);
+		if_attach(ifp);
+#if NBPFILTER > 0
+		bpfattach(ifp, DLT_NULL, sizeof(u_int));
+#endif
+	}
+	bticnt = btinext;
+}
+
+/*
+ * output of IPv4 packets by encapsulation in IPv6
+ */
+int
+btioutput(ifp, m0, dst, rt)
+	register struct ifnet *ifp;
+	struct mbuf *m0;
+	struct sockaddr *dst;
+	struct rtentry *rt;
+{
+	register struct mbuf *m;
+	struct ipv6 *ip;
+	int error;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_BTIOUT)
+		printf("btioutput(%p,%p,%p,%p) -> %s\n",
+		       ifp, m0, dst, rt,
+		       inet_ntoa(satosin(dst)->sin_addr));
+
+#endif
+
+	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+		m_freem(m0);
+		return (ENETDOWN);
+	}
+
+	getmicrotime(&ifp->if_lastchange);
+	ifp->if_opackets++;
+#ifdef DIAGNOSTIC
+	if ((m0->m_flags & M_PKTHDR) == 0)
+		panic("btioutput no HDR");
+#endif
+
+#if NBFILTER > 0
+	if (ifp->if_bpf) {
+		/* too soon ?! */
+		/*
+		 * We need to prepend the address family as
+		 * a four byte field.  Cons up a dummy header
+		 * to pacify bpf.  This is safe because bpf
+		 * will only read from the mbuf (i.e., it won't
+		 * try to free it or keep a pointer to it).
+		 */
+		struct mbuf m;
+		u_int af = dst->sa_family;
+
+		m.m_next = m0;
+		m.m_len = 4;
+		m.m_data = (char *)&af;
+
+		bpf_mtap(ifp, &m);
+	}
+#endif
+
+	/*
+	 * Get a header mbuf.
+	 */
+	MGETHDR(m, M_DONTWAIT, MT_DATA);
+	if (m == NULL) {
+		m_freem(m0);
+		return (ENOBUFS);
+	}
+	m->m_len = sizeof(struct ipv6);
+	m->m_next = m0;
+	m->m_pkthdr.len = m0->m_pkthdr.len + sizeof(struct ipv6);
+	ifp->if_obytes += m->m_pkthdr.len;
+
+	/*
+	 * Fill in IPv6 header.
+	 */
+	ip = mtod(m, struct ipv6 *);
+	bcopy(&((struct bti_softc *)ifp)->bti_hdr, ip, sizeof(struct ipv6));
+	ip->ip6_len = m0->m_pkthdr.len;
+
+	/*
+	 * Output final datagram.
+	 */
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_BTIOUT)
+		printf("btioutput src %s dst %s len %d\n",
+		       ip6_sprintf(&ip->ip6_src),
+		       ip6_sprintf(&ip->ip6_dst),
+		       m->m_pkthdr.len);
+#endif
+	error = ip6_output(m,
+			   (struct mbuf *)0,
+			   &((struct bti_softc *)ifp)->bti_ro.route,
+			   0, NULL, NULL);
+	if (error)
+		ifp->if_oerrors++;
+	return (error);
+}
+
+/*
+ * Ioctls on BTI pseudo-interfaces.
+ */
+
+int
+btiioctl(ifp, cmd, data)
+	struct ifnet *ifp;
+	int cmd;
+	caddr_t data;
+{
+	struct ifaddr *ifa;
+	struct in_addr *si, *sd;
+	struct ifreq *ifr;
+	struct in6_aliasreq *ifr6;
+	struct bti_softc *sc = (struct bti_softc *)ifp;
+	struct ipv6 *ip = &sc->bti_hdr;
+	int s = splimp(), error = 0;
+
+	switch (cmd) {
+
+	case SIOCSIFADDR:
+	case SIOCSIFDSTADDR:
+		ifa = (struct ifaddr *)data;
+		if ((ifa == 0) ||
+		    (ifa->ifa_addr->sa_family != AF_INET)) {
+			error = EAFNOSUPPORT;
+			break;
+		}
+		si = &satosin(ifa->ifa_addr)->sin_addr;
+		sd = &satosin(ifa->ifa_dstaddr)->sin_addr;
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_BTICTL)
+			printf("btiioctl set ifp %p: %08x -> %08x\n",
+			       ifp, si->s_addr, sd->s_addr);
+#endif
+		if (si->s_addr && in_canforward(*si) &&
+		    sd->s_addr && in_canforward(*sd)) 
+				ifp->if_flags |= IFF_UP;
+		break;
+				
+	case SIOCGBTIADDR6:
+		ifr6 = (struct in6_aliasreq *)data;
+		bzero(&ifr6->ifra_addr, 3 * sizeof(struct sockaddr_in6));
+		ifr6->ifra_addr.sin6_family = AF_INET6;
+		ifr6->ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
+		ifr6->ifra_addr.sin6_flowinfo =
+			ip->ip6_head & IPV6_FLOWINFO_PRIFLOW;
+		COPY_ADDR6(ip->ip6_src, ifr6->ifra_addr.sin6_addr);
+		ifr6->ifra_dstaddr.sin6_family = AF_INET6;
+		ifr6->ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
+		COPY_ADDR6(ip->ip6_dst, ifr6->ifra_dstaddr.sin6_addr);
+		break;
+
+	case SIOCSBTIADDR6:
+		ifr6 = (struct in6_aliasreq *)data;
+		ip->ip6_head = ifr6->ifra_addr.sin6_flowinfo;
+		ip->ip6_head &= IPV6_FLOWINFO_PRIFLOW;
+		ip->ip6_head |= IPV6_VERSION;
+		COPY_ADDR6(ifr6->ifra_addr.sin6_addr, ip->ip6_src);
+		COPY_ADDR6(ifr6->ifra_dstaddr.sin6_addr, ip->ip6_dst);
+		if (sc->bti_ro.route.ro_rt) {
+			RTFREE(sc->bti_ro.route.ro_rt);
+			bzero(&sc->bti_ro, sizeof(union route_6));
+		}
+		if (!IS_ANYADDR6(ip->ip6_src) &&
+		    !IS_ANYADDR6(ip->ip6_dst) &&
+		    !IS_LOOPADDR6(ip->ip6_src) &&
+		    !IS_LOOPADDR6(ip->ip6_dst) &&
+		    !IS_MULTIADDR6(ip->ip6_src) &&
+		    !IS_MULTIADDR6(ip->ip6_dst))
+			ifp->if_flags |= IFF_RUNNING;
+		else
+			ifp->if_flags &= ~IFF_RUNNING;
+		break;
+
+	case SIOCSIFMTU:
+		ifr = (struct ifreq *)data;
+		ifp->if_mtu = ifr->ifr_mtu;
+		break;
+
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		ifr = (struct ifreq *)data;
+		if ((ifr == 0) || (ifr->ifr_addr.sa_family != AF_INET))
+			error = EAFNOSUPPORT;
+		break;
+
+	default:
+		error = EINVAL;
+	}
+	splx(s);
+	return (error);
+}
+
+/*
+ * IPv4-into-IPv6 input routine.
+ */
+
+void
+bti_input(m, arg)
+	register struct mbuf *m;
+	int arg;
+{
+	register struct ipv6 *bip, *ip = mtod(m, struct ipv6 *);
+	struct mbuf *opts = (struct mbuf *)arg;
+	struct bti_softc *sc = last_btiif;
+	struct ifnet *ifp;
+
+	if (opts)
+		m_freem(opts);
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_BTIIN)
+		printf("bti_input src %s dst %s len %d\n",
+		       ip6_sprintf(&ip->ip6_src),
+		       ip6_sprintf(&ip->ip6_dst),
+		       ip->ip6_len);
+#endif
+
+	/*
+	 * Get the input tunnel.
+	 */
+	bip = &sc->bti_hdr;
+	if (SAME_ADDR6(ip->ip6_src, bip->ip6_dst) &&
+	    SAME_ADDR6(ip->ip6_dst, bip->ip6_src)) {
+		ifp = &sc->bti_if;
+	} else {
+		last_btiif = bti_head.stqh_first;
+		for (sc = last_btiif; sc; sc = sc->bti_list.stqe_next) {
+			ifp = &sc->bti_if;
+			if (((ifp->if_flags & IFF_UP) == 0) ||
+			    ((ifp->if_flags & IFF_RUNNING) == 0))
+				continue;
+			bip = &sc->bti_hdr;
+			if (SAME_ADDR6(ip->ip6_src, bip->ip6_dst) &&
+			    SAME_ADDR6(ip->ip6_dst, bip->ip6_src)) {
+				last_btiif = sc;
+				break;
+			}
+		}
+		if (sc == 0)
+			ifp = &last_btiif->bti_if;
+	}
+	ifp->if_ipackets++;
+	ifp->if_ibytes += m->m_pkthdr.len;
+
+	m->m_pkthdr.rcvif = ifp;
+	/* should use link0 and link1 for AH and ESP */
+	m->m_flags &= ~(M_AUTH|M_CRYPT);
+
+	/*
+	 * Strip IPv6 header and get IPv4 one.
+	 */
+	m->m_pkthdr.len -= sizeof(struct ipv6);
+	m->m_len -= sizeof(struct ipv6);
+	m->m_data += sizeof(struct ipv6);
+	if (m->m_len < sizeof (struct ip) &&
+	    (m = m_pullup(m, sizeof (struct ip))) == 0) {
+		ipstat.ips_toosmall++;
+		return;
+	}
+
+	ip_input(m);
+}
+
+/*
+ * TODO: bti_ctlinput()
+ */
+#endif
diff -uN src-current/sys/netinet/if_cti6.c src-current-ipv6/sys/netinet/if_cti6.c
--- src-current/sys/netinet/if_cti6.c
+++ src-current-ipv6/sys/netinet/if_cti6.c
@@ -0,0 +1,304 @@
+/*
+ * Configured Tunnel Interface (special case of SIT)
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include "cti.h"
+#include "sit.h"
+#if NCTI > 0
+
+#ifndef INET
+#error "CTI DOES NEED INET !!!"
+#endif
+#ifndef INET6
+#error "CTI DOES NEED INET6 !!!"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/sockio.h>
+#include <sys/time.h>
+#include <sys/syslog.h>
+
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
+#include <net/bpf.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/ip6_icmp.h>
+#include <netinet/if_ndp6.h>
+#include <netinet/if_sit6.h>
+
+#include "bpfilter.h"
+
+int	ctioutput __P((struct ifnet *, struct mbuf *, struct sockaddr *,
+		       struct rtentry *));
+int	ctiioctl __P((struct ifnet *, int, caddr_t));
+
+void
+ctiadd(cnt)
+	u_int cnt;
+{
+	register u_int i;
+	register struct sit_softc *sc;
+	register struct ifnet *ifp;
+
+	for (i = sitcnt; i < cnt; i++) {
+		sc = malloc(sizeof(struct sit_softc), M_DEVBUF, M_NOWAIT);
+		if (sc == NULL)
+			break;
+		bzero(sc, sizeof(struct sit_softc));
+		STAILQ_INSERT_TAIL(&sitif, sc, sit_list);
+		sitcnt = i + 1;
+		ifp = &sc->sit_if;
+		ifp->if_unit = i - NSIT;
+		ifp->if_name = "cti";
+		ifp->if_mtu = SITMTU;
+		ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
+		ifp->if_snd.ifq_maxlen = ifqmaxlen;
+		ifp->if_ioctl = ctiioctl;
+		ifp->if_output = ctioutput;
+		ifp->if_type = IFT_OTHER;
+		sc->sit_llinfo.sit_ip.ip_ttl = IPDEFTTL;
+		sc->sit_llinfo.sit_ip.ip_p = IPPROTO_IPV6;
+		ifp->if_hdrlen = sizeof(struct ip);
+		ifp->if_addrlen = 8;
+		ifp->if_ndtype = IFND6_SIT |
+			(((int)&(((struct sit_softc *)0)->sit_llip6) -
+			  sizeof(struct ifnet)) << 8);
+		if_attach(ifp);
+#if NBPFILTER > 0
+		bpfattach(ifp, DLT_NULL, sizeof(u_int));
+#endif
+	}
+	cticnt = sitcnt - NSIT;
+}
+
+/*
+ * output of IPv6 packets by encapsulation in IPv4
+ */
+int
+ctioutput(ifp, m0, dst, rt)
+	register struct ifnet *ifp;
+	struct mbuf *m0;
+	struct sockaddr *dst;
+	struct rtentry *rt;
+{
+	register struct mbuf *m;
+	register struct llinfo_sit *ll;
+	struct ip *ip;
+	int error;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_SITOUT)
+		printf("ctioutput(%p,%p,%p,%p) -> %s\n",
+		       ifp, m0, dst, rt,
+		       ip6_sprintf(&((struct sockaddr_in6 *)dst)->sin6_addr));
+#endif
+
+	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+		m_freem(m0);
+		return (ENETDOWN);
+	}
+
+	getmicrotime(&ifp->if_lastchange);
+	ifp->if_opackets++;
+#ifdef DIAGNOSTIC
+	if ((m0->m_flags & M_PKTHDR) == 0)
+		panic("ctioutput no HDR");
+#endif
+	ll = &((struct sit_softc *)ifp)->sit_llinfo;
+
+#if NBFILTER > 0
+	if (ifp->if_bpf) {
+		/* too soon ?! */
+		/*
+		 * We need to prepend the address family as
+		 * a four byte field.  Cons up a dummy header
+		 * to pacify bpf.  This is safe because bpf
+		 * will only read from the mbuf (i.e., it won't
+		 * try to free it or keep a pointer to it).
+		 */
+		struct mbuf m;
+		u_int af = dst->sa_family;
+
+		m.m_next = m0;
+		m.m_len = 4;
+		m.m_data = (char *)&af;
+
+		bpf_mtap(ifp, &m);
+	}
+#endif
+
+	/*
+	 * Get a header mbuf.
+	 */
+	MGETHDR(m, M_DONTWAIT, MT_DATA);
+	if (m == NULL) {
+		m_freem(m0);
+		return (ENOBUFS);
+	}
+	m->m_len = sizeof(struct ip);
+	m->m_next = m0;
+	m->m_pkthdr.len = m0->m_pkthdr.len + sizeof(struct ip);
+
+	/*
+	 * Fill in IPv4 header.
+	 */
+	bcopy((caddr_t)&ll->sit_ip, mtod(m, caddr_t), sizeof(struct ip));
+	ip = mtod(m, struct ip *);
+	ip->ip_len = m->m_pkthdr.len;
+	ifp->if_obytes += m->m_pkthdr.len;
+
+	/*
+	 * Output final datagram.
+	 */
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_SITOUT)
+		printf("ctioutput src %08x dst %08x len %d\n",
+		       ntohl(ip->ip_src.s_addr),
+		       ntohl(ip->ip_dst.s_addr),
+		       m->m_pkthdr.len);
+#endif
+	error = ip_output(m, (struct mbuf *)0, &ll->sit_route, 0, NULL);
+	if (error)
+		ifp->if_oerrors++;
+	return (error);
+}
+
+/*
+ * Ioctls on CTI pseudo-interfaces.
+ */
+
+int
+ctiioctl(ifp, cmd, data)
+	struct ifnet *ifp;
+	int cmd;
+	caddr_t data;
+{
+	struct ifaddr *ifa;
+	struct ifreq *ifr;
+	struct in6_addr *addr;
+	struct sockaddr_dl *sdl = 0;
+	static struct sockaddr_in sin = {sizeof(sin), AF_INET};
+	int s = splimp(), error = 0;
+
+	switch (cmd) {
+
+	case SIOCSIFADDR:
+		ifa = (struct ifaddr *)data;
+		if ((ifa == 0) || (ifa->ifa_addr->sa_family != AF_INET6)) {
+			error = EAFNOSUPPORT;
+			break;
+		}
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_SITCTL)
+			printf("ctiioctl ifp %p go up %s\n", ifp,
+			    ip6_sprintf(&satosin6(ifa->ifa_addr)->sin6_addr));
+#endif
+		addr = &satosin6(ifa->ifa_addr)->sin6_addr;
+		if (IS_LINKLADDR6(*addr)) {
+			COPY_ADDR6(*addr,
+				   ((struct sit_softc *)ifp)->sit_llip6);
+			ifp->if_ndtype |= IFND6_LLSET;
+			break;
+		}
+		sin.sin_addr.s_addr = addr->s6_addr32[3];
+		if ((addr->s6_addr32[0] != 0) ||
+		    (addr->s6_addr32[1] != 0) ||
+		    (addr->s6_addr32[2] != 0) ||
+		    (ifa_ifwithaddr((struct sockaddr *)&sin) == 0))
+			break;
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_SITCTL)
+			printf("ctiioctl sets src %lx\n",
+			       ntohl(sin.sin_addr.s_addr));
+#endif
+		((struct sit_softc *)ifp)->sit_src = sin.sin_addr;
+		ifp->if_flags |= IFF_UP;
+		if (ifp->if_addrhead.tqh_first &&
+		    ifp->if_addrhead.tqh_first->ifa_addr &&
+		    (ifp->if_addrhead.tqh_first->ifa_addr->sa_family == AF_LINK)) {
+			sdl = (struct sockaddr_dl *)ifp->if_addrhead.tqh_first->ifa_addr;
+			bcopy(&sin.sin_addr, LLADDR(sdl), 4);
+			sdl->sdl_alen = 8;
+		}
+		if (ifa->ifa_dstaddr->sa_family != AF_INET6)
+			break;
+		/* falls in */
+
+	case SIOCSIFDSTADDR:
+		ifa = (struct ifaddr *)data;
+		if ((ifa == 0) || (ifa->ifa_dstaddr->sa_family != AF_INET6)) {
+			error = EAFNOSUPPORT;
+			break;
+		}
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_SITCTL)
+			printf("ctiioctl ifp %p dst %s\n", ifp,
+			  ip6_sprintf(&satosin6(ifa->ifa_dstaddr)->sin6_addr));
+#endif
+		addr = &satosin6(ifa->ifa_dstaddr)->sin6_addr;
+		sin.sin_addr.s_addr = addr->s6_addr32[3];
+		if ((addr->s6_addr32[0] != 0) ||
+		    (addr->s6_addr32[1] != 0) ||
+		    (addr->s6_addr32[2] != 0) ||
+		    (addr->s6_addr32[3] == 0))
+			break;
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_SITCTL)
+			printf("ctiioctl sets dst %lx\n",
+			       ntohl(sin.sin_addr.s_addr));
+#endif
+		((struct sit_softc *)ifp)->sit_dst = sin.sin_addr;
+		if (ifp->if_addrhead.tqh_first && ifp->if_addrhead.tqh_first->ifa_addr &&
+		    (ifp->if_addrhead.tqh_first->ifa_addr->sa_family == AF_LINK)) {
+			sdl = (struct sockaddr_dl *)ifp->if_addrhead.tqh_first->ifa_addr;
+			bcopy(&sin.sin_addr, LLADDR(sdl) + 4, 4);
+				sdl->sdl_alen = 8;
+		}
+		ifp->if_flags |= IFF_RUNNING;
+		break;
+
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		ifr = (struct ifreq *)data;
+		if ((ifr == 0) || (ifr->ifr_addr.sa_family != AF_INET6)) {
+			error = EAFNOSUPPORT;
+			break;
+		}
+		break;
+
+	case SIOCSIFMTU:
+		ifr = (struct ifreq *)data;
+		ifp->if_mtu = ifr->ifr_mtu;
+		break;
+
+	default:
+		error = EINVAL;
+	}
+	splx(s);
+	return (error);
+}
+#endif
diff -uN src-current/sys/netinet/if_ether.h src-current-ipv6/sys/netinet/if_ether.h
--- src-current/sys/netinet/if_ether.h
+++ src-current-ipv6/sys/netinet/if_ether.h
@@ -40,6 +40,23 @@
 #include <net/ethernet.h>
 #include <net/if_arp.h>
 
+#define	ETHERTYPE_PUP		0x0200	/* PUP protocol */
+#define	ETHERTYPE_IP		0x0800	/* IP protocol */
+#define	ETHERTYPE_IPV6		0x86dd	/* IPv6 protocol */
+#define ETHERTYPE_ARP		0x0806	/* Addr. resolution protocol */
+#define ETHERTYPE_REVARP	0x8035	/* reverse Addr. resolution protocol */
+
+/*
+ * The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL have
+ * (type-ETHERTYPE_TRAIL)*512 bytes of data followed
+ * by an ETHER type (as given above) and then the (variable-length) header.
+ */
+#define	ETHERTYPE_TRAIL		0x1000		/* Trailer packet */
+#define	ETHERTYPE_NTRAILER	16
+
+#define	ETHERMTU	(ETHER_MAX_LEN-ETHER_HDR_LEN-ETHER_CRC_LEN)
+#define	ETHERMIN	(ETHER_MIN_LEN-ETHER_HDR_LEN-ETHER_CRC_LEN)
+
 /*
  * Macro to map an IP multicast address to an Ethernet multicast address.
  * The high-order 25 bits of the Ethernet address are statically assigned,
@@ -98,6 +115,7 @@
 extern u_char	ether_ipmulticast_max[ETHER_ADDR_LEN];
 extern struct	ifqueue arpintrq;
 
+void	arp_rtrequest __P((int, struct rtentry *, struct sockaddr *));
 int	arpresolve __P((struct arpcom *, struct rtentry *, struct mbuf *,
 			struct sockaddr *, u_char *, struct rtentry *));
 void	arp_ifinit __P((struct arpcom *, struct ifaddr *));
diff -uN src-current/sys/netinet/if_ether6.h src-current-ipv6/sys/netinet/if_ether6.h
--- src-current/sys/netinet/if_ether6.h
+++ src-current-ipv6/sys/netinet/if_ether6.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ *
+ *	@(#)if_ether.h	8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _NETINET_IF_ETHER6_H_
+#define _NETINET_IF_ETHER6_H_
+
+#include <net/ethernet.h>
+
+#ifdef KERNEL
+/*
+ * Macro to map an IPv6 multicast address to an Ethernet multicast address.
+ * The high-order 16 bits of the Ethernet address are statically assigned,
+ * and the low-order 32 bits are taken from the low end of the IPv6 address.
+ *
+ * TODO: get the *real* address!
+ */
+#define ETHER_MAP_IP6_MULTICAST(ip6addr, enaddr)			\
+	/* struct in6_addr *ip6addr; */					\
+	/* u_int8_t enaddr[ETHER_ADDR_LEN]; */				\
+{									\
+	(enaddr)[0] = 0x33;						\
+	(enaddr)[1] = 0x33;						\
+	(enaddr)[2] = ((u_int8_t *)ip6addr)[12];			\
+	(enaddr)[3] = ((u_int8_t *)ip6addr)[13];			\
+	(enaddr)[4] = ((u_int8_t *)ip6addr)[14];			\
+	(enaddr)[5] = ((u_int8_t *)ip6addr)[15];			\
+}
+
+#ifdef INET6
+extern u_char ether_ip6multicast_min[ETHER_ADDR_LEN];
+extern u_char ether_ip6multicast_max[ETHER_ADDR_LEN];
+#endif
+#endif
+
+#endif
diff -uN src-current/sys/netinet/if_fddi.h src-current-ipv6/sys/netinet/if_fddi.h
--- src-current/sys/netinet/if_fddi.h
+++ src-current-ipv6/sys/netinet/if_fddi.h
@@ -73,8 +73,15 @@
 #define	fddibroadcastaddr	etherbroadcastaddr
 #define	fddi_ipmulticast_min	ether_ipmulticast_min
 #define	fddi_ipmulticast_max	ether_ipmulticast_max
+#ifdef INET6
+#define	fddi_ip6multicast_min	ether_ip6multicast_min
+#define	fddi_ip6multicast_max	ether_ip6multicast_max
+#endif
 #define	fddi_addmulti		ether_addmulti
 #define	fddi_delmulti		ether_delmulti
+#ifdef INET6
+#define	fddi_matchmulti		ether_matchmulti
+#endif
 #define	fddi_sprintf		ether_sprintf
 
 void    fddi_ifattach __P((struct ifnet *));
diff -uN src-current/sys/netinet/if_llink6.c src-current-ipv6/sys/netinet/if_llink6.c
--- src-current/sys/netinet/if_llink6.c
+++ src-current-ipv6/sys/netinet/if_llink6.c
@@ -0,0 +1,280 @@
+/*
+ * IPv6 link-local interface hook.
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/ip6_icmp.h>
+#include <netinet/ip6_opts.h>
+#include <netinet/if_ether.h>
+#include <netinet/if_ndp6.h>
+#include <netinet/icmp6_var.h>
+
+#if defined(INET6) && (MULTI_HOMED > 0)
+
+struct	ifnet llif;
+
+#define satosdl(s)	((struct sockaddr_dl *)s)
+#define rt_expire	rt_rmx.rmx_expire
+#define rt_mtu		rt_rmx.rmx_mtu
+#define rt_metric	rt_rmx.rmx_hopcount
+
+extern	u_int ndpt_retrans, ndp_mmaxtries;
+
+static	void llinkattach __P((void *));
+int	llinkoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *,
+			 struct rtentry *));
+int	llinkioctl __P((struct ifnet *, int, caddr_t));
+void	llink_resolve __P((struct mbuf *, struct sockaddr *,
+			   struct rtentry *));
+
+/*
+ * Link-Local interface attach.
+ */
+void
+llinkattach(dummy)
+	void *dummy;
+{
+	register struct ifnet *ifp;
+
+	llif.if_unit = 0;
+	llif.if_name = "ll";
+	llif.if_mtu = ETHERMTU;
+	llif.if_flags = IFF_BROADCAST;
+#ifdef STRICT_LLINK
+	llif.if_flags |= IFF_NOARP;
+#endif
+	llif.if_ioctl = llinkioctl;
+	llif.if_output = llinkoutput;
+	llif.if_type = IFT_OTHER;
+	llif.if_ndtype = IFND6_LLINK;
+
+	if_attach(&llif);
+}
+
+PSEUDO_SET(llinkattach, if_llink6);
+
+/*
+ * Link-Local interface output.
+ */
+int
+llinkoutput(ifp, m0, dst, rt0)
+	register struct ifnet *ifp;
+	struct mbuf *m0;
+	struct sockaddr *dst;
+	struct rtentry *rt0;
+{
+	int error = 0;
+	register struct rtentry *rt = rt0;
+	struct llinfo_ndp6 *ln;
+
+#define	senderr(e)	{ error = (e); goto bad;}
+
+	if ((ifp->if_flags & IFF_UP) == 0)
+		senderr(ENETDOWN);
+	if (dst->sa_family != AF_INET6)
+		senderr(EAFNOSUPPORT);
+	if (!IS_LINKLADDR6(satosin6(dst)->sin6_addr))
+		senderr(EHOSTUNREACH);
+	ifp->if_lastchange = time;
+
+#if (MULTI_HOMED == 1)
+	if (ifp->if_flags & IFF_NOARP)
+#endif
+		senderr(EHOSTUNREACH);
+
+	if (rt == 0) {
+		if ((ln = ndplookup(&satosin6(dst)->sin6_addr, 1)) != 0)
+			rt = ln->ln_rt;
+		else
+			senderr(EHOSTUNREACH);
+	}
+	if ((rt->rt_flags & RTF_UP) == 0) {
+		if ((rt0 = rt = rtalloc1(dst, 1, 0UL)) != 0)
+			rt->rt_refcnt--;
+		else 
+			senderr(EHOSTUNREACH);
+	}
+	if (rt->rt_flags & RTF_GATEWAY) {
+		if (rt->rt_gwroute == 0)
+			goto lookup;
+		if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
+			rtfree(rt); rt = rt0;
+		lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL);
+			if ((rt = rt->rt_gwroute) == 0)
+				senderr(EHOSTUNREACH);
+		}
+	}
+	if (rt->rt_flags & RTF_REJECT)
+		if (rt->rt_rmx.rmx_expire == 0 ||
+		    time.tv_sec < rt->rt_rmx.rmx_expire)
+			senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
+
+	llink_resolve(m0, dst, rt);
+	return (error);
+    bad:
+	if (m0)
+		m_freem(m0);
+	return (error);
+}
+
+/*
+ * Link-Local interface ioctls.
+ */
+int
+llinkioctl(ifp, cmd, data)
+	struct ifnet *ifp;
+	int cmd;
+	caddr_t data;
+{
+	struct ifaddr *ifa;
+	struct ifreq *ifr;
+	struct in6_addr *maddr;
+	struct in6_multi *inm;
+	int s = splimp(), error = 0;
+
+	switch (cmd) {
+
+	case SIOCSIFADDR:
+		if ((ifa = (struct ifaddr *)data) &&
+		    (ifa->ifa_addr->sa_family == AF_INET6)) {
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_NDP1)
+				printf("llinkioctl ifp go up %s\n",
+	    ip6_sprintf(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr));
+#endif
+			ifp->if_flags |= IFF_UP;
+			ifa->ifa_rtrequest = ndp6_rtrequest;
+			ifa->ifa_flags |= RTF_CLONING;
+		}
+		break;
+
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		ifr = (struct ifreq *)data;
+		if (ifr == 0 || ifr->ifr_addr.sa_family != AF_INET6) {
+			error = EAFNOSUPPORT;
+			break;
+		}
+		maddr = &satosin6(&ifr->ifr_addr)->sin6_addr;
+		if (!IS_MULTIADDR6(*maddr) ||
+		    MADDR6_SCOPE(*maddr) != MADDR6_SCP_LINK) {
+			error = EADDRNOTAVAIL;
+			break;
+		}
+		for (ifp = ifnet; ifp != 0; ifp = ifp->if_next) {
+			if ((ifp->if_ndtype & IFND6_INLL) == 0)
+				continue;
+			if (cmd == SIOCADDMULTI)
+				(void) in6_addmulti(maddr, ifp);
+			else {
+				IN6_LOOKUP_MULTI(*maddr, ifp, inm);
+				if (inm)
+					in6_delmulti(inm);
+			}
+		}
+		break;
+
+	case SIOCSIFMTU:
+		ifr = (struct ifreq *)data;
+		ifp->if_mtu = ifr->ifr_mtu;
+		break;
+
+	default:
+		error = EINVAL;
+	}
+	splx(s);
+	return (error);
+}
+
+/*
+ * Link-Local interface pseudo address resolution.
+ */
+void
+llink_resolve(m, dst, rt)
+	struct mbuf *m;
+	struct sockaddr *dst;
+	struct rtentry *rt;
+{
+	register struct ifnet *ifp;
+	register struct llinfo_ndp6 *ln;
+	struct sockaddr_dl *sdl = satosdl(rt->rt_gateway);
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_NDP1)
+		printf("llink_resolve(%p,%s,%p)\n",
+		       m, ip6_sprintf(&(satosin6(dst))->sin6_addr), rt);
+#endif
+	if (dst->sa_family != AF_INET6 ||
+	    !IS_LINKLADDR6(satosin6(dst)->sin6_addr)) {
+		if (m)
+			m_freem(m);
+		return;
+	}
+	    
+	ln = (struct llinfo_ndp6 *)rt->rt_llinfo;
+	if (ln == 0) {
+		log(LOG_DEBUG, "llink_resolve: can't allocate llinfo for %s\n",
+		    ip6_sprintf(&(satosin6(dst))->sin6_addr));
+		if (m)
+			m_freem(m);
+		return;
+	}
+
+	/*
+	 * There is an invalid ndp entry
+	 * Replace the held mbuf with this latest one.
+	 */
+	ln->ln_state = LLNDP6_INCOMPLETE;
+	if (m) {
+		if (ln->ln_hold)
+			m_freem(ln->ln_hold);
+		ln->ln_hold = m;
+	}
+	sdl->sdl_alen = 0;
+	/*
+	 * Re-send a Neighbor Solicitation when appropriate
+	 * on all IEEE-link interfaces with an IPv6 address.
+	 */
+	if (ln->ln_hold == 0 ||
+	    rt->rt_expire > time.tv_sec ||
+	    ln->ln_asked >= ndp_mmaxtries)
+		return;
+	ln->ln_asked++;
+	rt->rt_expire = time.tv_sec + ndpt_retrans;
+	for (ifp = ifnet; ifp != 0; ifp = ifp->if_next) {
+		if (((ifp->if_ndtype & IFND6_INLL) == 0) ||
+		    ((ifp->if_ndtype & IFND6_LLSET) == 0))
+			continue;
+		ndsol6_output(ifp, ln->ln_hold, NULL,
+			      &satosin6(dst)->sin6_addr);
+	}
+
+}
+#endif /* defined(INET6) && (MULTI_HOMED > 0) */
diff -uN src-current/sys/netinet/if_ndp6.c src-current-ipv6/sys/netinet/if_ndp6.c
--- src-current/sys/netinet/if_ndp6.c
+++ src-current-ipv6/sys/netinet/if_ndp6.c
@@ -0,0 +1,1754 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 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.
+ *
+ *	@(#)if_ether.c	8.1 (Berkeley) 6/10/93
+ */
+
+#include "opt_inet6.h"
+
+/*
+ * IPv6 neighbor discovery protocol.
+ */
+
+#ifdef INET6
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/ip6_icmp.h>
+#include <netinet/ip6_opts.h>
+#include <netinet/if_ether.h>
+#include <netinet/if_ether6.h>
+#include <netinet/if_ndp6.h>
+#include <netinet/icmp6_var.h>
+
+#define satosdl(s) ((struct sockaddr_dl *)s)
+
+MALLOC_DECLARE(M_IPMOPTS);
+
+/*
+ * Timer values
+ */
+u_int	ndpt_keep = 10*60;	/* route default lifetime (10 minutes) */
+u_int	ndpt_reachable = 120;	/* reachable time (4 * 30 seconds) */
+u_int	ndpt_retrans = 40;	/* retrans timer (4 * 10 seconds) */
+u_int	ndpt_probe = 20;	/* delay first probe (4 * 5 seconds) */
+u_int	ndpt_down = 10;		/* hold down timer (10 seconds) */
+u_int	ndp_umaxtries = 3;	/* max unicast solicit (3) */
+u_int	ndp_mmaxtries = 3;	/* max multicast solicit (3) */
+
+SYSCTL_INT(_net_inet6_ipv6, IP6CTL_KEEP, keep, CTLFLAG_RW,
+	&ndpt_keep, 0, "");
+SYSCTL_INT(_net_inet6_ipv6, IP6CTL_REACHABLE, reachable, CTLFLAG_RW,
+	&ndpt_reachable, 0, "");
+SYSCTL_INT(_net_inet6_ipv6, IP6CTL_RETRANS, retrans, CTLFLAG_RW,
+	&ndpt_retrans, 0, "");
+SYSCTL_INT(_net_inet6_ipv6, IP6CTL_PROBE, probe, CTLFLAG_RW,
+	&ndpt_probe, 0, "");
+SYSCTL_INT(_net_inet6_ipv6, IP6CTL_DOWN, hold_down, CTLFLAG_RW,
+	&ndpt_down, 0, "");
+SYSCTL_INT(_net_inet6_ipv6, IP6CTL_UMAXTRIES, utries_max, CTLFLAG_RW,
+	&ndp_umaxtries, 0, "");
+SYSCTL_INT(_net_inet6_ipv6, IP6CTL_MMAXTRIES, mtries_max, CTLFLAG_RW,
+	&ndp_mmaxtries, 0, "");
+
+#define	rt_expire	rt_rmx.rmx_expire
+#define rt_mtu		rt_rmx.rmx_mtu
+#define rt_metric	rt_rmx.rmx_hopcount
+
+#if (MULTI_HOMED > 0)
+extern	void llink_resolve __P((struct mbuf *,
+			struct sockaddr *, struct rtentry *));
+#endif
+
+int	ndp_inuse, ndp_allocated;
+extern	int useloopback;	/* use loopback interface for local traffic */
+int	ndp6_init_done = 0;
+
+struct	in6_addr allnodes6_group =
+#if BYTE_ORDER == BIG_ENDIAN
+   {{{ 0xff020000, 0, 0, 1 }}};
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+   {{{ 0x02ff, 0, 0, 0x01000000 }}};
+#endif
+
+extern	int ip6forwarding;
+
+#define ROUTER_ADV		0x80000000
+#define SOLICITED_ADV		0x40000000
+#define OVERRIDE_ADV		0x20000000
+#define NO_LLA_ADV		0x00000001
+#define MASK_ADV		0xe0000000
+
+/*
+ * Parallel to llc_rtrequest.
+ */
+void
+ndp6_rtrequest(req, rt, sa)
+	int req;
+	register struct rtentry *rt;
+	struct sockaddr *sa;
+{
+	register struct sockaddr *gate = rt->rt_gateway;
+	register struct llinfo_ndp6 *ln = (struct llinfo_ndp6 *)rt->rt_llinfo;
+	register struct sockaddr_dl *sdl;
+	static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
+
+	if (!ndp6_init_done) {
+		ndp6_init_done = 1;
+		/*
+		 * We generate expiration times from time_second
+		 * so avoid accidently creating permanent routes.
+		 */
+		if (time_second == 0) {
+			time_second++;
+		}
+	}
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_NDP1)
+		printf("ndp6_rtrequest(%d,%p,%p)\n", req, rt, sa);
+#endif
+	if (rt->rt_flags & RTF_GATEWAY)
+		return;
+	switch (req) {
+
+	case RTM_ADD:
+		if (rt->rt_mtu == 0)
+			rt->rt_mtu = rt->rt_ifp->if_mtu;
+		if ((rt->rt_flags & RTF_CLONING) &&
+		    (rt->rt_flags & RTF_HOST) &&
+		    (rt->rt_ifa->ifa_flags & RTF_HOST)) {
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_NDP0)
+				printf("ndp6_rtrequest: uncloning\n");
+#endif
+			rt->rt_flags &= ~RTF_CLONING;
+			rt_setgate(rt, rt_key(rt),
+					(struct sockaddr *)&null_sdl);
+			gate = rt->rt_gateway;
+		}
+		if (rt->rt_flags & RTF_CLONING) {
+			/*
+			 * Case 1:
+			 *  This route should come from a route to iface.
+			 */
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_NDP0)
+				printf("ndp6_rtrequest: cloning\n");
+#endif
+			rt_setgate(rt, rt_key(rt),
+					(struct sockaddr *)&null_sdl);
+			gate = rt->rt_gateway;
+			sdl = satosdl(gate);
+			sdl->sdl_type = rt->rt_ifp->if_type;
+			sdl->sdl_index = rt->rt_ifp->if_index;
+			rt->rt_expire = time_second;
+			break;
+		}
+#if (MULTI_HOMED > 0)
+		if (IFND6_IS_LLINK(rt->rt_ifp)) {
+			register struct ifnet *ifp;
+			register struct in6_ifaddr *ia = 0;
+
+			sdl = satosdl(gate);
+			if (sdl->sdl_family != AF_LINK ||
+			    sdl->sdl_len < sizeof(*sdl) ||
+			    sdl->sdl_index == 0 ||
+			    sdl->sdl_index == rt->rt_ifp->if_index) {
+				log(LOG_ERR,
+				    "llink_rtrequest: illegal route add\n");
+				return;
+			}
+			for (ifp = ifnet;
+			     ifp != 0 && ifp->if_index != sdl->sdl_index;
+			     ifp = ifp->if_next)
+				continue;
+			if (ifp)
+				IFP_TO_IA6(ifp, ia);
+			if (ifp == 0 ||
+			    ia == 0 ||
+			    ia->ia_ifa.ifa_rtrequest != ndp6_rtrequest) {
+				log(LOG_ERR,
+				    "llink_rtrequest: can't find interface\n");
+				return;
+			}
+			rt->rt_ifp = ifp;
+			rt->rt_mtu = ifp->if_mtu;
+		}
+#endif
+		/*FALLTHROUGH*/
+	case RTM_RESOLVE:
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_NDP0)
+			 printf("ndp6_rtrequest: resolve\n");
+#endif
+		if (gate->sa_family != AF_LINK ||
+		    gate->sa_len < sizeof(null_sdl)) {
+			if (req == RTM_RESOLVE)
+				log(LOG_DEBUG,
+				    "ndp6_rtrequest: bad gateway value\n");
+			break;
+		}
+		sdl = satosdl(gate);
+		sdl->sdl_type = rt->rt_ifp->if_type;
+		sdl->sdl_index = rt->rt_ifp->if_index;
+		if (ln != 0)
+			break; /* This happens on a route change */
+		/*
+		 * Case 2:  This route may come from cloning, or a manual route
+		 * add with a LL address.
+		 */
+		R_Malloc(ln, struct llinfo_ndp6 *, sizeof(*ln));
+		rt->rt_llinfo = (caddr_t)ln;
+		if (ln == 0) {
+			log(LOG_DEBUG, "ndp6_rtrequest: malloc failed\n");
+			break;
+		}
+		ndp_inuse++, ndp_allocated++;
+		Bzero(ln, sizeof(*ln));
+		ln->ln_rt = rt;
+		if (req == RTM_ADD && sdl->sdl_alen == ETHER_ADDR_LEN)
+			ln->ln_state = LLNDP6_REACHABLE;
+		rt->rt_flags |= RTF_LLINFO | RTF_DYNAMIC;
+		/* do someting for multicast ? */
+		if (SAME_SOCKADDR(satosin6(rt_key(rt)), IA_SIN6(rt->rt_ifa))) {
+		    /*
+		     * This test used to be
+		     *	if (loif->if_flags & IFF_UP)
+		     * It allowed local traffic to be forced
+		     * through the hardware by configuring the loopback down.
+		     * However, it causes problems during network configuration
+		     * for boards that can't receive packets they send.
+		     * It is now necessary to clear "useloopback" and remove
+		     * the route to force traffic out to the hardware.
+		     */
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_NDP0)
+				printf("ndp6_rtrequest: local hack\n");
+#endif
+#if (MULTI_HOMED > 0)
+			if (IFND6_IS_LLINK(rt->rt_ifp)) {
+				sdl->sdl_alen = ETHER_ADDR_LEN;
+				useloopback = 1;
+			} else
+#endif
+			if (rt->rt_ifp->if_ndtype & IFND6_ADDRES)
+				Bcopy(GETL2ADDR(rt->rt_ifp),
+				      LLADDR(sdl),
+				      sdl->sdl_alen = rt->rt_ifp->if_addrlen);
+			ln->ln_state = LLNDP6_BUILTIN;
+#if (MULTI_HOMED > 0)
+			rt->rt_expire = 0;
+#else
+			rt->rt_expire = time_second + ndpt_reachable;
+#endif
+			if (useloopback) {
+				rt->rt_flags |= RTF_LOCAL;
+				rt->rt_mtu = loif->if_mtu;
+			}
+		}
+		break;
+
+	case RTM_DELETE:
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_NDP0)
+			printf("ndp6_rtrequest: delete\n");
+#endif
+		if (ln == 0)
+			break;
+		ndp_inuse--;
+		rt->rt_llinfo = 0;
+		rt->rt_flags &= ~(RTF_LLINFO | RTF_DYNAMIC);
+		if (ln->ln_hold)
+			m_freem(ln->ln_hold);
+		Free((caddr_t)ln);
+		break;
+
+	case RTM_EXPIRE:
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_NDP0)
+			printf("ndp6_rtrequest: expire\n");
+#endif
+		if (ln == 0) {
+			log(LOG_ERR, "IPv6 route expire without llinfo!\n");
+			return;
+		}
+		sdl = satosdl(gate);
+#ifdef DIAGNOSTIC
+		if (sdl == 0 || sdl->sdl_family != AF_LINK) {
+			log(LOG_ERR, "IPv6 route expire with bad gateway\n");
+			return;
+		}
+#endif
+
+		/* Neighbor Unreachable Discovery */
+		if (rt->rt_expire + ndpt_keep <= time_second &&
+		    ln->ln_state != LLNDP6_PHASEDOUT)
+			if (rt->rt_refcnt > 0) {
+				ln->ln_state = LLNDP6_PHASEDOUT;
+				ln->ln_asked = 0;
+				rt->rt_flags &= ~RTF_REJECT;
+				sdl->sdl_alen = 0;
+				return;
+			} else {
+				rtrequest(RTM_DELETE, rt_key(rt), 0,
+					  rt_mask(rt), 0, 0);
+				return;
+			}
+
+		switch (ln->ln_state) {
+		    case LLNDP6_PHASEDOUT:
+			if (rt->rt_refcnt > 0)
+				return;
+			rtrequest(RTM_DELETE, rt_key(rt), 0,
+				  rt_mask(rt), 0, 0);
+			return;
+
+		    case LLNDP6_INCOMPLETE:
+			if (rt->rt_flags & RTF_REJECT) {
+				/* holddown finished */
+				rt->rt_flags &= ~RTF_REJECT;
+				ln->ln_state = LLNDP6_PHASEDOUT;
+				return;
+			}
+			if (ln->ln_asked < ndp_mmaxtries) {
+				/* resend a NS */
+#if (MULTI_HOMED > 0)
+				if (IFND6_IS_LLINK(rt->rt_ifp)) {
+					llink_resolve(NULL, rt_key(rt), rt);
+					return;
+				}
+#endif
+				ln->ln_asked++;
+				rt->rt_expire = time_second + ndpt_retrans;
+				ndsol6_output(rt->rt_ifp,
+				      ln->ln_hold, NULL,
+				      &satosin6(rt_key(rt))->sin6_addr);
+				return;
+			}
+			/* enter hold down from incomplete */
+		    down:
+			if (ln->ln_flags) {
+				sdl->sdl_alen = 0;
+				ndp6_rtlost(rt, 1);
+			}
+			ln->ln_state = LLNDP6_INCOMPLETE;
+			rt->rt_expire = time_second + ndpt_down;
+			rt->rt_flags |= RTF_REJECT;
+			ln->ln_asked = 0;
+			sdl->sdl_alen = 0;
+			if (ln->ln_hold &&
+			    (ln->ln_hold->m_len >= sizeof(struct ipv6))) {
+				NTOHS(mtod(ln->ln_hold, struct ipv6 *)->ip6_len);
+				icmp6_error(ln->ln_hold,
+					    ICMP6_UNREACH,
+					    ICMP6_UNREACH_ADDRESS,
+					    NULL);
+			} else if (ln->ln_hold)
+				m_freem(ln->ln_hold);
+			ln->ln_hold = 0;
+			return;
+
+		    case LLNDP6_PROBING:
+			if (ln->ln_asked < ndp_umaxtries) {
+				ln->ln_asked++;
+				rt->rt_expire = time_second + ndpt_retrans;
+				ndsol6_output(rt->rt_ifp,
+				      ln->ln_hold,
+				      &satosin6(rt_key(rt))->sin6_addr,
+				      &satosin6(rt_key(rt))->sin6_addr);
+				return;
+			}
+			/* enter hold down from probe */
+			goto down;
+		}
+	}
+}
+
+/*
+ * Resolve an IPv6 address into an ethernet address.  If success,
+ * desten is filled in.  If there is no entry in the ndp table,
+ * set one up and send a GS for the IPv6 address.
+ * Hold onto this mbuf and resend it once the address
+ * is finally resolved.  A return value of 1 indicates
+ * that desten has been filled in and the packet should be sent
+ * normally; a 0 return indicates that the packet has been
+ * taken over here, either now or for later transmission.
+ */
+int
+ndp6_resolve(ifp, rt, m, dst, desten)
+	register struct ifnet *ifp;
+	register struct rtentry *rt;
+	struct mbuf *m;
+	register struct sockaddr *dst;
+	register u_char *desten;
+{
+	register struct llinfo_ndp6 *ln;
+	struct sockaddr_dl *sdl = satosdl(0);
+	struct in6_ifaddr *ia;
+	static int baddriver = 0;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_NDP1)
+		printf("ndp6_resolve(%p,%p,%p,%s,...)\n", ifp, rt, m,
+		       ip6_sprintf(&(satosin6(dst))->sin6_addr));
+#endif
+	if (m->m_flags & M_MCAST) {	/* multicast */
+		ETHER_MAP_IP6_MULTICAST(&satosin6(dst)->sin6_addr, desten);
+		return (1);
+	}
+	IFP_TO_IA6(ifp, ia);
+	if (ia == NULL) {
+		printf("ndp6_resolve on an interface without IPv6\n");
+		m_freem(m);
+		return (0);
+	}
+	if (ia->ia_flags & IFA_BOOTING) {
+		log(LOG_DEBUG, "ndp6_resolve on booting interface\n");
+		m_freem(m);
+		return (0);
+	}
+	if (rt)
+		ln = (struct llinfo_ndp6 *)rt->rt_llinfo;
+	else {
+		if ((ln = ndplookup(&satosin6(dst)->sin6_addr, 1)) != 0)
+			rt = ln->ln_rt;
+	}
+	if (ln == 0 || rt == 0) {
+		log(LOG_DEBUG,
+		    "ndp6_resolve: can't allocate llinfo for %s\n",
+		    ip6_sprintf(&(satosin6(dst))->sin6_addr));
+		if (((ia->ia_flags & RTF_CLONING) == 0) &&
+		    (ia->ia_ifp->if_type == IFT_ETHER) &&
+		    ((baddriver++ & 127) == 0))
+			log(LOG_ERR,
+			    "the driver for %s don't call ndp6_ifinit\n",
+			    ia->ia_ifp->if_name);
+		m_freem(m);
+		return (0);
+	}
+	sdl = satosdl(rt->rt_gateway);
+#ifdef DIAGNOSTIC
+	if (sdl == 0 || sdl->sdl_family != AF_LINK) {
+		log(LOG_ERR, "ndp6_resolve: bad gateway\n");
+		m_freem(m);
+		return (0);
+	}
+#endif
+	/*
+	 * If the state is not PROBING nor REACHABLE try to resolve.
+	 */
+	if (ln->ln_state >= LLNDP6_PROBING) {
+		bcopy(LLADDR(sdl), desten, ETHER_ADDR_LEN);
+
+		/* test if PROBING state must be entered */
+		if (ln->ln_state == LLNDP6_REACHABLE &&
+		    rt->rt_expire &&
+		    rt->rt_expire <= time_second &&
+		    (m->m_flags & M_NOPROBE) == 0) {
+			ln->ln_state = LLNDP6_PROBING;
+			rt->rt_expire = time_second + ndpt_probe;
+		}
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_NDP1)
+			printf("ndp6_resolve -> %6D (state = %d)\n",
+			       (u_char *)LLADDR(sdl), ":", ln->ln_state);
+#endif
+		return (1);
+	}
+	/*
+	 * There is an ndp entry, but no ethernet address
+	 * response yet.  Replace the held mbuf with this
+	 * latest one.
+	 */
+	ln->ln_state = LLNDP6_INCOMPLETE;
+	if (ln->ln_hold)
+		m_freem(ln->ln_hold);
+	m->m_pkthdr.rcvif = ifp;
+	ln->ln_hold = m;
+	sdl->sdl_alen = 0;
+#ifdef	DIAGNOSTIC
+	if (rt->rt_expire == 0) {
+		/* This should never happen. (Should it? -gwr) */
+		printf("ndp6_resolve: unresolved and rt_expire == 0\n");
+		/* Set expiration time to now (expired). */
+		rt->rt_expire = time_second;
+	}
+#endif
+	/*
+	 * Re-send the Neighbor Solicitation when appropriate.
+	 */
+	if (rt->rt_expire <= time_second && ln->ln_asked < ndp_mmaxtries) {
+		ln->ln_asked++;
+		rt->rt_expire = time_second + ndpt_retrans;
+		ndsol6_output(ifp, m, NULL, &satosin6(dst)->sin6_addr);
+	}
+	return (0);
+}
+
+/*
+ * Send a Neighbor Solicitation packet, asking who has addr on interface.
+ */
+void
+ndsol6_output(ifp, hold, dst, target)
+	register struct ifnet *ifp;
+	register struct mbuf *hold;
+	register struct in6_addr *dst, *target;
+{
+	register struct mbuf *m;
+	register struct ipv6 *ip;
+	register struct icmpv6 *icp;
+	register struct ndx6_lladdr *lp;
+	struct ip_moptions *imo = NULL;
+	int icmplen;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ETHEROUT)
+		printf("ndsol6_output(%p,%s)\n", ifp, ip6_sprintf(target));
+	if ((ifp->if_ndtype & IFND6_LLSET) == 0) {
+		printf("ndsol6_output on interface without local-link address\n");
+		return;
+	}
+#endif
+
+	if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
+		return;
+	m->m_flags |= M_NOPROBE;
+	if ((dst == NULL) || IS_MULTIADDR6(*dst)) {
+		m->m_flags |= M_MCAST;
+		imo = (struct ip_moptions*)malloc(sizeof(*imo),
+						  M_IPMOPTS, M_NOWAIT);
+		if (imo == NULL) {
+			m_free(m);
+			return;
+		}
+		imo->imo_multicast_ifp = ifp;
+		imo->imo_multicast_ttl = ICMP6_ND_HOPS;
+		imo->imo_multicast_loop = 0;
+	}
+	icmplen = ICMP6_NSLEN;
+	if (imo && (ifp->if_ndtype & IFND6_ADDRES))
+		icmplen += sizeof(*lp);
+	m->m_len = sizeof(*ip) + icmplen;
+	if (m->m_len > MHLEN)
+		panic("ndsol6_output too big");
+	m->m_pkthdr.len = m->m_len;
+	MH_ALIGN(m, m->m_len);
+	bzero(mtod(m, caddr_t), m->m_len);
+
+	/* fill Neighbor Solicitation packet */
+	ip = mtod(m, struct ipv6 *);
+	icp = (struct icmpv6 *)(ip + 1);
+	if (imo && (ifp->if_ndtype & IFND6_ADDRES)) {
+		lp = (struct ndx6_lladdr *)((caddr_t)icp + ICMP6_NSLEN);
+		lp->lla_ext = NDX6_LLADDR_SRC;
+		lp->lla_len = sizeof(*lp) >> 3;
+		bcopy(GETL2ADDR(ifp), lp->lla_addr, ifp->if_addrlen);
+	}
+	COPY_ADDR6(*target, icp->icmp6_tgt);
+	icp->icmp6_type = ICMP6_SOLICITATION_ND;
+	ip->ip6_head = IPV6_VERSION | ICMP6_ND_PRIORITY;
+	ip->ip6_len = icmplen;
+	ip->ip6_nh = IPPROTO_ICMPV6;
+	ip->ip6_hlim = ICMP6_ND_HOPS;
+	if (hold) {
+		struct ipv6 *hip;
+		struct ifnet *ifp2;
+
+		if (hold->m_len >= (int)&(((struct ipv6 *)0)->ip6_dst))
+			hip = mtod(hold, struct ipv6 *);
+		else
+			goto nosource;
+		IN6ADDR_TO_IFP(hip->ip6_src, ifp2);
+		if ((ifp2 == NULL) || (ifp2 != ifp))
+			goto nosource;
+		COPY_ADDR6(hip->ip6_src, ip->ip6_src);
+	} else {
+	    nosource:
+		if (ifp->if_ndtype & IFND6_LLSET) {
+			COPY_ADDR6(*GETLLADDR(ifp), ip->ip6_src);
+		} else {
+			struct in6_ifaddr *ia;
+
+			IFP_TO_IA6(ifp, ia);
+			if (ia == NULL) {
+				(void) m_free(m);
+				if (imo != NULL)
+					free(imo, M_IPMOPTS);
+				log(LOG_ERR,
+				    "ndsol6_output: interface (%p) without IPv6?!\n",
+				    ifp);
+				return;
+			}
+			COPY_ADDR6(ia->ia_addr.sin6_addr, ip->ip6_src);
+		}
+	}
+	if (dst) {
+		COPY_ADDR6(*dst, ip->ip6_dst);
+	} else {
+		ip->ip6_dst.s6_addr32[0] = htonl(0xff020000);
+		ip->ip6_dst.s6_addr32[1] = 0;
+		ip->ip6_dst.s6_addr32[2] = htonl(1);
+		ip->ip6_dst.s6_addr32[3] = target->s6_addr32[3];
+#if IPV6_TOKEN_LENGTH == 64
+		ip->ip6_dst.s6_addr8[12] = 0xff;
+#endif
+	}
+
+	/* send */
+	icmp6_send(m, NULL, imo);
+	if (imo != NULL)
+		free(imo, M_IPMOPTS);
+	icmp6stat.icp6s_snd_ndsol++;
+}
+
+/*
+ * Send a Neighbor Advertisement packet.
+ */
+void
+ndadv6_output(ifp, dst, target, flags)
+	register struct ifnet *ifp;
+	register struct in6_addr *dst, *target;
+	int flags;
+{
+	register struct mbuf *m;
+	register struct ipv6 *ip;
+	register struct icmpv6 *icp;
+	register struct ndx6_lladdr *lp;
+	struct ip_moptions *imo = NULL;
+	int icmplen, needlla = sizeof(*lp);
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ETHEROUT)
+		printf("ndadv6_output(%p,%s,%s,%x)\n", ifp,
+		       ip6_sprintf(dst), ip6_sprintf(target), flags);
+#endif
+	if ((flags & NO_LLA_ADV) || ((ifp->if_ndtype & IFND6_ADDRES) == 0))
+		needlla = 0;
+#ifdef DIAGNOSTIC
+	else if ((ifp->if_ndtype & IFND6_LLSET) == 0) {
+		printf("ndadv6_output on interface without local-link address\n");
+		return;
+	}
+#endif
+	if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
+		return;
+	m->m_flags |= M_NOPROBE;
+	icmplen = ICMP6_NALEN + needlla;
+	m->m_len = sizeof(*ip) + icmplen;
+	if (m->m_len > MHLEN)
+		panic("ndadv6_output too big");
+	m->m_pkthdr.len = m->m_len;
+	MH_ALIGN(m, m->m_len);
+	bzero(mtod(m, caddr_t), m->m_len);
+	if (IS_MULTIADDR6(*dst)) {
+		m->m_flags |= M_MCAST;
+		imo = (struct ip_moptions*)malloc(sizeof(*imo),
+						  M_IPMOPTS, M_NOWAIT);
+		if (imo == NULL) {
+			m_free(m);
+			return;
+		}
+		imo->imo_multicast_ifp = ifp;
+		imo->imo_multicast_ttl = ICMP6_ND_HOPS;
+		imo->imo_multicast_loop = 0;
+	}
+
+	/* fill Neighbor Advertisement packet */
+	ip = mtod(m, struct ipv6 *);
+	icp = (struct icmpv6 *)(ip + 1);
+	if (needlla) {
+		lp = (struct ndx6_lladdr *)((caddr_t)icp + ICMP6_NALEN);
+		lp->lla_ext = NDX6_LLADDR_TGT;
+		lp->lla_len = sizeof(*lp) >> 3;
+		bcopy(GETL2ADDR(ifp), lp->lla_addr, ifp->if_addrlen);
+	}
+	COPY_ADDR6(*target, icp->icmp6_tgt);
+	icp->icmp6_type = ICMP6_ADVERTISEMENT_ND;
+	icp->icmp6_code = 0;
+	icp->icmp6_flags = htonl(flags & MASK_ADV);
+	ip->ip6_head = IPV6_VERSION | ICMP6_ND_PRIORITY;
+	ip->ip6_len = icmplen;
+	ip->ip6_nh = IPPROTO_ICMPV6;
+	ip->ip6_hlim = ICMP6_ND_HOPS;
+	if (needlla && (ifp->if_ndtype & IFND6_LLSET)) {
+		COPY_ADDR6(*GETLLADDR(ifp), ip->ip6_src);
+	} else {
+		struct in6_ifaddr *ia;
+
+		IFP_TO_IA6(ifp, ia);
+		if (ia == NULL) {
+			(void) m_free(m);
+			if (imo != NULL)
+				free(imo, M_IPMOPTS);
+			log(LOG_ERR,
+			    "ndadv6_output: interface (%p) without IPv6?!\n",
+			    ifp);
+			return;
+		}
+		COPY_ADDR6(ia->ia_addr.sin6_addr, ip->ip6_src);
+	}
+	COPY_ADDR6(*dst, ip->ip6_dst);
+
+	/* send */
+	icmp6_send(m, NULL, imo);
+	if (imo != NULL)
+		free(imo, M_IPMOPTS);
+	icmp6stat.icp6s_snd_ndadv++;
+}
+
+/*
+ * Send a Redirect packet.
+ */
+void
+redirect6_output(m0, rt)
+	register struct mbuf *m0;
+	register struct rtentry *rt;
+{
+	register struct mbuf *m;
+	register struct ipv6 *ip0, *ip;
+	register struct icmpv6 *icp;
+	register struct ndx6_lladdr *lp;
+	struct ndx6_any *xp;
+	struct llinfo_ndp6 *ln;
+	struct sockaddr_dl *sdl;
+	struct in6_addr target;
+
+	ip0 = mtod(m0, struct ipv6 *);
+	if (rt->rt_flags & RTF_GATEWAY) {
+		COPY_ADDR6(satosin6(rt->rt_gateway)->sin6_addr, target);
+		if ((rt = rt->rt_gwroute) == NULL)
+			goto bad;
+	} else
+		COPY_ADDR6(ip0->ip6_dst, target);
+	ln = (struct llinfo_ndp6 *)rt->rt_llinfo;
+	sdl = satosdl(rt->rt_gateway);
+	if (ln == NULL || ln->ln_state < LLNDP6_PROBING ||
+	    sdl == NULL || sdl->sdl_family != AF_LINK)
+		goto bad;
+	if ((rt->rt_ifp == NULL) ||
+	    ((rt->rt_ifp->if_ndtype & IFND6_LLSET) == 0))
+		goto bad;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ETHEROUT)
+		printf("redirect6_output(%p,%p,%s,%s,%6D)\n", m0, rt,
+		       ip6_sprintf(&ip0->ip6_src),
+		       ip6_sprintf(&ip0->ip6_dst),
+		       (u_char *)LLADDR(sdl), ":");
+#endif
+	if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) {
+		m_freem(m0);
+		return;
+	}
+	m->m_flags |= M_NOPROBE;
+	m->m_len = sizeof(*ip) + ICMP6_RDLEN + sizeof(*lp) + sizeof(*xp);
+	if (m->m_len > MHLEN)
+		panic("redirect6_output too big");
+	if (m0->m_pkthdr.len + m->m_len > IP6_MMTU)
+		m_adj(m0, IP6_MMTU - (m0->m_pkthdr.len + m->m_len));
+	m->m_pkthdr.len = m->m_len + m0->m_pkthdr.len;
+	m->m_next = m0;
+	MH_ALIGN(m, m->m_len);
+	bzero(mtod(m, caddr_t), m->m_len);
+
+	/* fill Redirect packet */
+	ip = mtod(m, struct ipv6 *);
+	icp = (struct icmpv6 *)(ip + 1);
+	lp = (struct ndx6_lladdr *)((caddr_t)icp + ICMP6_RDLEN);
+	xp = (struct ndx6_any *)((caddr_t)lp + sizeof(*lp));
+	xp->x6any_ext = NDX6_RDRT_HDR;
+	xp->x6any_len = (m0->m_pkthdr.len >> 3) + 1;
+	lp->lla_ext = NDX6_LLADDR_TGT;
+	lp->lla_len = sizeof(*lp) >> 3;
+	bcopy(LLADDR(sdl), (caddr_t)lp->lla_addr, ETHER_ADDR_LEN);
+	COPY_ADDR6(target, icp->icmp6_tgt);
+	COPY_ADDR6(ip0->ip6_dst, icp->icmp6_rdst);
+	icp->icmp6_type = ICMP6_REDIRECT;
+	ip->ip6_head = IPV6_VERSION | ICMP6_ND_PRIORITY;
+	ip->ip6_len = m->m_pkthdr.len - sizeof(*ip);
+	ip->ip6_nh = IPPROTO_ICMPV6;
+	ip->ip6_hlim = ICMP6_ND_HOPS;
+	COPY_ADDR6(*GETLLADDR(rt->rt_ifp), ip->ip6_src);
+	COPY_ADDR6(ip0->ip6_src, ip->ip6_dst);
+
+	/* send */
+	icmp6_send(m, NULL, NULL);
+	icmp6stat.icp6s_snd_redirect++;
+	return;
+
+    bad:
+	m_freem(m0);
+}
+
+/*
+ * Neighbor Discovery for IPv6 protocols on 10 Mbits/s Ethernet.
+ * Algorithm is that given in RFC xxxx.
+ * In addition, a sanity check is performed on the sender
+ * protocol address, to catch impersonators.
+ */
+
+#define NEXT_EXTENSION(name) \
+	if (icmplen == 0) \
+		goto done; \
+retry: \
+/*#ifdef DIAGNOSTIC*/ \
+	if (ip6printfs & D6_ETHERIN) \
+		printf("NEXT_EXTENSION extra=%d needed=%d icmplen=%d\n", \
+		       extra, needed, icmplen); \
+/*#endif*/ \
+	if (icmplen < needed) { \
+		log(LOG_INFO, "%s: truncated\n", name); \
+		if (mcopy) \
+			m_freem(m0); \
+		return (0); \
+	} \
+	\
+	if (m0->m_len >= extra + needed) { \
+		xp = (struct ndx6_any *)(mtod(m0, caddr_t) + extra); \
+	} else { \
+		if (mcopy == 0) { \
+/*#ifdef DIAGNOSTIC*/ \
+			if (ip6printfs & D6_ETHERIN) \
+				printf("NEXT_EXTENSION m_copy\n"); \
+/*#endif*/ \
+			if ((mcopy = m_copy(m0, extra, M_COPYALL)) == 0) { \
+				log(LOG_INFO, "%s: m_copy failed\n", name); \
+				return (0); \
+			} \
+			m0 = mcopy; \
+		} else if (m0->m_len >= extra) { \
+			m0->m_data += extra; \
+			m0->m_len -= extra; \
+		} else \
+			m_adj(m0, extra); \
+		if (m0->m_len < needed && (m0 = m_pullup(m0, needed)) == 0) { \
+			log(LOG_INFO, "%s: m_pullup failed\n", name); \
+			return (0); \
+		} \
+		extra = 0; \
+		xp = mtod(m0, struct ndx6_any *); \
+	}
+
+#define GETEXT(type)	\
+	if (needed < sizeof(type)) { \
+		needed = sizeof(type); \
+		goto retry; \
+	}
+
+#define LLA(p)	((struct ndx6_lladdr *)p)
+#define MTU(p)	((struct ndx6_mtu *)p)
+#define PREF(p)	((struct ndx6_pref *)p)
+
+#define GETEXTLLADDR(name)	\
+	if (haslladdr) { \
+		log(LOG_INFO, "%s: duplicate LLaddr\n", name); \
+		goto next; \
+	} \
+	haslladdr = 1; \
+	if ((LLA(xp)->lla_len << 3) < sizeof(struct ndx6_lladdr)) { \
+		log(LOG_INFO, "%s: bad LLaddr option\n", name); \
+		if (mcopy) \
+			m_freem(m0); \
+		return (0); \
+	} \
+	bcopy((caddr_t)LLA(xp)->lla_addr, lladdr, ETHER_ADDR_LEN); \
+	goto next;
+
+#define GETEXTMTU(name)	\
+	if (mtu) { \
+		log(LOG_INFO, "%s: duplicate MTU\n", name); \
+		goto next; \
+	} \
+	if ((MTU(xp)->mtu_len << 3) < sizeof(struct ndx6_mtu)) { \
+		log(LOG_INFO, "%s: bad MTU option\n", name); \
+		if (mcopy) \
+			m_freem(m0); \
+		return (0); \
+	} \
+	mtu = ntohl(MTU(xp)->mtu_mtu); \
+	if ((mtu > ifp->if_mtu) || (mtu < IP6_MMTU)) { \
+		log(LOG_INFO, "%s: ignore bad MTU %d\n", name, mtu); \
+		mtu = 0; \
+	} \
+	goto next;
+
+#define GETNEXTEXT(name)	\
+	if (xp->x6any_len == 0) { \
+		log(LOG_INFO, "%s: 0 length extension!\n", name); \
+		if (mcopy) \
+			m_freem(m0); \
+		return (0); \
+	} \
+	extra += xp->x6any_len << 3; \
+	icmplen -= xp->x6any_len << 3; \
+	if (icmplen != 0) \
+		goto retry;
+
+#define LLSRCOVERWRITE(name)	\
+	if ((ln->ln_state >= LLNDP6_PROBING) && \
+	    bcmp(lladdr, LLADDR(sdl), ETHER_ADDR_LEN)) { \
+		log(LOG_INFO, \
+		    "%s source overwrite for %s/%6D\n", \
+		    name, ip6_sprintf(&srcaddr), lladdr, ":"); \
+		ln->ln_state = LLNDP6_INCOMPLETE; \
+	} \
+	bcopy(lladdr, LLADDR(sdl), sdl->sdl_alen = ETHER_ADDR_LEN);
+
+
+#define UPDATEMHIFA(name)	\
+	if (rt->rt_ifp != ifp) { \
+		struct in6_ifaddr *ia; \
+		\
+		if (!IFND6_IS_LLINK(rt->rt_ifp)) \
+			log(LOG_NOTICE, \
+			    "%s: router for %s ifp#%d->%d\n", \
+			    name, \
+			    ip6_sprintf(&srcaddr), \
+			    rt->rt_ifp->if_index, \
+			    ifp->if_index); \
+		rt->rt_ifp = ifp; \
+		rt->rt_mtu = ifp->if_mtu; \
+		sdl->sdl_type = ifp->if_type; \
+		sdl->sdl_index = ifp->if_index; \
+		for (ia = in6_ifaddr.tqh_first; ia; \
+		     ia = ia->ia_list.tqe_next) \
+			if ((ia->ia_ifp == ifp) && \
+			    SAME_ADDR6(dstaddr, ia->ia_addr.sin6_addr)) \
+				break; \
+		if (ia == (struct in6_ifaddr *)0) \
+			IFP_TO_IA6(rt->rt_ifp, ia); \
+		if (ia) { \
+			IFAFREE(rt->rt_ifa); \
+			rt->rt_ifa = &ia->ia_ifa; \
+			rt->rt_ifa->ifa_refcnt++; \
+		} else \
+			log(LOG_ERR, "%s without ifa?\n", name); \
+	}
+
+#define ENTERSTALE()	\
+	ln->ln_state = LLNDP6_REACHABLE; \
+	rt->rt_expire = time_second; \
+	rt->rt_flags &= ~RTF_REJECT; \
+	ln->ln_asked = 0; \
+	if (ln->ln_hold) { \
+		(*ifp->if_output)(ifp, ln->ln_hold, rt_key(rt), rt); \
+		ln->ln_hold = 0; \
+	}
+
+/*
+ * Receive a Neighbor Solicitation packet.
+ */
+int
+ndsol6_input(m0)
+	register struct mbuf *m0;
+{
+	struct ipv6 *ip = mtod(m0, struct ipv6 *);
+	struct icmpv6 *icp = (struct icmpv6 *)(ip + 1);
+	register struct ndx6_any *xp;
+	int icmplen = ip->ip6_len - ICMP6_NSLEN;
+	register struct ifnet *ifp = m0->m_pkthdr.rcvif;
+	register struct llinfo_ndp6 *ln = 0;
+	register struct rtentry *rt;
+	struct mbuf *mcopy = 0;
+	struct in6_ifaddr *ia, *sia = 0, *tia = 0;
+	struct sockaddr_dl *sdl;
+	struct in6_addr srcaddr, dstaddr, tgtaddr;
+	u_char lladdr[ETHER_ADDR_LEN];
+	int extra = sizeof(*ip) + ICMP6_NSLEN;
+	int needed = sizeof(struct ndx6_lladdr);
+	int addrconfsol = 0, haslladdr = 0;
+
+	COPY_ADDR6(ip->ip6_src, srcaddr);
+	COPY_ADDR6(ip->ip6_dst, dstaddr);
+	COPY_ADDR6(icp->icmp6_tgt, tgtaddr);
+
+#ifdef DIAGNOSTIC
+	bzero(lladdr, ETHER_ADDR_LEN);
+	if (ip6printfs & D6_ETHERIN)
+		printf("ndsol6_input from %s\n", ip6_sprintf(&srcaddr));
+	if (IS_MULTIADDR6(dstaddr) &&
+	    MADDR6_SCOPE(dstaddr) != MADDR6_SCP_LINK) {
+		log(LOG_INFO,
+		    "ndsol6_input to illegal mcast %s\n",
+		    ip6_sprintf(&dstaddr));
+
+	}
+#endif
+	if (icp->icmp6_code != 0) {
+		log(LOG_INFO, "ndsol6_input code(%d) != 0\n", icp->icmp6_code);
+		return (0);
+	}
+	if (IS_MULTIADDR6(tgtaddr)) {
+		log(LOG_INFO, "ndsol6_input for mcast %s!\n",
+		    ip6_sprintf(&tgtaddr));
+		return (0);
+	}
+	if (IS_ANYADDR6(srcaddr))
+		addrconfsol = 1;
+
+NEXT_EXTENSION("ndsol6_input")
+
+	switch (xp->x6any_ext) {
+
+	case NDX6_LLADDR_SRC:
+		GETEXTLLADDR("ndsol6_input");
+
+	default:
+	next:
+		GETNEXTEXT("ndsol6_input");
+	}
+	if (mcopy)
+		m_freem(m0);
+    done:
+	if ((haslladdr == 0) &&
+	    (addrconfsol == 0) &&
+	    IS_MULTIADDR6(dstaddr)) {
+		log(LOG_INFO, "ndsol6_input: no needed LLaddr?\n");
+		return (0);
+	}
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ETHERIN) {
+		printf("ndsol6_input target=%s", ip6_sprintf(&tgtaddr));
+		if (haslladdr)
+			printf(" lladdr=%6D\n", lladdr, ":");
+		else
+			printf("\n");
+	}
+#endif
+	for (ia = in6_ifaddrhead.tqh_first; ia; ia = ia->ia_list.tqe_next)
+		if (ia->ia_ifp == ifp) {
+		/* multi-homed model/llip6 ??? */
+			if (SAME_ADDR6(srcaddr, ia->ia_addr.sin6_addr))
+				sia = ia;
+			if (SAME_ADDR6(tgtaddr, ia->ia_addr.sin6_addr))
+				tia = ia;
+		}			
+
+	if ((sia == 0) && (tia == 0)) {
+		/* not impossible: anycasts, proxies, ... */
+		return (1);
+	}
+	if (sia && !addrconfsol) {
+		if (haslladdr == 0)
+			return (1);
+		if (bcmp(lladdr, GETL2ADDR(ifp), ifp->if_addrlen) == 0)
+			return (1);	/* it should be from me, ignore it. */
+		log(LOG_ERR,
+		    "ndp6: %6D is using my IPv6 address %s!\n",
+		    lladdr, ":", ip6_sprintf(&srcaddr));
+		return (1);
+	}
+	if (addrconfsol) {
+		if (tia && (tia->ia_flags & IFA_BOOTING))
+			return (1);
+		/* should not happen ? */
+		if (ip6forwarding && in6_isanycast(&tgtaddr))
+			return (1);
+		log(LOG_ERR, 
+		    "duplicate IPv6 address %s!!\n",
+		    ip6_sprintf(&tgtaddr));
+		ndadv6_output(ifp, &allnodes6_group, &tgtaddr,
+			      ip6forwarding ? ROUTER_ADV : 0);
+		return (1);
+	}
+	if (haslladdr == 0)
+		goto adv;
+	/*
+	 * add an entry for the source in ndp table.
+	 */
+	ln = ndplookup(&srcaddr, 1);
+	if (ln && (rt = ln->ln_rt) && (sdl = satosdl(rt->rt_gateway))) {
+		LLSRCOVERWRITE("ndsol6_input");
+		if (ln->ln_state >= LLNDP6_PROBING)
+			goto adv;
+#if (MULTI_HOMED > 0)
+		if (rt->rt_ifp != ifp) {
+			if (!IFND6_IS_LLINK(rt->rt_ifp))
+				log(LOG_NOTICE,
+				    "ndsol6_input: router for %s ifp#%d->%d\n",
+				    ip6_sprintf(&srcaddr),
+				    rt->rt_ifp->if_index,
+				    ifp->if_index);
+			rt->rt_ifp = ifp;
+			rt->rt_mtu = ifp->if_mtu;
+			sdl->sdl_type = ifp->if_type;
+			sdl->sdl_index = ifp->if_index;
+			if (tia) {
+				IFAFREE(rt->rt_ifa);
+				rt->rt_ifa = &tia->ia_ifa;
+				rt->rt_ifa->ifa_refcnt++;
+			} else
+				log(LOG_ERR, "ndsol6_input without ifa?\n");
+		}
+#endif
+		ENTERSTALE();
+	}
+
+    adv:
+	if (tia && (tia->ia_flags & IFA_BOOTING))
+		return (1);
+	/* anycast advertisements are done by an user process after a delay */
+	if (ip6forwarding && in6_isanycast(&tgtaddr))
+		return (1);
+	ndadv6_output(ifp, &srcaddr, &tgtaddr,
+		      (ip6forwarding ? ROUTER_ADV : 0) |
+		      SOLICITED_ADV | OVERRIDE_ADV);
+	return (1);
+}
+
+/*
+ * Receive a Neighbor Advertisement packet.
+ */
+int
+ndadv6_input(m0)
+	register struct mbuf *m0;
+{
+	struct ipv6 *ip = mtod(m0, struct ipv6 *);
+	struct icmpv6 *icp = (struct icmpv6 *)(ip + 1);
+	register struct ndx6_any *xp;
+	int icmplen = ip->ip6_len - ICMP6_NALEN;
+	register struct ifnet *ifp = m0->m_pkthdr.rcvif;
+	register struct llinfo_ndp6 *ln = 0;
+	register struct rtentry *rt;
+	struct mbuf *mcopy = 0;
+	struct in6_ifaddr *ia, *maybe_ia = 0;
+	struct sockaddr_dl *sdl;
+	struct in6_addr srcaddr, dstaddr, tgtaddr;
+	u_char lladdr[ETHER_ADDR_LEN];
+	int extra = sizeof(*ip) + ICMP6_NALEN;
+	int needed = sizeof(struct ndx6_lladdr);
+	int is_router, is_solicited, is_secondary, haslladdr = 0;
+
+	is_router = (ntohl(icp->icmp6_flags) & ROUTER_ADV) != 0;
+	is_solicited = (ntohl(icp->icmp6_flags) & SOLICITED_ADV) != 0;
+	is_secondary = (ntohl(icp->icmp6_flags) & OVERRIDE_ADV) == 0;
+	COPY_ADDR6(ip->ip6_src, srcaddr);
+	COPY_ADDR6(ip->ip6_dst, dstaddr);
+	COPY_ADDR6(icp->icmp6_tgt, tgtaddr);
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ETHERIN)
+		printf("ndadv6_input %s%s%s from %s to %s for %s\n",
+		       is_router ? "R" : "",
+		       is_solicited ? "S" : "",
+		       is_secondary ? "" : "O",
+		       ip6_sprintf(&srcaddr),
+		       ip6_sprintf(&dstaddr),
+		       ip6_sprintf(&tgtaddr));
+#endif
+	if (icp->icmp6_code != 0) {
+		log(LOG_INFO, "ndadv6_input code(%d) != 0\n", icp->icmp6_code);
+		return (0);
+	}
+	if (IS_MULTIADDR6(dstaddr)) {
+		if (MADDR6_SCOPE(dstaddr) != MADDR6_SCP_LINK) {
+			log(LOG_INFO, "ndadv6_input to illegal mcast\n");
+		}
+		if (is_solicited) {
+			log(LOG_INFO, "ndadv6_input mcast solicited\n");
+			return (0);
+		}
+	}
+	if (IS_MULTIADDR6(tgtaddr)) {
+		log(LOG_INFO, "ndadv6_input for mcast\n");
+		return (0);
+	}
+NEXT_EXTENSION("ndadv6_input")
+
+	switch (xp->x6any_ext) {
+
+	case NDX6_LLADDR_TGT:
+		GETEXTLLADDR("ndadv6_input");
+
+	default:
+	next:
+		GETNEXTEXT("ndadv6_input");
+	}
+	if (mcopy)
+		m_freem(m0);
+#ifdef DIAGNOSTIC
+	if (haslladdr && (ip6printfs & D6_ETHERIN))
+		printf("ndadv6_input lladdr=%6D\n", lladdr, ":");
+#endif
+    done:
+
+	for (ia = in6_ifaddrhead.tqh_first; ia; ia = ia->ia_list.tqe_next)
+		if (ia->ia_ifp == ifp) {
+			/* multi-homed model ??? */
+			if (maybe_ia == 0)
+				maybe_ia = ia;
+			if (SAME_ADDR6(tgtaddr, ia->ia_addr.sin6_addr))
+				break;
+		}
+	if (maybe_ia == 0)
+		return (0);
+	if (ia && haslladdr) {
+		if (!bcmp(lladdr, GETL2ADDR(ifp), ifp->if_addrlen))
+			return (1);	/* it should be from me, ignore it. */
+		log(LOG_ERR,
+		    "ndp6: %6D is using my IPv6 address %s!\n",
+		    lladdr, ":", ip6_sprintf(&srcaddr));
+		return (1);
+	}
+	ln = ndplookup(&tgtaddr, 0);
+	if ((ln == NULL) ||
+	    ((rt = ln->ln_rt) == NULL) ||
+	    ((sdl = satosdl(rt->rt_gateway)) == NULL))
+		return (1);
+
+	/* got an entry */
+	if ((ln->ln_state >= LLNDP6_PROBING) && haslladdr &&
+	    bcmp(lladdr, LLADDR(sdl), ETHER_ADDR_LEN)) {
+		log(LOG_INFO,
+		    "ndp6: %s makes that %s %s move from %6D to %6D\n",
+		    ip6_sprintf(&srcaddr), ip6_sprintf(&tgtaddr),
+		    is_secondary ? "could" : "will",
+		    (u_char *)LLADDR(sdl), ":",
+		    lladdr, ":");
+	}
+	if (haslladdr && (!is_secondary || (ln->ln_state < LLNDP6_PROBING))) {
+		bcopy(lladdr, LLADDR(sdl), sdl->sdl_alen = ETHER_ADDR_LEN);
+#if (MULTI_HOMED > 0)
+		if ((ln->ln_state < LLNDP6_BUILTIN) &&
+		    (rt->rt_ifp != ifp)) {
+			if (!IFND6_IS_LLINK(rt->rt_ifp))
+				log(LOG_NOTICE,
+				    "ndadv6_input: router for %s ifp#%d->%d\n",
+				    ip6_sprintf(&tgtaddr),
+				    rt->rt_ifp->if_index,
+				    ifp->if_index);
+			rt->rt_ifp = ifp;
+			rt->rt_mtu = ifp->if_mtu;
+			sdl->sdl_type = ifp->if_type;
+			sdl->sdl_index = ifp->if_index;
+			IFAFREE(rt->rt_ifa);
+			rt->rt_ifa = &maybe_ia->ia_ifa;
+			rt->rt_ifa->ifa_refcnt++;
+		}
+#endif
+	}
+	if (ln->ln_flags && is_router == 0)
+		ndp6_rtlost(rt, 1);
+	ln->ln_flags = is_router;
+	if ((haslladdr == 0) && (ln->ln_state < LLNDP6_PROBING)) {
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_ETHERIN)
+			printf("ndadv6_input not useful\n");
+#endif
+		return (1);
+	}
+	ln->ln_state = LLNDP6_REACHABLE;
+	if (rt->rt_expire) {
+		rt->rt_expire = time_second;
+		if (is_solicited)
+			rt->rt_expire += ndpt_reachable;
+	}
+	rt->rt_flags &= ~RTF_REJECT;
+	ln->ln_asked = 0;
+	if (ln->ln_hold) {
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_ETHERIN)
+			printf("ndadv6_input send held\n");
+#endif
+		(*ifp->if_output)(ifp, ln->ln_hold, rt_key(rt), rt);
+		ln->ln_hold = 0;
+	}
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_NDP1)
+		printf("ndadv6_input -> %s (state = %d)\n",
+		       ip6_sprintf(&tgtaddr), ln->ln_state);
+#endif
+	return (1);
+}
+
+/*
+ * Receive a Router Solicitation packet.
+ */
+int
+rtsol6_input(m0)
+	register struct mbuf *m0;
+{
+	struct ipv6 *ip = mtod(m0, struct ipv6 *);
+	struct icmpv6 *icp = (struct icmpv6 *)(ip + 1);
+	register struct ndx6_any *xp;
+	int icmplen = ip->ip6_len - ICMP6_RSLEN;
+	register struct ifnet *ifp = m0->m_pkthdr.rcvif;
+	register struct llinfo_ndp6 *ln = 0;
+	register struct rtentry *rt;
+	struct mbuf *mcopy = 0;
+	struct sockaddr_dl *sdl;
+	struct in6_addr srcaddr, dstaddr;
+	u_char lladdr[ETHER_ADDR_LEN];
+	int extra = sizeof(*ip) + ICMP6_RSLEN;
+	int needed = sizeof(struct ndx6_lladdr);
+	int haslladdr = 0;
+
+	COPY_ADDR6(ip->ip6_src, srcaddr);
+	COPY_ADDR6(ip->ip6_dst, dstaddr);
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ETHERIN)
+		printf("rtsol6_input from %s\n", ip6_sprintf(&srcaddr));
+#endif
+#ifdef DIAGNOSTIC
+	if (IS_MULTIADDR6(dstaddr) &&
+	    (MADDR6_SCOPE(dstaddr) != MADDR6_SCP_LINK))
+		log(LOG_INFO, "rtsol6_input to illegal mcast\n");
+#endif
+	if (icp->icmp6_code != 0) {
+		log(LOG_INFO, "rtsol6_input code(%d) != 0\n", icp->icmp6_code);
+		return (0);
+	}
+
+NEXT_EXTENSION("rtsol6_input")
+
+	switch (xp->x6any_ext) {
+
+	case NDX6_LLADDR_SRC:
+		GETEXTLLADDR("rtsol6_input");
+
+	default:
+	next:
+		GETNEXTEXT("rtsol6_input");
+	}
+	if (mcopy)
+		m_freem(m0);
+    done:
+	if (haslladdr == 0)
+		return (1);
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ETHERIN)
+		printf("rtsol6_input lladdr=%6D\n", lladdr, ":");
+#endif
+	if (IS_ANYADDR6(srcaddr))
+		return (1);
+	ln = ndplookup(&srcaddr, 1);
+	if (ln && (rt = ln->ln_rt) && (sdl = satosdl(rt->rt_gateway))) {
+		LLSRCOVERWRITE("rtsol6_input");
+		if (ln->ln_state >= LLNDP6_PROBING)
+			return (1);
+#if (MULTI_HOMED > 0)
+		UPDATEMHIFA("rtsol6_input");
+#endif
+		ENTERSTALE();
+		/* a router should not send router solicitations */
+		if (ln->ln_flags)
+			ndp6_rtlost(rt, 0);
+	}
+	return (1);
+}
+
+/*
+ * Receive a Router Advertisement packet.
+ */
+int
+rtadv6_input(m0)
+	register struct mbuf *m0;
+{
+	struct ipv6 *ip = mtod(m0, struct ipv6 *);
+	struct icmpv6 *icp = (struct icmpv6 *)(ip + 1);
+	register struct ndx6_any *xp;
+	int icmplen = ip->ip6_len - ICMP6_RALEN;
+	register struct ifnet *ifp = m0->m_pkthdr.rcvif;
+	register struct llinfo_ndp6 *ln = 0;
+	register struct rtentry *rt;
+	struct mbuf *mcopy = 0;
+	struct sockaddr_dl *sdl;
+	struct in6_addr srcaddr, dstaddr;
+	u_char lladdr[ETHER_ADDR_LEN];
+	int extra = sizeof(*ip) + ICMP6_RALEN;
+	int needed = sizeof(struct ndx6_lladdr);
+	int haslladdr = 0, mtu = 0;
+
+	COPY_ADDR6(ip->ip6_src, srcaddr);
+	COPY_ADDR6(ip->ip6_dst, dstaddr);
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ETHERIN)
+		printf("rtadv6_input from %s\n", ip6_sprintf(&srcaddr));
+#endif
+	if (icp->icmp6_code != 0) {
+		log(LOG_INFO, "rtadv6_input code(%d) != 0\n", icp->icmp6_code);
+		return (0);
+	}
+	if (!IS_LOCALADDR6(srcaddr)) {
+		log(LOG_INFO,
+		    "rtadv6_input from illegal %s\n",
+		    ip6_sprintf(&srcaddr));
+		return (0);
+	}
+#ifdef DIAGNOSTIC
+	if (IS_MULTIADDR6(dstaddr) &&
+	    (MADDR6_SCOPE(dstaddr) != MADDR6_SCP_LINK))
+			log(LOG_INFO, "rtadv6_input to illegal mcast\n");
+#endif
+
+NEXT_EXTENSION("rtadv6_input")
+
+	switch (xp->x6any_ext) {
+
+	case NDX6_LLADDR_SRC:
+		GETEXTLLADDR("rtadv6_input");
+
+	case NDX6_MTU:
+		GETEXTMTU("rtadv6_input");
+
+	default:
+	next:
+		GETNEXTEXT("rtadv6_input");
+	}
+	if (mcopy)
+		m_freem(m0);
+#ifdef DIAGNOSTIC
+	if (haslladdr && (ip6printfs & D6_ETHERIN))
+		printf("rtadv6_input lladdr=%6D\n", lladdr, ":");
+	if (mtu && (ip6printfs & D6_ETHERIN))
+		printf("rtadv6_input (ignored) mtu=%d\n", mtu);
+#endif
+    done:
+
+	ln = ndplookup(&srcaddr, 1);
+	if (ln && (rt = ln->ln_rt) && (sdl = satosdl(rt->rt_gateway))) {
+		ln->ln_flags = 1;
+		if (ln->ln_state >= LLNDP6_PROBING)
+			return (1);
+#if (MULTI_HOMED > 0)
+		UPDATEMHIFA("rtadv6_input");
+#endif
+		if (haslladdr == 0) {
+			/* this stupid router doesn't give its address */
+			ln->ln_state = LLNDP6_INCOMPLETE;
+			sdl->sdl_alen = 0;
+			rt->rt_expire = time_second;
+			rt->rt_flags &= ~RTF_REJECT;
+			return (1);
+		}
+		LLSRCOVERWRITE("rtadv6_input");
+		ENTERSTALE();
+	}
+	return (1);
+}
+
+/*
+ * Receive a Redirect packet.
+ */
+int
+redirect6_input(m0)
+	register struct mbuf *m0;
+{
+	struct ipv6 *ip = mtod(m0, struct ipv6 *);
+	struct icmpv6 *icp = (struct icmpv6 *)(ip + 1);
+	register struct ndx6_any *xp;
+	int icmplen = ip->ip6_len - ICMP6_RDLEN;
+	register struct ifnet *ifp = m0->m_pkthdr.rcvif;
+	register struct llinfo_ndp6 *ln = 0;
+	register struct rtentry *rt;
+	struct mbuf *mcopy = 0;
+	struct sockaddr_dl *sdl;
+	struct in6_addr srcaddr, dstaddr, tgtaddr;
+	u_char lladdr[ETHER_ADDR_LEN];
+	int extra = sizeof(*ip) + ICMP6_RDLEN;
+	int needed = sizeof(struct ndx6_lladdr);
+	int haslladdr = 0, is_router;
+
+	COPY_ADDR6(ip->ip6_src, srcaddr);
+	COPY_ADDR6(ip->ip6_dst, dstaddr);
+	COPY_ADDR6(icp->icmp6_tgt, tgtaddr);
+	is_router = !SAME_ADDR6(tgtaddr, icp->icmp6_rdst);
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ETHERIN)
+		printf("redirect6_input from %s for %s to %s\n",
+		       ip6_sprintf(&srcaddr),
+		       ip6_sprintf(&icp->icmp6_rdst),
+		       ip6_sprintf(&tgtaddr));
+#endif
+	if (icp->icmp6_code != 0) {
+		log(LOG_INFO,
+		    "redirect6_input code(%d) != 0\n",
+		    icp->icmp6_code);
+		return (0);
+	}
+	if (!IS_LOCALADDR6(srcaddr)) {
+		log(LOG_INFO,
+		    "redirect6_input from illegal %s\n",
+		    ip6_sprintf(&srcaddr));
+		return (0);
+	}
+#ifdef DIAGNOSTIC
+	if (is_router && !IS_LOCALADDR6(tgtaddr)) {
+		log(LOG_INFO,
+		    "redirect6_input for illegal router %s\n",
+		    ip6_sprintf(&tgtaddr));
+		return (0);
+	}
+#endif
+	if (IS_MULTIADDR6(dstaddr))
+		log(LOG_WARNING,
+		    "redirect6_input to multicast %s\n",
+		    ip6_sprintf(&dstaddr));
+	if (IS_MULTIADDR6(tgtaddr)) {
+		log(LOG_INFO, "redirect6_input for illegal mcast\n");
+		return (0);
+	}
+
+NEXT_EXTENSION("redirect6_input")
+
+	switch (xp->x6any_ext) {
+
+	case NDX6_LLADDR_TGT:
+		GETEXTLLADDR("redirect6_input");
+
+	case NDX6_RDRT_HDR:
+		break;
+
+	default:
+	next:
+		GETNEXTEXT("redirect6_input");
+	}
+	if (mcopy)
+		m_freem(m0);
+    done:
+	if (haslladdr == 0)
+		return (1);
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ETHERIN)
+		printf("redirect6_input lladdr=%6D\n", lladdr, ":");
+#endif
+	/* external redirect: create == 2 */
+	ln = ndplookup(&tgtaddr, is_router ? 1 : 2);
+	if (ln && (rt = ln->ln_rt) && (sdl = satosdl(rt->rt_gateway))) {
+		if ((ln->ln_state >= LLNDP6_PROBING) &&
+		    bcmp(lladdr, LLADDR(sdl), ETHER_ADDR_LEN)) {
+			log(LOG_INFO,
+			    "redirect: %s makes %s moved from %6D to %6D\n",
+			    ip6_sprintf(&srcaddr), ip6_sprintf(&tgtaddr),
+			    (u_char *) LLADDR(sdl), ":",
+			    lladdr, ":");
+			ln->ln_state = LLNDP6_INCOMPLETE;
+		}
+		bcopy(lladdr, LLADDR(sdl), sdl->sdl_alen = ETHER_ADDR_LEN);
+		if (ln->ln_state >= LLNDP6_BUILTIN)
+			return (1);
+#if (MULTI_HOMED > 0)
+		if (rt->rt_ifp != ifp) {
+			struct in6_ifaddr *ia;
+
+			if (!IFND6_IS_LLINK(rt->rt_ifp))
+				log(LOG_NOTICE,
+				    "redirect6_input: router for %s ifp#%d->%d\n",
+				    ip6_sprintf(&tgtaddr),
+				    rt->rt_ifp->if_index,
+				    ifp->if_index);
+			rt->rt_ifp = ifp;
+			rt->rt_mtu = ifp->if_mtu;
+			sdl->sdl_type = ifp->if_type;
+			sdl->sdl_index = ifp->if_index;
+			for (ia = in6_ifaddr.tqh_first; ia;
+			     ia = ia->ia_list.tqe_next)
+				if ((ia->ia_ifp == ifp) &&
+				    SAME_ADDR6(dstaddr, ia->ia_addr.sin6_addr))
+					break;
+			if (ia == (struct in6_ifaddr *)0)
+				IFP_TO_IA6(rt->rt_ifp, ia);
+			if (ia) {
+				IFAFREE(rt->rt_ifa);
+				rt->rt_ifa = &ia->ia_ifa;
+				rt->rt_ifa->ifa_refcnt++;
+			} else
+				log(LOG_ERR, "redirect6_input without ifa?\n");
+		}
+#endif
+		ln->ln_flags |= is_router;
+		ENTERSTALE();
+	}
+	return (1);
+}
+
+/*
+ * Neighbor Unreachable Discovery hints from upper layers.
+ */
+void
+ip6_reachhint(inp)
+	register struct inpcb *inp;
+{
+	register struct rtentry *rt;
+	register struct llinfo_ndp6 *ln;
+
+	if (inp == 0 ||
+	    (inp->inp_flags & INP_COMPATV6) == 0 ||
+	    (inp->inp_latype & IPATYPE_IPV6) == 0 ||
+	    (inp->inp_fatype & IPATYPE_IPV6) == 0)
+		return;
+	if ((rt = inp->inp_route.ro_rt) == 0)
+		return;
+	if (rt->rt_flags & RTF_GATEWAY)
+		rt = rt->rt_gwroute;
+	if (rt == 0 ||
+	    rt->rt_flags & RTF_GATEWAY ||
+	    (rt->rt_flags & RTF_DYNAMIC) == 0 ||
+	    (rt->rt_flags & RTF_LLINFO) == 0 ||
+	    rt->rt_expire == 0 ||
+	    rt->rt_ifa->ifa_rtrequest != ndp6_rtrequest ||
+	    !SAME_ADDR6(satosin6(&inp->inp_route.ro_dst)->sin6_addr,
+			inp->inp_faddr6))
+		return;
+	ln = (struct llinfo_ndp6 *)rt->rt_llinfo;
+	if (ln == 0 || ln->ln_state < LLNDP6_PROBING)
+		return;
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_NDP1)
+		printf("ip6_reachhint(%p)\n", rt);
+#endif
+	if (ln->ln_state == LLNDP6_PROBING)
+		ln->ln_state = LLNDP6_REACHABLE;
+	rt->rt_expire = time_second + ndpt_reachable;
+}
+
+/*
+ * Lookup or enter a new address in the ndp table.
+ */
+struct llinfo_ndp6 *
+ndplookup(addr, create)
+	struct in6_addr *addr;
+	int create;
+{
+	register struct rtentry *rt;
+	static struct sockaddr_in6 sin = {sizeof(sin), AF_INET6};
+	const char *why = 0;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_NDP1)
+		printf("ndplookup(%s,%d)\n", ip6_sprintf(addr), create);
+#endif
+	COPY_ADDR6(*addr, sin.sin6_addr);
+	/* TODO: add proxy */
+	rt = rtalloc1(sin6tosa(&sin), create, 0UL);
+	if (rt == 0)
+		return (0);
+	rt->rt_refcnt--;
+	if (rt->rt_flags & RTF_GATEWAY)
+		why = "host is not on local network";
+	else if ((rt->rt_flags & RTF_LLINFO) == 0)
+		why = "could not allocate llinfo";
+	else if (rt->rt_gateway->sa_family != AF_LINK)
+		why = "gateway route is not ours";
+	else if ((rt->rt_ifa == 0) ||
+		 (rt->rt_ifa->ifa_rtrequest == 0) ||
+		 (rt->rt_ifa->ifa_rtrequest != ndp6_rtrequest))
+		why = "host is not on an IEEE network";
+
+	if (why) {
+		if (create > 1) {
+			/* external redirects done by an user process */
+			return (0);
+		} else if (create)
+			log(LOG_DEBUG, "ndplookup %s failed: %s\n",
+			    ip6_sprintf(addr), why);
+		return (0);
+	}
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_NDP1)
+		printf("ndplookup return %p\n", rt->rt_llinfo);
+#endif
+	return ((struct llinfo_ndp6 *)rt->rt_llinfo);
+}
+
+void
+ndp6_ifinit(ifp, ifa)
+	struct ifnet *ifp;
+	struct ifaddr *ifa;
+{
+	register struct sockaddr_in6 *sin = satosin6(ifa->ifa_addr);
+
+	if (IS_LOCALADDR6(sin->sin6_addr)) {
+		ifp->if_ndtype |= IFND6_LLSET;
+		COPY_ADDR6(sin->sin6_addr, *GETLLADDR(ifp));
+	}
+	ifa->ifa_rtrequest = ndp6_rtrequest;
+	ifa->ifa_flags |= RTF_CLONING;
+}
+
+/*
+ * Neighbor Discovery has detected the lost of a router.
+ */
+void
+ndp6_rtlost(rt, dead)
+	struct rtentry *rt;
+	int dead;
+{
+	struct rt_addrinfo info;
+	struct llinfo_ndp6 *ln;
+
+	if (dead) {
+		/* we know the router is dead or no more a router */
+		bzero((caddr_t)&info, sizeof(info));
+		info.rti_info[RTAX_DST] = rt_key(rt);
+		info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
+		rt_missmsg(RTM_RTLOST, &info, 0, 0);
+	} else {
+		/* the router is suspect, force a neighbor solicitation */
+		ln = (struct llinfo_ndp6 *)rt->rt_llinfo;
+		if (ln && ln->ln_state) {
+			ln->ln_state = LLNDP6_PROBING;
+			rt->rt_expire = time_second + ndpt_probe;
+		}
+	}
+}
+#endif /* INET6 */
diff -uN src-current/sys/netinet/if_ndp6.h src-current-ipv6/sys/netinet/if_ndp6.h
--- src-current/sys/netinet/if_ndp6.h
+++ src-current-ipv6/sys/netinet/if_ndp6.h
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ *
+ *	@(#)if_ether.h	8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _NETINET_IF_NDP6_H_
+#define _NETINET_IF_NDP6_H_
+
+/*
+ * Definitions for if_ndtype
+ */
+
+#define IFND6_TYPE	0xff000000	/* type of the interface */
+#define IFND6_FLAGS	0x00ff0000	/* flags */
+#define IFND6_LLOFF	0x0000ff00	/* link-local address offset */
+#define IFND6_L2OFF	0x000000ff	/* link-layer address offset */
+
+#define IFND6_UNKNOWN	0x00000000	/* unknown ND type */
+#define IFND6_LOOP	0x01000000	/* loopback */
+#define IFND6_IEEE	0x02000000	/* IEEE LAN */
+#define IFND6_SIT	0x03000000	/* SIT IPv6 over IPv4 */
+#define IFND6_TUG	0x04000000	/* TUG IPv6 over IPv6 */
+#define IFND6_TUN	0x05000000	/* TUN interface/device */
+#define IFND6_PPP	0x06000000	/* PPP serial */
+#define IFND6_ATM	0x07000000	/* ATM */
+#define IFND6_LLINK	0xff000000	/* link-local pseudo interface */
+
+#define IFND6_IS_LLINK(ifp) \
+	(((ifp)->if_ndtype & IFND6_TYPE) == IFND6_LLINK)
+
+#define IFND6_INLL	0x00010000	/* participate to llink */
+#define IFND6_ADDRES	0x00020000	/* use address resolution */
+#define IFND6_MTU	0x00040000	/* fancy MTU values */
+
+#define IFND6_LLSET	0x00100000	/* link-local address is set */
+
+#define GETLLADDR(ifp) \
+	(struct in6_addr *)((char *)(ifp) + sizeof(struct ifnet) + \
+			    (((ifp)->if_ndtype >> 8) & 0xff))
+
+#define GETL2ADDR(ifp) \
+	((char *)(ifp) + sizeof(struct ifnet) + ((ifp)->if_ndtype & 0xff))
+
+#ifdef KERNEL
+/*
+ * IPv6 Neighbor Discovery Protocol.
+ *
+ * See RFC xxxx for protocol description.
+ */
+
+struct llinfo_ndp6 {
+	struct	rtentry *ln_rt;
+	struct	mbuf *ln_hold;		/* last packet until resolved/timeout */
+	long	ln_asked;		/* last time we QUERIED for this addr */
+	short	ln_state;		/* state */
+	short	ln_flags;		/* flags (is_router) */
+/* deletion time in seconds, 0 == locked */
+#define ln_timer ln_rt->rt_rmx.rmx_expire
+};
+#define LLNDP6_PHASEDOUT	0	/* held very old routes */
+#define LLNDP6_INCOMPLETE	1	/* no info yet */
+#define LLNDP6_PROBING		2	/* usable, NUD probes it */
+#define LLNDP6_REACHABLE	3	/* valid */
+#define LLNDP6_BUILTIN		4	/* don't fall into probing */
+
+#define M_NOPROBE		M_BCAST	/* don't trigger NUD probes */
+
+/*
+ * Neighbor Discovery specific interface flag.
+ */
+#define IFA_BOOTING	RTF_XRESOLVE
+
+#ifdef INET6
+
+void	ndsol6_output __P((struct ifnet *,
+		struct mbuf *, struct in6_addr *, struct in6_addr *));
+void	ndadv6_output __P((struct ifnet *,
+		struct in6_addr *, struct in6_addr *, int));
+void	redirect6_output __P((struct mbuf *, struct rtentry *));
+int	ndsol6_input __P((struct mbuf *));
+int	ndadv6_input __P((struct mbuf *));
+int	rtsol6_input __P((struct mbuf *));
+int	rtadv6_input __P((struct mbuf *));
+int	redirect6_input __P((struct mbuf *));
+
+int	ndp6_resolve __P((struct ifnet *,
+	   struct rtentry *, struct mbuf *, struct sockaddr *, u_char *));
+void	ndp6_ifinit __P((struct ifnet *, struct ifaddr *));
+void	ndp6_rtrequest __P((int, struct rtentry *, struct sockaddr *));
+void	ndp6_rtlost __P((struct rtentry *, int));
+struct	llinfo_ndp6 *ndplookup __P((struct in6_addr *, int));
+#endif
+#endif
+
+#endif
diff -uN src-current/sys/netinet/if_sit6.c src-current-ipv6/sys/netinet/if_sit6.c
--- src-current/sys/netinet/if_sit6.c
+++ src-current-ipv6/sys/netinet/if_sit6.c
@@ -0,0 +1,643 @@
+/*
+ * Simple Internet Transition.
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include "sit.h"
+#include "cti.h"
+#if NSIT > 0 || NCTI > 0
+
+#ifndef INET
+#error "SIT DOES NEED INET !!!"
+#endif
+#ifndef INET6
+#error "SIT DOES NEED INET6 !!!"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/sockio.h>
+#include <sys/time.h>
+#include <sys/syslog.h>
+#include <sys/sysctl.h>
+
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
+#include <net/bpf.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/ip6_icmp.h>
+#include <netinet/if_ndp6.h>
+#include <netinet/if_sit6.h>
+
+#include "bpfilter.h"
+
+struct sit_head sitif;
+struct sit_softc *last_sitif;
+u_int sitcnt;
+
+#if NCTI > 0
+u_int cticnt;
+
+static int
+sysctl_net_inet6_sitcnt SYSCTL_HANDLER_ARGS
+{
+	int error = sysctl_handle_int(oidp,
+		oidp->oid_arg1, oidp->oid_arg2, req);
+
+	if (!error) {
+		if (cticnt + NSIT > sitcnt)
+			ctiadd(cticnt + NSIT);
+		cticnt = sitcnt - NSIT;
+	}
+	return error;
+}
+
+SYSCTL_PROC(_net_inet6_ipv6, IP6CTL_CTICNT, cti_count,
+	CTLTYPE_INT|CTLFLAG_RW, &cticnt, 0,
+	&sysctl_net_inet6_sitcnt, "I", "");
+#endif
+
+extern	int arpt_keep, arpt_prune;	/* use same values as arp cache */
+#define rt_expire	rt_rmx.rmx_expire
+
+static	void sitattach __P((void *));
+int	sitoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *,
+		       struct rtentry *));
+int	sitioctl __P((struct ifnet *, int, caddr_t));
+void	sit_rtrequest __P((int, struct rtentry *, struct sockaddr *));
+
+/*
+ * attach SIT interfaces
+ */
+
+static void
+sitattach(dummy)
+	void *dummy;
+{
+	STAILQ_INIT(&sitif);
+	/* add preconfigured SIT interfaces */
+#if NSIT > 0
+	sitadd(NSIT);
+#endif
+	/* add preconfigured CTI interfaces */
+#if NCTI > 0
+	ctiadd(NSIT + NCTI);
+#endif
+	last_sitif = sitif.stqh_first;
+
+	/* don't start at 1970/01/01 at 0h00 */
+	if (time_second == 0)
+		time_second++;
+}
+
+PSEUDO_SET(sitattach, if_sit6);
+
+#if NSIT > 0
+void
+sitadd(cnt)
+	u_int cnt;
+{
+	register u_int i;
+	register struct sit_softc *sc;
+	register struct ifnet *ifp;
+
+	for (i = sitcnt; i < cnt; i++) {
+		sc = malloc(sizeof(struct sit_softc), M_DEVBUF, M_NOWAIT);
+		if (sc == NULL)
+			break;
+		bzero(sc, sizeof(struct sit_softc));
+		STAILQ_INSERT_TAIL(&sitif, sc, sit_list);
+		sitcnt = i + 1;
+		ifp = &sc->sit_if;
+		ifp->if_unit = i;
+		ifp->if_name = "sit";
+		ifp->if_mtu = SITMTU;
+		ifp->if_flags = SIT_NBMA;
+		ifp->if_ioctl = sitioctl;
+		ifp->if_output = sitoutput;
+		ifp->if_type = IFT_OTHER;
+		sc->sit_llinfo.sit_ip.ip_ttl = IPDEFTTL;
+		sc->sit_llinfo.sit_ip.ip_p = IPPROTO_IPV6;
+		ifp->if_hdrlen = sizeof(struct ip);
+		ifp->if_addrlen = 4;
+		ifp->if_ndtype = IFND6_SIT |
+			(((int)&(((struct sit_softc *)0)->sit_llip6) -
+			  sizeof(struct ifnet)) << 8);
+		if_attach(ifp);
+#if NBPFILTER > 0
+		bpfattach(ifp, DLT_NULL, sizeof(u_int));
+#endif
+	}
+#if NCTI > 0
+	cticnt = sitcnt - NSIT;
+#endif
+}
+
+/*
+ * output of IPv6 packets by encapsulation in IPv4
+ */
+int
+sitoutput(ifp, m0, dst, rt0)
+	register struct ifnet *ifp;
+	struct mbuf *m0;
+	struct sockaddr *dst;
+	struct rtentry *rt0;
+{
+	register struct mbuf *m;
+	register struct rtentry *rt;
+	register struct llinfo_sit *ll;
+	struct ip *ip;
+	int error;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_SITOUT)
+		printf("sitoutput(%p,%p,%p,%p) -> %s\n",
+		       ifp, m0, dst, rt0,
+		       ip6_sprintf(&((struct sockaddr_in6 *)dst)->sin6_addr));
+#endif
+
+	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+		m_freem(m0);
+		return (ENETDOWN);
+	}
+
+	getmicrotime(&ifp->if_lastchange);
+	ifp->if_opackets++;
+#ifdef DIAGNOSTIC
+	if ((m0->m_flags & M_PKTHDR) == 0)
+		panic("sitoutput no HDR");
+#endif
+
+	if ((rt = rt0) != 0) {
+		if ((rt->rt_flags & RTF_UP) == 0) {
+			if ((rt0 = rt = rtalloc1(dst, 1, 0UL)) != 0)
+				rt->rt_refcnt--;
+			else {
+				m_freem(m0);
+				return (EHOSTUNREACH);
+			}
+		}
+		if (rt->rt_flags & RTF_GATEWAY) {
+			if (rt->rt_gwroute == 0)
+				goto lookup;
+			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
+				rtfree(rt); rt = rt0;
+			lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway,
+							  1, 0UL);
+				if ((rt = rt->rt_gwroute) == 0) {
+					m_freem(m0);
+					return (EHOSTUNREACH);
+				}
+			}
+		}
+		if ((ll = (struct llinfo_sit *)rt->rt_llinfo) == 0 ||
+		    (ll->sit_flags & RTF_UP) == 0) {
+			m_freem(m0);
+			return (EHOSTUNREACH);
+		}
+		if (rt->rt_expire)
+			rt->rt_expire = time_second + arpt_keep;
+	} else
+		return (EHOSTDOWN);	/* ll = &sc->sit_llinfo; ??? */
+
+#if NBFILTER > 0
+	if (ifp->if_bpf) {
+		/* too soon ?! */
+		/*
+		 * We need to prepend the address family as
+		 * a four byte field.  Cons up a dummy header
+		 * to pacify bpf.  This is safe because bpf
+		 * will only read from the mbuf (i.e., it won't
+		 * try to free it or keep a pointer to it).
+		 */
+		struct mbuf m;
+		u_int af = dst->sa_family;
+
+		m.m_next = m0;
+		m.m_len = 4;
+		m.m_data = (char *)&af;
+
+		bpf_mtap(ifp, &m);
+	}
+#endif
+
+	/*
+	 * Get a header mbuf.
+	 */
+	MGETHDR(m, M_DONTWAIT, MT_DATA);
+	if (m == NULL) {
+		m_freem(m0);
+		return (ENOBUFS);
+	}
+	m->m_len = sizeof(struct ip);
+	m->m_next = m0;
+	m->m_pkthdr.len = m0->m_pkthdr.len + sizeof(struct ip);
+	bcopy((caddr_t)&ll->sit_ip, mtod(m, caddr_t), sizeof(struct ip));
+
+	/*
+	 * Fill in IPv4 header.
+	 */
+	ip = mtod(m, struct ip *);
+	ip->ip_len = m->m_pkthdr.len;
+	ifp->if_obytes += m->m_pkthdr.len;
+
+	/*
+	 * Output final datagram.
+	 */
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_SITOUT)
+		printf("sitoutput src %08x dst %08x len %d\n",
+		       ntohl(ip->ip_src.s_addr),
+		       ntohl(ip->ip_dst.s_addr),
+		       m->m_pkthdr.len);
+#endif
+	error = ip_output(m, (struct mbuf *)0, &ll->sit_route, 0, NULL);
+	if (error)
+		ifp->if_oerrors++;
+	return (error);
+}
+
+/*
+ * Ioctls on SIT pseudo-interfaces.
+ */
+
+int
+sitioctl(ifp, cmd, data)
+	struct ifnet *ifp;
+	int cmd;
+	caddr_t data;
+{
+	struct ifaddr *ifa;
+	struct ifreq *ifr;
+	struct in6_addr *addr;
+	struct sockaddr_dl *sdl = 0;
+	static struct sockaddr_in sin = {sizeof(sin), AF_INET};
+	int s = splimp(), error = 0;
+
+	switch (cmd) {
+
+	case SIOCSIFADDR:
+		ifa = (struct ifaddr *)data;
+		if ((ifa == 0) || (ifa->ifa_addr->sa_family != AF_INET6)) {
+			error = EAFNOSUPPORT;
+			break;
+		}
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_SITCTL)
+			printf("sitioctl ifp %p go up %s\n", ifp,
+			    ip6_sprintf(&satosin6(ifa->ifa_addr)->sin6_addr));
+#endif
+		ifa->ifa_rtrequest = sit_rtrequest;
+		ifa->ifa_flags |= RTF_CLONING;
+		addr = &satosin6(ifa->ifa_addr)->sin6_addr;
+		if (IS_LINKLADDR6(*addr)) {
+			COPY_ADDR6(*addr,
+				   ((struct sit_softc *)ifp)->sit_llip6);
+			ifp->if_ndtype |= IFND6_LLSET;
+			break;
+		}
+		sin.sin_addr.s_addr = addr->s6_addr32[3];
+		if ((addr->s6_addr32[0] != 0) ||
+		    (addr->s6_addr32[1] != 0) ||
+		    (addr->s6_addr32[2] != 0) ||
+		    (ifa_ifwithaddr((struct sockaddr *)&sin) == 0))
+			break;
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_SITCTL)
+			printf("sitioctl sets src %lx\n",
+			       ntohl(sin.sin_addr.s_addr));
+#endif
+		((struct sit_softc *)ifp)->sit_src = sin.sin_addr;
+		ifp->if_flags |= IFF_UP | IFF_RUNNING;
+		if (ifp->if_addrhead.tqh_first && ifp->if_addrhead.tqh_first->ifa_addr &&
+		    (ifp->if_addrhead.tqh_first->ifa_addr->sa_family == AF_LINK)) {
+			sdl = (struct sockaddr_dl *)ifp->if_addrhead.tqh_first->ifa_addr;
+			bcopy(&sin.sin_addr, LLADDR(sdl), sdl->sdl_alen = 4);
+		}
+		break;
+
+	case SIOCSIFMTU:
+		ifr = (struct ifreq *)data;
+		ifp->if_mtu = ifr->ifr_mtu;
+		break;
+
+	default:
+		error = EINVAL;
+	}
+	splx(s);
+	return (error);
+}
+#endif	/* NSIT > 0 */
+
+/*
+ * IPv6-into-IPv4 input routine.
+ */
+
+void
+sit_input(m, iphlen)
+	struct mbuf *m;
+	int iphlen;
+{
+	struct ip *ip = mtod(m, struct ip *);
+	struct sit_softc *sc = last_sitif;
+	struct ifnet *ifp = &sc->sit_if;
+
+	if ((ifp->if_flags & IFF_POINTOPOINT) &&
+	    (sc->sit_dst.s_addr == ip->ip_src.s_addr) &&
+	    (sc->sit_src.s_addr == ip->ip_dst.s_addr)) {
+	  /* success */
+	} else {
+		last_sitif = sitif.stqh_first;
+		for (sc = last_sitif; sc; sc = sc->sit_list.stqe_next) {
+			ifp = &sc->sit_if;
+			if (((ifp->if_flags & IFF_UP) == 0) ||
+			    ((ifp->if_flags & IFF_RUNNING) == 0))
+				continue;
+			if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
+				if (sc->sit_src.s_addr == ip->ip_dst.s_addr)
+					last_sitif = sc;
+			} else if ((sc->sit_dst.s_addr == ip->ip_src.s_addr) &&
+				   (sc->sit_src.s_addr == ip->ip_dst.s_addr)) {
+				last_sitif = sc;
+				break;
+			}
+		}
+		if (sc == 0)
+			ifp = &last_sitif->sit_if;
+	}
+	ifp->if_ipackets++;
+	ifp->if_ibytes += m->m_pkthdr.len;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_SITIN)
+		printf("sit_input src %08x dst %08x len %d\n",
+		       ntohl(ip->ip_src.s_addr),
+		       ntohl(ip->ip_dst.s_addr),
+		       ip->ip_len + iphlen);
+#endif
+	/*
+	 * Strip IPv4 header including options.
+	 */
+	m_adj(m, iphlen);
+
+	/*
+	 * Get IPv6 header.
+	 */
+	if (m->m_len < sizeof (struct ipv6) &&
+	    (m = m_pullup(m, sizeof (struct ipv6))) == 0) {
+		ip6stat.ip6s_toosmall++;
+		return;
+	}
+
+	m->m_pkthdr.rcvif = ifp;
+	ip6_input(m, 0);
+}
+
+/*
+ * TODO: sit_ctlinput()
+ */
+
+#if NSIT > 0
+/*
+ * Parallel to other *rtrequest.
+ */
+void
+sit_rtrequest(req, rt, sa)
+	int req;
+	register struct rtentry *rt;
+	struct sockaddr *sa;
+{
+	register struct sockaddr *gate = rt->rt_gateway;
+	register struct llinfo_sit *ll = (struct llinfo_sit *)rt->rt_llinfo;
+	struct in_addr addr;
+	struct route *ro;
+	static struct sockaddr_in null_in = {sizeof(null_in), AF_INET};
+
+#define SIN(sa)	((struct sockaddr_in *)sa)
+
+	if (rt->rt_flags & RTF_GATEWAY)
+		return;
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_SITCTL)
+		printf("sit_rtrequest(%d,%p,%p)\n", req, rt, sa);
+#endif
+	switch (req) {
+
+	case RTM_ADD:
+		if ((rt->rt_flags & RTF_CLONING) &&
+		    (rt->rt_flags & RTF_HOST) &&
+		    (rt->rt_ifa->ifa_flags & RTF_HOST)) {
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_SITCTL)
+				printf("sit_rtrequest: uncloning\n");
+#endif
+			rt->rt_flags &= ~RTF_CLONING;
+			rt_setgate(rt, rt_key(rt),
+				   (struct sockaddr *)&null_in);
+			gate = rt->rt_gateway;
+		}
+		if (rt->rt_flags & RTF_CLONING) {
+			/*
+			 * This route should come from a route to iface.
+			 */
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_SITCTL)
+				printf("sit_rtrequest: cloning\n");
+#endif
+			rt_setgate(rt, rt_key(rt),
+				   (struct sockaddr *)&null_in);
+			gate = rt->rt_gateway;
+			/*
+			 * Give this route an expiration time !?
+			 */
+			rt->rt_expire = time_second;
+			return;
+		}
+		/*FALLTHROUGH*/
+	case RTM_RESOLVE:
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_SITCTL)
+			printf("sit_rtrequest: resolve\n");
+#endif
+		/*
+		 * Have we get both IPv4 addresses ?
+		 */
+		if ((gate->sa_family != AF_INET) ||
+		    (gate->sa_len != sizeof(struct sockaddr_in))) {
+			log(LOG_ERR, "sit_rtrequest: invalid gateway\n");
+			return;
+		}
+		addr.s_addr = IA_SIN6(rt->rt_ifa)->sin6_addr.s6_addr32[3];
+		if (ll != 0)
+			break;		/* This happens on a route change */
+		/*
+		 * This route may come from cloning or
+		 * a manual route add with an IPv4 address.
+		 */
+		R_Malloc(ll, struct llinfo_sit *, sizeof(*ll));
+		rt->rt_llinfo = (caddr_t)ll;
+		if (ll == 0)
+			return;
+		Bzero(ll, sizeof(*ll));
+		ll->sit_rt = rt;
+		rt->rt_flags |= RTF_LLINFO;
+		if (req == RTM_RESOLVE)
+			rt->rt_flags |= RTF_DYNAMIC;
+		if (SAME_SOCKADDR((struct sockaddr_in6 *)rt_key(rt),
+				  IA_SIN6(rt->rt_ifa))) {
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_SITCTL)
+				printf("sit_rtrequest: local hack\n");
+#endif
+			/* 0 or time_second + arpt_keep ??? */
+			rt->rt_expire = 0;
+			SIN(gate)->sin_addr = addr;
+			rt->rt_flags |= RTF_LOCAL;
+			rt->rt_rmx.rmx_mtu = loif->if_mtu;
+			return;
+		}
+		break;
+
+	case RTM_DELETE:
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_SITCTL)
+			printf("sit_rtrequest: delete\n");
+#endif
+		if (ll == 0)
+			return;
+		rt->rt_llinfo = 0;
+		rt->rt_flags &= ~(RTF_LLINFO | RTF_DYNAMIC);
+		if (ll->sit_route.ro_rt)
+			RTFREE(ll->sit_route.ro_rt);
+		Free((caddr_t)ll);
+		return;
+
+	 case RTM_EXPIRE:
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_SITCTL)
+			printf("sit_rtrequest: expire\n");
+#endif
+		if (ll == 0) {
+			log(LOG_ERR,
+			    "IPv6 SIT route expire without llinfo!\n");
+			return;
+		}
+		if (rt->rt_refcnt > 0)
+			return;
+		rtrequest(RTM_DELETE, rt_key(rt), 0, rt_mask(rt), 0, 0);
+		return;
+	}
+	if (((rt->rt_ifp->if_flags & IFF_UP) == 0) ||
+	    ((rt->rt_ifp->if_flags & IFF_RUNNING) == 0)) {
+		log(LOG_NOTICE, "sit_rtrequest on down ifp\n");
+		return;
+	}
+
+	/*
+	 * Automatic mapping.
+	 */
+	if (((rt->rt_ifp->if_flags & IFF_POINTOPOINT) == 0) &&
+	    (SIN(gate)->sin_addr.s_addr == INADDR_ANY)) {
+		register struct sockaddr_in6 *sin;
+		struct in_addr in;
+
+		sin = (struct sockaddr_in6 *)rt_key(rt);
+		if ((sin->sin6_family != AF_INET6) ||
+		    (sin->sin6_len != sizeof(*sin))) {
+			log(LOG_ERR, "sit_rtrequest: invalid destination\n");
+			return;
+		}
+		in.s_addr = sin->sin6_addr.s6_addr32[3];
+		if ((sin->sin6_addr.s6_addr32[0] != 0) ||
+		    (sin->sin6_addr.s6_addr32[1] != 0) ||
+		    (sin->sin6_addr.s6_addr32[2] != 0) ||
+		    !in_canforward(in)) {
+			log(LOG_NOTICE, "sit_rtrequest: bad mapping\n");
+			return;
+		}
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_SITCTL)
+			printf("sit_rtrequest auto dst %08x\n",
+			       ntohl(in.s_addr));
+#endif
+		SIN(gate)->sin_addr = in;
+	}
+	/*
+	 * Point-to-point case
+	 */
+	if (SIN(gate)->sin_addr.s_addr == INADDR_ANY) {
+		register struct sit_softc *sc;
+
+		sc = (struct sit_softc *)(rt->rt_ifp);
+		SIN(gate)->sin_addr = sc->sit_dst;
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_SITCTL)
+			printf("sit_rtrequest p2p dst %08x\n",
+			       ntohl(SIN(gate)->sin_addr.s_addr));
+#endif
+	}
+
+	/*
+	 * Fill llinfo_sit structure.
+	 */
+	ll->sit_ip.ip_ttl = IPDEFTTL;
+	ll->sit_ip.ip_p = IPPROTO_IPV6;
+	ll->sit_ip.ip_src = addr;
+	ll->sit_ip.ip_dst = SIN(gate)->sin_addr;
+	ro = &ll->sit_route;
+	ro->ro_dst.sa_family = AF_INET;
+	ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
+	SIN(&ro->ro_dst)->sin_addr = SIN(gate)->sin_addr;
+
+	/*
+	 * If there is a cached route,
+	 * check that it is to the same destination
+	 * and is still up.  If not, free it and try again.
+	 */
+	if (ro->ro_rt) {
+		struct sockaddr *dst = rt_key(ro->ro_rt);
+
+		if ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
+		    SIN(gate)->sin_addr.s_addr != SIN(dst)->sin_addr.s_addr) {
+			RTFREE(ro->ro_rt);
+			ro->ro_rt = (struct rtentry *)0;
+		}
+	}
+	rtalloc(ro);
+	if (ro->ro_rt)
+		ro->ro_rt->rt_use++;
+	if (ro->ro_rt && (rt->rt_rmx.rmx_mtu == 0)) {
+		if (ro->ro_rt->rt_rmx.rmx_mtu)
+			rt->rt_rmx.rmx_mtu =
+				ro->ro_rt->rt_rmx.rmx_mtu - sizeof(struct ip);
+		else
+			rt->rt_rmx.rmx_mtu =
+				ro->ro_rt->rt_ifp->if_mtu - sizeof(struct ip);
+	} else if (rt->rt_rmx.rmx_mtu == 0)
+		rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu;
+	ll->sit_flags |= RTF_UP;
+}
+#endif	/* NSIT > 0 */
+#endif	/* NSIT > 0 || NCTI > 0 */
diff -uN src-current/sys/netinet/if_sit6.h src-current-ipv6/sys/netinet/if_sit6.h
--- src-current/sys/netinet/if_sit6.h
+++ src-current-ipv6/sys/netinet/if_sit6.h
@@ -0,0 +1,40 @@
+/*
+ * IPv6 over IPv4 tunnel (SIT & CTI) defines
+ */
+
+#ifndef _NETINET_IF_SIT6_H_
+#define _NETINET_IF_SIT6_H_
+
+/* Maximum packet size */
+#define SITMTU		(1500-20)
+
+struct	llinfo_sit {
+	int	sit_flags;			/* cache valid ? */
+	struct	rtentry *sit_rt;		/* back pointer */
+	struct	ip sit_ip;			/* cached IPv4 header */
+	struct	route sit_route;		/* cached IPv4 route */
+};
+
+struct	sit_softc {
+	struct	ifnet sit_if;
+	STAILQ_ENTRY(sit_softc) sit_list;
+	struct	llinfo_sit sit_llinfo;
+	struct	in6_addr sit_llip6;
+#define	sit_src		sit_llinfo.sit_ip.ip_src
+#define	sit_dst		sit_llinfo.sit_ip.ip_dst
+#define	SIT_NBMA	IFF_LINK0
+};
+
+#ifdef KERNEL
+
+STAILQ_HEAD(sit_head, sit_softc);
+extern	struct sit_head sitif;
+extern	struct sit_softc *last_sitif;
+extern	u_int sitcnt, cticnt;
+
+extern	void sitadd __P((u_int));
+extern	void ctiadd __P((u_int));
+extern	void sit_input __P((struct mbuf *, int));
+#endif
+
+#endif
diff -uN src-current/sys/netinet/if_tug6.c src-current-ipv6/sys/netinet/if_tug6.c
--- src-current/sys/netinet/if_tug6.c
+++ src-current-ipv6/sys/netinet/if_tug6.c
@@ -0,0 +1,365 @@
+/*
+ * IPv6 in IPv6 tunnels.
+ */
+
+#include "opt_inet6.h"
+
+#ifndef INET6
+#error "IPv6 in IPv6 DOES NEED INET6 !!!"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/sockio.h>
+#include <sys/time.h>
+#include <sys/syslog.h>
+
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
+#include <net/bpf.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/ip6_icmp.h>
+#include <netinet/if_ndp6.h>
+
+#include "bpfilter.h"
+
+#include "tug.h"
+#if NTUG > 0
+
+/* Maximum packet size */
+#define TUGMTU		(1500-40)
+
+struct	tug_softc {
+	struct	ifnet tug_if;
+	struct	in6_addr tug_addr;
+	union	route_6 tug_ro;
+} tugif[NTUG];
+
+static	void tugattach __P((void *));
+int	tugoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *,
+		       struct rtentry *));
+int	tugioctl __P((struct ifnet *, int, caddr_t));
+
+/*
+ * attach TUG interfaces
+ */
+
+static void
+tugattach(dummy)
+	void *dummy;
+{
+	register int i;
+	register struct ifnet *ifp;
+
+	for (i = 0; i < NTUG; i++) {
+		ifp = &tugif[i].tug_if;
+		ifp->if_softc = &tugif[i];
+		ifp->if_unit = i;
+		ifp->if_name = "tug";
+		ifp->if_mtu = TUGMTU;
+		ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
+		ifp->if_ioctl = tugioctl;
+		ifp->if_output = tugoutput;
+		ifp->if_type = IFT_OTHER;
+		ifp->if_hdrlen = sizeof(struct ipv6);
+		ifp->if_ndtype = IFND6_TUG;
+		if_attach(ifp);
+#if NBPFILTER > 0
+		bpfattach(ifp, DLT_NULL, sizeof(u_int));
+#endif
+	}
+}
+
+PSEUDO_SET(tugattach, if_tug6);
+
+/*
+ * output of IPv6 packets by encapsulation in IPv6
+ */
+int
+tugoutput(ifp, m0, dst, rt)
+	register struct ifnet *ifp;
+	struct mbuf *m0;
+	struct sockaddr *dst;
+	struct rtentry *rt;
+{
+	register struct mbuf *m;
+	struct ipv6 *ip;
+	struct in6_ifaddr *ia;
+	int error;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_TUGOUT)
+		printf("tugoutput(%p,%p,%p,%p) -> %s\n",
+		       ifp, m0, dst, rt,
+		       ip6_sprintf(&((struct sockaddr_in6 *)dst)->sin6_addr));
+#endif
+
+	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+		m_freem(m0);
+		return (ENETDOWN);
+	}
+	if (dst->sa_family != AF_INET6) {
+		m_freem(m0);
+		return (EAFNOSUPPORT);
+	}
+	if (rt && rt->rt_ifa)
+		ia = (struct in6_ifaddr *)(rt->rt_ifa);
+	else {
+		IFP_TO_IA6(ifp, ia);
+	}
+	if (ia == NULL) {
+		m_freem(m0);
+		ifp->if_oerrors++;
+		return(ENETDOWN);
+	}
+	if (SAME_ADDR6(satosin6(dst)->sin6_addr,
+		       ((struct tug_softc *)ifp)->tug_addr)) {
+		m_freem(m0);
+		ifp->if_collisions++;
+		return(ETOOMANYREFS);
+	}
+
+	getmicrotime(&ifp->if_lastchange);
+	ifp->if_opackets++;
+#ifdef DIAGNOSTIC
+	if ((m0->m_flags & M_PKTHDR) == 0)
+		panic("tugoutput no HDR");
+#endif
+
+#if NBFILTER > 0
+	if (ifp->if_bpf) {
+		/* too soon ?! */
+		/*
+		 * We need to prepend the address family as
+		 * a four byte field.  Cons up a dummy header
+		 * to pacify bpf.  This is safe because bpf
+		 * will only read from the mbuf (i.e., it won't
+		 * try to free it or keep a pointer to it).
+		 */
+		struct mbuf m;
+		u_int af = dst->sa_family;
+
+		m.m_next = m0;
+		m.m_len = 4;
+		m.m_data = (char *)&af;
+
+		bpf_mtap(ifp, &m);
+	}
+#endif
+
+	/*
+	 * Get a header mbuf.
+	 */
+	MGETHDR(m, M_DONTWAIT, MT_DATA);
+	if (m == NULL) {
+		m_freem(m0);
+		return (ENOBUFS);
+	}
+	m->m_len = sizeof(struct ipv6);
+	m->m_next = m0;
+	m->m_pkthdr.len = m0->m_pkthdr.len + sizeof(struct ipv6);
+	ifp->if_obytes += m->m_pkthdr.len;
+
+	/*
+	 * Fill in IPv6 header.
+	 */
+	ip = mtod(m, struct ipv6 *);
+	ip->ip6_head = IPV6_VERSION;
+	ip->ip6_len = m0->m_pkthdr.len;
+	ip->ip6_nh = IPPROTO_IPV6;
+	ip->ip6_hlim = ip_defttl;
+	COPY_ADDR6(IA_SIN6(ia)->sin6_addr, ip->ip6_src);
+	COPY_ADDR6(((struct tug_softc *)ifp)->tug_addr, ip->ip6_dst);
+
+	/*
+	 * Output final datagram.
+	 */
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_TUGOUT)
+		printf("tugoutput src %s dst %s len %d\n",
+		       ip6_sprintf(&ip->ip6_src),
+		       ip6_sprintf(&ip->ip6_dst),
+		       m->m_pkthdr.len);
+#endif
+	error = ip6_output(m,
+			   (struct mbuf *)0,
+			   &((struct tug_softc *)ifp)->tug_ro.route,
+			   0, NULL, NULL);
+	if (error)
+		ifp->if_oerrors++;
+	return (error);
+}
+
+/*
+ * Ioctls on TUG pseudo-interfaces.
+ */
+
+int
+tugioctl(ifp, cmd, data)
+	struct ifnet *ifp;
+	int cmd;
+	caddr_t data;
+{
+	struct ifaddr *ifa;
+	struct ifreq *ifr;
+	struct in6_ifreq *ifr6;
+	struct tug_softc *sc = (struct tug_softc *)ifp;
+	int s = splimp(), error = 0;
+
+	switch (cmd) {
+
+	case SIOCSIFADDR:
+	case SIOCSIFDSTADDR:
+		if ((ifa = (struct ifaddr *)data) &&
+		    (ifa->ifa_addr->sa_family == AF_INET6)) {
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_TUGCTL)
+				printf("tugioctl set ifp %p: %s -> %s\n",
+				       ifp,
+			  ip6_sprintf(&satosin6(ifa->ifa_addr)->sin6_addr),
+			  ip6_sprintf(&satosin6(ifa->ifa_dstaddr)->sin6_addr));
+
+#endif
+			if (!IS_ANYSOCKADDR(satosin6(ifa->ifa_addr)) &&
+			    !IS_ANYSOCKADDR(satosin6(ifa->ifa_dstaddr)))
+				ifp->if_flags |= IFF_UP;
+		}
+		break;
+				
+	case SIOCGTUGADDR6:
+		ifr6 = (struct in6_ifreq *)data;
+		bzero(&ifr6->ifr_Addr, sizeof(struct sockaddr_in6));
+		ifr6->ifr_Addr.sin6_family = AF_INET6;
+		ifr6->ifr_Addr.sin6_len = sizeof(struct sockaddr_in6);
+		COPY_ADDR6(sc->tug_addr, ifr6->ifr_Addr.sin6_addr);
+		break;
+
+	case SIOCSTUGADDR6:
+		ifr6 = (struct in6_ifreq *)data;
+		COPY_ADDR6(ifr6->ifr_Addr.sin6_addr, sc->tug_addr);
+		if (sc->tug_ro.route.ro_rt) {
+			RTFREE(sc->tug_ro.route.ro_rt);
+			sc->tug_ro.route.ro_rt = 0;
+			bzero(&sc->tug_ro, sizeof(union route_6));
+		}
+		if (!IS_ANYADDR6(sc->tug_addr))
+			ifp->if_flags |= IFF_RUNNING;
+		else
+			ifp->if_flags &= ~IFF_RUNNING;
+		break;
+
+	case SIOCSIFMTU:
+		ifr = (struct ifreq *)data;
+		ifp->if_mtu = ifr->ifr_mtu;
+		break;
+
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		break;
+
+	default:
+		error = EINVAL;
+	}
+	splx(s);
+	return (error);
+}
+
+/*
+ * IPv6-into-IPv6 input routine.
+ */
+
+void
+ip6ip6_input(m, arg)
+	register struct mbuf *m;
+	int arg;
+{
+	struct mbuf *opts = (struct mbuf *)arg;
+	struct ipv6 *ip = mtod(m, struct ipv6 *);
+	register struct ifqueue *inq = &ipintrq;
+	int s;
+
+	if (opts)
+		m_freem(opts);
+
+	/* get real interface a la SIT P2P */
+	tugif[0].tug_if.if_ipackets++;
+	tugif[0].tug_if.if_ibytes += m->m_pkthdr.len;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_TUGIN)
+		printf("tuginput src %s dst %s len %d\n",
+		       ip6_sprintf(&ip->ip6_src),
+		       ip6_sprintf(&ip->ip6_dst),
+		       ip->ip6_len);
+#endif
+	m->m_pkthdr.rcvif = &tugif[0].tug_if;
+	/* should use link0 and link1 for AH and ESP */
+	m->m_flags &= ~(M_AUTH|M_CRYPT);
+
+	m->m_pkthdr.len -= sizeof(struct ipv6);
+	m->m_len -= sizeof(struct ipv6);
+	m->m_data += sizeof(struct ipv6);
+	s = splimp();
+	if (IF_QFULL(inq)) {
+		IF_DROP(inq);
+		m_freem(m);
+	} else
+		IF_ENQUEUE(inq, m);
+	/* no schednetisr(NETISR_IP) because we are in ip_input */
+	splx(s);
+}
+
+/*
+ * TODO: tug_ctlinput()
+ */
+
+#else
+
+/*
+ * default IPv6 in IPv6 input
+ */
+
+void
+ip6ip6_input(m, arg)
+	register struct mbuf *m;
+	int arg;
+{
+	struct mbuf *opts = (struct mbuf *)arg;
+	register struct ifqueue *inq = &ipintrq;
+	int s;
+
+	if (opts)
+		m_freem(opts);
+
+	m->m_flags &= ~(M_AUTH|M_CRYPT);
+	m->m_pkthdr.len -= sizeof(struct ipv6);
+	m->m_len -= sizeof(struct ipv6);
+	m->m_data += sizeof(struct ipv6);
+	s = splimp();
+	if (IF_QFULL(inq)) {
+		IF_DROP(inq);
+		m_freem(m);
+	} else
+		IF_ENQUEUE(inq, m);
+	/* no schednetisr(NETISR_IP) because we are in ip_input */
+	splx(s);
+}
+#endif
diff -uN src-current/sys/netinet/in.c src-current-ipv6/sys/netinet/in.c
--- src-current/sys/netinet/in.c
+++ src-current-ipv6/sys/netinet/in.c
@@ -34,6 +34,8 @@
  *	$Id: in.c,v 1.37 1997/10/12 20:25:23 phk Exp $
  */
 
+#include "opt_inet6.h"
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/sockio.h>
@@ -51,7 +53,7 @@
 
 #include <netinet/igmp_var.h>
 
-static MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address");
+MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address");
 
 static void	in_socktrim __P((struct sockaddr_in *));
 static int	in_ifinit __P((struct ifnet *,
@@ -186,12 +188,14 @@
 				    ifra->ifra_addr.sin_addr.s_addr)
 					break;
 			}
+#ifndef INET6
 			if ((ifp->if_flags & IFF_POINTOPOINT)
 			    && (cmd == SIOCAIFADDR)
 			    && (ifra->ifra_dstaddr.sin_addr.s_addr
 				== INADDR_ANY)) {
 				return EDESTADDRREQ;
 			}
+#endif
 		}
 		if (cmd == SIOCDIFADDR && ia == 0)
 			return (EADDRNOTAVAIL);
@@ -449,6 +453,8 @@
 			return (0);
 		flags |= RTF_HOST;
 	}
+	if (ia->ia_subnetmask == 0xffffffff)
+		ia->ia_flags |= RTF_HOST;
 	if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
 		ia->ia_flags |= IFA_ROUTE;
 
diff -uN src-current/sys/netinet/in6.c src-current-ipv6/sys/netinet/in6.c
--- src-current/sys/netinet/in6.c
+++ src-current-ipv6/sys/netinet/in6.c
@@ -0,0 +1,762 @@
+/*
+ * Copyright (c) 1982, 1986, 1991, 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.
+ *
+ *	@(#)in.c	8.2 (Berkeley) 11/15/93
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/ip6_icmp.h>
+#include <netinet/if_ether.h>
+#include <netinet/if_ndp6.h>
+
+MALLOC_DECLARE(M_IPMADDR);
+
+extern struct in6_addr allnodes6_group;
+
+static int in6_ifinit __P((struct ifnet *,
+	struct in6_ifaddr *, struct sockaddr_in6 *, int));
+static void in6_ifscrub __P((struct ifnet *, struct in6_ifaddr *));
+
+static int in6_interfaces;	/* number of external IPv6 interfaces */
+
+/* Multi-homed stuff */
+
+static int multi_homed = MULTI_HOMED;
+
+#ifndef MAIN_INTERFACE6
+#define MAIN_INTERFACE6	0
+#endif
+
+int main_if6 = MAIN_INTERFACE6;
+
+#ifndef MAIN_SITE6
+#define MAIN_SITE6		0
+#endif
+
+int main_site6 = MAIN_SITE6;
+
+int site6_index = 0;		/* max index of IPv6 sites */
+
+SYSCTL_INT(_net_inet6_ipv6, IP6CTL_MHLEVEL, multi_homed, CTLFLAG_RD,
+	&multi_homed, 0, "");
+
+SYSCTL_INT(_net_inet6_ipv6, IP6CTL_MAININTF, main_interface, CTLFLAG_RW,
+	&main_if6, 0, "");
+
+SYSCTL_INT(_net_inet6_ipv6, IP6CTL_MAINSITE, main_site, CTLFLAG_RW,
+	&main_site6, 0, "");
+
+SYSCTL_INT(_net_inet6_ipv6, IP6CTL_SITEMI, site_index, CTLFLAG_RD,
+	&site6_index, 0, "");
+
+struct in6_multihead in6_multihead; /* XXX BSS initialization */
+
+struct in6_anyhead in6_anyhead;
+
+static int anycast_cnt = 0;
+
+static int in6_addanycast __P((struct in6_addr *, u_int));
+static int in6_delanycast __P((struct in6_addr *));
+
+/*
+ * Dump IPv6 anycast address list (via sysctl).
+ */
+/* ARGSUSED */
+static int
+sysctl_anycasts SYSCTL_HANDLER_ARGS
+{
+	register struct in6_anycast *ia;
+	int error;
+
+#define ANYCASTSZ	(sizeof(struct in6_addr) + 2 * sizeof(u_int))
+
+	req->lock = 0;
+	if (!req->oldptr) /* Make an estimate */
+		return (SYSCTL_OUT(req, 0, anycast_cnt * ANYCASTSZ));
+
+	for (ia = in6_anyhead.lh_first; ia; ia = ia->ina6_list.le_next)
+		if (error = SYSCTL_OUT(req, &ia->ina6_addr, ANYCASTSZ))
+			return (error);
+	return (0);
+}
+
+SYSCTL_PROC(_net_inet6_ipv6, IP6CTL_ANYCASTS, anycasts,
+	CTLTYPE_OPAQUE|CTLFLAG_RD, 0, 0, sysctl_anycasts, "S,anycast", "");
+
+/*
+ * Test if an address is an anycast address, return flags.
+ */
+int
+in6_isanycast(addr)
+	struct in6_addr *addr;
+{
+	register struct in6_anycast *ia;
+
+	if (IS_ANYADDR6(*addr))
+		return (0);
+	for (ia = in6_anyhead.lh_first; ia; ia = ia->ina6_list.le_next)
+		if (SAME_ADDR6(*addr, ia->ina6_addr))
+			return ((int)ia->ina6_flags);
+	return (0);
+}
+
+/*
+ * Add an anycast address in the list.
+ */
+static int
+in6_addanycast(addr, flags)
+	struct in6_addr *addr;
+	u_int flags;
+{
+	register struct in6_anycast *ia;
+	int s = splnet();
+
+	for (ia = in6_anyhead.lh_first; ia; ia = ia->ina6_list.le_next)
+		if (SAME_ADDR6(*addr, ia->ina6_addr)) {
+			ia->ina6_refcount++;
+			ia->ina6_flags = max(flags, IP6ANY_VALID);
+			splx(s);
+			return (0);
+		}
+	ia = (struct in6_anycast *)malloc(sizeof *ia, M_IFADDR, M_WAITOK);
+	if (ia == (struct in6_anycast *)0) {
+		splx(s);
+		return (ENOBUFS);
+	}
+	bzero((caddr_t)ia, sizeof *ia);
+	LIST_INSERT_HEAD(&in6_anyhead, ia, ina6_list);
+	COPY_ADDR6(*addr, ia->ina6_addr);
+	ia->ina6_refcount++;
+	ia->ina6_flags = max(flags, IP6ANY_VALID);
+	anycast_cnt++;
+	splx(s);
+	return (0);
+}
+
+/*
+ * Delete an anycast address in the list.
+ */
+static int
+in6_delanycast(addr)
+	struct in6_addr *addr;
+{
+	register struct in6_anycast *ia;
+	int s = splnet();
+
+	for (ia = in6_anyhead.lh_first; ia; ia = ia->ina6_list.le_next)
+		if (SAME_ADDR6(*addr, ia->ina6_addr))
+			break;
+	if (ia == (struct in6_anycast *)0) {
+		splx(s);
+		return (EADDRNOTAVAIL);
+	}
+	ia->ina6_refcount--;
+	if (ia->ina6_refcount) {
+		splx(s);
+		return (0);
+	}
+	LIST_REMOVE(ia, ina6_list);
+	anycast_cnt--;
+	splx(s);
+	free(ia, M_IFADDR);
+	return (0);
+}
+
+/*
+ * Convert IPv6 address to printable (loggable) representation.
+ */
+static char digits[] = "0123456789abcdef";
+static int ipv6round = 0;
+char *
+ip6_sprintf(addr)
+        register struct in6_addr *addr;
+{
+        static char ipv6buf[8][46];
+        register int i;
+        register char *cp;
+        register u_int16_t *a = (u_int16_t *)addr;
+        register u_int8_t *d;
+        int dcolon = 0;
+
+	ipv6round = (ipv6round + 1) & 7;
+	cp = ipv6buf[ipv6round];
+
+        for (i = 0; i < 8; i++) {
+                if (dcolon == 1) {
+                        if (*a == 0) {
+				if (i == 7)
+					*cp++ = ':';
+                                a++;
+                                continue;
+                        } else
+                                dcolon = 2;
+                }
+                if (*a == 0) {
+                        if (dcolon == 0 && i == 7) {
+                                *cp++ = '0';
+                                *cp++ = '0';
+                                break;
+                        }
+                        if (dcolon == 0 && *(a + 1) == 0) {
+				if (i == 0)
+	                                *cp++ = ':';
+                                *cp++ = ':';
+                                dcolon = 1;
+                        } else {
+                                *cp++ = '0';
+                                *cp++ = ':';
+                        }
+			a++;
+                        continue;
+                }
+                d = (u_int8_t *)a;
+                *cp++ = digits[*d >> 4];
+                *cp++ = digits[*d++ & 0xf];
+                *cp++ = digits[*d >> 4];
+                *cp++ = digits[*d & 0xf];
+                *cp++ = ':';
+                a++;
+        }
+        *--cp = 0;
+        return (ipv6buf[ipv6round]);
+}
+
+/*
+ * Generic internet control operations (ioctl's).
+ * Ifp is 0 if not an interface-specific ioctl.
+ */
+/* ARGSUSED */
+int
+in6_control(so, cmd, data, ifp, p)
+	struct socket *so;
+	int cmd;
+	caddr_t data;
+	register struct ifnet *ifp;
+	struct proc *p;
+{
+	register struct in6_ifreq *ifr = (struct in6_ifreq *)data;
+	register struct in6_ifaddr *fia, *oia, *ia = 0;
+	register struct ifaddr *ifa;
+	struct in6_aliasreq *ifra = (struct in6_aliasreq *)data;
+	struct sockaddr_in6 oldaddr;
+	int error, hostIsNew, maskIsNew, s;
+
+	/*
+	 * Find address for this interface, if it exists.
+	 */
+	if (ifp)
+		for (ia = in6_ifaddrhead.tqh_first; ia; ia = ia->ia_list.tqe_next)
+			if (ia->ia_ifp == ifp)
+				break;
+	fia = ia;
+	switch (cmd) {
+
+	case SIOCAIFADDR6:
+	case SIOCDIFADDR6:
+	case SIOCFIFADDR6:
+	case SIOCVIFADDR6:
+		/* If an alias address was specified, find it */
+		if (ifra->ifra_addr.sin6_family == AF_INET6)
+		    for (; ia; ia = ia->ia_list.tqe_next) {
+			if (ia->ia_ifp == ifp  &&
+			    SAME_SOCKADDR(&ia->ia_addr, &ifra->ifra_addr))
+			    break;
+		}
+		if (cmd != SIOCAIFADDR6 && ia == 0)
+			return (EADDRNOTAVAIL);
+		/* FALLTHROUGH */
+	case SIOCSIFADDR6:
+	case SIOCSIFNETMASK6:
+	case SIOCSIFDSTADDR6:
+		if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0)
+			return error;
+
+		if (ifp == 0)
+			panic("in6_control");
+		if (ia == (struct in6_ifaddr *)0) {
+			ia = (struct in6_ifaddr *)
+				malloc(sizeof *ia, M_IFADDR, M_WAITOK);
+			if (ia == (struct in6_ifaddr *)0)
+				return (ENOBUFS);
+			bzero((caddr_t)ia, sizeof *ia);
+			/*
+			 * Protect from ipintr() traversing address list
+			 * while we're modifying it.
+			 */
+			s = splnet();
+
+			TAILQ_INSERT_TAIL(&in6_ifaddrhead, ia, ia_list);
+			ifa = ifp->if_addrhead.tqh_first;
+			if (ifa) {
+				for ( ; ifa->ifa_link.tqe_next; ifa = ifa->ifa_link.tqe_next)
+					continue;
+				ifa->ifa_link.tqe_next = (struct ifaddr *) ia;
+			} else
+				ifp->if_addrhead.tqh_first = (struct ifaddr *) ia;
+			ia->ia_ifa.ifa_refcnt++;
+			ia->ia_ifa.ifa_addr = sin6tosa(&ia->ia_addr);
+			ia->ia_ifa.ifa_dstaddr = sin6tosa(&ia->ia_dstaddr);
+			ia->ia_ifa.ifa_netmask = sin6tosa(&ia->ia_sockmask);
+			ia->ia_sockmask.sin6_len = sizeof(ia->ia_sockmask);
+			ia->ia_ifp = ifp;
+			LIST_INIT(&ia->ia_multiaddrs);
+			if ((ifp->if_flags & IFF_LOOPBACK) == 0)
+				in6_interfaces++;
+			splx(s);
+		}
+		break;
+
+	case SIOCGIFADDR6:
+	case SIOCGIFNETMASK6:
+	case SIOCGIFDSTADDR6:
+		if (ia == (struct in6_ifaddr *)0)
+			return (EADDRNOTAVAIL);
+		break;
+	}
+	switch (cmd) {
+
+	case SIOCGIFADDR6:
+		ifr->ifr_Addr = ia->ia_addr;
+		break;
+
+	case SIOCGIFDSTADDR6:
+		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
+			return (EINVAL);
+		ifr->ifr_Addr = ia->ia_dstaddr;
+		break;
+
+	case SIOCGIFNETMASK6:
+		ifr->ifr_Addr = ia->ia_sockmask;
+		break;
+
+	case SIOCSIFDSTADDR6:
+		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
+			return (EINVAL);
+		oldaddr = ia->ia_dstaddr;
+		ia->ia_dstaddr = ifr->ifr_Addr;
+		if (ifp->if_ioctl && (error = (*ifp->if_ioctl)
+					(ifp, SIOCSIFDSTADDR, (caddr_t)ia))) {
+			ia->ia_dstaddr = oldaddr;
+			return (error);
+		}
+		if (ia->ia_flags & IFA_ROUTE) {
+			ia->ia_ifa.ifa_dstaddr = sin6tosa(&oldaddr);
+			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
+			ia->ia_ifa.ifa_dstaddr = sin6tosa(&ia->ia_dstaddr);
+			rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
+		}
+		break;
+
+	case SIOCSIFADDR6:
+		return (in6_ifinit(ifp, ia, &ifr->ifr_Addr, 1));
+
+	case SIOCSIFNETMASK6:
+		ifr->ifr_Addr = ia->ia_sockmask;
+		break;
+
+	case SIOCAIFADDR6:
+		maskIsNew = 0;
+		hostIsNew = 1;
+		error = 0;
+		if (ia->ia_addr.sin6_family == AF_INET6) {
+			if (ifra->ifra_addr.sin6_len == 0) {
+				ifra->ifra_addr = ia->ia_addr;
+				hostIsNew = 0;
+			} else if (SAME_SOCKADDR(&ifra->ifra_addr,
+						  &ia->ia_addr))
+				hostIsNew = 0;
+		}
+		if (ifra->ifra_mask.sin6_len) {
+			in6_ifscrub(ifp, ia);
+			ia->ia_sockmask = ifra->ifra_mask;
+			maskIsNew = 1;
+		}
+		if ((ifp->if_flags & IFF_POINTOPOINT) &&
+		    (ifra->ifra_dstaddr.sin6_family == AF_INET6)) {
+			in6_ifscrub(ifp, ia);
+			ia->ia_dstaddr = ifra->ifra_dstaddr;
+			maskIsNew  = 1; /* We lie; but the effect's the same */
+		}
+		if (ifra->ifra_addr.sin6_family == AF_INET6 &&
+		    (hostIsNew || maskIsNew))
+			error = in6_ifinit(ifp, ia, &ifra->ifra_addr, 0);
+		return (error);
+
+	case SIOCDIFADDR6:
+		if (fia == ia) {
+			for (fia = ia->ia_list.tqe_next; fia;
+			     fia = fia->ia_list.tqe_next)
+				if (fia->ia_ifp == ifp)
+					break;
+		} else
+			fia = 0;
+		in6_ifscrub(ifp, ia);
+		/*
+		 * Protect from ipintr() traversing address list
+		 * while we're modifying it.
+		 */
+		s = splnet();
+
+		if ((ifa = ifp->if_addrhead.tqh_first) == (struct ifaddr *)ia)
+			ifp->if_addrhead.tqh_first = ifa->ifa_link.tqe_next;
+		else {
+			while (ifa->ifa_link.tqe_next &&
+			       (ifa->ifa_link.tqe_next != (struct ifaddr *)ia))
+				    ifa = ifa->ifa_link.tqe_next;
+			if (ifa->ifa_link.tqe_next)
+				ifa->ifa_link.tqe_next = ((struct ifaddr *)ia)->ifa_link.tqe_next;
+			else
+				printf("Couldn't unlink in6ifaddr from ifp\n");
+		}
+		TAILQ_REMOVE(&in6_ifaddrhead, ia, ia_list);
+		ia->ia_ifa.ifa_refcnt--;
+		if (fia) {
+			struct in6_multi **inmp;
+
+			fia->ia_multiaddrs = ia->ia_multiaddrs;
+			inmp = &fia->ia_multiaddrs.lh_first;
+			if (*inmp)
+				(*inmp)->inm6_link.le_prev = inmp;
+			LIST_INIT(&ia->ia_multiaddrs);
+		}
+		IFAFREE((&ia->ia_ifa));
+		splx(s);
+		break;
+
+	case SIOCFIFADDR6:
+		if (fia == ia)
+			break;
+		/*
+		 * Protect from ipintr() traversing address list
+		 * while we're modifying it.
+		 */
+		s = splnet();
+		if ((ifa = ifp->if_addrhead.tqh_first) == (struct ifaddr *)ia) {
+			/* should not happen ? */
+			ifp->if_addrhead.tqh_first = ifa->ifa_link.tqe_next;
+		} else {
+			while (ifa->ifa_link.tqe_next &&
+			       (ifa->ifa_link.tqe_next != (struct ifaddr *)ia))
+				    ifa = ifa->ifa_link.tqe_next;
+			if (ifa->ifa_link.tqe_next)
+				ifa->ifa_link.tqe_next = ((struct ifaddr *)ia)->ifa_link.tqe_next;
+			else
+				printf("Couldn't unlink in6ifaddr from ifp\n");
+		}
+		if ((ifa = ifp->if_addrhead.tqh_first) == (struct ifaddr *)fia)
+			ifp->if_addrhead.tqh_first = (struct ifaddr *)ia;
+		else {
+			while (ifa->ifa_link.tqe_next &&
+			       (ifa->ifa_link.tqe_next != (struct ifaddr *)fia))
+				    ifa = ifa->ifa_link.tqe_next;
+			if (ifa->ifa_link.tqe_next)
+				ifa->ifa_link.tqe_next = (struct ifaddr *)ia;
+			else
+				printf("Couldn't link in6ifaddr from ifp\n");
+		}
+		ia->ia_ifa.ifa_link.tqe_next = (struct ifaddr *)fia;
+		TAILQ_REMOVE(&in6_ifaddrhead, ia, ia_list);
+		TAILQ_INSERT_BEFORE(fia, ia, ia_list);
+		ia->ia_multiaddrs = fia->ia_multiaddrs;
+		if (ia->ia_multiaddrs.lh_first)
+			ia->ia_multiaddrs.lh_first->inm6_link.le_prev =
+				&ia->ia_multiaddrs.lh_first;
+		LIST_INIT(&fia->ia_multiaddrs);
+		splx(s);
+		break;
+
+	case SIOCVIFADDR6:
+		if (ifra->ifra_mask.sin6_len)
+			ia->ia_flags |= IFA_BOOTING;
+		else
+			ia->ia_flags &= ~IFA_BOOTING;
+		break;
+
+	case SIOCADDANY6:
+		return (in6_addanycast(&ifr->ifr_Addr.sin6_addr,
+				       ifr->ifr_Addr.sin6_flowinfo));
+
+	case SIOCDELANY6:
+		return (in6_delanycast(&ifr->ifr_Addr.sin6_addr));
+
+	case SIOCGIFSITE6:
+		((struct ifreq *)data)->ifr_site6 = ifp->if_site6;
+		break;
+
+	case SIOCSIFSITE6:
+		ifp->if_site6 = ((struct ifreq *)data)->ifr_site6;
+		if ((int)ifp->if_site6 > site6_index)
+			site6_index = ifp->if_site6;
+		break;
+
+	default:
+		if (ifp == 0 || ifp->if_ioctl == 0)
+			return (EOPNOTSUPP);
+		return ((*ifp->if_ioctl)(ifp, cmd, data));
+	}
+	return (0);
+}
+
+/*
+ * Delete any existing route for an interface.
+ */
+static void
+in6_ifscrub(ifp, ia)
+	register struct ifnet *ifp;
+	register struct in6_ifaddr *ia;
+{
+	if ((ia->ia_flags & IFA_ROUTE) == 0)
+		return;
+	if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
+		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
+	else
+		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
+	ia->ia_flags &= ~IFA_ROUTE;
+
+	/*
+	 * If the interface supports multicast, leave the
+	 * "solicited nodes" multicast group on that interface.
+	 */
+	if (ifp->if_flags & IFF_MULTICAST) {
+		register struct in6_multi *inm;
+		struct in6_addr addr;
+#ifdef notyet
+		/* this removes a memory leak ??? */
+		IN6_LOOKUP_MULTI(allnodes6_group, ifp, inm);
+		if (inm != NULL)
+			in6_delmulti(inm);
+#endif
+		addr.s6_addr32[0] = htonl(0xff020000);
+		addr.s6_addr32[1] = 0;
+		addr.s6_addr32[2] = htonl(1);
+		addr.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
+#if IPV6_TOKEN_LENGTH == 64
+		addr.s6_addr8[12] = 0xff;
+#endif
+		IN6_LOOKUP_MULTI(addr, ifp, inm);
+		if (inm != NULL)
+			in6_delmulti(inm);
+	}
+}
+
+/*
+ * Initialize an interface's IPv6 address
+ * and routing table entry.
+ */
+static int
+in6_ifinit(ifp, ia, sin, scrub)
+	register struct ifnet *ifp;
+	register struct in6_ifaddr *ia;
+	struct sockaddr_in6 *sin;
+	int scrub;
+{
+	struct sockaddr_in6 oldaddr;
+	int s = splimp(), flags = RTF_UP, error;
+
+	oldaddr = ia->ia_addr;
+	ia->ia_addr = *sin;
+	/*
+	 * Give the interface a chance to initialize
+	 * if this is its first address,
+	 * and to validate the address if necessary.
+	 */
+	if (ifp->if_ioctl &&
+	    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
+		splx(s);
+		ia->ia_addr = oldaddr;
+		return (error);
+	}
+	splx(s);
+	if (scrub) {
+		ia->ia_ifa.ifa_addr = sin6tosa(&oldaddr);
+		in6_ifscrub(ifp, ia);
+		ia->ia_ifa.ifa_addr = sin6tosa(&ia->ia_addr);
+	}
+	/*
+	 * Add route for the network.
+	 */
+	ia->ia_ifa.ifa_metric = ifp->if_metric;
+	if (ifp->if_flags & IFF_LOOPBACK) {
+		ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
+		flags |= RTF_HOST;
+	} else if (ifp->if_flags & IFF_POINTOPOINT) {
+		if (ia->ia_dstaddr.sin6_family != AF_INET6)
+			return (0);
+		flags |= RTF_HOST;
+	}
+	/*
+	 * Don't create cloning route for an host.
+	 */
+#define MASK(x)	ia->ia_sockmask.sin6_addr.s6_addr32[x]
+	if ((MASK(0) == 0xffffffff) &&
+	    (MASK(1) == 0xffffffff) &&
+	    (MASK(2) == 0xffffffff) &&
+	    (MASK(3) == 0xffffffff))
+		ia->ia_flags |= RTF_HOST;
+#undef MASK
+	if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
+		ia->ia_flags |= IFA_ROUTE;
+	/*
+	 * If the interface supports multicast, join the "all nodes" and
+	 * "solicited nodes" multicast groups on that interface.
+	 */
+	if (ifp->if_flags & IFF_MULTICAST) {
+		struct in6_addr addr;
+
+		(void)in6_addmulti(&allnodes6_group, ifp);
+		addr.s6_addr32[0] = htonl(0xff020000);
+		addr.s6_addr32[1] = 0;
+		addr.s6_addr32[2] = htonl(1);
+		addr.s6_addr32[3] = sin->sin6_addr.s6_addr32[3];
+#if IPV6_TOKEN_LENGTH == 64
+		addr.s6_addr8[12] = 0xff;
+#endif
+		(void)in6_addmulti(&addr, ifp);
+	}
+	return (error);
+}
+
+/*
+ * Add an address to the list of IPv6 multicast addresses
+ * for a given interface.
+ */
+struct in6_multi *
+in6_addmulti(addr, ifp)
+	register struct in6_addr *addr;
+	register struct ifnet *ifp;
+{
+	register struct in6_multi *inm;
+	struct in6_ifreq ifr;
+	struct in6_ifaddr *ia;
+
+	int error;
+	struct sockaddr_in6 sin6;
+	struct ifmultiaddr *ifma;
+
+	int s = splnet();
+
+	/*
+	 * Call generic routine to add membership or increment
+	 * refcount.  It wants addresses in the form of a sockaddr,
+	 * so we build one here (being careful to zero the unused bytes).
+	 */
+	bzero(&sin6, sizeof sin6);
+	sin6.sin6_family = AF_INET6;
+	sin6.sin6_len = sizeof sin6;
+	sin6.sin6_addr = *addr;
+	error = if_addmulti(ifp, (struct sockaddr *)&sin6, &ifma);
+	if (error) {
+		splx(s);
+		return 0;
+	}
+
+	/*
+	 * If ifma->ifma_protospec is null, then if_addmulti() created
+	 * a new record.  Otherwise, we are done.
+	 */
+	if (ifma->ifma_protospec != 0)
+		return ifma->ifma_protospec;
+
+	/* XXX - if_addmulti uses M_WAITOK.  Can this really be called
+	   at interrupt time?  If so, need to fix if_addmulti. XXX */
+	inm = (struct in6_multi *)malloc(sizeof(*inm), M_IPMADDR, M_NOWAIT);
+	if (inm == NULL) {
+		splx(s);
+		return (NULL);
+	}
+
+	bzero(inm, sizeof *inm);
+	inm->inm6_addr = *addr;
+	inm->inm6_ifp = ifp;
+	inm->inm6_ifma = ifma;
+	ifma->ifma_protospec = inm;
+	LIST_INSERT_HEAD(&in6_multihead, inm, inm6_link);
+
+	/*
+	 * Let ICMPv6 know that we have joined
+	 * a new IPv6 multicast group.
+	 */
+	icmp6_joingroup(inm);
+	splx(s);
+	return (inm);
+}
+
+/*
+ * Delete a multicast address record.
+ */
+void
+in6_delmulti(inm)
+	register struct in6_multi *inm;
+{
+	struct ifmultiaddr *ifma = inm->inm6_ifma;
+	int s = splnet();
+
+	if (ifma->ifma_refcount == 0) {
+		/*
+		 * No remaining claims to this record; let ICMPv6 know that
+		 * we are leaving the multicast group.
+		 */
+		icmp6_leavegroup(inm);
+		ifma->ifma_protospec = 0;
+		LIST_REMOVE(inm, inm6_link);
+		free(inm, M_IPMADDR);
+	}
+	/* XXX - should be separate API for when we have an ifma? */
+	if_delmulti(ifma->ifma_ifp, ifma->ifma_addr);
+	splx(s);
+}
diff -uN src-current/sys/netinet/in6_pcb.c src-current-ipv6/sys/netinet/in6_pcb.c
--- src-current/sys/netinet/in6_pcb.c
+++ src-current-ipv6/sys/netinet/in6_pcb.c
@@ -0,0 +1,1040 @@
+/*
+ * Copyright (c) 1982, 1986, 1991, 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.
+ *
+ *	@(#)in_pcb.c	8.2 (Berkeley) 1/4/94
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/proc.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/if_ether.h>
+#include <netinet/if_ndp6.h>
+
+struct	in6_addr zeroin6_addr = {{{0, 0, 0, 0}}};
+
+extern int arpt_keep;
+
+extern int ipport_lowfirstauto;
+extern int ipport_lowlastauto;
+extern int ipport_firstauto;
+extern int ipport_lastauto;
+extern int ipport_hifirstauto;
+extern int ipport_hilastauto;
+
+#define RANGECHK(var, min, max) \
+	if ((var) < (min)) { (var) = (min); } \
+	else if ((var) > (max)) { (var) = (max); }
+
+int
+in6_pcbbind(inp, nam, dyn, p)
+	register struct inpcb *inp;
+	struct sockaddr *nam;
+	int dyn;
+	struct proc *p;
+{
+	register struct socket *so = inp->inp_socket;
+	unsigned short *lastport;
+	register struct sockaddr_in6 *sin6;
+	register struct sockaddr_in *sin;
+	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
+	u_int32_t flowinfo = 0;
+	u_int16_t lport = 0;
+	int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
+	int error, atype, tos = 0;
+
+	if ((!dyn && inp->inp_lport) || inp->inp_latype != IPATYPE_UNBD)
+		return (EINVAL);
+	if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
+		wild = 1;
+	atype = IPATYPE_UNBD;
+	if (nam == 0)
+		goto noname;
+
+	/* deal with address in nam mbuf */
+	sin6 = (struct sockaddr_in6 *)nam;
+	if (nam->sa_len != sizeof (*sin6))
+		return (EINVAL);
+	if (sin6->sin6_family != AF_INET6)
+		return (EAFNOSUPPORT);
+	lport = sin6->sin6_port;
+	if (dyn && inp->inp_lport && lport)
+		return (EINVAL);
+	/* classify address */
+	if (IS_ANYSOCKADDR(sin6)) {
+		if (TAILQ_FIRST(&in_ifaddrhead) == 0
+		    && TAILQ_FIRST(&in6_ifaddrhead) == 0)
+			return (EADDRNOTAVAIL);
+		atype = IPATYPE_UNBD;
+	} else if (IS_IPV4SOCKADDR(sin6)) {
+		if (TAILQ_FIRST(&in_ifaddrhead) == 0)
+			return (EADDRNOTAVAIL);
+		atype = IPATYPE_IPV4;
+	} else {
+		if (TAILQ_FIRST(&in6_ifaddrhead) == 0)
+			return (EADDRNOTAVAIL);
+		atype = IPATYPE_IPV6;
+	}
+	/* deal with flowinfo */
+	flowinfo = sin6->sin6_flowinfo;
+	if ((flowinfo & ~IPV6_FLOWINFO_PRIFLOW) != 0)
+		return (EINVAL);
+	if ((atype == IPATYPE_IPV4) &&
+	    ((flowinfo & IPV6_FLOWINFO_FLOWLABEL) != 0))
+		return (EADDRNOTAVAIL);
+	/* try to remap Priority to TOS */
+	switch (flowinfo & IPV6_FLOWINFO_PRIORITY) {
+	    case IPV6_PRIORITY_INTERACTIVE:
+		tos = IPTOS_LOWDELAY;
+		break;
+	    case IPV6_PRIORITY_BULK:
+		tos = IPTOS_THROUGHPUT;
+		break;
+	}
+	if (atype == IPATYPE_IPV6) {
+		if (IS_MULTIADDR6(sin6->sin6_addr)) {
+			/*
+			 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
+			 * allow complete duplication of binding if
+			 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
+			 * and a multicast address is bound on both
+			 * new and duplicated sockets.
+			 */
+			if (so->so_options & SO_REUSEADDR)
+				reuseport = SO_REUSEADDR|SO_REUSEPORT;
+		} else {
+			sin6->sin6_flowinfo = 0;	/* yech... */
+			sin6->sin6_port = 0;
+			if (ifa_ifwithaddr((struct sockaddr *)sin6) == 0)
+				return (EADDRNOTAVAIL);
+		}
+		if (lport) {
+			struct inpcb *t;
+
+			/* GROSS */
+			if (ntohs(lport) < IPPORT_RESERVED && p &&
+			    suser(p->p_ucred, &p->p_acflag))
+				return (EACCES);
+			if (so->so_uid) {
+				t = in6_pcblookup(inp->inp_pcbinfo, NULL, 0,
+				    &sin6->sin6_addr, lport, INPLOOKUP_WILDCARD);
+				if (t && (so->so_uid != t->inp_socket->so_uid))
+					return (EADDRINUSE);
+			}
+			t = in6_pcblookup(pcbinfo, NULL, 0, &sin6->sin6_addr,
+			    lport, wild);
+			if (t && (reuseport & t->inp_socket->so_options) == 0)
+				return (EADDRINUSE);
+		} else
+			lport = inp->inp_lport;
+		COPY_ADDR6(sin6->sin6_addr, inp->inp_laddr6);
+		if (lport == 0) {
+			ushort first, last;
+			int count;
+	
+			inp->inp_flags |= INP_ANONPORT;
+	
+			if (inp->inp_flags & INP_HIGHPORT) {
+				first = ipport_hifirstauto;	/* sysctl */
+				last  = ipport_hilastauto;
+				lastport = &pcbinfo->lasthi;
+			} else if (inp->inp_flags & INP_LOWPORT) {
+				if (error = suser(p->p_ucred, &p->p_acflag))
+					return (EACCES);
+				first = ipport_lowfirstauto;	/* 1023 */
+				last  = ipport_lowlastauto;	/* 600 */
+				lastport = &pcbinfo->lastlow;
+			} else {
+				first = ipport_firstauto;	/* sysctl */
+				last  = ipport_lastauto;
+				lastport = &pcbinfo->lastport;
+			}
+			/*
+			 * Simple check to ensure all ports are not used up
+			 * causing a deadlock here.
+			 *
+			 * We split the two cases (up and down) so that
+			 * the direction is not being tested on each round
+			 * of the loop.
+			 */
+			if (first > last) {
+				/*
+				 * counting down
+				 */
+				count = first - last;
+	
+				do {
+					/* completely used? */
+					if (count-- <= 0)
+						return (EADDRNOTAVAIL);
+					--*lastport;
+					if (*lastport > first ||
+					    *lastport < last)
+						*lastport = first;
+					lport = htons(*lastport);
+				} while (in6_pcblookup(pcbinfo,
+						       NULL, 0,
+						       &inp->inp_laddr6,
+						       lport, wild));
+			} else {
+				/*
+				 * counting up
+				 */
+				count = last - first;
+	
+				do {
+					/* completely used? */
+					if (count-- <= 0)
+						return (EADDRNOTAVAIL);
+					++*lastport;
+					if (*lastport < first ||
+					    *lastport > last)
+						*lastport = first;
+					lport = htons(*lastport);
+				} while (in6_pcblookup(pcbinfo,
+						       NULL, 0,
+						       &inp->inp_laddr6,
+						       lport, wild));
+			}
+		}
+		inp->inp_flags &= ~INP_COMPATV4;
+		inp->inp_latype = atype;
+		inp->inp_lport = lport;
+		if (tos)
+			inp->inp_tos = tos;
+		if (flowinfo)
+			inp->inp_oflowinfo = flowinfo;
+		if (in_pcbinshash(inp) != 0) {
+			inp->inp_flags |= INP_COMPATANY;
+			CLR_ADDR6(inp->inp_laddr6);
+			inp->inp_latype = IPATYPE_UNBD;
+			inp->inp_lport = 0;
+			return (EAGAIN);
+		}
+		return (0);
+	}
+
+	/* backpatch name */
+	sin = (struct sockaddr_in *)nam;
+	sin->sin_len = sizeof(struct sockaddr_in);
+	sin->sin_family = AF_INET;
+	sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
+	bzero(sin->sin_zero, 8);
+	nam->sa_len = sizeof(struct sockaddr_in);
+
+    noname:
+	if ((error = in_pcbbind(inp, nam, dyn, p)) != 0)
+		return (error);
+	inp->inp_flags |= INP_COMPATANY;
+	if (tos)
+		inp->inp_tos = tos;
+	if (flowinfo)
+		inp->inp_oflowinfo = flowinfo;
+	return (0);
+}
+
+/*
+ * Change the version of local address (GROSS!)
+ */
+int
+in6_pcbrebind(inp, af)
+	register struct inpcb *inp;
+	int af;
+{
+	register struct in_ifaddr *ia;
+	register struct in6_ifaddr *ia6;
+	register struct ifnet *ifp;
+
+	switch (af) {
+	case AF_INET:
+		/* local address must be IPv6 interface address */
+		if (inp->inp_latype != IPATYPE_IPV6)
+			return (EADDRNOTAVAIL);
+		if (IS_MULTIADDR6(inp->inp_laddr6))
+			return (EADDRNOTAVAIL);
+		if ((ia6 = in6_ifaddrhead.tqh_first) == (struct in6_ifaddr *)0)
+			goto unbind;
+		if ((ia = in_ifaddrhead.tqh_first) == (struct in_ifaddr *)0)
+			goto unbind;
+	    next:
+		for ( ; ia6 ; ia6 = ia6->ia_list.tqe_next)
+			if (SAME_ADDR6(inp->inp_laddr6,
+				       ia6->ia_addr.sin6_addr))
+				break;
+		if (ia6 == 0)
+			goto unbind;
+		ifp = ia6->ia_ifp;
+		for ( ; ia ; ia = ia->ia_link.tqe_next)
+			if (ia->ia_ifp == ifp)
+				break;
+		if (ia == 0)
+			goto next;
+
+		inp->inp_flags |= INP_COMPATANY;
+		inp->inp_laddr6.s6_addr32[0] = 0;
+		inp->inp_laddr6.s6_addr32[1] = 0;
+		inp->inp_laddr6.s6_addr32[2] = htonl(0xffff);
+		inp->inp_laddr6.s6_addr32[3] = ia->ia_addr.sin_addr.s_addr;
+		inp->inp_latype = IPATYPE_IPV4;
+		in_pcbrehash(inp);
+		return (0);
+
+	case AF_INET6:
+		/* local address must be IPv4 interface address */
+		if (inp->inp_latype != IPATYPE_IPV4)
+			return (EADDRNOTAVAIL);
+		if (IN_MULTICAST(ntohl(inp->inp_laddr.s_addr)))
+			return (EADDRNOTAVAIL);
+		if ((ia = in_ifaddrhead.tqh_first) == (struct in_ifaddr *)0)
+			goto unbind;
+		if ((ia6 = in6_ifaddrhead.tqh_first) == (struct in6_ifaddr *)0)
+			goto unbind;
+	    next6:
+		for ( ; ia ; ia = ia->ia_link.tqe_next)
+			if (inp->inp_laddr.s_addr ==
+			      ia->ia_addr.sin_addr.s_addr)
+				break;
+		if (ia == 0)
+			goto unbind;
+		ifp = ia->ia_ifp;
+		for ( ; ia6 ; ia6 = ia6->ia_list.tqe_next)
+			if (ia6->ia_ifp == ifp)
+				break;
+		if (ia6 == 0)
+			goto next6;
+
+		inp->inp_flags &= ~INP_COMPATV4;
+		COPY_ADDR6(ia6->ia_addr.sin6_addr, inp->inp_laddr6);
+		inp->inp_latype = IPATYPE_IPV6;
+		in_pcbrehash(inp);
+		return (0);
+
+	unbind:
+		/* TODO: stats ! */
+		inp->inp_flags |= INP_COMPATANY;
+		CLR_ADDR6(inp->inp_laddr6);
+		inp->inp_latype = IPATYPE_UNBD;
+		in_pcbrehash(inp);
+		return (0);
+
+	default:
+		return (EAFNOSUPPORT);
+	}
+}
+
+/*
+ *   Transform old in6_pcbconnect() into an inner subroutine for new
+ *   in6_pcbconnect(): Do some validity-checking on the remote
+ *   address (in mbuf 'nam') and then determine local host address
+ *   (i.e., which interface) to use to access that remote host.
+ *
+ *   This preserves definition of in6_pcbconnect(), while supporting a
+ *   slightly different version for T/TCP.  (This is more than
+ *   a bit of a kludge, but cleaning up the internal interfaces would
+ *   have forced minor changes in every protocol).
+ */
+
+int
+in6_pcbladdr(inp, nam, plocal_sin6, flowp)
+	register struct inpcb *inp;
+	struct sockaddr *nam;
+	struct sockaddr_in6 **plocal_sin6;
+	u_int32_t *flowp;
+{
+	struct in6_ifaddr *ia;
+	register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
+	register struct sockaddr_in *sin;
+	int error, atype;
+
+	if (nam->sa_len != sizeof (*sin6))
+		return (EINVAL);
+	if (sin6->sin6_family != AF_INET6)
+		return (EAFNOSUPPORT);
+	if (sin6->sin6_port == 0)
+		return (EADDRNOTAVAIL);
+	/* classify address */
+	if (IS_ANYSOCKADDR(sin6)) {
+		/* IPv4 centric! */
+		if (inp->inp_latype != IPATYPE_IPV6) {
+			if (in_ifaddrhead.tqh_first == 0)
+				return (EADDRNOTAVAIL);
+			sin6->sin6_addr.s6_addr32[2] = htonl(0xffff);
+			sin6->sin6_addr.s6_addr32[3] =
+			    in_ifaddrhead.tqh_first->ia_addr.sin_addr.s_addr;
+			atype = IPATYPE_IPV4;
+		} else {
+			if (in6_ifaddrhead.tqh_first == 0)
+				return (EADDRNOTAVAIL);
+			COPY_ADDR6(in6_ifaddrhead.tqh_first->ia_addr.sin6_addr,
+				   sin6->sin6_addr);
+			atype = IPATYPE_IPV6;
+		}
+	} else if (IS_IPV4SOCKADDR(sin6)) {
+		if (inp->inp_latype == IPATYPE_IPV6) {
+			if ((error = in6_pcbrebind(inp, AF_INET)) != 0)
+				return (error);
+		}
+		atype = IPATYPE_IPV4;
+	} else {
+		if (inp->inp_latype == IPATYPE_IPV4) {
+			if ((error = in6_pcbrebind(inp, AF_INET6)) != 0)
+				return (error);
+		}
+		atype = IPATYPE_IPV6;
+	}
+	/* deal with flowinfo */
+	*flowp = sin6->sin6_flowinfo;
+	if ((*flowp & ~IPV6_FLOWINFO_PRIFLOW) != 0)
+		return (EINVAL);
+	if ((atype == IPATYPE_IPV4) &&
+	    ((*flowp & IPV6_FLOWINFO_FLOWLABEL) != 0))
+		return (EADDRNOTAVAIL);
+	if (atype != IPATYPE_IPV6)
+		goto version4;
+
+	if (inp->inp_latype == IPATYPE_UNBD) {
+		register struct route *ro;
+
+		ia = (struct in6_ifaddr *)0;
+		/* 
+		 * If route is known or can be allocated now,
+		 * our src addr is taken from the i/f, else punt.
+		 */
+		ro = &inp->inp_route;
+		if (ro->ro_rt &&
+		    (satosin6(&ro->ro_dst)->sin6_family != AF_INET6 ||
+		     !SAME_SOCKADDR(satosin6(&ro->ro_dst), sin6) ||
+		     inp->inp_socket->so_options & SO_DONTROUTE)) {
+			RTFREE(ro->ro_rt);
+			ro->ro_rt = (struct rtentry *)0;
+		}
+		if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
+		    (ro->ro_rt == (struct rtentry *)0 ||
+		    ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
+			/* No route yet, so try to acquire one */
+			ro->ro_dst.sa_family = AF_INET6;
+			ro->ro_dst.sa_len = sizeof(struct sockaddr_in6);
+			COPY_ADDR6(sin6->sin6_addr,
+				   satosin6(&ro->ro_dst)->sin6_addr);
+			in6_rtalloc(ro, INP_IFA);
+		}
+		/*
+		 * If we found a route, use the address
+		 * corresponding to the outgoing interface
+		 * unless it is the loopback (in case a route
+		 * to our address on another net goes to loopback).
+		 */
+		if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
+			ia = ifatoia6(ro->ro_rt->rt_ifa);
+		if (ia == 0) {
+			u_int16_t fport = sin6->sin6_port;
+
+			sin6->sin6_port = 0;
+			ia = ifatoia6(ifa_ifwithdstaddr(sin6tosa(sin6)));
+			if (ia == 0)
+				ia = ifatoia6(ifa_ifwithnet(sin6tosa(sin6)));
+			sin6->sin6_port = fport;
+			if (ia == 0)
+				ia = in6_ifaddrhead.tqh_first;
+			if (ia == 0)
+				return (EADDRNOTAVAIL);
+		}
+		/*
+		 * If the destination address is multicast and an outgoing
+		 * interface has been set as a multicast option
+		 * or preempted with PKTINFO, use the
+		 * address of that interface as our source address.
+		 */
+		if (IS_MULTIADDR6(sin6->sin6_addr)) {
+#if (MULTI_HOMED > 0)
+		    if (inp->inp_ifa)
+			ia = (struct in6_ifaddr *)(inp->inp_ifa);
+		    else
+#endif
+		    if (inp->inp_moptions != NULL) {
+			struct ip_moptions *imo;
+			struct ifnet *ifp;
+
+			imo = inp->inp_moptions;
+			if (imo->imo_multicast_ifp != NULL) {
+				ifp = imo->imo_multicast_ifp;
+				for (ia = in6_ifaddrhead.tqh_first; ia != 0;
+				     ia = ia->ia_list.tqe_next)
+					if (ia->ia_ifp == ifp)
+						break;
+				if (ia == 0)
+					return (EADDRNOTAVAIL);
+			}
+		    }
+		}
+	/*
+	 * Don't do pcblookup call here; return interface in plocal_sin6
+	 * and exit to caller, that will do the lookup.
+	 */
+		*plocal_sin6 = &ia->ia_addr;
+
+	}
+	return(0);
+
+    version4:
+	/* backpatch name */
+	sin = (struct sockaddr_in *)nam;
+	sin->sin_len = sizeof(struct sockaddr_in);
+	sin->sin_family = AF_INET;
+	sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
+	bzero(sin->sin_zero, 8);
+	bzero(satosin(&inp->inp_route.ro_dst)->sin_zero, 8);
+	nam->sa_len = sizeof(struct sockaddr_in);
+	return (in_pcbladdr(inp, nam, (struct sockaddr_in **)plocal_sin6));
+}
+
+/*
+ * Connect from a socket to a specified address.
+ * Both address and port must be specified in argument sin.
+ * If don't have a local address for this socket yet,
+ * then pick one.
+ */
+int
+in6_pcbconnect(inp, nam, p)
+	register struct inpcb *inp;
+	struct sockaddr *nam;
+	struct proc *p;
+{
+	struct sockaddr_in6 *ifaddr6 = 0;
+	struct sockaddr_in *ifaddr;
+	register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
+	register struct sockaddr_in *sin;
+	u_int32_t flowinfo;
+	int error, tos = 0;
+
+	/*
+	 *   Call inner routine, to assign local interface address.
+	 */
+	if (error = in6_pcbladdr(inp, nam, &ifaddr6, &flowinfo))
+		return(error);
+
+	/* try to remap Priority to TOS */
+	switch (flowinfo & IPV6_FLOWINFO_PRIORITY) {
+	    case IPV6_PRIORITY_INTERACTIVE:
+		tos = IPTOS_LOWDELAY;
+		break;
+	    case IPV6_PRIORITY_BULK:
+		tos = IPTOS_THROUGHPUT;
+		break;
+	}
+
+	if (sin6->sin6_family == AF_INET)
+		goto version4;
+
+	if (in6_pcblookup_hash(inp->inp_pcbinfo,
+		   &sin6->sin6_addr, sin6->sin6_port,
+		   inp->inp_latype ? &inp->inp_laddr6 : &ifaddr6->sin6_addr,
+		   inp->inp_lport, 0) != NULL)
+		return (EADDRINUSE);
+	if (inp->inp_latype == IPATYPE_UNBD) {
+		if (inp->inp_lport == 0)
+			(void)in6_pcbbind(inp, (struct sockaddr *)0, 0, p);
+		COPY_ADDR6(ifaddr6->sin6_addr, inp->inp_laddr6);
+		inp->inp_latype = IPATYPE_IPV6;
+	}
+	inp->inp_flags &= ~INP_COMPATV4;
+	COPY_ADDR6(sin6->sin6_addr, inp->inp_faddr6);
+	inp->inp_fatype = IPATYPE_IPV6;
+	inp->inp_fport = sin6->sin6_port;
+	in_pcbrehash(inp);
+	if (tos)
+		inp->inp_tos = tos;
+	if (flowinfo)
+		inp->inp_oflowinfo = flowinfo;
+	return (0);
+
+    version4:
+	ifaddr = (struct sockaddr_in *)ifaddr6;
+	sin = (struct sockaddr_in *)nam;
+	if (in_pcblookup_hash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port,
+	    inp->inp_latype ? inp->inp_laddr : ifaddr->sin_addr,
+	    inp->inp_lport, 0) != NULL)
+		return (EADDRINUSE);
+	if (inp->inp_latype == IPATYPE_UNBD) {
+		if (inp->inp_lport == 0)
+			(void)in_pcbbind(inp, (struct sockaddr *)0, 0, p);
+		inp->inp_laddr = ifaddr->sin_addr;
+		inp->inp_latype = IPATYPE_IPV4;
+		inp->inp_laddr6.s6_addr32[0] = 0;
+		inp->inp_laddr6.s6_addr32[1] = 0;
+		inp->inp_laddr6.s6_addr32[2] = htonl(0xffff);
+	}
+	inp->inp_faddr = sin->sin_addr;
+	if (inp->inp_faddr.s_addr != INADDR_ANY) {
+		inp->inp_fatype = IPATYPE_IPV4;
+		inp->inp_faddr6.s6_addr32[0] = 0;
+		inp->inp_faddr6.s6_addr32[1] = 0;
+		inp->inp_faddr6.s6_addr32[2] = htonl(0xffff);
+	}
+	inp->inp_fport = sin->sin_port;
+	in_pcbrehash(inp);
+	if (tos)
+		inp->inp_tos = tos;
+	if (flowinfo)
+		inp->inp_oflowinfo = flowinfo;
+	return (0);
+}
+
+int
+in6_setsockaddr(so, nam)
+	struct socket *so;
+	struct sockaddr **nam;
+{
+	int s;
+	register struct inpcb *inp;
+	register struct sockaddr_in6 *sin6;
+
+	/*
+	 * Do the malloc first in case it blocks.
+	 */
+	MALLOC(sin6, struct sockaddr_in6 *, sizeof *sin6, M_SONAME, M_WAITOK);
+	bzero((caddr_t)sin6, sizeof (*sin6));
+	sin6->sin6_family = AF_INET6;
+	sin6->sin6_len = sizeof(*sin6);
+
+	s = splnet();
+	inp = sotoinpcb(so);
+	if (!inp) {
+		splx(s);
+		free(sin6, M_SONAME);
+		return EINVAL;
+	}
+	sin6->sin6_port = inp->inp_lport;
+	sin6->sin6_flowinfo = inp->inp_oflowinfo;
+	COPY_ADDR6(inp->inp_laddr6, sin6->sin6_addr);
+	splx(s);
+
+	*nam = (struct sockaddr *)sin6;
+	return 0;
+}
+
+int
+in6_setpeeraddr(so, nam)
+	struct socket *so;
+	struct sockaddr **nam;
+{
+	int s;
+	struct inpcb *inp;
+	register struct sockaddr_in6 *sin6;
+
+	/*
+	 * Do the malloc first in case it blocks.
+	 */
+	MALLOC(sin6, struct sockaddr_in6 *, sizeof *sin6, M_SONAME, M_WAITOK);
+	bzero((caddr_t)sin6, sizeof (*sin6));
+	sin6->sin6_family = AF_INET6;
+	sin6->sin6_len = sizeof(*sin6);
+
+	s = splnet();
+	inp = sotoinpcb(so);
+	if (!inp) {
+		splx(s);
+		free(sin6, M_SONAME);
+		return EINVAL;
+	}
+	sin6->sin6_port = inp->inp_fport;
+	sin6->sin6_flowinfo = inp->inp_iflowinfo;
+	COPY_ADDR6(inp->inp_faddr6, sin6->sin6_addr);
+	splx(s);
+
+	*nam = (struct sockaddr *)sin6;
+	return 0;
+}
+
+/*
+ * Pass some notification to all connections of a protocol
+ * associated with address dst.  The local address and/or port numbers
+ * may be specified to limit the search.  The "usual action" will be
+ * taken, depending on the ctlinput cmd.  The caller must filter any
+ * cmds that are uninteresting (e.g., no error in the map).
+ * Call the protocol specific routine (if any) to report
+ * any errors for each matching socket.
+ *
+ * Must be called at splnet.
+ */
+void
+in6_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
+	struct inpcbhead *head;
+	struct sockaddr *dst;
+	u_int fport_arg, lport_arg;
+	struct in6_addr *laddr;
+	int cmd;
+	void (*notify) __P((struct inpcb *, int));
+{
+	register struct inpcb *inp, *oinp;
+	struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst;
+	u_int16_t fport = fport_arg, lport = lport_arg;
+	int errno, s;
+
+	if (((unsigned)cmd > PRC_NCMDS) ||
+	    (dst == NULL) ||
+	    (dst->sa_family != AF_INET6))
+		return;
+	if (IS_ANYSOCKADDR(dst6) || IS_IPV4SOCKADDR(dst6))
+		return;
+
+	/*
+	 * Redirects go to all references to the destination,
+	 * and use in_rtchange to invalidate the route cache.
+	 * Dead host indications: notify all references to the destination.
+	 * Otherwise, if we have knowledge of the local port and address,
+	 * deliver only to that socket.
+	 */
+	if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
+		fport = 0;
+		lport = 0;
+		laddr = NULL;
+		if (cmd != PRC_HOSTDEAD)
+			notify = in_rtchange;
+	}
+	errno = inetctlerrmap[cmd];
+	s = splnet();
+	for (inp = head->lh_first; inp != NULL;) {
+		if ((inp->inp_flags & INP_COMPATV6) == 0 ||
+		    (inp->inp_fatype & IPATYPE_IPV6) == 0 ||
+		    !SAME_ADDR6(inp->inp_faddr6, dst6->sin6_addr) ||
+		    inp->inp_socket == 0 ||
+		    (lport && inp->inp_lport != lport) ||
+		    (laddr &&
+		     ((inp->inp_latype & IPATYPE_IPV6) == 0 ||
+		     !SAME_ADDR6(inp->inp_laddr6, *laddr))) ||
+		    (fport && inp->inp_fport != fport)) {
+			inp = inp->inp_list.le_next;
+			continue;
+		}
+		oinp = inp;
+		inp = inp->inp_list.le_next;
+		if (notify)
+			(*notify)(oinp, errno);
+	}
+	splx(s);
+}
+
+static struct sockaddr_in6 sindst = { sizeof(sindst), AF_INET6 };
+/*
+ * Clone an host route.
+ */
+struct rtentry *
+in6_rthost(dst)
+	struct in6_addr *dst;
+{
+	struct rtentry *rt, *newrt;
+	struct sockaddr *genmask;
+	int s;
+
+	COPY_ADDR6(*dst, sindst.sin6_addr);
+	rt = rtalloc1(sin6tosa(&sindst), 1, 0UL);
+	if (rt == 0)
+		return rt;
+	rt->rt_refcnt--;
+	if (rt->rt_rmx.rmx_mtu == 0)
+		rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu;
+	if (rt->rt_flags & RTF_HOST)
+		return rt;
+	s = splnet();
+	genmask = rt->rt_genmask;
+	rt->rt_genmask = (struct sockaddr *)0;
+	newrt = rt;
+	if (rtrequest(RTM_RESOLVE, sin6tosa(&sindst),
+		      (struct sockaddr *)0, (struct sockaddr *)0,
+		      0, &newrt)) {
+		rt->rt_genmask = genmask;
+		splx(s);
+		return rt;
+	}
+	rt->rt_genmask = genmask;
+	splx(s);
+	rt = newrt;
+	rt->rt_refcnt--;
+	if ((rt->rt_flags & RTF_HOST) == 0)
+		return rt;
+	rt->rt_flags |= RTF_DYNAMIC;
+	/* TODO: use a dedicated delay */
+	if (rt->rt_rmx.rmx_expire == 0)
+		rt->rt_rmx.rmx_expire = time_second + arpt_keep;
+	return rt;
+}
+
+/*
+ * Apply strong multi-homed model to link-local stuff.
+ */
+void
+in6_rtalloc(ro, ifa)
+	struct route *ro;
+	struct ifaddr *ifa;
+{
+	struct rtentry *rt;
+	struct sockaddr_in6 *sin = satosin6(&ro->ro_dst);
+	struct ifnet *ifp;
+	struct ifaddr *oifa;
+	int s;
+
+	rtalloc(ro);
+	if ((ifa == 0) ||
+	    ((ifp = ifa->ifa_ifp) == 0) ||
+	    ((ifp->if_ndtype & IFND6_INLL) == 0) ||
+	    ((ifp->if_ndtype & IFND6_LLSET) == 0) ||
+	    ((rt = ro->ro_rt) == 0) ||
+	    (rt->rt_ifp == ifp) ||
+	    (rt->rt_flags & RTF_GATEWAY) ||
+	    ((oifa = rt->rt_ifa) == 0) ||
+	    !IS_LOCALADDR6(sin->sin6_addr) ||
+	    (!IFND6_IS_LLINK(rt->rt_ifp) &&
+	     (rt->rt_ifp->if_ndtype & IFND6_INLL) == 0))
+		return;
+	s = splnet();
+	ro->ro_rt = rt = in6_rthost(&sin->sin6_addr);
+#define	MASK	(RTF_UP|RTF_GATEWAY|RTF_HOST|RTF_DYNAMIC|RTF_LLINFO|RTF_STATIC)
+#define NEEDED	(RTF_UP|RTF_HOST|RTF_DYNAMIC|RTF_LLINFO)
+	if ((rt == 0) || ((rt->rt_flags & MASK) != NEEDED)) {
+		log(LOG_ERR, "in6_rtalloc: in6_rthost failed\n");
+		splx(s);
+		return;
+	}
+#undef MASK
+#undef NEEDED
+	if ((rt->rt_ifp == ifp) ||
+	    ((oifa = rt->rt_ifa) == 0) ||
+	    (!IFND6_IS_LLINK(rt->rt_ifp) &&
+	     (rt->rt_ifp->if_ndtype & IFND6_INLL) == 0)) {
+		log(LOG_WARNING, "in6_rtalloc: clobber?\n");
+		splx(s);
+		return;
+	}
+	if (oifa->ifa_ifp != rt->rt_ifp)
+		log(LOG_ERR, "in6_rtalloc: ifa/ifp mismatch\n");
+	if (oifa->ifa_rtrequest)
+		oifa->ifa_rtrequest(RTM_DELETE, rt, (struct sockaddr *)0);
+	IFAFREE(oifa);
+	rt->rt_ifa = ifa;
+	rt->rt_ifp = ifp;
+	ifa->ifa_refcnt++;
+	if (ifa->ifa_rtrequest)
+		ifa->ifa_rtrequest(RTM_ADD, rt, (struct sockaddr *)0);
+	rt->rt_flags |= RTF_MODIFIED;
+	splx(s);
+}
+
+int
+in6_setifa(inp, ifa)
+	struct inpcb *inp;
+	struct ifaddr *ifa;
+{
+#if (MULTI_HOMED > 0)
+	register struct route *ro;
+	register struct sockaddr_in6 *dst;
+	int s = splnet();
+
+	if (inp->inp_ifa)
+		IFAFREE(inp->inp_ifa);
+	inp->inp_ifa = ifa;
+	ifa->ifa_refcnt++;
+	splx(s);
+
+	if ((inp->inp_fatype == IPATYPE_UNBD) ||
+	    (inp->inp_socket->so_options & SO_DONTROUTE))
+		return (0);
+
+	ro = &inp->inp_route;
+	dst = satosin6(&ro->ro_dst);
+	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
+			  !SAME_ADDR6(dst->sin6_addr, inp->inp_faddr6))) {
+		RTFREE(ro->ro_rt);
+		ro->ro_rt = (struct rtentry *)0;
+	}
+	if (ro->ro_rt == 0) {
+		dst->sin6_family = AF_INET6;
+		dst->sin6_len = sizeof(struct sockaddr_in6);
+		COPY_ADDR6(inp->inp_faddr6, dst->sin6_addr);
+		in6_rtalloc(ro, ifa);
+	}
+	if (ro->ro_rt == 0)
+		return (EHOSTUNREACH);
+	ro->ro_rt->rt_use++;
+#endif
+	return (0);
+}
+
+struct inpcb *
+in6_pcblookup(pcbinfo, faddr, fport_arg, laddr, lport_arg, wild_okay)
+	struct inpcbinfo *pcbinfo;
+	struct in6_addr *faddr, *laddr;
+	u_int fport_arg, lport_arg;
+	int wild_okay;
+{
+	register struct inpcb *inp, *match = 0;
+	int matchwild = 3, wildcard;
+	u_int16_t fport = fport_arg, lport = lport_arg;
+	int s;
+
+	s = splnet();
+
+	for (inp = pcbinfo->listhead->lh_first;
+	     inp != NULL;
+	     inp = inp->inp_list.le_next) {
+		if (inp->inp_lport != lport)
+			continue;
+		wildcard = 0;
+		if ((inp->inp_flags & INP_COMPATV6) == 0)
+			continue;
+		if (inp->inp_fatype != IPATYPE_UNBD) {
+			if (faddr == (struct in6_addr *)0)
+				wildcard++;
+			else if ((inp->inp_fatype & IPATYPE_IPV6) == 0 ||
+				 !SAME_ADDR6(inp->inp_faddr6, *faddr) ||
+				 inp->inp_fport != fport)
+				continue;
+		} else {
+			if (faddr != (struct in6_addr *)0)
+				wildcard++;
+		}
+		if (inp->inp_latype != IPATYPE_UNBD) {
+			if (laddr == (struct in6_addr *)0)
+				wildcard++;
+			else if ((inp->inp_latype & IPATYPE_IPV6) == 0 ||
+				 !SAME_ADDR6(inp->inp_laddr6, *laddr))
+				continue;
+		} else {
+			if (laddr != (struct in6_addr *)0)
+				wildcard++;
+		}
+		if (wildcard && wild_okay == 0)
+			continue;
+		if (wildcard < matchwild) {
+			match = inp;
+			matchwild = wildcard;
+			if (matchwild == 0)
+				break;
+		}
+	}
+	splx(s);
+	return (match);
+}
+
+/*
+ * Lookup PCB in hash list.
+ */
+struct inpcb *
+in6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard)
+	struct inpcbinfo *pcbinfo;
+	struct in6_addr *faddr, *laddr;
+	u_int fport_arg, lport_arg;
+	int wildcard;
+{
+	struct inpcbhead *head;
+	register struct inpcb *inp;
+	u_short fport = fport_arg, lport = lport_arg;
+	int s;
+
+	s = splnet();
+	/*
+	 * First look for an exact match.
+	 */
+	head = &pcbinfo->hashbase[INP_PCBHASH(faddr->s6_addr32[3], lport, fport, pcbinfo->hashmask)];
+	for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
+		if ((inp->inp_flags & INP_COMPATV6) != 0 &&
+		    (inp->inp_fatype & IPATYPE_IPV6) != 0 &&
+		    SAME_ADDR6(inp->inp_faddr6, *faddr) &&
+		    (inp->inp_latype & IPATYPE_IPV6) != 0 &&
+		    SAME_ADDR6(inp->inp_laddr6, *laddr) &&
+		    inp->inp_fport == fport &&
+		    inp->inp_lport == lport)
+			goto found;
+	}
+	if (wildcard) {
+		struct inpcb *local_wild = NULL;
+
+		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
+		for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
+			if ((inp->inp_flags & INP_COMPATV6) != 0 &&
+			    inp->inp_fatype == IPATYPE_UNBD &&
+			    inp->inp_fport == 0 && inp->inp_lport == lport) {
+				if ((inp->inp_latype & IPATYPE_IPV6) != 0 &&
+				    SAME_ADDR6(inp->inp_laddr6, *laddr))
+					goto found;
+				else if (inp->inp_latype == IPATYPE_UNBD)
+					local_wild = inp;
+			}
+		}
+		if (local_wild != NULL) {
+			inp = local_wild;
+			goto found;
+		}
+	}
+	splx(s);
+	return (NULL);
+
+found:
+	/*
+	 * Move PCB to head of this hash chain so that it can be
+	 * found more quickly in the future.
+	 * XXX - this is a pessimization on machines with few
+	 * concurrent connections.
+	 */
+	if (inp != head->lh_first) {
+		LIST_REMOVE(inp, inp_hash);
+		LIST_INSERT_HEAD(head, inp, inp_hash);
+	}
+	splx(s);
+	return (inp);
+}
diff -uN src-current/sys/netinet/in6_proto.c src-current-ipv6/sys/netinet/in6_proto.c
--- src-current/sys/netinet/in6_proto.c
+++ src-current-ipv6/sys/netinet/in6_proto.c
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ *
+ *	@(#)in_proto.c	8.1 (Berkeley) 6/10/93
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/domain.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/radix.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip6_icmp.h>
+#include <netinet/igmp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcpip.h>
+#include <netinet/tcp6_var.h>
+#include <netinet/tcp_debug.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/udp6_var.h>
+/*
+ * TCP/IP protocol family: IP, ICMP, UDP, TCP.
+ */
+
+#include "bti.h"
+#if NBTI > 0
+extern void bti_input __P((struct mbuf *, int));
+#endif
+
+extern	struct domain inet6domain;
+static	struct pr_usrreqs nousrreqs;
+
+struct protosw inet6sw[] = {
+{ 0,		&inet6domain,	0,		0,
+  0,		0,		0,		0,
+  0,
+  ip6_init,	0,		0,		0,
+  &nousrreqs
+},
+{ SOCK_DGRAM,	&inet6domain,	IPPROTO_UDP,	PR_ATOMIC|PR_ADDR,
+  udp6_input,	0,		udp6_ctlinput,	ip6_ctloutput,
+  0,
+  0,		0,		0,		0,
+  &udp6_usrreqs
+},
+{ SOCK_STREAM,	&inet6domain,	IPPROTO_TCP,
+	PR_CONNREQUIRED|PR_IMPLOPCL|PR_WANTRCVD,
+  tcp6_input,	0,		tcp6_ctlinput,	tcp6_ctloutput,
+  0,
+  tcp6_init,	tcp6_fasttimo,	tcp6_slowtimo,	tcp_drain,
+  &tcp6_usrreqs
+},
+{ SOCK_RAW,	&inet6domain,	IPPROTO_RAW,	PR_ATOMIC|PR_ADDR,
+  rip6_input,	0,		rip6_ctlinput,	rip6_ctloutput,
+  0,
+  0,		0,		0,		0,
+  &rip6_usrreqs
+},
+{ SOCK_RAW,	&inet6domain,	IPPROTO_ICMPV6,	PR_ATOMIC|PR_ADDR,
+  icmp6_input,	0,		rip6_ctlinput,	rip6_ctloutput,
+  0,
+  icmp6_init,	icmp6_fasttimo,	0,		0,
+  &rip6_usrreqs
+},
+{ 0,		&inet6domain,	IP6_NHDR_FRAG,	0,
+  frg6_input,	0,		opt6_ctlinput,	0,
+  0,
+  0,		0,		frg6_slowtimo,	frg6_drain,
+  &rip6_usrreqs
+},
+{ 0,		&inet6domain,	IP6_NHDR_HOP,	0,
+  hop6_input,	0,		opt6_ctlinput,	0,
+  0,
+  0,		0,		0,		0,
+  &rip6_usrreqs
+},
+{ 0,		&inet6domain,	IP6_NHDR_RT,	0,
+  rt6_input,	0,		opt6_ctlinput,	0,
+  0,
+  0,		0,		0,		0,
+  &rip6_usrreqs
+},
+{ 0,		&inet6domain,	IP6_NHDR_DOPT,	0,
+  dopt6_input,	0,		opt6_ctlinput,	0,
+  0,
+  0,		0,		0,		0,
+  &rip6_usrreqs
+},
+{ 0,		&inet6domain,	IP6_NHDR_AUTH,	0,
+  ah6_input,	0,		opt6_ctlinput,	0,
+  0,
+  ipsec_init,	0,		0,		0,
+  &rip6_usrreqs
+},
+{ 0,		&inet6domain,	IP6_NHDR_ESP,	0,
+  esp6_input,	0,		opt6_ctlinput,	0,
+  0,
+  0,		0,		0,		0,
+  &rip6_usrreqs
+},
+{ 0,		&inet6domain,	IP6_NHDR_NONH,	0,
+  end6_input,	0,		0,		0,
+  0,
+  0,		0,		0,		0,
+  &rip6_usrreqs
+},
+#if NBTI > 0
+{ SOCK_RAW,	&inet6domain,	IPPROTO_IPIP,	PR_ATOMIC|PR_ADDR,
+  bti_input,	0,		0,		rip6_ctloutput,
+  0,
+  0,		0,		0,		0,
+  &rip6_usrreqs
+},
+#endif
+{ SOCK_RAW,	&inet6domain,	IPPROTO_IPV6,	PR_ATOMIC|PR_ADDR,
+  ip6ip6_input,	0,		0,		rip6_ctloutput,
+  0,
+  0,		0,		0,		0,
+  &rip6_usrreqs
+},
+	/* raw wildcard */
+{ SOCK_RAW,	&inet6domain,	0,		PR_ATOMIC|PR_ADDR,
+  rip6_input,	0,		rip6_ctlinput,	rip6_ctloutput,
+  0,
+  0,		0,		0,		0,
+  &rip6_usrreqs
+},
+};
+
+struct domain inet6domain =
+    { AF_INET6, "internet6", 0, 0, 0, 
+      inet6sw, &inet6sw[sizeof(inet6sw)/sizeof(inet6sw[0])], 0,
+      rn_inithead, 64, sizeof(struct sockaddr_in6) * 2
+    };
+
+DOMAIN_SET(inet6);
+
+SYSCTL_NODE(_net,      PF_INET6,	inet6,	CTLFLAG_RW, 0,
+	"IPv6 Family");
+
+SYSCTL_NODE(_net_inet6, IPPROTO_IP,	ipv6,	CTLFLAG_RW, 0,	"IPv6");
+SYSCTL_NODE(_net_inet6, IPPROTO_ICMPV6,	icmpv6,	CTLFLAG_RW, 0,	"ICMPv6");
diff -uN src-current/sys/netinet/in6_var.h src-current-ipv6/sys/netinet/in6_var.h
--- src-current/sys/netinet/in6_var.h
+++ src-current-ipv6/sys/netinet/in6_var.h
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 1985, 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.
+ *
+ *	@(#)in_var.h	8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _NETINET_IN6_VAR_H_
+#define _NETINET_IN6_VAR_H_
+
+#include <sys/queue.h>
+
+/*
+ * Interface address, IPv6 version.  One of these structures
+ * is allocated for each interface with an IPv6 address.
+ * The ifaddr structure contains the protocol-independent part
+ * of the structure and is assumed to be first.
+ */
+struct in6_ifaddr {
+	struct	ifaddr ia_ifa;		/* protocol-independent info */
+#define	ia_ifp		ia_ifa.ifa_ifp
+#define ia_flags	ia_ifa.ifa_flags
+	TAILQ_ENTRY(in6_ifaddr) ia_list; /* list of IPv6 addresses */
+	struct	sockaddr_in6 ia_addr;	/* space for interface name */
+	struct	sockaddr_in6 ia_dstaddr; /* space for broadcast addr */
+	struct	sockaddr_in6 ia_sockmask; /* space for general netmask */
+	LIST_HEAD(, in6_multi) ia_multiaddrs; /* list of multicast addresses */
+};
+
+struct	in6_aliasreq {
+	char	ifra_name[IFNAMSIZ];		/* if name, e.g. "en0" */
+	struct	sockaddr_in6 ifra_addr;
+	struct	sockaddr_in6 ifra_dstaddr;
+	struct	sockaddr_in6 ifra_mask;
+};
+
+struct in6_ifreq {
+	char	ifr_name[IFNAMSIZ];		/* if name, e.g. "en0" */
+	struct	sockaddr_in6 ifr_Addr;
+};
+
+/*
+ * Given a pointer to an in6_ifaddr (ifaddr),
+ * return a pointer to the addr as a sockaddr_in6.
+ */
+#define	IA_SIN6(ia) (&(((struct in6_ifaddr *)(ia))->ia_addr))
+#define	IA_DSTSIN6(ia) (&(((struct in6_ifaddr *)(ia))->ia_dstaddr))
+
+#define SIOCSIFADDR6  _IOW('i', 12, struct in6_ifreq)   /* set ifnet address */
+#define SIOCGIFADDR6 _IOWR('i', 33, struct in6_ifreq)   /* get ifnet address */
+#define SIOCSIFDSTADDR6  _IOW('i', 14, struct in6_ifreq)/* set p-p address */
+#define SIOCGIFDSTADDR6 _IOWR('i', 34, struct in6_ifreq)/* get p-p address */
+#define SIOCSIFNETMASK6 _IOW('i', 22, struct in6_ifreq) /* set net addr mask */
+#define SIOCGIFNETMASK6 _IOWR('i', 37, struct in6_ifreq)/* get net addr mask */
+
+#define SIOCDIFADDR6  _IOW('i', 25, struct in6_ifreq)   /* delete IF addr */
+#define SIOCAIFADDR6  _IOW('i', 26, struct in6_aliasreq)/* add/chg IF alias */
+#define SIOCFIFADDR6  _IOW('i', 39, struct in6_ifreq)   /* put IF addr in front */
+#define SIOCVIFADDR6  _IOW('i', 40, struct in6_aliasreq) /* validate IF addr */
+
+#define SIOCADDANY6   _IOW('i', 41, struct in6_ifreq)	/* add an anycast */
+#define SIOCDELANY6   _IOW('i', 42, struct in6_ifreq)	/* delete an anycast */
+
+#define	SIOCGIFSITE6  _IOWR('i', 43, struct ifreq)	/* get ifnet site */
+#define	SIOCSIFSITE6  _IOW('i', 44, struct ifreq)	/* set ifnet site */
+
+#define SIOCGTUGADDR6 _IOWR('i', 45, struct in6_ifreq)  /* get TUG real addr */
+#define SIOCSTUGADDR6 _IOW('i', 46, struct in6_ifreq)   /* set TUG real addr */
+
+#define SIOCGBTIADDR6 _IOWR('i', 45, struct in6_aliasreq)  /* get BTI addr6 */
+#define SIOCSBTIADDR6 _IOW('i', 46, struct in6_aliasreq)   /* set BTI addr6 */
+
+#if defined(KERNEL) && defined(INET6)
+
+extern TAILQ_HEAD(in6_ifaddrhead, in6_ifaddr) in6_ifaddrhead;
+
+extern	int site6_index;
+
+/*
+ * Macro for finding the interface (ifnet structure) corresponding to one
+ * of our IPv6 addresses.
+ */
+#define IN6ADDR_TO_IFP(addr, ifp) \
+	/* struct in6_addr addr; */ \
+	/* struct ifnet *ifp; */ \
+{ \
+	register struct in6_ifaddr *ia; \
+\
+	for (ia = in6_ifaddrhead.tqh_first; \
+	    ia != NULL && \
+	      !SAME_ADDR6(((ia->ia_ifp->if_flags & IFF_POINTOPOINT) ? \
+		    IA_DSTSIN6(ia) : IA_SIN6(ia))->sin6_addr, addr); \
+	    ia = ia->ia_list.tqe_next) \
+		 continue; \
+	if (ia == NULL) \
+	    for (ia = in6_ifaddrhead.tqh_first; \
+		ia != NULL; \
+		ia = ia->ia_list.tqe_next) \
+		    if (ia->ia_ifp->if_flags & IFF_POINTOPOINT && \
+			SAME_ADDR6(IA_SIN6(ia)->sin6_addr, addr)) \
+			    break; \
+	(ifp) = (ia == NULL) ? NULL : ia->ia_ifp; \
+}
+
+/*
+ * Macro for finding the IPv6 address structure (in6_ifaddr) corresponding
+ * to a given interface (ifnet structure).
+ */
+#define IFP_TO_IA6(ifp, ia) \
+	/* struct ifnet *ifp; */ \
+	/* struct in6_ifaddr *ia; */ \
+{ \
+	for ((ia) = in6_ifaddrhead.tqh_first; \
+	    (ia) != NULL && (ia)->ia_ifp != (ifp); \
+	    (ia) = (ia)->ia_list.tqe_next) \
+		continue; \
+}
+#endif
+
+/*
+ * IPv6 multicast address structure.  There is one of these for each IPv6
+ * multicast group to which this host belongs on a given network interface.
+ * They are kept in a linked list, rooted in the interface's in6_ifaddr
+ * structure.
+ */
+struct in6_multi {
+	LIST_ENTRY(in6_multi) inm6_link; /* list glue */ 
+	struct	in6_addr inm6_addr;	/* IPv6 multicast address */
+	struct	ifnet *inm6_ifp;	/* back pointer to ifnet */
+	struct	ifmultiaddr *inm6_ifma;	/* back pointer to ifmultiaddr */
+	u_int	inm6_timer;		/* ICMPv6 membership report timer */
+	u_int	inm6_state;		/* state of the membership */
+};
+
+#define MULTI6_OTHERMEMBER		1
+#define MULTI6_IREPORTEDLAST		2
+
+#if defined(KERNEL) && defined(INET6)
+extern LIST_HEAD(in6_multihead, in6_multi) in6_multihead;
+
+/*
+ * Structure used by macros below to remember position when stepping through
+ * all of the in6_multi records.
+ */
+struct in6_multistep {
+	struct in6_multi *i6_inm;
+};
+
+/*
+ * Macro for looking up the in6_multi record
+ * for a given IPv6 multicast address on a given interface.
+ * If no matching record is found, "inm" returns NULL.
+ */
+#define IN6_LOOKUP_MULTI(addr, ifp, inm) \
+	/* struct in6_addr addr; */ \
+	/* struct ifnet *ifp; */ \
+	/* struct in6_multi *inm; */ \
+do { \
+	register struct ifmultiaddr *ifma; \
+\
+	for (ifma = (ifp)->if_multiaddrs.lh_first; ifma; \
+	     ifma = ifma->ifma_link.le_next) { \
+		if (ifma->ifma_addr->sa_family == AF_INET6 \
+		    && SAME_ADDR6(((struct sockaddr_in6 *)ifma->ifma_addr) \
+				  ->sin6_addr, (addr))) \
+			break; \
+	} \
+	(inm) = ifma ? ifma->ifma_protospec : 0; \
+} while(0)
+
+/*
+ * Macro to step through all of the in6_multi records, one at a time.
+ * The current position is remembered in "step", which the caller must
+ * provide.  IN6_FIRST_MULTI(), below, must be called to initialize "step"
+ * and get the first record.  Both macros return a NULL "inm" when there
+ * are no remaining records.
+ */
+#define IN6_NEXT_MULTI(step, inm) \
+	/* struct in6_multistep  step; */ \
+	/* struct in6_multi *inm; */ \
+{ \
+	if (((inm) = (step).i6_inm) != NULL) \
+		(step).i6_inm = (inm)->inm6_link.le_next; \
+}
+
+#define IN6_FIRST_MULTI(step, inm) \
+	/* struct in6_multistep step; */ \
+	/* struct in6_multi *inm; */ \
+{ \
+	(step).i6_inm = in6_multihead.lh_first; \
+	IN6_NEXT_MULTI((step), (inm)); \
+}
+
+struct	in6_multi *in6_addmulti __P((struct in6_addr *, struct ifnet *));
+void	in6_delmulti __P((struct in6_multi *));
+int	in6_control __P((struct socket *, int, caddr_t, struct ifnet *,
+	    struct proc *));
+
+#endif
+
+/*
+ * Anycast address structure.
+ */
+
+struct in6_anycast {
+#ifdef KERNEL
+	LIST_ENTRY(in6_anycast) ina6_list;	/* list glue */
+#endif
+	struct	in6_addr ina6_addr;		/* IPv6 anycast address */
+	u_int	ina6_refcount;			/* reference count */
+	u_int	ina6_flags;			/* flags */
+};
+#define	IP6ANY_VALID		1		/* valid entry */
+#define	IP6ANY_ROUTER		2		/* router anycast */
+#define	IP6ANY_ALLWAYS		3		/* allways get it! */
+
+#if defined(KERNEL) && defined(INET6)
+
+extern LIST_HEAD(in6_anyhead, in6_anycast) in6_anyhead;
+
+#endif
+
+/*
+ * Definitions for IPv6 sysctl operations.
+ *
+ * Third level is protocol number.
+ * Fourth level is desired variable within that protocol.
+ */
+#define	IP6PROTO_MAXID	(1)		/* don't list to IP6PROTO_MAX */
+
+#define	CTL_IP6PROTO_NAMES { \
+	{ "ipv6", CTLTYPE_NODE }, \
+}
+
+/*
+ * Names for IPv6 sysctl objects
+ */
+#define	IP6CTL_FORWARDING	1	/* act as router */
+#define	IP6CTL_MFORWARDING	2	/* act as multicast router */
+#define	IP6CTL_FORWSRCRT	3	/* forward source-routed packets */
+#define IP6CTL_DEFTTL		4	/* default TTL */
+#define	IP6CTL_PRUNE		5	/* route prune timer */
+#define	IP6CTL_KEEP		6	/* route default lifetime */
+#define	IP6CTL_REACHABLE	7	/* reachable time */
+#define	IP6CTL_RETRANS		8	/* retrans timer */
+#define	IP6CTL_PROBE		9	/* delay first probe */
+#define	IP6CTL_DOWN		10	/* hold down timer */
+#define	IP6CTL_UMAXTRIES	11	/* max unicast solicit */
+#define	IP6CTL_MMAXTRIES	12	/* max multicast solicit */
+#define	IP6CTL_MHLEVEL		13	/* multi-homed support level */
+#define	IP6CTL_MAININTF		14	/* index of the main interface */
+#define	IP6CTL_MAINSITE		15	/* index of the main site */
+#define	IP6CTL_SITEMI		16	/* max index of sites */
+#define	IP6CTL_ANYCASTS		17	/* anycast address list */
+#define	IP6CTL_CTICNT		18	/* number of CTI interfaces */
+#define	IP6CTL_BTICNT		19	/* number of BTI interfaces */
+#define	IP6CTL_MAXID		20
+
+#define	IP6CTL_NAMES { \
+	{ 0, 0 }, \
+	{ "forwarding", CTLTYPE_INT }, \
+	{ "mforwarding", CTLTYPE_INT }, \
+	{ "forwsrcrt", CTLTYPE_INT }, \
+	{ "ttl", CTLTYPE_INT }, \
+	{ "prune", CTLTYPE_INT }, \
+	{ "keep", CTLTYPE_INT }, \
+	{ "reachable", CTLTYPE_INT }, \
+	{ "retrans", CTLTYPE_INT }, \
+	{ "probe", CTLTYPE_INT }, \
+	{ "hold_down", CTLTYPE_INT }, \
+	{ "utries_max", CTLTYPE_INT }, \
+	{ "mtries_max", CTLTYPE_INT }, \
+	{ "multi_homed", CTLTYPE_INT }, \
+	{ "main_interface", CTLTYPE_INT }, \
+	{ "main_site", CTLTYPE_INT }, \
+	{ "site_index", CTLTYPE_INT }, \
+	{ "anycasts", CTLTYPE_STRUCT }, \
+	{ "cti_count", CTLTYPE_INT }, \
+	{ "bti_count", CTLTYPE_INT }, \
+}
+
+int	get_multi_homed __P((void));
+int	main_interface __P((int *));
+int	main_site __P((int *));
+
+#endif
diff -uN src-current/sys/netinet/in_pcb.c src-current-ipv6/sys/netinet/in_pcb.c
--- src-current/sys/netinet/in_pcb.c
+++ src-current-ipv6/sys/netinet/in_pcb.c
@@ -34,6 +34,8 @@
  *	$Id: in_pcb.c,v 1.44 1998/05/15 20:11:32 wollman Exp $
  */
 
+#include "opt_inet6.h"
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/malloc.h>
@@ -53,25 +55,28 @@
 #include <net/route.h>
 
 #include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
 #include <netinet/in_pcb.h>
 #include <netinet/in_var.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
 
 struct	in_addr zeroin_addr;
 
 static void	in_pcbremlists __P((struct inpcb *));
-static void	in_rtchange __P((struct inpcb *, int));
+/* static void	in_rtchange __P((struct inpcb *, int)); */
 
 /*
  * These configure the range of local port addresses assigned to
  * "unspecified" outgoing connections/packets/whatever.
  */
-static int ipport_lowfirstauto  = IPPORT_RESERVED - 1;	/* 1023 */
-static int ipport_lowlastauto = IPPORT_RESERVEDSTART;	/* 600 */
-static int ipport_firstauto = IPPORT_RESERVED;		/* 1024 */
-static int ipport_lastauto  = IPPORT_USERRESERVED;	/* 5000 */
-static int ipport_hifirstauto = IPPORT_HIFIRSTAUTO;	/* 49152 */
-static int ipport_hilastauto  = IPPORT_HILASTAUTO;	/* 65535 */
+int ipport_lowfirstauto  = IPPORT_RESERVED - 1;	/* 1023 */
+int ipport_lowlastauto = IPPORT_RESERVEDSTART;	/* 600 */
+int ipport_firstauto = IPPORT_RESERVED;		/* 1024 */
+int ipport_lastauto  = IPPORT_USERRESERVED;	/* 5000 */
+int ipport_hifirstauto = IPPORT_HIFIRSTAUTO;	/* 49152 */
+int ipport_hilastauto  = IPPORT_HILASTAUTO;	/* 65535 */
 
 #define RANGECHK(var, min, max) \
 	if ((var) < (min)) { (var) = (min); } \
@@ -143,9 +148,10 @@
 }
 
 int
-in_pcbbind(inp, nam, p)
+in_pcbbind(inp, nam, dyn, p)
 	register struct inpcb *inp;
 	struct sockaddr *nam;
+	int dyn;
 	struct proc *p;
 {
 	register struct socket *so = inp->inp_socket;
@@ -158,7 +164,7 @@
 
 	if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */
 		return (EADDRNOTAVAIL);
-	if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
+	if ((!dyn && inp->inp_lport) || inp->inp_latype != IPATYPE_UNBD)
 		return (EINVAL);
 	if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
 		wild = 1;
@@ -175,6 +181,8 @@
 			return (EAFNOSUPPORT);
 #endif
 		lport = sin->sin_port;
+		if (dyn && inp->inp_lport && lport)
+			return (EINVAL);
 		if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
 			/*
 			 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
@@ -207,7 +215,8 @@
 			    lport, wild);
 			if (t && (reuseport & t->inp_socket->so_options) == 0)
 				return (EADDRINUSE);
-		}
+		} else
+			lport = inp->inp_lport;
 		inp->inp_laddr = sin->sin_addr;
 	}
 	if (lport == 0) {
@@ -251,6 +260,7 @@
 					 * occurred above.
 					 */
 					inp->inp_laddr.s_addr = INADDR_ANY;
+					inp->inp_latype = IPATYPE_UNBD;
 					return (EAGAIN);
 				}
 				--*lastport;
@@ -272,6 +282,7 @@
 					 * occurred above.
 					 */
 					inp->inp_laddr.s_addr = INADDR_ANY;
+					inp->inp_latype = IPATYPE_UNBD;
 					return (EAGAIN);
 				}
 				++*lastport;
@@ -282,9 +293,18 @@
 				 inp->inp_laddr, lport, wild));
 		}
 	}
+	if (inp->inp_laddr.s_addr != INADDR_ANY) {
+		inp->inp_latype = IPATYPE_IPV4;
+#ifdef INET6
+		inp->inp_laddr6.s6_addr32[0] = 0;
+		inp->inp_laddr6.s6_addr32[1] = 0;
+		inp->inp_laddr6.s6_addr32[2] = htonl(0xffff);
+#endif
+	}
 	inp->inp_lport = lport;
 	if (in_pcbinshash(inp) != 0) {
 		inp->inp_laddr.s_addr = INADDR_ANY;
+		inp->inp_latype = IPATYPE_UNBD;
 		inp->inp_lport = 0;
 		return (EAGAIN);
 	}
@@ -326,16 +346,13 @@
 		 * and the primary interface supports broadcast,
 		 * choose the broadcast address for that interface.
 		 */
-#define	satosin(sa)	((struct sockaddr_in *)(sa))
-#define sintosa(sin)	((struct sockaddr *)(sin))
-#define ifatoia(ifa)	((struct in_ifaddr *)(ifa))
 		if (sin->sin_addr.s_addr == INADDR_ANY)
 		    sin->sin_addr = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr;
 		else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
 		  (in_ifaddrhead.tqh_first->ia_ifp->if_flags & IFF_BROADCAST))
 		    sin->sin_addr = satosin(&in_ifaddrhead.tqh_first->ia_broadaddr)->sin_addr;
 	}
-	if (inp->inp_laddr.s_addr == INADDR_ANY) {
+	if (inp->inp_latype == IPATYPE_UNBD) {
 		register struct route *ro;
 
 		ia = (struct in_ifaddr *)0;
@@ -345,9 +362,10 @@
 		 */
 		ro = &inp->inp_route;
 		if (ro->ro_rt &&
-		    (satosin(&ro->ro_dst)->sin_addr.s_addr !=
+		    (satosin(&ro->ro_dst)->sin_family != AF_INET ||
+		     satosin(&ro->ro_dst)->sin_addr.s_addr !=
 			sin->sin_addr.s_addr ||
-		    inp->inp_socket->so_options & SO_DONTROUTE)) {
+		     inp->inp_socket->so_options & SO_DONTROUTE)) {
 			RTFREE(ro->ro_rt);
 			ro->ro_rt = (struct rtentry *)0;
 		}
@@ -441,12 +459,26 @@
 	    inp->inp_lport, 0) != NULL) {
 		return (EADDRINUSE);
 	}
-	if (inp->inp_laddr.s_addr == INADDR_ANY) {
+	if (inp->inp_latype == IPATYPE_UNBD) {
 		if (inp->inp_lport == 0)
-			(void)in_pcbbind(inp, (struct sockaddr *)0, p);
+			(void)in_pcbbind(inp, (struct sockaddr *)0, 0, p);
 		inp->inp_laddr = ifaddr->sin_addr;
+		inp->inp_latype = IPATYPE_IPV4;
+#ifdef INET6
+		inp->inp_laddr6.s6_addr32[0] = 0;
+		inp->inp_laddr6.s6_addr32[1] = 0;
+		inp->inp_laddr6.s6_addr32[2] = htonl(0xffff);
+#endif
 	}
 	inp->inp_faddr = sin->sin_addr;
+	if (inp->inp_faddr.s_addr != INADDR_ANY) {
+		inp->inp_fatype = IPATYPE_IPV4;
+#ifdef INET6
+		inp->inp_faddr6.s6_addr32[0] = 0;
+		inp->inp_faddr6.s6_addr32[1] = 0;
+		inp->inp_faddr6.s6_addr32[2] = htonl(0xffff);
+#endif
+	}
 	inp->inp_fport = sin->sin_port;
 	in_pcbrehash(inp);
 	return (0);
@@ -457,9 +489,21 @@
 	struct inpcb *inp;
 {
 
-	inp->inp_faddr.s_addr = INADDR_ANY;
+	CLR_ADDR6(inp->inp_faddr6);
+	inp->inp_fatype = IPATYPE_UNBD;
 	inp->inp_fport = 0;
+	inp->inp_oflowinfo &= IPV6_FLOWINFO_PRIORITY;
 	in_pcbrehash(inp);
+#if (MULTI_HOMED > 0)
+	if (inp->inp_ifa)
+		IFAFREE(inp->inp_ifa);
+	inp->inp_ifa = 0;
+#endif
+	while (inp->inp_xinfo != 0) {
+		struct inp_xhdr *xp = mtod(inp->inp_xinfo, struct inp_xhdr *);
+
+		xp->inp_xfree(inp, inp->inp_xinfo);
+	}
 	if (inp->inp_socket->so_state & SS_NOFDREF)
 		in_pcbdetach(inp);
 }
@@ -476,10 +520,31 @@
 	so->so_pcb = 0;
 	sofree(so);
 	if (inp->inp_options)
-		(void)m_free(inp->inp_options);
+		m_freem(inp->inp_options);
 	if (inp->inp_route.ro_rt)
 		rtfree(inp->inp_route.ro_rt);
+#ifndef INET6
 	ip_freemoptions(inp->inp_moptions);
+#else
+	if (inp->inp_moptions) {
+		if (inp->inp_flags & INP_COMPATV4)
+			ip_freemoptions(inp->inp_moptions);
+		else
+			ip6_freemoptions(inp->inp_moptions);
+	}
+	if (inp->inp_soptions.lh_first)
+		ip6_freesoptions(inp);
+#if (MULTI_HOMED > 0)
+	if (inp->inp_ifa)
+		IFAFREE(inp->inp_ifa);
+	inp->inp_ifa = 0;
+#endif
+#endif
+	while (inp->inp_xinfo != 0) {
+		struct inp_xhdr *xp = mtod(inp->inp_xinfo, struct inp_xhdr *);
+
+		xp->inp_xfree(inp, inp->inp_xinfo);
+	}
 	zfreei(ipi->ipi_zone, inp);
 }
 
@@ -603,10 +668,14 @@
 	errno = inetctlerrmap[cmd];
 	s = splnet();
 	for (inp = head->lh_first; inp != NULL;) {
-		if (inp->inp_faddr.s_addr != faddr.s_addr ||
+		if ((inp->inp_flags & INP_COMPATV4) == 0 ||
+		    (inp->inp_fatype & IPATYPE_IPV4) == 0 ||
+		    inp->inp_faddr.s_addr != faddr.s_addr ||
 		    inp->inp_socket == 0 ||
 		    (lport && inp->inp_lport != lport) ||
-		    (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
+		    (laddr.s_addr &&
+		     ((inp->inp_latype & IPATYPE_IPV4) == 0 ||
+		      inp->inp_laddr.s_addr != laddr.s_addr)) ||
 		    (fport && inp->inp_fport != fport)) {
 			inp = inp->inp_list.le_next;
 			continue;
@@ -657,7 +726,7 @@
  * After a routing change, flush old routing
  * and allocate a (hopefully) better one.
  */
-static void
+void
 in_rtchange(inp, errno)
 	register struct inpcb *inp;
 	int errno;
@@ -694,7 +763,10 @@
 		 */
 		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
 		for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
-			if (inp->inp_faddr.s_addr == INADDR_ANY &&
+			if ((inp->inp_flags & INP_COMPATV4) == 0)
+				continue;
+			if (inp->inp_fatype == IPATYPE_UNBD &&
+			    (inp->inp_latype & IPATYPE_IPV4) &&
 			    inp->inp_laddr.s_addr == laddr.s_addr &&
 			    inp->inp_lport == lport) {
 				/*
@@ -730,13 +802,16 @@
 			 */
 			for (inp = phd->phd_pcblist.lh_first; inp != NULL;
 			    inp = inp->inp_portlist.le_next) {
+				if ((inp->inp_flags & INP_COMPATV4) == 0)
+					continue;
 				wildcard = 0;
-				if (inp->inp_faddr.s_addr != INADDR_ANY)
+				if (inp->inp_fatype != IPATYPE_UNBD)
 					wildcard++;
-				if (inp->inp_laddr.s_addr != INADDR_ANY) {
+				if (inp->inp_latype != IPATYPE_UNBD) {
 					if (laddr.s_addr == INADDR_ANY)
 						wildcard++;
-					else if (inp->inp_laddr.s_addr != laddr.s_addr)
+					else if ((inp->inp_latype & IPATYPE_IPV4) == 0 ||
+						 inp->inp_laddr.s_addr != laddr.s_addr)
 						continue;
 				} else {
 					if (laddr.s_addr != INADDR_ANY)
@@ -774,7 +849,10 @@
 	 */
 	head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
 	for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
-		if (inp->inp_faddr.s_addr == faddr.s_addr &&
+		if ((inp->inp_flags & INP_COMPATV4) != 0 &&
+		    (inp->inp_fatype & IPATYPE_IPV4) != 0 &&
+		    inp->inp_faddr.s_addr == faddr.s_addr &&
+		    (inp->inp_latype & IPATYPE_IPV4) != 0 &&
 		    inp->inp_laddr.s_addr == laddr.s_addr &&
 		    inp->inp_fport == fport &&
 		    inp->inp_lport == lport) {
@@ -789,11 +867,13 @@
 
 		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
 		for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
-			if (inp->inp_faddr.s_addr == INADDR_ANY &&
+			if ((inp->inp_flags & INP_COMPATV4) != 0 &&
+			    inp->inp_fatype == IPATYPE_UNBD &&
 			    inp->inp_lport == lport) {
-				if (inp->inp_laddr.s_addr == laddr.s_addr)
+				if ((inp->inp_latype & IPATYPE_IPV4) != 0 &&
+				    inp->inp_laddr.s_addr == laddr.s_addr)
 					return (inp);
-				else if (inp->inp_laddr.s_addr == INADDR_ANY)
+				else if (inp->inp_latype == IPATYPE_UNBD)
 					local_wild = inp;
 			}
 		}
diff -uN src-current/sys/netinet/in_pcb.h src-current-ipv6/sys/netinet/in_pcb.h
--- src-current/sys/netinet/in_pcb.h
+++ src-current-ipv6/sys/netinet/in_pcb.h
@@ -46,6 +46,24 @@
  * up (to a socket structure) and down (to a protocol-specific)
  * control block.
  */
+/*
+ * because IPv6 addresses are huge !
+ */
+union route_6 {
+    struct route route;
+    struct {
+	struct	rtentry *space_rt;
+	struct	sockaddr_in6 spare_dst;
+    } spare_route6;
+};
+union in_addr_6 {
+    struct {
+	u_int32_t spare[3];
+	struct	  in_addr addr;
+    } in_addr_4;
+    struct  in6_addr addr6;
+};
+
 LIST_HEAD(inpcbhead, inpcb);
 LIST_HEAD(inpcbporthead, inpcbport);
 typedef	u_quad_t	inp_gen_t;
@@ -58,24 +76,33 @@
  */
 struct inpcb {
 	LIST_ENTRY(inpcb) inp_hash;	/* hash list */
-	struct	in_addr inp_faddr;	/* foreign host table entry */
-	struct	in_addr inp_laddr;	/* local host table entry */
+	u_int32_t inp_iflowinfo;	/* input flow label */
+	union	in_addr_6 inp_faddr_6;	/* foreign host table entry */
 	u_short	inp_fport;		/* foreign port */
+	u_int16_t inp_fatype;		/* foreign address type */
+	u_int32_t inp_oflowinfo;	/* output flow label & priority */
+	union	in_addr_6 inp_laddr_6;	/* local host table entry */
 	u_short	inp_lport;		/* local port */
+	u_int16_t inp_latype;		/* local address type */
 	LIST_ENTRY(inpcb) inp_list;	/* list for all PCBs of this proto */
 	caddr_t	inp_ppcb;		/* pointer to per-protocol pcb */
 	struct	inpcbinfo *inp_pcbinfo;	/* PCB list info */
 	struct	socket *inp_socket;	/* back pointer to socket */
-	struct	mbuf *inp_options;	/* IP options */
-	struct	route inp_route;	/* placeholder for routing entry */
+	union	route_6 inp_route_6;	/* placeholder for routing entry */
+	struct	ifaddr *inp_ifa;	/* interface address to use */
+#define INP_IFA	(inp ? inp->inp_ifa : (struct ifaddr *)0)
 	int	inp_flags;		/* generic IP/datagram flags */
-	u_char	inp_ip_tos;		/* type of service proto */
-	u_char	inp_ip_ttl;		/* time to live proto */
-	u_char	inp_ip_p;		/* protocol proto */
-	u_char	pad[1];			/* alignment */
+	u_char  inp_proto;		/* protocol */
+	u_char  inp_tos;		/* type of service */
+	u_char  inp_ttl;		/* time to live */
+	u_char  inp_rcvttl;		/* received time to live */
+	struct	ifnet *inp_rcvif;	/* received interface */
+	struct	mbuf *inp_options;	/* IP options */
 	struct	ip_moptions *inp_moptions; /* IP multicast options */
 	LIST_ENTRY(inpcb) inp_portlist;	/* list for this PCB's local port */
 	struct	inpcbport *inp_phd;	/* head of this list */
+	LIST_HEAD(ip_soptions, ip_seclist) inp_soptions; /* IP security */
+	struct	mbuf *inp_xinfo;	/* extensions */
 	inp_gen_t inp_gencnt;		/* generation count of this instance */
 };
 /*
@@ -111,6 +138,12 @@
 	u_short phd_port;
 };
 
+#define	inp_faddr	inp_faddr_6.in_addr_4.addr
+#define	inp_laddr	inp_laddr_6.in_addr_4.addr
+#define	inp_faddr6	inp_faddr_6.addr6
+#define	inp_laddr6	inp_laddr_6.addr6
+#define	inp_route	inp_route_6.route
+
 struct inpcbinfo {		/* XXX documentation, prefixes */
 	struct	inpcbhead *hashbase;
 	u_long	hashmask;
@@ -130,6 +163,12 @@
 #define INP_PCBPORTHASH(lport, mask) \
 	(ntohs((lport)) & (mask))
 
+/* address types */
+#define IPATYPE_UNBD		0x0	/* unbound address */
+#define IPATYPE_IPV4		0x1	/* IPv4 address */
+#define IPATYPE_IPV6		0x2	/* IPv6 address */
+#define IPATYPE_DUAL		0x3	/* both IPv4 & IPv6 address */
+
 /* flags in inp_flags: */
 #define	INP_RECVOPTS		0x01	/* receive incoming IP options */
 #define	INP_RECVRETOPTS		0x02	/* receive IP options for reply */
@@ -140,17 +179,36 @@
 #define	INP_ANONPORT		0x40	/* port chosen for user */
 #define	INP_RECVIF		0x80	/* receive incoming interface */
 #define	INP_MTUDISC		0x100	/* user can do MTU discovery */
-#define	INP_CONTROLOPTS		(INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\
-					INP_RECVIF)
+#define INP_RECVPKTINFO		0x1000	/* receive packet info */
+#define INP_RECVTTL		0x2000	/* receive TTL/hlim info */
+#define	INP_CONTROLOPTS		(INP_RECVOPTS|INP_RECVRETOPTS|\
+	INP_RECVDSTADDR|INP_RECVIF|INP_RECVPKTINFO|INP_RECVTTL)
+#define	INP_NOPROBE		0x200	/* don't trigger NUD probes */
+
+#define INP_COMPATV4		0x400	/* can be used by IPv4 stack */
+#define INP_COMPATV6		0x800	/* can be used by IPv6 stack */
+#define INP_COMPATANY		0xC00	/* can be used by any stack */
+
+#define INP_NEEDAUTH		0x4000	/* need authentication */
+#define INP_NEEDCRYPT		0x8000	/* need confidentiality */
 
 #define	INPLOOKUP_WILDCARD	1
 
 #define	sotoinpcb(so)	((struct inpcb *)(so)->so_pcb)
 
+/* extension common header */
+struct inp_xhdr {
+    void (*inp_xfree) __P((struct inpcb *, struct mbuf *));
+    int (*inp_xoutput) __P((struct mbuf *, int,
+	struct mbuf *, struct mbuf *, struct route *,
+	int, struct ip_moptions *, struct inpcb *));
+};
+
 #ifdef KERNEL
 void	in_losing __P((struct inpcb *));
 int	in_pcballoc __P((struct socket *, struct inpcbinfo *, struct proc *));
-int	in_pcbbind __P((struct inpcb *, struct sockaddr *, struct proc *));
+int	in_pcbbind __P((struct inpcb *, struct sockaddr *, int dyn,
+	    struct proc *));
 int	in_pcbconnect __P((struct inpcb *, struct sockaddr *, struct proc *));
 void	in_pcbdetach __P((struct inpcb *));
 void	in_pcbdisconnect __P((struct inpcb *));
@@ -166,8 +224,41 @@
 void	in_pcbnotify __P((struct inpcbhead *, struct sockaddr *,
 	    u_int, struct in_addr, u_int, int, void (*)(struct inpcb *, int)));
 void	in_pcbrehash __P((struct inpcb *));
+void	in_rtchange __P((struct inpcb *, int));
 int	in_setpeeraddr __P((struct socket *so, struct sockaddr **nam));
 int	in_setsockaddr __P((struct socket *so, struct sockaddr **nam));
 #endif /* KERNEL */
+
+#ifdef INET6
+int	in6_setpeeraddr __P((struct socket *so, struct sockaddr **nam));
+int	in6_setsockaddr __P((struct socket *so, struct sockaddr **nam));
+int	in6_pcbbind __P((struct inpcb *, struct sockaddr *, int, struct proc *));
+int	in6_pcbrebind __P((struct inpcb *, int));
+int	in6_pcbconnect __P((struct inpcb *, struct sockaddr *, struct proc *));
+int	in6_pcbladdr __P((struct inpcb *, struct sockaddr *,
+	    struct sockaddr_in6 **, u_int32_t *));
+int	ip_changeversion __P((int, struct socket *, struct inpcb *));
+struct inpcb *
+	in6_pcblookup __P((struct inpcbinfo *,
+	    struct in6_addr *, u_int, struct in6_addr *, u_int, int));
+struct inpcb *
+	in6_pcblookup_hash __P((struct inpcbinfo *,
+	    struct in6_addr *, u_int, struct in6_addr *, u_int, int));
+void	in6_pcbnotify __P((struct inpcbhead *, struct sockaddr *,
+	u_int, struct in6_addr *, u_int, int, void (*)(struct inpcb *, int)));
+int	in6_setifa __P((struct inpcb *, struct ifaddr *));
+void	in6_rtalloc __P((struct route *, struct ifaddr *));
+struct rtentry *
+	in6_rthost __P((struct in6_addr *));
+void	ip6_reachhint __P((struct inpcb *));
+
+int	ipsec_attach __P((struct inpcb *, struct sockaddr_ipsec *, int));
+int	ipsec_detach __P((struct inpcb *, struct sockaddr_ipsec *, int));
+int	ipsec_match __P((struct inpcb *, struct mbuf *,
+			 struct mbuf *, int));
+void	ip6_freesoptions __P((struct inpcb *));
+int	ip6_setoptions __P((struct mbuf **, struct mbuf *,
+			    struct inpcb *));
+#endif
 
 #endif /* !_NETINET_IN_PCB_H_ */
diff -uN src-current/sys/netinet/in_proto.c src-current-ipv6/sys/netinet/in_proto.c
--- src-current/sys/netinet/in_proto.c
+++ src-current-ipv6/sys/netinet/in_proto.c
@@ -34,6 +34,7 @@
  *	$Id: in_proto.c,v 1.46 1998/03/21 11:33:57 peter Exp $
  */
 
+#include "opt_inet6.h"
 #include "opt_ipdivert.h"
 #include "opt_ipx.h"
 
@@ -42,6 +43,7 @@
 #include <sys/socket.h>
 #include <sys/domain.h>
 #include <sys/protosw.h>
+#include <sys/socketvar.h>
 #include <sys/sysctl.h>
 
 #include <net/if.h>
@@ -50,7 +52,11 @@
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
 #include <netinet/ip_icmp.h>
 #include <netinet/igmp_var.h>
 #include <netinet/tcp.h>
@@ -71,6 +77,17 @@
 #include <netns/ns_if.h>
 #endif
 
+#include "sit.h"
+#include "cti.h"
+#if NSIT > 0 || NCTI > 0
+#include <netinet/if_sit6.h>
+#endif
+
+#include "gre.h"
+#if NGRE > 0
+#include <netinet/if_gre.h>
+#endif
+
 #ifdef TPIP
 void	tpip_input(), tpip_ctlinput(), tp_init(), tp_slowtimo(), tp_drain();
 int	tp_ctloutput(), tp_usrreq();
@@ -139,6 +156,22 @@
   0,
   div_init,	0,		0,		0,
   &div_usrreqs,
+},
+#endif
+#if NSIT > 0 || NCTI > 0
+{ SOCK_RAW,	&inetdomain,	IPPROTO_IPV6,	PR_ATOMIC|PR_ADDR,
+  sit_input,	0,		0,		rip_ctloutput,
+  0,
+  0,		0,		0,		0,
+  &rip_usrreqs
+},
+#endif
+#if NGRE > 0
+{ SOCK_RAW,	&inetdomain,	IPPROTO_GRE,	PR_ATOMIC|PR_ADDR,
+  gre_input,	0,		gre_ctlinput,	0,
+  0,
+  0,		0,		0,		0,
+  &rip_usrreqs
 },
 #endif
 #ifdef TPIP
diff -uN src-current/sys/netinet/if_gre.h src-current-ipv6/sys/netinet/if_gre.h
--- src-current/sys/netinet/if_gre.h
+++ src-current-ipv6/sys/netinet/if_gre.h
@@ -0,0 +1,116 @@
+/*
+ * GRE IP/IP (really ANY/IP)
+ * RFC 1701 and 1702
+ *
+ * Francis.Dupont@inria.fr March 1998,
+ * from SunOS implementation, September 1993
+ */
+
+/* header file */
+
+#ifndef _NETINET_IF_GRE_
+#define _NETINET_IF_GRE_
+
+struct gre {
+    struct ip gre_ip;		/* IP header */
+    struct gre_hdr {		/* GRE header */
+	u_int16_t gre_flgv;	/* flags & version */
+	u_int16_t gre_pt;	/* protocol type */
+    } gre_hdr;
+};
+
+#define GRE_MIN_SIZE	(sizeof (struct ip) + sizeof (struct gre_hdr))
+
+#ifdef _IP_VHL
+#define gre_ip_vhl	gre_ip.ip_vhl
+#else
+#define gre_ip_v	gre_ip.ip_v
+#define gre_ip_hl	gre_ip.ip_hl
+#endif
+#define gre_ip_tos	gre_ip.ip_tos
+#define gre_ip_len	gre_ip.ip_len
+#define gre_ip_id	gre_ip.ip_id
+#define gre_ip_off	gre_ip.ip_off
+#define gre_ip_ttl	gre_ip.ip_ttl
+#define gre_ip_p	gre_ip.ip_p
+#define gre_ip_sum	gre_ip.ip_sum
+#define gre_ip_src	gre_ip.ip_src
+#define gre_ip_dst	gre_ip.ip_dst
+#define gre_flgver	gre_hdr.gre_flgv
+#define gre_protyp	gre_hdr.gre_pt
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define GRE_HAS_CHKSUM	0x8000	/* Checksum Present */
+#define GRE_HAS_ROUTE	0x4000	/* Routing Present */
+#define GRE_HAS_KEY	0x2000	/* Key Present */
+#define GRE_HAS_SEQNB	0x1000	/* Sequence Number Present */
+#define GRE_HAS_SSR	0x0800	/* Strict Source Route */
+#define GRE_VER_MASK	0x0007	/* Version Number (mask) */
+#define GRE_VER_NB	0x0000	/* Version Number (value) */
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define GRE_HAS_CHKSUM	0x0080	/* Checksum Present */
+#define GRE_HAS_ROUTE	0x0040	/* Routing Present */
+#define GRE_HAS_KEY	0x0020	/* Key Present */
+#define GRE_HAS_SEQNB	0x0010	/* Sequence Number Present */
+#define GRE_HAS_SSR	0x0008	/* Strict Source Route */
+#define GRE_VER_MASK	0x0700	/* Version Number (mask) */
+#define GRE_VER_NB	0x0000	/* Version Number (value) */
+#endif
+
+struct gre_softc {
+    struct ifnet gre_if;	/* the interface */
+    struct in_addr gre_peer;	/* peer address */
+    struct route gre_ro;	/* route */
+    u_short gre_flags;		/* flags */
+    u_short gre_ptype;		/* protocol type */
+    u_int32_t gre_key;		/* key */
+    u_int32_t gre_iseq;		/* inband sequence number */
+    u_int32_t gre_oseq;		/* outband sequence number */
+    int gre_tpltl;		/* GRE template (length) */
+    int gre_tpltcd;		/* GRE template (checksum offset) */
+    int gre_tpltkd;		/* GRE template (key offset) */
+    int gre_tpltsd;		/* GRE template (sequence number offset) */
+    struct gre *gre_tpl;	/* GRE template (pointer) */
+};
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define GRE_SRC		0x0010	/* src address is set */
+#define GRE_DST		0x0020	/* dst address is set */
+#define GRE_PEER	0x0040	/* peer (real dst) address is set */
+#define GRE_GOOD	0x0070	/* all things are set */
+#define GRE_CANSET	0xf807	/* can be set flags */
+#define GRE_IMPLEMENTED	0xb000	/* real can be set flags */
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define GRE_SRC		0x1000	/* src address is set */
+#define GRE_DST		0x2000	/* dst address is set */
+#define GRE_PEER	0x4000	/* peer (real dst) address is set */
+#define GRE_GOOD	0x7000	/* all things are set */
+#define GRE_CANSET	0x07f8	/* can be set flags */
+#define GRE_IMPLEMENTED	0x00b0	/* real can be set flags */
+#endif
+
+#ifndef IPPROTO_GRE
+#define IPPROTO_GRE	47
+#endif
+
+struct gre_data {
+    char gre_name[IFNAMSIZ];	/* name (like struct ifreq) */
+    struct in_addr gre_peer;	/* peer address */
+    u_int16_t gre_flags;	/* flags & version */
+    u_int16_t gre_ptype;	/* protocol type */
+    u_int32_t gre_key;		/* key */
+    u_int32_t gre_seq;		/* (outband) sequence number */
+};
+
+#define SIOCGIFGRED	_IOWR('i', 45, struct gre_data)
+#define SIOCSIFGRED	_IOW('i', 46, struct gre_data)
+
+#ifdef KERNEL
+
+void gre_input __P((struct mbuf *, int));
+void gre_ctlinput __P((int, struct sockaddr *, void *));
+
+#endif
+#endif
diff -uN src-current/sys/netinet/ip6.h src-current-ipv6/sys/netinet/ip6.h
--- src-current/sys/netinet/ip6.h
+++ src-current-ipv6/sys/netinet/ip6.h
@@ -0,0 +1,196 @@
+#ifndef _NETINET_IP6_H_
+#define _NETINET_IP6_H_
+
+/*
+ * Definitions for internet protocol version 6.
+ * Per RFC 1883
+ */
+
+/*
+ * Structure of an IPv6 (first) header.
+ */
+
+struct ipv6 {
+	u_int32_t ip6_head;		/* version and flow label */
+	u_int16_t ip6_len;		/* payload length */
+	u_int8_t  ip6_nh;		/* next header */
+	u_int8_t  ip6_hlim;		/* hop limit */
+	struct    in6_addr ip6_src;	/* source address */
+	struct	  in6_addr ip6_dst;	/* destination address */
+};
+
+#define IP6_MMTU	576		/* minimal MTU and reassembly */
+
+/*
+ * Definitions of next header field values.
+ */
+
+#define IP6_NHDR_HOP	0	/* hop-by-hop IPv6 header */
+#define IP6_NHDR_RT	43	/* routing IPv6 header */
+#define IP6_NHDR_FRAG	44	/* fragment IPv6 header */
+#define IP6_NHDR_AUTH	51	/* authentication IPv6 header */
+#define IP6_NHDR_ESP	50	/* encryption IPv6 header */
+#define IP6_NHDR_DOPT	60	/* destination options IPv6 header */
+#define IP6_NHDR_NONH	59	/* no next header */
+
+/*
+ * Fragment Header.
+ */
+
+struct ipv6_fraghdr {
+	u_int8_t  if6_nh;	/* next header */
+	u_int8_t  if6_res;	/* reserved */
+	u_int16_t if6_off;	/* offset */
+#define IP6_MF 0x1		/* more flag */
+#define IP6_OFFMASK 0xfff8	/* mask of real offset field */
+	u_int32_t if6_id;	/* identifier */
+};
+
+/*
+ * Hop-by-Hop Options Header.
+ */
+
+struct ipv6_h2hhdr {
+	u_int8_t  ih6_nh;	/* next header */
+	u_int8_t  ih6_hlen;	/* header extension length */
+	u_int16_t ih6_pad1;	/* to 4 byte length */
+	u_int32_t ih6_pad2;	/* to 8 byte length */
+};
+
+/*
+ * Routing Header.
+ */
+
+struct ipv6_rthdr {
+	u_int8_t  ir6_nh;	/* next header */
+	u_int8_t  ir6_hlen;	/* header extension length */
+	u_int8_t  ir6_type;	/* routing type */
+#define IP6_LSRRT 0		/* type 0: loose source route */
+	u_int8_t  ir6_sglt;	/* index of next address */
+	u_int32_t ir6_slmsk;	/* strict/loose bit mask */
+};
+#define IP6_RT_MAX	23	/* maximum number of addresses */
+#define IP6_RT_SLMSK	0x00ffffff
+#define IP6_RT_SLBIT(n)	(1 << (IP6_RT_MAX - n))
+
+/*
+ * Destination Options Header.
+ */
+
+struct ipv6_dopthdr {
+	u_int8_t  io6_nh;	/* next header */
+	u_int8_t  io6_hlen;	/* header extension length */
+	u_int16_t io6_pad1;	/* to 4 byte length */
+	u_int32_t io6_pad2;	/* to 8 byte length */
+};
+
+/*
+ * Authentication Header.
+ */
+
+struct ipv6_authhdr {
+	u_int8_t  ah6_nh;	/* next header */
+	u_int8_t  ah6_hlen;	/* header extension length */
+	u_int16_t ah6_pad;	/* to 4 byte length */
+	u_int32_t ah6_spi;	/* security parameter index */
+};
+
+/*
+ * Encryption Security Payload Header.
+ */
+
+struct ipv6_esphdr {
+	u_int32_t esp6_spi;	/* security parameter index */
+};
+
+#define IP6_OPT_PAD1	0	/* one-byte pad option type */
+#define IP6_OPT_PADN	1	/* N-byte pad option type */
+
+/*
+ * IPv6 implementation parameters.
+ */
+
+#define	IP6FRAGTTL	120		/* time to live for frags, slowhz */
+
+/*
+ * Header structure of BSD advanced API
+ */
+
+#ifdef STEVENS_API
+
+struct ip6_hdr {
+    union {
+	struct ip6_hdrctl {
+	    u_int32_t	ip6_un1_flow;	/* 24 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, 4 bits priority */
+    } ip6_ctlun;
+    struct in6_addr ip6_src;		/* source address */
+    struct in6_addr ip6_dst;		/* destination address */
+};
+
+#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_hops
+
+/* Hop-by-Hop options header */
+struct ip6_hbh {
+    u_int8_t	ip6h_nxt;	/* next header */
+    u_int8_t	ip6h_len;	/* length in units of 8 octets */
+	/* followed by options */
+};
+
+/* Destination options header */
+struct ip6_dest {
+    u_int8_t	ip6d_nxt;	/* next header */
+    u_int8_t	ip6d_len;	/* length in units of 8 octets */
+	/* followed by options */
+};
+
+/* 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 */
+};
+
+/* 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 */
+};
+
+/* 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 */
+};
+
+#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_FLAG		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_FLAG		0x0100	/* more-fragments flag */
+#endif
+
+#endif
+
+#endif
diff -uN src-current/sys/netinet/ip6_fw.c src-current-ipv6/sys/netinet/ip6_fw.c
--- src-current/sys/netinet/ip6_fw.c
+++ src-current-ipv6/sys/netinet/ip6_fw.c
@@ -0,0 +1,1061 @@
+/*
+ * Copyright (c) 1993 Daniel Boulet
+ * Copyright (c) 1994 Ugen J.S.Antsilevich
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * Redistribution in binary form may occur without any restrictions.
+ * Obviously, it would be nice if you gave credit where credit is due
+ * but requiring it would be too onerous.
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind.
+ *
+ *	$Id: ip_fw.c,v 1.14.4.9 1996/06/25 03:16:41 alex Exp $
+ */
+
+/*
+ * Implement IPv6 packet firewall
+ */
+
+#ifndef IPFIREWALL_MODULE
+#include "opt_ip6fw.h"
+#include "opt_inet6.h"
+#ifndef INET6
+#error IPFIREWALL requires INET6.
+#endif /* INET6 */
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ip6_opts.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip6_icmp.h>
+#include <netinet/ip6_fw.h>
+
+static int fw_debug = 1;
+#ifdef IP6FIREWALL_VERBOSE
+static int fw_verbose = 1;
+#else
+static int fw_verbose = 0;
+#endif
+#ifdef IP6FIREWALL_VERBOSE_LIMIT
+static int fw_verbose_limit = IP6FIREWALL_VERBOSE_LIMIT;
+#else
+static int fw_verbose_limit = 0;
+#endif
+
+static LIST_HEAD (ip6_fw_head, ip6_fw_chain) ip6_fw_chain;
+
+static MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
+
+#ifdef SYSCTL_NODE
+SYSCTL_NODE(net_inet6_ipv6, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
+SYSCTL_INT(net_inet6_ipv6_fw, OID_AUTO, debug, CTLFLAG_RW, &fw_debug, 0, "");
+SYSCTL_INT(net_inet6_ipv6_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw_verbose, 0, "");
+SYSCTL_INT(net_inet6_ipv6_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, "");
+#endif
+
+#define dprintf(a)	if (!fw_debug); else printf a
+
+#define print_ip(a)	printf("%s", ip6_sprintf(a));
+
+#define dprint_ip(a)	if (!fw_debug); else print_ip(a)
+
+static int	add_entry __P((struct ip6_fw_head *chainptr, struct ip6_fw *frwl));
+static int	del_entry __P((struct ip6_fw_head *chainptr, u_short number));
+static int	zero_entry __P((struct mbuf *m));
+static struct ip6_fw *
+		check_ipfw_struct __P(( struct ip6_fw *frwl));
+static int	ipopts_match __P((struct ipv6 *ip, struct ip6_fw *f));
+static int	port_match __P((u_short *portptr, int nports, u_short port,
+				int range_flag));
+static int	tcpflg_match __P((struct tcphdr *tcp, struct ip6_fw *f));
+static void	ipfw_report __P((struct ip6_fw *f, struct ipv6 *ip,
+				 struct ifnet *rif, struct ifnet *oif));
+
+static char err_prefix[] = "ip6_fw_ctl:";
+
+/*
+ * Returns 1 if the port is matched by the vector, 0 otherwise
+ */
+static __inline int 
+port_match(u_short *portptr, int nports, u_short port, int range_flag)
+{
+	if (!nports)
+		return 1;
+	if (range_flag) {
+		if (portptr[0] <= port && port <= portptr[1]) {
+			return 1;
+		}
+		nports -= 2;
+		portptr += 2;
+	}
+	while (nports-- > 0) {
+		if (*portptr++ == port) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int
+tcpflg_match(struct tcphdr *tcp, struct ip6_fw *f)
+{
+	u_char		flg_set, flg_clr;
+	
+	if ((f->fw_tcpf & IP6_FW_TCPF_ESTAB) &&
+	    (tcp->th_flags & (IP6_FW_TCPF_RST | IP6_FW_TCPF_ACK)))
+		return 1;
+
+	flg_set = tcp->th_flags & f->fw_tcpf;
+	flg_clr = tcp->th_flags & f->fw_tcpnf;
+
+	if (flg_set != f->fw_tcpf)
+		return 0;
+	if (flg_clr)
+		return 0;
+
+	return 1;
+}
+
+static int
+icmptype_match(struct icmpv6 *icmp, struct ip6_fw *f)
+{
+	int type;
+
+	if (!(f->fw_flg & IP6_FW_F_ICMPBIT))
+		return(1);
+
+	type = icmp->icmp6_type;
+
+	/* check for matching type in the bitmap */
+	if (type < IP6_FW_ICMPTYPES_MAX &&
+	    (f->fw_uar.fw_icmptypes[type / (sizeof(unsigned) * 8)] &
+	     (1U << (type % (8 * sizeof(unsigned))))))
+		return(1);
+
+	return(0); /* no match */
+}
+
+static int
+ipopts_match(struct ipv6 *ip, struct ip6_fw *f)
+{
+	/* not yet !!! */
+	return 0;
+}
+
+static int
+is_icmp_query(struct ipv6 *ip)
+{
+	const struct icmpv6 *icmp;
+	int icmp_type;
+
+	icmp = (struct icmpv6 *)(ip + 1);
+	icmp_type = icmp->icmp6_type;
+
+	if (icmp_type == ICMP6_ECHO
+	    || icmp_type == ICMP6_SOLICITATION_RT
+	    || icmp_type == ICMP6_GROUPMEM_QUERY
+	    || icmp_type == ICMP6_SOLICITATION_ND)
+		return(1);
+
+	return(0);
+}
+
+static __inline int
+iface_match(struct ifnet *ifp, union ip6_fw_if *ifu, int byname)
+{
+	/* Check by name or by IP address */
+	if (byname) {
+		/* Check unit number (-1 is wildcard) */
+		if (ifu->fu_via_if.unit != -1
+		    && ifp->if_unit != ifu->fu_via_if.unit)
+			return(0);
+		/* Check name */
+		if (strncmp(ifp->if_name, ifu->fu_via_if.name, FW6_IFNLEN))
+			return(0);
+		return(1);
+	} else if (IS_ANYADDR6(ifu->fu_via_ip)) {	/* Zero == wildcard */
+		struct ifaddr *ia;
+
+		for (ia = ifp->if_addrhead.tqh_first;
+		    ia != NULL; ia = ia->ifa_link.tqe_next) {
+			if (ia->ifa_addr == NULL)
+				continue;
+			if (ia->ifa_addr->sa_family != AF_INET6)
+				continue;
+			if (SAME_ADDR6(ifu->fu_via_ip,
+				       ((struct sockaddr_in6 *)(ia->ifa_addr))->sin6_addr))
+				continue;
+			return(1);
+		}
+		return(0);
+	}
+	return(1);
+}
+
+static void
+ipfw_report(struct ip6_fw *f, struct ipv6 *ip,
+	struct ifnet *rif, struct ifnet *oif)
+{
+	static u_int64_t counter;
+	struct tcphdr *tcp = (struct tcphdr *) (ip + 1);
+	struct udphdr *udp = (struct udphdr *) (ip + 1);
+	struct icmpv6 *icmp = (struct icmpv6 *) (ip + 1);
+	int count;
+
+	count = f ? f->fw_pcnt : ++counter;
+	if (fw_verbose_limit != 0 && count > fw_verbose_limit)
+		return;
+
+	/* Print command name */
+	printf("ip6fw: %d ", f ? f->fw_number : -1);
+	if (!f)
+		printf("Refuse");
+	else
+		switch (f->fw_flg & IP6_FW_F_COMMAND) {
+		case IP6_FW_F_DENY:
+			printf("Deny");
+			break;
+		case IP6_FW_F_REJECT:
+			if (f->fw_reject_code == IP6_FW_REJECT_RST)
+				printf("Reset");
+			else
+				printf("Unreach");
+			break;
+		case IP6_FW_F_ACCEPT:
+			printf("Accept");
+			break;
+		case IP6_FW_F_COUNT:
+			printf("Count");
+			break;
+		case IP6_FW_F_DIVERT:
+			printf("Divert %d", f->fw_divert_port);
+			break;
+		case IP6_FW_F_TEE:
+			printf("Tee %d", f->fw_divert_port);
+			break;
+		case IP6_FW_F_SKIPTO:
+			printf("SkipTo %d", f->fw_skipto_rule);
+			break;
+		default:	
+			printf("UNKNOWN");
+			break;
+		}
+	printf(" ");
+
+	switch (ip->ip6_nh) {
+	case IPPROTO_TCP:
+		printf("TCP ");
+		print_ip(&ip->ip6_src);
+		printf(":%d ", ntohs(tcp->th_sport));
+		print_ip(&ip->ip6_dst);
+		printf(":%d", ntohs(tcp->th_dport));
+		break;
+	case IPPROTO_UDP:
+		printf("UDP ");
+		print_ip(&ip->ip6_src);
+		printf(":%d ", ntohs(udp->uh_sport));
+		print_ip(&ip->ip6_dst);
+		printf(":%d", ntohs(udp->uh_dport));
+		break;
+	case IPPROTO_ICMPV6:
+		printf("ICMPv6:%u.%u ", icmp->icmp6_type, icmp->icmp6_code);
+		print_ip(&ip->ip6_src);
+		printf(" ");
+		print_ip(&ip->ip6_dst);
+		break;
+	default:
+		printf("NH:%d ", ip->ip6_nh);
+		print_ip(&ip->ip6_src);
+		printf(" ");
+		print_ip(&ip->ip6_dst);
+		break;
+	}
+	printf("\n");
+	if (oif)
+		printf(" out via %s%d", oif->if_name, oif->if_unit);
+	else if (rif)
+		printf(" in via %s%d", rif->if_name, rif->if_unit);
+	printf("\n");
+	if (fw_verbose_limit != 0 && count == fw_verbose_limit)
+		printf("ip6fw: limit reached on rule #%d\n",
+		f ? f->fw_number : -1);
+}
+
+/*
+ * Parameters:
+ *
+ *	ip	Pointer to packet header (struct ipv6 *)
+ *	oif	Outgoing interface, or NULL if packet is incoming
+ *	ignport	Ignore all divert/tee rules to this port (if non-zero)
+ *	*m	The packet; we set to NULL when/if we nuke it.
+ *
+ * Return value:
+ *
+ *	0	The packet is to be accepted and routed normally OR
+ *      	the packet was denied/rejected and has been dropped;
+ *		in the latter case, *m is equal to NULL upon return.
+ *	port	Divert the packet to port.
+ */
+
+static int 
+ip6_fw_chk(struct ipv6 **pip,
+	   struct ifnet *oif, int ignport, struct mbuf **m)
+{
+	struct ip6_fw_chain *chain;
+	struct ip6_fw *rule = NULL;
+	struct ipv6 *ip = *pip;
+	struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
+	struct in6_addr *src, *dst;
+	u_short src_port, dst_port;
+	u_short len = 0;
+
+	src = &ip->ip6_src;
+	dst = &ip->ip6_dst;
+
+	/*
+	 * Go down the chain, looking for enlightment
+	 */
+	for (chain=LIST_FIRST(&ip6_fw_chain); chain; chain = LIST_NEXT(chain, chain)) {
+		register struct ip6_fw *const f = chain->rule;
+		if (oif) {
+			/* Check direction outbound */
+			if (!(f->fw_flg & IP6_FW_F_OUT))
+				continue;
+		} else {
+			/* Check direction inbound */
+			if (!(f->fw_flg & IP6_FW_F_IN))
+				continue;
+		}
+
+		/* Fragments */
+		if ((f->fw_flg & IP6_FW_F_FRAG) && 1)
+			continue;
+
+#define CMPMASK(x, m, y)	\
+	((((x).s6_addr32[0] & (m).s6_addr32[0]) == (y).s6_addr32[0]) && \
+	 (((x).s6_addr32[1] & (m).s6_addr32[1]) == (y).s6_addr32[1]) && \
+	 (((x).s6_addr32[2] & (m).s6_addr32[2]) == (y).s6_addr32[2]) && \
+	 (((x).s6_addr32[3] & (m).s6_addr32[3]) == (y).s6_addr32[3]))
+
+		/* If src-addr doesn't match, not this rule. */
+		if (((f->fw_flg & IP6_FW_F_INVSRC) != 0)
+		    ^ !CMPMASK(*src, f->fw_smsk, f->fw_src))
+			continue;
+
+		/* If dest-addr doesn't match, not this rule. */
+		if (((f->fw_flg & IP6_FW_F_INVDST) != 0)
+		    ^ !CMPMASK(*dst, f->fw_dmsk, f->fw_dst))
+			continue;
+
+		/* Interface check */
+		if ((f->fw_flg & IF6_FW_F_VIAHACK) == IF6_FW_F_VIAHACK) {
+			struct ifnet *const iface = oif ? oif : rif;
+
+			/* Backwards compatibility hack for "via" */
+			if (!iface || !iface_match(iface,
+			    &f->fw_in_if, f->fw_flg & IP6_FW_F_OIFNAME))
+				continue;
+		} else {
+			/* Check receive interface */
+			if ((f->fw_flg & IP6_FW_F_IIFACE)
+			    && (!rif || !iface_match(rif,
+			      &f->fw_in_if, f->fw_flg & IP6_FW_F_IIFNAME)))
+				continue;
+			/* Check outgoing interface */
+			if ((f->fw_flg & IP6_FW_F_OIFACE)
+			    && (!oif || !iface_match(oif,
+			      &f->fw_out_if, f->fw_flg & IP6_FW_F_OIFNAME)))
+				continue;
+		}
+
+		/* Check IP options */
+		if (f->fw_ipopt != f->fw_ipnopt && !ipopts_match(ip, f))
+			continue;
+
+		/* Check protocol; if wildcard, match */
+		if (f->fw_prot == IPPROTO_IP)
+			goto got_match;
+
+		/* If different, don't match */
+		if (ip->ip6_nh != f->fw_prot) 
+			continue;
+
+#define PULLUP_TO(len)	do {						\
+			    if ((*m)->m_len < (len)			\
+				&& (*m = m_pullup(*m, (len))) == 0) {	\
+				    goto bogusfrag;			\
+			    }						\
+			    *pip = ip = mtod(*m, struct ipv6 *);	\
+			} while (0)
+
+		/* Protocol specific checks */
+		switch (ip->ip6_nh) {
+		case IPPROTO_TCP:
+		    {
+			struct tcphdr *tcp;
+			PULLUP_TO(sizeof(*ip)+14);
+			tcp = (struct tcphdr *)(ip + 1);
+			if (f->fw_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f))
+				continue;
+			src_port = ntohs(tcp->th_sport);
+			dst_port = ntohs(tcp->th_dport);
+			goto check_ports;
+		    }
+
+		case IPPROTO_UDP:
+		    {
+			struct udphdr *udp;
+			PULLUP_TO(sizeof(*ip)+4);
+			udp = (struct udphdr *)(ip + 1);
+			src_port = ntohs(udp->uh_sport);
+			dst_port = ntohs(udp->uh_dport);
+check_ports:
+			if (!port_match(&f->fw_uar.fw_pts[0],
+			    IP6_FW_GETNSRCP(f), src_port,
+			    f->fw_flg & IP6_FW_F_SRNG))
+				continue;
+			if (!port_match(&f->fw_uar.fw_pts[IP6_FW_GETNSRCP(f)],
+			    IP6_FW_GETNDSTP(f), dst_port,
+			    f->fw_flg & IP6_FW_F_DRNG)) 
+				continue;
+			break;
+		    }
+
+		case IPPROTO_ICMPV6:
+		    {
+			struct icmpv6 *icmp;
+			PULLUP_TO(sizeof(*ip)+sizeof(*icmp));
+			icmp = (struct icmpv6 *)(ip + 1);
+			if (!icmptype_match(icmp, f))
+				continue;
+			break;
+		    }
+#undef PULLUP_TO
+
+bogusfrag:
+			if (fw_verbose)
+				ipfw_report(NULL, ip, rif, oif);
+			goto dropit;
+		}
+
+got_match:
+		/* Ignore divert/tee rule if socket port is "ignport" */
+		switch (f->fw_flg & IP6_FW_F_COMMAND) {
+		case IP6_FW_F_DIVERT:
+		case IP6_FW_F_TEE:
+			if (f->fw_divert_port == ignport)
+				continue;       /* ignore this rule */
+			break;
+		}
+
+		/* Update statistics */
+		f->fw_pcnt += 1;
+		f->fw_bcnt += ip->ip6_len + sizeof(struct ipv6);
+		f->timestamp = time_second;
+
+		/* Log to console if desired */
+		if ((f->fw_flg & IP6_FW_F_PRN) && fw_verbose)
+			ipfw_report(f, ip, rif, oif);
+
+		/* Take appropriate action */
+		switch (f->fw_flg & IP6_FW_F_COMMAND) {
+		case IP6_FW_F_ACCEPT:
+			return(0);
+		case IP6_FW_F_COUNT:
+			continue;
+		case IP6_FW_F_DIVERT:
+			return(f->fw_divert_port);
+		case IP6_FW_F_TEE:
+			/*
+			 * XXX someday tee packet here, but beware that you
+			 * can't use m_copym() or m_copypacket() because
+			 * the divert input routine modifies the mbuf
+			 * (and these routines only increment reference
+			 * counts in the case of mbuf clusters), so need
+			 * to write custom routine.
+			 */
+			continue;
+		case IP6_FW_F_SKIPTO:
+#ifdef DIAGNOSTIC
+			while (LIST_NEXT(chain, chain)
+			    && LIST_NEXT(chain, chain)->rule->fw_number
+				< f->fw_skipto_rule)
+#else
+			while (LIST_NEXT(chain, chain)->rule->fw_number
+			    < f->fw_skipto_rule)
+#endif
+				chain = LIST_NEXT(chain, chain);
+			continue;
+		}
+
+		/* Deny/reject this packet using this rule */
+		rule = f;
+		break;
+	}
+
+#ifdef DIAGNOSTIC
+	/* Rule 65535 should always be there and should always match */
+	if (!chain)
+		panic("ip6_fw: chain");
+#endif
+
+	/*
+	 * At this point, we're going to drop the packet.
+	 * Send a reject notice if all of the following are true:
+	 *
+	 * - The packet matched a reject rule
+	 * - The packet is not an ICMPv6 packet, or is an ICMPv6 query packet
+	 * - The packet is not a multicast or broadcast packet
+	 */
+	if ((rule->fw_flg & IP6_FW_F_COMMAND) == IP6_FW_F_REJECT
+	    && (ip->ip6_nh != IPPROTO_ICMPV6 || is_icmp_query(ip))
+	    && !((*m)->m_flags & (M_BCAST|M_MCAST))
+	    && !IS_MULTIADDR6(ip->ip6_dst)) {
+		switch (rule->fw_reject_code) {
+#ifdef notyet
+		case IP6_FW_REJECT_RST:
+		  {
+			struct tcphdr *const tcp =
+				(struct tcphdr *) (ip + 1);
+			struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip;
+
+			if (offset != 0 || (tcp->th_flags & TH_RST))
+				break;
+			ti.ti_i = *((struct ipovly *) ip);
+			ti.ti_t = *tcp;
+			bcopy(&ti, ip, sizeof(ti));
+			NTOHL(tip->ti_seq);
+			NTOHL(tip->ti_ack);
+			tip->ti_len = ip->ip_len - hlen - (tip->ti_off << 2);
+			if (tcp->th_flags & TH_ACK) {
+				tcp_respond(NULL, tip, *m,
+				    (tcp_seq)0, ntohl(tcp->th_ack), TH_RST);
+			} else {
+				if (tcp->th_flags & TH_SYN)
+					tip->ti_len++;
+				tcp_respond(NULL, tip, *m, tip->ti_seq
+				    + tip->ti_len, (tcp_seq)0, TH_RST|TH_ACK);
+			}
+			*m = NULL;
+			break;
+		  }
+#endif
+		default:	/* Send an ICMPv6 unreachable using code */
+			icmp6_error(*m, ICMP6_UNREACH,
+				    rule->fw_reject_code, NULL);
+			*m = NULL;
+			break;
+		}
+	}
+
+dropit:
+	/*
+	 * Finally, drop the packet.
+	 */
+	if (*m) {
+		m_freem(*m);
+		*m = NULL;
+	}
+	return(0);
+}
+
+static int
+add_entry(struct ip6_fw_head *chainptr, struct ip6_fw *frwl)
+{
+	struct ip6_fw *ftmp = 0;
+	struct ip6_fw_chain *fwc = 0, *fcp, *fcpl = 0;
+	u_short nbr = 0;
+	int s;
+
+	fwc = malloc(sizeof *fwc, M_IPFW, M_DONTWAIT);
+	ftmp = malloc(sizeof *ftmp, M_IPFW, M_DONTWAIT);
+	if (!fwc || !ftmp) {
+		dprintf(("malloc said no\n", err_prefix));
+		if (fwc)  free(fwc, M_IPFW);
+		if (ftmp) free(ftmp, M_IPFW);
+		return (ENOSPC);
+	}
+
+	bcopy(frwl, ftmp, sizeof(struct ip6_fw));
+	ftmp->fw_in_if.fu_via_if.name[FW6_IFNLEN - 1] = '\0';
+	ftmp->fw_pcnt = 0L;
+	ftmp->fw_bcnt = 0L;
+	fwc->rule = ftmp;
+	
+	s = splnet();
+
+	if (!LIST_FIRST(chainptr)) {
+		LIST_INSERT_HEAD(chainptr, fwc, chain);
+		splx(s);
+		return(0);
+	} else if (ftmp->fw_number == (u_short)-1) {
+		if (fwc)  free(fwc, M_IPFW);
+		if (ftmp) free(ftmp, M_IPFW);
+		splx(s);
+		dprintf(("%s bad rule number\n", err_prefix));
+		return (EINVAL);
+	}
+
+	/* If entry number is 0, find highest numbered rule and add 100 */
+	if (ftmp->fw_number == 0) {
+		for (fcp = LIST_FIRST(chainptr); fcp; fcp = LIST_NEXT(fcp, chain)) {
+			if (fcp->rule->fw_number != (u_short)-1)
+				nbr = fcp->rule->fw_number;
+			else
+				break;
+		}
+		if (nbr < (u_short)-1 - 100)
+			nbr += 100;
+		ftmp->fw_number = nbr;
+	}
+
+	/* Got a valid number; now insert it, keeping the list ordered */
+	for (fcp = LIST_FIRST(chainptr); fcp; fcp = LIST_NEXT(fcp, chain)) {
+		if (fcp->rule->fw_number > ftmp->fw_number) {
+			if (fcpl) {
+				LIST_INSERT_AFTER(fcpl, fwc, chain);
+			} else {
+				LIST_INSERT_HEAD(chainptr, fwc, chain);
+			}
+			break;
+		} else {
+			fcpl = fcp;
+		}
+	}
+
+	splx(s);
+	return (0);
+}
+
+static int
+del_entry(struct ip6_fw_head *chainptr, u_short number)
+{
+	struct ip6_fw_chain *fcp;
+
+	fcp = LIST_FIRST(chainptr);
+	if (number != (u_short)-1) {
+		for (; fcp; fcp = LIST_NEXT(fcp, chain)) {
+			if (fcp->rule->fw_number == number) {
+				int s;
+
+				/* prevent access to rules while removing them */
+				s = splnet();
+				while (fcp && fcp->rule->fw_number == number) {
+					struct ip6_fw_chain *next;
+
+					next = LIST_NEXT(fcp, chain);
+					LIST_REMOVE(fcp, chain);
+					free(fcp->rule, M_IPFW);
+					free(fcp, M_IPFW);
+					fcp = next;
+				}
+				splx(s);
+				return 0;
+			}
+		}
+	}
+
+	return (EINVAL);
+}
+
+static int
+zero_entry(struct mbuf *m)
+{
+	struct ip6_fw *frwl;
+	struct ip6_fw_chain *fcp;
+	int s;
+
+	if (m) {
+		if (m->m_len != sizeof(struct ip6_fw))
+			return(EINVAL);
+		frwl = mtod(m, struct ip6_fw *);
+	}
+	else
+		frwl = NULL;
+
+	if (!frwl) {
+		s = splnet();
+		for (fcp = LIST_FIRST(&ip6_fw_chain); fcp; fcp = LIST_NEXT(fcp, chain)) {
+			fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0;
+			fcp->rule->timestamp = 0;
+		}
+		splx(s);
+	}
+	else {
+		int cleared = 0;
+
+		/*
+		 *	It's possible to insert multiple chain entries with the
+		 *	same number, so we don't stop after finding the first
+		 *	match if zeroing a specific entry.
+		 */
+		for (fcp = LIST_FIRST(&ip6_fw_chain); fcp;
+		     fcp = LIST_NEXT(fcp, chain))
+			if (frwl->fw_number == fcp->rule->fw_number) {
+				s = splnet();
+				while (fcp && frwl->fw_number == fcp->rule->fw_number) {
+					fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0;
+					fcp->rule->timestamp = 0;
+					fcp = LIST_NEXT(fcp, chain);
+				}
+				splx(s);
+				cleared = 1;
+				break;
+			}
+		if (!cleared)
+			return(EINVAL);	/* we didn't find any matching rules */
+	}
+
+	if (fw_verbose) {
+		if (frwl)
+			printf("ip6fw: Entry %d cleared.\n", frwl->fw_number);
+		else
+			printf("ip6fw: Accounting cleared.\n");
+	}
+
+	return(0);
+}
+
+static struct ip6_fw *
+check_ipfw_mbuf(struct mbuf *m)
+{
+	/* Check length */
+	if (m->m_len != sizeof(struct ip6_fw)) {
+		dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len,
+		    sizeof(struct ip6_fw)));
+		return (NULL);
+	}
+	return(check_ipfw_struct(mtod(m, struct ip6_fw *)));
+}
+
+static struct ip6_fw *
+check_ipfw_struct(struct ip6_fw *frwl)
+{
+	/* Check for invalid flag bits */
+	if ((frwl->fw_flg & ~IP6_FW_F_MASK) != 0) {
+		dprintf(("%s undefined flag bits set (flags=%x)\n",
+		    err_prefix, frwl->fw_flg));
+		return (NULL);
+	}
+	/* Must apply to incoming or outgoing (or both) */
+	if (!(frwl->fw_flg & (IP6_FW_F_IN | IP6_FW_F_OUT))) {
+		dprintf(("%s neither in nor out\n", err_prefix));
+		return (NULL);
+	}
+	/* Empty interface name is no good */
+	if (((frwl->fw_flg & IP6_FW_F_IIFNAME)
+	      && !*frwl->fw_in_if.fu_via_if.name)
+	    || ((frwl->fw_flg & IP6_FW_F_OIFNAME)
+	      && !*frwl->fw_out_if.fu_via_if.name)) {
+		dprintf(("%s empty interface name\n", err_prefix));
+		return (NULL);
+	}
+	/* Sanity check interface matching */
+	if ((frwl->fw_flg & IF6_FW_F_VIAHACK) == IF6_FW_F_VIAHACK) {
+		;		/* allow "via" backwards compatibility */
+	} else if ((frwl->fw_flg & IP6_FW_F_IN)
+	    && (frwl->fw_flg & IP6_FW_F_OIFACE)) {
+		dprintf(("%s outgoing interface check on incoming\n",
+		    err_prefix));
+		return (NULL);
+	}
+	/* Sanity check port ranges */
+	if ((frwl->fw_flg & IP6_FW_F_SRNG) && IP6_FW_GETNSRCP(frwl) < 2) {
+		dprintf(("%s src range set but n_src_p=%d\n",
+		    err_prefix, IP6_FW_GETNSRCP(frwl)));
+		return (NULL);
+	}
+	if ((frwl->fw_flg & IP6_FW_F_DRNG) && IP6_FW_GETNDSTP(frwl) < 2) {
+		dprintf(("%s dst range set but n_dst_p=%d\n",
+		    err_prefix, IP6_FW_GETNDSTP(frwl)));
+		return (NULL);
+	}
+	if (IP6_FW_GETNSRCP(frwl) + IP6_FW_GETNDSTP(frwl) > IP6_FW_MAX_PORTS) {
+		dprintf(("%s too many ports (%d+%d)\n",
+		    err_prefix, IP6_FW_GETNSRCP(frwl), IP6_FW_GETNDSTP(frwl)));
+		return (NULL);
+	}
+	/*
+	 *	Protocols other than TCP/UDP don't use port range
+	 */
+	if ((frwl->fw_prot != IPPROTO_TCP) &&
+	    (frwl->fw_prot != IPPROTO_UDP) &&
+	    (IP6_FW_GETNSRCP(frwl) || IP6_FW_GETNDSTP(frwl))) {
+		dprintf(("%s port(s) specified for non TCP/UDP rule\n",
+		    err_prefix));
+		return(NULL);
+	}
+
+	/*
+	 *	Rather than modify the entry to make such entries work, 
+	 *	we reject this rule and require user level utilities
+	 *	to enforce whatever policy they deem appropriate.
+	 */
+#define ERRMASK(a,m)	\
+	(((a).s6_addr32[0] & ~(m).s6_addr32[0]) \
+       ||((a).s6_addr32[1] & ~(m).s6_addr32[1]) \
+       ||((a).s6_addr32[2] & ~(m).s6_addr32[2]) \
+       ||((a).s6_addr32[3] & ~(m).s6_addr32[3]))
+
+	if (ERRMASK(frwl->fw_src, frwl->fw_smsk) || 
+	    ERRMASK(frwl->fw_dst, frwl->fw_dmsk)) {
+		dprintf(("%s rule never matches\n", err_prefix));
+		return(NULL);
+	}
+
+	if ((frwl->fw_flg & IP6_FW_F_FRAG) &&
+		(frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
+		if (frwl->fw_nports) {
+			dprintf(("%s cannot mix 'frag' and ports\n", err_prefix));
+			return(NULL);
+		}
+		if (frwl->fw_prot == IPPROTO_TCP &&
+			frwl->fw_tcpf != frwl->fw_tcpnf) {
+			dprintf(("%s cannot mix 'frag' and TCP flags\n", err_prefix));
+			return(NULL);
+		}
+	}
+
+	/* Check command specific stuff */
+	switch (frwl->fw_flg & IP6_FW_F_COMMAND)
+	{
+	case IP6_FW_F_REJECT:
+		if (frwl->fw_reject_code >= 0x100
+		    && !(frwl->fw_prot == IPPROTO_TCP
+		      && frwl->fw_reject_code == IP6_FW_REJECT_RST)) {
+			dprintf(("%s unknown reject code\n", err_prefix));
+			return(NULL);
+		}
+		break;
+	case IP6_FW_F_DIVERT:		/* Diverting to port zero is invalid */
+	case IP6_FW_F_TEE:
+		if (frwl->fw_divert_port == 0) {
+			dprintf(("%s can't divert to port 0\n", err_prefix));
+			return (NULL);
+		}
+		break;
+	case IP6_FW_F_DENY:
+	case IP6_FW_F_ACCEPT:
+	case IP6_FW_F_COUNT:
+	case IP6_FW_F_SKIPTO:
+		break;
+	default:
+		dprintf(("%s invalid command\n", err_prefix));
+		return(NULL);
+	}
+
+	return frwl;
+}
+
+static int
+ip6_fw_ctl(int stage, struct mbuf **mm)
+{
+	int error;
+	struct mbuf *m;
+
+	if (stage == IP6_FW_GET) {
+		/* 
+	 	 * If we have any number of rules, then it's worth while
+		 * using clusters for this. The smaller case is rare.
+		 * Note that using clusters for setsockopt is only in
+		 * 3.0 at this time.
+		 */
+		struct ip6_fw_chain *fcp = LIST_FIRST(&ip6_fw_chain);
+		*mm = m = m_get(M_WAIT, MT_SOOPTS);
+		if (m == NULL)  
+			return (ENOBUFS);
+		MCLGET(m, M_WAIT);
+		if(!(m->m_flags & M_EXT)) {
+abort:			m_freem(*mm);
+			*mm = NULL;
+			return (ENOBUFS);
+		}
+		m->m_len = 0;
+		for (; fcp; fcp = LIST_NEXT(fcp, chain)) {
+			/* Will we need a new cluster? */
+			if((m->m_len + sizeof *(fcp->rule)) > MCLBYTES) {
+				m = m->m_next = m_get(M_WAIT, MT_SOOPTS);
+				if (m == NULL) {
+					goto abort;
+				}
+				MCLGET(m, M_WAIT);
+				if (!(m->m_flags & M_EXT)) {
+					goto abort;
+				}
+				m->m_len = 0;
+			}
+			memcpy(m->m_data + m->m_len, fcp->rule,
+					sizeof *(fcp->rule));
+			m->m_len += sizeof *(fcp->rule);
+		}
+		return (0);
+	}
+	m = *mm;
+	/* only allow get calls if secure mode > 2 */
+	if (securelevel > 2) {
+		if (m) (void)m_free(m);
+		return(EPERM);
+	}
+	if (stage == IP6_FW_FLUSH) {
+		while (LIST_FIRST(&ip6_fw_chain) != NULL && 
+		    LIST_FIRST(&ip6_fw_chain)->rule->fw_number != (u_short)-1) {
+			struct ip6_fw_chain *fcp = LIST_FIRST(&ip6_fw_chain);
+			int s = splnet();
+			LIST_REMOVE(LIST_FIRST(&ip6_fw_chain), chain);
+			splx(s);
+			free(fcp->rule, M_IPFW);
+			free(fcp, M_IPFW);
+		}
+		if (m) (void)m_free(m);
+		return (0);
+	}
+	if (stage == IP6_FW_ZERO) {
+		error = zero_entry(m);
+		if (m) (void)m_free(m);
+		return (error);
+	}
+	if (m == NULL) {
+		printf("%s NULL mbuf ptr\n", err_prefix);
+		return (EINVAL);
+	}
+
+	if (stage == IP6_FW_ADD) {
+		struct ip6_fw *frwl = check_ipfw_mbuf(m);
+
+		if (!frwl)
+			error = EINVAL;
+		else
+			error = add_entry(&ip6_fw_chain, frwl);
+		if (m) (void)m_free(m);
+		return error;
+	}
+	if (stage == IP6_FW_DEL) {
+		if (m->m_len != sizeof(struct ip6_fw)) {
+			dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len,
+			    sizeof(struct ip6_fw)));
+			error = EINVAL;
+		} else if (mtod(m, struct ip6_fw *)->fw_number == (u_short)-1) {
+			dprintf(("%s can't delete rule 65535\n", err_prefix));
+			error = EINVAL;
+		} else
+			error = del_entry(&ip6_fw_chain,
+			    mtod(m, struct ip6_fw *)->fw_number);
+		if (m) (void)m_free(m);
+		return error;
+	}
+
+	dprintf(("%s unknown request %d\n", err_prefix, stage));
+	if (m) (void)m_free(m);
+	return (EINVAL);
+}
+
+void
+ip6_fw_init(void)
+{
+	struct ip6_fw default_rule;
+
+	ip6_fw_chk_ptr = ip6_fw_chk;
+	ip6_fw_ctl_ptr = ip6_fw_ctl;
+	LIST_INIT(&ip6_fw_chain);
+
+	bzero(&default_rule, sizeof default_rule);
+	default_rule.fw_prot = IPPROTO_IP;
+	default_rule.fw_number = (u_short)-1;
+#ifdef IP6FIREWALL_DEFAULT_TO_ACCEPT
+	default_rule.fw_flg |= IP6_FW_F_ACCEPT;
+#else
+	default_rule.fw_flg |= IP6_FW_F_DENY;
+#endif
+	default_rule.fw_flg |= IP6_FW_F_IN | IP6_FW_F_OUT;
+	if (check_ipfw_struct(&default_rule) == NULL ||
+	    add_entry(&ip6_fw_chain, &default_rule))
+		panic(__FUNCTION__);
+
+	printf("IPv6 packet filtering initialized, "
+#ifdef IPDIVERT
+		"divert enabled, ");
+#else
+		"divert disabled, ");
+#endif
+#ifdef IP6FIREWALL_DEFAULT_TO_ACCEPT
+	printf("default to accept, ");
+#endif
+#ifndef IP6FIREWALL_VERBOSE
+	printf("logging disabled\n");
+#else
+	if (fw_verbose_limit == 0)
+		printf("unlimited logging\n");
+	else
+		printf("logging limited to %d packets/entry\n",
+		    fw_verbose_limit);
+#endif
+}
+
+#ifdef IP6FIREWALL_MODULE
+
+#include <sys/exec.h>
+#include <sys/sysent.h>
+#include <sys/lkm.h>
+
+MOD_MISC(ip6fw);
+
+static int
+ip6fw_load(struct lkm_table *lkmtp, int cmd)
+{
+	int s=splnet();
+
+	old_chk_ptr = ip6_fw_chk_ptr;
+	old_ctl_ptr = ip6_fw_ctl_ptr;
+
+	ip6_fw_init();
+	splx(s);
+	return 0;
+}
+
+static int
+ip6fw_unload(struct lkm_table *lkmtp, int cmd)
+{
+	int s=splnet();
+
+	ip6_fw_chk_ptr =  old_chk_ptr;
+	ip6_fw_ctl_ptr =  old_ctl_ptr;
+
+	while (LIST_FIRST(&ip6_fw_chain) != NULL) {
+		struct ip6_fw_chain *fcp = ip6_fw_chain.lh_first;
+		LIST_REMOVE(LIST_FIRST(&ip6_fw_chain), chain);
+		free(fcp->rule, M_IPFW);
+		free(fcp, M_IPFW);
+	}
+	
+	splx(s);
+	printf("IPv6 firewall unloaded\n");
+	return 0;
+}
+
+int
+ip6fw_mod(struct lkm_table *lkmtp, int cmd, int ver)
+{
+	MOD_DISPATCH(ip6fw, lkmtp, cmd, ver,
+		     ip6fw_load, ip6fw_unload, lkm_nullcmd);
+}
+#endif
diff -uN src-current/sys/netinet/ip6_fw.h src-current-ipv6/sys/netinet/ip6_fw.h
--- src-current/sys/netinet/ip6_fw.h
+++ src-current-ipv6/sys/netinet/ip6_fw.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 1993 Daniel Boulet
+ * Copyright (c) 1994 Ugen J.S.Antsilevich
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * Redistribution in binary form may occur without any restrictions.
+ * Obviously, it would be nice if you gave credit where credit is due
+ * but requiring it would be too onerous.
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind.
+ *
+ *	$Id: ip_fw.h,v 1.11.4.7 1996/06/25 03:16:43 alex Exp $
+ */
+
+#ifndef _IP6_FW_H
+#define _IP6_FW_H
+
+#include <sys/queue.h>
+
+/*
+ * This union structure identifies an interface, either explicitly
+ * by name or implicitly by IP address. The flags IP6_FW_F_IIFNAME
+ * and IP6_FW_F_OIFNAME say how to interpret this structure. An
+ * interface unit number of -1 matches any unit number, while an
+ * IPv6 address of 0.0.0.0 indicates matches any interface.
+ *
+ * The receive and transmit interfaces are only compared against the
+ * the packet if the corresponding bit (IP6_FW_F_IIFACE or IP6_FW_F_OIFACE)
+ * is set. Note some packets lack a receive or transmit interface
+ * (in which case the missing "interface" never matches).
+ */
+
+union ip6_fw_if {
+    struct in6_addr fu_via_ip;	/* Specified by IP address */
+    struct {			/* Specified by interface name */
+#define FW6_IFNLEN     IFNAMSIZ
+	    char  name[FW6_IFNLEN];
+	    short unit;		/* -1 means match any unit */
+    } fu_via_if;
+};
+
+/*
+ * Format of an IPv6 firewall descriptor
+ *
+ * fw_src, fw_dst, fw_smsk, fw_dmsk are always stored in network byte order.
+ * fw_flg and fw_n*p are stored in host byte order (of course).
+ * Port numbers are stored in HOST byte order.
+ */
+
+struct ip6_fw {
+    u_int64_t fw_pcnt, fw_bcnt;		/* Packet and byte counters */
+    struct in6_addr fw_src, fw_dst;	/* Source and destination IP addr */
+    struct in6_addr fw_smsk, fw_dmsk;	/* Mask for src and dest IP addr */
+    u_short fw_number;			/* Rule number */
+    u_short fw_flg;			/* Flags word */
+#define IP6_FW_MAX_PORTS	10		/* A reasonable maximum */
+	union {
+	u_short fw_pts[IP6_FW_MAX_PORTS];	/* Array of port numbers to match */
+#define IP6_FW_ICMPTYPES_MAX	128
+#define IP6_FW_ICMPTYPES_DIM	(IP6_FW_ICMPTYPES_MAX / (sizeof(unsigned) * 8))
+	unsigned fw_icmptypes[IP6_FW_ICMPTYPES_DIM]; /* ICMP types bitmap */
+	} fw_uar;
+    u_char fw_ipopt,fw_ipnopt;		/* IP options set/unset */
+    u_char fw_tcpf,fw_tcpnf;		/* TCP flags set/unset */
+    long timestamp;			/* timestamp (tv_sec) of last match */
+    union ip6_fw_if fw_in_if, fw_out_if;	/* Incoming and outgoing interfaces */
+    union {
+	u_short fu_divert_port;		/* Divert/tee port (options IPDIVERT) */
+	u_short fu_skipto_rule;		/* SKIPTO command rule number */
+	u_short fu_reject_code;		/* REJECT response code */
+    } fw_un;
+    u_char fw_prot;			/* IP protocol */
+    u_char fw_nports;			/* N'of src ports and # of dst ports */
+					/* in ports array (dst ports follow */
+					/* src ports; max of 10 ports in all; */
+					/* count of 0 means match all ports) */
+};
+
+#define IP6_FW_GETNSRCP(rule)		((rule)->fw_nports & 0x0f)
+#define IP6_FW_SETNSRCP(rule, n)		do {			\
+					  (rule)->fw_nports &= ~0x0f;	\
+					  (rule)->fw_nports |= (n);	\
+					} while (0)
+#define IP6_FW_GETNDSTP(rule)		((rule)->fw_nports >> 4)
+#define IP6_FW_SETNDSTP(rule, n)		do {			\
+					  (rule)->fw_nports &= ~0xf0;	\
+					  (rule)->fw_nports |= (n) << 4;\
+					} while (0)
+
+#define fw_divert_port	fw_un.fu_divert_port
+#define fw_skipto_rule	fw_un.fu_skipto_rule
+#define fw_reject_code	fw_un.fu_reject_code
+
+struct ip6_fw_chain {
+        LIST_ENTRY(ip6_fw_chain) chain;
+        struct ip6_fw    *rule;
+};
+
+/*
+ * Values for "flags" field .
+ */
+
+#define IP6_FW_F_IN	0x0001	/* Check inbound packets		*/
+#define IP6_FW_F_OUT	0x0002	/* Check outbound packets		*/
+#define IP6_FW_F_IIFACE	0x0004	/* Apply inbound interface test		*/
+#define IP6_FW_F_OIFACE	0x0008	/* Apply outbound interface test	*/
+
+#define IP6_FW_F_COMMAND 0x0070	/* Mask for type of chain entry:	*/
+#define IP6_FW_F_DENY	0x0000	/* This is a deny rule			*/
+#define IP6_FW_F_REJECT	0x0010	/* Deny and send a response packet	*/
+#define IP6_FW_F_ACCEPT	0x0020	/* This is an accept rule		*/
+#define IP6_FW_F_COUNT	0x0030	/* This is a count rule			*/
+#define IP6_FW_F_DIVERT	0x0040	/* This is a divert rule		*/
+#define IP6_FW_F_TEE	0x0050	/* This is a tee rule			*/
+#define IP6_FW_F_SKIPTO	0x0060	/* This is a skipto rule		*/
+
+#define IP6_FW_F_PRN	0x0080	/* Print if this rule matches	      */
+
+#define IP6_FW_F_SRNG	0x0100	/* The first two src ports are a min	*
+				 * and max range (stored in host byte	*
+				 * order).				*/
+
+#define IP6_FW_F_DRNG	0x0200	/* The first two dst ports are a min	*
+				 * and max range (stored in host byte	*
+				 * order).				*/
+
+
+#define IP6_FW_F_IIFNAME	0x0400	/* In interface by name/unit (not IP)	*/
+#define IP6_FW_F_OIFNAME	0x0800	/* Out interface by name/unit (not IP)	*/
+
+#define IP6_FW_F_INVSRC	0x1000	/* Invert sense of src check		*/
+#define IP6_FW_F_INVDST	0x2000	/* Invert sense of dst check		*/
+
+#define IP6_FW_F_FRAG	0x4000	/* Fragment				*/
+
+#define IP6_FW_F_ICMPBIT 0x8000	/* ICMP type bitmap is valid		*/
+
+#define IP6_FW_F_MASK	0xFFFF	/* All possible flag bits mask        */
+
+/*
+ * For backwards compatibility with rules specifying "via iface" but
+ * not restricted to only "in" or "out" packets, we define this combination
+ * of bits to represent this configuration.
+ */
+
+#define IF6_FW_F_VIAHACK	\
+	(IP6_FW_F_IN|IP6_FW_F_OUT|IP6_FW_F_IIFACE|IP6_FW_F_OIFACE)
+
+/*
+ * Definitions for REJECT response codes.
+ * Values less than 256 correspond to ICMP unreachable codes.
+ */
+#define IP6_FW_REJECT_RST	0x0100		/* TCP packets: send RST */
+
+/*
+ * Definitions for IPv6 extension names.
+ */
+#define IP6_FW_IP6OPT_H2H	0x01
+#define IP6_FW_IP6OPT_DEST	0x02
+#define IP6_FW_IP6OPT_ROUTE	0x04
+#define IP6_FW_IP6OPT_AUTH	0x08
+#define IP6_FW_IP6OPT_CRYPT	0x10
+
+/*
+ * Definitions for TCP flags.
+ */
+#define IP6_FW_TCPF_FIN		TH_FIN
+#define IP6_FW_TCPF_SYN		TH_SYN
+#define IP6_FW_TCPF_RST		TH_RST
+#define IP6_FW_TCPF_PSH		TH_PUSH
+#define IP6_FW_TCPF_ACK		TH_ACK
+#define IP6_FW_TCPF_URG		TH_URG
+#define IP6_FW_TCPF_ESTAB	0x40
+
+/*
+ * New IPv6 firewall options for [gs]etsockopt at the RAW IPv6 level.
+ */
+#define IP6_FW_BASE_CTL	50
+
+#define IP6_FW_ADD     (IP6_FW_BASE_CTL+0)
+#define IP6_FW_DEL     (IP6_FW_BASE_CTL+1)
+#define IP6_FW_FLUSH   (IP6_FW_BASE_CTL+2)
+#define IP6_FW_ZERO    (IP6_FW_BASE_CTL+3)
+#define IP6_FW_GET     (IP6_FW_BASE_CTL+4)
+
+/*
+ * Main firewall chains definitions and global var's definitions.
+ */
+#ifdef KERNEL
+
+/*
+ * Function definitions.
+ */
+void ip6_fw_init(void);
+
+#endif /* KERNEL */
+
+#endif /* _IP6_FW_H */
diff -uN src-current/sys/netinet/ip6_icmp.c src-current-ipv6/sys/netinet/ip6_icmp.c
--- src-current/sys/netinet/ip6_icmp.c
+++ src-current-ipv6/sys/netinet/ip6_icmp.c
@@ -0,0 +1,1144 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 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.c	8.2 (Berkeley) 1/4/94
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/in6_var.h>
+#include <netinet/if_ether.h>
+#include <netinet/if_ndp6.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ip6_opts.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip6_icmp.h>
+#include <netinet/icmp6_var.h>
+#include <netinet/igmp.h>
+#include <netinet/igmp_var.h>
+
+/*
+ * ICMPv6 routines: error generation, receive packet processing, and
+ * routines to turnaround packets back to the originator, and
+ * host table maintenance routines.
+ */
+
+MALLOC_DECLARE(M_IPMOPTS);
+
+struct	icmp6stat icmp6stat;
+
+SYSCTL_STRUCT(_net_inet6_icmpv6, ICMP6CTL_STATS, stats, CTLFLAG_RD,
+	&icmp6stat, icmp6stat, "");
+
+u_int	icmp6_ipsec = 0;
+
+SYSCTL_INT(_net_inet6_icmpv6, ICMP6CTL_IPSEC, ipsec, CTLFLAG_RW,
+	&icmp6_ipsec, 0, "");
+
+#ifdef DIAGNOSTIC
+extern	int icmpprintfs;
+#endif
+extern	int arpt_keep;
+
+static	void icmp6_reflect __P((struct mbuf *, struct mbuf *));
+
+#define rt_expire	rt_rmx.rmx_expire
+#define rt_mtu		rt_rmx.rmx_mtu
+
+#define IGMP_TIMER_SCALE	10
+static int icmp6_timers_are_running = 0;
+extern struct in6_addr allnodes6_group;
+static void icmp6_sendgroup __P((struct in6_multi *, int, struct in6_addr *));
+
+extern	int ip6forwarding;
+extern	int ip6mforwarding;
+extern	struct protosw inet6sw[];
+int	last_icmp6_error_time, last_icmp6_error_count;
+
+static struct sockaddr_in6 icmpsrc = { sizeof (icmpsrc), AF_INET6 };
+static struct sockaddr_in6 icmpdst = { sizeof (icmpdst), AF_INET6 };
+static struct sockaddr_in6 icmpgw = { sizeof (icmpgw), AF_INET6 };
+
+static struct mbuf *grp_opts = NULL;
+
+static void icmp6_filter_xfree __P((struct inpcb *, struct mbuf *));
+static int icmp6_filter_xoutput __P((struct mbuf *, int, struct mbuf *,
+    struct mbuf *, struct route *, int, struct ip_moptions *, struct inpcb *));
+
+#define MADDR6_REPORTABLE(addr) \
+	((MADDR6_SCOPE(addr) > MADDR6_SCP_LINK) || \
+	 ((MADDR6_SCOPE(addr) == MADDR6_SCP_LINK) && \
+	  (MADDR6_FLAGS(addr) & MADDR6_FLG_TS)))
+
+void
+icmp6_init()
+{
+#ifdef OPT6_ROUTER_ALERT
+	struct mbuf *m;
+	struct ipv6_fraghdr *hp;
+	struct opt6_ra *op;
+
+	MGETHDR(m, M_WAIT, MT_SOOPTS);
+	if (m == NULL)
+		panic("icmp6_init");
+	MH_ALIGN(m, sizeof(*hp));
+	m->m_pkthdr.pktype = IP6_NHDR_HOP;
+	m->m_pkthdr.len = m->m_len = sizeof(*hp);
+
+	hp = mtod(m, struct ipv6_fraghdr *);
+	bzero(hp, sizeof(*hp));
+	hp->ih6_hlen = 0;
+
+	op = (struct opt6_ra *)((caddr_t)hp + 2);
+	op->ra_ext = OPT6_ROUTER_ALERT;
+	op->ra_len = 2;
+	op->ra_code = htons(OPT6_RA_GROUP);
+
+	grp_opts = m;
+#endif
+	/* don't begin with errors ... */
+
+	last_icmp6_error_time = time_second;
+	last_icmp6_error_count = ICMP6_MAX_RATE;
+}
+
+void
+icmp6_joingroup(inm)
+	struct in6_multi *inm;
+{
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_MCASTOUT)
+		printf("icmp6_joingroup %s\n", ip6_sprintf(&inm->inm6_addr));
+#endif
+	if (MADDR6_REPORTABLE(inm->inm6_addr) &&
+	    (inm->inm6_ifp->if_flags & IFF_LOOPBACK) == 0) {
+		icmp6_sendgroup(inm, ICMP6_GROUPMEM_REPORT, NULL);
+		inm->inm6_timer = ICMP6_DEFAULT_DELAY();
+		inm->inm6_state = MULTI6_IREPORTEDLAST;
+		icmp6_timers_are_running = 1;
+	} else {
+		inm->inm6_timer = 0;
+		inm->inm6_state = MULTI6_OTHERMEMBER;
+	}
+}
+
+void
+icmp6_leavegroup(inm)
+	struct in6_multi *inm;
+{
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_MCASTOUT)
+		printf("icmp6_leavegroup %s\n", ip6_sprintf(&inm->inm6_addr));
+#endif
+
+	if ((inm->inm6_state == MULTI6_IREPORTEDLAST) &&
+	    MADDR6_REPORTABLE(inm->inm6_addr) &&
+	    ((inm->inm6_ifp->if_flags & IFF_LOOPBACK) == 0)) {
+		/* not yet IGMP v2 ... */
+		icmp6_sendgroup(inm, ICMP6_GROUPMEM_TERM, NULL);
+	}
+}
+
+void
+icmp6_fasttimo()
+{
+	struct in6_multi *inm;
+	struct in6_multistep step;
+	int s;
+
+	/*
+	 * Quick check to see if any work needs to be done, in order
+	 * to minimize the overhead of fasttimo processing.
+	 */
+	if (!icmp6_timers_are_running)
+		return;
+
+	s = splnet();
+	icmp6_timers_are_running = 0;
+	IN6_FIRST_MULTI(step, inm);
+	while (inm != NULL) {
+		if (inm->inm6_timer == 0) {
+			/* do nothing */
+		} else if (--inm->inm6_timer == 0) {
+			icmp6_sendgroup(inm, ICMP6_GROUPMEM_REPORT, NULL);
+			inm->inm6_state = MULTI6_IREPORTEDLAST;
+		} else {
+			icmp6_timers_are_running = 1;
+		}
+		IN6_NEXT_MULTI(step, inm);
+	}
+	splx(s);
+}
+
+static void
+icmp6_sendgroup(inm, type, addr)
+	struct in6_multi *inm;
+	int type;
+	struct in6_addr *addr;
+{
+	struct mbuf *m;
+	struct icmpv6 *icp;
+	struct ipv6 *ip;
+	struct ip_moptions *imo;
+	struct in6_ifaddr *ia;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_MCASTOUT)
+		printf("icmp6_sendgroup %d to %s for %s\n",
+		       type,
+		       addr ? ip6_sprintf(addr) : ip6_sprintf(&inm->inm6_addr),
+		       ip6_sprintf(&inm->inm6_addr));
+#endif
+	MGETHDR(m, M_DONTWAIT, MT_HEADER);
+	if (m == NULL)
+		return;
+	imo = (struct ip_moptions*)malloc(sizeof(*imo), M_IPMOPTS, M_NOWAIT);
+	if (imo == NULL) {
+		m_free(m);
+		return;
+	}
+	m->m_len = sizeof(struct ipv6) + ICMP6_GRPLEN;
+	MH_ALIGN(m, m->m_len);
+	m->m_pkthdr.len = m->m_len;
+	m->m_pkthdr.rcvif = loif;
+	bzero(mtod(m, caddr_t), m->m_len);
+
+	ip = mtod(m, struct ipv6 *);
+	ip->ip6_head = IPV6_VERSION;
+	ip->ip6_len = ICMP6_GRPLEN;
+	ip->ip6_nh = IPPROTO_ICMPV6;
+	ip->ip6_hlim = 1;
+	COPY_ADDR6(addr ? *addr : inm->inm6_addr, icmpdst.sin6_addr);
+	ia = (struct in6_ifaddr *)ifaof_ifpforaddr(
+				sin6tosa(&icmpdst), inm->inm6_ifp);
+	if (ia == NULL) {
+		log(LOG_ERR, "icmp6_sendgroup: bad address\n");
+		m_free(m);
+		free(imo, M_IPMOPTS);
+	}
+	COPY_ADDR6(ia->ia_addr.sin6_addr, ip->ip6_src);
+	COPY_ADDR6(inm->inm6_addr, ip->ip6_dst);
+
+	icp = (struct icmpv6 *)(ip + 1);
+	icp->icmp6_type = type;
+	COPY_ADDR6(inm->inm6_addr, icp->icmp6_grp);
+
+	imo->imo_multicast_ifp = inm->inm6_ifp;
+	imo->imo_multicast_ttl = 1;
+        /*
+         * Request loopback of the report if we are acting as a multicast
+         * router, so that the process-level routing demon can hear it.
+         */
+	imo->imo_multicast_loop = ip6mforwarding;
+
+	icmp6_send(m, grp_opts, imo);
+
+	free(imo, M_IPMOPTS);
+
+	switch (type) {
+	case ICMP6_GROUPMEM_QUERY:
+		icmp6stat.icp6s_snd_grpqry++;
+		break;
+
+	case ICMP6_GROUPMEM_REPORT:
+		icmp6stat.icp6s_snd_grprep++;
+		break;
+
+	case ICMP6_GROUPMEM_TERM:
+		icmp6stat.icp6s_snd_grpterm++;
+		break;
+	}
+}
+
+/*
+ * Generate a parameter problem, bad next header error.
+ */
+void
+icmp6_errparam(m, opts, len)
+	struct mbuf *m, *opts;
+	int len;
+{
+	if (opts) {
+		m = ip6_insertoption(m, opts, 0, IP6_INSOPT_RAW);
+		if (m == NULL) {
+			m_freem(opts);
+			return;
+		}
+	}
+	icmp6_error(m, ICMP6_PARAMPROB, ICMP6_PARAMPROB_NH,
+		    (caddr_t)(sizeof(struct ipv6) + len));
+	if (opts)
+		m_freem(opts);
+}
+
+/*
+ * Generate an error packet of type error
+ * in response to bad packet IPv6.
+ */
+void
+icmp6_error(n, type, code, arg)
+	struct mbuf *n;
+	int type, code;
+	caddr_t arg;
+{
+	struct ipv6 *oip = mtod(n, struct ipv6 *), *nip;
+	struct icmpv6 *icp;
+	struct mbuf *m;
+
+#ifdef DIAGNOSTIC
+	if (icmpprintfs || (ip6printfs & D6_CTLOUT))
+		printf("icmp6_error(%p, %d, %d, %p)\n",
+		       oip, type, code, arg);
+#endif
+	icmp6stat.icp6s_error++;
+
+	/*
+	 * Don't send error in response to packet
+	 * without an identified source or
+	 * a multicast if it is not for path MTU discovery.
+	 */
+	if (IS_MULTIADDR6(oip->ip6_src) ||
+	    IS_ANYADDR6(oip->ip6_src) ||
+	    in6_isanycast(&oip->ip6_src) ||
+	    (type != ICMP6_PKTTOOBIG &&
+	     (n->m_flags & (M_BCAST|M_MCAST) || IS_MULTIADDR6(oip->ip6_dst))))
+		goto freeit;
+	/*
+	 * Don't error if the old packet protocol was ICMPv6 error.
+	 */
+	if ((oip->ip6_nh == IPPROTO_ICMPV6) &&
+	    ((oip->ip6_len < ICMP6_MINLEN) ||
+	     (n->m_len < sizeof(struct ipv6) + sizeof(u_int8_t)) ||
+	     !ICMP6_INFOTYPE(((struct icmpv6 *)(oip + 1))->icmp6_type))) {
+		icmp6stat.icp6s_oldicmp++;
+		goto freeit;
+	}
+	/*
+	 * Don't send clear text of ESP packets.
+	 */
+	if (n->m_flags & M_CRYPT)
+		goto freeit;
+	/*
+	 * Limit rate of icmp6 errors.
+	 */
+	if (last_icmp6_error_time == time_second) {
+		if (last_icmp6_error_count++ > ICMP6_MAX_RATE) {
+			icmp6stat.icp6s_ratelim++;
+			goto freeit;
+		}
+	} else {
+		last_icmp6_error_time = time_second;
+		last_icmp6_error_count = 1;
+	}
+
+	/*
+	 * First, formulate ICMPv6 message
+	 */
+	m = m_gethdr(M_DONTWAIT, MT_HEADER);
+	if (m == NULL)
+		goto freeit;
+	m->m_len = sizeof(struct ipv6) + ICMP6_MINLEN;
+	MH_ALIGN(m, m->m_len);
+	m->m_next = n;
+	m->m_pkthdr.len = m->m_len + n->m_pkthdr.len;
+	m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
+	if (m->m_pkthdr.len > IP6_MMTU)
+		m_adj(m, IP6_MMTU - m->m_pkthdr.len);
+	nip = mtod(m, struct ipv6 *);
+	icp = (struct icmpv6 *)(nip + 1);
+	icp->icmp6_type = type;
+	switch (type) {
+	case ICMP6_PKTTOOBIG:
+		if (arg == NULL)
+			panic("icmpv6 pmtu");
+		icp->icmp6_pmtu = htonl(((struct ifnet *)arg)->if_mtu);
+		icmp6stat.icp6s_snd_pkttoobig++;
+		break;
+
+	case ICMP6_PARAMPROB:
+		icp->icmp6_pptr = htonl((u_int32_t)arg);
+		icmp6stat.icp6s_snd_paramprob++;
+		break;
+
+	case ICMP6_TIMXCEED:
+		icmp6stat.icp6s_snd_timxceed++;
+		icp->icmp6_pmtu = 0;
+		break;
+
+	case ICMP6_UNREACH:
+		icmp6stat.icp6s_snd_unreach++;
+	default:
+		icp->icmp6_pmtu = 0;
+		break;
+	}
+	icp->icmp6_code = code;
+	oip->ip6_len = htons(oip->ip6_len);
+
+	/*
+	 * Now, copy old IPv6 header in front of ICMPv6 message.
+	 */
+	bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ipv6));
+	nip->ip6_head = IPV6_VERSION;
+	nip->ip6_len = m->m_pkthdr.len - sizeof(struct ipv6);
+	nip->ip6_nh = IPPROTO_ICMPV6;
+	icmp6_reflect(m, 0);
+	return;
+
+freeit:
+	m_freem(n);
+}
+
+extern u_char ip6_protox[];
+
+/*
+ * Process a received ICMPv6 message.
+ */
+void
+icmp6_input(m, oarg)
+	struct mbuf *m;
+	int oarg;
+{
+	struct mbuf *opts = (struct mbuf *)oarg;
+	struct icmpv6 *icp;
+	struct ipv6 *ip = mtod(m, struct ipv6 *);
+	int icmplen = ip->ip6_len;
+	struct ifnet *ifp = m->m_pkthdr.rcvif;
+	int i;
+	struct rtentry *rt;
+	struct in6_multi *inm;
+	struct in6_multistep step;
+	void (*ctlfunc) __P((int, struct sockaddr *, void *));
+	struct ctli_arg arg;
+	int code, timer, flags;
+	struct in6_ifaddr *ia;
+
+	/*
+	 * Locate ICMPv6 structure in mbuf, and check
+	 * that not corrupted and of at least minimum length.
+	 */
+#ifdef DIAGNOSTIC
+	if (icmpprintfs || (ip6printfs & D6_CTLIN))
+		printf("icmp6_input from %s to %s, len %d\n",
+		       ip6_sprintf(&ip->ip6_src),
+		       ip6_sprintf(&ip->ip6_dst),
+		       icmplen);
+#endif
+	if (icmplen < ICMP6_MINLEN) {
+		icmp6stat.icp6s_tooshort++;
+		goto freeit;
+	}
+	i = min(sizeof(struct ipv6) + icmplen, MHLEN);
+	if (m->m_len < i && (m = m_pullup(m, i)) == 0)  {
+		icmp6stat.icp6s_tooshort++;
+		if (opts)
+			m_freem(opts);
+		return;
+	}
+	ip = mtod(m, struct ipv6 *);
+	icp = (struct icmpv6 *)(ip + 1);
+	{
+		struct ip6ovck *ipc = (struct ip6ovck *)ip;
+		struct ip6ovck save_ip = *ipc;
+
+		ipc->ih6_wrd1 = ipc->ih6_wrd0 = 0;
+		ipc->ih6_len = htons(icmplen);
+		ipc->ih6_pr = IPPROTO_ICMPV6;
+		if (in_cksum(m, m->m_pkthdr.len)) {
+			icmp6stat.icp6s_checksum++;
+			goto freeit;
+		}
+		*ipc = save_ip;
+	}
+
+#ifdef DIAGNOSTIC
+	if (icmpprintfs || (ip6printfs & D6_CTLIN))
+		printf("icmp6_input type %d code %d\n",
+		       icp->icmp6_type, icp->icmp6_code);
+#endif
+	/*
+	 * Message type specific processing.
+	 */
+	code = icp->icmp6_code;
+	if (IS_ANYADDR6(ip->ip6_src) &&
+	    (icp->icmp6_type != ICMP6_SOLICITATION_ND) &&
+	    (icp->icmp6_type != ICMP6_SOLICITATION_RT)) {
+		log(LOG_INFO, "icmp6_input: unspec source\n");
+		goto freeit;
+	}
+
+	switch (icp->icmp6_type) {
+
+	case ICMP6_UNREACH:
+		if ((icmp6_ipsec & ICMP6SEC_ERRORS) &&
+		    ((m->m_flags & M_AUTH) == 0))
+			goto logandfree;
+		icmp6stat.icp6s_rcv_unreach++;
+		switch (code) {
+		case ICMP6_UNREACH_NOROUTE:
+			code = PRC_UNREACH_NET;
+			break;
+
+		case ICMP6_UNREACH_ADMIN:
+			code = PRC_UNREACH_HOST;
+			break;
+
+		case ICMP6_UNREACH_RTFAIL:
+			code = PRC_UNREACH_SRCFAIL;
+			break;
+
+		case ICMP6_UNREACH_ADDRESS:
+			code = PRC_UNREACH_HOST;
+			break;
+
+		case ICMP6_UNREACH_PORT:
+			code = PRC_UNREACH_PORT;
+			break;
+
+		default:
+			goto badcode;
+		}
+		goto deliver;
+
+	case ICMP6_PKTTOOBIG:
+		if ((icmp6_ipsec & ICMP6SEC_ERRORS) &&
+		    ((m->m_flags & M_AUTH) == 0))
+			goto logandfree;
+		icmp6stat.icp6s_rcv_pkttoobig++;
+		code = PRC_MSGSIZE;
+		rt = in6_rthost(&icp->icmp6_ip.ip6_dst);
+		if (rt == 0) {
+			log(LOG_NOTICE,
+			    "icmp6_input/pkttoobig: in6_rthost failed\n");
+			goto deliver;
+		}
+		if ((rt->rt_mtu > rt->rt_ifp->if_mtu) ||
+		    (ntohl(icp->icmp6_pmtu) > rt->rt_mtu) ||
+		    (ntohl(icp->icmp6_pmtu) < IP6_MMTU)) {
+			/* note: this can happen with real path */
+			log(LOG_NOTICE,
+			    "icmp6_input/pkttoobig: bad MTU\n");
+			goto freeit;
+		}
+		if ((rt->rt_flags & RTF_HOST) == 0) {
+			log(LOG_NOTICE,
+			    "icmp6_input/pkttoobig: in6_rthost doesn't work\n");
+				goto freeit;
+		}
+#ifdef DEBUG_MTUDISC
+		printf("MTU for %s reduced from %d to %d\n",
+		       ip6_printf(&icp->icmp6_ip.ip6_dst),
+		       rt->rt_mtu, ntohl(icp->icmp6_pmtu));
+#endif
+		if ((ntohl(icp->icmp6_pmtu) < rt->rt_mtu)
+		     /* || ((rt->rt_rmx.rmx_locks & RTV_MTU) == 0) */)
+			rt->rt_mtu = ntohl(icp->icmp6_pmtu);
+		goto deliver;
+				
+	case ICMP6_TIMXCEED:
+		if ((icmp6_ipsec & ICMP6SEC_ERRORS) &&
+		    ((m->m_flags & M_AUTH) == 0))
+			goto logandfree;
+		icmp6stat.icp6s_rcv_timxceed++;
+		if ((code != ICMP6_TIMXCEED_INTRANS) &&
+		    (code != ICMP6_TIMXCEED_REASS))
+			goto badcode;
+		code += PRC_TIMXCEED_INTRANS;
+		goto deliver;
+
+	case ICMP6_PARAMPROB:
+		if ((icmp6_ipsec & ICMP6SEC_ERRORS) &&
+		    ((m->m_flags & M_AUTH) == 0))
+			goto logandfree;
+		icmp6stat.icp6s_rcv_paramprob++;
+		if (code == ICMP6_PARAMPROB_NH)
+			code = PRC_UNREACH_PROTOCOL;
+		else
+			code = PRC_PARAMPROB;
+		goto deliver;
+
+	deliver:
+		/*
+		 * Problem with datagram; advise higher level routines.
+		 */
+		NTOHS(icp->icmp6_ip.ip6_len);
+#ifdef DIAGNOSTIC
+		if (icmpprintfs || (ip6printfs & D6_CTLIN))
+			printf("deliver to IPv6 protocol %d\n",
+			       icp->icmp6_ip.ip6_nh);
+#endif
+		COPY_ADDR6(icp->icmp6_ip.ip6_dst, icmpsrc.sin6_addr);
+		ctlfunc = inet6sw[ip6_protox[icp->icmp6_ip.ip6_nh]].pr_ctlinput;
+		arg.ctli_ip = &icp->icmp6_ip;
+		arg.ctli_m = m;
+		if (ctlfunc)
+			(*ctlfunc)(code, sin6tosa(&icmpsrc), &arg);
+		HTONS(icp->icmp6_ip.ip6_len);
+		break;
+
+	case ICMP6_SOLICITATION_RT:
+		if (ip->ip6_hlim != ICMP6_ND_HOPS) {
+			icmp6stat.icp6s_rcv_badrtsol++;
+			goto freeit;
+		}
+		if (icmplen < ICMP6_RSLEN) {
+			icmp6stat.icp6s_badlen++;
+			goto freeit;
+		}
+		if ((icmp6_ipsec & ICMP6SEC_NEIGHBORS) &&
+		    ((m->m_flags & M_AUTH) == 0))
+			goto logandfree;
+		if (!ip6forwarding)
+			break;
+		IFP_TO_IA6(ifp, ia);
+		if ((ia == NULL) || (ia->ia_flags & IFA_BOOTING))
+			break;
+		if (!rtsol6_input(m)) {
+			icmp6stat.icp6s_rcv_badrtsol++;
+			goto freeit;
+		}
+		icmp6stat.icp6s_rcv_rtsol++;
+		break;
+
+	case ICMP6_ADVERTISEMENT_RT:
+		if (ip->ip6_hlim != ICMP6_ND_HOPS) {
+			icmp6stat.icp6s_rcv_badrtadv++;
+			goto freeit;
+		}
+		if (icmplen < ICMP6_RALEN) {
+			icmp6stat.icp6s_badlen++;
+			goto freeit;
+		}
+		if ((icmp6_ipsec & ICMP6SEC_NEIGHBORS) &&
+		    ((m->m_flags & M_AUTH) == 0))
+			goto logandfree;
+		IFP_TO_IA6(ifp, ia);
+		if ((ia == NULL) || (ia->ia_flags & IFA_BOOTING))
+			break;
+		if (!rtadv6_input(m)) {
+			icmp6stat.icp6s_rcv_badrtadv++;
+			goto freeit;
+		}
+		icmp6stat.icp6s_rcv_rtadv++;
+		break;
+
+	case ICMP6_SOLICITATION_ND:
+		if (ip->ip6_hlim != ICMP6_ND_HOPS) {
+			icmp6stat.icp6s_rcv_badndsol++;
+			goto freeit;
+		}
+		if (icmplen < ICMP6_NSLEN) {
+			icmp6stat.icp6s_badlen++;
+			goto freeit;
+		}
+		if ((icmp6_ipsec & ICMP6SEC_NEIGHBORS) &&
+		    ((m->m_flags & M_AUTH) == 0))
+			goto logandfree;
+		if (!ndsol6_input(m)) {
+			icmp6stat.icp6s_rcv_badndsol++;
+			goto freeit;
+		}
+		icmp6stat.icp6s_rcv_ndsol++;
+		break;
+
+	case ICMP6_ADVERTISEMENT_ND:
+		if (ip->ip6_hlim != ICMP6_ND_HOPS) {
+			icmp6stat.icp6s_rcv_badndadv++;
+			goto freeit;
+		}
+		if (icmplen < ICMP6_NALEN) {
+			icmp6stat.icp6s_badlen++;
+			goto freeit;
+		}
+		if ((icmp6_ipsec & ICMP6SEC_NEIGHBORS) &&
+		    ((m->m_flags & M_AUTH) == 0))
+			goto logandfree;
+		IFP_TO_IA6(ifp, ia);
+		if ((ia == NULL) || (ia->ia_flags & IFA_BOOTING))
+			break;
+		if (!ndadv6_input(m)) {
+			icmp6stat.icp6s_rcv_badndadv++;
+			goto freeit;
+		}
+		icmp6stat.icp6s_rcv_ndadv++;
+		break;
+
+	case ICMP6_REDIRECT:
+		if (ip->ip6_hlim != ICMP6_ND_HOPS) {
+			icmp6stat.icp6s_rcv_badredirect++;
+			goto freeit;
+		}
+		if (icmplen < ICMP6_RDLEN) {
+			icmp6stat.icp6s_badlen++;
+			goto freeit;
+		}
+		if ((icmp6_ipsec & ICMP6SEC_NEIGHBORS) &&
+		    ((m->m_flags & M_AUTH) == 0))
+			goto logandfree;
+		IFP_TO_IA6(ifp, ia);
+		if ((ia == NULL) || (ia->ia_flags & IFA_BOOTING))
+			break;
+		COPY_ADDR6(icp->icmp6_rdst, icmpsrc.sin6_addr);
+		if (!redirect6_input(m)) {
+			icmp6stat.icp6s_rcv_badredirect++;
+			goto freeit;
+		}
+		icmp6stat.icp6s_rcv_redirect++;
+		/* a direct call to rtredirect should fail */
+		pfctlinput(PRC_REDIRECT_HOST, sin6tosa(&icmpsrc));
+		break;
+
+	badcode:
+		icmp6stat.icp6s_badcode++;
+		break;
+
+	case ICMP6_GROUPMEM_QUERY:
+		if (icmplen < ICMP6_GRPLEN) {
+			icmp6stat.icp6s_badlen++;
+			goto freeit;
+		}
+		if ((icmp6_ipsec & ICMP6SEC_GROUPS) &&
+		    ((m->m_flags & M_AUTH) == 0))
+			goto logandfree;
+		icmp6stat.icp6s_rcv_grpqry++;
+
+		if (ifp->if_flags & IFF_LOOPBACK)
+			break;
+		IFP_TO_IA6(ifp, ia);
+		if ((ia == NULL) || (ia->ia_flags & IFA_BOOTING))
+			break;
+
+		if (!IS_MULTIADDR6(ip->ip6_dst)) {
+			icmp6stat.icp6s_rcv_bad_grpqry++;
+			goto freeit;
+		}
+
+		timer = ICMP6_TIMER2HZ(icp->icmp6_mrd);
+
+		/*
+		 * - Start the timers in all of our membership records
+		 *   for the interface on which the query arrived
+		 *   except those that are already running and those
+		 *   that are "local".
+		 * - For timers already running check if they need to
+		 *   be reset.
+		 */
+		IN6_FIRST_MULTI(step, inm);
+		while (inm != NULL) {
+			if (inm->inm6_ifp == ifp &&
+			    MADDR6_REPORTABLE(inm->inm6_addr) &&
+			    (SAME_ADDR6(ip->ip6_dst, allnodes6_group) ||
+			     SAME_ADDR6(ip->ip6_dst, inm->inm6_addr))) {
+				if (inm->inm6_timer == 0 ||
+				    inm->inm6_timer > timer) {
+					inm->inm6_timer =
+					    ICMP6_RANDOM_DELAY(timer);
+					icmp6_timers_are_running = 1;
+				}
+			}
+			IN6_NEXT_MULTI(step, inm);
+		}
+		break;
+
+	case ICMP6_GROUPMEM_REPORT:
+		if (icmplen < ICMP6_GRPLEN) {
+			icmp6stat.icp6s_badlen++;
+			goto freeit;
+		}
+		if ((icmp6_ipsec & ICMP6SEC_GROUPS) &&
+		    ((m->m_flags & M_AUTH) == 0))
+			goto logandfree;
+		icmp6stat.icp6s_rcv_grprep++;
+
+		if (ifp->if_flags & IFF_LOOPBACK)
+			break;
+		IFP_TO_IA6(ifp, ia);
+		if ((ia == NULL) || (ia->ia_flags & IFA_BOOTING))
+			break;
+
+		if (!IS_MULTIADDR6(icp->icmp6_grp) ||
+		    !SAME_ADDR6(icp->icmp6_grp, ip->ip6_dst)) {
+			icmp6stat.icp6s_rcv_bad_grprep++;
+			goto freeit;
+		}
+		/*
+		 * If we belong to the group being reported, stop
+		 * our timer for that group.
+		 */
+		IN6_LOOKUP_MULTI(icp->icmp6_grp, ifp, inm);
+		if (inm != NULL) {
+			inm->inm6_timer = 0;
+			icmp6stat.icp6s_rcv_our_grprep++;
+
+			inm->inm6_state = MULTI6_OTHERMEMBER;
+		}
+		break;
+
+	case ICMP6_GROUPMEM_TERM:
+		if (icmplen < ICMP6_GRPLEN) {
+			icmp6stat.icp6s_badlen++;
+			goto freeit;
+		}
+		if ((icmp6_ipsec & ICMP6SEC_GROUPS) &&
+		    ((m->m_flags & M_AUTH) == 0))
+			goto logandfree;
+		icmp6stat.icp6s_rcv_grpterm++;
+
+		if (ifp->if_flags & IFF_LOOPBACK)
+			break;
+		IFP_TO_IA6(ifp, ia);
+		if ((ia == NULL) || (ia->ia_flags & IFA_BOOTING))
+			break;
+
+		icmp6stat.icp6s_rcv_bad_grpterm++;
+		break;
+
+	case ICMP6_ECHO:
+		if ((icmp6_ipsec & ICMP6SEC_REQUESTS) &&
+		    ((m->m_flags & M_AUTH) == 0))
+			goto logandfree;
+		icmp6stat.icp6s_rcv_echoreq++;
+		/* reflect a copy */
+		{
+			struct mbuf *n, *o = 0;
+
+			n = m_copy(m, 0, (int)M_COPYALL);
+			if (n != 0)
+				n = m_pullup(n, sizeof(*ip) + sizeof(*icp));
+			if (n == 0) {
+				ip6stat.ip6s_inomem++;
+				icp->icmp6_type = ICMP6_ECHOREPLY;
+				icmp6stat.icp6s_reflect++;
+				icmp6_reflect(m, opts);
+				return;
+			}
+			if (opts)
+				o = ip6_copyoptions(opts, 0);
+			if ((opts != 0) && (o == 0)) {
+				m_freem(n);
+				ip6stat.ip6s_inomem++;
+				icp->icmp6_type = ICMP6_ECHOREPLY;
+				icmp6stat.icp6s_reflect++;
+				icmp6_reflect(m, opts);
+				return;
+			}
+			ip = mtod(n, struct ipv6 *);
+			icp = (struct icmpv6 *)(ip + 1);
+			icp->icmp6_type = ICMP6_ECHOREPLY;
+			icmp6stat.icp6s_reflect++;
+			icmp6_reflect(n, o);
+		}
+		break;
+
+	/*
+	 * No kernel processing for the following;
+	 * just fall through to send to raw listener.
+	 */
+	case ICMP6_ECHOREPLY:
+		/* no IPSec processing for this */
+		icmp6stat.icp6s_rcv_echorep++;
+		break;
+
+	default:
+		log(LOG_INFO,
+		    "icmp6_input: unknown type %d\n", icp->icmp6_type);
+		if (ICMP6_INFOTYPE(icp->icmp6_type))
+			goto freeit;
+		break;
+	}
+
+	rip6_input(m, (int)opts);
+	return;
+
+logandfree:
+	log(LOG_WARNING,
+    "icmp6_input: Auth failed for packet from %s to %s type %d code %d\n",
+	    ip6_sprintf(&ip->ip6_src), ip6_sprintf(&ip->ip6_dst),
+	    icp->icmp6_type, icp->icmp6_code);
+
+freeit:
+	if (opts)
+		m_freem(opts);
+	m_freem(m);
+}
+
+/*
+ * Reflect the IPv6 packet back to the source
+ */
+static void
+icmp6_reflect(m, opts)
+	struct mbuf *m;
+	struct mbuf *opts;
+{
+	struct ipv6 *ip = mtod(m, struct ipv6 *);
+	struct in6_ifaddr *ia;
+	struct in6_addr t;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_CTLOUT)
+		printf("icmp6_reflect(%p,%p) %s <> %s\n", m, opts,
+		       ip6_sprintf(&ip->ip6_src), ip6_sprintf(&ip->ip6_dst));
+#endif
+	if (IS_ANYADDR6(ip->ip6_src) || IS_MULTIADDR6(ip->ip6_src)) {
+		m_freem(m);	/* Bad return address */
+		goto done;
+	}
+
+	if (opts)
+		opts = opt6_reverse(ip, opts);
+
+	COPY_ADDR6(ip->ip6_dst, t);
+	COPY_ADDR6(ip->ip6_src, ip->ip6_dst);
+	/*
+	 * If the incoming packet was addressed directly to us,
+	 * use dst as the src for the reply.  Otherwise (broadcast
+	 * or anonymous), use the address which corresponds
+	 * to the incoming interface.
+	 */
+	for (ia = in6_ifaddrhead.tqh_first; ia; ia = ia->ia_list.tqe_next) {
+		if (SAME_ADDR6(t, IA_SIN6(ia)->sin6_addr))
+			break;
+	}
+	COPY_ADDR6(t, icmpdst.sin6_addr);
+	if ((ia == (struct in6_ifaddr *)0) && m->m_pkthdr.rcvif)
+		ia = (struct in6_ifaddr *)ifaof_ifpforaddr(
+				sin6tosa(&icmpdst), m->m_pkthdr.rcvif);
+	/*
+	 * The following happens if the packet was not addressed to us,
+	 * and was received on an interface with no IPv6 address
+	 * or for raw ip packets with option IP_HDRINCL.
+	 */
+	if (ia == (struct in6_ifaddr *)0)
+		ia = in6_ifaddrhead.tqh_first;
+	COPY_ADDR6(IA_SIN6(ia)->sin6_addr, t);
+	COPY_ADDR6(t, ip->ip6_src);
+	ip->ip6_hlim = MAXTTL;
+	m->m_flags &= ~(M_BCAST|M_MCAST);
+	icmp6_send(m, opts, NULL);
+done:
+	if (opts)
+		m_freem(opts);
+}
+
+/*
+ * Send an ICMPv6 packet back to the IPv6 level,
+ * after supplying a checksum.
+ */
+void
+icmp6_send(m, opts, imo)
+	struct mbuf *m;
+	struct mbuf *opts;
+	struct ip_moptions *imo;
+{
+	struct ipv6 *ip = mtod(m, struct ipv6 *);
+	struct icmpv6 *icp;
+	struct ip6ovck *ipc = (struct ip6ovck *)ip;
+	struct ip6ovck save_ip = *ipc;
+	union route_6 ro_6;
+	u_int16_t len = ip->ip6_len;
+
+	ipc->ih6_wrd1 = ipc->ih6_wrd0 = 0;
+	ipc->ih6_len = htons(len);
+	ipc->ih6_pr = IPPROTO_ICMPV6;
+	icp = (struct icmpv6 *)(ip + 1);
+	icp->icmp6_cksum = 0;
+	icp->icmp6_cksum = in_cksum(m, m->m_pkthdr.len);
+	*ipc = save_ip;
+#ifdef DIAGNOSTIC
+	if (icmpprintfs || (ip6printfs & D6_CTLOUT))
+		printf("icmp6_send dst %s src %s\n",
+		       ip6_sprintf(&ip->ip6_dst),
+		       ip6_sprintf(&ip->ip6_src));
+#endif
+	bzero(&ro_6, sizeof ro_6);
+	(void) ip6_output(m, opts, &ro_6.route, 0, imo, NULL);
+	if (ro_6.route.ro_rt)
+		RTFREE(ro_6.route.ro_rt);
+}
+
+/*
+ * Filter stuff
+ */
+/* Free */
+static void
+icmp6_filter_xfree(inp, m)
+	struct inpcb *inp;
+	struct mbuf *m;
+{
+	struct inp_xhdr *ixo = mtod(m, struct inp_xhdr *);
+	int s = splnet();
+
+	if ((m == inp->inp_xinfo) && (ixo->inp_xfree == icmp6_filter_xfree)) {
+		MFREE(m, inp->inp_xinfo);
+	}
+	splx(s);
+}
+
+/* Output */
+static int
+icmp6_filter_xoutput(x0, s, m0, opts, ro, flags, imo, inp)
+	struct mbuf *x0;
+	int s;
+	struct mbuf *m0;
+	struct mbuf *opts;
+	struct route *ro;
+	int flags;
+	struct ip_moptions *imo;
+	struct inpcb *inp;
+{
+	struct mbuf *x;
+	struct inp_xhdr *xp;
+
+	if (inp == NULL)
+		panic("icmp6_filter_xoutput: inp");
+	for (x = inp->inp_xinfo; x != x0; x = x->m_next)
+		/* continue */;
+	if (x != x0)
+		panic("icmp6_filter_xoutput: mbuf mismatch");
+	xp = mtod(x, struct inp_xhdr *);
+	if (xp->inp_xoutput != icmp6_filter_xoutput)
+		panic("icmp6_filter_xoutput: xoutput mismatch");
+	x = x0->m_next;
+	if (x) {
+		xp = mtod(x, struct inp_xhdr *);
+		return (xp->inp_xoutput(x, s, m0, opts, ro, flags, imo, inp));
+	}
+	splx(s);
+	return (real_ip6_output(m0, opts, ro, flags, imo, inp));
+}
+
+/* Set */
+int
+icmp6_filter_set(inp, m0)
+	struct inpcb *inp;
+	struct mbuf *m0;
+{
+	struct mbuf *m;
+	struct inp_xhdr *xp;
+	struct icmp6_filter *fp;
+	int s;
+
+	if ((m0 == NULL) || (m0->m_len != sizeof(*fp)))
+		return (EINVAL);
+	m = m_get(M_WAIT, MT_SOOPTS);
+	m->m_len = sizeof(*xp) + sizeof(*fp);
+	xp = mtod(m, struct inp_xhdr *);
+	xp->inp_xfree = icmp6_filter_xfree;
+	xp->inp_xoutput = icmp6_filter_xoutput;
+	fp = (struct icmp6_filter *)(xp + 1);
+	bcopy(mtod(m0, caddr_t), (caddr_t)fp, sizeof(*fp));
+	s = splnet();
+	m->m_next = inp->inp_xinfo;
+	inp->inp_xinfo = m;
+	splx(s);
+	return (0);
+}
+
+/* Get */
+int
+icmp6_filter_get(inp, mp)
+	struct inpcb *inp;
+	struct mbuf **mp;
+{
+	struct mbuf *m, *x;
+	struct inp_xhdr *xp;
+	struct icmp6_filter *fp;
+	int s;
+
+	*mp = m = m_get(M_WAIT, MT_SOOPTS);
+	if (m == NULL)
+		return (ENOBUFS);
+	m->m_len = sizeof(*fp);
+	fp = mtod(m, struct icmp6_filter *);
+	if ((inp == NULL) || ((x = inp->inp_xinfo) == NULL)) {
+		ICMP6_FILTER_SETPASSALL(fp);
+		return (0);
+	}
+	s = splnet();
+	for (x = inp->inp_xinfo; x != NULL; x = x->m_next) {
+		xp = mtod(x, struct inp_xhdr *);
+		if (xp->inp_xfree == icmp6_filter_xfree)
+			break;
+	}
+	splx(s);
+	if (x == NULL) {
+		ICMP6_FILTER_SETPASSALL(fp);
+		return (0);
+	}
+	bcopy((caddr_t)(xp + 1), (caddr_t)fp, sizeof(*fp));
+	return (0);
+}
+
+/* Filter (1 == block) */
+int
+icmp6_filter(inp, ip)
+	struct inpcb *inp;
+	struct ipv6 *ip;
+{
+	struct mbuf *x;
+	struct inp_xhdr *xp = 0;
+	struct icmp6_filter *fp;
+	struct icmpv6 *icp = (struct icmpv6 *)(ip + 1);
+	int s = splnet();
+
+	for (x = inp->inp_xinfo; x != NULL; x = x->m_next) {
+		xp = mtod(x, struct inp_xhdr *);
+		if (xp->inp_xfree == icmp6_filter_xfree)
+			break;
+	}
+	splx(s);
+	if (x == NULL)
+		return (0);
+	fp = (struct icmp6_filter *)(xp + 1);
+	return (ICMP6_FILTER_WILLBLOCK(icp->icmp6_type, fp));
+}
diff -uN src-current/sys/netinet/ip6_icmp.h src-current-ipv6/sys/netinet/ip6_icmp.h
--- src-current/sys/netinet/ip6_icmp.h
+++ src-current-ipv6/sys/netinet/ip6_icmp.h
@@ -0,0 +1,209 @@
+/*
+ * 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_IP6_ICMP_H_
+#define _NETINET_IP6_ICMP_H_
+
+/*
+ * Interface Control Message Protocol Definitions.
+ * Per not yet RFC xxxx
+ */
+
+/*
+ * Structure of an ICMPv6 header.
+ */
+struct icmpv6 {
+	u_int8_t	icmp6_type;	/* type of message, see below */
+	u_int8_t	icmp6_code;	/* type sub code */
+	u_int16_t	icmp6_cksum;	/* checksum */
+	union {
+	    n_long	 ih6_pmtu;	    /* next MTU (for discovery) */
+	    n_long	 ih6_pptr;	    /* bad parameter pointer */
+	    n_long	 ih6_flags;	    /* reserved/flags field */
+	    struct ih6_idseq {		    /* echo */
+		n_short	  icd6_id;
+		n_short	  icd6_seq;
+	    } ih6_idseq;
+	    struct ih6_gmm {
+		n_short	  igm6_mrd;	    /* maximum response delay */
+		n_short	  igm6_spare;
+	    } ih6_gmm;
+	    struct ih6_rtad {
+	        u_int8_t  irta_mhlim;
+		u_int8_t  irta_aflg;
+		u_int16_t irta_life;
+	    } ih6_rtad;
+	} icmp6_hun;
+#define icmp6_pmtu	icmp6_hun.ih6_pmtu
+#define icmp6_pptr	icmp6_hun.ih6_pptr
+#define icmp6_flags	icmp6_hun.ih6_flags
+#define icmp6_id	icmp6_hun.ih6_idseq.icd6_id
+#define icmp6_seq	icmp6_hun.ih6_idseq.icd6_seq
+#define icmp6_mrd	icmp6_hun.ih6_gmm.igm6_mrd
+#define icmp6_mhlim	icmp6_hun.ih6_rtad.irta_mhlim
+#define icmp6_aflg	icmp6_hun.ih6_rtad.irta_aflg
+#define icmp6_life	icmp6_hun.ih6_rtad.irta_life
+	union {
+	    struct in6_addr id6_grp;	    /* group address */
+	    struct id6_addr {
+	        struct in6_addr  id6_tgt;     /* target address */
+	        struct in6_addr  id6_rdst;    /* (redirect) destination */
+	    } id6_addr;
+	    struct id6_nud {
+	        u_int32_t	 id6_reach;   /* reachable time */
+	        u_int32_t	 id6_retrans; /* retrans timer */
+	    } id6_nud;
+	    struct ipv6	    id6_ip;	    /* header of packet in error */
+	    int8_t	    id6_data[1];    /* echo packet data */
+	} icmp6_dun;
+#define icmp6_grp	icmp6_dun.id6_grp
+#define icmp6_tgt	icmp6_dun.id6_addr.id6_tgt
+#define icmp6_rdst	icmp6_dun.id6_addr.id6_rdst
+#define icmp6_reach	icmp6_dun.id6_nud.id6_reach
+#define icmp6_retrans	icmp6_dun.id6_nud.id6_retrans
+#define icmp6_ip	icmp6_dun.id6_ip
+#define icmp6_data	icmp6_dun.id6_data
+};
+
+#define	ICMP6_MINLEN	8		/* abs minimum */
+#define ICMP6_GRPLEN	24		/* group stuff */
+#define ICMP6_RSLEN	8		/* router solicitation */
+#define ICMP6_RALEN	16		/* router advertisement */
+#define ICMP6_NSLEN	24		/* neighbor solicitation */
+#define ICMP6_NALEN	24		/* neighbor advertisement */
+#define ICMP6_RDLEN	40		/* redirect */
+
+/*
+ * Definition of type and code field values.
+ */
+#define ICMP6_UNREACH		1	/* dest unreachable, codes: */
+#define  ICMP6_UNREACH_NOROUTE	  0	 /* no route to destination */
+#define  ICMP6_UNREACH_ADMIN	  1	 /* administratively prohibited */
+#define  ICMP6_UNREACH_RTFAIL	  2	 /* not a neighbor */
+#define  ICMP6_UNREACH_ADDRESS	  3	 /* address unreachable */
+#define  ICMP6_UNREACH_PORT	  4	 /* port unreachable */
+#define ICMP6_PKTTOOBIG		2	/* packet too big */
+#define ICMP6_TIMXCEED		3	/* time exceeded, code: */
+#define  ICMP6_TIMXCEED_INTRANS	  0	 /* ttl==0 in transit */
+#define  ICMP6_TIMXCEED_REASS	  1	 /* ttl==0 in reass */
+#define ICMP6_PARAMPROB		4	/* ip header bad */
+#define  ICMP6_PARAMPROB_HDR	  0      /* erroneous header field */
+#define  ICMP6_PARAMPROB_NH	  1      /* unrecognized next header */
+#define  ICMP6_PARAMPROB_OPT	  2      /* unrecognized option */
+#define ICMP6_OLDREDIRECT	5	/* old redirect */
+#define ICMP6_ECHO		128	/* echo service */
+#define ICMP6_ECHOREPLY		129	/* echo reply */
+#define ICMP6_GROUPMEM_QUERY	130	/* group membership query */
+#define ICMP6_GROUPMEM_REPORT	131	/* group membership report */
+#define ICMP6_GROUPMEM_TERM	132	/* group membership termination */
+#define ICMP6_SOLICITATION_RT	133	/* router solicitation */
+#define ICMP6_ADVERTISEMENT_RT	134	/* router advertisment */
+#define ICMP6_SOLICITATION_ND	135	/* neighbor solicitation */
+#define ICMP6_ADVERTISEMENT_ND	136	/* neighbor advertisment */
+#define ICMP6_REDIRECT		137	/* redirect */
+
+#define	ICMP6_INFOTYPE(type)	((type) >= ICMP6_ECHO)
+
+#define ICMP6_ND_HOPS		255	/* hop count for ND */
+#define ICMP6_ND_PRIORITY	IPV6_PRIORITY_15
+
+/* IPSec flags */
+
+#define	ICMP6SEC_ERRORS		1	/* auth error types */
+#define ICMP6SEC_REQUESTS	2	/* auth echo requests */
+#define ICMP6SEC_GROUPS		4	/* auth group management */
+#define ICMP6SEC_NEIGHBORS	8	/* auth neighbor management */
+
+#ifndef ICMP6_FILTER_WILLPASS
+
+/*
+ * ICMPv6 filter definition
+ */
+
+struct icmp6_filter {
+	u_int32_t icmp6_filt[8];	/* 8*32 = 256 bits */
+};
+
+#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)
+#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_SETPASSALL(filterp)	\
+    {	\
+	register int i;	\
+	for (i = 0; i < 8; i++)	\
+	    (filterp)->icmp6_filt[i] = 0xffffffff;	\
+    }
+#define ICMP6_FILTER_SETBLOCKALL(filterp)	\
+    {	\
+	register int i;	\
+	for (i = 0; i < 8; i++)	\
+	    (filterp)->icmp6_filt[i] = 0;	\
+    }
+
+#endif
+
+#if defined(KERNEL) && defined(INET6)
+
+#define ICMP6_TIMER_SCALE	1000
+#define ICMP6_TIMER2HZ(mrd)	(ntohs(mrd) * PR_FASTHZ / ICMP6_TIMER_SCALE)
+/*
+ * Macro to compute a random timer value between 1 and its argument
+ * in countdown period units.  We assume that the routine random()
+ * is defined somewhere (and that it returns a positive number).
+ */
+#define	ICMP6_RANDOM_DELAY(maxdelay)	(random() % (maxdelay) + 1)
+#define ICMP6_DEFAULT_DELAY()		(random() % (9 * PR_FASTHZ) + 1)
+
+#define ICMP6_MAX_RATE		10
+
+void	icmp6_error __P((struct mbuf *, int, int, caddr_t));
+void	icmp6_errparam __P((struct mbuf *, struct mbuf *, int));
+void	icmp6_fasttimo __P((void));
+int	icmp6_filter __P((struct inpcb *, struct ipv6 *));
+int	icmp6_filter_set __P((struct inpcb *, struct mbuf *));
+int	icmp6_filter_get __P((struct inpcb *, struct mbuf **));
+void	icmp6_init __P((void));
+void	icmp6_input __P((struct mbuf *, int));
+void	icmp6_joingroup __P((struct in6_multi *));
+void	icmp6_leavegroup __P((struct in6_multi *));
+void	icmp6_send __P((struct mbuf *, struct mbuf *, struct ip_moptions *));
+#endif
+
+#endif
diff -uN src-current/sys/netinet/ip6_input.c src-current-ipv6/sys/netinet/ip6_input.c
--- src-current/sys/netinet/ip6_input.c
+++ src-current-ipv6/sys/netinet/ip6_input.c
@@ -0,0 +1,2253 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 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_input.c	8.2 (Berkeley) 1/4/94
+ */
+
+#include "opt_inet6.h"
+#include "opt_ip6fw.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+
+#include <machine/limits.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/radix.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/ip6_icmp.h>
+#include <netinet/ip6_opts.h>
+#include <netinet/if_ether.h>
+#include <netinet/if_ndp6.h>
+
+#include <sys/socketvar.h>
+
+#ifdef IP6FIREWALL
+#include <netinet/ip6_fw.h>
+#endif
+
+extern	struct domain inet6domain;
+extern	struct protosw inet6sw[];
+u_char	ip6_protox[IPPROTO_MAX];
+struct	in6_ifaddrhead in6_ifaddrhead;
+struct	ip6stat ip6stat;
+
+/* Packet reassembly stuff */
+#define IP6REASS_NHASH_LOG2	6
+#define IP6REASS_NHASH		(1 << IP6REASS_NHASH_LOG2)
+#define IP6REASS_HMASK		(IP6REASS_NHASH - 1)
+#define IP6REASS_HASH(x1,x2,y) \
+	((((x1) & 0xF | (((x2) & 0xF) << 4)) ^ (y)) & IP6REASS_HMASK)
+
+static struct ip6q ip6q[IP6REASS_NHASH];
+static int nip6q = 0;		/* total # of reass queues */
+static int maxnip6q;
+
+int	ip6forwarding = 0;
+int	ip6mforwarding = 0;
+static	int ip6forwsrcrt = 0;
+
+static	void rt6_reverse __P((struct ipv6 *, struct mbuf *));
+
+static int
+sysctl_net_inet6_forwarding SYSCTL_HANDLER_ARGS
+{
+	int error = sysctl_handle_int(oidp,
+		oidp->oid_arg1, oidp->oid_arg2, req);
+
+	if (!error) {
+		ip6forwarding = ip6forwarding != 0;
+		ip6forwsrcrt = ip6forwsrcrt != 0;
+	}
+	return error;
+}
+
+SYSCTL_PROC(_net_inet6_ipv6, IP6CTL_FORWARDING, forwarding,
+	CTLTYPE_INT|CTLFLAG_RW, &ip6forwarding, 0,
+	&sysctl_net_inet6_forwarding, "I", "");
+
+static int
+sysctl_net_inet6_mforwarding SYSCTL_HANDLER_ARGS
+{   
+	struct ifnet *ifp;
+	struct in6_ifaddr *ia;
+	struct in6_addr anyaddr6 = IN6ADDR_ANY_INIT;
+	struct in6_multi *inm;
+	int error = sysctl_handle_int(oidp,
+		oidp->oid_arg1, oidp->oid_arg2, req);
+
+	if (error)
+		return error;
+	ip6mforwarding = ip6mforwarding != 0;
+	/* 
+	 * If mforwarding is turned on(/off), all capable interfaces
+	 * should (stop to) receive any multicast packets on the net.
+	 */
+	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_link)) {
+		if (ifp->if_flags & IFF_MULTICAST) {
+			IFP_TO_IA6(ifp, ia);
+			if (ia) {
+				if (ip6mforwarding)
+					in6_addmulti(&anyaddr6, ifp);
+				else {
+					IN6_LOOKUP_MULTI(anyaddr6, ifp, inm);
+					if (inm != NULL)
+						in6_delmulti(inm);
+				}
+			}
+		}
+	}
+	return error;
+}
+
+SYSCTL_PROC(_net_inet6_ipv6, IP6CTL_MFORWARDING, mforwarding,
+	CTLTYPE_INT|CTLFLAG_RW, &ip6mforwarding, 0,
+	&sysctl_net_inet6_mforwarding, "I", "");
+
+SYSCTL_PROC(_net_inet6_ipv6, IP6CTL_FORWSRCRT, forwsrcrt,
+	CTLTYPE_INT|CTLFLAG_RW, &ip6forwsrcrt, 0,
+	&sysctl_net_inet6_forwarding, "I", "");
+
+static int
+sysctl_net_inet6_defttl SYSCTL_HANDLER_ARGS
+{
+	static int old_ip_defttl = IPDEFTTL;
+	int error = sysctl_handle_int(oidp,
+		oidp->oid_arg1, oidp->oid_arg2, req);
+
+	if (!error) {
+		if (old_ip_defttl != ip_defttl)
+			log(LOG_WARNING,
+			    "default TTL is shared between IPv4 and IPv6\n");
+		old_ip_defttl = ip_defttl;
+	}
+	return error;
+}
+
+SYSCTL_PROC(_net_inet6_ipv6, IP6CTL_DEFTTL, ttl,
+	CTLTYPE_INT|CTLFLAG_RW, &ip_defttl, 0,
+	&sysctl_net_inet6_defttl, "I", "");
+
+/* this is used inside macros, don't put #ifdef DIAGNOSTIC ! */
+int	ip6printfs = 0;
+
+/* Firewall hooks */
+ip6_fw_chk_t *ip6_fw_chk_ptr;
+ip6_fw_ctl_t *ip6_fw_ctl_ptr;
+
+static void	frg6_deq __P((struct ip6asfrag *));
+static void	frg6_enq __P((struct ip6asfrag *, struct ip6asfrag *));
+static void	frg6_freef __P((struct ip6q *));
+static void	ip6_forward __P((struct mbuf *, int));
+static struct ipv6 *
+	ip6_reass __P((struct ip6asfrag *, struct ip6q *, struct ip6q *));
+static int	ip6rttimeout __P((struct radix_node *, void *));
+static void	ip6rttimer __P((void *));
+static struct mbuf *
+	ip6_saveoption __P((struct mbuf *, struct mbuf *, int, int));
+static void	ip6_deloption __P((struct mbuf *, int));
+
+/* timers */
+u_int	flcache_keep = 20;	/* 20 seconds */
+u_int	ip6_prune = 2;		/* 2 seconds */
+
+SYSCTL_INT(_net_inet6_ipv6, IP6CTL_PRUNE, prune, CTLFLAG_RW,
+	&ip6_prune,  0, "");
+
+/*
+ * IPv6 route timeout routines.
+ */
+/* ARGSUSED */
+static int
+ip6rttimeout(rn, arg)
+	struct radix_node *rn;
+	void *arg;
+{
+	struct rtentry *rt = (struct rtentry *)rn;
+	struct ifnet *ifp;
+	int mtu;
+
+	if ((rt->rt_flags & RTF_DYNAMIC) &&
+	    rt->rt_rmx.rmx_expire &&
+	    rt->rt_rmx.rmx_expire <= time_second) {
+		if (rt->rt_flags & RTF_LOCAL)
+			ifp = loif;
+		else
+			ifp = rt->rt_ifp;
+		mtu = rt->rt_rmx.rmx_mtu;
+		if (mtu == 0)
+			rt->rt_rmx.rmx_mtu = ifp->if_mtu;
+		else if (mtu > ifp->if_mtu) {
+			rt->rt_rmx.rmx_mtu = ifp->if_mtu;
+			log(LOG_ERR, "ip6rttimeout: bad MTU\n");
+		}
+		/* TODO: plateau and call tcp6_mtudisc */
+		if ((rt->rt_flags & RTF_DYNAMIC) &&
+		    (rt->rt_flags & RTF_LLINFO) &&
+		    rt->rt_ifa->ifa_rtrequest)
+			rt->rt_ifa->ifa_rtrequest(RTM_EXPIRE, rt, 0);
+		else if (rt->rt_refcnt < 1)
+			rtrequest(RTM_DELETE,
+				  rt_key(rt), NULL, rt_mask(rt), 0, NULL);
+	}
+	return (0);
+}
+
+/* ARGSUSED */
+static void
+ip6rttimer(arg)
+	void *arg;
+{
+	struct radix_node_head *rnh;
+	int s = splnet();
+
+	timeout(ip6rttimer, NULL, ip6_prune * hz);
+
+	rnh = rt_tables[AF_INET6];
+	if (rnh == NULL)
+		return;
+	rnh->rnh_walktree(rnh, ip6rttimeout, NULL);
+
+	splx(s);
+}
+
+/*
+ * IPv6 initialization: fill in IPv6 protocol switch table.
+ * All protocols not implemented in kernel go to raw IP protocol handler.
+ */
+void
+ip6_init()
+{
+	struct protosw *pr;
+	int i;
+
+	pr = pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW);
+	if (pr == 0)
+		panic("ip6_init");
+	for (i = 0; i < IPPROTO_MAX; i++)
+		ip6_protox[i] = pr - inet6sw;
+	for (pr = inet6domain.dom_protosw + 1;
+	    pr < inet6domain.dom_protoswNPROTOSW; pr++) {
+		if (pr->pr_domain->dom_family != PF_INET6)
+			continue;
+		if (pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
+			ip6_protox[pr->pr_protocol] = pr - inet6sw;
+		if (pr->pr_type == 0 && pr->pr_protocol == IP6_NHDR_HOP)
+			ip6_protox[pr->pr_protocol] = pr - inet6sw;
+	}
+	for (i = 0; i < IP6REASS_NHASH; i++)
+		ip6q[i].next = ip6q[i].prev = &ip6q[i];
+
+	maxnip6q = nmbclusters/4;
+
+	ip6_id = time_second;
+	TAILQ_INIT(&in6_ifaddrhead);
+	LIST_INIT(&in6_anyhead);
+#ifdef IP6FIREWALL
+	ip6_fw_init();
+#endif
+#ifdef IP6NAT
+	ip6_nat_init();
+#endif
+	{
+		struct timeval t;
+		getmicrotime(&t);
+		(void) flow6_rand((int)(t.tv_sec + t.tv_usec));
+	}
+	timeout(ip6rttimer, NULL, ip6_prune * hz);
+}
+
+/*
+ * Random generator for flow IDs.
+ */
+int
+flow6_rand(new)
+	int new;
+{
+	static int next;
+	int h, l, x, n, s = splnet();
+
+	if (new) {
+		next = new;
+		if (next <= 0)
+			next += 0x7fffffff;
+	}
+	n = 0;
+    again:
+	if (n > 10)
+		panic("flow6_rand");
+	
+	h = next / 127773;
+	l = next % 127773;
+	next = 16807 * l + 2836 * h;
+	if (next <= 0)
+		next += 0x7fffffff;
+	/* only 24 bits are needed */
+	x = next >> 7;
+	x &= 0xffffff;
+	if (x == 0)
+		goto again;
+	splx(s);
+	return (x);
+}
+
+/*
+ * IPv6 input routine.  Checksum and byte swap header.  If fragmented
+ * try to reassemble.  Process options.  Pass to next level.
+ */
+void
+ip6_input(m, arg)
+	struct mbuf *m;
+	int arg;
+{
+	struct mbuf *opts = (struct mbuf *)arg;
+	struct ipv6 *ip;
+	struct in6_ifaddr *ia;
+	int len;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_INPUT)
+		printf("ip6_input(%p) len=%d/%d\n",
+		       m, m->m_pkthdr.len, m->m_len);
+#endif
+	/*
+	 * We can do nothing useful with options ?!
+	 */
+	if (opts)
+		m_freem(opts);
+
+	/*
+	 * If no IPv6 addresses have been set yet but the interfaces
+	 * are receiving, can't do anything with incoming packets yet.
+	 */
+	if (TAILQ_EMPTY(&in6_ifaddrhead))
+		goto bad;
+	ip6stat.ip6s_total++;
+
+#ifdef	DIAGNOSTIC
+	if (m->m_len < sizeof(struct ipv6))
+		panic("ipintr mbuf too short");
+#endif
+
+	if (m->m_len < sizeof (struct ipv6) &&
+	    (m = m_pullup(m, sizeof (struct ipv6))) == 0) {
+		ip6stat.ip6s_toosmall++;
+		return;
+	}
+
+	ip = mtod(m, struct ipv6 *);
+	if ((ip->ip6_head & IPV6_FLOWINFO_VERSION) != IPV6_VERSION) {
+		ip6stat.ip6s_badvers++;
+		goto bad;
+	}
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_INPUT)
+		printf("ip6_input src %s dst %s len %d nh %d\n",
+		       ip6_sprintf(&ip->ip6_src),
+		       ip6_sprintf(&ip->ip6_dst),
+		       ntohs(ip->ip6_len), ip->ip6_nh);
+#endif
+	/*
+	 * Check source address.
+	 */
+	if (IS_MULTIADDR6(ip->ip6_src) || in6_isanycast(&ip->ip6_src)) {
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_INPUT)
+			printf("ip6_input bad src\n");
+#endif
+		ip6stat.ip6s_badsource++;
+		goto bad;
+	}
+
+	/*
+	 * Check buffer length and trim extra.
+	 */
+	NTOHS(ip->ip6_len);
+	len = sizeof(struct ipv6) + ip->ip6_len;
+	if (m->m_pkthdr.len < len) {
+		ip6stat.ip6s_tooshort++;
+		goto bad;
+	}
+	if (m->m_pkthdr.len > len) {
+		if (m->m_len == m->m_pkthdr.len) {
+			m->m_len = len;
+			m->m_pkthdr.len = len;
+		} else
+			m_adj(m, len - m->m_pkthdr.len);
+	}
+
+	/*
+	 * IpHack's section.
+	 * Right now when no processing on packet has done
+	 * and it is still fresh out of network we do our black
+	 * deals with it.
+	 * - Firewall: deny/allow(/divert)
+	 * (- Xlate: translate packet's addr/port (NAT)).
+	 * - Wrap: fake packet's addr/port <unimpl.>
+	 * - Encapsulate: put it in another IPv6 and send out. <unimp.>
+ 	 */
+
+	if (ip6_fw_chk_ptr) {
+#ifdef IPDIVERT
+		u_short port;
+
+		port = (*ip6_fw_chk_ptr)(&ip, NULL, ip_divert_ignore, &m);
+		ip_divert_ignore = 0;
+		if (port) {			/* Divert packet */
+			frag_divert_port = port;
+			goto ours;
+		}
+#else
+		/* If ipfw says divert, we have to just drop packet */
+		if ((*ip6_fw_chk_ptr)(&ip, NULL, 0, &m)) {
+			m_freem(m);
+			m = NULL;
+		}
+#endif
+	}
+
+	/*
+	 * Check our list of addresses, to see if the packet is for us.
+	 */
+	for (ia = in6_ifaddrhead.tqh_first; ia; ia = ia->ia_list.tqe_next)
+		if (SAME_ADDR6(IA_SIN6(ia)->sin6_addr, ip->ip6_dst))
+			goto ours;
+	if (IS_MULTIADDR6(ip->ip6_dst)) {
+		struct in6_multi *inm;
+
+		if (ip6mforwarding) {
+			/*
+			 * If we are acting as a multicast router, all
+			 * incoming multicast packets are passed to the
+			 * kernel-level multicast forwarding function.
+			 * The packet is returned (relatively) intact; if
+			 * ip6_mforward() returns a non-zero value, the packet
+			 * must be discarded, else it may be accepted below.
+			 */
+			if (ip6_mforward(m, m->m_pkthdr.rcvif) != 0) {
+				ip6stat.ip6s_cantforward++;
+				goto bad;
+			}
+			/*
+			 * The process-level routing daemon needs to receive
+			 * all multicast ICMPv6 packets, whether or not this
+			 * host belongs to their destination groups.
+			 */
+			if (ip->ip6_nh == IPPROTO_ICMPV6)
+				goto ours;
+			ip6stat.ip6s_forward++;
+		}
+		/*
+		 * See if we belong to the destination multicast group on the
+		 * arrival interface.
+		 */
+		IN6_LOOKUP_MULTI(ip->ip6_dst, m->m_pkthdr.rcvif, inm);
+		if (inm == NULL) {
+			ip6stat.ip6s_cantforward++;
+			goto bad;
+		}
+		goto ours;
+	}
+	if (ip6forwarding) {
+		if (in6_isanycast(&ip->ip6_dst) >= IP6ANY_ROUTER)
+			goto ours;
+	} else if (in6_isanycast(&ip->ip6_dst) == IP6ANY_ALLWAYS)
+		goto ours;
+
+	/*
+	 * Not for us; forward if possible and desirable.
+	 */
+	if (ip6forwarding == 0) {
+		ip6stat.ip6s_cantforward++;
+		goto bad;
+	} else {
+		ip6_forward(m, 0);
+		return;
+	}
+
+ours:
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_INPUT)
+		printf("ip6_input for protocol %d\n", ip->ip6_nh);
+#endif
+	/*
+	 * Switch out to protocol's input routine.
+	 */
+	ip6stat.ip6s_delivered++;
+	ip6stat.ip6s_inhist[ip->ip6_nh]++;
+	(*inet6sw[ip6_protox[ip->ip6_nh]].pr_input)(m, 0);
+	return;
+bad:
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_INPUT)
+		 printf("ip6_input bad packet\n");
+#endif
+	m_freem(m);
+}
+
+/*
+ * Fragment header input processing.
+ */
+
+void
+frg6_input(m, arg)
+	struct mbuf *m;
+	int arg;
+{
+	struct mbuf *opts = (struct mbuf *)arg;
+	struct ipv6 *ip;
+	struct ipv6_fraghdr *frgp;
+	struct ip6q *fp;
+	int i, hash;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_REASS)
+		printf("frg6_input\n");
+#endif
+	ip6stat.ip6s_delivered--;
+
+	/*
+	 * Reassemble, first pullup headers.
+	 * (if a cluster is used headers will be moved to a mbuf)
+	 */
+	if ((m = m_pullup(m, sizeof(*ip) + sizeof(*frgp))) == 0) {
+		ip6stat.ip6s_toosmall++;
+		if (opts)
+			m_freem(opts);
+		return;
+	}
+	ip = mtod(m, struct ipv6 *);
+	frgp = (struct ipv6_fraghdr *)(ip + 1);
+	NTOHS(frgp->if6_off);
+	NTOHL(frgp->if6_id);
+
+	/*
+	 * Make sure that fragments have a data length
+	 * that's a non-zero multiple of 8 bytes.
+	 */
+	if ((frgp->if6_off & IP6_MF) &&
+	    ((ip->ip6_len <= sizeof(*frgp)) || ((ip->ip6_len & 0x7) != 0))) {
+		ip6stat.ip6s_toosmall++;
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_REASS)
+			printf("frg6_input: bad length %d\n", ip->ip6_len);
+#endif
+		if (opts)
+			m_freem(opts);
+		m_freem(m);
+		return;
+	}
+
+	hash = IP6REASS_HASH(ip->ip6_src.s6_addr[15],
+			     ip->ip6_src.s6_addr[14],
+			     frgp->if6_id);
+	/*
+	 * Look for queue of fragments of this datagram.
+	 */
+	for (fp = ip6q[hash].next; fp != &ip6q[hash]; fp = fp->next)
+		if (frgp->if6_id == fp->ip6q_id &&
+		    SAME_ADDR6(ip->ip6_src, fp->ip6q_src) &&
+		    SAME_ADDR6(ip->ip6_dst, fp->ip6q_dst) &&
+		    frgp->if6_nh == fp->ip6q_nh)
+			goto found;
+
+	fp = 0;
+
+	/* check if there's a place for the new queue */
+	if (nip6q > maxnip6q) {
+	    /*
+	     * drop something from the tail of the current queue
+	     * before proceeding further
+	     */
+	    if (ip6q[hash].prev == &ip6q[hash]) {	/* gak */
+		for (i = 0; i < IP6REASS_NHASH; i++) {
+		    if (ip6q[i].prev != &ip6q[i]) {
+		        frg6_freef(ip6q[i].prev);
+			break;
+		    }
+		}
+	    } else
+		frg6_freef(ip6q[hash].prev);
+	}
+found:
+
+	/*
+	 * Adjust ip6_len to not reflect header,
+	 * set if6_res (same than ip6f_mff)
+	 * if more fragments are expected,
+	 * set ip6_nh to next header type.
+	 */
+	ip->ip6_len -= sizeof(*frgp);
+	ip->ip6_nh = frgp->if6_nh;
+	if (frgp->if6_off & IP6_MF) {
+		frgp->if6_res = 1;
+		frgp->if6_off &= ~IP6_MF;
+		/* check if the fragment is in bound */
+		if ((int)frgp->if6_off + (int)ip->ip6_len > USHRT_MAX) {
+			ip6stat.ip6s_toosmall++;
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_REASS)
+				printf("frg6_input: too large\n");
+#endif
+			if (opts)
+				m_freem(opts);
+			m_freem(m);
+			return;
+		}
+	} else
+		frgp->if6_res = 0;
+
+	/*
+	 * If datagram marked as having more fragments
+	 * or if this is not the first fragment,
+	 * attempt reassembly; if it succeeds, proceed.
+	 */
+	if (frgp->if6_res || frgp->if6_off) {
+		ip6stat.ip6s_fragments++;
+		ip = ip6_reass((struct ip6asfrag *)ip, fp, &ip6q[hash]);
+		if (ip == 0) {
+			if (opts)
+				m_freem(opts);
+			return;
+		}
+		ip6stat.ip6s_reassembled++;
+		m = dtom(ip);
+	} else
+		if (fp)
+			frg6_freef(fp);
+
+	/*
+	 * Zap fragment header
+	 */
+	m->m_data += sizeof(struct ipv6_fraghdr);
+	m->m_len -= sizeof(struct ipv6_fraghdr);
+	m->m_pkthdr.len -= sizeof(struct ipv6_fraghdr);
+	ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ipv6));
+	ip = mtod(m, struct ipv6 *);
+
+	/*
+	 * Switch out to protocol's input routine.
+	 */
+	if (ip->ip6_nh == IP6_NHDR_HOP) {
+		if (opts)
+			m_freem(opts);
+		icmp6_errparam(m, 0, 0);
+		return;
+	}
+	ip6stat.ip6s_delivered++;
+	ip6stat.ip6s_inhist[ip->ip6_nh]++;
+	(*inet6sw[ip6_protox[ip->ip6_nh]].pr_input)(m, (int)opts);
+	return;
+}
+
+/*
+ * Take incoming datagram fragment and try to
+ * reassemble it into whole datagram.  If a chain for
+ * reassembly of this datagram already exists, then it
+ * is given as fp; otherwise have to make a chain.
+ */
+static struct ipv6 *
+ip6_reass(ip, fp, where)
+	struct ip6asfrag *ip;
+	struct ip6q *fp;
+	struct ip6q *where;
+{
+	struct mbuf *m = dtom(ip);
+	struct ip6asfrag *q;
+	struct mbuf *t;
+	int i, next;
+
+	/*
+	 * Presence of header sizes in mbufs
+	 * would confuse code below.
+	 */
+	m->m_data += sizeof(*ip);
+	m->m_len -= sizeof(*ip);
+
+	/*
+	 * If first fragment to arrive, create a reassembly queue.
+	 */
+	if (fp == 0) {
+		if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) {
+			ip6stat.ip6s_inomem++;
+			goto dropfrag;
+		}
+		fp = mtod(t, struct ip6q *);
+		insque(fp, where);
+		nip6q++;
+		fp->ip6q_ttl = IP6FRAGTTL;
+		fp->ip6q_nh = ip->ip6f_nh;
+		fp->ip6q_id = ip->ip6f_id;
+		fp->ip6q_next = fp->ip6q_prev = (struct ip6asfrag *)fp;
+		COPY_ADDR6(((struct ipv6 *)ip)->ip6_src, fp->ip6q_src);
+		COPY_ADDR6(((struct ipv6 *)ip)->ip6_dst, fp->ip6q_dst);
+		q = (struct ip6asfrag *)fp;
+		goto insert;
+	}
+
+	/*
+	 * Find a segment which begins after this one does.
+	 */
+	for (q = fp->ip6q_next; q != (struct ip6asfrag *)fp; q = q->ip6f_next)
+		if (q->ip6f_off > ip->ip6f_off)
+			break;
+
+	/*
+	 * If there is a preceding segment, it may provide some of
+	 * our data already.  If so, drop the data from the incoming
+	 * segment.  If it provides all of our data, drop us.
+	 */
+	if (q->ip6f_prev != (struct ip6asfrag *)fp) {
+		i = q->ip6f_prev->ip6f_off +
+			q->ip6f_prev->ip6f_len - ip->ip6f_off;
+		if (i > 0) {
+			if (i >= ip->ip6f_len)
+				goto dropfrag;
+			m_adj(dtom(ip), i);
+			ip->ip6f_off += i;
+			ip->ip6f_len -= i;
+		}
+	}
+
+	/*
+	 * While we overlap succeeding segments trim them or,
+	 * if they are completely covered, dequeue them.
+	 */
+	while (q != (struct ip6asfrag *)fp &&
+	       ip->ip6f_off + ip->ip6f_len > q->ip6f_off) {
+		struct mbuf *m0;
+
+		i = (ip->ip6f_off + ip->ip6f_len) - q->ip6f_off;
+		if (i < q->ip6f_len) {
+			q->ip6f_len -= i;
+			q->ip6f_off += i;
+			m_adj(dtom(q), i);
+			break;
+		}
+		m0 = dtom(q);
+		q = q->ip6f_next;
+		frg6_deq(q->ip6f_prev);
+		m_freem(m0);
+	}
+
+insert:
+	/*
+	 * Stick new segment in its place;
+	 * check for complete reassembly.
+	 */
+	frg6_enq(ip, q->ip6f_prev);
+	next = 0;
+	for (q = fp->ip6q_next;
+	     q != (struct ip6asfrag *)fp;
+	     q = q->ip6f_next) {
+		if (q->ip6f_off != next)
+			return (0);
+		next += q->ip6f_len;
+	}
+	if (q->ip6f_prev->ip6f_mff & 1)
+		return (0);
+
+	/*
+	 * Reassembly is complete; concatenate fragments.
+	 */
+	q = fp->ip6q_next;
+	m = dtom(q);
+	t = m->m_next;
+	m->m_next = 0;
+	m_cat(m, t);
+	q = q->ip6f_next;
+	while (q != (struct ip6asfrag *)fp) {
+		t = dtom(q);
+		q = q->ip6f_next;
+		m_cat(m, t);
+	}
+
+	/*
+	 * Create header for new IPv6 packet by
+	 * modifying header of first packet;
+	 * dequeue and discard fragment reassembly header.
+	 * Make header visible.
+	 */
+	ip = fp->ip6q_next;
+	ip->ip6f_len = next;
+	ip->ip6f_mff &= ~1;
+	COPY_ADDR6(fp->ip6q_src, ((struct ipv6 *)ip)->ip6_src);
+	COPY_ADDR6(fp->ip6q_dst, ((struct ipv6 *)ip)->ip6_dst);
+	remque(fp);
+	(void) m_free(dtom(fp));
+	nip6q--;
+	m = dtom(ip);
+	m->m_len += sizeof(*ip);
+	m->m_data -= sizeof(*ip);
+	/* some debugging cruft by sklower, below, will go away soon */
+	if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */
+		int plen = 0;
+		for (t = m; m; m = m->m_next)
+			plen += m->m_len;
+		t->m_pkthdr.len = plen;
+	}
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_REASS)
+		printf("frg6_reass return src %s dst %s len %d\n",
+		       ip6_sprintf(&((struct ipv6 *)ip)->ip6_src),
+		       ip6_sprintf(&((struct ipv6 *)ip)->ip6_dst),
+		       ((struct ipv6 *)ip)->ip6_len);
+#endif
+	return ((struct ipv6 *)ip);
+
+dropfrag:
+	ip6stat.ip6s_fragdropped++;
+	m_freem(m);
+	return (0);
+}
+
+/*
+ * Free an IPv6 fragment reassembly header and all
+ * associated datagrams.
+ */
+static void
+frg6_freef(fp)
+	struct ip6q *fp;
+{
+	struct ip6asfrag *q, *p;
+
+	for (q = fp->ip6q_next; q != (struct ip6asfrag *)fp; q = p) {
+		p = q->ip6f_next;
+		frg6_deq(q);
+		m_freem(dtom(q));
+	}
+	remque(fp);
+	(void) m_free(dtom(fp));
+	nip6q--;
+}
+
+/*
+ * Put an IPv6 fragment on a reassembly chain.
+ * Like insque, but pointers in middle of structure.
+ */
+static void
+frg6_enq(p, prev)
+	struct ip6asfrag *p, *prev;
+{
+
+	p->ip6f_prev = prev;
+	p->ip6f_next = prev->ip6f_next;
+	prev->ip6f_next->ip6f_prev = p;
+	prev->ip6f_next = p;
+}
+
+/*
+ * To frg6_enq as remque is to insque.
+ */
+static void
+frg6_deq(p)
+	struct ip6asfrag *p;
+{
+
+	p->ip6f_prev->ip6f_next = p->ip6f_next;
+	p->ip6f_next->ip6f_prev = p->ip6f_prev;
+}
+
+/*
+ * IPv6 fragment timer processing;
+ * if a timer expires on a reassembly
+ * queue, discard it.
+ */
+void
+frg6_slowtimo()
+{
+	struct ip6q *fp;
+	int i, s = splnet();
+
+	for (i = 0; i < IP6REASS_NHASH; i++) {
+		fp = ip6q[i].next;
+		if (fp == 0)
+			continue;
+		while (fp != &ip6q[i]) {
+			--fp->ip6q_ttl;
+			fp = fp->next;
+			if (fp->prev->ip6q_ttl == 0) {
+				ip6stat.ip6s_fragtimeout++;
+				frg6_freef(fp->prev);
+			}
+		}
+	}
+	splx(s);
+}
+
+/*
+ * Drain off all datagram fragments.
+ */
+void
+frg6_drain()
+{
+	int i;
+
+	for (i = 0; i < IP6REASS_NHASH; i++) {
+		while (ip6q[i].next != &ip6q[i]) {
+			ip6stat.ip6s_fragdropped++;
+			frg6_freef(ip6q[i].next);
+		}
+	}
+}
+
+/*
+ * Copy an option (ie header) to opts mbuf chain.
+ */
+static struct mbuf *
+ip6_saveoption(m0, opts, len, type)
+	struct mbuf *m0;
+	struct mbuf *opts;
+	int len;
+	int type;
+{
+	struct ipv6 *ip = mtod(m0, struct ipv6 *);
+	struct mbuf *m;
+	int saved = 0;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_OPTIN)
+		printf("ip6_saveoption(%p,%p,%d,%d)\n", m0, opts, len, type);
+#endif
+	if (type == IP6_NHDR_RT)
+		len += sizeof(struct in6_addr);
+
+	if (len > MCLBYTES)
+		goto zap;
+	MGETHDR(m, M_DONTWAIT, MT_SOOPTS);
+	if (m == 0) {
+		ip6stat.ip6s_inomem++;
+		goto zap;
+	}
+	if (MHLEN >= len) {
+		MH_ALIGN(m, len);
+	} else {
+		MCLGET(m, M_DONTWAIT);
+		if ((m->m_flags & M_EXT) == 0) {
+			ip6stat.ip6s_inomem++;
+			m_free(m);
+			goto zap;
+		}
+	}
+	if (type == IP6_NHDR_RT) {
+		len -= sizeof(struct in6_addr);
+		bzero(mtod(m, caddr_t) + len, sizeof(struct in6_addr));
+	}
+	m->m_pkthdr.len = m->m_len = len;
+	m->m_pkthdr.pktype = type;
+	if (opts) {
+		m->m_next = opts;
+		m->m_pkthdr.len += opts->m_pkthdr.len;
+	}
+	m_copydata(m0, sizeof(*ip), len, mtod(m, caddr_t));
+	opts = m;
+	saved = 1;
+
+zap:
+	m0->m_pkthdr.len -= len;
+	if (m0->m_len > sizeof(*ip) + len) {
+		m0->m_data += len;
+		m0->m_len -= len;
+		ovbcopy((caddr_t)ip, mtod(m0, caddr_t), sizeof(struct ipv6));
+	} else {
+		len -= m0->m_len - sizeof(*ip);
+		m0->m_len = sizeof(*ip);
+		m = m0->m_next;
+		/* from m_adj */
+		while (len > 0) {
+			if (m == NULL)
+				panic("ip6_saveoption");
+			if (m->m_len <= len) {
+				len -= m->m_len;
+				m->m_len = 0;
+				m = m->m_next;
+			} else {
+				m->m_len -= len;
+				m->m_data += len;
+				len = 0;
+			}
+		}
+	}
+	if (opts && !saved) {
+		m_freem(opts);
+		opts = (struct mbuf *)0;
+	}
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_OPTIN)
+		printf("ip6_saveoption returns %p\n", opts);
+#endif
+	return (opts);			
+}
+
+/*
+ * Delete an option (ie header).
+ */
+static void
+ip6_deloption(m0, len)
+	struct mbuf *m0;
+	int len;
+{
+	struct ipv6 *ip = mtod(m0, struct ipv6 *);
+	struct mbuf *m;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_OPTIN)
+		printf("ip6_deloption(%p,%d)\n", m0, len);
+#endif
+
+	m0->m_pkthdr.len -= len;
+	if (m0->m_len > sizeof(*ip) + len) {
+		m0->m_data += len;
+		m0->m_len -= len;
+		ovbcopy((caddr_t)ip, mtod(m0, caddr_t), sizeof(struct ipv6));
+	} else {
+		len -= m0->m_len - sizeof(*ip);
+		m0->m_len = sizeof(*ip);
+		m = m0->m_next;
+		/* from m_adj */
+		while (len > 0) {
+			if (m == NULL)
+				panic("ip6_deloption");
+			if (m->m_len <= len) {
+				len -= m->m_len;
+				m->m_len = 0;
+				m = m->m_next;
+			} else {
+				m->m_len -= len;
+				m->m_data += len;
+				len = 0;
+			}
+		}
+	}
+}
+
+/*
+ * Drop an option (ie header) in the saved option chain.
+ */
+struct mbuf *
+ip6_dropoption(opts, which)
+	struct mbuf *opts;
+	int which;
+{
+	struct mbuf *o, *tbd;
+
+	for (o = opts; o; o = o->m_next)
+		if (o->m_pkthdr.pktype == which)
+			break;
+	tbd = o;
+	if (tbd == NULL)
+		return (opts);
+	if (tbd == opts) {
+		MFREE(tbd, opts);
+		return (opts);
+	}
+	for (o = opts; o->m_next != tbd; o = o->m_next)
+		o->m_pkthdr.len -= tbd->m_len;
+	o->m_next = tbd->m_next;
+	MFREE(tbd, o);
+	return (opts);
+}
+
+/*
+ * Copy the option chain.
+ */
+struct mbuf *
+ip6_copyoptions(opts, canshare)
+	struct mbuf *opts;
+	int canshare;
+{
+	struct mbuf *m, **np;
+	struct mbuf *top;
+	int len;
+
+	np = &top;
+	top = 0;
+	while (opts) {
+		len = opts->m_len;
+		if (opts->m_pkthdr.pktype == IP6_NHDR_RT)
+			len += sizeof(struct in6_addr);
+		if (len > MCLBYTES)
+			panic("ip6_copyoptions: %d > %d", len, MCLBYTES);
+		MGETHDR(m, M_DONTWAIT, MT_SOOPTS);
+		*np = m;
+		if (m == 0)
+			goto nospace;
+		M_COPY_PKTHDR(m, opts);
+		m->m_len = opts->m_len;
+		if (opts->m_flags & M_EXT) {
+		    if (!canshare) {
+			MCLGET(m, M_DONTWAIT);
+			if ((m->m_flags & M_EXT) == 0)
+			    goto nospace;
+		    } else {
+			m->m_data = opts->m_data;
+			if (opts->m_ext.ext_ref)
+			    panic("ip6_copyoptions: external cluster");
+			mclrefcnt[mtocl(opts->m_ext.ext_buf)]++;
+			m->m_ext = opts->m_ext;
+			m->m_flags |= M_EXT;
+		    }
+		} else {
+		    if (MHLEN < len)
+			panic("ip6_copyoptions: %d > %d", len, MHLEN);
+		    MH_ALIGN(m, len);
+		}
+		bcopy(mtod(opts, caddr_t), mtod(m, caddr_t), len);
+		opts = opts->m_next;
+		np = &m->m_next;
+	}
+	return (top);
+    nospace:
+	if (top)
+		m_freem(top);
+	/* caller should return ENOBUFS */
+	return (0);
+}
+
+/*
+ * Hop-by-Hop header input processing.
+ */
+void
+hop6_input(m0, arg)
+	struct mbuf *m0;
+	int arg;
+{
+	struct mbuf *opts = (struct mbuf *)arg;
+	struct ipv6 *ip;
+	struct ipv6_h2hhdr *hp;
+	int len;
+
+	ip6stat.ip6s_delivered--;
+
+	if (m0->m_len < sizeof(*ip) + sizeof(*hp)) {
+		if ((m0 = m_pullup(m0, sizeof(*ip) + sizeof(*hp))) == 0) {
+			ip6stat.ip6s_toosmall++;
+			if (opts)
+				m_freem(opts);
+			return;
+		}
+	}
+
+	ip = mtod(m0, struct ipv6 *);
+	hp = (struct ipv6_h2hhdr *)(ip + 1);
+	len = (hp->ih6_hlen + 1) * sizeof(*hp);
+	if ((len > ip->ip6_len) || (len + sizeof(*ip) > m0->m_pkthdr.len)) {
+		ip6stat.ip6s_toosmall++;
+		if (opts)
+			m_freem(opts);
+		m_freem(m0);
+		return;
+	}
+	ip->ip6_nh = hp->ih6_nh;
+	hp->ih6_nh = 0;
+	ip->ip6_len -= len;
+	opts = ip6_saveoption(m0, opts, len, IP6_NHDR_HOP);
+	if (opts && hd6_inoptions(m0, opts, (int *)0))
+		return;
+	ip = mtod(m0, struct ipv6 *);
+
+        /*
+         * Switch out to protocol's input routine.
+         */
+	if (ip->ip6_nh == IP6_NHDR_HOP) {
+		icmp6_errparam(m0, opts, 0);
+		return;
+	}
+	ip6stat.ip6s_delivered++;
+	ip6stat.ip6s_inhist[ip->ip6_nh]++;
+        (*inet6sw[ip6_protox[ip->ip6_nh]].pr_input)(m0, (int)opts);
+        return;
+}
+
+/*
+ * (Generic) header option processing.
+ */
+int
+hd6_inoptions(m, opts, alert)
+	struct mbuf *m, *opts;
+	int *alert;
+{
+	struct ipv6 *ip;
+	struct ipv6_h2hhdr *hp;
+	struct opt6_any *op;
+	int len, olen;
+	u_int32_t errpptr = sizeof(struct ipv6);
+
+	ip = mtod(m, struct ipv6 *);
+	hp = mtod(opts, struct ipv6_h2hhdr *);
+	op = (struct opt6_any *)&hp->ih6_pad1;
+	len = ((hp->ih6_hlen + 1) * sizeof(*hp)) - (2 * sizeof(u_int8_t));
+
+	while (len > 0) {
+		switch (op->o6any_ext) {
+
+		case OPT6_PAD_0:
+			op = (struct opt6_any *)&op->o6any_len;
+			len--;
+			break;
+
+#ifdef OPT6_ROUTER_ALERT
+		case OPT6_ROUTER_ALERT:
+			if (op->o6any_len != 2)
+				goto badlen;
+			if (alert)
+				*alert = 1;
+			goto next;
+#endif
+
+		default:
+			switch (OPT6_ACTION(op->o6any_ext)) {
+				case OPT6_A_SKIP:
+					goto next;
+
+				case OPT6_A_DISC:
+					goto discard;
+
+				case OPT6_A_FERR:
+					goto bad;
+
+				case OPT6_A_OERR:
+					if (m->m_flags & (M_BCAST|M_MCAST) ||
+					    IS_MULTIADDR6(ip->ip6_dst))
+						goto discard;
+					else
+						goto bad;
+				}
+		case OPT6_PAD_N:
+		next:
+			olen = op->o6any_len + sizeof(*op);
+			if (olen > len)
+				goto badlen;
+			op = (struct opt6_any *)((caddr_t)op + olen);
+			len -= olen;
+			break;
+		}
+	}
+	return (0);
+
+	/*
+	 * Errors.
+	 */
+
+discard:
+	m_freem(opts);
+	m_freem(m);
+	return (1);
+
+badlen:
+	errpptr++;
+bad:
+	errpptr += (u_int32_t)op - (u_int32_t)hp;
+	m = ip6_insertoption(m, opts, NULL, IP6_INSOPT_RAW);
+	icmp6_error(m, ICMP6_PARAMPROB, ICMP6_PARAMPROB_OPT, (caddr_t)errpptr);
+	m_freem(opts);
+	return (1);
+}
+
+static struct sockaddr_in6 rt6addr = { sizeof (rt6addr), AF_INET6 };
+
+/*
+ * routing header input processing.
+ */
+void
+rt6_input(m0, arg)
+	struct mbuf *m0;
+	int arg;
+{
+	struct mbuf *opts = (struct mbuf *)arg;
+	struct ipv6 *ip;
+	struct ipv6_rthdr *hp;
+	int len, numa;
+	u_int32_t errpptr = sizeof(struct ipv6);
+
+	ip6stat.ip6s_delivered--;
+
+	if (m0->m_len < sizeof(*ip) + sizeof(*hp)) {
+		if ((m0 = m_pullup(m0, sizeof(*ip) + sizeof(*hp))) == 0) {
+			ip6stat.ip6s_toosmall++;
+			if (opts)
+				m_freem(opts);
+			return;
+		}
+	}
+
+	ip = mtod(m0, struct ipv6 *);
+	hp = (struct ipv6_rthdr *)(ip + 1);
+	len = (hp->ir6_hlen << 3) + sizeof(struct ipv6_rthdr);
+	numa = hp->ir6_hlen >> 1;
+	if (hp->ir6_type != IP6_LSRRT) {
+		errpptr += 2;
+		if (hp->ir6_sglt)
+			goto bad;
+		else {
+			ip->ip6_nh = hp->ir6_nh;
+			hp->ir6_nh = 0;
+			ip->ip6_len -= len;
+			ip6_deloption(m0, len);
+			ip = mtod(m0, struct ipv6 *);
+			goto next;
+		}
+	}
+	if ((hp->ir6_hlen & 1) || (numa > IP6_RT_MAX)) {
+		errpptr++;
+		goto bad;
+	}
+#ifdef notdef
+	if (ntohl(hp->ir6_slmsk) & ~IP6_RT_SLMSK) {
+		errpptr += 4;
+		goto bad;
+	}
+#endif
+	if (hp->ir6_sglt > numa) {
+		errpptr += 3;
+		goto bad;
+	} else if (hp->ir6_sglt != 0) {
+		struct mbuf *m;
+		int off, optalloc = 0;
+		struct in6_addr temp, *addr;
+
+		if ((ip6forwarding == 0) && (ip6forwsrcrt == 0))
+			goto noforward;
+		len += sizeof(struct ipv6);
+		if ((len - sizeof(struct ipv6) > ip->ip6_len) ||
+		    (len > m0->m_pkthdr.len)) {
+			ip6stat.ip6s_toosmall++;
+			if (opts)
+				m_freem(opts);
+			m_freem(m0);
+			return;
+		}
+		hp->ir6_sglt--;
+		off = sizeof(struct ipv6) + sizeof(struct ipv6_rthdr);
+		off += (numa - hp->ir6_sglt - 1) * sizeof(struct in6_addr);
+		if (off + sizeof(struct in6_addr) > m0->m_len) {
+			if (opts)
+				len += opts->m_pkthdr.len;
+			MGETHDR(m, M_DONTWAIT, MT_HEADER);
+			if (m == 0)
+				goto noforward;
+			M_COPY_PKTHDR(m, m0);
+			m0->m_flags &= ~M_PKTHDR;
+			MCLGET(m, M_DONTWAIT);
+			if (((m->m_flags & M_EXT) == 0) || (len > MCLBYTES)) {
+				m_free(m);
+				goto noforward;
+			}
+			m->m_len = len;
+			if (opts)
+				m->m_data += opts->m_pkthdr.len;
+			m_copydata(m0, 0, len, mtod(m, caddr_t));
+			m_adj(m0, len);
+			m->m_next = m0;
+			m0 = m;
+			optalloc = IP6_INSOPT_NOALLOC;
+			ip = mtod(m0, struct ipv6 *);
+			hp = (struct ipv6_rthdr *)(ip + 1);
+		}
+		addr = (struct in6_addr *)(mtod(m0, caddr_t) + off);
+		if (IS_MULTIADDR6(*addr) || IS_MULTIADDR6(ip->ip6_dst)) {
+			if (opts)
+				m_freem(opts);
+			m_freem(m0);
+			return;
+		}
+		COPY_ADDR6(*addr, temp);
+		COPY_ADDR6(ip->ip6_dst, *addr);
+		COPY_ADDR6(temp, ip->ip6_dst);
+		if (ntohl(hp->ir6_slmsk) & IP6_RT_SLBIT(numa - hp->ir6_sglt)) {
+			struct ifaddr *ia;
+
+			COPY_ADDR6(temp, rt6addr.sin6_addr);
+			ia = ifa_ifwithdstaddr(sin6tosa(&rt6addr));
+			if (ia == 0)
+				ia = ifa_ifwithnet(sin6tosa(&rt6addr));
+			if (ia == 0) {
+				if (opts)
+					m_freem(opts);
+				icmp6_error(m0, ICMP6_UNREACH,
+					    ICMP6_UNREACH_RTFAIL, NULL);
+				return;
+			}
+		}
+		while (opts) {
+			m0 = ip6_insertoption(m0, opts, NULL, optalloc);
+			opts = opts->m_next;
+		}
+		ip6_forward(m0, 1);
+		return;
+	    noforward:
+		if (opts)
+			m_freem(opts);
+		m_freem(m0);
+		return;
+	}
+	if ((len > ip->ip6_len) ||
+	    (len + sizeof(struct ipv6) > m0->m_pkthdr.len)) {
+		ip6stat.ip6s_toosmall++;
+		if (opts)
+			m_freem(opts);
+		m_freem(m0);
+		return;
+	}
+	ip->ip6_nh = hp->ir6_nh;
+	hp->ir6_nh = 0;
+	ip->ip6_len -= len;
+	opts = ip6_saveoption(m0, opts, len, IP6_NHDR_RT);
+	ip = mtod(m0, struct ipv6 *);
+
+next:
+        /*
+         * Switch out to protocol's input routine.
+         */
+	if ((ip->ip6_nh == IP6_NHDR_HOP) ||
+	    (ip->ip6_nh == IP6_NHDR_RT)) {
+		icmp6_errparam(m0, opts, 0);
+		return;
+	}
+	ip6stat.ip6s_delivered++;
+	ip6stat.ip6s_inhist[ip->ip6_nh]++;
+        (*inet6sw[ip6_protox[ip->ip6_nh]].pr_input)(m0, (int)opts);
+        return;
+
+bad:
+	if (opts)
+		m_freem(opts);
+	icmp6_error(m0, ICMP6_PARAMPROB,
+		    ICMP6_PARAMPROB_HDR, (caddr_t)errpptr);
+	return;
+}
+
+/* Reverse a routing header */
+static void
+rt6_reverse(ip, opts)
+	struct ipv6 *ip;
+	struct mbuf *opts;
+{
+	struct ipv6_rthdr *hp;
+	struct in6_addr *addr0, *addr1, addrt;
+	int numa, i, j;
+	u_int32_t bitmsk;
+
+	/* get router header */
+	while (opts && opts->m_pkthdr.pktype != IP6_NHDR_RT)
+		opts = opts->m_next;
+	if (opts == 0)
+		return;
+	hp = mtod(opts, struct ipv6_rthdr *);
+	numa = hp->ir6_hlen >> 1;
+
+	/* fast check */
+	if ((numa * sizeof(struct in6_addr) + sizeof(*hp) != opts->m_len) ||
+	    (hp->ir6_type != IP6_LSRRT) ||
+	    (hp->ir6_hlen & 1) ||
+	    (numa > IP6_RT_MAX) ||
+#ifdef notdef
+	    (ntohl(hp->ir6_slmsk) & ~IP6_RT_SLMSK) ||
+#endif
+	    (hp->ir6_sglt != 0))
+		return;
+
+	/* test if the option has been already reversed (cf AH processing) */
+	addr0 = (struct in6_addr *)(hp + 1);
+	addr1 = addr0 + numa - 1;
+	if (!IS_ANYADDR6(*(addr1 + 1)))
+		return;
+	/* stupid empty routing header */
+	if (numa == 0) {
+		COPY_ADDR6(ip->ip6_src, *addr0);
+		return;
+	}
+
+	/* reverse bitmask and addresses */
+	hp->ir6_sglt = numa;
+	bitmsk = ntohl(hp->ir6_slmsk);
+	hp->ir6_slmsk = 0;
+	for (i = numa, j = 0; i >= 0; --i, j++) {
+		if (bitmsk & IP6_RT_SLBIT(i))
+			hp->ir6_slmsk |= htonl((u_int32_t)IP6_RT_SLBIT(j));
+	}
+	COPY_ADDR6(*addr1, *(addr1 + 1));
+	COPY_ADDR6(ip->ip6_src, *addr1);
+	addr1--;
+	while (addr1 > addr0) {
+		COPY_ADDR6(*addr0, addrt);
+		COPY_ADDR6(*addr1, *addr0);
+		COPY_ADDR6(addrt, *addr1);
+		addr1--, addr0++;
+	}
+}
+
+/*
+ * End of reception process of options:
+ *  - remove security headers
+ *  - remove unused option headers
+ *  - reverse a source route in a routing header.
+ */
+struct mbuf *
+opt6_reverse(ip, opts)
+	struct ipv6 *ip;
+	struct mbuf *opts;
+{
+	struct mbuf *o = opts;
+
+	o = ip6_dropoption(o, IP6_NHDR_DOPT);
+	o = ip6_dropoption(o, IP6_NHDR_ESP);
+	o = ip6_dropoption(o, IP6_NHDR_AUTH);
+	rt6_reverse(ip, o);
+	o = ip6_dropoption(o, IP6_NHDR_DOPT);
+	o = ip6_dropoption(o, IP6_NHDR_HOP);
+	return (o);
+}
+
+/*
+ * Destination Options header input processing.
+ */
+void
+dopt6_input(m0, arg)
+	struct mbuf *m0;
+	int arg;
+{
+	struct mbuf *opts = (struct mbuf *)arg;
+	struct ipv6 *ip;
+	struct ipv6_dopthdr *hp;
+	int len;
+
+    again:
+
+	ip6stat.ip6s_delivered--;
+
+	if (m0->m_len < sizeof(*ip) + sizeof(*hp)) {
+		if ((m0 = m_pullup(m0, sizeof(*ip) + sizeof(*hp))) == 0) {
+			ip6stat.ip6s_toosmall++;
+			if (opts)
+				m_freem(opts);
+			return;
+		}
+	}
+
+	ip = mtod(m0, struct ipv6 *);
+	hp = (struct ipv6_dopthdr *)(ip + 1);
+	len = (hp->io6_hlen + 1) * sizeof(*hp);
+	if ((len > ip->ip6_len) || (len + sizeof(*ip) > m0->m_pkthdr.len)) {
+		ip6stat.ip6s_toosmall++;
+		if (opts)
+			m_freem(opts);
+		m_freem(m0);
+		return;
+	}
+	ip->ip6_nh = hp->io6_nh;
+	hp->io6_nh = 0;
+	ip->ip6_len -= len;
+	opts = ip6_saveoption(m0, opts, len, IP6_NHDR_DOPT);
+	if (opts && hd6_inoptions(m0, opts, (int *)0))
+		return;
+	ip = mtod(m0, struct ipv6 *);
+
+        /*
+         * Switch out to protocol's input routine.
+         */
+	if (ip->ip6_nh == IP6_NHDR_HOP) {
+		icmp6_errparam(m0, opts, 0);
+		return;
+	}
+	ip6stat.ip6s_delivered++;
+	ip6stat.ip6s_inhist[ip->ip6_nh]++;
+	/* remove tail recursion */
+	if (ip->ip6_nh == IP6_NHDR_DOPT)
+		goto again;
+        (*inet6sw[ip6_protox[ip->ip6_nh]].pr_input)(m0, (int)opts);
+        return;
+}
+
+static struct sockaddr_ipsec ips6addr = { sizeof (ips6addr), AF_INET6 };
+static char hash0[64], hash[64];
+
+/*
+ * Authentication Header input processing.
+ */
+void
+ah6_input(m0, arg)
+	struct mbuf *m0;
+	int arg;
+{
+	struct mbuf *opts = (struct mbuf *)arg;
+	struct ipv6 *ip;
+	struct ipv6_authhdr *hp;
+	struct ipsec_entry_header *ieh = 0;
+	caddr_t state;
+	struct mbuf *m = 0;
+	int len, hlen;
+
+	ip6stat.ip6s_delivered--;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_AH)
+		printf("ah6_input(%p,%p)\n", m0, opts);
+#endif
+
+	if (m0->m_len < sizeof(*ip) + sizeof(*hp)) {
+		if ((m0 = m_pullup(m0, sizeof(*ip) + sizeof(*hp))) == 0) {
+			ip6stat.ip6s_toosmall++;
+			if (opts)
+				m_freem(opts);
+			return;
+		}
+	}
+
+	ip = mtod(m0, struct ipv6 *);
+	hp = (struct ipv6_authhdr *)(ip + 1);
+	/* AH length unit is 4 bytes! */
+	hlen = hp->ah6_hlen * 4;
+	len = hlen + sizeof(*hp);
+	if ((len > ip->ip6_len) || (len + sizeof(*ip) > m0->m_pkthdr.len)) {
+		ip6stat.ip6s_toosmall++;
+		if (opts)
+			m_freem(opts);
+		m_freem(m0);
+		return;
+	}
+	if (m0->m_len < sizeof(*ip) + len) {
+		if ((m0 = m_pullup(m0, sizeof(*ip) + len)) == 0) {
+			ip6stat.ip6s_toosmall++;
+			if (opts)
+				m_freem(opts);
+			return;
+		}
+	}
+	ip = mtod(m0, struct ipv6 *);
+	hp = (struct ipv6_authhdr *)(ip + 1);
+	if (hp->ah6_spi == 0)
+		goto drop;
+
+	ips6addr.sis_way = IPSEC_IN;
+	ips6addr.sis_kind = IP6_NHDR_AUTH;
+	ips6addr.sis_spi = hp->ah6_spi;
+	COPY_ADDR6(ip->ip6_dst, ips6addr.sis_addr);
+	ieh = ipsec_lookup(&ips6addr, NULL);
+	if (ieh)
+		ieh->ieh_refcnt--;
+	if (ieh == 0 ||
+	    (ieh->ieh_algo == 0) ||
+	    (ieh->ieh_algo->isa_ah_reslen > hlen) ||
+	    (ieh->ieh_algo->isa_ah_reslen > sizeof(hash0)))
+		goto bad;
+
+	ieh->ieh_use++;
+	bcopy((caddr_t)(hp + 1), hash0, ieh->ieh_algo->isa_ah_reslen);
+	bzero((caddr_t)(hp + 1), ieh->ieh_algo->isa_ah_reslen);
+	if ((m = ah6_build(m0, opts, IPSEC_IN)) == 0)
+		goto drop;
+	if ((state = ieh->ieh_algo->isa_ah_init(ieh)) == 0)
+		goto drop;
+	state = ieh->ieh_algo->isa_ah_update(state, m);
+	ieh->ieh_algo->isa_ah_finish(state, hash, ieh);
+	if (bcmp(hash0, hash, ieh->ieh_algo->isa_ah_reslen) == 0) {
+		m0->m_flags |= M_AUTH;
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_AH)
+			printf("ah6_input -> %p\n", ieh);
+#endif
+	} else {
+	    bad:
+		log(LOG_WARNING,
+"ah6_input: Auth failed for packet from %s to %s SPI %x%sflow %x nh %d\n",
+		    ip6_sprintf(&ip->ip6_src),
+		    ip6_sprintf(&ip->ip6_dst),
+		    ntohl(hp->ah6_spi),
+		    m == NULL ? "? " : " ",
+		    IPV6_GET_FLOWLABEL(ip->ip6_head),
+		    hp->ah6_nh);
+		m_freem(m);
+		m_freem(m0);
+		if (opts)
+			m_freem(opts);
+		return;
+	    drop:
+		m0->m_flags &= ~M_AUTH;
+	}
+	if (m)
+		m_freem(m);
+
+	ip->ip6_nh = hp->ah6_nh;
+	hp->ah6_nh = 0;
+	ip->ip6_len -= len;
+	if (m0->m_flags & M_AUTH) {
+		opts = ip6_saveoption(m0, opts, len, IP6_NHDR_AUTH);
+		if (opts && opts->m_pkthdr.pktype == IP6_NHDR_AUTH)
+			*mtod(opts, struct ipsec_entry_header **) = ieh;
+	} else
+		ip6_deloption(m0, len);
+	ip = mtod(m0, struct ipv6 *);
+
+	/*
+	 * Switch out to protocol's input routine.
+	 */
+	if ((ip->ip6_nh == IP6_NHDR_HOP) || (ip->ip6_nh == IP6_NHDR_FRAG)) {
+		icmp6_errparam(m0, opts, 0);
+		return;
+	}
+	ip6stat.ip6s_delivered++;
+	ip6stat.ip6s_inhist[ip->ip6_nh]++;
+	(*inet6sw[ip6_protox[ip->ip6_nh]].pr_input)(m0, (int)opts);
+	return;
+}
+
+/*
+ * Encryption Security Payload input processing.
+ */
+void
+esp6_input(m0, arg)
+	struct mbuf *m0;
+	int arg;
+{
+	struct mbuf *opts = (struct mbuf *)arg;
+	struct ipv6 *ip;
+	struct ipv6_esphdr *hp;
+	struct ipsec_entry_header *ieh;
+	caddr_t state;
+	u_char *p;
+	struct mbuf *m = 0;
+	int len, padlen = -2, nh = 0;
+
+	ip6stat.ip6s_delivered--;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ESP)
+		printf("esp6_input(%p,%p)\n", m0, opts);
+#endif
+	if (m0->m_len < sizeof(*ip) + sizeof(*hp)) {
+		if ((m0 = m_pullup(m0, sizeof(*ip) + sizeof(*hp))) == 0) {
+			ip6stat.ip6s_toosmall++;
+			if (opts)
+				m_freem(opts);
+			return;
+		}
+	}
+	ip = mtod(m0, struct ipv6 *);
+	hp = (struct ipv6_esphdr *)(ip + 1);
+	if (hp->esp6_spi == 0)
+		goto bad;
+
+	ips6addr.sis_way = IPSEC_IN;
+	ips6addr.sis_kind = IP6_NHDR_ESP;
+	ips6addr.sis_spi = hp->esp6_spi;
+	COPY_ADDR6(ip->ip6_dst, ips6addr.sis_addr);
+	ieh = ipsec_lookup(&ips6addr, NULL);
+	if (ieh)
+		ieh->ieh_refcnt--;
+	if (ieh == 0 || (ieh->ieh_algo == 0)) {
+		log(LOG_WARNING,
+"esp6_input: Crypt failed for packet from %s to %s SPI %x? flow %x\n",
+		    ip6_sprintf(&ip->ip6_src),
+		    ip6_sprintf(&ip->ip6_dst),
+		    ntohl(hp->esp6_spi),
+		    IPV6_GET_FLOWLABEL(ip->ip6_head));
+		goto bad;
+	}
+	len = sizeof(*hp) + ieh->ieh_ivlen;
+	if ((len > ip->ip6_len) || (len + sizeof(*ip) > m0->m_pkthdr.len)) {
+		ip6stat.ip6s_toosmall++;
+		if (opts)
+			m_freem(opts);
+		m_freem(m0);
+		return;
+	}
+	if (m0->m_len < sizeof(*ip) + len) {
+		if ((m0 = m_pullup(m0, sizeof(*ip) + len)) == 0) {
+			ip6stat.ip6s_toosmall++;
+			if (opts)
+				m_freem(opts);
+			return;
+		}
+	}
+	ip = mtod(m0, struct ipv6 *);
+	hp = (struct ipv6_esphdr *)(ip + 1);
+
+	ieh->ieh_use++;
+	if ((m = esp6_build(m0, ieh->ieh_ivlen, -2, 0)) == 0)
+		goto bad;
+	if ((state = ieh->ieh_algo->isa_esp_init(ieh, (caddr_t)(hp + 1))) == 0)
+		goto bad;
+	state = ieh->ieh_algo->isa_esp_decrypt(state, m);
+	ieh->ieh_algo->isa_esp_finish(state);
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ESP)
+		printf("esp6_input -> %p with %p\n", m, ieh);
+#endif
+	m0->m_flags |= M_CRYPT;
+	if (m0->m_next)
+		m_freem(m0->m_next);
+	m0->m_next = m;
+	m0->m_len = sizeof(struct ipv6) + len;
+	while (m->m_next)
+		m = m->m_next;
+	p = mtod(m, u_char *) + m->m_len;
+	m = 0;
+	nh = (int)*--p;
+	padlen = (int)*--p + 2;
+	if ((padlen < 0) || (padlen > m0->m_pkthdr.len - m0->m_len))
+		goto bad;
+	m_adj(m0, -padlen);
+
+	ip->ip6_nh = nh;
+	ip->ip6_len -= len + padlen;
+	opts = ip6_saveoption(m0, opts, len, IP6_NHDR_ESP);
+	if (opts && opts->m_pkthdr.pktype == IP6_NHDR_ESP)
+		*mtod(opts, struct ipsec_entry_header **) = ieh;
+	ip = mtod(m0, struct ipv6 *);
+
+	/*
+	 * Switch out to protocol's input routine.
+	 */
+	if ((ip->ip6_nh == IP6_NHDR_HOP) || (ip->ip6_nh == IP6_NHDR_FRAG)) {
+		if (opts)
+			m_freem(opts);
+		icmp6_errparam(m0, 0, 0);
+		return;
+	}
+	ip6stat.ip6s_delivered++;
+	ip6stat.ip6s_inhist[ip->ip6_nh]++;
+	(*inet6sw[ip6_protox[ip->ip6_nh]].pr_input)(m0, (int)opts);
+	return;
+
+    bad:
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ESP)
+		printf("esp6_input failed\n");
+#endif
+	if (m)
+		m_freem(m);
+	m_freem(m0);
+	if (opts)
+		m_freem(opts);
+}
+
+/*
+ * No Next Header header input processing.
+ */
+void
+end6_input(m0, arg)
+	struct mbuf *m0;
+	int arg;
+{
+	struct mbuf *opts = (struct mbuf *)arg;
+
+	if (opts)
+		m_freem(opts);
+	m_freem(m0);
+}
+
+/*
+ * Generic option ctlinput function.
+ */
+void
+opt6_ctlinput(cmd, sa, arg0)
+	int cmd;
+	struct sockaddr *sa;
+	void *arg0;
+{
+	struct ctli_arg *ca = (struct ctli_arg *)arg0;
+	struct ipv6 *ip0;
+	struct mbuf *m0;
+	struct ipv6 *ip;
+	struct mbuf *m = 0;
+	int type, off, len;
+	void (*ctlfunc) __P((int, struct sockaddr *, void *));
+	struct ctli_arg arg;
+
+	if ((unsigned)cmd >= PRC_NCMDS || arg0 == 0)
+		return;
+	ip0 = ca->ctli_ip;
+	m0 = ca->ctli_m;
+	if (ip0 == 0 || m0 == 0)
+		return;
+	off = (int)((caddr_t)ip0 - mtod(m0, caddr_t));
+	type = ip0->ip6_nh;
+	if (m0->m_pkthdr.len < sizeof(struct ipv6) + off + 8)
+		return;
+	if ((m = m_copy(m0, off, M_COPYALL)) == 0)
+		return;
+	/* keep the m_pullup in case of a shared cluster */
+	if ((m = m_pullup(m, sizeof(struct ipv6) + 8)) == 0)
+		return;
+	ip = mtod(m, struct ipv6 *);
+
+    again:
+	switch (type) {
+	    case IP6_NHDR_HOP: {
+		struct ipv6_h2hhdr *hp;
+
+		hp = (struct ipv6_h2hhdr *)(ip + 1);
+		len = (hp->ih6_hlen + 1) * sizeof(*hp);
+		type = hp->ih6_nh;
+		}
+		break;
+
+	    case IP6_NHDR_RT: {
+		struct ipv6_rthdr *hp;
+
+		hp = (struct ipv6_rthdr *)(ip + 1);
+		len = (hp->ir6_hlen + 1) * sizeof(*hp);
+		if ((hp->ir6_type != IP6_LSRRT) ||
+		    (hp->ir6_hlen & 1) ||
+		    (hp->ir6_hlen > (IP6_RT_MAX << 1)))
+			goto freeit;
+
+		type = hp->ir6_nh;
+		if (hp->ir6_sglt == 0)
+			break;
+		/* in transit */
+		off = len + sizeof(struct ipv6);
+		if (m->m_pkthdr.len < off + 8)
+			goto freeit;
+		m_copydata(m,
+			   off - sizeof(struct in6_addr),
+			   sizeof(struct in6_addr),
+			   (caddr_t)&satosin6(sa)->sin6_addr);
+		}
+		break;
+
+	    case IP6_NHDR_FRAG: {
+		struct ipv6_fraghdr *hp;
+
+		hp = (struct ipv6_fraghdr *)(ip + 1);
+		if (ntohs(hp->if6_off) & IP6_OFFMASK)
+			goto freeit;
+		len = sizeof(struct ipv6_fraghdr);
+		type = hp->if6_nh;
+		}
+		break;
+
+	    case IP6_NHDR_AUTH: {
+	    	struct ipv6_authhdr *hp;
+
+		hp = (struct ipv6_authhdr *)(ip + 1);
+		len = sizeof(*hp) + (hp->ah6_hlen * 4);
+		type = hp->ah6_nh;
+		}
+
+	    case IP6_NHDR_DOPT: {
+		struct ipv6_dopthdr *hp;
+
+		hp = (struct ipv6_dopthdr *)(ip + 1);
+		len = (hp->io6_hlen + 1) * sizeof(*hp);
+		type = hp->io6_nh;
+		/* Should deal with the OPT6_HOME_ADDR option! */
+		}
+		break;
+
+	    default:
+		goto freeit;
+	}
+	if (m->m_pkthdr.len < sizeof(struct ipv6) + len + 8)
+		goto freeit;
+	m_adj(m, len);
+	/* keep the m_pullup in case of a shared cluster */
+	if ((m = m_pullup(m, sizeof(struct ipv6) + 8)) == 0)
+		return;
+	bcopy((caddr_t)ip0, mtod(m, caddr_t), sizeof(struct ipv6));
+	ip = mtod(m, struct ipv6 *);
+	ip->ip6_nh = type;
+	ctlfunc = inet6sw[ip6_protox[type]].pr_ctlinput;
+	if (ctlfunc == opt6_ctlinput)
+		goto again;
+	arg.ctli_ip = ip;
+	arg.ctli_m = m;
+	if (ctlfunc)
+		(*ctlfunc)(cmd, sa, &arg);
+    freeit:
+	if (m)
+		m_freem(m);
+}
+
+/*
+ * Forward an IPv6 packet.
+ * If some error occurs return the sender an ICMPv6 packet.
+ * If not forwarding, just drop the packet.
+ */
+
+static union route_6 ip6forward_rt_6;
+#define ip6forward_rt	ip6forward_rt_6.route
+
+static void
+ip6_forward(m, srcrt)
+	struct mbuf *m;
+	int srcrt;
+{
+	struct ipv6 *ip = mtod(m, struct ipv6 *);
+	struct sockaddr_in6 *sin;
+	struct rtentry *rt;
+	int error, type = 0, code = 0;
+	struct mbuf *mcopy;
+	struct in6_addr dest;
+	struct ifnet *destifp;
+
+	CLR_ADDR6(dest);
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_FORWARD)
+		printf("ip6_forward: src %s dst %s hlim %d\n",
+		       ip6_sprintf(&ip->ip6_src),
+		       ip6_sprintf(&ip->ip6_dst),
+		       ip->ip6_hlim);
+#endif
+
+	if (IS_MULTIADDR6(ip->ip6_dst) ||
+	    m->m_flags & (M_BCAST|M_MCAST) ||
+	    IS_LINKLADDR6(ip->ip6_src)) {
+		ip6stat.ip6s_cantforward++;
+		m_freem(m);
+		return;
+	}
+	if (ip->ip6_hlim <= IPTTLDEC) {
+		icmp6_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS, NULL);
+		return;
+	}
+	ip->ip6_hlim -= IPTTLDEC;
+
+	sin = satosin6(&ip6forward_rt.ro_dst);
+	if ((rt = ip6forward_rt.ro_rt) == 0 ||
+	    !SAME_ADDR6(ip->ip6_dst, sin->sin6_addr)) {
+		if (ip6forward_rt.ro_rt) {
+			RTFREE(ip6forward_rt.ro_rt);
+			ip6forward_rt.ro_rt = 0;
+		}
+		sin->sin6_family = AF_INET6;
+		sin->sin6_len = sizeof(*sin);
+		COPY_ADDR6(ip->ip6_dst, sin->sin6_addr);
+
+		rtalloc(&ip6forward_rt);
+		rt = ip6forward_rt.ro_rt;
+		if (rt == 0) {
+			icmp6_error(m, ICMP6_UNREACH,
+				    ICMP6_UNREACH_NOROUTE, NULL);
+			return;
+		}
+		/* out of link routing */
+		if (IS_LINKLADDR6(ip->ip6_dst) &&
+		    m->m_pkthdr.rcvif != rt->rt_ifp) {
+			icmp6_error(m, ICMP6_UNREACH,
+				    ICMP6_UNREACH_ADDRESS, NULL);
+			return;
+		}
+		/* out of site routing */
+		if ((IS_SITELADDR6(ip->ip6_dst) ||
+		     IS_SITELADDR6(ip->ip6_src)) &&
+		    site6_index &&
+		    (m->m_pkthdr.rcvif &&
+		     (m->m_pkthdr.rcvif->if_site6 != rt->rt_ifp->if_site6))) {
+			if (IS_SITELADDR6(ip->ip6_src)) {
+				ip6stat.ip6s_cantforward++;
+				m_freem(m);
+				return;
+			}
+			icmp6_error(m, ICMP6_UNREACH,
+				    ICMP6_UNREACH_ADDRESS, NULL);
+			return;
+		}
+	}
+
+	/*
+	 * Save at most 576 bytes of the packet in case
+	 * we need to generate an ICMP message to the src.
+	 */
+	mcopy = m_copy(m, 0, imin((int)ip->ip6_len + sizeof(*ip), IP6_MMTU));
+
+	/*
+	 * If forwarding packet using same interface that it came in on,
+	 * perhaps should send a redirect to sender to shortcut a hop.
+	 * Only send redirect if source is sending directly to us,
+	 * and if packet was not source routed (or has any options).
+	 */
+	if (rt->rt_ifp == m->m_pkthdr.rcvif &&
+	    (rt->rt_ifp->if_flags & IFF_POINTOPOINT) == 0 &&
+	    !srcrt) {
+		if (rt->rt_flags & RTF_GATEWAY) {
+			COPY_ADDR6(satosin6(rt->rt_gateway)->sin6_addr, dest);
+		} else {
+			COPY_ADDR6(ip->ip6_dst, dest);
+		}
+		type = ICMP6_REDIRECT;
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_FORWARD)
+		        printf("redirect to %s\n", ip6_sprintf(&dest));
+#endif
+	}
+
+	/*
+	 * Hop-by-Hop header must be processed !!!
+	 * (cf Daniel S. Decasper)
+	 * TODO: better fix!
+	 */
+	if ((srcrt == 0) && (ip->ip6_nh == IP6_NHDR_HOP)) {
+		struct ipv6_h2hhdr *hp;
+		struct mbuf *opts;
+		int len, alert = 0;
+
+		if (m->m_len < sizeof(*ip) + sizeof(*hp)) {
+			if ((m = m_pullup(m, sizeof(*ip)+sizeof(*hp))) == 0) {
+				return;
+			}
+		}
+
+		ip = mtod(m, struct ipv6 *);
+		hp = (struct ipv6_h2hhdr *)(ip + 1);
+		len = (hp->ih6_hlen + 1) * sizeof(*hp);
+		if ((len > ip->ip6_len) ||
+		    (len + sizeof(*ip) > m->m_pkthdr.len)) {
+			m_freem(m);
+			return;
+		}
+		ip->ip6_nh = hp->ih6_nh;
+		hp->ih6_nh = 0;
+		ip->ip6_len -= len;
+		opts = ip6_saveoption(m, NULL, len, IP6_NHDR_HOP);
+		if (opts && hd6_inoptions(m, opts, &alert))
+			return;
+		if (opts)
+			m = ip6_insertoption(m, opts, NULL, IP6_INSOPT_RAW);
+		ip = mtod(m, struct ipv6 *);
+		/*
+		 * We should not multiply packet: what to do if nobody
+		 * wants it ? (rip6_input would return an ICMP error)
+		 */
+		if (alert)
+			hop6_input(m, 0);
+	}
+
+	error = ip6_output(m, 0, &ip6forward_rt, IP_FORWARDING, 0, 0);
+	if (error)
+		ip6stat.ip6s_cantforward++;
+	else {
+		ip6stat.ip6s_forward++;
+		if (!type) {
+			if (mcopy)
+				m_freem(mcopy);
+			return;
+		}
+	}
+	if (mcopy == NULL)
+		return;
+	destifp = NULL;
+
+	switch (error) {
+
+	case 0:				/* forwarded, but need redirect */
+		if (type == ICMP6_REDIRECT)
+			redirect6_output(mcopy, rt);
+		return;
+
+	case ENETUNREACH:		/* shouldn't happen, checked above */
+	case EHOSTUNREACH:
+	case ENETDOWN:
+	case EHOSTDOWN:
+	default:
+		type = ICMP6_UNREACH;
+		code = ICMP6_UNREACH_ADDRESS;
+		break;
+
+	case EMSGSIZE:
+		type = ICMP6_PKTTOOBIG;
+		ip6stat.ip6s_toobig++;
+		if (ip6forward_rt.ro_rt)
+			destifp = ip6forward_rt.ro_rt->rt_ifp;
+		break;
+
+	case ENOBUFS:
+		m_freem(mcopy);
+		return;
+	}
+	icmp6_error(mcopy, type, code, (caddr_t)destifp);
+}
+
+#include <stddef.h>
+
+void
+ip6_savecontrol(inp, mp, ip, m)
+	struct inpcb *inp;
+	struct mbuf **mp;
+	struct ipv6 *ip;
+	struct mbuf *m;
+{
+	if (inp->inp_socket->so_options & SO_TIMESTAMP) {
+		struct timeval tv;
+
+		microtime(&tv);
+		*mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
+			SCM_TIMESTAMP, SOL_SOCKET);
+		if (*mp)
+			mp = &(*mp)->m_next;
+	}
+	if (inp->inp_flags & INP_RECVDSTADDR) {
+		*mp = sbcreatecontrol((caddr_t) &ip->ip6_dst,
+		    sizeof(struct in6_addr), IP_RECVDSTADDR, IPPROTO_IP);
+		if (*mp)
+			mp = &(*mp)->m_next;
+	}
+	if (inp->inp_flags & INP_RECVIF) {
+		struct sockaddr_dl sdl;
+
+		sdl.sdl_len = offsetof(struct sockaddr_dl, sdl_data[0]);
+		sdl.sdl_family = AF_LINK;
+		sdl.sdl_index = m->m_pkthdr.rcvif ?
+			m->m_pkthdr.rcvif->if_index : 0;
+		sdl.sdl_nlen = sdl.sdl_alen = sdl.sdl_slen = 0;
+		*mp = sbcreatecontrol((caddr_t) &sdl, sdl.sdl_len,
+			IP_RECVIF, IPPROTO_IP);
+		if (*mp)
+			mp = &(*mp)->m_next;
+	}
+}
diff -uN src-current/sys/netinet/ip6_mroute.c src-current-ipv6/sys/netinet/ip6_mroute.c
--- src-current/sys/netinet/ip6_mroute.c
+++ src-current-ipv6/sys/netinet/ip6_mroute.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 1989 Stephen Deering
+ * Copyright (c) 1992 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Stephen Deering of Stanford University.
+ *
+ * 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.
+ *
+ *	@(#)
+ */
+
+/*
+ * Written by David Waitzman, BBN Labs, August 1988.
+ * Modified by Steve Deering, Stanford, February 1989.
+ * Rewritten by Tom Pusateri, Gated Consortium, November 1994.
+ * Adapted to IPv6 by Girish (unknown ref).
+ * Last changes by Yixin Jin, UCLA, November 1997.
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/queue.h>
+#include <sys/proc.h>           /* XXX needed for sysctl.h */
+#include <vm/vm.h>              /* XXX needed for sysctl.h */
+#include <sys/sysctl.h>
+
+#ifdef vax
+#include <machine/mtpr.h>
+#endif
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/radix.h>
+#include <net/raw_cb.h>
+#include <net/netisr.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_mroute.h>
+
+#include <netinet/ip6.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/ip6_icmp.h>
+#include <netinet/ip6_opts.h>
+
+static void multicast_send __P((struct mbuf *m, struct ifnet *ifp));
+static int mfc_addqueue __P((struct mbuf *m, struct mfcentry *mfc));
+static void mfctimer __P((void)); 
+static void unresolved_enq __P((struct mfcentry *p, struct mfcentry *prev));
+
+#define	SA(p) ((struct sockaddr *)(p))
+
+/* timer values */
+#define	MFC_AGE		(60*1)	/* aging timer, 1 min. */
+#define	MFC_KILLU	2	/* kill unresolved entries in 2 minutes */
+
+static struct mfcentry un_head;	/* head of unresolved entry list */
+static int restart_timer = 1;
+
+int
+ip6_mforward(m, ifp)
+	register struct mbuf *m;
+	register struct ifnet *ifp;
+{
+	register struct ipv6 *ipv6 = mtod(m, struct ipv6 *);
+	int	rc = 1;
+	struct	sockaddr *ifpaddr;
+	struct	sockaddr_in6 dst, src;
+	struct	rt_addrinfo info;
+	struct	ifaddr *ifa;
+	struct	ds_ifaddr *cur;
+	struct	mfcentry *mfc;
+	int duplicate = 0;
+
+	/*
+	 * Find the sockaddr_dl for the incoming interface
+	 */
+	for (ifa = TAILQ_FIRST(&ifp->if_addrhead);
+	     ifa && ifa->ifa_addr->sa_family != AF_LINK;
+	     ifa = TAILQ_NEXT(ifa, ifa_link))
+		/* continue */;
+	if (ifa) {
+		ifpaddr = ifa->ifa_addr;
+	} else {
+		return(rc);
+	}
+#ifdef MFC_DEBUG
+	printf("Forward packet: src=%s dst=%s hop=%d\n",
+	       ip6_sprintf(&ipv6->ip6_src),
+	       ip6_sprintf(&ipv6->ip6_dst),
+	       ipv6->ip6_hlim);
+#endif
+
+	/*
+	 * need to add check to make sure incoming interface
+	 * wasn't a tunnel - IFF_TUNNEL
+	 */
+	if (ipv6->ip6_hlim <= IPTTLDEC ||
+	    MADDR6_SCOPE(ipv6->ip6_dst) <= MADDR6_SCP_LINK) {
+#ifdef MFC_DEBUG
+		printf("Link-scoped address or run out of Hoplimit,"
+		       "drop it off\n");
+#endif
+        	return (0);
+	}
+
+	bzero(&dst, sizeof(dst));
+	bzero(&src, sizeof(src));
+
+	dst.sin6_family = AF_INET6;
+	dst.sin6_len = sizeof(struct sockaddr_in6);
+	dst.sin6_addr = ipv6->ip6_dst;
+
+	src.sin6_family = AF_INET6;
+	src.sin6_len = sizeof(struct sockaddr_in6);
+	src.sin6_addr = ipv6->ip6_src;
+
+	mfc = mfcalloc(SA(&dst), SA(&src));
+	if (mfc) {
+		/*
+		 * Is this packet not yet complete ?
+		 * If so, just add packet to end of queue and return
+		 */
+		if (mfc->mfc_flags & RTF_XRESOLVE) {
+			rc = mfc_addqueue(m, mfc);
+			/*
+			 * send duplicate RTM_RESOLVE
+			 * so cache entry can be calculated
+			 */
+			bzero((caddr_t)&info, sizeof(info));
+			info.rti_info[RTAX_DST] = SA(&dst);
+			info.rti_info[RTAX_IFP] = ifpaddr;
+			info.rti_info[RTAX_AUTHOR] = SA(&src);
+			rt_missmsg(RTM_RESOLVE, &info,
+				   RTF_MULTICAST|RTF_XRESOLVE, EADDRNOTAVAIL);
+			return(rc);
+		} /* else */
+		/*
+		 * Otherwise, if entry is useable now,
+		 * see if there were queued packets
+		 * that haven't been processed yet.
+		 */
+		if (mfc->packet_q[mfc->mfc_head]) {
+			/*
+			 * If so, put them back on the input queue
+			 */
+			rc = mfc_addqueue(m, mfc);
+			/* ipintrq is shared by IPv6 and IPv4 */
+			mfc_requeue(AF_INET6, &ipintrq, mfc); 
+			return(rc);
+		} /* else */
+		/*
+		 * Normal forwarding case.
+		 * check for valid incoming interface
+		 */
+		if (ifp == mfc->upstream_ifp) {
+			/*
+			 * if correct, forward to all downstream intfs
+			 */
+			ipv6->ip6_hlim -= IPTTLDEC;
+			cur = mfc->ds_list;
+			while (cur) {
+				if (cur->min_hoplimit < ipv6->ip6_hlim) {
+#ifdef MFC_DEBUG
+					printf("mforward: %s%d\n",
+					       cur->ds_ifp->if_name,
+					       cur->ds_ifp->if_unit);
+#endif
+					multicast_send(m, cur->ds_ifp);
+				}
+				cur = cur->ds_next;
+			}
+			mfc->mfc_use++;
+			return(0);
+		} /* else */
+		/*
+		 * Upstream interface is not correct.
+		 * If incoming interface is a broadcast LAN,
+		 * send RTM_RESOLVE with EADDRINUSE for user
+		 * level daemon to do possible pruning
+		 */
+		cur = mfc->ds_list;
+		while (cur) {
+			if (cur->ds_ifp == ifp) {
+				duplicate = 1;
+				break;
+			}
+			cur = cur->ds_next;
+		}
+		if (duplicate) {
+#ifdef MFC_DEBUG
+			printf("Upstream interface is not correct, "
+			       "send RTM_RESOLVE with EADDRINUSE for "
+			       "user level daemon to do possible pruning\n");
+#endif
+			if (ifp->if_flags & IFF_BROADCAST) {
+				bzero((caddr_t)&info, sizeof(info));
+				info.rti_info[RTAX_DST] = SA(&dst);
+				info.rti_info[RTAX_IFP] = ifpaddr;
+				info.rti_info[RTAX_AUTHOR] = SA(&src);
+				rt_missmsg(RTM_RESOLVE, &info,
+					   RTF_MULTICAST, EADDRINUSE);
+			}
+			return(1);
+		}
+		return (rc);
+	} /* else */
+	/*
+	 * send RTM_RESOLVE so cache entry can be calculated
+	 */
+#ifdef MFC_DEBUG
+	printf("send RTM_RESOLVE so cache entry can be calculated\n"); 
+#endif
+	bzero((caddr_t)&info, sizeof(info));
+	info.rti_info[RTAX_DST] = SA(&dst);
+	info.rti_info[RTAX_IFP] = ifpaddr;
+	info.rti_info[RTAX_AUTHOR] = SA(&src);
+	rt_missmsg(RTM_RESOLVE, &info,
+		   RTF_MULTICAST|RTF_XRESOLVE, EADDRNOTAVAIL);
+
+	/*
+	 * create cache entry as a place holder to queue packets
+	 */
+#ifdef MFC_DEBUG
+	printf("create cache entry as a place holder to queue packets\n");
+	printf("This MFC entry is unsolved (RTF_XRESOLVE)\n");
+#endif
+	if (!mfcrequest(RTM_ADD,
+			(struct sockaddr *) &dst,
+			SA(0),
+			(struct sockaddr *) &src,
+			SA(0),
+			RTF_MULTICAST|RTF_HOST|RTF_XRESOLVE) &&
+	    (mfc = mfcalloc(SA(&dst), SA(&src)))) {
+		/*
+		 * initialize list of unresolved entries
+		 * start timer to age unresolved entries
+		 */
+		if (restart_timer) {
+			restart_timer = 0;
+			un_head.un_next = un_head.un_prev = &un_head;
+			timeout((timeout_t *)mfctimer, (caddr_t) 0, hz);
+		}
+		/*
+		 * queue unresolved entry for timeout
+		 */
+		unresolved_enq(mfc, un_head.un_prev);
+		/*
+		 * queue this packet for future forwarding
+		 */
+		rc = mfc_addqueue(m, mfc);
+	}
+	return(rc);
+}
+
+static void
+multicast_send(m, ifp)
+	register struct mbuf *m;
+	register struct ifnet *ifp;
+{
+	register struct ipv6 *ipv6 = mtod(m, struct ipv6 *);
+	register struct mbuf *mb_copy;
+	register struct ip_moptions *imov6;
+	register int error;
+	struct ip_moptions simov6;
+
+	/*
+	 * Copy and pullup (because we'll change the header) the buffer.
+	 */
+	mb_copy = m_copy(m, 0, M_COPYALL);
+	if (mb_copy == NULL)
+		return;
+	mb_copy = m_pullup(mb_copy, sizeof(struct ipv6));
+	if (mb_copy == NULL)
+		return;
+
+	imov6 = &simov6;
+	imov6->imo_multicast_ifp = ifp;
+	imov6->imo_multicast_ttl = ipv6->ip6_hlim - 1;
+	imov6->imo_multicast_loop = 0; /* or 1, if loopback */
+
+	error = ip6_output(mb_copy, NULL, NULL,
+			   IP_FORWARDING | IP_ROUTETOIF, imov6, NULL); 
+}
+
+#if 1
+/*
+ * Store this packet in the circular buffer in the mfcentry associated
+ * with this group and source. This will be emptied out after the
+ * forwarding cache entry is completely built.
+ */
+
+static int
+mfc_addqueue(m, mfc)
+struct mbuf *m;
+struct mfcentry *mfc;
+{
+	int error = 0;
+	register struct mbuf *mcopy;
+
+	/*
+	 * if packet already there, must drop it before storing new one
+	 */
+	if (mfc->packet_q[mfc->mfc_tail]) {
+		m_freem(mfc->packet_q[mfc->mfc_tail]);
+		mfc->mfc_head = (mfc->mfc_head + 1) % MFC_PACKET_Q_SIZE;
+	}
+	if (mcopy = m_copy(m, 0, M_COPYALL)) {
+		mfc->packet_q[mfc->mfc_tail] = mcopy;
+		mfc->mfc_tail = (mfc->mfc_tail + 1) % MFC_PACKET_Q_SIZE;
+	} else {
+		error = ENOBUFS;
+	}
+	return(error);
+}
+
+/*
+ * Put stored multicast packets back on input queue.
+ * There is a circular buffer in the mfcentry that holds MFC_PACKET_Q_SIZE
+ * packets which is emptied into the protocol input queue if there is room.
+ * Otherwise, we just return and try again later.
+ */
+
+void
+mfc_requeue(fam, ifq, mfc)
+	int fam;	/* Which address family being talked about */ 
+	struct ifqueue *ifq;
+	struct mfcentry *mfc;
+{
+	int s = splimp();
+
+	while (!IF_QFULL(ifq) && mfc->packet_q[mfc->mfc_head]) {
+		register struct mbuf *m = mfc->packet_q[mfc->mfc_head];
+		switch (fam) {
+		case AF_INET: {
+			register struct ip *ip = mtod(m, struct ip *);
+			register int hlen = ip->ip_hl << 2;
+
+			/*
+			 * restore packet to previous state so ip_input
+			 * doesn't choke on it
+			 */
+			HTONS(ip->ip_len);
+			HTONS(ip->ip_id);
+			HTONS(ip->ip_off);
+			ip->ip_sum = in_cksum(m, hlen);
+			break;
+		}
+		case AF_INET6: {
+			register struct ipv6 *ip6 = mtod(m, struct ipv6 *);
+
+			HTONS(ip6->ip6_len);
+			break;
+		}
+		default:
+			printf("Unsupported family for multicasting(%d)\n",
+			       fam);
+			break;
+		}
+		mfc->packet_q[mfc->mfc_head] = (struct mbuf *) 0;
+		mfc->mfc_head = (mfc->mfc_head + 1) % MFC_PACKET_Q_SIZE;
+	    
+		IF_ENQUEUE(ifq, m);
+	}
+	splx(s);
+}
+
+/*
+ * Timeout routine. Age unresolved MFC entries
+ */
+
+static void
+mfctimer()
+{
+	int err;
+	struct mfcentry *mfc;
+
+	mfc = un_head.un_next;
+	while (mfc != &un_head) {
+		if ((mfc->mfc_flags & RTF_XRESOLVE) &&
+		    (mfc->mfc_un_timer++ < MFC_KILLU)) {
+			mfc = mfc->un_next;
+		} else {
+			struct mfcentry *next_mfc = mfc->un_next;
+			/*
+			 * timer has expired or mfc is resolved, clear entry
+			 */
+
+			unresolved_deq(mfc);
+
+			if (mfc->mfc_flags & RTF_XRESOLVE) { 
+				struct sockaddr_in6 sa_dst, sa_src;
+
+				mfc->mfc_flags &= ~RTF_XRESOLVE;
+				sockdata1(mfc_key(mfc), SA(&sa_dst));
+				sockdata2(mfc_key(mfc), SA(&sa_src));
+
+#ifdef MFC_DEBUG
+				printf("Timeout unsolved MFC entry\n");
+#endif
+				if (err = mfcrequest(RTM_DELETE, 
+						SA(&sa_dst), SA(0),
+						SA(&sa_src), SA(0), 
+						RTF_MULTICAST|RTF_HOST))
+				    log(LOG_ERR,
+					"ip_mroute: RTM_DELETE errno %d\n",
+					err);
+			}
+			mfc = next_mfc;
+		}
+	}
+	if (un_head.un_next == &un_head) {
+		restart_timer = 1;
+	} else {
+		timeout((timeout_t *)mfctimer, (caddr_t) 0, MFC_AGE * hz);
+	}
+}
+
+/*
+ * Put an unresolved mfc in a linked list for easy timeout.
+ * Like insque, but pointers in middle of structure.
+ */
+static void 
+unresolved_enq(p, prev)
+	register struct mfcentry *p, *prev;
+{
+	p->un_prev = prev;
+	p->un_next = prev->un_next;
+	prev->un_next->un_prev = p;
+	prev->un_next = p;
+}
+
+/*
+ * To unresolved_enq as remque is to insque.
+ */
+void
+unresolved_deq(p)
+	register struct mfcentry *p;
+{
+	p->un_prev->un_next = p->un_next;
+	p->un_next->un_prev = p->un_prev;
+
+	p->un_next = (struct mfcentry *) 0;
+	p->un_prev = (struct mfcentry *) 0;
+	p->mfc_un_timer = 0;
+}
+#endif
diff -uN src-current/sys/netinet/ip6_opts.h src-current-ipv6/sys/netinet/ip6_opts.h
--- src-current/sys/netinet/ip6_opts.h
+++ src-current-ipv6/sys/netinet/ip6_opts.h
@@ -0,0 +1,119 @@
+/*
+ * 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_IP6_OPTS_H_
+#define _NETINET_IP6_OPTS_H_
+
+/*
+ * Definition of IPv6 options and extensions for Neighbor Discovery
+ */
+#define OPT6_PAD_0		0	/* Single Pad */
+#define OPT6_PAD_N		1	/* Multiple Pad */
+#define OPT6_JUMBO		194	/* Jumbo-Payload */
+
+#define NDX6_LLADDR_SRC		1	/* Source Link-layer Address */
+#define NDX6_LLADDR_TGT		2	/* Target Link-layer Address */
+#define NDX6_PREF_INFO		3	/* Prefix-Information */
+#define NDX6_RDRT_HDR		4	/* Redirected-Header */
+#define NDX6_MTU		5	/* Maximum-Transmit-Unit */
+
+/*
+ * Macros on type bits.
+ */
+#define	OPT6_ACTION(t)		((t)&0xc0)	/* action */
+#define OPT6_A_SKIP		0x00		/* skip over */
+#define OPT6_A_DISC		0x40		/* discard */
+#define OPT6_A_FERR		0x80		/* already send error */
+#define OPT6_A_OERR		0xc0		/* send error */
+#define OPT6_RTCHANGE(t)	((t)&0x20)	/* change en-route */
+
+/*
+ * Options and Extensions layouts.
+ */
+
+struct opt6_any {			/* common header */
+	u_int8_t	o6any_ext;	/* extension type */
+	u_int8_t	o6any_len;	/* length */
+};
+
+struct opt6_jbo {			/* Jumbo-Payload */
+	u_int16_t	jbo_pad;	/* for alignment */
+	u_int8_t	jbo_ext;	/* extension type (194) */
+	u_int8_t	jbo_len;	/* length (4) */
+	u_int32_t	jbo_plen;	/* payload length */
+};
+
+struct opt6_ra {			/* Router-Alert */
+	u_int8_t	ra_ext;		/* extension type (TBD) */
+	u_int8_t	ra_len;		/* length (2) */
+	u_int16_t	ra_code;	/* code */
+};
+#define OPT6_RA_GROUP	0		/* ICMPv6 Group Membership */
+#define OPT6_RA_RSVP	1		/* RSVP */
+
+struct ndx6_any {			/* common header */
+	u_int8_t	x6any_ext;	/* extension type */
+	u_int8_t	x6any_len;	/* length */
+	u_int16_t	x6any_res1;	/* reserved */
+	u_int32_t	x6any_res2;	/* reserved */
+};
+
+struct ndx6_lladdr {			/* Link-layer Address */
+	u_int8_t	lla_ext;	/* extension type (1 or 2) */
+	u_int8_t	lla_len;	/* length (>=1) */
+	u_int8_t	lla_addr[6];	/* media address */
+};
+
+struct ndx6_pref {			/* Prefix-Information */
+	u_int8_t	pref_ext;	/* extension type (3) */
+	u_int8_t	pref_len;	/* length (4) */
+	u_int8_t	pref_plen;	/* prefix size (0..128) */
+	u_int8_t	pref_flg;	/* flags */
+	u_int32_t	pref_ilife;	/* invalidation lifetime */
+	u_int32_t	pref_dlife;	/* deprecation lifetime */
+	u_int32_t	pref_res2;
+	struct in6_addr	pref_pref;	/* prefix */
+};
+#define	NDX6_PREF_FLG_L	0x80		/* On-link flag */
+#define	NDX6_PREF_FLG_A	0x40		/* Address-configuration flag */
+
+struct ndx6_mtu {			/* Maximum-Transmit-Unit */
+	u_int8_t	mtu_ext;	/* extension type (5) */
+	u_int8_t	mtu_len;	/* length (1) */
+	u_int16_t	mtu_res;	/* reserved (0) */
+	u_int32_t	mtu_mtu;	/* MTU value */
+};
+
+#endif
diff -uN src-current/sys/netinet/ip6_output.c src-current-ipv6/sys/netinet/ip6_output.c
--- src-current/sys/netinet/ip6_output.c
+++ src-current-ipv6/sys/netinet/ip6_output.c
@@ -0,0 +1,2525 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 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_output.c	8.3 (Berkeley) 1/21/94
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/errno.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/time.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/ip6_opts.h>
+
+#include <netinet/ip6_fw.h>
+
+#ifdef vax
+#include <machine/mtpr.h>
+#endif
+#include <machine/in_cksum.h>
+
+MALLOC_DECLARE(M_IPMOPTS);
+
+u_int32_t ip6_id;
+extern int ip6forwarding;
+
+static void	ip6_mloopback
+	__P((struct ifnet *, struct mbuf *,
+	     struct mbuf *, struct sockaddr_in6 *));
+static int	dopt6_dontfrag __P((struct mbuf *));
+static void	hd6_outoptions __P((struct mbuf *));
+static int	ip6_getmoptions
+	__P((int, struct ip_moptions *, struct mbuf **));
+static int	ip6_getsoptions __P((struct inpcb *, int, struct mbuf **));
+static int	ip6_setmoptions __P((struct inpcb *, int, struct mbuf *));
+static int	ip6_setsoptions
+	__P((struct socket *, int, struct mbuf *, struct proc *p));
+
+static struct sockaddr_ipsec ips6addr = { sizeof (ips6addr), AF_INET6 };
+
+/*
+ * IPv6 output. The packet in mbuf chain m contains a skeletal IPv6
+ * header (with everything :-).
+ * The mbuf chain containing the packet will be freed.
+ * The mbuf opt, if present, will not be freed.
+ */
+int
+real_ip6_output(m0, opts, ro, flags, imo, inp)
+	struct mbuf *m0;
+	struct mbuf *opts;
+	struct route *ro;
+	int flags;
+	struct ip_moptions *imo;
+	struct inpcb *inp;
+{
+	struct ipv6 *ip;
+	struct ifnet *ifp = NULL;
+	int len, mtu, error = 0;
+	struct sockaddr_in6 *dst;
+	struct in6_ifaddr *ia;
+	struct ip_soptions *iso = inp ? &inp->inp_soptions : 0;
+
+	if (opts) {
+	nextopt:
+		switch (opts->m_pkthdr.pktype) {
+		case IP6_NHDR_DOPT:
+			if (dopt6_dontfrag(opts))
+				break;
+			/* falls into */
+
+		case IP6_NHDR_AUTH:
+		case IP6_NHDR_ESP:
+			m0 = ip6_insertoption(m0, opts, iso, 0);
+			if (m0 == 0)
+				return (EIPSEC);
+			/* falls into */
+
+		default:
+			/* not yet supported: ignored !? */
+			opts = opts->m_next;
+			if (opts)
+				goto nextopt;
+			break;
+
+		case IP6_NHDR_RT: {
+			register struct ipv6_rthdr *rhp;
+
+			/* update destination address */
+			ip = mtod(m0, struct ipv6 *);
+			rhp = mtod(opts, struct ipv6_rthdr *);
+			bcopy((caddr_t)rhp + opts->m_len,
+			      (caddr_t)&ip->ip6_dst,
+			      sizeof(struct in6_addr));
+			if (ntohl(rhp->ir6_slmsk) & IP6_RT_SLBIT(0))
+				flags |= IP6_RT_SLBIT(0);
+			}
+			break;
+
+		case IP6_NHDR_HOP:
+			/* fragment (if necessary) before */
+			break;
+		}
+	}
+	ip = mtod(m0, struct ipv6 *);
+	len = (u_int16_t)ip->ip6_len + sizeof(struct ipv6);
+	if (opts)
+		len += opts->m_pkthdr.len;
+	if ((ro == NULL) && IS_MULTIADDR6(ip->ip6_dst))
+		goto mcast;
+
+	dst = satosin6(&ro->ro_dst);
+	/*
+	 * If there is a cached route,
+	 * check that it is to the same destination
+	 * and is still up.  If not, free it and try again.
+	 */
+	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
+			  !SAME_ADDR6(dst->sin6_addr, ip->ip6_dst))) {
+		RTFREE(ro->ro_rt);
+		ro->ro_rt = (struct rtentry *)0;
+	}
+	if (ro->ro_rt == 0) {
+		dst->sin6_family = AF_INET6;
+		dst->sin6_len = sizeof(struct sockaddr_in6);
+		COPY_ADDR6(ip->ip6_dst, dst->sin6_addr);
+	}
+
+	/*
+	 * If routing to interface only,
+	 * short circuit routing lookup.
+	 */
+	if (flags & IP_ROUTETOIF) {
+		if ((ia = ifatoia6(ifa_ifwithdstaddr(sin6tosa(dst)))) == 0 &&
+		    (ia = ifatoia6(ifa_ifwithnet(sin6tosa(dst)))) == 0) {
+			ip6stat.ip6s_noroute++;
+			error = ENETUNREACH;
+			goto bad;
+		}
+		ifp = ia->ia_ifp;
+		ip->ip6_hlim = 1;
+	} else if (flags & IP6_RT_SLBIT(0) &&
+		   (ia = ifatoia6(ifa_ifwithdstaddr(sin6tosa(dst)))) == 0 &&
+		   (ia = ifatoia6(ifa_ifwithnet(sin6tosa(dst)))) == 0) {
+		ip6stat.ip6s_noroute++;
+		error = EHOSTUNREACH;
+		goto bad;
+	} else {
+		if (ro->ro_rt == 0)
+			in6_rtalloc(ro, INP_IFA);
+		if (ro->ro_rt == 0) {
+			ip6stat.ip6s_noroute++;
+			error = EHOSTUNREACH;
+			goto bad;
+		}
+		ia = ifatoia6(ro->ro_rt->rt_ifa);
+		if (ro->ro_rt->rt_flags & RTF_LOCAL)
+			ifp = loif;
+		else
+			ifp = ro->ro_rt->rt_ifp;
+		ro->ro_rt->rt_use++;
+		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
+			dst = satosin6(ro->ro_rt->rt_gateway);
+	}
+    mcast:
+	if (IS_MULTIADDR6(ip->ip6_dst)) {
+		struct in6_multi *inm;
+
+#ifdef  DIAGNOSTIC
+		if (ip6printfs & D6_MCASTOUT)
+			printf("ip6_output multicast\n");
+#endif
+		m0->m_flags |= M_MCAST;
+		/*
+		 * IPv6 destination address is multicast.  Make sure "dst"
+		 * still points to the address in "ro".  (It may have been
+		 * changed to point to a gateway address, above.)
+		 */
+		if (ro) {
+			ifp = ro->ro_rt->rt_ifp;
+			dst->sin6_family = AF_INET6;
+			dst->sin6_len = sizeof(struct sockaddr_in6);
+			COPY_ADDR6(ip->ip6_dst, dst->sin6_addr);
+		}
+		/*
+		 * See if the caller provided any multicast options
+		 */
+		if (imo != NULL) {
+			ip->ip6_hlim = imo->imo_multicast_ttl;
+			if (imo->imo_multicast_ifp != NULL)
+				ifp = imo->imo_multicast_ifp;
+		} else
+			ip->ip6_hlim = IP_DEFAULT_MULTICAST_TTL;
+
+#if (MULTI_HOMED > 0)
+		/*
+		 * Preempt the interface with PKTINFO !
+		 */
+		if (inp && inp->inp_ifa && inp->inp_ifa->ifa_ifp)
+			ifp = inp->inp_ifa->ifa_ifp;
+#endif
+		/*
+		 * Confirm that the outgoing interface supports multicast.
+		 */
+		if (ifp == NULL)
+			panic("ip6_output: no ifp for multicast");
+		if ((ifp->if_flags & IFF_MULTICAST) == 0) {
+			ip6stat.ip6s_noroute++;
+			error = ENETUNREACH;
+			goto bad;
+		}
+		/*
+		 * If source address not specified yet, use address
+		 * of outgoing interface unless we know what we are doing.
+		 */
+		if (IS_ANYADDR6(ip->ip6_src) &&
+		    (flags & IP_RAWOUTPUT) == 0) {
+			register struct in6_ifaddr *ia;
+
+			for (ia = in6_ifaddrhead.tqh_first; ia;
+			     ia = ia->ia_list.tqe_next)
+				if (ia->ia_ifp == ifp) {
+					COPY_ADDR6(IA_SIN6(ia)->sin6_addr,
+						   ip->ip6_src);
+					break;
+				}
+		}
+
+		IN6_LOOKUP_MULTI(ip->ip6_dst, ifp, inm);
+		if (inm != NULL &&
+		   (imo == NULL || imo->imo_multicast_loop)) {
+			/*
+			 * If we belong to the destination multicast group
+			 * on the outgoing interface, and the caller did not
+			 * forbid loopback, loop back a copy.
+			 */
+			ip6_mloopback(ifp, m0, opts, dst);
+		}
+		/*
+		 * Multicasts with a time-to-live of zero may be looped-
+		 * back, above, but must not be transmitted on a network.
+		 * Also, multicasts addressed to the loopback interface
+		 * are not sent -- the above call to ip6_mloopback() will
+		 * loop back a copy if this host actually belongs to the
+		 * destination group on the loopback interface.
+		 */
+		if (ip->ip6_hlim == 0 || (ifp->if_flags & IFF_LOOPBACK) != 0) {
+			m_freem(m0);
+			goto done;
+		}
+
+		goto sendit;
+	}
+#ifdef DIAGNOSTIC
+	if (in6_isanycast(&ip->ip6_src))
+		log(LOG_ERR,
+		    "illegal anycast source %s\n",
+		    ip6_sprintf(&ip->ip6_src));
+#endif
+#ifdef ALTQ
+	/*
+	 * disable packet drop hack.
+	 * packetdrop should be done by queueing.
+	 */
+#else /* !ALTQ */
+	/*
+	 * Verify that we have any chance at all of being able to queue
+	 *      the packet or packet fragments
+	 */
+	if ((ifp->if_snd.ifq_len + len / ifp->if_mtu + 1) >=
+	    ifp->if_snd.ifq_maxlen) {
+		ip6stat.ip6s_odropped++;
+		error = ENOBUFS;
+		goto bad;
+	}
+#endif /* !ALTQ */
+
+    sendit:
+
+	/*
+	 * IpHack's section. <unimpl>.
+	 * - Xlate: translate packet's addr/port (NAT).
+	 * - Firewall: deny/allow
+	 * - Wrap: fake packet's addr/port.
+	 * - Encapsulate: put it in another IP and send out.
+	 */ 
+
+	if ((flags & IP_ROUTETOIF) ||
+	    ((ifp != NULL) && ((ro == NULL) || (ro->ro_rt == NULL))))
+		mtu = ifp->if_mtu;
+	else if (ro->ro_rt->rt_rmx.rmx_mtu) {
+		mtu = ro->ro_rt->rt_rmx.rmx_mtu;
+		if (mtu > ifp->if_mtu) {
+			/* This case can happen if the user changed the MTU
+			 * of an interface after enabling IPv6 on it.
+			 */
+			mtu = ro->ro_rt->rt_rmx.rmx_mtu = ifp->if_mtu;
+			/* notify MTU change */
+		}
+	} else
+		mtu = ro->ro_rt->rt_rmx.rmx_mtu = ifp->if_mtu;
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_OUTPUT)
+		printf("ip6_output src %s ifp %p len %d mtu %d hlim %d\n",
+		       ip6_sprintf(&ip->ip6_src),
+		       ifp, len, mtu, ip->ip6_hlim);
+#endif
+
+	/*
+	 * Check with the firewall...
+	 */
+	if (ip6_fw_chk_ptr) {
+#ifdef notyet
+		ip_divert_port = (*ip6_fw_chk_ptr)(&ip,
+		    ifp, ip_divert_ignore, &m0);
+		ip_divert_ignore = 0;
+		if (ip_divert_port) {		/* Divert packet */
+			(*inet6sw[ip_protox[IPPROTO_DIVERT]].pr_input)(m0, 0);
+			goto done;
+		}
+#else
+		/* If ipfw says divert, we have to just drop packet */
+		if ((*ip6_fw_chk_ptr)(&ip, ifp, 0, &m0)) {
+			m_freem(m0);
+			goto done;
+		}
+#endif
+		if (!m0) {
+			error = EACCES;
+			goto done;
+		}
+	}
+
+	/*
+	 * If small enough for interface, can just send directly.
+	 */
+	if (len <= mtu) {
+		mtu = 0;
+		while (opts) {
+			m0 = ip6_insertoption(m0, opts, iso, 0);
+			opts = opts->m_next;
+			mtu = 1;
+		}
+		if (mtu)
+			ip = mtod(m0, struct ipv6 *);
+		ip->ip6_len = htons((u_int16_t)ip->ip6_len);
+		error = (*ifp->if_output)(ifp, m0, sin6tosa(dst), ro->ro_rt);
+		goto done;
+	}
+	/*
+	 * IPv6 fragmentation is end-to-end only.
+	 */
+	if (flags & (IP_FORWARDING|IP_RAWOUTPUT|IP6_DONTFRAG)) {
+		error = EMSGSIZE;
+		goto bad;
+	}
+    {
+	register struct ipv6_fraghdr *frgp;
+	register struct mbuf *m;
+	int off, mhlen, firstlen, plen;
+	struct mbuf **mnext = &m0->m_nextpkt;
+
+	len += sizeof(struct ipv6_fraghdr);
+	mhlen = sizeof(struct ipv6) + sizeof(struct ipv6_fraghdr);
+	if (opts)
+		mhlen += opts->m_pkthdr.len;
+	plen = firstlen = (mtu - mhlen) &~ 7;
+	/*
+	 * Too large for interface; fragment if possible.
+	 * Must be able to put at least 8 bytes per fragment.
+	 */
+	if (firstlen < 8) {
+		error = EMSGSIZE;
+		goto bad;
+	}
+	/*
+	 * Insert fragment header and others
+	 */
+	if (M_LEADINGSPACE(m0) >= mhlen - sizeof(struct ipv6)) {
+		m0->m_data -= sizeof(struct ipv6_fraghdr);
+		m0->m_len += sizeof(struct ipv6_fraghdr);
+		ovbcopy((caddr_t)ip, mtod(m0, caddr_t), sizeof(*ip));
+	} else {
+		MGETHDR(m, M_DONTWAIT, MT_HEADER);
+		if (m == 0) {
+			error = ENOBUFS;
+			ip6stat.ip6s_odropped++;
+			goto bad;
+		}
+		M_COPY_PKTHDR(m, m0);
+		m0->m_flags &= ~M_PKTHDR;
+		if (MHLEN >= mhlen) {
+			MH_ALIGN(m, mhlen);
+		} else if (MCLBYTES >= mhlen) {
+			MCLGET(m, M_DONTWAIT);
+			if ((m->m_flags & M_EXT) == 0) {
+				error = ENOBUFS;
+				ip6stat.ip6s_odropped++;
+				m_free(m);
+				goto bad;
+			}
+		} else {
+			error = EMSGSIZE;
+			m_free(m);
+			goto bad;
+		}
+		m->m_next = m0;
+		m->m_len = mhlen;
+		if (opts)
+			m->m_data += opts->m_pkthdr.len;
+		bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ipv6));
+		m0->m_data += sizeof(struct ipv6);
+		m0->m_len -= sizeof(struct ipv6);
+		m0 = m;
+		mnext = &m0->m_nextpkt;
+	}
+	m0->m_pkthdr.len += mhlen - sizeof(struct ipv6);
+	ip = mtod(m0, struct ipv6 *);
+	frgp = (struct ipv6_fraghdr *)((caddr_t)ip + mhlen) - 1;
+	frgp->if6_res = 0;
+	frgp->if6_nh = ip->ip6_nh;
+	ip->ip6_nh = IP6_NHDR_FRAG;
+	frgp->if6_id = htonl(ip6_id++);
+	mtu = 0;
+	while (opts) {
+		m0 = ip6_insertoption(m0, opts, iso, IP6_INSOPT_NOALLOC);
+		opts = opts->m_next;
+		mtu = 1;
+	}
+	if (mtu)
+		ip = mtod(m0, struct ipv6 *);
+	/*
+	 * Loop through length of segment after first fragment,
+	 * make new header and copy data of each part and link onto chain.
+	 */
+	for (off = mhlen + firstlen; off < len; off += firstlen) {
+		MGETHDR(m, M_DONTWAIT, MT_HEADER);
+		if (m == 0) {
+			error = ENOBUFS;
+			ip6stat.ip6s_odropped++;
+			goto sendorfree;
+		}
+		if (MHLEN >= mhlen) {
+			MH_ALIGN(m, mhlen);
+		} else {
+			MCLGET(m, M_DONTWAIT);
+			if ((m->m_flags & M_EXT) == 0) {
+				error = ENOBUFS;
+				ip6stat.ip6s_odropped++;
+				m_free(m);
+				goto sendorfree;
+			}
+		}
+		*mnext = m;
+		mnext = &m->m_nextpkt;
+		m->m_len = mhlen;
+		bcopy(mtod(m0, caddr_t), mtod(m, caddr_t), mhlen);
+		ip = mtod(m, struct ipv6 *);
+		frgp = (struct ipv6_fraghdr *)((caddr_t)ip + mhlen) - 1;
+		frgp->if6_off = off - mhlen;
+		if (off + plen >= len)
+			plen = len - off;
+		else
+			frgp->if6_off |= IP6_MF;
+		frgp->if6_off = htons((u_int16_t)frgp->if6_off);
+		ip->ip6_len = htons((u_int16_t)(mhlen + plen - sizeof(*ip)));
+		m->m_next = m_copy(m0, off, plen);
+		if (m->m_next == 0) {
+			error = ENOBUFS;	/* ??? */
+			ip6stat.ip6s_odropped++;
+			goto sendorfree;
+		}
+		m->m_pkthdr.len = mhlen + plen;
+		m->m_pkthdr.rcvif = (struct ifnet *)0;
+		ip6stat.ip6s_ofragments++;
+	}
+	/*
+	 * Update first fragment by trimming what's been copied out
+	 * and updating header, then send each fragment (in order).
+	 */
+	m = m0;
+	m_adj(m, mhlen + firstlen - len);
+	m->m_pkthdr.len = mhlen + firstlen;
+	ip = mtod(m0, struct ipv6 *);
+	frgp = (struct ipv6_fraghdr *)((caddr_t)ip + mhlen) - 1;
+	frgp->if6_off = htons((u_int16_t)IP6_MF);
+	ip->ip6_len = htons((u_int16_t)(m->m_pkthdr.len - sizeof(*ip)));
+sendorfree:
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_FRAG)
+		printf("ip6_output fragment (error=%d)\n", error);
+#endif
+	for (m = m0; m; m = m0) {
+		m0 = m->m_nextpkt;
+		m->m_nextpkt = 0;
+		if (error == 0)
+			error = (*ifp->if_output)(ifp, m,
+						  sin6tosa(dst), ro->ro_rt);
+		else
+			m_freem(m);
+	}
+
+	if (error == 0)
+		ip6stat.ip6s_fragmented++;
+    }
+done:
+	return (error);
+bad:
+#ifdef  DIAGNOSTIC
+	if (ip6printfs & D6_OUTPUT)
+		printf("ip6_output bad\n");
+#endif
+	m_freem(m0);
+	return (error);
+}
+
+/*
+ * Wrapper for IPv6 output.
+ */
+int
+ip6_output(m0, opts, ro, flags, imo, inp)
+	struct mbuf *m0;
+	struct mbuf *opts;
+	struct route *ro;
+	int flags;
+	struct ip_moptions *imo;
+	struct inpcb *inp;
+{
+	struct ipv6 *ip;
+	int s, error = 0;
+	struct sockaddr_in6 *dst;
+	struct ip_soptions *iso = inp ? &inp->inp_soptions : 0;
+
+#ifdef  DIAGNOSTIC
+	if ((m0->m_flags & M_PKTHDR) == 0)
+		panic("ip6_output no HDR");
+	if (!ro && (flags & IP_FORWARDING) == 0)
+		panic("ip6_output no route, proto = %d",
+		      mtod(m0, struct ipv6 *)->ip6_nh);
+	if (ip6printfs & D6_OUTPUT) {
+		ip = mtod(m0, struct ipv6 *);		
+		printf("ip6_output(%p,%p,%x,%d,%p,%p)",
+		       m0, opts, ro, flags, imo, iso);
+		printf(" src %s dst %s len %d (mbuf %d/%d)\n",
+		       ip6_sprintf(&ip->ip6_src),
+		       ip6_sprintf(&ip->ip6_dst),
+		       ip->ip6_len, m0->m_pkthdr.len, m0->m_len);
+	}
+#endif
+	if (flags & IP_FORWARDING)
+		return (real_ip6_output(m0, opts, ro, flags, imo, inp));
+
+	ip6stat.ip6s_localout++;
+
+	/* Check for special actions in PCB */
+	s = splnet();
+	if (inp && inp->inp_xinfo) {
+		struct mbuf *x;
+		struct inp_xhdr *xp;
+
+		x = inp->inp_xinfo;
+		xp = mtod(x, struct inp_xhdr *);
+		error = xp->inp_xoutput(x, s, m0, opts, ro, flags, imo, inp);
+		return (error);
+	}
+	splx(s);
+	ip = mtod(m0, struct ipv6 *);
+	dst = satosin6(&ro->ro_dst);
+
+	/* Lookup route and check for special actions */
+	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
+			  !SAME_ADDR6(dst->sin6_addr, ip->ip6_dst))) {
+		RTFREE(ro->ro_rt);
+		ro->ro_rt = (struct rtentry *)0;
+	}
+	if (ro->ro_rt == 0) {
+		dst->sin6_family = AF_INET6;
+		dst->sin6_len = sizeof(struct sockaddr_in6);
+		COPY_ADDR6(ip->ip6_dst, dst->sin6_addr);
+		rtalloc(ro);
+	}
+	splnet();
+	if (ro->ro_rt && ro->ro_rt->rt_xoptions) {
+		struct rtentry *rt = ro->ro_rt;
+		struct rt_xohdr *rxp;
+		struct mbuf *x;
+		struct inp_xhdr *ixp;
+
+		rxp = mtod(rt->rt_xoptions, struct rt_xohdr *);
+		x = rxp->rt_xomatch(rt, rt->rt_xoptions, rxp);
+		if (inp) {
+			x->m_next = inp->inp_xinfo;
+			inp->inp_xinfo = x;
+		}
+		ixp = mtod(x, struct inp_xhdr *);
+		error = ixp->inp_xoutput(x, s, m0, opts, ro, flags, imo, inp);
+		return (error);
+	}
+	splx(s);
+	return (real_ip6_output(m0, opts, ro, flags, imo, inp));
+}
+
+/*
+ * Test if a destination header is front or back.
+ * (should use option types)
+ */
+static int
+dopt6_dontfrag(opts0)
+	struct mbuf *opts0;
+{
+	register struct mbuf *opts = opts0;
+
+	while ((opts = opts->m_next) != 0)
+		switch (opts->m_pkthdr.pktype) {
+		case IP6_NHDR_RT:
+		case IP6_NHDR_FRAG:
+		case IP6_NHDR_AUTH:
+		case IP6_NHDR_ESP:
+		case IP6_NHDR_DOPT:
+			return (0);
+		}
+	/* decode options (TODO) */
+	/* default is can fragment */
+	return (0);
+}
+
+/*
+ * Insert an IPv6 option into a packet.
+ * Adjust IPv6 destination as required for IPv6 source routing.
+ */
+struct mbuf *
+ip6_insertoption(m, opt, iso, flags)
+	register struct mbuf *m;
+	struct mbuf *opt;
+	struct ip_soptions *iso;
+	int flags;
+{
+	register struct mbuf *n;
+	register struct ipv6 *ip = mtod(m, struct ipv6 *);
+	register u_char *cp;
+	register unsigned optlen;
+	int nh = 0;
+
+	optlen = opt->m_len;
+	if (opt->m_pkthdr.pktype == IP6_NHDR_ESP) {
+		/* the size of init vector is in the last byte */
+		cp = mtod(opt, u_char *) + optlen - 1;
+		optlen = *cp + sizeof(struct ipv6_esphdr);
+	}
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_OPTOUT) {
+		printf("ip6_insertoption(%p,%p,%p,%d)", m, opt, iso, flags);
+		printf(" type %d flen %d olen %d\n",
+		       opt->m_pkthdr.pktype, opt->m_pkthdr.len, optlen);
+	}
+#endif
+	if (optlen + (u_int16_t)ip->ip6_len + sizeof(*ip) > IP_MAXPACKET)
+		return (m);		/* XXX should fail */
+	if (((flags & IP6_INSOPT_NOALLOC) == 0) &&
+	    (M_LEADINGSPACE(m) < optlen)) {
+		MGETHDR(n, M_DONTWAIT, MT_HEADER);
+		if (n == 0) {
+			ip6stat.ip6s_onomem++;
+			return (m);
+		}
+		M_COPY_PKTHDR(n, m);
+		if (MHLEN >= sizeof(*ip) + optlen) {
+			MH_ALIGN(n, sizeof(*ip) + optlen);
+		} else if (MCLBYTES >= sizeof(*ip) + optlen) {
+			MCLGET(n, M_DONTWAIT);
+			if ((n->m_flags & M_EXT) == 0) {
+				ip6stat.ip6s_onomem++;
+				m_free(n);
+				return (m);
+			}
+		} else {
+			m_free(n);
+			return (m);
+		}
+		n->m_pkthdr.len += optlen;
+		m->m_len -= sizeof(struct ipv6);
+		m->m_data += sizeof(struct ipv6);
+		m->m_flags &= ~M_PKTHDR;
+		n->m_next = m;
+		m = n;
+		m->m_len = optlen + sizeof(struct ipv6);
+		bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(*ip));
+	} else {
+		m->m_data -= optlen;
+		m->m_len += optlen;
+		m->m_pkthdr.len += optlen;
+		ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(*ip));
+	}
+	ip = mtod(m, struct ipv6 *);
+	cp = (u_char *)(ip + 1);
+	bcopy(mtod(opt, caddr_t), cp, optlen);
+	ip->ip6_len += optlen;
+	if (opt->m_pkthdr.pktype == IP6_NHDR_ESP)
+		nh = ip->ip6_nh;
+	else
+		*cp = ip->ip6_nh;
+	ip->ip6_nh = opt->m_pkthdr.pktype;
+	switch (ip->ip6_nh) {
+	    case IP6_NHDR_RT:
+		if ((flags & IP6_INSOPT_RAW) == 0)
+			bcopy(mtod(opt, caddr_t) + optlen,
+			      (caddr_t)&ip->ip6_dst,
+			      sizeof(struct in6_addr));
+		break;
+
+	    case IP6_NHDR_HOP:
+	    case IP6_NHDR_DOPT:
+		if ((flags & IP6_INSOPT_RAW) == 0)
+			hd6_outoptions(m);
+		break;
+
+	    case IP6_NHDR_AUTH:
+		if ((flags & IP6_INSOPT_RAW) == 0)
+			m = ah6_output(m, opt->m_next, iso);
+		break;
+
+	    case IP6_NHDR_ESP:
+		m = esp6_output(m, opt, iso, optlen, nh);
+		break;
+	}
+	return (m);
+}
+
+/*
+ * (Generic) header option processing.
+ */
+static void
+hd6_outoptions(m)
+	struct mbuf *m;
+{
+	register struct ipv6 *ip;
+	register struct ipv6_h2hhdr *hp;
+	register struct opt6_any *op;
+	register int len;
+
+	ip = mtod(m, struct ipv6 *);
+	hp = (struct ipv6_h2hhdr *)(ip + 1);
+	op = (struct opt6_any *)&hp->ih6_pad1;
+	len = (hp->ih6_hlen + 1) * sizeof(*hp) - 2 * sizeof(u_int8_t);
+
+#ifdef notdef
+	/* Zap the whole thing ?! */
+	/* TODO: use OPT6_ACTION in order to be more clever ! */
+	/* note: this can be called with an incorrect option for ICMP */
+	/* but now we have IP6_INSOPT_RAW */
+	op->o6any_ext = OPT6_PAD_N;
+	op->o6any_len = len - sizeof(*op);
+#endif
+}
+
+/*
+ * Authentication Header processing.
+ */
+struct mbuf *
+ah6_output(m0, opts, iso)
+	struct mbuf *m0, *opts;
+	struct ip_soptions *iso;
+{
+	register struct ipv6 *ip;
+	register struct ipv6_authhdr *hp;
+	register struct ipsec_entry_header *ieh;
+	register caddr_t state;
+	struct mbuf *m = 0;
+	int len, hlen;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_AH)
+		printf("ah6_output(%p,%p,%p)\n", m0, opts, iso);
+#endif
+	ip = mtod(m0, struct ipv6 *);
+	hp = (struct ipv6_authhdr *)(ip + 1);
+	/* AH length unit is 4 bytes! */
+	hlen = hp->ah6_hlen * 4;
+	len = hlen + sizeof(*hp);
+	ips6addr.sis_way = IPSEC_OUT;
+	ips6addr.sis_kind = IP6_NHDR_AUTH;
+	ips6addr.sis_spi = hp->ah6_spi;
+	COPY_ADDR6(ip->ip6_dst, ips6addr.sis_addr);
+	ieh = ipsec_lookup(&ips6addr, iso ? iso->lh_first : 0);
+	if (ieh)
+		ieh->ieh_refcnt--;
+	if ((len > m0->m_len) ||
+	    (ieh == 0) ||
+	    (ieh->ieh_algo == 0) ||
+	    (ieh->ieh_algo->isa_ah_reslen > hlen))
+		goto bad;
+
+	ieh->ieh_use++;
+	bzero((caddr_t)(hp + 1), ieh->ieh_algo->isa_ah_reslen);
+	if ((m = ah6_build(m0, opts, IPSEC_OUT)) == 0)
+		goto bad;
+	if ((state = ieh->ieh_algo->isa_ah_init(ieh)) == 0)
+		goto bad;
+	state = ieh->ieh_algo->isa_ah_update(state, m);
+	ieh->ieh_algo->isa_ah_finish(state, (caddr_t)(hp + 1), ieh);
+	m_freem(m);
+	return (m0);
+
+    bad:
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_AH)
+		printf("ah6_output failed\n");
+#endif
+	if (m)
+		m_freem(m);
+	return (0);
+}
+
+/*
+ * Encryption Security Payload processing.
+ */
+struct mbuf *
+esp6_output(m0, opts, iso, optlen, nh)
+	struct mbuf *m0, *opts;
+	struct ip_soptions *iso;
+	int optlen, nh;
+{
+	register struct ipv6 *ip;
+	register struct ipv6_esphdr *hp;
+	register struct ipsec_entry_header *ieh;
+	register caddr_t state;
+	struct mbuf *m = 0;
+	int len, padlen;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ESP)
+		printf("esp6_output(%p,%p,%p,%d,%d)\n",
+		       m0, opts, iso, optlen, nh);
+#endif
+	ip = mtod(m0, struct ipv6 *);
+	hp = mtod(opts, struct ipv6_esphdr *);
+	len = ip->ip6_len - optlen + 2;
+	padlen = (-len) & 7;
+	ips6addr.sis_way = IPSEC_OUT;
+	ips6addr.sis_kind = IP6_NHDR_ESP;
+	ips6addr.sis_spi = hp->esp6_spi;
+	COPY_ADDR6(ip->ip6_dst, ips6addr.sis_addr);
+	ieh = ipsec_lookup(&ips6addr, iso ? iso->lh_first : 0);
+	if (ieh)
+		ieh->ieh_refcnt--;
+	if ((ieh == 0) ||
+	    (ieh->ieh_algo == 0) ||
+	    (ieh->ieh_ivlen + sizeof(*hp) != optlen))
+		goto bad;
+
+	ieh->ieh_use++;
+	if ((m = esp6_build(m0, ieh->ieh_ivlen, padlen, nh)) == 0)
+		goto bad;
+	if ((state = ieh->ieh_algo->isa_esp_init(ieh, (caddr_t)(hp + 1))) == 0)
+		goto bad;
+	state = ieh->ieh_algo->isa_esp_encrypt(state, m);
+	ieh->ieh_algo->isa_esp_finish(state);
+
+	if (m0->m_next)
+		m_freem(m0->m_next);
+	m0->m_next = m;
+	m0->m_len = optlen + sizeof(*ip);
+	m0->m_pkthdr.len += padlen + 2;
+	ip->ip6_len += padlen + 2;
+	return (m0);
+
+    bad:
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ESP)
+		printf("esp6_output failed\n");
+#endif
+	if (m)
+		m_freem(m);
+	return (0);
+}
+
+/*
+ * IPv6 socket option processing.
+ */
+int
+ip6_ctloutput(op, so, level, optname, mp, p)
+	int op;
+	struct socket *so;
+	int level, optname;
+	struct mbuf **mp;
+	struct proc *p;
+{
+	register struct inpcb *inp = sotoinpcb(so);
+	register struct mbuf *m = *mp;
+	register int optval = 0;
+	struct sockaddr_in6 *sin = 0;
+	struct ifnet *ifp = 0;
+	struct in6_ifaddr *ia = 0;
+	struct in6_pktinfo *pi = 0;
+	int error = 0;
+
+	if ((level == IP6_NHDR_AUTH) || (level == IP6_NHDR_ESP)) {
+		if ((inp->inp_flags & INP_COMPATV6) == 0) {
+			if (op == PRCO_SETOPT && *mp)
+				(void) m_free(*mp);
+			return (ENOPROTOOPT);
+		}
+		inp->inp_flags &= ~INP_COMPATV4;
+		if (op == PRCO_SETOPT)
+			return (ip6_setsoptions(so, optname, m, p));
+		else
+			return (ip6_getsoptions(inp, optname, mp));
+	}
+
+	if ((level != IPPROTO_IP) && (level != IPPROTO_IPV6)) {
+		error = EINVAL;
+		if (op == PRCO_SETOPT && *mp)
+			(void) m_free(*mp);
+	} else switch (op) {
+
+	case PRCO_SETOPT:
+		switch (optname) {
+		case IP_OPTIONS:
+			if ((inp->inp_flags & INP_COMPATV6) == 0) {
+				error = ENOPROTOOPT;
+				break;
+			}
+			inp->inp_flags &= ~INP_COMPATV4;
+			return (ip6_setoptions(&inp->inp_options, m, inp));
+			break;
+
+		case IPV6_PKTOPTIONS:
+			if ((inp->inp_flags & INP_COMPATV6) == 0) {
+				error = ENOPROTOOPT;
+				break;
+			}
+			inp->inp_flags &= ~INP_COMPATV4;
+			if (m)
+				error = ip6_setcontrol(inp, m, p);
+			break;
+
+		case IPV6_ADDRFORM:
+			if (m == NULL || m->m_len != sizeof(int)) {
+				error = EINVAL;
+				break;
+			}
+			optval = *mtod(m, int *);
+			switch (optval) {
+
+			case PF_INET6:
+				break;
+
+			case PF_INET:
+				error =
+				  ip_changeversion(optval, so, inp);
+				break;
+
+			default:
+				error = EPFNOSUPPORT;
+			}
+			break;
+
+		case IP_TOS:
+			if (so->so_proto->pr_type != SOCK_STREAM)
+				goto fallin;
+			/* try to remap TOS into Priority */
+			if (m == NULL || m->m_len != sizeof(int)) {
+				error = EINVAL;
+				break;
+			}
+			optval = *mtod(m, int *);
+			switch (optval) {
+
+			case IPTOS_LOWDELAY:
+				inp->inp_oflowinfo =
+				  IPV6_PRIORITY_INTERACTIVE;
+				break;
+
+			case IPTOS_THROUGHPUT:
+				inp->inp_oflowinfo =
+				  IPV6_PRIORITY_BULK;
+				break;
+			}
+			/* falls into */
+
+		case IPV6_UNICAST_HOPS:
+		case IP_RECVOPTS:
+		case IP_RECVRETOPTS:
+		case IP_RECVDSTADDR:
+		case IP_RECVIF:
+		case IPV6_RECVPKTINFO:
+		case IPV6_RECVHOPS:
+		case IP_PORTRANGE:
+		fallin:
+			return(ip_ctloutput(op, so, level, optname, mp, p));
+			break;
+
+		case IPV6_MULTICAST_IF:
+		case IPV6_MULTICAST_HOPS:
+		case IPV6_MULTICAST_LOOP:
+		case IPV6_ADD_MEMBERSHIP:
+		case IPV6_DROP_MEMBERSHIP:
+			if ((inp->inp_flags & INP_COMPATV6) == 0) {
+				error = ENOPROTOOPT;
+				break;
+			}
+			inp->inp_flags &= ~INP_COMPATV4;
+			error = ip6_setmoptions(inp, optname, m);
+			break;
+
+		case IPV6_SENDIF:
+			if (m == NULL ||
+			    (m->m_len && m->m_len < sizeof(u_short))) {
+				error = EINVAL;
+				break;
+			}
+			if (m->m_len == 0) {
+#if (MULTI_HOMED > 0)
+				if (inp->inp_ifa)
+					IFAFREE(inp->inp_ifa);
+				inp->inp_ifa = 0;
+#endif
+				break;
+			} else if (m->m_len == sizeof(u_short))
+				optval = *mtod(m, u_short *);
+			else {
+				sin = mtod(m, struct sockaddr_in6 *);
+				if (sin->sin6_len > m->m_len) {
+					error = EINVAL;
+					break;
+				}
+				if (sin->sin6_family == AF_LINK) {
+#define SDLINDEX(x)	(((struct sockaddr_dl *)x)->sdl_index)
+					optval = SDLINDEX(sin);
+					sin = 0;
+				} else if (sin->sin6_family == AF_INET6) {
+					if (sin->sin6_len != sizeof(*sin)) {
+						error = EINVAL;
+						break;
+					}
+					optval = sin->sin6_port;
+					sin->sin6_port = 0;
+				}
+			}
+		sendif1:
+			if (optval) {
+				for (ifp = TAILQ_FIRST(&ifnet); ifp;
+				     ifp = TAILQ_NEXT(ifp, if_link))
+					if (ifp->if_index == optval)
+						break;
+				if (ifp == 0) {
+					error = ENXIO;
+					break;
+				}
+				/* loopback is a special case! */
+				if (ifp->if_flags & IFF_LOOPBACK) {
+#if (MULTI_HOMED > 0)
+					if (inp->inp_ifa)
+						IFAFREE(inp->inp_ifa);
+					inp->inp_ifa = 0;
+#endif
+					break;
+				}
+			}
+			if (optval && sin == 0) {
+				for (ia = in6_ifaddrhead.tqh_first; ia;
+				     ia = ia->ia_list.tqe_next) {
+					if (ia->ia_ifp != ifp)
+						continue;
+					sin = IA_SIN6(ia);
+					if (IS_LOCALADDR6(sin->sin6_addr))
+						break;
+				}
+				if (ia == 0)
+					IFP_TO_IA6(ifp, ia);
+				if (ia == 0) {
+					error = ENETDOWN;
+					break;
+				}
+				goto sendif_done;
+			}
+			if (optval) {
+				for (ia = in6_ifaddrhead.tqh_first; ia;
+				     ia = ia->ia_list.tqe_next) {
+					if (ia->ia_ifp != ifp)
+						continue;
+					if (SAME_SOCKADDR(sin, IA_SIN6(ia)))
+						break;
+				}
+				goto sendif_done;
+			}
+			if (sin == 0)
+				goto sendif_done;
+			for (ia = in6_ifaddrhead.tqh_first; ia;
+			     ia = ia->ia_list.tqe_next)
+				if (SAME_SOCKADDR(sin, IA_SIN6(ia)))
+					break;
+		sendif_done:
+			if ((ia == 0) ||
+			    (sin && !SAME_SOCKADDR(sin, IA_SIN6(ia)))) {
+				error = EADDRNOTAVAIL;
+				break;
+			}
+			if (inp->inp_moptions) {
+				ifp = ia->ia_ifp;
+				if ((ifp->if_flags & IFF_MULTICAST) == 0) {
+					error = EADDRNOTAVAIL;
+					break;
+				}
+				inp->inp_moptions->imo_multicast_ifp = ifp;
+			}
+#if (MULTI_HOMED > 0)
+			error = in6_setifa(inp, &ia->ia_ifa);
+#else
+#ifdef DIAGNOSTIC
+			printf("set inp_ifa %p\n", ia);
+#endif
+#endif
+			break;
+
+		case IPV6_PKTINFO:
+			if (m == NULL ||
+			    m->m_len != sizeof(struct in6_pktinfo)) {
+				error = EINVAL;
+				break;
+			}
+			if ((inp->inp_flags & INP_COMPATV6) == 0) {
+				error = ENOPROTOOPT;
+				break;
+			}
+			inp->inp_flags &= ~INP_COMPATV4;
+			pi = mtod(m, struct in6_pktinfo *);
+			optval = pi->ipi6_ifindex;
+			if (!IS_ANYADDR6(pi->ipi6_addr)) {
+				int s;
+
+				if (M_LEADINGSPACE(m) < (int)&(sin->sin6_addr))
+					panic("in6_pktinfo");
+				m->m_data -= (int)&(sin->sin6_addr);
+				m->m_len = sizeof(*sin);
+				sin = mtod(m, struct sockaddr_in6 *);
+				sin->sin6_family = AF_INET6;
+				sin->sin6_len = sizeof(*sin);
+				sin->sin6_port = 0;
+				sin->sin6_flowinfo = 0;
+				s = splnet();
+				error = (*so->so_proto
+					 ->pr_usrreqs->pru_dynbind)
+					(so, (struct sockaddr *)sin, p);
+				splx(s);
+				if (error)
+					break;
+			}
+			if (optval == 0) {
+#if (MULTI_HOMED > 0)
+				if (inp->inp_ifa)
+					IFAFREE(inp->inp_ifa);
+				inp->inp_ifa = 0;
+#endif
+				break;
+			}
+			goto sendif1;
+
+		case FLOW6_RAND:
+			if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0)
+				break;
+			if (m == NULL || m->m_len != sizeof(int)) {
+				error = EINVAL;
+				break;
+			}
+			(void) flow6_rand(*mtod(m, int *));
+			break;
+
+		default:
+			error = ENOPROTOOPT;
+			break;
+		}
+		if (m)
+			(void)m_free(m);
+		break;
+
+	case PRCO_GETOPT:
+		switch (optname) {
+		case IP_OPTIONS:
+			if ((inp->inp_flags & INP_COMPATV6) == 0) {
+				error = ENOPROTOOPT;
+				break;
+			}
+			inp->inp_flags &= ~INP_COMPATV4;
+			error = ip6_getoptions(inp->inp_options, mp, 0);
+			break;
+
+		case IPV6_ADDRFORM:
+			*mp = m = m_get(M_WAIT, MT_SOOPTS);
+			m->m_len = sizeof(int);
+			optval = PF_INET6;
+			*mtod(m, int *) = optval;
+			break;
+
+		case IPV6_PKTINFO:
+			*mp = m = m_get(M_WAIT, MT_SOOPTS);
+			m->m_len = sizeof(struct in6_pktinfo);
+			pi = mtod(m, struct in6_pktinfo *);
+			COPY_ADDR6(inp->inp_laddr6, pi->ipi6_addr);
+			if (inp->inp_rcvif != NULL)
+				pi->ipi6_ifindex = inp->inp_rcvif->if_index;
+			else
+				pi->ipi6_ifindex = 0;
+			break;
+
+		case IP_TOS:
+		case IPV6_UNICAST_HOPS:
+		case IP_RECVOPTS:
+		case IP_RECVRETOPTS:
+		case IP_RECVDSTADDR:
+		case IP_RECVIF:
+		case IPV6_RECVPKTINFO:
+		case IPV6_RECVHOPS:
+		case IP_PORTRANGE:
+			return(ip_ctloutput(op, so, level, optname, mp, p));
+			break;
+
+		case IPV6_MULTICAST_IF:
+		case IPV6_MULTICAST_HOPS:
+		case IPV6_MULTICAST_LOOP:
+		case IPV6_ADD_MEMBERSHIP:
+		case IPV6_DROP_MEMBERSHIP:
+			if ((inp->inp_flags & INP_COMPATV6) == 0) {
+				error = ENOPROTOOPT;
+				break;
+			}
+			inp->inp_flags &= ~INP_COMPATV4;
+			error = ip6_getmoptions(optname,
+						inp->inp_moptions, mp);
+			break;
+
+		case IPV6_SENDIF:
+#if (MULTI_HOMED > 0)
+			if (inp->inp_ifa == 0) {
+#endif
+				*mp = 0;
+				break;
+#if (MULTI_HOMED > 0)
+			}
+			*mp = m = m_get(M_WAIT, M_SOOPTS);
+			m->m_len = sizeof(struct sockaddr_in6 *);
+			sin = mtod(m, struct sockaddr_in6 *);
+			bcopy((caddr_t)inp->inp_ifa->ifa_addr,
+			      (caddr_t)sin, m->m_len);
+			sin->sin6_port = inp->inp_ifa->ifa_ifp->if_index;
+			break;
+#endif
+		case FLOW6_RAND:
+			*mp = m = m_get(M_WAIT, MT_SOOPTS);
+			m->m_len = sizeof(int);
+			*mtod(m, int *) = flow6_rand(0);
+			break;
+
+		default:
+			error = ENOPROTOOPT;
+			break;
+		}
+		break;
+	}
+	return (error);
+}
+
+/*
+ * IPv6 ancillary data (aka msg_control) output processing
+ */
+int
+ip6_setcontrol(inp, control, p)
+	register struct inpcb *inp;
+	struct mbuf *control;
+	struct proc *p;
+{
+	register struct cmsghdr *cp;
+	struct mbuf *temp = 0;
+	struct in6_pktinfo pi;
+	struct sockaddr_in6 *sin = 0;
+	struct ifnet *ifp;
+	struct in6_ifaddr *ia;
+	struct ip_moptions *imo;
+	struct socket *so = inp->inp_socket;
+	int optval, len, error = 0;
+
+	imo = (struct ip_moptions *)malloc(sizeof(*imo), M_IPMOPTS,
+			M_DONTWAIT);
+
+	if (imo == NULL)
+		return (ENOBUFS);
+	if (inp->inp_moptions)
+		bcopy(inp->inp_moptions, imo, sizeof(*imo));
+	else {
+		imo->imo_multicast_ifp = NULL;
+		imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
+		imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
+		imo->imo_num_memberships = 0;
+	}
+
+	while (control->m_len > 0) {
+	    cp = mtod(control, struct cmsghdr *);
+	    len = ALIGN(cp->cmsg_len);
+	    if (len > control->m_len) {
+		error = EINVAL;
+		goto done;
+	    }
+	    switch (cp->cmsg_type) {
+	      case IP_OPTIONS:
+		goto unimpl;
+
+	      case IP_TOS:
+		goto unimpl;
+
+	      case IPV6_UNICAST_HOPS:
+		if ((cp->cmsg_level != IPPROTO_IP) &&
+		    (cp->cmsg_level != IPPROTO_IPV6)) {
+		    error = EINVAL;
+		    goto done;
+		}
+		if (cp->cmsg_len != sizeof(*cp) + sizeof(int)) {
+		    error = EINVAL;
+		    goto done;
+		}
+		bcopy(CMSG_DATA(cp), &optval, sizeof(int));
+		if (optval == -1)
+		    optval = ip_defttl;
+		if ((optval < 0) || (optval > MAXTTL)) {
+		    error = EINVAL;
+		    goto done;
+		}
+		inp->inp_ttl = optval;
+		break;
+
+	      case IPV6_PKTINFO:
+		if (cp->cmsg_level != IPPROTO_IPV6) {
+		    error = EINVAL;
+		    goto done;
+		}
+		if (cp->cmsg_len != sizeof(*cp) + sizeof(pi)) {
+		    error = EINVAL;
+		    goto done;
+		}
+		if ((inp->inp_flags & INP_COMPATV6) == 0) {
+		    error = ENOPROTOOPT;
+		    goto done;
+		}
+		inp->inp_flags &= ~INP_COMPATV4;
+		bcopy(CMSG_DATA(cp), &pi, sizeof(pi));
+		optval = pi.ipi6_ifindex;
+
+		if (!IS_ANYADDR6(pi.ipi6_addr)) {
+		    temp = m_get(M_DONTWAIT, MT_SONAME);
+		    if (temp == 0) {
+			error = ENOBUFS;
+			goto done;
+		    }
+		    temp->m_len = sizeof(*sin);
+		    MH_ALIGN(temp, sizeof(*sin));
+		    bzero(mtod(temp, caddr_t), sizeof(*sin));
+		    sin = mtod(temp, struct sockaddr_in6 *);
+		    sin->sin6_len = sizeof(*sin);
+		    sin->sin6_family = AF_INET6;
+		    COPY_ADDR6(pi.ipi6_addr, sin->sin6_addr);
+		    error = (*so->so_proto
+			     ->pr_usrreqs->pru_dynbind)
+			    (so, (struct sockaddr *)sin, p);
+		    if (error)
+			goto donepi;
+		}
+
+		if (optval == 0) {
+#if (MULTI_HOMED > 0)
+		    if (inp->inp_ifa)
+			IFAFREE(inp->inp_ifa);
+		    inp->inp_ifa = 0;
+#endif
+		    goto donepi;
+		}
+		for (ifp = TAILQ_FIRST(&ifnet); ifp;
+		     ifp = TAILQ_NEXT(ifp, if_link))
+		    if (ifp->if_index == optval)
+			break;
+		if (ifp == 0) {
+		    error = ENXIO;
+		    goto donepi;
+		}
+		/* loopback is a special case! */
+		if (ifp->if_flags & IFF_LOOPBACK) {
+#if (MULTI_HOMED > 0)
+		    if (inp->inp_ifa)
+			IFAFREE(inp->inp_ifa);
+		    inp->inp_ifa = 0;
+#endif
+		    goto donepi;
+		}
+		if (sin == 0) {
+		    for (ia = in6_ifaddrhead.tqh_first; ia;
+			 ia = ia->ia_list.tqe_next) {
+			if (ia->ia_ifp != ifp)
+			    continue;
+			if (IS_LOCALADDR6(IA_SIN6(ia)->sin6_addr))
+			    break;
+		    }
+		    if (ia == 0)
+			IFP_TO_IA6(ifp, ia);
+		    if (ia == 0) {
+			error = ENETDOWN;
+			goto donepi;
+		    }
+		} else {
+		    for (ia = in6_ifaddrhead.tqh_first; ia;
+			 ia = ia->ia_list.tqe_next) {
+			if (ia->ia_ifp != ifp)
+			    continue;
+			if (SAME_SOCKADDR(sin, IA_SIN6(ia)))
+			    break;
+		    }
+		    if (ia == 0) {
+			error = EADDRNOTAVAIL;
+			goto donepi;
+		    }
+		}
+		if (inp->inp_moptions) {
+		    if ((ifp->if_flags & IFF_MULTICAST) == 0) {
+			error = EADDRNOTAVAIL;
+			goto donepi;
+		    }
+		}
+		imo->imo_multicast_ifp = ifp;
+		inp->inp_moptions = imo;
+		imo = NULL;
+#if (MULTI_HOMED > 0)
+		error = in6_setifa(inp, &ia->ia_ifa);
+#else
+#ifdef DIAGNOSTIC
+		printf("set inp_ifa %p\n", ia);
+#endif
+#endif
+	      donepi:
+		if (temp)
+		    (void)m_free(temp);
+		if (error)
+		    goto done;
+		break;
+
+	      case IPV6_MULTICAST_HOPS:
+		if ((cp->cmsg_level != IPPROTO_IP) &&
+		    (cp->cmsg_level != IPPROTO_IPV6)) {
+		    error = EINVAL;
+		    goto done;
+		}
+		if (cp->cmsg_len != sizeof(*cp) + sizeof(int)) {
+		    error = EINVAL;
+		    goto done;
+		}
+		bcopy(CMSG_DATA(cp), &optval, sizeof(int));
+		if (optval == -1)
+		    optval = IP_DEFAULT_MULTICAST_TTL;
+		if ((optval < 0) || (optval > MAXTTL)) {
+		    error = EINVAL;
+		    goto done;
+		}
+		imo->imo_multicast_ttl = optval;
+		inp->inp_moptions = imo;
+		imo = NULL;
+		break;
+
+	      default:
+	      unimpl:
+		error = ENOPROTOOPT;
+		goto done;
+	    }
+	    control->m_len -= len;
+	    control->m_data += len;
+	}
+    done:
+	if (imo)
+		free(imo, M_IPMOPTS);
+	return (error);
+}
+
+
+/*
+ * Set up IPv6 options in pcb for insertion in output packets.
+ * Store in a mbuf chain with pointer in pcbopts.
+ */
+int
+ip6_setoptions(pcbopts, m0, inp)
+	register struct mbuf **pcbopts, *m0;
+	struct inpcb *inp;
+{
+	register u_int len = 0;
+	register struct mbuf *m;
+	register u_char *cp, *end, nh;
+	int error = 0;
+
+	/* turn off any old options */
+	if (*pcbopts)
+		m_freem(*pcbopts);
+	*pcbopts = 0;
+	if (m0 == (struct mbuf *)0 || m0->m_len == 0) {
+		/*
+		 * Only turning off any previous options.
+		 */
+		if (m0)
+			m_free(m0);
+		return (0);
+	}
+
+	if ((mtod(m0, u_int32_t) % 4) || (m0->m_len % 4)) {
+		error = EINVAL;
+		goto done;
+	}
+	cp = mtod(m0, u_char *);
+	end = cp + (u_int)m0->m_len;
+	while (cp < end) {
+		switch (nh = *cp) {
+		case IP6_NHDR_HOP:
+			len = (((struct ipv6_h2hhdr *)cp)->ih6_hlen * 8) +
+				sizeof(struct ipv6_h2hhdr);
+			if ((len % 8) || (cp + len > end)) {
+				error = EINVAL;
+				goto done;
+			}
+			*cp = 0;
+			break;
+
+		case IP6_NHDR_DOPT:
+			len = (((struct ipv6_dopthdr *)cp)->io6_hlen * 8) +
+				sizeof(struct ipv6_dopthdr);
+			if ((len % 8) || (cp + len > end)) {
+				error = EINVAL;
+				goto done;
+			}
+			*cp = 0;
+			break;
+
+		case IP6_NHDR_RT: {
+			register struct ipv6_rthdr *hp;
+
+			hp = (struct ipv6_rthdr *)cp;
+			hp->ir6_sglt = hp->ir6_hlen >> 1;
+			if ((hp->ir6_type != IP6_LSRRT) ||
+			    ((hp->ir6_hlen & 1) != 0) ||
+			    (hp->ir6_sglt > IP6_RT_MAX) ||
+			    (ntohl(hp->ir6_slmsk) & ~IP6_RT_SLMSK)) {
+				error = EINVAL;
+				goto done;
+			}
+			len = (hp->ir6_hlen * 8) + sizeof(struct ipv6_rthdr);
+			len += sizeof(struct in6_addr);
+			if (cp + len > end) {
+				error = EINVAL;
+				goto done;
+			}
+			*cp = 0;
+			break;
+			}
+
+		case IP6_NHDR_AUTH:
+			len = (((struct ipv6_authhdr *)cp)->ah6_hlen * 4) +
+				sizeof(struct ipv6_authhdr);
+			if ((len % 8) || (cp + len > end)) {
+				error = EINVAL;
+				goto done;
+			}
+			*cp = 0;
+			break;
+
+		case IP6_NHDR_ESP: {
+			u_int32_t spi;
+
+			/* first word is nh|len|ivlen|xpad */
+			len = cp[1];
+			if ((cp + len > end) ||
+			    (len < 2 * sizeof(spi) + cp[2])) {
+				error = EINVAL;
+				goto done;
+			}
+			/* copy SPI & ivlen at their place */
+			spi = *(u_int32_t *)&cp[len - sizeof(u_int32_t)];
+			cp[len - 1] = cp[2];
+			*(u_int32_t *)cp = spi;
+			}
+			break;
+
+		default:
+			error = EINVAL;
+			goto done;
+		}
+
+		/*
+		 * Allocate mbuf.
+		 */
+		MGETHDR(m, M_WAIT, MT_SOOPTS);
+		if (m == 0) {
+			error = ENOBUFS;
+			goto done;
+		}
+		if (MHLEN >= len) {
+			MH_ALIGN(m, len);
+		} else if (MCLBYTES >= len) {
+			MCLGET(m, M_WAIT);
+			if ((m->m_flags & M_EXT) == 0) {
+				error = ENOBUFS;
+				m_free(m);
+				goto done;
+			}
+		} else {
+			error = EMSGSIZE;
+			m_free(m);
+			goto done;
+		}
+
+		/*
+		 * Chain mbuf into pcbopts.
+		 */
+		m->m_next = *pcbopts;
+		if (*pcbopts)
+			m->m_pkthdr.len = (*pcbopts)->m_pkthdr.len;
+		else
+			m->m_pkthdr.len = 0;
+		*pcbopts = m;
+
+		/*
+		 * Save option.
+		 */
+		m->m_pkthdr.pktype = nh;
+		m->m_pkthdr.len += len;
+		m->m_len = len;
+		bcopy((caddr_t)cp, mtod(m, caddr_t), len);
+		if (m->m_pkthdr.pktype == IP6_NHDR_RT) {
+			m->m_pkthdr.len -= sizeof(struct in6_addr);
+			m->m_len -= sizeof(struct in6_addr);
+		}
+		cp += len;
+
+	}
+done:
+	m_free(m0);
+	return (error);
+}
+
+/*
+ * Get IPv6 options from pcb for user getsockopt() et IP_RECVOPTS.
+ */
+int
+ip6_getoptions(pcbopts, mp, control)
+	register struct mbuf *pcbopts;
+	register struct mbuf **mp;
+	int control;
+{
+	register u_int len = sizeof(struct in6_addr);
+	register struct mbuf *m;
+	register caddr_t cp;
+	int error = 0;
+
+	if (pcbopts)
+		len += pcbopts->m_pkthdr.len;
+	if (control)
+		len += sizeof(struct cmsghdr);
+	if (len > MCLBYTES)
+		return (EMSGSIZE);
+	
+	*mp = m = m_get(M_WAIT, MT_SOOPTS);
+	if (m == 0)
+		return (ENOBUFS);
+	if (len > MLEN) {
+		MCLGET(m, M_WAIT);
+		if ((m->m_flags & M_EXT) == 0)
+			return (ENOBUFS);
+	}
+	cp = mtod(m, caddr_t) + len;
+	len -= sizeof(struct in6_addr);
+	if (control)
+		len -= sizeof(struct cmsghdr);
+	m->m_len = len;
+	while (pcbopts) {
+		register int optlen = pcbopts->m_len;
+
+#ifdef DIAGNOSTIC
+		if (pcbopts->m_pkthdr.len != len)
+			panic("ip6_getoptions (hdr)");
+#endif
+		if (pcbopts->m_pkthdr.pktype == IP6_NHDR_RT) {
+			optlen += sizeof(struct in6_addr);
+			len += sizeof(struct in6_addr);
+			m->m_len += sizeof(struct in6_addr);
+		}
+		if (optlen > len)
+			panic("ip6_getoptions (big)");
+		bcopy(mtod(pcbopts, caddr_t), (caddr_t)cp - optlen, optlen);
+		cp -= optlen;
+		*cp = pcbopts->m_pkthdr.pktype;
+		len -= optlen;
+		pcbopts = pcbopts->m_next;
+	}
+#ifdef DIAGNOSTIC
+	if (len != 0)
+		panic("ip6_getoptions (lost)");
+#endif
+	return (error);
+}
+
+/*
+ * Set the IPv6 multicast options in response to user setsockopt().
+ */
+static int
+ip6_setmoptions(inp, optname, m)
+	struct inpcb *inp;
+	int optname;
+	struct mbuf *m;
+{
+	struct ip_moptions **imop = &inp->inp_moptions;
+	register int error = 0;
+	u_int loop;
+	register int i;
+	struct in6_addr addr;
+	unsigned int index;
+	struct in6_ifaddr *ia;
+	register struct ipv6_mreq *mreq;
+	register struct oipv6_mreq *omreq;
+	register struct ifnet *ifp = 0;
+	register struct ip_moptions *imo = *imop;
+	union route_6 iproute6;
+#define ro	iproute6.route
+	register struct sockaddr_in6 *dst;
+	int s;
+
+#if (MULTI_HOMED > 0)
+	if (inp->inp_ifa) {
+		ifp = inp->inp_ifa->ifa_ifp;
+		if ((ifp->if_flags & IFF_MULTICAST) == 0) {
+			IFAFREE(inp->inp_ifa);
+			inp->inp_ifa = NULL;
+			ifp = NULL;
+		}
+	}
+#endif
+	if (imo == NULL) {
+		/*
+		 * No multicast option buffer attached to the pcb;
+		 * allocate one and initialize to default values.
+		 */
+		imo = (struct ip_moptions *)malloc(sizeof(*imo), M_IPMOPTS,
+		    M_WAITOK);
+
+		if (imo == NULL)
+			return (ENOBUFS);
+		*imop = imo;
+		imo->imo_multicast_ifp = ifp;
+		imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
+		imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
+		imo->imo_num_memberships = 0;
+	}
+
+	switch (optname) {
+
+	case IPV6_MULTICAST_IF:
+		/*
+		 * Select the interface for outgoing multicast packets.
+		 */
+		if (m == NULL) {
+			error = EINVAL;
+			break;
+		}
+		if (m->m_len == sizeof(unsigned int)) {
+		    if (ifp) {
+			error = EADDRINUSE;
+			break;
+		    }
+		    index = *mtod(m, unsigned int *);
+		    /*
+		     * zero index is used to remove a previous selection.
+		     * When no interface is selected, a default one is
+		     * chosen every time a multicast packet is sent.
+		     */
+		    if (index == 0) {
+			imo->imo_multicast_ifp = NULL;
+			break;
+		    }
+		    /*
+		     * The selected interface is identified by its index.
+		     * Find the interface and confirm that it supports
+		     * IPv6 and multicasting.
+		     */
+		    s = splimp();
+		    for (ia = in6_ifaddrhead.tqh_first;
+			 ia && (ifp = ia->ia_ifp)->if_index != index;
+			 ia = ia->ia_list.tqe_next)
+			continue;
+		    if (ia == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
+			splx(s);
+			error = EADDRNOTAVAIL;
+			break;
+		    }
+		    imo->imo_multicast_ifp = ifp;
+		} else if (m->m_len == sizeof(struct in6_addr)) {
+		    if (ifp) {
+			error = EADDRINUSE;
+			break;
+		    }
+		    COPY_ADDR6(*mtod(m, struct in6_addr *), addr);
+		    /*
+		     * unspec address is used to remove a previous selection.
+		     * When no interface is selected, a default one is
+		     * chosen every time a multicast packet is sent.
+		     */
+		    if (IS_ANYADDR6(addr)) {
+			imo->imo_multicast_ifp = NULL;
+			break;
+		    }
+		    /*
+		     * The selected interface is identified by its local
+		     * IPv6 address.  Find the interface and confirm that
+		     * it supports multicasting.
+		     */
+		    s = splimp();
+		    IN6ADDR_TO_IFP(addr, ifp);
+		    if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
+			splx(s);
+			error = EADDRNOTAVAIL;
+			break;
+		    }
+		    imo->imo_multicast_ifp = ifp;
+		} else {
+			error = EINVAL;
+			break;
+		}
+		splx(s);
+		break;
+
+	case IPV6_MULTICAST_HOPS:
+		/*
+		 * Set the IP time-to-live for outgoing multicast packets.
+		 */
+		if (m == NULL ||
+		    (m->m_len != 1 && m->m_len != sizeof(int))) {
+			error = EINVAL;
+			break;
+		}
+		if (m->m_len == sizeof(int)) {
+			int optval = *(mtod(m, int *));
+
+			if (optval == -1)
+				optval = IP_DEFAULT_MULTICAST_TTL;
+			if ((optval < 0) || (optval > MAXTTL)) {
+				error = EINVAL;
+				break;
+			}
+			imo->imo_multicast_ttl = optval;
+		} else
+			imo->imo_multicast_ttl = *(mtod(m, u_char *));
+		break;
+
+	case IPV6_MULTICAST_LOOP:
+		/*
+		 * Set the loopback flag for outgoing multicast packets.
+		 * Must be zero or one.
+		 */
+		if (m == NULL ||
+		    (m->m_len != 1 && m->m_len != sizeof(u_int))) {
+			error = EINVAL;
+			break;
+		}
+		if (m->m_len == sizeof(u_int))
+			loop = *(mtod(m, u_int *));
+		else
+			loop = *(mtod(m, u_char *));
+		if (loop > 1) {
+			error = EINVAL;
+			break;
+		}
+		imo->imo_multicast_loop = loop;
+		break;
+
+	case IPV6_ADD_MEMBERSHIP:
+		/*
+		 * Add a multicast group membership.
+		 * Group must be a valid IPv6 multicast address.
+		 */
+		if (m == NULL) {
+			error = EINVAL;
+			break;
+		}
+		if (m->m_len == sizeof(struct oipv6_mreq)) {
+		    omreq = mtod(m, struct oipv6_mreq *);
+		    if (!IS_MULTIADDR6(omreq->ipv6mr_multiaddr)) {
+			error = EINVAL;
+			break;
+		    }
+		    s = splimp();
+		    /*
+		     * If no interface address was provided,
+		     * use the interface of the route to the
+		     * given multicast address.
+		     */
+		    if (IS_ANYADDR6(omreq->ipv6mr_interface)) {
+			bzero((caddr_t)&ro, sizeof(iproute6));
+			dst = satosin6(&ro.ro_dst);
+			dst->sin6_len = sizeof(*dst);
+			dst->sin6_family = AF_INET6;
+			COPY_ADDR6(omreq->ipv6mr_multiaddr, dst->sin6_addr);
+			rtalloc(&ro);
+			if (ro.ro_rt == NULL) {
+			    error = EADDRNOTAVAIL;
+			    splx(s);
+			    break;
+			}
+			ifp = ro.ro_rt->rt_ifp;
+			rtfree(ro.ro_rt);
+		    }
+		    else {
+			IN6ADDR_TO_IFP(omreq->ipv6mr_interface, ifp);
+		    }
+		    /*
+		     * See if we found an interface, and confirm that it
+		     * supports multicast.
+		     */
+		    if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
+			splx(s);
+			error = EADDRNOTAVAIL;
+			break;
+		    }
+		    /*
+		     * See if the membership already exists or if all the
+		     * membership slots are full.
+		     */
+		    for (i = 0; i < imo->imo_num_memberships; ++i) {
+			register struct in6_multi *inm =
+			    (struct in6_multi *)imo->imo_membership[i];
+
+			if (inm->inm6_ifp == ifp &&
+			    SAME_ADDR6(inm->inm6_addr,
+				       omreq->ipv6mr_multiaddr))
+			    break;
+		    }
+		    if (i < imo->imo_num_memberships) {
+			error = EADDRINUSE;
+			splx(s);
+			break;
+		    }
+		    if (i == IP_MAX_MEMBERSHIPS) {
+			error = ETOOMANYREFS;
+			splx(s);
+			break;
+		    }
+		    /*
+		     * Everything looks good; add a new record to the multicast
+		     * address list for the given interface.
+		     */
+		    if ((imo->imo_membership[i] = (struct in_multi *)
+			in6_addmulti(&omreq->ipv6mr_multiaddr, ifp)) == NULL) {
+			error = ENOBUFS;
+			splx(s);
+			break;
+		    }
+		    ++imo->imo_num_memberships;
+		    splx(s);
+		} else if (m->m_len == sizeof(struct ipv6_mreq)) {
+		    mreq = mtod(m, struct ipv6_mreq *);
+		    if (!IS_MULTIADDR6(mreq->ipv6mr_multiaddr)) {
+			error = EINVAL;
+			break;
+		    }
+		    s = splimp();
+		    /*
+		     * If interface index is zero
+		     * use the interface of the route to the
+		     * given multicast address.
+		     */
+		    if (mreq->ipv6mr_interface == 0) {
+			bzero((caddr_t)&ro, sizeof(iproute6));
+			dst = satosin6(&ro.ro_dst);
+			dst->sin6_len = sizeof(*dst);
+			dst->sin6_family = AF_INET6;
+			COPY_ADDR6(mreq->ipv6mr_multiaddr, dst->sin6_addr);
+			rtalloc(&ro);
+			if (ro.ro_rt == NULL) {
+			    error = EADDRNOTAVAIL;
+			    splx(s);
+			    break;
+			}
+			ifp = ro.ro_rt->rt_ifp;
+			rtfree(ro.ro_rt);
+		    }
+		    else {
+			for (ia = in6_ifaddrhead.tqh_first; ia;
+			     ia = ia->ia_list.tqe_next) {
+			    ifp = ia->ia_ifp;
+			    if (ifp->if_index == mreq->ipv6mr_interface)
+				break;
+			}
+			if (ia == NULL)
+			    ifp = NULL;
+		    }
+		    /*
+		     * See if we found an interface, and confirm that it
+		     * supports multicast.
+		     */
+		    if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
+			splx(s);
+			error = EADDRNOTAVAIL;
+			break;
+		    }
+		    /*
+		     * See if the membership already exists or if all the
+		     * membership slots are full.
+		     */
+		    for (i = 0; i < imo->imo_num_memberships; ++i) {
+			register struct in6_multi *inm =
+			    (struct in6_multi *)imo->imo_membership[i];
+
+			if (inm->inm6_ifp == ifp &&
+			    SAME_ADDR6(inm->inm6_addr, mreq->ipv6mr_multiaddr))
+			    break;
+		    }
+		    if (i < imo->imo_num_memberships) {
+			error = EADDRINUSE;
+			splx(s);
+			break;
+		    }
+		    if (i == IP_MAX_MEMBERSHIPS) {
+			error = ETOOMANYREFS;
+			splx(s);
+			break;
+		    }
+		    /*
+		     * Everything looks good; add a new record to the multicast
+		     * address list for the given interface.
+		     */
+		    if ((imo->imo_membership[i] = (struct in_multi *)
+			in6_addmulti(&mreq->ipv6mr_multiaddr, ifp)) == NULL) {
+			error = ENOBUFS;
+			splx(s);
+			break;
+		    }
+		    ++imo->imo_num_memberships;
+		    splx(s);
+		} else
+			error = EINVAL;
+		break;
+
+	case IPV6_DROP_MEMBERSHIP:
+		/*
+		 * Drop a multicast group membership.
+		 * Group must be a valid IP multicast address.
+		 */
+		if (m == NULL) {
+			error = EINVAL;
+			break;
+		}
+		if (m->m_len == sizeof(struct oipv6_mreq)) {
+		    omreq = mtod(m, struct oipv6_mreq *);
+		    if (!IS_MULTIADDR6(omreq->ipv6mr_multiaddr)) {
+			error = EINVAL;
+			break;
+		    }
+
+		    s = splimp();
+		    /*
+		     * If an interface address was specified, get a pointer
+		     * to its ifnet structure.
+		     */
+		    if (IS_ANYADDR6(omreq->ipv6mr_interface))
+			ifp = NULL;
+		    else {
+			IN6ADDR_TO_IFP(omreq->ipv6mr_interface, ifp);
+			if (ifp == NULL) {
+			    error = EADDRNOTAVAIL;
+			    splx(s);
+			    break;
+			}
+		    }
+		    /*
+		     * Find the membership in the membership array.
+		     */
+		    for (i = 0; i < imo->imo_num_memberships; ++i) {
+			register struct in6_multi *inm =
+			    (struct in6_multi *)imo->imo_membership[i];
+
+			if ((ifp == NULL || inm->inm6_ifp == ifp) &&
+			    SAME_ADDR6(inm->inm6_addr,
+				       omreq->ipv6mr_multiaddr))
+			    break;
+		    }
+		    if (i == imo->imo_num_memberships) {
+			error = EADDRNOTAVAIL;
+			splx(s);
+			break;
+		    }
+		    /*
+		     * Give up the multicast address record to which the
+		     * membership points.
+		     */
+		    in6_delmulti((struct in6_multi *)imo->imo_membership[i]);
+		    /*
+		     * Remove the gap in the membership array.
+		     */
+		    for (++i; i < imo->imo_num_memberships; ++i)
+			imo->imo_membership[i-1] = imo->imo_membership[i];
+		    --imo->imo_num_memberships;
+		    splx(s);
+		} else if (m->m_len == sizeof(struct ipv6_mreq)) {
+		    mreq = mtod(m, struct ipv6_mreq *);
+		    if (!IS_MULTIADDR6(mreq->ipv6mr_multiaddr)) {
+			error = EINVAL;
+			break;
+		    }
+
+		    s = splimp();
+		    /*
+		     * If interface index is not zero, get a pointer
+		     * to its ifnet structure.
+		     */
+		    if (mreq->ipv6mr_interface == 0)
+			ifp = NULL;
+		    else {
+			for (ia = in6_ifaddrhead.tqh_first; ia;
+			     ia = ia->ia_list.tqe_next) {
+			    ifp = ia->ia_ifp;
+			    if (ifp->if_index == mreq->ipv6mr_interface)
+				break;
+			}
+			if (ia == NULL) {
+			    error = EADDRNOTAVAIL;
+			    splx(s);
+			    break;
+			}
+		    }
+		    /*
+		     * Find the membership in the membership array.
+		     */
+		    for (i = 0; i < imo->imo_num_memberships; ++i) {
+			register struct in6_multi *inm =
+			    (struct in6_multi *)imo->imo_membership[i];
+
+			if ((ifp == NULL || inm->inm6_ifp == ifp) &&
+			    SAME_ADDR6(inm->inm6_addr, mreq->ipv6mr_multiaddr))
+			    break;
+		    }
+		    if (i == imo->imo_num_memberships) {
+			error = EADDRNOTAVAIL;
+			splx(s);
+			break;
+		    }
+		    /*
+		     * Give up the multicast address record to which the
+		     * membership points.
+		     */
+		    in6_delmulti((struct in6_multi *)imo->imo_membership[i]);
+		    /*
+		     * Remove the gap in the membership array.
+		     */
+		    for (++i; i < imo->imo_num_memberships; ++i)
+			imo->imo_membership[i-1] = imo->imo_membership[i];
+		    --imo->imo_num_memberships;
+		    splx(s);
+		}
+		break;
+
+	default:
+		error = EOPNOTSUPP;
+		break;
+	}
+
+	/*
+	 * If all options have default values, no need to keep the mbuf.
+	 */
+	if (imo->imo_multicast_ifp == NULL &&
+	    imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&
+	    imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&
+	    imo->imo_num_memberships == 0) {
+		free(*imop, M_IPMOPTS);
+		*imop = NULL;
+	}
+
+	return (error);
+}
+
+/*
+ * Return the IPv6 multicast options in response to user getsockopt().
+ */
+static int
+ip6_getmoptions(optname, imo, mp)
+	int optname;
+	register struct ip_moptions *imo;
+	register struct mbuf **mp;
+{
+	u_int *opval;
+
+	*mp = m_get(M_WAIT, MT_SOOPTS);
+
+	switch (optname) {
+
+	case IPV6_MULTICAST_IF:
+		opval = mtod(*mp, u_int *);
+		(*mp)->m_len = sizeof(u_int);
+		if (imo == NULL || imo->imo_multicast_ifp == NULL)
+			*opval = 0;
+		else
+			*opval = imo->imo_multicast_ifp->if_index;
+		return (0);
+
+	case IPV6_MULTICAST_HOPS:
+		opval = mtod(*mp, int *);
+		(*mp)->m_len = sizeof(int);
+		*opval = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL
+				     : imo->imo_multicast_ttl;
+		return (0);
+
+	case IPV6_MULTICAST_LOOP:
+		opval = mtod(*mp, u_int *);
+		(*mp)->m_len = sizeof(u_int);
+		*opval = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP
+				      : imo->imo_multicast_loop;
+		return (0);
+
+	default:
+		return (EOPNOTSUPP);
+	}
+}
+
+/*
+ * Discard the IPv6 multicast options.
+ */
+void
+ip6_freemoptions(imo)
+	register struct ip_moptions *imo;
+{
+	register int i;
+
+	if (imo != NULL) {
+		for (i = 0; i < imo->imo_num_memberships; ++i)
+			in6_delmulti((struct in6_multi *)imo->imo_membership[i]);
+		free(imo, M_IPMOPTS);
+	}
+}
+
+/*
+ * Set the IPv6 Security options in response to user setsockopt().
+ */
+static int
+ip6_setsoptions(so, optname, m ,p)
+	struct socket *so;
+	int optname;
+	struct mbuf *m;
+	struct proc *p;
+{
+	register int error = 0;
+	register struct sockaddr_ipsec *addr;
+	register struct ipsec_req *req;
+	register struct inpcb *inp = sotoinpcb(so);
+	int s = splnet();
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY)
+		printf("ip6_setsoptions %d\n", optname);
+#endif
+	switch (optname) {
+	case IPSEC_WANTAUTH:
+		/*
+		 * This socket wants authentic packets.
+		 */
+		if (m == NULL || m->m_len != sizeof(int)) {
+			error = EINVAL;
+			break;
+		}
+		if (*mtod(m, int *))
+			inp->inp_flags |= INP_NEEDAUTH;
+		else
+			inp->inp_flags &= ~INP_NEEDAUTH;
+		break;
+
+	case IPSEC_WANTCRYPT:
+		/*
+		 * This socket wants confidential packets.
+		 */
+		if (m == NULL || m->m_len != sizeof(int)) {
+			error = EINVAL;
+			break;
+		}
+		if (*mtod(m, int *))
+			inp->inp_flags |= INP_NEEDCRYPT;
+		else
+			inp->inp_flags &= ~INP_NEEDCRYPT;
+		break;
+
+	case IPSEC_CREATE:
+		/*
+		 * Create a new key entry.
+		 */
+		if (m == NULL || m->m_len < sizeof(struct ipsec_req)) {
+			error = EINVAL;
+			break;
+		}
+		req = mtod(m, struct ipsec_req *);
+		if (m->m_len < sizeof(*req) + req->ipr_klen) {
+			error = EINVAL;
+			break;
+		}
+		if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0)
+			break;
+		error = ipsec_create(req);
+		break;
+
+	case IPSEC_CHANGE:
+		/*
+		 * Change a key entry.
+		 */
+		if (m == NULL || m->m_len < sizeof(struct ipsec_req)) {
+			error = EINVAL;
+			break;
+		}
+		req = mtod(m, struct ipsec_req *);
+		if (m->m_len < sizeof(*req) + req->ipr_klen) {
+			error = EINVAL;
+			break;
+		}
+		if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0)
+			break;
+		error = ipsec_change(req);
+		break;
+
+	case IPSEC_DELETE:
+		/*
+		 * Delete a key entry.
+		 */
+		if (m == NULL || m->m_len != sizeof(struct sockaddr_ipsec)) {
+			error = EINVAL;
+			break;
+		}
+		addr = mtod(m, struct sockaddr_ipsec *);
+		if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0)
+			break;
+		error = ipsec_delete(addr);
+		break;
+
+	case IPSEC_ATTACH:
+	case IPSEC_ATTACHX:
+		/*
+		 * Attach a key entry to a socket (shared/exclusive use).
+		 */
+		if (m == NULL || m->m_len != sizeof(struct sockaddr_ipsec)) {
+			error = EINVAL;
+			break;
+		}
+		addr = mtod(m, struct sockaddr_ipsec *);
+		error = ipsec_attach(inp, addr,
+			    optname == IPSEC_ATTACHX ? IPSEC_EXCLUSIVE : 0);
+		break;
+
+	case IPSEC_ATTACHW:
+		/*
+		 * Attach the "wildcard" key entry to a socket.
+		 */
+		inp = sotoinpcb(so);
+		error = ipsec_attach(inp, NULL, IPSEC_WILDCARD);
+		break;
+
+	case IPSEC_DETACH:
+	case IPSEC_DETACHX:
+		/*
+		 * Detach a key entry from a socket (shared/exclusive use).
+		 */
+		if (m == NULL || m->m_len != sizeof(struct sockaddr_ipsec)) {
+			error = EINVAL;
+			break;
+		}
+		addr = mtod(m, struct sockaddr_ipsec *);
+		error = ipsec_detach(inp, addr,
+			    optname == IPSEC_DETACHX ? IPSEC_EXCLUSIVE : 0);
+		break;
+
+	case IPSEC_DETACHW:
+		/*
+		 * Detach the "wildcard" key entry from a socket.
+		 */
+		error = ipsec_detach(inp, NULL, IPSEC_WILDCARD);
+		break;
+
+	default:
+		error = EOPNOTSUPP;
+		break;
+	}
+	if (m)
+		(void) m_free(m);
+	splx(s);
+	return (error);
+}
+
+/*
+ * Return the IPv6 Security options in response to user getsockopt().
+ */
+static int
+ip6_getsoptions(inp, optname, mp)
+	struct inpcb *inp;
+	int optname;
+	struct mbuf **mp;
+{
+	int *flags;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY)
+		printf("ip6_getsoptions %d\n", optname);
+#endif
+	*mp = m_get(M_WAIT, MT_SOOPTS);
+
+	switch (optname) {
+	case IPSEC_WANTAUTH:
+		flags = mtod(*mp, int *);
+		(*mp)->m_len = sizeof(int);
+		*flags = (inp->inp_flags & INP_NEEDAUTH) == INP_NEEDAUTH;
+		return (0);
+
+	case IPSEC_WANTCRYPT:
+		flags = mtod(*mp, int *);
+		(*mp)->m_len = sizeof(int);
+		*flags = (inp->inp_flags & INP_NEEDCRYPT) == INP_NEEDCRYPT;
+		return (0);
+
+	default:
+		return (EOPNOTSUPP);
+	}
+}
+
+/*
+ * Discard the IPv6 security options.
+ */
+void
+ip6_freesoptions(inp)
+	register struct inpcb *inp;
+{
+	register struct ip_seclist *isl;
+
+	while ((isl = inp->inp_soptions.lh_first) != 0) {
+		LIST_REMOVE(isl, isl_list);
+		if (isl->isl_iep)
+			isl->isl_iep->ieh_refcnt--;
+		free(isl, M_IPMOPTS);
+	}
+}
+
+/*
+ * Routine called from ip6_output() to loop back a copy of an IPv6 multicast
+ * packet to the input queue of a specified interface.  Note that this
+ * calls the output routine of the loopback "driver", but with an interface
+ * pointer that might NOT be a loopback interface -- evil, but easier than
+ * replicating that code here.
+ */
+static void
+ip6_mloopback(ifp, m, opts, dst)
+	struct ifnet *ifp;
+	register struct mbuf *m, *opts;
+	register struct sockaddr_in6 *dst;
+{
+	register struct ipv6 *ip;
+	struct mbuf *copym;
+
+	copym = m_copy(m, 0, M_COPYALL);
+	if (copym != NULL && copym->m_flags & M_EXT)
+		copym = m_pullup(copym, sizeof(struct ipv6));
+	if (copym != NULL) {
+		while (opts) {
+			copym = ip6_insertoption(copym, opts, NULL, 0);
+			opts = opts->m_next;
+		}
+		/*
+		 * We don't bother to fragment if the IPv6 length is greater
+		 * than the interface's MTU.  Can this possibly matter?
+		 */
+		ip = mtod(copym, struct ipv6 *);
+		ip->ip6_len = htons((u_int16_t)ip->ip6_len);
+		/* can you call directly ip6_input ??? */
+		(void) looutput(ifp, copym, sin6tosa(dst), NULL);
+	} else
+		ip6stat.ip6s_odropped++;
+}
diff -uN src-current/sys/netinet/ip6_var.h src-current-ipv6/sys/netinet/ip6_var.h
--- src-current/sys/netinet/ip6_var.h
+++ src-current-ipv6/sys/netinet/ip6_var.h
@@ -0,0 +1,245 @@
+/*
+ * 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_var.h	8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _NETINET_IP6_VAR_H_
+#define _NETINET_IP6_VAR_H_
+
+/*
+ * Overlay for IPv6 header used for checksum by other protocols.
+ */
+struct ip6ovck {
+	u_int32_t ih6_wrd0;			/* first word */
+	union {
+		u_int32_t ihuw6_wrd1;		/* second word */
+		struct {
+			u_int8_t  ihu6_x;	/* reserved (0) */
+			u_int8_t  ihu6_pr;	/* protocol */
+			u_int16_t ihu6_len;	/* payload length */
+		} ihus6_wrd1;
+	} ihu6_wrd1;
+};
+#define ih6_wrd1	ihu6_wrd1.ihuw6_wrd1
+#define ih6_x		ihu6_wrd1.ihus6_wrd1.ihu6_x
+#define ih6_pr		ihu6_wrd1.ihus6_wrd1.ihu6_pr
+#define ih6_len		ihu6_wrd1.ihus6_wrd1.ihu6_len
+
+/*
+ * Structure for ctlinput routines.
+ */
+struct ctli_arg {
+	struct ipv6 *ctli_ip;
+	struct mbuf *ctli_m;
+};
+
+/*
+ * IPv6 reassembly queue structure.  Each fragment
+ * being reassembled is attached to one of these structures.
+ * They are timed out after ipq_ttl drops to 0, and may also
+ * be reclaimed if memory becomes tight.
+ */
+struct ip6q {
+	struct	  ip6q *next, *prev;	/* to other reass headers */
+	u_int8_t  ip6q_ttl;		/* time for reass q to live */
+	u_int8_t  ip6q_nh;		/* next header type of this fragment */
+	u_int16_t ip6q_spare;		/* for alignment */
+	u_int32_t ip6q_id;		/* sequence id for reassembly */
+	struct	  ip6asfrag *ip6q_next, *ip6q_prev;
+					/* to IPv6 headers of fragments */
+	struct	  in6_addr ip6q_src, ip6q_dst;
+};
+
+/*
+ * IPv6 header, when holding a fragment.
+ *
+ * Note: ip6f_next must be at same offset as ip6q_next above
+ */
+struct	ip6asfrag {
+	u_int32_t ip6f_head;		/* next */
+	u_int16_t ip6f_len;		/* prev */
+	u_int8_t  ip6f_nh;
+	u_int8_t  ip6f_hlim;
+	u_int32_t ip6f_w2;		/* ttl/nh */
+	u_int32_t ip6f_w3;		/* id */
+	struct	  ip6asfrag *ip6f_next;	/* ip6q_next */
+	struct	  ip6asfrag *ip6f_prev;	/* ip6q_prev */
+	struct	  in6_addr ip6f_dst;
+	u_int8_t  ip6f_fnh;		/* fragment header */
+	u_int8_t  ip6f_mff;
+	u_int16_t ip6f_off;
+	u_int32_t ip6f_id;
+};
+
+struct	ip6stat {
+	u_long	ip6s_total;		/* total packets received */
+	u_long	ip6s_tooshort;		/* packet too short */
+	u_long	ip6s_toosmall;		/* not enough data */
+	u_long	ip6s_inomem;		/* no more memory on input */
+	u_long	ip6s_fragments;		/* fragments received */
+	u_long	ip6s_fragdropped;	/* fragments dropped */
+	u_long	ip6s_fragtimeout;	/* fragments timed out */
+	u_long	ip6s_forward;		/* packets forwarded */
+	u_long	ip6s_cantforward;	/* packets rcvd for unreachable dest */
+	u_long	ip6s_badsource;		/* packets rcvd from bad sources */
+	u_long	ip6s_noproto;		/* unknown or unsupported protocol */
+	u_long	ip6s_delivered;		/* datagrams delivered to upper level*/
+	u_long	ip6s_inhist[256];	/* input histogram */
+	u_long	ip6s_localout;		/* total ipv6 packets generated here */
+	u_long	ip6s_onomem;		/* no more memory on output */
+	u_long	ip6s_odropped;		/* lost packets due to nobufs, etc. */
+	u_long	ip6s_reassembled;	/* total packets reassembled ok */
+	u_long	ip6s_fragmented;	/* datagrams successfully fragmented */
+	u_long	ip6s_ofragments;	/* output fragments created */
+	u_long	ip6s_noroute;		/* packets discarded due to no route */
+	u_long	ip6s_badvers;		/* ipv6 version != 6 */
+	u_long	ip6s_rawout;		/* total raw ipv6 packets generated */
+	u_long	ip6s_toobig;		/* not forwarded because size > MTU */
+};
+
+#if defined(KERNEL) && defined(INET6)
+
+/*
+ * MULTI_HOMED:
+ *  0: no multi-homed support
+ *  1: old (ie loose & buggy) multi-homed support
+ *  2: strict (and correct) multi-homed support
+ *  3: strict multi-homed and multi-sited support
+ */
+
+#ifndef MULTI_HOMED
+#define MULTI_HOMED	0
+#endif
+
+#if ((MULTI_HOMED < 0) || (MULTI_HOMED > 3))
+MULTI_HOMED should be 0, 1, 2 or 3 !!!
+#endif
+
+#define IP6_DONTFRAG	0x4		/* ip6_output must not fragment */
+
+#define IP6_INSOPT_NOALLOC	1
+#define IP6_INSOPT_RAW		2
+
+struct inpcb;
+struct route;
+
+extern struct	  ip6stat ip6stat;
+extern u_int32_t  ip6_id;		/* IPv6 packet ctr, for ids */
+
+extern int	  ip6printfs;
+#define D6_INPUT	0x00000001
+#define D6_CTLIN	0x00000002
+#define D6_MCASTIN	0x00000004
+#define D6_REASS	0x00000008
+#define D6_OPTIN	0x00000010
+#define D6_ETHERIN	0x00000020
+#define D6_SITIN	0x00000040
+#define D6_FORWARD	0x00000080
+#define D6_OUTPUT	0x00000100
+#define D6_CTLOUT	0x00000200
+#define D6_MCASTOUT	0x00000400
+#define D6_FRAG		0x00000800
+#define D6_OPTOUT	0x00001000
+#define D6_ETHEROUT	0x00002000
+#define D6_SITOUT	0x00004000
+#define D6_SITCTL	0x00008000
+#define D6_INIT		0x00010000
+#define D6_RAW		0x00020000
+#define D6_NDP0		0x00040000
+#define D6_NDP1		0x00080000
+#define D6_UDP		0x00100000
+#define D6_PMTU		0x00200000
+#define D6_TCP0		0x00400000
+#define D6_TCP1		0x00800000
+#define D6_AH		0x01000000
+#define D6_ESP		0x02000000
+#define D6_KEY		0x04000000
+#define D6_TUGCTL	0x10000000
+#define D6_BTICTL	0x10000000
+#define D6_TUGIN	0x20000000
+#define D6_BTIIN	0x20000000
+#define D6_TUGOUT	0x40000000
+#define D6_BTIOUT	0x40000000
+
+extern struct	pr_usrreqs rip6_usrreqs;
+
+void	 ah6_input __P((struct mbuf *, int));
+struct mbuf *
+	 ah6_output __P((struct mbuf *, struct mbuf *, struct ip_soptions *));
+void	 dopt6_input __P((struct mbuf *, int));
+void	 end6_input __P((struct mbuf *, int));
+void	 esp6_input __P((struct mbuf *, int));
+struct mbuf *
+	 esp6_output __P((struct mbuf *, struct mbuf *,
+			  struct ip_soptions *, int, int));
+int	 flow6_rand __P((int));
+void	 frg6_drain __P((void));
+void	 frg6_input __P((struct mbuf *, int));
+void	 frg6_slowtimo __P((void));
+int	 hd6_inoptions __P((struct mbuf *, struct mbuf *, int *));
+void	 hop6_input __P((struct mbuf *, int));
+struct mbuf *
+	 ip6_copyoptions __P((struct mbuf *, int));
+int	 ip6_ctloutput __P((int, struct socket *, int, int, struct mbuf **,
+			   struct proc *));
+struct mbuf *
+	 ip6_dropoption __P((struct mbuf *, int));
+void	 ip6_freemoptions __P((struct ip_moptions *));
+int	 ip6_getoptions __P((struct mbuf *, struct mbuf **, int));
+void	 ip6_init __P((void));
+void	 ip6_input __P((struct mbuf *, int));
+struct mbuf *ip6_insertoption
+	__P((struct mbuf *, struct mbuf *, struct ip_soptions *, int));
+int	 ip6_mforward __P((struct mbuf *, struct ifnet *));
+int	 ip6_output __P((struct mbuf *, struct mbuf *, struct route *,
+			 int, struct ip_moptions *, struct inpcb *));
+void	 ip6_savecontrol __P((struct inpcb *,
+	struct mbuf **, struct ipv6 *, struct mbuf *));
+int	 ip6_setcontrol __P((struct inpcb *, struct mbuf *, struct proc *));
+int	 ip6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));
+void	 ip6ip6_input __P((struct mbuf *, int));
+void	 ipsec_duplist __P((struct  ip_soptions *, struct  ip_soptions *));
+void	 opt6_ctlinput __P((int, struct sockaddr *, void *));
+struct mbuf *
+	 opt6_reverse __P((struct ipv6 *, struct mbuf *));
+int	 real_ip6_output __P((struct mbuf *, struct mbuf *, struct route *,
+			 int, struct ip_moptions *, struct inpcb *));
+void	 rip6_ctlinput __P((int, struct sockaddr *, void *));
+int	 rip6_ctloutput __P((int, struct socket *, int, int, struct mbuf **,
+			     struct proc *));
+void	 rip6_input __P((struct mbuf *, int));
+int	 rip6_output __P((struct mbuf *, struct socket *, struct in6_addr *));
+void	 rt6_input __P((struct mbuf *, int));
+#endif
+
+#endif
diff -uN src-current/sys/netinet/ip_mroute.c src-current-ipv6/sys/netinet/ip_mroute.c
--- src-current/sys/netinet/ip_mroute.c
+++ src-current-ipv6/sys/netinet/ip_mroute.c
@@ -30,7 +30,9 @@
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
 #include <netinet/ip_var.h>
+#include <netinet/ipsec.h>
 #include <netinet/in_var.h>
+#include <netinet/in_pcb.h>
 #include <netinet/igmp.h>
 #include <netinet/ip_mroute.h>
 #include <netinet/udp.h>
@@ -2146,6 +2148,10 @@
     static struct sockaddr_in rsvp_src = { sizeof rsvp_src, AF_INET };
     register int s;
     struct ifnet *ifp;
+    /* support IP_RECVIF used by rsvpd rel4.2a1 */
+    struct inpcb *inp;
+    struct socket *so;
+    struct mbuf *opts;
 
     if (rsvpdebug)
 	printf("rsvp_input: rsvp_on %d\n",rsvp_on);
@@ -2198,7 +2204,7 @@
     if (rsvpdebug)
 	printf("rsvp_input: check socket\n");
 
-    if (viftable[vifi].v_rsvpd == NULL) {
+    if ((so = viftable[vifi].v_rsvpd) == NULL) {
 	/* drop packet, since there is no specific socket for this
 	 * interface */
 	    if (rsvpdebug)
@@ -2213,12 +2219,23 @@
 	printf("rsvp_input: m->m_len = %d, sbspace() = %ld\n",
 	       m->m_len,sbspace(&(viftable[vifi].v_rsvpd->so_rcv)));
 
-    if (socket_send(viftable[vifi].v_rsvpd, m, &rsvp_src) < 0)
+    opts = NULL;
+    inp = (struct inpcb *)so->so_pcb;
+    if (inp->inp_flags & INP_CONTROLOPTS ||
+	inp->inp_socket->so_options & SO_TIMESTAMP)
+	ip_savecontrol(inp, &opts, ip, m);
+    if (sbappendaddr(&so->so_rcv,
+		     (struct sockaddr *)&rsvp_src, m, opts) == 0) {
+	m_freem(m);
+	if (opts)
+	    m_freem(opts);
 	if (rsvpdebug)
 	    printf("rsvp_input: Failed to append to socket\n");
-    else
+    } else {
+	sorwakeup(so);
 	if (rsvpdebug)
 	    printf("rsvp_input: send packet up\n");
+    }
     
     splx(s);
 }
diff -uN src-current/sys/netinet/ipsec.c src-current-ipv6/sys/netinet/ipsec.c
--- src-current/sys/netinet/ipsec.c
+++ src-current-ipv6/sys/netinet/ipsec.c
@@ -0,0 +1,785 @@
+/*
+ * IP Security Key routines
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/radix.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ip6_opts.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+
+struct radix_node_head *ipsec_tree;
+
+static void ipsec_real_init __P((void *));
+static void ipsec_dup1 __P((struct ip_seclist *, struct ip_soptions *));
+
+MALLOC_DECLARE(M_IPMOPTS);
+
+/*
+ * IPSEC initialization
+ */
+/* ARGSUSED */
+static void
+ipsec_real_init(v)
+	void *v;
+{
+	int s = splnet();
+
+	if (ipsec_tree == NULL)
+		rn_inithead((void **)&ipsec_tree, 16);
+	splx(s);
+}
+
+void
+ipsec_init()
+{
+	timeout(ipsec_real_init, NULL, hz);
+}
+
+/***********************************************************************
+
+		Key entry utilities
+
+***********************************************************************/
+
+/*
+ * IPSEC lookup (called at splnet)
+ */
+struct ipsec_entry_header *
+ipsec_lookup(addr, isl)
+	register struct sockaddr_ipsec *addr;
+	register struct ip_seclist *isl;
+{
+	register struct radix_node *rn;
+	register struct ipsec_entry_header *ieh;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY)
+		printf("ipsec_lookup(%p,%p)\n", addr, isl);
+#endif
+	if (ipsec_tree == NULL)
+		ipsec_real_init(0);
+	if (isl == (struct ip_seclist *)0)
+		goto wildcard;
+
+	/* lookup in the attached list */
+	for (; isl; isl = isl->isl_list.le_next) {
+		ieh = isl->isl_iep;
+		if (ieh == (struct ipsec_entry_header *)0)
+			goto wildcard;
+		if (bcmp(iehtosis(ieh), addr, sizeof(addr)) == 0) {
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_KEY)
+				printf("ipsec_lookup -> %p\n", ieh);
+#endif
+			ieh->ieh_refcnt++;
+			return (ieh);
+		}
+	}
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY)
+		printf("ipsec_lookup failed\n");
+#endif
+	return (struct ipsec_entry_header *)0;
+
+	/* lookup in the key entry table */
+    wildcard:
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY)
+		printf("ipsec_lookup wildcard\n");
+#endif
+	if ((rn = rn_match(addr, ipsec_tree)) &&
+	    ((rn->rn_flags & RNF_ROOT) == 0)) {
+		ieh = (struct ipsec_entry_header *)rn;
+		ieh->ieh_refcnt++;
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_KEY)
+			printf("ipsec_lookup -> %p\n", ieh);
+#endif
+		return (ieh);
+	}
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY)
+		printf("ipsec_lookup failed\n");
+#endif
+	return (struct ipsec_entry_header *)0;
+}
+
+/*
+ * IPSEC create (called at splnet)
+ */
+int
+ipsec_create(req)
+	struct ipsec_req *req;
+{
+	register struct ipsec_entry_header *ieh;
+	register struct ipsec_algo *isa;
+	register struct sockaddr_ipsec *addr;
+	struct radix_node *rn;
+	int size;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY)
+		printf("ipsec_create(%p)\n", req);
+#endif
+	isa = ipsec_getalgo(req->ipr_algo, req->ipr_addr.sis_kind,
+			    req->ipr_klen, req->ipr_ivlen);
+	if (isa == (struct ipsec_algo *)0)
+		return ESRCH;
+	size = sizeof(struct ipsec_entry_header) + req->ipr_klen;
+	ieh = (struct ipsec_entry_header *)malloc(size, M_RTABLE, M_NOWAIT);
+	if (ieh == (struct ipsec_entry_header *)0)
+		return ENOBUFS;
+	bzero(ieh, size);
+	size = sizeof(struct sockaddr_ipsec);
+	addr = (struct sockaddr_ipsec *)malloc(size, M_RTABLE, M_NOWAIT);
+	if (addr == (struct sockaddr_ipsec *)0) {
+		free(ieh, M_RTABLE);
+		return ENOBUFS;
+	}
+	bcopy((char *)&req->ipr_addr, (char *)addr, size);
+	ieh->ieh_algo = isa;
+	ieh->ieh_klen = req->ipr_klen;
+	ieh->ieh_ivlen = req->ipr_ivlen;
+	bcopy(req->ipr_key, ieh->ieh_key, ieh->ieh_klen);
+	if (ipsec_tree == NULL)
+		ipsec_real_init(0);
+	if ((rn = rn_match(addr, ipsec_tree)) &&
+	    ((rn->rn_flags & RNF_ROOT) == 0)) {
+		free(addr, M_RTABLE);
+		free(ieh, M_RTABLE);
+		return EEXIST;
+	}
+	ipsec_tree->rnh_addaddr((char *)addr, NULL,
+				ipsec_tree, ieh->ieh_nodes);
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY)
+		printf("ipsec_create -> %p\n", ieh);
+#endif
+	return 0;
+}
+
+/*
+ * IPSEC change (called at splnet)
+ */
+int
+ipsec_change(req)
+	struct ipsec_req *req;
+{
+	register struct ipsec_entry_header *ieh;
+	struct ipsec_algo *isa;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY)
+		printf("ipsec_change(%p)\n", req);
+#endif
+	ieh = ipsec_lookup(&req->ipr_addr, NULL);
+	if (ieh == (struct ipsec_entry_header *)0)
+		return ENOENT;
+	ieh->ieh_refcnt--;
+	isa = ipsec_getalgo(req->ipr_algo, req->ipr_addr.sis_kind,
+			    req->ipr_klen, req->ipr_ivlen);
+	if ((isa != ieh->ieh_algo) || (req->ipr_klen > ieh->ieh_klen))
+		return ESRCH;
+	/* security */
+	bzero(ieh->ieh_key, ieh->ieh_klen);
+	ieh->ieh_klen = req->ipr_klen;
+	ieh->ieh_ivlen = req->ipr_ivlen;
+	bcopy(req->ipr_key, ieh->ieh_key, ieh->ieh_klen);
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY)
+		printf("ipsec_change -> %p\n", ieh);
+#endif
+	return 0;
+}
+
+/*
+ * IPSEC delete (called at splnet)
+ */
+int
+ipsec_delete(addr)
+	struct sockaddr_ipsec *addr;
+{
+	register struct ipsec_entry_header *ieh;
+	register struct sockaddr_ipsec *key;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY)
+		printf("ipsec_delete(%p)\n", addr);
+#endif
+	ieh = ipsec_lookup(addr, NULL);
+	if (ieh == (struct ipsec_entry_header *)0)
+		return ENOENT;
+	ieh->ieh_refcnt--;
+	if (ieh->ieh_refcnt > 0)
+		return EBUSY;
+	key = iehtosis(ieh);
+	(void)ipsec_tree->rnh_deladdr(key, NULL, ipsec_tree);
+	/* security ! */
+	bzero(key, sizeof(struct sockaddr_ipsec));
+	free(key, M_RTABLE);
+	bzero(ieh, sizeof(struct ipsec_entry_header) + ieh->ieh_klen);
+	free(ieh, M_RTABLE);
+	return 0;
+}
+
+/*
+ * IPSEC attach
+ */
+int
+ipsec_attach(inp, addr, flags)
+	struct inpcb *inp;
+	struct sockaddr_ipsec *addr;
+	int flags;
+{
+	int s = splnet(), error = 0;
+	struct ipsec_entry_header *ieh;
+	struct ip_seclist *isl;
+
+#define	senderr(e)	{ error = (e); goto bad; }
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY)
+		printf("ipsec_attach(%p,%p,%d)\n", inp, addr, flags);
+#endif
+	if (flags & IPSEC_WILDCARD) {
+		ieh = (struct ipsec_entry_header *)0;
+		goto insert;
+	}
+	ieh = ipsec_lookup(addr, NULL);
+	if (ieh == (struct ipsec_entry_header *)0)
+		senderr(ENOENT);
+	if ((flags & IPSEC_EXCLUSIVE) && (ieh->ieh_refcnt > 1))
+		senderr(EEXIST);
+    insert:
+	isl = (struct ip_seclist *)malloc(sizeof(*isl), M_IPMOPTS, M_NOWAIT);
+	if (isl == (struct ip_seclist *)0)
+		senderr(ENOBUFS);
+	isl->isl_iep = ieh;
+	LIST_INSERT_HEAD(&inp->inp_soptions, isl, isl_list);
+	splx(s);
+	return (0);
+
+    bad:
+	if (ieh)
+		ieh->ieh_refcnt--;
+	splx(s);
+	return (error);
+}
+
+/*
+ * IPSEC detach
+ */
+int
+ipsec_detach(inp, addr, flags)
+	struct inpcb *inp;
+	struct sockaddr_ipsec *addr;
+	int flags;
+{
+	int s = splnet(), error = 0;
+	struct ipsec_entry_header *ieh;
+	struct ip_seclist *isl = inp->inp_soptions.lh_first;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY)
+		printf("ipsec_detach(%p,%p,%d)\n", inp, addr, flags);
+#endif
+	if (flags & IPSEC_WILDCARD) {
+		flags = IPSEC_WILDCARD;
+		ieh = (struct ipsec_entry_header *)0;
+		goto lookup;
+	}
+	ieh = ipsec_lookup(addr, NULL);
+	if (ieh == (struct ipsec_entry_header *)0)
+		senderr(ESRCH);
+	ieh->ieh_refcnt--;
+	if ((flags & IPSEC_EXCLUSIVE) && (ieh->ieh_refcnt != 1))
+		senderr(EEXIST);
+    lookup:
+	for (; isl; isl = isl->isl_list.le_next)
+		if (isl->isl_iep == ieh)
+			break;
+	if (isl == (struct ip_seclist *)0)
+		senderr(ENOENT);
+	ieh->ieh_refcnt--;
+	LIST_REMOVE(isl, isl_list);
+	free(isl, M_IPMOPTS);
+	if (IPSEC_EXCLUSIVE)
+		(void) ipsec_delete(iehtosis(ieh));
+    bad:
+	splx(s);
+	return (error);
+}
+
+/*
+ * IPSEC duplist (should be iterative)
+ */
+
+static void
+ipsec_dup1(isl, list)
+	register struct ip_seclist *isl;
+	struct ip_soptions *list;
+{
+	struct ipsec_entry_header *ieh;
+
+	if (isl == (struct ip_seclist *)0) {
+		list->lh_first = (struct ip_seclist *)0;
+		return;
+	}
+
+	ipsec_dup1(isl->isl_list.le_next, list);
+	ieh = isl->isl_iep;
+
+	isl = (struct ip_seclist *)malloc(sizeof(*isl), M_IPMOPTS, M_NOWAIT);
+	if (isl == (struct ip_seclist *)0) {
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_KEY)
+			printf("ipsec_dup1: malloc failed\n");
+#endif
+		return;
+	}
+	bzero(isl, sizeof(struct ip_seclist));
+	isl->isl_iep = ieh;
+	if (ieh)
+		ieh->ieh_refcnt++;
+	LIST_INSERT_HEAD(list, isl, isl_list);
+}
+
+void
+ipsec_duplist(list0, list)
+	struct ip_soptions *list0, *list;
+{
+#ifdef DIAGNOSTIC
+	register struct ip_seclist *isl;
+
+	if (ip6printfs & D6_KEY) {
+		printf("ipsec_duplist (before):");
+		for (isl = list0->lh_first; isl; isl = isl->isl_list.le_next)
+			printf(" %p/%p", isl, isl->isl_iep);
+		printf("\n");
+	}
+#endif
+	ipsec_dup1(list0->lh_first, list);
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY) {
+		printf("ipsec_duplist (after):");
+		for (isl = list->lh_first; isl; isl = isl->isl_list.le_next)
+			printf(" %p/%p", isl, isl->isl_iep);
+		printf("\n");
+	}
+#endif
+}
+
+#ifdef notyet
+void
+ipsec_duplist(list0, list)
+	struct ip_soptions *list0, *list;
+{
+	register struct ip_seclist *isl0, isl, *next;
+
+	if ((isl0 = list0->lh_first) == (struct ip_seclist *)0) {
+		list->lh_first = (struct ip_seclist *)0;
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_KEY)
+			printf("ipsec_duplist: void");
+#endif
+		return;
+	}
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY) {
+		printf("ipsec_duplist (before):");
+		for (isl = isl0; isl; isl = isl->isl_list.le_next)
+			printf(" %p/%p", isl, isl->isl_iep);
+		printf("\n");
+	}
+#endif
+
+	for (isl = 0; isl0; isl0 = isl0->isl_list.le_next) {
+		next = (struct ip_seclist *)malloc(sizeof(*isl),
+						   M_IPMOPTS, M_NOWAIT);
+		if (next == (struct ip_seclist *)0) {
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_KEY)
+				printf("ipsec_duplist: malloc failed\n");
+#endif
+			break;
+		}
+		next->isl_iep = isl0->isl_iep;
+		if (next->isl_iep)
+			next->isl_iep->ieh_refcnt++;
+		next->isl_list.le_prev = isl;
+		next->isl_list.le_next = 0;
+		isl->isl_list.le_next = next;
+		isl = next;
+	}
+	for (next = isl; isl; isl = next->isl_list.le_prev)
+		next = isl;
+	list->lh_first = isl;
+	if (isl)
+		isl->isl_list.le_prev = &list->lh_first;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY) {
+		printf("ipsec_duplist (before):");
+		for (next = isl; next; next = next->isl_list.le_next)
+			printf(" %p/%p", next, next->isl_iep);
+		printf("\n");
+#endif
+}
+#endif
+
+/*
+ * IPSEC match
+ */
+int
+ipsec_match(inp, m, opts, which)
+	struct inpcb *inp;
+	struct mbuf *m, *opts;
+	int which;
+{
+	register struct ipsec_entry_header *ieh;
+	register struct ip_seclist *isl;
+
+	if (which == INP_NEEDAUTH) {
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_AH)
+			printf("ipsec_match(%p,%p,%p,%d)\n",
+			       inp, m, opts, which);
+#endif
+		while (opts && (opts->m_pkthdr.pktype != IP6_NHDR_AUTH))
+			opts = opts->m_next;
+		if (opts == NULL)
+			return 0;
+		ieh = *mtod(opts, struct ipsec_entry_header **);
+	} else {
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_ESP)
+			printf("ipsec_match(%p,%p,%p,%d)\n",
+			       inp, m, opts, which);
+#endif
+		while (opts && (opts->m_pkthdr.pktype != IP6_NHDR_ESP))
+			opts = opts->m_next;
+		if (opts == NULL)
+			return 0;
+		ieh = *mtod(opts, struct ipsec_entry_header **);
+	}
+
+	isl = inp->inp_soptions.lh_first;
+
+	for (; isl; isl = isl->isl_list.le_next)
+		if ((isl->isl_iep == NULL) || (isl->isl_iep == ieh))
+			return 1;
+	return 0;
+}
+
+/***********************************************************************
+
+		Auth Header Utilities
+
+************************************************************************/
+
+/*
+ * Build a packet ready for authentication
+ */
+
+struct mbuf *
+ah6_build(m0, opts, way)
+	struct mbuf *m0, *opts;
+	int way;
+{
+	register struct ipv6 *ip;
+	register struct mbuf *m, *n;
+	int hlen, olen, nh, copied = sizeof(struct ipv6);
+	caddr_t p;
+
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_AH)
+		printf("ah6_build(%p,%p)\n", m0, opts);
+#endif
+	if (opts == NULL) {
+		MGETHDR(m, M_DONTWAIT, MT_HEADER);
+		if (m == NULL)
+			return NULL;
+		m->m_len = sizeof(struct ipv6);
+		bcopy(mtod(m0, caddr_t), mtod(m, caddr_t), copied);
+		n = m_copym(m0, 0, M_COPYALL, M_DONTWAIT);
+		if (n == NULL)
+			goto bad;
+		m->m_pkthdr.len = n->m_pkthdr.len;
+		m->m_next = n;
+		n->m_data += copied;
+		n->m_len -= copied;
+		n->m_pkthdr.len -= copied;
+		ip = mtod(m, struct ipv6 *);
+#ifdef NEW_IPSEC
+		ip->ip6_head = 0;
+#endif
+		ip->ip6_hlim = 0;
+		HTONS(ip->ip6_len);
+		return (m);
+	}
+
+	/* deal with opts */
+
+	hlen = sizeof(struct ipv6) + opts->m_pkthdr.len;
+
+	MGETHDR(m, M_DONTWAIT, MT_HEADER);
+	if (m == NULL)
+		return NULL;
+	m->m_len = MHLEN;
+	if (hlen > MHLEN) {
+		MCLGET(m, M_DONTWAIT);
+		if (m->m_flags & M_EXT)
+			m->m_len = MCLBYTES;
+	}
+	if (hlen > m->m_len)
+		goto bad;
+	m->m_len = hlen;
+	bcopy(mtod(m0, caddr_t), mtod(m, caddr_t), sizeof(struct ipv6));
+	p = mtod(m, caddr_t) + copied;
+	bzero(p, hlen - copied);
+	n = m_copym(m0, 0, M_COPYALL, M_DONTWAIT);
+	if (n == NULL)
+		goto bad;
+	n->m_data += copied;
+	n->m_len -= copied;
+	n->m_pkthdr.len -= copied;
+	m->m_next = n;
+	m->m_pkthdr.len = hlen + n->m_pkthdr.len;
+	ip = mtod(m, struct ipv6 *);
+#ifdef NEW_IPSEC
+	ip->ip6_head = 0;
+#endif
+	ip->ip6_hlim = 0;
+	ip->ip6_len += opts->m_pkthdr.len;
+	nh = ip->ip6_nh;
+	HTONS(ip->ip6_len);
+
+	p = mtod(m, caddr_t) + hlen;
+	while (opts) {
+		switch (opts->m_pkthdr.pktype) {
+		case IP6_NHDR_HOP: {
+			struct ipv6_h2hhdr *hp0, *hp;
+			struct opt6_any *op0, *op;
+
+			hp0 = mtod(opts, struct ipv6_h2hhdr *);
+			p -= opts->m_len;
+			hp = (struct ipv6_h2hhdr *)p;
+			hp->ih6_nh = nh;
+			nh = IP6_NHDR_HOP;
+			hp->ih6_hlen = hp0->ih6_hlen;
+			op0 = (struct opt6_any *)(hp0+1);
+			op = (struct opt6_any *)(hp+1);
+			if (op0->o6any_ext == OPT6_PAD_0)
+				olen = 1;
+			else
+				olen = op0->o6any_len + sizeof(*op0);
+			if (OPT6_RTCHANGE(op0->o6any_ext))
+				goto nexthopt;
+			else
+				bcopy(op0, op, olen);
+		    nexthopt:
+			op0 = (struct opt6_any *)((caddr_t)op0 + olen);
+			op = (struct opt6_any *)((caddr_t)op + olen);
+			if ((caddr_t)op < p + opts->m_len)
+				goto nexthopt;
+			else
+				goto nextopt;
+			}
+
+		case IP6_NHDR_RT: {
+			struct ipv6_rthdr *rp0, *rp;
+			struct in6_addr *ap0, *ap;
+			caddr_t rend;
+
+			rp0 = mtod(opts, struct ipv6_rthdr *);
+			rend = mtod(opts, caddr_t) + opts->m_len;
+			p -= opts->m_len;
+			rp = (struct ipv6_rthdr *)p;
+			rp->ir6_nh = nh;
+			nh = IP6_NHDR_RT;
+			rp->ir6_hlen = rp0->ir6_hlen;
+			rp->ir6_type = rp0->ir6_type;
+			rp->ir6_sglt = 0;
+			rp->ir6_slmsk = rp0->ir6_slmsk;
+			ap = (struct in6_addr *)(rp + 1);
+			ap0 = (struct in6_addr *)(rp0 + 1);
+			if (way == IPSEC_OUT) {
+				bcopy(rend, ap, sizeof(struct in6_addr));
+				ap++;
+				while ((caddr_t)(ap0 + 1) < rend) {
+					COPY_ADDR6(*ap0, *ap);
+					ap0++, ap++;
+				}
+				COPY_ADDR6(*ap0, ip->ip6_dst);
+			} else {
+				bcopy((caddr_t)ap0, ap,
+				      opts->m_len - sizeof(struct ipv6_rthdr));
+			}
+			goto nextopt;
+			}
+
+		case IP6_NHDR_DOPT: {
+			struct ipv6_dopthdr *dp0, *dp;
+			struct opt6_any *op0, *op;
+
+			dp0 = mtod(opts, struct ipv6_dopthdr *);
+			p -= opts->m_len;
+			dp = (struct ipv6_dopthdr *)p;
+			dp->io6_nh = nh;
+			nh = IP6_NHDR_DOPT;
+			dp->io6_hlen = dp0->io6_hlen;
+			op0 = (struct opt6_any *)((caddr_t)dp0 + 2);
+			op = (struct opt6_any *)((caddr_t)dp + 2);
+		    nextdopt:
+			if (op0->o6any_ext == OPT6_PAD_0)
+				olen = 1;
+			else
+				olen = op0->o6any_len + sizeof(*op0);
+			if (!OPT6_RTCHANGE(op0->o6any_ext))
+				bcopy(op0, op, olen);
+#ifdef OPT6_HOME_ADDR
+			if ((way == IPSEC_OUT) &&
+			    (op->o6any_ext == OPT6_HOME_ADDR)) {
+				struct in6_addr t, *ap;
+
+				ap = (struct in6_addr *)(op + 1);
+				COPY_ADDR6(ip->ip6_src, t);
+				COPY_ADDR6(*ap, ip->ip6_src);
+				COPY_ADDR6(t, *ap);
+			}
+#endif
+			op0 = (struct opt6_any *)((caddr_t)op0 + olen);
+			op = (struct opt6_any *)((caddr_t)op + olen);
+			if ((caddr_t)op < p + opts->m_len)
+				goto nextdopt;
+			else
+				goto nextopt;
+			}
+
+		case IP6_NHDR_ESP:
+			/* really buggy! */
+			goto bad;
+
+		default:
+		  	/* should not happen ? */
+			p -= opts->m_len;
+			bcopy(mtod(opts, caddr_t), p, opts->m_len);
+			*p = nh;
+			nh = opts->m_pkthdr.pktype;
+
+		   nextopt:
+			opts = opts->m_next;
+		}
+	}
+	ip->ip6_nh = nh;
+	return (m);
+    bad:
+	m_freem(m);
+	return NULL;
+}
+
+/***********************************************************************
+
+		Encryption Security Payload Header Utilities
+
+************************************************************************/
+
+/*
+ * Build a packet ready for encryption
+ */
+
+struct mbuf *
+esp6_build(m0, ivlen, padlen, nh)
+	struct mbuf *m0;
+	int ivlen, padlen, nh;
+{
+	register struct mbuf *m = 0;
+	struct mbuf *top, **np;
+	int len, srclen, dstlen = 0;
+	caddr_t p = 0;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ESP)
+		printf("esp6_build(%p,%d,%d,%d)\n", m0, ivlen, padlen, nh);
+#endif
+
+	srclen = sizeof(struct ipv6) + sizeof(struct ipv6_esphdr) + ivlen;
+	len = m0->m_pkthdr.len + padlen + 2 - srclen;
+	np = &top;
+	top = NULL;
+	while (len > 0) {
+		MGET(m, M_DONTWAIT, MT_DATA);
+		if (m == 0)
+			goto bad;
+		m->m_len = MLEN & ~7;
+		if (len > m->m_len) {
+			MCLGET(m, M_DONTWAIT);
+			if (m->m_flags & M_EXT)
+				m->m_len = MCLBYTES;
+		}
+		*np = m;
+		m->m_len = min(len, m->m_len);
+		dstlen = 0;
+		while (dstlen < m->m_len) {
+			int copy;
+
+			if (m0 == NULL)
+				goto pad;
+			copy = min(m->m_len - dstlen, m0->m_len - srclen);
+			bcopy(mtod(m0, caddr_t) + srclen,
+			      mtod(m, caddr_t) + dstlen,
+			      copy);
+			dstlen += copy;
+			srclen += copy;
+			len -= copy;
+			if (srclen == m0->m_len) {
+				m0 = m0->m_next;
+				srclen = 0;
+			}
+		}
+		np = &m->m_next;
+	}
+    pad:
+	p = mtod(m, caddr_t) + dstlen;
+	if (len != padlen + 2)
+		panic("esp6_build");
+	if (len == 0)
+		return (top);
+	for (; len > 2; len--)
+		*p++ = 0 /* (char)crypto_random() */;
+	*p++ = padlen;
+	*p = nh;
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_ESP)
+		printf("esp6_build -> %p\n", top);
+#endif
+	return (top);
+    bad:
+	if (top)
+		m_freem(top);
+	return NULL;
+}
diff -uN src-current/sys/netinet/ipsec.h src-current-ipv6/sys/netinet/ipsec.h
--- src-current/sys/netinet/ipsec.h
+++ src-current-ipv6/sys/netinet/ipsec.h
@@ -0,0 +1,122 @@
+/*
+ * IP security defines.
+ */
+
+#ifndef _NETINET_IPSEC_H_
+#define _NETINET_IPSEC_H_
+
+/* IP security pseudo-socket address (same layout than IPv6) */
+
+#define IPSEC_IN	1
+#define IPSEC_OUT	2
+
+struct sockaddr_ipsec {
+	u_int8_t	sis_len;	/* length */
+	u_int8_t	sis_family;	/* family (AF_INET*) */
+	u_int8_t	sis_way;	/* [in|out]bound */
+	u_int8_t	sis_kind;	/* AH or ESP */
+	u_int32_t	sis_spi;	/* security parameter index */
+	struct in6_addr	sis_addr;	/* (destination) address */
+};
+
+/* IP security {get,set}sockopt argument header */
+
+struct ipsec_req {
+	struct sockaddr_ipsec	ipr_addr;		/* dest & SPI */
+#define IANAMSIZ	16
+	char			ipr_algo[IANAMSIZ];	/* algorithm */
+	u_short			ipr_klen;		/* key length */
+	u_short			ipr_ivlen;		/* init vect length */
+	char			ipr_key[0];		/* key */
+};
+
+#define IPSEC_EXCLUSIVE		1	/* can't be shared */
+#define IPSEC_WILDCARD		2	/* wildcard */
+
+#define IPSEC_WANTAUTH		1	/* int */
+#define IPSEC_WANTCRYPT		2	/* int */
+#define IPSEC_CREATE		3	/* ipsec_req */
+#define IPSEC_CHANGE		4	/* ipsec_req */
+#define IPSEC_DELETE		5	/* sockaddr_ipsec */
+#define IPSEC_ATTACH		6	/* sockaddr_ipsec */
+#define IPSEC_ATTACHX		7	/* sockaddr_ipsec */
+#define IPSEC_ATTACHW		8	/* any */
+#define IPSEC_DETACH		9	/* sockaddr_ipsec */
+#define IPSEC_DETACHX		10	/* sockaddr_ipsec */
+#define IPSEC_DETACHW		11	/* any */
+
+/* IP security mbuf flags */
+
+#define M_AUTH		0x0400
+#define M_CRYPT		0x0800
+
+/* IP security entry header */
+
+struct ipsec_entry_header {
+	struct radix_node	ieh_nodes[2];	/* for radix code */
+	struct ipsec_algo	*ieh_algo;	/* algorithm */
+	int			ieh_refcnt;	/* reference counter */
+	u_long			ieh_use;	/* use counter */
+	u_short			ieh_klen;	/* key length */
+	u_short			ieh_ivlen;	/* init vector length */
+	char			ieh_key[0];	/* key */
+};
+#define iehtosis(ieh)	((struct sockaddr_ipsec *)(ieh)->ieh_nodes->rn_key)
+
+/* IP security algorithm */
+
+#define AH_ALGO		51		/* IP6_NHDR_AUTH */
+#define ESP_ALGO	50		/* IP6_NHDR_ESP */
+
+struct ipsec_algo {
+	char  *isa_name;			/* name */
+	u_char isa_type;			/* type */
+	u_char isa_index;			/* index */
+	u_char isa_mklen;			/* max key length */
+	u_char isa_mivlen;			/* max init vect length */
+	struct {				/* AH algorithms */
+		caddr_t (*ah_init) __P((struct ipsec_entry_header *));
+		caddr_t (*ah_update) __P((caddr_t, struct mbuf *));
+		void	(*ah_finish) __P((caddr_t, caddr_t,
+					  struct ipsec_entry_header *));
+		int	ah_reslen;
+	} isa_ah_algo;
+	struct {				/* ESP algorithms */
+		caddr_t (*esp_init) __P((struct ipsec_entry_header *,
+				         caddr_t));
+		caddr_t (*esp_encrypt) __P((caddr_t, struct mbuf *));
+		caddr_t (*esp_decrypt) __P((caddr_t, struct mbuf *));
+		void	(*esp_finish) __P((caddr_t));
+	} isa_esp_algo;
+};
+#define isa_ah_init	isa_ah_algo.ah_init
+#define isa_ah_update	isa_ah_algo.ah_update
+#define isa_ah_finish	isa_ah_algo.ah_finish
+#define isa_ah_reslen	isa_ah_algo.ah_reslen
+#define isa_esp_init	isa_esp_algo.esp_init
+#define isa_esp_encrypt	isa_esp_algo.esp_encrypt
+#define isa_esp_decrypt	isa_esp_algo.esp_decrypt
+#define isa_esp_finish	isa_esp_algo.esp_finish
+
+/* IP security PCB options */
+
+struct ip_seclist {
+	LIST_ENTRY(ip_seclist) isl_list;	/* chain */
+	struct ipsec_entry_header *isl_iep;	/* entry */
+};
+
+#ifdef KERNEL
+extern	struct radix_node_head *ipsec_tree;
+
+void	ipsec_init __P((void));
+struct	ipsec_entry_header *ipsec_lookup
+		__P((struct sockaddr_ipsec *, struct ip_seclist *));
+int	ipsec_create __P((struct ipsec_req *));
+int	ipsec_change __P((struct ipsec_req *));
+int	ipsec_delete __P((struct sockaddr_ipsec *));
+struct	mbuf *ah6_build __P((struct mbuf *, struct mbuf *, int));
+struct	mbuf *esp6_build __P((struct mbuf *, int, int, int));
+struct	ipsec_algo *ipsec_getalgo __P((char *, u_char, u_char, u_char));
+#endif
+
+#endif
diff -uN src-current/sys/netinet/ipsec_algo.c src-current-ipv6/sys/netinet/ipsec_algo.c
--- src-current/sys/netinet/ipsec_algo.c
+++ src-current-ipv6/sys/netinet/ipsec_algo.c
@@ -0,0 +1,226 @@
+/*
+ * IP Security Algorithm routines
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/radix.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+
+#include <netinet/md5.h>
+#include <netinet/sha.h>
+#include <netinet/des.h>
+
+/*
+ * Dummy Authentication (do nothing, for tests)
+ */
+
+caddr_t dummy_ah_init __P((struct ipsec_entry_header *));
+caddr_t dummy_ah_update __P((caddr_t, struct mbuf *));
+void dummy_ah_finish __P((caddr_t, caddr_t, struct ipsec_entry_header *));
+
+caddr_t
+dummy_ah_init(ieh)
+	struct ipsec_entry_header *ieh;
+{
+	return (caddr_t)1;
+}
+
+caddr_t
+dummy_ah_update(state, m)
+	caddr_t state;
+	struct mbuf *m;
+{
+	return NULL;
+}
+
+void
+dummy_ah_finish(state, result, ieh)
+	caddr_t state, result;
+	struct ipsec_entry_header *ieh;
+{
+	return;
+}
+
+/*
+ * Checksum authentication (for tests)
+ */
+
+caddr_t cksum_ah_init __P((struct ipsec_entry_header *));
+caddr_t cksum_ah_update __P((caddr_t, struct mbuf *));
+void cksum_ah_finish __P((caddr_t, caddr_t, struct ipsec_entry_header *));
+
+caddr_t
+cksum_ah_init(ieh)
+	struct ipsec_entry_header *ieh;
+{
+	register u_short *ctx;
+
+	ctx = (u_short *)malloc(sizeof(*ctx), M_TEMP, M_NOWAIT);
+	if (ctx == (u_short *)0)
+		return NULL;
+	*ctx = 0;
+	return (caddr_t)ctx;
+}
+
+caddr_t
+cksum_ah_update(state, m)
+	caddr_t state;
+	struct mbuf *m;
+{
+	register u_short *ctx = (u_short *)state;
+	int c;
+
+	c = in_cksum(m, m->m_pkthdr.len);
+	*ctx = htons((u_short)c);
+	return (caddr_t)ctx;
+}
+
+void
+cksum_ah_finish(state, result, ieh)
+	caddr_t state, result;
+	struct ipsec_entry_header *ieh;
+{
+	register u_short *ctx = (u_short *)state;
+
+	bcopy(ctx, result, sizeof(*ctx));
+	free(ctx, M_TEMP);
+}
+
+/*
+ * Keyed MD5 (RFC 1828)
+ */
+
+
+/*
+ * Keyed SHA (RFC 1952)
+ */
+
+
+/*
+ * HMAC MD5 (RFC 2085)
+ */
+
+
+/*
+ * HMAC SHA
+ */
+
+
+/*
+ * Dummy Encryption (do nothing, for tests)
+ */
+
+caddr_t dummy_esp_init __P((struct ipsec_entry_header *, caddr_t));
+caddr_t dummy_esp_encrypt __P((caddr_t, struct mbuf *));
+caddr_t dummy_esp_decrypt __P((caddr_t, struct mbuf *));
+void dummy_esp_finish __P((caddr_t));
+
+caddr_t
+dummy_esp_init(ieh, iv)
+	struct ipsec_entry_header *ieh;
+	caddr_t iv;
+{
+	return (caddr_t)1;
+}
+
+caddr_t
+dummy_esp_encrypt(state, m)
+	caddr_t state;
+	struct mbuf *m;
+{
+	return NULL;
+}
+
+caddr_t
+dummy_esp_decrypt(state, m)
+	caddr_t state;
+	struct mbuf *m;
+{
+	return NULL;
+}
+
+void
+dummy_esp_finish(state)
+	caddr_t state;
+{
+	return;
+}
+
+/*
+ * DES and Triple DES CBC (RFC 1829/1851)
+ */
+
+
+/*
+ * Algorithm table
+ */
+
+struct ipsec_algo ipsec_algo[] = {
+	/* dummy AH */
+  { "NONE-AH",	AH_ALGO,	0,	16,		0,
+   {dummy_ah_init,   dummy_ah_update,   dummy_ah_finish,   0},
+   {0,               0,                 0,                 0}},
+	/* checksum */
+  { "CHECKSUM",	AH_ALGO,	1,	16,		0,
+   {cksum_ah_init,   cksum_ah_update,   cksum_ah_finish,   2},
+   {0,               0,                 0,                 0}},
+	/* keyed MD5 */
+	/* HMAC MD5 */
+	/* dummy ESP */
+  { "NONE-ESP",	ESP_ALGO,	0,	16,		4,
+   {0,               0,                 0,                 0},
+   {dummy_esp_init,  dummy_esp_encrypt, dummy_esp_decrypt, dummy_esp_finish}},
+	/* DES CBC */
+	/* end of list */
+  { NULL,	0,		-1,	0,	0 }
+};
+
+/*
+ * Lookup algorithm routine
+ */
+
+struct ipsec_algo *
+ipsec_getalgo(name, type, klen, ivlen)
+	char *name;
+	u_char type, klen, ivlen;
+{
+	register struct ipsec_algo *isa;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_KEY)
+		printf("ipsec_getalgo(%s,%d,%d,%d)\n",
+		       name, type, klen, ivlen);
+#endif
+	for (isa = ipsec_algo; isa->isa_name; isa++) {
+		if (type != isa->isa_type)
+			continue;
+		if (strncmp(name, isa->isa_name, IANAMSIZ) == 0)
+			break;
+	}
+	if (isa && klen <= isa->isa_mklen &&
+	    ((isa->isa_type == AH_ALGO) || (klen == isa->isa_mklen)) &&
+	    ivlen <= isa->isa_mivlen) {
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_KEY)
+			printf("ipsec_getalgo -> %p\n", isa);
+#endif
+		return isa;
+	}
+	return (struct ipsec_algo *)0;
+}
diff -uN src-current/sys/netinet/md5.c src-current-ipv6/sys/netinet/md5.c
--- src-current/sys/netinet/md5.c
+++ src-current-ipv6/sys/netinet/md5.c
@@ -0,0 +1,26 @@
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ * from FreeBSD /usr/src/lib/libmd
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
diff -uN src-current/sys/netinet/md5.h src-current-ipv6/sys/netinet/md5.h
--- src-current/sys/netinet/md5.h
+++ src-current-ipv6/sys/netinet/md5.h
@@ -0,0 +1,38 @@
+/* MD5.H - header file for MD5C.C
+ * from FreeBSD /usr/src/lib/libmd
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+#ifndef _NETINET_MD5_H_
+#define _NETINET_MD5_H_
+
+/* MD5 context. */
+typedef struct {
+  unsigned long state[4];	/* state (ABCD) */
+  unsigned long count[2];	/* number of bits, modulo 2^64 (lsb first) */
+  unsigned char buffer[64];	/* input buffer */
+} MD5_CTX;
+
+
+#endif
diff -uN src-current/sys/netinet/raw_ip.c src-current-ipv6/sys/netinet/raw_ip.c
--- src-current/sys/netinet/raw_ip.c
+++ src-current-ipv6/sys/netinet/raw_ip.c
@@ -34,6 +34,8 @@
  *	$Id: raw_ip.c,v 1.54 1998/05/15 20:11:34 wollman Exp $
  */
 
+#include "opt_inet6.h"
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
@@ -54,6 +56,10 @@
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif
+#include <netinet/ipsec.h>
 #include <netinet/in_pcb.h>
 #include <netinet/in_var.h>
 #include <netinet/ip_var.h>
@@ -68,8 +74,8 @@
 #undef COMPAT_IPFW
 #endif
 
-static struct inpcbhead ripcb;
-static struct inpcbinfo ripcbinfo;
+struct inpcbhead ripcb;
+struct inpcbinfo ripcbinfo;
 
 /*
  * Nominal space allocated to a raw ip socket.
@@ -101,6 +107,7 @@
 }
 
 static struct	sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
+
 /*
  * Setup generic address and protocol structures
  * for raw_input routine, then pass them along with
@@ -118,23 +125,27 @@
 
 	ripsrc.sin_addr = ip->ip_src;
 	for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
-		if (inp->inp_ip_p && inp->inp_ip_p != ip->ip_p)
+		if (inp->inp_proto && inp->inp_proto != ip->ip_p)
 			continue;
-		if (inp->inp_laddr.s_addr &&
-                  inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
+		if ((inp->inp_flags & INP_COMPATV4) == 0)
 			continue;
-		if (inp->inp_faddr.s_addr &&
-                  inp->inp_faddr.s_addr != ip->ip_src.s_addr)
+		if (inp->inp_latype != IPATYPE_UNBD &&
+		    ((inp->inp_latype & IPATYPE_IPV4) == 0 ||
+		     inp->inp_laddr.s_addr != ip->ip_dst.s_addr))
+			continue;
+		if (inp->inp_fatype != IPATYPE_UNBD &&
+		    ((inp->inp_fatype & IPATYPE_IPV4) == 0 ||
+		     inp->inp_faddr.s_addr != ip->ip_src.s_addr))
 			continue;
 		if (last) {
 			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
+
 			if (n) {
 				if (last->inp_flags & INP_CONTROLOPTS ||
 				    last->inp_socket->so_options & SO_TIMESTAMP)
 				    ip_savecontrol(last, &opts, ip, n);
 				if (sbappendaddr(&last->inp_socket->so_rcv,
-				    (struct sockaddr *)&ripsrc, n,
-				    opts) == 0) {
+				    sintosa(&ripsrc), n, opts) == 0) {
 					/* should notify about lost packet */
 					m_freem(n);
 					if (opts)
@@ -151,7 +162,7 @@
 		    last->inp_socket->so_options & SO_TIMESTAMP)
 			ip_savecontrol(last, &opts, ip, m);
 		if (sbappendaddr(&last->inp_socket->so_rcv,
-		    (struct sockaddr *)&ripsrc, m, opts) == 0) {
+		    sintosa(&ripsrc), m, opts) == 0) {
 			m_freem(m);
 			if (opts)
 			    m_freem(opts);
@@ -191,7 +202,7 @@
 		ip = mtod(m, struct ip *);
 		ip->ip_tos = 0;
 		ip->ip_off = 0;
-		ip->ip_p = inp->inp_ip_p;
+		ip->ip_p = inp->inp_proto;
 		ip->ip_len = m->m_pkthdr.len;
 		ip->ip_src = inp->inp_laddr;
 		ip->ip_dst.s_addr = dst;
@@ -384,8 +395,8 @@
 	}
 }
 
-static u_long	rip_sendspace = RIPSNDQ;
-static u_long	rip_recvspace = RIPRCVQ;
+u_long	rip_sendspace = RIPSNDQ;
+u_long	rip_recvspace = RIPRCVQ;
 
 SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW, &rip_sendspace,
 	   0, "");
@@ -413,7 +424,8 @@
 	if (error)
 		return error;
 	inp = (struct inpcb *)so->so_pcb;
-	inp->inp_ip_p = proto;
+	inp->inp_flags = INP_COMPATV4;
+	inp->inp_proto = proto;
 	return 0;
 }
 
@@ -464,6 +476,14 @@
 	     ifa_ifwithaddr((struct sockaddr *)addr) == 0))
 		return EADDRNOTAVAIL;
 	inp->inp_laddr = addr->sin_addr;
+	if (inp->inp_laddr.s_addr != INADDR_ANY) {
+#ifdef INET6
+		inp->inp_laddr6.s6_addr32[0] = 0;
+		inp->inp_laddr6.s6_addr32[1] = 0;
+		inp->inp_laddr6.s6_addr32[2] = htonl(0xffff);
+#endif
+		inp->inp_latype = IPATYPE_IPV4;
+	}
 	return 0;
 }
 
@@ -481,6 +501,14 @@
 	    (addr->sin_family != AF_IMPLINK))
 		return EAFNOSUPPORT;
 	inp->inp_faddr = addr->sin_addr;
+	if (inp->inp_faddr.s_addr != INADDR_ANY) {
+#ifdef INET6
+		inp->inp_faddr6.s6_addr32[0] = 0;
+		inp->inp_faddr6.s6_addr32[1] = 0;
+		inp->inp_faddr6.s6_addr32[2] = htonl(0xffff);
+#endif
+		inp->inp_fatype = IPATYPE_IPV4;
+	}
 	soisconnected(so);
 	return 0;
 }
diff -uN src-current/sys/netinet/raw_ip6.c src-current-ipv6/sys/netinet/raw_ip6.c
--- src-current/sys/netinet/raw_ip6.c
+++ src-current-ipv6/sys/netinet/raw_ip6.c
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 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.
+ *
+ *	@(#)raw_ip.c	8.2 (Berkeley) 1/4/94
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/protosw.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+#include <sys/systm.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip6_icmp.h>
+#include <netinet/if_ether.h>
+#include <netinet/if_ndp6.h>
+
+#include <netinet/ip6_fw.h>
+
+extern struct inpcbhead ripcb;
+extern struct inpcbinfo ripcbinfo;
+
+MALLOC_DECLARE(M_IPMOPTS);
+
+/*
+ * Raw interface to IP protocol.
+ */
+
+static	struct sockaddr_in6 rip6src = { sizeof(rip6src), AF_INET6 };
+static	struct mbuf *raw6_saverecv __P((struct mbuf *, int));
+
+/*
+ * Setup generic address and protocol structures
+ * for raw_input routine, then pass them along with
+ * mbuf chain.
+ */
+void
+rip6_input(m, arg)
+	struct mbuf *m;
+	int arg;
+{
+	struct mbuf *opts = (struct mbuf *)arg;
+	struct ipv6 *ip = mtod(m, struct ipv6 *);
+	struct inpcb *inp;
+	struct inpcb *last = 0;
+	struct mbuf *copts = 0;
+	int ipsec_failed = 0;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_RAW)
+		printf("rip6_input(%p,%p) src %s dst %s len %d nh %d\n",
+		       m, opts,
+		       ip6_sprintf(&ip->ip6_src),
+		       ip6_sprintf(&ip->ip6_dst),
+		       ip->ip6_len,
+		       ip->ip6_nh);
+#endif
+	COPY_ADDR6(ip->ip6_src, rip6src.sin6_addr);
+	rip6src.sin6_flowinfo = ip->ip6_head & IPV6_FLOWINFO_PRIFLOW;
+	for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
+		if (inp->inp_proto && inp->inp_proto != ip->ip6_nh)
+			continue;
+		if ((inp->inp_flags & INP_COMPATV6) == 0)
+			continue;
+		if (inp->inp_latype != IPATYPE_UNBD &&
+		    ((inp->inp_latype & IPATYPE_IPV6) == 0 ||
+		     !SAME_ADDR6(inp->inp_laddr6, ip->ip6_dst)))
+			continue;
+		if (inp->inp_fatype != IPATYPE_UNBD &&
+		    ((inp->inp_fatype & IPATYPE_IPV6) == 0 ||
+		     !SAME_ADDR6(inp->inp_faddr6, ip->ip6_src)))
+			continue;
+		if ((inp->inp_flags & INP_NEEDAUTH) &&
+		    ((m->m_flags & M_AUTH) == 0 ||
+		     !ipsec_match(inp, m, opts, INP_NEEDAUTH))) {
+			ipsec_failed = 1;
+			continue;
+		}
+		if ((inp->inp_flags & INP_NEEDCRYPT) &&
+		    ((m->m_flags & M_CRYPT) == 0 ||
+		     !ipsec_match(inp, m, opts, INP_NEEDCRYPT))) {
+			ipsec_failed = 1;
+			continue;
+		}
+		if ((inp->inp_proto == IPPROTO_ICMPV6) &&
+		    icmp6_filter(inp, ip))
+			continue;
+		if (last) {
+			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
+
+#define RAW_CONTROLOPTS	\
+	(INP_RECVDSTADDR|INP_RECVIF|INP_RECVPKTINFO|INP_RECVTTL)
+			if (last->inp_flags & RAW_CONTROLOPTS)
+				copts = raw6_saverecv(m, last->inp_flags);
+			else
+				copts = (struct mbuf *)0;
+			if (n) {
+				if (sbappendaddr(&last->inp_socket->so_rcv,
+				    sin6tosa(&rip6src), n, copts) == 0) {
+					/* should notify about lost packet */
+					m_freem(n);
+					if (copts)
+						m_freem(copts);
+				} else
+					sorwakeup(last->inp_socket);
+				copts = 0;
+			}
+		}
+		last = inp;
+	}
+	if (last) {
+		if (last->inp_flags & RAW_CONTROLOPTS)
+			copts = raw6_saverecv(m, last->inp_flags);
+		else
+			copts = (struct mbuf *)0;
+		if (sbappendaddr(&last->inp_socket->so_rcv,
+			 sin6tosa(&rip6src), m, copts) == 0) {
+			m_freem(m);
+			if (copts)
+				m_freem(copts);
+		} else
+			sorwakeup(last->inp_socket);
+	} else if (ipsec_failed || ip->ip6_nh != IPPROTO_ICMPV6) {
+		ip6stat.ip6s_noproto++;
+		ip6stat.ip6s_delivered--;
+		icmp6_error(m, ICMP6_PARAMPROB, ICMP6_PARAMPROB_NH,
+			    (caddr_t)((caddr_t)&ip->ip6_nh - (caddr_t)ip));
+	} else
+		m_freem(m);
+
+	/* TODO: options */
+	if (opts)
+		m_freem(opts);
+}
+
+/*
+ * Save in a "control" mbuf received informations.
+ */
+static struct mbuf *
+raw6_saverecv(m0, flags)
+	struct mbuf *m0;
+	int flags;
+{
+	struct ipv6 *ip;
+	struct cmsghdr *cp;
+	struct mbuf *m;
+	int recval, size = 0;
+
+	if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
+		return ((struct mbuf *) NULL);
+	cp = mtod(m, struct cmsghdr *);
+	if (flags & INP_RECVDSTADDR) {
+		ip = mtod(m0, struct ipv6 *);
+		cp->cmsg_len = sizeof(*cp) + sizeof(struct in6_addr);
+		size += ALIGN(cp->cmsg_len);
+		cp->cmsg_level = IPPROTO_IP;
+		cp->cmsg_type = IP_RECVDSTADDR;
+		bcopy(&ip->ip6_dst, CMSG_DATA(cp), sizeof(struct in6_addr));
+		cp = (struct cmsghdr *)(mtod(m, caddr_t) + size);
+	} else if (flags & INP_RECVIF) {
+		recval = m0->m_pkthdr.rcvif->if_index;
+		cp->cmsg_len = sizeof(*cp) + sizeof(int);
+		size += ALIGN(cp->cmsg_len);
+		cp->cmsg_level = IPPROTO_IP;
+		cp->cmsg_type = IP_RECVIF;
+		bcopy(&recval, CMSG_DATA(cp), sizeof(int));
+		cp = (struct cmsghdr *)(mtod(m, caddr_t) + size);
+	} else if (flags & INP_RECVPKTINFO) {
+		ip = mtod(m0, struct ipv6 *);
+		recval = m0->m_pkthdr.rcvif->if_index;
+		cp->cmsg_len = sizeof(*cp) + sizeof(struct in6_pktinfo);
+		size += ALIGN(cp->cmsg_len);
+		cp->cmsg_level = IPPROTO_IPV6;
+		cp->cmsg_type = IPV6_PKTINFO;
+		bcopy(&ip->ip6_dst, CMSG_DATA(cp), sizeof(struct in6_addr));
+		bcopy(&recval,
+		      CMSG_DATA(cp) + sizeof(struct in6_addr),
+		      sizeof(int));
+		cp = (struct cmsghdr *)(mtod(m, caddr_t) + size);
+	}
+	if (flags & INP_RECVTTL) {
+		ip = mtod(m0, struct ipv6 *);
+		recval = ip->ip6_hlim;
+		cp->cmsg_len = sizeof(*cp) + sizeof(int);
+		size += ALIGN(cp->cmsg_len);
+		cp->cmsg_level = IPPROTO_IP;
+		cp->cmsg_type = IP_TTL;
+		bcopy(&recval, CMSG_DATA(cp), sizeof(int));
+	}
+	m->m_len = size;
+	return (m);
+}
+
+/*
+ * Generate IPv6 header and pass packet to ip6_output.
+ * Tack on options user may have setup with control call.
+ */
+int
+rip6_output(m, so, dst)
+	struct mbuf *m;
+	struct socket *so;
+	struct in6_addr *dst;
+{
+	struct ipv6 *ip;
+	struct inpcb *inp = sotoinpcb(so);
+	struct mbuf *opts;
+	int flags = so->so_options & SO_DONTROUTE;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_RAW)
+		printf("rip6_output(%p,%p,%s)\n", m, so, ip6_sprintf(dst));
+#endif
+	/*
+	 * If the user handed us a complete IPv6 packet, use it.
+	 * Otherwise, allocate an mbuf for a header and fill it in.
+	 */
+	if ((inp->inp_flags & INP_HDRINCL) == 0) {
+		int len = m->m_pkthdr.len;
+
+		opts = inp->inp_options;
+		if (len + (opts ? opts->m_pkthdr.len : 0) >
+				IP_MAXPACKET + sizeof(struct ipv6)) {
+			m_freem(m);
+			return(EMSGSIZE);
+		}
+		M_PREPEND(m, sizeof(struct ipv6), M_WAIT);
+		ip = mtod(m, struct ipv6 *);
+		COPY_ADDR6(inp->inp_laddr6, ip->ip6_src);
+		COPY_ADDR6(*dst, ip->ip6_dst);
+		if (inp->inp_proto == IPPROTO_ICMPV6) {
+			struct ip6ovck *ipc;
+			struct icmpv6 *icp;
+
+			if ((m = m_pullup(m, sizeof(*ip) + ICMP6_MINLEN)) == 0)
+				return(ENOBUFS);
+			ip = mtod(m, struct ipv6 *);
+			icp = (struct icmpv6 *)(ip + 1);
+			if (icp->icmp6_cksum == 0) {
+				ipc = (struct ip6ovck *)ip;
+				ipc->ih6_wrd0 = 0;
+				ipc->ih6_wrd1 = 0;
+				ipc->ih6_len = htons(len);
+				ipc->ih6_pr = IPPROTO_ICMPV6;
+				icp->icmp6_cksum =
+					in_cksum(m, m->m_pkthdr.len);
+			}
+		}
+		ip->ip6_head = inp->inp_oflowinfo | IPV6_VERSION;
+		ip->ip6_len = len;
+		ip->ip6_nh = inp->inp_proto;
+		ip->ip6_hlim = inp->inp_ttl;
+	} else {
+		ip = mtod(m, struct ipv6 *);
+		/* don't allow both user specified and setsockopt options,
+		   and don't allow packet length sizes that will crash */
+		opts = NULL;
+		NTOHS(ip->ip6_len);
+		if (ip->ip6_len + sizeof(struct ipv6) >  m->m_pkthdr.len) {
+			m_freem(m);
+			return(EMSGSIZE);
+		}
+		/* XXX prevent ip6_output from overwriting header fields */
+		flags |= IP_RAWOUTPUT;
+		ip6stat.ip6s_rawout++;
+	}
+	if (inp->inp_flags & INP_NOPROBE)
+		m->m_flags |= M_NOPROBE;
+	return (ip6_output(m, opts, &inp->inp_route, flags,
+			   inp->inp_moptions, inp));
+}
+
+/*
+ * Raw IPv6 socket option processing.
+ */
+int
+rip6_ctloutput(op, so, level, optname, m, p)
+	int op;
+	struct socket *so;
+	int level, optname;
+	struct mbuf **m;
+	struct proc *p;
+{
+	struct inpcb *inp = sotoinpcb(so);
+	int error;
+	int flag;
+
+	if ((level != IPPROTO_IP) && (level != IPPROTO_IPV6) &&
+	    ((level == IPPROTO_ICMPV6) && (optname != ICMP6_FILTER))) {
+		if (op == PRCO_SETOPT && *m != 0)
+			(void)m_free(*m);
+		return (EINVAL);
+	}
+
+	switch (optname) {
+
+	case IP_HDRINCL:
+	case IPV6_NOPROBE:
+		error = 0;
+		if (optname == IP_HDRINCL)
+			flag = INP_HDRINCL;
+		else
+			flag = INP_NOPROBE;
+		if (op == PRCO_SETOPT) {
+			if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int))
+				error = EINVAL;
+			else if (*mtod(*m, int *))
+				inp->inp_flags |= flag;
+			else
+				inp->inp_flags &= ~flag;
+			if (*m)
+				(void)m_free(*m);
+		} else {
+			*m = m_get(M_WAIT, MT_SOOPTS);
+			(*m)->m_len = sizeof (int);
+			*mtod(*m, int *) = inp->inp_flags & flag;
+		}
+		return (error);
+
+	case IP6_FW_GET:
+		if (ip6_fw_ctl_ptr == NULL || op == PRCO_SETOPT) {
+			if (*m) (void)m_freem(*m);
+			return (EINVAL);
+		}
+		return (*ip6_fw_ctl_ptr)(optname, m); 
+
+	case IP6_FW_ADD:
+	case IP6_FW_DEL:
+	case IP6_FW_FLUSH:
+	case IP6_FW_ZERO:
+		if (ip6_fw_ctl_ptr == NULL || op != PRCO_SETOPT) {
+			if (*m) (void)m_freem(*m);
+			return (EINVAL);
+		}
+		return (*ip6_fw_ctl_ptr)(optname, m); 
+
+	/* case IP6_NAT: */
+	/* case MFC6_*: */
+
+	case ICMP6_FILTER:
+		if (op == PRCO_SETOPT) {
+			if (inp->inp_proto != IPPROTO_ICMPV6)
+				error = EOPNOTSUPP;
+			else
+				error = icmp6_filter_set(inp, *m);
+			if (*m)
+				(void)m_free(*m);
+		} else if (op == PRCO_GETOPT) {
+			error = icmp6_filter_get(inp, m);
+		} else
+			error = EINVAL;
+		return (error);
+	}
+	return (ip6_ctloutput(op, so, level, optname, m, p));
+}
+
+extern u_long rip_sendspace;
+extern u_long rip_recvspace;
+
+/* ARGSUSED */
+void
+rip6_ctlinput(cmd, sa, arg)
+	int cmd;
+	struct sockaddr *sa;
+	void *arg;
+{
+	struct inpcb *inp, *oinp;
+	struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)sa;
+	int s;
+
+	if (!PRC_IS_REDIRECT(cmd))
+		return;
+	if ((sa == NULL) || (sa->sa_family != AF_INET6))
+		return;
+	if (IS_ANYSOCKADDR(dst6) || IS_IPV4SOCKADDR(dst6))
+		return;
+
+	s = splnet();
+	for (inp = ripcb.lh_first; inp != NULL;) {
+		if ((inp->inp_flags & INP_COMPATV6) == 0 ||
+		    inp->inp_socket == 0 ||
+		    inp->inp_route.ro_rt == 0 ||
+		    !SAME_ADDR6(dst6->sin6_addr, 
+			satosin6(&inp->inp_route.ro_dst)->sin6_addr)) {
+			inp = inp->inp_list.le_next;
+			continue;
+		}
+		oinp = inp;
+		inp = inp->inp_list.le_next;
+		in_rtchange(oinp, 0);
+	}
+	splx(s);
+}
+
+static int
+rip6_attach(struct socket *so, int proto, struct proc *p)
+{
+	struct inpcb *inp;
+	int error, s;
+
+	inp = sotoinpcb(so);
+	if (inp)
+		panic("rip6_attach");
+	if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0)
+		return error;
+
+	s = splnet();
+	error = in_pcballoc(so, &ripcbinfo, p);
+	splx(s);
+	if (error)
+		return error;
+	error = soreserve(so, rip_sendspace, rip_recvspace);
+	if (error)
+		return error;
+	inp = (struct inpcb *)so->so_pcb;
+	inp->inp_flags = INP_COMPATV6;
+	inp->inp_proto = proto;
+	inp->inp_ttl = MAXTTL;
+	return 0;
+}
+
+static int
+rip6_detach(struct socket *so)
+{
+	struct inpcb *inp;
+
+	inp = sotoinpcb(so);
+	if (inp == 0)
+		panic("rip6_detach");
+	in_pcbdetach(inp);
+	return 0;
+}
+
+static int
+rip6_abort(struct socket *so)
+{
+	soisdisconnected(so);
+	return rip6_detach(so);
+}
+
+static int
+rip6_disconnect(struct socket *so)
+{
+	if ((so->so_state & SS_ISCONNECTED) == 0)
+		return ENOTCONN;
+	return rip6_abort(so);
+}
+
+static int
+rip6_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
+{
+	struct inpcb *inp = sotoinpcb(so);
+	struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
+
+	if (nam->sa_len != sizeof(*addr))
+		return EINVAL;
+	if (TAILQ_EMPTY(&ifnet))
+		return EADDRNOTAVAIL;
+
+	if (addr->sin6_family != AF_INET6)
+		return EAFNOSUPPORT;
+
+	if (IS_ANYSOCKADDR(addr)) {
+		inp->inp_latype = IPATYPE_UNBD;
+	} else if (IS_IPV4SOCKADDR(addr)) {
+		return EADDRNOTAVAIL;
+	} else {
+		if (ifa_ifwithaddr(sin6tosa(addr)) == 0) {
+			return EADDRNOTAVAIL;
+		} else
+			inp->inp_latype = IPATYPE_IPV6;
+	}
+	COPY_ADDR6(addr->sin6_addr, inp->inp_laddr6);
+	return 0;
+}
+
+static int
+rip6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
+{
+	struct inpcb *inp = sotoinpcb(so);
+	struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
+
+	if (nam->sa_len != sizeof(*addr))
+		return EINVAL;
+	if (TAILQ_EMPTY(&ifnet))
+		return EADDRNOTAVAIL;
+	if (addr->sin6_family != AF_INET6)
+		return EAFNOSUPPORT;
+
+	COPY_ADDR6(addr->sin6_addr, inp->inp_faddr6);
+	if (IS_ANYSOCKADDR(addr))
+		inp->inp_fatype = IPATYPE_UNBD;
+	else if (IS_IPV4SOCKADDR(addr)) {
+		return EADDRNOTAVAIL;
+	} else {
+		inp->inp_fatype = IPATYPE_IPV6;
+	}
+	soisconnected(so);
+	return 0;
+	}
+
+static int
+rip6_shutdown(struct socket *so)
+{
+	socantsendmore(so);
+	return 0;
+}
+
+static int
+rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
+	 struct mbuf *control, struct proc *p)
+{
+	struct inpcb *inp = sotoinpcb(so);
+	register struct in6_addr *dst;
+	int error = 0;
+#if (MULTI_HOMED > 0)
+	struct ifaddr *ifa = 0;
+#endif
+	struct in6_addr laddr;
+	struct ip_moptions *imo = 0;
+	int latype = 0, flowinfo = 0, hlim = 0, compat = 0;
+
+	if (so->so_state & SS_ISCONNECTED) {
+		if (nam) {
+			m_freem(m);
+			return EISCONN;
+		}
+		dst = &inp->inp_faddr6;
+	} else {
+		if (nam == NULL) {
+			m_freem(m);
+			return ENOTCONN;
+		}
+		if (nam->sa_len != sizeof(struct sockaddr_in6)) {
+			m_freem(m);
+			return EINVAL;
+		}
+		if (((struct sockaddr *)nam)->sa_family != AF_INET6) {
+			m_freem(m);
+			return EAFNOSUPPORT;
+		}
+
+		dst = &((struct sockaddr_in6 *)nam)->sin6_addr;
+		if (TAILQ_EMPTY(&ifnet) || IS_IPV4ADDR6(*dst)) {
+			m_freem(m);
+			return EADDRNOTAVAIL;
+		}
+	}
+	if (control) {
+		COPY_ADDR6(inp->inp_laddr6, laddr);
+		latype = inp->inp_latype;
+		compat = inp->inp_flags & INP_COMPATANY;
+		flowinfo = inp->inp_oflowinfo;
+		hlim = inp->inp_ttl;
+		imo = inp->inp_moptions;
+#if (MULTI_HOMED > 0)
+		ifa = inp->inp_ifa;
+		if (ifa)
+			ifa->ifa_refcnt++;
+#endif
+		error = ip6_setcontrol(inp, control, p);
+	}
+	if (error == 0)
+		error = rip6_output(m, so, dst);
+	if (control) {
+		COPY_ADDR6(laddr, inp->inp_laddr6);
+		inp->inp_latype = latype;
+		inp->inp_flags |= compat;
+		inp->inp_oflowinfo = flowinfo;
+		inp->inp_ttl = hlim;
+#if (MULTI_HOMED > 0)
+		if (inp->inp_ifa)
+			IFAFREE(inp->inp_ifa);
+		inp->inp_ifa = ifa;
+#endif
+		if (inp->inp_moptions != imo)
+			free(inp->inp_moptions, M_IPMOPTS);
+		inp->inp_moptions = imo;
+	}
+	return error;
+}
+
+struct pr_usrreqs rip6_usrreqs = {
+	rip6_abort, pru_accept_notsupp, rip6_attach, rip6_bind, rip6_connect,
+	pru_connect2_notsupp, in6_control, rip6_detach, rip6_disconnect,
+	pru_listen_notsupp, in6_setpeeraddr, pru_rcvd_notsupp,
+	pru_rcvoob_notsupp, rip6_send, pru_sense_null, rip6_shutdown, 
+	in6_setsockaddr, sosend, soreceive, sopoll, rip6_bind
+};
diff -uN src-current/sys/netinet/red.c src-current-ipv6/sys/netinet/red.c
--- src-current/sys/netinet/red.c
+++ src-current-ipv6/sys/netinet/red.c
@@ -0,0 +1,772 @@
+/*
+ * Copyright (C) 1997, 1998
+ *	Sony Computer Science Laboratory Inc.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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) 1990-1994 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 Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory 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.
+ */
+
+#if defined(__FreeBSD__) && defined(ALTQ)
+#include "opt_altq.h"
+#endif
+
+#ifdef RED	/* red is enabled by RED option in opt_altq.h */
+
+/*
+static char rcsid[] = "$Id: red.c,v 1.4 1998/01/30 09:06:31 kjc Exp kjc $";
+*/
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/ioctl.h>
+#include <sys/conf.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif
+#include <netinet/red.h>
+
+/*
+ * ALTQ/RED (Random Early Detection) implementation using 32-bit
+ * fixed-point calculation.
+ *
+ * written by kjc using the ns code as a reference.
+ * you can learn more about red and ns from Sally's home page at
+ * http://www-nrg.ee.lbl.gov/floyd/
+ *
+ * most of the red parameter values are fixed in this implementation
+ * to prevent fixed-point overflow/underflow.
+ * if you change the parameters, watch out for overflow/underflow!
+ *
+ * the parameters used are recommended values by Sally.
+ * the corresponding ns config looks:
+ *	q_weight=0.00195
+ *	minthresh=5 maxthresh=15 queue-size=60
+ *	linterm=30
+ *	dropmech=random-drop
+ *	bytes=false (can't be handled by 32-bit fixed-point)
+ *	doubleq=false dqthresh=false 
+ *	wait=true
+ */
+
+/* fixed-point uses 12-bit decimal places */
+#define FP_SHIFT	12	/* fixed-point shift */
+
+/* fixed red parameters */
+#define TH_MIN		5			/* min threshold */
+#define TH_MAX		15			/* max threshold */
+#define TH_RANGE	(TH_MAX - TH_MIN)	/* threshold range */
+#define INV_P_MAX	30		/* inverse of max drop probability */
+
+#define FP_TH_MIN	(TH_MIN << FP_SHIFT)	/* th_min in fixed-point */
+
+#define W_WEIGHT	512	/* inverse of weight of EWMA (511/512) */
+				/* q_weight = 0.00195 */
+#define W_SHIFT		9	/* log(W_WEIGHT) */
+#define AVG_SHIFT	(W_SHIFT + FP_SHIFT)	/* stored avg value is */
+						/* scaled by both */
+
+#define RED_LIMIT	60	/* default max queue lenght */
+#define RED_STATS		/* collect statistics */
+
+/* red_list keeps all red_state_t's allocated. */
+static red_state_t *red_list = NULL;
+
+/* internal function prototypes */
+static int red_enqueue __P((struct ifnet *, struct mbuf *, struct pr_hdr *, int));
+static struct mbuf *red_dequeue __P((struct ifnet *, int));
+static int drop_early __P((red_state_t *));
+static int mark_ecn __P((struct pr_hdr *, int));
+static int pow_w __P((int));
+static int red_detach __P((red_state_t *));
+static void red_flush __P((red_state_t *));
+
+/*
+ * red device interface
+ */
+d_open_t	redopen;
+d_close_t	redclose;
+d_ioctl_t	redioctl;
+
+int
+redopen(dev, flag, fmt, p)
+    dev_t dev;
+    int flag, fmt;
+    struct proc *p;
+{
+    /* everything will be done when the queueing scheme is attached. */
+    return 0;
+}
+
+int
+redclose(dev, flag, fmt, p)
+    dev_t dev;
+    int flag, fmt;
+    struct proc *p;
+{
+    red_state_t *q;
+    int err, error = 0;
+
+    while ((q = red_list) != NULL) {
+	/* destroy all */
+	err = red_detach(q);
+	if (err != 0 && error == 0)
+	    error = err;
+    }
+
+    return error;
+}
+
+int
+redioctl(dev, cmd, addr, flag, p)
+    dev_t dev;
+    int cmd;
+    caddr_t addr;
+    int flag;
+    struct proc *p;
+{
+    red_state_t *q;
+    struct red_interface *ifacep;
+    struct ifnet *ifp;
+    int	error = 0;
+
+    /* check super-user privilege */
+    switch (cmd) {
+    case RED_GETSTATS:
+	break;
+    default:
+	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
+	    return (error);
+	break;
+    }
+    
+    switch (cmd) {
+
+    case RED_ENABLE:
+	ifacep = (struct red_interface *)addr;
+	if ((q = altq_lookup(ifacep->red_ifname, ALTQT_RED)) == NULL) {
+	    error = EINVAL;
+	    break;
+	}
+	error = if_altqenable(q->q_ifp);
+	break;
+
+    case RED_DISABLE:
+	ifacep = (struct red_interface *)addr;
+	if ((q = altq_lookup(ifacep->red_ifname, ALTQT_RED)) == NULL) {
+	    error = EINVAL;
+	    break;
+	}
+    	error = if_altqdisable(q->q_ifp);
+	break;
+
+    case RED_IF_ATTACH:
+	ifp = ifunit(((struct red_interface *)addr)->red_ifname);
+	if (ifp == NULL) {
+	    error = ENXIO;
+	    break;
+	}
+
+	/* allocate and initialize red_state_t */
+	MALLOC(q, red_state_t *, sizeof(red_state_t), M_DEVBUF, M_WAITOK);
+	bzero(q, sizeof(red_state_t));
+
+	q->q_ifp = ifp;
+	q->q_head = q->q_tail = NULL;
+	q->q_len = 0;
+	q->q_limit = RED_LIMIT;
+
+	q->q_avg = 0;
+	q->q_idle = 1;
+	microtime(&q->q_last);
+
+	q->q_pkttime = 800;	/* 1000 bytes / 10Mbps * 8 * 1000000 */
+
+	/*
+	 * set RED to this ifnet structure.
+	 */
+	error = if_altqattach(ifp, q, red_enqueue, red_dequeue, ALTQT_RED);
+	if (error) {
+	    FREE(q, M_DEVBUF);
+	    break;
+	}
+
+	/* add this state to the red list */
+	q->q_next = red_list;
+	red_list = q;
+	break;
+
+    case RED_IF_DETACH:
+	ifacep = (struct red_interface *)addr;
+	if ((q = altq_lookup(ifacep->red_ifname, ALTQT_RED)) == NULL) {
+	    error = EINVAL;
+	    break;
+	}
+	error = red_detach(q);
+	break;
+
+    case RED_GETSTATS:
+	do {
+	    struct red_getstats *q_stats;
+
+	    q_stats = (struct red_getstats *)addr;
+	    if ((q = altq_lookup(q_stats->iface.red_ifname,
+				 ALTQT_RED)) == NULL) {
+		error = EINVAL;
+		break;
+	    }
+
+	    q_stats->q_len 	   = q->q_len;
+	    q_stats->q_limit 	   = q->q_limit;
+	    q_stats->q_avg 	   = q->q_avg;
+
+	    q_stats->xmit_packets  = q->q_stats.xmit_packets;
+	    q_stats->xmit_bytes    = q->q_stats.xmit_bytes;
+	    q_stats->drop_packets  = q->q_stats.drop_packets;
+	    q_stats->drop_bytes    = q->q_stats.drop_bytes;
+	    q_stats->drop_forced   = q->q_stats.drop_forced;
+	    q_stats->drop_unforced = q->q_stats.drop_unforced;
+	    q_stats->marked_packets = q->q_stats.marked_packets;
+
+	} while (0);
+	break;
+
+    case RED_CONFIG:
+	do {
+	    struct red_conf *fc;
+	    int limit;
+
+	    fc = (struct red_conf *)addr;
+	    if ((q = altq_lookup(fc->iface.red_ifname,
+				 ALTQT_RED)) == NULL) {
+		error = EINVAL;
+		break;
+	    }
+	    limit = fc->red_limit;
+	    if (limit < TH_MAX)
+		limit = TH_MAX;
+	    q->q_limit = limit;
+	    fc->red_limit = limit;
+	    if (fc->red_pkttime > 0)
+		q->q_pkttime = fc->red_pkttime;
+	    q->q_flags = fc->red_flags;
+	} while (0);
+	break;
+
+    case RED_ACC_ENABLE:
+	/* enable accounting mode */
+	ifacep = (struct red_interface *)addr;
+	if ((q = altq_lookup(ifacep->red_ifname, ALTQT_RED)) == NULL) {
+	    error = EINVAL;
+	    break;
+	}
+	SET_ACCOUNTING(q->q_ifp);
+	break;
+
+    case RED_ACC_DISABLE:
+	/* disable accounting mode */
+	ifacep = (struct red_interface *)addr;
+	if ((q = altq_lookup(ifacep->red_ifname, ALTQT_RED)) == NULL) {
+	    error = EINVAL;
+	    break;
+	}
+	CLEAR_ACCOUNTING(q->q_ifp);
+	break;
+
+    default:
+	error = EINVAL;
+	break;
+    }
+    return error;
+}
+
+/*
+ * red support routines
+ */
+
+/*
+ * enqueue routine:
+ *
+ *	returns: 0 when successfully queued.
+ *		 ENOBUFS when drop occurs.
+ */
+#define DTYPE_NODROP	0	/* no drop */
+#define DTYPE_FORCED	1	/* a "forced" drop */
+#define DTYPE_EARLY	2	/* an "unforced" (early) drop */
+
+static int
+red_enqueue(ifp, m, pr_hdr, mode)
+    struct ifnet *ifp;
+    struct mbuf *m;
+    struct pr_hdr *pr_hdr;
+    int mode;
+{
+    red_state_t *q = (red_state_t *)ifp->if_altqp;
+    int avg, droptype;
+    struct mbuf *prev = NULL;
+    int i, n, error = 0;
+    
+    switch (mode) {
+    case ALTEQ_NORMAL:
+	avg = q->q_avg;
+    
+	/*
+	 * if we were idle, we pretend that n packets arrived during
+	 * the idle period.
+	 */
+	if (q->q_idle) {
+	    struct timeval now;
+	    int t;
+	
+	    q->q_idle = 0;
+	    microtime(&now);
+	    t = (now.tv_sec - q->q_last.tv_sec);
+	    if (t > 60) {
+		/*
+		 * being idle for more than 1 minute, set avg to zero.
+		 * this prevents t from overflow.
+		 */ 
+		avg = 0;
+	    }
+	    else {
+		t = t * 1000000 + (now.tv_usec - q->q_last.tv_usec);
+		n = t / q->q_pkttime;
+
+		/* the following line does (avg = (1 - Wq)^n * avg) */
+		if (n > 0)
+		    avg = (avg >> FP_SHIFT) * pow_w(n);
+	    }
+	}
+
+	/* run estimator. (note: avg is scaled by 512 in fixed-point) */
+	avg += (q->q_len << FP_SHIFT) - (avg >> W_SHIFT);
+	q->q_avg = avg;		/* save the new value */
+
+	/*
+	 * count keeps a tally of arriving traffic that has not
+	 * been dropped.
+	 */
+	q->q_count++;
+    
+	/* see if we drop early */
+	droptype = DTYPE_NODROP;
+	if (avg >= (TH_MIN << AVG_SHIFT) && q->q_len > 1) {
+	    if (avg >= (TH_MAX << AVG_SHIFT)) {
+		/* avg >= th_max: forced drop */
+		droptype = DTYPE_FORCED;
+	    }
+	    else if (q->q_old == 0) {
+		/* first exceeds th_min */
+		q->q_count = 1;
+		q->q_old = 1;
+	    }
+	    else if (drop_early(q)) {
+		/* mark or drop by red */
+		if ((q->q_flags & REDF_ECN) && mark_ecn(pr_hdr, q->q_flags)) {
+		    /* successfully marked.  do not drop. */
+		    q->q_count = 0;
+#ifdef RED_STATS
+		    q->q_stats.marked_packets++;
+#endif
+		}
+		else { 
+		    /* unforced drop by red */
+		    droptype = DTYPE_EARLY;
+	        }
+	    }
+	}
+	else {
+	    /* avg < th_min */
+	    q->q_old = 0;
+	}
+
+	/*
+	 * if the queue length hits the hard limit, it's a forced drop.
+	 */
+	if (droptype == DTYPE_NODROP && q->q_len >= q->q_limit)
+	    droptype = DTYPE_FORCED;
+
+	/* if successful or forced drop, enqueue this packet. */
+	if (droptype != DTYPE_EARLY) {
+	    m->m_nextpkt = NULL;
+	    if (q->q_tail == NULL)
+		q->q_head = m;
+	    else
+		q->q_tail->m_nextpkt = m;
+	    q->q_tail = m;
+	    q->q_len++;
+	}
+
+	if (droptype == DTYPE_NODROP) {
+	    /* successfully queued.  start the driver */
+	    if (ifp->if_start && (ifp->if_flags & IFF_OACTIVE) == 0)
+		(*ifp->if_start)(ifp);
+	}
+	else {
+	    if (droptype == DTYPE_EARLY) {
+		/* drop the incoming packet */
+#ifdef RED_STATS
+		q->q_stats.drop_unforced++;
+#endif
+	    }
+	    else {
+		/* forced drop, select a victim packet in the queue. */
+		m = q->q_head;
+		n = random() % q->q_len;
+		if (n == 0) {
+		    if ((q->q_head = m->m_nextpkt) == NULL)
+			q->q_tail = NULL;
+		}
+		else {
+		    for (i=0; i<n; i++) {
+			prev = m;
+			m = m->m_nextpkt;
+		    }
+		    if ((prev->m_nextpkt = m->m_nextpkt) == NULL)
+			q->q_tail = prev;
+		}
+		q->q_len--;
+#ifdef RED_STATS
+		q->q_stats.drop_forced++;
+#endif
+	    }
+#ifdef RED_STATS
+	    q->q_stats.drop_packets++;
+	    q->q_stats.drop_bytes += m->m_pkthdr.len;
+#endif
+	    q->q_count = 0;
+	    m->m_nextpkt = NULL;
+	    m_freem(m);
+	    error =  ENOBUFS;
+	}
+	break;
+
+#if defined(ALTQ_ACCOUNT) && defined(RED_STATS)
+	/*
+	 * altq accounting mode: used just for statistics.
+	 */
+    case ALTEQ_ACCOK:
+	q->q_stats.xmit_packets++;
+	q->q_stats.xmit_bytes += m->m_pkthdr.len;
+	break;
+
+    case ALTEQ_ACCDROP:
+	q->q_stats.drop_packets++;
+	q->q_stats.drop_bytes += m->m_pkthdr.len;
+	break;
+
+#endif /* ALTQ_ACCOUNT && RED_STATS */
+    }
+    return error;
+}
+
+/*
+ * early-drop probability is calculated as follows:
+ * prob = p_max * (avg - th_min) / (th_max - th_min)
+ * prob_a = prob / (2 - count*prob)
+ *	  = (avg-th_min) / (2*(th_max-th_min)*inv_p_max - count*(avg-th_min))
+ *
+ */
+static int drop_early(q)
+    red_state_t *q;
+{
+    int avg;	/* avg in fixed-point */
+    int d;	/* denominator of drop-probability */
+
+    avg = q->q_avg >> W_SHIFT;	/* unscale avg */
+
+    d = ((2 * TH_RANGE * INV_P_MAX) << FP_SHIFT)
+	- q->q_count * (avg - FP_TH_MIN);
+
+    if (d <= 0)
+	/* count exceeds the hard limit: drop or mark */
+	return (1);
+
+    /*
+     * now the range of d is [1..600] in fixed-point.
+     *
+     * drop probability = (avg - FP_TH_MIN) / d
+     */
+
+    if ((random() % d) < (avg - FP_TH_MIN)) {
+	/* drop or mark */
+	return (1);
+    }
+    /* no drop/mark */
+    return (0);
+}
+
+/*
+ * try to mark CE bit to the packet.
+ *    returns 1 if successfully marked, 0 otherwise.
+ */
+static int mark_ecn(pr_hdr, flags)
+    struct pr_hdr *pr_hdr;
+    int flags;
+{
+
+    switch (pr_hdr->ph_family) {
+    case AF_INET:
+	if (flags & REDF_ECN4) {
+	    struct ip *ip = (struct ip *)pr_hdr->ph_hdr;
+	    
+	    if (ip->ip_tos & IPTOS_ECT) {
+		/* ECN-capable, mark ECN bit. */
+		if ((ip->ip_tos & IPTOS_CE) == 0) {
+		    long sum;
+		    
+		    ip->ip_tos |= IPTOS_CE;
+		    /*
+		     * update checksum (from RFC1624)
+		     *	   HC' = ~(~HC + ~m + m')
+		     */
+		    sum = ~ntohs(ip->ip_sum) & 0xffff;
+		    sum += 0xffff + IPTOS_CE;
+		    sum = (sum >> 16) + (sum & 0xffff);
+		    sum += (sum >> 16);		     	/* add carry */
+		
+		    ip->ip_sum = htons(~sum & 0xffff);
+		}
+		return (1);
+	    }
+	}
+	break;
+#if defined(INET6) && defined(something_for_ipv6_ecn)
+    case AF_INET6:
+	if (flags & REDF_ECN6) {
+	    struct ipv6 *ip = (struct ipv6 *)pr_hdr->ph_hdr;
+
+#if BYTE_ORDER == BIG_ENDIAN
+#ifndef IPV6_ECT
+#define IPV6_ECT	0x00200000
+#endif
+#ifndef IPV6_CE
+#define IPV6_CE		0x00100000
+#endif
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+#ifndef IPV6_ECT
+#define IPV6_ECT	0x00002000
+#endif
+#ifndef IPV6_CE
+#define IPV6_CE		0x00001000
+#endif
+#endif
+	    if (ip->ip6_head & IPV6_ECT) {
+		/* ECN-capable, mark ECN bit. */
+		ip->ip6_head |= IPV6_CE;
+		return (1);
+	    }
+	}
+	break;
+#endif  /* INET6 && something_for_ipv6_ecn */
+    }
+
+    /* not marked */
+    return (0);
+}
+
+/*
+ * dequeue routine:
+ *	must be called in splimp.
+ *
+ *	returns: mbuf dequeued.
+ *		 NULL when no packet is available in the queue.
+ */
+
+static struct mbuf *
+red_dequeue(ifp, mode)
+    struct ifnet *ifp;
+    int mode;
+{
+    red_state_t *q = (red_state_t *)ifp->if_altqp;
+    struct mbuf *m = NULL;
+
+    switch (mode) {
+    case ALTDQ_DEQUEUE:
+	if ((m = q->q_head) == NULL) {
+	    q->q_idle = 1;
+	    microtime(&q->q_last);
+	    break;
+	}
+
+	if ((q->q_head = m->m_nextpkt) == NULL)
+	    q->q_tail = NULL;
+	m->m_nextpkt = NULL;
+	q->q_len--;
+    
+	q->q_idle = 0;
+#ifdef RED_STATS
+	q->q_stats.xmit_packets++;
+	q->q_stats.xmit_bytes += m->m_pkthdr.len;
+#endif
+	break;
+
+    case ALTDQ_PEEK:
+	m = q->q_head;
+	break;
+
+    case ALTDQ_FLUSH:
+	red_flush(q);
+	m = NULL;
+	break;
+    }
+    return m;
+}
+
+static int red_detach(q)
+    red_state_t *q;
+{
+    red_state_t *tmp;
+    int error = 0;
+
+    if (ALTQ_IS_ON(q->q_ifp))
+	if_altqdisable(q->q_ifp);
+
+    red_flush(q);
+
+    if ((error = if_altqdetach(q->q_ifp)))
+	return (error);
+
+    if (red_list == q)
+	red_list = q->q_next;
+    else {
+	for (tmp = red_list; tmp != NULL; tmp = tmp->q_next)
+	    if (tmp->q_next == q) {
+		tmp->q_next = q->q_next;
+		break;
+	    }
+	if (tmp == NULL)
+	    printf("red_detach: no state found in red_list!\n");
+    }
+
+    FREE(q, M_DEVBUF);
+    return (error);
+}
+
+/*
+ * red_flush
+ * should be called in splimp or after disabling the red.
+ */
+static void red_flush(q)
+    red_state_t *q;
+{
+    struct mbuf *m;
+    
+    while ((m = q->q_head) != NULL) {
+	q->q_head = m->m_nextpkt;
+	m_freem(m);
+    }
+    q->q_tail = NULL;
+    q->q_len = 0;
+}
+
+/*
+ * helper routine to calibrate avg during idle.
+ * pow_w(n) returns (1 - Wq)^n in fixed-point
+ * the code assumes Wq is close to zero.
+ *
+ * wtab[n] holds ((1 - Wq)^(2^n)) in fixed-point.
+ */
+static int32_t wtab[32];
+static int w_param_max = 0;	/* max effective parameter for pow_w() */
+
+static int32_t pow_w(n)
+    int n;
+{
+    int i, bit;
+    int32_t val;
+
+    if (w_param_max == 0) {
+	/* first time called. initialize wtab. */
+	wtab[0] = ((W_WEIGHT - 1) << FP_SHIFT) / W_WEIGHT;
+	for (i = 1; i < 32; i++) {
+	    wtab[i] = (wtab[i-1] * wtab[i-1]) >> FP_SHIFT;
+	    if (wtab[i] == 0 && w_param_max == 0)
+		w_param_max = 1 << i;
+	}
+    }
+    
+    if (n >= w_param_max)
+	return (0);
+
+    val = 1 << FP_SHIFT;
+    if (n <= 0)
+	return (val);
+
+    bit = 1;
+    i = 0;
+    while (n) {
+	if (n & bit) {
+	    val = (val * wtab[i]) >> FP_SHIFT;
+	    n &= ~bit;
+	}
+	i++;
+	bit <<=  1;
+    }
+    return (val);
+}
+
+#endif /* RED */
diff -uN src-current/sys/netinet/red.h src-current-ipv6/sys/netinet/red.h
--- src-current/sys/netinet/red.h
+++ src-current-ipv6/sys/netinet/red.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 1997, 1998
+ *	Sony Computer Science Laboratory Inc.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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.
+ *
+ * $Id: red.h,v 1.3 1998/01/27 02:50:14 kjc Exp $
+ */
+
+#ifndef _NETINET_RED_H_
+#define _NETINET_RED_H_
+
+struct red_interface {
+	char	red_ifname[IFNAMSIZ];
+};
+
+struct red_getstats {
+    struct red_interface iface;
+    int q_len;
+    int q_limit;
+    int q_avg;
+    quad_t xmit_packets;
+    quad_t xmit_bytes;
+    quad_t drop_packets;
+    quad_t drop_bytes;
+    quad_t drop_forced;
+    quad_t drop_unforced;
+    quad_t marked_packets;
+};
+
+struct red_conf {
+    struct red_interface iface;
+    int red_limit;
+    int red_pkttime;	/* average packettime in usec */
+    int red_flags;
+};
+
+/* red flags */
+#define REDF_ECN4	0x01	/* use packet marking for IPv4 packets */
+#define REDF_ECN6	0x02	/* use packet marking for IPv6 packets */
+#define REDF_ECN	(REDF_ECN4 | REDF_ECN6)
+
+/* 
+ * IOCTLs for RED
+ */
+#define RED_ENABLE		_IOW('Q', 1, struct red_interface)
+#define RED_DISABLE		_IOW('Q', 2, struct red_interface)
+#define	RED_IF_ATTACH		_IOW('Q', 3, struct red_interface)
+#define	RED_IF_DETACH		_IOW('Q', 4, struct red_interface)
+#define	RED_ACC_ENABLE		_IOW('Q', 5, struct red_interface)
+#define	RED_ACC_DISABLE		_IOW('Q', 6, struct red_interface)
+#define	RED_GETSTATS		_IOWR('Q', 7, struct red_getstats)
+#define	RED_CONFIG		_IOWR('Q', 8, struct red_conf)
+
+#ifdef KERNEL
+
+typedef struct red_state {
+    struct red_state *q_next;	/* next red_state in the list */
+    struct ifnet *q_ifp;	/* backpointer to ifnet */
+
+    struct mbuf *q_head;	/* head of queue */
+    struct mbuf *q_tail;	/* tail of queue */
+    int q_len;			/* queue length */
+    int q_limit;		/* max queue length */
+
+    int q_pkttime;	/* average packettime used for idle calibration */
+    int q_flags;	/* red flags */
+
+    int q_avg;		/* queue length average scaled by AVG_SHIFT */
+    int q_count; 	/* unmarked packet count since last marked packet */
+    int q_idle;		/* queue was empty */
+    int q_old;		/* avg is above th_min */
+    struct timeval q_last; 	/* timestamp when the queue becomes idle */
+
+    struct {
+	quad_t xmit_packets;
+	quad_t xmit_bytes;
+	quad_t drop_packets;
+	quad_t drop_bytes;
+	quad_t drop_forced;
+	quad_t drop_unforced;
+	quad_t marked_packets;
+    } q_stats;
+} red_state_t;
+
+#endif /* KERNEL */
+
+#endif /* _NETINET_RED_H_ */
diff -uN src-current/sys/netinet/rm_class.c src-current-ipv6/sys/netinet/rm_class.c
--- src-current/sys/netinet/rm_class.c
+++ src-current-ipv6/sys/netinet/rm_class.c
@@ -0,0 +1,1899 @@
+/* $Id: rm_class.c,v 0.7 1998/01/09 03:09:10 kjc Exp $ */
+/*
+ * Copyright (c) 1991-1997 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 Network Research
+ *      Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory 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.
+ *
+ * LBL code modified by speer@eng.sun.com, May 1977.
+ * For questions and/or comments, please send mail to cbq@ee.lbl.gov
+ */
+
+/*
+static char rcsid[] = "$Id: rm_class.c,v 0.7 1998/01/09 03:09:10 kjc Exp $";
+*/
+#ident "@(#)rm_class.c  1.34     97/07/24 SMI"
+
+#if defined(__FreeBSD__) && defined(ALTQ)
+#include "opt_altq.h"
+#endif
+
+#ifdef CBQ	/* cbq is enabled by CBQ option in opt_altq.h */
+
+#include <sys/param.h>
+#ifndef	SOLARIS
+#include <sys/mbuf.h>
+#endif
+#include <sys/buf.h>
+#ifndef ALTQ
+#include <sys/map.h>
+#endif
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#ifndef ALTQ
+#include <sys/debug.h>
+#endif
+
+#include <sys/time.h>
+#ifndef	SOLARIS
+#include <sys/kernel.h>
+#endif
+
+#include <net/if.h>
+#ifndef	SOLARIS
+#include <net/netisr.h>
+#endif
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifdef	SOLARIS
+#include <sys/kmem.h>
+#include <sys/stream.h>
+#endif
+
+#include <netinet/rm_class.h>
+#include <netinet/rm_class_debug.h>
+
+#ifdef	SOLARIS
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <netinet/cbq.h>
+#endif
+
+#ifdef SOLARIS
+#define	panic(str)	cmn_err(CE_PANIC, (str));
+#endif
+
+#if defined(__NetBSD__)
+typedef void (timeout_t)(void *);
+#endif
+
+/*
+ * Local Macros
+ */
+
+#define reset_cutoff(ifd) { \
+	ifd->cutoff_ = RM_MAXDEPTH; \
+}
+
+/*
+ * Local routines.
+ */
+
+#ifdef USE_HRTIME
+static int	rmc_satisfied(struct rm_class *cl, hrtime_t *now);
+#else
+static int	rmc_satisfied(struct rm_class *cl, struct timeval *now);
+#endif
+static void	rmc_wrr_set_weights(struct rm_ifdat *ifd);
+static void	rmc_depth_compute(struct rm_class *cl);
+
+static void	_rmc_addq(class_queue_t *q, mbuf_t *m);
+#ifdef ALTQ
+static mbuf_t	*_rmc_dropq(class_queue_t *q);
+#else
+static void	_rmc_dropq(class_queue_t *q);
+#endif
+static mbuf_t	*_rmc_getq(class_queue_t *q);
+#ifdef ALTQ
+static mbuf_t	*_rmc_peekq(class_queue_t *q);
+#endif
+
+#ifdef ALTQ
+#define BORROW_OFFTIME
+/*
+ * BORROW_OFFTIME (experimental):
+ * borrow the offtime of the class borrowing from.
+ * the reason is that when its own offtime is set, the class is unable
+ * to borrow much, especially when cutoff is taking effect.
+ * but when the borrowed class is overloaded (advidle is close to minidle),
+ * use the borrowing class's offtime to avoid overload.
+ */
+#define ADJUST_CUTOFF
+/*
+ * ADJUST_CUTOFF (experimental):
+ * if no underlimit class is found due to cutoff, increase cutoff and
+ * retry the scheduling loop.
+ * also, don't invoke delay_actions while cutoff is taking effect,
+ * since a sleeping class won't have a chance to be scheduled in the
+ * next loop.
+ *
+ * now heuristics for setting the top-level variable (cutoff_) becomes:
+ *	1. if a packet arrives for a not-overlimit class, set cutoff
+ *	   to the depth of the class.
+ *	2. if cutoff is i, and a packet arrives for an overlimit class
+ *	   with an underlimit ancestor at a lower level than i (say j),
+ *	   then set cutoff to j.
+ *	3. at scheduling a packet, if there is no underlimit class
+ *	   due to the current cutoff level, increase cutoff by 1 and
+ *	   then try to schedule again.
+ */
+#endif /* ALTQ */
+
+/*
+ * local data.
+ */
+#if defined(CBQDEBUG)
+struct cbqtrace		cbqtrace_buffer[NCBQTRACE+1];
+struct cbqtrace		*cbqtrace_ptr = NULL;
+int			cbqtrace_count;
+#endif
+
+/*
+ * Table for mapping a bit mask (with one bit per priority level)
+ * into the number of the highest priority set bit.
+ */
+u_char rmc_mask2pri[] = {
+	0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, /* 00 - 0f */
+	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* 10 - 1f */
+	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, /* 20 - 2f */
+	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, /* 30 - 3f */
+	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, /* 40 - 4f */
+	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, /* 50 - 5f */
+	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, /* 60 - 6f */
+	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, /* 70 - 7f */
+	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* 80 - 8f */
+	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* 90 - 9f */
+	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* a0 - af */
+	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* b0 - bf */
+	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* c0 - cf */
+	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* d0 - df */
+	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* e0 - ef */
+	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7  /* f0 - ff */
+};
+
+/*
+ * rm_class_t *
+ * rmc_newclass(...) - Create a new resource management class at priority
+ * 'pri' on the interface given by 'ifd'.
+ *
+ * nsecPerByte  is the data rate of the interface in nanoseconds/byte.
+ *              E.g., 800 for a 10Mb/s ethernet.  If the class gets less
+ *              than 100% of the bandwidth, this number should be the
+ *              'effective' rate for the class.  Let f be the
+ *              bandwidth fraction allocated to this class, and let
+ *              nsPerByte be the data rate of the output link in
+ *              nanoseconds/byte.  Then nsecPerByte is set to
+ *              nsPerByte / f.  E.g., 1600 (= 800 / .5)
+ *              for a class that gets 50% of an ethernet's bandwidth.
+ *
+ * action       the routine to call when the class is over limit.
+ *
+ * maxq         max allowable queue size for class (in packets).
+ *
+ * parent       parent class pointer.
+ *
+ * borrow       class to borrow from (should be either 'parent' or null).
+ *
+ * maxidle      max value allowed for class 'idle' time estimate (this
+ *              parameter determines how large an initial burst of packets
+ *              can be before overlimit action is invoked.
+ *
+ * offtime      how long 'delay' action will delay when class goes over
+ *              limit (this parameter determines the steady-state burst
+ *              size when a class is running over its limit).
+ *
+ * Maxidle and offtime have to be computed from the following:  If the
+ * average packet size is s, the bandwidth fraction allocated to this
+ * class is f, we want to allow b packet bursts, and the gain of the
+ * averaging filter is g (= 1 - 2^(-RM_FILTER_GAIN)), then:
+ *
+ *   ptime = s * nsPerByte * (1 - f) / f
+ *   maxidle = ptime * (1 - g^b) / g^b
+ *   minidle = -ptime * (1 / (f - 1))
+ *   offtime = ptime * (1 + 1/(1 - g) * (1 - g^(b - 1)) / g^(b - 1)
+ *
+ * Operationally, it's convenient to specify maxidle & offtime in units
+ * independent of the link bandwidth so the maxidle & offtime passed to
+ * this routine are the above values multiplied by 8*f/(1000*nsPerByte).
+ * (The constant factor is a scale factor needed to make the parameters
+ * integers.  This scaling also means that the 'unscaled' values of
+ * maxidle*nsecPerByte/8 and offtime*nsecPerByte/8 will be in microseconds,
+ * not nanoseconds.)  Also note that the 'idle' filter computation keeps
+ * an estimate scaled upward by 2^RM_FILTER_GAIN so the passed value of
+ * maxidle also must be scaled upward by this value.  Thus, the passed
+ * values for maxidle and offtime can be computed as follows:
+ *
+ * maxidle = maxidle * 2^RM_FILTER_GAIN * 8 / (1000 * nsecPerByte)
+ * offtime = offtime * 8 / (1000 * nsecPerByte)
+ *
+ * When USE_HRTIME is employed, then maxidle and offtime become: 
+ * 	maxidle = maxilde * (8.0 / nsecPerByte); 
+ * 	offtime = offtime * (8.0 / nsecPerByte);
+ */
+
+struct rm_class *
+rmc_newclass(pri, ifd, nsecPerByte, action, maxq, parent, borrow,
+	     maxidle, minidle, offtime)
+    int			pri;
+    struct rm_ifdat	*ifd;
+    u_int		nsecPerByte;
+#ifdef ALTQ
+    void		(*action)(rm_class_t *, rm_class_t *);
+#else
+    void		(*action)(rm_class_t *);
+#endif
+    int			maxq;
+    struct rm_class	*parent;
+    struct rm_class	*borrow;
+    u_int		maxidle;
+    int			minidle;
+    u_int		offtime;
+{
+    struct rm_class *cl;
+    struct rm_class *peer;
+    int i, v, tim;
+
+    if (pri >= RM_MAXPRIO)
+	return (NULL);
+
+#ifdef ALTQ
+    MALLOC(cl, struct rm_class *, sizeof(struct rm_class),
+	   M_DEVBUF, M_WAITOK);
+    bzero(cl, sizeof(struct rm_class));
+    MALLOC(cl->q_, class_queue_t *, sizeof(class_queue_t),
+	   M_DEVBUF, M_WAITOK);
+    bzero(cl->q_, sizeof(class_queue_t));
+#else
+    if (!(cl = (struct rm_class *)kmem_zalloc(sizeof (*cl), KM_SLEEP)))
+	return (NULL);
+    if (!(cl->q_ = (class_queue_t *)
+	  kmem_zalloc(sizeof (class_queue_t), KM_SLEEP)))
+	return (NULL);
+#endif
+
+    if ((peer = ifd->active_[pri])) {
+	/* find the last class at this pri */
+	cl->peer_ = peer;
+	while (peer->peer_ != ifd->active_[pri])
+	    peer = peer->peer_;
+	peer->peer_ = cl;
+    }
+    else {
+	ifd->active_[pri] = cl;
+	cl->peer_ = cl;
+	ifd->hsum_ |= (1 << pri);
+    }
+
+    /*
+     * Class initialization.
+     */
+    cl->children_ = NULL;
+    cl->parent_ = parent;
+    cl->borrow_ = borrow;
+    cl->leaf_ = 1;
+    if (cl->parent_) {
+	cl->next_ = parent->children_;
+	parent->children_ = cl;
+	parent->leaf_ = 0;
+    }
+    cl->ifdat_ = ifd;
+    cl->pri_ = pri;
+    cl->allotment_ = RM_NS_PER_SEC / nsecPerByte; /* Bytes per sec */
+    cl->depth_ = 0;
+
+    qlimit(cl->q_) = maxq;
+    qtype(cl->q_) = Q_DROPTAIL;
+    qthresh(cl->q_) = 0;
+    qlen(cl->q_) = 0;
+
+    /*
+     * Compute the depth of this class and it's ancestors in the class
+     * hierarchy.
+     */
+    rmc_depth_compute(cl);
+
+    /*
+     * If CBQ's WRR is enabled, then initailize the class WRR state.
+     */
+    if (ifd->wrr_) {
+	ifd->num_[pri]++;
+	ifd->alloc_[pri] += cl->allotment_;
+	rmc_wrr_set_weights(ifd);
+    }
+    cl->minidle_ = minidle;
+#ifdef USE_HRTIME
+    if (cl->parent_ == NULL)
+	cl->minidle_ = -RM_NS_PER_SEC; 
+#endif
+    cl->maxidle_ = (maxidle * nsecPerByte) / 8;
+#ifdef ALTQ
+    if (cl->maxidle_ == 0)
+	cl->maxidle_ = 1;
+#endif
+#ifdef ALTQ	/* offtime is also scaled */
+    cl->avgidle_ = cl->maxidle_;
+    cl->offtime_ = ((offtime * nsecPerByte) / 8) >> RM_FILTER_GAIN;
+    if (cl->offtime_ == 0)
+	cl->offtime_ = 1;
+#else
+    cl->avgidle_ = 0;
+    cl->offtime_ = (offtime * nsecPerByte) / 8;
+#endif
+    cl->overlimit = action;
+
+    /*
+     * Pre-compute the packtime times for various size packets.
+     *	XXX - works only for 1500 byte MTU.
+     */
+    tim = 0;
+    for (i = 0; i < RM_DEFAULT_MTU; i++) {
+#ifdef USE_HRTIME
+	v = tim;
+	cl->len2time_[i] = v;
+#else
+	v = tim / 1000;
+	cl->len2time_[i] =  v == 0? 1 : v;
+#endif
+	tim += nsecPerByte;
+    }
+    return (cl);
+}
+
+/*
+ * static void
+ * rmc_wrr_set_weights(struct rm_ifdat *ifdat) - This function computes
+ * 	the appropriate run robin weights for the CBQ weighted round robin
+ *	algorithm.
+ *
+ *	Returns: NONE
+ */
+
+static void
+rmc_wrr_set_weights(struct rm_ifdat *ifd)
+{
+    int		i;
+    struct rm_class	*cl, *clh;
+
+    for (i = 0; i < RM_MAXPRIO; i++) {
+	if (ifd->alloc_[i] > 0) {
+	    /*
+	     * This is inverted from that of the simulator to
+	     * maintain precision.
+	     */
+	    ifd->M_[i] = ifd->alloc_[i] /
+		(ifd->num_[i] * ifd->maxpkt_);
+	    /*
+	     * Compute the weigthed allotment for each class.
+	     * This takes the expensive div instruction out
+	     * of the main loop for the wrr scheduling path.
+	     * These only get recomputed when a class comes or
+	     * goes.
+	     */
+	    if (ifd->active_[i] != NULL) {
+		clh = cl = ifd->active_[i];
+		do {
+#ifdef ALTQ
+		    /* safe-guard for slow link or alloc == 0 */
+		    if (ifd->M_[i] == 0) {
+			if (ifd->alloc_[i] == 0)
+			    cl->w_allotment_ = 0;
+			else
+			    cl->w_allotment_ = cl->allotment_ * ifd->num_[i]
+				* ifd->maxpkt_ / ifd->alloc_[i];
+		    }
+		    else
+#endif /* ALTQ */
+			cl->w_allotment_ = cl->allotment_ / ifd->M_[i];
+		    cl = cl->peer_;
+		} while ((cl != NULL) && (cl != clh));
+	    }
+	} else
+	    ifd->M_[i] = 0;
+    }
+}
+
+/*
+ * static void
+ * rmc_depth_compute(struct rm_class *cl) - This function computes the
+ * 	appropriate depth of class 'cl' and its ancestors.
+ *
+ *	Returns:	NONE
+ */
+
+static void
+rmc_depth_compute(struct rm_class *cl)
+{
+    rm_class_t *t = cl, *p;
+
+    /*
+     * Recompute the depth for the branch of the tree.
+     */
+    while (t != NULL) {
+	p = t->parent_;
+	if (p && (t->depth_ >= p->depth_)) {
+	    p->depth_++;
+	    t = p;
+	} else
+	    t = NULL;
+    }
+}
+
+/*
+ * void
+ * rmc_delete_class(struct rm_ifdat *ifdat, struct rm_class *cl) - This
+ *	function deletes a class from the link-sharing stucture and frees
+ *	all resources associated with the class.
+ *
+ *	Returns: NONE
+ */
+
+void
+rmc_delete_class(struct rm_ifdat *ifd, struct rm_class *cl)
+{
+    struct rm_class		*p, *head, *previous;
+    mbuf_t			*m;
+
+#ifdef ALTQ
+    if (cl->sleeping_)
+	untimeout((timeout_t *)rmc_restart, cl); 
+#endif
+    /*
+     * Free packets in the packet queue.
+     * XXX - this may not be a desired behavior.  Packets should be
+     * 		re-queued.
+     */
+    if (!qempty(cl->q_)) {
+	while ((m = _rmc_getq(cl->q_)) != NULL)
+	    m_freem(m);
+
+	ifd->na_[cl->pri_]--;
+	if (ifd->na_[cl->pri_] == 0)
+	    ifd->csum_ &= ~(1 << cl->pri_);
+    }
+
+    /*
+     * If the class has a parent, then remove the class from the
+     * class from the parent's children chain.
+     */
+    if (cl->parent_ != NULL) {
+	head = cl->parent_->children_;
+	p = previous = head;
+	if (head->next_ == NULL) {
+	    cl->parent_->children_ = NULL;
+	    cl->parent_->leaf_ = 1;
+	} else while (p != NULL) {
+	    if (p == cl) {
+		if (cl == head)
+		    cl->parent_->children_ = cl->next_;
+		else
+		    previous->next_ = cl->next_;
+		cl->next_ = NULL;
+		p = NULL;
+	    } else {
+		previous = p;
+		p = p->next_;
+	    }
+	}
+    }
+
+    /*
+     * Delete class from class priority peer list.
+     */
+    if ((p = ifd->active_[cl->pri_])) {
+	/*
+	 * If there is more than one member of this priority
+	 * level, then look for class(cl) in the priority level.
+	 */
+	if (p != p->peer_) {
+	    while (p->peer_ != cl)
+		p = p->peer_;
+	    p->peer_ = cl->peer_;
+
+	    if (ifd->active_[cl->pri_] == cl)
+		ifd->active_[cl->pri_] = cl->peer_;
+	} else {
+	    ifd->active_[cl->pri_] = NULL;
+	    ifd->hsum_ &= ~(1 << cl->pri_);
+	}
+    }
+
+    /*
+     * Recompute the WRR weights.
+     */
+    if (ifd->wrr_) {
+	ifd->alloc_[cl->pri_] -= cl->allotment_;
+	ifd->num_[cl->pri_]--;
+	rmc_wrr_set_weights(ifd);
+    }
+
+    /*
+     * Free the class structure.
+     */
+#ifdef ALTQ
+    FREE(cl->q_, M_DEVBUF);
+    FREE(cl, M_DEVBUF);
+#else
+    kmem_free((void *)cl->q_, sizeof (class_queue_t));
+    kmem_free((void *)cl, sizeof (struct rm_class));
+#endif
+
+    /*
+     * XXX - need to re-compute the depth of the link-sharing
+     * structure.
+     */
+}
+
+
+/*
+ * void
+ * rmc_init(...) - Initialize the resource management data structures
+ *	associated with the output portion of interface 'ifp'.  'ifd' is
+ *	where the structures will be built (for backwards compatibility, the
+ *	structures aren't kept in the ifnet struct).  'nsecPerByte'
+ *	gives the link speed (inverse of bandwidth) in nanoseconds/byte.
+ *	'restart' is the driver-specific routine that the generic 'delay
+ *	until under limit' action will call to restart output.  `maxq'
+ *	is the queue size of the 'link' & 'default' classes.  'maxqueued'
+ *	is the maximum number of packets that the resource management
+ *	code will allow to be queued 'downstream' (this is typically 1).
+ *
+ *	Returns:	NONE
+ */
+
+void
+rmc_init(ifp, ifd, nsecPerByte, restart, maxq, maxqueued, maxidle,
+	 minidle, offtime, wrr, workconserving)
+#ifdef SOLARIS
+    queue_t		*ifp;
+#else
+    struct ifnet	*ifp;
+#endif
+    struct rm_ifdat *ifd;
+    u_int	nsecPerByte;
+    void	(*restart)(struct ifnet *);
+    int		maxq, maxqueued;
+    u_int	maxidle;
+    int		minidle;
+    u_int	offtime;
+    int		wrr;
+    int		workconserving;
+{
+    int		i;
+
+    /*
+     * Initialize the CBQ traciing/debug facility.
+     */
+    CBQTRACEINIT();	
+
+    bzero((char *)ifd, sizeof (*ifd));
+    ifd->ifp = ifp;
+    ifd->restart = restart;
+    ifd->maxqueued_ = maxqueued;
+    ifd->ns_per_byte_ = nsecPerByte;
+#ifdef ALTQ
+    ifd->maxpkt_ = ifp->if_mtu;
+#else
+    ifd->maxpkt_ = 1500; /* XXX - set to default mtusize for e-net. */
+#endif
+    ifd->wrr_ = wrr;
+    ifd->efficient_ = workconserving;
+
+    reset_cutoff(ifd);
+    CBQTRACE(rmc_init, 'INIT', ifd->cutoff_);
+
+    /*
+     * Initialize the CBQ's WRR state.
+     */
+    for (i = 0; i < RM_MAXPRIO; i++) {
+	ifd->alloc_[i] = 0;
+	ifd->M_[i] = 0;
+	ifd->num_[i] = 0;
+	ifd->na_[i] = 0;
+	ifd->active_[i] = NULL;
+    }
+
+    /*
+     * Initialize current packet state.
+     */
+    ifd->qi_ = 0;
+    ifd->qo_ = 0;
+    for (i = 0; i < RM_MAXQUEUED; i++) {
+	ifd->class_[i] = NULL;
+	ifd->curlen_[i] = 0;
+	ifd->borrowed_[i] = NULL;
+    }
+
+    /*
+     * Create the root class of the link-sharing structure.
+     */
+    if ((ifd->root_ = rmc_newclass(0, ifd,
+#ifdef notdef
+				   (nsecPerByte * 9875) / 10000,
+#else
+				   nsecPerByte,
+#endif
+				   rmc_root_overlimit, maxq, 0, 0,
+				   maxidle, minidle, offtime)) == NULL) {
+#ifdef SOLARIS
+	cmn_err(CE_CONT, "rmc_init: root class not allocated\n");
+#endif
+#ifdef ALTQ
+	printf("rmc_init: root class not allocated\n");
+#endif
+	return ;
+    }
+    ifd->root_->depth_ = 0;
+}
+
+/*
+ * void
+ * rmc_queue_packet(struct rm_class *cl, mbuf_t *m) - Add packet given by
+ *	mbuf 'm' to queue for resource class 'cl'.  This routine is called
+ *	by a driver's if_output routine.  This routine must be called with
+ *	output packet completion interrupts locked out (to avoid racing with
+ *	rmc_dequeue_next).
+ *
+ *	Returns:	0 on successful queueing
+ *			1 when packet drop occurs
+ */
+#ifdef ALTQ
+int
+#else
+void
+#endif
+rmc_queue_packet(struct rm_class *cl, mbuf_t *m)
+{
+#ifndef USE_HRTIME
+    struct timeval	now;
+#else
+    hrtime_t	now;
+#endif
+    struct rm_ifdat *ifd = cl->ifdat_;
+    int		cpri = cl->pri_;
+    int		is_empty = qempty(cl->q_);
+
+    RM_GETTIME(now);
+    if (ifd->cutoff_ > 0) {
+	if (TV_LT(&cl->undertime_, &now)) {
+#ifdef ALTQ
+	    if (ifd->cutoff_ > cl->depth_)
+#endif
+		ifd->cutoff_ = cl->depth_;
+	    CBQTRACE(rmc_queue_packet, 'ffoc', cl->depth_);
+	}
+#ifdef ALTQ
+	else {
+	    /*
+	     * the class is overlimit. if the class has underlimit ancestors,
+	     * set cutoff to the lowest depth among them.
+	     */
+	    struct rm_class *borrow = cl->borrow_;
+
+	    while (borrow != NULL && borrow->depth_ < ifd->cutoff_) {
+		if (TV_LT(&borrow->undertime_, &now)) {
+		    ifd->cutoff_ = borrow->depth_;
+		    CBQTRACE(rmc_queue_packet, 'ffob', ifd->cutoff_);
+		    break;
+		}
+		borrow = borrow->borrow_;
+	    }
+	} 
+#else /* !ALTQ */
+	else if ((ifd->cutoff_ > 1) && cl->borrow_) {
+	    if (TV_LT(&cl->borrow_->undertime_, &now)) {
+		ifd->cutoff_ = cl->borrow_->depth_;
+		CBQTRACE(rmc_queue_packet, 'ffob',
+			 cl->borrow_->depth_);
+	    }
+	} 
+#endif /* !ALTQ */
+    }
+
+    _rmc_addq(cl->q_, m);
+    if (is_empty) {
+	CBQTRACE(rmc_queue_packet, 'ytpe', cl->stats_.handle);
+	ifd->na_[cpri]++;
+	if (ifd->na_[cpri] == 1)
+	    ifd->csum_ |= (1 << cpri);
+    }
+#ifdef ALTQ
+    /* allow qlimit to be set to 0 or 1 */
+    if (qlen(cl->q_) > qlimit(cl->q_)) {
+	rmc_drop_action(cl);
+	return (1);
+    }
+    return (0);
+#else
+    else if (qlen(cl->q_) >= qlimit(cl->q_))
+	rmc_drop_action(cl);
+#endif
+}
+
+/*
+ * void
+ * rmc_tl_satisfied(struct rm_ifdat *ifd, struct timeval *now) - Check all
+ *	classes to see if there are satified.
+ *
+ *	Returns:	0, not satisfied.
+ *			1, satisfied.
+ */
+
+#ifdef USE_HRTIME
+void
+rmc_tl_satisfied(struct rm_ifdat *ifd, hrtime_t *now)
+#else
+void
+rmc_tl_satisfied(struct rm_ifdat *ifd, struct timeval *now)
+#endif
+{
+    u_int	hsum, i;
+    rm_class_t	*p, *bp;
+
+    hsum = ifd->hsum_;
+    while (hsum) { 
+	i = rmc_mask2pri[hsum];
+	if ((bp = ifd->active_[i]) != NULL) {
+	    p = bp;
+	    do {
+		if (!rmc_satisfied(p, now)) {
+		    ifd->cutoff_ = p->depth_;
+		    return;
+		} 
+		p = p->peer_;
+	    } while (p && (p != bp));
+	}
+	hsum &= ~(1 << i);
+    }
+}
+
+/*
+ * rmc_satisfied - Return 1 of the class is satisfied.  O, otherwise.
+ */
+
+#ifdef USE_HRTIME
+static int
+rmc_satisfied(struct rm_class *cl, hrtime_t *now)
+#else
+static int
+rmc_satisfied(struct rm_class *cl, struct timeval *now)
+#endif
+{
+    rm_class_t 	*p;
+
+    if (cl == NULL)
+	return (1);
+    if (TV_LT(now, &cl->undertime_))
+	return (1);
+    if (cl->depth_ == 0) {
+	if (!cl->sleeping_ && (qlen(cl->q_) > qthresh(cl->q_)))
+	    return (0);
+	else 
+	    return (1);
+    }
+    if (cl->children_ != NULL) {
+	p = cl->children_;
+	while (p != NULL) {
+	    if (!rmc_satisfied(p, now))
+		return (0);
+	    p = p->next_;
+	}
+    }
+
+    return (1);
+}
+
+/*
+ * Return 1 if class 'cl' is under limit or can borrow from a parent,
+ * 0 if overlimit.  As a side-effect, this routine will invoke the
+ * class overlimit action if the class if overlimit.
+ */
+#ifdef ALTQ
+
+int
+rmc_under_limit(struct rm_class *cl, struct timeval *now)
+{
+    rm_class_t	*p = cl;
+    rm_class_t	*top;
+    struct rm_ifdat	*ifd = cl->ifdat_;
+
+    ifd->borrowed_[ifd->qi_] = NULL;
+    /*
+     * If cl is the root class, then always return that it is
+     * underlimit.  Otherwise, check to see if the class is underlimit.
+     */
+    if (cl->parent_ == NULL)
+	return (1);
+
+    if (cl->sleeping_) {
+	if (TV_LT(now, &cl->undertime_))
+	    return (0);
+
+	untimeout((timeout_t *)rmc_restart, cl); 
+	cl->sleeping_ = 0;
+    }
+    else {
+	top = NULL;
+	while (cl->undertime_.tv_sec && TV_LT(now, &cl->undertime_)) {
+	    if (((cl = cl->borrow_) == NULL) || (cl->depth_ > ifd->cutoff_)) {
+#ifdef ADJUST_CUTOFF
+		if (cl != NULL)
+		    /* cutoff is taking effect, just return false
+		       without calling the delay action. */
+		    return (0);
+#endif
+#ifdef BORROW_OFFTIME
+		/*
+		 * check if the class can borrow offtime too.
+		 * borrow offtime from the top of the borrow chain
+		 * if the top class is not overloaded.
+		 */
+		if (cl != NULL) {
+		    /* cutoff is taking effect, use this class as top. */
+		    top = cl;	
+		    CBQTRACE(rmc_under_limit, 'ffou', ifd->cutoff_);
+		}
+		if (top != NULL && (top->avgidle_ <  top->minidle_ * 3 / 4))
+		    top = NULL;
+		p->overtime_ = *now;
+		(p->overlimit)(p, top);
+#else
+		p->overtime_ = *now;
+		(p->overlimit)(p, NULL);
+#endif
+		return (0);
+	    }
+	    top = cl;
+	}
+    }
+
+    if (cl != p)
+	ifd->borrowed_[ifd->qi_] = cl;
+    return (1);
+}
+#else /* !ALTQ */
+
+#ifdef USE_HRTIME
+int
+rmc_under_limit(struct rm_class *cl, hrtime_t *now)
+#else
+int
+rmc_under_limit(struct rm_class *cl, struct timeval *now)
+#endif
+{
+    rm_class_t	*p = cl;
+    struct rm_ifdat	*ifd = cl->ifdat_;
+
+    /*
+     * If cl is the root class, then always return that it is
+     * underlimit.  Otherwise, check to see if the class is underlimit.
+     */
+    if (cl->parent_ == NULL) {
+	return (1);
+    } else if (TV_LT(&cl->undertime_, now)) {  
+	cl->sleeping_timeout_id_ = 0;
+	cl->sleeping_ = 0;
+    } else while (TV_LT(now, &cl->undertime_)) {
+	++cl->stats_.borrows;
+	if (((cl = cl->borrow_) == NULL) ||
+	    (cl->depth_ > ifd->cutoff_)) {
+	    p->overtime_ = *now;
+	    (p->overlimit)(p);
+	    return (0);
+	}
+    }
+
+    ifd->borrowed_[ifd->qi_] = cl;
+    return (1);
+}
+#endif /* !ALTQ */
+
+/*
+ * _rmc_wrr_dequeue_next() - This is scheduler for WRR as opposed to
+ *	Packet-by-packet round robin.
+ *
+ * The heart of the weigthed round-robin scheduler, which decides which
+ * class next gets to send a packet.  Highest priority first, then
+ * weighted round-robin within priorites.
+ *
+ * Each able-to-send class gets to send until its byte allocation is
+ * exhausted.  Thus, the active pointer is only changed after a class has
+ * exhausted its allocation.
+ *
+ * If the scheduler finds no class that is underlimit or able to borrow,
+ * then the first class found that had a nonzero queue and is allowed to
+ * borrow gets to send.
+ */
+
+#ifdef ALTQ
+static mbuf_t *
+_rmc_wrr_dequeue_next(struct rm_ifdat *ifd, int mode)
+#else
+static mbuf_t *
+_rmc_wrr_dequeue_next(struct rm_ifdat *ifd)
+#endif
+{
+    struct rm_class	*cl = NULL, *first = NULL;
+    u_int		csum, cpri, deficit = 0;
+    mbuf_t		*m;
+#ifdef USE_HRTIME
+    hrtime_t		now;
+#else
+    struct timeval	now;
+#endif
+
+    RM_GETTIME(now);
+
+#ifdef ALTQ
+    /*
+     * if the driver peeks the top of the queue and then removes
+     * the peeked packet, we must return the same packet.
+     */
+    if (mode == ALTDQ_DEQUEUE && ifd->peekcache_) {
+	cl = ifd->peekcache_;
+	cpri = cl->pri_;
+	if (ifd->efficient_) {
+	    /* check if this class is overlimit */
+	    if (cl->undertime_.tv_sec != 0 && rmc_under_limit(cl, &now) == 0)
+		first = cl;
+	}
+	ifd->peekcache_ = NULL;
+	goto _wrr_out;
+    }
+    else {
+	/* mode == ALTDQ_PEEK || peekcache == NULL */
+	ifd->peekcache_ = NULL;
+	ifd->borrowed_[ifd->qi_] = NULL;
+    }
+#ifdef ADJUST_CUTOFF
+ again:
+#endif
+#endif /* ALTQ */
+
+    csum = ifd->csum_;
+    while (csum) {
+	/*
+	 * Loop through twice for a priority level, if some class
+	 * was unable to send a packet the first round because
+	 * of the weighted round-robin mechanism.
+	 * During the second loop at this level, deficit==2.
+	 * (This second loop is not needed if for every class,
+	 * "M[cl->pri_])" times "cl->allotment" is greater than
+	 * the byte size for the largest packet in the class.)
+	 */
+wrr_loop:
+	cpri = rmc_mask2pri[csum];
+	if ((cl = ifd->active_[cpri]) == NULL)
+	    goto _wrr_next_pri;
+	else do {
+	    if ((deficit < 2) && (cl->bytes_alloc_ <= 0))
+		cl->bytes_alloc_ += cl->w_allotment_;
+	    if (!qempty(cl->q_)) {
+#ifdef USE_HRTIME
+		if (rmc_under_limit(cl, &now)) {
+#else
+		if ((cl->undertime_.tv_sec == 0) ||
+		    rmc_under_limit(cl, &now)) {
+#endif
+		    if (cl->bytes_alloc_ > 0 || deficit > 1)
+			goto _wrr_out;
+		    else {
+			deficit = 1;
+#ifdef ALTQ
+			ifd->borrowed_[ifd->qi_] = NULL;
+#endif
+		    }
+		}
+		else if (first == NULL && cl->borrow_ != NULL)
+		    first = cl;
+	    }
+
+	    cl->bytes_alloc_ = 0;
+	    cl = cl->peer_;
+	} while (cl && (cl != ifd->active_[cpri]));
+
+	if (deficit == 1) {
+	    /* Loop on same priority level, with new deficit.  */
+	    deficit = 2;
+	    goto wrr_loop;
+	} else {
+_wrr_next_pri:
+	    /* New priority level.  */
+	    deficit = 0;
+	    csum &= ~(1 << cpri);
+	}
+    }
+
+#ifdef ADJUST_CUTOFF
+   /*
+    * no underlimit class found.  if cutoff is taking effect, increase
+    * cutoff and try again.
+    */
+   if (first != NULL && ifd->cutoff_ < ifd->root_->depth_) {
+       ifd->cutoff_++;
+       CBQTRACE(_rmc_wrr_dequeue_next, 'ojda', ifd->cutoff_);
+       goto again;
+   }
+#endif /* ADJUST_CUTOFF */
+    /*
+     * If LINK_EFFICIENCY is turned on, then the first overlimit
+     * class we encounter will send a packet if all the classes
+     * of the link-sharing structure are overlimit.
+     */
+    reset_cutoff(ifd);
+#ifdef ALTQ
+    CBQTRACE(_rmc_wrr_dequeue_next, 'otsr', ifd->cutoff_);
+#endif
+    if (!ifd->efficient_ || first == NULL)
+	return (NULL);
+
+    cl = first;
+    cpri = cl->pri_;
+    cl->sleeping_timeout_id_ = 0;
+#ifdef ALTQ
+    if (cl->sleeping_)
+	untimeout((timeout_t *)rmc_restart, cl);
+#endif	
+    cl->sleeping_ = 0;
+    ifd->borrowed_[ifd->qi_] = cl->borrow_;
+    ifd->cutoff_ = cl->borrow_->depth_;
+
+    /*
+     * Deque the packet and do the book keeping...
+     */
+_wrr_out:
+#ifdef ALTQ
+    if (mode == ALTDQ_DEQUEUE) {
+#endif
+	m = _rmc_getq(cl->q_);
+#ifdef ALTQ
+	if (m == NULL)
+	    panic("_rmc_wrr_dequeue_next");
+#endif
+	if (qempty(cl->q_)) {
+	    ifd->na_[cpri]--;
+	    if (ifd->na_[cpri] == 0)
+		ifd->csum_ &= ~(1 << cpri);
+	}
+
+	/*
+	 * Update class statistics and link data.
+	 */
+	if (cl->bytes_alloc_ > 0) {
+#ifdef ALTQ
+	    cl->bytes_alloc_ -= m_pktlen(m);
+#else
+	    cl->bytes_alloc_ -= m_len(m);
+#endif
+	}
+
+	if ((cl->bytes_alloc_ <= 0) || first == cl)
+	    ifd->active_[cl->pri_] = cl->peer_;
+	else
+	    ifd->active_[cl->pri_] = cl;
+
+	ifd->class_[ifd->qi_] = cl;
+#ifdef ALTQ
+	ifd->curlen_[ifd->qi_] = m_pktlen(m);
+#else
+	ifd->curlen_[ifd->qi_] = m_len(m);
+#endif
+	ifd->now_[ifd->qi_] = now;
+	ifd->qi_ = (ifd->qi_ + 1) % ifd->maxqueued_;
+	ifd->queued_++;
+#ifdef ALTQ
+    }
+    else {
+	/* mode == ALTDQ_PEEK */
+	m = _rmc_peekq(cl->q_);
+	ifd->peekcache_ = cl;
+    }
+#endif
+    return (m);
+}
+
+/*
+ * Dequeue & return next packet from the highest priority class that
+ * has a packet to send & has enough allocation to send it.  This
+ * routine is called by a driver whenever it needs a new packet to
+ * output.
+ */
+#ifdef ALTQ
+static mbuf_t *
+_rmc_prr_dequeue_next(struct rm_ifdat *ifd, int mode)
+#else
+static mbuf_t *
+_rmc_prr_dequeue_next(struct rm_ifdat *ifd)
+#endif
+{
+    mbuf_t		*m;
+    int			csum, cpri;
+    struct rm_class	*cl, *first = NULL;
+#ifdef USE_HRTIME
+    hrtime_t		now;
+#else
+    struct timeval	now;
+#endif
+
+    RM_GETTIME(now);
+
+#ifdef ALTQ
+    /*
+     * if the driver peeks the top of the queue and then removes
+     * the peeked packet, we must return the same packet.
+     */
+    if (mode == ALTDQ_DEQUEUE && ifd->peekcache_) {
+	cl = ifd->peekcache_;
+	cpri = cl->pri_;
+	ifd->peekcache_ = NULL;
+	goto _prr_out;
+    }
+    else {
+	/* mode == ALTDQ_PEEK || peekcache == NULL */
+	ifd->peekcache_ = NULL;
+	ifd->borrowed_[ifd->qi_] = NULL;
+    }
+#ifdef ADJUST_CUTOFF
+ again:
+#endif
+#endif /* ALTQ */
+
+    csum = ifd->csum_;
+    while (csum) {
+	cpri = rmc_mask2pri[csum];
+	if ((cl = ifd->active_[cpri]) == NULL)
+	    goto _prr_next_pri;
+	do {
+	    if (!qempty(cl->q_)) {
+#ifdef USE_HRTIME
+		if (rmc_under_limit(cl, &now))
+#else
+		if ((cl->undertime_.tv_sec == 0) ||
+		    rmc_under_limit(cl, &now))
+#endif
+		    goto _prr_out;
+		else if ((first == NULL) && (cl->borrow_ != NULL))
+		    first = cl;
+	    }
+	    cl = cl->peer_;
+	} while (cl && cl != ifd->active_[cpri]);
+_prr_next_pri:
+	csum &= ~(1 << cpri);
+    }
+
+#ifdef ADJUST_CUTOFF
+   /*
+    * no underlimit class found.  if cutoff is taking effect, increase
+    * cutoff and try again.
+    */
+   if (first != NULL && ifd->cutoff_ < ifd->root_->depth_) {
+       ifd->cutoff_++;
+       goto again;
+   }
+#endif /* ADJUST_CUTOFF */
+    /*
+     * If LINK_EFFICIENCY is turned on, then the first overlimit
+     * class we encounter will send a packet if all the classes
+     * of the link-sharing structure are overlimit.
+     */
+    reset_cutoff(ifd);
+    if (!ifd->efficient_ || first == NULL)
+	return (NULL);
+
+    cl = first;
+    cpri = cl->pri_;
+    cl->sleeping_timeout_id_ = 0;
+#ifdef ALTQ
+    if (cl->sleeping_)
+	untimeout((timeout_t *)rmc_restart, cl);
+#endif	
+    cl->sleeping_ = 0;
+    ifd->borrowed_[ifd->qi_] = cl->borrow_;
+    ifd->cutoff_ = cl->borrow_->depth_;
+
+    /*
+     * Deque the packet and do the book keeping...
+     */
+_prr_out:
+#ifdef ALTQ
+    if (mode == ALTDQ_DEQUEUE) {
+#endif
+	ifd->active_[cpri] = cl->peer_;
+	m = _rmc_getq(cl->q_);
+#ifdef ALTQ
+	if (m == NULL)
+	    panic("_rmc_prr_dequeue_next");
+#endif
+	if (qempty(cl->q_)) {
+	    ifd->na_[cpri]--;
+	    if (ifd->na_[cpri] == 0)
+		ifd->csum_ &= ~(1 << cpri);
+	}
+
+	ifd->class_[ifd->qi_] = cl;
+#ifdef ALTQ
+	ifd->curlen_[ifd->qi_] = m_pktlen(m);
+#else
+	ifd->curlen_[ifd->qi_] = m_len(m);
+#endif
+	ifd->now_[ifd->qi_] = now;
+	ifd->qi_ = (ifd->qi_ + 1) % ifd->maxqueued_;
+	ifd->queued_++;
+#ifdef ALTQ
+    }
+    else {
+	/* mode == ALTDQ_PEEK */
+	m = _rmc_peekq(cl->q_);
+	ifd->peekcache_ = cl;
+    }
+#endif
+    return (m);
+}
+
+/*
+ * mbuf_t *
+ * rmc_dequeue_next(struct rm_ifdat *ifd, struct timeval *now) - this function
+ *	is invoked by the packet driver to get the next packet to be
+ *	dequeued and output on the link.  If WRR is enabled, then the
+ *	WRR dequeue next routine will determine the next packet to sent.
+ *	Otherwise, packet-by-packet round robin is invoked.
+ *
+ *	Returns:	NULL, if a packet is not available or if all
+ *			classes are overlimit.
+ *
+ *			Otherwise, Pointer to the next packet.
+ */
+
+mbuf_t *
+#ifdef ALTQ
+rmc_dequeue_next(struct rm_ifdat *ifd, int mode)
+#else
+rmc_dequeue_next(struct rm_ifdat *ifd)
+#endif
+{
+    if (ifd == NULL)
+#ifdef ALTQ
+	panic("rmc_dequeue_next, ifd is NULL\n");
+#else
+        cmn_err(CE_PANIC, "rmc_dequeue_next, ifd is NULL\n");
+#endif
+    else if (ifd->queued_ >= ifd->maxqueued_)
+	return (NULL);
+    else if (ifd->wrr_)
+#ifdef ALTQ
+	return (_rmc_wrr_dequeue_next(ifd, mode));
+    else
+	return (_rmc_prr_dequeue_next(ifd, mode));
+#else
+        return (_rmc_wrr_dequeue_next(ifd));
+    else
+	return (_rmc_prr_dequeue_next(ifd));
+#endif
+}
+
+/*
+ * Update the utilization estimate for the packet that just completed.
+ * The packet's class & the parent(s) of that class all get their
+ * estimators updated.  This routine is called by the driver's output-
+ * packet-completion interrupt service routine.
+ */
+
+void
+rmc_update_class_util(struct rm_ifdat *ifd)
+{
+    int		idle, avgidle, pktlen;
+    rm_class_t	*cl, *borrowed;
+#ifdef ALTQ
+    rm_class_t	*borrows;
+    int pkt_time;
+    struct timeval	*nowp;
+#else /* !ALTQ */
+#ifdef USE_HRTIME
+    hrtime_t	now;
+#else
+    struct timeval	now;
+#endif
+#endif /* !ALTQ */
+
+    /*
+     * Get the most recent completed class.
+     */
+    if ((cl = ifd->class_[ifd->qo_]) == NULL) {
+#ifdef ALTQ
+	printf("rmc_update_class_util: NULL\n");
+#endif
+	return;
+    }
+
+    pktlen = ifd->curlen_[ifd->qo_];
+    borrowed = ifd->borrowed_[ifd->qo_];
+#ifdef ALTQ
+    borrows = borrowed;
+    /* count packets only for leaf classes */
+    ++cl->stats_.npackets;
+    cl->stats_.nbytes += pktlen;
+#endif
+
+    /*
+     * Run estimator on class and it's ancesstors.
+     */
+#ifdef ALTQ
+    /*
+     * rm_update_class util is designed to be called when the
+     * transfer is completed from a xmit complete interrupt,
+     * but most drivers don't implement an upcall for that.
+     * so, just use estimated completion time.
+     * as a result, ifd->qi_ and ifd->qo_ are always synced.
+     */
+    nowp = &ifd->now_[ifd->qo_];
+    /* get pkt_time (for link) in usec */
+    pkt_time = (ifd->curlen_[ifd->qo_] * ifd->ns_per_byte_) / 1000;
+    if (TV_LT(nowp, &ifd->ifnow)) {
+	TV_ADD_DELTA(&ifd->ifnow, pkt_time, &ifd->ifnow);
+    }
+    else {
+	TV_ADD_DELTA(nowp, pkt_time, &ifd->ifnow);
+    }
+#else /* !ALTQ */
+    RM_GETTIME(now);
+#endif /* !ALTQ */
+    while (cl != NULL) {
+#ifdef ALTQ
+	TV_DELTA(&ifd->ifnow, &cl->last_, idle);
+	if (idle >= 2000000) {
+	    /*
+	     * this class is idle enough, reset avgidle.
+	     * (TV_DELTA returns 2000000 us when delta is large.)
+	     */
+	    cl->avgidle_ = cl->maxidle_;
+	}
+
+	/* get pkt_time (for class) in usec */
+	if (pktlen > RM_DEFAULT_MTU) {
+	    /* safe-gard for large packets */
+	    int len = pktlen;
+	    pkt_time = 0;
+	    while (len >= RM_DEFAULT_MTU) {
+		pkt_time += cl->len2time_[RM_DEFAULT_MTU-1];
+		len -= RM_DEFAULT_MTU - 1;
+	    }
+	    pkt_time += cl->len2time_[len];
+	}
+	else
+	    pkt_time = cl->len2time_[pktlen];
+	idle -= pkt_time;
+#else /* !ALTQ */
+	TV_DELTA(&now, &cl->last_, idle);
+	idle -= cl->len2time_[pktlen];
+#endif /* !ALTQ */
+	avgidle = cl->avgidle_;
+#ifdef USE_HRTIME
+	avgidle += ((idle - avgidle) >> RM_FILTER_GAIN);
+#else
+	avgidle += idle - (avgidle >> RM_FILTER_GAIN);
+#endif
+	cl->avgidle_ = avgidle;
+	
+	/* Are we overlimit ? */
+	if (avgidle <= 0) {
+	    CBQTRACE(rmc_update_class_util, 'milo', cl->stats_.handle);
+#ifdef ALTQ
+	    /*
+	     * need some lower bound for avgidle, otherwise a borrowing
+	     * class gets unbounded penalty.
+	     */
+	    if (avgidle < cl->minidle_)
+		avgidle = cl->avgidle_ = cl->minidle_;
+#endif /* !ALTQ */
+#ifdef ALTQ
+	    /* set next idle to make avgidle 0 */
+	    pkt_time += (1 - RM_POWER) * avgidle >> RM_FILTER_GAIN;
+	    TV_ADD_DELTA(&ifd->ifnow, pkt_time, &cl->undertime_);
+#else /* !ALTQ */
+	    TV_ADD_DELTA(&now, cl->len2time_[pktlen], &cl->undertime_);
+#ifdef USE_HRTIME
+	    TV_ADD_DELTA(&cl->undertime_, (1 - RM_POWER) * avgidle,
+			 &cl->undertime_); 
+#else
+	    TV_ADD_DELTA(&cl->undertime_,
+			 ((1 - RM_POWER) * avgidle) >> RM_FILTER_GAIN,
+			 &cl->undertime_); 
+#endif
+#endif /* !ALTQ */
+	    ++cl->stats_.over;
+	} else {
+	    cl->avgidle_ = (avgidle > cl->maxidle_) ? cl->maxidle_ : avgidle;
+#ifndef USE_HRTIME
+	    cl->undertime_.tv_sec = 0;
+#endif
+#ifdef ALTQ
+	    if (cl->sleeping_) {
+		untimeout((timeout_t *)rmc_restart, cl);
+		cl->sleeping_ = 0;
+	    }
+#endif
+	}
+#ifdef ALTQ
+	if (borrows != NULL) {
+	    if (borrows != cl)
+		++cl->stats_.borrows;
+	    else
+		borrows = NULL;
+        }
+	cl->last_ = ifd->ifnow;
+#else
+	++cl->stats_.npackets;
+	cl->stats_.nbytes += pktlen;
+	cl->last_ = now;
+#endif
+	cl = cl->parent_;
+    } 
+
+    /*
+     * Check to see if cutoff needs to set to a new level.
+     */
+    cl = ifd->class_[ifd->qo_];
+    if (borrowed && (ifd->cutoff_ >= borrowed->depth_)) {
+#ifdef ALTQ
+	if ((qlen(cl->q_) <= 1) || TV_LT(nowp, &borrowed->undertime_)) {
+	    rmc_tl_satisfied(ifd, nowp);
+	    CBQTRACE(rmc_update_class_util, 'broe', ifd->cutoff_);
+	}
+	else { 
+	    ifd->cutoff_ = borrowed->depth_;
+	    CBQTRACE(rmc_update_class_util, 'ffob', borrowed->depth_);
+	}
+#else /* !ALTQ */
+	if ((qlen(cl->q_) <= 1) || TV_LT(&now, &borrowed->undertime_)) {
+	    rmc_tl_satisfied(ifd, &now);
+	    CBQTRACE(rmc_update_class_util, 'broe', ifd->cutoff_);
+	}
+	else { 
+	    ifd->cutoff_ = borrowed->depth_;
+	    CBQTRACE(rmc_update_class_util, 'ffob', borrowed->depth_);
+	}
+#endif /* !ALTQ */
+    }
+
+    /*
+     * Release class slot
+     */
+    ifd->borrowed_[ifd->qo_] = NULL;
+    ifd->class_[ifd->qo_] = NULL;
+    ifd->qo_ = (ifd->qo_ + 1) % ifd->maxqueued_;
+    ifd->queued_--;
+}
+
+/*
+ * void
+ * rmc_drop_action(struct rm_class *cl) - Generic (not protocol-specific)
+ *	over-limit action routines.  These get invoked by rmc_under_limit()
+ *	if a class with packets to send if over its bandwidth limit & can't
+ *	borrow from a parent class.
+ *
+ *	Returns: NONE
+ */
+
+void
+rmc_drop_action(struct rm_class *cl)
+{
+    mbuf_t		*m;
+    struct rm_ifdat	*ifd = cl->ifdat_;
+
+#ifdef ALTQ
+    m = _rmc_dropq(cl->q_);
+#else
+    _rmc_dropq(cl->q_);
+#endif
+    if (qempty(cl->q_)) {
+	ifd->na_[cl->pri_]--;
+	if (ifd->na_[cl->pri_] == 0)
+	    ifd->csum_ &= ~(1 << cl->pri_);
+    }
+    ++cl->stats_.drops;
+#ifdef ALTQ
+    cl->stats_.drop_bytes += m_pktlen(m);
+    m_freem(m);
+#endif
+}
+
+/*
+ * void
+ * rmc_delay_action(struct rm_class *cl) - This function is the generic CBQ
+ *	delay action routine.  It is invoked via rmc_under_limit when the
+ *	packet is discoverd to be overlimit.
+ *
+ *	Returns: NONE
+ */
+
+void
+#ifdef ALTQ
+rmc_delay_action(struct rm_class *cl, struct rm_class *borrow)
+#else
+rmc_delay_action(struct rm_class *cl)
+#endif
+{
+    int		delay;
+#ifdef ALTQ
+    int		t;
+#endif
+
+    cl->stats_.overactions++;
+#ifdef ALTQ
+    if (TV_LT(&cl->overtime_, &cl->ifdat_->ifnow))
+	cl->overtime_ = cl->ifdat_->ifnow;
+#endif
+    TV_DELTA(&cl->undertime_, &cl->overtime_, delay);
+#ifndef BORROW_OFFTIME
+    delay += cl->offtime_;
+#endif
+
+    if ((delay > 0) && !cl->sleeping_) {
+	CBQTRACE(rmc_delay_action, 'yled', cl->stats_.handle);
+#ifdef BORROW_OFFTIME
+	if (borrow != NULL) {
+	    TV_ADD_DELTA(&cl->undertime_, borrow->offtime_, &cl->undertime_);
+	    delay += borrow->offtime_;
+	}
+	else {
+	    TV_ADD_DELTA(&cl->undertime_, cl->offtime_, &cl->undertime_);
+	    delay += cl->offtime_;
+	}
+#else /* BORROW_OFFTIME */
+	TV_ADD_DELTA(&cl->undertime_, cl->offtime_, &cl->undertime_);
+#endif /* BORROW_OFFTIME */
+#ifdef USE_HRTIME
+	TV_ADD_DELTA(&cl->undertime_, -(1 - RM_POWER) * cl->avgidle_,
+		     &cl->undertime_);
+#else
+	/* this code cancels the undertime set in rmc_update_class_util. */
+	TV_ADD_DELTA(&cl->undertime_,
+		     -((1 - RM_POWER) * cl->avgidle_) >> RM_FILTER_GAIN,
+		     &cl->undertime_);
+#endif
+	cl->sleeping_ = 1;
+	cl->stats_.delays++;
+
+	/*
+	 * Since packets are phased randomly with respect to the
+	 * clock, 1 tick (the next clock tick) can be an arbitrarily
+	 * short time so we have to wait for at least two ticks.
+	 * NOTE:  If there's no other traffic, we need the timer as
+	 * a 'backstop' to restart this class.
+	 */  
+#ifdef ALTQ
+	if (delay > tick * 2)
+	    t = hzto(&cl->undertime_);
+	else
+	    t = 2;
+	timeout((timeout_t *)rmc_restart, (caddr_t)cl, t);
+#else /* !ALTQ */
+	cl->sleeping_timeout_id_ = timeout(rmc_restart,
+					   (caddr_t)cl, RM_TIMEOUT); 
+#endif /* !ALTQ */
+    }
+}
+
+/*
+ * void
+ * rmc_restart() - is just a helper routine for rmc_delay_action -- it is
+ *	called by the system timer code & is responsible checking if the
+ *	class is still sleeping (it might have been restarted as a side
+ *	effect of the queue scan on a packet arrival) and, if so, restarting
+ *	output for the class.  Inspecting the class state & restarting output
+ *	require locking the class structure.  In general the driver is
+ *	responsible for locking but this is the only routine that is not
+ *	called directly or indirectly from the interface driver so it has
+ *	know about system locking conventions.  Under bsd, locking is done
+ *	by raising IPL to splimp so that's what's implemented here.  On a
+ *	different system this would probably need to be changed.
+ *
+ *	Returns:	NONE
+ */
+
+void
+rmc_restart(struct rm_class *cl)
+{
+    struct rm_ifdat *ifd = cl->ifdat_;
+#ifdef ALTQ
+    int s;
+#endif
+
+#ifdef SOLARIS
+    cbqlock(ifd->ifp);
+#endif
+#ifdef ALTQ
+    s = splimp();
+#endif
+    if (cl->sleeping_) {
+	cl->sleeping_ = 0;
+	cl->sleeping_timeout_id_ = 0;
+	
+	if (ifd->queued_ < ifd->maxqueued_) {
+	    CBQTRACE(rmc_restart, 'trts', cl->stats_.handle);
+	    (ifd->restart)(ifd->ifp);
+	}
+    }
+#ifdef SOLARIS
+    cbqunlock(ifd->ifp);
+#endif
+#ifdef ALTQ
+    splx(s);
+#endif
+}
+
+/*
+ * void
+ * rmc_root_overlimit(struct rm_class *cl) - This the generic overlimit
+ *	handling routine for the root class of the link sharing structure.
+ *
+ *	Returns: NONE
+ */
+
+void
+#ifdef ALTQ
+rmc_root_overlimit(struct rm_class *cl, struct rm_class *borrow)
+#else
+rmc_root_overlimit(struct rm_class *cl)
+#endif
+{
+    panic("rmc_root_overlimit");
+}
+
+/*
+ * Packet Queue handling routines.  Eventually, this is to localize the
+ *	effects on the code whether queues are red queues or droptail
+ *	queues.
+ */
+
+#ifdef notyet
+static void
+_rmc_initq(class_queue_t *q)
+{
+	switch (qtype(q)) {
+	case Q_DROPTAIL:
+		break;
+#ifdef CBQ_RED
+	case Q_RED:
+		if ((q->rqp_ = red_init(...)) == NULL)
+			cmn_err(CE_PANIC, "red_init FAILED\n");
+		break;
+#endif
+	}
+}
+#endif
+
+static void
+_rmc_addq(class_queue_t *q, mbuf_t *m)
+{ 
+    mbuf_t  *m0;
+
+    switch (qtype(q)) {
+    case Q_DROPTAIL:
+	if ((m0 = qtail(q)) != NULL)
+	    m->m_act = m0->m_act;
+	else
+	    m0 = m;
+
+	m0->m_act = m;
+	qtail(q) = m;
+	qlen(q)++;
+	break;
+	
+#ifdef CBQ_RED
+    case Q_RED:
+	red_enqueue(q, m);
+	break;
+#endif
+    }
+}
+
+#ifdef ALTQ
+static mbuf_t *
+#else
+static void
+#endif
+_rmc_dropq(class_queue_t *q)
+{
+    mbuf_t  *m, *m0 = 0;
+
+    switch (qtype(q)) {
+    case Q_DROPTAIL:
+	if (qtail(q) == NULL)
+#ifdef ALTQ
+	    panic("_rmc_dropq: empty queue");
+#else
+	    cmn_err(CE_PANIC, "_rmc_dropq: empty queue");
+#endif
+	else {
+	    m = qtail(q);
+	    if (((m0 = m->m_act) != NULL) && (m0 != m))
+		m->m_act = m0->m_act;
+	    else
+		qtail(q) = NULL;
+	}
+	qlen(q)--;
+#ifndef ALTQ
+	m_freem(m0);
+#endif
+	break;
+
+#ifdef CBQ_RED
+    case Q_RED:
+#ifdef ALTQ
+	m0 = NULL;
+#endif
+	break;
+#endif
+    }
+
+#ifdef ALTQ
+    return (m0);
+#endif    
+}
+
+static mbuf_t *
+_rmc_getq(class_queue_t *q)
+{
+    mbuf_t	*m, *m0 = NULL;
+
+    switch (qtype(q)) {
+    case Q_DROPTAIL:
+	if (qtail(q) == NULL)
+	    return (NULL);
+    
+	if (((m = qtail(q)) != NULL) && ((m0 = m->m_act) != m)) {
+	    m->m_act = m0->m_act;
+	} else
+	    qtail(q) = NULL;
+	qlen(q)--;
+	break;
+
+#ifdef CBQ_RED
+    case Q_RED:
+	m0 = red_deque(q);
+	break;
+#endif
+    }
+	
+    return (m0);
+}
+
+#ifdef ALTQ
+static mbuf_t *
+_rmc_peekq(class_queue_t *q)
+{
+    mbuf_t	*m = 0;
+
+    switch (qtype(q)) {
+    case Q_DROPTAIL:
+	if ((m = qtail(q)) == NULL)
+	    return (NULL);
+	m = m->m_act;
+	break;
+
+#ifdef CBQ_RED
+    case Q_RED:
+	m = red_peekq(q);
+	break;
+#endif
+    }
+    return (m);
+}
+
+void rmc_flush(cl)
+    struct rm_class *cl;
+{
+    struct rm_ifdat *ifd = cl->ifdat_;
+    struct mbuf *m;
+    
+    /*
+     * Free packets in the packet queue
+     */
+    if (!qempty(cl->q_)) {
+	while ((m = _rmc_getq(cl->q_)) != NULL)
+	    m_freem(m);
+
+	ifd->na_[cl->pri_]--;
+	if (ifd->na_[cl->pri_] == 0)
+	    ifd->csum_ &= ~(1 << cl->pri_);
+    }
+}
+
+#ifdef CBQDEBUG
+/*
+ * DDB hook to trace cbq events:
+ *  the last 1024 events are held in a circular buffer.
+ *  use "call cbqtrace_dump(N)" to display 20 events from Nth event.
+ */
+void cbqtrace_dump(int);
+static char *rmc_funcname(void *);
+
+static struct rmc_funcs {
+    void *func;
+    char *name;
+} rmc_funcs[] = 
+{
+    rmc_init, "rmc_init",
+    rmc_queue_packet, "rmc_queue_packet",
+    rmc_under_limit, "rmc_under_limit",
+    rmc_update_class_util, "rmc_update_class_util",
+    rmc_delay_action, "rmc_delay_action",
+    rmc_restart, "rmc_restart",
+    _rmc_wrr_dequeue_next, "_rmc_wrr_dequeue_next",
+    NULL, NULL
+};
+
+static char *rmc_funcname(func)
+    void *func;
+{
+    struct rmc_funcs *fp;
+
+    for (fp = rmc_funcs; fp->func != NULL; fp++)
+	if (fp->func == func)
+	    return (fp->name);
+    return ("unknown");
+}
+
+void cbqtrace_dump(counter)
+    int counter;
+{
+    int i, *p;
+    char *cp;
+
+    counter = counter % NCBQTRACE;
+    p = (int *)&cbqtrace_buffer[counter];
+    
+    for (i=0; i<20; i++) {
+	printf("[0x%x] ", *p++);
+	printf("%s: ", rmc_funcname((void *)*p++));
+	cp = (char *)p++;
+	printf("%c%c%c%c: ", cp[0], cp[1], cp[2], cp[3]);
+	printf("%d\n",*p++);
+
+	if (p >= (int *)&cbqtrace_buffer[NCBQTRACE])
+	    p = (int *)cbqtrace_buffer;
+    }
+}
+#endif /* CBQDEBUG */
+
+#endif /* ALTQ */
+
+#endif /* CBQ */
diff -uN src-current/sys/netinet/rm_class.h src-current-ipv6/sys/netinet/rm_class.h
--- src-current/sys/netinet/rm_class.h
+++ src-current-ipv6/sys/netinet/rm_class.h
@@ -0,0 +1,418 @@
+/* $Id: rm_class.h,v 0.4 1997/10/27 02:32:42 kjc Exp $ */
+/*
+ * Copyright (c) 1991-1997 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 Network Research
+ *	Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory 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.
+ */
+
+#ifndef _NETINET_RM_CLASS_H
+#define	_NETINET_RM_CLASS_H
+
+#pragma ident "@(#)rm_class.h  1.13     97/07/24 SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef ALTQ
+#if defined(KERNEL) && !defined(_KERNEL)
+#define _KERNEL
+#endif
+#endif
+
+#ifdef _KERNEL
+/* CBQ_RED is not supported yet */
+#ifdef CBQ_RED
+#include <netinet/cbq_red.h>
+#endif
+
+#ifdef SOLARIS
+#ifndef _mbuf_
+#define	_mbuf_
+typedef mblk_t		mbuf_t;
+#define	m_act		b_next
+#define	m_freem(m0)	freemsg(m0)
+#define	m_len(m0)	msgdsize(m0)
+#define	microtime	uniqtime
+#endif
+#endif
+#ifdef ALTQ
+typedef struct mbuf		mbuf_t;
+#define	m_pktlen(m0)	((m0)->m_pkthdr.len)
+#endif
+/*
+ * Macros for dealing with time values.  We assume all times are
+ * 'timevals'.  `microtime' is used to get the best available clock
+ * resolution.  If `microtime' *doesn't* return a value that's about
+ * ten times smaller than the average packet time on the fastest
+ * link that will use these routines, a slightly different clock
+ * scheme than this one should be used.
+ * (Bias due to truncation error in this scheme will overestimate utilization
+ * and discriminate against high bandwidth classes.  To remove this bias an
+ * integrator needs to be added.  The simplest integrator uses a history of
+ * 10 * avg.packet.time / min.tick.time packet completion entries.  This is
+ * straight forward to add but we don't want to pay the extra memory
+ * traffic to maintain it if it's not necessary (occasionally a vendor
+ * accidentally builds a workstation with a decent clock - e.g., Sun & HP).)
+ */
+
+#ifndef USE_HRTIME
+
+#define	RM_GETTIME(now) microtime(&now)
+
+#define TV_LT(a, b) (((a)->tv_sec < (b)->tv_sec) ||  \
+	(((a)->tv_usec < (b)->tv_usec) && ((a)->tv_sec <= (b)->tv_sec)))
+
+#define	TV_DELTA(a, b, delta) { \
+	register int	xxs;	\
+							\
+	delta = (a)->tv_usec - (b)->tv_usec; \
+	if ((xxs = (a)->tv_sec - (b)->tv_sec)) { \
+		switch (xxs) { \
+		default: \
+			if (xxs < 0) \
+				printf("rm_class: bogus time values"); \
+			delta = 0; \
+			/* fall through */ \
+		case 2: \
+			delta += 1000000; \
+			/* fall through */ \
+		case 1: \
+			delta += 1000000; \
+			break; \
+		} \
+	} \
+}
+
+#define	TV_ADD_DELTA(a, delta, res) { \
+	register int xxus = (a)->tv_usec + (delta); \
+	\
+	(res)->tv_sec = (a)->tv_sec; \
+	while (xxus >= 1000000) { \
+		++((res)->tv_sec); \
+		xxus -= 1000000; \
+	} \
+	(res)->tv_usec = xxus; \
+}
+#else
+
+/*
+ * When USE_HRTIME is employed, these macros now use hrtime_t vals
+ * for time.  Hrtime_t is a 64-bit representation of wall-clock time on
+ * Solaris/Sparc workstations.
+ */
+
+#define RM_GETTIME(now)	(now) = gethrtime()
+
+#define TV_LT(a, b)	((*a) < (*b))
+
+#define TV_DELTA(a, b, delta) { \
+	(delta) = (*a) - (*b); \
+}
+
+#define TV_ADD_DELTA(a, delta, result) { \
+	(*result) = (*a) + (delta); \
+}
+
+#endif
+
+#define RM_DEFAULT_MTU	1536	/* XXX - Assume ethernet MTU */
+#define RM_TIMEOUT	2	/* 1 Clock tick. */
+
+#ifdef ALTQ
+#define	RM_MAXQUEUED	1	/* this isn't used in ALTQ/CBQ */
+#else
+#define	RM_MAXQUEUED	16	/* Max number of packets downstream of CBQ */
+#endif
+#define	RM_MAXPRIO	8	/* Max priority */
+#define	RM_MAXQUEUE	64	/* Max queue length */
+#define	RM_FILTER_GAIN	5	/* log2 of gain, e.g., 5 => 31/32 */
+#define RM_POWER	(1 << RM_FILTER_GAIN)
+#define	RM_MAXDEPTH	32
+#define	RM_NS_PER_SEC	(1000000000)
+
+#ifdef ALTQ
+
+typedef struct _rm_class_stats_ {
+	u_int		handle;
+	u_int		depth;
+
+	int		npackets;	/* packets sent in this class */
+	int		nbytes;		/* bytes sent in this class */
+	int		over;		/* # times went over limit */
+	int		borrows;	/* # times tried to borrow */
+	int		drops;		/* # times dropped packets */
+	int		overactions;	/* # times invoked overlimit action */
+	int		delays;		/* # times invoked delay actions */
+
+	/* added for ALTQ */
+	int		drop_bytes;	/* bytes dropped in this class */
+} rm_class_stats_t;
+
+#else /* !ALTQ */
+
+#ifndef _CLASS_STATS
+#define	_CLASS_STATS
+
+typedef struct _class_stats_ {
+	u_int		handle;
+	u_int		depth;
+
+	int		npackets;	/* packets sent in this class */
+	int		nbytes;		/* bytes sent in this class */
+	int		over;		/* # times went over limit */
+	int		borrows;	/* # times tried to borrow */
+	int		drops;		/* # times dropped packets */
+	int		overactions;	/* # times invoked overlimit action */
+	int		delays;		/* # times invoked delay actions */
+} class_stats_t;
+
+#endif /* _CLASS_STATS_ */
+#endif /* !ALTQ */
+
+typedef struct rm_ifdat		rm_ifdat_t;
+typedef struct rm_class		rm_class_t;
+typedef struct _class_queue_	class_queue_t;
+
+/*
+ * Packet Queue strcutures and macros to manipulate them.
+ */
+struct _class_queue_ {
+	mbuf_t	*tail_;		/* Tail of packet queue */
+	mbuf_t	*head_;		/* Head of packet queue */
+
+	int	qlen_;		/* Queue length (in number of packets) */
+	int	qlim_;		/* Queue limit (in number of packets*) */
+	int	qthresh_;	/* Queue threshold for formal link sharing */
+	int	qtype_;		/* QUeue type */
+
+#ifdef CBQ_RED
+	redq_t	*rqp_;		/* RED Queue state pointer */
+#endif
+};
+
+/*
+ * Packet Queue types: RED or DROPTAIL.
+ */
+#define Q_DROPTAIL	0x00
+#define Q_RED		0x01
+
+#define qtype(q)	(q)->qtype_		/* Get queue type */
+#define qthresh(q)	(q)->qthresh_		/* Threshold for satifaction */
+#define qlimit(q)	(q)->qlim_		/* Max packets to be queued */
+#define	qlen(q)		(q)->qlen_		/* Current queue length. */
+#define	qtail(q)	(q)->tail_		/* Tail of the queue */
+#define qhead(q)	(q)->head_		/* Head of the queue */
+
+#define qempty(q)	((q)->qlen_ == 0)	/* Is the queue empty?? */
+#define q_is_red(q)	((q)->qtype_ == Q_RED)	/* Is the queue a red queue */
+
+/*
+ * CBQ Class state structure
+ */
+struct rm_class {
+	class_queue_t	*q_;		/* Queue of packets */
+	rm_ifdat_t	*ifdat_;			
+	int		pri_;		/* Class priority. */
+	int		depth_;		/* Class depth */
+	u_int		maxrate_;	/* Bytes per second for this class. */
+	u_int		allotment_;	/* Fraction of link bandwidth. */
+	u_int		w_allotment_;	/* Weighted allotment for WRR */
+	int		bytes_alloc_;	/* Allocation for round of WRR */
+
+	int		avgidle_;
+	int		maxidle_;
+	int		minidle_;
+	int		offtime_;
+	int		sleeping_;	/* != 0 if delaying */
+	int		sleeping_timeout_id_;	
+
+	int		leaf_;		/* Note whether leaf class or not.*/
+
+	rm_class_t	*children_;	/* Children of this class */
+	rm_class_t	*next_;		/* Next pointer, used if child */
+
+	rm_class_t	*peer_;		/* Peer class */
+	rm_class_t	*borrow_;	/* Borrow class */
+	rm_class_t	*parent_;	/* Parent class */
+
+#ifdef ALTQ
+	void	(*overlimit)(struct rm_class *, struct rm_class *);
+#else
+	void	(*overlimit)(struct rm_class *);  /* Over limit action. */
+#endif
+	void	(*drop)(struct rm_class *);       /* Class drop action. */
+
+#ifdef USE_HRTIME
+	hrtime_t	undertime_;
+	hrtime_t	last_;
+	hrtime_t	overtime_;
+#else
+	struct timeval	undertime_;	/* time can next send */
+	struct timeval	last_;		/* time last packet sent */
+	struct timeval	overtime_;
+#endif
+#ifdef ALTQ
+	rm_class_stats_t	stats_;		/* Class Statistics */
+#else
+	class_stats_t	stats_;		/* Class Statistics */
+#endif
+
+	int		len2time_[RM_DEFAULT_MTU];	/* Packet times */
+};
+
+/*
+ * CBQ Interface state
+ */
+struct rm_ifdat {
+	int		queued_;	/* # pkts queued downstream */
+	int		efficient_;	/* Link Efficency bit */
+	int		wrr_;		/* Enable Weighted Round-Robin */
+	u_long		ns_per_byte_;	/* Link byte speed. */
+	int		maxqueued_;	/* Max packets to queue */
+	int		maxpkt_;	/* Max packet size. */
+	int		qi_;		/* In/out pointers for downstream */
+	int		qo_;		/* packets */
+
+	/*
+	 * Active class state and WRR state.
+	 */
+	rm_class_t	*active_[RM_MAXPRIO];	/* Active cl's in each pri */
+	int		na_[RM_MAXPRIO];	/* # of active cl's in a pri */
+	rm_class_t	*classes_[RM_MAXPRIO];	/* All classes in pri */
+	int		num_[RM_MAXPRIO];	/* # of cl's per pri */
+	int		alloc_[RM_MAXPRIO];	/* Byte Allocation */
+	u_long		M_[RM_MAXPRIO];		/* WRR weights. */
+
+	/*
+	 * Network Interface/Solaris Queue state pointer.
+	 */
+#ifdef SOLARIS
+	queue_t		*ifp;
+#else
+	struct ifnet	*ifp;
+#endif
+	rm_class_t	*default_;	/* Default Pkt class, BE */
+	rm_class_t	*root_;		/* Root Link class. */
+	rm_class_t	*ctl_;		/* Control Traffic class. */
+	void		(*restart)(struct ifnet *);	/* Restart routine. */
+
+	/*
+	 * Current packet downstream packet state and dynamic state.
+	 */
+	rm_class_t	*borrowed_[RM_MAXQUEUED]; /* Class borrowed last */
+	rm_class_t	*class_[RM_MAXQUEUED];	/* class sending */
+	int		curlen_[RM_MAXQUEUED];	/* Current pktlen */
+#ifndef USE_HRTIME
+	struct timeval	now_[RM_MAXQUEUED];	/* Current packet time. */
+#else
+	hrtime_t	now_[RM_MAXQUEUED];	/* Current packet time. */
+#endif
+	int		is_overlimit_[RM_MAXQUEUED];/* Current packet time. */
+
+	int		cutoff_;	/* Cut-off depth for borrowing */
+	int		csum_;		/* Class priorites with active cl's */
+	int		hsum_;		/* Class priorites that exist in the */
+					/* class hierararchy. */
+#ifdef ALTQ
+	struct timeval	ifnow;		/* expected xmit completion time */
+        rm_class_t	*peekcache_;	/* cached rm_class by peek operation */
+#endif
+};
+
+#if defined(SOLARIS) || defined(ALTQ)
+
+#ifdef ALTQ
+extern void		rmc_init(struct ifnet *ifp, struct rm_ifdat *ifdat,
+				u_int nsecPerByte,
+				void (*restart)(struct ifnet *ifp),
+				int maxq, int maxqueued, u_int maxidle,
+				int minidle, u_int offtime, int wrr,
+				int workconserving);
+#else
+extern void		rmc_init(queue_t *q, struct rm_ifdat *ifdat,
+				u_int nsecPerByte, void (*restart)(),
+				int maxq, int maxqueued, u_int maxidle,
+				int minidle, u_int offtime, int wrr,
+				int workconserving);
+#endif
+#ifndef USE_HRTIME
+extern int		rmc_is_under_limit(struct rm_class *, struct timeval *);
+extern int		rmc_under_limit(struct rm_class *, struct timeval *);
+extern void		rmc_tl_satisfied(struct rm_ifdat *, struct timeval *);
+#else
+extern int		rmc_is_under_limit(struct rm_class *, hrtime_t *);
+extern int		rmc_under_limit(struct rm_class *, hrtime_t *);
+extern void		rmc_tl_satisfied(struct rm_ifdat *, hrtime_t *);
+#endif
+
+extern void		rmc_drop_action(struct rm_class *);
+#ifdef ALTQ
+extern void		rmc_delay_action(struct rm_class *, struct rm_class *);
+extern int		rmc_queue_packet(struct rm_class *, mbuf_t *);
+extern mbuf_t		*rmc_dequeue_next(struct rm_ifdat *, int);
+#else
+extern void		rmc_delay_action(struct rm_class *);
+extern void		rmc_queue_packet(struct rm_class *, mbuf_t *);
+extern mbuf_t		*rmc_dequeue_next(struct rm_ifdat *);
+#endif
+extern void		rmc_update_class_util(struct rm_ifdat *);
+#ifdef ALTQ
+extern rm_class_t	*rmc_newclass(int pri, struct rm_ifdat *ifdat,
+				u_int nsecPerByte,
+				void (*action)(struct rm_class *,
+					       struct rm_class *),
+				int maxq, struct rm_class *parent,
+				struct rm_class *borrow, u_int maxidle,
+				int minidle, u_int offtime);
+#else
+extern rm_class_t	*rmc_newclass(int pri, struct rm_ifdat *ifdat,
+				u_int nsecPerByte, void (*action)(),
+				int maxq, struct rm_class *parent,
+				struct rm_class *borrow, u_int maxidle,
+				int minidle, u_int offtime);
+#endif
+extern void		rmc_delete_class(struct rm_ifdat *, struct rm_class *);
+extern void		rmc_restart(struct rm_class *);
+#ifdef ALTQ
+extern void		rmc_root_overlimit(struct rm_class *, struct rm_class *);
+extern void		rmc_flush(struct rm_class *cl);
+#else
+extern void		rmc_root_overlimit(struct rm_class *);
+#endif
+
+#endif /* SOLARIS || ALTQ */
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !NETINET_RM_CLASS_H */
diff -uN src-current/sys/netinet/rm_class_debug.h src-current-ipv6/sys/netinet/rm_class_debug.h
--- src-current/sys/netinet/rm_class_debug.h
+++ src-current-ipv6/sys/netinet/rm_class_debug.h
@@ -0,0 +1,87 @@
+/* $Id: rm_class_debug.h,v 1.1 1997/07/02 06:06:07 kjc Exp $ */
+/*
+ * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
+ */
+
+#ifndef _NETINET_RM_CLASS_DEBUG_H
+#define	_NETINET_RM_CLASS_DEBUG_H
+
+#pragma ident	"@(#)rm_class_debug.h	1.5	97/05/19 SMI"
+
+/*
+ * Cbq debugging macros
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef	CBQDEBUG
+
+#ifndef NCBQTRACE
+#define	NCBQTRACE (16 * 1024)
+#endif
+
+/*
+ * To view the trace output, using adb, type:
+ *	adb -k /dev/ksyms /dev/mem <cr>, then type
+ *	cbqtrace_count/D to get the count, then type
+ *	cbqtrace_buffer,0tcount/Dp4C" "Xn
+ *	This will dump the trace buffer from 0 to count.
+ */
+
+struct cbqtrace {
+	int count;
+	int function;		/* address of function */
+	int trace_action;	/* descriptive 4 characters */
+	int object;		/* object operated on */
+};
+
+extern struct cbqtrace cbqtrace_buffer[];
+extern struct cbqtrace *cbqtrace_ptr;
+extern int cbqtrace_count;
+
+#define	CBQTRACEINIT() {				\
+	if (cbqtrace_ptr == NULL)		\
+		cbqtrace_ptr = cbqtrace_buffer; \
+	else { \
+		cbqtrace_ptr = cbqtrace_buffer; \
+		bzero((void *)cbqtrace_ptr, sizeof(cbqtrace_buffer)); \
+		cbqtrace_count = 0; \
+	} \
+}
+
+#ifdef ALTQ
+#define	LOCK_TRACE()	splimp()
+#define	UNLOCK_TRACE(x)	splx(x)
+#else
+#define	LOCK_TRACE()	(uint_t) ddi_enter_critical()
+#define	UNLOCK_TRACE(x)	ddi_exit_critical((uint_t) x)
+#endif
+
+#define	CBQTRACE(func, act, obj) {		\
+	int __s = LOCK_TRACE();			\
+	int *_p = &cbqtrace_ptr->count;	\
+	*_p++ = ++cbqtrace_count;		\
+	*_p++ = (int)(func);			\
+	*_p++ = (int)(act);			\
+	*_p++ = (int)(obj);			\
+	if ((struct cbqtrace *)(void *)_p >= &cbqtrace_buffer[NCBQTRACE])\
+		cbqtrace_ptr = cbqtrace_buffer; \
+	else					\
+		cbqtrace_ptr = (struct cbqtrace *)(void *)_p; \
+	UNLOCK_TRACE(__s);			\
+	}
+#else
+
+/* If no tracing, define no-ops */
+#define	CBQTRACEINIT()
+#define	CBQTRACE(a, b, c)
+
+#endif	/* !CBQDEBUG */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _NETINET_RM_CLASS_DEBUG_H */
diff -uN src-current/sys/netinet/sha.c src-current-ipv6/sys/netinet/sha.c
--- src-current/sys/netinet/sha.c
+++ src-current-ipv6/sys/netinet/sha.c
@@ -0,0 +1,8 @@
+/* NIST Secure Hash Algorithm */
+/* heavily modified by Uwe Hollerbach uh@alumni.caltech edu */
+/* from Peter C. Gutmann's implementation as found in */
+/* Applied Cryptography by Bruce Schneier */
+
+/* NIST's proposed modification to SHA of 7/11/94 may be */
+/* activated by defining USE_MODIFIED_SHA */
+
diff -uN src-current/sys/netinet/sha.h src-current-ipv6/sys/netinet/sha.h
--- src-current/sys/netinet/sha.h
+++ src-current-ipv6/sys/netinet/sha.h
@@ -0,0 +1,25 @@
+#ifndef _NETINET_SHA_H_
+#define _NETINET_SHA_H_
+
+/* NIST Secure Hash Algorithm */
+/* heavily modified from Peter C. Gutmann's implementation */
+
+/* Useful defines & typedefs */
+
+#define UNROLL_LOOPS		1
+#define USE_MODIFIED_SHA	1
+
+typedef u_int8_t BYTE;
+typedef u_int32_t LONG;
+
+#define SHA_BLOCKSIZE		64
+#define SHA_DIGESTSIZE		20
+
+typedef struct {
+    LONG digest[5];		/* message digest */
+    LONG count_lo, count_hi;	/* 64-bit bit count */
+    LONG data[16];		/* SHA data buffer */
+} SHA_INFO;
+
+
+#endif
diff -uN src-current/sys/netinet/tcp6_input.c src-current-ipv6/sys/netinet/tcp6_input.c
--- src-current/sys/netinet/tcp6_input.c
+++ src-current-ipv6/sys/netinet/tcp6_input.c
@@ -0,0 +1,2340 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994
+ *	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.
+ *
+ *	@(#)tcp_input.c	8.5 (Berkeley) 4/10/94
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/proc.h>		/* for proc0 declaration */
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+
+#include <machine/cpu.h>	/* before tcp_seq.h, for tcp_random18() */
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp6_var.h>
+#include <netinet/tcpip.h>
+#include <netinet/tcp_debug.h>
+
+extern	int tcprexmtthresh;
+extern	int tcp_log_in_vain;
+
+struct	tcp6hdrs tcp_savetr;
+
+static void	tcp6_dooptions __P((struct tcpcb *,
+	u_char *, int, struct tcp6hdrs *, struct tcpopt *));
+static void	tcp6_pulloutofband __P((struct socket *,
+	struct tcp6hdrs *, struct mbuf *));
+static int	tcp6_reass __P((struct tcpcb *,
+	struct tcp6hdrs *, struct mbuf *));
+
+/*
+ * Insert segment tr into reassembly queue of tcp with
+ * control block tp.  Return TH_FIN if reassembly now includes
+ * a segment with FIN.  The macro form does the common case inline
+ * (segment is the next to be received on an established connection,
+ * and the queue is empty), avoiding linkage into and removal
+ * from the queue and repetition of various conversions.
+ * Set DELACK for segments received in order, but ack immediately
+ * when segments are out of order (so fast retransmit can work).
+ */
+#ifdef TCP_ACK_HACK
+#define	TCP6_REASS(tp, tr, m, so, flags) { \
+	if ((tr)->tr_seq == (tp)->rcv_nxt && \
+	    (tp)->seg_next6 == (struct tcp6hdrs *)(tp) && \
+	    (tp)->t_state == TCPS_ESTABLISHED) { \
+		if ((tr)->tr_flags & TH_PUSH) \
+			tp->t_flags |= TF_ACKNOW; \
+		else \
+			tp->t_flags |= TF_DELACK; \
+		(tp)->rcv_nxt += (tr)->tr_len; \
+		flags = (tr)->tr_flags & TH_FIN; \
+		tcpstat.tcps_rcvpack++;\
+		tcpstat.tcps_rcvbyte += (tr)->tr_len;\
+		ip6_reachhint(tp->t_inpcb); \
+		sbappend(&(so)->so_rcv, (m)); \
+		sorwakeup(so); \
+	} else { \
+		(flags) = tcp6_reass((tp), (tr), (m)); \
+		tp->t_flags |= TF_ACKNOW; \
+	} \
+}
+#else
+#define	TCP6_REASS(tp, tr, m, so, flags) { \
+	if ((tr)->tr_seq == (tp)->rcv_nxt && \
+	    (tp)->seg_next6 == (struct tcp6hdrs *)(tp) && \
+	    (tp)->t_state == TCPS_ESTABLISHED) { \
+		tp->t_flags |= TF_DELACK; \
+		(tp)->rcv_nxt += (tr)->tr_len; \
+		flags = (tr)->tr_flags & TH_FIN; \
+		tcpstat.tcps_rcvpack++;\
+		tcpstat.tcps_rcvbyte += (tr)->tr_len;\
+		ip6_reachhint(tp->t_inpcb); \
+		sbappend(&(so)->so_rcv, (m)); \
+		sorwakeup(so); \
+	} else { \
+		(flags) = tcp6_reass((tp), (tr), (m)); \
+		tp->t_flags |= TF_ACKNOW; \
+	} \
+}
+#endif
+
+static int
+tcp6_reass(tp, tr, m)
+	struct tcpcb *tp;
+	struct tcp6hdrs *tr;
+	struct mbuf *m;
+{
+	struct tcp6hdrs *q;
+	struct socket *so = tp->t_inpcb->inp_socket;
+	int flags;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_TCP1)
+		printf("tcp6_reass(%p,%p,%p)\n", tp, tr, m);
+#endif
+	/*
+	 * Call with tr==0 after become established to
+	 * force pre-ESTABLISHED data up to user socket.
+	 */
+	if (tr == 0)
+		goto present;
+
+	/*
+	 * Find a segment which begins after this one does.
+	 */
+	for (q = tp->seg_next6; q != (struct tcp6hdrs *)tp; q = q->tr_next)
+		if (SEQ_GT(q->tr_seq, tr->tr_seq))
+			break;
+
+	/*
+	 * If there is a preceding segment, it may provide some of
+	 * our data already.  If so, drop the data from the incoming
+	 * segment.  If it provides all of our data, drop us.
+	 */
+	if (q->tr_prev != (struct tcp6hdrs *)tp) {
+		int i;
+		q = q->tr_prev;
+		/* conversion to int (in i) handles seq wraparound */
+		i = q->tr_seq + q->tr_len - tr->tr_seq;
+		if (i > 0) {
+			if (i >= tr->tr_len) {
+				tcpstat.tcps_rcvduppack++;
+				tcpstat.tcps_rcvdupbyte += tr->tr_len;
+				m_freem(m);
+				/*
+				 * Try to present any queued data
+				 * at the left window edge to the user.
+				 * This is needed after the 3-WHS
+				 * completes.
+				 */
+				goto present;	/* ??? */
+			}
+			m_adj(m, i);
+			tr->tr_len -= i;
+			tr->tr_seq += i;
+		}
+		q = q->tr_next;
+	}
+	tcpstat.tcps_rcvoopack++;
+	tcpstat.tcps_rcvoobyte += tr->tr_len;
+	REASS_MBUF6(tr) = m;		/* XXX */
+
+	/*
+	 * While we overlap succeeding segments trim them or,
+	 * if they are completely covered, dequeue them.
+	 */
+	while (q != (struct tcp6hdrs *)tp) {
+		int i = (tr->tr_seq + tr->tr_len) - q->tr_seq;
+		if (i <= 0)
+			break;
+		if (i < q->tr_len) {
+			q->tr_seq += i;
+			q->tr_len -= i;
+			m_adj(REASS_MBUF6(q), i);
+			break;
+		}
+		q = q->tr_next;
+		m = REASS_MBUF6(q->tr_prev);
+		remque(q->tr_prev);
+		m_freem(m);
+	}
+
+	/*
+	 * Stick new segment in its place.
+	 */
+	insque(tr, q->tr_prev);
+
+present:
+	/*
+	 * Present data to user, advancing rcv_nxt through
+	 * completed sequence space.
+	 */
+	if (!TCPS_HAVEESTABLISHED(tp->t_state))
+		return (0);
+	tr = tp->seg_next6;
+	if (tr == (struct tcp6hdrs *)tp || tr->tr_seq != tp->rcv_nxt)
+		return (0);
+	do {
+		tp->rcv_nxt += tr->tr_len;
+		flags = tr->tr_flags & TH_FIN;
+		remque(tr);
+		m = REASS_MBUF6(tr);
+		tr = tr->tr_next;
+		if (so->so_state & SS_CANTRCVMORE)
+			m_freem(m);
+		else
+			sbappend(&so->so_rcv, m);
+	} while (tr != (struct tcp6hdrs *)tp && tr->tr_seq == tp->rcv_nxt);
+	ip6_reachhint(tp->t_inpcb);
+	sorwakeup(so);
+	return (flags);
+}
+
+/*
+ * TCP input routine, follows pages 65-76 of the
+ * protocol specification dated September, 1981 very closely.
+ */
+void
+tcp6_input(m, arg)
+	struct mbuf *m;
+	int arg;
+{
+	struct mbuf *opts = (struct mbuf *)arg;
+	struct tcp6hdrs *tr;
+	struct inpcb *inp;
+	struct ip6ovck *ipc;
+	u_char *optp = NULL;
+	int optlen = 0;
+	int len, tlen, off;
+	struct tcpcb *tp = 0;
+	int trflags;
+	struct socket *so = 0;
+	int todrop, acked, ourfinisacked, needoutput = 0;
+	u_int32_t iflowinfo, oflowinfo = 0;
+	struct in6_addr laddr;
+	int atype, flags, hlim;
+	struct ip_soptions *ipsec_list;
+	int dropsocket = 0;
+	int iss = 0;
+	u_long trwin;
+	struct tcpopt to;		/* options in this segment */
+	struct rmxp_tao *taop;		/* pointer to our TAO cache entry */
+	struct rmxp_tao	tao_noncached;	/* in case there's no cached entry */
+#ifdef TCPDEBUG
+	short ostate = 0;
+#endif
+
+	bzero((char *)&to, sizeof(to));
+
+	tcpstat.tcps_rcvtotal++;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_TCP0)
+		printf("tcp6_input(%p,%p)\n", m, opts);
+#endif
+	/*
+	 * Get IPv6 and TCP header together in first mbuf.
+	 * Note: IPv6 leaves IPv6 header in first mbuf.
+	 * add place for queue links.
+	 */
+	M_PREPEND(m,
+		  sizeof(struct tcp6hdrs) - sizeof(struct tcpip6hdr),
+		  M_DONTWAIT);
+	if (m == 0) {
+		tcpstat.tcps_rcvshort++;
+		if (opts)
+			m_freem(opts);
+		return;
+	}
+	tr = mtod(m, struct tcp6hdrs *);
+	if (m->m_len < sizeof (struct tcp6hdrs)) {
+		if ((m = m_pullup(m, sizeof (struct tcp6hdrs))) == 0) {
+			tcpstat.tcps_rcvshort++;
+			if (opts)
+				m_freem(opts);
+			return;
+		}
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_TCP1)
+			printf("tcp6_input pullup %p for %d\n",
+			       m, sizeof (struct tcp6hdrs));
+#endif
+		tr = mtod(m, struct tcp6hdrs *);
+	}
+	tr->tr_prev = tr->tr_next = 0;
+
+	/*
+	 * Checksum extended TCP header and data.
+	 */
+	iflowinfo = tr->tr_head & IPV6_FLOWINFO_PRIFLOW;
+	tlen = tr->tr_len;
+	len = tlen + sizeof(struct tcp6hdrs) - sizeof(struct tcphdr);
+	hlim = tr->tr_hlim;
+	ipc = (struct ip6ovck *)&tr->tr_i6;
+	ipc->ih6_wrd1 = ipc->ih6_wrd0 = 0;
+	ipc->ih6_pr = IPPROTO_TCP;
+	ipc->ih6_len = htons(tlen);
+	if (tr->tr_sum = in_cksum(m, len)) {
+		tcpstat.tcps_rcvbadsum++;
+		if (opts)
+			m_freem(opts);
+		goto drop;
+	}
+
+	/*
+	 * Check that TCP offset makes sense,
+	 * pull out TCP options and adjust length.		XXX
+	 */
+	off = tr->tr_off << 2;
+	if (off < sizeof (struct tcphdr) || off > tlen) {
+		tcpstat.tcps_rcvbadoff++;
+		if (opts)
+			m_freem(opts);
+		goto drop;
+	}
+	tlen -= off;
+	tr->tr_len = tlen;
+	off -= sizeof (struct tcphdr);
+	if (off > 0) {
+		len = off + sizeof(struct tcp6hdrs);
+		if (m->m_len < len) {
+			if (len <= MHLEN)
+				m = m_pullup(m, len);
+			else
+				m = m_clpullup(m, len);
+			if (m == 0) {
+				tcpstat.tcps_rcvshort++;
+				if (opts)
+					m_freem(opts);
+				return;
+			}
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_TCP1)
+				printf("tcp6_input pullup %p for %d\n",
+				       m, len);
+#endif
+			tr = mtod(m, struct tcp6hdrs *);
+		}
+		optlen = off;
+		optp = mtod(m, u_char *) + sizeof (struct tcp6hdrs);
+	}
+	trflags = tr->tr_flags;
+
+	/*
+	 * Convert TCP protocol specific fields to host format.
+	 */
+	NTOHL(tr->tr_seq);
+	NTOHL(tr->tr_ack);
+	NTOHS(tr->tr_win);
+	NTOHS(tr->tr_urp);
+
+	/*
+	 * Drop TCP, IP headers and TCP options.
+	 */
+	m->m_data += sizeof(struct tcp6hdrs) + off;
+	m->m_len  -= sizeof(struct tcp6hdrs) + off;
+
+	/*
+	 * Locate pcb for segment.
+	 */
+findpcb:
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_TCP0)
+		printf("tcp6_input findpcb src %s/%d dst %s/%d len %d\n",
+		       ip6_sprintf(&tr->tr_src),
+		       ntohs(tr->tr_sport),
+		       ip6_sprintf(&tr->tr_dst),
+		       ntohs(tr->tr_dport),
+		       tr->tr_len);
+#endif
+	inp = in6_pcblookup_hash(&tcbinfo, &tr->tr_src, tr->tr_sport,
+	    &tr->tr_dst, tr->tr_dport, 1);
+
+	/*
+	 * If the state is CLOSED (i.e., TCB does not exist) then
+	 * all data in the incoming segment is discarded.
+	 * If the TCB exists but is in CLOSED state, it is embryonic,
+	 * but should either do a listen or a connect soon.
+	 */
+	if (inp == NULL) {
+		if (tcp_log_in_vain && trflags & TH_SYN)
+			log(LOG_INFO,
+			    "Connection attempt to TCP %s:%d from %s:%d\n",
+			    ip6_sprintf(&tr->tr_dst),
+			    ntohs(tr->tr_dport),
+			    ip6_sprintf(&tr->tr_src),
+			    ntohs(tr->tr_sport));
+		if (opts)
+			m_freem(opts);
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_TCP0)
+			printf("tcp6_input no inpcb\n");
+#endif
+		goto dropwithreset;
+	}
+	if ((inp->inp_flags & INP_NEEDAUTH) &&
+	    ((m->m_flags & M_AUTH) == 0 ||
+	     !ipsec_match(inp, m, opts, INP_NEEDAUTH))) {
+		if (opts)
+			m_freem(opts);
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_TCP0)
+			printf("tcp6_input no AH\n");
+#endif
+		if (tp)
+			goto drop;
+		else
+			goto dropwithreset;
+	}
+	if ((inp->inp_flags & INP_NEEDCRYPT) &&
+	    ((m->m_flags & M_CRYPT) == 0 ||
+	     !ipsec_match(inp, m, opts, INP_NEEDCRYPT))) {
+		if (opts)
+			m_freem(opts);
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_TCP0)
+			printf("tcp6_input no ESP\n");
+#endif
+		if (tp)
+			goto drop;
+		else
+			goto dropwithreset;
+	}
+	tp = intotcpcb(inp);
+	if (tp == 0) {
+		if (opts)
+			m_freem(opts);
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_TCP0)
+		printf("tcp6_input no tcpcb\n");
+#endif
+		goto dropwithreset;
+	}
+	if (tp->t_state == TCPS_CLOSED) {
+		if (opts)
+			m_freem(opts);
+		goto drop;
+	}
+
+	/* Unscale the window into a 32-bit value. */
+	if ((trflags & TH_SYN) == 0)
+		trwin = tr->tr_win << tp->snd_scale;
+	else
+		trwin = tr->tr_win;
+
+	so = inp->inp_socket;
+	if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) {
+#ifdef notyet
+		if (so->so_options & SO_DEBUG) {
+			ostate = tp->t_state;
+			tcp_savetr = *tr;
+		}
+#endif
+		if (so->so_options & SO_ACCEPTCONN) {
+			struct tcpcb *tp0 = tp;
+			struct socket *so2;
+			if ((trflags & (TH_RST|TH_ACK|TH_SYN)) != TH_SYN) {
+				/*
+				 * Note: dropwithreset makes sure we don't
+				 * send a RST in response to a RST.
+				 */
+				if (trflags & TH_ACK) {
+					tcpstat.tcps_badsyn++;
+					goto dropwithreset;
+				}
+				goto drop;
+			}
+			so2 = sonewconn(so, 0);
+			if (so2 == 0) {
+				tcpstat.tcps_listendrop++;
+				so2 = sodropablereq(so);
+				if (so2) {
+					tcp6_drop(sototcpcb(so2), ETIMEDOUT);
+					so2 = sonewconn(so, 0);
+				}
+				if (!so2)
+					goto drop;
+			}
+			so = so2;
+			/*
+			 * This is ugly, but ....
+			 *
+			 * Mark socket as temporary until we're
+			 * committed to keeping it.  The code at
+			 * ``drop'' and ``dropwithreset'' check the
+			 * flag dropsocket to see if the temporary
+			 * socket created here should be discarded.
+			 * We mark the socket as discardable until
+			 * we're committed to it below in TCPS_LISTEN.
+			 */
+			dropsocket++;
+			oflowinfo = inp->inp_oflowinfo;
+			ipsec_list = &inp->inp_soptions;
+			flags = inp->inp_flags;
+			inp = (struct inpcb *)so->so_pcb;
+			inp->inp_flags |= flags;
+			inp->inp_flags &= ~INP_COMPATV4;
+			COPY_ADDR6(tr->tr_dst, inp->inp_laddr6);
+			inp->inp_latype = IPATYPE_IPV6;
+			inp->inp_lport = tr->tr_dport;
+			if (in_pcbinshash(inp) != 0) {
+				/*
+				 * Undo the assignments above if we failed to put
+				 * the PCB on the hash lists.
+				 */
+				CLR_ADDR6(inp->inp_laddr6);
+				inp->inp_latype = IPATYPE_UNBD;
+				inp->inp_lport = 0;
+				goto drop;
+			}
+
+			if (opts)
+				opts = opt6_reverse(&tr->tr_i6, opts);
+			inp->inp_options = opts;
+			opts = (struct mbuf *)0;
+			ipsec_duplist(ipsec_list, &inp->inp_soptions);
+			tp = intotcpcb(inp);
+			tp->t_state = TCPS_LISTEN;
+			tp->t_flags |= tp0->t_flags & (TF_NOPUSH|TF_NOOPT);
+
+			/* RFC1644 options are too large */
+			tp->t_flags &= ~TF_REQ_CC;
+
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_TCP0)
+				printf("tcp6_input newconn0\n");
+#endif
+			/* Compute proper scaling value from buffer space */
+			while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
+			   TCP_MAXWIN << tp->request_r_scale < so->so_rcv.sb_hiwat)
+				tp->request_r_scale++;
+		}
+	}
+	/* after the last place where opts are useful: */
+	if ((so->so_options & SO_ACCEPTCONN) == 0) {
+		if (opts)
+			m_freem(opts);
+		opts = (struct mbuf *)0;
+	}
+	inp->inp_rcvttl = hlim;
+	inp->inp_rcvif = m->m_pkthdr.rcvif;
+
+	/*
+	 * Segment received on connection.
+	 * Reset idle time and keep-alive timer.
+	 */
+	tp->t_idle = 0;
+	if (TCPS_HAVEESTABLISHED(tp->t_state))
+		tp->t_timer[TCPT_KEEP] = tcp_keepidle;
+
+	/*
+	 * Process options if not in LISTEN state,
+	 * else do it below (after getting remote address).
+	 */
+	if (tp->t_state != TCPS_LISTEN)
+		tcp6_dooptions(tp, optp, optlen, tr, &to);
+
+#ifdef ALTQ_ECN
+	/* if congestion experienced, set ECN bit in the next output. */
+	if (((ntohl(iflowinfo) >> 20) & (IPTOS_ECT|IPTOS_CE)) == (IPTOS_ECT|IPTOS_CE))
+		tp->t_flags |= TF_RCVD_CE;
+#endif
+	/* 
+	 * Header prediction: check for the two common cases
+	 * of a uni-directional data xfer.  If the packet has
+	 * no control flags, is in-sequence, the window didn't
+	 * change and we're not retransmitting, it's a
+	 * candidate.  If the length is zero and the ack moved
+	 * forward, we're the sender side of the xfer.  Just
+	 * free the data acked & wake any higher level process
+	 * that was blocked waiting for space.  If the length
+	 * is non-zero and the ack didn't move, we're the
+	 * receiver side.  If we're getting packets in-order
+	 * (the reassembly queue is empty), add the data to
+	 * the socket buffer and note that we need a delayed ack.
+	 * Make sure that the hidden state-flags are also off.
+	 * Since we check for TCPS_ESTABLISHED above, it can only
+	 * be TH_NEEDSYN.
+	 */
+	if (tp->t_state == TCPS_ESTABLISHED &&
+#ifdef ALTQ_ECN
+	    (trflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ECN|TH_ACK)) == TH_ACK &&
+#else
+	    (trflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&
+#endif
+	    ((tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN)) == 0) &&
+	    ((to.to_flag & TOF_TS) == 0 ||
+	     TSTMP_GEQ(to.to_tsval, tp->ts_recent)) &&
+	    /*
+	     * Using the CC option is compulsory if once started:
+	     *   the segment is OK if no T/TCP was negotiated or
+	     *   if the segment has a CC option equal to CCrecv
+	     */
+	    ((tp->t_flags & (TF_REQ_CC|TF_RCVD_CC)) != (TF_REQ_CC|TF_RCVD_CC) ||
+	     (to.to_flag & TOF_CC) != 0 && to.to_cc == tp->cc_recv) &&
+	    tr->tr_seq == tp->rcv_nxt &&
+	    trwin && trwin == tp->snd_wnd &&
+	    tp->snd_nxt == tp->snd_max) {
+
+		/* 
+		 * If last ACK falls within this segment's sequence numbers,
+		 * record the timestamp.
+		 * NOTE that the test is modified according to the latest
+		 * proposal of the tcplw@cray.com list (Braden 1993/04/26).
+		 */
+		if ((to.to_flag & TOF_TS) != 0 &&
+		   SEQ_LEQ(tr->tr_seq, tp->last_ack_sent)) {
+			tp->ts_recent_age = tcp_now;
+			tp->ts_recent = to.to_tsval;
+		}
+
+		if (tr->tr_len == 0) {
+			if (SEQ_GT(tr->tr_ack, tp->snd_una) &&
+			    SEQ_LEQ(tr->tr_ack, tp->snd_max) &&
+			    tp->snd_cwnd >= tp->snd_wnd &&
+			    tp->t_dupacks < tcprexmtthresh) {
+				/*
+				 * this is a pure ack for outstanding data.
+				 */
+				++tcpstat.tcps_predack;
+				if ((to.to_flag & TOF_TS) != 0)
+					tcp_xmit_timer(tp,
+					    tcp_now - to.to_tsecr + 1);
+				else if (tp->t_rtt &&
+					    SEQ_GT(tr->tr_ack, tp->t_rtseq))
+					tcp_xmit_timer(tp, tp->t_rtt);
+				acked = tr->tr_ack - tp->snd_una;
+				tcpstat.tcps_rcvackpack++;
+				tcpstat.tcps_rcvackbyte += acked;
+				sbdrop(&so->so_snd, acked);
+				tp->snd_una = tr->tr_ack;
+#ifdef ALTQ_ECN
+				/* sync snc_rcvr with snd_una */
+				if (SEQ_GT(tp->snd_una, tp->snd_rcvr))
+					tp->snd_rcvr = tp->snd_una;
+#endif
+				m_freem(m);
+				/* some progress has been done */
+				ip6_reachhint(tp->t_inpcb);
+
+				/*
+				 * If all outstanding data are acked, stop
+				 * retransmit timer, otherwise restart timer
+				 * using current (possibly backed-off) value.
+				 * If process is waiting for space,
+				 * wakeup/selwakeup/signal.  If data
+				 * are ready to send, let tcp6_output
+				 * decide between more output or persist.
+				 */
+				if (tp->snd_una == tp->snd_max)
+					tp->t_timer[TCPT_REXMT] = 0;
+				else if (tp->t_timer[TCPT_PERSIST] == 0)
+					tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+
+				if (so->so_snd.sb_flags & SB_NOTIFY)
+					sowwakeup(so);
+				if (so->so_snd.sb_cc)
+					(void) tcp6_output(tp);
+				return;
+			}
+		} else if (tr->tr_ack == tp->snd_una &&
+		    tp->seg_next6 == (struct tcp6hdrs *)tp &&
+		    tr->tr_len <= sbspace(&so->so_rcv)) {
+			/*
+			 * this is a pure, in-sequence data packet
+			 * with nothing on the reassembly queue and
+			 * we have enough buffer space to take it.
+			 */
+			++tcpstat.tcps_preddat;
+			tp->rcv_nxt += tr->tr_len;
+			tcpstat.tcps_rcvpack++;
+			tcpstat.tcps_rcvbyte += tr->tr_len;
+			/* some progress has been done */
+			ip6_reachhint(tp->t_inpcb);
+			/*
+			 * Add data to socket buffer.
+			 */
+			sbappend(&so->so_rcv, m);
+			sorwakeup(so);
+#ifdef TCP_ACK_HACK
+			/*
+			 * If this is a short packet, then ACK now - with Nagel
+			 *	congestion avoidance sender won't send more until
+			 *	he gets an ACK.
+			 */
+			if (tr->tr_flags & TH_PUSH) {
+				tp->t_flags |= TF_ACKNOW;
+				tcp_output(tp);
+			} else {
+				tp->t_flags |= TF_DELACK;
+			}
+#else
+			tp->t_flags |= TF_DELACK;
+#endif
+			return;
+		}
+	}
+
+	/*
+	 * Calculate amount of space in receive window,
+	 * and then do TCP input processing.
+	 * Receive window is amount of space in rcv queue,
+	 * but not less than advertised window.
+	 */
+	{ int win;
+
+	win = sbspace(&so->so_rcv);
+	if (win < 0)
+		win = 0;
+	tp->rcv_wnd = imax(win, (int)(tp->rcv_adv - tp->rcv_nxt));
+	}
+
+	switch (tp->t_state) {
+
+	/*
+	 * If the state is LISTEN then ignore segment if it contains an RST.
+	 * If the segment contains an ACK then it is bad and send a RST.
+	 * If it does not contain a SYN then it is not interesting; drop it.
+	 * Don't bother responding if the destination was a broadcast.
+	 * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial
+	 * tp->iss, and send a segment:
+	 *     <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>
+	 * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss.
+	 * Fill in remote peer address fields if not previously specified.
+	 * Enter SYN_RECEIVED state, and process any other fields of this
+	 * segment in this state.
+	 */
+	case TCPS_LISTEN: {
+		struct sockaddr_in6 *sin;
+
+		if (trflags & TH_RST)
+			goto drop;
+		if (trflags & TH_ACK)
+			goto dropwithreset;
+		if ((trflags & TH_SYN) == 0)
+			goto drop;
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_TCP0)
+			printf("tcp6_input connecting\n");
+#endif
+		/*
+		 * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN
+		 */
+		if (IS_MULTIADDR6(tr->tr_dst))
+			goto drop;
+		MALLOC(sin, struct sockaddr_in6 *, sizeof *sin, M_SONAME,
+		       M_NOWAIT);
+		if (sin == NULL)
+			goto drop;
+		sin->sin6_family = AF_INET6;
+		sin->sin6_len = sizeof(*sin);
+		sin->sin6_port = tr->tr_sport;
+		/* flow ID must be randomized! */
+		if (oflowinfo & IPV6_FLOWINFO_FLOWLABEL) {
+			oflowinfo &= IPV6_FLOWINFO_PRIORITY;
+			oflowinfo |= IPV6_SET_FLOWLABEL(flow6_rand(0));
+		} else
+			oflowinfo &= IPV6_FLOWINFO_PRIORITY;
+		sin->sin6_flowinfo = oflowinfo;
+		COPY_ADDR6(tr->tr_src, sin->sin6_addr);
+		COPY_ADDR6(inp->inp_laddr6, laddr);
+		atype = inp->inp_latype;
+		if (atype == IPATYPE_UNBD) {
+			COPY_ADDR6(tr->tr_dst, inp->inp_laddr6);
+			inp->inp_latype = IPATYPE_IPV6;
+		}
+		if (in6_pcbconnect(inp, (struct sockaddr *)sin, &proc0)) {
+			COPY_ADDR6(laddr, inp->inp_laddr6);
+			inp->inp_latype = atype;
+			FREE(sin, M_SONAME);
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_TCP0)
+				printf("tcp6_input connect failed\n");
+#endif
+			goto drop;
+		}
+		FREE(sin, M_SONAME);
+		inp->inp_flags &= ~INP_COMPATV4;
+		inp->inp_iflowinfo = iflowinfo;
+		tp->t_template = tcp_template(tp);
+		if (tp->t_template == 0) {
+			tp = tcp6_drop(tp, ENOBUFS);
+			dropsocket = 0;		/* socket is already gone */
+			goto drop;
+		}
+		if ((taop = tcp_gettaocache(inp)) == NULL) {
+			taop = &tao_noncached;
+			bzero(taop, sizeof(*taop));
+		}
+		tcp6_dooptions(tp, optp, optlen, tr, &to);
+		if (iss)
+			tp->iss = iss;
+		else
+			tp->iss = tcp_iss;
+		tcp_iss += TCP_ISSINCR/4;
+		tp->irs = tr->tr_seq;
+		tcp_sendseqinit(tp);
+		tcp_rcvseqinit(tp);
+#ifdef ALTQ_ECN
+		tp->snd_rcvr = tp->snd_una;
+		/* if ECN flag bit is set, peer is ECN capable */
+		if (tcp_ecn && (trflags & TH_ECN)) {
+			tp->t_flags |= TF_REQ_ECN;
+			trflags &= ~TH_ECN;
+		}
+#endif
+		/*
+		 * Initialization of the tcpcb for transaction;
+		 *   set SND.WND = SEG.WND,
+		 *   initialize CCsend and CCrecv.
+		 */
+		tp->snd_wnd = trwin;	/* initial send-window */
+		tp->cc_send = CC_INC(tcp_ccgen);
+		tp->cc_recv = to.to_cc;
+		/*
+		 * Perform TAO test on incoming CC (SEG.CC) option, if any.
+		 * - compare SEG.CC against cached CC from the same host,
+		 *	if any.
+		 * - if SEG.CC > chached value, SYN must be new and is accepted
+		 *	immediately: save new CC in the cache, mark the socket
+		 *	connected, enter ESTABLISHED state, turn on flag to
+		 *	send a SYN in the next segment.
+		 *	A virtual advertised window is set in rcv_adv to
+		 *	initialize SWS prevention.  Then enter normal segment
+		 *	processing: drop SYN, process data and FIN.
+		 * - otherwise do a normal 3-way handshake.
+		 */
+		if ((to.to_flag & TOF_CC) != 0) {
+		    if (taop->tao_cc != 0 && CC_GT(to.to_cc, taop->tao_cc)) {
+			taop->tao_cc = to.to_cc;
+			tp->t_state = TCPS_ESTABLISHED;
+
+			/*
+			 * If there is a FIN, or if there is data and the
+			 * connection is local, then delay SYN,ACK(SYN) in
+			 * the hope of piggy-backing it on a response
+			 * segment.  Otherwise must send ACK now in case
+			 * the other side is slow starting.
+			 */
+			if ((trflags & TH_FIN) || (tr->tr_len != 0 &&
+#ifdef notyet
+			    in6_localaddr(inp->inp_faddr6)
+#else
+			    0
+#endif
+			     ))
+				tp->t_flags |= (TF_DELACK | TF_NEEDSYN);
+			else
+				tp->t_flags |= (TF_ACKNOW | TF_NEEDSYN);
+
+			/*
+			 * Limit the `virtual advertised window' to TCP_MAXWIN
+			 * here.  Even if we requested window scaling, it will
+			 * become effective only later when our SYN is acked.
+			 */
+			tp->rcv_adv += min(tp->rcv_wnd, TCP_MAXWIN);
+			tcpstat.tcps_connects++;
+			soisconnected(so);
+			tp->t_timer[TCPT_KEEP] = tcp_keepinit;
+			dropsocket = 0;		/* committed to socket */
+			tcpstat.tcps_accepts++;
+			goto trimthenstep6;
+		    }
+		/* else do standard 3-way handshake */
+		} else {
+		    /*
+		     * No CC option, but maybe CC.NEW:
+		     *   invalidate cached value.
+		     */
+		     taop->tao_cc = 0;
+		}
+		/*
+		 * TAO test failed or there was no CC option,
+		 *    do a standard 3-way handshake.
+		 */
+		tp->t_flags |= TF_ACKNOW;
+		tp->t_state = TCPS_SYN_RECEIVED;
+		tp->t_timer[TCPT_KEEP] = tcp_keepinit;
+		dropsocket = 0;		/* committed to socket */
+		tcpstat.tcps_accepts++;
+		ip6_reachhint(inp);
+		goto trimthenstep6;
+		}
+
+	/*
+	 * If the state is SYN_SENT:
+	 *	if seg contains an ACK, but not for our SYN, drop the input.
+	 *	if seg contains a RST, then drop the connection.
+	 *	if seg does not contain SYN, then drop it.
+	 * Otherwise this is an acceptable SYN segment
+	 *	initialize tp->rcv_nxt and tp->irs
+	 *	if seg contains ack then advance tp->snd_una
+	 *	if SYN has been acked change to ESTABLISHED else SYN_RCVD state
+	 *	arrange for segment to be acked (eventually)
+	 *	continue processing rest of data/controls, beginning with URG
+	 */
+	case TCPS_SYN_SENT:
+		if ((taop = tcp_gettaocache(inp)) == NULL) {
+			taop = &tao_noncached;
+			bzero(taop, sizeof(*taop));
+		}
+
+		if ((trflags & TH_ACK) &&
+		    (SEQ_LEQ(tr->tr_ack, tp->iss) ||
+		     SEQ_GT(tr->tr_ack, tp->snd_max))) {
+			/*
+			 * If we have a cached CCsent for the remote host,
+			 * hence we haven't just crashed and restarted,
+			 * do not send a RST.  This may be a retransmission
+			 * from the other side after our earlier ACK was lost.
+			 * Our new SYN, when it arrives, will serve as the
+			 * needed ACK.
+			 */
+			if (taop->tao_ccsent != 0)
+				goto drop;
+			else
+				goto dropwithreset;
+		}
+		if (trflags & TH_RST) {
+			if (trflags & TH_ACK)
+				tp = tcp6_drop(tp, ECONNREFUSED);
+			goto drop;
+		}
+		if ((trflags & TH_SYN) == 0)
+			goto drop;
+		tp->snd_wnd = tr->tr_win;	/* initial send window */
+		tp->cc_recv = to.to_cc;		/* foreign CC */
+
+		tp->irs = tr->tr_seq;
+		tcp_rcvseqinit(tp);
+#ifdef ALTQ_ECN
+		tp->snd_rcvr = tp->snd_una;
+		/* if ECN flag bit is set, peer is ECN capable */
+		if (tcp_ecn && (trflags & TH_ECN)) {
+			tp->t_flags |= TF_REQ_ECN;
+			trflags &= ~TH_ECN;
+		}
+#endif
+		if (trflags & TH_ACK) {
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_TCP0)
+				printf("tcp6_input try connected\n");
+#endif
+			/*
+			 * Our SYN was acked.  If segment contains CC.ECHO
+			 * option, check it to make sure this segment really
+			 * matches our SYN.  If not, just drop it as old
+			 * duplicate, but send an RST if we're still playing
+			 * by the old rules.  If no CC.ECHO option, make sure
+			 * we don't get fooled into using T/TCP.
+			 */
+			if (to.to_flag & TOF_CCECHO) {
+				if (tp->cc_send != to.to_ccecho)
+					if (taop->tao_ccsent != 0)
+						goto drop;
+					else
+						goto dropwithreset;
+			} else
+				tp->t_flags &= ~TF_RCVD_CC;
+			tcpstat.tcps_connects++;
+			soisconnected(so);
+			/* Do window scaling on this connection? */
+			if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==
+				(TF_RCVD_SCALE|TF_REQ_SCALE)) {
+				tp->snd_scale = tp->requested_s_scale;
+				tp->rcv_scale = tp->request_r_scale;
+			}
+			/* Segment is acceptable, update cache if undefined. */
+			if (taop->tao_ccsent == 0)
+				taop->tao_ccsent = to.to_ccecho;
+
+			tp->rcv_adv += tp->rcv_wnd;
+			tp->snd_una++;		/* SYN is acked */
+			/*
+			 * If there's data, delay ACK; if there's also a FIN
+			 * ACKNOW will be turned on later.
+			 */
+			if (tr->tr_len != 0)
+				tp->t_flags |= TF_DELACK;
+			else
+				tp->t_flags |= TF_ACKNOW;
+			/*
+			 * Received <SYN,ACK> in SYN_SENT[*] state.
+			 * Transitions:
+			 *	SYN_SENT  --> ESTABLISHED
+			 *	SYN_SENT* --> FIN_WAIT_1
+			 */
+			if (tp->t_flags & TF_NEEDFIN) {
+				tp->t_state = TCPS_FIN_WAIT_1;
+				tp->t_flags &= ~TF_NEEDFIN;
+				trflags &= ~TH_SYN;
+			} else {
+				tp->t_state = TCPS_ESTABLISHED;
+				tp->t_timer[TCPT_KEEP] = tcp_keepidle;
+			}
+		} else {
+		/*
+		 *  Received initial SYN in SYN-SENT[*] state => simul-
+		 *  taneous open.  If segment contains CC option and there is
+		 *  a cached CC, apply TAO test; if it succeeds, connection is
+		 *  half-synchronized.  Otherwise, do 3-way handshake:
+		 *        SYN-SENT -> SYN-RECEIVED
+		 *        SYN-SENT* -> SYN-RECEIVED*
+		 *  If there was no CC option, clear cached CC value.
+		 */
+			tp->t_flags |= TF_ACKNOW;
+			tp->t_timer[TCPT_REXMT] = 0;
+			if (to.to_flag & TOF_CC) {
+				if (taop->tao_cc != 0 &&
+				    CC_GT(to.to_cc, taop->tao_cc)) {
+					/*
+					 * update cache and make transition:
+					 *        SYN-SENT -> ESTABLISHED*
+					 *        SYN-SENT* -> FIN-WAIT-1*
+					 */
+					taop->tao_cc = to.to_cc;
+					if (tp->t_flags & TF_NEEDFIN) {
+						tp->t_state = TCPS_FIN_WAIT_1;
+						tp->t_flags &= ~TF_NEEDFIN;
+					} else {
+						tp->t_state = TCPS_ESTABLISHED;
+						tp->t_timer[TCPT_KEEP] = tcp_keepidle;
+					}
+					tp->t_flags |= TF_NEEDSYN;
+				} else
+					tp->t_state = TCPS_SYN_RECEIVED;
+			} else {
+				/* CC.NEW or no option => invalidate cache */
+				taop->tao_cc = 0;
+				tp->t_state = TCPS_SYN_RECEIVED;
+			}
+		}
+
+trimthenstep6:
+		/*
+		 * Advance tr->tr_seq to correspond to first data byte.
+		 * If data, trim to stay within window,
+		 * dropping FIN if necessary.
+		 */
+		tr->tr_seq++;
+		if (tr->tr_len > tp->rcv_wnd) {
+			todrop = tr->tr_len - tp->rcv_wnd;
+			m_adj(m, -todrop);
+			tr->tr_len = tp->rcv_wnd;
+			trflags &= ~TH_FIN;
+			tcpstat.tcps_rcvpackafterwin++;
+			tcpstat.tcps_rcvbyteafterwin += todrop;
+		}
+		tp->snd_wl1 = tr->tr_seq - 1;
+		tp->rcv_up = tr->tr_seq;
+		/*
+		 *  Client side of transaction: already sent SYN and data.
+		 *  If the remote host used T/TCP to validate the SYN,
+		 *  our data will be ACK'd; if so, enter normal data segment
+		 *  processing in the middle of step 5, ack processing.
+		 *  Otherwise, goto step 6.
+		 */
+ 		if (trflags & TH_ACK)
+			goto process_ACK;
+		goto step6;
+	/*
+	 * If the state is LAST_ACK or CLOSING or TIME_WAIT:
+	 *	if segment contains a SYN and CC [not CC.NEW] option:
+	 *              if state == TIME_WAIT and connection duration > MSL,
+	 *                  drop packet and send RST;
+	 *
+	 *		if SEG.CC > CCrecv then is new SYN, and can implicitly
+	 *		    ack the FIN (and data) in retransmission queue.
+	 *                  Complete close and delete TCPCB.  Then reprocess
+	 *                  segment, hoping to find new TCPCB in LISTEN state;
+	 *
+	 *		else must be old SYN; drop it.
+	 *      else do normal processing.
+	 */
+	case TCPS_LAST_ACK:
+	case TCPS_CLOSING:
+	case TCPS_TIME_WAIT:
+		if ((trflags & TH_SYN) &&
+		    (to.to_flag & TOF_CC) && tp->cc_recv != 0) {
+			if (tp->t_state == TCPS_TIME_WAIT &&
+					tp->t_duration > TCPTV_MSL)
+				goto dropwithreset;
+			if (CC_GT(to.to_cc, tp->cc_recv)) {
+				tp = tcp6_close(tp);
+				goto findpcb;
+			}
+			else
+				goto drop;
+		}
+ 		break;  /* continue normal processing */
+	}
+
+	/*
+	 * States other than LISTEN or SYN_SENT.
+	 * First check timestamp, if present.
+	 * Then check the connection count, if present.
+	 * Then check that at least some bytes of segment are within
+	 * receive window.  If segment begins before rcv_nxt,
+	 * drop leading data (and SYN); if nothing left, just ack.
+	 * 
+	 * RFC 1323 PAWS: If we have a timestamp reply on this segment
+	 * and it's less than ts_recent, drop it.
+	 */
+	if ((to.to_flag & TOF_TS) != 0 && (trflags & TH_RST) == 0 &&
+	    tp->ts_recent && TSTMP_LT(to.to_tsval, tp->ts_recent)) {
+
+		/* Check to see if ts_recent is over 24 days old.  */
+		if ((int)(tcp_now - tp->ts_recent_age) > TCP_PAWS_IDLE) {
+			/*
+			 * Invalidate ts_recent.  If this segment updates
+			 * ts_recent, the age will be reset later and ts_recent
+			 * will get a valid value.  If it does not, setting
+			 * ts_recent to zero will at least satisfy the
+			 * requirement that zero be placed in the timestamp
+			 * echo reply when ts_recent isn't valid.  The
+			 * age isn't reset until we get a valid ts_recent
+			 * because we don't want out-of-order segments to be
+			 * dropped when ts_recent is old.
+			 */
+			tp->ts_recent = 0;
+		} else {
+			tcpstat.tcps_rcvduppack++;
+			tcpstat.tcps_rcvdupbyte += tr->tr_len;
+			tcpstat.tcps_pawsdrop++;
+			goto dropafterack;
+		}
+	}
+
+	/*
+	 * T/TCP mechanism
+	 *   If T/TCP was negotiated and the segment doesn't have CC,
+	 *   or if it's CC is wrong then drop the segment.
+	 *   RST segments do not have to comply with this.
+	 */
+	if ((tp->t_flags & (TF_REQ_CC|TF_RCVD_CC)) == (TF_REQ_CC|TF_RCVD_CC) &&
+	    ((to.to_flag & TOF_CC) == 0 || tp->cc_recv != to.to_cc) &&
+	    (trflags & TH_RST) == 0)
+ 		goto dropafterack;
+
+	todrop = tp->rcv_nxt - tr->tr_seq;
+	if (todrop > 0) {
+		if (trflags & TH_SYN) {
+			trflags &= ~TH_SYN;
+			tr->tr_seq++;
+			if (tr->tr_urp > 1)
+				tr->tr_urp--;
+			else
+				trflags &= ~TH_URG;
+			todrop--;
+		}
+		/*
+		 * Following if statement from Stevens, vol. 2, p. 960.
+		 */
+		if (todrop > tr->tr_len
+		    || (todrop == tr->tr_len && (trflags & TH_FIN) == 0)) {
+			/*
+			 * Any valid FIN must be to the left of the window.
+			 * At this point the FIN must be a duplicate or out
+			 * of sequence; drop it.
+			 */
+			trflags &= ~TH_FIN;
+
+			/*
+			 * Send an ACK to resynchronize and drop any data.
+			 * But keep on processing for RST or ACK.
+			 */
+			tp->t_flags |= TF_ACKNOW;
+			todrop = tr->tr_len;
+			tcpstat.tcps_rcvduppack++;
+			tcpstat.tcps_rcvdupbyte += todrop;
+		} else {
+			tcpstat.tcps_rcvpartduppack++;
+			tcpstat.tcps_rcvpartdupbyte += todrop;
+		}
+		m_adj(m, todrop);
+		tr->tr_seq += todrop;
+		tr->tr_len -= todrop;
+		if (tr->tr_urp > todrop)
+			tr->tr_urp -= todrop;
+		else {
+			trflags &= ~TH_URG;
+			tr->tr_urp = 0;
+		}
+	}
+
+	/*
+	 * If new data are received on a connection after the
+	 * user processes are gone, then RST the other end.
+	 */
+	if ((so->so_state & SS_NOFDREF) &&
+	    tp->t_state > TCPS_CLOSE_WAIT && tr->tr_len) {
+		tp = tcp6_close(tp);
+		tcpstat.tcps_rcvafterclose++;
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_TCP0)
+			printf("tcp6_input connection closed\n");
+#endif
+		goto dropwithreset;
+	}
+
+	/*
+	 * If segment ends after window, drop trailing data
+	 * (and PUSH and FIN); if nothing left, just ACK.
+	 */
+	todrop = (tr->tr_seq+tr->tr_len) - (tp->rcv_nxt+tp->rcv_wnd);
+	if (todrop > 0) {
+		tcpstat.tcps_rcvpackafterwin++;
+		if (todrop >= tr->tr_len) {
+			tcpstat.tcps_rcvbyteafterwin += tr->tr_len;
+			/*
+			 * If a new connection request is received
+			 * while in TIME_WAIT, drop the old connection
+			 * and start over if the sequence numbers
+			 * are above the previous ones.
+			 */
+			if (trflags & TH_SYN &&
+			    tp->t_state == TCPS_TIME_WAIT &&
+			    SEQ_GT(tr->tr_seq, tp->rcv_nxt)) {
+				iss = tp->rcv_nxt + TCP_ISSINCR;
+				tp = tcp6_close(tp);
+				goto findpcb;
+			}
+			/*
+			 * If window is closed can only take segments at
+			 * window edge, and have to drop data and PUSH from
+			 * incoming segments.  Continue processing, but
+			 * remember to ack.  Otherwise, drop segment
+			 * and ack.
+			 */
+			if (tp->rcv_wnd == 0 && tr->tr_seq == tp->rcv_nxt) {
+				tp->t_flags |= TF_ACKNOW;
+				tcpstat.tcps_rcvwinprobe++;
+			} else
+				goto dropafterack;
+		} else
+			tcpstat.tcps_rcvbyteafterwin += todrop;
+		m_adj(m, -todrop);
+		tr->tr_len -= todrop;
+		trflags &= ~(TH_PUSH|TH_FIN);
+	}
+
+	/*
+	 * If last ACK falls within this segment's sequence numbers,
+	 * record its timestamp.
+	 * NOTE that the test is modified according to the latest
+	 * proposal of the tcplw@cray.com list (Braden 1993/04/26).
+	 */
+	if ((to.to_flag & TOF_TS) != 0 &&
+	    SEQ_LEQ(tr->tr_seq, tp->last_ack_sent)) {
+		tp->ts_recent_age = tcp_now;
+		tp->ts_recent = to.to_tsval;
+	}
+
+	/*
+	 * If the RST bit is set examine the state:
+	 *    SYN_RECEIVED STATE:
+	 *	If passive open, return to LISTEN state.
+	 *	If active open, inform user that connection was refused.
+	 *    ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES:
+	 *	Inform user that connection was reset, and close tcb.
+	 *    CLOSING, LAST_ACK, TIME_WAIT STATES
+	 *	Close the tcb.
+	 */
+	if (trflags&TH_RST)
+#ifdef DIAGNOSTIC
+	{
+	if (ip6printfs & D6_TCP0)		
+		printf("tcp6_input received RST\n");
+#endif
+	switch (tp->t_state) {
+	case TCPS_SYN_RECEIVED:
+		so->so_error = ECONNREFUSED;
+		goto close;
+
+	case TCPS_ESTABLISHED:
+	case TCPS_FIN_WAIT_1:
+	case TCPS_FIN_WAIT_2:
+	case TCPS_CLOSE_WAIT:
+		so->so_error = ECONNRESET;
+	close:
+		tp->t_state = TCPS_CLOSED;
+		tcpstat.tcps_drops++;
+		tp = tcp6_close(tp);
+		goto drop;
+
+	case TCPS_CLOSING:
+	case TCPS_LAST_ACK:
+	case TCPS_TIME_WAIT:
+		tp = tcp6_close(tp);
+		goto drop;
+	}
+#ifdef DIAGNOSTIC
+	}
+#endif
+
+	/*
+	 * If a SYN is in the window, then this is an
+	 * error and we send an RST and drop the connection.
+	 */
+	if (trflags & TH_SYN) {
+		tp = tcp6_drop(tp, ECONNRESET);
+		goto dropwithreset;
+	}
+
+	/*
+	 * If the ACK bit is off:  if in SYN-RECEIVED state or SENDSYN
+	 * flag is on (half-synchronized state), then queue data for
+	 * later processing; else drop segment and return.
+	 */
+	if ((trflags & TH_ACK) == 0) {
+		if (tp->t_state == TCPS_SYN_RECEIVED ||
+		    (tp->t_flags & TF_NEEDSYN))
+			goto step6;
+		else
+			goto drop;
+	}
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_TCP0)
+		printf("tcp6_input received ACK\n");
+#endif
+	/*
+	 * Ack processing.
+	 */
+	switch (tp->t_state) {
+
+	/*
+	 * In SYN_RECEIVED state if the ack ACKs our SYN then enter
+	 * ESTABLISHED state and continue processing, otherwise
+	 * send an RST.
+	 */
+	case TCPS_SYN_RECEIVED:
+		if (SEQ_GT(tp->snd_una, tr->tr_ack) ||
+		    SEQ_GT(tr->tr_ack, tp->snd_max))
+			goto dropwithreset;
+
+		tcpstat.tcps_connects++;
+		soisconnected(so);
+		/* Do window scaling? */
+		if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==
+			(TF_RCVD_SCALE|TF_REQ_SCALE)) {
+			tp->snd_scale = tp->requested_s_scale;
+			tp->rcv_scale = tp->request_r_scale;
+		}
+		/*
+		 * Upon successful completion of 3-way handshake,
+		 * update cache.CC if it was undefined, pass any queued
+		 * data to the user, and advance state appropriately.
+		 */
+		if ((taop = tcp_gettaocache(inp)) != NULL &&
+		    taop->tao_cc == 0)
+			taop->tao_cc = tp->cc_recv;
+
+		/*
+		 * Make transitions:
+		 *      SYN-RECEIVED  -> ESTABLISHED
+		 *      SYN-RECEIVED* -> FIN-WAIT-1
+		 */
+		if (tp->t_flags & TF_NEEDFIN) {
+			tp->t_state = TCPS_FIN_WAIT_1;
+			tp->t_flags &= ~TF_NEEDFIN;
+		} else {
+			tp->t_state = TCPS_ESTABLISHED;
+			tp->t_timer[TCPT_KEEP] = tcp_keepidle;
+		}
+		/*
+		 * If segment contains data or ACK, will call tcp_reass()
+		 * later; if not, do so now to pass queued data to user.
+		 */
+		if (tr->tr_len == 0 && (trflags & TH_FIN) == 0)
+			(void) tcp6_reass(tp, (struct tcp6hdrs *)0,
+			    (struct mbuf *)0);
+		tp->snd_wl1 = tr->tr_seq - 1;
+		/* fall into ... */
+
+	/*
+	 * In ESTABLISHED state: drop duplicate ACKs; ACK out of range
+	 * ACKs.  If the ack is in the range
+	 *	tp->snd_una < tr->tr_ack <= tp->snd_max
+	 * then advance tp->snd_una to tr->tr_ack and drop
+	 * data from the retransmission queue.  If this ACK reflects
+	 * more up to date window information we update our window information.
+	 */
+	case TCPS_ESTABLISHED:
+	case TCPS_FIN_WAIT_1:
+	case TCPS_FIN_WAIT_2:
+	case TCPS_CLOSE_WAIT:
+	case TCPS_CLOSING:
+	case TCPS_LAST_ACK:
+	case TCPS_TIME_WAIT:
+
+#ifdef ALTQ_ECN
+		/*
+		 * if we receive ECN notify and we are not already in
+		 * receovery phase, reduce cwnd by half but don't slow-
+		 * start.
+		 */
+		if (tcp_ecn && (trflags & TH_ECN)) {
+			if (SEQ_GEQ(tp->snd_una, tp->snd_rcvr)) {
+				u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 /
+					tp->t_maxseg;
+				if (win < 2)
+					win = 2;
+				tp->snd_ssthresh = win * tp->t_maxseg;
+				tp->snd_cwnd = tp->snd_ssthresh;
+				/*
+				 * advance snd_rcvr to snd_max not to
+				 * reduce cwnd again until all outstanding
+				 * packets are acked.
+				 */
+				tp->snd_rcvr = tp->snd_max;
+			}
+		}
+#endif /* ALTQ_ECN */
+		    
+		if (SEQ_LEQ(tr->tr_ack, tp->snd_una)) {
+			if (tr->tr_len == 0 && trwin == tp->snd_wnd) {
+				tcpstat.tcps_rcvdupack++;
+				/*
+				 * If we have outstanding data (other than
+				 * a window probe), this is a completely
+				 * duplicate ack (ie, window info didn't
+				 * change), the ack is the biggest we've
+				 * seen and we've seen exactly our rexmt
+				 * threshhold of them, assume a packet
+				 * has been dropped and retransmit it.
+				 * Kludge snd_nxt & the congestion
+				 * window so we send only this one
+				 * packet.
+				 *
+				 * We know we're losing at the current
+				 * window size so do congestion avoidance
+				 * (set ssthresh to half the current window
+				 * and pull our congestion window back to
+				 * the new ssthresh).
+				 *
+				 * Dup acks mean that packets have left the
+				 * network (they're now cached at the receiver)
+				 * so bump cwnd by the amount in the receiver
+				 * to keep a constant cwnd packets in the
+				 * network.
+				 */
+				if (tp->t_timer[TCPT_REXMT] == 0 ||
+				    tr->tr_ack != tp->snd_una)
+					tp->t_dupacks = 0;
+				else if (++tp->t_dupacks == tcprexmtthresh) {
+					tcp_seq onxt = tp->snd_nxt;
+#ifdef ALTQ_ECN
+					if (SEQ_LT(tp->snd_una, tp->snd_rcvr)) {
+						/*
+						 * we are in recovery phase
+						 * and have already halved
+						 * cwnd within a roundtrip.
+						 * don't reduce cwnd again.
+						 */
+					}
+					else {
+#endif /* ALTQ_ECN */
+					u_int win =
+					    min(tp->snd_wnd, tp->snd_cwnd) / 2 /
+						tp->t_maxseg;
+
+					if (win < 2)
+						win = 2;
+					tp->snd_ssthresh = win * tp->t_maxseg;
+#ifdef ALTQ_ECN
+					/* mark we are in recovery phase */
+					tp->snd_rcvr = tp->snd_max;
+				        }
+#endif
+					tp->t_timer[TCPT_REXMT] = 0;
+					tp->t_rtt = 0;
+					tp->snd_nxt = tr->tr_ack;
+					tp->snd_cwnd = tp->t_maxseg;
+					(void) tcp6_output(tp);
+					tp->snd_cwnd = tp->snd_ssthresh +
+					       tp->t_maxseg * tp->t_dupacks;
+					if (SEQ_GT(onxt, tp->snd_nxt))
+						tp->snd_nxt = onxt;
+					goto drop;
+				} else if (tp->t_dupacks > tcprexmtthresh) {
+					tp->snd_cwnd += tp->t_maxseg;
+					(void) tcp6_output(tp);
+					goto drop;
+				}
+			} else
+				tp->t_dupacks = 0;
+			break;
+		}
+		/*
+		 * If the congestion window was inflated to account
+		 * for the other side's cached packets, retract it.
+		 */
+		if (tp->t_dupacks >= tcprexmtthresh &&
+		    tp->snd_cwnd > tp->snd_ssthresh)
+			tp->snd_cwnd = tp->snd_ssthresh;
+		tp->t_dupacks = 0;
+		if (SEQ_GT(tr->tr_ack, tp->snd_max)) {
+			tcpstat.tcps_rcvacktoomuch++;
+			goto dropafterack;
+		}
+		/*
+		 *  If we reach this point, ACK is not a duplicate,
+		 *     i.e., it ACKs something we sent.
+		 */
+		if (tp->t_flags & TF_NEEDSYN) {
+			/*
+			 * T/TCP: Connection was half-synchronized, and our
+			 * SYN has been ACK'd (so connection is now fully
+			 * synchronized).  Go to non-starred state,
+			 * increment snd_una for ACK of SYN, and check if
+			 * we can do window scaling.
+			 */
+			tp->t_flags &= ~TF_NEEDSYN;
+			tp->snd_una++;
+			/* Do window scaling? */
+			if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==
+				(TF_RCVD_SCALE|TF_REQ_SCALE)) {
+				tp->snd_scale = tp->requested_s_scale;
+				tp->rcv_scale = tp->request_r_scale;
+			}
+		}
+
+process_ACK:
+		acked = tr->tr_ack - tp->snd_una;
+		tcpstat.tcps_rcvackpack++;
+		tcpstat.tcps_rcvackbyte += acked;
+		if (acked > 0)
+			ip6_reachhint(tp->t_inpcb);
+
+		/*
+		 * If we have a timestamp reply, update smoothed
+		 * round trip time.  If no timestamp is present but
+		 * transmit timer is running and timed sequence
+		 * number was acked, update smoothed round trip time.
+		 * Since we now have an rtt measurement, cancel the
+		 * timer backoff (cf., Phil Karn's retransmit alg.).
+		 * Recompute the initial retransmit timer.
+		 */
+		if (to.to_flag & TOF_TS)
+			tcp_xmit_timer(tp, tcp_now - to.to_tsecr + 1);
+		else if (tp->t_rtt && SEQ_GT(tr->tr_ack, tp->t_rtseq))
+			tcp_xmit_timer(tp,tp->t_rtt);
+
+		/*
+		 * If all outstanding data is acked, stop retransmit
+		 * timer and remember to restart (more output or persist).
+		 * If there is more data to be acked, restart retransmit
+		 * timer, using current (possibly backed-off) value.
+		 */
+		if (tr->tr_ack == tp->snd_max) {
+			tp->t_timer[TCPT_REXMT] = 0;
+			needoutput = 1;
+		} else if (tp->t_timer[TCPT_PERSIST] == 0)
+			tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+
+		/*
+		 * If no data (only SYN) was ACK'd,
+		 *    skip rest of ACK processing.
+		 */
+		if (acked == 0)
+			goto step6;
+
+		/*
+		 * When new data is acked, open the congestion window.
+		 * If the window gives us less than ssthresh packets
+		 * in flight, open exponentially (maxseg per packet).
+		 * Otherwise open linearly: maxseg per window
+		 * (maxseg^2 / cwnd per packet).
+		 */
+		{
+		u_int cw = tp->snd_cwnd;
+		u_int incr = tp->t_maxseg;
+
+		if (cw > tp->snd_ssthresh)
+			incr = incr * incr / cw;
+		tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale);
+		}
+		if (acked > so->so_snd.sb_cc) {
+			tp->snd_wnd -= so->so_snd.sb_cc;
+			sbdrop(&so->so_snd, (int)so->so_snd.sb_cc);
+			ourfinisacked = 1;
+		} else {
+			sbdrop(&so->so_snd, acked);
+			tp->snd_wnd -= acked;
+			ourfinisacked = 0;
+		}
+		if (so->so_snd.sb_flags & SB_NOTIFY)
+			sowwakeup(so);
+		tp->snd_una = tr->tr_ack;
+#ifdef ALTQ_ECN
+		/* sync snc_rcvr with snd_una */
+		if (SEQ_GT(tp->snd_una, tp->snd_rcvr))
+			tp->snd_rcvr = tp->snd_una;
+#endif
+		if (SEQ_LT(tp->snd_nxt, tp->snd_una))
+			tp->snd_nxt = tp->snd_una;
+
+		switch (tp->t_state) {
+
+		/*
+		 * In FIN_WAIT_1 STATE in addition to the processing
+		 * for the ESTABLISHED state if our FIN is now acknowledged
+		 * then enter FIN_WAIT_2.
+		 */
+		case TCPS_FIN_WAIT_1:
+			if (ourfinisacked) {
+				/*
+				 * If we can't receive any more
+				 * data, then closing user can proceed.
+				 * Starting the timer is contrary to the
+				 * specification, but if we don't get a FIN
+				 * we'll hang forever.
+				 */
+				if (so->so_state & SS_CANTRCVMORE) {
+					soisdisconnected(so);
+					tp->t_timer[TCPT_2MSL] = tcp_maxidle;
+				}
+				tp->t_state = TCPS_FIN_WAIT_2;
+			}
+			break;
+
+	 	/*
+		 * In CLOSING STATE in addition to the processing for
+		 * the ESTABLISHED state if the ACK acknowledges our FIN
+		 * then enter the TIME-WAIT state, otherwise ignore
+		 * the segment.
+		 */
+		case TCPS_CLOSING:
+			if (ourfinisacked) {
+				tp->t_state = TCPS_TIME_WAIT;
+				tcp_canceltimers(tp);
+				/* Shorten TIME_WAIT [RFC-1644, p.28] */
+				if (tp->cc_recv != 0 &&
+				    tp->t_duration < TCPTV_MSL)
+					tp->t_timer[TCPT_2MSL] =
+					    tp->t_rxtcur * TCPTV_TWTRUNC;
+				else
+					tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+				soisdisconnected(so);
+			}
+			break;
+
+		/*
+		 * In LAST_ACK, we may still be waiting for data to drain
+		 * and/or to be acked, as well as for the ack of our FIN.
+		 * If our FIN is now acknowledged, delete the TCB,
+		 * enter the closed state and return.
+		 */
+		case TCPS_LAST_ACK:
+			if (ourfinisacked) {
+				tp = tcp6_close(tp);
+				goto drop;
+			}
+			break;
+
+		/*
+		 * In TIME_WAIT state the only thing that should arrive
+		 * is a retransmission of the remote FIN.  Acknowledge
+		 * it and restart the finack timer.
+		 */
+		case TCPS_TIME_WAIT:
+			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+			goto dropafterack;
+		}
+	}
+
+step6:
+	/*
+	 * Update window information.
+	 * Don't look at window if no ACK: TAC's send garbage on first SYN.
+	 */
+	if ((trflags & TH_ACK) &&
+	    (SEQ_LT(tp->snd_wl1, tr->tr_seq) ||
+	    (tp->snd_wl1 == tr->tr_seq && (SEQ_LT(tp->snd_wl2, tr->tr_ack) ||
+	     (tp->snd_wl2 == tr->tr_ack && trwin > tp->snd_wnd))))) {
+		/* keep track of pure window updates */
+		if (tr->tr_len == 0 &&
+		    tp->snd_wl2 == tr->tr_ack && trwin > tp->snd_wnd)
+			tcpstat.tcps_rcvwinupd++;
+		tp->snd_wnd = trwin;
+		tp->snd_wl1 = tr->tr_seq;
+		tp->snd_wl2 = tr->tr_ack;
+		if (tp->snd_wnd > tp->max_sndwnd)
+			tp->max_sndwnd = tp->snd_wnd;
+		needoutput = 1;
+	}
+
+	/*
+	 * Process segments with URG.
+	 */
+	if ((trflags & TH_URG) && tr->tr_urp &&
+	    TCPS_HAVERCVDFIN(tp->t_state) == 0) {
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_TCP0)
+			printf("tcp6_input received URG\n");
+#endif
+		/*
+		 * This is a kludge, but if we receive and accept
+		 * random urgent pointers, we'll crash in
+		 * soreceive.  It's hard to imagine someone
+		 * actually wanting to send this much urgent data.
+		 */
+		if (tr->tr_urp + so->so_rcv.sb_cc > sb_max) {
+			tr->tr_urp = 0;			/* XXX */
+			trflags &= ~TH_URG;		/* XXX */
+			goto dodata;			/* XXX */
+		}
+		/*
+		 * If this segment advances the known urgent pointer,
+		 * then mark the data stream.  This should not happen
+		 * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since
+		 * a FIN has been received from the remote side.
+		 * In these states we ignore the URG.
+		 *
+		 * According to RFC961 (Assigned Protocols),
+		 * the urgent pointer points to the last octet
+		 * of urgent data.  We continue, however,
+		 * to consider it to indicate the first octet
+		 * of data past the urgent section as the original
+		 * spec states (in one of two places).
+		 */
+		if (SEQ_GT(tr->tr_seq+tr->tr_urp, tp->rcv_up)) {
+			tp->rcv_up = tr->tr_seq + tr->tr_urp;
+			so->so_oobmark = so->so_rcv.sb_cc +
+			    (tp->rcv_up - tp->rcv_nxt) - 1;
+			if (so->so_oobmark == 0)
+				so->so_state |= SS_RCVATMARK;
+			sohasoutofband(so);
+			tp->t_oobflags &= ~(TCPOOB_HAVEDATA | TCPOOB_HADDATA);
+		}
+		/*
+		 * Remove out of band data so doesn't get presented to user.
+		 * This can happen independent of advancing the URG pointer,
+		 * but if two URG's are pending at once, some out-of-band
+		 * data may creep in... ick.
+		 */
+		if (tr->tr_urp <= (u_long)tr->tr_len
+#ifdef SO_OOBINLINE
+		     && (so->so_options & SO_OOBINLINE) == 0
+#endif
+		     )
+			tcp6_pulloutofband(so, tr, m);
+	} else
+		/*
+		 * If no out of band data is expected,
+		 * pull receive urgent pointer along
+		 * with the receive window.
+		 */
+		if (SEQ_GT(tp->rcv_nxt, tp->rcv_up))
+			tp->rcv_up = tp->rcv_nxt;
+dodata:							/* XXX */
+
+	/*
+	 * Process the segment text, merging it into the TCP sequencing queue,
+	 * and arranging for acknowledgment of receipt if necessary.
+	 * This process logically involves adjusting tp->rcv_wnd as data
+	 * is presented to the user (this happens in tcp6_usrreq.c,
+	 * case PRU_RCVD).  If a FIN has already been received on this
+	 * connection then we just ignore the text.
+	 */
+	if ((tr->tr_len || (trflags&TH_FIN)) &&
+	    TCPS_HAVERCVDFIN(tp->t_state) == 0) {
+		TCP6_REASS(tp, tr, m, so, trflags);
+		/*
+		 * Note the amount of data that peer has sent into
+		 * our window, in order to estimate the sender's
+		 * buffer size.
+		 */
+		len = so->so_rcv.sb_hiwat - (tp->rcv_adv - tp->rcv_nxt);
+	} else {
+		m_freem(m);
+		trflags &= ~TH_FIN;
+	}
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_TCP0)
+		printf("tcp6_input received data\n");
+#endif
+	/*
+	 * If FIN is received ACK the FIN and let the user know
+	 * that the connection is closing.
+	 */
+	if (trflags & TH_FIN) {
+		if (TCPS_HAVERCVDFIN(tp->t_state) == 0) {
+			socantrcvmore(so);
+			/*
+			 *  If connection is half-synchronized
+			 *  (ie NEEDSYN flag on) then delay ACK,
+			 *  so it may be piggybacked when SYN is sent.
+			 *  Otherwise, since we received a FIN then no
+			 *  more input can be expected, send ACK now.
+			 */
+			if (tp->t_flags & TF_NEEDSYN)
+				tp->t_flags |= TF_DELACK;
+			else
+				tp->t_flags |= TF_ACKNOW;
+			tp->rcv_nxt++;
+		}
+		switch (tp->t_state) {
+
+	 	/*
+		 * In SYN_RECEIVED and ESTABLISHED STATES
+		 * enter the CLOSE_WAIT state.
+		 */
+		case TCPS_SYN_RECEIVED:
+		case TCPS_ESTABLISHED:
+			tp->t_state = TCPS_CLOSE_WAIT;
+			break;
+
+	 	/*
+		 * If still in FIN_WAIT_1 STATE FIN has not been acked so
+		 * enter the CLOSING state.
+		 */
+		case TCPS_FIN_WAIT_1:
+			tp->t_state = TCPS_CLOSING;
+			break;
+
+	 	/*
+		 * In FIN_WAIT_2 state enter the TIME_WAIT state,
+		 * starting the time-wait timer, turning off the other
+		 * standard timers.
+		 */
+		case TCPS_FIN_WAIT_2:
+			tp->t_state = TCPS_TIME_WAIT;
+			tcp_canceltimers(tp);
+			/* Shorten TIME_WAIT [RFC-1644, p.28] */
+			if (tp->cc_recv != 0 &&
+			    tp->t_duration < TCPTV_MSL) {
+				tp->t_timer[TCPT_2MSL] =
+				    tp->t_rxtcur * TCPTV_TWTRUNC;
+				/* For transaction client, force ACK now. */
+				tp->t_flags |= TF_ACKNOW;
+			}
+			else
+				tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+			soisdisconnected(so);
+			break;
+
+		/*
+		 * In TIME_WAIT state restart the 2 MSL time_wait timer.
+		 */
+		case TCPS_TIME_WAIT:
+			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+			break;
+		}
+	}
+#ifdef notyet
+	if (so->so_options & SO_DEBUG)
+		tcp_trace(TA_INPUT, ostate, tp, &tcp_savetr, 0);
+#endif
+
+	/*
+	 * Return any desired output.
+	 */
+	if (needoutput || (tp->t_flags & TF_ACKNOW))
+		(void) tcp6_output(tp);
+	return;
+
+dropafterack:
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_TCP0)
+		printf("tcp6_input drops after ask\n");
+#endif
+	/*
+	 * Generate an ACK dropping incoming segment if it occupies
+	 * sequence space, where the ACK reflects our state.
+	 */
+	if (trflags & TH_RST)
+		goto drop;
+#ifdef notyet
+	if (so->so_options & SO_DEBUG)
+		tcp_trace(TA_DROP, ostate, tp, &tcp_savetr, 0);
+#endif
+	m_freem(m);
+	tp->t_flags |= TF_ACKNOW;
+	(void) tcp6_output(tp);
+	return;
+
+dropwithreset:
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_TCP0)
+		printf("tcp6_input drops with reset\n");
+#endif
+	/*
+	 * Generate a RST, dropping incoming segment.
+	 * Make ACK acceptable to originator of segment.
+	 * Don't bother to respond if destination was multicast.
+	 */
+	if ((trflags & TH_RST) || IS_MULTIADDR6(tr->tr_dst))
+		goto drop;
+#ifdef notyet
+	if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
+		tcp_trace(TA_DROP, ostate, tp, &tcp_savetr, 0);
+#endif
+	if (trflags & TH_ACK)
+		tcp6_resprst(tp, tr, m, (tcp_seq)0, tr->tr_ack, TH_RST);
+	else {
+		if (trflags & TH_SYN)
+			tr->tr_len++;
+		tcp6_resprst(tp, tr, m, tr->tr_seq+tr->tr_len, (tcp_seq)0,
+		    TH_RST|TH_ACK);
+	}
+	/* destroy temporarily created socket */
+	if (dropsocket)
+		(void) soabort(so);
+	return;
+
+drop:
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_TCP0)
+		printf("tcp6_input drops\n");
+#endif
+	/*
+	 * Drop space held by incoming segment and return.
+	 */
+#ifdef notyet
+	if (tp == 0 && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
+		tcp_trace(TA_DROP, ostate, tp, &tcp_savetr, 0);
+#endif
+	m_freem(m);
+	/* destroy temporarily created socket */
+	if (dropsocket)
+		(void) soabort(so);
+	return;
+}
+
+static void
+tcp6_dooptions(tp, cp, cnt, tr, to)
+	struct tcpcb *tp;
+	u_char *cp;
+	int cnt;
+	struct tcp6hdrs *tr;
+	struct tcpopt *to;
+{
+	u_int16_t mss = 0;
+	int opt, optlen;
+
+	for (; cnt > 0; cnt -= optlen, cp += optlen) {
+		opt = cp[0];
+		if (opt == TCPOPT_EOL)
+			break;
+		if (opt == TCPOPT_NOP)
+			optlen = 1;
+		else {
+			optlen = cp[1];
+			if (optlen <= 0)
+				break;
+		}
+		switch (opt) {
+
+		default:
+			continue;
+
+		case TCPOPT_MAXSEG:
+			if (optlen != TCPOLEN_MAXSEG)
+				continue;
+			if (!(tr->tr_flags & TH_SYN))
+				continue;
+			bcopy((char *) cp + 2, (char *) &mss, sizeof(mss));
+			NTOHS(mss);
+			tp->t_omaxopd = mss;		/* hard limit */
+			break;
+
+		case TCPOPT_WINDOW:
+			if (optlen != TCPOLEN_WINDOW)
+				continue;
+			if (!(tr->tr_flags & TH_SYN))
+				continue;
+			tp->t_flags |= TF_RCVD_SCALE;
+			tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT);
+			break;
+
+		case TCPOPT_TIMESTAMP:
+			if (optlen != TCPOLEN_TIMESTAMP)
+				continue;
+			to->to_flag |= TOF_TS;
+			bcopy((char *)cp + 2,
+			    (char *)&to->to_tsval, sizeof(to->to_tsval));
+			NTOHL(to->to_tsval);
+			bcopy((char *)cp + 6,
+			    (char *)&to->to_tsecr, sizeof(to->to_tsecr));
+			NTOHL(to->to_tsecr);
+
+			/*
+			 * A timestamp received in a SYN makes
+			 * it ok to send timestamp requests and replies.
+			 */
+			if (tr->tr_flags & TH_SYN) {
+				tp->t_flags |= TF_RCVD_TSTMP;
+				tp->ts_recent = to->to_tsval;
+				tp->ts_recent_age = tcp_now;
+			}
+			break;
+		case TCPOPT_CC:
+			if (optlen != TCPOLEN_CC)
+				continue;
+			to->to_flag |= TOF_CC;
+			bcopy((char *)cp + 2,
+			    (char *)&to->to_cc, sizeof(to->to_cc));
+			NTOHL(to->to_cc);
+			/*
+			 * A CC or CC.new option received in a SYN makes
+			 * it ok to send CC in subsequent segments.
+			 */
+			if (tr->tr_flags & TH_SYN)
+				tp->t_flags |= TF_RCVD_CC;
+			break;
+		case TCPOPT_CCNEW:
+			if (optlen != TCPOLEN_CC)
+				continue;
+			if (!(tr->tr_flags & TH_SYN))
+				continue;
+			to->to_flag |= TOF_CCNEW;
+			bcopy((char *)cp + 2,
+			    (char *)&to->to_cc, sizeof(to->to_cc));
+			NTOHL(to->to_cc);
+			/*
+			 * A CC or CC.new option received in a SYN makes
+			 * it ok to send CC in subsequent segments.
+			 */
+			tp->t_flags |= TF_RCVD_CC;
+			break;
+		case TCPOPT_CCECHO:
+			if (optlen != TCPOLEN_CC)
+				continue;
+			if (!(tr->tr_flags & TH_SYN))
+				continue;
+			to->to_flag |= TOF_CCECHO;
+			bcopy((char *)cp + 2,
+			    (char *)&to->to_ccecho, sizeof(to->to_ccecho));
+			NTOHL(to->to_ccecho);
+			break;
+		}
+	}
+	if (tr->tr_flags & TH_SYN)
+		tcp6_mss(tp, mss);	/* sets t_maxseg */
+}
+
+/*
+ * Pull out of band byte out of a segment so
+ * it doesn't appear in the user's data queue.
+ * It is still reflected in the segment length for
+ * sequencing purposes.
+ */
+static void
+tcp6_pulloutofband(so, tr, m)
+	struct socket *so;
+	struct tcp6hdrs *tr;
+	struct mbuf *m;
+{
+	int cnt = tr->tr_urp - 1;
+
+	while (cnt >= 0) {
+		if (m->m_len > cnt) {
+			char *cp = mtod(m, caddr_t) + cnt;
+			struct tcpcb *tp = sototcpcb(so);
+
+			tp->t_iobc = *cp;
+			tp->t_oobflags |= TCPOOB_HAVEDATA;
+			bcopy(cp+1, cp, (unsigned)(m->m_len - cnt - 1));
+			m->m_len--;
+			return;
+		}
+		cnt -= m->m_len;
+		m = m->m_next;
+		if (m == 0)
+			break;
+	}
+	panic("tcp6_pulloutofband");
+}
+
+/*
+ * Determine a reasonable value for maxseg size.
+ * If the route is known, check route for mtu.
+ * If none, use an mss that can be handled on the outgoing
+ * interface without forcing IP to fragment; if bigger than
+ * an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES
+ * to utilize large mbufs.  If no route is found, route has no mtu,
+ * or the destination isn't local, use a default, hopefully conservative
+ * size (usually 512 or the default IP max size, but no more than the mtu
+ * of the interface), as we can't discover anything about intervening
+ * gateways or networks.  We also initialize the congestion/slow start
+ * window to be a single segment if the destination isn't local.
+ * While looking at the routing entry, we also initialize other path-dependent
+ * parameters from pre-set or cached values in the routing entry.
+ *
+ * Also take into account the space needed for options that we
+ * send regularly.  Make maxseg shorter by that amount to assure
+ * that we can send maxseg amount of data even when the options
+ * are present.  Store the upper limit of the length of options plus
+ * data in maxopd.
+ *
+ * NOTE that this routine is only called when we process an incoming
+ * segment, for outgoing segments only tcp_mssopt is called.
+ *
+ * In case of T/TCP, we call this routine during implicit connection
+ * setup as well (offer = -1), to initialize maxseg from the cached
+ * MSS of our peer.
+ */
+void
+tcp6_mss(tp, offer)
+	struct tcpcb *tp;
+	int offer;
+{
+	struct rtentry *rt;
+	struct ifnet *ifp;
+	int rtt, mss;
+	u_long bufsize;
+	struct inpcb *inp;
+	struct socket *so;
+	struct rmxp_tao *taop;
+	int origoffer = offer;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_PMTU)
+		printf("tcp6_mss(%p,%d)\n", tp, offer);
+#endif
+
+	inp = tp->t_inpcb;
+	if ((rt = tcp6_rtlookup(inp)) == NULL) {
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_PMTU)
+			printf("tcp6_mss no route -> %d\n", tcp_mssdflt);
+#endif
+		tp->t_maxopd = tp->t_maxseg = tcp_mssdflt;
+		return;
+	}
+	if (rt->rt_flags & RTF_LOCAL)
+		ifp = loif;
+	else
+		ifp = rt->rt_ifp;
+	so = inp->inp_socket;
+
+	taop = rmx_taop(rt->rt_rmx);
+	/*
+	 * Offer == -1 means that we didn't receive SYN yet,
+	 * use cached value in that case;
+	 */
+	if (offer == -1)
+		offer = taop->tao_mssopt;
+	/*
+	 * Offer == 0 means that there was no MSS on the SYN segment,
+	 * in this case we use tcp_mssdflt.
+	 */
+	if (offer == 0)
+		offer = tcp_mssdflt;
+	else {
+		/*
+		 * Sanity check: make sure that maxopd will be large
+		 * enough to allow some data on segments even is the
+		 * all the option space is used (40bytes).  Otherwise
+		 * funny things may happen in tcp_output.
+		 */
+		offer = max(offer, 64);
+	}
+	taop->tao_mssopt = offer;
+
+	/*
+	 * While we're here, check if there's an initial rtt
+	 * or rttvar.  Convert from the route-table units
+	 * to scaled multiples of the slow timeout timer.
+	 */
+	if (tp->t_srtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) {
+		/*
+		 * XXX the lock bit for RTT indicates that the value
+		 * is also a minimum value; this is subject to time.
+		 */
+		if (rt->rt_rmx.rmx_locks & RTV_RTT)
+			tp->t_rttmin = rtt / (RTM_RTTUNIT / PR_SLOWHZ);
+		tp->t_srtt = rtt / (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE));
+		tcpstat.tcps_usedrtt++;
+		if (rt->rt_rmx.rmx_rttvar) {
+			tp->t_rttvar = rt->rt_rmx.rmx_rttvar /
+			    (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE));
+			tcpstat.tcps_usedrttvar++;
+		} else {
+			/* default variation is +- 1 rtt */
+			tp->t_rttvar =
+			    tp->t_srtt * TCP_RTTVAR_SCALE / TCP_RTT_SCALE;
+		}
+		TCPT_RANGESET(tp->t_rxtcur,
+		    ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1,
+		    tp->t_rttmin, TCPTV_REXMTMAX);
+	}
+	/*
+	 * if there's an mtu associated with the route, use it
+	 */
+	if (rt->rt_rmx.rmx_mtu)
+		mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpip6hdr);
+	else {
+		rt->rt_rmx.rmx_mtu = ifp->if_mtu;
+		mss = ifp->if_mtu - sizeof(struct tcpip6hdr);
+	}
+	if (inp->inp_options)
+		mss -= inp->inp_options->m_pkthdr.len;
+	mss = min(mss, offer);
+	/*
+	 * maxopd stores the maximum length of data AND options
+	 * in a segment; maxseg is the amount of data in a normal
+	 * segment.  We need to store this value (maxopd) apart
+	 * from maxseg, because now every segment carries options
+	 * and thus we normally have somewhat less data in segments.
+	 */
+	tp->t_maxopd = mss;
+
+	/*
+	 * In case of T/TCP, origoffer==-1 indicates, that no segments
+	 * were received yet.  In this case we just guess, otherwise
+	 * we do the same as before T/TCP.
+	 */
+ 	if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP &&
+	    (origoffer == -1 ||
+	     (tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP))
+		mss -= TCPOLEN_TSTAMP_APPA;
+ 	if ((tp->t_flags & (TF_REQ_CC|TF_NOOPT)) == TF_REQ_CC &&
+	    (origoffer == -1 ||
+	     (tp->t_flags & TF_RCVD_CC) == TF_RCVD_CC))
+		mss -= TCPOLEN_CC_APPA;
+
+#if	(MCLBYTES & (MCLBYTES - 1)) == 0
+		if (mss > MCLBYTES)
+			mss &= ~(MCLBYTES-1);
+#else
+		if (mss > MCLBYTES)
+			mss = mss / MCLBYTES * MCLBYTES;
+#endif
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_PMTU)
+		printf("tcp6_mss computes %d\n", mss);
+#endif
+	/*
+	 * If there's a pipesize, change the socket buffer
+	 * to that size.  Make the socket buffers an integral
+	 * number of mss units; if the mss is larger than
+	 * the socket buffer, decrease the mss.
+	 */
+	if ((bufsize = rt->rt_rmx.rmx_sendpipe) == 0)
+		bufsize = so->so_snd.sb_hiwat;
+	if (bufsize < mss)
+		mss = bufsize;
+	else {
+		bufsize = roundup(bufsize, mss);
+		if (bufsize > sb_max)
+			bufsize = sb_max;
+		(void)sbreserve(&so->so_snd, bufsize);
+	}
+	tp->t_maxseg = mss;
+
+	if ((bufsize = rt->rt_rmx.rmx_recvpipe) == 0)
+		bufsize = so->so_rcv.sb_hiwat;
+	if (bufsize > mss) {
+		bufsize = roundup(bufsize, mss);
+		if (bufsize > sb_max)
+			bufsize = sb_max;
+		(void)sbreserve(&so->so_rcv, bufsize);
+	}
+#ifdef notyet
+	/*
+	 * Don't force slow-start on local network.
+	 */
+	if (!in6_localaddr(inp->inp_faddr6))
+#endif
+		tp->snd_cwnd = mss;
+
+	if (rt->rt_rmx.rmx_ssthresh) {
+		/*
+		 * There's some sort of gateway or interface
+		 * buffer limit on the path.  Use this to set
+		 * the slow start threshhold, but set the
+		 * threshold to no less than 2*mss.
+		 */
+		tp->snd_ssthresh = max(2 * mss, rt->rt_rmx.rmx_ssthresh);
+		tcpstat.tcps_usedssthresh++;
+	}
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_PMTU)
+		printf("tcp6_mss returns %d\n", mss);
+#endif
+}
+
+/*
+ * Determine the MSS option to send on an outgoing SYN.
+ */
+int
+tcp6_mssopt(tp)
+	struct tcpcb *tp;
+{
+	struct rtentry *rt;
+	struct ifnet *ifp;
+
+	rt = tcp6_rtlookup(tp->t_inpcb);
+	if (rt == NULL) {
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_PMTU)
+			printf("tcp6_mssopt no route -> %d\n", tcp_mssdflt);
+#endif
+		return tcp_mssdflt;
+	}
+	if (rt->rt_flags & RTF_LOCAL)
+		ifp = loif;
+	else
+		ifp = rt->rt_ifp;
+
+	return ifp->if_mtu - sizeof(struct tcpip6hdr);
+}
diff -uN src-current/sys/netinet/tcp6_output.c src-current-ipv6/sys/netinet/tcp6_output.c
--- src-current/sys/netinet/tcp6_output.c
+++ src-current-ipv6/sys/netinet/tcp6_output.c
@@ -0,0 +1,745 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 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.
+ *
+ *	@(#)tcp_output.c	8.3 (Berkeley) 12/30/93
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/tcp.h>
+#define	TCPOUTFLAGS
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp6_var.h>
+#include <netinet/tcpip.h>
+#include <netinet/tcp_debug.h>
+
+/*
+ * Tcp output routine: figure out what should be sent and send it.
+ */
+int
+tcp6_output(tp)
+	register struct tcpcb *tp;
+{
+	register struct socket *so = tp->t_inpcb->inp_socket;
+	register long len, win;
+	int off, flags, error;
+	register struct mbuf *m;
+	register struct tcpip6hdr *ti;
+	struct ip6ovck save_ipc;
+	u_char opt[TCP_MAXOLEN];
+	unsigned optlen, hdrlen;
+	int idle, sendalot;
+	struct rmxp_tao *taop;
+	struct rmxp_tao tao_noncached;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_TCP0)
+		printf("tcp6_output tcpcb %p inpcb %p\n",
+		       tp, tp->t_inpcb);
+#endif
+	/*
+	 * Determine length of data that should be transmitted,
+	 * and flags that will be used.
+	 * If there is some data or critical controls (SYN, RST)
+	 * to send, then transmit; otherwise, investigate further.
+	 */
+	idle = (tp->snd_max == tp->snd_una);
+	if (idle && tp->t_idle >= tp->t_rxtcur)
+		/*
+		 * We have been idle for "a while" and no acks are
+		 * expected to clock out any data we send --
+		 * slow start to get ack "clock" running again.
+		 */
+		tp->snd_cwnd = tp->t_maxseg;
+again:
+	sendalot = 0;
+	off = tp->snd_nxt - tp->snd_una;
+	win = min(tp->snd_wnd, tp->snd_cwnd);
+
+	flags = tcp_outflags[tp->t_state];
+	/*
+	 * Get standard flags, and add SYN or FIN if requested by 'hidden'
+	 * state flags.
+	 */
+	if (tp->t_flags & TF_NEEDFIN)
+		flags |= TH_FIN;
+	if (tp->t_flags & TF_NEEDSYN)
+		flags |= TH_SYN;
+
+	/*
+	 * If in persist timeout with window of 0, send 1 byte.
+	 * Otherwise, if window is small but nonzero
+	 * and timer expired, we will send what we can
+	 * and go to transmit state.
+	 */
+	if (tp->t_force) {
+		if (win == 0) {
+			/*
+			 * If we still have some data to send, then
+			 * clear the FIN bit.  Usually this would
+			 * happen below when it realizes that we
+			 * aren't sending all the data.  However,
+			 * if we have exactly 1 byte of unset data,
+			 * then it won't clear the FIN bit below,
+			 * and if we are in persist state, we wind
+			 * up sending the packet without recording
+			 * that we sent the FIN bit.
+			 *
+			 * We can't just blindly clear the FIN bit,
+			 * because if we don't have any more data
+			 * to send then the probe will be the FIN
+			 * itself.
+			 */
+			if (off < so->so_snd.sb_cc)
+				flags &= ~TH_FIN;
+			win = 1;
+		} else {
+			tp->t_timer[TCPT_PERSIST] = 0;
+			tp->t_rxtshift = 0;
+		}
+	}
+
+	len = min(so->so_snd.sb_cc, win) - off;
+
+	if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) {
+		taop = &tao_noncached;
+		bzero(taop, sizeof(*taop));
+	}
+
+	/*
+	 * Lop off SYN bit if it has already been sent.  However, if this
+	 * is SYN-SENT state and if segment contains data and if we don't
+	 * know that foreign host supports TAO, suppress sending segment.
+	 */
+	if ((flags & TH_SYN) && SEQ_GT(tp->snd_nxt, tp->snd_una)) {
+		flags &= ~TH_SYN;
+		off--, len++;
+		if (len > 0 && tp->t_state == TCPS_SYN_SENT &&
+		    taop->tao_ccsent == 0)
+			return 0;
+	}
+
+	/*
+	 * Be careful not to send data and/or FIN on SYN segments
+	 * in cases when no CC option will be sent.
+	 * This measure is needed to prevent interoperability problems
+	 * with not fully conformant TCP implementations.
+	 */
+	if ((flags & TH_SYN) &&
+	    ((tp->t_flags & TF_NOOPT) || !(tp->t_flags & TF_REQ_CC) ||
+	     ((flags & TH_ACK) && !(tp->t_flags & TF_RCVD_CC)))) {
+		len = 0;
+		flags &= ~TH_FIN;
+	}
+
+	if (len < 0) {
+		/*
+		 * If FIN has been sent but not acked,
+		 * but we haven't been called to retransmit,
+		 * len will be -1.  Otherwise, window shrank
+		 * after we sent into it.  If window shrank to 0,
+		 * cancel pending retransmit, pull snd_nxt back
+		 * to (closed) window, and set the persist timer
+		 * if it isn't already going.  If the window didn't
+		 * close completely, just wait for an ACK.
+		 */
+		len = 0;
+		if (win == 0) {
+			tp->t_timer[TCPT_REXMT] = 0;
+			tp->t_rxtshift = 0;
+			tp->snd_nxt = tp->snd_una;
+			if (tp->t_timer[TCPT_PERSIST] == 0)
+				tcp_setpersist(tp);
+		}
+	}
+	if (len > tp->t_maxseg) {
+		len = tp->t_maxseg;
+		sendalot = 1;
+	}
+	if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
+		flags &= ~TH_FIN;
+
+	win = sbspace(&so->so_rcv);
+
+	/*
+	 * Sender silly window avoidance.  If connection is idle
+	 * and can send all data, a maximum segment,
+	 * at least a maximum default-size segment do it,
+	 * or are forced, do it; otherwise don't bother.
+	 * If peer's buffer is tiny, then send
+	 * when window is at least half open.
+	 * If retransmitting (possibly after persist timer forced us
+	 * to send into a small window), then must resend.
+	 */
+	if (len) {
+		if (len == tp->t_maxseg)
+			goto send;
+		if ((idle || tp->t_flags & TF_NODELAY) &&
+		    (tp->t_flags & TF_NOPUSH) == 0 &&
+		    len + off >= so->so_snd.sb_cc)
+			goto send;
+		if (tp->t_force)
+			goto send;
+		if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0)
+			goto send;
+		if (SEQ_LT(tp->snd_nxt, tp->snd_max))
+			goto send;
+	}
+
+	/*
+	 * Compare available window to amount of window
+	 * known to peer (as advertised window less
+	 * next expected input).  If the difference is at least two
+	 * max size segments, or at least 50% of the maximum possible
+	 * window, then want to send a window update to peer.
+	 */
+	if (win > 0) {
+		/*
+		 * "adv" is the amount we can increase the window,
+		 * taking into account that we are limited by
+		 * TCP_MAXWIN << tp->rcv_scale.
+		 */
+		long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) -
+			(tp->rcv_adv - tp->rcv_nxt);
+
+		if (adv >= (long) (2 * tp->t_maxseg))
+			goto send;
+		if (2 * adv >= (long) so->so_rcv.sb_hiwat)
+			goto send;
+	}
+
+	/*
+	 * Send if we owe peer an ACK.
+	 */
+	if (tp->t_flags & TF_ACKNOW)
+		goto send;
+	if ((flags & TH_RST) ||
+	    ((flags & TH_SYN) && (tp->t_flags & TF_NEEDSYN) == 0))
+		goto send;
+	if (SEQ_GT(tp->snd_up, tp->snd_una))
+		goto send;
+	/*
+	 * If our state indicates that FIN should be sent
+	 * and we have not yet done so, or we're retransmitting the FIN,
+	 * then we need to send.
+	 */
+	if (flags & TH_FIN &&
+	    ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una))
+		goto send;
+
+	/*
+	 * TCP window updates are not reliable, rather a polling protocol
+	 * using ``persist'' packets is used to insure receipt of window
+	 * updates.  The three ``states'' for the output side are:
+	 *	idle			not doing retransmits or persists
+	 *	persisting		to move a small or zero window
+	 *	(re)transmitting	and thereby not persisting
+	 *
+	 * tp->t_timer[TCPT_PERSIST]
+	 *	is set when we are in persist state.
+	 * tp->t_force
+	 *	is set when we are called to send a persist packet.
+	 * tp->t_timer[TCPT_REXMT]
+	 *	is set when we are retransmitting
+	 * The output side is idle when both timers are zero.
+	 *
+	 * If send window is too small, there is data to transmit, and no
+	 * retransmit or persist is pending, then go to persist state.
+	 * If nothing happens soon, send when timer expires:
+	 * if window is nonzero, transmit what we can,
+	 * otherwise force out a byte.
+	 */
+	if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 &&
+	    tp->t_timer[TCPT_PERSIST] == 0) {
+		tp->t_rxtshift = 0;
+		tcp_setpersist(tp);
+	}
+
+	/*
+	 * No reason to send a segment, just return.
+	 */
+	return (0);
+
+send:
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_TCP0)
+		printf("tcp6_output sends\n");
+#endif
+	/*
+	 * Before ESTABLISHED, force sending of initial options
+	 * unless TCP set not to do any options.
+	 */
+	optlen = 0;
+	hdrlen = sizeof (struct tcpip6hdr);
+	if (flags & TH_SYN) {
+		tp->snd_nxt = tp->iss;
+		if ((tp->t_flags & TF_NOOPT) == 0) {
+			u_int16_t mss;
+
+			opt[0] = TCPOPT_MAXSEG;
+			opt[1] = TCPOLEN_MAXSEG;
+			mss = htons((u_int16_t) tcp6_mssopt(tp));
+			(void)memcpy(opt + 2, &mss, sizeof(mss));
+			optlen = TCPOLEN_MAXSEG;
+	 
+			if ((tp->t_flags & TF_REQ_SCALE) &&
+			    ((flags & TH_ACK) == 0 ||
+			    (tp->t_flags & TF_RCVD_SCALE))) {
+				*((u_int32_t *) (opt + optlen)) = htonl(
+					TCPOPT_NOP << 24 |
+					TCPOPT_WINDOW << 16 |
+					TCPOLEN_WINDOW << 8 |
+					tp->request_r_scale);
+				optlen += 4;
+			}
+		}
+ 	}
+
+ 	/*
+	 * Send a timestamp and echo-reply if this is a SYN and our side
+	 * wants to use timestamps (TF_REQ_TSTMP is set) or both our side
+	 * and our peer have sent timestamps in our SYN's.
+ 	 */
+ 	if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP &&
+ 	    (flags & TH_RST) == 0 &&
+	    ((flags & TH_ACK) == 0 ||
+	     (tp->t_flags & TF_RCVD_TSTMP))) {
+		u_int32_t *lp = (u_int32_t *)(opt + optlen);
+
+ 		/* Form timestamp option as shown in appendix A of RFC 1323. */
+ 		*lp++ = htonl(TCPOPT_TSTAMP_HDR);
+ 		*lp++ = htonl(tcp_now);
+ 		*lp   = htonl(tp->ts_recent);
+ 		optlen += TCPOLEN_TSTAMP_APPA;
+ 	}
+
+ 	/*
+	 * Send `CC-family' options if our side wants to use them (TF_REQ_CC),
+	 * options are allowed (!TF_NOOPT) and it's not a RST.
+ 	 */
+ 	if ((tp->t_flags & (TF_REQ_CC|TF_NOOPT)) == TF_REQ_CC &&
+ 	     (flags & TH_RST) == 0) {
+		switch (flags & (TH_SYN|TH_ACK)) {
+		/*
+		 * This is a normal ACK, send CC if we received CC before
+		 * from our peer.
+		 */
+		case TH_ACK:
+			if (!(tp->t_flags & TF_RCVD_CC))
+				break;
+			/*FALLTHROUGH*/
+
+		/*
+		 * We can only get here in T/TCP's SYN_SENT* state, when
+		 * we're a sending a non-SYN segment without waiting for
+		 * the ACK of our SYN.  A check above assures that we only
+		 * do this if our peer understands T/TCP.
+		 */
+		case 0:
+			opt[optlen++] = TCPOPT_NOP;
+			opt[optlen++] = TCPOPT_NOP;
+			opt[optlen++] = TCPOPT_CC;
+			opt[optlen++] = TCPOLEN_CC;
+			*(u_int32_t *)&opt[optlen] = htonl(tp->cc_send);
+
+			optlen += 4;
+			break;
+
+		/*
+		 * This is our initial SYN, check whether we have to use
+		 * CC or CC.new.
+		 */
+		case TH_SYN:
+			opt[optlen++] = TCPOPT_NOP;
+			opt[optlen++] = TCPOPT_NOP;
+			opt[optlen++] = tp->t_flags & TF_SENDCCNEW ?
+						TCPOPT_CCNEW : TCPOPT_CC;
+			opt[optlen++] = TCPOLEN_CC;
+			*(u_int32_t *)&opt[optlen] = htonl(tp->cc_send);
+ 			optlen += 4;
+			break;
+
+		/*
+		 * This is a SYN,ACK; send CC and CC.echo if we received
+		 * CC from our peer.
+		 */
+		case (TH_SYN|TH_ACK):
+			if (tp->t_flags & TF_RCVD_CC) {
+				opt[optlen++] = TCPOPT_NOP;
+				opt[optlen++] = TCPOPT_NOP;
+				opt[optlen++] = TCPOPT_CC;
+				opt[optlen++] = TCPOLEN_CC;
+				*(u_int32_t *)&opt[optlen] =
+					htonl(tp->cc_send);
+				optlen += 4;
+				opt[optlen++] = TCPOPT_NOP;
+				opt[optlen++] = TCPOPT_NOP;
+				opt[optlen++] = TCPOPT_CCECHO;
+				opt[optlen++] = TCPOLEN_CC;
+				*(u_int32_t *)&opt[optlen] =
+					htonl(tp->cc_recv);
+				optlen += 4;
+			}
+			break;
+		}
+ 	}
+
+ 	hdrlen += optlen;
+
+	/*
+	 * Adjust data length if insertion of options will
+	 * bump the packet length beyond the t_maxopd length.
+	 * Clear the FIN bit because we cut off the tail of
+	 * the segment.
+	 */
+	if (len + optlen > tp->t_maxopd) {
+		/*
+		 * If there is still more to send, don't close the connection.
+		 */
+		flags &= ~TH_FIN;
+		len = tp->t_maxopd - optlen;
+		sendalot = 1;
+	}
+
+#ifdef DIAGNOSTIC
+ 	if (hdrlen > MHLEN)
+		panic("tcphdr too big");
+#endif
+
+	/*
+	 * Grab a header mbuf, attaching a copy of data to
+	 * be transmitted, and initialize the header from
+	 * the template for sends on this connection.
+	 */
+	if (len) {
+		if (tp->t_force && len == 1)
+			tcpstat.tcps_sndprobe++;
+		else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) {
+			tcpstat.tcps_sndrexmitpack++;
+			tcpstat.tcps_sndrexmitbyte += len;
+		} else {
+			tcpstat.tcps_sndpack++;
+			tcpstat.tcps_sndbyte += len;
+		}
+		MGETHDR(m, M_DONTWAIT, MT_HEADER);
+		if (m == NULL) {
+			error = ENOBUFS;
+			goto out;
+		}
+		if (MHLEN < hdrlen + max_linkhdr) {
+			MH_ALIGN(m, hdrlen);
+		} else
+			m->m_data += max_linkhdr;
+		m->m_len = hdrlen;
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_TCP1)
+			printf("tcp6_output get %p/%d off %d len %ld\n",
+			       m, hdrlen, off, len);
+#endif
+		if (m->m_data + hdrlen + len <= &m->m_pktdat[MHLEN]) {
+			m_copydata(so->so_snd.sb_mb, off, (int) len,
+			    mtod(m, caddr_t) + hdrlen);
+			m->m_len += len;
+		} else {
+			m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len);
+			if (m->m_next == 0) {
+				(void) m_free(m);
+				error = ENOBUFS;
+				goto out;
+			}
+		}
+		/*
+		 * If we're sending everything we've got, set PUSH.
+		 * (This will keep happy those implementations which only
+		 * give data to the user when a buffer fills or
+		 * a PUSH comes in.)
+		 */
+		if (off + len == so->so_snd.sb_cc)
+			flags |= TH_PUSH;
+	} else {
+		if (tp->t_flags & TF_ACKNOW)
+			tcpstat.tcps_sndacks++;
+		else if (flags & (TH_SYN|TH_FIN|TH_RST))
+			tcpstat.tcps_sndctrl++;
+		else if (SEQ_GT(tp->snd_up, tp->snd_una))
+			tcpstat.tcps_sndurg++;
+		else
+			tcpstat.tcps_sndwinup++;
+
+		MGETHDR(m, M_DONTWAIT, MT_HEADER);
+		if (m == NULL) {
+			error = ENOBUFS;
+			goto out;
+		}
+		MH_ALIGN(m, hdrlen);
+		m->m_len = hdrlen;
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_TCP1)
+			printf("tcp6_output get %p/%d\n", m, hdrlen);
+#endif
+	}
+	m->m_pkthdr.rcvif = (struct ifnet *)0;
+	ti = mtod(m, struct tcpip6hdr *);
+	if (tp->t_template == 0)
+		panic("tcp6_output");
+	bcopy((caddr_t)&tp->t_template->tt_i6,
+	      (caddr_t)ti,
+	      sizeof(struct ipv6));
+	bcopy((caddr_t)&tp->t_template->tt_t,
+	      (caddr_t)ti + sizeof(struct ipv6),
+	      sizeof(struct tcphdr));
+
+#ifdef ALTQ_ECN
+	/*
+	 * if we have received congestion experienced segs
+	 * or this is a SYN seg, set ECN bit.
+	 */
+	if (tcp_ecn &&
+	    ((tp->t_flags & TF_RCVD_CE) || (flags & TH_SYN))) {
+		flags |= TH_ECN;
+		tp->t_flags &= ~TF_RCVD_CE;
+	}
+#endif
+	/*
+	 * Fill in fields, remembering maximum advertised
+	 * window for use in delaying messages about window sizes.
+	 * If resending a FIN, be sure not to use a new sequence number.
+	 */
+	if (flags & TH_FIN && tp->t_flags & TF_SENTFIN &&
+	    tp->snd_nxt == tp->snd_max)
+		tp->snd_nxt--;
+	/*
+	 * If we are doing retransmissions, then snd_nxt will
+	 * not reflect the first unsent octet.  For ACK only
+	 * packets, we do not want the sequence number of the
+	 * retransmitted packet, we want the sequence number
+	 * of the next unsent octet.  So, if there is no data
+	 * (and no SYN or FIN), use snd_max instead of snd_nxt
+	 * when filling in ti6_seq.  But if we are in persist
+	 * state, snd_max might reflect one byte beyond the
+	 * right edge of the window, so use snd_nxt in that
+	 * case, since we know we aren't doing a retransmission.
+	 * (retransmit and persist are mutually exclusive...)
+	 */
+	if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST])
+		ti->ti6_seq = htonl(tp->snd_nxt);
+	else
+		ti->ti6_seq = htonl(tp->snd_max);
+	ti->ti6_ack = htonl(tp->rcv_nxt);
+	if (optlen) {
+		bcopy(opt, ti + 1, optlen);
+		ti->ti6_off = (sizeof (struct tcphdr) + optlen) >> 2;
+	}
+	ti->ti6_flags = flags;
+	/*
+	 * Calculate receive window.  Don't shrink window,
+	 * but avoid silly window syndrome.
+	 */
+	if (win < (long)(so->so_rcv.sb_hiwat / 4) && win < (long)tp->t_maxseg)
+		win = 0;
+	if (win < (long)(tp->rcv_adv - tp->rcv_nxt))
+		win = (long)(tp->rcv_adv - tp->rcv_nxt);
+	if (win > (long)TCP_MAXWIN << tp->rcv_scale)
+		win = (long)TCP_MAXWIN << tp->rcv_scale;
+	ti->ti6_win = htons((u_int16_t) (win>>tp->rcv_scale));
+	if (SEQ_GT(tp->snd_up, tp->snd_nxt)) {
+		ti->ti6_urp = htons((u_int16_t)(tp->snd_up - tp->snd_nxt));
+		ti->ti6_flags |= TH_URG;
+	} else
+		/*
+		 * If no urgent pointer to send, then we pull
+		 * the urgent pointer to the left edge of the send window
+		 * so that it doesn't drift into the send window on sequence
+		 * number wraparound.
+		 */
+		tp->snd_up = tp->snd_una;		/* drag it along */
+
+	/*
+	 * Put TCP length in extended header, and then
+	 * checksum extended header and data.
+	 */
+	save_ipc = *mtod(m, struct ip6ovck *);
+	((struct ip6ovck *)ti)->ih6_len =
+		htons((u_int16_t)(sizeof (struct tcphdr) + optlen + len));
+        ((struct ip6ovck *)ti)->ih6_pr = IPPROTO_TCP;
+	ti->ti6_sum = in_cksum(m, (int)(hdrlen + len));
+	*mtod(m, struct ip6ovck *) = save_ipc;
+
+	/*
+	 * In transmit state, time the transmission and arrange for
+	 * the retransmit.  In persist state, just set snd_max.
+	 */
+	if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) {
+		tcp_seq startseq = tp->snd_nxt;
+
+		/*
+		 * Advance snd_nxt over sequence space of this segment.
+		 */
+		if (flags & (TH_SYN|TH_FIN)) {
+			if (flags & TH_SYN)
+				tp->snd_nxt++;
+			if (flags & TH_FIN) {
+				tp->snd_nxt++;
+				tp->t_flags |= TF_SENTFIN;
+			}
+		}
+		tp->snd_nxt += len;
+		if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
+			tp->snd_max = tp->snd_nxt;
+			/*
+			 * Time this transmission if not a retransmission and
+			 * not currently timing anything.
+			 */
+			if (tp->t_rtt == 0) {
+				tp->t_rtt = 1;
+				tp->t_rtseq = startseq;
+				tcpstat.tcps_segstimed++;
+			}
+		}
+
+		/*
+		 * Set retransmit timer if not currently set,
+		 * and not doing an ack or a keep-alive probe.
+		 * Initial value for retransmit timer is smoothed
+		 * round-trip time + 2 * round-trip time variance.
+		 * Initialize shift counter which is used for backoff
+		 * of retransmit time.
+		 */
+		if (tp->t_timer[TCPT_REXMT] == 0 &&
+		    tp->snd_nxt != tp->snd_una) {
+			tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+			if (tp->t_timer[TCPT_PERSIST]) {
+				tp->t_timer[TCPT_PERSIST] = 0;
+				tp->t_rxtshift = 0;
+			}
+		}
+	} else
+		if (SEQ_GT(tp->snd_nxt + len, tp->snd_max))
+			tp->snd_max = tp->snd_nxt + len;
+
+#ifdef notyet
+	/*
+	 * Trace.
+	 */
+	if (so->so_options & SO_DEBUG)
+		tcp_trace(TA_OUTPUT, tp->t_state, tp, ti, 0);
+#endif
+
+	/*
+	 * Fill in IP length and desired time to live and
+	 * send to IP level.  There should be a better way
+	 * to handle ttl and tos; we could keep them in
+	 * the template, but need a way to checksum without them.
+	 */
+	m->m_pkthdr.len = hdrlen + len;
+	ti->ti6_head = tp->t_inpcb->inp_oflowinfo | IPV6_VERSION;
+	ti->ti6_len = m->m_pkthdr.len - sizeof(struct ipv6);
+	ti->ti6_nh = IPPROTO_TCP;
+	ti->ti6_hlim = tp->t_inpcb->inp_ttl;		/* XXX */
+#ifdef ALTQ_ECN
+	/*
+	 * if peer is ECN capable and this is not a pure ack seg,
+	 * set ECN capable bit in IPv6 header.
+	 */
+	if ((tp->t_flags & TF_REQ_ECN) && len > 0)
+		ti->ti6_head |= htonl(IPTOS_ECT << 20);
+#endif
+	error = ip6_output(m,
+			   tp->t_inpcb->inp_options,
+			   &tp->t_inpcb->inp_route,
+			   (so->so_options & SO_DONTROUTE) | IP6_DONTFRAG,
+			   NULL,
+			   tp->t_inpcb);
+
+	if (error) {
+out:
+		if (error == ENOBUFS) {
+			tcp_quench(tp->t_inpcb, 0);
+			return (0);
+		}
+		if (error == EMSGSIZE) {
+			/*
+			 * ip6_output() will have already fixed the route
+			 * for us.  tcp6_mtudisc() will, as its last action,
+			 * initiate retransmission, so it is important to
+			 * not do so here.
+			 */
+			tcp6_mtudisc(tp->t_inpcb, error);
+			return 0;
+		}
+		if ((error == EHOSTUNREACH || error == ENETDOWN)
+		    && TCPS_HAVERCVDSYN(tp->t_state)) {
+			tp->t_softerror = error;
+			return (0);
+		}
+		return (error);
+	}
+	tcpstat.tcps_sndtotal++;
+
+	/*
+	 * Data sent (as far as we can tell).
+	 * If this advertises a larger window than any other segment,
+	 * then remember the size of the advertised window.
+	 * Any pending ACK has now been sent.
+	 */
+	if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))
+		tp->rcv_adv = tp->rcv_nxt + win;
+	tp->last_ack_sent = tp->rcv_nxt;
+	tp->t_flags &= ~(TF_ACKNOW|TF_DELACK);
+	if (sendalot)
+		goto again;
+	return (0);
+}
diff -uN src-current/sys/netinet/tcp6_subr.c src-current-ipv6/sys/netinet/tcp6_subr.c
--- src-current/sys/netinet/tcp6_subr.c
+++ src-current-ipv6/sys/netinet/tcp6_subr.c
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 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.
+ *
+ *	@(#)tcp_subr.c	8.1 (Berkeley) 6/10/93
+ */
+
+#include "opt_inet6.h"
+#include "opt_compat.h"
+#include "opt_tcpdebug.h"
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+#include <sys/errno.h>
+#include <vm/vm_zone.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#define _IP_VHL
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip6_icmp.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp6_var.h>
+#include <netinet/tcpip.h>
+#ifdef TCPDEBUG
+#include <netinet/tcp_debug.h>
+#endif
+
+extern void	tcp_notify __P((struct inpcb *, int));
+
+/*
+ * This is the actual shape of what we allocate using the zone
+ * allocator.  Doing it this way allows us to protect both structures
+ * using the same generation count, and also eliminates the overhead
+ * of allocating tcpcbs separately.  By hiding the structure here,
+ * we avoid changing most of the rest of the code (although it needs
+ * to be changed, eventually, for greater efficiency).
+ */
+#define ALIGNMENT	32
+#define	ALIGNM1		(ALIGNMENT-1)
+struct	inp_tp {
+	union {
+		struct	inpcb inp;
+		char	align[(sizeof(struct inpcb) + ALIGNM1) & ~ALIGNM1];
+	} inp_tp_u;
+	struct	tcpcb tcb;
+};
+#undef ALIGNMENT
+#undef ALIGNM1
+
+/*
+ * Tcp initialization
+ */
+void
+tcp6_init()
+{
+	/* tcpip6hdr or tcp6hdrs ? */
+	if (max_protohdr < sizeof(struct tcpip6hdr))
+		max_protohdr = sizeof(struct tcpip6hdr);
+	if (max_linkhdr + sizeof(struct tcpip6hdr) > MHLEN)
+		panic("tcp6_init");
+}
+
+/*
+ * Send a reset message back to the TCP at address specified by
+ * the given TCP/IP segment ti, and discard the mbuf containing it
+ * and any other attached mbufs.
+ *
+ * In any case the ack and sequence number of the transmitted
+ * segment are as specified by the parameters.
+ *
+ * NOTE: If m != NULL, then tr must point to *inside* the mbuf.
+ */
+void
+tcp6_resprst(tp, tr, m, ack, seq, flags)
+	struct tcpcb *tp;
+	struct tcp6hdrs *tr;
+	register struct mbuf *m;
+	tcp_seq ack, seq;
+	int flags;
+{
+	struct tcpip6hdr *ti = &tr->tr_ti6;
+	int tlen;
+	struct ip6ovck *ipc;
+	struct inpcb *inp = 0;
+	int win = 0;
+	struct route *ro = 0;
+	union route_6 sro;
+	u_int32_t flowinfo = 0;
+
+	if (tp) {
+		inp = tp->t_inpcb;
+		win = sbspace(&inp->inp_socket->so_rcv);
+		ro = &inp->inp_route;
+		flowinfo = inp->inp_oflowinfo;
+	} else {
+		ro = &sro.route;
+		bzero(&sro, sizeof sro);
+	}
+	m_freem(m->m_next);
+	m->m_next = 0;
+	m->m_data = (caddr_t)ti;
+	m->m_len = sizeof (struct tcpip6hdr);
+	tlen = sizeof (struct tcpip6hdr);
+	ipc = mtod(m, struct ip6ovck *);
+	{
+		struct in6_addr t;
+
+		COPY_ADDR6(ti->ti6_dst, t);
+		COPY_ADDR6(ti->ti6_src, ti->ti6_dst);
+		COPY_ADDR6(t, ti->ti6_src);
+	}
+	{
+		register u_int16_t t;
+
+		t = ti->ti6_dport;
+		ti->ti6_dport = ti->ti6_sport;
+		ti->ti6_sport = t;
+	}
+	m->m_len = tlen;
+	m->m_pkthdr.len = tlen;
+	m->m_pkthdr.rcvif = (struct ifnet *) 0;
+	ipc->ih6_wrd1 = ipc->ih6_wrd0 = 0;
+	ipc->ih6_len = htons(sizeof (struct tcphdr));
+	ipc->ih6_pr = IPPROTO_TCP;
+	ti->ti6_seq = htonl(seq);
+	ti->ti6_ack = htonl(ack);
+	ti->ti6_x2 = 0;
+	ti->ti6_off = sizeof (struct tcphdr) >> 2;
+	ti->ti6_flags = flags;
+	if (tp)
+		ti->ti6_win = htons((u_int16_t) (win >> tp->rcv_scale));
+	else
+		ti->ti6_win = htons((u_int16_t)win);
+	ti->ti6_urp = 0;
+	ti->ti6_sum = 0;
+	ti->ti6_sum = in_cksum(m, tlen);
+	ti->ti6_head = flowinfo | IPV6_VERSION;
+	ti->ti6_len = sizeof (struct tcphdr);
+	ti->ti6_nh = IPPROTO_TCP;
+	ti->ti6_hlim = ip_defttl;
+	(void) ip6_output(m, NULL, ro, 0, NULL, inp);
+	if (ro == &sro.route && ro->ro_rt) {
+		RTFREE(ro->ro_rt);
+	}
+}
+
+/*
+ * This is used to force keep alive messages out using the TCP
+ * template for a connection tp->t_template. We make a copy
+ * of the template and send directly to the addressed host.
+ *
+ * In any case the ack and sequence number of the transmitted
+ * segment are as specified by the parameters.
+ */
+void
+tcp6_sendkeep(tp, ack, seq)
+	struct tcpcb *tp;
+	tcp_seq ack, seq;
+{
+	register struct tcpip6hdr *ti;
+	register struct mbuf *m;
+	register int tlen;
+	register struct ip6ovck *ipc;
+	struct inpcb *inp;
+	int flags, win;
+	struct route *ro;
+	u_int32_t flowinfo = 0;
+
+	inp = tp->t_inpcb;
+	win = sbspace(&inp->inp_socket->so_rcv);
+	ro = &inp->inp_route;
+	flowinfo = inp->inp_oflowinfo;
+
+	m = m_gethdr(M_DONTWAIT, MT_HEADER);
+	if (m == NULL)
+		return;
+#ifdef TCP_COMPAT_42
+	tlen = 1;
+#else
+	tlen = 0;
+#endif
+	m->m_data += max_linkhdr;
+	bcopy((caddr_t)&tp->t_template->tt_i6,
+	      mtod(m, caddr_t),
+	      sizeof(struct ipv6));
+	bcopy((caddr_t)&tp->t_template->tt_t,
+	      mtod(m, caddr_t) + sizeof(struct ipv6),
+	      sizeof(struct tcphdr));
+	ti = mtod(m, struct tcpip6hdr *);
+	flags = TH_ACK;
+	tlen += sizeof (struct tcpip6hdr);
+	m->m_len = tlen;
+	m->m_pkthdr.len = tlen;
+	m->m_pkthdr.rcvif = (struct ifnet *) 0;
+	ipc = mtod(m, struct ip6ovck *);
+	ipc->ih6_wrd1 = ipc->ih6_wrd0 = 0;
+	ipc->ih6_len = htons(tlen - sizeof(struct ipv6));
+	ipc->ih6_pr = IPPROTO_TCP;
+	ti->ti6_seq = htonl(seq);
+	ti->ti6_ack = htonl(ack);
+	ti->ti6_x2 = 0;
+	ti->ti6_off = sizeof (struct tcphdr) >> 2;
+	ti->ti6_flags = flags;
+	if (tp)
+		ti->ti6_win = htons((u_int16_t) (win >> tp->rcv_scale));
+	else
+		ti->ti6_win = htons((u_int16_t)win);
+	ti->ti6_urp = 0;
+	ti->ti6_sum = 0;
+	ti->ti6_sum = in_cksum(m, tlen);
+	ti->ti6_head = flowinfo | IPV6_VERSION;
+	ti->ti6_len = tlen - sizeof(struct ipv6);
+	ti->ti6_nh = IPPROTO_TCP;
+	ti->ti6_hlim = ip_defttl;
+	(void) ip6_output(m, NULL, ro, 0, NULL, inp);
+}
+
+/*
+ * Drop a TCP connection, reporting
+ * the specified error.  If connection is synchronized,
+ * then send a RST to peer.
+ */
+struct tcpcb *
+tcp6_drop(tp, errno)
+	register struct tcpcb *tp;
+	int errno;
+{
+	struct socket *so = tp->t_inpcb->inp_socket;
+
+	if (TCPS_HAVERCVDSYN(tp->t_state)) {
+		tp->t_state = TCPS_CLOSED;
+		(void) tcp6_output(tp);
+		tcpstat.tcps_drops++;
+	} else
+		tcpstat.tcps_conndrops++;
+	if (errno == ETIMEDOUT && tp->t_softerror)
+		errno = tp->t_softerror;
+	so->so_error = errno;
+	return (tcp6_close(tp));
+}
+
+/*
+ * Close a TCP control block:
+ *	discard all space held by the tcp
+ *	discard internet protocol block
+ *	wake up any sleepers
+ */
+struct tcpcb *
+tcp6_close(tp)
+	register struct tcpcb *tp;
+{
+	register struct tcp6hdrs *t;
+	struct inpcb *inp = tp->t_inpcb;
+	struct socket *so = inp->inp_socket;
+	register struct mbuf *m;
+	register struct rtentry *rt;
+	int dosavessthresh;
+
+	/*
+	 * If we got enough samples through the srtt filter,
+	 * save the rtt and rttvar in the routing entry.
+	 * 'Enough' is arbitrarily defined as the 16 samples.
+	 * 16 samples is enough for the srtt filter to converge
+	 * to within 5% of the correct value; fewer samples and
+	 * we could save a very bogus rtt.
+	 *
+	 * Don't update the default route's characteristics and don't
+	 * update anything that the user "locked".
+	 */
+	if (tp->t_rttupdated >= 16 &&
+	    (rt = inp->inp_route.ro_rt) &&
+	    !IS_ANYSOCKADDR(satosin6(rt_key(rt)))) {
+		register u_long i = 0;
+
+		if ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0) {
+			i = tp->t_srtt *
+			    (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE));
+			if (rt->rt_rmx.rmx_rtt && i)
+				/*
+				 * filter this update to half the old & half
+				 * the new values, converting scale.
+				 * See route.h and tcp_var.h for a
+				 * description of the scaling constants.
+				 */
+				rt->rt_rmx.rmx_rtt =
+				    (rt->rt_rmx.rmx_rtt + i) / 2;
+			else
+				rt->rt_rmx.rmx_rtt = i;
+			tcpstat.tcps_cachedrtt++;
+		}
+		if ((rt->rt_rmx.rmx_locks & RTV_RTTVAR) == 0) {
+			i = tp->t_rttvar *
+			    (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE));
+			if (rt->rt_rmx.rmx_rttvar && i)
+				rt->rt_rmx.rmx_rttvar =
+				    (rt->rt_rmx.rmx_rttvar + i) / 2;
+			else
+				rt->rt_rmx.rmx_rttvar = i;
+			tcpstat.tcps_cachedrttvar++;
+		}
+		/*
+		 * The old comment here said:
+		 * update the pipelimit (ssthresh) if it has been updated
+		 * already or if a pipesize was specified & the threshhold
+		 * got below half the pipesize.  I.e., wait for bad news
+		 * before we start updating, then update on both good
+		 * and bad news.
+		 *
+		 * But we want to save the ssthresh even if no pipesize is
+		 * specified explicitly in the route, because such
+		 * connections still have an implicit pipesize specified
+		 * by the global tcp_sendspace.  In the absence of a reliable
+		 * way to calculate the pipesize, it will have to do.
+		 */
+		i = tp->snd_ssthresh;
+#if 1
+		if (rt->rt_rmx.rmx_sendpipe != 0)
+			dosavessthresh = (i < rt->rt_rmx.rmx_sendpipe / 2);
+		else
+			dosavessthresh = (i < so->so_snd.sb_hiwat / 2);
+#else
+		dosavessthresh = (i < rt->rt_rmx.rmx_sendpipe / 2);
+#endif
+		if (((rt->rt_rmx.rmx_locks & RTV_SSTHRESH) == 0 &&
+		     i != 0 && rt->rt_rmx.rmx_ssthresh != 0)
+		    || dosavessthresh) {
+			/*
+			 * convert the limit from user data bytes to
+			 * packets then to packet data bytes.
+			 */
+			i = (i + tp->t_maxseg / 2) / tp->t_maxseg;
+			if (i < 2)
+				i = 2;
+			i *= (u_long)(tp->t_maxseg + sizeof (struct tcpip6hdr));
+			if (rt->rt_rmx.rmx_ssthresh)
+				rt->rt_rmx.rmx_ssthresh =
+				    (rt->rt_rmx.rmx_ssthresh + i) / 2;
+			else
+				rt->rt_rmx.rmx_ssthresh = i;
+			tcpstat.tcps_cachedssthresh++;
+		}
+	}
+	/* free the reassembly queue, if any */
+	t = tp->seg_next6;
+	while (t != (struct tcp6hdrs *)tp) {
+		t = (struct tcp6hdrs *)t->tr_next;
+		m = REASS_MBUF6((struct tcp6hdrs *)t->tr_prev);
+		remque(t->tr_prev);
+		m_freem(m);
+	}
+	if (tp->t_template)
+		(void) m_free(dtom(tp->t_template));
+	inp->inp_ppcb = NULL;
+	soisdisconnected(so);
+	in_pcbdetach(inp);
+	tcpstat.tcps_closed++;
+	return ((struct tcpcb *)0);
+}
+
+/* ARGSUSED */
+void
+tcp6_ctlinput(cmd, sa, arg)
+	int cmd;
+	struct sockaddr *sa;
+	void *arg;
+{
+	struct ctli_arg *ca = (struct ctli_arg *)arg;
+	register struct ipv6 *ip = ca ? ca->ctli_ip : 0;
+	register struct tcphdr *th;
+	void (*notify) __P((struct inpcb *, int)) = tcp_notify;
+	int errno;
+
+	if (cmd == PRC_QUENCH)
+		notify = tcp_quench;
+	else if (cmd == PRC_MSGSIZE) {
+		if (ip == 0)
+			return;
+		notify = tcp6_mtudisc;
+		/* notify will be sent to only one PCB ?!? */
+	} else if (!PRC_IS_REDIRECT(cmd) &&
+		 ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0))
+		return;
+	if (ip) {
+		th = (struct tcphdr *)(ip + 1);
+		in6_pcbnotify(&tcb, sa, th->th_dport,
+			      &ip->ip6_src, th->th_sport,
+			      cmd, notify);
+	} else
+		in6_pcbnotify(&tcb, sa, 0, NULL, 0, cmd, notify);
+}
+
+/*
+ * When `need fragmentation' ICMP is received, update our idea of the MSS
+ * based on the new value in the route.  Also nudge TCP to send something,
+ * since we know the packet we just sent was dropped.
+ * This duplicates some code in the tcp6_mss() function in tcp6_input.c.
+ * If errno != 0 this triggers retransmit.
+ */
+void
+tcp6_mtudisc(inp, errno)
+	struct inpcb *inp;
+	int errno;
+{
+	struct tcpcb *tp = intotcpcb(inp);
+	struct rtentry *rt;
+	struct rmxp_tao *taop;
+	struct socket *so = inp->inp_socket;
+	int offered;
+	int mss;
+
+	if (tp) {
+		/* first cleanup the route */
+
+		if (inp->inp_route.ro_rt) {
+			rtfree(inp->inp_route.ro_rt);
+			inp->inp_route.ro_rt = 0;
+		}
+
+		rt = tcp6_rtlookup(inp);
+		if (rt == 0) {
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_PMTU)
+				printf("tcp6_mtudisc no route\n");
+#endif
+			tp->t_maxopd = tp->t_maxseg = tcp_mssdflt;
+			return;
+		}
+		taop = rmx_taop(rt->rt_rmx);
+		offered = taop->tao_mssopt;
+		if (rt->rt_rmx.rmx_mtu == 0)
+			rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu;
+		mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpip6hdr);
+		if (inp->inp_options)
+			mss -= inp->inp_options->m_pkthdr.len;
+		if (tp->t_omaxopd)
+			mss = min(mss, tp->t_omaxopd);
+		if (offered)
+			mss = min(mss, offered);
+		mss = max(mss, 64);		/* sanity */
+
+		/* This disables growing PMTU ?!? */
+		if (tp->t_maxopd <= mss) {
+#ifdef DIAGNOSTIC
+			if (ip6printfs & D6_PMTU)
+				printf("tcp6_mtudisc %d > %d\n",
+				       mss, tp->t_maxopd);
+#endif
+			return;
+		}
+		tp->t_maxopd = mss;
+
+		if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP &&
+		    (tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP)
+			mss -= TCPOLEN_TSTAMP_APPA;
+		if ((tp->t_flags & (TF_REQ_CC|TF_NOOPT)) == TF_REQ_CC &&
+		    (tp->t_flags & TF_RCVD_CC) == TF_RCVD_CC)
+			mss -= TCPOLEN_CC_APPA;
+#if	(MCLBYTES & (MCLBYTES - 1)) == 0
+		if (mss > MCLBYTES)
+			mss &= ~(MCLBYTES-1);
+#else
+		if (mss > MCLBYTES)
+			mss = mss / MCLBYTES * MCLBYTES;
+#endif
+		if (so->so_snd.sb_hiwat < mss)
+			mss = so->so_snd.sb_hiwat;
+
+		if (mss < tp->t_maxseg)
+			tp->snd_cwnd = mss;
+		tp->t_maxseg = mss;
+
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_PMTU)
+			printf("tcp6_mtudisc -> %d/%d\n", tp->t_maxopd, mss);
+#endif
+
+		if (errno) {
+			tcpstat.tcps_mturesent++;
+			tp->t_rtt = 0;
+			tp->snd_nxt = tp->snd_una;
+			tcp6_output(tp);
+		}
+	}
+}
+
+/*
+ * Look-up the routing entry to the peer of this inpcb.  If no route
+ * is found and it cannot be allocated the return NULL.  This routine
+ * is called by TCP routines that access the rmx structure and by tcp_mss
+ * to get the interface MTU.
+ */
+struct rtentry *
+tcp6_rtlookup(inp)
+	struct inpcb *inp;
+{
+	struct route *ro;
+	struct rtentry *rt;
+
+	ro = &inp->inp_route;
+	rt = ro->ro_rt;
+	if (rt == NULL || !(rt->rt_flags & RTF_UP)) {
+		/* No route yet, so try to acquire one */
+		if (inp->inp_fatype & IPATYPE_IPV6) {
+			ro->ro_dst.sa_family = AF_INET6;
+			ro->ro_dst.sa_len = sizeof(struct sockaddr_in6);
+			COPY_ADDR6(inp->inp_faddr6,
+				   satosin6(&ro->ro_dst)->sin6_addr);
+			in6_rtalloc(ro, INP_IFA);
+			rt = ro->ro_rt;
+		}
+	}
+	return rt;
+}
diff -uN src-current/sys/netinet/tcp6_timer.c src-current-ipv6/sys/netinet/tcp6_timer.c
--- src-current/sys/netinet/tcp6_timer.c
+++ src-current-ipv6/sys/netinet/tcp6_timer.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 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.
+ *
+ *	@(#)tcp_timer.c	8.1 (Berkeley) 6/10/93
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+#include <sys/errno.h>
+
+#include <machine/cpu.h>	/* before tcp_seq.h, for tcp_random18() */
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp6_var.h>
+#include <netinet/tcpip.h>
+
+extern	int always_keepalive;
+extern	int tcp_maxpersistidle;
+extern	int tcp_totbackoff;
+extern	int tcp_keepintvl;
+
+/*
+ * Fast timeout routine for processing delayed acks
+ */
+void
+tcp6_fasttimo()
+{
+	register struct inpcb *inp;
+	register struct tcpcb *tp;
+	int s;
+
+	s = splnet();
+	for (inp = tcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
+		if (((inp->inp_flags & INP_COMPATV4) == 0) &&
+		    (tp = (struct tcpcb *)inp->inp_ppcb) &&
+		    (tp->t_flags & TF_DELACK)) {
+			tp->t_flags &= ~TF_DELACK;
+			tp->t_flags |= TF_ACKNOW;
+			tcpstat.tcps_delack++;
+			(void) tcp6_output(tp);
+		}
+	}
+	splx(s);
+}
+
+/*
+ * Tcp protocol timeout routine called every 500 ms.
+ * Updates the timers in all active tcb's and
+ * causes finite state machine actions if timers expire.
+ */
+void
+tcp6_slowtimo()
+{
+	register struct inpcb *ip, *ipnxt;
+	register struct tcpcb *tp;
+	register int i;
+	int s;
+
+	s = splnet();
+
+	tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl;
+
+	ip = tcb.lh_first;
+	if (ip == NULL) {
+		splx(s);
+		return;
+	}
+	/*
+	 * Search through tcb's and update active timers.
+	 */
+	for (; ip != NULL; ip = ipnxt) {
+		ipnxt = ip->inp_list.le_next;
+		tp = intotcpcb(ip);
+		if (((ip->inp_flags & INP_COMPATV4) != 0) ||
+		    (tp == 0) || (tp->t_state == TCPS_LISTEN))
+			continue;
+		for (i = 0; i < TCPT_NTIMERS; i++) {
+			if (tp->t_timer[i] && --tp->t_timer[i] == 0) {
+				tp = tcp6_timers(tp, i);
+				if (tp == NULL)
+					goto tpgone;
+			}
+		}
+		tp->t_idle++;
+		tp->t_duration++;
+		if (tp->t_rtt)
+			tp->t_rtt++;
+tpgone:
+		;
+	}
+	tcp_iss += TCP_ISSINCR/PR_SLOWHZ;		/* increment iss */
+#ifdef TCP_COMPAT_42
+	if ((int)tcp_iss < 0)
+		tcp_iss = TCP_ISSINCR;			/* XXX */
+#endif
+	tcp_now++;					/* for timestamps */
+	splx(s);
+}
+
+/*
+ * TCP timer processing.
+ */
+struct tcpcb *
+tcp6_timers(tp, timer)
+	register struct tcpcb *tp;
+	int timer;
+{
+	register int rexmt;
+
+	switch (timer) {
+
+	/*
+	 * 2 MSL timeout in shutdown went off.  If we're closed but
+	 * still waiting for peer to close and connection has been idle
+	 * too long, or if 2MSL time is up from TIME_WAIT, delete connection
+	 * control block.  Otherwise, check again in a bit.
+	 */
+	case TCPT_2MSL:
+		if (tp->t_state != TCPS_TIME_WAIT &&
+		    tp->t_idle <= tcp_maxidle)
+			tp->t_timer[TCPT_2MSL] = tcp_keepintvl;
+		else
+			tp = tcp6_close(tp);
+		break;
+
+	/*
+	 * Retransmission timer went off.  Message has not
+	 * been acked within retransmit interval.  Back off
+	 * to a longer retransmit interval and retransmit one segment.
+	 */
+	case TCPT_REXMT:
+		if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
+			tp->t_rxtshift = TCP_MAXRXTSHIFT;
+			tcpstat.tcps_timeoutdrop++;
+			tp = tcp6_drop(tp, tp->t_softerror ?
+			    tp->t_softerror : ETIMEDOUT);
+			break;
+		}
+		tcpstat.tcps_rexmttimeo++;
+		rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
+		TCPT_RANGESET(tp->t_rxtcur, rexmt,
+		    tp->t_rttmin, TCPTV_REXMTMAX);
+		tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+		/*
+		 * If losing, let the lower level know and try for
+		 * a better route.  Also, if we backed off this far,
+		 * our srtt estimate is probably bogus.  Clobber it
+		 * so we'll take the next rtt measurement as our srtt;
+		 * move the current srtt into rttvar to keep the current
+		 * retransmit times until then.
+		 */
+		if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
+			in_losing(tp->t_inpcb);
+			tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
+			tp->t_srtt = 0;
+		}
+		tp->snd_nxt = tp->snd_una;
+		/*
+		 * Force a segment to be sent.
+		 */
+		tp->t_flags |= TF_ACKNOW;
+		/*
+		 * If timing a segment in this window, stop the timer.
+		 */
+		tp->t_rtt = 0;
+		/*
+		 * Close the congestion window down to one segment
+		 * (we'll open it by one segment for each ack we get).
+		 * Since we probably have a window's worth of unacked
+		 * data accumulated, this "slow start" keeps us from
+		 * dumping all that data as back-to-back packets (which
+		 * might overwhelm an intermediate gateway).
+		 *
+		 * There are two phases to the opening: Initially we
+		 * open by one mss on each ack.  This makes the window
+		 * size increase exponentially with time.  If the
+		 * window is larger than the path can handle, this
+		 * exponential growth results in dropped packet(s)
+		 * almost immediately.  To get more time between
+		 * drops but still "push" the network to take advantage
+		 * of improving conditions, we switch from exponential
+		 * to linear window opening at some threshhold size.
+		 * For a threshhold, we use half the current window
+		 * size, truncated to a multiple of the mss.
+		 *
+		 * (the minimum cwnd that will give us exponential
+		 * growth is 2 mss.  We don't allow the threshhold
+		 * to go below this.)
+		 */
+		{
+		u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
+		if (win < 2)
+			win = 2;
+		tp->snd_cwnd = tp->t_maxseg;
+		tp->snd_ssthresh = win * tp->t_maxseg;
+		tp->t_dupacks = 0;
+#ifdef ALTQ_ECN
+		tp->snd_rcvr = tp->snd_max;
+#endif
+		}
+		(void) tcp6_output(tp);
+		break;
+
+	/*
+	 * Persistance timer into zero window.
+	 * Force a byte to be output, if possible.
+	 */
+	case TCPT_PERSIST:
+		tcpstat.tcps_persisttimeo++;
+		/*
+		 * Hack: if the peer is dead/unreachable, we do not
+		 * time out if the window is closed.  After a full
+		 * backoff, drop the connection if the idle time
+		 * (no responses to probes) reaches the maximum
+		 * backoff that we would use if retransmitting.
+		 */
+		if (tp->t_rxtshift == TCP_MAXRXTSHIFT) {
+			u_long maxidle = TCP_REXMTVAL(tp);
+			if (maxidle < tp->t_rttmin)
+				maxidle = tp->t_rttmin;
+			maxidle *= tcp_totbackoff;
+			if (tp->t_idle >= tcp_maxpersistidle ||
+			    tp->t_idle >= maxidle) {
+				tcpstat.tcps_persistdrop++;
+				tp = tcp6_drop(tp, ETIMEDOUT);
+				break;
+			}
+		}
+		tcp_setpersist(tp);
+		tp->t_force = 1;
+		(void) tcp6_output(tp);
+		tp->t_force = 0;
+		break;
+
+	/*
+	 * Keep-alive timer went off; send something
+	 * or drop connection if idle for too long.
+	 */
+	case TCPT_KEEP:
+		tcpstat.tcps_keeptimeo++;
+		if (tp->t_state < TCPS_ESTABLISHED)
+			goto dropit;
+		if ((always_keepalive ||
+		     tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE) &&
+		    tp->t_state <= TCPS_CLOSING) {
+		    	if (tp->t_idle >= tcp_keepidle + tcp_maxidle)
+				goto dropit;
+			/*
+			 * Send a packet designed to force a response
+			 * if the peer is up and reachable:
+			 * either an ACK if the connection is still alive,
+			 * or an RST if the peer has closed the connection
+			 * due to timeout or reboot.
+			 * Using sequence number tp->snd_una-1
+			 * causes the transmitted zero-length segment
+			 * to lie outside the receive window;
+			 * by the protocol spec, this requires the
+			 * correspondent TCP to respond.
+			 */
+			tcpstat.tcps_keepprobe++;
+#ifdef TCP_COMPAT_42
+			/*
+			 * The keepalive packet must have nonzero length
+			 * to get a 4.2 host to respond.
+			 */
+			tcp6_sendkeep(tp, tp->rcv_nxt - 1, tp->snd_una - 1);
+#else
+			tcp6_sendkeep(tp, tp->rcv_nxt, tp->snd_una - 1);
+#endif
+			tp->t_timer[TCPT_KEEP] = tcp_keepintvl;
+		} else
+			tp->t_timer[TCPT_KEEP] = tcp_keepidle;
+		break;
+	dropit:
+		tcpstat.tcps_keepdrops++;
+		tp = tcp6_drop(tp, ETIMEDOUT);
+		break;
+	}
+	return (tp);
+}
diff -uN src-current/sys/netinet/tcp6_usrreq.c src-current-ipv6/sys/netinet/tcp6_usrreq.c
--- src-current/sys/netinet/tcp6_usrreq.c
+++ src-current-ipv6/sys/netinet/tcp6_usrreq.c
@@ -0,0 +1,831 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 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.
+ *
+ *	@(#)tcp_usrreq.c	8.2 (Berkeley) 1/3/94
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcpip.h>
+#include <netinet/tcp6_var.h>
+#include <netinet/tcp_debug.h>
+
+/*
+ * TCP protocol interface to socket abstraction.
+ */
+
+static int tcp6_connect __P((struct tcpcb *, struct sockaddr *, struct proc *p));
+
+/*
+ * TCP attaches to socket via pru_attach(), reserving space,
+ * and an internet control block.
+ */
+static int
+tcp6_usr_attach(struct socket *so, int proto, struct proc *p)
+{
+	int s = splnet();
+	int error;
+	struct inpcb *inp = sotoinpcb(so);
+	struct tcpcb *tp = 0;
+
+	if (inp) {
+		error = EISCONN;
+		goto out;
+	}
+
+	error = tcp_attach(so, p);
+	if (error)
+		goto out;
+
+	((struct inpcb *) so->so_pcb)->inp_flags = INP_COMPATANY;
+	if ((so->so_options & SO_LINGER) && so->so_linger == 0)
+		so->so_linger = TCP_LINGERTIME * hz;
+	tp = sototcpcb(so);
+out:
+	splx(s);
+	return error;
+}
+
+/*
+ * pru_detach() detaches the TCP protocol from the socket.
+ * If the protocol state is non-embryonic, then can't
+ * do this directly: have to initiate a pru_disconnect(),
+ * which may finish later; embryonic TCB's can just
+ * be discarded here.
+ */
+static int
+tcp6_usr_detach(struct socket *so)
+{
+	int s = splnet();
+	int error = 0;
+	struct inpcb *inp = sotoinpcb(so);
+	struct tcpcb *tp;
+
+	if (inp == 0) {
+		splx(s);
+		return EINVAL;	/* XXX */
+	}
+	tp = intotcpcb(inp);
+	if (tp->t_state > TCPS_LISTEN)
+		tp = SELECT(disconnect)(tp);
+	else
+		tp = SELECT(close)(tp);
+
+	splx(s);
+	return error;
+}
+
+#define	COMMON_START()	do { \
+				     if (inp == 0) { \
+					     splx(s); \
+					     return EINVAL; \
+				     } \
+				     tp = intotcpcb(inp); \
+		     } while(0)
+			     
+#define COMMON_END(req)	out: splx(s); return error; goto out
+
+
+/*
+ * Give the socket an address.
+ */
+static int
+tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
+{
+	int s = splnet();
+	int error = 0;
+	struct inpcb *inp = sotoinpcb(so);
+	struct tcpcb *tp;
+	struct sockaddr_in *sinp;
+	struct sockaddr_in6 *sin6p;
+
+	COMMON_START();
+
+	/*
+	 * Must check for multicast addresses and disallow binding
+	 * to them.
+	 */
+	sin6p = (struct sockaddr_in6 *)nam;
+	if (sin6p->sin6_family == AF_INET6 &&
+	    IS_MULTIADDR6(sin6p->sin6_addr)) {
+		error = EAFNOSUPPORT;
+		goto out;
+	}
+	sinp = (struct sockaddr_in *)nam;
+	if (sinp->sin_family == AF_INET &&
+	    IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
+		error = EAFNOSUPPORT;
+		goto out;
+	}
+	error = in6_pcbbind(inp, nam, 0, p);
+	if (error)
+		goto out;
+	COMMON_END(PRU_BIND);
+
+}
+
+/*
+ * Give the socket an address (dynamic version).
+ */
+static int
+tcp6_usr_dynbind(struct socket *so, struct sockaddr *nam, struct proc *p)
+{
+	return EINVAL;
+}
+
+/*
+ * Prepare to accept connections.
+ */
+static int
+tcp6_usr_listen(struct socket *so, struct proc *p)
+{
+	int s = splnet();
+	int error = 0;
+	struct inpcb *inp = sotoinpcb(so);
+	struct tcpcb *tp;
+
+	COMMON_START();
+	if (inp->inp_lport == 0)
+		error = in6_pcbbind(inp, NULL, 0, p);
+	if (error == 0)
+		tp->t_state = TCPS_LISTEN;
+	COMMON_END(PRU_LISTEN);
+}
+
+/*
+ * Initiate connection to peer.
+ * Create a template for use in transmissions on this connection.
+ * Enter SYN_SENT state, and mark socket as connecting.
+ * Start keep-alive timer, and seed output sequence space.
+ * Send initial segment on connection.
+ */
+static int
+tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
+{
+	int s = splnet();
+	int error = 0;
+	struct inpcb *inp = sotoinpcb(so);
+	struct tcpcb *tp;
+	struct sockaddr_in *sinp;
+	struct sockaddr_in6 *sin6p;
+
+	COMMON_START();
+
+	/*
+	 * Must disallow TCP ``connections'' to multicast addresses.
+	 */
+	sin6p = (struct sockaddr_in6 *)nam;
+	if (sin6p->sin6_family == AF_INET6
+	    && IS_MULTIADDR6(sin6p->sin6_addr)) {
+		error = EAFNOSUPPORT;
+		goto out;
+	}
+	sinp = (struct sockaddr_in *)nam;
+	if (sinp->sin_family == AF_INET
+	    && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
+		error = EAFNOSUPPORT;
+		goto out;
+	}
+
+	if ((error = tcp6_connect(tp, nam ,p)) != 0)
+		goto out;
+	error = SELECT(output)(tp);
+	COMMON_END(PRU_CONNECT);
+}
+
+/*
+ * Initiate disconnect from peer.
+ * If connection never passed embryonic stage, just drop;
+ * else if don't need to let data drain, then can just drop anyways,
+ * else have to begin TCP shutdown process: mark socket disconnecting,
+ * drain unread data, state switch to reflect user close, and
+ * send segment (e.g. FIN) to peer.  Socket will be really disconnected
+ * when peer sends FIN and acks ours.
+ *
+ * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
+ */
+static int
+tcp6_usr_disconnect(struct socket *so)
+{
+	int s = splnet();
+	int error = 0;
+	struct inpcb *inp = sotoinpcb(so);
+	struct tcpcb *tp;
+
+	COMMON_START();
+	tp = SELECT(disconnect)(tp);
+	COMMON_END(PRU_DISCONNECT);
+}
+
+/*
+ * Accept a connection.  Essentially all the work is
+ * done at higher levels; just return the address
+ * of the peer, storing through addr.
+ */
+static int
+tcp6_usr_accept(struct socket *so, struct sockaddr **nam)
+{
+	int s = splnet();
+	int error = 0;
+	struct inpcb *inp = sotoinpcb(so);
+	struct tcpcb *tp;
+
+	COMMON_START();
+	if ((inp->inp_flags & INP_COMPATV6) == 0) {
+		/* connected to an IPv4 peer */
+		inp->inp_laddr6.s6_addr32[2] = htonl(0xffff);
+	}
+	in6_setpeeraddr(so, nam);
+	COMMON_END(PRU_ACCEPT);
+}
+
+/*
+ * Mark the connection as being incapable of further output.
+ */
+static int
+tcp6_usr_shutdown(struct socket *so)
+{
+	int s = splnet();
+	int error = 0;
+	struct inpcb *inp = sotoinpcb(so);
+	struct tcpcb *tp;
+
+	COMMON_START();
+	socantsendmore(so);
+	tp = SELECT(usrclosed)(tp);
+	if (tp)
+		error = SELECT(output)(tp);
+	COMMON_END(PRU_SHUTDOWN);
+}
+
+/*
+ * After a receive, possibly send window update to peer.
+ */
+static int
+tcp6_usr_rcvd(struct socket *so, int flags)
+{
+	int s = splnet();
+	int error = 0;
+	struct inpcb *inp = sotoinpcb(so);
+	struct tcpcb *tp;
+
+	COMMON_START();
+	(void) SELECT(output)(tp);
+	COMMON_END(PRU_RCVD);
+}
+
+/*
+ * Do a send by putting data in output queue and updating urgent
+ * marker if URG set.  Possibly send more data.
+ */
+static int
+tcp6_usr_send(struct socket *so, int flags, struct mbuf *m,
+	     struct sockaddr *nam, struct mbuf *control, struct proc *p)
+{
+	int s = splnet();
+	int error = 0;
+	struct inpcb *inp = sotoinpcb(so);
+	struct tcpcb *tp;
+
+	COMMON_START();
+	if (control && control->m_len) {
+		m_freem(control); /* XXX shouldn't caller do this??? */
+		if (m)
+			m_freem(m);
+		return EINVAL;
+	}
+
+	if (!(flags & PRUS_OOB)) {
+		sbappend(&so->so_snd, m);
+		if (nam && tp->t_state < TCPS_SYN_SENT) {
+			/*
+			 * Do implied connect if not yet connected,
+			 * initialize window to default value, and
+			 * initialize maxseg/maxopd using peer's cached
+			 * MSS.
+			 */
+			error = tcp6_connect(tp, nam, p);
+			if (error)
+				goto out;
+			tp->snd_wnd = TTCP_CLIENT_SND_WND;
+			SELECT(mss)(tp, -1);
+		}
+
+		if (flags & PRUS_EOF) {
+			/*
+			 * Close the send side of the connection after
+			 * the data is sent.
+			 */
+			socantsendmore(so);
+			tp = SELECT(usrclosed)(tp);
+		}
+		if (tp != NULL)
+			error = SELECT(output)(tp);
+	} else {
+		if (sbspace(&so->so_snd) < -512) {
+			m_freem(m);
+			error = ENOBUFS;
+			goto out;
+		}
+		/*
+		 * According to RFC961 (Assigned Protocols),
+		 * the urgent pointer points to the last octet
+		 * of urgent data.  We continue, however,
+		 * to consider it to indicate the first octet
+		 * of data past the urgent section.
+		 * Otherwise, snd_up should be one lower.
+		 */
+		sbappend(&so->so_snd, m);
+		if (nam && tp->t_state < TCPS_SYN_SENT) {
+			/*
+			 * Do implied connect if not yet connected,
+			 * initialize window to default value, and
+			 * initialize maxseg/maxopd using peer's cached
+			 * MSS.
+			 */
+			error = tcp6_connect(tp, nam, p);
+			if (error)
+				goto out;
+			tp->snd_wnd = TTCP_CLIENT_SND_WND;
+			SELECT(mss)(tp, -1);
+		}
+		tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
+		tp->t_force = 1;
+		error = SELECT(output)(tp);
+		tp->t_force = 0;
+	}
+	COMMON_END((flags & PRUS_OOB) ? PRU_SENDOOB : 
+		   ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
+}
+
+/*
+ * Abort the TCP.
+ */
+static int
+tcp6_usr_abort(struct socket *so)
+{
+	int s = splnet();
+	int error = 0;
+	struct inpcb *inp = sotoinpcb(so);
+	struct tcpcb *tp;
+
+	COMMON_START();
+	tp = SELECT(drop)(tp, ECONNABORTED);
+	COMMON_END(PRU_ABORT);
+}
+
+/*
+ * Fill in st_bklsize for fstat() operations on a socket.
+ */
+static int
+tcp6_usr_sense(struct socket *so, struct stat *sb)
+{
+	int s = splnet();
+
+	sb->st_blksize = so->so_snd.sb_hiwat;
+	splx(s);
+	return 0;
+}
+
+/*
+ * Receive out-of-band data.
+ */
+static int
+tcp6_usr_rcvoob(struct socket *so, struct mbuf *m, int flags)
+{
+	int s = splnet();
+	int error = 0;
+	struct inpcb *inp = sotoinpcb(so);
+	struct tcpcb *tp;
+
+	COMMON_START();
+	if ((so->so_oobmark == 0 &&
+	     (so->so_state & SS_RCVATMARK) == 0) ||
+	    so->so_options & SO_OOBINLINE ||
+	    tp->t_oobflags & TCPOOB_HADDATA) {
+		error = EINVAL;
+		goto out;
+	}
+	if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
+		error = EWOULDBLOCK;
+		goto out;
+	}
+	m->m_len = 1;
+	*mtod(m, caddr_t) = tp->t_iobc;
+	if ((flags & MSG_PEEK) == 0)
+		tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
+	COMMON_END(PRU_RCVOOB);
+}
+
+/* xxx - should be const */
+struct pr_usrreqs tcp6_usrreqs = {
+	tcp6_usr_abort, tcp6_usr_accept, tcp6_usr_attach, tcp6_usr_bind,
+	tcp6_usr_connect, pru_connect2_notsupp, 
+in6_control, 
+tcp6_usr_detach,
+	tcp6_usr_disconnect, tcp6_usr_listen, in6_setpeeraddr, tcp6_usr_rcvd,
+	tcp6_usr_rcvoob, tcp6_usr_send, tcp6_usr_sense, tcp6_usr_shutdown,
+	in6_setsockaddr, sosend, soreceive, sopoll, tcp6_usr_dynbind
+};
+
+/*
+ * Common subroutine to open a TCP connection to remote host specified
+ * by struct sockaddr_in6 in mbuf *nam.  Call in6_pcbbind to assign a local
+ * port number if needed.  Call in6_pcbladdr to do the routing and to choose
+ * a local host address (interface).  If there is an existing incarnation
+ * of the same connection in TIME-WAIT state and if the remote host was
+ * sending CC options and if the connection duration was < MSL, then
+ * truncate the previous TIME-WAIT state and proceed.
+ * Initialize connection parameters and enter SYN-SENT state.
+ */
+static int
+tcp6_connect(tp, nam, p)
+	register struct tcpcb *tp;
+	struct sockaddr *nam;
+	struct proc *p;
+{
+	struct inpcb *inp = tp->t_inpcb, *oinp;
+	struct socket *so = inp->inp_socket;
+	struct tcpcb *otp;
+	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
+	struct sockaddr_in *sin;
+	struct sockaddr_in6 *ifaddr6 = 0;
+	struct sockaddr_in *ifaddr;
+	u_int32_t flowinfo;
+	int error, tos = 0;
+	struct rmxp_tao *taop;
+	struct rmxp_tao tao_noncached;
+
+	if (inp->inp_lport == 0) {
+		error = in6_pcbbind(inp, NULL, 0, p);
+		if (error)
+			return error;
+	}
+
+#ifdef notyet
+	/*
+	 * Cannot simply call in6_pcbconnect, because there might be an
+	 * earlier incarnation of this same connection still in
+	 * TIME_WAIT state, creating an ADDRINUSE error.
+	 */
+	error = in6_pcbladdr(inp, nam, &ifaddr6, &flowinfo);
+	if (error)
+		return error;
+
+	/* try to remap Priority to TOS */
+	switch (flowinfo & IPV6_FLOWINFO_PRIORITY) {
+	    case IPV6_PRIORITY_INTERACTIVE:
+		tos = IPTOS_LOWDELAY;
+		break;
+	    case IPV6_PRIORITY_BULK:
+		tos = IPTOS_THROUGHPUT;
+		break;
+	}
+
+	if (sin6->sin6_family == AF_INET)
+		goto version4;
+
+	oinp = in6_pcblookup_hash(inp->inp_pcbinfo,
+	    &sin6->sin6_addr, sin6->sin6_port,
+	    inp->inp_latype ? &inp->inp_laddr6 : &ifaddr6->sin6_addr,
+	    inp->inp_lport,  0);
+	if (oinp) {
+		if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&
+		otp->t_state == TCPS_TIME_WAIT &&
+		    otp->t_duration < TCPTV_MSL &&
+		    (otp->t_flags & TF_RCVD_CC))
+			otp = tcp6_close(otp);
+		else
+			return EADDRINUSE;
+	}
+	if (inp->inp_latype == IPATYPE_UNBD) {
+		COPY_ADDR6(ifaddr6->sin6_addr, inp->inp_laddr6);
+		inp->inp_latype = IPATYPE_IPV6;
+	}
+	inp->inp_flags &= ~INP_COMPATV4;
+	COPY_ADDR6(sin6->sin6_addr, inp->inp_faddr6);
+	inp->inp_fatype = IPATYPE_IPV6;
+	inp->inp_fport = sin6->sin6_port;
+	in_pcbrehash(inp);
+	if (tos)
+		inp->inp_tos = tos;
+	if (flowinfo)
+		inp->inp_oflowinfo = flowinfo;
+
+    version4:
+	ifaddr = (struct sockaddr_in *)ifaddr6;
+	sin = (struct sockaddr_in *)nam;
+	oinp = in_pcblookup(inp->inp_pcbinfo->listhead,
+	    sin->sin_addr, sin->sin_port,
+	    inp->inp_latype ? inp->inp_laddr : ifaddr->sin_addr,
+	    inp->inp_lport,  0);
+	if (oinp) {
+		if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&
+		otp->t_state == TCPS_TIME_WAIT &&
+		    otp->t_duration < TCPTV_MSL &&
+		    (otp->t_flags & TF_RCVD_CC))
+			otp = tcp_close(otp);
+		else
+			return EADDRINUSE;
+	}
+	if (inp->inp_latype == IPATYPE_UNBD) {
+		inp->inp_laddr = ifaddr->sin_addr;
+		inp->inp_latype = IPATYPE_IPV4;
+		inp->inp_laddr6.s6_addr32[0] = 0;
+		inp->inp_laddr6.s6_addr32[1] = 0;
+		inp->inp_laddr6.s6_addr32[2] = htonl(0xffff);
+	}
+	inp->inp_faddr = sin->sin_addr;
+	if (inp->inp_faddr.s_addr != INADDR_ANY) {
+		inp->inp_fatype = IPATYPE_IPV4;
+		inp->inp_faddr6.s6_addr32[0] = 0;
+		inp->inp_faddr6.s6_addr32[1] = 0;
+		inp->inp_faddr6.s6_addr32[2] = htonl(0xffff);
+	}
+	inp->inp_fport = sin->sin_port;
+	in_pcbrehash(inp);
+	if (tos)
+		inp->inp_tos = tos;
+	if (flowinfo)
+		inp->inp_oflowinfo = flowinfo;
+
+#else
+	error = in6_pcbconnect(inp, nam, p);
+	if (error)
+		return error;
+#endif
+
+	tp->t_template = tcp_template(tp);
+	if (tp->t_template == 0) {
+		in_pcbdisconnect(inp);
+		return ENOBUFS;
+	}
+
+	/* Compute window scaling to request.  */
+	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
+	    (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
+		tp->request_r_scale++;
+
+	soisconnecting(so);
+	tcpstat.tcps_connattempt++;
+	tp->t_state = TCPS_SYN_SENT;
+	tp->t_timer[TCPT_KEEP] = tcp_keepinit;
+	tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
+	tcp_sendseqinit(tp);
+
+	/*
+	 * Generate a CC value for this connection and
+	 * check whether CC or CCnew should be used.
+	 */
+	if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) {
+		taop = &tao_noncached;
+		bzero(taop, sizeof(*taop));
+	}
+
+	tp->cc_send = CC_INC(tcp_ccgen);
+	if (taop->tao_ccsent != 0 &&
+	    CC_GEQ(tp->cc_send, taop->tao_ccsent)) {
+		taop->tao_ccsent = tp->cc_send;
+	} else {
+		taop->tao_ccsent = 0;
+		tp->t_flags |= TF_SENDCCNEW;
+	}
+
+	return 0;
+}
+
+int
+tcp6_ctloutput(op, so, level, optname, mp, p)
+	int op;
+	struct socket *so;
+	int level, optname;
+	struct mbuf **mp;
+	struct proc *p;
+{
+	int error = 0, s;
+	struct inpcb *inp;
+	register struct tcpcb *tp;
+	register struct mbuf *m;
+	register int i;
+
+	s = splnet();
+	inp = sotoinpcb(so);
+	if (inp == NULL) {
+		splx(s);
+		if (op == PRCO_SETOPT && *mp)
+			(void) m_free(*mp);
+		return (ECONNRESET);
+	}
+	if (level != IPPROTO_TCP) {
+		error = ip6_ctloutput(op, so, level, optname, mp, p);
+		splx(s);
+		return (error);
+	}
+	tp = intotcpcb(inp);
+
+	switch (op) {
+
+	case PRCO_SETOPT:
+		m = *mp;
+		switch (optname) {
+
+		case TCP_NODELAY:
+			if (m == NULL || m->m_len < sizeof (int))
+				error = EINVAL;
+			else if (*mtod(m, int *))
+				tp->t_flags |= TF_NODELAY;
+			else
+				tp->t_flags &= ~TF_NODELAY;
+			break;
+
+		case TCP_MAXSEG:
+			if (m && (i = *mtod(m, int *)) > 0 && i <= tp->t_maxseg)
+				tp->t_maxseg = i;
+			else
+				error = EINVAL;
+			break;
+
+		case TCP_NOOPT:
+			if (m == NULL || m->m_len < sizeof (int))
+				error = EINVAL;
+			else if (*mtod(m, int *))
+				tp->t_flags |= TF_NOOPT;
+			else
+				tp->t_flags &= ~TF_NOOPT;
+			break;
+
+		case TCP_NOPUSH:
+			if (m == NULL || m->m_len < sizeof (int))
+				error = EINVAL;
+			else if (*mtod(m, int *))
+				tp->t_flags |= TF_NOPUSH;
+			else
+				tp->t_flags &= ~TF_NOPUSH;
+			break;
+
+		default:
+			error = ENOPROTOOPT;
+			break;
+		}
+		if (m)
+			(void) m_free(m);
+		break;
+
+	case PRCO_GETOPT:
+		*mp = m = m_get(M_WAIT, MT_SOOPTS);
+		m->m_len = sizeof(int);
+
+		switch (optname) {
+		case TCP_NODELAY:
+			*mtod(m, int *) = tp->t_flags & TF_NODELAY;
+			break;
+		case TCP_MAXSEG:
+			*mtod(m, int *) = tp->t_maxseg;
+			break;
+		case TCP_NOOPT:
+			*mtod(m, int *) = tp->t_flags & TF_NOOPT;
+			break;
+		case TCP_NOPUSH:
+			*mtod(m, int *) = tp->t_flags & TF_NOPUSH;
+			break;
+		default:
+			error = ENOPROTOOPT;
+			break;
+		}
+		break;
+	}
+	splx(s);
+	return (error);
+}
+
+/*
+ * Initiate (or continue) disconnect.
+ * If embryonic state, just send reset (once).
+ * If in ``let data drain'' option and linger null, just drop.
+ * Otherwise (hard), mark socket disconnecting and drop
+ * current input data; switch states based on user close, and
+ * send segment to peer (with FIN).
+ */
+struct tcpcb *
+tcp6_disconnect(tp)
+	register struct tcpcb *tp;
+{
+	struct socket *so = tp->t_inpcb->inp_socket;
+
+	if (tp->t_state < TCPS_ESTABLISHED)
+		tp = tcp6_close(tp);
+	else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
+		tp = tcp6_drop(tp, 0);
+	else {
+		soisdisconnecting(so);
+		sbflush(&so->so_rcv);
+		tp = tcp6_usrclosed(tp);
+		if (tp)
+			(void) tcp6_output(tp);
+	}
+	return (tp);
+}
+
+/*
+ * User issued close, and wish to trail through shutdown states:
+ * if never received SYN, just forget it.  If got a SYN from peer,
+ * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
+ * If already got a FIN from peer, then almost done; go to LAST_ACK
+ * state.  In all other cases, have already sent FIN to peer (e.g.
+ * after PRU_SHUTDOWN), and just have to play tedious game waiting
+ * for peer to send FIN or not respond to keep-alives, etc.
+ * We can let the user exit from the close as soon as the FIN is acked.
+ */
+struct tcpcb *
+tcp6_usrclosed(tp)
+	register struct tcpcb *tp;
+{
+
+	switch (tp->t_state) {
+
+	case TCPS_CLOSED:
+	case TCPS_LISTEN:
+		tp->t_state = TCPS_CLOSED;
+		tp = tcp6_close(tp);
+		break;
+
+	case TCPS_SYN_SENT:
+	case TCPS_SYN_RECEIVED:
+		tp->t_flags |= TF_NEEDFIN;
+		break;
+
+	case TCPS_ESTABLISHED:
+		tp->t_state = TCPS_FIN_WAIT_1;
+		break;
+
+	case TCPS_CLOSE_WAIT:
+		tp->t_state = TCPS_LAST_ACK;
+		break;
+	}
+	if (tp && tp->t_state >= TCPS_FIN_WAIT_2) {
+		soisdisconnected(tp->t_inpcb->inp_socket);
+		/* To prevent the connection hanging in FIN_WAIT_2 forever. */
+		if (tp->t_state == TCPS_FIN_WAIT_2)
+			tp->t_timer[TCPT_2MSL] = tcp_maxidle;
+	}
+	return (tp);
+}
diff -uN src-current/sys/netinet/tcp6_var.h src-current-ipv6/sys/netinet/tcp6_var.h
--- src-current/sys/netinet/tcp6_var.h
+++ src-current-ipv6/sys/netinet/tcp6_var.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1982, 1986, 1993, 1994
+ *	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.
+ *
+ *	@(#)tcp_var.h	8.3 (Berkeley) 4/10/94
+ */
+
+#ifndef _NETINET_TCP6_VAR_H_
+#define _NETINET_TCP6_VAR_H_
+
+#include "opt_inet6.h"
+
+/* XXX
+ * We want to avoid doing m_pullup on incoming packets but that
+ * means avoiding dtom on the tcp reassembly code.  That in turn means
+ * keeping an mbuf pointer in the reassembly queue (since we might
+ * have a cluster).  As a quick hack, the source & destination
+ * port numbers (which are no longer needed once we've located the
+ * tcpcb) are overlayed with an mbuf pointer.
+ */
+#define REASS_MBUF6(tr) (*(struct mbuf **)&((tr)->tr_t))
+
+#ifdef KERNEL
+
+#ifdef INET6
+#define SELECT(func) \
+	((inp->inp_flags & INP_COMPATV4) ? \
+		__CONCAT(tcp_,func) : __CONCAT(tcp6_,func))
+#else
+#define SELECT(func)	__CONCAT(tcp_,func)
+#endif
+
+#ifdef INET6
+struct tcpcb *
+	 tcp6_close __P((struct tcpcb *));
+void	 tcp6_ctlinput __P((int, struct sockaddr *, void *));
+int	 tcp6_ctloutput __P((int, struct socket *, int, int,
+			     struct mbuf **, struct proc *));
+struct tcpcb *
+	 tcp6_disconnect __P((struct tcpcb *));
+struct tcpcb *
+	 tcp6_drop __P((struct tcpcb *, int));
+void	 tcp6_fasttimo __P((void));
+void	 tcp6_init __P((void));
+void	 tcp6_input __P((struct mbuf *, int));
+void	 tcp6_mss __P((struct tcpcb *, int));
+int	 tcp6_mssopt __P((struct tcpcb *));
+void	 tcp6_mtudisc __P((struct inpcb *, int));
+int	 tcp6_output __P((struct tcpcb *));
+void	 tcp6_resprst __P((struct tcpcb *,
+	    struct tcp6hdrs *, struct mbuf *, tcp_seq, tcp_seq, int));
+struct rtentry *
+	 tcp6_rtlookup __P((struct inpcb *));
+void	 tcp6_sendkeep __P((struct tcpcb *, tcp_seq, tcp_seq));
+void	 tcp6_slowtimo __P((void));
+struct tcpcb *
+	 tcp6_timers __P((struct tcpcb *, int));
+struct tcpcb *
+	 tcp6_usrclosed __P((struct tcpcb *));
+
+extern	struct pr_usrreqs tcp6_usrreqs;
+
+#endif /* INET6 */
+#endif /* KERNEL */
+
+#endif /* _NETINET_TCP6_VAR_H_ */
diff -uN src-current/sys/netinet/tcp_debug.c src-current-ipv6/sys/netinet/tcp_debug.c
--- src-current/sys/netinet/tcp_debug.c
+++ src-current-ipv6/sys/netinet/tcp_debug.c
@@ -55,7 +55,10 @@
 
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
 #include <netinet/tcp.h>
 #include <netinet/tcp_fsm.h>
 #include <netinet/tcp_timer.h>
diff -uN src-current/sys/netinet/tcp_subr.c src-current-ipv6/sys/netinet/tcp_subr.c
--- src-current/sys/netinet/tcp_subr.c
+++ src-current-ipv6/sys/netinet/tcp_subr.c
@@ -34,6 +34,7 @@
  *	$Id: tcp_subr.c,v 1.45 1998/05/15 20:11:35 wollman Exp $
  */
 
+#include "opt_inet6.h"
 #include "opt_compat.h"
 #include "opt_tcpdebug.h"
 
@@ -49,21 +50,25 @@
 
 #include <vm/vm_zone.h>
 
-#include <net/route.h>
 #include <net/if.h>
+#include <net/route.h>
 
 #define _IP_VHL
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
 #include <netinet/in_pcb.h>
 #include <netinet/in_var.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
 #include <netinet/tcp.h>
 #include <netinet/tcp_fsm.h>
 #include <netinet/tcp_seq.h>
 #include <netinet/tcp_timer.h>
 #include <netinet/tcp_var.h>
+#include <netinet/tcp6_var.h>
 #include <netinet/tcpip.h>
 #ifdef TCPDEBUG
 #include <netinet/tcp_debug.h>
@@ -89,7 +94,7 @@
 	   0, "Number of active PCBs");
 
 static void	tcp_cleartaocache __P((void));
-static void	tcp_notify __P((struct inpcb *, int));
+void	tcp_notify __P((struct inpcb *, int));
 
 /*
  * Target size of TCP PCB hash tables. Must be a power of two.
@@ -147,37 +152,35 @@
  * in a skeletal tcp/ip header, minimizing the amount of work
  * necessary when the connection is used.
  */
-struct tcpiphdr *
+struct tcptemp *
 tcp_template(tp)
 	struct tcpcb *tp;
 {
 	register struct inpcb *inp = tp->t_inpcb;
 	register struct mbuf *m;
-	register struct tcpiphdr *n;
+	register struct tcptemp *n;
 
 	if ((n = tp->t_template) == 0) {
 		m = m_get(M_DONTWAIT, MT_HEADER);
 		if (m == NULL)
 			return (0);
-		m->m_len = sizeof (struct tcpiphdr);
-		n = mtod(m, struct tcpiphdr *);
+		m->m_len = sizeof (struct tcptemp);
+		n = mtod(m, struct tcptemp *);
 	}
-	n->ti_next = n->ti_prev = 0;
-	n->ti_x1 = 0;
-	n->ti_pr = IPPROTO_TCP;
-	n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
-	n->ti_src = inp->inp_laddr;
-	n->ti_dst = inp->inp_faddr;
-	n->ti_sport = inp->inp_lport;
-	n->ti_dport = inp->inp_fport;
-	n->ti_seq = 0;
-	n->ti_ack = 0;
-	n->ti_x2 = 0;
-	n->ti_off = 5;
-	n->ti_flags = 0;
-	n->ti_win = 0;
-	n->ti_sum = 0;
-	n->ti_urp = 0;
+	bzero((caddr_t)n, sizeof(struct tcptemp));
+	n->tt_pr = IPPROTO_TCP;
+	n->tt_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
+	n->tt_src = inp->inp_laddr;
+	n->tt_dst = inp->inp_faddr;
+	n->tt_sport = inp->inp_lport;
+	n->tt_dport = inp->inp_fport;
+	n->tt_off = 5;
+#ifdef INET6
+	n->tt_pr6 = IPPROTO_TCP;
+	n->tt_len6 = n->tt_len;
+	COPY_ADDR6(inp->inp_laddr6, n->tt_src6);
+	COPY_ADDR6(inp->inp_faddr6, n->tt_dst6);
+#endif
 	return (n);
 }
 
@@ -306,7 +309,7 @@
 	tp->t_rxtcur = TCPTV_RTOBASE;
 	tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
 	tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
-	inp->inp_ip_ttl = ip_defttl;
+	inp->inp_ttl = ip_defttl;
 	inp->inp_ppcb = (caddr_t)tp;
 	return (tp);		/* XXX */
 }
@@ -460,7 +463,7 @@
  * store error as soft error, but wake up user
  * (for now, won't do anything until can select for soft error).
  */
-static void
+void
 tcp_notify(inp, error)
 	struct inpcb *inp;
 	int error;
@@ -730,7 +733,7 @@
 tcp_gettaocache(inp)
 	struct inpcb *inp;
 {
-	struct rtentry *rt = tcp_rtlookup(inp);
+	struct rtentry *rt = SELECT(rtlookup)(inp);
 
 	/* Make sure this is a host route and is up. */
 	if (rt == NULL ||
diff -uN src-current/sys/netinet/tcp_timer.c src-current-ipv6/sys/netinet/tcp_timer.c
--- src-current/sys/netinet/tcp_timer.c
+++ src-current-ipv6/sys/netinet/tcp_timer.c
@@ -47,12 +47,16 @@
 
 #include <machine/cpu.h>	/* before tcp_seq.h, for tcp_random18() */
 
+#include <net/if.h>
 #include <net/route.h>
 
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
 #include <netinet/in_pcb.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
 #include <netinet/tcp.h>
 #include <netinet/tcp_fsm.h>
 #include <netinet/tcp_seq.h>
@@ -71,17 +75,17 @@
 SYSCTL_INT(_net_inet_tcp, TCPCTL_KEEPIDLE, keepidle,
 	CTLFLAG_RW, &tcp_keepidle , 0, "");
 
-static int	tcp_keepintvl = TCPTV_KEEPINTVL;
+int	tcp_keepintvl = TCPTV_KEEPINTVL;
 SYSCTL_INT(_net_inet_tcp, TCPCTL_KEEPINTVL, keepintvl,
 	CTLFLAG_RW, &tcp_keepintvl , 0, "");
 
-static int	always_keepalive = 0;
+int	always_keepalive = 0;
 SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive,
 	CTLFLAG_RW, &always_keepalive , 0, "");
 
 static int	tcp_keepcnt = TCPTV_KEEPCNT;
 	/* max idle probes */
-static int	tcp_maxpersistidle = TCPTV_KEEP_IDLE;
+int	tcp_maxpersistidle = TCPTV_KEEP_IDLE;
 	/* max idle time in persist */
 int	tcp_maxidle;
 
@@ -98,7 +102,8 @@
 	if (tcp_delack_enabled) {
 		s = splnet();
 		for (inp = tcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
-			if ((tp = (struct tcpcb *)inp->inp_ppcb) &&
+		    if ((inp->inp_flags & INP_COMPATV4) &&
+			(tp = (struct tcpcb *)inp->inp_ppcb) &&
 			    (tp->t_flags & TF_DELACK)) {
 				tp->t_flags &= ~TF_DELACK;
 				tp->t_flags |= TF_ACKNOW;
@@ -141,7 +146,8 @@
 	for (; ip != NULL; ip = ipnxt) {
 		ipnxt = ip->inp_list.le_next;
 		tp = intotcpcb(ip);
-		if (tp == 0 || tp->t_state == TCPS_LISTEN)
+		if (((ip->inp_flags & INP_COMPATV4) == 0) ||
+		    tp == 0 || tp->t_state == TCPS_LISTEN)
 			continue;
 		for (i = 0; i < TCPT_NTIMERS; i++) {
 			if (tp->t_timer[i] && --tp->t_timer[i] == 0) {
@@ -192,7 +198,7 @@
 int	tcp_backoff[TCP_MAXRXTSHIFT + 1] =
     { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
 
-static int tcp_totbackoff = 511;	/* sum of tcp_backoff[] */
+int tcp_totbackoff = 511;		/* sum of tcp_backoff[] */
 
 /*
  * TCP timer processing.
@@ -291,6 +297,9 @@
 		tp->snd_cwnd = tp->t_maxseg;
 		tp->snd_ssthresh = win * tp->t_maxseg;
 		tp->t_dupacks = 0;
+#ifdef ALTQ_ECN
+		tp->snd_rcvr = tp->snd_max;
+#endif
 		}
 		(void) tcp_output(tp);
 		break;
diff -uN src-current/sys/netinet/tcp_usrreq.c src-current-ipv6/sys/netinet/tcp_usrreq.c
--- src-current/sys/netinet/tcp_usrreq.c
+++ src-current-ipv6/sys/netinet/tcp_usrreq.c
@@ -34,6 +34,7 @@
  *	$Id: tcp_usrreq.c,v 1.37 1998/01/27 09:15:11 davidg Exp $
  */
 
+#include "opt_inet6.h"
 #include "opt_tcpdebug.h"
 
 #include <sys/param.h>
@@ -50,9 +51,12 @@
 
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
 #include <netinet/in_pcb.h>
 #include <netinet/in_var.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
 #include <netinet/tcp.h>
 #include <netinet/tcp_fsm.h>
 #include <netinet/tcp_seq.h>
@@ -68,13 +72,15 @@
  */
 extern	char *tcpstates[];	/* XXX ??? */
 
-static int	tcp_attach __P((struct socket *, struct proc *));
+/* static int	tcp_attach __P((struct socket *, struct proc *)); */
 static int	tcp_connect __P((struct tcpcb *, struct sockaddr *, 
 				 struct proc *));
+/*
 static struct tcpcb *
 		tcp_disconnect __P((struct tcpcb *));
 static struct tcpcb *
 		tcp_usrclosed __P((struct tcpcb *));
+*/
 
 #ifdef TCPDEBUG
 #define	TCPDEBUG0	int ostate
@@ -110,6 +116,7 @@
 	if (error)
 		goto out;
 
+	((struct inpcb *) so->so_pcb)->inp_flags = INP_COMPATV4;
 	if ((so->so_options & SO_LINGER) && so->so_linger == 0)
 		so->so_linger = TCP_LINGERTIME * hz;
 	tp = sototcpcb(so);
@@ -185,7 +192,7 @@
 		error = EAFNOSUPPORT;
 		goto out;
 	}
-	error = in_pcbbind(inp, nam, p);
+	error = in_pcbbind(inp, nam, 0, p);
 	if (error)
 		goto out;
 	COMMON_END(PRU_BIND);
@@ -193,6 +200,15 @@
 }
 
 /*
+ * Give the socket an address (dynamic version)
+ */
+static int
+tcp_usr_dynbind(struct socket *so, struct sockaddr *nam, struct proc *p)
+{
+	return EINVAL;
+}
+
+/*
  * Prepare to accept connections.
  */
 static int
@@ -205,7 +221,7 @@
 
 	COMMON_START();
 	if (inp->inp_lport == 0)
-		error = in_pcbbind(inp, (struct sockaddr *)0, p);
+		error = in_pcbbind(inp, (struct sockaddr *)0, 0, p);
 	if (error == 0)
 		tp->t_state = TCPS_LISTEN;
 	COMMON_END(PRU_LISTEN);
@@ -459,7 +475,7 @@
 	tcp_usr_connect, pru_connect2_notsupp, in_control, tcp_usr_detach,
 	tcp_usr_disconnect, tcp_usr_listen, in_setpeeraddr, tcp_usr_rcvd,
 	tcp_usr_rcvoob, tcp_usr_send, pru_sense_null, tcp_usr_shutdown,
-	in_setsockaddr, sosend, soreceive, sopoll
+	in_setsockaddr, sosend, soreceive, sopoll, tcp_usr_dynbind
 };
 
 /*
@@ -488,7 +504,7 @@
 	int error;
 
 	if (inp->inp_lport == 0) {
-		error = in_pcbbind(inp, (struct sockaddr *)0, p);
+		error = in_pcbbind(inp, (struct sockaddr *)0, 0, p);
 		if (error)
 			return error;
 	}
@@ -503,8 +519,7 @@
 		return error;
 	oinp = in_pcblookup_hash(inp->inp_pcbinfo,
 	    sin->sin_addr, sin->sin_port,
-	    inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr
-						: ifaddr->sin_addr,
+	    inp->inp_latype ? inp->inp_laddr : ifaddr->sin_addr,
 	    inp->inp_lport,  0);
 	if (oinp) {
 		if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&
@@ -515,9 +530,24 @@
 		else
 			return EADDRINUSE;
 	}
-	if (inp->inp_laddr.s_addr == INADDR_ANY)
+	if (inp->inp_latype == IPATYPE_UNBD) {
 		inp->inp_laddr = ifaddr->sin_addr;
+		inp->inp_latype = IPATYPE_IPV4;
+#ifdef INET6
+		inp->inp_laddr6.s6_addr32[0] = 0;
+		inp->inp_laddr6.s6_addr32[1] = 0;
+		inp->inp_laddr6.s6_addr32[2] = htonl(0xffff);
+#endif
+	}
 	inp->inp_faddr = sin->sin_addr;
+	if (inp->inp_faddr.s_addr != INADDR_ANY) {
+		inp->inp_fatype = IPATYPE_IPV4;
+#ifdef INET6
+		inp->inp_faddr6.s6_addr32[0] = 0;
+		inp->inp_faddr6.s6_addr32[1] = 0;
+		inp->inp_faddr6.s6_addr32[2] = htonl(0xffff);
+#endif
+	}
 	inp->inp_fport = sin->sin_port;
 	in_pcbrehash(inp);
 
@@ -681,7 +711,7 @@
  * internet protocol control block, tcp control block,
  * bufer space, and entering LISTEN state if to accept connections.
  */
-static int
+int
 tcp_attach(so, p)
 	struct socket *so;
 	struct proc *p;
@@ -720,7 +750,7 @@
  * current input data; switch states based on user close, and
  * send segment to peer (with FIN).
  */
-static struct tcpcb *
+struct tcpcb *
 tcp_disconnect(tp)
 	register struct tcpcb *tp;
 {
@@ -750,7 +780,7 @@
  * for peer to send FIN or not respond to keep-alives, etc.
  * We can let the user exit from the close as soon as the FIN is acked.
  */
-static struct tcpcb *
+struct tcpcb *
 tcp_usrclosed(tp)
 	register struct tcpcb *tp;
 {
diff -uN src-current/sys/netinet/tcp_var.h src-current-ipv6/sys/netinet/tcp_var.h
--- src-current/sys/netinet/tcp_var.h
+++ src-current-ipv6/sys/netinet/tcp_var.h
@@ -45,10 +45,25 @@
  * Organized for 16 byte cacheline efficiency.
  */
 struct tcpcb {
+#ifndef INET6
 	struct	tcpiphdr *seg_next;	/* sequencing queue */
 	struct	tcpiphdr *seg_prev;
+#else
+	union {				/* sequencing queue */
+		struct	tcpiphdr *seg_next_4;
+		struct	tcp6hdrs *seg_next_6;
+	} tcpcb_next;
+#define seg_next	tcpcb_next.seg_next_4
+#define seg_next6	tcpcb_next.seg_next_6
+	union {
+		struct	tcpiphdr *seg_prev_4;
+		struct	tcp6hdrs *seg_prev_6;
+	} tcpcb_prev;
+#define seg_prev	tcpcb_prev.seg_prev_4
+#define seg_prev6	tcpcb_prev.seg_prev_6
+#endif
 	int	t_dupacks;		/* consecutive dup acks recd */
-	struct	tcpiphdr *t_template;	/* skeletal packet for transmit */
+	struct	tcptemp *t_template;	/* skeletal packet for transmit */
 
 	int	t_timer[TCPT_NTIMERS];	/* tcp timers */
 
@@ -71,8 +86,17 @@
 #define TF_REQ_CC	0x2000		/* have/will request CC */
 #define	TF_RCVD_CC	0x4000		/* a CC was received in SYN */
 #define TF_SENDCCNEW	0x8000		/* send CCnew instead of CC in SYN */
+#ifdef ALTQ_ECN
+#define TF_REQ_ECN	0x10000		/* peer is ECN capable */
+#define TF_RCVD_CE	0x20000		/* send ECN in next seg */
+#endif
 	int	t_force;		/* 1 if forcing out a byte */
 
+/*
+ * The following fields are used as in the protocol specification.
+ * See RFC783, Dec. 1981, page 21.
+ */
+/* send sequence variables */
 	tcp_seq	snd_una;		/* send unacknowledged */
 	tcp_seq	snd_max;		/* highest sequence number sent;
 					 * used to recognize retransmits
@@ -83,6 +107,9 @@
 	tcp_seq	snd_wl1;		/* window update seg seq number */
 	tcp_seq	snd_wl2;		/* window update seg ack number */
 	tcp_seq	iss;			/* initial send sequence number */
+#ifdef ALTQ_ECN
+	tcp_seq snd_rcvr;		/* outstanding seg at fastrecovery */
+#endif
 	tcp_seq	irs;			/* initial receive sequence number */
 
 	tcp_seq	rcv_nxt;		/* receive next */
@@ -97,6 +124,7 @@
 					 * linear switch
 					 */
 	u_int	t_maxopd;		/* mss plus options */
+	u_int	t_omaxopd;		/* offered max mss plus options */
 
 	u_int	t_idle;			/* inactivity time */
 	u_long	t_duration;		/* connection duration */
@@ -315,7 +343,8 @@
 #define	TCPCTL_RECVSPACE	9	/* receive buffer space */
 #define	TCPCTL_KEEPINIT		10	/* receive buffer space */
 #define	TCPCTL_PCBLIST		11	/* list of all outstanding PCBs */
-#define TCPCTL_MAXID		12
+#define	TCPCTL_ECN		12	/* explicit congestion notification */
+#define TCPCTL_MAXID		13
 
 #define TCPCTL_NAMES { \
 	{ 0, 0 }, \
@@ -330,6 +359,7 @@
 	{ "recvspace", CTLTYPE_INT }, \
 	{ "keepinit", CTLTYPE_INT }, \
 	{ "pcblist", CTLTYPE_STRUCT }, \
+	{ "ecn", CTLTYPE_INT }, \
 }
 
 #ifdef KERNEL
@@ -340,6 +370,7 @@
 extern	u_long tcp_now;		/* for RFC 1323 timestamps */
 extern	int tcp_delack_enabled;
 
+int	 tcp_attach __P((struct socket *, struct proc *));
 void	 tcp_canceltimers __P((struct tcpcb *));
 struct tcpcb *
 	 tcp_close __P((struct tcpcb *));
@@ -347,6 +378,8 @@
 int	 tcp_ctloutput __P((int, struct socket *, int, int, struct mbuf **,
 			    struct proc *));
 struct tcpcb *
+	 tcp_disconnect __P((struct tcpcb *));
+struct tcpcb *
 	 tcp_drop __P((struct tcpcb *, int));
 void	 tcp_drain __P((void));
 void	 tcp_fasttimo __P((void));
@@ -365,17 +398,22 @@
 	    struct tcpiphdr *, struct mbuf *, u_long, u_long, int));
 struct rtentry *
 	 tcp_rtlookup __P((struct inpcb *));
+void	 tcp_sendkeep __P((struct tcpcb *, tcp_seq, tcp_seq));
 void	 tcp_setpersist __P((struct tcpcb *));
 void	 tcp_slowtimo __P((void));
-struct tcpiphdr *
+struct tcptemp *
 	 tcp_template __P((struct tcpcb *));
 struct tcpcb *
 	 tcp_timers __P((struct tcpcb *, int));
 void	 tcp_trace __P((int, int, struct tcpcb *, struct tcpiphdr *, int));
+struct tcpcb *
+	 tcp_usrclosed __P((struct tcpcb *));
+void	 tcp_xmit_timer __P((struct tcpcb *, int));
 
 extern	struct pr_usrreqs tcp_usrreqs;
 extern	u_long tcp_sendspace;
 extern	u_long tcp_recvspace;
+extern	int tcp_ecn;
 
 #endif /* KERNEL */
 
diff -uN src-current/sys/netinet/tcpip.h src-current-ipv6/sys/netinet/tcpip.h
--- src-current/sys/netinet/tcpip.h
+++ src-current-ipv6/sys/netinet/tcpip.h
@@ -72,4 +72,92 @@
 #define	ti_sum		ti_t.th_sum
 #define	ti_urp		ti_t.th_urp
 
+#ifndef INET6
+/*
+ * Same for templates.
+ */
+struct tcptemp {
+	struct 	ipovly tt_i;		/* overlaid ip structure */
+	struct	tcphdr tt_t;		/* tcp header */
+};
+#define	tt_pr		tt_i.ih_pr
+#define	tt_len		tt_i.ih_len
+#define	tt_src		tt_i.ih_src
+#define	tt_dst		tt_i.ih_dst
+#define	tt_sport	tt_t.th_sport
+#define	tt_dport	tt_t.th_dport
+#define	tt_off		tt_t.th_off
+#else
+/*
+ * IPv6+TCP headers.
+ */
+struct tcpip6hdr {
+	struct 	ipv6 ti6_i;		/* IPv6 header */
+	struct	tcphdr ti6_t;		/* TCP header */
+};
+#define	ti6_head	ti6_i.ip6_head
+#define	ti6_len		ti6_i.ip6_len
+#define	ti6_nh		ti6_i.ip6_nh
+#define	ti6_hlim	ti6_i.ip6_hlim
+#define	ti6_src		ti6_i.ip6_src
+#define	ti6_dst		ti6_i.ip6_dst
+#define	ti6_sport	ti6_t.th_sport
+#define	ti6_dport	ti6_t.th_dport
+#define	ti6_seq		ti6_t.th_seq
+#define	ti6_ack		ti6_t.th_ack
+#define	ti6_x2		ti6_t.th_x2
+#define	ti6_off		ti6_t.th_off
+#define	ti6_flags	ti6_t.th_flags
+#define	ti6_win		ti6_t.th_win
+#define	ti6_sum		ti6_t.th_sum
+#define	ti6_urp		ti6_t.th_urp
+
+/*
+ * Same with queue links.
+ */
+struct tcp6hdrs {
+	struct	tcp6hdrs *tr_next, *tr_prev;	/* queue links */
+	struct	tcpip6hdr tr_ti6;		/* headers */
+};
+#define	tr_i6		tr_ti6.ti6_i
+#define	tr_head		tr_ti6.ti6_head
+#define	tr_len		tr_ti6.ti6_len
+#define	tr_nh		tr_ti6.ti6_nh
+#define	tr_hlim		tr_ti6.ti6_hlim
+#define	tr_src		tr_ti6.ti6_src
+#define	tr_dst		tr_ti6.ti6_dst
+#define	tr_t		tr_ti6.ti6_t
+#define	tr_sport	tr_ti6.ti6_sport
+#define	tr_dport	tr_ti6.ti6_dport
+#define	tr_seq		tr_ti6.ti6_seq
+#define	tr_ack		tr_ti6.ti6_ack
+#define	tr_x2		tr_ti6.ti6_x2
+#define	tr_off		tr_ti6.ti6_off
+#define	tr_flags	tr_ti6.ti6_flags
+#define	tr_win		tr_ti6.ti6_win
+#define	tr_sum		tr_ti6.ti6_sum
+#define	tr_urp		tr_ti6.ti6_urp
+
+/*
+ * Dual template for IPv4/IPv6 TCP.
+ *
+ * Optimized for IPv4
+ */
+struct tcptemp {
+	struct	ipovly tt_i;		/* overlaid ip structure */
+	struct	tcphdr tt_t;		/* tcp header */
+	struct	ip6ovck tt_i6;		/* IPv6 header^2 */
+	struct	in6_addr tt_src6;	/* source address */
+	struct	in6_addr tt_dst6;	/* destination address */
+};
+#define	tt_pr		tt_i.ih_pr
+#define	tt_len		tt_i.ih_len
+#define	tt_src		tt_i.ih_src
+#define	tt_dst		tt_i.ih_dst
+#define	tt_sport	tt_t.th_sport
+#define	tt_dport	tt_t.th_dport
+#define	tt_off		tt_t.th_off
+#define	tt_pr6		tt_i6.ih6_pr
+#define	tt_len6		tt_i6.ih6_len
+#endif
 #endif
diff -uN src-current/sys/netinet/udp6_usrreq.c src-current-ipv6/sys/netinet/udp6_usrreq.c
--- src-current/sys/netinet/udp6_usrreq.c
+++ src-current-ipv6/sys/netinet/udp6_usrreq.c
@@ -0,0 +1,839 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 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.
+ *
+ *	@(#)udp_usrreq.c	8.4 (Berkeley) 1/21/94
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/in6_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip6_icmp.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/udp6_var.h>
+
+/*
+ * UDP protocol implementation.
+ * Per RFC 768, August, 1980.
+ */
+extern int udpcksum;
+extern int udp_log_in_vain;
+
+MALLOC_DECLARE(M_IPMOPTS);
+
+struct	sockaddr_in6 udp_in6 = { sizeof(udp_in6), AF_INET6 };
+
+static	int udp6_detach __P((struct socket *));
+static	int udp6_output __P((struct inpcb *, struct mbuf *, struct sockaddr *,
+			    struct mbuf *, struct proc *));
+static	void udp6_notify __P((struct inpcb *, int));
+static	struct mbuf *udp6_saverecv __P((struct mbuf *, struct mbuf *, int));
+
+extern	struct	udpstat udpstat;		/* from udp_var.h */
+extern	struct	inpcbhead udb;			/* from udp_var.h */
+extern	struct	inpcbinfo udbinfo;
+
+void
+udp6_input(m, arg)
+	struct mbuf *m;
+	int arg;
+{
+	struct mbuf *opts = (struct mbuf *)arg;
+	struct ipv6 *ip;
+	struct udphdr *uh;
+	struct inpcb *inp;
+	int len, ipsec_failed = 0;
+	struct ip6ovck save_ip;
+	struct mbuf *save_opts = 0;
+
+	udpstat.udps_ipackets++;
+
+	/*
+	 * Get IPv6 and UDP header together in first mbuf.
+	 */
+	ip = mtod(m, struct ipv6 *);
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_UDP) {
+		printf("udp6_input(%p,%p)", m, opts);
+		printf(" src %s dst %s len %d mbuf(%d/%d)\n",
+		       ip6_sprintf(&ip->ip6_src),
+		       ip6_sprintf(&ip->ip6_dst),
+		       ip->ip6_len, m->m_pkthdr.len, m->m_len);
+	}
+#endif
+	if (m->m_len < sizeof(struct udpip6hdr)) {
+		if ((m = m_pullup(m, sizeof(struct udpip6hdr))) == 0) {
+			udpstat.udps_hdrops++;
+			goto end;
+		}
+		ip = mtod(m, struct ipv6 *);
+	}
+	uh = (struct udphdr *)(ip + 1);
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_UDP)
+		printf("udp6_input sport %d dpost %d ulen %d\n",
+		       ntohs(uh->uh_sport),
+		       ntohs(uh->uh_dport),
+		       ntohs(uh->uh_ulen));
+#endif
+	/*
+	 * Make mbuf data length reflect UDP length.
+	 * If not enough data to reflect UDP length, drop.
+	 */
+	len = ntohs((u_int16_t)uh->uh_ulen);
+	if (ip->ip6_len != len) {
+		if (len > ip->ip6_len || len < sizeof(struct udphdr)) {
+			udpstat.udps_badlen++;
+			goto bad;
+		}
+		m_adj(m, len - ip->ip6_len);
+		/* ip->ip6_len = len; */
+	}
+
+	/*
+	 * Save a copy of the IP header in case we want restore it
+	 * for sending an ICMPv6 error message in response.
+	 */
+	save_ip = *((struct ip6ovck *)ip);
+
+	/*
+	 * Checksum extended UDP header and data.
+	 */
+	{
+		struct ip6ovck *ipc = (struct ip6ovck *)ip;
+
+		ipc->ih6_wrd1 = ipc->ih6_wrd0 = 0;
+		ipc->ih6_pr = IPPROTO_UDP;
+		ipc->ih6_len = (u_int16_t)uh->uh_ulen;
+		if ((uh->uh_sum = in_cksum(m, len + sizeof (struct ipv6))) != 0) {
+			udpstat.udps_badsum++;
+			goto bad;
+		}
+		*ipc = save_ip;
+	}
+
+	if (IS_MULTIADDR6(ip->ip6_dst)) {
+		struct inpcb *last;
+		/*
+		 * Deliver a multicast or broadcast datagram to *all* sockets
+		 * for which the local and remote addresses and ports match
+		 * those of the incoming datagram.  This allows more than
+		 * one process to receive multi/broadcasts on the same port.
+		 * (This really ought to be done for unicast datagrams as
+		 * well, but that would cause problems with existing
+		 * applications that open both address-specific sockets and
+		 * a wildcard socket listening to the same port -- they would
+		 * end up receiving duplicates of every unicast datagram.
+		 * Those applications open the multiple sockets to overcome an
+		 * inadequacy of the UDP socket interface, but for backwards
+		 * compatibility we avoid the problem here rather than
+		 * fixing the interface.  Maybe 4.5BSD will remedy this?)
+		 */
+
+		/*
+		 * Construct sockaddr format source address.
+		 */
+		udp_in6.sin6_port = uh->uh_sport;
+		udp_in6.sin6_flowinfo = ip->ip6_head & IPV6_FLOWINFO_PRIFLOW;
+		COPY_ADDR6(ip->ip6_src, udp_in6.sin6_addr);
+		m->m_len -= sizeof (struct udpip6hdr);
+		m->m_pkthdr.len -= sizeof(struct udpip6hdr);
+		m->m_data += sizeof (struct udpip6hdr);
+
+#define MULTI6_GETOPT(inp, opt) \
+	if ((inp)->inp_flags & INP_CONTROLOPTS) { \
+		m->m_data -= sizeof (struct udpip6hdr); \
+ 		opt = udp6_saverecv(m, opts, (inp)->inp_flags); \
+		m->m_data += sizeof (struct udpip6hdr); \
+	} else \
+		opt = (struct mbuf *)0;
+
+		/*
+		 * Locate pcb(s) for datagram.
+		 * (Algorithm copied from raw_intr().)
+		 */
+		last = NULL;
+		for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
+			if (inp->inp_lport != uh->uh_dport)
+				continue;
+			if ((inp->inp_flags & INP_COMPATV6) == 0)
+				continue;
+			if ((inp->inp_latype != IPATYPE_UNBD) &&
+			    ((inp->inp_latype & IPATYPE_IPV6) == 0 ||
+			     !SAME_ADDR6(inp->inp_laddr6, ip->ip6_dst)))
+					continue;
+			if ((inp->inp_fatype != IPATYPE_UNBD) &&
+			    ((inp->inp_fatype & IPATYPE_IPV6) == 0 ||
+			     !SAME_ADDR6(inp->inp_faddr6, ip->ip6_src) ||
+			     inp->inp_fport != uh->uh_sport))
+					continue;
+			if ((inp->inp_flags & INP_NEEDAUTH) &&
+			    ((m->m_flags & M_AUTH) == 0 ||
+			     !ipsec_match(inp, m, opts, INP_NEEDAUTH))) {
+				ipsec_failed = 1;
+				continue;
+			}
+			if ((inp->inp_flags & INP_NEEDCRYPT) &&
+			    ((m->m_flags & M_CRYPT) == 0 ||
+			     !ipsec_match(inp, m, opts, INP_NEEDCRYPT))) {
+				ipsec_failed = 1;
+				continue;
+			}
+
+			if (last != NULL) {
+				struct mbuf *n, *o;
+
+				MULTI6_GETOPT(last, o);
+				if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
+					if (sbappendaddr(&last->inp_socket->so_rcv,
+						sin6tosa(&udp_in6),
+						n, o) == 0) {
+						m_freem(n);
+						if (o)
+							m_freem(o);
+						udpstat.udps_fullsock++;
+					} else
+						sorwakeup(last->inp_socket);
+				}
+			}
+			last = inp;
+			/*
+			 * Don't look for additional matches if this one does
+			 * not have either the SO_REUSEPORT or SO_REUSEADDR
+			 * socket options set.  This heuristic avoids searching
+			 * through all pcbs in the common case of a non-shared
+			 * port.  It * assumes that an application will never
+			 * clear these options after setting them.
+			 */
+			if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0)
+				break;
+		}
+
+		if (last == NULL) {
+			/*
+			 * No matching pcb found; discard datagram.
+			 * (No need to send an ICMPv6 Port Unreachable
+			 * for a broadcast or multicast datgram.)
+			 */
+			if (ipsec_failed == 0)
+				udpstat.udps_noportbcast++;
+			goto bad;
+		}
+		MULTI6_GETOPT(last, save_opts);
+		if (sbappendaddr(&last->inp_socket->so_rcv, sin6tosa(&udp_in6),
+		    m, save_opts) == 0) {
+			udpstat.udps_fullsock++;
+			goto bad;
+		}
+		sorwakeup(last->inp_socket);
+		if (opts)
+			m_freem(opts);
+		return;
+	}
+	/*
+	 * Locate pcb for datagram.
+	 */
+	inp = in6_pcblookup_hash(&udbinfo, &ip->ip6_src, uh->uh_sport,
+	    &ip->ip6_dst, uh->uh_dport, 1);
+	if (inp &&
+	    (inp->inp_flags & INP_NEEDAUTH) &&
+	    ((m->m_flags & M_AUTH) == 0 ||
+	     !ipsec_match(inp, m, opts, INP_NEEDAUTH))) {
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_UDP)
+			printf("udp6_input no AH\n");
+#endif
+		inp = NULL;
+	}
+	if (inp &&
+	    (inp->inp_flags & INP_NEEDCRYPT) &&
+	    ((m->m_flags & M_CRYPT) == 0 ||
+	     !ipsec_match(inp, m, opts, INP_NEEDCRYPT))) {
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_UDP)
+			printf("udp6_input no ESP\n");
+#endif
+		inp = NULL;
+	}
+	if (inp == NULL) {
+		if (udp_log_in_vain)
+			log(LOG_INFO,
+			    "Connection attempt to UDP %s:%d from %s:%d\n",
+			    ip6_sprintf(&ip->ip6_dst), ntohs(uh->uh_dport),
+			    ip6_sprintf(&ip->ip6_src), ntohs(uh->uh_sport));
+		udpstat.udps_noport++;
+#ifdef DIAGNOSTIC
+		if (ip6printfs & D6_UDP)
+			printf("udp6_input can't find inpcb\n");
+#endif
+		if (m->m_flags & (M_BCAST | M_MCAST)) {
+			udpstat.udps_noportbcast++;
+			goto bad;
+		}
+		icmp6_error(m, ICMP6_UNREACH, ICMP6_UNREACH_PORT, 0);
+		goto end;
+	}
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_UDP)
+		printf("udp6_input finds inpcb %p\n", inp);
+#endif
+
+	/*
+	 * Construct sockaddr format source address.
+	 * Stuff source address and datagram in user buffer.
+	 */
+	udp_in6.sin6_port = uh->uh_sport;
+	udp_in6.sin6_flowinfo = ip->ip6_head & IPV6_FLOWINFO_PRIFLOW;
+	COPY_ADDR6(ip->ip6_src, udp_in6.sin6_addr);
+	if (inp->inp_flags & INP_CONTROLOPTS) {
+		if (opts)
+			opts = opt6_reverse(ip, opts);
+		save_opts = udp6_saverecv(m, opts, inp->inp_flags);
+	}
+	if (opts)
+		m_freem(opts);
+
+	m->m_len -= sizeof(struct udpip6hdr);
+	m->m_pkthdr.len -= sizeof(struct udpip6hdr);
+	m->m_data += sizeof(struct udpip6hdr);
+	if (sbappendaddr(&inp->inp_socket->so_rcv,
+			 sin6tosa(&udp_in6), m, save_opts) == 0) {
+		udpstat.udps_fullsock++;
+		m_freem(m);
+		goto bad1;
+	}
+	sorwakeup(inp->inp_socket);
+	return;
+bad:
+	m_freem(m);
+end:
+	if (opts)
+		m_freem(opts);
+bad1:
+	if (save_opts)
+		m_free(save_opts);
+}
+
+/*
+ * Create a "control" mbuf containing all the received informations.
+ */
+/* ARGSUSED */
+struct mbuf *
+udp6_saverecv(m0, opts, flags)
+	struct mbuf *m0, *opts;
+	int flags;
+{
+	struct ipv6 *ip;
+	struct cmsghdr *cp;
+	struct mbuf *m;
+	int recval, size = 0;
+
+	if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
+		return ((struct mbuf *) NULL);
+	if (flags & (INP_RECVOPTS | INP_RECVRETOPTS)) {
+		log(LOG_INFO, "udp6_saverecv: IP_RECVOPTS failed\n");
+		flags &= ~(IP_RECVOPTS | IP_RECVRETOPTS);
+		if ((flags & INP_CONTROLOPTS) == 0) {
+			m_free(m);
+			return ((struct mbuf *) NULL);
+		}
+	}
+	if (flags & INP_RECVDSTADDR) {
+		ip = mtod(m0, struct ipv6 *);
+		size = ALIGN(size);
+		cp = (struct cmsghdr *)(mtod(m, caddr_t) + size);
+		cp->cmsg_len = sizeof(*cp) + sizeof(struct in6_addr);
+		size += cp->cmsg_len;
+		cp->cmsg_level = IPPROTO_IP;
+		cp->cmsg_type = IP_RECVDSTADDR;
+		bcopy(&ip->ip6_dst, CMSG_DATA(cp), sizeof(struct in6_addr));
+	} else if (flags & INP_RECVIF) {
+		recval = m0->m_pkthdr.rcvif->if_index;
+		size = ALIGN(size);
+		cp = (struct cmsghdr *)(mtod(m, caddr_t) + size);
+		cp->cmsg_len = sizeof(*cp) + sizeof(int);
+		size += cp->cmsg_len;
+		cp->cmsg_level = IPPROTO_IP;
+		cp->cmsg_type = IP_RECVIF;
+		bcopy(&recval, CMSG_DATA(cp), sizeof(int));
+	} else if (flags & INP_RECVPKTINFO) {
+		ip = mtod(m0, struct ipv6 *);
+		recval = m0->m_pkthdr.rcvif->if_index;
+		size = ALIGN(size);
+		cp = (struct cmsghdr *)(mtod(m, caddr_t) + size);
+		cp->cmsg_len = sizeof(*cp) + sizeof(struct in6_pktinfo);
+		size += cp->cmsg_len;
+		cp->cmsg_level = IPPROTO_IPV6;
+		cp->cmsg_type = IPV6_PKTINFO;
+		bcopy(&ip->ip6_dst, CMSG_DATA(cp), sizeof(struct in6_addr));
+		bcopy(&recval,
+		      CMSG_DATA(cp) + sizeof(struct in6_addr),
+		      sizeof(int));
+	}
+	if (flags & INP_RECVTTL) {
+		ip = mtod(m0, struct ipv6 *);
+		recval = ip->ip6_hlim;
+		size = ALIGN(size);
+		cp = (struct cmsghdr *)(mtod(m, caddr_t) + size);
+		cp->cmsg_len = sizeof(*cp) + sizeof(int);
+		size += cp->cmsg_len;
+		cp->cmsg_level = IPPROTO_IP;
+		cp->cmsg_type = IP_TTL;
+		bcopy(&recval, CMSG_DATA(cp), sizeof(int));
+	}
+	m->m_len = size;
+	return (m);
+}
+
+/*
+ * Notify a udp user of an asynchronous error;
+ * just wake up so that he can collect error status.
+ */
+static void
+udp6_notify(inp, errno)
+	struct inpcb *inp;
+	int errno;
+{
+	inp->inp_socket->so_error = errno;
+	sorwakeup(inp->inp_socket);
+	sowwakeup(inp->inp_socket);
+}
+
+/* ARGSUSED */
+void
+udp6_ctlinput(cmd, sa, arg)
+	int cmd;
+	struct sockaddr *sa;
+	void *arg;
+{
+	struct ctli_arg *ca = (struct ctli_arg *)arg;
+	struct ipv6 *ip = ca ? ca->ctli_ip : 0;
+	struct udphdr *uh;
+
+	if (!PRC_IS_REDIRECT(cmd) &&
+	    ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0))
+		return;
+	if (ip) {
+		uh = (struct udphdr *)(ip + 1);
+		in6_pcbnotify(&udb, sa, uh->uh_dport,
+			      &ip->ip6_src, uh->uh_sport,
+			      cmd, udp6_notify);
+	} else
+		in6_pcbnotify(&udb, sa, 0, NULL, 0, cmd, udp6_notify);
+}
+
+static int
+udp6_output(inp, m, addr, control, p)
+	struct inpcb *inp;
+	struct mbuf *m;
+	struct sockaddr *addr;
+	struct mbuf *control;
+	struct proc *p;
+{
+	struct udpiphdr *ui;
+	struct udpip6hdr *ui6;
+	struct ip6ovck *ipc;
+	int len = m->m_pkthdr.len;
+	struct in6_addr laddr;
+#if (MULTI_HOMED > 0)
+	struct ifaddr *ifa = 0;
+#endif
+	struct ip_moptions *imo = 0;
+	int latype = 0, flowinfo = 0, hlim = 0, compat = 0, s = 0, error = 0;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_UDP)
+		printf("udp6_output(%p,%p,%p,%p)\n", inp, m, addr, control);
+#endif
+
+	if (control || addr) {
+		/*
+		 * Must block input while temporarily connected.
+		 */
+		s = splnet();
+		COPY_ADDR6(inp->inp_laddr6, laddr);
+		latype = inp->inp_latype;
+		compat = inp->inp_flags & INP_COMPATANY;
+		flowinfo = inp->inp_oflowinfo;
+	}
+	if (control) {
+		hlim = inp->inp_ttl;
+		imo = inp->inp_moptions;
+#if (MULTI_HOMED > 0)
+		ifa = inp->inp_ifa;
+		if (ifa)
+			ifa->ifa_refcnt++;
+#endif
+		error = ip6_setcontrol(inp, control, p);
+		if (error)
+			goto release;
+	}
+	if (addr) {
+		if (inp->inp_fatype != IPATYPE_UNBD) {
+			error = EISCONN;
+			goto release;
+		}
+		error = in6_pcbconnect(inp, addr, p);
+		if (error)
+			goto release;
+	} else {
+		if (inp->inp_fatype == IPATYPE_UNBD) {
+			error = ENOTCONN;
+			goto release;
+		}
+	}
+
+	/* IPv4 centric! */
+	if (inp->inp_flags & INP_COMPATV4)
+		goto version4;
+
+#ifdef DIAGNOSTIC
+	if (ip6printfs & D6_UDP)
+		printf("udp6_output to %s\n", ip6_sprintf(&inp->inp_faddr6));
+#endif
+	/*
+	 * Calculate data length and get a mbuf
+	 * for UDP and IPv6 headers.
+	 */
+	if (len + sizeof(struct udphdr) > IP_MAXPACKET) {
+		error = EMSGSIZE;
+		m_freem(m);
+		goto sent;
+	}
+
+	M_PREPEND(m, sizeof(struct udpip6hdr), M_DONTWAIT);
+	if (m == 0) {
+		error = ENOBUFS;
+		/* must disconnect ! */
+		goto sent;
+	}
+
+	/*
+	 * Fill in mbuf with extended UDP header
+	 * and addresses and length put into network format.
+	 */
+	ui6 = mtod(m, struct udpip6hdr *);
+	ipc = (struct ip6ovck *)ui6;
+	ipc->ih6_wrd1 = ipc->ih6_wrd0 = 0;
+	ipc->ih6_pr = IPPROTO_UDP;
+	ipc->ih6_len = htons((u_int16_t)len + sizeof (struct udphdr));
+	COPY_ADDR6(inp->inp_laddr6, ui6->ui6_src);
+	COPY_ADDR6(inp->inp_faddr6, ui6->ui6_dst);
+	ui6->ui6_sport = inp->inp_lport;
+	ui6->ui6_dport = inp->inp_fport;
+	ui6->ui6_ulen = ipc->ih6_len;
+
+	/*
+	 * Stuff checksum and output datagram.
+	 */
+	ui6->ui6_sum = 0;
+	if ((ui6->ui6_sum = in_cksum(m, sizeof (struct udpip6hdr) + len)) == 0)
+		ui6->ui6_sum = 0xffff;
+	ui6->ui6_head = inp->inp_oflowinfo | IPV6_VERSION;
+	ui6->ui6_len = sizeof (struct udphdr) + len;
+	ui6->ui6_ulen = htons(ui6->ui6_len);
+	ui6->ui6_nh = IPPROTO_UDP;
+	ui6->ui6_hlim = inp->inp_ttl;
+	udpstat.udps_opackets++;
+	error = ip6_output(m, inp->inp_options, &inp->inp_route,
+	    inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
+	    inp->inp_moptions, inp);
+	goto sent;
+
+version4:
+
+	/*
+	 * Calculate data length and get a mbuf
+	 * for UDP and IPv4 headers.
+	 */
+	if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
+		error = EMSGSIZE;
+		m_freem(m);
+		goto sent;
+	}
+
+	M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
+	if (m == 0) {
+		error = ENOBUFS;
+		/* must disconnect ! */
+		goto sent;
+	}
+
+	/*
+	 * Fill in mbuf with extended UDP header
+	 * and addresses and length put into network format.
+	 */
+	ui = mtod(m, struct udpiphdr *);
+	ui->ui_next = ui->ui_prev = 0;
+	ui->ui_x1 = 0;
+	ui->ui_pr = IPPROTO_UDP;
+	ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr));
+	ui->ui_src = inp->inp_laddr;
+	ui->ui_dst = inp->inp_faddr;
+	ui->ui_sport = inp->inp_lport;
+	ui->ui_dport = inp->inp_fport;
+	ui->ui_ulen = ui->ui_len;
+
+	/*
+	 * Stuff checksum and output datagram.
+	 */
+	ui->ui_sum = 0;
+	if (udpcksum) {
+	    if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
+		ui->ui_sum = 0xffff;
+	}
+	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
+	((struct ip *)ui)->ip_ttl = inp->inp_ttl;	/* XXX */
+	((struct ip *)ui)->ip_tos = inp->inp_tos;	/* XXX */
+	udpstat.udps_opackets++;
+	error = ip_output(m, inp->inp_options, &inp->inp_route,
+	    inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
+	    inp->inp_moptions);
+
+sent:
+	m = (struct mbuf *)0;
+	if (addr)
+		in_pcbdisconnect(inp);
+release:
+	if (control || addr) {
+		COPY_ADDR6(laddr, inp->inp_laddr6);
+		inp->inp_latype = latype;
+		inp->inp_flags |= compat;
+		inp->inp_oflowinfo = flowinfo;
+	}
+	if (control) {
+		inp->inp_ttl = hlim;
+#if (MULTI_HOMED > 0)
+		if (inp->inp_ifa)
+			IFAFREE(inp->inp_ifa);
+		inp->inp_ifa = ifa;
+#endif
+		if (inp->inp_moptions != imo)
+			free(inp->inp_moptions, M_IPMOPTS);
+		inp->inp_moptions = imo;
+	}
+	if (control || addr)
+		splx(s);
+	if (control)
+		m_freem(control);
+	if (m)
+		m_freem(m);
+	return (error);
+}
+
+extern u_long udp_sendspace;
+extern u_long udp_recvspace;
+
+static int
+udp6_abort(struct socket *so)
+{
+	struct inpcb *inp;
+	int s;
+
+	inp = sotoinpcb(so);
+	if (inp == 0)
+		return EINVAL;	/* ??? possible? panic instead? */
+	soisdisconnected(so);
+	s = splnet();
+	in_pcbdetach(inp);
+	splx(s);
+	return 0;
+}
+
+static int
+udp6_attach(struct socket *so, int proto, struct proc *p)
+{
+	struct inpcb *inp;
+	int s, error;
+
+	inp = sotoinpcb(so);
+	if (inp != 0)
+		return EINVAL;
+
+	s = splnet();
+	error = in_pcballoc(so, &udbinfo, p);
+	splx(s);
+	if (error)
+		return error;
+	error = soreserve(so, udp_sendspace, udp_recvspace);
+	if (error)
+		return error;
+	((struct inpcb *) so->so_pcb)->inp_flags = INP_COMPATANY;
+	((struct inpcb *) so->so_pcb)->inp_ttl = ip_defttl;
+	return 0;
+}
+
+static int
+udp6_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
+{
+	struct inpcb *inp;
+	int s, error;
+	inp = sotoinpcb(so);
+	if (inp == 0)
+		return EINVAL;
+	s = splnet();
+	error = in6_pcbbind(inp, nam, 0, p);
+	splx(s);
+	return error;
+}
+
+static int
+udp6_dynbind(struct socket *so, struct sockaddr *nam, struct proc *p)
+{
+	struct inpcb *inp;
+	int s, error;
+	inp = sotoinpcb(so);
+	if (inp == 0)
+		return EINVAL;
+	s = splnet();
+	error = in6_pcbbind(inp, nam, 1, p);
+	splx(s);
+	return error;
+}
+
+static int
+udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
+{
+	struct inpcb *inp;
+	int s, error;
+
+	inp = sotoinpcb(so);
+	if (inp == 0)
+		return EINVAL;
+	if (inp->inp_fatype != IPATYPE_UNBD)
+		return EISCONN;
+	s = splnet();
+	error = in6_pcbconnect(inp, nam, p);
+	splx(s);
+	if (error == 0)
+		soisconnected(so);
+	return error;
+}
+
+static int
+udp6_detach(struct socket *so)
+{
+	struct inpcb *inp;
+	int s;
+
+	inp = sotoinpcb(so);
+	if (inp == 0)
+		return EINVAL;
+	s = splnet();
+	in_pcbdetach(inp);
+	splx(s);
+	return 0;
+}
+
+static int
+udp6_disconnect(struct socket *so)
+{
+	struct inpcb *inp;
+	int s;
+
+	inp = sotoinpcb(so);
+	if (inp == 0)
+		return EINVAL;
+	if (inp->inp_fatype == IPATYPE_UNBD)
+		return ENOTCONN;
+
+	s = splnet();
+	in_pcbdisconnect(inp);
+	CLR_ADDR6(inp->inp_laddr6);
+	inp->inp_latype = IPATYPE_UNBD;
+	inp->inp_flags |= INP_COMPATANY;
+	inp->inp_iflowinfo = 0;
+	splx(s);
+	so->so_state &= ~SS_ISCONNECTED;		/* XXX */
+	return 0;
+}
+
+static int
+udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
+	    struct mbuf *control, struct proc *p)
+{
+	struct inpcb *inp;
+
+	inp = sotoinpcb(so);
+	if (inp == 0) {
+		m_freem(m);
+		return EINVAL;
+	}
+	return udp6_output(inp, m, addr, control, p);
+}
+
+static int
+udp6_shutdown(struct socket *so)
+{
+	struct inpcb *inp;
+
+	inp = sotoinpcb(so);
+	if (inp == 0)
+		return EINVAL;
+	socantsendmore(so);
+	return 0;
+}
+
+struct pr_usrreqs udp6_usrreqs = {
+	udp6_abort, pru_accept_notsupp, udp6_attach, udp6_bind, udp6_connect, 
+	pru_connect2_notsupp, in6_control, udp6_detach, udp6_disconnect, 
+	pru_listen_notsupp, in6_setpeeraddr, pru_rcvd_notsupp, 
+	pru_rcvoob_notsupp, udp6_send, pru_sense_null, udp6_shutdown,
+	in6_setsockaddr, sosend, soreceive, sopoll, 
+
+udp6_dynbind
+};
diff -uN src-current/sys/netinet/udp6_var.h src-current-ipv6/sys/netinet/udp6_var.h
--- src-current/sys/netinet/udp6_var.h
+++ src-current-ipv6/sys/netinet/udp6_var.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1982, 1986, 1989, 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.
+ *
+ *	@(#)udp_var.h	8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _NETINET_UDP6_VAR_H_
+#define _NETINET_UDP6_VAR_H_
+
+#include "opt_inet6.h"
+
+/*
+ * UDP kernel structures and variables.
+ */
+struct	udpip6hdr {
+	struct ipv6	ui6_i;		/* real ipv6 structure */
+	struct udphdr	ui6_u;		/* udp header */
+};
+#define ui6_head	ui6_i.ip6_head
+#define ui6_len		ui6_i.ip6_len
+#define ui6_nh		ui6_i.ip6_nh
+#define ui6_hlim	ui6_i.ip6_hlim
+#define ui6_src		ui6_i.ip6_src
+#define ui6_dst		ui6_i.ip6_dst
+#define ui6_sport	ui6_u.uh_sport
+#define ui6_dport	ui6_u.uh_dport
+#define ui6_ulen	ui6_u.uh_ulen
+#define ui6_sum		ui6_u.uh_sum
+
+#if defined(KERNEL) && defined(INET6)
+extern struct	pr_usrreqs udp6_usrreqs;
+
+void	 udp6_ctlinput __P((int, struct sockaddr *, void *));
+void	 udp6_input __P((struct mbuf *, int));
+#endif
+
+#endif
diff -uN src-current/sys/netinet/udp_usrreq.c src-current-ipv6/sys/netinet/udp_usrreq.c
--- src-current/sys/netinet/udp_usrreq.c
+++ src-current-ipv6/sys/netinet/udp_usrreq.c
@@ -34,6 +34,8 @@
  *	$Id: udp_usrreq.c,v 1.47 1998/05/15 20:11:35 wollman Exp $
  */
 
+#include "opt_inet6.h"
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
@@ -53,6 +55,10 @@
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif
+#include <netinet/ipsec.h>
 #include <netinet/in_pcb.h>
 #include <netinet/in_var.h>
 #include <netinet/ip_var.h>
@@ -65,33 +71,42 @@
  * Per RFC 768, August, 1980.
  */
 #ifndef	COMPAT_42
-static int	udpcksum = 1;
+int	udpcksum = 1;
 #else
-static int	udpcksum = 0;		/* XXX */
+int	udpcksum = 0;			/* XXX */
 #endif
 SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW,
 		&udpcksum, 0, "");
 
-static int log_in_vain = 0;
+int udp_log_in_vain = 0;
 SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW, 
-	&log_in_vain, 0, "");
+	&udp_log_in_vain, 0, "");
 
-static struct	inpcbhead udb;		/* from udp_var.h */
-static struct	inpcbinfo udbinfo;
+struct	inpcbhead udb;			/* from udp_var.h */
+struct	inpcbinfo udbinfo;
 
 #ifndef UDBHASHSIZE
 #define UDBHASHSIZE 16
 #endif
 
-static struct	udpstat udpstat;	/* from udp_var.h */
+struct	udpstat udpstat;		/* from udp_var.h */
 SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD,
 	&udpstat, udpstat, "");
 
 static struct	sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
+extern	struct sockaddr_in6 udp_in6;
+#ifdef	INET6
+#define	UDP_INP(inp)	\
+	(((inp)->inp_flags & INP_COMPATV6) ? \
+		sin6tosa(&udp_in6) : sintosa(&udp_in))
+#else
+#define	UDP_INP(inp)	(sintosa(&udp_in))
+#endif
 
 static	int udp_output __P((struct inpcb *, struct mbuf *, struct sockaddr *,
 			    struct mbuf *, struct proc *));
 static	void udp_notify __P((struct inpcb *, int));
+static	struct mbuf *udp_saveopt __P((caddr_t, struct mbuf *, int, int));
 
 void
 udp_init()
@@ -202,8 +217,28 @@
 		 */
 		udp_in.sin_port = uh->uh_sport;
 		udp_in.sin_addr = ip->ip_src;
+#ifdef INET6
+		udp_in6.sin6_port = uh->uh_sport;
+		udp_in6.sin6_flowinfo = 0;
+		udp_in6.sin6_addr.s6_addr32[0] = 0;
+		udp_in6.sin6_addr.s6_addr32[1] = 0;
+		udp_in6.sin6_addr.s6_addr32[2] = htonl(0xffff);
+		udp_in6.sin6_addr.s6_addr32[3] = ip->ip_src.s_addr;
+#endif
 		m->m_len -= sizeof (struct udpiphdr);
+		m->m_pkthdr.len -= sizeof (struct udpiphdr);
 		m->m_data += sizeof (struct udpiphdr);
+
+#define MULTI_GETOPT(inp, opt) \
+	if ((inp)->inp_flags & INP_RECVIF) { \
+		int index = m->m_pkthdr.rcvif->if_index; \
+ 		opt = udp_saveopt((caddr_t) &index, \
+				  (struct mbuf *)0, \
+				  sizeof(int), \
+				  IP_RECVIF); \
+	} else \
+		opt = (struct mbuf *)0;
+
 		/*
 		 * Locate pcb(s) for datagram.
 		 * (Algorithm copied from raw_intr().)
@@ -212,35 +247,40 @@
 		for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
 			if (inp->inp_lport != uh->uh_dport)
 				continue;
-			if (inp->inp_laddr.s_addr != INADDR_ANY) {
-				if (inp->inp_laddr.s_addr !=
-				    ip->ip_dst.s_addr)
+			if ((inp->inp_flags & INP_COMPATV4) == 0)
+				continue;
+			if ((inp->inp_latype != IPATYPE_UNBD) &&
+			    ((inp->inp_latype & IPATYPE_IPV4) == 0 ||
+			     inp->inp_laddr.s_addr != ip->ip_dst.s_addr))
 					continue;
-			}
-			if (inp->inp_faddr.s_addr != INADDR_ANY) {
-				if (inp->inp_faddr.s_addr !=
-				    ip->ip_src.s_addr ||
-				    inp->inp_fport != uh->uh_sport)
+			if ((inp->inp_fatype != IPATYPE_UNBD) &&
+			    ((inp->inp_fatype & IPATYPE_IPV4) == 0 ||
+			     inp->inp_faddr.s_addr != ip->ip_src.s_addr ||
+			     inp->inp_fport != uh->uh_sport))
 					continue;
-			}
 
 			if (last != NULL) {
-				struct mbuf *n;
+				struct mbuf *n, *o;
 
+				MULTI_GETOPT(last, o);
 				if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
+#ifdef notyet
 					if (last->inp_flags & INP_CONTROLOPTS
 					    || last->inp_socket->so_options & SO_TIMESTAMP)
 						ip_savecontrol(last, &opts, ip, n);
+#endif
 					if (sbappendaddr(&last->inp_socket->so_rcv,
-						(struct sockaddr *)&udp_in,
-						n, opts) == 0) {
+						UDP_INP(last),
+						n, o) == 0) {
 						m_freem(n);
-						if (opts)
-						    m_freem(opts);
+						if (o)
+						    m_freem(o);
 						udpstat.udps_fullsock++;
 					} else
 						sorwakeup(last->inp_socket);
+#ifdef notyet
 					opts = 0;
+#endif
 				}
 			}
 			last = inp;
@@ -265,12 +305,12 @@
 			udpstat.udps_noportbcast++;
 			goto bad;
 		}
+		MULTI_GETOPT(last, opts);
 		if (last->inp_flags & INP_CONTROLOPTS
 		    || last->inp_socket->so_options & SO_TIMESTAMP)
 			ip_savecontrol(last, &opts, ip, m);
 		if (sbappendaddr(&last->inp_socket->so_rcv,
-		     (struct sockaddr *)&udp_in,
-		     m, opts) == 0) {
+		     UDP_INP(last), m, opts) == 0) {
 			udpstat.udps_fullsock++;
 			goto bad;
 		}
@@ -283,7 +323,7 @@
 	inp = in_pcblookup_hash(&udbinfo, ip->ip_src, uh->uh_sport,
 	    ip->ip_dst, uh->uh_dport, 1);
 	if (inp == NULL) {
-		if (log_in_vain) {
+		if (udp_log_in_vain) {
 			char buf[4*sizeof "123"];
 
 			strcpy(buf, inet_ntoa(ip->ip_dst));
@@ -298,6 +338,7 @@
 			goto bad;
 		}
 		*ip = save_ip;
+		ip->ip_len += iphlen;
 		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
 		return;
 	}
@@ -306,16 +347,57 @@
 	 * Construct sockaddr format source address.
 	 * Stuff source address and datagram in user buffer.
 	 */
+#ifdef INET6
+	if (inp->inp_flags & INP_COMPATV6) {
+		udp_in6.sin6_port = uh->uh_sport;
+		udp_in6.sin6_flowinfo = 0;
+		udp_in6.sin6_addr.s6_addr32[0] = 0;
+		udp_in6.sin6_addr.s6_addr32[1] = 0;
+		udp_in6.sin6_addr.s6_addr32[2] = htonl(0xffff);
+		udp_in6.sin6_addr.s6_addr32[3] = ip->ip_src.s_addr;
+	} else {
+		udp_in.sin_port = uh->uh_sport;
+		udp_in.sin_addr = ip->ip_src;
+	}
+#else
 	udp_in.sin_port = uh->uh_sport;
 	udp_in.sin_addr = ip->ip_src;
+#endif
+	if (inp->inp_flags & INP_CONTROLOPTS) {
+		if (inp->inp_flags & INP_RECVDSTADDR) {
+			opts = udp_saveopt((caddr_t) &ip->ip_dst, opts,
+				sizeof(struct in_addr), IP_RECVDSTADDR);
+		}
+		if (inp->inp_flags & INP_RECVIF) {
+			register struct ifnet *ifp = m->m_pkthdr.rcvif;
+			int index = ifp->if_index;
+
+			opts = udp_saveopt((caddr_t) &index, opts,
+				sizeof(int), IP_RECVIF);
+		}
+#ifdef notyet
+		/* options were tossed above */
+		if (inp->inp_flags & INP_RECVOPTS) {
+			opts = udp_saveopt((caddr_t) opts_deleted_above, opts,
+				sizeof(struct in_addr), IP_RECVOPTS);
+		}
+		/* ip_srcroute doesn't do what we want here, need to fix */
+		if (inp->inp_flags & INP_RECVRETOPTS) {
+			opts = udp_saveopt((caddr_t) ip_srcroute(), opts,
+				sizeof(struct in_addr), IP_RECVRETOPTS);
+		}
+#endif
+	}
+#ifdef notyet
 	if (inp->inp_flags & INP_CONTROLOPTS
 	    || inp->inp_socket->so_options & SO_TIMESTAMP)
 		ip_savecontrol(inp, &opts, ip, m);
+#endif
 	iphlen += sizeof(struct udphdr);
 	m->m_len -= iphlen;
 	m->m_pkthdr.len -= iphlen;
 	m->m_data += iphlen;
-	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
+	if (sbappendaddr(&inp->inp_socket->so_rcv, UDP_INP(inp),
 	    m, opts) == 0) {
 		udpstat.udps_fullsock++;
 		goto bad;
@@ -329,6 +411,43 @@
 }
 
 /*
+ * Create a "control" mbuf containing the specified data
+ * with the specified type for presentation with a datagram.
+ */
+struct mbuf *
+udp_saveopt(p, m, size, type)
+	caddr_t p;
+	struct mbuf *m;
+	register int size;
+	int type;
+{
+	register struct cmsghdr *cp;
+	int len;
+
+	if (m) {
+		len = ALIGN(m->m_len);
+		if (len + size + sizeof(*cp) > MLEN) {
+			log(LOG_INFO, "udp_saveopt: too much control\n");
+			return (m);
+		}
+		m->m_len = len;
+		cp = (struct cmsghdr *)(mtod(m, caddr_t) + len);
+	} else {
+		if ((m = m_getclr(M_DONTWAIT, MT_CONTROL)) == NULL)
+			return ((struct mbuf *) NULL);
+		m->m_len = 0;
+		cp = mtod(m, struct cmsghdr *);
+	}
+	(void)memcpy(CMSG_DATA(cp), p, size);
+	size += sizeof(*cp);
+	m->m_len += size;
+	cp->cmsg_len = size;
+	cp->cmsg_level = IPPROTO_IP;
+	cp->cmsg_type = type;
+	return (m);
+}
+
+/*
  * Notify a udp user of an asynchronous error;
  * just wake up so that he can collect error status.
  */
@@ -459,7 +578,7 @@
 	register struct udpiphdr *ui;
 	register int len = m->m_pkthdr.len;
 	struct in_addr laddr;
-	int s = 0, error = 0;
+	int latype = 0, s = 0, error = 0;
 
 	if (control)
 		m_freem(control);		/* XXX */
@@ -471,7 +590,8 @@
 
 	if (addr) {
 		laddr = inp->inp_laddr;
-		if (inp->inp_faddr.s_addr != INADDR_ANY) {
+		latype = inp->inp_latype;
+		if (inp->inp_fatype != IPATYPE_UNBD) {
 			error = EISCONN;
 			goto release;
 		}
@@ -485,7 +605,7 @@
 			goto release;
 		}
 	} else {
-		if (inp->inp_faddr.s_addr == INADDR_ANY) {
+		if (inp->inp_fatype == IPATYPE_UNBD) {
 			error = ENOTCONN;
 			goto release;
 		}
@@ -526,8 +646,8 @@
 		ui->ui_sum = 0xffff;
 	}
 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
-	((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl;	/* XXX */
-	((struct ip *)ui)->ip_tos = inp->inp_ip_tos;	/* XXX */
+	((struct ip *)ui)->ip_ttl = inp->inp_ttl;	/* XXX */
+	((struct ip *)ui)->ip_tos = inp->inp_tos;	/* XXX */
 	udpstat.udps_opackets++;
 	error = ip_output(m, inp->inp_options, &inp->inp_route,
 	    inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
@@ -536,6 +656,7 @@
 	if (addr) {
 		in_pcbdisconnect(inp);
 		inp->inp_laddr = laddr;	/* XXX rehash? */
+		inp->inp_latype = latype;
 		splx(s);
 	}
 	return (error);
@@ -545,12 +666,12 @@
 	return (error);
 }
 
-static u_long	udp_sendspace = 9216;		/* really max datagram size */
+u_long	udp_sendspace = 9216;		/* really max datagram size */
 					/* 40 1K datagrams */
 SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW,
 	&udp_sendspace, 0, "");
 
-static u_long	udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
+u_long	udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
 SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
 	&udp_recvspace, 0, "");
 
@@ -588,7 +709,8 @@
 	error = soreserve(so, udp_sendspace, udp_recvspace);
 	if (error)
 		return error;
-	((struct inpcb *) so->so_pcb)->inp_ip_ttl = ip_defttl;
+	((struct inpcb *) so->so_pcb)->inp_flags = INP_COMPATV4;
+	((struct inpcb *) so->so_pcb)->inp_ttl = ip_defttl;
 	return 0;
 }
 
@@ -597,17 +719,22 @@
 {
 	struct inpcb *inp;
 	int s, error;
-
 	inp = sotoinpcb(so);
 	if (inp == 0)
 		return EINVAL;
 	s = splnet();
-	error = in_pcbbind(inp, nam, p);
+	error = in_pcbbind(inp, nam, 0, p);
 	splx(s);
 	return error;
 }
 
 static int
+udp_dynbind(struct socket *so, struct sockaddr *nam, struct proc *p)
+{
+	return EINVAL;
+}
+
+static int
 udp_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
 {
 	struct inpcb *inp;
@@ -616,7 +743,7 @@
 	inp = sotoinpcb(so);
 	if (inp == 0)
 		return EINVAL;
-	if (inp->inp_faddr.s_addr != INADDR_ANY)
+	if (inp->inp_fatype != IPATYPE_UNBD)
 		return EISCONN;
 	s = splnet();
 	error = in_pcbconnect(inp, nam, p);
@@ -650,12 +777,13 @@
 	inp = sotoinpcb(so);
 	if (inp == 0)
 		return EINVAL;
-	if (inp->inp_faddr.s_addr == INADDR_ANY)
+	if (inp->inp_fatype == IPATYPE_UNBD)
 		return ENOTCONN;
 
 	s = splnet();
 	in_pcbdisconnect(inp);
-	inp->inp_laddr.s_addr = INADDR_ANY;
+	CLR_ADDR6(inp->inp_laddr6);
+	inp->inp_latype = IPATYPE_UNBD;
 	splx(s);
 	so->so_state &= ~SS_ISCONNECTED;		/* XXX */
 	return 0;
@@ -692,5 +820,5 @@
 	pru_connect2_notsupp, in_control, udp_detach, udp_disconnect, 
 	pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, 
 	pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown,
-	in_setsockaddr, sosend, soreceive, sopoll
+	in_setsockaddr, sosend, soreceive, sopoll, udp_dynbind
 };
diff -uN src-current/sys/netinet/wfq.c src-current-ipv6/sys/netinet/wfq.c
--- src-current/sys/netinet/wfq.c
+++ src-current-ipv6/sys/netinet/wfq.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright (C) 1997
+ *	Sony Computer Science Laboratory Inc.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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.
+ *
+ * $Id: wfq.c,v 0.5 1998/01/26 11:05:48 kjc Exp $
+ */
+/*
+ *  March 27, 1997.  Written by Hiroshi Kyusojin of Keio University
+ *  (kyu@mt.cs.keio.ac.jp). 
+ */
+/*
+static char rcsid[] = "$Id: wfq.c,v 0.5 1998/01/26 11:05:48 kjc Exp $";
+*/
+
+#include "opt_inet6.h"
+
+#if defined(__FreeBSD__) && defined(ALTQ)
+#include "opt_altq.h"
+#endif
+
+#ifdef WFQ
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <netinet/wfq.h>
+/*
+#define WFQ_DEBUG
+*/
+
+static int		wfq_setenable(struct wfq_interface *, int);
+static int		wfq_ifattach(struct wfq_interface *);
+static int		wfq_ifdetach(struct wfq_interface *);
+static int		wfq_ifenqueue(struct ifnet *, struct mbuf *, struct pr_hdr *, int);
+u_long			wfq_hash(struct flowinfo *, int);
+u_long			wfq_hashbydstaddr(struct flowinfo *, int);
+u_long			wfq_hashbysrcport(struct flowinfo *, int);
+static wfq		*wfq_maxqueue(wfq_state_t *);
+static struct mbuf	*wfq_ifdequeue(struct ifnet *, int);
+static int		wfq_getqid(struct wfq_getqid *);
+static int		wfq_setweight(struct wfq_setweight *);
+static int		wfq_getstats(struct wfq_getstats *);
+static int		wfq_changehashfnc(struct wfq_changehashfnc *);
+static int		wfq_flush(struct ifnet *);
+
+/* global value : pointer to wfq queue list */
+static wfq_state_t *wfq_list = NULL;
+
+
+static int
+wfq_setenable(ifacep, flag)
+    struct wfq_interface *ifacep;
+    int flag;
+{
+    int error = 0;
+    wfq_state_t *wfqp;
+    char *ifacename;
+
+    ifacename = ifacep->wfq_ifacename;
+    if ((wfqp = altq_lookup(ifacename, ALTQT_WFQ)) == NULL)
+	return (ENXIO);
+
+    switch(flag){
+    case ENABLE:
+	error = if_altqenable(wfqp->ifp);
+	break;
+    case DISABLE:
+	error = if_altqdisable(wfqp->ifp);
+	break;
+    }
+    return error;
+}
+
+
+static int
+wfq_ifattach(ifacep)
+    struct wfq_interface *ifacep;
+{
+    int error = 0, i;
+    struct ifnet *ifp;
+    wfq_state_t *new_wfqp;
+    wfq *queue;
+
+    if ((ifp = ifunit(ifacep->wfq_ifacename)) == NULL) {
+#ifdef WFQ_DEBUG
+	printf("wfq_ifattach()...no ifp found\n");
+#endif
+	return (ENXIO);
+    }
+
+    if (!ALTQ_IS_READY(ifp)) {
+#ifdef WFQ_DEBUG
+	printf("wfq_ifattach()...altq is not ready\n");
+#endif
+	return (ENXIO);
+    }
+
+    if(ifacep->nqueues <= 0 ||  MAX_QSIZE < ifacep->nqueues)
+      ifacep->nqueues = DEFAULT_QSIZE;
+
+    /* allocate and initialize wfq_state_t */
+    MALLOC(new_wfqp, wfq_state_t *, sizeof(wfq_state_t), M_DEVBUF, M_WAITOK);
+    bzero(new_wfqp, sizeof(wfq_state_t));
+    MALLOC(queue, wfq *, sizeof(wfq) * ifacep->nqueues, M_DEVBUF, M_WAITOK);
+    bzero(queue, sizeof(wfq) * ifacep->nqueues);
+
+    new_wfqp->next = wfq_list;
+    wfq_list = new_wfqp;
+
+    /* keep the ifp */
+    new_wfqp->ifp = ifp;
+    new_wfqp->nums = ifacep->nqueues;
+    new_wfqp->hwm = HWM;
+    new_wfqp->bytes = 0;
+    new_wfqp->rrp = NULL;
+    new_wfqp->queue = queue;
+    new_wfqp->hash_func = wfq_hashbydstaddr;
+
+    for (i = 0; i < new_wfqp->nums; i++, queue++) {
+	queue->next = queue->prev = NULL;
+	queue->head = queue->tail = NULL;
+	queue->bytes = queue->quota = 0;
+	queue->weight = 100;
+    }
+
+    /*
+     * set WFQ to this ifnet structure.
+     */
+    if (if_altqattach(ifp, new_wfqp, wfq_ifenqueue, wfq_ifdequeue, ALTQT_WFQ))
+	(void)wfq_ifdetach(ifacep);
+
+    return (error);
+}
+
+
+static int
+wfq_ifdetach(ifacep)
+    struct wfq_interface *ifacep;
+{
+    int			error = 0;
+    wfq_state_t		*wfqp;
+    struct ifnet	*ifp;
+
+    if ((ifp = ifunit(ifacep->wfq_ifacename)) == NULL)
+	return (ENXIO);
+
+    wfqp = (wfq_state_t *)ifp->if_altqp;
+
+    /* free queued mbuf */
+    wfq_flush(ifp);
+
+    /* remove WFQ from the ifnet structure. */
+    (void)if_altqdisable(ifp);
+    (void)if_altqdetach(ifp);
+    
+    /* remove from the wfqstate list */
+    if (wfq_list == wfqp)
+	wfq_list = wfqp->next;
+    else {
+	wfq_state_t *wp = wfq_list;
+	do {
+	    if (wp->next == wfqp) {
+		wp->next = wfqp->next;
+		break;
+	    }
+	} while ((wp = wp->next) != NULL);
+    }
+    
+    /* deallocate wfq_state_t */
+    FREE(wfqp->queue, M_DEVBUF);
+    FREE(wfqp, M_DEVBUF);
+    return (error);
+}
+
+static int
+wfq_flush(ifp)
+    struct ifnet *ifp;
+{
+    struct mbuf *mp;
+
+    while ((mp = wfq_ifdequeue(ifp, ALTDQ_DEQUEUE)) != NULL)
+	m_freem(mp);
+    return 0;
+}
+
+static int
+wfq_ifenqueue(ifp, mp, pr_hdr, mode)
+    struct ifnet *ifp;
+    struct mbuf *mp;
+    struct pr_hdr *pr_hdr;
+    int mode;
+{
+    wfq_state_t *wfqp;
+    struct flowinfo flow;
+    wfq *queue;
+    int byte, error = 0;
+
+    if (mode != ALTEQ_NORMAL)
+	return 0;
+
+    wfqp = (wfq_state_t *)ifp->if_altqp;
+    mp->m_nextpkt = NULL;
+
+    altq_extractflow(mp, pr_hdr, &flow);
+    queue = &wfqp->queue[(*wfqp->hash_func)(&flow, wfqp->nums)];
+    if (queue->tail == NULL)
+	queue->head = mp;
+    else
+	queue->tail->m_nextpkt = mp;
+    queue->tail = mp;
+    byte = mp->m_pkthdr.len;
+    queue->bytes += byte;
+    wfqp->bytes += byte;
+
+    if (queue->next == NULL) {
+	/* this queue gets active. add the queue to the active list */
+	if (wfqp->rrp == NULL){
+	    /* no queue in the active list */
+	    queue->next = queue->prev = queue;
+	    wfqp->rrp = queue;
+	    WFQ_ADDQUOTA(queue);
+	}
+	else{
+	    /* insert the queue at the tail of the active list */
+	    queue->prev = wfqp->rrp->prev;
+	    wfqp->rrp->prev->next = queue;
+	    wfqp->rrp->prev = queue;
+	    queue->next = wfqp->rrp;
+	    queue->quota = 0;
+	}
+    }
+
+    /* check overflow. if the total size exceeds the high water mark,
+       drop packets from the longest queue. */
+    while (wfqp->bytes > wfqp->hwm) {
+	wfq *drop_queue = wfq_maxqueue(wfqp);
+
+	/* drop the packet at the head. */
+	mp = drop_queue->head;
+	if ((drop_queue->head = mp->m_nextpkt) == NULL)
+	    drop_queue->tail = NULL;
+	mp->m_nextpkt = NULL;
+	byte = mp->m_pkthdr.len;
+	drop_queue->bytes -= byte;
+	drop_queue->drop_packets++;
+	drop_queue->drop_bytes += byte;
+	wfqp->bytes -= byte;
+	m_freem(mp);
+	if(drop_queue == queue)
+	    /* the queue for this flow is selected for drop queue */
+	    error = ENOBUFS;
+    }
+
+    /*
+     * call the driver's start routine.
+     */
+    ifp = wfqp->ifp;
+    if(ifp->if_start && (ifp->if_flags & IFF_OACTIVE) == 0)
+	(*ifp->if_start)(ifp);
+
+    return error;
+}
+	
+
+u_long wfq_hash(flow, n)
+    struct flowinfo *flow;
+    int n;
+{
+    if (flow == NULL)
+	return 0;
+    if (flow->fi_family == AF_INET) {
+	struct flowinfo_in *fp;
+	u_long val, val2;
+
+	fp = (struct flowinfo_in *)flow;
+	val = fp->fi_dst.s_addr ^ fp->fi_src.s_addr;
+	val = val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24);
+	val2 = fp->fi_dport ^ fp->fi_sport ^ fp->fi_proto;
+	val2 = val2 ^ (val2 >> 8);
+	val = val ^ val2;
+	return (val % n);
+    } 
+#ifdef INET6
+     else if (flow->fi_family == AF_INET6) {
+	struct flowinfo_in6 *fp;
+	u_long val;
+
+	fp = (struct flowinfo_in6 *)flow;
+	val = fp->fi_flowlabel ^ fp->fi_src.s6_addr32[3];
+	val = val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24);
+	return (val % n);
+    }
+#endif
+     else
+	return 0;
+}
+
+
+u_long wfq_hashbydstaddr(flow, n)
+    struct flowinfo *flow;
+    int n;
+{
+    if (flow == NULL)
+	return 0;
+    if (flow->fi_family == AF_INET) {
+	struct flowinfo_in *fp;
+	u_long val;
+
+	fp = (struct flowinfo_in *)flow;
+	val = fp->fi_dst.s_addr;
+	val = val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24);
+
+	return (val % n);
+    }
+#ifdef INET6
+      else if (flow->fi_family == AF_INET6) {
+	struct flowinfo_in6 *fp;
+	u_long val;
+
+	fp = (struct flowinfo_in6 *)flow;
+	val = fp->fi_flowlabel;
+	val = val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24);
+
+	return (val % n);
+    }
+#endif
+      else
+	return 0;
+}
+
+u_long wfq_hashbysrcport(flow, n)
+    struct flowinfo *flow;
+    int n;
+{
+    struct flowinfo_in *fp;
+    u_long val;
+
+    if (flow == NULL || flow->fi_family != AF_INET)
+	/* currently only AF_INET is supported, use qid 0. */
+	return 0;
+
+    fp = (struct flowinfo_in *)flow;
+    val = fp->fi_sport;
+    val = val ^ (val >> 8);
+
+    return (val % n);
+
+}
+
+
+static wfq *wfq_maxqueue(wfqp)
+    wfq_state_t *wfqp;
+{
+    int byte, max_byte = 0;
+    wfq *queue, *max_queue = NULL;
+
+    if((queue = wfqp->rrp) == NULL)
+	/* never happens */
+	return NULL;
+
+    do{
+	if ((byte = queue->bytes * 100 / queue->weight) > max_byte) {
+	    max_queue = queue;
+	    max_byte = byte;
+	}
+    } while ((queue = queue->next) != wfqp->rrp);
+
+    return max_queue;
+}
+
+
+static struct mbuf *
+wfq_ifdequeue(ifp, mode)
+    struct ifnet *ifp;
+    int mode;
+{
+    wfq_state_t *wfqp;
+    wfq *queue;
+    struct mbuf *mp;
+    int byte;
+
+    wfqp = (wfq_state_t *)ifp->if_altqp;
+
+    if (mode == ALTDQ_FLUSH) {
+	wfq_flush(ifp);
+	return NULL;
+    }
+
+    if ((wfqp->bytes == 0) || ((queue = wfqp->rrp) == NULL))
+	/* no packt in the queues */
+	return NULL;
+	
+    while (1) {
+	if(queue->quota > 0) {
+	    if(queue->bytes <= 0) {
+		/* this queue no longer has packet.  remove the queue
+		   from the active list. */
+		if(queue->next == queue){
+		    /* no other active queue 
+		       -- this case never happens in this algorithm. */
+		    queue->next = queue->prev = NULL;
+		    wfqp->rrp = NULL;
+		    return NULL;
+		}
+		else {
+		    queue->prev->next = queue->next;
+		    queue->next->prev = queue->prev;
+		    /* the round-robin pointer points to this queue,
+		       advance the rrp */
+		    wfqp->rrp = queue->next;
+		    queue->next = queue->prev = NULL;
+		    queue = wfqp->rrp;
+		    WFQ_ADDQUOTA(queue);
+		    continue;
+		}
+	    }
+
+	    /* dequeue a packet from this queue */
+	    mp = queue->head;
+	    if (mode == ALTDQ_DEQUEUE) {
+		if((queue->head = mp->m_nextpkt) == NULL)
+		    queue->tail = NULL;
+		byte = mp->m_pkthdr.len;
+		mp->m_nextpkt = NULL;
+		queue->quota -= byte;
+		queue->bytes -= byte;
+		queue->sent_packets++;
+		queue->sent_bytes += byte;
+		wfqp->bytes -= byte;
+	    }
+	    return mp;
+
+	    /* if the queue gets empty by this dequeueing, the queue
+	       will be removed from the active list at the next round */
+	}
+	
+	/* advance the round-robin pointer */
+	queue = wfqp->rrp = queue->next;
+	WFQ_ADDQUOTA(queue);
+    }
+}
+
+
+static int
+wfq_getqid(gqidp)
+    struct wfq_getqid *gqidp;
+{
+    struct ifnet *ifp;
+    wfq_state_t *wfqp;
+
+    if ((ifp = ifunit(gqidp->iface.wfq_ifacename)) == NULL)
+	return (ENXIO);
+
+    wfqp = (wfq_state_t *)ifp->if_altqp;
+    gqidp->qid = (*wfqp->hash_func)(&gqidp->flow, wfqp->nums);
+    return 0;
+}
+
+static int
+wfq_setweight(swp)
+    struct wfq_setweight *swp;
+{
+    struct ifnet *ifp;
+    wfq *queue;
+    int old;
+
+    if (swp->weight < 0) {
+	printf("set weight in natural number\n");
+	return (ENXIO);
+    }
+
+    if ((ifp = ifunit(swp->iface.wfq_ifacename)) == NULL)
+	return (ENXIO);
+
+    queue = &((wfq_state_t *)ifp->if_altqp)->queue[swp->qid];
+    old = queue->weight;
+    queue->weight = swp->weight;
+    swp->weight = old;
+    return 0;
+}
+
+
+static int
+wfq_getstats(gsp)
+    struct wfq_getstats *gsp;
+{
+    struct ifnet *ifp;
+    wfq *queue;
+    queue_stats *stats;
+
+    if ((ifp = ifunit(gsp->iface.wfq_ifacename)) == NULL)
+	return (ENXIO);
+
+    queue = &((wfq_state_t *)ifp->if_altqp)->queue[gsp->qid];
+    stats = &gsp->stats;
+
+    stats->bytes		= queue->bytes;
+    stats->weight		= queue->weight;
+    stats->sent_packets	= queue->sent_packets;
+    stats->sent_bytes	= queue->sent_bytes;
+    stats->drop_packets	= queue->drop_packets;
+    stats->drop_bytes	= queue->drop_bytes;
+
+    return 0;
+}
+
+
+static int
+wfq_changehashfnc(chf)
+     struct wfq_changehashfnc *chf;
+{
+    struct ifnet *ifp;
+    int error = 0;
+
+    if ((ifp = ifunit(chf->iface.wfq_ifacename)) == NULL)
+	return (ENXIO);
+
+    switch (chf->hash_policy) {
+    case WFQ_HASH_DSTADDR:
+	((wfq_state_t *)ifp->if_altqp)->hash_func = wfq_hashbydstaddr;
+    case WFQ_HASH_SRCPORT:
+	((wfq_state_t *)ifp->if_altqp)->hash_func = wfq_hashbysrcport;
+    case WFQ_HASH_FULL:
+	((wfq_state_t *)ifp->if_altqp)->hash_func = wfq_hash;
+	break;
+    default:
+	error = EINVAL;
+    }
+
+    return error;
+}
+
+
+
+/*
+ * wfq device interface
+ */
+#include <sys/ioctl.h>
+#include <sys/conf.h>
+
+d_open_t	wfqopen;
+d_close_t	wfqclose;
+d_ioctl_t	wfqioctl;
+
+int
+wfqopen(dev, flag, fmt, p)
+    dev_t dev;
+    int flag, fmt;
+    struct proc *p;
+{
+    return 0;
+}
+
+
+int
+wfqclose(dev, flag, fmt, p)
+    dev_t dev;
+    int flag, fmt;
+    struct proc *p;
+{
+    struct ifnet *ifp;
+    struct wfq_interface iface;
+    wfq_state_t *wfqp;
+    int s;
+    
+    s = splimp();
+    while ((wfqp = wfq_list) != NULL) {
+	ifp = wfqp->ifp;
+	sprintf(iface.wfq_ifacename, "%s%d", ifp->if_name, ifp->if_unit);
+	iface.wfq_ifacelen = strlen(iface.wfq_ifacename);
+	wfq_ifdetach(&iface);
+    }
+    splx(s);
+    return 0;
+}
+
+
+int
+wfqioctl(dev, cmd, addr, flag, p)
+    dev_t dev;
+    int cmd;
+    caddr_t addr;
+    int flag;
+    struct proc *p;
+{
+    int	error = 0;
+    int s;
+
+    /* check cmd for superuser only */
+    switch (cmd) {
+    case WFQ_GET_QID:
+    case WFQ_GET_STATS:
+	break;
+    default:
+	if ((error = suser(p->p_ucred, &p->p_acflag))) {
+#ifdef WFQ_DEBUG
+	    printf("wfqioctl()...not super user\n");
+#endif
+	    return (error);
+	}
+	break;
+    }
+
+    s = splimp();
+    switch (cmd) {
+	
+    case WFQ_ENABLE:
+	error = wfq_setenable((struct wfq_interface *)addr, ENABLE);
+	break;
+
+    case WFQ_DISABLE:
+	error = wfq_setenable((struct wfq_interface *)addr, DISABLE);
+	break;
+
+    case WFQ_IF_ATTACH:
+	error = wfq_ifattach((struct wfq_interface *)addr);
+	break;
+
+    case WFQ_IF_DETACH:
+	error = wfq_ifdetach((struct wfq_interface *)addr);
+	break;
+
+    case WFQ_GET_QID:
+	error = wfq_getqid((struct wfq_getqid *)addr);
+	break;
+
+    case WFQ_SET_WEIGHT:
+	error = wfq_setweight((struct wfq_setweight *)addr);
+	break;
+
+    case WFQ_GET_STATS:
+	error = wfq_getstats((struct wfq_getstats *)addr);
+	break;
+
+    case WFQ_CHANGE_HASHFNC:
+	error = wfq_changehashfnc((struct wfq_changehashfnc *)addr);
+	break;
+
+    default:
+	error = EINVAL;
+	break;
+    }
+    splx(s);
+    return error;
+}
+
+#endif /* WFQ */
diff -uN src-current/sys/netinet/wfq.h src-current-ipv6/sys/netinet/wfq.h
--- src-current/sys/netinet/wfq.h
+++ src-current-ipv6/sys/netinet/wfq.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 1997
+ *	Sony Computer Science Laboratory Inc.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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.
+ *
+ * $Id: wfq.h,v 0.3 1997/07/02 06:06:07 kjc Exp $
+ */
+/*
+ *  March 27, 1997.  Written by Hiroshi Kyusojin of Keio University
+ *  (kyu@mt.cs.keio.ac.jp). 
+ */
+
+#ifndef __NETINET_WFQ_H
+#define __NETINET_WFQ_H
+
+#include <netinet/in.h>
+
+#define DEFAULT_QSIZE	256
+#define MAX_QSIZE	2048
+
+#ifdef KERNEL
+
+#define	HWM			(64 * 1024)
+#define WFQ_QUOTA		512	/* quota bytes to send at a time */
+#define WFQ_ADDQUOTA(q)		((q)->quota += WFQ_QUOTA * (q)->weight / 100)
+#define ENABLE			0
+#define DISABLE			1
+
+typedef struct weighted_fair_queue{
+    struct weighted_fair_queue *next, *prev;
+    struct mbuf *head, *tail;
+    int bytes;				/* bytes in this queue */
+    int quota;				/* bytes sent in this round */
+    int weight;				/* weight in percent */
+    int sent_packets;			/* packets sent in this queue */
+    int sent_bytes;			/* bytes sent in this queue */
+    int drop_packets;			/* dropped packets */
+    int drop_bytes;			/* bytes dropped in this queue */
+} wfq;
+
+
+typedef struct wfqstate {
+    struct wfqstate *next;	/* for wfqstate list */
+    struct ifnet *ifp;
+    int nums;			/* number of queues */
+    int hwm;			/* high water mark */
+    int bytes;			/* total bytes in all the queues */
+    wfq *rrp;			/* round robin pointer */
+    wfq *queue;			/* pointer to queue list */
+    u_long (*hash_func)(struct flowinfo *, int);
+} wfq_state_t;
+
+#endif /* KERNEL */
+
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ        16
+#endif
+
+typedef struct wfq_interface{
+    char wfq_ifacename[IFNAMSIZ];
+    u_int wfq_ifacelen;
+    int nqueues;
+} wfq_iface_t;
+
+#define WFQ_ENABLE		_IOW('Q', 1, struct wfq_interface)
+#define WFQ_DISABLE		_IOW('Q', 2, struct wfq_interface)
+
+#define WFQ_IF_ATTACH		_IOW('Q', 3, struct wfq_interface)
+#define WFQ_IF_DETACH		_IOW('Q', 4, struct wfq_interface)
+
+#include <net/if_altq.h>
+
+struct wfq_getqid{
+    wfq_iface_t 	iface;
+    struct flowinfo 	flow;
+    u_long		qid;
+};
+
+#define WFQ_GET_QID		_IOWR('Q', 5, struct wfq_getqid)
+
+struct wfq_setweight {
+    wfq_iface_t iface;
+    int qid;
+    int weight;
+};
+
+#define WFQ_SET_WEIGHT		_IOWR('Q', 6, struct wfq_setweight)
+
+typedef struct each_queue_stats {
+    int bytes;			/* bytes in this queue */
+    int weight;			/* weight in percent */
+    int sent_packets;		/* number of packets sent in this queue */
+    int sent_bytes;		/* bytes sent in this queue */
+    int drop_packets;		/* number of packets dropped in this queue */
+    int drop_bytes;		/* bytes dropped in this queue */
+} queue_stats;
+
+struct wfq_getstats{
+    wfq_iface_t iface;
+    int qid;
+    queue_stats stats;
+};
+
+#define WFQ_GET_STATS		_IOWR('Q', 7, struct wfq_getstats)
+
+struct wfq_changehashfnc{
+    wfq_iface_t iface;
+    int hash_policy;
+};
+
+#define WFQ_HASH_DSTADDR	0	/* hash by dst address */
+#define WFQ_HASH_SRCPORT	1	/* hash by src port */
+#define WFQ_HASH_FULL		2	/* hash by all fields */
+
+#define WFQ_CHANGE_HASHFNC	_IOWR('Q', 8, struct wfq_changehashfnc)
+
+#endif /* __NETINET_WFQ_H */
diff -uN src-current/sys/netinet/ip_auth.c src-current-ipv6/sys/netinet/ip_auth.c
--- src-current/sys/netinet/ip_auth.c
+++ src-current-ipv6/sys/netinet/ip_auth.c
@@ -9,6 +9,8 @@
 static const char rcsid[] = "@(#)$Id: ip_auth.c,v 1.3 1998/03/21 13:37:42 peter Exp $";
 #endif
 
+#include "opt_inet6.h"
+
 #if defined(KERNEL) && !defined(_KERNEL)
 #define _KERNEL
 #endif
@@ -92,6 +94,10 @@
 #include <netinet/udp.h>
 #include <netinet/ip_icmp.h>
 #include "netinet/ip_compat.h"
+#ifdef INET6
+#include <netinet/ip6.h>
+#include <netinet/ip6_var.h>
+#endif
 #include <netinet/tcpip.h>
 #include "netinet/ip_fil.h"
 #include "netinet/ip_auth.h"
diff -uN src-current/sys/netinet/ip.h src-current-ipv6/sys/netinet/ip.h
--- src-current/sys/netinet/ip.h
+++ src-current-ipv6/sys/netinet/ip.h
@@ -90,6 +90,16 @@
 #define	IPTOS_RELIABILITY	0x04
 #define	IPTOS_MINCOST		0x02
 
+/* ALTQ_ECN */
+/* ECN bits proposed by Sally Floyd */
+#define	IPTOS_CE	0x01	/* congestion experienced */
+#define	IPTOS_ECT	0x02	/* ECN-capable transport */
+#ifdef notdef
+/* ECN bits proposed by Ed Elleson */
+#define	IPTOS_CE	0x80	/* congestion experienced */
+#define	IPTOS_ECT	0x40	/* ECN-capable transport */
+#endif
+
 /*
  * Definitions for IP precedence (also in ip_tos) (hopefully unused)
  */
diff -uN src-current/sys/netinet/tcp.h src-current-ipv6/sys/netinet/tcp.h
--- src-current/sys/netinet/tcp.h
+++ src-current-ipv6/sys/netinet/tcp.h
@@ -64,7 +64,9 @@
 #define	TH_PUSH	0x08
 #define	TH_ACK	0x10
 #define	TH_URG	0x20
-#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG)
+/* ALTQ_ECN */
+#define	TH_ECN	0x40
+#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECN)
 
 	u_short	th_win;			/* window */
 	u_short	th_sum;			/* checksum */
diff -uN src-current/sys/netinet/in_altq.h src-current-ipv6/sys/netinet/in_altq.h
--- src-current/sys/netinet/in_altq.h
+++ src-current-ipv6/sys/netinet/in_altq.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 1998
+ *	Sony Computer Science Laboratory Inc.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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.
+ *
+ * $Id: in_altq.h,v 0.1 1998/01/27 02:49:31 kjc Exp $
+ */
+#ifndef _NETINET_IN_ALTQ_H_
+#define _NETINET_IN_ALTQ_H_
+
+/*
+ * flow info structure for internet protocol family.
+ * (currently this is the only protocol family supported)
+ */
+
+struct flowinfo_in {
+	u_char		fi_len;		/* sizeof(struct flowinfo_in) */
+	u_char		fi_family;	/* AF_INET */
+	u_int8_t	fi_proto;	/* IPPROTO_XXX */
+	u_int8_t	fi_tos;		/* type-of-service */
+	struct in_addr	fi_dst;		/* dest address */
+	struct in_addr	fi_src;		/* src address */
+	u_int16_t	fi_dport;	/* dest port */
+	u_int16_t	fi_sport;	/* src port */
+	u_int8_t	_pad[32];	/* unused */
+};
+
+#ifdef INET6
+struct flowinfo_in6 {
+	u_char		fi_len;		/* sizeof(struct flowinfo_in6) */
+	u_char		fi_family;	/* AF_INET6 */
+	u_int8_t	fi_proto;	/* IPPROTO_XXX */
+	u_int8_t	fi_pri;		/* priority */
+	u_int32_t	fi_flowlabel;	/* ipv6 flowlabel */
+	u_int16_t	fi_dport;	/* dest port */
+	u_int16_t	fi_sport;	/* src port */
+	u_int8_t	_pad[4];	/* unused */
+	struct in6_addr fi_dst;		/* dest address */
+	struct in6_addr fi_src;		/* src address */
+};
+#endif /* INET6 */
+
+#endif /* _NETINET_IN_ALTQ_H_ */
diff -uN src-current/sys/netnatm/natm.c src-current-ipv6/sys/netnatm/natm.c
--- src-current/sys/netnatm/natm.c
+++ src-current-ipv6/sys/netnatm/natm.c
@@ -39,12 +39,20 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/domain.h>
 #include <sys/sockio.h>
+#include <sys/proc.h>
 #include <sys/protosw.h>
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
+#include <sys/syslog.h>
+#include <vm/vm.h>
+#include <sys/sysctl.h>
+#ifdef __FreeBSD__
+#include <sys/stat.h>
+#endif
 
 #include <net/if.h>
 #include <net/if_atm.h>
@@ -54,11 +62,13 @@
 
 #include <netnatm/natm.h>
 
-static u_long natm5_sendspace = 16*1024;
-static u_long natm5_recvspace = 16*1024;
+u_long natm5_sendspace = 16*1024;
+u_long natm5_recvspace = 16*1024;
+
+u_long natm0_sendspace = 16*1024;
+u_long natm0_recvspace = 16*1024;
 
-static u_long natm0_sendspace = 16*1024;
-static u_long natm0_recvspace = 16*1024;
+u_int atm_hw_if_count = 0;
 
 /*
  * user requests
@@ -67,25 +77,28 @@
 /*
  * FreeBSD new usrreqs supersedes pr_usrreq.
  */
-static int natm_usr_attach __P((struct socket *, int, struct proc *));
+static int natm_usr_attach __P((struct socket *, int));
 static int natm_usr_detach __P((struct socket *));
-static int natm_usr_connect __P((struct socket *, struct sockaddr *,
-				 struct proc *));
+static int natm_usr_connect __P((struct socket *, struct mbuf *));
 static int natm_usr_disconnect __P((struct socket *));
 static int natm_usr_shutdown __P((struct socket *));
 static int natm_usr_send __P((struct socket *, int, struct mbuf *,
-			      struct sockaddr *, struct mbuf *, 
-			      struct proc *));
-static int natm_usr_peeraddr __P((struct socket *, struct sockaddr **));
+			      struct mbuf *, struct mbuf *));
+static int natm_usr_sense __P((struct socket *, struct stat *));
+static int natm_usr_peeraddr __P((struct socket *, struct mbuf *));
 static int natm_usr_control __P((struct socket *, int, caddr_t,
-				 struct ifnet *, struct proc *));
+				 struct ifnet *));
 static int natm_usr_abort __P((struct socket *));
-static int natm_usr_bind __P((struct socket *, struct sockaddr *, 
-			      struct proc *));
-static int natm_usr_sockaddr __P((struct socket *, struct sockaddr **));
+static int natm_usr_accept __P((struct socket *, struct mbuf *));
+static int natm_usr_bind __P((struct socket *, struct mbuf *));
+static int natm_usr_dynbind __P((struct socket *, struct mbuf *));
+static int natm_usr_listen __P((struct socket *));
+static int natm_usr_rcvd __P((struct socket *, int));
+static int natm_usr_rcvoob __P((struct socket *, struct mbuf *, int));
+static int natm_usr_sockaddr __P((struct socket *, struct mbuf *));
 
 static int
-natm_usr_attach(struct socket *so, int proto, struct proc *p)
+natm_usr_attach(struct socket *so, int proto)
 {
     struct natmpcb *npcb;
     int error = 0;
@@ -109,6 +122,7 @@
 
     so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
     npcb->npcb_socket = so;
+    npcb->npcb_refcnt++;
  out:
     splx(s);
     return (error);
@@ -139,9 +153,9 @@
 }
 
 static int
-natm_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
+natm_usr_connect(struct socket *so, struct mbuf *nam)
 {
-    struct natmpcb *npcb;
+    struct natmpcb *npcb, *cpcb;
     struct sockaddr_natm *snatm;
     struct atm_pseudoioctl api;
     struct atm_pseudohdr *aph;
@@ -149,6 +163,8 @@
     int error = 0;
     int s2, s = SPLSOFTNET();
     int proto = so->so_proto->pr_protocol;
+    int flags;
+    int tried = 0;
 
     npcb = (struct natmpcb *) so->so_pcb;
     if (npcb == NULL) {
@@ -160,7 +176,11 @@
      * validate nam and npcb
      */
 
-    snatm = (struct sockaddr_natm *)nam;
+    if (nam->m_len != sizeof(*snatm)) {
+        error = EINVAL;
+	goto out;
+    }
+    snatm = mtod(nam, struct sockaddr_natm *);
     if (snatm->snatm_len != sizeof(*snatm) ||
 	(npcb->npcb_flags & NPCB_FREE) == 0) {
 	error = EINVAL;
@@ -187,29 +207,58 @@
 	error = EAFNOSUPPORT;
 	goto out;
     }
+    if (ifp->if_ioctl == NULL) {
+	error = EIO;
+	goto out;
+    }
 
     /*
      * register us with the NATM PCB layer
      */
 
-    if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
+    flags = (proto == PROTO_NATMAAL5) ? (ATM_PH_AAL5 | ATM_PH_LLCSNAP) : 0;
+    if ((proto == PROTO_NATMAAL5) && (snatm->snatm_vci == ATM_VCI_ANY)) {
+retry:
+        tried = npcb_find(ifp, snatm->snatm_vpi);
+	if (tried == -1) {
+	    /* full ? */
+	    error = EADDRNOTAVAIL;
+	    goto out;
+	}
+	snatm->snatm_vci = tried;
+    }
+    cpcb = npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi, flags);
+    if (cpcb == NULL) {
+	if (tried)
+	    goto retry;
         error = EADDRINUSE;
         goto out;
     }
+    if (cpcb != npcb) {
+	npcb_free(npcb, NPCB_DESTROY);
+	npcb = cpcb;
+	so->so_pcb = (caddr_t) npcb;
+	npcb->npcb_socket = so;
+    } else
+	npcb->npcb_refcnt--;
 
     /*
      * enable rx
      */
-
-    ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
+    ATM_PH_FLAGS(&api.aph) = npcb->npcb_phflg;
     ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
     ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
-    api.rxhand = npcb;
     s2 = splimp();
-    if (ifp->if_ioctl == NULL || 
-	ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) {
+    api.rxhand = NULL;
+    if (npcb->npcb_refcnt > 1)
+	(void) ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api);
+    api.rxhand = npcb;
+    if (ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) {
 	splx(s2);
-	npcb_free(npcb, NPCB_REMOVE);
+	log(LOG_ERR,
+	    "natm_usr_connect(%s%d,%d,%d) failed!\n",
+	    ifp->if_name, ifp->if_unit,
+	    npcb->npcb_vpi, npcb->npcb_vci);
         error = EIO;
 	goto out;
     }
@@ -246,21 +295,39 @@
 	goto out;
     }
     ifp = npcb->npcb_ifp;
+    if (ifp->if_ioctl == NULL) {
+	error = EIO;
+	goto out;
+    }
 
     /*
      * disable rx
      */
 
-    ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
+    ATM_PH_FLAGS(&api.aph) = npcb->npcb_phflg;
     ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
     ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
-    api.rxhand = npcb;
     s2 = splimp();
-    if (ifp->if_ioctl != NULL)
-	ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api);
-    splx(s2);
+    api.rxhand = npcb;
+    (void) ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api);
+    api.rxhand = NULL;
+    if (npcb->npcb_refcnt > 1 &&
+	ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) {
+	splx(s2);
+	log(LOG_ERR,
+	    "natm_usr_disconnect(%s%d,%d,%d) failed!\n",
+	    ifp->if_name, ifp->if_unit,
+	    npcb->npcb_vpi, npcb->npcb_vci);
+    } else
+	splx(s2);
 
+    npcb->npcb_socket = NULL;
     npcb_free(npcb, NPCB_REMOVE);
+    if ((npcb->npcb_flags & NPCB_FREE) == 0) {
+	so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
+    }
+    npcb->npcb_refcnt++;		/* we keep this pcb */
+    npcb->npcb_socket = so;
     soisdisconnected(so);
 
  out:
@@ -276,8 +343,8 @@
 }
 
 static int
-natm_usr_send(struct socket *so, int flags, struct mbuf *m, 
-	      struct sockaddr *nam, struct mbuf *control, struct proc *p)
+natm_usr_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *nam,
+	     struct mbuf *control)
 {
     struct natmpcb *npcb;
     struct atm_pseudohdr *aph;
@@ -320,10 +387,20 @@
 }
 
 static int
-natm_usr_peeraddr(struct socket *so, struct sockaddr **nam)
+natm_usr_sense(struct socket *so, struct stat *sb)
+{
+    int s = SPLSOFTNET();
+
+    sb->st_blksize = so->so_snd.sb_hiwat;
+    splx(s);
+    return 0;
+}
+
+static int
+natm_usr_peeraddr(struct socket *so, struct mbuf *nam)
 {
     struct natmpcb *npcb;
-    struct sockaddr_natm *snatm, ssnatm;
+    struct sockaddr_natm *snatm;
     int error = 0;
     int s = SPLSOFTNET();
 
@@ -333,15 +410,14 @@
 	goto out;
     }
 
-    snatm = &ssnatm;
+    snatm = mtod(nam, struct sockaddr_natm *);
     bzero(snatm, sizeof(*snatm));
-    snatm->snatm_len = sizeof(*snatm);
+    nam->m_len = snatm->snatm_len = sizeof(*snatm);
     snatm->snatm_family = AF_NATM;
     sprintf(snatm->snatm_if, "%s%d", npcb->npcb_ifp->if_name,
 	    npcb->npcb_ifp->if_unit);
     snatm->snatm_vci = npcb->npcb_vci;
     snatm->snatm_vpi = npcb->npcb_vpi;
-    *nam = dup_sockaddr((struct sockaddr *)snatm, 0);
 
  out:
     splx(s);
@@ -349,11 +425,11 @@
 }
 
 static int
-natm_usr_control(struct socket *so, int cmd, caddr_t arg,
-		 struct ifnet *ifp, struct proc *p)
+natm_usr_control(struct socket *so, int cmd, caddr_t arg, struct ifnet *ifp)
 {
     struct natmpcb *npcb;
     struct atm_rawioctl ario;
+    struct ifreq *ifr = (struct ifreq *)arg;
     int error = 0;
     int s = SPLSOFTNET();
 
@@ -367,7 +443,8 @@
      * raw atm ioctl.   comes in as a SIOCRAWATM.   we convert it to
      * SIOCXRAWATM and pass it to the driver.
      */
-    if (cmd == SIOCRAWATM) {
+    switch (cmd) {
+      case SIOCRAWATM:
         if (npcb->npcb_ifp == NULL) {
 	    error = ENOTCONN;
 	    goto out;
@@ -382,9 +459,43 @@
 	    else
 		npcb->npcb_flags &= ~(NPCB_RAW);
 	}
-    }
-    else
+	break;
+
+      case SIOCATMASIF:
+	ifp = ifunit(ifr->ifr_name);
+	if (ifp == 0) {
+	    error = ENXIO;
+	    goto out;
+	}
+	if (npcb->npcb_ifp == NULL) {
+	    error = ENOTCONN;
+	    goto out;
+	}
+	if (npcb->npcb_sifp != NULL) {
+	    error = EBUSY;
+	    goto out;
+	}
+	error = ifp->if_ioctl(ifp, SIOCATMASIF, (caddr_t) npcb);
+	break;
+
+      case SIOCATMDSIF:
+	ifp = ifunit(ifr->ifr_name);
+	if (ifp == 0) {
+	    error = ENXIO;
+	    goto out;
+	}
+	if ((npcb->npcb_ifp == NULL) ||
+	    (npcb->npcb_sifp = NULL)) {
+	    error = ENOTCONN;
+	    goto out;
+	}
+	error = ifp->if_ioctl(ifp, SIOCATMDSIF, (caddr_t) npcb);
+	break;
+
+      default:
 	error = EOPNOTSUPP;
+	break;
+    }
 
  out:
     splx(s);
@@ -394,31 +505,62 @@
 static int
 natm_usr_abort(struct socket *so)
 {
-    return natm_usr_shutdown(so);
+    return EOPNOTSUPP;
+}
+
+static int
+natm_usr_accept(struct socket *so, struct mbuf *nam)
+{
+    return EOPNOTSUPP;
+}
+
+static int
+natm_usr_bind(struct socket *so, struct mbuf *nam)
+{
+    return EOPNOTSUPP;
+}
+
+static int
+natm_usr_dynbind(struct socket *so, struct mbuf *nam)
+{
+    return EOPNOTSUPP;
 }
 
 static int
-natm_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
+natm_usr_listen(struct socket *so)
 {
     return EOPNOTSUPP;
 }
 
 static int
-natm_usr_sockaddr(struct socket *so, struct sockaddr **nam)
+natm_usr_rcvd(struct socket *so, int flags)
+{
+    return EOPNOTSUPP;
+}
+
+static int
+natm_usr_rcvoob(struct socket *so, struct mbuf *m, int flags)
+{
+    return EOPNOTSUPP;
+}
+
+static int
+natm_usr_sockaddr(struct socket *so, struct mbuf *nam)
 {
     return EOPNOTSUPP;
 }
 
 /* xxx - should be const */
 struct pr_usrreqs natm_usrreqs = {
-	natm_usr_abort, pru_accept_notsupp, natm_usr_attach, natm_usr_bind,
+	natm_usr_abort, natm_usr_accept, natm_usr_attach, natm_usr_bind,
 	natm_usr_connect, pru_connect2_notsupp, natm_usr_control,
-	natm_usr_detach, natm_usr_disconnect, pru_listen_notsupp,
-	natm_usr_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp,
-	natm_usr_send, pru_sense_null, natm_usr_shutdown,
-	natm_usr_sockaddr, sosend, soreceive, sopoll
+	natm_usr_detach, natm_usr_disconnect, natm_usr_listen,
+	natm_usr_peeraddr, natm_usr_rcvd, natm_usr_rcvoob,
+	natm_usr_send, natm_usr_sense, natm_usr_shutdown,
+	natm_usr_sockaddr, natm_usr_dynbind
 };
 
+
 #else  /* !FREEBSD_USRREQS */
 
 #if defined(__NetBSD__) || defined(__OpenBSD__)
@@ -436,13 +578,15 @@
 
 {
   int error = 0, s, s2;
-  struct natmpcb *npcb;
+  struct natmpcb *npcb, *cpcb;
   struct sockaddr_natm *snatm;
   struct atm_pseudoioctl api;
   struct atm_pseudohdr *aph;
   struct atm_rawioctl ario;
   struct ifnet *ifp;
   int proto = so->so_proto->pr_protocol;
+  int flags;
+  int tried = 0;
 
   s = SPLSOFTNET();
 
@@ -473,6 +617,7 @@
 
       so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
       npcb->npcb_socket = so;
+      npcb->npcb_refcnt++;
 
       break;
 
@@ -525,30 +670,64 @@
 	error = EAFNOSUPPORT;
 	break;
       }
-
+      if (ifp->if_ioctl == NULL) {
+	error = EIO;
+	break;
+      }
 
       /*
        * register us with the NATM PCB layer
        */
 
-      if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
+      flags = (proto == PROTO_NATMAAL5) ? (ATM_PH_AAL5 | ATM_PH_LLCSNAP) : 0;
+      if ((proto == PROTO_NATMAAL5) && (snatm->snatm_vci == ATM_VCI_ANY)) {
+  retry:
+        tried = npcb_find(ifp, snatm->snatm_vpi);
+	if (tried == -1) {
+	  /* full ? */
+	  error = EADDRNOTAVAIL;
+	  break;
+	}
+	snatm->snatm_vci = tried;
+      }
+      cpcb = npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi, flags);
+      if (cpcb == NULL) {
+	if (tried)
+	  goto retry;
         error = EADDRINUSE;
         break;
       }
+      if (cpcb != npcb) {
+	npcb_free(npcb, NPCB_DESTROY);
+	npcb = cpcb;
+	so->so_pcb = (caddr_t) npcb;
+	npcb->npcb_socket = so;
+      } else
+	npcb->npcb_refcnt--;
 
       /*
        * enable rx
        */
 
-      ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
+      ATM_PH_FLAGS(&api.aph) = npcb->npcb_phflg;
       ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
       ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
-      api.rxhand = npcb;
       s2 = splimp();
-      if (ifp->if_ioctl == NULL || 
-	  ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) {
+      api.rxhand = NULL;
+      if (npcb->npcb_refcnt > 1)
+	(void) ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api);
+      api.rxhand = npcb;
+      if (ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) {
 	splx(s2);
-	npcb_free(npcb, NPCB_REMOVE);
+	log(LOG_ERR,
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+	    "natm_usr_connect(%s,%d,%d) failed!\n",
+	    ifp->if_xname,
+#else
+	    "natm_usr_connect(%s%d,%d,%d) failed!\n",
+	    ifp->if_name, ifp->if_unit,
+#endif
+	    npcb->npcb_vpi, npcb->npcb_vci);
         error = EIO;
 	break;
       }
@@ -566,21 +745,43 @@
 	break;
       }
       ifp = npcb->npcb_ifp;
+      if (ifp->if_ioctl == NULL) {
+	error = EIO;
+	break;
+      }
 
       /*
        * disable rx
        */
 
-      ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
+      ATM_PH_FLAGS(&api.aph) = npcb->npcb_phflg;
       ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
       ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
-      api.rxhand = npcb;
       s2 = splimp();
-      if (ifp->if_ioctl != NULL)
-	  ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api);
-      splx(s2);
+      api.rxhand = npcb;
+      (void) ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api);
+      api.rxhand = NULL;
+      if (npcb->npcb_refcnt > 1 &&
+	  ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) {
+	splx(s2);
+	log(LOG_ERR,
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+	    "natm_usr_disconnect(%s,%d,%d) failed!\n",
+	    ifp->if_xname,
+#else
+	    "natm_usr_disconnect(%s%d,%d,%d) failed!\n",
+	    ifp->if_name, ifp->if_unit,
+#endif
+	    npcb->npcb_vpi, npcb->npcb_vci);
+      } else
+	splx(s2);
 
       npcb_free(npcb, NPCB_REMOVE);
+      if ((npcb->npcb_flags & NPCB_FREE) == 0) {
+	so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
+	npcb->npcb_socket = so;
+      }
+      npcb->npcb_refcnt++;		/* we keep this pcb */
       soisdisconnected(so);
 
       break;
@@ -639,7 +840,8 @@
        * raw atm ioctl.   comes in as a SIOCRAWATM.   we convert it to
        * SIOCXRAWATM and pass it to the driver.
        */
-      if ((u_long)m == SIOCRAWATM) {
+      switch ((u_long)m) {
+      case SIOCRAWATM:
         if (npcb->npcb_ifp == NULL) {
           error = ENOTCONN;
           break;
@@ -654,11 +856,35 @@
 	  else
 	    npcb->npcb_flags &= ~(NPCB_RAW);
 	}
-
         break;
-      }
 
-      error = EOPNOTSUPP;
+      case SIOCATMASIF:
+	if (npcb->npcb_ifp == NULL) {
+	  error = ENOTCONN;
+	  break;
+	}
+	if (npcb->npcb_sifp != NULL) {
+	  error = EBUSY;
+	  break;
+	}
+	ifp = (struct ifnet *)control;
+	error = ifp->if_ioctl(ifp, SIOCATMASIF, (caddr_t) npcb);
+	break;
+
+      case SIOCATMDSIF:
+	if ((npcb->npcb_ifp == NULL) ||
+	    (npcb->npcb_sifp == NULL)) {
+	  error = ENOTCONN;
+	  break;
+	}
+	ifp = (struct ifnet *)control;
+	error = ifp->if_ioctl(ifp, SIOCATMDSIF, (caddr_t) npcb);
+	break;
+
+      default:
+	error = EOPNOTSUPP;
+	break;
+      }
       break;
 
     case PRU_BIND:			/* bind socket to address */
@@ -688,7 +914,6 @@
   splx(s);
   return(error);
 }
-
 #endif  /* !FREEBSD_USRREQS */
 
 /*
@@ -739,13 +964,15 @@
     goto next;
   }
 
-#ifdef NEED_TO_RESTORE_IFP
-  m->m_pkthdr.rcvif = npcb->npcb_ifp;
-#else
-#ifdef DIAGNOSTIC
-m->m_pkthdr.rcvif = NULL;	/* null it out to be safe */
-#endif
-#endif
+  /* don't joke: it is needed! */
+  if (npcb->npcb_sifp == NULL)
+    m->m_pkthdr.rcvif = npcb->npcb_ifp;
+  else {
+    m->m_pkthdr.rcvif = npcb->npcb_sifp;
+    npcb->npcb_sifp->if_lastchange = time;
+    npcb->npcb_sifp->if_ipackets++;
+    npcb->npcb_sifp->if_ibytes += m->m_pkthdr.len;
+  }
 
   if (sbspace(&so->so_rcv) > m->m_pkthdr.len ||
      ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.sb_cc < NPCB_RAWCC) ) {
@@ -768,13 +995,153 @@
 
 #if defined(__FreeBSD__)
 NETISR_SET(NETISR_NATM, natmintr);
+
+/*
+ * Sysctl definitions
+ */
+
+/* ARGSUSED */
+static int
+sysctl_aal0pcbs SYSCTL_HANDLER_ARGS
+{
+    register struct natmpcb *npcb;
+    struct natm_usrpcb upcb;
+    int error = 0, size = 0, out = 0;
+
+    req->lock = 0;
+    /* need a size estimate or a dump? */
+    if (req->oldptr)
+	out = 1;
+
+    for (npcb = natm_pcbs.lh_first;
+	 npcb != NULL;
+	 npcb = npcb->pcblist.le_next) {
+	if (((npcb->npcb_flags & NPCB_CONNECTED) != 0) &&
+	    ((npcb->npcb_phflg & ATM_PH_AAL5) == 0)) {
+	    if (!out)
+		size += sizeof(upcb);
+	    else {
+		bzero(&upcb, sizeof(upcb));
+		sprintf(upcb.ifname, "%s%d",
+			npcb->npcb_ifp->if_name,
+			npcb->npcb_ifp->if_unit);
+		if (npcb->npcb_sifp)
+		    sprintf(upcb.sifname, "%s%d",
+			    npcb->npcb_sifp->if_name,
+			    npcb->npcb_sifp->if_unit);
+		upcb.phflg = npcb->npcb_phflg;
+		upcb.vpi = npcb->npcb_vpi;
+		upcb.vci = npcb->npcb_vci;
+		upcb.flags = npcb->npcb_flags;
+		upcb.refcnt = npcb->npcb_refcnt;
+		COPY_ADDR6(npcb->ipaddr6, upcb.addr);
+		error = SYSCTL_OUT(req, &upcb, sizeof(upcb));
+	    }
+	}
+    }
+    if (!out)
+	error = SYSCTL_OUT(req, 0, size);
+    return (error);
+}
+
+SYSCTL_PROC(_net_natm_aal0, NATMAAL0CTL_PCBS, pcbs,
+	CTLTYPE_OPAQUE|CTLFLAG_RD, 0, 0, sysctl_aal0pcbs, "S,natm_usrpcb", "");
+
+SYSCTL_INT(_net_natm_aal5, NATMAAL5CTL_FIRST, first_vci, CTLFLAG_RW,
+	&first_vci, 0, "");
+
+SYSCTL_INT(_net_natm_aal5, NATMAAL5CTL_LAST, last_vci, CTLFLAG_RW,
+	&last_vci, 0, "");
+
+SYSCTL_INT(_net_natm_aal5, NATMAAL5CTL_IFCNT, hw_if_count, CTLFLAG_RD,
+	&atm_hw_if_count, 0, "");
+
+#include "sat.h"
+#if NSAT > 0
+
+extern void atmsubadd __P((u_int));
+
+/* ARGSUSED */
+static int
+sysctl_aal5sifcnt SYSCTL_HANDLER_ARGS
+{
+    int error = sysctl_handle_int(oidp,
+	oidp->oid_arg1, oidp->oid_arg2, req);
+
+    if (!error) {
+	if (atm_sub_cnt > atm_sub_next)
+	    atmsubadd(atm_sub_cnt);
+	atm_sub_cnt = atm_sub_next;
+    }
+    return (error);
+}
+
+SYSCTL_PROC(_net_natm_aal5, NATMAAL5CTL_SUBCNT, sub_if_count,
+	CTLTYPE_INT|CTLFLAG_RW, &atm_sub_cnt, 0,
+	&sysctl_aal5sifcnt, "I", "");
+
 #endif
 
+/* ARGSUSED */
+static int
+sysctl_aal5pcbs SYSCTL_HANDLER_ARGS
+{
+    register struct natmpcb *npcb;
+    struct natm_usrpcb upcb;
+    int error = 0, size = 0, out = 0;
+
+    req->lock = 0;
+    /* need a size estimate or a dump? */
+    if (req->oldptr)
+	out = 1;
+
+    for (npcb = natm_pcbs.lh_first;
+	 npcb != NULL;
+	 npcb = npcb->pcblist.le_next) {
+	if (((npcb->npcb_flags & NPCB_CONNECTED) != 0) &&
+	    ((npcb->npcb_phflg & ATM_PH_AAL5) == ATM_PH_AAL5)) {
+	    if (!out)
+		size += sizeof(upcb);
+	    else {
+		bzero(&upcb, sizeof(upcb));
+		sprintf(upcb.ifname, "%s%d",
+			npcb->npcb_ifp->if_name,
+			npcb->npcb_ifp->if_unit);
+		if (npcb->npcb_sifp)
+		    sprintf(upcb.sifname, "%s%d",
+			    npcb->npcb_sifp->if_name,
+			    npcb->npcb_sifp->if_unit);
+		upcb.phflg = npcb->npcb_phflg;
+		upcb.vpi = npcb->npcb_vpi;
+		upcb.vci = npcb->npcb_vci;
+		upcb.flags = npcb->npcb_flags;
+		upcb.refcnt = npcb->npcb_refcnt;
+		COPY_ADDR6(npcb->ipaddr6, upcb.addr);
+		error = SYSCTL_OUT(req, &upcb, sizeof(upcb));
+	    }
+	}
+    }
+    if (!out)
+	error = SYSCTL_OUT(req, 0, size);
+    return (error);
+}
+
+SYSCTL_PROC(_net_natm_aal5, NATMAAL5CTL_PCBS, pcbs,
+	CTLTYPE_OPAQUE|CTLFLAG_RD, 0, 0, sysctl_aal5pcbs, "S,natm_usrpcb", "");
+
+#endif
 
+#if defined(__NetBSD__) || defined(__OpenBSD__)
 /* 
  * natm0_sysctl: not used, but here in case we want to add something
  * later...
  */
+#include "sat.h"
+
+static sysctl_pcbs __P((int, void *, size_t *, void *));
+#if NSAT > 0
+static sysctl_sub __P((void *, size_t *, void *, size_t));
+#endif
 
 int natm0_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
 
@@ -789,7 +1156,15 @@
   /* All sysctl names at this level are terminal. */
   if (namelen != 1)
     return (ENOTDIR);
-  return (ENOPROTOOPT);
+
+  switch (name[0]) {
+  case NATMAAL0CTL_PCBS:
+    return (sysctl_pcbs(0, oldp, oldlenp, newp));
+
+  default:
+    return (ENOPROTOOPT);
+  }
+  /* NOTREACHED */
 }
 
 /* 
@@ -810,5 +1185,102 @@
   /* All sysctl names at this level are terminal. */
   if (namelen != 1)
     return (ENOTDIR);
-  return (ENOPROTOOPT);
+
+  switch (name[0]) {
+  case NATMAAL5CTL_FIRST:
+    return (sysctl_int(oldp, oldlenp, newp, newlen, &first_vci));
+
+  case NATMAAL5CTL_LAST:
+    return (sysctl_int(oldp, oldlenp, newp, newlen, &last_vci));
+
+  case NATMAAL5CTL_IFCNT:
+    return (sysctl_rdint(oldp, oldlenp, newp, atm_hw_if_count));
+
+  case NATMAAL5CTL_PCBS:
+    return (sysctl_pcbs(ATM_PH_AAL5, oldp, oldlenp, newp));
+
+  case NATMAAL5CTL_SUBCNT:
+#if NSAT > 0
+    return (sysctl_sub(oldp, oldlenp, newp, newlen));
+#else
+    return (sysctl_rdint(oldp, oldlenp, newp, 0));
+#endif
+
+  default:
+    return (ENOPROTOOPT);
+  }
+  /* NOTREACHED */
 }
+
+#if NSAT > 0
+
+extern void atmsubadd __P((u_int));
+
+static int
+sysctl_sub(oldp, oldlenp, newp, newlen)
+    void *oldp;
+    size_t *oldlenp;
+    void *newp;
+    size_t newlen;
+{
+    int error = sysctl_int(oldp, oldlenp, newp, newlen, &atm_sub_cnt);
+
+    if (!error) {
+	if (atm_sub_cnt > atm_sub_next)
+	    atmsubadd(atm_sub_cnt);
+	atm_sub_cnt = atm_sub_next;
+    }
+    return (error);
+}
+#endif
+
+static int
+sysctl_pcbs(aal, oldp, oldlenp, newp)
+    int aal;
+    void *oldp;
+    size_t *oldlenp;
+    void *newp;
+{
+    register struct natmpcb *npcb;
+    struct natm_usrpcb upcb;
+    register void *p = oldp;
+    int error = 0, size = 0;
+
+    if (newp)
+	return (EPERM);
+
+    for (npcb = natm_pcbs.lh_first;
+	 npcb != NULL;
+	 npcb = npcb->pcblist.le_next) {
+	if (((npcb->npcb_flags & NPCB_CONNECTED) != 0) &&
+	    ((npcb->npcb_phflg & ATM_PH_AAL5) == aal)) {
+	    size += sizeof(upcb);
+	    if (oldp) {
+		if (size > *oldlenp) {
+		    error = ENOMEM;
+		    break;
+		}
+		bzero(&upcb, sizeof(upcb));
+		strncpy(upcb.ifname, npcb->npcb_ifp->if_xname, IFNAMSIZ);
+		if (npcb->npcb_sifp)
+		    strncpy(upcb.sifname, npcb->npcb_sifp->if_xname, IFNAMSIZ);
+		upcb.phflg = npcb->npcb_phflg;
+		upcb.vpi = npcb->npcb_vpi;
+		upcb.vci = npcb->npcb_vci;
+		upcb.flags = npcb->npcb_flags;
+		upcb.refcnt = npcb->npcb_refcnt;
+		COPY_ADDR6(npcb->ipaddr6, upcb.addr);
+		error = copyout((caddr_t)&upcb, p, sizeof(upcb));
+		if (error)
+		    break;
+		p += sizeof(upcb);
+	    }
+	}
+    }
+    if (oldp)
+	*oldlenp = p - oldp;
+    else
+	*oldlenp = size;
+    return (0);
+}
+#endif
diff -uN src-current/sys/netnatm/natm.h src-current-ipv6/sys/netnatm/natm.h
--- src-current/sys/netnatm/natm.h
+++ src-current-ipv6/sys/netnatm/natm.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: natm.h,v 1.1 1996/07/04 03:20:12 chuck Exp $	*/
+/*	$NetBSD: natm.h,v 1.2 1997/07/19 22:51:13 chuck Exp $	*/
 
 /*
  *
@@ -56,6 +56,69 @@
   u_int8_t	snatm_vpi;		/* vpi */
 };
 
+#define ATM_VCI_ANY	0	/* wildcard VCI number */
+#define ATM_VCI_FIRST	32	/* first unreserved VCI number */
+#define ATM_VCI_LAST	500	/* last unreserved VCI number */
+
+/*
+ * NATM sysctl operations.
+ */
+
+#define NATMCTL_MAXID	(PROTO_NATMAAL5 + 1)
+
+#define NATMCTL_NAMES	{ \
+	{ 0, 0 }, \
+	{ "aal0", CTLTYPE_NODE }, \
+	{ "aal5", CTLTYPE_NODE }, \
+}
+
+/*
+ * AAL0 sysctl operations.
+ */
+
+#define NATMAAL0CTL_PCBS	1	/* AAL0 PCBs */
+#define NATMAAL0CTL_MAXID	2
+
+#define NATMAAL0CTL_NAMES	{ \
+	{ 0, 0 }, \
+	{ "pcbs", CTLTYPE_STRUCT }, \
+}
+
+/*
+ * AAL5 sysctl operations.
+ */
+
+#define NATMAAL5CTL_FIRST	1	/* First unreserved VCI */
+#define NATMAAL5CTL_LAST	2	/* Last unreserved VCI */
+#define NATMAAL5CTL_IFCNT	3	/* Hardinterface count */
+#define NATMAAL5CTL_SUBCNT	4	/* Subinterface count */
+#define NATMAAL5CTL_PCBS	5	/* AAL5 PCBs */
+#define NATMAAL5CTL_MAXID	6
+
+#define NATMAAL5CTL_NAMES	{ \
+	{ 0, 0 }, \
+	{ "first_vci", CTLTYPE_INT }, \
+	{ "last_vci", CTLTYPE_INT }, \
+	{ "hw_if_count", CTLTYPE_INT }, \
+	{ "sub_if_count", CTLTYPE_INT }, \
+	{ "pcbs", CTLTYPE_STRUCT }, \
+}
+
+/*
+ * PCB like structure for sysctls.
+ */
+
+struct natm_usrpcb {
+  char ifname[IFNAMSIZ];
+  char sifname[IFNAMSIZ];
+  u_int8_t phflg;
+  u_int8_t vpi;
+  u_int16_t vci;
+  short flags;
+  short refcnt;
+  struct in6_addr addr;
+};
+
 
 #if defined(__FreeBSD__) && defined(KERNEL)
 
@@ -77,15 +140,35 @@
  * natm protocol control block
  */
 
+union in_addr_6 {
+    struct {
+        u_int32_t spare[3];
+        struct    in_addr addr;
+      } in_addr_4;
+    struct  in6_addr addr6;
+};
+
+
 struct natmpcb {
   LIST_ENTRY(natmpcb) pcblist;		/* list pointers */
   u_int	npcb_inq;			/* # of our pkts in proto q */
   struct socket	*npcb_socket;		/* backpointer to socket */
   struct ifnet *npcb_ifp;		/* pointer to hardware */
-  struct in_addr ipaddr;		/* remote IP address, if APCB_IP */
+  struct ifnet *npcb_sifp;		/* pointer to subinterface */
+  union {				/* remote IP address, if NPCB_IP */
+    struct {
+      u_int32_t spare[3];
+      struct in_addr addr;
+    } addr4;
+    struct in6_addr addr6;
+  } u_ipaddr;
+#define ipaddr	u_ipaddr.addr4.addr
+#define ipaddr6	u_ipaddr.addr6
   u_int16_t npcb_vci;			/* VCI */
   u_int8_t npcb_vpi;			/* VPI */
-  u_int8_t npcb_flags;			/* flags */
+  u_int8_t npcb_phflg;			/* pseudo-header flags */
+  short npcb_flags;			/* flags */
+  short npcb_refcnt;			/* reference count */
 };
 
 /* flags */
@@ -94,6 +177,7 @@
 #define NPCB_IP		0x04		/* used by IP */
 #define NPCB_DRAIN	0x08		/* destory as soon as inq == 0 */
 #define NPCB_RAW	0x10		/* in 'raw' mode? */
+#define NPCB_SUBIF	0x20		/* has a subinterface */
 
 /* flag arg to npcb_free */
 #define NPCB_REMOVE	0		/* remove from global list */
@@ -113,7 +197,7 @@
 
 /* global data structures */
 
-extern struct npcblist natm_pcbs;	/* global list of pcbs */
+extern	struct npcblist natm_pcbs;	/* global list of pcbs */
 extern	struct ifqueue natmintrq;	/* natm packet input queue */
 #define	NATM_STAT
 #ifdef NATM_STAT
@@ -130,32 +214,39 @@
 }; 
 #define SIOCXRAWATM     _IOWR('a', 125, struct atm_rawioctl)
 
+extern	int first_vci, last_vci;	/* for wildcard allocation */
+
 /* external functions */
 
 /* natm_pcb.c */
 struct	natmpcb *npcb_alloc __P((int));
 void	npcb_free __P((struct natmpcb *, int));
-struct	natmpcb *npcb_add __P((struct natmpcb *, struct ifnet *, int, int));
+struct	natmpcb *
+	npcb_add __P((struct natmpcb *, struct ifnet *, int, int, int));
+int	npcb_find __P((struct ifnet *, int));
 
 /* natm.c */
 #if defined(__NetBSD__) || defined(__OpenBSD__)
 int	natm_usrreq __P((struct socket *, int, struct mbuf *,
                              struct mbuf *, struct mbuf *, struct proc *));
+
+int	natm0_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));
+int	natm5_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));
 #elif defined(__FreeBSD__)
-#if __FreeBSD__ > 2
+#ifdef PRUS_OOB
 /*
  * FreeBSD new usrreqs style appeared since 2.2.  compatibility to old style
  * has gone since 3.0.
+ * use PRUS_OOB defined in "sys/protosw.h" as an identifier.
+ * (note sys/protosw.h should be included first.)
  */
 #define FREEBSD_USRREQS
 extern struct pr_usrreqs natm_usrreqs;
-#else /* !( __FreeBSD__ > 2) */
+#else
 int	natm_usrreq __P((struct socket *, int, struct mbuf *,
                              struct mbuf *, struct mbuf *));
-#endif /* !( __FreeBSD__ > 2) */
 #endif
-int	natm0_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));
-int	natm5_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));
+#endif
 void	natmintr __P((void));
 
 #endif
diff -uN src-current/sys/netnatm/natm_pcb.c src-current-ipv6/sys/netnatm/natm_pcb.c
--- src-current/sys/netnatm/natm_pcb.c
+++ src-current-ipv6/sys/netnatm/natm_pcb.c
@@ -44,6 +44,7 @@
 #include <sys/socketvar.h>
 
 #include <net/if.h>
+#include <net/if_atm.h>
 
 #include <netinet/in.h>
 
@@ -88,6 +89,17 @@
 {
   int s = splimp();
 
+  npcb->npcb_refcnt--;
+
+  if (npcb->npcb_refcnt > 0) {
+     splx(s);
+     if ((npcb->npcb_refcnt == 1) && (npcb->npcb_socket != 0)) {
+	npcb->npcb_flags &= ~NPCB_IP;
+	CLR_ADDR6(npcb->ipaddr6);
+     }
+     return;
+  }
+
   if ((npcb->npcb_flags & NPCB_FREE) == 0) {
     LIST_REMOVE(npcb, pcblist);
     npcb->npcb_flags = NPCB_FREE;
@@ -109,12 +121,13 @@
  *   returns npcb if ok
  */
 
-struct natmpcb *npcb_add(npcb, ifp, vci, vpi)
+struct natmpcb *npcb_add(npcb, ifp, vci, vpi, flags)
 
 struct natmpcb *npcb;
 struct ifnet *ifp;
 u_int16_t vci;
 u_int8_t vpi;
+u_int8_t flags;
 
 {
   struct natmpcb *cpcb = NULL;		/* current pcb */
@@ -125,9 +138,12 @@
    * lookup required
    */
 
-  for (cpcb = natm_pcbs.lh_first ; cpcb != NULL ; 
-					cpcb = cpcb->pcblist.le_next) {
-    if (ifp == cpcb->npcb_ifp && vci == cpcb->npcb_vci && vpi == cpcb->npcb_vpi)
+  for (cpcb = natm_pcbs.lh_first;
+       cpcb != NULL; 
+       cpcb = cpcb->pcblist.le_next) {
+    if (ifp == cpcb->npcb_ifp &&
+	vci == cpcb->npcb_vci &&
+	vpi == cpcb->npcb_vpi)
       break;
   }
 
@@ -135,7 +151,10 @@
    * add & something already there?
    */
 
-  if (cpcb) {
+  if (cpcb &&
+      (((cpcb->npcb_phflg & ATM_PH_AAL5) != (flags & ATM_PH_AAL5)) ||
+       ((cpcb->npcb_phflg & ATM_PH_LLCSNAP) != (flags & ATM_PH_LLCSNAP)) ||
+       (npcb && (cpcb->npcb_socket != 0)))) {
     cpcb = NULL;
     goto done;					/* fail */
   }
@@ -144,28 +163,72 @@
    * need to allocate a pcb?
    */
 
-  if (npcb == NULL) {
-    cpcb = npcb_alloc(M_NOWAIT);	/* could be called from lower half */
-    if (cpcb == NULL) 
-      goto done;			/* fail */
-  } else {
-    cpcb = npcb;
+  if (cpcb == NULL) {
+    if (npcb == NULL) {
+      cpcb = npcb_alloc(M_NOWAIT);	/* could be called from lower half */
+      if (cpcb == NULL) 
+	goto done;			/* fail */
+    } else {
+      cpcb = npcb;
+    }
   }
 
   cpcb->npcb_ifp = ifp;
-  cpcb->ipaddr.s_addr = 0;
+  if ((cpcb->npcb_flags & NPCB_IP) == 0) {
+    CLR_ADDR6(cpcb->ipaddr6);
+  }
   cpcb->npcb_vci = vci;
   cpcb->npcb_vpi = vpi;
-  cpcb->npcb_flags = NPCB_CONNECTED;
+  cpcb->npcb_phflg = flags;
+  cpcb->npcb_flags &= ~NPCB_FREE;
+  if ((cpcb->npcb_flags & NPCB_CONNECTED) == 0) {
+    cpcb->npcb_flags |= NPCB_CONNECTED;
 
-  LIST_INSERT_HEAD(&natm_pcbs, cpcb, pcblist);
+    LIST_INSERT_HEAD(&natm_pcbs, cpcb, pcblist);
+  }
+  cpcb->npcb_refcnt++;
 
 done:
   splx(s);
   return(cpcb);
 }
 
+/*
+ * npcb_find: get the first free VCI number
+ *  returns it or -1
+ */
+
+int free_vci = ATM_VCI_FIRST;
+int first_vci = ATM_VCI_FIRST;
+int last_vci = ATM_VCI_LAST;
 
+int npcb_find(ifp, vpi)
+
+struct ifnet *ifp;
+u_int8_t vpi;
+
+{
+   register struct natmpcb *cpcb;
+   int looped = free_vci;
+
+again:
+   for (cpcb = natm_pcbs.lh_first;
+	cpcb != NULL;
+	cpcb = cpcb->pcblist.le_next) {
+     if (ifp == cpcb->npcb_ifp &&
+	 free_vci == cpcb->npcb_vci &&
+	 vpi == cpcb->npcb_vpi)
+       break;
+   }
+   if (cpcb == NULL)
+     return(free_vci);
+   free_vci++;
+   if (free_vci == looped)
+     return(-1);
+   if (free_vci > last_vci)
+     free_vci = first_vci;
+   goto again;
+}
 
 #ifdef DDB
 
@@ -177,12 +240,21 @@
   struct natmpcb *cpcb;
 
   printf("npcb dump:\n");
-  for (cpcb = natm_pcbs.lh_first ; cpcb != NULL ; 
-					cpcb = cpcb->pcblist.le_next) {
+  for (cpcb = natm_pcbs.lh_first;
+       cpcb != NULL; 
+       cpcb = cpcb->pcblist.le_next) {
+#if defined(__NetBSD__) || defined(__OpenBSD__)
     printf("if=%s, vci=%d, vpi=%d, IP=0x%x, sock=%p, flags=0x%x, inq=%d\n",
 	cpcb->npcb_ifp->if_xname, cpcb->npcb_vci, cpcb->npcb_vpi,
 	cpcb->ipaddr.s_addr, cpcb->npcb_socket, 
 	cpcb->npcb_flags, cpcb->npcb_inq);
+#elif defined(__FreeBSD__)
+    printf("if=%s%d, vci=%d, vpi=%d, IP=0x%x, sock=%p, flags=0x%x, inq=%d\n",
+	cpcb->npcb_ifp->if_name, cpcb->npcb_ifp->if_unit,
+	cpcb->npcb_vci, cpcb->npcb_vpi,
+	cpcb->ipaddr.s_addr, cpcb->npcb_socket, 
+	cpcb->npcb_flags, cpcb->npcb_inq);
+#endif
   }
   printf("done\n");
   return(0);
diff -uN src-current/sys/netnatm/natm_proto.c src-current-ipv6/sys/netnatm/natm_proto.c
--- src-current/sys/netnatm/natm_proto.c
+++ src-current-ipv6/sys/netnatm/natm_proto.c
@@ -39,11 +39,18 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/queue.h>
 #include <sys/socket.h>
 #include <sys/protosw.h>
 #include <sys/domain.h>
+#include <sys/mbuf.h>
+#include <sys/proc.h>
+#include <vm/vm.h>
+#include <sys/sysctl.h>
 
 #include <net/if.h>
+#include <net/radix.h>
+#include <net/route.h>
 
 #include <netinet/in.h>
 
@@ -53,10 +60,10 @@
 
 static	void natm_init __P((void));
 
-static struct protosw natmsw[] = {
+struct protosw natmsw[] = {
 { SOCK_STREAM,	&natmdomain,	PROTO_NATMAAL5, PR_CONNREQUIRED,
   0,	0,	0,	0,
-#ifdef FREEBSD_USRREQS
+#if defined(FREEBSD_USRREQS)
   0,
 #else
   natm_usrreq,
@@ -64,13 +71,14 @@
   0,	0,	0,	0,	
 #if defined(__NetBSD__) || defined(__OpenBSD__)
 	natm5_sysctl
-#elif defined(FREEBSD_USRREQS)
-        &natm_usrreqs
+#endif
+#if defined(FREEBSD_USRREQS)
+	&natm_usrreqs
 #endif
 },
 { SOCK_DGRAM,	&natmdomain,	PROTO_NATMAAL5,	PR_CONNREQUIRED | PR_ATOMIC,
   0,	0,	0,	0,
-#ifdef FREEBSD_USRREQS
+#if defined(FREEBSD_USRREQS)
   0,
 #else
   natm_usrreq,
@@ -78,13 +86,14 @@
   0,	0,	0,	0,	
 #if defined(__NetBSD__) || defined(__OpenBSD__)
 	natm5_sysctl
-#elif defined(FREEBSD_USRREQS)
-        &natm_usrreqs
+#endif
+#if defined(FREEBSD_USRREQS)
+	&natm_usrreqs
 #endif
 },
 { SOCK_STREAM,	&natmdomain,	PROTO_NATMAAL0, PR_CONNREQUIRED,
   0,	0,	0,	0,
-#ifdef FREEBSD_USRREQS
+#if defined(FREEBSD_USRREQS)
   0,
 #else
   natm_usrreq,
@@ -92,19 +101,20 @@
   0,	0,	0,	0,	
 #if defined(__NetBSD__) || defined(__OpenBSD__)
 	natm0_sysctl
-#elif defined(FREEBSD_USRREQS)
-        &natm_usrreqs
+#endif
+#if defined(FREEBSD_USRREQS)
+	&natm_usrreqs
 #endif
 },
 };
 
-static struct domain natmdomain =
+struct domain natmdomain =
     { AF_NATM, "natm", natm_init, 0, 0, 
       natmsw, &natmsw[sizeof(natmsw)/sizeof(natmsw[0])], 0,
       0, 0, 0};
 
 struct	ifqueue natmintrq;       	/* natm packet input queue */
-static int natmqmaxlen = IFQ_MAXLEN;	/* max # of packets on queue */
+int	natmqmaxlen = IFQ_MAXLEN;	/* max # of packets on queue */
 #ifdef NATM_STAT
 u_int natm_sodropcnt = 0;		/* # mbufs dropped due to full sb */
 u_int natm_sodropbytes = 0;		/* # of bytes dropped */
@@ -124,4 +134,12 @@
 
 #if defined(__FreeBSD__)
 DOMAIN_SET(natm);
+
+SYSCTL_NODE(_net,	PF_NATM,	natm,	CTLFLAG_RW,	0,
+	"ATM Family");
+
+SYSCTL_NODE(_net_natm,	PROTO_NATMAAL0,	aal0,	CTLFLAG_RW,	0,
+	"AAL0");
+SYSCTL_NODE(_net_natm,	PROTO_NATMAAL5,	aal5,	CTLFLAG_RW,	0,
+	"AAL5");
 #endif
diff -uN src-current/sys/netnatm/natm_sif.c src-current-ipv6/sys/netnatm/natm_sif.c
--- src-current/sys/netnatm/natm_sif.c
+++ src-current-ipv6/sys/netnatm/natm_sif.c
@@ -0,0 +1,346 @@
+/*
+ * ATM sub-interfaces for PVC (or how to transform a NBNA in P2Ps)
+ */
+
+#include "opt_inet6.h"
+
+#ifndef NATM
+#error "SAT DOES NEED NATM !!!"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/syslog.h>
+#include <sys/proc.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#ifdef __NetBSD__
+#include <net/if_ether.h>
+#endif
+#include <net/if_types.h>
+#include <net/if_atm.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_atm.h>
+#ifdef __FreeBSD__
+#include <netinet/if_ether.h>
+#endif
+#ifdef INET6
+#include <netinet/in6_var.h>
+#ifdef __FreeBSD__
+#include <netinet/if_ether6.h>
+#endif
+#include <netinet/if_ndp6.h>
+#endif
+
+#include <netnatm/natm.h>
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+extern int ifqmaxlen;
+#endif
+
+#include "sat.h"
+
+u_int atm_sub_next, atm_sub_cnt;
+
+#if NSAT > 0
+
+struct sat_softc {
+	struct ifnet sat_if;
+	TAILQ_ENTRY(sat_softc) sat_list;
+	struct natmpcb *sat_npcb;
+};
+
+TAILQ_HEAD(sat_head, sat_softc);
+struct sat_head sat_head;
+
+void satattach __P((void *));
+void atmsubadd __P((u_int));
+int sat_output __P((struct ifnet *, struct mbuf *,
+		    struct sockaddr *, struct rtentry *));
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+#define IOCTL_CMDT	u_long
+#elif defined(__FreeBSD__) || defined(__bsdi__)
+#define IOCTL_CMDT	int
+#endif
+int sat_ioctl __P((struct ifnet *, IOCTL_CMDT, caddr_t));
+
+/*
+ * Attach SAT interfaces
+ */
+
+void
+satattach(dummy)
+	void *dummy;
+{
+	TAILQ_INIT(&sat_head);
+	atm_sub_cnt = NSAT;
+	atm_sub_next = 0;
+	/* add preconfigured SAT interfaces */
+	atmsubadd(atm_sub_cnt);
+}
+
+#if defined(__FreeBSD__) || defined(__bsdi__)
+PSEUDO_SET(satattach, natm_sif);
+#endif
+
+void
+atmsubadd(cnt)
+	u_int cnt;
+{
+	register int i;
+	register struct sat_softc *sc;
+	register struct ifnet *ifp;
+
+	for (i = atm_sub_next; i < cnt; i++) {
+		sc = malloc(sizeof(struct sat_softc), M_DEVBUF, M_NOWAIT);
+		if (sc == NULL)
+			break;
+		bzero(sc, sizeof(struct sat_softc));
+		TAILQ_INSERT_TAIL(&sat_head, sc, sat_list);
+		atm_sub_next = i + 1;
+		ifp = &sc->sat_if;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+		sprintf(ifp->if_xname, "sat%d", i);
+#elif defined(__FreeBSD__) || defined(__bsdi__)
+		ifp->if_unit = i;
+		ifp->if_name = "sat";
+#endif
+		ifp->if_softc = sc;
+		ifp->if_mtu = ATMMTU;
+		ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
+		ifp->if_snd.ifq_maxlen = ifqmaxlen;
+		ifp->if_ioctl = sat_ioctl;
+		ifp->if_output = sat_output;
+		ifp->if_type = IFT_ATM;
+		ifp->if_addrlen = sizeof(struct atm_pseudohdr);
+#ifdef INET6
+		ifp->if_ndtype = IFND6_ATM;
+#endif
+		if_attach(ifp);
+	}
+	atm_sub_cnt = atm_sub_next;
+}
+
+/*
+ * Output routine (very simple because it is point-to-point).
+ */
+
+int
+sat_output(ifp0, m, dst, rt0)
+	register struct ifnet *ifp0;
+	struct mbuf *m;
+	struct sockaddr *dst;
+	struct rtentry *rt0;
+{
+	u_int16_t etype = 0;
+	int s, error = 0;
+	struct atm_pseudohdr *ad;
+	register struct natmpcb *npcb;
+	register struct ifnet *ifp;
+	struct atmllc *atmllc;
+#ifdef ALTQ
+	struct pr_hdr pr_hdr;
+#endif
+
+#define senderr(e)	{ error = (e); goto bad; }
+
+	if ((ifp0->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+		senderr(ENETDOWN);
+	npcb = ((struct sat_softc *)ifp0->if_softc)->sat_npcb;
+	ifp = npcb->npcb_ifp;
+	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+		senderr(ENETDOWN);
+	ifp0->if_opackets++;
+
+#ifdef DIAGNOSTIC
+	if ((m->m_flags & M_PKTHDR) == 0)
+		panic("sat_output no HDR");
+#endif
+
+#ifdef ALTQ
+	/*
+	 * save a pointer to the protocol level header before adding
+	 * link headers.
+	 */
+	if (dst)
+		pr_hdr.ph_family = dst->sa_family;
+	else
+		pr_hdr.ph_family = AF_UNSPEC;
+	pr_hdr.ph_hdr = mtod(m, caddr_t);
+#endif
+
+	/*
+	 * check for non-native ATM traffic (dst != NULL)
+	 */
+	if (dst) {
+		switch (dst->sa_family) {
+#ifdef INET
+		    case AF_INET:
+			etype = htons(ETHERTYPE_IP);
+			break;
+#ifdef INET6
+		    case AF_INET6:
+			etype = htons(ETHERTYPE_IPV6);
+			break;
+#endif
+#endif
+		    default:
+			senderr(EAFNOSUPPORT);
+		}
+
+		/*
+		 * must add atm_pseudohdr and llc/snap to data.
+		 */
+		M_PREPEND(m, 12, M_DONTWAIT);
+		if (m == 0)
+			senderr(ENOBUFS);
+		ad = mtod(m, struct atm_pseudohdr *);
+		ATM_PH_FLAGS(ad) = npcb->npcb_phflg;
+		ATM_PH_VPI(ad) = npcb->npcb_vpi;
+		ATM_PH_SETVCI(ad, npcb->npcb_vci);
+		atmllc = (struct atmllc *)(ad + 1);
+		bcopy(ATMLLC_HDR, atmllc->llchdr, sizeof(atmllc->llchdr));
+		ATM_LLC_SETTYPE(atmllc, etype);
+	}
+
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp)) {
+		s = splimp();
+		error = (*ifp->if_altqenqueue)(ifp, m, &pr_hdr, ALTEQ_NORMAL);
+		splx(s);
+		if (!error) {
+			ifp0->if_obytes += m->m_pkthdr.len;
+			ifp->if_obytes += m->m_pkthdr.len;
+			if (m->m_flags & M_MCAST)
+				ifp0->if_omcasts++;
+		}
+		return (error);
+	}
+#endif
+
+	s = splimp();
+	if (IF_QFULL(&ifp->if_snd)) {
+		IF_DROP(&ifp->if_snd);
+#ifdef ALTQ_ACCOUNT
+		ALTQ_ACCOUNTING(ifp, m, &pr_hdr, ALTEQ_ACCDROP);
+#endif
+		splx(s);
+		senderr(ENOBUFS);
+	}
+	ifp0->if_obytes += m->m_pkthdr.len;
+	ifp->if_obytes += m->m_pkthdr.len;
+	IF_ENQUEUE(&ifp->if_snd, m);
+#ifdef ALTQ_ACCOUNT
+	ALTQ_ACCOUNTING(ifp, m, &pr_hdr, ALTEQ_ACCOK);
+#endif
+	if ((ifp->if_flags & IFF_OACTIVE) == 0)
+		(*ifp->if_start)(ifp);
+	splx(s);
+	return (error);
+
+bad:
+	if (m)
+		m_freem(m);
+	return (error);
+}
+
+/*
+ * Ioctls on SAT pseudo-interfaces.
+ */
+
+int
+sat_ioctl(ifp, cmd, data)
+	struct ifnet *ifp;
+	IOCTL_CMDT cmd;
+	caddr_t data;
+{
+	struct ifaddr *ifa;
+	struct ifreq *ifr;
+	struct natmpcb *npcb;
+	int s = splimp(), error = 0;
+
+	switch (cmd) {
+	    case SIOCATMASIF:
+		if (((struct sat_softc *)ifp->if_softc)->sat_npcb != NULL) {
+			error = EADDRINUSE;
+			break;
+		}
+		npcb = (struct natmpcb *)data;
+		npcb->npcb_sifp = ifp;
+		npcb->npcb_flags |= NPCB_SUBIF;
+		((struct sat_softc *)ifp->if_softc)->sat_npcb = npcb;
+		ifp->if_flags |= IFF_RUNNING;
+		break;
+
+	    case SIOCATMDSIF:
+		npcb = (struct natmpcb *)data;
+		if (npcb != ((struct sat_softc *)ifp->if_softc)->sat_npcb) {
+			error = EADDRNOTAVAIL;
+			break;
+		}
+		if (npcb->npcb_sifp != ifp)
+			panic("sat_ioctl: ifp mismatch");
+		npcb->npcb_sifp = NULL;
+		npcb->npcb_flags &= ~NPCB_SUBIF;
+		((struct sat_softc *)ifp->if_softc)->sat_npcb = NULL;
+		ifp->if_flags &= ~IFF_RUNNING;
+		break;
+
+	    case SIOCSIFADDR:
+	    case SIOCSIFDSTADDR:
+		ifa = (struct ifaddr *)data;
+		if (ifa == 0) {
+			error = EAFNOSUPPORT;
+			break;
+		}
+		if ((ifa->ifa_addr->sa_family == AF_INET) &&
+		    (ifa->ifa_dstaddr->sa_family == AF_INET) &&
+		    (satosin(ifa->ifa_addr)->sin_addr.s_addr != INADDR_ANY) &&
+		    (satosin(ifa->ifa_dstaddr)->sin_addr.s_addr != INADDR_ANY))
+			ifp->if_flags |= IFF_UP;
+		else if ((ifa->ifa_addr->sa_family == AF_INET6) &&
+			 (ifa->ifa_dstaddr->sa_family == AF_INET6) &&
+			 !IS_ANYADDR6(satosin6(ifa->ifa_addr)->sin6_addr) &&
+			 !IS_ANYADDR6(satosin6(ifa->ifa_dstaddr)->sin6_addr))
+			ifp->if_flags |= IFF_UP;
+		break;
+
+#ifdef SIOCSIFMTU
+#ifndef ifr_mtu
+#define ifr_mtu	ifr_metric
+#endif
+	    case SIOCSIFMTU:
+		ifr = (struct ifreq *)data;
+		ifp->if_mtu = ifr->ifr_mtu;
+		break;
+#endif
+	    case SIOCADDMULTI:
+	    case SIOCDELMULTI:
+		ifr = (struct ifreq *)data;
+		if ((ifr == 0) ||
+		    ((ifr->ifr_addr.sa_family != AF_INET) &&
+		     (ifr->ifr_addr.sa_family != AF_INET6)))
+			error = EAFNOSUPPORT;
+		break;
+
+	    default:
+		error = EINVAL;
+		break;
+	}
+	splx(s);
+	return (error);
+}
+#endif
diff -uN src-current/sys/nfs/nfs_subs.c src-current-ipv6/sys/nfs/nfs_subs.c
--- src-current/sys/nfs/nfs_subs.c
+++ src-current-ipv6/sys/nfs/nfs_subs.c
@@ -37,6 +37,8 @@
  * $Id: nfs_subs.c,v 1.55 1998/05/24 14:41:53 peter Exp $
  */
 
+#include "opt_inet6.h"
+
 /*
  * These functions support the macros and help fiddle mbuf chains for
  * the nfs op functions. They do things like create the rpc header and
@@ -1958,6 +1960,19 @@
 		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
 			return (1);
 		break;
+#ifdef INET6
+	case AF_INET6:
+	    {
+		register struct sockaddr_in6 *inet6addr1, *inet6addr2;
+
+		inet6addr1 = (struct sockaddr_in6 *)nam;
+		inet6addr2 = (struct sockaddr_in6 *)(haddr->had_nam);
+		if (inet6addr1->sin6_family == AF_INET6 &&
+		    SAME_ADDR6(inet6addr1->sin6_addr, inet6addr2->sin6_addr))
+			return (1);
+		break;
+	    }
+#endif
 #ifdef ISO
 	case AF_ISO:
 	    {
diff -uN src-current/sys/nfs/nfs.h src-current-ipv6/sys/nfs/nfs.h
--- src-current/sys/nfs/nfs.h
+++ src-current-ipv6/sys/nfs/nfs.h
@@ -416,7 +416,17 @@
 /* Bits for nu_flag */
 #define	NU_INETADDR	0x1
 #define NU_NAM		0x2
+#ifdef INET6
+# ifdef ISO
+#define NU_NETFAM(u)	(((u)->nu_flag & NU_INETADDR) ? \
+			 (((u)->nu_flag & NU_NAM) ? AF_INET6 : AF_INET) : \
+			 AF_ISO)
+# else
+#define NU_NETFAM(u)	(((u)->nu_flag & NU_NAM) ? AF_INET6 : AF_INET)
+# endif
+#else
 #define NU_NETFAM(u)	(((u)->nu_flag & NU_INETADDR) ? AF_INET : AF_ISO)
+#endif
 
 struct nfsrv_rec {
 	STAILQ_ENTRY(nfsrv_rec) nr_link;
diff -uN src-current/sys/nfs/nfs_nqlease.c src-current-ipv6/sys/nfs/nfs_nqlease.c
--- src-current/sys/nfs/nfs_nqlease.c
+++ src-current-ipv6/sys/nfs/nfs_nqlease.c
@@ -51,6 +51,9 @@
  *		Performance of Cache-Consistency Protocols", Digital
  *		Equipment Corporation WRL Research Report 89/5, May 1989.
  */
+
+#include "opt_inet6.h"
+
 #include <sys/param.h>
 #include <sys/vnode.h>
 #include <sys/malloc.h>
@@ -385,9 +388,18 @@
 		lph->lph_flag |= (LC_VALID | LC_LOCAL);
 	else if (slp == nfs_udpsock) {
 		saddr = (struct sockaddr_in *)nam;
+#ifdef INET6
+		if (saddr->sin_family == AF_INET6) {
+			lph->lph_flag |= (LC_VALID | LC_UDP | LC_CLTP);
+			lph->lph_nam = dup_sockaddr(nam, 1);
+		} else {
+#endif
 		lph->lph_flag |= (LC_VALID | LC_UDP);
 		lph->lph_inetaddr = saddr->sin_addr.s_addr;
 		lph->lph_port = saddr->sin_port;
+#ifdef INET6
+		}
+#endif
 	} else if (slp == nfs_cltpsock) {
 		lph->lph_nam = dup_sockaddr(nam, 1);
 		lph->lph_flag |= (LC_VALID | LC_CLTP);
@@ -462,7 +474,13 @@
 	else
 		addr = slp->ns_nam;
 	if (lph->lph_flag & LC_UDP)
+#ifdef INET6
+		ret = netaddr_match(
+			lph->lph_flag & LC_CLTP ? AF_INET6 : AF_INET,
+			&lph->lph_haddr, addr);
+#else
 		ret = netaddr_match(AF_INET, &lph->lph_haddr, addr);
+#endif
 	else if (lph->lph_flag & LC_CLTP)
 		ret = netaddr_match(AF_ISO, &lph->lph_claddr, addr);
 	else {
@@ -509,6 +527,11 @@
 			lph->lph_flag |= LC_VACATED;
 		else if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) {
 			if (lph->lph_flag & LC_UDP) {
+#ifdef INET6
+				if (lph->lph_flag & LC_CLTP) {
+					nam2 = lph->lph_nam;
+				} else {
+#endif
 				MALLOC(nam2, struct sockaddr *,
 				       sizeof *nam2, M_SONAME, M_WAITOK);
 				saddr = (struct sockaddr_in *)nam2;
@@ -516,6 +539,9 @@
 				saddr->sin_family = AF_INET;
 				saddr->sin_addr.s_addr = lph->lph_inetaddr;
 				saddr->sin_port = lph->lph_port;
+#ifdef INET6
+				}
+#endif
 				so = nfs_udpsock->ns_so;
 			} else if (lph->lph_flag & LC_CLTP) {
 				nam2 = lph->lph_nam;
diff -uN src-current/sys/nfs/nfs_socket.c src-current-ipv6/sys/nfs/nfs_socket.c
--- src-current/sys/nfs/nfs_socket.c
+++ src-current-ipv6/sys/nfs/nfs_socket.c
@@ -41,6 +41,8 @@
  * Socket operations for use by nfs
  */
 
+#include "opt_inet6.h"
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/proc.h>
@@ -190,6 +192,7 @@
 	int s, error, rcvreserve, sndreserve;
 	struct sockaddr *saddr;
 	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin6;
 	struct mbuf *m;
 	u_short tport;
 	struct proc *p = &proc0; /* only used for socreate and sobind */
@@ -206,6 +209,30 @@
 	/*
 	 * Some servers require that the client port be a reserved port number.
 	 */
+#ifdef INET6
+	if (saddr->sa_family == AF_INET6 && (nmp->nm_flag & NFSMNT_RESVPORT)) {
+		struct sockaddr_in6 ssin6;
+		bzero(&ssin6, sizeof ssin6);
+		sin6 = &ssin6;
+		tport = IPPORT_RESERVED - 1;
+		for (;;) {
+			/*
+			 * set the socket each time,
+			 * as sobind changes it into V4 form
+			 */
+			sin6->sin6_port = htons(tport);
+			sin6->sin6_len = sizeof (struct sockaddr_in6);
+			sin6->sin6_family = AF_INET6;
+			if ((error = sobind(so,
+					    (struct sockaddr *)sin6,
+					    p)) != EADDRINUSE ||
+			    --tport <= IPPORT_RESERVED / 2)
+				break;
+		}
+		if (error)
+			goto bad;
+	} else
+#endif
 	if (saddr->sa_family == AF_INET && (nmp->nm_flag & NFSMNT_RESVPORT)) {
 		struct sockaddr_in ssin;
 		bzero(&ssin, sizeof ssin);
@@ -391,6 +418,9 @@
 {
 	struct sockaddr *sendnam;
 	int error, soflags, flags;
+#ifdef INET6
+	struct sockaddr_in6 addr;
+#endif
 
 	if (rep) {
 		if (rep->r_flags & R_SOFTTERM) {
@@ -410,6 +440,12 @@
 		sendnam = (struct sockaddr *)0;
 	else
 		sendnam = nam;
+#ifdef INET6
+	/* protect the name, as sosend may modify the sockaddr */
+	addr.sin6_family = 0;
+	if (sendnam && sendnam->sa_len == sizeof addr)
+		addr = *(struct sockaddr_in6 *)sendnam;
+#endif
 	if (so->so_type == SOCK_SEQPACKET)
 		flags = MSG_EOR;
 	else
@@ -417,6 +453,13 @@
 
 	error = so->so_proto->pr_usrreqs->pru_sosend(so, sendnam, 0, top, 0,
 						     flags, curproc /*XXX*/);
+#ifdef INET6
+	if (addr.sin6_family &&
+	    addr.sin6_family != sendnam->sa_family) {
+		*(struct sockaddr_in6 *)sendnam = addr;
+		sendnam->sa_len = sizeof addr;
+	}
+#endif
 	if (error) {
 		if (rep) {
 			log(LOG_INFO, "nfs send error %d for server %s\n",
@@ -1367,10 +1410,28 @@
 			    error = (*so->so_proto->pr_usrreqs->pru_send)
 				    (so, 0, m, (struct sockaddr *)0,
 				     (struct mbuf *)0, p);
-			else
+			else {
+#ifdef INET6
+			    struct sockaddr_in6 addr;
+
+			    /* protect the name, as PRU_SEND
+			       may modify the sockaddr */
+			    addr.sin6_family = 0;
+			    if (nmp->nm_nam->sa_len == sizeof addr)
+				addr = *(struct sockaddr_in6 *)nmp->nm_nam;
+#endif
 			    error = (*so->so_proto->pr_usrreqs->pru_send)
 				    (so, 0, m, nmp->nm_nam, (struct mbuf *)0,
 				     p);
+#ifdef INET6
+			    if (addr.sin6_family &&
+				addr.sin6_family != nmp->nm_nam->sa_family) {
+				    *(struct sockaddr_in6 *)(nmp->nm_nam)
+					= addr;
+				    nmp->nm_nam->sa_len = sizeof addr;
+			    }
+#endif
+			}
 			if (error) {
 				if (NFSIGNORE_SOERROR(nmp->nm_soflags, error))
 					so->so_error = 0;
diff -uN src-current/sys/nfs/nfs_srvcache.c src-current-ipv6/sys/nfs/nfs_srvcache.c
--- src-current/sys/nfs/nfs_srvcache.c
+++ src-current-ipv6/sys/nfs/nfs_srvcache.c
@@ -37,6 +37,8 @@
  * $Id: nfs_srvcache.c,v 1.16 1998/02/09 06:10:36 eivind Exp $
  */
 
+#include "opt_inet6.h"
+
 #ifndef NFS_NOSERVER 
 /*
  * Reference: Chet Juszczak, "Improving the Performance and Correctness
@@ -252,6 +254,12 @@
 		rp->rc_flag |= RC_INETADDR;
 		rp->rc_inetaddr = saddr->sin_addr.s_addr;
 		break;
+#ifdef INET6
+	case AF_INET6:
+		rp->rc_flag |= RC_INETADDR | RC_NAM;
+		rp->rc_nam = dup_sockaddr(nd->nd_nam, 1);
+		break;
+#endif
 	case AF_ISO:
 	default:
 		rp->rc_flag |= RC_NAM;
diff -uN src-current/sys/nfs/nfs_syscalls.c src-current-ipv6/sys/nfs/nfs_syscalls.c
--- src-current/sys/nfs/nfs_syscalls.c
+++ src-current-ipv6/sys/nfs/nfs_syscalls.c
@@ -37,6 +37,8 @@
  * $Id: nfs_syscalls.c,v 1.38 1998/05/19 07:11:25 peter Exp $
  */
 
+#include "opt_inet6.h"
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/sysproto.h>
@@ -317,6 +319,14 @@
 					nuidp->nu_inetaddr =
 					     saddr->sin_addr.s_addr;
 					break;
+#ifdef INET6
+				    case AF_INET6:
+					nuidp->nu_flag |= NU_INETADDR | NU_NAM;
+					nuidp->nu_nam =
+						dup_sockaddr(nfsd->nfsd_nd->
+							     nd_nam2, 1);
+					break;
+#endif
 				    case AF_ISO:
 				    default:
 					nuidp->nu_flag |= NU_NAM;
@@ -404,7 +414,12 @@
 		m->m_len = sizeof(int);
 		sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m, p);
 	}
+#ifdef INET6
+	if ((so->so_proto->pr_domain->dom_family == AF_INET ||
+	     so->so_proto->pr_domain->dom_family == AF_INET6) &&
+#else
 	if (so->so_proto->pr_domain->dom_family == AF_INET &&
+#endif
 	    so->so_proto->pr_protocol == IPPROTO_TCP) {
 		MGET(m, M_WAIT, MT_SOOPTS);
 		*mtod(m, int *) = 1;
@@ -565,9 +580,24 @@
 		     */
 		    if (nfsd->nfsd_flag & NFSD_NEEDAUTH) {
 			nfsd->nfsd_flag &= ~NFSD_NEEDAUTH;
+#ifdef INET6
+			if (((struct sockaddr_in6 *)nd->nd_nam)->
+				sin6_family == AF_INET6) {
+			    if (IS_IPV4SOCKADDR((struct sockaddr_in6 *)
+						(nd->nd_nam)))
+				nsd->nsd_haddr =
+				    ((struct sockaddr_in6 *)nd->nd_nam)->
+					sin6_addr.s6_addr32[3];
+			    else {
+				/* Kerberos with IPv6 not supported */
+				nsd->nsd_haddr = 0;
+			    }
+			} else
+#else
 			nsd->nsd_haddr = 
 				((struct sockaddr_in *)
 				 nd->nd_nam)->sin_addr.s_addr;
+#endif
 			nsd->nsd_authlen = nfsd->nfsd_authlen;
 			nsd->nsd_verflen = nfsd->nfsd_verflen;
 			if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr,
@@ -612,6 +642,12 @@
 			struct sockaddr_in *sin;
 
 			sin = (struct sockaddr_in *)nam;
+#ifdef INET6
+			/*
+			 * code OK:
+			 *    sin_port and sin6_port are at same offset
+			 */
+#endif
 			port = ntohs(sin->sin_port);
 			if (port >= IPPORT_RESERVED && 
 			    nd->nd_procnum != NFSPROC_NULL) {
@@ -619,6 +655,10 @@
 			    nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
 			    cacherep = RC_DOIT;
 			    printf("NFS request from unprivileged port (%s:%d)\n",
+#ifdef INET6
+				   sin->sin_family == AF_INET6 ?
+	   	ip6_sprintf(&((struct sockaddr_in6 *)sin)->sin6_addr) :
+#endif
 				   inet_ntoa(sin->sin_addr), port);
 			}
 		    }
@@ -1181,6 +1221,9 @@
 	else if (nd->nd_flag & ND_NFSV3)
 		rt->flag |= DRT_NFSV3;
 	rt->proc = nd->nd_procnum;
+#ifdef INET6
+	/* IPv6 : no log supported - YET */
+#endif
 	if (nd->nd_nam->sa_family == AF_INET)
 	    rt->ipadr = ((struct sockaddr_in *)nd->nd_nam)->sin_addr.s_addr;
 	else
diff -uN src-current/sys/pci/if_de.c src-current-ipv6/sys/pci/if_de.c
--- src-current/sys/pci/if_de.c
+++ src-current-ipv6/sys/pci/if_de.c
@@ -40,6 +40,7 @@
 #define	TULIP_HDR_DATA
 
 #include "opt_inet.h"
+#include "opt_inet6.h"
 #include "opt_ipx.h"
 
 #include <sys/param.h>
@@ -101,6 +102,11 @@
 #if defined(__FreeBSD__)
 #include <vm/pmap.h>
 #include <pci.h>
+#include <netinet/if_ether.h>
+#ifdef INET6
+#include <netinet/if_ether6.h>
+#include <netinet/if_ndp6.h>
+#endif
 #if NPCI > 0
 #include <pci/pcivar.h>
 #include <pci/dc21040reg.h>
@@ -4193,6 +4199,11 @@
 #else
     struct mbuf *m0;
 #endif
+#ifdef ALTQ
+    struct ifnet *ifp = &sc->tulip_if;
+    struct mbuf *ombuf = m;
+    int compressed = 0;
+#endif
 
 #if defined(TULIP_DEBUG)
     if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) {
@@ -4324,6 +4335,28 @@
 		 * entries that we can use for one packet, so we have
 		 * recopy it into one mbuf and then try again.
 		 */
+#ifdef ALTQ
+		if (ALTQ_IS_ON(ifp)) {
+		    struct mbuf *tmp;
+		    /*
+		     * tulip_mbuf_compress() frees the original mbuf.
+		     * thus, we have to remove the mbuf from the queue
+		     * before calling it.
+		     * we don't have to worry about space shortage
+		     * after compressing the mbuf since the compressed
+		     * mbuf will take only two segs.
+		     */
+		    if (compressed) {
+			/* should not happen */
+			printf("tulip_txput: compress called twice!\n");
+			goto finish;
+		    }
+		    tmp = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+		    if (tmp != ombuf)
+			panic("tulip_txput: different mbuf dequeued!");
+		    compressed = 1;
+		}
+#endif
 		m = tulip_mbuf_compress(m);
 		if (m == NULL)
 		    goto finish;
@@ -4372,10 +4405,20 @@
     } while ((m0 = m0->m_next) != NULL);
 #endif /* TULIP_BUS_DMA */
 
+
     /*
      * The descriptors have been filled in.  Now get ready
      * to transmit.
      */
+#ifdef ALTQ
+    if (ALTQ_IS_ON(ifp) && !compressed) {
+	/* remove the mbuf from the queue */
+	struct mbuf *tmp = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+	if (tmp != ombuf)
+	    panic("tulip_txput: different mbuf dequeued!");
+    }
+#endif
+
     IF_ENQUEUE(&sc->tulip_txq, m);
     m = NULL;
 
@@ -4599,6 +4642,14 @@
 		}
 #endif /* INET */
 
+#ifdef INET6
+		case AF_INET6: {
+		    tulip_init(sc);
+		    ndp6_ifinit(ifp, ifa);
+		    break;
+		}
+#endif /* INET6 */
+
 #ifdef IPX
 		case AF_IPX: {
 		    struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
@@ -4762,6 +4813,14 @@
     return error;
 }
 
+#ifdef ALTQ
+/*
+ * the original dequeueing policy is dequeue-and-prepend if something
+ * goes wrong.  when altq is used, it is changed to peek-and-dequeue.
+ * the modification becomes a bit complicated since tulip_txput() might
+ * copy and modify the mbuf passed.
+ */
+#endif
 /*
  * These routines gets called at device spl (from ether_output).  This might
  * pose a problem for TULIP_USE_SOFTINTR if ether_output is called at
@@ -4780,6 +4839,21 @@
 	if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP)
 	    tulip_txput_setup(sc);
 
+#ifdef ALTQ
+	if (ALTQ_IS_ON(ifp)) {
+	    struct mbuf *m, *m0;
+	    while ((m = (*ifp->if_altqdequeue)(ifp, ALTDQ_PEEK)) != NULL) {
+		if ((m0 = tulip_txput(sc, m)) != NULL) {
+		    /* txput failed */
+		    if (m0 != m)
+			/* should not happen */
+			printf("tulip_if_start: bad mbuf dequeued!\n");
+		    break;
+		}
+	    }
+	}
+	else
+#endif /* ALTQ */
 	while (sc->tulip_if.if_snd.ifq_head != NULL) {
 	    struct mbuf *m;
 	    IF_DEQUEUE(&sc->tulip_if.if_snd, m);
@@ -4800,6 +4874,21 @@
     TULIP_PERFSTART(ifstart_one)
     tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp);
 
+#ifdef ALTQ
+    if (ALTQ_IS_ON(ifp)) {
+	struct mbuf *m, *m0;
+	if ((sc->tulip_if.if_flags & IFF_RUNNING)
+	        && ((m = (*ifp->if_altqdequeue)(ifp, ALTDQ_PEEK)) != NULL)) {
+	    if ((m0 = tulip_txput(sc, m)) != NULL) {
+		/* txput tailed! */
+		if (m0 != m)
+		    /* should not happen */
+		    printf("tulip_if_start: bad mbuf dequeued!\n");
+	    }
+	}
+    }
+    else
+#endif /* !ALTQ */
     if ((sc->tulip_if.if_flags & IFF_RUNNING)
 	    && sc->tulip_if.if_snd.ifq_head != NULL) {
 	struct mbuf *m;
@@ -4999,6 +5088,9 @@
 
     tulip_reset(sc);
 
+#ifdef ALTQ
+    ifp->if_altqflags |= ALTQF_READY;
+#endif
 #if defined(__bsdi__) && _BSDI_VERSION >= 199510
     sc->tulip_pf = printf;
     TULIP_ETHER_IFATTACH(sc);
diff -uN src-current/sys/pci/if_en_pci.c src-current-ipv6/sys/pci/if_en_pci.c
--- src-current/sys/pci/if_en_pci.c
+++ src-current-ipv6/sys/pci/if_en_pci.c
@@ -50,17 +50,6 @@
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/systm.h>
-#ifndef SHUTDOWN_PRE_SYNC
-/*
- * device shutdown mechanism has been changed since 2.2-ALPHA.
- * if SHUTDOWN_PRE_SYNC is defined in "sys/systm.h", use new one.
- * otherwise, use old one.
- *	new: 2.2-ALPHA, 2.2-BETA, 2.2-GAMME, 2.2-RELEASE, 3.0
- *	old: 2.1.5, 2.1.6, 2.2-SNAP
- *			-- kjc
- */
-#include <sys/devconf.h>
-#endif
 #include <sys/malloc.h>
 #include <sys/socket.h>
 
@@ -81,11 +70,7 @@
 
 static	void en_pci_attach __P((pcici_t, int));
 static	char *en_pci_probe __P((pcici_t, pcidi_t));
-#ifdef SHUTDOWN_PRE_SYNC
 static void en_pci_shutdown __P((int, void *));
-#else
-static	int en_pci_shutdown __P((struct kern_devconf *, int));
-#endif
 
 /*
  * local structures
@@ -98,9 +83,16 @@
   /* PCI bus glue */
   void *sc_ih;			/* interrupt handle */
   pci_chipset_tag_t en_pc;	/* for PCI calls */
-
+  pcici_t en_confid;		/* config id */
 };
 
+#if !defined(MIDWAY_ENIONLY)
+static  void eni_get_macaddr __P((struct en_pci_softc *));
+#endif
+#if !defined(MIDWAY_ADPONLY)
+static  void adp_get_macaddr __P((struct en_pci_softc *));
+#endif
+
 /*
  * pointers to softcs (we alloc)
  */
@@ -119,11 +111,7 @@
 	en_pci_probe,
 	en_pci_attach,
 	&en_pci_count,
-#ifdef SHUTDOWN_PRE_SYNC
 	NULL,
-#else
-	en_pci_shutdown,
-#endif
 };  
 
 DATA_SET (pcidevice_set, endevice);
@@ -262,6 +250,7 @@
   sprintf(sc->sc_dev.dv_xname, "en%d", unit);
   sc->enif.if_unit = unit;
   sc->enif.if_name = "en";
+  scp->en_confid = config_id;
 
   /*
    * figure out if we are an adaptec card or not.
@@ -272,14 +261,12 @@
   device_id = pci_conf_read(config_id, PCI_ID_REG);
   sc->is_adaptec = (PCI_VENDOR(device_id) == PCI_VENDOR_ADP) ? 1 : 0;
   
-#ifdef SHUTDOWN_PRE_SYNC
   /*
    * Add shutdown hook so that DMA is disabled prior to reboot. Not
    * doing so could allow DMA to corrupt kernel memory during the
    * reboot before the driver initializes.
    */
   at_shutdown(en_pci_shutdown, scp, SHUTDOWN_POST_SYNC);
-#endif
 
   if (!pci_map_int(config_id, en_intr, (void *) sc, &net_imask)) {
     printf("%s: couldn't establish interrupt\n", sc->sc_dev.dv_xname);
@@ -293,6 +280,7 @@
 
 #if !defined(MIDWAY_ENIONLY)
   if (sc->is_adaptec) {
+    adp_get_macaddr(scp);
     sc->en_busreset = adp_busreset;
     adp_busreset(sc);
   }
@@ -300,6 +288,7 @@
 
 #if !defined(MIDWAY_ADPONLY)
   if (!sc->is_adaptec) {
+    eni_get_macaddr(scp);
     sc->en_busreset = NULL;
     pci_conf_write(config_id, EN_TONGA, (TONGA_SWAP_DMA|TONGA_SWAP_WORD));
   }
@@ -313,7 +302,6 @@
 
 }
 
-#ifdef SHUTDOWN_PRE_SYNC
 static void
 en_pci_shutdown(
 	int howto,
@@ -324,22 +312,126 @@
     en_reset(&psc->esc);
     DELAY(10);
 }
-#else  /* !SHUTDOWN_PRE_SYNC */
-static int
-en_pci_shutdown(kdc, force)
 
-struct kern_devconf *kdc;
-int force;
+#if !defined(MIDWAY_ENIONLY)
+
+#if defined(sparc) || defined(__FreeBSD__)
+#define bus_space_read_1(t, h, o) \
+  		((void)t, (*(volatile u_int8_t *)((h) + (o))))
+#endif
 
+static void 
+adp_get_macaddr(scp)
+     struct en_pci_softc *scp;
 {
-  if (kdc->kdc_unit < NEN) {
-    struct en_pci_softc *psc = enpcis[kdc->kdc_unit];
-    if (psc)			/* can it be null? */
-      en_reset(&psc->esc);
-    DELAY(10);
+  struct en_softc * sc = (struct en_softc *)scp;
+  int lcv;
+
+  for (lcv = 0; lcv < sizeof(sc->macaddr); lcv++)
+    sc->macaddr[lcv] = bus_space_read_1(sc->en_memt, sc->en_base,
+					MID_ADPMACOFF + lcv);
+}
+
+#endif /* MIDWAY_ENIONLY */
+
+#if !defined(MIDWAY_ADPONLY)
+
+/*
+ * Read station (MAC) address from serial EEPROM.
+ * derived from linux drivers/atm/eni.c by Werner Almesberger, EPFL LRC.
+ */
+#define EN_PROM_MAGIC  0x0c
+#define EN_PROM_DATA   0x02
+#define EN_PROM_CLK    0x01
+#define EN_ESI         64
+
+static void 
+eni_get_macaddr(scp)
+     struct en_pci_softc *scp;
+{
+  struct en_softc * sc = (struct en_softc *)scp;
+  pcici_t id = scp->en_confid;
+  int i, j, address, status;
+  u_int32_t data, t_data;
+  u_int8_t tmp;
+  
+  t_data = pci_conf_read(id, EN_TONGA) & 0xffffff00;
+
+  data =  EN_PROM_MAGIC | EN_PROM_DATA | EN_PROM_CLK;
+  pci_conf_write(id, EN_TONGA, data);
+
+  for (i = 0; i < sizeof(sc->macaddr); i ++){
+    /* start operation */
+    data |= EN_PROM_DATA ;
+    pci_conf_write(id, EN_TONGA, data);
+    data |= EN_PROM_CLK ;
+    pci_conf_write(id, EN_TONGA, data);
+    data &= ~EN_PROM_DATA ;
+    pci_conf_write(id, EN_TONGA, data);
+    data &= ~EN_PROM_CLK ;
+    pci_conf_write(id, EN_TONGA, data);
+    /* send address with serial line */
+    address = ((i + EN_ESI) << 1) + 1;
+    for ( j = 7 ; j >= 0 ; j --){
+      data = (address >> j) & 1 ? data | EN_PROM_DATA :
+      data & ~EN_PROM_DATA;
+      pci_conf_write(id, EN_TONGA, data);
+      data |= EN_PROM_CLK ;
+      pci_conf_write(id, EN_TONGA, data);
+      data &= ~EN_PROM_CLK ;
+      pci_conf_write(id, EN_TONGA, data);
+    }
+    /* get ack */
+    data |= EN_PROM_DATA ;
+    pci_conf_write(id, EN_TONGA, data);
+    data |= EN_PROM_CLK ;
+    pci_conf_write(id, EN_TONGA, data);
+    data = pci_conf_read(id, EN_TONGA);
+    status = data & EN_PROM_DATA;
+    data &= ~EN_PROM_CLK ;
+    pci_conf_write(id, EN_TONGA, data);
+    data |= EN_PROM_DATA ;
+    pci_conf_write(id, EN_TONGA, data);
+
+    tmp = 0;
+
+    for ( j = 7 ; j >= 0 ; j --){
+      tmp <<= 1;
+      data |= EN_PROM_DATA ;
+      pci_conf_write(id, EN_TONGA, data);
+      data |= EN_PROM_CLK ;
+      pci_conf_write(id, EN_TONGA, data);
+      data = pci_conf_read(id, EN_TONGA);
+      if(data & EN_PROM_DATA) tmp |= 1;
+      data &= ~EN_PROM_CLK ;
+      pci_conf_write(id, EN_TONGA, data);
+      data |= EN_PROM_DATA ;
+      pci_conf_write(id, EN_TONGA, data);
+    }
+    /* get ack */
+    data |= EN_PROM_DATA ;
+    pci_conf_write(id, EN_TONGA, data);
+    data |= EN_PROM_CLK ;
+    pci_conf_write(id, EN_TONGA, data);
+    data = pci_conf_read(id, EN_TONGA);
+    status = data & EN_PROM_DATA;
+    data &= ~EN_PROM_CLK ;
+    pci_conf_write(id, EN_TONGA, data);
+    data |= EN_PROM_DATA ;
+    pci_conf_write(id, EN_TONGA, data);
+
+    sc->macaddr[i] = tmp;
   }
-  dev_detach(kdc);
-  return(0);
+  /* stop operation */
+  data &=  ~EN_PROM_DATA;
+  pci_conf_write(id, EN_TONGA, data);
+  data |=  EN_PROM_CLK;
+  pci_conf_write(id, EN_TONGA, data);
+  data |=  EN_PROM_DATA;
+  pci_conf_write(id, EN_TONGA, data);
+  pci_conf_write(id, EN_TONGA, t_data);
 }
-#endif /* !SHUTDOWN_PRE_SYNC */
+
+#endif /* !MIDWAY_ADPONLY */
+
 #endif /* NEN > 0 && NPCI > 0 */
diff -uN src-current/sys/pci/if_fxp.c src-current-ipv6/sys/pci/if_fxp.c
--- src-current/sys/pci/if_fxp.c
+++ src-current-ipv6/sys/pci/if_fxp.c
@@ -560,6 +560,9 @@
 	ifp->if_ioctl = fxp_ioctl;
 	ifp->if_start = fxp_start;
 	ifp->if_watchdog = fxp_watchdog;
+#ifdef ALTQ
+	ifp->if_altqflags |= ALTQF_READY;
+#endif
 
 	/*
 	 * Attach the interface.
@@ -798,15 +801,24 @@
 	 * We're finished if there is nothing more to add to the list or if
 	 * we're all filled up with buffers to transmit.
 	 */
-	while (ifp->if_snd.ifq_head != NULL && sc->tx_queued < FXP_NTXCB) {
+	while (sc->tx_queued < FXP_NTXCB) {
 		struct mbuf *m, *mb_head;
 		int segment;
 
 		/*
 		 * Grab a packet to transmit.
 		 */
+#ifdef ALTQ
+		if (ALTQ_IS_ON(ifp)) {
+			mb_head = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE);
+		}
+		else
+#endif
 		IF_DEQUEUE(&ifp->if_snd, mb_head);
 
+		if (mb_head == NULL)
+			break;
+
 		/*
 		 * Get pointer to next available tx desc.
 		 */
@@ -1027,6 +1039,11 @@
 			/*
 			 * Try to start more packets transmitting.
 			 */
+#ifdef ALTQ
+			if (ALTQ_IS_ON(ifp))
+			        fxp_start(ifp);
+			else
+#endif
 			if (ifp->if_snd.ifq_head != NULL)
 				fxp_start(ifp);
 		}
diff -uN src-current/sys/sys/errno.h src-current-ipv6/sys/sys/errno.h
--- src-current/sys/sys/errno.h
+++ src-current-ipv6/sys/sys/errno.h
@@ -163,7 +163,8 @@
 #define	ENEEDAUTH	81		/* Need authenticator */
 #define EIDRM           82              /* Identifier removed */
 #define ENOMSG          83              /* No message of desired type */
-#define	ELAST		83		/* Must be equal largest errno */
+#define	EIPSEC		84		/* IPSec fatal error */
+#define	ELAST		84		/* Must be equal largest errno */
 
 #endif /* _POSIX_SOURCE */
 
diff -uN src-current/sys/sys/mbuf.h src-current-ipv6/sys/sys/mbuf.h
--- src-current/sys/sys/mbuf.h
+++ src-current-ipv6/sys/sys/mbuf.h
@@ -49,6 +49,7 @@
 #define	MHLEN		(MLEN - sizeof(struct pkthdr))	/* data len w/pkthdr */
 
 #define	MINCLSIZE	(MHLEN + MLEN)	/* smallest amount to put in cluster */
+#define	MINCLSPACE	1024		/* smallest space to use a cluster */
 #define	M_MAXCOMPRESS	(MHLEN / 2)	/* max amount to copy for compression */
 
 /*
@@ -75,9 +76,14 @@
 
 /* record/packet header in first mbuf of chain; valid if M_PKTHDR set */
 struct	pkthdr {
-	struct	ifnet *rcvif;		/* rcv interface */
+	union {
+		struct ifnet *c_rcvif;	/* rcv interface */
+		int c_pktype;		/* packet type */
+	} pkctl;
 	int	len;			/* total packet length */
 };
+#define rcvif	pkctl.c_rcvif
+#define pktype	pkctl.c_pktype
 
 /* description of external storage mapped into mbuf, valid if M_EXT set */
 struct m_ext {
@@ -125,7 +131,7 @@
 #define	M_MCAST		0x0200	/* send/received as link-level multicast */
 
 /* flags copied when copying m_pkthdr */
-#define	M_COPYFLAGS	(M_PKTHDR|M_EOR|M_PROTO1|M_BCAST|M_MCAST)
+#define	M_COPYFLAGS	(~M_EXT)
 
 /* mbuf types */
 #define	MT_FREE		0	/* should be on free list */
@@ -306,6 +312,11 @@
 #define	M_ALIGN(m, len) \
 	{ (m)->m_data += (MLEN - (len)) &~ (sizeof(long) - 1); }
 /*
+ * As above, double word aligned.
+ */
+#define	M_DALIGN(m, len) \
+	{ (m)->m_data += (MLEN - (len)) &~ (sizeof(double) - 1); }
+/*
  * As above, for mbufs allocated with m_gethdr/MGETHDR
  * or initialized by M_COPY_PKTHDR.
  */
@@ -402,6 +413,7 @@
 struct	mbuf *m_gethdr __P((int, int));
 struct	mbuf *m_prepend __P((struct mbuf *,int,int));
 struct	mbuf *m_pullup __P((struct mbuf *, int));
+struct	mbuf *m_clpullup __P((struct mbuf *, int));
 struct	mbuf *m_retry __P((int, int));
 struct	mbuf *m_retryhdr __P((int, int));
 struct	mbuf *m_split __P((struct mbuf *,int,int));
diff -uN src-current/sys/sys/protosw.h src-current-ipv6/sys/sys/protosw.h
--- src-current/sys/sys/protosw.h
+++ src-current-ipv6/sys/sys/protosw.h
@@ -151,7 +151,8 @@
 #define	PRU_PROTOSEND		21	/* send to below */
 /* end for protocol's internal use */
 #define PRU_SEND_EOF		22	/* send and close */
-#define PRU_NREQ		22
+#define	PRU_DYNBIND		23	/* dynamic binding */
+#define PRU_NREQ		23
 
 #ifdef PRUREQUESTS
 char *prurequests[] = {
@@ -161,7 +162,7 @@
 	"SENSE",	"RCVOOB",	"SENDOOB",	"SOCKADDR",
 	"PEERADDR",	"CONNECT2",	"FASTTIMO",	"SLOWTIMO",
 	"PROTORCV",	"PROTOSEND",
-	"SEND_EOF",
+	"SEND_EOF",	"DYNBIND",
 };
 #endif
 
@@ -226,6 +227,10 @@
 				      struct mbuf **controlp, int *flagsp));
 	int	(*pru_sopoll) __P((struct socket *so, int events,
 				     struct ucred *cred, struct proc *p));
+	/* extra */
+	int	(*pru_dynbind) __P((struct socket *so,
+				    struct sockaddr *nam,
+				    struct proc *p));
 };
 
 int	pru_accept_notsupp __P((struct socket *so, struct sockaddr **nam));
diff -uN src-current/sys/sys/socket.h src-current-ipv6/sys/sys/socket.h
--- src-current/sys/sys/socket.h
+++ src-current-ipv6/sys/sys/socket.h
@@ -127,6 +127,7 @@
 #define	pseudo_AF_KEY	27		/* Internal key-management function */
 #define	AF_INET6	28		/* IPv6 */
 #define	AF_NATM		29		/* native ATM access */
+#define	AF_ATM		AF_NATM		/* HARP ATM */
 
 #define	AF_MAX		30
 
@@ -185,6 +186,7 @@
 #define	PF_KEY		pseudo_AF_KEY
 #define	PF_INET6	AF_INET6
 #define	PF_NATM		AF_NATM
+#define	PF_ATM		AF_ATM
 
 #define	PF_MAX		AF_MAX
 
@@ -328,6 +330,12 @@
 	    (struct cmsghdr *)((caddr_t)(cmsg) + ALIGN((cmsg)->cmsg_len)))
 
 #define	CMSG_FIRSTHDR(mhdr)	((struct cmsghdr *)(mhdr)->msg_control)
+
+/* Stevens' macros (no alignment constraints) */
+
+#define CMSG_SPACE(length)	(sizeof(struct cmsghdr) + (length))
+
+#define CMSG_LEN(length)	(sizeof(struct cmsghdr) + (length))
 
 /* "Socket"-level control message types: */
 #define	SCM_RIGHTS	0x01		/* access rights (array of int) */
diff -uN src-current/usr.bin/finger/net.c src-current-ipv6/usr.bin/finger/net.c
--- src-current/usr.bin/finger/net.c
+++ src-current-ipv6/usr.bin/finger/net.c
@@ -48,6 +48,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <resolv.h>
 #include <db.h>
 #include <err.h>
 #include <unistd.h>
@@ -67,24 +68,35 @@
 	extern int Tflag;
 	register FILE *fp;
 	register int c, lastc;
-	struct in_addr defaddr;
+	struct in6_addr defaddr;
 	struct hostent *hp, def;
 	struct servent *sp;
-	struct sockaddr_in sin;
+	struct sockaddr_in6 sin;
 	int s;
 	char *alist[1], *host;
 	struct iovec iov[3];
 	struct msghdr msg;
+	static int first = 0;
+
+	if (first == 0) {
+		(void) res_init();
+		_res.options |= RES_USE_INET6;
+		first++;
+	}
 
 	if (!(host = rindex(name, '@')))
 		return;
 	*host++ = '\0';
-	if (isdigit(*host) && (defaddr.s_addr = inet_addr(host)) != -1) {
+#ifdef SIN6_LEN
+	sin.sin6_len = sizeof(sin);
+#endif
+	if ((isxdigit(*host) || (*host == ':')) &&
+	    (inet_pton(AF_INET6, host, &defaddr) > 0)) {
 		def.h_name = host;
 		def.h_addr_list = alist;
 		def.h_addr = (char *)&defaddr;
-		def.h_length = sizeof(struct in_addr);
-		def.h_addrtype = AF_INET;
+		def.h_length = sizeof(struct in6_addr);
+		def.h_addrtype = AF_INET6;
 		def.h_aliases = 0;
 		hp = &def;
 	} else if (!(hp = gethostbyname(host))) {
@@ -95,9 +107,13 @@
 		warnx("tcp/finger: unknown service");
 		return;
 	}
-	sin.sin_family = hp->h_addrtype;
-	bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
-	sin.sin_port = sp->s_port;
+	bzero(&sin, sizeof(sin));
+#ifdef SIN6_LEN
+	sin.sin6_len = sizeof(sin);
+#endif
+	sin.sin6_family = hp->h_addrtype;
+	bcopy(hp->h_addr, (char *)&sin.sin6_addr, hp->h_length);
+	sin.sin6_port = sp->s_port;
 	if ((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) {
 		perror("finger: socket");
 		return;
diff -uN src-current/usr.bin/ftp/cmds.c src-current-ipv6/usr.bin/ftp/cmds.c
--- src-current/usr.bin/ftp/cmds.c
+++ src-current-ipv6/usr.bin/ftp/cmds.c
@@ -2094,6 +2094,34 @@
 }
 
 /*
+ * Start up extended port/passive mode interaction
+ */
+void
+setextport(argc, argv)
+	int argc;
+	char *argv[];
+{
+	code = togglevar(argc, argv, &extportmode,
+	    verbose ? (passivemode ? "Extended passive mode"
+				   : "Extended port mode")
+		    : NULL);
+}
+
+/*
+ * Start up short port/passive mode interaction
+ */
+void
+setshortport(argc, argv)
+	int argc;
+	char *argv[];
+{
+	code = togglevar(argc, argv, &shortportmode,
+	    verbose ? (passivemode ? "Short passive mode"
+				   : "Short port mode")
+		    : NULL);
+}
+
+/*
  * Restrict FTP data port range to a high group of "safe" ports
  */
 void
diff -uN src-current/usr.bin/ftp/cmdtab.c src-current-ipv6/usr.bin/ftp/cmdtab.c
--- src-current/usr.bin/ftp/cmdtab.c
+++ src-current-ipv6/usr.bin/ftp/cmdtab.c
@@ -70,6 +70,7 @@
 #ifndef SMALL
 char	edithelp[] =	"toggle command line editing";
 #endif /* !SMALL */
+char	extporthelp[] =	"enter extended port/passive transfer mode";
 char	formhelp[] =	"set file transfer format";
 char	gatehelp[] =	"toggle gate-ftp; specify host[:port] to change proxy";
 char	globhelp[] =	"toggle metacharacter expansion of local file names";
@@ -115,6 +116,7 @@
 char	runiquehelp[] = "toggle store unique for local files";
 char	sendhelp[] =	"send one file";
 char	shellhelp[] =	"escape to the shell";
+char	shortporthelp[] ="enter short port/passive transfer mode";
 char	sitehelp[] =	"send site specific command to remote server\n"
 			"\t\tTry \"rhelp site\" or \"site help\" "
 			"for more information";
@@ -160,6 +162,7 @@
 #ifndef SMALL
 	{ "edit",	edithelp,	0, 0, 0, CMPL0		setedit },
 #endif /* !SMALL */
+	{ "extport",	extporthelp,	0, 0, 0, CMPL0		setextport },
 	{ "exit",	quithelp,	0, 0, 0, CMPL0		quit },
 	{ "form",	formhelp,	0, 1, 1, CMPL0		setform },
 	{ "ftp",	connecthelp,	0, 0, 1, CMPL0		setpeer },
@@ -212,6 +215,7 @@
 	{ "runique",	runiquehelp,	0, 0, 1, CMPL0		setrunique },
 	{ "send",	sendhelp,	1, 1, 1, CMPL(lr)	put },
 	{ "sendport",	porthelp,	0, 0, 0, CMPL0		setport },
+	{ "shortport",	shortporthelp,	0, 0, 0, CMPL0		setshortport },
 	{ "site",	sitehelp,	0, 1, 1, CMPL0		site },
 	{ "size",	sizecmdhelp,	1, 1, 1, CMPL(r)	sizecmd },
 	{ "status",	statushelp,	0, 0, 1, CMPL0		status },
diff -uN src-current/usr.bin/ftp/extern.h src-current-ipv6/usr.bin/ftp/extern.h
--- src-current/usr.bin/ftp/extern.h
+++ src-current-ipv6/usr.bin/ftp/extern.h
@@ -131,6 +131,7 @@
 void	setcr __P((int, char **));
 void	setdebug __P((int, char **));
 void	setedit __P((int, char **));
+void	setextport __P(());
 void	setform __P((int, char **));
 void	setftmode __P((int, char **));
 void	setgate __P((int, char **));
@@ -146,6 +147,7 @@
 void	setprompt __P((int, char **));
 void	setrestrict __P((int, char **));
 void	setrunique __P((int, char **));
+void	setshortport __P(());
 void	setstruct __P((int, char **));
 void	setsunique __P((int, char **));
 void	settenex __P((int, char **));
diff -uN src-current/usr.bin/ftp/ftp.1 src-current-ipv6/usr.bin/ftp/ftp.1
--- src-current/usr.bin/ftp/ftp.1
+++ src-current-ipv6/usr.bin/ftp/ftp.1
@@ -307,6 +307,14 @@
 .It Ic ftp Ar host Op Ar port
 A synonym for
 .Ic open .
+.It Ic extport
+Toggle between extended
+.Dv EPRT
+and long
+.Dv LPRT
+forms of the
+.Dv PORT
+command for IPv6.
 .It Ic form Ar format
 Set the file transfer
 .Ic form
@@ -915,6 +923,14 @@
 implementations which do ignore
 .Dv PORT
 commands but, incorrectly, indicate they've been accepted.
+.It Ic shortport
+Toggle between short
+.Dv SPORT/SPASV
+and common
+.Dv PORT/PASV
+forms of
+.Dv PORT/PASV
+commands.
 .It Ic site Ar arg1 arg2 ...
 The arguments specified are sent, verbatim, to the remote
 .Tn FTP
diff -uN src-current/usr.bin/ftp/ftp.c src-current-ipv6/usr.bin/ftp/ftp.c
--- src-current/usr.bin/ftp/ftp.c
+++ src-current-ipv6/usr.bin/ftp/ftp.c
@@ -51,6 +51,7 @@
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <arpa/inet.h>
 #include <arpa/ftp.h>
 #include <arpa/telnet.h>
@@ -71,14 +72,14 @@
 
 #include "ftp_var.h"
 
-struct	sockaddr_in hisctladdr;
-struct	sockaddr_in data_addr;
+struct	sockaddr_in6 hisctladdr;
+struct	sockaddr_in6 data_addr;
 int	data = -1;
 int	abrtflag = 0;
 jmp_buf	ptabort;
 int	ptabflg;
 int	ptflag = 0;
-struct	sockaddr_in myctladdr;
+struct	sockaddr_in6 myctladdr;
 
 
 FILE	*cin, *cout;
@@ -89,14 +90,16 @@
 	int port;
 {
 	struct hostent *hp = NULL;
-	int s, len, tos;
+	int s, len;
 	static char hostnamebuf[MAXHOSTNAMELEN];
 
 	memset((void *)&hisctladdr, 0, sizeof(hisctladdr));
-	if (inet_aton(host, &hisctladdr.sin_addr) != 0) {
-		hisctladdr.sin_family = AF_INET;
-		(void)strncpy(hostnamebuf, host, sizeof(hostnamebuf) - 1);
-		hostnamebuf[sizeof(hostnamebuf) - 1] = '\0';
+#ifdef SIN6_LEN
+	hisctladdr.sin6_len = sizeof (hisctladdr);
+#endif
+	if (inet_pton(AF_INET6, host, &hisctladdr.sin6_addr) > 0) {
+		hisctladdr.sin6_family = AF_INET6;
+		(void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
 	} else {
 		hp = gethostbyname(host);
 		if (hp == NULL) {
@@ -104,34 +107,37 @@
 			code = -1;
 			return ((char *) 0);
 		}
-		hisctladdr.sin_family = hp->h_addrtype;
-		memcpy(&hisctladdr.sin_addr, hp->h_addr, hp->h_length);
+		hisctladdr.sin6_family = hp->h_addrtype;
+		memcpy(&hisctladdr.sin6_addr, hp->h_addr, hp->h_length);
 		(void)strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf) - 1);
 		hostnamebuf[sizeof(hostnamebuf) - 1] = '\0';
 	}
 	hostname = hostnamebuf;
-	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
+	s = socket(hisctladdr.sin6_family, SOCK_STREAM, 0);
 	if (s < 0) {
 		warn("socket");
 		code = -1;
 		return (0);
 	}
-	hisctladdr.sin_port = port;
+	hisctladdr.sin6_port = port;
+	hisctladdr.sin6_flowinfo = IPV6_PRIORITY_INTERACTIVE;
 	while (connect(s, (struct sockaddr *)&hisctladdr,
 			sizeof(hisctladdr)) < 0) {
 		if (hp && hp->h_addr_list[1]) {
 			int oerrno = errno;
-			char *ia;
+			char ia[64];
 
-			ia = inet_ntoa(hisctladdr.sin_addr);
+			inet_ntop(AF_INET6, &hisctladdr.sin6_addr,
+				  ia, sizeof (ia));
 			errno = oerrno;
 			warn("connect to address %s", ia);
 			hp->h_addr_list++;
-			memcpy(&hisctladdr.sin_addr, hp->h_addr, hp->h_length);
+			memcpy(&hisctladdr.sin6_addr, hp->h_addr, hp->h_length);
 			printf("Trying %s...\n",
-			    inet_ntoa(hisctladdr.sin_addr));
+			    inet_ntop(AF_INET6, &hisctladdr.sin6_addr,
+				      ia, sizeof (ia)));
 			(void)close(s);
-			s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
+			s = socket(hisctladdr.sin6_family, SOCK_STREAM, 0);
 			if (s < 0) {
 				warn("socket");
 				code = -1;
@@ -149,11 +155,6 @@
 		code = -1;
 		goto bad;
 	}
-#ifdef IP_TOS
-	tos = IPTOS_LOWDELAY;
-	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
-		warn("setsockopt TOS (ignored)");
-#endif
 	cin = fdopen(s, "r");
 	cout = fdopen(s, "w");
 	if (cin == NULL || cout == NULL) {
@@ -327,11 +328,11 @@
 			}
 			if (dig < 4 && isdigit((unsigned char)c))
 				code = code * 10 + (c - '0');
-			if (!pflag && code == 227)
+			if (!pflag && code >= 227 && code <= 229)
 				pflag = 1;
-			if (dig > 4 && pflag == 1 && isdigit((unsigned char)c))
+			if (dig > 4 && pflag == 1 && c == '(')
 				pflag = 2;
-			if (pflag == 2) {
+			if (pflag == 2 && c != '(') {
 				if (c != '\r' && c != ')')
 					*pt++ = c;
 				else {
@@ -1079,14 +1080,18 @@
 int
 initconn()
 {
-	char *p, *a;
+	register char *p, *a;
+	register int i;
 	int result, len, tmpno = 0;
-	int on = 1;
-	int a0, a1, a2, a3, p0, p1;
+	int on = 1, isv4;
 	int ports;
+	int af, hal, ha[16], pal, pa0, pa1;
+	char *cmd, name[64];
+	int port;
 
 	if (passivemode) {
-		data = socket(AF_INET, SOCK_STREAM, 0);
+		isv4 = IN6_IS_ADDR_V4MAPPED(&hisctladdr.sin6_addr);
+		data = socket(AF_INET6, SOCK_STREAM, 0);
 		if (data < 0) {
 			warn("socket");
 			return (1);
@@ -1095,39 +1100,109 @@
 		    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
 			       sizeof(on)) < 0)
 			warn("setsockopt (ignored)");
-		if (command("PASV") != COMPLETE) {
-			puts("Passive mode refused.");
+		if (shortportmode)
+			cmd = "SPASV";
+		else if (isv4)
+			cmd = "PASV";
+		else if (extportmode)
+			cmd = "EPSV";
+		else
+			cmd = "LPSV";
+		if (command(cmd) != COMPLETE) {
+			puts("Passive mode refused.\n");
 			goto bad;
 		}
 
+  		/*
+		 * Default to IPv4-mapped IPv6 address.
+		 */
+		af = 6;
+		hal = 16;
+		pal = 2;
+		for (i = 0; i < 10; i++)
+			ha[i] = 0;
+		ha[11] = ha[10] = -1;
+
 		/*
 		 * What we've got at this point is a string of comma
 		 * separated one-byte unsigned integer values.
-		 * The first four are the an IP address. The fifth is
-		 * the MSB of the port number, the sixth is the LSB.
-		 * From that we'll prepare a sockaddr_in.
 		 */
 
-		if (sscanf(pasv, "%d,%d,%d,%d,%d,%d",
-			   &a0, &a1, &a2, &a3, &p0, &p1) != 6) {
+		if (shortportmode) {
+			if (sscanf(pasv, "%d,%d", &pa0, &pa1) != 2) {
+				puts(
+"Short passive mode port scan failure. Shouldn't happen!\n");
+				goto bad;
+			}
+			memset(&data_addr, 0, sizeof(data_addr));
+#ifdef SIN6_LEN
+			data_addr.sin6_len = sizeof(data_addr);
+#endif
+			data_addr.sin6_family = AF_INET6;
+			data_addr.sin6_addr = hisctladdr.sin6_addr;
+			p = (char *)&data_addr.sin6_port;
+			p[0] = pa0 & 0xff;
+			p[1] = pa1 & 0xff;
+			goto doconnect;
+		}				
+
+		if (isv4 && sscanf(pasv,"%d,%d,%d,%d,%d,%d",
+&ha[12], &ha[13], &ha[14], &ha[15], &pa0, &pa1) != 6) {
+			puts(
+"Passive mode address scan failure. Shouldn't happen!\n");
+			goto bad;
+		};
+
+		if (!isv4 && !extportmode && sscanf(pasv,
+"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+&af, &hal,
+&ha[0], &ha[1], &ha[2], &ha[3], &ha[4], &ha[5], &ha[6], &ha[7],
+&ha[8], &ha[9], &ha[10], &ha[11], &ha[12], &ha[13], &ha[14], &ha[15],
+&pal, &pa0, &pa1) != 21) {
+			puts(
+"Long passive mode address scan failure. Shouldn't happen!\n");
+			goto bad;
+		}
+
+		if (!isv4 && extportmode &&
+		    sscanf(pasv, "IP%d|TCP|%64[.0-9:A-Fa-f]|%d",
+			   &af, name, &port) != 3) {
+			puts(
+"Extended passive mode address scan failure. Shouldn't happen!\n");
+			goto bad;
+		}
+		if ((af != 6) || (hal != 16) || (pal != 2)) {
 			puts(
-"Passive mode address scan failure. Shouldn't happen!");
+"Passive mode address bad format. Shouldn't happen!\n");
 			goto bad;
 		}
 
-		memset(&data_addr, 0, sizeof(data_addr));
-		data_addr.sin_family = AF_INET;
-		a = (char *)&data_addr.sin_addr.s_addr;
-		a[0] = a0 & 0xff;
-		a[1] = a1 & 0xff;
-		a[2] = a2 & 0xff;
-		a[3] = a3 & 0xff;
-		p = (char *)&data_addr.sin_port;
-		p[0] = p0 & 0xff;
-		p[1] = p1 & 0xff;
+		bzero(&data_addr, sizeof(data_addr));
+#ifdef SIN6_LEN
+		data_addr.sin6_len = sizeof(data_addr);
+#endif
+		data_addr.sin6_family = AF_INET6;
+		a = (char *)&data_addr.sin6_addr;
+		for (i = 0; i < sizeof(struct in6_addr); i++)
+			a[i] = ha[i] & 0xff;
+		p = (char *)&data_addr.sin6_port;
+		p[0] = pa0 & 0xff;
+		p[1] = pa1 & 0xff;
+		if (!isv4 && extportmode) {
+			if (inet_pton(AF_INET6, name,
+				      &data_addr.sin6_addr) <= 0) {
+				printf(
+"Extended passive mode bad address %s.\n", name);
+				goto bad;
+			}
+			data_addr.sin6_port = port;
+		}
 
-		if (connect(data, (struct sockaddr *)&data_addr,
-			    sizeof(data_addr)) < 0) {
+	    doconnect:
+		data_addr.sin6_flowinfo = IPV6_PRIORITY_BULK;
+  
+		if (connect(data, (struct sockaddr *) &data_addr,
+		    sizeof(data_addr))<0) {
 			warn("connect");
 			goto bad;
 		}
@@ -1142,11 +1217,12 @@
 
 noport:
 	data_addr = myctladdr;
+	data_addr.sin6_flowinfo = IPV6_PRIORITY_BULK;
 	if (sendport)
-		data_addr.sin_port = 0;	/* let system pick one */
+		data_addr.sin6_port = 0;	/* let system pick one */
 	if (data != -1)
 		(void)close(data);
-	data = socket(AF_INET, SOCK_STREAM, 0);
+	data = socket(AF_INET6, SOCK_STREAM, 0);
 	if (data < 0) {
 		warn("socket");
 		if (tmpno)
@@ -1178,16 +1254,35 @@
 		warn("getsockname");
 		goto bad;
 	}
+	isv4 = IN6_IS_ADDR_V4MAPPED(&data_addr.sin6_addr);
 	if (listen(data, 1) < 0)
 		warn("listen");
 	if (sendport) {
-		a = (char *)&data_addr.sin_addr;
-		p = (char *)&data_addr.sin_port;
+		a = (char *)&data_addr.sin6_addr;
+		p = (char *)&data_addr.sin6_port;
 #define	UC(b)	(((int)b)&0xff)
-		result =
-		    command("PORT %d,%d,%d,%d,%d,%d",
-		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
-		      UC(p[0]), UC(p[1]));
+		if (shortportmode)
+			result = command("SPORT %d,%d", UC(p[0]), UC(p[1]));
+		else if (isv4)
+			result = command("PORT %d,%d,%d,%d,%d,%d",
+				    UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
+				    UC(p[0]), UC(p[1]));
+		else if (!extportmode)
+			result = command(
+"LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+6, 16,
+UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
+UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
+UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
+UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
+2, UC(p[0]), UC(p[1]));
+		else
+			result = command("EPRT IP6|TCP|%s|%d",
+					 inet_ntop(AF_INET6,
+						   &data_addr.sin6_addr,
+						   name, sizeof(name)),
+					 (int)data_addr.sin6_port);
+
 		if (result == ERROR && sendport == -1) {
 			sendport = 0;
 			tmpno = 1;
@@ -1197,11 +1292,6 @@
 	}
 	if (tmpno)
 		sendport = 1;
-#ifdef IP_TOS
-	on = IPTOS_THROUGHPUT;
-	if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
-		warn("setsockopt TOS (ignored)");
-#endif
 	return (0);
 bad:
 	(void)close(data), data = -1;
@@ -1214,7 +1304,7 @@
 dataconn(lmode)
 	const char *lmode;
 {
-	struct sockaddr_in from;
+	struct sockaddr_in6 from;
 	int s, fromlen, tos;
 
 	fromlen = sizeof(from);
@@ -1231,9 +1321,12 @@
 	(void)close(data);
 	data = s;
 #ifdef IP_TOS
-	tos = IPTOS_THROUGHPUT;
-	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
-		warn("setsockopt TOS (ignored)");
+	if (IN6_IS_ADDR_V4MAPPED(&from.sin6_addr)) {
+		tos = IPTOS_THROUGHPUT;
+		if (setsockopt(s, IPPROTO_IP, IP_TOS,
+			       (char *)&tos, sizeof(int)) < 0)
+			warn("setsockopt TOS (ignored)");
+	}
 #endif
 	return (fdopen(data, lmode));
 }
@@ -1264,8 +1357,8 @@
 	static struct comvars {
 		int connect;
 		char name[MAXHOSTNAMELEN];
-		struct sockaddr_in mctl;
-		struct sockaddr_in hctl;
+		struct sockaddr_in6 mctl;
+		struct sockaddr_in6 hctl;
 		FILE *in;
 		FILE *out;
 		int tpe;
@@ -1372,6 +1465,7 @@
 	volatile int secndflag;
 	char *cmd2;
 	struct fd_set mask;
+	int isv4 = IN6_IS_ADDR_V4MAPPED(&hisctladdr.sin6_addr);
 
 #ifdef __GNUC__			/* XXX: to shut up gcc warnings */
 	(void)&oldintr;
@@ -1392,8 +1486,8 @@
 	}
 	if (curtype != prox_type)
 		changetype(prox_type, 1);
-	if (command("PASV") != COMPLETE) {
-		puts("proxy server does not support third party transfers.");
+	if (command(isv4 ? "PASV" : "LPSV") != COMPLETE) {
+		puts("proxy server does not support third party transfers.\n");
 		return;
 	}
 	pswitch(0);
@@ -1403,9 +1497,15 @@
 		code = -1;
 		return;
 	}
+	if (isv4 != IN6_IS_ADDR_V4MAPPED(&hisctladdr.sin6_addr)) {
+		printf("Proxy IP version mismatch\n");
+		pswitch(1);
+		code = 521;
+		return;
+	}
 	if (curtype != prox_type)
 		changetype(prox_type, 1);
-	if (command("PORT %s", pasv) != COMPLETE) {
+	if (command(isv4 ? "PORT %s" : "LPRT %s", pasv) != COMPLETE) {
 		pswitch(1);
 		return;
 	}
diff -uN src-current/usr.bin/ftp/ftp_var.h src-current-ipv6/usr.bin/ftp/ftp_var.h
--- src-current/usr.bin/ftp/ftp_var.h
+++ src-current-ipv6/usr.bin/ftp/ftp_var.h
@@ -97,6 +97,8 @@
 int	crflag;			/* if 1, strip car. rets. on ascii gets */
 char	pasv[64];		/* passive port for proxy data connection */
 int	passivemode;		/* passive mode enabled */
+int	extportmode;		/* extended/long port/passive mode */
+int	shortportmode;		/* short port/passive mode */
 int	restricted_data_ports;	/* enable quarantine FTP area */
 char   *altarg;			/* argv[1] with no shell-like preprocessing  */
 char	ntin[17];		/* input translation table */
diff -uN src-current/usr.bin/ftp/main.c src-current-ipv6/usr.bin/ftp/main.c
--- src-current/usr.bin/ftp/main.c
+++ src-current-ipv6/usr.bin/ftp/main.c
@@ -58,6 +58,8 @@
 #include <err.h>
 #include <locale.h>
 #include <netdb.h>
+#include <netinet/in.h>
+#include <resolv.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -83,6 +85,9 @@
 
 	(void) setlocale(LC_ALL, "");
 
+	(void) res_init();
+	_res.options |= RES_USE_INET6;
+
 	sp = getservbyname("ftp", "tcp");
 	if (sp == 0)
 		ftpport = htons(FTP_PORT);	/* good fallback */
@@ -114,6 +119,8 @@
 	interactive = 1;
 	autologin = 1;
 	passivemode = 0;
+	extportmode = 0;
+	shortportmode = 0;
 	restricted_data_ports = 1;
 	preserve = 1;
 	verbose = 0;
@@ -163,7 +170,7 @@
 	if (isatty(fileno(stdout)) && !dumbterm)
 		progress = 1;		/* progress bar on if tty is usable */
 
-	while ((ch = getopt(argc, argv, "adeginpP:tvVU")) != -1) {
+	while ((ch = getopt(argc, argv, "adeginpP:stvxVU")) != -1) {
 		switch (ch) {
 		case 'a':
 			anonftp = 1;
@@ -204,6 +211,10 @@
 				ftpport = htons(port);
 			break;
 
+		case 's':
+			shortportmode = 1;
+			break;
+
 		case 't':
 			trace = 1;
 			break;
@@ -214,6 +225,10 @@
 
 		case 'V':
 			verbose = 0;
+			break;
+
+		case 'x':
+			extportmode = 1;
 			break;
 
 		case 'U':
diff -uN src-current/usr.bin/netstat/inet.c src-current-ipv6/usr.bin/netstat/inet.c
--- src-current/usr.bin/netstat/inet.c
+++ src-current-ipv6/usr.bin/netstat/inet.c
@@ -50,11 +50,14 @@
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <netinet/in_pcb.h>
 #include <netinet/ip_icmp.h>
 #include <netinet/icmp_var.h>
 #include <netinet/igmp_var.h>
+#include <netinet/icmp6_var.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip6_var.h>
 #include <netinet/tcp.h>
 #include <netinet/tcpip.h>
 #include <netinet/tcp_seq.h>
@@ -76,8 +79,16 @@
 #include <unistd.h>
 #include "netstat.h"
 
+struct inp_addr {
+	union in_addr_6 addr;
+	u_int16_t port;
+	u_int16_t type;
+};
+
 char	*inetname __P((struct in_addr *));
 void	inetprint __P((struct in_addr *, int, char *, int));
+char	*inet6name __P((struct in6_addr *));
+void	inet6print __P((union in_addr_6 *, u_int16_t, u_int16_t, char *, int));
 
 /*
  * Print a summary of connections related to an Internet
@@ -99,6 +110,7 @@
 	struct xinpgen *xig, *oxig;
 	struct xsocket *so;
 	size_t len;
+	char name2[6];
 
 	istcp = 0;
 	switch (proto) {
@@ -172,22 +184,40 @@
 		}
 		if (Aflag)
 			printf("%8lx ", (u_long)so->so_pcb);
-		printf("%-5.5s %6ld %6ld ", name, so->so_rcv.sb_cc,
+
+		strncpy(name2, name, sizeof(name2));
+		name2[sizeof(name2)-1] = '\0';
+		if (strlen(name2) < sizeof(name2)-1) {
+#define INP_FLAGS	(inp->inp_flags & INP_COMPATANY)
+			if (INP_FLAGS == INP_COMPATV6) {
+				strcat(name2, "6");
+			} else if (INP_FLAGS == INP_COMPATV4) {
+				strcat(name2, "4");
+			}
+		}
+
+		printf("%-5.5s %6ld %6ld ", name2, so->so_rcv.sb_cc,
 			so->so_snd.sb_cc);
 		if (nflag) {
-			inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+			inet6print(&inp->inp_laddr_6, inp->inp_lport,
+			    inp->inp_latype,
 			    name, 1);
-			inetprint(&inp->inp_faddr, (int)inp->inp_fport,
+			inet6print(&inp->inp_faddr_6, inp->inp_fport,
+			    inp->inp_fatype,
 			    name, 1);
 		} else if (inp->inp_flags & INP_ANONPORT) {
-			inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+			inet6print(&inp->inp_laddr_6, inp->inp_lport,
+			    inp->inp_latype,
 			    name, 1);
-			inetprint(&inp->inp_faddr, (int)inp->inp_fport,
+			inet6print(&inp->inp_faddr_6, inp->inp_fport,
+			    inp->inp_fatype,
 			    name, 0);
 		} else {
-			inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+			inet6print(&inp->inp_laddr_6, inp->inp_lport,
+			    inp->inp_latype,
 			    name, 0);
-			inetprint(&inp->inp_faddr, (int)inp->inp_fport,
+			inet6print(&inp->inp_faddr_6, inp->inp_fport,
+			    inp->inp_fatype,
 			    name, inp->inp_lport != inp->inp_fport);
 		}
 		if (istcp) {
@@ -523,6 +553,393 @@
 #undef py
 }
 
+static	char *ip6names[] = {
+	"hop-by-hop header",
+	"#1",
+	"#2",
+	"#3",
+	"#4",
+	"#5",
+	"TCP",
+	"#7",
+	"#8",
+	"#9",
+	"#10",
+	"#11",
+	"#12",
+	"#13",
+	"#14",
+	"#15",
+	"#16",
+	"UDP",
+	"#18",
+	"#19",
+	"#20",
+	"#21",
+	"#22",
+	"#23",
+	"#24",
+	"#25",
+	"#26",
+	"#27",
+	"#28",
+	"ISO TP4",
+	"#30",
+	"#31",
+	"#32",
+	"#33",
+	"#34",
+	"#35",
+	"#36",
+	"#37",
+	"#38",
+	"#39",
+	"#40",
+	"IPv6 encap.",
+	"#42",
+	"routing header",
+	"fragment header",
+	"#45",
+	"#46",
+	"#47",
+	"#48",
+	"#49",
+	"ESP header",
+	"auth header",
+	"#52",
+	"#53",
+	"#54",
+	"#55",
+	"#56",
+	"#57",
+	"ICMP v6",
+	"no next header",
+	"end-to-end header",
+	"#61",
+	"#62",
+	"#63",
+	"#64",
+	"#65",
+	"#66",
+	"#67",
+	"#68",
+	"#69",
+	"#70",
+	"#71",
+	"#72",
+	"#73",
+	"#74",
+	"#75",
+	"#76",
+	"#77",
+	"#78",
+	"#79",
+	"#80",
+	"#81",
+	"#82",
+	"#83",
+	"#84",
+	"#85",
+	"#86",
+	"#87",
+	"#88",
+	"#89",
+	"#90",
+	"#91",
+	"#92",
+	"#93",
+	"#94",
+	"#95",
+	"#96",
+	"#97",
+	"#98",
+	"#99",
+	"#100",
+	"#101",
+	"#102",
+	"#103",
+	"#104",
+	"#105",
+	"#106",
+	"#107",
+	"#108",
+	"#109",
+	"#110",
+	"#111",
+	"#112",
+	"#113",
+	"#114",
+	"#115",
+	"#116",
+	"#117",
+	"#118",
+	"#119",
+	"#120",
+	"#121",
+	"#122",
+	"#123",
+	"#124",
+	"#125",
+	"#126",
+	"#127",
+	"#128",
+	"#129",
+	"#130",
+	"#131",
+	"#132",
+	"#133",
+	"#134",
+	"#135",
+	"#136",
+	"#137",
+	"#138",
+	"#139",
+	"#140",
+	"#141",
+	"#142",
+	"#143",
+	"#144",
+	"#145",
+	"#146",
+	"#147",
+	"#148",
+	"#149",
+	"#150",
+	"#151",
+	"#152",
+	"#153",
+	"#154",
+	"#155",
+	"#156",
+	"#157",
+	"#158",
+	"#159",
+	"#160",
+	"#161",
+	"#162",
+	"#163",
+	"#164",
+	"#165",
+	"#166",
+	"#167",
+	"#168",
+	"#169",
+	"#170",
+	"#171",
+	"#172",
+	"#173",
+	"#174",
+	"#175",
+	"#176",
+	"#177",
+	"#178",
+	"#179",
+	"#180",
+	"#181",
+	"#182",
+	"#183",
+	"#184",
+	"#185",
+	"#186",
+	"#187",
+	"#188",
+	"#189",
+	"#190",
+	"#191",
+	"#192",
+	"#193",
+	"#194",
+	"#195",
+	"#196",
+	"#197",
+	"#198",
+	"#199",
+	"#200",
+	"#201",
+	"#202",
+	"#203",
+	"#204",
+	"#205",
+	"#206",
+	"#207",
+	"#208",
+	"#209",
+	"#210",
+	"#211",
+	"#212",
+	"#213",
+	"#214",
+	"#215",
+	"#216",
+	"#217",
+	"#218",
+	"#219",
+	"#220",
+	"#221",
+	"#222",
+	"#223",
+	"#224",
+	"#225",
+	"#226",
+	"#227",
+	"#228",
+	"#229",
+	"#230",
+	"#231",
+	"#232",
+	"#233",
+	"#234",
+	"#235",
+	"#236",
+	"#237",
+	"#238",
+	"#239",
+	"#240",
+	"#241",
+	"#242",
+	"#243",
+	"#244",
+	"#245",
+	"#246",
+	"#247",
+	"#248",
+	"#249",
+	"#250",
+	"#251",
+	"#252",
+	"#253",
+	"#254",
+	"#255",
+};
+
+/*
+ * Dump IPv6 statistics structure.
+ */
+void
+ip6_stats(off, name)
+	u_long off;
+	char *name;
+{
+	struct ip6stat ip6stat;
+	register int i, first;
+
+	if (off == 0)
+		return;
+	kread(off, (char *)&ip6stat, sizeof (ip6stat));
+	printf("%s:\n", name);
+
+#define	p(f, m) if (ip6stat.f || sflag <= 1) \
+    printf(m, ip6stat.f, plural(ip6stat.f))
+
+	p(ip6s_total, "\t%lu total packet%s received\n");
+	for (first = 1, i = 0; i < 256; i++)
+		if (ip6stat.ip6s_inhist[i] != 0) {
+			if (first) {
+				printf("\tInput histogram:\n");
+				first = 0;
+			}
+			printf("\t\t%s: %lu\n", ip6names[i],
+			       ip6stat.ip6s_inhist[i]);
+		}
+	p(ip6s_toosmall, "\t%lu with size smaller than minimum\n");
+	p(ip6s_tooshort, "\t%lu with data size < data length\n");
+	p(ip6s_badvers, "\t%lu with incorrect version number\n");
+	p(ip6s_badsource, "\t%lu with illegal source\n");
+	p(ip6s_inomem, "\t%lu input packet%s without enough memory\n");
+	p(ip6s_fragments, "\t%lu fragment%s received\n");
+	p(ip6s_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
+	p(ip6s_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
+	p(ip6s_reassembled, "\t%lu packet%s reassembled ok\n");
+	p(ip6s_delivered, "\t%lu packet%s for this host\n");
+	p(ip6s_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
+	p(ip6s_forward, "\t%lu packet%s forwarded\n");
+	p(ip6s_cantforward, "\t%lu packet%s not forwardable\n");
+	p(ip6s_toobig, "\t%lu too big packet%s not forwarded\n");
+	p(ip6s_localout, "\t%lu packet%s sent from this host\n");
+	p(ip6s_rawout, "\t%lu packet%s sent with fabricated ipv6 header\n");
+	p(ip6s_odropped, "\t%lu output packet%s dropped due to no bufs\n");
+	p(ip6s_onomem, "\t%lu output packet%s without enough memory\n");
+	p(ip6s_noroute, "\t%lu output packet%s discarded due to no route\n");
+	p(ip6s_fragmented, "\t%lu output datagram%s fragmented\n");
+	p(ip6s_ofragments, "\t%lu fragment%s created\n");
+#undef p
+}
+
+static	char *icmp6names[] = {
+};
+
+/*
+ * Dump ICMPv6 statistics.
+ */
+void
+icmp6_stats(off, name)
+	u_long off;
+	char *name;
+{
+	struct icmp6stat icmp6stat;
+	register int i, first;
+
+	if (off == 0)
+		return;
+	kread(off, (char *)&icmp6stat, sizeof (icmp6stat));
+	printf("%s:\n", name);
+
+#define	p(f, m) if (icmp6stat.f || sflag <= 1) \
+    printf(m, icmp6stat.f, plural(icmp6stat.f))
+#define	ph(f, m) if (icmp6stat.f || sflag <= 1) \
+    printf(m, plural(icmp6stat.f), icmp6stat.f)
+
+	p(icp6s_error, "\t%lu call%s to icmp6_error\n");
+	p(icp6s_oldicmp,
+	    "\t%lu error%s not generated 'cuz old message was icmpv6\n");
+	printf("\tOutput histgram:\n");
+	ph(icp6s_snd_unreach, "\t\tunreachable%s: %lu\n");
+	ph(icp6s_snd_pkttoobig, "\t\tpacket too big%s: %lu\n");
+	ph(icp6s_snd_timxceed, "\t\ttime exceeded%s: %lu\n");
+	ph(icp6s_snd_paramprob, "\t\tparameter problem%s: %lu\n");
+	ph(icp6s_snd_redirect, "\t\tredirect%s: %lu\n");
+	ph(icp6s_snd_echoreq, "\t\techo request%s: %lu\n");
+	ph(icp6s_snd_echorep, "\t\techo replie%s: %lu\n");
+	ph(icp6s_snd_grpqry, "\t\tgroup querie%s: %lu\n");
+	ph(icp6s_snd_grprep, "\t\tgroup report%s: %lu\n");
+	ph(icp6s_snd_grpterm, "\t\tgroup termination%s: %lu\n");
+	ph(icp6s_snd_rtsol, "\t\trouter solicitation%s: %lu\n");
+	ph(icp6s_snd_rtadv, "\t\trouter advertisement%s: %lu\n");
+	ph(icp6s_snd_ndsol, "\t\tneighbor solicitation%s: %lu\n");
+	ph(icp6s_snd_ndadv, "\t\tneighbor advertisement%s: %lu\n");
+	p(icp6s_badcode, "\t%lu message%s with bad code fields\n");
+	p(icp6s_tooshort, "\t%lu message%s < minimum length\n");
+	p(icp6s_checksum, "\t%lu bad checksum%s\n");
+	p(icp6s_badlen, "\t%lu message%s with bad length\n");
+	printf("\tInput histogram:\n");
+	ph(icp6s_rcv_unreach, "\t\tunreachable%s: %lu\n");
+	ph(icp6s_rcv_pkttoobig, "\t\tpacket too big%s: %lu\n");
+	ph(icp6s_rcv_timxceed, "\t\ttime exceeded%s: %lu\n");
+	ph(icp6s_rcv_paramprob, "\t\tparameter problem%s: %lu\n");
+	ph(icp6s_rcv_echoreq, "\t\techo request%s: %lu\n");
+	ph(icp6s_rcv_echorep, "\t\techo replie%s: %lu\n");
+	ph(icp6s_rcv_grpqry, "\t\tgroup querie%s: %lu\n");
+	ph(icp6s_rcv_bad_grpqry, "\t\t\tbad group querie%s: %lu\n");
+	ph(icp6s_rcv_grprep, "\t\tgroup report%s: %lu\n");
+	ph(icp6s_rcv_bad_grprep, "\t\t\tbad group report%s: %lu\n");
+	ph(icp6s_rcv_our_grprep, "\t\t\tour groups' report%s: %lu\n");
+	ph(icp6s_rcv_grpterm, "\t\tgroup termination%s: %lu\n");
+	ph(icp6s_rcv_bad_grpterm, "\t\tbad group termination%s: %lu\n");
+	ph(icp6s_rcv_rtsol, "\t\trouter solicitation%s: %lu\n");
+	ph(icp6s_rcv_badrtsol, "\t\tbad router solicitation%s: %lu\n");
+	ph(icp6s_rcv_rtadv, "\t\trouter advertisement%s: %lu\n");
+	ph(icp6s_rcv_badrtadv, "\t\tbad router advertisement%s: %lu\n");
+	ph(icp6s_rcv_ndsol, "\t\tneighbor solicitation%s: %lu\n");
+	ph(icp6s_rcv_badndsol, "\t\tbad neighbor solicitation%s: %lu\n");
+	ph(icp6s_rcv_ndadv, "\t\tneighbor advertisement%s: %lu\n");
+	ph(icp6s_rcv_badndadv, "\t\tbad neighbor advertisement%s: %lu\n");
+	ph(icp6s_rcv_redirect, "\t\tredirect%s: %lu\n");
+	ph(icp6s_rcv_badredirect, "\t\tbad redirect%s: %lu\n");
+	p(icp6s_reflect, "\t%lu message response%s generated\n");
+#undef p
+#undef ph
+}
+
 /*
  * Pretty print an Internet address (net address + port).
  */
@@ -591,5 +1008,72 @@
 		sprintf(line, "%lu.%lu.%lu.%lu", C(inp->s_addr >> 24),
 		    C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
 	}
+	return (line);
+}
+
+/*
+ * Pretty print an IPv6 address (net address + port).
+ */
+void
+inet6print(in, port, type, proto, numeric)
+	register union in_addr_6 *in;
+	u_int16_t port;
+	u_int16_t type;
+	char *proto;
+	int numeric;
+{
+	struct servent *sp = 0;
+	char line[80], *cp;
+	int width;
+
+	if (type == IPATYPE_IPV4) {
+		inetprint(&in->in_addr_4.addr,
+			  port, proto, numeric);
+		return;
+	} else sprintf(line, "%.*s.", (Aflag && !numeric) ? 12 : 16,
+		       type == IPATYPE_UNBD ? "*" :
+		           inet6name(&in->addr6));
+	cp = index(line, '\0');
+	if (!numeric && port)
+		sp = getservbyport(port, proto);
+	if (sp || port == 0)
+		sprintf(cp, "%.15s", sp ? sp->s_name : "*");
+	else
+		sprintf(cp, "%d", ntohs(port));
+	width = Aflag ? 18 : 22;
+	printf(" %-*.*s", width, width, line);
+}
+
+/*
+ * Construct an IPv6 address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+char *
+inet6name(inp)
+	struct in6_addr *inp;
+{
+	register char *cp;
+	static char line[50];
+	struct hostent *hp;
+
+	cp = 0;
+	if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(inp)) {
+		if (cp == 0) {
+			hp = gethostbyaddr((char *)inp, 
+					   sizeof (*inp), 
+					   AF_INET6);
+			if (hp) {
+				cp = hp->h_name;
+				trimdomain(cp);
+			}
+		}
+	}
+	if (IN6_IS_ADDR_UNSPECIFIED(inp))
+		strcpy(line, "*");
+	else if (cp)
+		strcpy(line, cp);
+	else
+		return ((char *)inet_ntop(AF_INET6, inp, line, sizeof(line)));
 	return (line);
 }
diff -uN src-current/usr.bin/netstat/if.c src-current-ipv6/usr.bin/netstat/if.c
--- src-current/usr.bin/netstat/if.c
+++ src-current-ipv6/usr.bin/netstat/if.c
@@ -51,6 +51,7 @@
 #include <net/ethernet.h>
 #include <netinet/in.h>
 #include <netinet/in_var.h>
+#include <netinet/in6_var.h>
 #include <netipx/ipx.h>
 #include <netipx/ipx_if.h>
 #ifdef NS
@@ -89,6 +90,7 @@
 	union {
 		struct ifaddr ifa;
 		struct in_ifaddr in;
+		struct in6_ifaddr in6;
 		struct ipx_ifaddr ipx;
 #ifdef NS
 		struct ns_ifaddr ns;
@@ -116,8 +118,7 @@
 	ifnetaddr = (u_long)ifnethead.tqh_first;
 	if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
 		return;
-
-	printf("%-5.5s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
+	printf("%-5.5s %-5.5s %-11.11s %-15.15s %10.10s %5.5s",
 		"Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
 	if (bflag)
 		printf(" %10.10s","Ibytes");
@@ -155,8 +156,8 @@
 		printf("%-5.5s %-5lu ", name, ifnet.if_mtu);
 		ifaddrfound = ifaddraddr;
 		if (ifaddraddr == 0) {
-			printf("%-13.13s ", "none");
-			printf("%-15.15s ", "none");
+			printf("%-11.11s ", "none");
+			printf("%-17.17s ", "none");
 		} else {
 			if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) {
 				ifaddraddr = 0;
@@ -167,8 +168,8 @@
 				CP(&ifaddr); sa = (struct sockaddr *)cp;
 			switch (sa->sa_family) {
 			case AF_UNSPEC:
-				printf("%-13.13s ", "none");
-				printf("%-15.15s ", "none");
+				printf("%-11.11s ", "none");
+				printf("%-17.17s ", "none");
 				break;
 			case AF_INET:
 				sin = (struct sockaddr_in *)sa;
@@ -178,15 +179,27 @@
 				 */
 				in = inet_makeaddr(ifaddr.in.ia_subnet,
 					INADDR_ANY);
-				printf("%-13.13s ", netname(in.s_addr,
+				printf("%-11.11s ", netname(in.s_addr,
 				    ifaddr.in.ia_subnetmask));
 #else
-				printf("%-13.13s ",
+				printf("%-11.11s ",
 				    netname(htonl(ifaddr.in.ia_subnet),
 				    ifaddr.in.ia_subnetmask));
 #endif
-				printf("%-15.15s ",
+				printf("%-17.17s ",
 				    routename(sin->sin_addr.s_addr));
+
+				break;
+			case AF_INET6:
+				{
+				struct sockaddr_in6 *sin6 =
+				  (struct sockaddr_in6 *)sa;
+				char abuf[64];
+
+				printf("%-29.29s ",
+				       inet_ntop(AF_INET6, &sin6->sin6_addr,
+						 abuf, sizeof(abuf)));
+				}
 				break;
 			case AF_IPX:
 				{
@@ -199,7 +212,7 @@
 				sprintf(netnum, "%lx", ntohl(net));
 				printf("ipx:%-8s ", netnum);
 /*				printf("ipx:%-8s ", netname(net, 0L)); */
-				printf("%-15s ",
+				printf("%-17s ",
 				    ipx_phost((struct sockaddr *)sipx));
 				}
 				break;
@@ -219,20 +232,50 @@
 				*(union ns_net *) &net = sns->sns_addr.x_net;
 				sprintf(netnum, "%lxH", ntohl(net));
 				upHex(netnum);
-				printf("ns:%-8s ", netnum);
+				printf("ns:%-10s ", netnum);
 				printf("%-15s ",
 				    ns_phost((struct sockaddr *)sns));
 				}
 				break;
 #endif
+#ifdef ISO
+			case AF_ISO:
+				{
+				struct sockaddr_iso *siso =
+				  (struct sockaddr_iso *)sa;
+
+				printf("%-29.29s ",
+				       iso_ntoa(&siso->siso_addr));
+				}
+				break;
+#endif
 			case AF_LINK:
 				{
 				struct sockaddr_dl *sdl =
 					(struct sockaddr_dl *)sa;
-				    cp = (char *)LLADDR(sdl);
-				    n = sdl->sdl_alen;
+
+				m = printf("link#%d", sdl->sdl_index);
+				m = 12 - m;
+				while (m-- > 0)
+					putchar(' ');
+
+				if (sdl->sdl_type == IFT_ETHER ||
+				    sdl->sdl_type == IFT_FDDI) {
+				  cp = sdl->sdl_data + sdl->sdl_nlen;
+				  m = 0;
+				  for (n = 0; n < sdl->sdl_alen; n++)
+				    m += printf("%s%x",
+						n == 0 ? "" : ":",
+						(u_char)*cp++);
+				  m = 18 - m;
+				  while (m-- > 0)
+				  	putchar(' ');
+				  break;
+				}
+				cp = (char *)LLADDR(sdl);
+				n = sdl->sdl_alen;
+				m = 12;
 				}
-				m = printf("%-11.11s ", "<Link>");
 				goto hexprint;
 			default:
 				m = printf("(%d)", sa->sa_family);
@@ -274,9 +317,11 @@
 			union {
 				struct sockaddr sa;
 				struct sockaddr_in in;
+				struct sockaddr_in6 in6;
 				struct sockaddr_dl dl;
 			} msa;
 			const char *fmt;
+			char abuf[64];
 
 			for(multiaddr = (u_long)ifnet.if_multiaddrs.lh_first;
 			    multiaddr;
@@ -295,6 +340,11 @@
 				case AF_INET:
 					fmt = routename(msa.in.sin_addr.s_addr);
 					break;
+				case AF_INET6:
+					fmt = inet_ntop(AF_INET6,
+							&msa.in6.sin6_addr,
+							abuf, sizeof(abuf));
+					break;
 
 				case AF_LINK:
 					switch (ifnet.if_type) {
@@ -310,6 +360,132 @@
 				if (fmt)
 					printf("%23s %s\n", "", fmt);
 			}
+#if 0
+||||||| ./usr.bin/netstat/if.c-orig
+		    /*
+		     * Print family's multicast addresses
+		     */
+		    switch (sa->sa_family) {
+		    case AF_INET:
+			{
+			    u_long multiaddr;
+			    struct in_multi inm;
+
+			    multiaddr = (u_long)ifaddr.in.ia_multiaddrs.lh_first;
+			    while (multiaddr != 0) {
+				    kread(multiaddr, (char *)&inm,
+							sizeof inm);
+				    multiaddr = (u_long)inm.inm_entry.le_next;
+				    printf("%23s %s\n", "",
+					    routename(inm.inm_addr.s_addr));
+			    }
+			    break;
+			}
+		    case AF_LINK:
+			    switch (ifnet.if_type) {
+			    case IFT_ETHER:
+			    case IFT_FDDI:	/*XXX*/
+				{
+				    off_t multiaddr;
+				    struct arpcom ac;
+				    struct ether_multi enm;
+
+				    kread(ifnetfound, (char *)&ac, sizeof ac);
+				    multiaddr = (u_long)ac.ac_multiaddrs;
+				    while (multiaddr != 0) {
+					    kread(multiaddr, (char *)&enm,
+						    sizeof enm);
+					    multiaddr = (u_long)enm.enm_next;
+					    printf("%23s %s", "",
+						ether_ntoa(&enm.enm_addrlo));
+					    if (bcmp(&enm.enm_addrlo,
+						     &enm.enm_addrhi, 6) != 0)
+						printf(" to %s",
+						    ether_ntoa(&enm.enm_addrhi));
+					    printf("\n");
+				    }
+				    break;
+				}
+			    default:
+				    break;
+			    }
+		    default:
+			    break;
+		    }
+=======
+		    /*
+		     * Print family's multicast addresses
+		     */
+		    switch (sa->sa_family) {
+		    case AF_INET:
+			{
+			    u_long multiaddr;
+			    struct in_multi inm;
+
+			    multiaddr = (u_long)ifaddr.in.ia_multiaddrs.lh_first;
+			    while (multiaddr != 0) {
+				    kread(multiaddr, (char *)&inm,
+							sizeof inm);
+				    multiaddr = (u_long)inm.inm_entry.le_next;
+				    printf("%23s %s\n", "",
+					    routename(inm.inm_addr.s_addr));
+			    }
+			    break;
+			}
+		    case AF_INET6:
+			{
+			    u_long multiaddr;
+			    struct in6_multi inm;
+			    char abuf[64];
+
+			    if (ifnet.if_site6)
+				    printf("%23s site #%d\n", "",
+					   (int)ifnet.if_site6);
+			    ifnet.if_site6 = 0;
+
+			    multiaddr = (u_long)ifaddr.in6.ia_multiaddrs.lh_first;
+			    while (multiaddr != 0) {
+				    kread(multiaddr, (char *)&inm,
+							sizeof inm);
+				    multiaddr = (u_long)inm.inm6_entry.le_next;
+				    printf("%23s %s\n", "",
+					   inet_ntop(AF_INET6, &inm.inm6_addr,
+						     abuf, sizeof(abuf)));
+			    }
+			    break;
+			}
+		    case AF_LINK:
+			    switch (ifnet.if_type) {
+			    case IFT_ETHER:
+			    case IFT_FDDI:	/*XXX*/
+				{
+				    off_t multiaddr;
+				    struct arpcom ac;
+				    struct ether_multi enm;
+
+				    kread(ifnetfound, (char *)&ac, sizeof ac);
+				    multiaddr = (u_long)ac.ac_multiaddrs;
+				    while (multiaddr != 0) {
+					    kread(multiaddr, (char *)&enm,
+						    sizeof enm);
+					    multiaddr = (u_long)enm.enm_next;
+					    printf("%23s %s", "",
+						ether_ntoa(&enm.enm_addrlo));
+					    if (bcmp(&enm.enm_addrlo,
+						     &enm.enm_addrhi, 6) != 0)
+						printf(" to %s",
+						    ether_ntoa(&enm.enm_addrhi));
+					    printf("\n");
+				    }
+				    break;
+				}
+			    default:
+				    break;
+			    }
+		    default:
+			    break;
+		    }
+#endif
 		}
 	}
 }
diff -uN src-current/usr.bin/netstat/main.c src-current-ipv6/usr.bin/netstat/main.c
--- src-current/usr.bin/netstat/main.c
+++ src-current-ipv6/usr.bin/netstat/main.c
@@ -123,6 +123,16 @@
 	{ "_ddpstat"},
 #define N_DDPCB		27
 	{ "_ddpcb"},
+#define N_DIVPCB	28
+	{ "_divcb"},
+#define N_DIVSTAT	29
+	{ "_divstat"},
+#define	N_IP6STAT	30
+	{ "_ip6stat" },
+#define	N_ICMP6STAT	31
+	{ "_icmp6stat" },
+#define	N_IPV6MFC	32
+	{ "_mfc_tables" },
 	{ "" },
 };
 
@@ -151,6 +161,15 @@
 	  0,		0 }
 };
 
+struct protox v6protox[] = {
+	{ -1,		N_IP6STAT,	1,	0,
+	  ip6_stats,	"ipv6" },
+	{ -1,		N_ICMP6STAT,	1,	0,
+	  icmp6_stats,	"icmpv6" },
+	{ -1,		-1,		0,	0,
+	  0,		0 }
+};
+
 struct protox atalkprotox[] = {
 	{ N_DDPCB,	N_DDPSTAT,	1,	atalkprotopr,
 	  ddp_stats,	"ddp" },
@@ -195,7 +214,7 @@
 };
 #endif
 
-struct protox *protoprotox[] = { protox, ipxprotox, atalkprotox,
+struct protox *protoprotox[] = { protox, v6protox, ipxprotox, atalkprotox,
 #ifdef NS
 					 nsprotox, 
 #endif
@@ -248,6 +267,8 @@
 				af = AF_IPX;
 			else if (strcmp(optarg, "inet") == 0)
 				af = AF_INET;
+			else if (strcmp(optarg, "inet6") == 0)
+				af = AF_INET6;
 			else if (strcmp(optarg, "unix") == 0)
 				af = AF_UNIX;
 			else if (strcmp(optarg, "atalk") == 0)
@@ -404,7 +425,9 @@
 		exit(0);
 	}
 	if (gflag) {
-		if (sflag)
+		if (af == AF_INET6)
+			routepr(nl[N_IPV6MFC].n_value);
+		else if (sflag)
 			mrt_stats(nl[N_MRTPROTO].n_value,
 			    nl[N_MRTSTAT].n_value);
 		else
@@ -427,6 +450,9 @@
 		}
 		endprotoent();
 	}
+	if (af == AF_INET6 || af == AF_UNSPEC)
+		for (tp = v6protox; tp->pr_name; tp++)
+			printproto(tp, tp->pr_name);
 	if (af == AF_IPX || af == AF_UNSPEC)
 		for (tp = ipxprotox; tp->pr_name; tp++)
 			printproto(tp, tp->pr_name);
diff -uN src-current/usr.bin/netstat/netstat.1 src-current-ipv6/usr.bin/netstat/netstat.1
--- src-current/usr.bin/netstat/netstat.1
+++ src-current-ipv6/usr.bin/netstat/netstat.1
@@ -235,13 +235,18 @@
 C	RTF_CLONING	Generate new routes on use 
 c	RTF_PRCLONING	Protocol-specified generate new routes on use
 D	RTF_DYNAMIC	Created dynamically (by redirect) 
+e	RTF_BCE	Has a binding cache entry
 G	RTF_GATEWAY	Destination requires forwarding by intermediary
 H	RTF_HOST	Host entry (net otherwise) 
 L	RTF_LLINFO	Valid protocol to link address translation
+l	RTF_LOCAL	The route represents a local address
 M	RTF_MODIFIED	Modified dynamically (by redirect) 
+m	RTF_MULTICAST	The route represents a multicast address
+P	RTF_PINNED	Pinned route
 R	RTF_REJECT	Host or net unreachable 
 S	RTF_STATIC	Manually added 
 U	RTF_UP	Route usable 
+u	RTF_BUL	Has a binding update list
 W	RTF_WASCLONED	Route was generated as a result of cloning
 X	RTF_XRESOLVE	External daemon translates proto to link address
 .El
diff -uN src-current/usr.bin/netstat/netstat.h src-current-ipv6/usr.bin/netstat/netstat.h
--- src-current/usr.bin/netstat/netstat.h
+++ src-current-ipv6/usr.bin/netstat/netstat.h
@@ -66,6 +66,8 @@
 void	ip_stats __P((u_long, char *));
 void	icmp_stats __P((u_long, char *));
 void	igmp_stats __P((u_long, char *));
+void	ip6_stats __P((u_long, char *));
+void	icmp6_stats __P((u_long, char *));
 void	protopr __P((u_long, char *));
 
 void	mbpr __P((void));
@@ -119,4 +121,5 @@
 
 void	mroutepr __P((u_long, u_long, u_long));
 void	mrt_stats __P((u_long, u_long));
+int	prefix(void *, int);
 
diff -uN src-current/usr.bin/netstat/route.c src-current-ipv6/usr.bin/netstat/route.c
--- src-current/usr.bin/netstat/route.c
+++ src-current-ipv6/usr.bin/netstat/route.c
@@ -58,6 +58,11 @@
 #include <netns/ns.h>
 #endif
 
+#ifdef ISO
+#include <netiso/iso.h>
+#endif
+
+#include <arpa/inet.h>
 #include <sys/sysctl.h>
 
 #include <netdb.h>
@@ -89,13 +94,18 @@
 	{ RTF_XRESOLVE,	'X' },
 	{ RTF_LLINFO,	'L' },
 	{ RTF_STATIC,	'S' },
-	{ RTF_PROTO1,	'1' },
+	{ RTF_BLACKHOLE,'B' },
+	{ RTF_BUL,	'u' },
 	{ RTF_PROTO2,	'2' },
-	{ RTF_WASCLONED,'W' },
+	{ RTF_PROTO1,	'1' },
 	{ RTF_PRCLONING,'c' },
+	{ RTF_WASCLONED,'W' },
 	{ RTF_PROTO3,	'3' },
-	{ RTF_BLACKHOLE,'B' },
+	{ RTF_BCE,	'e' },
+	{ RTF_PINNED,	'P' },
+	{ RTF_LOCAL,	'l' },
 	{ RTF_BROADCAST,'b' },
+	{ RTF_MULTICAST,'m' },
 	{ 0 }
 };
 
@@ -104,10 +114,20 @@
 	u_short	u_data[128];
 } sa_u;
 
+/* Since this file will try to print IP, IPv6 and ISO routing table */
+union sockaddr_union {
+	struct sockaddr_in  in;
+	struct sockaddr_in6 in6;
+#ifdef ISO
+	struct sockaddr_iso iso;
+#endif;
+};
+
 static sa_u pt_u;
 
 int	do_rtent = 0;
 struct	rtentry rtentry;
+struct	mfcentry mfcentry;
 struct	radix_node rnode;
 struct	radix_mask rmask;
 struct	radix_node_head *rt_tables[AF_MAX+1];
@@ -119,9 +139,11 @@
 static void p_rtnode __P((void));
 static void ntreestuff __P((void));
 static void np_rtentry __P((struct rt_msghdr *));
-static void p_sockaddr __P((struct sockaddr *, struct sockaddr *, int, int));
+static void p_sockaddr __P((struct sockaddr *,
+	struct sockaddr *, int, int, int));
 static void p_flags __P((int, char *));
 static void p_rtentry __P((struct rtentry *));
+static void p_mfcentry __P((struct mfcentry *));
 static u_long forgemask __P((u_long));
 static void domask __P((char *, u_long, u_long));
 
@@ -135,7 +157,10 @@
 	struct radix_node_head *rnh, head;
 	int i;
 
-	printf("Routing tables\n");
+	if (gflag)
+		printf("Multicast Forwarding Cache Table\n");
+	else
+		printf("Routing tables\n");
 
 	if (Aflag == 0 && NewTree)
 		ntreestuff();
@@ -178,6 +203,9 @@
 	case AF_INET:
 		afname = "Internet";
 		break;
+	case AF_INET6:
+		afname = "IPv6";
+		break;
 	case AF_IPX:
 		afname = "IPX";
 		break;
@@ -215,12 +243,16 @@
 void
 pr_rthdr()
 {
+	if (gflag) {
+		 printf("\nGroup                      Source               \tFlags Use Queued Up-If  Down-If Hops\n");
+		return;
+	}
 	if (Aflag)
 		printf("%-8.8s ","Address");
-	printf("%-*.*s %-*.*s %-6.6s  %6.6s%8.8s  %8.8s %6s\n",
+	printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s%6.6s %6.6s %6s\n",
 		WID_DST, WID_DST, "Destination",
 		WID_GW, WID_GW, "Gateway",
-		"Flags", "Refs", "Use", "Netif", "Expire");
+		"Flags", "Refs", "Use", "Mtu", "Netif", "Expire");
 }
 
 static struct sockaddr *
@@ -249,13 +281,24 @@
 				printf("(root node)%s",
 				    rnode.rn_dupedkey ? " =>\n" : "\n");
 		} else if (do_rtent) {
-			kget(rn, rtentry);
-			p_rtentry(&rtentry);
+			struct sockaddr_in6 *sain;
+
+			sain = (struct sockaddr_in6 *)
+				kgetsa((struct sockaddr *)rnode.rn_key);
+			if (sain->sin6_family == AF_INET6 &&
+			    IS_MULTIADDR6(sain->sin6_addr) &&
+			    gflag) {
+				kget(rn, mfcentry);
+				p_mfcentry(&mfcentry);
+			} else if (!gflag) {
+				kget(rn, rtentry);
+				p_rtentry(&rtentry);
+			}
 			if (Aflag)
 				p_rtnode();
 		} else {
 			p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key),
-				   NULL, 0, 44);
+				   NULL, 0, 0, 44);
 			putchar('\n');
 		}
 		if ((rn = rnode.rn_dupedkey))
@@ -282,7 +325,7 @@
 		if (rnode.rn_mask) {
 			printf("\t  mask ");
 			p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask),
-				   NULL, 0, -1);
+				   NULL, 0, 0, -1);
 		} else if (rm == 0)
 			return;
 	} else {
@@ -299,10 +342,10 @@
 			printf(" <normal>, ");
 			kget(rmask.rm_leaf, rnode_aux);
 			p_sockaddr(kgetsa((struct sockaddr *)rnode_aux.rn_mask),
-				    NULL, 0, -1);
+				    NULL, 0, 0, -1);
 		} else
 		    p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask),
-				NULL, 0, -1);
+			        NULL, 0, 0, -1);
 		putchar('}');
 		if ((rm = rmask.rm_mklist))
 			printf(" ->");
@@ -323,8 +366,11 @@
 	mib[2] = 0;
 	mib[3] = 0;
 	mib[4] = NET_RT_DUMP;
-	mib[5] = 0;
-	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
+	if (af == AF_INET6 && gflag)
+		mib[5] = RTF_MULTICAST;
+	else
+		mib[5] = 0;
+        if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
 		err(1, "sysctl: net.route.0.0.dump estimate");
 	}
 
@@ -371,41 +417,55 @@
 		old_af = af;
 	}
 	if (rtm->rtm_addrs == RTA_DST)
-		p_sockaddr(sa, NULL, 0, 36);
+		p_sockaddr(sa, NULL, 0, 0, 36);
 	else {
-		p_sockaddr(sa, NULL, rtm->rtm_flags, 16);
+		p_sockaddr(sa, NULL, rtm->rtm_flags, 0, 16);
 		if (sa->sa_len == 0)
 			sa->sa_len = sizeof(long);
 		sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
-		p_sockaddr(sa, NULL, 0, 18);
+		p_sockaddr(sa, NULL, 0, 0, 18);
 	}
 	p_flags(rtm->rtm_flags & interesting, "%-6.6s ");
 	putchar('\n');
 }
 
 static void
-p_sockaddr(sa, mask, flags, width)
+p_sockaddr(sa, mask, flags, prlen, width)
 	struct sockaddr *sa, *mask;
-	int flags, width;
+	int flags, prlen, width;
 {
 	char workbuf[128], *cplim;
 	register char *cp = workbuf;
+	int iidx = 0;
 
 	switch(sa->sa_family) {
 	case AF_INET:
 	    {
 		register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
 
-		if (sin->sin_addr.s_addr == INADDR_ANY)
-			cp = "default";
-		else if (flags & RTF_HOST)
+		if (flags & RTF_HOST)
 			cp = routename(sin->sin_addr.s_addr);
-		else if (mask)
+		else if (mask && sin->sin_addr.s_addr && prlen == 0)
 			cp = netname(sin->sin_addr.s_addr,
 				     ntohl(((struct sockaddr_in *)mask)
 					   ->sin_addr.s_addr));
 		else
-			cp = netname(sin->sin_addr.s_addr, 0L);
+			cp = (sin->sin_addr.s_addr == 0 && prlen == 0) ?
+				"default" :
+				netname(sin->sin_addr.s_addr, INADDR_ANY);
+		break;
+	    }
+
+	case AF_INET6:
+	    {
+		register struct sockaddr_rt6 *sin6 = (struct sockaddr_rt6 *)sa;
+
+		iidx = sin6->sin6_local;
+		if ((flags & RTF_HOST) == 0 && prlen == 0)
+			cp = "default";
+		else
+			cp = (char *)inet_ntop(AF_INET6, &sin6->sin6_addr,
+					       workbuf, sizeof(workbuf));
 		break;
 	    }
 
@@ -432,6 +492,21 @@
 		break;
 #endif
 
+#ifdef ISO
+	case AF_ISO:
+	    {
+		register struct sockaddr_iso *siso = (struct sockaddr_iso *)sa;
+
+		if (siso->siso_nlen == 0 && siso->siso_data[0] != 0)
+			/* kludge for iso_ntoa !!! */
+			siso->siso_nlen = sizeof(siso->siso_data);
+		cp = iso_ntoa(&siso->siso_addr);
+		if (siso->siso_nlen == 0)
+			cp = "default";
+		break;
+	    }
+#endif
+
 	case AF_LINK:
 	    {
 		register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
@@ -443,6 +518,7 @@
 			switch (sdl->sdl_type) {
 
 			case IFT_ETHER:
+			case IFT_FDDI:
 			    {
 				register int i;
 				register u_char *lla = (u_char *)sdl->sdl_data +
@@ -479,13 +555,46 @@
 		cp = workbuf;
 	    }
 	}
-	if (width < 0 )
-		printf("%s ", cp);
-	else {
-		if (nflag)
+	if (width < 0 ) {
+		if (prlen) {
+			if (iidx)
+				printf("%d#%s/%d ", iidx, cp, prlen);
+			else
+				printf("%s/%d ", cp, prlen);
+		} else {
+			if (iidx)
+				printf("%d#%s ", iidx, cp);
+			else
+				printf("%s ", cp);
+		}
+	} else {
+		if (iidx) {
+			char idxbuf[8];
+
+			sprintf(idxbuf, "%d#", iidx);
+			iidx = strlen(idxbuf);
+			printf("%s", idxbuf);
+			width -= iidx;
+		}
+		if (nflag) {
+			if (prlen)
+				sprintf(cp + strlen(cp), "/%d", prlen);
 			printf("%-*s ", width, cp);
-		else
+		} else {
+			if (prlen) {
+				int len0, len1;
+
+				len0 = strlen(cp);
+				cplim = workbuf + sizeof(workbuf) - 6;
+				len1 = snprintf(cplim, 5, "/%d", prlen);
+				cplim[len1] = 0;
+				if (len0 + len1 > width)
+					strcpy(cp + width - len1, cplim);
+				else
+					strcpy(cp + len0, cplim);
+			}
 			printf("%-*.*s ", width, width, cp);
+		}
 	}
 }
 
@@ -508,11 +617,12 @@
 p_rtentry(rt)
 	register struct rtentry *rt;
 {
-	static struct ifnet ifnet, *lastif;
+	static struct ifnet ifnet, *lastif = 0;
 	static char name[16];
 	static char prettyname[9];
-	struct sockaddr *sa;
-	sa_u addr, mask;
+	struct sockaddr *rts, *rtsm = NULL;
+	union sockaddr_union addr, mask;
+	int prlen;
 
 	/*
 	 * Don't print protocol-cloned routes unless -a.
@@ -520,25 +630,73 @@
 	if (rt->rt_parent && !aflag)
 		return;
 
-	bzero(&addr, sizeof addr);
-	if ((sa = kgetsa(rt_key(rt))))
-		bcopy(sa,&addr,sa->sa_len);
-
-	bzero(&mask, sizeof mask);
-	if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt))))
-		bcopy(sa,&mask,sa->sa_len);
-
-	p_sockaddr(&addr, &mask, rt->rt_flags, WID_DST);
-	p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, WID_GW);
+	if (rt->rt_flags & RTF_HOST || rt_mask(rt) == NULL)
+		prlen = 0;
+	else {
+		rts = kgetsa(rt_key(rt));
+		if (rts) switch (rts->sa_family) {
+		case AF_INET:
+		    {
+			struct sockaddr_in *sin;
+
+			rtsm = kgetsa(rt_mask(rt));
+			sin = (struct sockaddr_in *)rtsm;
+			prlen = prefix((char *)&sin->sin_addr,
+				       sizeof(struct in_addr));
+			break;
+		    }
+		case AF_INET6:
+		    {
+			struct sockaddr_in6 *sin6;
+
+			rtsm = kgetsa(rt_mask(rt));
+			sin6 = (struct sockaddr_in6 *)rtsm;
+			prlen = prefix((char *)&sin6->sin6_addr,
+				       sizeof(struct in6_addr));
+			break;
+		    }
+#ifdef ISO
+		case AF_ISO:
+		    {
+			struct sockaddr_iso *siso;
+
+			rtsm = kgetsa(rt_mask(rt));
+			siso = (struct sockaddr_iso *)rtsm;
+			prlen = prefix(&siso->siso_data,
+				    siso->siso_nlen ?
+				    siso->siso_nlen : sizeof(siso->siso_data));
+			break;
+		    }
+#endif
+		default:
+		    prlen = 0;
+		    break;
+		}
+	}
+	bzero(&addr, sizeof(addr));
+	if ((rts = kgetsa(rt_key(rt))))
+		addr = *(union sockaddr_union *)rts;
+	bzero(&mask, sizeof(mask));
+	if (rtsm)
+		mask = *(union sockaddr_union *)rtsm;
+
+	p_sockaddr((struct sockaddr *)&addr,
+		   (struct sockaddr *)&mask,
+		   rt->rt_flags, prlen, WID_DST);
+	p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, 0, WID_GW);
 	p_flags(rt->rt_flags, "%-6.6s ");
-	printf("%6d %8ld ", rt->rt_refcnt, rt->rt_use);
+	printf("%5d %8ld ", rt->rt_refcnt, rt->rt_use);
+	if (rt->rt_rmx.rmx_mtu)
+		printf("%5d", rt->rt_rmx.rmx_mtu);
+	else
+		printf("%5s", "-");
 	if (rt->rt_ifp) {
 		if (rt->rt_ifp != lastif) {
 			kget(rt->rt_ifp, ifnet);
 			kread((u_long)ifnet.if_name, name, 16);
 			lastif = rt->rt_ifp;
 			snprintf(prettyname, sizeof prettyname,
-				 "%.6s%d", name, ifnet.if_unit);
+				 "%.5s%d", name, ifnet.if_unit);
 		}
 		printf("%8.8s", prettyname);
 		if (rt->rt_rmx.rmx_expire) {
@@ -666,7 +824,6 @@
 	else
 		sprintf(line, "%lu.%lu.%lu.%lu", C(i >> 24),
 			C(i >> 16), C(i >> 8), C(i));
-	domask(line+strlen(line), i, omask);
 	return (line);
 }
 
@@ -876,3 +1033,82 @@
 			break;
 		}
 }
+
+int
+prefix(val, size)
+	void *val;
+	int size;
+{
+	register u_char *name = (u_char *)val;
+	register int byte, bit, plen = 0;
+
+	for (byte = 0; byte < size; byte++, plen += 8)
+		if (name[byte] != 0xff)
+			break;
+	for (bit = 7; bit != 0; bit--, plen++)
+		if (!(name[byte] & (1 << bit)))
+			break;
+	for (; bit != 0; bit--)
+		if (name[byte] & (1 << bit))
+			return(0);
+	byte++;
+	for (; byte < size; byte++)
+		if (name[byte])
+			return(0);
+	return (plen);
+}
+
+static void
+p_mfcentry(mfc)
+	register struct mfcentry *mfc;
+{       
+        int     size;
+        char    ifstring[5], name[5], v[64];
+        caddr_t cp;
+        struct  ifnet ifp;   
+        struct  ds_ifaddr *dsp, dsifp;
+        struct  in6_addr dst, src;
+        struct  sockaddr_in6 *sa_in6;
+            
+        sa_in6 = (struct sockaddr_in6 *) kgetsa(mfc_key(mfc));
+        cp = (caddr_t) &sa_in6->sin6_addr;
+        bcopy(cp, &dst, sizeof(dst));
+        cp += sizeof(dst);
+        bcopy(cp, &src, sizeof(src));
+
+        if (mfc->upstream_ifp) {
+            kget(mfc->upstream_ifp, ifp);
+            kget(ifp.if_name, name);
+            sprintf(ifstring, "%s%d ", name, ifp.if_unit);
+        } else {
+            ifstring[0] = '\0';
+        }
+        printf("%s  ", inet_ntop(AF_INET6, &dst, v, sizeof(v)));      
+        printf("%s \t", inet_ntop(AF_INET6, &src, v, sizeof(v)));
+        p_flags(mfc->mfc_flags, "%-4.4s ");
+        printf("%6u ", mfc->mfc_use);
+        
+        if (mfc->mfc_tail == mfc->mfc_head && mfc->packet_q[mfc->mfc_head]) {
+                size = MFC_PACKET_Q_SIZE;
+        } else {
+                size = mfc->mfc_tail - mfc->mfc_head;
+                if (size < 0)
+                        size += MFC_PACKET_Q_SIZE;
+        }
+        printf("%6d ", size);
+
+        printf("%-7s", ifstring);
+        dsp = mfc->ds_list;
+        while (dsp) {
+                kget(dsp, dsifp);
+                kget(dsifp.ds_ifp, ifp);
+                kget(ifp.if_name, name);
+                sprintf(ifstring, "%s%d ", name, ifp.if_unit);
+                printf("%-8s %d", ifstring, dsifp.min_hoplimit);
+                dsp = dsifp.ds_next;
+		if (dsp)
+                        printf("\n%-*s", 82, " ");
+        }
+        putchar('\n'); 
+}       
+
diff -uN src-current/usr.bin/rdist/main.c src-current-ipv6/usr.bin/rdist/main.c
--- src-current/usr.bin/rdist/main.c
+++ src-current-ipv6/usr.bin/rdist/main.c
@@ -43,6 +43,7 @@
 #endif /* not lint */
 
 #include "defs.h"
+#include <resolv.h>
 
 #define NHOSTS 100
 
@@ -94,6 +95,8 @@
 	strcpy(user, pw->pw_name);
 	strcpy(homedir, pw->pw_dir);
 	groupid = pw->pw_gid;
+	(void) res_init();
+	_res.options |= RES_USE_INET6;
 	gethostname(host, sizeof(host));
 	strcpy(tempfile, _PATH_TMP);
 	strcat(tempfile, _RDIST_TMP);
diff -uN src-current/usr.bin/rlogin/rlogin.c src-current-ipv6/usr.bin/rlogin/rlogin.c
--- src-current/usr.bin/rlogin/rlogin.c
+++ src-current-ipv6/usr.bin/rlogin/rlogin.c
@@ -71,6 +71,8 @@
 #include <unistd.h>
 #include <err.h>
 
+#include <resolv.h>
+
 #ifdef KERBEROS
 #include <des.h>
 #include <krb.h>
@@ -234,6 +236,14 @@
 	if (!user)
 		user = pw->pw_name;
 
+#ifdef RES_USE_INET6
+	(void) res_init();
+#ifdef KERBEROS
+	if (!use_kerberos)	/* kerberos not yet IPv6 */
+#endif
+		_res.options |= RES_USE_INET6;
+#endif
+
 	sp = NULL;
 #ifdef KERBEROS
 	if (use_kerberos) {
@@ -334,6 +344,7 @@
 		warn("setsockopt NODELAY (ignored)");
 
 	one = IPTOS_LOWDELAY;
+	/* should be IPV6_PRIORITY_INTERACTIVE in IPv6 */
 	if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0)
 		warn("setsockopt TOS (ignored)");
 
diff -uN src-current/usr.bin/rpcinfo/rpcinfo.8 src-current-ipv6/usr.bin/rpcinfo/rpcinfo.8
--- src-current/usr.bin/rpcinfo/rpcinfo.8
+++ src-current-ipv6/usr.bin/rpcinfo/rpcinfo.8
@@ -25,6 +25,9 @@
 .Fl b
 .Ar program version
 .Nm rpcinfo
+.Fl m
+.Ar program version
+.Nm rpcinfo
 .Fl d
 .Ar program version
 .Sh DESCRIPTION
@@ -77,6 +80,16 @@
 Make an
 .Tn RPC
 broadcast to procedure 0 of the specified
+.Ar program
+and
+.Ar version
+using
+.Tn UDP
+and report all hosts that respond.
+.It Fl m
+Make an
+.Tn RPC
+multicast to address IPv6 ff02::1 and to procedure 0 of the specified
 .Ar program
 and
 .Ar version
diff -uN src-current/usr.bin/rpcinfo/rpcinfo.c src-current-ipv6/usr.bin/rpcinfo/rpcinfo.c
--- src-current/usr.bin/rpcinfo/rpcinfo.c
+++ src-current-ipv6/usr.bin/rpcinfo/rpcinfo.c
@@ -45,6 +45,10 @@
 
 #include <err.h>
 #include <ctype.h>
+/*
+ * ipv6 rpc : use base address type struct sockaddr_in6 *  in rpc includes
+ */
+#define RPC_USE_INET6	/*  address type is struct sockaddr_in6 *  */
 #include <rpc/rpc.h>
 #include <stdio.h>
 #include <sys/socket.h>
@@ -52,6 +56,7 @@
 #include <rpc/pmap_prot.h>
 #include <rpc/pmap_clnt.h>
 #include <signal.h>
+#include <resolv.h>
 
 #define MAXHOSTLEN 256
 
@@ -62,13 +67,13 @@
 static void	tcpping(/*u_short portflag, int argc, char **argv*/);
 static int	pstatus(/*CLIENT *client, u_long prognum, u_long vers*/);
 static void	pmapdump(/*int argc, char **argv*/);
-static bool_t	reply_proc(/*void *res, struct sockaddr_in *who*/);
+static bool_t	reply_proc(/*void *res, struct sockaddr *who*/);
 static void	brdcst(/*int argc, char **argv*/);
 static void	deletereg(/* int argc, char **argv */) ;
 static void	usage(/*void*/);
 static u_long	getprognum(/*char *arg*/);
 static u_long	getvers(/*char *arg*/);
-static void	get_inet_address(/*struct sockaddr_in *addr, char *host*/);
+static void	get_inet_address(/*struct sockaddr_in6 *addr, char *host*/);
 extern u_long inet_addr();  /* in 4.2BSD, arpa/inet.h called that a in_addr */
 extern char *inet_ntoa();
 
@@ -93,11 +98,12 @@
 	int errflg;
 	int function;
 	u_short portnum;
+	int usev4 = 0;
 
 	function = NONE;
 	portnum = 0;
 	errflg = 0;
-	while ((c = getopt(argc, argv, "ptubdn:")) != -1) {
+	while ((c = getopt(argc, argv, "ptubmdn:")) != -1) {
 		switch (c) {
 
 		case 'p':
@@ -122,6 +128,8 @@
 			break;
 
 		case 'b':
+			usev4 = 1;
+		case 'm':
 			if (function != NONE)
 				errflg = 1;
 			else
@@ -149,6 +157,10 @@
 		return (1);
 	}
 
+	(void)res_init();
+	if (!usev4)
+		_res.options |= RES_USE_INET6;
+
 	switch (function) {
 
 	case PMAPDUMP:
@@ -190,7 +202,7 @@
 	char **argv;
 {
 	struct timeval to;
-	struct sockaddr_in addr;
+	struct sockaddr_in6 addr;
 	enum clnt_stat rpc_stat;
 	CLIENT *client;
 	u_long prognum, vers, minvers, maxvers;
@@ -205,7 +217,7 @@
 	prognum = getprognum(argv[1]);
 	get_inet_address(&addr, argv[0]);
 	/* Open the socket here so it will survive calls to clnt_destroy */
-	sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	sock = socket( AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
 	if (sock < 0) {
 		perror("rpcinfo: socket");
 		exit(1);
@@ -216,7 +228,7 @@
 		 * A call to version 0 should fail with a program/version
 		 * mismatch, and give us the range of versions supported.
 		 */
-		addr.sin_port = htons(portnum);
+		addr.sin6_port = htons(portnum);
 		to.tv_sec = 5;
 		to.tv_usec = 0;
 		if ((client = clntudp_create(&addr, prognum, (u_long)0,
@@ -239,7 +251,7 @@
 			 * Oh dear, it DOES support version 0.
 			 * Let's try version MAX_VERS.
 			 */
-			addr.sin_port = htons(portnum);
+			addr.sin6_port = htons(portnum);
 			to.tv_sec = 5;
 			to.tv_usec = 0;
 			if ((client = clntudp_create(&addr, prognum, MAX_VERS,
@@ -276,7 +288,7 @@
 		}
 		clnt_destroy(client);
 		for (vers = minvers; vers <= maxvers; vers++) {
-			addr.sin_port = htons(portnum);
+			addr.sin6_port = htons(portnum);
 			to.tv_sec = 5;
 			to.tv_usec = 0;
 			if ((client = clntudp_create(&addr, prognum, vers,
@@ -297,7 +309,7 @@
 	}
 	else {
 		vers = getvers(argv[2]);
-		addr.sin_port = htons(portnum);
+		addr.sin6_port = htons(portnum);
 		to.tv_sec = 5;
 		to.tv_usec = 0;
 		if ((client = clntudp_create(&addr, prognum, vers,
@@ -326,7 +338,7 @@
 	char **argv;
 {
 	struct timeval to;
-	struct sockaddr_in addr;
+	struct sockaddr_in6 addr;
 	enum clnt_stat rpc_stat;
 	CLIENT *client;
 	u_long prognum, vers, minvers, maxvers;
@@ -346,7 +358,7 @@
 		 * A call to version 0 should fail with a program/version
 		 * mismatch, and give us the range of versions supported.
 		 */
-		addr.sin_port = htons(portnum);
+		addr.sin6_port = htons(portnum);
 		if ((client = clnttcp_create(&addr, prognum, MIN_VERS,
 		    &sock, 0, 0)) == NULL) {
 			clnt_pcreateerror("rpcinfo");
@@ -367,7 +379,7 @@
 			 * Oh dear, it DOES support version 0.
 			 * Let's try version MAX_VERS.
 			 */
-			addr.sin_port = htons(portnum);
+			addr.sin6_port = htons(portnum);
 			if ((client = clnttcp_create(&addr, prognum, MAX_VERS,
 			    &sock, 0, 0)) == NULL) {
 				clnt_pcreateerror("rpcinfo");
@@ -404,7 +416,7 @@
 		(void) close(sock);
 		sock = RPC_ANYSOCK; /* Re-initialize it for later */
 		for (vers = minvers; vers <= maxvers; vers++) {
-			addr.sin_port = htons(portnum);
+			addr.sin6_port = htons(portnum);
 			if ((client = clnttcp_create(&addr, prognum, vers,
 			    &sock, 0, 0)) == NULL) {
 				clnt_pcreateerror("rpcinfo");
@@ -425,7 +437,7 @@
 	}
 	else {
 		vers = getvers(argv[2]);
-		addr.sin_port = htons(portnum);
+		addr.sin6_port = htons(portnum);
 		if ((client = clnttcp_create(&addr, prognum, vers, &sock,
 		    0, 0)) == NULL) {
 			clnt_pcreateerror("rpcinfo");
@@ -477,7 +489,7 @@
 	int argc;
 	char **argv;
 {
-	struct sockaddr_in server_addr;
+	struct sockaddr_in6 server_addr;
 	register struct hostent *hp;
 	struct pmaplist *head = NULL;
 	int socket = RPC_ANYSOCK;
@@ -491,18 +503,11 @@
 	}
 	if (argc == 1)
 		get_inet_address(&server_addr, argv[0]);
-	else {
-		bzero((char *)&server_addr, sizeof server_addr);
-		server_addr.sin_family = AF_INET;
-		if ((hp = gethostbyname("localhost")) != NULL)
-			bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
-			    hp->h_length);
-		else
-			server_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
-	}
+	else
+		get_myaddress(&server_addr);
 	minutetimeout.tv_sec = 60;
 	minutetimeout.tv_usec = 0;
-	server_addr.sin_port = htons(PMAPPORT);
+	server_addr.sin6_port = htons(PMAPPORT);
 	if ((client = clnttcp_create(&server_addr, PMAPPROG,
 	    PMAPVERS, &socket, 50, 500)) == NULL) {
 		clnt_pcreateerror("rpcinfo: can't contact portmapper");
@@ -548,14 +553,24 @@
 static bool_t
 reply_proc(res, who)
 	void *res;		/* Nothing comes back */
-	struct sockaddr_in *who; /* Who sent us the reply */
+	struct sockaddr_in6 *who; /* Who sent us the reply */
 {
 	register struct hostent *hp;
+	char *addr;
+	char vb[INET6_ADDRSTRLEN];	/* buffer for Vixie's inet_ntop */
 
-	hp = gethostbyaddr((char *) &who->sin_addr, sizeof who->sin_addr,
-	    AF_INET);
-	printf("%s %s\n", inet_ntoa(who->sin_addr),
-	    (hp == NULL) ? "(unknown)" : hp->h_name);
+	addr = who->sin6_family == AF_INET6 ?
+		(char *)&who->sin6_addr :
+		(char *)&((struct sockaddr_in*)who)->sin_addr;
+
+	hp = gethostbyaddr(addr,
+			   who->sin6_family == AF_INET6 ?
+				sizeof(struct in6_addr) :
+				sizeof(struct in_addr),
+			   who->sin6_family);
+	printf("%s %s\n",
+	       inet_ntop(who->sin6_family, addr, vb, sizeof(vb)),
+	       (hp == NULL) ? "(unknown)" : hp->h_name);
 	return(FALSE);
 }
 
@@ -605,11 +620,12 @@
 static void
 usage()
 {
-	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
+	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n",
 		"usage: rpcinfo [-n portnum] -u host prognum [versnum]",
 		"       rpcinfo [-n portnum] -t host prognum [versnum]",
 		"       rpcinfo -p [host]",
 		"       rpcinfo -b prognum versnum",
+		"       rpcinfo -m prognum versnum (multicast IPv6)",
 		"       rpcinfo -d prognum versnum");
 }
 
@@ -644,17 +660,21 @@
 
 static void
 get_inet_address(addr, host)
-	struct sockaddr_in *addr;
+	struct sockaddr_in6 *addr;
 	char *host;
 {
 	register struct hostent *hp;
 
 	bzero((char *)addr, sizeof *addr);
-	addr->sin_addr.s_addr = (u_long) inet_addr(host);
-	if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
-		if ((hp = gethostbyname(host)) == NULL)
-			errx(1, "%s is unknown host", host);
-		bcopy(hp->h_addr, (char *)&addr->sin_addr, hp->h_length);
-	}
-	addr->sin_family = AF_INET;
+	if ((hp = gethostbyname(host)) == NULL)
+		errx(1, "%s is unknown host\n", host);
+	addr->sin6_family = hp->h_addrtype;
+	addr->sin6_len = hp->h_addrtype == AF_INET6 ?
+				sizeof(struct sockaddr_in6) :
+				sizeof(struct sockaddr_in);
+	bcopy(hp->h_addr,
+	      hp->h_addrtype == AF_INET6 ?
+		(char *)&addr->sin6_addr :
+		(char *)&((struct sockaddr_in*)addr)->sin_addr,
+	      hp->h_length);
 }
diff -uN src-current/usr.bin/rsh/rsh.c src-current-ipv6/usr.bin/rsh/rsh.c
--- src-current/usr.bin/rsh/rsh.c
+++ src-current-ipv6/usr.bin/rsh/rsh.c
@@ -64,6 +64,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <err.h>
+#include <resolv.h>
 
 #include "pathnames.h"
 
@@ -194,6 +195,14 @@
 		errx(1, "unknown user id");
 	if (!user)
 		user = pw->pw_name;
+
+#ifdef RES_USE_INET6
+	(void) res_init();
+#ifdef KERBEROS
+	if (!use_kerberos)	/* kerberos not yet IPv6 */
+#endif
+		_res.options |= RES_USE_INET6;
+#endif
 
 #ifdef KERBEROS
 #ifdef CRYPT
diff -uN src-current/usr.bin/rusers/rusers.c src-current-ipv6/usr.bin/rusers/rusers.c
--- src-current/usr.bin/rusers/rusers.c
+++ src-current-ipv6/usr.bin/rusers/rusers.c
@@ -39,16 +39,22 @@
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/socket.h>
+#include <netinet/in.h>
 #include <err.h>
 #include <netdb.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <strings.h>
 #include <unistd.h>
+/*
+ * ipv6 rpc : use base address type struct sockaddr_in6 *  in rpc includes
+ */
+#define RPC_USE_INET6	/*  address type is struct sockaddr_in6 *  */
 #include <rpc/rpc.h>
 #include <rpc/pmap_clnt.h>
 #include <arpa/inet.h>
 #include <rpcsvc/rnusers.h>
+#include <resolv.h>
 
 #define MAX_INT 0x7fffffff
 #define HOST_WIDTH 20
@@ -59,11 +65,11 @@
 
 struct host_list {
 	struct host_list *next;
-	struct in_addr addr;
+	struct in6_addr addr;
 } *hosts;
 
 int
-search_host(struct in_addr addr)
+search_host(struct in6_addr *addr)
 {
 	struct host_list *hp;
 
@@ -71,119 +77,127 @@
 		return(0);
 
 	for (hp = hosts; hp != NULL; hp = hp->next) {
-		if (hp->addr.s_addr == addr.s_addr)
+		if (IN6_ARE_ADDR_EQUAL(&hp->addr, addr))
 			return(1);
 	}
 	return(0);
 }
 
 void
-remember_host(struct in_addr addr)
+remember_host(struct in6_addr *addr)
 {
 	struct host_list *hp;
 
 	if (!(hp = (struct host_list *)malloc(sizeof(struct host_list))))
 		errx(1, "no memory");
-	hp->addr.s_addr = addr.s_addr;
+	bcopy(addr, &hp->addr, sizeof *addr);
 	hp->next = hosts;
 	hosts = hp;
 }
 
 int
-rusers_reply(char *replyp, struct sockaddr_in *raddrp)
+rusers_reply(char *replyp, struct sockaddr_in6 *raddrp)
 {
-        int x, idle;
-        char date[32], idle_time[64], remote[64];
-        struct hostent *hp;
-        utmpidlearr *up = (utmpidlearr *)replyp;
-        char *host;
-        int days, hours, minutes, seconds;
-
-	if (search_host(raddrp->sin_addr))
+	int x, idle;
+	char date[32], idle_time[64], remote[64];
+	struct hostent *hp;
+	utmpidlearr *up = (utmpidlearr *)replyp;
+	const char *host;
+	int days, hours, minutes, seconds;
+	char vb[INET6_ADDRSTRLEN];       /* buffer for Vixie's inet_ntop */
+
+	if (raddrp->sin6_family == AF_INET) {
+		raddrp->sin6_family = AF_INET6;
+		bcopy(&((struct sockaddr_in*)raddrp)->sin_addr,
+			&raddrp->sin6_addr.s6_addr[16-4], 4);
+		memset(&raddrp->sin6_addr.s6_addr[16-4-2], -1, 2);
+		bzero(&raddrp->sin6_addr.s6_addr[0], 16-4-2);
+	}
+	if (search_host(&raddrp->sin6_addr))
 		return(0);
 
-        if (!allopt && !up->utmpidlearr_len)
-                return(0);
+	if (!allopt && !up->utmpidlearr_len)
+		return(0);
 
-        hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr,
-                           sizeof(struct in_addr), AF_INET);
-        if (hp)
-                host = hp->h_name;
-        else
-                host = inet_ntoa(raddrp->sin_addr);
-
-        if (!longopt)
-                printf("%-*s ", HOST_WIDTH, host);
-
-        for (x = 0; x < up->utmpidlearr_len; x++) {
-                strncpy(date,
-                        &(ctime((time_t *)&(up->utmpidlearr_val[x].ui_utmp.ut_time))[4]),
-                        sizeof(date)-1);
-
-                idle = up->utmpidlearr_val[x].ui_idle;
-                sprintf(idle_time, "  :%02d", idle);
-                if (idle == MAX_INT)
-                        strcpy(idle_time, "??");
-                else if (idle == 0)
-                        strcpy(idle_time, "");
-                else {
-                        seconds = idle;
-                        days = seconds/(60*60*24);
-                        seconds %= (60*60*24);
-                        hours = seconds/(60*60);
-                        seconds %= (60*60);
-                        minutes = seconds/60;
-                        seconds %= 60;
-                        if (idle > 60)
-                                sprintf(idle_time, "%d:%02d",
-                                        minutes, seconds);
-                        if (idle >= (60*60))
-                                sprintf(idle_time, "%d:%02d:%02d",
-                                        hours, minutes, seconds);
-                        if (idle >= (24*60*60))
-                                sprintf(idle_time, "%d days, %d:%02d:%02d",
-                                        days, hours, minutes, seconds);
-                }
-
-                strncpy(remote, up->utmpidlearr_val[x].ui_utmp.ut_host, sizeof(remote)-1);
-                if (strlen(remote) != 0)
-                        sprintf(remote, "(%.16s)", up->utmpidlearr_val[x].ui_utmp.ut_host);
-
-                if (longopt)
-                        printf("%-8.8s %*s:%-*.*s %-12.12s  %6s %.18s\n",
-                               up->utmpidlearr_val[x].ui_utmp.ut_name,
-                               HOST_WIDTH, host,
-                               LINE_WIDTH, LINE_WIDTH, up->utmpidlearr_val[x].ui_utmp.ut_line,
-                               date,
-                               idle_time,
-                               remote
-                               );
-                else
-                        printf("%s ",
-                               up->utmpidlearr_val[x].ui_utmp.ut_name);
-        }
-        if (!longopt)
-                putchar('\n');
+	hp = gethostbyaddr((char *)&raddrp->sin6_addr,
+			   sizeof(struct in6_addr), AF_INET6);
+	if (hp)
+		host = hp->h_name;
+	else
+		host = inet_ntop(AF_INET6, &raddrp->sin6_addr, vb, sizeof vb);
+
+	if (!longopt)
+		printf("%-*s ", HOST_WIDTH, host);
+
+	for (x = 0; x < up->utmpidlearr_len; x++) {
+		strncpy(date,
+			&(ctime((time_t *)&(up->utmpidlearr_val[x].ui_utmp.ut_time))[4]),
+			sizeof(date)-1);
+
+		idle = up->utmpidlearr_val[x].ui_idle;
+		sprintf(idle_time, "  :%02d", idle);
+		if (idle == MAX_INT)
+			strcpy(idle_time, "??");
+		else if (idle == 0)
+			strcpy(idle_time, "");
+		else {
+			seconds = idle;
+			days = seconds/(60*60*24);
+			seconds %= (60*60*24);
+			hours = seconds/(60*60);
+			seconds %= (60*60);
+			minutes = seconds/60;
+			seconds %= 60;
+			if (idle > 60)
+				sprintf(idle_time, "%d:%02d",
+					minutes, seconds);
+			if (idle >= (60*60))
+				sprintf(idle_time, "%d:%02d:%02d",
+					hours, minutes, seconds);
+			if (idle >= (24*60*60))
+				sprintf(idle_time, "%d days, %d:%02d:%02d",
+					days, hours, minutes, seconds);
+		}
+
+		strncpy(remote, up->utmpidlearr_val[x].ui_utmp.ut_host, sizeof(remote)-1);
+		if (strlen(remote) != 0)
+			sprintf(remote, "(%.16s)", up->utmpidlearr_val[x].ui_utmp.ut_host);
+
+		if (longopt)
+			printf("%-8.8s %*s:%-*.*s %-12.12s  %6s %.18s\n",
+			       up->utmpidlearr_val[x].ui_utmp.ut_name,
+			       HOST_WIDTH, host,
+			       LINE_WIDTH, LINE_WIDTH, up->utmpidlearr_val[x].ui_utmp.ut_line,
+			       date,
+			       idle_time,
+			       remote
+			       );
+		else
+			printf("%s ",
+			       up->utmpidlearr_val[x].ui_utmp.ut_name);
+	}
+	if (!longopt)
+		putchar('\n');
 
-	remember_host(raddrp->sin_addr);
+	remember_host(&raddrp->sin6_addr);
 	return(0);
 }
 
 void
 onehost(char *host)
 {
-        utmpidlearr up;
-        CLIENT *rusers_clnt;
-        struct sockaddr_in addr;
-        struct hostent *hp;
-		struct timeval tv;
+	utmpidlearr up;
+	CLIENT *rusers_clnt;
+	struct sockaddr_in6 addr;
+	struct hostent *hp;
+	struct timeval tv;
 
-        hp = gethostbyname(host);
-        if (hp == NULL)
+	hp = gethostbyname(host);
+	if (hp == NULL)
                 errx(1, "unknown host \"%s\"", host);
 
-        rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_IDLE, "udp");
-        if (rusers_clnt == NULL)
+	rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_IDLE, "udp");
+	if (rusers_clnt == NULL)
                 errx(1, "%s", clnt_spcreateerror(""));
 
 	bzero((char *)&up, sizeof(up));
@@ -191,10 +205,13 @@
 	tv.tv_usec = 0;
 	if (clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL, xdr_utmpidlearr, &up, tv) != RPC_SUCCESS)
                 errx(1, "%s", clnt_sperror(rusers_clnt, ""));
-        addr.sin_addr.s_addr = *(int *)hp->h_addr;
-        rusers_reply((char *)&up, &addr);
+	bcopy(hp->h_addr, &addr.sin6_addr, hp->h_length);
+	rusers_reply((char *)&up, &addr);
 }
 
+/*
+ * do it only in ipv4: all ipv6 are ipv4
+ */
 void
 allhosts()
 {
@@ -202,6 +219,7 @@
 	enum clnt_stat clnt_stat;
 
 	bzero((char *)&up, sizeof(up));
+	_res.options &= ~RES_USE_INET6;
 	clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_IDLE, RUSERSPROC_NAMES,
 				   xdr_void, NULL,
 				   xdr_utmpidlearr, (char *)&up, rusers_reply);
@@ -213,33 +231,36 @@
 usage()
 {
         fprintf(stderr, "usage: rusers [-la] [hosts ...]\n");
-        exit(1);
+	exit(1);
 }
 
 int
 main(int argc, char *argv[])
 {
-        int ch;
+	int ch;
+
+	while ((ch = getopt(argc, argv, "al")) != -1)
+		switch (ch) {
+		case 'a':
+			allopt++;
+			break;
+		case 'l':
+			longopt++;
+			break;
+		default:
+			usage();
+			/*NOTREACHED*/
+		}
 
-        while ((ch = getopt(argc, argv, "al")) != -1)
-	        switch (ch) {
-                case 'a':
-                        allopt++;
-                        break;
-                case 'l':
-                        longopt++;
-                        break;
-                default:
-                        usage();
-                        /*NOTREACHED*/
-                }
+	(void)res_init();
+	_res.options |= RES_USE_INET6;
 
-        setlinebuf(stdout);
+	setlinebuf(stdout);
 	if (argc == optind)
 		allhosts();
 	else {
 		for (; optind < argc; optind++)
 			(void) onehost(argv[optind]);
 	}
-        exit(0);
+	exit(0);
 }
diff -uN src-current/usr.bin/showmount/showmount.c src-current-ipv6/usr.bin/showmount/showmount.c
--- src-current/usr.bin/showmount/showmount.c
+++ src-current-ipv6/usr.bin/showmount/showmount.c
@@ -56,6 +56,10 @@
 
 #include <err.h>
 #include <netdb.h>
+/*
+ * ipv6 rpc : use base address type struct sockaddr_in6 *  in rpc includes
+ */
+#define	RPC_USE_INET6	/* address type is struct sockaddr_in6 * */
 #include <rpc/rpc.h>
 #include <rpc/pmap_clnt.h>
 #include <rpc/pmap_prot.h>
@@ -65,6 +69,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <resolv.h>
 
 /* Constant defs */
 #define	ALL	1
@@ -159,6 +164,9 @@
 
 	if (rpcs == 0)
 		rpcs = DODUMP;
+
+	(void)res_init();
+	_res.options |= RES_USE_INET6;
 
 	if (rpcs & DODUMP)
 		if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers,
diff -uN src-current/usr.bin/systat/netstat.c src-current-ipv6/usr.bin/systat/netstat.c
--- src-current/usr.bin/systat/netstat.c
+++ src-current-ipv6/usr.bin/systat/netstat.c
@@ -52,6 +52,8 @@
 #include <net/route.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ip6_var.h>
 #include <netinet/in_pcb.h>
 #include <netinet/ip_icmp.h>
 #include <netinet/icmp_var.h>
diff -uN src-current/usr.bin/telnet/commands.c src-current-ipv6/usr.bin/telnet/commands.c
--- src-current/usr.bin/telnet/commands.c
+++ src-current-ipv6/usr.bin/telnet/commands.c
@@ -53,11 +53,13 @@
 #include <string.h>
 #include <signal.h>
 #include <netdb.h>
+#include <resolv.h>
 #include <ctype.h>
 #include <pwd.h>
 #include <varargs.h>
 #include <errno.h>
 
+#include <arpa/inet.h>
 #include <arpa/telnet.h>
 
 #include "general.h"
@@ -75,15 +77,13 @@
 # endif /* vax */
 #endif /* !defined(CRAY) && !defined(sysV88) */
 #include <netinet/ip.h>
-
+#include <netinet/ip6.h>
 
 #ifndef       MAXHOSTNAMELEN
 #define       MAXHOSTNAMELEN 64
 #endif        MAXHOSTNAMELEN
 
-#if	defined(IPPROTO_IP) && defined(IP_TOS)
-int tos = -1;
-#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
+u_int flow = IPV6_PRIORITY_INTERACTIVE;
 
 char	*hostname;
 static char _hostname[MAXHOSTNAMELEN];
@@ -2093,26 +2093,33 @@
 }
 #endif
 
-unsigned long inet_addr();
-
 int
 tn(argc, argv)
     int argc;
     char *argv[];
 {
     register struct hostent *host = 0;
-    struct sockaddr_in sin;
+    struct sockaddr_in6 sin;
     struct servent *sp = 0;
-    unsigned long temp;
-    extern char *inet_ntoa();
 #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
+    int temp;
     char *srp = 0, *strrchr();
-    unsigned long sourceroute(), srlen;
+    int sourceroute(), srlen;
 #endif
     char *cmd, *hostp = 0, *portp = 0, *user = 0;
+    static first = 0;
+
+    if (first == 0) {
+	(void) res_init();
+	_res.options |= RES_USE_INET6;
+	first++;
+    }
 
     /* clear the socket address prior to use */
     bzero((char *)&sin, sizeof(sin));
+#ifdef SIN6_LEN
+    sin.sin6_len = sizeof(sin);
+#endif
 
     if (connected) {
 	printf("?Already connected to %s\n", hostname);
@@ -2165,11 +2172,10 @@
 
 #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
     if (hostp[0] == '@' || hostp[0] == '!') {
-	if ((hostname = strrchr(hostp, ':')) == NULL)
-	    hostname = strrchr(hostp, '@');
+	hostname = strrchr(hostp, '@');
 	hostname++;
 	srp = 0;
-	temp = sourceroute(hostp, &srp, &srlen);
+	temp = sourceroute(hostp, &sin, &srp, &srlen);
 	if (temp == 0) {
 	    herror(srp);
 	    setuid(getuid());
@@ -2178,41 +2184,25 @@
 	    printf("Bad source route option: %s\n", hostp);
 	    setuid(getuid());
 	    return 0;
-	} else {
-	    sin.sin_addr.s_addr = temp;
-	    sin.sin_family = AF_INET;
 	}
     } else {
 #endif
-	temp = inet_addr(hostp);
-	if (temp != INADDR_NONE) {
-	    sin.sin_addr.s_addr = temp;
-	    sin.sin_family = AF_INET;
-	    host = gethostbyaddr((char *)&temp, sizeof(temp), AF_INET);
-	    if (host)
-	        (void) strncpy(_hostname, host->h_name, sizeof(_hostname));
-	    else
-		(void) strncpy(_hostname, hostp, sizeof(_hostname));
-	    _hostname[sizeof(_hostname)-1] = '\0';
-	    hostname = _hostname;
-	} else {
-	    host = gethostbyname(hostp);
-	    if (host) {
-		sin.sin_family = host->h_addrtype;
+	host = gethostbyname(hostp);
+	if (host) {
+	    sin.sin6_family = host->h_addrtype;
 #if	defined(h_addr)		/* In 4.3, this is a #define */
-		memmove((caddr_t)&sin.sin_addr,
-				host->h_addr_list[0], host->h_length);
+	    memmove((caddr_t)&sin.sin6_addr,
+		    host->h_addr_list[0], host->h_length);
 #else	/* defined(h_addr) */
-		memmove((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
+	    memmove((caddr_t)&sin.sin6_addr, host->h_addr, host->h_length);
 #endif	/* defined(h_addr) */
-		strncpy(_hostname, host->h_name, sizeof(_hostname));
-		_hostname[sizeof(_hostname)-1] = '\0';
-		hostname = _hostname;
-	    } else {
-		herror(hostp);
-	        setuid(getuid());
-		return 0;
-	    }
+	    strncpy(_hostname, host->h_name, sizeof(_hostname));
+	    _hostname[sizeof(_hostname)-1] = '\0';
+	    hostname = _hostname;
+	} else {
+	    herror(hostp);
+	    setuid(getuid());
+	    return 0;
 	}
 #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
     }
@@ -2223,11 +2213,11 @@
 	    telnetport = 1;
 	} else
 	    telnetport = 0;
-	sin.sin_port = atoi(portp);
-	if (sin.sin_port == 0) {
+	sin.sin6_port = atoi(portp);
+	if (sin.sin6_port == 0) {
 	    sp = getservbyname(portp, "tcp");
 	    if (sp)
-		sin.sin_port = sp->s_port;
+		sin.sin6_port = sp->s_port;
 	    else {
 		printf("%s: bad port number\n", portp);
 	        setuid(getuid());
@@ -2237,7 +2227,7 @@
 #if	!defined(htons)
 	    u_short htons P((unsigned short));
 #endif	/* !defined(htons) */
-	    sin.sin_port = htons(sin.sin_port);
+	    sin.sin6_port = htons(sin.sin6_port);
 	}
     } else {
 	if (sp == 0) {
@@ -2247,54 +2237,92 @@
 	        setuid(getuid());
 		return 0;
 	    }
-	    sin.sin_port = sp->s_port;
+	    sin.sin6_port = sp->s_port;
 	}
 	telnetport = 1;
     }
-    printf("Trying %s...\n", inet_ntoa(sin.sin_addr));
+    {
+	char dbuf[64];
+
+	printf("Trying %s...\n",
+	       inet_ntop(AF_INET6, &sin.sin6_addr,
+			 dbuf, sizeof(dbuf)));
+    }
     do {
-	net = socket(AF_INET, SOCK_STREAM, 0);
+	net = socket(AF_INET6, SOCK_STREAM, 0);
 	setuid(getuid());
 	if (net < 0) {
 	    perror("telnet: socket");
 	    return 0;
 	}
+	if ((flow & IPV6_FLOWINFO_VERSION)) {
+		int r, rl;
+
+		rl = sizeof(int);
+		if (getsockopt(net, IPPROTO_IPV6, FLOW6_RAND,
+			       (char *)&r, &rl) < 0)
+			perror("getsockopt (FLOW6_RAND)");
+		flow &= IPV6_FLOWINFO_PRIORITY;
+		flow |= IPV6_SET_FLOWLABEL(r);
+	}
+	sin.sin6_flowinfo = flow;
 #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
-	if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
-		perror("setsockopt (IP_OPTIONS)");
-#endif
+	if (srp) {
+		if (temp == AF_INET) {
+#ifdef SIN6_LEN
+			sin.sin6_len = sizeof(struct sockaddr_in);
+#endif
+			sin.sin6_family = temp;
+			bcopy(&sin.sin6_addr.s6_addr[12],
+			      &sin.sin6_flowinfo, sizeof(int));
+			if (setsockopt(net, IPPROTO_IPV6, IPV6_ADDRFORM,
+				       (char *)&temp, sizeof(int)) < 0)
+				perror("setsockopt (IPV6_ADDRFORM)");
 #if	defined(IPPROTO_IP) && defined(IP_TOS)
-	{
-# if	defined(HAS_GETTOS)
-	    struct tosent *tp;
-	    if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
-		tos = tp->t_tos;
-# endif
-	    if (tos < 0)
-		tos = IPTOS_LOWDELAY;
-	    if (tos
-		&& (setsockopt(net, IPPROTO_IP, IP_TOS,
-		    (char *)&tos, sizeof(int)) < 0)
-		&& (errno != ENOPROTOOPT))
-		    perror("telnet: setsockopt (IP_TOS) (ignored)");
-	}
-#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
+			if ((flow & IPV6_FLOWINFO_PRIORITY) ==
+			    IPV6_PRIORITY_INTERACTIVE)
+				flow = IPTOS_LOWDELAY;
+			else
+				flow = IPV6_GET_PRIORITY(flow);
+			if (flow &&
+			    (setsockopt(net, IPPROTO_IP, IP_TOS,
+					(char *)&flow, sizeof(int)) < 0))
+				perror("setsockopt (IP_TOS)");
+#endif
+			if (setsockopt(net, IPPROTO_IP, IP_OPTIONS,
+				       (char *)srp, srlen) < 0)
+				perror("setsockopt (IP_OPTIONS)");
 
+		} else {
+			if (setsockopt(net, IPPROTO_IP, IP_OPTIONS,
+				       (char *)srp, srlen) < 0)
+				perror("setsockopt (IP_OPTIONS)");
+		}
+	}
+#endif
 	if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
 		perror("setsockopt (SO_DEBUG)");
 	}
 
-	if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
+#ifdef SIN6_LEN
+	if (connect(net, (struct sockaddr *)&sin, sin.sin6_len) < 0) {
+#else
+	if (connect(net, (struct sockaddr *)&sin,
+		    sin->sin6_family == AF_INET ?
+			sizeof(struct sockaddr_in) : sizeof (sin)) < 0) {
+#endif
 #if	defined(h_addr)		/* In 4.3, this is a #define */
 	    if (host && host->h_addr_list[1]) {
 		int oerrno = errno;
+		char abuf[64];
 
 		fprintf(stderr, "telnet: connect to address %s: ",
-						inet_ntoa(sin.sin_addr));
+			inet_ntop(AF_INET6, &sin.sin6_addr,
+				  abuf, sizeof(abuf)));
 		errno = oerrno;
 		perror((char *)0);
 		host->h_addr_list++;
-		memcpy((caddr_t)&sin.sin_addr,
+		memcpy((caddr_t)&sin.sin6_addr,
 			host->h_addr_list[0], host->h_length);
 		(void) NetClose(net);
 		continue;
@@ -2650,19 +2678,22 @@
 
 /*
  * Source route is handed in as
- *	[!]@hop1@hop2...[@|:]dst
- * If the leading ! is present, it is a
- * strict source route, otherwise it is
- * assmed to be a loose source route.
+ *	[!]@hop1[!]@hop2...[!][@|:]dst
+ * If a ! is present, it is a strict
+ * source route segment, otherwise it is
+ * assumed to be a loose source route segment.
+ * In IPv4 the whole source route is strict or loose.
  *
  * We fill in the source route option as
  *	hop1,hop2,hop3...dest
- * and return a pointer to hop1, which will
+ * and return a pointer to dest, which will
  * be the address to connect() to.
  *
  * Arguments:
  *	arg:	pointer to route list to decipher
  *
+ *	sin:	pointer to sockaddr_in6 to fill
+ *
  *	cpp: 	If *cpp is not equal to NULL, this is a
  *		pointer to a pointer to a character array
  *		that should be filled in with the option.
@@ -2672,7 +2703,7 @@
  *
  * Return values:
  *
- *	Returns the address of the host to connect to.  If the
+ *	Returns the address family to use.  If the
  *	return value is -1, there was a syntax error in the
  *	option, either unknown characters, or too many hosts.
  *	If the return value is 0, one of the hostnames in the
@@ -2681,25 +2712,28 @@
  *
  *	*cpp:	If *cpp was equal to NULL, it will be filled
  *		in with a pointer to our static area that has
- *		the option filled in.  This will be 32bit aligned.
+ *		the option filled in.
+ *		This will be 32bit aligned in IPv4
+ *		and should be 64bit aligned in IPv6.
  *
  *	*lenp:	This will be filled in with how long the option
  *		pointed to by *cpp is.
  *
  */
-	unsigned long
-sourceroute(arg, cpp, lenp)
+int
+sourceroute(arg, sin, cpp, lenp)
 	char	*arg;
+	struct	sockaddr_in6 *sin;
 	char	**cpp;
 	int	*lenp;
 {
-	static char lsr[44];
+	static double lsr[408 / sizeof(double)];
 #ifdef	sysV88
 	static IOPTN ipopt;
 #endif
 	char *cp, *cp2, *lsrp, *lsrep;
-	register int tmp;
-	struct in_addr sin_addr;
+	int af = 0;
+	struct in6_addr sin6_addr;
 	register struct hostent *host = 0;
 	register char c;
 
@@ -2708,9 +2742,9 @@
 	 * at least 7 bytes for the option.
 	 */
 	if (cpp == NULL || lenp == NULL)
-		return((unsigned long)-1);
+		return(-1);
 	if (*cpp != NULL && *lenp < 7)
-		return((unsigned long)-1);
+		return(-1);
 	/*
 	 * Decide whether we have a buffer passed to us,
 	 * or if we need to use our own static buffer.
@@ -2719,8 +2753,8 @@
 		lsrp = *cpp;
 		lsrep = lsrp + *lenp;
 	} else {
-		*cpp = lsrp = lsr;
-		lsrep = lsrp + 44;
+		*cpp = lsrp = (char *)lsr;
+		lsrep = lsrp + 408;
 	}
 
 	cp = arg;
@@ -2745,29 +2779,20 @@
 #endif
 
 	if (*cp != '@')
-		return((unsigned long)-1);
-
-#ifndef	sysV88
-	lsrp++;		/* skip over length, we'll fill it in later */
-	*lsrp++ = 4;
-#endif
+		return(-1);
 
 	cp++;
 
-	sin_addr.s_addr = 0;
+	CLR_ADDR6(sin6_addr);
 
 	for (c = 0;;) {
-		if (c == ':')
-			cp2 = 0;
-		else for (cp2 = cp; c = *cp2; cp2++) {
+		for (cp2 = cp; c = *cp2; cp2++) {
 			if (c == ',') {
 				*cp2++ = '\0';
 				if (*cp2 == '@')
 					cp2++;
 			} else if (c == '@') {
 				*cp2++ = '\0';
-			} else if (c == ':') {
-				*cp2++ = '\0';
 			} else
 				continue;
 			break;
@@ -2775,21 +2800,48 @@
 		if (!c)
 			cp2 = 0;
 
-		if ((tmp = inet_addr(cp)) != -1) {
-			sin_addr.s_addr = tmp;
-		} else if (host = gethostbyname(cp)) {
+		if (host = gethostbyname(cp)) {
 #if	defined(h_addr)
-			memcpy((caddr_t)&sin_addr,
+			memcpy((caddr_t)&sin6_addr,
 				host->h_addr_list[0], host->h_length);
 #else
-			memcpy((caddr_t)&sin_addr, host->h_addr, host->h_length);
+			memcpy((caddr_t)&sin6_addr, host->h_addr, host->h_length);
 #endif
 		} else {
 			*cpp = cp;
 			return(0);
 		}
-		memcpy(lsrp, (char *)&sin_addr, 4);
-		lsrp += 4;
+		if (af == 0) {
+			if (IN6_IS_ADDR_V4MAPPED(&sin6_addr)) {
+				af = AF_INET;
+#ifndef	sysV88
+				lsrep = lsrp + 43;
+				/* skip over length, we'll fill it in later */
+				lsrp++;
+				*lsrp++ = 4;
+#endif
+			} else {
+				af = AF_INET6;
+				lsrp--;
+				/* fill option */
+				*lsrp++ = IP6_NHDR_RT;
+				/* skip over header length */
+				lsrp++;
+				*lsrp++ = IP6_LSRRT;
+				*lsrp++ = 0;
+				*lsrp++ = 0;
+				*lsrp++ = 0;
+				*lsrp++ = 0;
+				*lsrp++ = 0;
+			}
+		}
+		if (af == AF_INET) {
+			memcpy(lsrp, (char *)&sin6_addr.s6_addr[12], 4);
+			lsrp += 4;
+		} else {
+			memcpy(lsrp, (char *)&sin6_addr, 16);
+			lsrp += 16;
+		}
 		if (cp2)
 			cp = cp2;
 		else
@@ -2798,26 +2850,42 @@
 		 * Check to make sure there is space for next address
 		 */
 		if (lsrp + 4 > lsrep)
-			return((unsigned long)-1);
+			return(-1);
 	}
 #ifndef	sysV88
-	if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
-		*cpp = 0;
-		*lenp = 0;
-		return((unsigned long)-1);
+	if (af == AF_INET) {
+		if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
+			*cpp = 0;
+			*lenp = 0;
+			return(-1);
+		}
+		*lsrp++ = IPOPT_NOP; /* 32 bit word align it */
+	} else {
+		if ((*(*cpp+1) = (lsrp - *cpp - 24) / 8) <= 0) {
+			*cpp = 0;
+			*lenp = 0;
+			return(-1);
+		}
 	}
-	*lsrp++ = IPOPT_NOP; /* 32 bit word align it */
+	sin->sin6_family = AF_INET6;
+	COPY_ADDR6(sin6_addr, sin->sin6_addr);
 	*lenp = lsrp - *cpp;
+	if (af == AF_INET6) {
+		lsrp = *cpp + 8;
+		COPY_ADDR6(*((struct in6_addr *)lsrp), sin6_addr);
+		bcopy(lsrp + 16, lsrp, *lenp - 8);
+		bcopy(&sin6_addr, lsrp + *lenp - 24, 16);
+	}
 #else
 	ipopt.io_len = lsrp - *cpp;
 	if (ipopt.io_len <= 5) {		/* Is 3 better ? */
 		*cpp = 0;
 		*lenp = 0;
-		return((unsigned long)-1);
+		return(-1);
 	}
 	*lenp = sizeof(ipopt);
 	*cpp = (char *) &ipopt;
 #endif
-	return(sin_addr.s_addr);
+	return(af);
 }
 #endif
diff -uN src-current/usr.bin/telnet/main.c src-current-ipv6/usr.bin/telnet/main.c
--- src-current/usr.bin/telnet/main.c
+++ src-current-ipv6/usr.bin/telnet/main.c
@@ -117,6 +117,7 @@
 #ifdef	FORWARD
 	extern int forward_flags;
 #endif	/* FORWARD */
+	extern u_int flow;
 
 	tninit();		/* Clear out things */
 #if	defined(CRAY) && !defined(__STDC__)
@@ -152,21 +153,7 @@
 			eight |= 2;	/* binary output only */
 			break;
 		case 'S':
-		    {
-#ifdef	HAS_GETTOS
-			extern int tos;
-
-			if ((tos = parsetos(optarg, "tcp")) < 0)
-				fprintf(stderr, "%s%s%s%s\n",
-					prompt, ": Bad TOS argument '",
-					optarg,
-					"; will try to use default TOS");
-#else
-			fprintf(stderr,
-			   "%s: Warning: -S ignored, no parsetos() support.\n",
-								prompt);
-#endif
-		    }
+			flow = htonl(atol(optarg));
 			break;
 		case 'X':
 #ifdef	AUTHENTICATION
diff -uN src-current/usr.bin/tftp/main.c src-current-ipv6/usr.bin/tftp/main.c
--- src-current/usr.bin/tftp/main.c
+++ src-current-ipv6/usr.bin/tftp/main.c
@@ -62,6 +62,7 @@
 #include <ctype.h>
 #include <err.h>
 #include <netdb.h>
+#include <resolv.h>
 #include <setjmp.h>
 #include <signal.h>
 #include <stdio.h>
@@ -73,7 +74,7 @@
 
 #define	TIMEOUT		5		/* secs between rexmt's */
 
-struct	sockaddr_in peeraddr;
+struct	sockaddr_in6 peeraddr;
 int	f;
 short   port;
 int	trace;
@@ -156,16 +157,22 @@
 	int argc;
 	char *argv[];
 {
-	struct sockaddr_in sin;
+	struct sockaddr_in6 sin;
+
+	(void) res_init();
+	_res.options |= RES_USE_INET6;
 
 	sp = getservbyname("tftp", "udp");
 	if (sp == 0)
 		errx(1, "udp/tftp: unknown service");
-	f = socket(AF_INET, SOCK_DGRAM, 0);
+	f = socket(AF_INET6, SOCK_DGRAM, 0);
 	if (f < 0)
 		err(3, "socket");
 	bzero((char *)&sin, sizeof(sin));
-	sin.sin_family = AF_INET;
+#ifdef SIN6_LEN
+	sin.sin6_len = sizeof (sin);
+#endif
+	sin.sin6_family = AF_INET6;
 	if (bind(f, (struct sockaddr *)&sin, sizeof(sin)) < 0)
 		err(1, "bind");
 	strcpy(mode, "netascii");
@@ -203,18 +210,13 @@
 	}
 	host = gethostbyname(argv[1]);
 	if (host) {
-		peeraddr.sin_family = host->h_addrtype;
-		bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length);
-		strcpy(hostname, host->h_name);
+		peeraddr.sin6_family = host->h_addrtype;
+		bcopy(host->h_addr, &peeraddr.sin6_addr, host->h_length);
+		(void) strcpy(hostname, host->h_name);
 	} else {
-		peeraddr.sin_family = AF_INET;
-		peeraddr.sin_addr.s_addr = inet_addr(argv[1]);
-		if (peeraddr.sin_addr.s_addr == -1) {
-			connected = 0;
-			printf("%s: unknown host\n", argv[1]);
-			return;
-		}
-		strcpy(hostname, argv[1]);
+		connected = 0;
+		printf("%s: unknown host\n", argv[1]);
+		return;
 	}
 	port = sp->s_port;
 	if (argc == 3) {
@@ -348,8 +350,11 @@
 			herror((char *)NULL);
 			return;
 		}
-		bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, hp->h_length);
-		peeraddr.sin_family = hp->h_addrtype;
+		bcopy(hp->h_addr, (caddr_t)&peeraddr.sin6_addr, hp->h_length);
+#ifdef SIN6_LEN
+		peeraddr.sin6_len = sizeof(peeraddr);
+#endif
+		peeraddr.sin6_family = hp->h_addrtype;
 		connected = 1;
 		strcpy(hostname, hp->h_name);
 	}
@@ -367,7 +372,7 @@
 		if (verbose)
 			printf("putting %s to %s:%s [%s]\n",
 				cp, hostname, targ, mode);
-		peeraddr.sin_port = port;
+		peeraddr.sin6_port = port;
 		sendfile(fd, targ, mode);
 		return;
 	}
@@ -385,7 +390,7 @@
 		if (verbose)
 			printf("putting %s to %s:%s [%s]\n",
 				argv[n], hostname, targ, mode);
-		peeraddr.sin_port = port;
+		peeraddr.sin6_port = port;
 		sendfile(fd, targ, mode);
 	}
 }
@@ -444,9 +449,15 @@
 				herror((char *)NULL);
 				continue;
 			}
-			bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr,
+			bcopy(hp->h_addr, (caddr_t)&peeraddr.sin6_addr,
 			    hp->h_length);
-			peeraddr.sin_family = hp->h_addrtype;
+			peeraddr.sin6_family = hp->h_addrtype;
+#ifdef SIN6_LEN
+			if (hp->h_addrtype == AF_INET)
+				peeraddr.sin6_len = sizeof(struct sockaddr_in);
+			else
+				peeraddr.sin6_len = sizeof(peeraddr);
+#endif
 			connected = 1;
 			strcpy(hostname, hp->h_name);
 		}
@@ -460,7 +471,7 @@
 			if (verbose)
 				printf("getting from %s:%s to %s [%s]\n",
 					hostname, src, cp, mode);
-			peeraddr.sin_port = port;
+			peeraddr.sin6_port = port;
 			recvfile(fd, src, mode);
 			break;
 		}
@@ -473,7 +484,7 @@
 		if (verbose)
 			printf("getting from %s:%s to %s [%s]\n",
 				hostname, src, cp, mode);
-		peeraddr.sin_port = port;
+		peeraddr.sin6_port = port;
 		recvfile(fd, src, mode);
 	}
 }
diff -uN src-current/usr.bin/tftp/tftp.c src-current-ipv6/usr.bin/tftp/tftp.c
--- src-current/usr.bin/tftp/tftp.c
+++ src-current-ipv6/usr.bin/tftp/tftp.c
@@ -63,7 +63,7 @@
 #include "extern.h"
 #include "tftpsubs.h"
 
-extern  struct sockaddr_in peeraddr;	/* filled in by main */
+extern  struct sockaddr_in6 peeraddr;	/* filled in by main */
 extern  int     f;			/* the opened socket */
 extern  int     trace;
 extern  int     verbose;
@@ -98,7 +98,7 @@
 	register int n;
 	volatile int block, size, convert;
 	volatile unsigned long amount;
-	struct sockaddr_in from;
+	struct sockaddr_in6 from;
 	int fromlen;
 	FILE *file;
 
@@ -148,7 +148,7 @@
 				warn("recvfrom");
 				goto abort;
 			}
-			peeraddr.sin_port = from.sin_port;	/* added */
+			peeraddr.sin6_port = from.sin6_port;	/* added */
 			if (trace)
 				tpacket("received", ap, n);
 			/* should verify packet came from server */
@@ -203,7 +203,7 @@
 	register int n;
 	volatile int block, size, firsttrip;
 	volatile unsigned long amount;
-	struct sockaddr_in from;
+	struct sockaddr_in6 from;
 	int fromlen;
 	FILE *file;
 	volatile int convert;		/* true if converting crlf -> lf */
@@ -252,7 +252,7 @@
 				warn("recvfrom");
 				goto abort;
 			}
-			peeraddr.sin_port = from.sin_port;	/* added */
+			peeraddr.sin6_port = from.sin6_port;	/* added */
 			if (trace)
 				tpacket("received", dp, n);
 			/* should verify client address */
@@ -434,8 +434,8 @@
 {
 	double delta;
 			/* compute delta in 1/10's second units */
-	delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) -
-		((tstart.tv_sec*10.)+(tstart.tv_usec/100000));
+	delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000.)) -
+		((tstart.tv_sec*10.)+(tstart.tv_usec/100000.));
 	delta = delta/10.;      /* back to seconds */
 	printf("%s %d bytes in %.1f seconds", direction, amount, delta);
 	if (verbose)
diff -uN src-current/usr.bin/tftp/tftpsubs.c src-current-ipv6/usr.bin/tftp/tftpsubs.c
--- src-current/usr.bin/tftp/tftpsubs.c
+++ src-current-ipv6/usr.bin/tftp/tftpsubs.c
@@ -260,7 +260,7 @@
 {
 	int i, j = 0;
 	char rbuf[PKTSIZE];
-	struct sockaddr_in from;
+	struct sockaddr_in6 from;
 	int fromlen;
 
 	while (1) {
diff -uN src-current/usr.sbin/Makefile src-current-ipv6/usr.sbin/Makefile
--- src-current/usr.sbin/Makefile
+++ src-current-ipv6/usr.sbin/Makefile
@@ -7,12 +7,15 @@
 	keyserv lpr manctl mkdosfs mrouted mtest mtree \
 	named named.reload named.restart ndc newsyslog nslookup nsupdate \
 	pccard pciconf periodic pkg_install portmap \
-	ppp pppctl pppd pppstats procctl pw pwd_mkdb quot quotaon rarpd \
+	ppp pppctl pppstats procctl pw pwd_mkdb quot quotaon rarpd \
 	repquota rmt rpc.lockd rpc.statd rpc.yppasswdd rpc.ypxfrd \
 	rpc.ypupdated rwhod sa sliplogin slstat \
 	spray sysctl syslogd tcpdump timed traceroute trpt tzsetup vipw \
 	vnconfig watch wormcontrol xntpd xten ypbind yp_mkdb \
-	yppoll yppush ypset ypserv zic
+	yppoll yppush ypset ypserv zic \
+	ndp6 ndpd-host ndpd-router traceroute6 zing
+
+SUBDIR+=IPXrouted
 
 SUBDIR+=ipfstat ipftest ipmon ipnat ipresend ipsend iptest
 
diff -uN src-current/usr.sbin/ipftest/Makefile src-current-ipv6/usr.sbin/ipftest/Makefile
--- src-current/usr.sbin/ipftest/Makefile
+++ src-current-ipv6/usr.sbin/ipftest/Makefile
@@ -6,15 +6,19 @@
 PROG=	ipftest
 MAN1=	ipftest.1
 SRCS=	opt_ipfilter.h \
+	opt_inet6.h \
 	ipt.c fil.c ipft_hx.c ipft_sn.c ipft_ef.c ipft_td.c ipft_pc.c \
 	ipft_tx.c misc.c parse.c opt.c ip_frag.c ip_nat.c ip_state.c \
 	ip_auth.c ip_fil.c ip_proxy.c
 
 CFLAGS+=-DIPL_NAME=\"/dev/ipl\" -I- -I${.OBJDIR} -I${.CURDIR}/../../sys/netinet -I${.CURDIR}/../../sys -I${.CURDIR}/../../contrib/ipfilter
 
-CLEANFILES+=	opt_ipfilter.h
+CLEANFILES+=	opt_ipfilter.h	opt_inet6.h
 
 opt_ipfilter.h:	Makefile
 	echo "#define IPFILTER 1" > opt_ipfilter.h
+
+opt_inet6.h:	Makefile
+	echo "#define INET6 1" > opt_inet6.h
 
 .include <bsd.prog.mk>
diff -uN src-current/usr.sbin/inetd/inetd.8 src-current-ipv6/usr.sbin/inetd/inetd.8
--- src-current/usr.sbin/inetd/inetd.8
+++ src-current-ipv6/usr.sbin/inetd/inetd.8
@@ -210,14 +210,22 @@
 .Dq tcp
 or
 .Dq udp .
+The names
+.Dq tcp4 ,
+.Dq udp4
+specialize the entry to IPv4 only .
 If it is desired that the service is reachable via T/TCP, one should
 specify
-.Dq tcp/ttcp .
+.Dq tcp/ttcp or tcp4/ttcp .
 Rpc based services are specified with the 
 .Dq rpc/tcp
 or 
 .Dq rpc/udp 
 service type.
+The names
+.Dq rpc/tcp4 ,
+.Dq rpc/udp4
+specialized the entry to IPv4 only too.
 TCPMUX services must use 
 .Dq tcp .
 .Pp
@@ -424,10 +432,10 @@
 Here are several example service entries for the various types of services:
 .Bd -literal
 ftp          stream  tcp   nowait root  /usr/libexec/ftpd        ftpd -l
-ntalk        dgram   udp   wait   root  /usr/libexec/ntalkd      ntalkd
+ntalk        dgram   udp4  wait   root  /usr/libexec/ntalkd      ntalkd
 tcpmux/+date stream  tcp   nowait guest /bin/date                date
 tcpmux/phonebook stream tcp nowait guest /usr/local/bin/phonebook phonebook
-rstatd/1-3   dgram   rpc/udp wait root  /usr/libexec/rpc.rstatd  rpc.rstatd
+rstatd/1-3   dgram   rpc/udp4 wait root  /usr/libexec/rpc.rstatd  rpc.rstatd
 .Ed
 .Sh "ERROR MESSAGES"
 The
diff -uN src-current/usr.sbin/inetd/inetd.c src-current-ipv6/usr.sbin/inetd/inetd.c
--- src-current/usr.sbin/inetd/inetd.c
+++ src-current-ipv6/usr.sbin/inetd/inetd.c
@@ -171,11 +171,14 @@
 int	maxcpm = MAXCHILD;
 struct	servent *sp;
 struct	rpcent *rpc;
-struct	in_addr bind_address;
+struct	in_addr bind_address4;
+struct	in6_addr bind_address6;
+extern	struct in6_addr in6addr_any;
 
 struct	servtab {
 	char	*se_service;		/* name of service */
 	int	se_socktype;		/* type of socket to use */
+	int	se_family;		/* address family */
 	char	*se_proto;		/* protocol used */
 	int	se_maxchild;		/* max number of children */
 	int	se_maxcpm;		/* max connects per IP per minute */
@@ -191,7 +194,15 @@
 #define	MAXARGV 20
 	char	*se_argv[MAXARGV+1];	/* program arguments */
 	int	se_fd;			/* open descriptor */
-	struct	sockaddr_in se_ctrladdr;/* bound address */
+	union {				/* bound address */
+		struct	sockaddr se_un_ctrladdr;
+		struct	sockaddr_in se_un_ctrladdr4;
+		struct	sockaddr_in6 se_un_ctrladdr6;
+	} se_un;
+#define se_ctrladdr	se_un.se_un_ctrladdr
+#define se_ctrladdr4	se_un.se_un_ctrladdr4
+#define se_ctrladdr6	se_un.se_un_ctrladdr6
+  	int	se_ctrladdr_size;
 	u_char	se_type;		/* type: normal, mux, or mux+ */
 	u_char	se_checked;		/* looked at during merge */
 	u_char	se_accept;		/* i.e., wait/nowait mode */
@@ -317,7 +328,14 @@
 	int tmpint, ch, dofork;
 	pid_t pid;
 	char buf[50];
-	struct  sockaddr_in peer;
+	union {
+		struct sockaddr peer_un;
+		struct sockaddr_in peer_un4;
+		struct sockaddr_in6 peer_un6;
+	} p_un;
+#define peer	p_un.peer_un
+#define peer4	p_un.peer_un4
+#define peer6	p_un.peer_un6
 	int i;
 #ifdef LOGIN_CAP
 	login_cap_t *lc = NULL;
@@ -335,7 +353,8 @@
 
 	openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
 
-	bind_address.s_addr = htonl(INADDR_ANY);
+	bind_address4.s_addr = htonl(INADDR_ANY);
+	bind_address6 = in6addr_any;
 	while ((ch = getopt(argc, argv, "dlR:a:c:C:p:")) != -1)
 		switch(ch) {
 		case 'd':
@@ -358,7 +377,8 @@
 				"-C %s: bad value for maximum children/minute");
 			break;
 		case 'a':
-			if (!inet_aton(optarg, &bind_address)) {
+			if ((inet_pton(AF_INET6, optarg, &bind_address6) <= 0) &&
+			    !inet_aton(optarg, &bind_address4)) {
 				syslog(LOG_ERR,
 			         "-a %s: invalid IP address", optarg);
 				exit(EX_USAGE);
@@ -469,9 +489,10 @@
 				continue;
 			    }
 			    if (log) {
-				i = sizeof peer;
-				if (getpeername(ctrl, (struct sockaddr *)
-						&peer, &i)) {
+				char pname[64];
+
+				i = sizeof peer6;
+				if (getpeername(ctrl, &peer, &i)) {
 					syslog(LOG_WARNING,
 						"getpeername(for %s): %m",
 						sep->se_service);
@@ -480,7 +501,26 @@
 				}
 				syslog(LOG_INFO,"%s from %s",
 					sep->se_service,
-					inet_ntoa(peer.sin_addr));
+				        peer.sa_family == AF_INET6 ?
+				           inet_ntop(AF_INET6,
+						     &peer6.sin6_addr,
+						     pname,
+						     sizeof(pname)) :
+				           inet_ntoa(peer4.sin_addr));
+			    }
+			    /*
+			     * Call tcpmux to find the real service to exec.
+			     */
+			    if (sep->se_bi &&
+				sep->se_bi->bi_fn == (void (*)()) tcpmux) {
+				    struct servtab *tsep;
+
+				    tsep = tcpmux(ctrl);
+				    if (tsep == NULL) {
+					    close(ctrl);
+					    continue;
+				    }
+				    sep = tsep;
 			    }
 		    } else
 			    ctrl = sep->se_fd;
@@ -746,6 +786,12 @@
 
 #define SWAP(a, b) { typeof(a) c = a; a = b; b = c; }
 			omask = sigblock(SIGBLOCK);
+
+			if (sep->se_family != new->se_family) {
+				sep->se_family = new->se_family;
+				memset(&sep->se_un, 0, sizeof(sep->se_un));
+			}
+
 			/* copy over outstanding child pids */
 			if (sep->se_maxchild && new->se_maxchild) {
 				new->se_numchild = sep->se_numchild;
@@ -792,7 +838,12 @@
 			sep->se_fd = -1;
 			continue;
 		}
-		if (!sep->se_rpc) {
+		switch (sep->se_family) {
+		case AF_INET:
+			sep->se_ctrladdr4.sin_family = AF_INET;
+			sep->se_ctrladdr_size = sizeof sep->se_ctrladdr4;
+			if (sep->se_rpc)
+				goto rpc;
 			sp = getservbyname(sep->se_service, sep->se_proto);
 			if (sp == 0) {
 				syslog(LOG_ERR, "%s/%s: unknown service",
@@ -800,14 +851,41 @@
 				sep->se_checked = 0;
 				continue;
 			}
-			if (sp->s_port != sep->se_ctrladdr.sin_port) {
-				sep->se_ctrladdr.sin_family = AF_INET;
-				sep->se_ctrladdr.sin_addr = bind_address;
-				sep->se_ctrladdr.sin_port = sp->s_port;
+			if (sp->s_port != sep->se_ctrladdr4.sin_port) {
+				sep->se_ctrladdr4.sin_port = sp->s_port;
+				sep->se_ctrladdr4.sin_family = AF_INET;
+				sep->se_ctrladdr4.sin_addr = bind_address4;
+				sep->se_ctrladdr4.sin_port = sp->s_port;
 				if (sep->se_fd >= 0)
 					close_sep(sep);
 			}
-		} else {
+			break;
+		case AF_INET6:
+			sep->se_ctrladdr6.sin6_family = AF_INET6;
+			sep->se_ctrladdr_size = sizeof sep->se_ctrladdr6;
+#ifdef SIN6_LEN
+			sep->se_ctrladdr6.sin6_len = sep->se_ctrladdr_size;
+#endif
+			if (sep->se_socktype == SOCK_STREAM)
+				sep->se_ctrladdr6.sin6_flowinfo =
+					IPV6_PRIORITY_INTERACTIVE;
+			if (sep->se_rpc)
+				goto rpc;
+			sp = getservbyname(sep->se_service, sep->se_proto);
+			if (sp == 0) {
+				syslog(LOG_ERR, "%s/%s: unknown service",
+			    	sep->se_service, sep->se_proto);
+				sep->se_checked = 0;
+				continue;
+			}
+			if (sp->s_port != sep->se_ctrladdr6.sin6_port) {
+				sep->se_ctrladdr6.sin6_port = sp->s_port;
+				sep->se_ctrladdr6.sin6_addr = bind_address6;
+				if (sep->se_fd >= 0)
+					close_sep(sep);
+			}
+			break;
+		rpc:
 			rpc = getrpcbyname(sep->se_service);
 			if (rpc == 0) {
 				syslog(LOG_ERR, "%s/%s unknown RPC service.",
@@ -817,7 +895,8 @@
 				sep->se_fd = -1;
 					continue;
 			}
-			if (rpc->r_number != sep->se_rpc_prog) {
+			if (rpc->r_number != sep->se_rpc_prog ||
+			    sep->se_ctrladdr6.sin6_port == 0) {
 				if (sep->se_rpc_prog)
 					unregisterrpc(sep);
 				sep->se_rpc_prog = rpc->r_number;
@@ -899,7 +978,7 @@
 {
 	int on = 1;
 
-	if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
+	if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
 		if (debug)
 			warn("socket failed on %s/%s",
 				sep->se_service, sep->se_proto);
@@ -918,13 +997,19 @@
 	if (turnon(sep->se_fd, SO_PRIVSTATE) < 0)
 		syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m");
 #endif
+	/* tftpd opens a new connection then needs more infos */
+	if ((sep->se_family == AF_INET6) &&
+	    (strcmp(sep->se_proto, "udp") == 0) &&
+	    (sep->se_accept == 0) &&
+	    (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+			(char *)&on, sizeof (on)) < 0))
+		syslog(LOG_ERR, "setsockopt (IPV6_RECVPKTINFO): %m");
 #undef turnon
 	if (sep->se_type == TTCP_TYPE)
 		if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH,
 		    (char *)&on, sizeof (on)) < 0)
 			syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m");
-	if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
-	    sizeof (sep->se_ctrladdr)) < 0) {
+	if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
 		if (debug)
 			warn("bind failed on %s/%s",
 				sep->se_service, sep->se_proto);
@@ -939,10 +1024,9 @@
 		return;
 	}
         if (sep->se_rpc) {
-                int i, len = sizeof(struct sockaddr);
+                int i, len = sep->se_ctrladdr_size;
 
-                if (getsockname(sep->se_fd,
-				(struct sockaddr*)&sep->se_ctrladdr, &len) < 0){
+                if (getsockname(sep->se_fd, &sep->se_ctrladdr, &len) < 0){
                         syslog(LOG_ERR, "%s/%s: getsockname: %m",
                                sep->se_service, sep->se_proto);
                         (void) close(sep->se_fd);
@@ -956,7 +1040,7 @@
                         pmap_set(sep->se_rpc_prog, i,
                                  (sep->se_socktype == SOCK_DGRAM)
                                  ? IPPROTO_UDP : IPPROTO_TCP,
-                                 ntohs(sep->se_ctrladdr.sin_port));
+                                 ntohs(sep->se_ctrladdr4.sin_port));
                 }
 
         }
@@ -1144,13 +1228,22 @@
 		sep->se_socktype = SOCK_RAW;
 	else
 		sep->se_socktype = -1;
-
 	arg = sskip(&cp);
-	if (strcmp(arg, "tcp/ttcp") == 0) {
-		sep->se_type = TTCP_TYPE;
-		sep->se_proto = newstr("tcp");
-	} else {
-		sep->se_proto = newstr(arg);
+	if (strncmp(arg, "tcp", 3) == 0) {
+		char *s = arg+3;
+		if (*s == '4' || *s == '6') s++;
+		if (*s == '\0' || *s == '/') {
+			if (strcmp(s, "/ttcp") == 0)
+				sep->se_type = TTCP_TYPE;
+		}
+	}
+	sep->se_proto = newstr(arg);
+	sep->se_family = AF_INET6;
+	if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') {
+		sep->se_proto[strlen(sep->se_proto) - 1] = 0;
+	} else if (sep->se_proto[strlen(sep->se_proto) - 1] == '4') {
+		sep->se_proto[strlen(sep->se_proto) - 1] = 0;
+		sep->se_family = AF_INET;
 	}
         if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
                 memmove(sep->se_proto, sep->se_proto + 4,
@@ -1158,9 +1251,6 @@
                 sep->se_rpc = 1;
                 sep->se_rpc_prog = sep->se_rpc_lowvers =
 			sep->se_rpc_lowvers = 0;
-                sep->se_ctrladdr.sin_family = AF_INET;
-                sep->se_ctrladdr.sin_port = 0;
-                sep->se_ctrladdr.sin_addr = bind_address;
                 if ((versp = rindex(sep->se_service, '/'))) {
                         *versp++ = '\0';
                         switch (sscanf(versp, "%d-%d",
@@ -1408,15 +1498,23 @@
 {
 	int size;
 	char *cp;
-	struct sockaddr_in sin;
-	char buf[80];
+	union {
+		struct sockaddr peer_un;
+		struct sockaddr_in peer_un4;
+		struct sockaddr_in6 peer_un6;
+	} p_un;
+	char buf[80], pbuf[50];
 
 	cp = Argv[0];
-	size = sizeof(sin);
-	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
-		(void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
+	size = sizeof(peer6);
+	if (getpeername(s, &peer, &size) == 0)
+		(void) sprintf(buf, "-%.20s [%.50s]", a,
+			       peer.sa_family == AF_INET6 ?
+				inet_ntop(AF_INET6, &peer6.sin6_addr,
+					  pbuf, sizeof(pbuf)) :
+			        inet_ntoa(peer4.sin_addr));
 	else
-		(void) sprintf(buf, "-%s", a);
+		(void) sprintf(buf, "-%.60s", a);
 	strncpy(cp, buf, LastArg - cp);
 	cp += strlen(cp);
 	while (cp < LastArg)
@@ -1429,14 +1527,22 @@
 	int s;
 {
 	int size;
-	struct sockaddr_in sin;
-	char buf[80];
-
-	size = sizeof(sin);
-	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
-		(void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin.sin_addr));
+	union {
+		struct sockaddr peer_un;
+		struct sockaddr_in peer_un4;
+		struct sockaddr_in6 peer_un6;
+	} p_un;
+	char buf[80], pbuf[50];
+
+	size = sizeof(peer6);
+	if (getpeername(s, &peer, &size) == 0)
+		(void) sprintf(buf, "%.20s [%.50s]", a,
+			       peer.sa_family == AF_INET6 ?
+				inet_ntop(AF_INET6, &peer6.sin6_addr,
+					  pbuf, sizeof(pbuf)) :
+			        inet_ntoa(peer4.sin_addr));
 	else
-		(void) sprintf(buf, "%s", a);
+		(void) sprintf(buf, "%.60s", a);
 	setproctitle("%s", buf);
 }
 #endif
@@ -1446,6 +1552,11 @@
  * Internet services provided internally by inetd:
  */
 #define	BUFSIZE	8192
+#define	SA(s)	((struct sockaddr *)s)
+
+/*
+ * Note: *_dg should use a message for options!
+ */
 
 /* ARGSUSED */
 void
@@ -1464,21 +1575,25 @@
 }
 
 int check_loop(sin, sep)
-	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin;
 	struct servtab *sep;
 {
 	struct servtab *se2;
+	char hname[64];
 
 	for (se2 = servtab; se2; se2 = se2->se_next) {
 		if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM)
 			continue;
 
-		if (sin->sin_port == se2->se_ctrladdr.sin_port) {
+		if (sin->sin6_port == se2->se_ctrladdr6.sin6_port) {
 			syslog(LOG_WARNING,
 			       "%s/%s:%s/%s loop request REFUSED from %s",
 			       sep->se_service, sep->se_proto,
 			       se2->se_service, se2->se_proto,
-			       inet_ntoa(sin->sin_addr));
+			       sin->sin6_family == AF_INET6 ?
+				inet_ntop(AF_INET6, &sin->sin6_addr,
+					  hname, sizeof(hname)) :
+				inet_ntoa(((struct sockaddr_in *)sin)->sin_addr));
 			return 1;
 		}
 	}
@@ -1493,18 +1608,16 @@
 {
 	char buffer[BUFSIZE];
 	int i, size;
-	struct sockaddr_in sin;
+	struct sockaddr_in6 sin;
 
 	size = sizeof(sin);
-	if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
-			  (struct sockaddr *)&sin, &size)) < 0)
+	if ((i = recvfrom(s, buffer, sizeof(buffer), 0, SA(&sin), &size)) < 0)
 		return;
 
 	if (check_loop(&sin, sep))
 		return;
 
-	(void) sendto(s, buffer, i, 0, (struct sockaddr *)&sin,
-		      sizeof(sin));
+	(void) sendto(s, buffer, i, 0, SA(&sin), size);
 }
 
 /* ARGSUSED */
@@ -1593,7 +1706,7 @@
 	int s;
 	struct servtab *sep;
 {
-	struct sockaddr_in sin;
+	struct sockaddr_in6 sin;
 	static char *rs;
 	int len, size;
 	char text[LINESIZ+2];
@@ -1604,8 +1717,7 @@
 	}
 
 	size = sizeof(sin);
-	if (recvfrom(s, text, sizeof(text), 0,
-		     (struct sockaddr *)&sin, &size) < 0)
+	if (recvfrom(s, text, sizeof(text), 0, SA(&sin), &size) < 0)
 		return;
 
 	if (check_loop(&sin, sep))
@@ -1621,8 +1733,7 @@
 		rs = ring;
 	text[LINESIZ] = '\r';
 	text[LINESIZ + 1] = '\n';
-	(void) sendto(s, text, sizeof(text), 0,
-		      (struct sockaddr *)&sin, sizeof(sin));
+	(void) sendto(s, text, sizeof(text), 0, SA(&sin), size);
 }
 
 /*
@@ -1667,20 +1778,20 @@
 	struct servtab *sep;
 {
 	long result;
-	struct sockaddr_in sin;
+	struct sockaddr_in6 sin;
 	int size;
 
 	size = sizeof(sin);
-	if (recvfrom(s, (char *)&result, sizeof(result), 0,
-		     (struct sockaddr *)&sin, &size) < 0)
+	if (recvfrom(s, (char *)&result, sizeof(result),
+		     0, SA(&sin), &size) < 0)
 		return;
 
 	if (check_loop(&sin, sep))
 		return;
 
 	result = machtime();
-	(void) sendto(s, (char *) &result, sizeof(result), 0,
-		      (struct sockaddr *)&sin, sizeof(sin));
+	(void) sendto(s, (char *) &result, sizeof(result),
+		      0, SA(&sin), size);
 }
 
 /* ARGSUSED */
@@ -1706,22 +1817,20 @@
 {
 	char buffer[256];
 	time_t clock;
-	struct sockaddr_in sin;
+	struct sockaddr_in6 sin;
 	int size;
 
 	clock = time((time_t *) 0);
 
 	size = sizeof(sin);
-	if (recvfrom(s, buffer, sizeof(buffer), 0,
-		     (struct sockaddr *)&sin, &size) < 0)
+	if (recvfrom(s, buffer, sizeof(buffer), 0, SA(&sin), &size) < 0)
 		return;
 
 	if (check_loop(&sin, sep))
 		return;
 
 	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
-	(void) sendto(s, buffer, strlen(buffer), 0,
-		      (struct sockaddr *)&sin, sizeof(sin));
+	(void) sendto(s, buffer, strlen(buffer), 0, SA(&sin), size);
 }
 
 /*
diff -uN src-current/usr.sbin/lpr/common_source/common.c src-current-ipv6/usr.sbin/lpr/common_source/common.c
--- src-current/usr.sbin/lpr/common_source/common.c
+++ src-current-ipv6/usr.sbin/lpr/common_source/common.c
@@ -47,6 +47,8 @@
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/time.h>
+#include <netinet/in.h>
+#include <resolv.h>
 
 #include <dirent.h>
 #include <stdio.h>
diff -uN src-current/usr.sbin/lpr/common_source/net.c src-current-ipv6/usr.sbin/lpr/common_source/net.c
--- src-current/usr.sbin/lpr/common_source/net.c
+++ src-current-ipv6/usr.sbin/lpr/common_source/net.c
@@ -52,6 +52,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <resolv.h>
 
 #include <dirent.h>		/* required for lp.h, not used here */
 #include <errno.h>
@@ -71,6 +72,25 @@
 
 extern uid_t	uid, euid;
 
+union sockaddr_u {		/*_len, _family, _port are at same offset */
+	struct sockaddr_in s4; 
+	struct sockaddr_in6 s6; 
+};
+/*
+ * set DNS in IPv6 mode 
+ */
+void
+lp_init_dns_6(void)
+{
+	static int done = 0;
+
+	if (!done) {
+		done = 1;
+		(void) res_init();
+		_res.options |= RES_USE_INET6;
+	}
+}
+
 /*
  * Create a TCP connection to host "rhost" at port "rport".
  * If rport == 0, then use the printer service port.
@@ -81,7 +101,9 @@
 {
 	struct hostent *hp;
 	struct servent *sp;
-	struct sockaddr_in sin;
+	union sockaddr_u Sin;
+#define sin	Sin.s4
+#define sin6	Sin.s6
 	int s, timo = 1, lport = IPPORT_RESERVED - 1;
 	int err;
 
@@ -90,24 +112,30 @@
 	 */
 	if (rhost == NULL)
 		fatal(pp, "no remote host to connect to");
-	bzero((char *)&sin, sizeof(sin));
-	sin.sin_len = sizeof sin;
-	sin.sin_family = AF_INET;
-	if (inet_aton(rhost, &sin.sin_addr) == 0) {
-		hp = gethostbyname2(rhost, AF_INET);
-		if (hp == NULL)
-			fatal(pp, "cannot resolve %s: %s", rhost, 
-			      hstrerror(h_errno));
-		/* XXX - should deal with more addresses */
-		sin.sin_addr = *(struct in_addr *)hp->h_addr_list[0];
-	}
+	lp_init_dns_6();
+	hp = gethostbyname(rhost);
+	if (hp == NULL)
+		fatal(pp, "cannot resolve %s: %s", rhost, 
+		      hstrerror(h_errno));
 	if (rport == 0) {
 		sp = getservbyname("printer", "tcp");
 		if (sp == NULL)
 			fatal(pp, "printer/tcp: unknown service");
-		sin.sin_port = sp->s_port;
+		rport = sp->s_port;
 	} else
-		sin.sin_port = htons(rport);
+		rport = htons(rport);
+	if (hp->h_addrtype == AF_INET) {
+		sin.sin_family = hp->h_addrtype;
+		sin.sin_len = sizeof(struct sockaddr_in);
+		bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
+		sin.sin_port = rport;
+	} else {
+		sin6.sin6_family = hp->h_addrtype;
+		sin6.sin6_len = sizeof(struct sockaddr_in6);
+		sin6.sin6_flowinfo = IPV6_PRIORITY_UNCHARACTERIZED;
+		bcopy(hp->h_addr, (caddr_t)&sin6.sin6_addr, hp->h_length);
+		sin6.sin6_port = rport; 
+	}
 
 	/*
 	 * Try connecting to the server.
@@ -157,15 +185,16 @@
 	char name[MAXHOSTNAMELEN];
 	register struct hostent *hp;
 	char *err;
-	struct in_addr *localaddrs;
-	int i, j, nlocaladdrs, ncommonaddrs;
+	void *localaddrs;
+	int i, j, nlocaladdrs, ncommonaddrs, lenaddrs;
 
 	pp->remote = 0;	/* assume printer is local */
 	if (pp->remote_host != NULL) {
 		/* get the addresses of the local host */
 		gethostname(name, sizeof(name));
 		name[sizeof(name) - 1] = '\0';
-		hp = gethostbyname2(name, AF_INET);
+		lp_init_dns_6();
+		hp = gethostbyname(name);
 		if (hp == (struct hostent *) NULL) {
 			asprintf(&err, "unable to get official name "
 				 "for local machine %s: %s",
@@ -176,16 +205,18 @@
 			;
 		nlocaladdrs = i;
 		localaddrs = malloc(i * sizeof(struct in_addr));
+		lenaddrs = hp->h_length;
 		if (localaddrs == 0) {
 			asprintf(&err, "malloc %lu bytes failed",
-				 (u_long)i * sizeof(struct in_addr));
+				 (u_long)i * lenaddrs);
 			return err;
 		}
 		for (i = 0; hp->h_addr_list[i]; i++)
-			localaddrs[i] = *(struct in_addr *)hp->h_addr_list[i];
+			memcpy(localaddrs + i*lenaddrs, hp->h_addr_list[i],
+			       lenaddrs);
 
 		/* get the official name of RM */
-		hp = gethostbyname2(pp->remote_host, AF_INET);
+		hp = gethostbyname(pp->remote_host);
 		if (hp == (struct hostent *) NULL) {
 			asprintf(&err, "unable to get address list for "
 				 "remote machine %s: %s",
@@ -195,15 +226,16 @@
 		}
 
 		ncommonaddrs = 0;
-		for (i = 0; i < nlocaladdrs; i++) {
-			for (j = 0; hp->h_addr_list[j]; j++) {
-				char *them = hp->h_addr_list[j];
-				if (localaddrs[i].s_addr ==
-				    (*(struct in_addr *)them).s_addr)
-					ncommonaddrs++;
+		if (lenaddrs == hp->h_length)
+			for (i = 0; i < nlocaladdrs; i++) {
+				for (j = 0; hp->h_addr_list[j]; j++) {
+					if (memcmp(localaddrs+i*lenaddrs,
+						   hp->h_addr_list[j],
+						   lenaddrs) == 0)
+						ncommonaddrs++;
+				}
 			}
-		}
-			
+
 		/*
 		 * if the two hosts do not share at least one IP address
 		 * then the printer must be remote.
diff -uN src-current/usr.sbin/lpr/common_source/lp.h src-current-ipv6/usr.sbin/lpr/common_source/lp.h
--- src-current/usr.sbin/lpr/common_source/lp.h
+++ src-current-ipv6/usr.sbin/lpr/common_source/lp.h
@@ -203,6 +203,7 @@
 void	 free_printer __P((struct printer *pp));
 void	 free_request __P((struct request *rp));
 int	 getline __P((FILE *));
+void	 lp_init_dns_6(void);
 int	 getport __P((const struct printer *pp, const char *, int));
 int	 getprintcap __P((const char *printer, struct printer *pp));
 int	 getq __P((const struct printer *, struct queue *(*[])));
diff -uN src-current/usr.sbin/lpr/lpd/lpd.c src-current-ipv6/usr.sbin/lpr/lpd/lpd.c
--- src-current/usr.sbin/lpr/lpd/lpd.c
+++ src-current-ipv6/usr.sbin/lpr/lpd/lpd.c
@@ -86,6 +86,7 @@
 #include <arpa/inet.h>
 
 #include <netdb.h>
+#include <resolv.h>
 #include <unistd.h>
 #include <syslog.h>
 #include <signal.h>
@@ -110,12 +111,14 @@
 static void       mcleanup __P((int));
 static void       doit __P((void));
 static void       startup __P((void));
-static void       chkhost __P((struct sockaddr_in *));
+static void       chkhost __P((struct sockaddr_in6 *));
 static int	  ckqueue __P((struct printer *));
 static void	  usage __P((void));
 /* From rcmd.c: */
 int		  __ivaliduser __P((FILE *, u_long, const char *, 
 				    const char *));
+int		  __ivaliduser2 __P((int, FILE *, const char *,
+				    int, const char *, const char *));
 
 uid_t	uid, euid;
 
@@ -127,7 +130,7 @@
 	int f, funix, finet, options, fromlen, i, errs;
 	fd_set defreadfds;
 	struct sockaddr_un un, fromunix;
-	struct sockaddr_in sin, frominet;
+	struct sockaddr_in6 sin, frominet;
 	int lfd;
 	sigset_t omask, nmask;
 	struct servent *sp, serv;
@@ -277,16 +280,18 @@
 	FD_ZERO(&defreadfds);
 	FD_SET(funix, &defreadfds);
 	listen(funix, 5);
-	finet = socket(AF_INET, SOCK_STREAM, 0);
+	finet = socket(AF_INET6, SOCK_STREAM, 0);
 	if (finet >= 0) {
+		lp_init_dns_6();	/* set DNS in IPv6 mode */
 		if (options & SO_DEBUG)
 			if (setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) {
 				syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
 				mcleanup(0);
 			}
 		memset(&sin, 0, sizeof(sin));
-		sin.sin_family = AF_INET;
-		sin.sin_port = sp->s_port;
+		sin.sin6_family = AF_INET6;
+		sin.sin6_len = sizeof(sin);
+		sin.sin6_port = sp->s_port;
 		if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
 			syslog(LOG_ERR, "bind: %m");
 			mcleanup(0);
@@ -318,10 +323,10 @@
 			s = accept(funix,
 			    (struct sockaddr *)&fromunix, &fromlen);
 		} else /* if (FD_ISSET(finet, &readfds)) */  {
-			domain = AF_INET, fromlen = sizeof(frominet);
+			domain = AF_INET6, fromlen = sizeof(frominet);
 			s = accept(finet,
 			    (struct sockaddr *)&frominet, &fromlen);
-			if (frominet.sin_port == htons(20)) {
+			if (frominet.sin6_port == htons(20)) {
 				close(s);
 				continue;
 			}
@@ -341,7 +346,7 @@
 			(void) close(finet);
 			dup2(s, 1);
 			(void) close(s);
-			if (domain == AF_INET) {
+			if (domain == AF_INET6) {
 				from_remote = 1;
 				chkhost(&frominet);
 			} else
@@ -574,19 +579,21 @@
  */
 static void
 chkhost(f)
-	struct sockaddr_in *f;
+	struct sockaddr_in6 *f;
 {
 	register struct hostent *hp;
 	register FILE *hostf;
 	int first = 1;
 	int good = 0;
+	char vb[INET6_ADDRSTRLEN];	/* buffer for Vixie's inet_ntop */
 
 	/* Need real hostname for temporary filenames */
-	hp = gethostbyaddr((char *)&f->sin_addr,
-	    sizeof(struct in_addr), f->sin_family);
+	hp = gethostbyaddr((char *)&f->sin6_addr,
+	    sizeof(struct in6_addr), f->sin6_family);
 	if (hp == NULL)
 		fatal(0, "Host name for your address (%s) unknown",
-			inet_ntoa(f->sin_addr));
+			inet_ntop(f->sin6_family, (char *)&f->sin6_addr,
+				  vb, sizeof vb));
 
 	(void) strncpy(fromb, hp->h_name, sizeof(fromb) - 1);
 	from[sizeof(fromb) - 1] = '\0';
@@ -596,20 +603,23 @@
 	hp = gethostbyname(fromb);
 	if (!hp)
 		fatal(0, "hostname for your address (%s) unknown",
-		    inet_ntoa(f->sin_addr));
+		    inet_ntop(f->sin6_family, (char *)&f->sin6_addr,
+			      vb, sizeof vb));
 	for (; good == 0 && hp->h_addr_list[0] != NULL; hp->h_addr_list++) {
-		if (!bcmp(hp->h_addr_list[0], (caddr_t)&f->sin_addr,
-		    sizeof(f->sin_addr)))
+		if (!bcmp(hp->h_addr_list[0], (caddr_t)&f->sin6_addr,
+		    sizeof(f->sin6_addr)))
 			good = 1;
 	}
 	if (good == 0)
 		fatal(0, "address for your hostname (%s) not matched",
-		    inet_ntoa(f->sin_addr));
+		    inet_ntop(f->sin6_family, (char *)&f->sin6_addr,
+			      vb, sizeof vb));
 
 	hostf = fopen(_PATH_HOSTSEQUIV, "r");
 again:
 	if (hostf) {
-		if (__ivaliduser(hostf, f->sin_addr.s_addr,
+		if (__ivaliduser2(f->sin6_family, hostf,
+		    (char *)&f->sin6_addr, sizeof(struct in6_addr),
 		    DUMMY, DUMMY) == 0) {
 			(void) fclose(hostf);
 			return;
diff -uN src-current/usr.sbin/portmap/pmap_dump/pmap_dump.c src-current-ipv6/usr.sbin/portmap/pmap_dump/pmap_dump.c
--- src-current/usr.sbin/portmap/pmap_dump/pmap_dump.c
+++ src-current-ipv6/usr.sbin/portmap/pmap_dump/pmap_dump.c
@@ -21,9 +21,14 @@
 #else
 #include <netdb.h>
 #endif
+/*
+ * ipv6 rpc : use base address type struct sockaddr_in6 *  in rpc includes
+ */
+#define RPC_USE_INET6	/*  address type is struct sockaddr_in6 *  */
 #include <rpc/rpc.h>
 #include <rpc/pmap_clnt.h>
 #include <rpc/pmap_prot.h>
+#include <resolv.h>
 
 static char *protoname();
 
@@ -32,9 +37,12 @@
 int     argc;
 char  **argv;
 {
-    struct sockaddr_in addr;
+    struct sockaddr_in6 addr;
     register struct pmaplist *list;
     register struct rpcent *rpc;
+
+    (void)res_init();
+    _res.options |= RES_USE_INET6;
 
     get_myaddress(&addr);
 
diff -uN src-current/usr.sbin/portmap/pmap_set/pmap_set.c src-current-ipv6/usr.sbin/portmap/pmap_set/pmap_set.c
--- src-current/usr.sbin/portmap/pmap_set/pmap_set.c
+++ src-current-ipv6/usr.sbin/portmap/pmap_set/pmap_set.c
@@ -19,8 +19,13 @@
 #ifdef SYSV40
 #include <netinet/in.h>
 #endif
+/*
+ * ipv6 rpc : use base address type struct sockaddr_in6 *  in rpc includes
+ */
+#define RPC_USE_INET6	/*  address type is struct sockaddr_in6 *  */
 #include <rpc/rpc.h>
 #include <rpc/pmap_clnt.h>
+#include <resolv.h>
 
 int parse_line __P((char *, u_long *, u_long *, int *, unsigned *));
 
@@ -29,12 +34,15 @@
 int     argc;
 char  **argv;
 {
-    struct sockaddr_in addr;
+    struct sockaddr_in6 addr;
     char    buf[BUFSIZ];
     u_long  prog;
     u_long  vers;
     int     prot;
     unsigned port;
+
+    (void)res_init();
+    _res.options |= RES_USE_INET6;
 
     get_myaddress(&addr);
 
diff -uN src-current/usr.sbin/portmap/from_local.c src-current-ipv6/usr.sbin/portmap/from_local.c
--- src-current/usr.sbin/portmap/from_local.c
+++ src-current-ipv6/usr.sbin/portmap/from_local.c
@@ -59,6 +59,7 @@
 
 #include <net/if.h>
 #include <net/if_dl.h>
+#include <net/route.h>
 #include <netinet/in.h>
 
 #ifndef TRUE
@@ -69,8 +70,37 @@
 /* How many interfaces could there be on a computer? */
 
 #define	ESTIMATED_LOCAL 20
+#define	MAX_LOCAL 64
 static int num_local = -1;
-static struct in_addr *addrs;
+static struct in6_addr *addrs;
+
+#include <stdio.h>
+
+/*
+ * Expand the compacted form of addresses as returned via the
+ * configuration read via sysctl().
+ */
+
+#define ROUNDUP(a) \
+	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+void
+rt_xaddrs(cp, cplim, rtinfo)
+	caddr_t cp, cplim;
+	struct rt_addrinfo *rtinfo;
+{
+	struct sockaddr *sa;
+	int i;
+
+	memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
+	for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
+		if ((rtinfo->rti_addrs & (1 << i)) == 0)
+			continue;
+		rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
+		ADVANCE(cp, sa);
+	}
+}
 
 /* find_local - find all IP addresses for this host */
 
@@ -119,37 +149,79 @@
   end = buf + needed;
 
   for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) {
+    int addrcount;
+    struct if_msghdr *nextifm;
+    struct ifa_msghdr *ifam;
     ifm = (struct if_msghdr *)ptr;
     dl = (struct sockaddr_dl *)(ifm + 1);
     n = dl->sdl_nlen > sizeof ifr.ifr_name ?
         sizeof ifr.ifr_name : dl->sdl_nlen;
     if (n == 0)
       continue;
-    strncpy(ifr.ifr_name, dl->sdl_data, n);
-    if (n < sizeof ifr.ifr_name)
-      ifr.ifr_name[n] = '\0';
-    /* we only want the first address from each interface */
-    if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
-      perror("SIOCGIFFLAGS");
-    else if (ifr.ifr_flags & IFF_UP)    /* active interface */
-      if (ioctl(s, SIOCGIFADDR, &ifr) < 0)
-        perror("SIOCGIFADDR");
-      else {
-        if (alloced < num_local + 1) {
-          alloced += ESTIMATED_LOCAL;
-          if (addrs)
-            addrs = (struct in_addr *)realloc(addrs, alloced * sizeof addrs[0]);
-          else
-            addrs = (struct in_addr *)malloc(alloced * sizeof addrs[0]);
-          if (addrs == NULL) {
-            perror("malloc/realloc");
-            num_local = 0;
-            break;
-          }
-        }
-        addrs[num_local++] = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
+
+    addrcount = 0;
+    ifam = NULL;
+    for (; ptr < end; ptr += ifm->ifm_msglen) {
+      ifm = (struct if_msghdr *)ptr;
+      if (ifm->ifm_type != RTM_NEWADDR)
+	break;
+      if (ifam == NULL)
+	ifam = (struct ifa_msghdr *)ifm;
+      addrcount++;
+    }
+
+    while (addrcount > 0) {
+      struct rt_addrinfo info;
+      info.rti_addrs = ifam->ifam_addrs;
+
+      if (alloced < num_local + 1) {
+	alloced += ESTIMATED_LOCAL;
+	if (addrs)
+	  addrs = (struct in6_addr *)realloc(addrs, alloced * sizeof addrs[0]);
+	else
+	  addrs = (struct in6_addr *)malloc(alloced * sizeof addrs[0]);
+	if (addrs == NULL) {
+	  perror("malloc/realloc");
+	  num_local = 0;
+	  break;
+	}
+      }
+
+      /* Expand the compacted addresses */
+      rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
+		&info);
+
+      if (info.rti_info[RTAX_IFA]->sa_family == AF_INET) {
+	struct sockaddr_in *sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
+	memset(&addrs[num_local], 0, sizeof addrs[num_local]);
+	memcpy(&addrs[num_local].s6_addr[16-4], &sin->sin_addr, 4);
+	memset(&addrs[num_local].s6_addr[16-2-4], -1, 2);
+	num_local++;
+      } else if (info.rti_info[RTAX_IFA]->sa_family == AF_INET6) {
+	struct sockaddr_in6 *sin6
+	  = (struct sockaddr_in6 *)info.rti_info[RTAX_IFA];
+	addrs[num_local++] = sin6->sin6_addr;
+      }
+
+#if 0
+      {
+	int i;
+	fprintf(stderr, "addr=");
+	for (i = 0; i < 7; i++)
+	  fprintf(stderr, "%02x%02x:",
+			  addrs[num_local-1].s6_addr[i*2],
+			  addrs[num_local-1].s6_addr[i*2+1]);
+	fprintf(stderr, "%02x%02x\n",
+			addrs[num_local-1].s6_addr[i*2],
+			addrs[num_local-1].s6_addr[i*2+1]);
       }
+#endif
+
+      addrcount--;
+      ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
+    }
   }
+
   free(buf);
   close(s);
 
@@ -160,17 +232,31 @@
 
 int
 from_local(addr)
-struct sockaddr_in *addr;
+struct sockaddr *addr;
 {
     int     i;
 
+    /* do it every time, the addr list may change ! */
+    /* return TRUE; */
+#if 0
     if (num_local == -1 && find_local() == 0)
+#else
+    if (find_local() == 0)
+#endif
+
 	syslog(LOG_ERR, "cannot find any active local network interfaces");
 
     for (i = 0; i < num_local; i++) {
-	if (memcmp((char *) &(addr->sin_addr), (char *) &(addrs[i]),
-		   sizeof(struct in_addr)) == 0)
-	    return (TRUE);
+        if (addr->sa_family == AF_INET) {
+	    if (IN6_IS_ADDR_V4MAPPED(&addrs[i]) &&
+		memcmp((char *) &(((struct sockaddr_in *)addr)->sin_addr),
+		       ((char *)&(addrs[i])) + 16 - 4, 4) == 0)
+		return (TRUE);
+	} else {
+	    if (memcmp((char *) &(((struct sockaddr_in6 *)addr)->sin6_addr),
+		       (char *) &(addrs[i]), 16) == 0)
+		return (TRUE);
+	}
     }
     return (FALSE);
 }
@@ -181,10 +267,11 @@
 {
     char   *inet_ntoa();
     int     i;
+    char    vb[INET6_ADDRSTRLEN];
 
     find_local();
     for (i = 0; i < num_local; i++)
-	printf("%s\n", inet_ntoa(addrs[i]));
+	printf("%s\n", inet_ntop(AF_INET6, &addrs[i], vb, sizeof vb));
 }
 
 #endif
diff -uN src-current/usr.sbin/portmap/pmap_check.c src-current-ipv6/usr.sbin/portmap/pmap_check.c
--- src-current/usr.sbin/portmap/pmap_check.c
+++ src-current-ipv6/usr.sbin/portmap/pmap_check.c
@@ -46,6 +46,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
+#define RPC_USE_INET6	/*  address type is struct sockaddr_in6 *  */
 #include <rpc/rpc.h>
 #include <rpc/pmap_prot.h>
 #include <syslog.h>
@@ -66,15 +67,19 @@
 static void logit();
 static void toggle_verboselog();
 int     verboselog = 0;
+int	allow_nullproc = 1;
 int     allow_severity = LOG_INFO;
 int     deny_severity = LOG_WARNING;
-
+static	char vb[INET6_ADDRSTRLEN];	/* buffer for Vixie's inet_ntop */
 /* A handful of macros for "readability". */
 
-#define	good_client(a) hosts_ctl("portmap", "", inet_ntoa(a->sin_addr), "")
+#define	good_client(a) hosts_ctl("portmap", "", \
+		 inet_ntop(AF_INET6, (char*)&TOSIN6(addr)->sin6_addr, \
+			   vb, sizeof(vb)), \
+		 "")
 
 #define	legal_port(a,p) \
-  (ntohs((a)->sin_port) < IPPORT_RESERVED || (p) >= IPPORT_RESERVED)
+  (ntohs((a)->sin6_port) < IPPORT_RESERVED || (p) >= IPPORT_RESERVED)
 
 #define log_bad_port(addr, proc, prog) \
   logit(deny_severity, addr, proc, prog, ": request from unprivileged port")
@@ -111,7 +116,7 @@
 
 int
 check_default(addr, proc, prog)
-struct sockaddr_in *addr;
+struct sockaddr_in6 *addr;
 u_long  proc;
 u_long  prog;
 {
@@ -130,7 +135,7 @@
 
 int
 check_privileged_port(addr, proc, prog, port)
-struct sockaddr_in *addr;
+struct sockaddr_in6 *addr;
 u_long  proc;
 u_long  prog;
 u_long  port;
@@ -148,7 +153,7 @@
 
 int
 check_setunset(addr, proc, prog, port)
-struct sockaddr_in *addr;
+struct sockaddr_in6 *addr;
 u_long  proc;
 u_long  prog;
 u_long  port;
@@ -171,7 +176,7 @@
 
 int
 check_callit(addr, proc, prog, aproc)
-struct sockaddr_in *addr;
+struct sockaddr_in6 *addr;
 u_long  proc;
 u_long  prog;
 u_long  aproc;
@@ -182,12 +187,13 @@
 	return (FALSE);
     }
 #endif
-    if (prog == PMAPPROG || prog == NFSPROG || prog == YPXPROG ||
-	(prog == MOUNTPROG && aproc == MOUNTPROC_MNT) ||
-	(prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) {
-	log_no_forward(addr, proc, prog);
-	return (FALSE);
-    }
+    if ( !allow_nullproc || aproc != 0 )
+	if (prog == PMAPPROG || prog == NFSPROG || prog == YPXPROG ||
+	    (prog == MOUNTPROG && aproc == MOUNTPROC_MNT) ||
+	    (prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) {
+	  log_no_forward(addr, proc, prog);
+	  return (FALSE);
+	}
     if (verboselog)
 	log_client(addr, proc, prog);
     return (TRUE);
@@ -206,7 +212,7 @@
 
 static void logit(severity, addr, procnum, prognum, text)
 int     severity;
-struct sockaddr_in *addr;
+struct sockaddr_in6 *addr;
 u_long  procnum;
 u_long  prognum;
 char   *text;
@@ -258,7 +264,8 @@
 	/* Write syslog record. */
 
 	syslog(severity, "connect from %s to %s(%s)%s",
-	       inet_ntoa(addr->sin_addr), procname, progname, text);
+	       inet_ntop(AF_INET6, (char*)&addr->sin6_addr, vb, sizeof(vb)),
+	       procname, progname, text);
 	exit(0);
     }
 }
diff -uN src-current/usr.sbin/portmap/pmap_check.h src-current-ipv6/usr.sbin/portmap/pmap_check.h
--- src-current/usr.sbin/portmap/pmap_check.h
+++ src-current-ipv6/usr.sbin/portmap/pmap_check.h
@@ -1,11 +1,12 @@
 /* @(#) pmap_check.h 1.3 93/11/21 16:18:53 */
 
-extern int from_local();
+extern int from_local(struct sockaddr_in6 *);
 extern void check_startup();
-extern int check_default();
-extern int check_setunset();
-extern int check_privileged_port();
-extern int check_callit();
+extern int check_default(struct sockaddr_in6 *, u_long, u_long);
+extern int check_setunset(struct sockaddr_in6 *, u_long, u_long, u_long);
+extern int check_privileged_port(struct sockaddr_in6 *,
+				 u_long, u_long, u_long);
+extern int check_callit(struct sockaddr_in6 *, u_long, u_long, u_long);
 extern int verboselog;
 extern int allow_severity;
 extern int deny_severity;
diff -uN src-current/usr.sbin/portmap/portmap.c src-current-ipv6/usr.sbin/portmap/portmap.c
--- src-current/usr.sbin/portmap/portmap.c
+++ src-current-ipv6/usr.sbin/portmap/portmap.c
@@ -92,6 +92,7 @@
 #include <string.h>
 #include <syslog.h>
 #include <unistd.h>
+#define RPC_USE_INET6	/*  address type is struct sockaddr_in6 *  */
 #include <rpc/rpc.h>
 #include <rpc/pmap_prot.h>
 #include <sys/socket.h>
@@ -99,6 +100,7 @@
 #include <sys/wait.h>
 #include <sys/signal.h>
 #include <sys/resource.h>
+#include <resolv.h>
 
 #include "pmap_check.h"
 
@@ -117,8 +119,8 @@
 {
 	SVCXPRT *xprt;
 	int sock, c;
-	struct sockaddr_in addr;
-	int len = sizeof(struct sockaddr_in);
+	struct sockaddr_in6 addr;
+	int len = sizeof(struct sockaddr_in6);
 	register struct pmaplist *pml;
 
 	while ((c = getopt(argc, argv, "dv")) != -1) {
@@ -137,20 +139,25 @@
 		}
 	}
 
+	(void)res_init();
+	_res.options |= RES_USE_INET6;
+
 	if (!debugging && daemon(0, 0))
 		err(1, "fork");
 
 	openlog("portmap", debugging ? LOG_PID | LOG_PERROR : LOG_PID,
 	    LOG_DAEMON);
 
-	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+	if ((sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
 		syslog(LOG_ERR, "cannot create udp socket: %m");
 		exit(1);
 	}
 
-	addr.sin_addr.s_addr = 0;
-	addr.sin_family = AF_INET;
-	addr.sin_port = htons(PMAPPORT);
+	addr.sin6_family = AF_INET6;
+	addr.sin6_len = sizeof(struct sockaddr_in6);
+	addr.sin6_flowinfo = IPV6_PRIORITY_UNCHARACTERIZED;
+	addr.sin6_port = htons(PMAPPORT);
+	addr.sin6_addr = in6addr_any;
 	if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
 		syslog(LOG_ERR, "cannot bind udp: %m");
 		exit(1);
@@ -169,7 +176,7 @@
 	pml->pml_map.pm_port = PMAPPORT;
 	pmaplist = pml;
 
-	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+	if ((sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) < 0) {
 		syslog(LOG_ERR, "cannot create tcp socket: %m");
 		exit(1);
 	}
@@ -582,9 +589,10 @@
 		return;
 	}
 	port = pml->pml_map.pm_port;
-	get_myaddress(&me);
+	get_myaddress((struct sockaddr_in6 *)&me);
 	me.sin_port = htons(port);
-	client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &so);
+	client = clntudp_create((struct sockaddr_in6 *)&me,
+				a.rmt_prog, a.rmt_vers, timeout, &so);
 	if (client != (CLIENT *)NULL) {
 		if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) {
 			client->cl_auth = authunix_create(au->aup_machname,
diff -uN src-current/usr.sbin/pppd/Makefile src-current-ipv6/usr.sbin/pppd/Makefile
--- src-current/usr.sbin/pppd/Makefile
+++ src-current-ipv6/usr.sbin/pppd/Makefile
@@ -3,7 +3,7 @@
 CFLAGS+= -DHAVE_PATHS_H
 
 PROG=	pppd
-SRCS=	main.c magic.c fsm.c lcp.c ipcp.c ipxcp.c upap.c chap.c ccp.c \
+SRCS=	main.c magic.c fsm.c lcp.c ipcp.c ipv6cp.c ipxcp.c upap.c chap.c ccp.c \
 	demand.c auth.c options.c sys-bsd.c
 MAN8=	pppd.8
 BINMODE=4555
@@ -12,6 +12,7 @@
 # as per handbook policies section
 MAINTAINER=	peter@freebsd.org
 
+COPTS=	-DINET6
 LDADD=	-lcrypt -lutil -lmd
 DPADD=	${LIBCRYPT} ${LIBUTIL} ${LIBMD}
 
diff -uN src-current/usr.sbin/pppd/auth.c src-current-ipv6/usr.sbin/pppd/auth.c
--- src-current/usr.sbin/pppd/auth.c
+++ src-current-ipv6/usr.sbin/pppd/auth.c
@@ -82,6 +82,30 @@
 #ifdef CBCP_SUPPORT
 #include "cbcp.h"
 #endif
+#ifdef INET6
+#include "ipv6cp.h"
+#define IPCP_OPEN(unit)	{ \
+	extern int do_ipv4, do_ipv6; \
+	if (do_ipv4) ipcp_open(unit); \
+	if (do_ipv6) ipv6cp_open(unit); }
+#define IPCP_CLOSE(unit)	{ \
+	extern int do_ipv4, do_ipv6; \
+	if (do_ipv4) ipcp_close(unit); \
+	if (do_ipv6) ipv6cp_close(unit); }
+#define IPCP_LOWERUP(unit)	{ \
+	extern int do_ipv4, do_ipv6; \
+	if (do_ipv4) ipcp_lowerup(unit); \
+	if (do_ipv6) ipv6cp_lowerup(unit); }
+#define IPCP_LOWERDOWN(unit)	{ \
+	extern int do_ipv4, do_ipv6; \
+	if (do_ipv4) ipcp_lowerdown(unit); \
+	if (do_ipv6) ipv6cp_lowerdown(unit); }
+#else
+#define IPCP_OPEN(unit)		ipcp_open(unit)
+#define IPCP_CLOSE(unit)	ipcp_close(unit)
+#define IPCP_LOWERUP(unit)	ipcp_lowerup(unit)
+#define IPCP_LOWERDOWN(unit)	ipcp_lowerdown(unit)
+#endif
 #include "pathnames.h"
 
 /* Used for storing a sequence of words.  Usually malloced. */
diff -uN src-current/usr.sbin/pppd/ipv6cp.c src-current-ipv6/usr.sbin/pppd/ipv6cp.c
--- src-current/usr.sbin/pppd/ipv6cp.c
+++ src-current-ipv6/usr.sbin/pppd/ipv6cp.c
@@ -0,0 +1,1058 @@
+#ifdef INET6
+/*
+ * ipv6cp.c - PPP IPV6 Control Protocol.
+ *
+ * Derived form ipcp.c  :
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: ipv6cp.c,v 1.1 1997/03/01 19:34:48 Exp $";
+#endif
+
+/*
+ * TODO: negociate compression when supported in kernel
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "ppp.h"
+#include "fsm.h"
+#include "ipcp.h"
+#include "ipv6cp.h"
+#include "pathnames.h"
+
+/* global vars */
+ipv6cp_options ipv6cp_wantoptions[NUM_PPP];	/* Options that we want to request */
+ipv6cp_options ipv6cp_gotoptions[NUM_PPP];	/* Options that peer ack'd */
+ipv6cp_options ipv6cp_allowoptions[NUM_PPP];	/* Options we allow peer to request */
+ipv6cp_options ipv6cp_hisoptions[NUM_PPP];	/* Options that we ack'd */
+
+extern char ifname[];
+extern char devnam[];
+extern int baud_rate;
+int no_token_neg = 0;
+
+/* local vars */
+static int cis_received[NUM_PPP];		/* # Conf-Reqs received */
+
+/*
+ * Callbacks for fsm code.  (CI = Configuration Information)
+ */
+static void ipv6cp_resetci __P((fsm *));	/* Reset our CI */
+static int  ipv6cp_cilen __P((fsm *));	        /* Return length of our CI */
+static void ipv6cp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
+static int  ipv6cp_ackci __P((fsm *, u_char *, int));	/* Peer ack'd our CI */
+static int  ipv6cp_nakci __P((fsm *, u_char *, int));	/* Peer nak'd our CI */
+static int  ipv6cp_rejci __P((fsm *, u_char *, int));	/* Peer rej'd our CI */
+static int  ipv6cp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
+static void ipv6cp_up __P((fsm *));		/* We're UP */
+static void ipv6cp_down __P((fsm *));		/* We're DOWN */
+static void ipv6cp_script __P((fsm *, char *)); /* Run an up/down script */
+
+fsm ipv6cp_fsm[NUM_PPP];		/* IPV6CP fsm structure */
+
+static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */
+    ipv6cp_resetci,		/* Reset our Configuration Information */
+    ipv6cp_cilen,			/* Length of our Configuration Information */
+    ipv6cp_addci,			/* Add our Configuration Information */
+    ipv6cp_ackci,			/* ACK our Configuration Information */
+    ipv6cp_nakci,			/* NAK our Configuration Information */
+    ipv6cp_rejci,			/* Reject our Configuration Information */
+    ipv6cp_reqci,			/* Request peer's Configuration Information */
+    ipv6cp_up,			/* Called when fsm reaches OPENED state */
+    ipv6cp_down,			/* Called when fsm leaves OPENED state */
+    NULL,			/* Called when we want the lower layer up */
+    NULL,			/* Called when we want the lower layer down */
+    NULL,			/* Called when Protocol-Reject received */
+    NULL,			/* Retransmission is necessary */
+    NULL,			/* Called to handle protocol-specific codes */
+    "IPV6CP"			/* String name of protocol */
+};
+
+/*
+ * Protocol entry points from main code.
+ */
+static void ipv6cp_init __P((int));
+static void ipv6cp_open __P((int));
+static void ipv6cp_close __P((int, char *));
+static void ipv6cp_lowerup __P((int));
+static void ipv6cp_lowerdown __P((int));
+static void ipv6cp_input __P((int, u_char *, int));
+static void ipv6cp_protrej __P((int));
+static int  ipv6cp_printpkt __P((u_char *, int,
+			       void (*) __P((void *, char *, ...)), void *));
+static void ipv6_check_options __P((void));
+static int  ipv6_demand_conf __P((int));
+static int  ipv6_active_pkt __P((u_char *, int));
+
+struct protent ipv6cp_protent = {
+    PPP_IPCP,
+    ipv6cp_init,
+    ipv6cp_input,
+    ipv6cp_protrej,
+    ipv6cp_lowerup,
+    ipv6cp_lowerdown,
+    ipv6cp_open,
+    ipv6cp_close,
+    ipv6cp_printpkt,
+    NULL,
+    1,
+    "IPV6CP",
+    ipv6_check_options,
+    ipv6_demand_conf,
+    ipv6_active_pkt
+};
+
+/*
+ * Lengths of configuration options.
+ */
+#define CILEN_VOID	2
+#define CILEN_COMPRESS	4	/* length for RFC2023 compress opt. */
+#define CILEN_ADDR	6	/* new-style single address option */
+
+
+#define CODENAME(x)	((x) == CONFACK ? "ACK" : \
+			 (x) == CONFNAK ? "NAK" : "REJ")
+
+
+/*
+ * Make a string representation of a network address.
+ */
+char *
+token_ntoa(ipaddr)
+u_long ipaddr;
+{
+    static char b[64];
+
+    ipaddr = ntohl(ipaddr);
+
+    sprintf(b, "fe80::%d.%d.%d.%d",
+	    (u_char)(ipaddr >> 24),
+	    (u_char)(ipaddr >> 16),
+	    (u_char)(ipaddr >> 8),
+	    (u_char)(ipaddr));
+    return b;
+}
+
+
+/*
+ * ipv6cp_init - Initialize IPV6CP.
+ */
+void
+ipv6cp_init(unit)
+    int unit;
+{
+    fsm *f = &ipv6cp_fsm[unit];
+    ipv6cp_options *wo = &ipv6cp_wantoptions[unit];
+    ipv6cp_options *ao = &ipv6cp_allowoptions[unit];
+
+    f->unit = unit;
+    f->protocol = PPP_IPV6CP;
+    f->callbacks = &ipv6cp_callbacks;
+    fsm_init(&ipv6cp_fsm[unit]);
+
+    memset(wo, 0, sizeof(*wo));
+    memset(ao, 0, sizeof(*ao));
+
+    wo->accept_local = 1;
+    wo->neg_addr = 1;
+    wo->ouraddr = 0;
+    wo->hisaddr = 0;
+    ao->neg_addr = 1;
+
+#ifdef notyet
+    wo->neg_vj = 1;
+    ao->neg_vj = 1;
+    wo->vj_protocol = IPV6CP_COMP;
+#else
+    wo->neg_vj = 0;
+    ao->neg_vj = 0;
+#endif
+}
+
+
+/*
+ * ipv6cp_open - IPV6CP is allowed to come up.
+ */
+void
+ipv6cp_open(unit)
+    int unit;
+{
+    fsm_open(&ipv6cp_fsm[unit]);
+}
+
+
+/*
+ * ipv6cp_close - Take IPV6CP down.
+ */
+void
+ipv6cp_close(unit, reason)
+    int unit;
+    char *reason;
+{
+    fsm_close(&ipv6cp_fsm[unit], reason);
+}
+
+
+/*
+ * ipv6cp_lowerup - The lower layer is up.
+ */
+void
+ipv6cp_lowerup(unit)
+    int unit;
+{
+    fsm_lowerup(&ipv6cp_fsm[unit]);
+}
+
+
+/*
+ * ipv6cp_lowerdown - The lower layer is down.
+ */
+void
+ipv6cp_lowerdown(unit)
+    int unit;
+{
+    fsm_lowerdown(&ipv6cp_fsm[unit]);
+}
+
+
+/*
+ * ipv6cp_input - Input IPV6CP packet.
+ */
+void
+ipv6cp_input(unit, p, len)
+    int unit;
+    u_char *p;
+    int len;
+{
+    fsm_input(&ipv6cp_fsm[unit], p, len);
+}
+
+
+/*
+ * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP.
+ *
+ * Pretend the lower layer went down, so we shut up.
+ */
+void
+ipv6cp_protrej(unit)
+    int unit;
+{
+    fsm_lowerdown(&ipv6cp_fsm[unit]);
+}
+
+
+/*
+ * ipv6cp_resetci - Reset our CI.
+ */
+static void
+ipv6cp_resetci(f)
+    fsm *f;
+{
+    ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
+    ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+    extern u_long gethostid __P((void));
+
+    wo->req_addr = wo->neg_addr && ipv6cp_allowoptions[f->unit].neg_addr;
+    if (!wo->opt_remote)
+	wo->hisaddr = ipcp_wantoptions[f->unit].hisaddr;
+    if (!wo->opt_local) {
+	wo->ouraddr = ipcp_wantoptions[f->unit].ouraddr;
+	if (!wo->ouraddr)
+	    wo->ouraddr = gethostid();
+	while (!wo->ouraddr)
+	    wo->ouraddr = magic();
+    }
+    *go = *wo;
+    go->hisaddr = 0;	/* last proposed token */
+    cis_received[f->unit] = 0;
+}
+
+
+/*
+ * ipv6cp_cilen - Return length of our CI.
+ */
+static int
+ipv6cp_cilen(f)
+    fsm *f;
+{
+    ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+
+#define LENCIVJ(neg)	(neg ? CILEN_COMPRESS : 0)
+#define LENCIADDR(neg)	(neg ? CILEN_ADDR : 0)
+
+    return (LENCIADDR(go->neg_addr) +
+	    LENCIVJ(go->neg_vj));
+}
+
+
+/*
+ * ipv6cp_addci - Add our desired CIs to a packet.
+ */
+static void
+ipv6cp_addci(f, ucp, lenp)
+    fsm *f;
+    u_char *ucp;
+    int *lenp;
+{
+    ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+    int len = *lenp;
+
+#define ADDCIVJ(opt, neg, val) \
+    if (neg) { \
+	int vjlen = CILEN_COMPRESS; \
+	if (len >= vjlen) { \
+	    PUTCHAR(opt, ucp); \
+	    PUTCHAR(vjlen, ucp); \
+	    PUTSHORT(val, ucp); \
+	    len -= vjlen; \
+	} else \
+	    neg = 0; \
+    }
+
+#define ADDCIADDR(opt, neg, val1) \
+    if (neg) { \
+	int addrlen = CILEN_ADDR; \
+	if (len >= addrlen) { \
+	    u_long l; \
+	    PUTCHAR(opt, ucp); \
+	    PUTCHAR(addrlen, ucp); \
+	    l = ntohl(val1); \
+	    PUTLONG(l, ucp); \
+	    len -= addrlen; \
+	} else \
+	    neg = 0; \
+    }
+
+    ADDCIADDR(CI_TOKEN, go->neg_addr, go->ouraddr);
+
+    ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
+
+    *lenp -= len;
+}
+
+
+/*
+ * ipv6cp_ackci - Ack our CIs.
+ *
+ * Returns:
+ *	0 - Ack was bad.
+ *	1 - Ack was good.
+ */
+static int
+ipv6cp_ackci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+    u_short cilen, citype, cishort;
+    u_long cilong;
+
+    /*
+     * CIs must be in exactly the same order that we sent...
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+
+#define ACKCIVJ(opt, neg, val) \
+    if (neg) { \
+	int vjlen = CILEN_COMPRESS; \
+	if ((len -= vjlen) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != vjlen || \
+	    citype != opt)  \
+	    goto bad; \
+	GETSHORT(cishort, p); \
+	if (cishort != val) \
+	    goto bad; \
+    }
+
+#define ACKCIADDR(opt, neg, val1) \
+    if (neg) { \
+	int addrlen = CILEN_ADDR; \
+	u_long l; \
+	if ((len -= addrlen) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != addrlen || \
+	    citype != opt) \
+	    goto bad; \
+	GETLONG(l, p); \
+	cilong = htonl(l); \
+	if (val1 != cilong) \
+	    goto bad; \
+    }
+
+    ACKCIADDR(CI_TOKEN, go->neg_addr, go->ouraddr);
+
+    ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
+
+    /*
+     * If there are any remaining CIs, then this packet is bad.
+     */
+    if (len != 0)
+	goto bad;
+    return (1);
+
+bad:
+    IPV6CPDEBUG((LOG_INFO, "ipv6cp_ackci: received bad Ack!"));
+    return (0);
+}
+
+/*
+ * ipv6cp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if IPV6CP is in the OPENED state.
+ *
+ * Returns:
+ *	0 - Nak was bad.
+ *	1 - Nak was good.
+ */
+static int
+ipv6cp_nakci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+    u_char citype, cilen, *next;
+    u_short cishort;
+    u_long ciaddr1, l;
+    ipv6cp_options no;		/* options we've seen Naks for */
+    ipv6cp_options try;		/* options to request next time */
+
+    BZERO(&no, sizeof(no));
+    try = *go;
+
+    /*
+     * Any Nak'd CIs must be in exactly the same order that we sent.
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+#define NAKCIADDR(opt, neg, code) \
+    if (go->neg && \
+	len >= (cilen = CILEN_ADDR) && \
+	p[1] == cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETLONG(l, p); \
+	ciaddr1 = htonl(l); \
+	no.neg = 1; \
+	code \
+    }
+
+#define NAKCIVJ(opt, neg, code) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_COMPRESS) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	no.neg = 1; \
+        code \
+    }
+
+    /*
+     * Accept the peer's idea of {our,his} address, if different
+     * from our idea, only if the accept_{local,remote} flag is set.
+     */
+    NAKCIADDR(CI_TOKEN, neg_addr,
+	      if (go->accept_local) {
+		  while (!ciaddr1 || ciaddr1 == go->hisaddr) /* bad luck */
+		      ciaddr1 = magic();
+		  try.ouraddr = ciaddr1;
+		  IPV6CPDEBUG((LOG_INFO, "local LL address %s",
+			     token_ntoa(ciaddr1)));
+	      }
+	      );
+
+    NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
+	    {
+		if (cishort == IPV6CP_COMP) {
+		    try.vj_protocol = cishort;
+		} else {
+		    try.neg_vj = 0;
+		}
+	    }
+	    );
+
+    /*
+     * There may be remaining CIs, if the peer is requesting negotiation
+     * on an option that we didn't include in our request packet.
+     * If they want to negotiate about addresses, we comply.
+     * If they want us to ask for compression, we refuse.
+     */
+    while (len > CILEN_VOID) {
+	GETCHAR(citype, p);
+	GETCHAR(cilen, p);
+	if( (len -= cilen) < 0 )
+	    goto bad;
+	next = p + cilen - 2;
+
+	switch (citype) {
+	case CI_COMPRESSTYPE:
+	    if (go->neg_vj || no.neg_vj ||
+		(cilen != CILEN_COMPRESS))
+		goto bad;
+	    no.neg_vj = 1;
+	    break;
+	case CI_TOKEN:
+	    if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)
+		goto bad;
+	    try.neg_addr = 1;
+	    GETLONG(l, p);
+	    ciaddr1 = htonl(l);
+	    if (go->accept_local) {
+		while (!ciaddr1 || ciaddr1 == go->hisaddr) /* bad luck */
+		    ciaddr1 = magic();
+		try.ouraddr = ciaddr1;
+	    }
+	    no.neg_addr = 1;
+	    break;
+	default:
+	    goto bad;
+	}
+	p = next;
+    }
+
+    /* If there is still anything left, this packet is bad. */
+    if (len != 0)
+	goto bad;
+
+    /*
+     * OK, the Nak is good.  Now we can update state.
+     */
+    if (f->state != OPENED)
+	*go = try;
+
+    return 1;
+
+bad:
+    IPV6CPDEBUG((LOG_INFO, "ipv6cp_nakci: received bad Nak!"));
+    return 0;
+}
+
+
+/*
+ * ipv6cp_rejci - Reject some of our CIs.
+ */
+static int
+ipv6cp_rejci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+    u_char cilen;
+    u_short cishort;
+    u_long cilong;
+    ipv6cp_options try;		/* options to request next time */
+
+    try = *go;
+    /*
+     * Any Rejected CIs must be in exactly the same order that we sent.
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+#define REJCIADDR(opt, neg, val1) \
+    if (go->neg && \
+	len >= (cilen = CILEN_ADDR) && \
+	p[1] == cilen && \
+	p[0] == opt) { \
+	u_long l; \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETLONG(l, p); \
+	cilong = htonl(l); \
+	/* Check rejected value. */ \
+	if (cilong != val1) \
+	    goto bad; \
+	try.neg = 0; \
+    }
+
+#define REJCIVJ(opt, neg, val) \
+    if (go->neg && \
+	p[1] == CILEN_COMPRESS && \
+	len >= p[1] && \
+	p[0] == opt) { \
+	len -= p[1]; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	/* Check rejected value. */  \
+	if (cishort != val) \
+	    goto bad; \
+	try.neg = 0; \
+     }
+
+    REJCIADDR(CI_TOKEN, neg_addr, go->ouraddr);
+
+    REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol);
+
+    /*
+     * If there are any remaining CIs, then this packet is bad.
+     */
+    if (len != 0)
+	goto bad;
+    /*
+     * Now we can update state.
+     */
+    if (f->state != OPENED)
+	*go = try;
+    return 1;
+
+bad:
+    IPV6CPDEBUG((LOG_INFO, "ipv6cp_rejci: received bad Reject!"));
+    return 0;
+}
+
+
+/*
+ * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately.  If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+ipv6cp_reqci(f, inp, len, reject_if_disagree)
+    fsm *f;
+    u_char *inp;		/* Requested CIs */
+    int *len;			/* Length of requested CIs */
+    int reject_if_disagree;
+{
+    ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
+    ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
+    ipv6cp_options *ao = &ipv6cp_allowoptions[f->unit];
+    ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+    u_char *cip, *next;		/* Pointer to current and next CIs */
+    u_short cilen, citype;	/* Parsed len, type */
+    u_short cishort;		/* Parsed short value */
+    u_long tl, ciaddr1;		/* Parsed address values */
+    int rc = CONFACK;		/* Final packet return code */
+    int orc;			/* Individual option return code */
+    u_char *p;			/* Pointer to next char to parse */
+    u_char *ucp = inp;		/* Pointer to current output char */
+    int l = *len;		/* Length left */
+
+    /*
+     * Reset all his options.
+     */
+    BZERO(ho, sizeof(*ho));
+
+    /*
+     * Process all his options.
+     */
+    next = inp;
+    while (l) {
+	orc = CONFACK;			/* Assume success */
+	cip = p = next;			/* Remember begining of CI */
+	if (l < 2 ||			/* Not enough data for CI header or */
+	    p[1] < 2 ||			/*  CI length too small or */
+	    p[1] > l) {			/*  CI length too big? */
+	    IPV6CPDEBUG((LOG_INFO, "ipv6cp_reqci: bad CI length!"));
+	    orc = CONFREJ;		/* Reject bad CI */
+	    cilen = l;			/* Reject till end of packet */
+	    l = 0;			/* Don't loop again */
+	    goto endswitch;
+	}
+	GETCHAR(citype, p);		/* Parse CI type */
+	GETCHAR(cilen, p);		/* Parse CI length */
+	l -= cilen;			/* Adjust remaining length */
+	next += cilen;			/* Step to next CI */
+
+	switch (citype) {		/* Check CI type */
+	case CI_TOKEN:
+	    IPV6CPDEBUG((LOG_INFO, "ipv6cp: received ADDR "));
+
+	    if (!ao->neg_addr ||
+		cilen != CILEN_ADDR) {	/* Check CI length */
+		orc = CONFREJ;		/* Reject CI */
+		break;
+	    }
+
+	    /*
+	     * If he has no address, or if we both have same address
+	     * then NAK it with new idea.
+	     * In particular, if we don't know his address, but he does,
+	     * then accept it.
+	     */
+	    GETLONG(tl, p);	/* Parse source address (his) */
+	    ciaddr1 = htonl(tl);
+	    IPV6CPDEBUG((LOG_INFO, "(%s)", token_ntoa(ciaddr1)));
+	    if (ciaddr1 == 0 && go->ouraddr == 0) {
+		orc = CONFREJ;		/* Reject CI */
+		break;
+	    }
+	    if (ciaddr1 == 0 || ciaddr1 == go->ouraddr ) {
+		orc = CONFNAK;
+		if (!go->hisaddr)	/* first time, try option */
+		    ciaddr1 = wo->hisaddr;
+		while (!ciaddr1 || ciaddr1 == go->ouraddr) /* bad luck */
+		    ciaddr1 = magic();
+		go->hisaddr = ciaddr1;
+		DECPTR(sizeof (long), p);
+		tl = ntohl(ciaddr1);
+		PUTLONG(tl, p);
+	    }
+
+	    ho->neg_addr = 1;
+	    ho->hisaddr = ciaddr1;
+	    break;
+
+	case CI_COMPRESSTYPE:
+	    IPV6CPDEBUG((LOG_INFO, "ipv6cp: received COMPRESSTYPE "));
+	    if (!ao->neg_vj ||
+		(cilen != CILEN_COMPRESS)) {
+		orc = CONFREJ;
+		break;
+	    }
+	    GETSHORT(cishort, p);
+	    IPV6CPDEBUG((LOG_INFO, "(%d)", cishort));
+
+	    if (!(cishort == IPV6CP_COMP)) {
+		orc = CONFREJ;
+		break;
+	    }
+
+	    ho->neg_vj = 1;
+	    ho->vj_protocol = cishort;
+	    break;
+
+	default:
+	    orc = CONFREJ;
+	    break;
+	}
+
+endswitch:
+	IPV6CPDEBUG((LOG_INFO, " (%s)\n", CODENAME(orc)));
+
+	if (orc == CONFACK &&		/* Good CI */
+	    rc != CONFACK)		/*  but prior CI wasnt? */
+	    continue;			/* Don't send this one */
+
+	if (orc == CONFNAK) {		/* Nak this CI? */
+	    if (reject_if_disagree)	/* Getting fed up with sending NAKs? */
+		orc = CONFREJ;		/* Get tough if so */
+	    else {
+		if (rc == CONFREJ)	/* Rejecting prior CI? */
+		    continue;		/* Don't send this one */
+		if (rc == CONFACK) {	/* Ack'd all prior CIs? */
+		    rc = CONFNAK;	/* Not anymore... */
+		    ucp = inp;		/* Backup */
+		}
+	    }
+	}
+
+	if (orc == CONFREJ &&		/* Reject this CI */
+	    rc != CONFREJ) {		/*  but no prior ones? */
+	    rc = CONFREJ;
+	    ucp = inp;			/* Backup */
+	}
+
+	/* Need to move CI? */
+	if (ucp != cip)
+	    BCOPY(cip, ucp, cilen);	/* Move it */
+
+	/* Update output pointer */
+	INCPTR(cilen, ucp);
+    }
+
+    /*
+     * If we aren't rejecting this packet, and we want to negotiate
+     * their address, and they didn't send their address, then we
+     * send a NAK with a CI_TOKEN option appended.  We assume the
+     * input buffer is long enough that we can append the extra
+     * option safely.
+     */
+    if (rc != CONFREJ && !ho->neg_addr &&
+	wo->req_addr && !reject_if_disagree) {
+	if (rc == CONFACK) {
+	    rc = CONFNAK;
+	    ucp = inp;			/* reset pointer */
+	    wo->req_addr = 0;		/* don't ask again */
+	}
+	PUTCHAR(CI_TOKEN, ucp);
+	PUTCHAR(CILEN_ADDR, ucp);
+	tl = ntohl(wo->hisaddr);
+	PUTLONG(tl, ucp);
+    }
+
+    *len = ucp - inp;			/* Compute output length */
+    IPV6CPDEBUG((LOG_INFO, "ipv6cp: returning Configure-%s", CODENAME(rc)));
+    return (rc);			/* Return final code */
+}
+
+
+/*
+ * ipv6_check_options - check that any IPv6-related options are OK,
+ * and assign appropriate defaults.
+ */
+static void
+ipv6_check_options()
+{
+}
+
+/*
+ * ipv6_demand_conf - configure the interface as though
+ * IPV6CP were up, for use with dial-on-demand.
+ */
+static int
+ipv6_demand_conf(u)
+    int u;
+{
+    return 1;
+}
+
+
+/*
+ * ipv6cp_up - IPV6CP has come UP.
+ *
+ * Configure the IPv6 network interface appropriately and bring it up.
+ */
+static void
+ipv6cp_up(f)
+    fsm *f;
+{
+    ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
+    ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+
+    IPV6CPDEBUG((LOG_INFO, "ipv6cp: up"));
+
+    /*
+     * We must have a non-zero LL address for both ends of the link.
+     */
+    if (!ho->neg_addr)
+	ho->hisaddr = ipv6cp_wantoptions[f->unit].hisaddr;
+
+    if (!no_token_neg) {
+      if (ho->hisaddr == 0) {
+	syslog(LOG_ERR, "Could not determine remote LL address");
+	ipv6cp_close(f->unit, "Could not determine remote LL address");
+	return;
+      }
+      if (go->ouraddr == 0) {
+	syslog(LOG_ERR, "Could not determine local LL address");
+	ipv6cp_close(f->unit, "Could not determine local LL address");
+	return;
+      }
+      if (go->ouraddr == ho->hisaddr) {
+	syslog(LOG_ERR, "local and remote LL addresses are equal");
+	ipv6cp_close(f->unit, "local and remote LL addresses are equal");
+	return;
+      }
+    }
+
+    syslog(LOG_NOTICE, "local  LL address %s", token_ntoa(go->ouraddr));
+    syslog(LOG_NOTICE, "remote LL address %s", token_ntoa(ho->hisaddr));
+
+    /*
+     * Set LL addresses
+     */
+    if (!sif6addr(f->unit, go->ouraddr, ho->hisaddr)) {
+	IPV6CPDEBUG((LOG_WARNING, "sif6addr failed"));
+	ipv6cp_close(f->unit, "sif6addr failed");
+	return;
+    }
+
+#ifdef noyet
+    /* set tcp compression */
+    sif6comp(f->unit, ho->neg_vj);
+#endif
+
+    /* bring the interface up for IPv6 */
+    if (!sif6up(f->unit)) {
+	IPV6CPDEBUG((LOG_WARNING, "sif6up failed"));
+	ipv6cp_close(f->unit, "sif6up failed");
+	return;
+    }
+    sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
+
+    /*
+     * Execute the ipv6-up script, like this:
+     *	/etc/ppp/ipv6-up interface tty speed local-LL remote-LL
+     */
+    ipv6cp_script(f, _PATH_IPV6UP);
+
+}
+
+
+/*
+ * ipv6cp_down - IPV6CP has gone DOWN.
+ *
+ * Take the IPv6 network interface down, clear its addresses
+ * and delete routes through it.
+ */
+static void
+ipv6cp_down(f)
+    fsm *f;
+{
+    u_long ouraddr, hisaddr;
+
+    IPV6CPDEBUG((LOG_INFO, "ipv6cp: down"));
+
+    ouraddr = ipv6cp_gotoptions[f->unit].ouraddr;
+    hisaddr = ipv6cp_hisoptions[f->unit].hisaddr;
+    sif6down(f->unit);
+    cif6addr(f->unit, ouraddr, hisaddr);
+
+    /* Execute the ipv6-down script */
+    ipv6cp_script(f, _PATH_IPV6DOWN);
+}
+
+
+/*
+ * ipv6cp_script - Execute a script with arguments
+ * interface-name tty-name speed local-LL remote-LL.
+ */
+static void
+ipv6cp_script(f, script)
+    fsm *f;
+    char *script;
+{
+    char strspeed[32], strlocal[32], strremote[32];
+    char *argv[8];
+
+    sprintf(strspeed, "%d", baud_rate);
+    strcpy(strlocal, token_ntoa(ipv6cp_gotoptions[f->unit].ouraddr));
+    strcpy(strremote, token_ntoa(ipv6cp_hisoptions[f->unit].hisaddr));
+
+    argv[0] = script;
+    argv[1] = ifname;
+    argv[2] = devnam;
+    argv[3] = strspeed;
+    argv[4] = strlocal;
+    argv[5] = strremote;
+    argv[6] = NULL;
+    if (!ipv6cp_gotoptions[f->unit].ouraddr)
+	argv[4] = NULL;
+    run_program(script, argv, 0);
+}
+
+/*
+ * ipv6cp_printpkt - print the contents of an IPV6CP packet.
+ */
+char *ipv6cp_codenames[] = {
+    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+    "TermReq", "TermAck", "CodeRej"
+};
+
+int
+ipv6cp_printpkt(p, plen, printer, arg)
+    u_char *p;
+    int plen;
+    void (*printer) __P((void *, char *, ...));
+    void *arg;
+{
+    int code, id, len, olen;
+    u_char *pstart, *optend;
+    u_short cishort;
+    u_long cilong;
+
+    if (plen < HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *))
+	printer(arg, " %s", ipv6cp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+    switch (code) {
+    case CONFREQ:
+    case CONFACK:
+    case CONFNAK:
+    case CONFREJ:
+	/* print option list */
+	while (len >= 2) {
+	    GETCHAR(code, p);
+	    GETCHAR(olen, p);
+	    p -= 2;
+	    if (olen < 2 || olen > len) {
+		break;
+	    }
+	    printer(arg, " <");
+	    len -= olen;
+	    optend = p + olen;
+	    switch (code) {
+	    case CI_COMPRESSTYPE:
+		if (olen >= CILEN_COMPRESS) {
+		    p += 2;
+		    GETSHORT(cishort, p);
+		    printer(arg, "compress ");
+		    switch (cishort) {
+		    case IPV6CP_COMP:
+			printer(arg, "V6");
+			break;
+		    default:
+			printer(arg, "0x%x", cishort);
+		    }
+		}
+		break;
+	    case CI_TOKEN:
+		if (olen == CILEN_ADDR) {
+		    p += 2;
+		    GETLONG(cilong, p);
+		    printer(arg, "addr %s", token_ntoa(htonl(cilong)));
+		}
+		break;
+	    }
+	    while (p < optend) {
+		GETCHAR(code, p);
+		printer(arg, " %.2x", code);
+	    }
+	    printer(arg, ">");
+	}
+	break;
+    }
+
+    /* print the rest of the bytes in the packet */
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", code);
+    }
+
+    return p - pstart;
+}
+
+static int
+ipv6_active_pkt(pkt, len)
+    u_char *pkt;
+    int len;
+{
+    return 0;
+}
+
+#endif INET6
diff -uN src-current/usr.sbin/pppd/ipv6cp.h src-current-ipv6/usr.sbin/pppd/ipv6cp.h
--- src-current/usr.sbin/pppd/ipv6cp.h
+++ src-current-ipv6/usr.sbin/pppd/ipv6cp.h
@@ -0,0 +1,53 @@
+#ifdef INET6
+/*
+ * ipv6cp.h - IP Control Protocol definitions.
+ *
+ * ipcp.h - IP Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ipcp.h,v 1.3.4.1 1996/03/01 19:34:49 phk Exp $
+ */
+
+/*
+ * Options.
+ */
+#define	CI_TOKEN	1	/* Token */
+#define CI_COMPRESSTYPE	2	/* Compression Type */
+
+/* no compression supported */
+#define IPV6CP_COMP 0x004f	/* current value for compression option*/
+
+typedef struct ipv6cp_options {
+    int neg_addr : 1;		/* Negotiate token ? */
+    int req_addr : 1;		/* Ask peer to send token ? */
+    int neg_vj : 1;		/* Van Jacobson Compression? */
+    int accept_local : 1;	/* accept peer's value for ouraddr */
+    int opt_local : 1;		/* ouraddr set by option */
+    int opt_remote : 1;		/* hisaddr set by option */
+    u_short vj_protocol;	/* protocol value to use in VJ option */
+    u_long ouraddr, hisaddr;	/* Tokens (32 bits) in NETWORK BYTE ORDER */
+} ipv6cp_options;
+
+extern fsm ipv6cp_fsm[];
+extern ipv6cp_options ipv6cp_wantoptions[];
+extern ipv6cp_options ipv6cp_gotoptions[];
+extern ipv6cp_options ipv6cp_allowoptions[];
+extern ipv6cp_options ipv6cp_hisoptions[];
+
+extern struct protent ipv6cp_protent;
+
+#endif /* INET6 */
diff -uN src-current/usr.sbin/pppd/lcp.c src-current-ipv6/usr.sbin/pppd/lcp.c
diff -uN src-current/usr.sbin/pppd/main.c src-current-ipv6/usr.sbin/pppd/main.c
--- src-current/usr.sbin/pppd/main.c
+++ src-current-ipv6/usr.sbin/pppd/main.c
@@ -46,6 +46,9 @@
 #include "fsm.h"
 #include "lcp.h"
 #include "ipcp.h"
+#ifdef INET6
+#include "ipv6cp.h"
+#endif
 #include "upap.h"
 #include "chap.h"
 #include "ccp.h"
@@ -103,6 +106,9 @@
 
 char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n";
 
+int do_ipv4 = 1;		/* accept IPv4 on ppp */
+int do_ipv6 = 1;		/* accept IPv6 on ppp */
+
 /* Prototypes for procedures local to this file. */
 
 static void cleanup __P((void));
@@ -111,6 +117,7 @@
 static void calltimeout __P((void));
 static struct timeval *timeleft __P((struct timeval *));
 static void kill_my_pg __P((int));
+
 static void hup __P((int));
 static void term __P((int));
 static void chld __P((int));
@@ -148,6 +155,9 @@
     &cbcp_protent,
 #endif
     &ipcp_protent,
+#ifdef INET6
+    &ipv6cp_protent,
+#endif
     &ccp_protent,
 #ifdef IPX_CHANGE
     &ipxcp_protent,
diff -uN src-current/usr.sbin/pppd/options.c src-current-ipv6/usr.sbin/pppd/options.c
--- src-current/usr.sbin/pppd/options.c
+++ src-current-ipv6/usr.sbin/pppd/options.c
@@ -33,6 +33,7 @@
 #include <netdb.h>
 #include <pwd.h>
 #include <sys/types.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -47,6 +48,9 @@
 #include "fsm.h"
 #include "lcp.h"
 #include "ipcp.h"
+#ifdef INET6
+#include "ipv6cp.h"
+#endif
 #include "upap.h"
 #include "chap.h"
 #include "ccp.h"
@@ -255,6 +259,19 @@
 static int setmslanman __P((char **));
 #endif
 
+#ifdef INET6
+static int setipv6cptimeout __P((char **));
+static int setipv6cpterm __P((char **));
+static int setipv6cpconf __P((char **));
+static int setipv6cpfails __P((char **));
+static int setipv6cpfix __P((char **));
+static int noipv6addr __P((char **));
+static int noipv6addrdef __P((char **));
+static int settoken __P((char **));
+static int noipv4 __P((char **));
+static int noipv6 __P((char **));
+#endif
+
 static int number_option __P((char *, u_int32_t *, int));
 static int int_option __P((char *, int *));
 static int readable __P((int fd));
@@ -421,6 +438,18 @@
     {"ms-lanman", 0, setmslanman},	/* Use LanMan psswd when using MS-CHAP */
 #endif
 
+#ifdef INET6
+    {"ipv6cp-restart", 1, setipv6cptimeout}, /* Set timeout for IPV6CP */
+    {"ipv6cp-max-terminate", 1, setipv6cpterm}, /* Set max #xmits for term-reqs */
+    {"ipv6cp-max-configure", 1, setipv6cpconf}, /* Set max #xmits for conf-reqs */
+    {"ipv6cp-max-failure", 1, setipv6cpfails}, /* Set max #conf-naks for IPV6CP */
+    {"ipv6cp-fixed-local", 0, setipv6cpfix}, /* Reject peer's address for us */
+    {"--token", 0, noipv6addr}, /* Disable IP token negotiation */
+    {"-token", 0, noipv6addrdef}, /* Disable IP token negotiation */
+    {"link6", 1, settoken}, /* set IPv6 token(s) */
+    {"noipv4", 0, noipv4}, /* Disable IPv4 */
+    {"noipv6", 0, noipv6}, /* Disable IPv6 */
+#endif
     {NULL, 0, NULL}
 };
 
@@ -1190,6 +1219,10 @@
     BZERO((char *) &ipxcp_allowoptions[0], sizeof (struct ipxcp_options));
 #endif /* IPX_CHANGE */
 
+#ifdef INET6
+    BZERO((char *) &ipv6cp_wantoptions[0], sizeof (struct ipv6cp_options));
+    BZERO((char *) &ipv6cp_allowoptions[0], sizeof (struct ipv6cp_options));
+#endif
     return (1);
 }
 
@@ -2552,4 +2585,147 @@
     ms_lanman = 1;
     return (1);
 }
+#endif
+
+#ifdef INET6
+static int setipv6cptimeout(argv)
+    char **argv;
+{
+    return int_option(*argv, &ipv6cp_fsm[0].timeouttime);
+}
+static int
+setipv6cpterm(argv)
+    char **argv;
+{
+    return int_option(*argv, &ipv6cp_fsm[0].maxtermtransmits);
+}
+
+static int
+setipv6cpconf(argv)
+    char **argv;
+{
+    return int_option(*argv, &ipv6cp_fsm[0].maxconfreqtransmits);
+}
+
+static int
+setipv6cpfails(argv)
+    char **argv;
+{
+    return int_option(*argv, &lcp_fsm[0].maxnakloops);
+}
+
+static int
+setipv6cpfix(argv)
+    char **argv;
+{
+    ipv6cp_wantoptions[0].accept_local = 0;
+    return (1);
+}
+
+/*
+ * noipv6addr - Disable token address negotiation.
+ */
+extern int no_token_neg;
+static int
+noipv6addr(argv)
+    char **argv;
+{
+    ipv6cp_wantoptions[0].neg_addr = 0;
+    ipv6cp_allowoptions[0].neg_addr = 0;
+    no_token_neg = 1;
+    return (1);
+}
+
+static int
+noipv6addrdef(argv)
+    char **argv;
+{
+    ipv6cp_wantoptions[0].neg_addr = 0;
+    ipv6cp_allowoptions[0].neg_addr = 1;
+    no_token_neg = 1;
+    return (1);
+}
+
+static int
+noipv4(argv)
+    char **argv;
+{
+    do_ipv4 = 0;
+    return (1);
+}
+
+static int
+noipv6(argv)
+    char **argv;
+{
+    do_ipv6 = 0;
+    return (1);
+}
+
+/*
+ * settoken - Set the v6 token
+ */
+static int
+settoken(argv)
+    char **argv;
+{
+    char *colon, *arg = *argv,  *index();
+    u_long local = 0, remote = 0;
+    ipv6cp_options *wo = &ipv6cp_wantoptions[0];
+    struct in6_addr addr;
+
+    /*
+     * LL address pair separated by a delimiter, (not . or :).
+     */
+#define VALIDC(c) 	(((c) >= '0' && (c) <= '9') || \
+			 ((c) >= 'a' && (c) <= 'z') || \
+			 ((c) >= 'A' && (c) <= 'Z') || \
+			 ((c) == ':' || (c) == '.'))
+
+#define VALIDA(a) 	(IS_LINKLADDR6(a) && \
+			 ((a).s6_addr8[2] == 0) && \
+			 ((a).s6_addr8[3] == 0) && \
+			 ((a).s6_addr32[1] == 0) && \
+			 ((a).s6_addr32[2] == 0))
+			
+    colon = arg;
+    while (VALIDC(*colon))
+	colon++;
+
+    /*
+     * If colon first character, then no local addr.
+     */
+    if (colon != arg) {
+	char c = *colon;
+
+	*colon = '\0';
+	if (inet_pton(AF_INET6, arg, &addr) <= 0 || !VALIDA(addr)) {
+		*colon = c;
+		fprintf(stderr, "illegal token parameter : %s\n", arg);
+		return (-1);
+	}
+	local = (long)addr.s6_addr32[3];
+	wo->ouraddr = local;
+	wo->opt_local = 1;
+	*colon = c;
+    }
+
+    /*
+     * If colon last character, then no remote addr.
+     */
+    if (*colon != '\0')
+	colon++;
+    if (*colon != '\0') {
+	if (inet_pton(AF_INET6, colon, &addr) <= 0 || !VALIDA(addr)) {
+		fprintf(stderr, "illegal token parameter : %s\n", arg);
+		return (-1);
+	}
+	remote = (long)addr.s6_addr32[3];
+	wo->hisaddr = remote;
+	wo->opt_remote = 1;
+    }
+
+    return (1);
+}
+
 #endif
diff -uN src-current/usr.sbin/pppd/pathnames.h src-current-ipv6/usr.sbin/pppd/pathnames.h
--- src-current/usr.sbin/pppd/pathnames.h
+++ src-current-ipv6/usr.sbin/pppd/pathnames.h
@@ -19,6 +19,10 @@
 #define _PATH_IPDOWN	"/etc/ppp/ip-down"
 #define _PATH_AUTHUP	"/etc/ppp/auth-up"
 #define _PATH_AUTHDOWN	"/etc/ppp/auth-down"
+#ifdef INET6
+#define _PATH_IPV6UP	"/etc/ppp/ipv6-up"
+#define _PATH_IPV6DOWN	"/etc/ppp/ipv6-down"
+#endif
 #define _PATH_TTYOPT	"/etc/ppp/options."
 #define _PATH_CONNERRS	"/etc/ppp/connect-errors"
 #define _PATH_USEROPT	".ppprc"
diff -uN src-current/usr.sbin/pppd/ppp.h src-current-ipv6/usr.sbin/pppd/ppp.h
--- src-current/usr.sbin/pppd/ppp.h
+++ src-current-ipv6/usr.sbin/pppd/ppp.h
@@ -35,6 +35,9 @@
 #define CHAP            0xc223  /* Crytpographic Handshake Protocol */
 #define LQR		0xc025	/* Link Quality Report protocol */
 #define IP_VJ_COMP	0x002d	/* VJ TCP compressed IP packet */
+#ifdef INET6
+#define IPV6CP		0x8057	/* IPv6 Control Protocol */
+#endif
 #define DLLHEADERLEN	(sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
 #define MTU		1500	/* Default MTU */
 
diff -uN src-current/usr.sbin/pppd/pppd.8 src-current-ipv6/usr.sbin/pppd/pppd.8
--- src-current/usr.sbin/pppd/pppd.8
+++ src-current-ipv6/usr.sbin/pppd/pppd.8
@@ -27,9 +27,11 @@
 and configuring different network-layer protocols.
 .LP
 The encapsulation scheme is provided by driver code in the kernel.
-Pppd provides the basic LCP, authentication support, and an NCP for
-establishing and configuring the Internet Protocol (IP) (called the IP
-Control Protocol, IPCP).
+Pppd provides the basic LCP, authentication support, and
+NCP for establishing and configuring the Internet Protocol (IP)
+(called the IP Control Protocol, IPCP), and NCP
+for establishing and configuring the Internet Protocol version 6 (IPV6)
+(called the IPv6 Control Protocol, IPV6CP).
 .SH FREQUENTLY USED OPTIONS
 .TP
 .I <tty_name>
@@ -169,6 +171,10 @@
 negotiation, unless the \fIipcp-accept-local\fR and/or
 \fIipcp-accept-remote\fR options are given, respectively.
 .TP
+.B -all
+Don't request or allow negotiation of any options for LCP,  IPCP
+and IPV6CP (use default values).
+.TP
 .B bsdcomp \fInr,nt
 Request that the peer compress packets that it sends, using the
 BSD-Compress scheme, with a maximum code size of \fInr\fR bits, and
@@ -642,6 +648,53 @@
 .B xonxoff
 Use software flow control (i.e. XON/XOFF) to control the flow of data on
 the serial port.
+.SH IPv6 OPTIONS
+.TP
+.B noipv4
+Do not configure IPv4 over ppp.
+.TP
+.B noipv6
+Do not configure IPv6 over ppp.
+.TP
+.B link6 \fI<local_LL_address>\fB/\fI<remote_LL_address>
+Set the local and/or remote interface link-local IPv6 addresses.
+Either one may be omitted.
+The addresses must be a valid link-local address in standard IPv6 notation
+with less that 32 bits in the token part.  (e.g. FE80::1:25 or
+FE80::150.234.56.78).
+The addresses are used to define the 32-bit tokens of the PPP connection.
+.TP
+.B -token
+Do not start the IPv6 token negotiation, but accept if the peer starts a 
+negociation.
+.TP
+.B --token
+Disable the IPv6 token negotiation (with this option, the local and remote
+link-local IPv6 addresses must be specified with the
+.B link6
+option.
+.TP
+.B ipv6cp-fixed-local
+With this option,
+.I pppd
+will reject the peer's idea of our link local IPv6 address and token.
+.TP
+.B ipv6cp-restart \fI<n>
+Set the IPV6CP restart interval (retransmission timeout) to <n> seconds
+(default 3).
+.TP
+.B ipv6cp-max-terminate \fI<n>
+Set the maximum number of IPV6CP terminate-request transmissions to <n>
+(default 3).
+.TP
+.B ipv6cp-max-configure \fI<n>
+Set the maximum number of IPV6CP configure-request transmissions to <n>
+(default 10).
+.TP
+.B ipv6cp-max-failure \fI<n>
+Set the maximum number of IPV6CP configure-NAKs returned before starting
+to send configure-Rejects instead to <n> (default 10).
+.TP
 .SH OPTIONS FILES
 Options can be taken from files as well as the command line.  Pppd
 reads options from the files /etc/ppp/options, ~/.ppprc and
@@ -861,6 +914,33 @@
 to the negotiated addresses.  This may disrupt existing connections,
 and the use of demand dialling with peers that do dynamic IP address
 assignment is not recommended.
+.SH IPv6 NOTES
+.LP
+There is no IPv6 equivalent of the IP options \fBdefaultroute\fR,
+\fBproxyarp\fR, \fBnetmask\fR, \fBdns1\fR, \fBdns2\fR. The interface is always
+configured in point to point mode, with a /128 prefix length.
+.LP
+There is no support (yet) for the IPv6 compression.
+.LP
+The IPv6 mtu is automatically derived from the IPv4 \fBmtu\fR option, or from
+the \fBmru\fR option.
+.LP
+If there is no \fBlink6\fR option, the token used is the IPv4 address
+(if it exists), the hostid, or a random number.
+.LP
+If 
+.I pppd
+is unable to determine both link-local address, and if there is no
+.B -token
+or
+.B --token
+option, the IPv6 connexion fails. If the option
+is present, the interface is configured without addresses.
+.LP
+The IPv6 addresses are not used for matches in the authentification files.
+There is no IPv6 equivalent of the
+.B usehostname
+option.
 .SH EXAMPLES
 .LP
 The following examples assume that the /etc/ppp/options file contains
@@ -1053,6 +1133,20 @@
 invoked in the same manner and with the same parameters as the ipx-up
 script, and the same security considerations apply.
 .TP
+.B /etc/ppp/ipv6-up
+A program or script which is executed when the link is available for
+sending and receiving IPv6 packets (that is, IPV6CP has come up).  It is
+executed with the parameters \fIinterface-name tty-device speed
+link-local-local-IPv6-address link-local-remote-IPv6-address\fR.
+If not Link-local address has been configured, the two last arguments are
+suppressed.
+.TP
+.B /etc/ppp/ipv6-down
+A program or script which is executed when the link is no longer
+available for sending and receiving IPv6 packets.  This script can be
+used for undoing the effects of the /etc/ppp/ipv6-up script.  It is
+invoked with the same parameters as the ipv6-up script.
+.TP
 .B /etc/ppp/pap-secrets
 Usernames, passwords and IP addresses for PAP authentication.  This
 file should be owned by root and not readable or writable by any other
@@ -1124,6 +1218,10 @@
 Simpson, W.A.
 .I PPP in HDLC-like Framing.
 July 1994.
+.B RFC2023
+Haskin D., Allen E.
+IP Version 6 over PPP
+1996 October.
 .SH NOTES
 The following signals have the specified effect when sent to pppd.
 .TP
diff -uN src-current/usr.sbin/pppd/pppd.h src-current-ipv6/usr.sbin/pppd/pppd.h
--- src-current/usr.sbin/pppd/pppd.h
+++ src-current-ipv6/usr.sbin/pppd/pppd.h
@@ -68,6 +68,10 @@
 extern char	peer_authname[];/* Authenticated name of peer */
 extern int	privileged;	/* We were run by real-uid root */
 extern int	need_holdoff;	/* Need holdoff period after link terminates */
+#ifdef INET6
+extern int do_ipv4;		/* IPv4 on ppp */
+extern int do_ipv6;		/* IPv6 on ppp */
+#endif
 
 /*
  * Variables set by command-line options.
@@ -407,14 +411,15 @@
 #define DEBUGFSM	1
 #define DEBUGLCP	1
 #define DEBUGIPCP	1
+#define DEBUGIPV6CP	1
 #define DEBUGUPAP	1
 #define DEBUGCHAP	1
 #endif
 
 #ifndef LOG_PPP			/* we use LOG_LOCAL2 for syslog by default */
 #if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUGSYS) \
-  || defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGUPAP) \
-  || defined(DEBUGCHAP) || defined(DEBUG)
+  || defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGIPV6CP) \
+  || defined(DEBUGUPAP) || defined(DEBUGCHAP) || defined(DEBUG)
 #define LOG_PPP LOG_LOCAL2
 #else
 #define LOG_PPP LOG_DAEMON
@@ -449,6 +454,12 @@
 #define IPCPDEBUG(x)	if (debug) syslog x
 #else
 #define IPCPDEBUG(x)
+#endif
+
+#ifdef DEBUGIPV6CP
+#define IPV6CPDEBUG(x)	if (debug) syslog x
+#else
+#define IPV6CPDEBUG(x)
 #endif
 
 #ifdef DEBUGUPAP
diff -uN src-current/usr.sbin/pppd/sys-bsd.c src-current-ipv6/usr.sbin/pppd/sys-bsd.c
--- src-current/usr.sbin/pppd/sys-bsd.c
+++ src-current-ipv6/usr.sbin/pppd/sys-bsd.c
@@ -62,6 +62,11 @@
 #include <netipx/ipx.h>
 #endif
 
+#ifdef INET6
+#include <net/if_var.h>
+#include <netinet/in6_var.h>
+#endif
+
 #if RTM_VERSION >= 3
 #include <sys/param.h>
 #if defined(NetBSD)
@@ -83,6 +88,10 @@
 static int initfdflags = -1;	/* Initial file descriptor flags for ppp_fd */
 static int ppp_fd = -1;		/* fd which is set to PPP discipline */
 static int rtm_seq;
+#ifdef INET6
+static int sifup_any __P((int, int));
+static int sifdown_any __P((int, int));
+#endif
 
 static int restore_term;	/* 1 => we've munged the terminal */
 static struct termios inittermios; /* Initial TTY termios */
@@ -870,9 +879,34 @@
 /*
  * sifup - Config the interface up and enable IP packets to pass.
  */
+#ifdef INET6
+int
+sifup(u)
+    int u;
+{
+    return sifup_any(u, PPP_IP);
+}
+
+/*
+ * sif6up - Config the interface up and enable IPv6 packets to pass.
+ */
+int
+sif6up(u)
+    int u;
+{
+    return sifup_any(u, PPP_IPV6);
+}
+#endif
+
+#ifdef INET6
+static int
+sifup_any(u, f)
+    int u, f;
+#else
 int
 sifup(u)
     int u;
+#endif
 {
     struct ifreq ifr;
 
@@ -913,16 +947,44 @@
 /*
  * sifdown - Config the interface down and disable IP.
  */
+#ifdef INET6
+int
+sifdown(u)
+    int u;
+{
+	return sifdown_any(u, PPP_IP);
+}
+/*
+ * sif6down - Config the interface down and disable IPv6.
+ */
+int
+sif6down(u)
+    int u;
+{
+	return sifdown_any(u, PPP_IPV6);
+}
+#endif
+
+#ifdef INET6
+static int
+sifdown_any(u, f)
+    int u, f;
+#else
 int
 sifdown(u)
     int u;
+#endif
 {
     struct ifreq ifr;
     int rv;
     struct npioctl npi;
 
     rv = 1;
+#ifdef INET6
+    npi.protocol = f;
+#else
     npi.protocol = PPP_IP;
+#endif
     npi.mode = NPMODE_ERROR;
     ioctl(ppp_fd, PPPIOCSNPMODE, (caddr_t) &npi);
     /* ignore errors, because ppp_fd might have been closed by now. */
@@ -1017,6 +1079,111 @@
     }
     return 1;
 }
+
+#ifdef INET6
+/*
+ * sif6addr - Config the interface IPv6 link local addresses
+ */
+static int s6 = -1;			/* socket descriptor */
+
+int
+sif6addr(u, o, h, m)
+    int u;
+    u_long o, h, m;
+{
+    struct in6_aliasreq ifra;
+
+    if (!o || !h)
+	return 1;
+    if ((s6 < 0) && (s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+	syslog(LOG_ERR, "socket : %m");
+	return 0;
+    }
+    bzero(&ifra, sizeof ifra);
+    strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
+    ifra.ifra_addr.sin6_family = AF_INET6;
+    ifra.ifra_dstaddr.sin6_family = AF_INET6;
+    ifra.ifra_mask.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+    ifra.ifra_addr.sin6_len = sizeof (struct sockaddr_in6);
+    ifra.ifra_dstaddr.sin6_len = sizeof (struct sockaddr_in6);
+    ifra.ifra_mask.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+    ifra.ifra_addr.sin6_addr.s6_addr8[0] = 0xfe;
+    ifra.ifra_addr.sin6_addr.s6_addr8[1] = 0x80;
+    ifra.ifra_addr.sin6_addr.s6_addr32[3] = o;
+    ifra.ifra_dstaddr.sin6_addr.s6_addr8[0] = 0xfe;
+    ifra.ifra_dstaddr.sin6_addr.s6_addr8[1] = 0x80;
+    ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] = h;
+    memset((caddr_t)&ifra.ifra_mask.sin6_addr, -1, 16);
+    if (ioctl(s6, SIOCAIFADDR6, (caddr_t) &ifra) < 0) {
+	if (errno != EEXIST) {
+	    syslog(LOG_ERR, "ioctl(SIOCAIFADDR6): %m");
+	    return 0;
+	}
+	syslog(LOG_WARNING, "ioctl(SIOCAIFADDR6): Address already exists");
+    }
+    return 1;
+}
+
+/*
+ * cif6addr - Clear the interface IPv6 addresses, and delete routes
+ * through the interface if possible.
+ */
+int
+cif6addr(u, o, h)
+    int u;
+    u_long o, h;
+{
+    struct in6_aliasreq ifra;
+
+#if 1	/* preferred version : destroy ALL inet6 addrs */
+    struct in6_ifreq *ifr = (struct in6_ifreq *)&ifra;	/* same structure */
+
+    for(;;) {
+	bzero(&ifra, sizeof ifra);
+	strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
+	if (ioctl(s6, SIOCGIFADDR6, (caddr_t)ifr) < 0) {
+	    if (errno == EADDRNOTAVAIL)
+		break;		/* no more address */
+	    syslog(LOG_WARNING, "ioctl(SIOCGIFADDR6): %m");
+	    return 0;
+	}
+/* SIOCDIFADDR6 use only the ifra_addr(==ifr_Addr) information */
+	if (ioctl(s6, SIOCDIFADDR6, (caddr_t) &ifra) < 0) {
+	    syslog(LOG_WARNING, "ioctl(SIOCDIFADDR6): %m");
+	    return 0;
+	}
+    }
+    return 1;
+#else
+    if (!o || !h || s6 < 0)
+	return 1;
+    bzero(&ifra, sizeof ifra);
+    strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
+    ifra.ifra_addr.sin6_family = AF_INET6;
+    ifra.ifra_dstaddr.sin6_family = AF_INET6;
+    ifra.ifra_mask.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+    ifra.ifra_addr.sin6_len = sizeof (struct sockaddr_in6);
+    ifra.ifra_dstaddr.sin6_len = sizeof (struct sockaddr_in6);
+    ifra.ifra_mask.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+    ifra.ifra_addr.sin6_addr.s6_addr8[0] = 0xfe;
+    ifra.ifra_addr.sin6_addr.s6_addr8[1] = 0x80;
+    ifra.ifra_addr.sin6_addr.s6_addr32[3] = o;
+    ifra.ifra_dstaddr.sin6_addr.s6_addr8[0] = 0xfe;
+    ifra.ifra_dstaddr.sin6_addr.s6_addr8[1] = 0x80;
+    ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] = h;
+    memset((caddr_t)&ifra.ifra_mask.sin6_addr, -1, 16);
+    if (ioctl(s6, SIOCDIFADDR6, (caddr_t) &ifra) < 0) {
+	syslog(LOG_WARNING, "ioctl(SIOCDIFADDR6): %m");
+	return 0;
+    }
+    return 1;
+#endif
+}
+#endif /* INET6 */
 
 /*
  * sifdefaultroute - assign a default route through the address given.
diff -uN src-current/usr.sbin/rpc.lockd/Makefile src-current-ipv6/usr.sbin/rpc.lockd/Makefile
--- src-current/usr.sbin/rpc.lockd/Makefile
+++ src-current-ipv6/usr.sbin/rpc.lockd/Makefile
@@ -7,7 +7,7 @@
 DPADD=	${LIBRPCSVC}
 LDADD=	-lrpcsvc
 
-CFLAGS+= -I.
+CFLAGS+= -DRPC_USE_INET6 -I.
 
 CLEANFILES= nlm_prot_svc.c nlm_prot.h
 
diff -uN src-current/usr.sbin/rpc.lockd/lockd.c src-current-ipv6/usr.sbin/rpc.lockd/lockd.c
--- src-current/usr.sbin/rpc.lockd/lockd.c
+++ src-current-ipv6/usr.sbin/rpc.lockd/lockd.c
@@ -46,6 +46,7 @@
 #include <rpc/rpc.h>
 #include <rpc/pmap_clnt.h>
 #include "lockd.h"
+#include <resolv.h>
 
 void nlm_prog_1 __P((struct svc_req *, SVCXPRT *));
 void nlm_prog_3 __P((struct svc_req *, SVCXPRT *));
@@ -67,6 +68,9 @@
     /* Ensure at least some debug if -d with no specified level		*/
     if (!debug_level) debug_level = 1;
   }
+
+  (void)res_init();
+  _res.options |= RES_USE_INET6;
 
   (void)pmap_unset(NLM_PROG, NLM_VERS);
   (void)pmap_unset(NLM_PROG, NLM_VERSX);
diff -uN src-current/usr.sbin/rpc.lockd/procs.c src-current-ipv6/usr.sbin/rpc.lockd/procs.c
--- src-current/usr.sbin/rpc.lockd/procs.c
+++ src-current-ipv6/usr.sbin/rpc.lockd/procs.c
@@ -49,6 +49,7 @@
 #define	CLIENT_CACHE_SIZE	64	/* No. of client sockets cached	*/
 #define	CLIENT_CACHE_LIFETIME	120	/* In seconds			*/
 
+char vb[INET6_ADDRSTRLEN];		/* buffer for Vixie's inet_ntop */
 
 /* log_from_addr ----------------------------------------------------------- */
 /*
@@ -60,12 +61,12 @@
 
 static void log_from_addr(char *fun_name, struct svc_req *req)
 {
-  struct sockaddr_in *addr;
+  struct sockaddr_in6 *addr;
   struct hostent *host;
   char hostname_buf[40];
 
   addr = svc_getcaller(req->rq_xprt);
-  host = gethostbyaddr((char *)&(addr->sin_addr), addr->sin_len, AF_INET);
+  host = gethostbyaddr((char *)&(addr->sin6_addr), addr->sin6_len, AF_INET6);
   if (host)
   {
     strncpy(hostname_buf, host->h_name, sizeof(hostname_buf));
@@ -73,7 +74,8 @@
   }
   else	/* No hostname available - print raw address	*/
   {
-    strcpy(hostname_buf, inet_ntoa(addr->sin_addr));
+    strcpy(hostname_buf,
+	   inet_ntop(AF_INET6, &addr->sin6_addr, vb, sizeof(vb)));
   }
 
   syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf);
@@ -112,10 +114,10 @@
 
 static CLIENT *clnt_cache_ptr[CLIENT_CACHE_SIZE];
 static long clnt_cache_time[CLIENT_CACHE_SIZE];	/* time entry created	*/
-static struct in_addr clnt_cache_addr[CLIENT_CACHE_SIZE];
+static struct in6_addr clnt_cache_addr[CLIENT_CACHE_SIZE];
 static int clnt_cache_next_to_use = 0;
 
-static CLIENT *get_client(struct sockaddr_in *host_addr)
+static CLIENT *get_client(struct sockaddr_in6 *host_addr)
 {
   CLIENT *client;
   int sock_no;
@@ -140,8 +142,8 @@
       client = NULL;
     }
 
-    if (client && !memcmp(&clnt_cache_addr[i], &host_addr->sin_addr,
-      sizeof(struct in_addr)))
+    if (client && !memcmp(&clnt_cache_addr[i], &host_addr->sin6_addr,
+      sizeof(struct in6_addr)))
     {
       /* Found it!							*/
       if (debug_level > 3) syslog(LOG_DEBUG, "Found CLIENT* in cache");
@@ -161,19 +163,19 @@
   sock_no = RPC_ANYSOCK;
   retry_time.tv_sec = 5;
   retry_time.tv_usec = 0;
-  host_addr->sin_port = 0;	/* Force consultation with portmapper	*/
+  host_addr->sin6_port = 0;	/* Force consultation with portmapper	*/
   client = clntudp_create(host_addr, NLM_PROG, NLM_VERS, retry_time, &sock_no);
   if (!client)
   {
     syslog(LOG_ERR, clnt_spcreateerror("clntudp_create"));
     syslog(LOG_ERR, "Unable to return result to %s",
-      inet_ntoa(host_addr->sin_addr));
+	   inet_ntop(AF_INET6, &host_addr->sin6_addr, vb, sizeof(vb)));
     return NULL;
   }
 
   /* Success - update the cache entry					*/
   clnt_cache_ptr[clnt_cache_next_to_use] = client;
-  clnt_cache_addr[clnt_cache_next_to_use] = host_addr->sin_addr;
+  clnt_cache_addr[clnt_cache_next_to_use] = host_addr->sin6_addr;
   clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec;
   if (++clnt_cache_next_to_use > CLIENT_CACHE_SIZE)
     clnt_cache_next_to_use = 0;
@@ -185,8 +187,9 @@
   retry_time.tv_usec = -1;
   clnt_control(client, CLSET_TIMEOUT, &retry_time);
 
-  if (debug_level > 3) syslog(LOG_DEBUG, "Created CLIENT* for %s",
-      inet_ntoa(host_addr->sin_addr));
+  if (debug_level > 3)
+    syslog(LOG_DEBUG, "Created CLIENT* for %s",
+	   inet_ntop(AF_INET6, &host_addr->sin6_addr, vb, sizeof(vb)));
   return client;
 }
 
@@ -203,7 +206,7 @@
 static void transmit_result(int opcode, nlm_res *result, struct svc_req *req)
 {
   static char dummy;
-  struct sockaddr_in *addr;
+  struct sockaddr_in6 *addr;
   CLIENT *cli;
   int success;
   struct timeval timeo;
@@ -275,7 +278,7 @@
 {
   nlm_testres res;
   static char dummy;
-  struct sockaddr_in *addr;
+  struct sockaddr_in6 *addr;
   CLIENT *cli;
   int success;
   struct timeval timeo;
diff -uN src-current/usr.sbin/rpc.lockd/test.c src-current-ipv6/usr.sbin/rpc.lockd/test.c
--- src-current/usr.sbin/rpc.lockd/test.c
+++ src-current-ipv6/usr.sbin/rpc.lockd/test.c
@@ -7,8 +7,10 @@
 	"$Id: test.c,v 1.3 1997/10/13 11:11:02 charnier Exp $";
 #endif /* not lint */
 
+#define RPC_USE_INET6	/* address type is struct sockaddr_in6 * */
 #include <rpc/rpc.h>
 #include <rpcsvc/nlm_prot.h>
+#include <resolv.h>
 
 /* Default timeout can be changed using clnt_control() */
 static struct timeval TIMEOUT = { 0, 0 };
@@ -309,6 +311,9 @@
   nlm_res *out;
   nlm_lockargs arg;
   struct timeval tim;
+
+  (void)res_init();
+  _res.options |= RES_USE_INET6;
 
   printf("Creating client for host %s\n", argv[1]);
   cli = clnt_create(argv[1], NLM_PROG, NLM_VERS, "udp");
diff -uN src-current/usr.sbin/rpc.statd/Makefile src-current-ipv6/usr.sbin/rpc.statd/Makefile
--- src-current/usr.sbin/rpc.statd/Makefile
+++ src-current-ipv6/usr.sbin/rpc.statd/Makefile
@@ -7,7 +7,7 @@
 DPADD=	${LIBRPCSVC}
 LDADD=	-lrpcsvc
 
-CFLAGS+= -I.
+CFLAGS+= -DRPC_USE_INET6 -I.
 
 CLEANFILES= sm_inter_svc.c sm_inter.h
 
diff -uN src-current/usr.sbin/rpc.statd/statd.c src-current-ipv6/usr.sbin/rpc.statd/statd.c
--- src-current/usr.sbin/rpc.statd/statd.c
+++ src-current-ipv6/usr.sbin/rpc.statd/statd.c
@@ -51,9 +51,14 @@
 #include <signal.h>
 #include "statd.h"
 
+#include <resolv.h>
+
 int debug = 0;		/* Controls syslog() calls for debug messages	*/
 
 extern void sm_prog_1(struct svc_req *rqstp, SVCXPRT *transp);
+/* sm_inter.x distributed by Sun omits the SM_NOTIFY */
+static void my_sm_prog_1(struct svc_req *rqstp, SVCXPRT *transp);
+extern void *sm_notify_1_svc(stat_chge *arg, struct svc_req *req);
 static void handle_sigchld();
 static void usage __P((void));
 
@@ -70,18 +75,21 @@
     debug = 1;
   }
 
+  (void)res_init();
+  _res.options |= RES_USE_INET6;
+
   (void)pmap_unset(SM_PROG, SM_VERS);
 
   transp = svcudp_create(RPC_ANYSOCK);
   if (transp == NULL)
     errx(1, "cannot create udp service");
-  if (!svc_register(transp, SM_PROG, SM_VERS, sm_prog_1, IPPROTO_UDP))
+  if (!svc_register(transp, SM_PROG, SM_VERS, my_sm_prog_1, IPPROTO_UDP))
     errx(1, "unable to register (SM_PROG, SM_VERS, udp)");
 
   transp = svctcp_create(RPC_ANYSOCK, 0, 0);
   if (transp == NULL)
     errx(1, "cannot create tcp service");
-  if (!svc_register(transp, SM_PROG, SM_VERS, sm_prog_1, IPPROTO_TCP))
+  if (!svc_register(transp, SM_PROG, SM_VERS, my_sm_prog_1, IPPROTO_TCP))
     errx(1, "unable to register (SM_PROG, SM_VERS, tcp)");
   init_file("/var/db/statd.status");
 
@@ -136,5 +144,30 @@
   }
   else syslog(LOG_ERR, "Child %d failed with status %d", pid,
     WEXITSTATUS(status));
+}
+
+void
+my_sm_prog_1(struct svc_req *rqstp, register SVCXPRT *transp)
+{
+	struct stat_chge argument;
+	char *result;
+
+	if (rqstp->rq_proc != SM_NOTIFY)
+		return sm_prog_1(rqstp, transp);
+
+	(void) memset((char *)&argument, 0, sizeof (argument));
+	if (!svc_getargs(transp, xdr_stat_chge, (caddr_t) &argument)) {
+		svcerr_decode(transp);
+		return;
+	}
+	result = sm_notify_1_svc(&argument, rqstp);
+	if (result != NULL && !svc_sendreply(transp, xdr_void, result)) {
+		svcerr_systemerr(transp);
+	}
+	if (!svc_freeargs(transp, xdr_stat_chge, (caddr_t) &argument)) {
+		syslog(LOG_ERR, "unable to free arguments");
+		exit(1);
+	}
+	return;
 }
 
diff -uN src-current/usr.sbin/rpc.statd/test.c src-current-ipv6/usr.sbin/rpc.statd/test.c
--- src-current/usr.sbin/rpc.statd/test.c
+++ src-current-ipv6/usr.sbin/rpc.statd/test.c
@@ -4,9 +4,11 @@
 	"$Id: test.c,v 1.2 1997/10/13 11:13:33 charnier Exp $";
 #endif /* not lint */
 
+#define RPC_USE_INET6	/* address type is struct sockaddr_in6 * */
 #include <stdio.h>
 #include <rpc/rpc.h>
 #include <rpcsvc/sm_inter.h>
+#include <resolv.h>
 
 
 /* Default timeout can be changed using clnt_control() */
@@ -100,6 +102,9 @@
     fprintf(stderr, "always talks to statd at localhost\n");
     exit(1);
   }
+
+  (void)res_init();
+  _res.options |= RES_USE_INET6;
 
   printf("Creating client for localhost\n" );
   cli = clnt_create("localhost", SM_PROG, SM_VERS, "udp");
diff -uN src-current/usr.sbin/sendmail/cf/cf/freebsd.mc src-current-ipv6/usr.sbin/sendmail/cf/cf/freebsd.mc
--- src-current/usr.sbin/sendmail/cf/cf/freebsd.mc
+++ src-current-ipv6/usr.sbin/sendmail/cf/cf/freebsd.mc
@@ -52,3 +52,4 @@
 define(`BITNET_RELAY', mailhost.Berkeley.EDU)dnl
 define(`CSNET_RELAY', mailhost.Berkeley.EDU)dnl
 define(`confCW_FILE', `-o /etc/sendmail.cw')dnl
+define(`confDAEMON_OPTIONS', `Family=inet6')dnl
diff -uN src-current/usr.sbin/sendmail/src/Makefile src-current-ipv6/usr.sbin/sendmail/src/Makefile
--- src-current/usr.sbin/sendmail/src/Makefile
+++ src-current-ipv6/usr.sbin/sendmail/src/Makefile
@@ -25,7 +25,7 @@
 #TCPWRAPPERSBASEDIR=	/usr/local
 #TCPWRAPPERS=		-DTCPWRAPPERS -I${TCPWRAPPERSBASEDIR}/include
 
-CFLAGS+=-I${.CURDIR} ${DBMDEF} ${NIS} ${TCPWRAPPERS} #-DNETISO
+CFLAGS+=-I${.CURDIR} ${DBMDEF} ${NIS} ${TCPWRAPPERS} -DNETINET6 #-DNETISO
 
 SRCS=	alias.c arpadate.c clock.c collect.c conf.c convtime.c daemon.c \
 	deliver.c domain.c envelope.c err.c headers.c macro.c main.c map.c \
diff -uN src-current/usr.sbin/sendmail/src/conf.c src-current-ipv6/usr.sbin/sendmail/src/conf.c
--- src-current/usr.sbin/sendmail/src/conf.c
+++ src-current-ipv6/usr.sbin/sendmail/src/conf.c
@@ -4905,6 +4905,9 @@
 #if NETINET
 	"NETINET",
 #endif
+#if NETINET6
+	"NETINET6",
+#endif
 #if NETINFO
 	"NETINFO",
 #endif
diff -uN src-current/usr.sbin/sendmail/src/conf.h src-current-ipv6/usr.sbin/sendmail/src/conf.h
--- src-current/usr.sbin/sendmail/src/conf.h
+++ src-current-ipv6/usr.sbin/sendmail/src/conf.h
@@ -92,6 +92,10 @@
 #  define NETINET	1	/* include internet support */
 # endif
 
+# ifndef NETINET6
+#  define NETINET6	1	/* include IPv6 support */
+# endif
+
 # ifndef NETISO
 #  define NETISO	0	/* do not include ISO socket support */
 # endif
@@ -2176,7 +2180,7 @@
 **  Do some required dependencies
 */
 
-#if NETINET || NETISO
+#if NETINET || NETINET6 || NETISO
 # ifndef SMTP
 #  define SMTP		1	/* enable user and server SMTP */
 # endif
diff -uN src-current/usr.sbin/sendmail/src/daemon.c src-current-ipv6/usr.sbin/sendmail/src/daemon.c
--- src-current/usr.sbin/sendmail/src/daemon.c
+++ src-current-ipv6/usr.sbin/sendmail/src/daemon.c
@@ -151,6 +151,13 @@
 		port = DaemonAddr.sin.sin_port;
 		break;
 
+#if NETINET6
+	  case AF_INET6:
+		/* do something if any != :: */
+		port = DaemonAddr.sin6.sin6_port;
+		break;
+#endif
+
 	  default:
 		/* unknown protocol */
 		port = 0;
@@ -176,6 +183,12 @@
 		DaemonAddr.sin.sin_port = port;
 		break;
 
+#if NETINET6
+	  case AF_INET6:
+		DaemonAddr.sin6.sin6_port = port;
+		break;
+#endif
+
 	  default:
 		/* unknown protocol */
 		break;
@@ -544,6 +557,12 @@
 				break;
 # endif
 
+# if NETINET6
+			  case AF_INET6:
+				socksize = sizeof DaemonAddr.sin6;
+				break;
+# endif
+
 # if NETISO
 			  case AF_ISO:
 				socksize = sizeof DaemonAddr.siso;
@@ -644,6 +663,14 @@
 			else if (strcasecmp(v, "inet") == 0)
 				DaemonAddr.sa.sa_family = AF_INET;
 #endif
+#if NETINET6
+			else if (strcasecmp(v, "inet6") == 0) {
+				DaemonAddr.sa.sa_family = AF_INET6;
+# ifdef SIN6_LEN
+				DaemonAddr.sa.sa_len = sizeof(struct sockaddr_in6);
+# endif
+			}
+#endif
 #if NETISO
 			else if (strcasecmp(v, "iso") == 0)
 				DaemonAddr.sa.sa_family = AF_ISO;
@@ -680,6 +707,8 @@
 				break;
 #endif
 
+			  /* TODO: IPv6/len ? */
+
 			  default:
 				syserr("554 Address= option unsupported for family %d",
 					DaemonAddr.sa.sa_family);
@@ -711,6 +740,23 @@
 				break;
 #endif
 
+#if NETINET6
+			  case AF_INET6:
+				if (isascii(*v) && isdigit(*v))
+					DaemonAddr.sin6.sin6_port = htons(atoi(v));
+				else
+				{
+					register struct servent *sp;
+
+					sp = getservbyname(v, "tcp");
+					if (sp == NULL)
+						syserr("554 service \"%s\" unknown", v);
+					else
+						DaemonAddr.sin6.sin6_port = sp->s_port;
+				}
+				break;
+#endif
+
 #if NETISO
 			  case AF_ISO:
 				/* assume two byte transport selector */
@@ -809,6 +855,7 @@
 #endif
 	errno = 0;
 	bzero(&CurHostAddr, sizeof CurHostAddr);
+	bzero(&addr, sizeof addr);
 	SmtpPhase = mci->mci_phase = "initial connection";
 	CurHostName = host;
 
@@ -907,6 +954,14 @@
 			break;
 #endif
 
+#if NETINET6
+		  case AF_INET6:
+			bcopy(hp->h_addr,
+				&addr.sin6.sin6_addr,
+				sizeof addr.sin6.sin6_addr);
+			break;
+#endif
+
 		  default:
 			bcopy(hp->h_addr,
 				addr.sa.sa_data,
@@ -944,6 +999,16 @@
 		break;
 #endif
 
+#if NETINET6
+	  case AF_INET6:
+		addr.sin6.sin6_port = port;
+		addrlen = sizeof (struct sockaddr_in6);
+# ifdef SIN6_LEN
+		addr.sin6.sin6_len = addrlen;
+# endif
+		break;
+#endif
+
 #if NETISO
 	  case AF_ISO:
 		/* assume two byte transport selector */
@@ -982,7 +1047,7 @@
 		{
 			int rport = IPPORT_RESERVED - 1;
 
-			s = rresvport(&rport);
+			s = rresvport_af(&rport, addr.sa.sa_family);
 		}
 		else
 		{
@@ -1076,6 +1141,14 @@
 				break;
 #endif
 
+#if NETINET6
+			  case AF_INET6:
+				bcopy(hp->h_addr_list[addrno++],
+				      &addr.sin6.sin6_addr,
+				      sizeof addr.sin6.sin6_addr);
+				break;
+#endif
+
 			  default:
 				bcopy(hp->h_addr_list[addrno++],
 					addr.sa.sa_data,
@@ -1215,6 +1288,11 @@
 			return bcmp(ha, (char *) &sa->sin.sin_addr, hp->h_length);
 		break;
 
+	  case AF_INET6:
+		if (hp->h_addrtype == AF_INET6)
+			return bcmp(ha, (char *) &sa->sin6.sin6_addr, hp->h_length);
+		break;
+
 	}
 	return -1;
 }
@@ -1930,6 +2008,14 @@
 		return inet_ntoa(sap->sin.sin_addr);
 #endif
 
+#if NETINET6
+	  case AF_INET6:
+		return (char *)inet_ntop(AF_INET6,
+				  &((struct sockaddr_in6 *) sap)->sin6_addr,
+				  buf,
+				  sizeof(buf));
+#endif
+
 #if NETLINK
 	  case AF_LINK:
 		snprintf(buf, sizeof buf, "[LINK: %s]",
@@ -1987,6 +2073,14 @@
 		hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
 			INADDRSZ,
 			AF_INET);
+		break;
+#endif
+
+#if NETINET6
+	  case AF_INET6:
+		hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr,
+			sizeof sap->sin6.sin6_addr,
+			AF_INET6);
 		break;
 #endif
 
diff -uN src-current/usr.sbin/sendmail/src/main.c src-current-ipv6/usr.sbin/sendmail/src/main.c
--- src-current/usr.sbin/sendmail/src/main.c
+++ src-current-ipv6/usr.sbin/sendmail/src/main.c
@@ -428,6 +428,7 @@
 #if NAMED_BIND
 	if (!bitset(RES_INIT, _res.options))
 		res_init();
+	_res.options |= RES_USE_INET6;
 	if (tTd(8, 8))
 		_res.options |= RES_DEBUG;
 	else
@@ -1409,6 +1410,10 @@
 		       newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope);
 		if (RealHostAddr.sa.sa_family == AF_INET)
 			snprintf(pbuf, sizeof pbuf, "%d", RealHostAddr.sin.sin_port);
+#  ifdef NETINET6
+		else if (RealHostAddr.sa.sa_family == AF_INET6)
+			snprintf(pbuf, sizeof pbuf, "%d", RealHostAddr.sin6.sin6_port);
+#  endif
 		else
 			snprintf(pbuf, sizeof pbuf, "0");
 		define(macid("{client_port}", NULL), newstr(pbuf), &BlankEnvelope);
diff -uN src-current/usr.sbin/sendmail/src/sendmail.h src-current-ipv6/usr.sbin/sendmail/src/sendmail.h
--- src-current/usr.sbin/sendmail/src/sendmail.h
+++ src-current-ipv6/usr.sbin/sendmail/src/sendmail.h
@@ -68,13 +68,13 @@
 # include <syslog.h>
 # endif /* LOG */
 
-# if NETINET || NETUNIX || NETISO || NETNS || NETX25
+# if NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25
 # include <sys/socket.h>
 # endif
 # if NETUNIX
 # include <sys/un.h>
 # endif
-# if NETINET
+# if NETINET || NETINET6
 # include <netinet/in.h>
 # endif
 # if NETISO
@@ -1032,7 +1032,7 @@
 **  we are forced to declare a supertype here.
 */
 
-# if NETINET || NETUNIX || NETISO || NETNS || NETX25
+# if NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25
 union bigsockaddr
 {
 	struct sockaddr		sa;	/* general version */
@@ -1041,6 +1041,9 @@
 #endif
 #if NETINET
 	struct sockaddr_in	sin;	/* INET family */
+#endif
+#if NETINET6
+	struct sockaddr_in6	sin6;	/* INET6 family */
 #endif
 #if NETISO
 	struct sockaddr_iso	siso;	/* ISO family */
diff -uN src-current/usr.sbin/sendmail/src/util.c src-current-ipv6/usr.sbin/sendmail/src/util.c
--- src-current/usr.sbin/sendmail/src/util.c
+++ src-current-ipv6/usr.sbin/sendmail/src/util.c
@@ -1242,7 +1242,8 @@
 		else
 		{
 			hp = hostnamebyanyaddr(&sa);
-			if (sa.sa.sa_family == AF_INET)
+			if ((sa.sa.sa_family == AF_INET) ||
+			    (sa.sa.sa_family == AF_INET6))
 				snprintf(p, SPACELEFT(buf, p), "%s/%d",
 					hp, ntohs(sa.sin.sin_port));
 			else
@@ -1257,7 +1258,8 @@
 		else
 		{
 			hp = hostnamebyanyaddr(&sa);
-			if (sa.sa.sa_family == AF_INET)
+			if ((sa.sa.sa_family == AF_INET) ||
+			    (sa.sa.sa_family == AF_INET6))
 				snprintf(p, SPACELEFT(buf, p), "%s/%d",
 					hp, ntohs(sa.sin.sin_port));
 			else
diff -uN src-current/usr.sbin/spray/spray.c src-current-ipv6/usr.sbin/spray/spray.c
--- src-current/usr.sbin/spray/spray.c
+++ src-current-ipv6/usr.sbin/spray/spray.c
@@ -33,10 +33,17 @@
 	"$Id: spray.c,v 1.4 1997/10/20 12:44:53 charnier Exp $";
 #endif /* not lint */
 
+#include <sys/param.h>
+#include <netinet/in.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <resolv.h>
 
+/*
+ * ipv6 rpc : use base address type struct sockaddr_in6 *  in rpc includes
+ */
+#define RPC_USE_INET6	/*  address type is struct sockaddr_in6 *  */
 #include <rpc/rpc.h>
 #include <rpcsvc/spray.h>
 
@@ -69,6 +76,9 @@
 	int delay = 0;
 	int length = 0;
 	double xmit_time;			/* time to receive data */
+
+	(void)res_init();
+	_res.options |= RES_USE_INET6;
 
 	while ((c = getopt(argc, argv, "c:d:l:")) != -1) {
 		switch (c) {
