diff options
| author | itojun <itojun@NetBSD.org> | 1999-12-13 15:17:17 +0000 |
|---|---|---|
| committer | itojun <itojun@NetBSD.org> | 1999-12-13 15:17:17 +0000 |
| commit | ea861f0183f07970865fa35737f2b42e49e3aba0 (patch) | |
| tree | 66276ba5ce54db63f1e39e0faf66b6d48a561f54 | |
| parent | 1501f61891a7a207cce1aa417e23eb96889384b2 (diff) | |
sync IPv6 part with latest KAME tree. IPsec part is left unmodified
due to massive changes in KAME side.
- IPv6 output goes through nd6_output
- faith can capture IPv4 packets as well - you can run IPv4-to-IPv6 translator
using heavily modified DNS servers
- per-interface statistics (required for IPv6 MIB)
- interface autoconfig is revisited
- udp input handling has a big change for mapped address support.
- introduce in4_cksum() for non-overwriting checksumming
- introduce m_pulldown()
- neighbor discovery cleanups/improvements
- netinet/in.h strictly conforms to RFC2553 (no extra defs visible to userland)
- IFA_STATS is fixed a bit (not tested)
- and more more more.
TODO:
- cleanup os-independency #ifdef
- avoid rcvif dual use (for IPsec) to help ifdetach
(sorry for jumbo commit, I can't separate this any more...)
62 files changed, 6298 insertions, 1839 deletions
diff --git a/sys/conf/files b/sys/conf/files index 467088108ff..0e5f13bee41 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $NetBSD: files,v 1.337 1999/12/07 08:28:47 itohy Exp $ +# $NetBSD: files,v 1.338 1999/12/13 15:17:17 itojun Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -598,11 +598,13 @@ file netkey/keysock.c ipsec # inet6 stuff file net/if_faith.c faith needs-count file net/if_gif.c gif needs-count +file net/net_osdep.c file netinet/ip_ecn.c inet | inet6 file netinet/in_gif.c gif & inet file netinet6/in6_gif.c gif & inet6 file netinet6/in6.c inet6 file netinet6/in6_ifattach.c inet6 +file netinet/in4_cksum.c file netinet6/in6_cksum.c inet6 file netinet6/in6_pcb.c inet6 file netinet6/in6_prefix.c inet6 @@ -684,6 +686,7 @@ file kern/tty_tb.c tb needs-count file kern/tty_tty.c file kern/uipc_domain.c file kern/uipc_mbuf.c +file kern/uipc_mbuf2.c file kern/uipc_proto.c file kern/uipc_socket.c file kern/uipc_socket2.c diff --git a/sys/kern/uipc_mbuf2.c b/sys/kern/uipc_mbuf2.c index 999501f6fe3..9866e05f4d4 100644 --- a/sys/kern/uipc_mbuf2.c +++ b/sys/kern/uipc_mbuf2.c @@ -1,4 +1,4 @@ -/* $NetBSD: uipc_mbuf2.c,v 1.1.2.1 1999/11/30 13:34:47 itojun Exp $ */ +/* $NetBSD: uipc_mbuf2.c,v 1.2 1999/12/13 15:17:18 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. diff --git a/sys/net/if.h b/sys/net/if.h index 54d9bbd7ff7..c102ca9a995 100644 --- a/sys/net/if.h +++ b/sys/net/if.h @@ -1,4 +1,4 @@ -/* $NetBSD: if.h,v 1.42 1999/11/19 10:41:42 bouyer Exp $ */ +/* $NetBSD: if.h,v 1.43 1999/12/13 15:17:19 itojun Exp $ */ /* * Copyright (c) 1982, 1986, 1989, 1993 @@ -297,7 +297,7 @@ struct ifaddr { /* * The prefix structure contains information about one prefix * of an interface. They are maintained by the different address families, - * are allocated and attached when an prefix or an address is set, + * are allocated and attached when an prefix or an address is set, * and are linked together so all prfefixes for an interface can be located. */ struct ifprefix { @@ -305,6 +305,7 @@ struct ifprefix { struct ifnet *ifpr_ifp; /* back-pointer to interface */ struct ifprefix *ifpr_next; u_char ifpr_plen; /* prefix length in bits */ + u_char ifpr_type; /* protocol dependent prefix type */ }; /* diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 2ac16afa6ac..02fd2e7170a 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_ethersubr.c,v 1.50 1999/10/12 04:53:45 matt Exp $ */ +/* $NetBSD: if_ethersubr.c,v 1.51 1999/12/13 15:17:19 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -264,13 +264,16 @@ ether_output(ifp, m0, dst, rt0) #endif #ifdef INET6 case AF_INET6: -#ifdef NEWIP6OUTPUT - if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst)) - return(0); /* it must be impossible, but... */ -#else +#ifdef OLDIP6OUTPUT if (!nd6_resolve(ifp, rt, m, dst, (u_char *)edst)) return(0); /* if not yet resolves */ -#endif /* NEWIP6OUTPUT */ +#else + if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst)){ + /* this must be impossible, so we bark */ + printf("nd6_storelladdr failed\n"); + return(0); + } +#endif /* OLDIP6OUTPUT */ etype = htons(ETHERTYPE_IPV6); break; #endif diff --git a/sys/net/if_faith.c b/sys/net/if_faith.c index 45f58034bff..69cd0fdc7ea 100644 --- a/sys/net/if_faith.c +++ b/sys/net/if_faith.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_faith.c,v 1.6 1999/12/02 07:22:19 itojun Exp $ */ +/* $NetBSD: if_faith.c,v 1.7 1999/12/13 15:17:19 itojun Exp $ */ /* * Copyright (c) 1982, 1986, 1993 @@ -54,9 +54,15 @@ #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/errno.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/sockio.h> +#else #include <sys/ioctl.h> +#endif #include <sys/time.h> +#ifdef __bsdi__ #include <machine/cpu.h> +#endif #include <net/if.h> #include <net/if_types.h> @@ -81,7 +87,9 @@ #include "bpfilter.h" -#ifdef __FreeBSD__ +#include <net/net_osdep.h> + +#if defined(__FreeBSD__) && __FreeBSD__ < 3 static int faithioctl __P((struct ifnet *, int, caddr_t)); #else static int faithioctl __P((struct ifnet *, u_long, caddr_t)); @@ -90,9 +98,11 @@ int faithoutput __P((struct ifnet *, register struct mbuf *, struct sockaddr *, register struct rtentry *)); static void faithrtrequest __P((int, struct rtentry *, struct sockaddr *)); -void faithattach __P((void *)); #ifdef __FreeBSD__ +void faithattach __P((void *)); PSEUDO_SET(faithattach, if_faith); +#else +void faithattach __P((int)); #endif static struct ifnet faithif[NFAITH]; @@ -102,7 +112,11 @@ static struct ifnet faithif[NFAITH]; /* ARGSUSED */ void faithattach(faith) +#ifdef __FreeBSD__ void *faith; +#else + int faith; +#endif { register struct ifnet *ifp; register int i; @@ -110,7 +124,7 @@ faithattach(faith) for (i = 0; i < NFAITH; i++) { ifp = &faithif[i]; bzero(ifp, sizeof(faithif[i])); -#ifdef __NetBSD__ +#if defined(__NetBSD__) || defined(__OpenBSD__) sprintf(ifp->if_xname, "faith%d", i); #else ifp->if_name = "faith"; @@ -126,7 +140,7 @@ faithattach(faith) ifp->if_addrlen = 0; if_attach(ifp); #if NBPFILTER > 0 -#ifdef __FreeBSD__ +#ifdef HAVE_OLD_BPF bpfattach(ifp, DLT_NULL, sizeof(u_int)); #else bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int)); @@ -171,7 +185,7 @@ faithoutput(ifp, m, dst, rt) m0.m_len = 4; m0.m_data = (char *)⁡ -#ifdef __FreeBSD__ +#ifdef HAVE_OLD_BPF bpf_mtap(ifp, &m0); #else bpf_mtap(ifp->if_bpf, &m0); @@ -187,6 +201,12 @@ faithoutput(ifp, m, dst, rt) ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; switch (dst->sa_family) { +#ifdef INET + case AF_INET: + ifq = &ipintrq; + isr = NETISR_IP; + break; +#endif #ifdef INET6 case AF_INET6: ifq = &ip6intrq; @@ -242,7 +262,7 @@ faithrtrequest(cmd, rt, sa) static int faithioctl(ifp, cmd, data) register struct ifnet *ifp; -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) && __FreeBSD__ < 3 int cmd; #else u_long cmd; @@ -271,6 +291,10 @@ faithioctl(ifp, cmd, data) break; } switch (ifr->ifr_addr.sa_family) { +#ifdef INET + case AF_INET: + break; +#endif #ifdef INET6 case AF_INET6: break; @@ -283,10 +307,12 @@ faithioctl(ifp, cmd, data) break; #ifdef SIOCSIFMTU +#ifndef __OpenBSD__ case SIOCSIFMTU: ifp->if_mtu = ifr->ifr_mtu; break; #endif +#endif case SIOCSIFFLAGS: break; diff --git a/sys/net/if_fddisubr.c b/sys/net/if_fddisubr.c index 139db361de9..82760bf0417 100644 --- a/sys/net/if_fddisubr.c +++ b/sys/net/if_fddisubr.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_fddisubr.c,v 1.28 1999/09/21 22:18:51 matt Exp $ */ +/* $NetBSD: if_fddisubr.c,v 1.29 1999/12/13 15:17:19 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -272,8 +272,16 @@ fddi_output(ifp, m0, dst, rt0) #endif #ifdef INET6 case AF_INET6: +#ifdef OLDIP6OUTPUT if (!nd6_resolve(ifp, rt, m, dst, edst)) return (0); /* if not yet resolved */ +#else + if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst)){ + /* this must be impossible, so we bark */ + printf("nd6_storelladdr failed\n"); + return(0); + } +#endif /* OLDIP6OUTPUT */ etype = htons(ETHERTYPE_IPV6); break; #endif diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c index 769f3c9fb52..5b3e02458e0 100644 --- a/sys/net/if_gif.c +++ b/sys/net/if_gif.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_gif.c,v 1.3 1999/12/02 07:18:44 itojun Exp $ */ +/* $NetBSD: if_gif.c,v 1.4 1999/12/13 15:17:19 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -40,11 +40,16 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/malloc.h> +#endif #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/sockio.h> #include <sys/errno.h> -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if defined(__FreeBSD__) || __FreeBSD__ >= 3 +/*nothing*/ +#else #include <sys/ioctl.h> #endif #include <sys/time.h> @@ -73,7 +78,6 @@ #include <netinet/ip6.h> #include <netinet6/ip6_var.h> #include <netinet6/in6_gif.h> -#include <netinet6/in6_ifattach.h> #endif /* INET6 */ #include <net/if_gif.h> @@ -81,9 +85,15 @@ #include "gif.h" #include "bpfilter.h" +#include <net/net_osdep.h> + #if NGIF > 0 +#ifdef __FreeBSD__ void gifattach __P((void *)); +#else +void gifattach __P((int)); +#endif /* * gif global variable definitions @@ -93,7 +103,11 @@ struct gif_softc *gif = 0; void gifattach(dummy) +#ifdef __FreeBSD__ void *dummy; +#else + int dummy; +#endif { register struct gif_softc *sc; register int i; @@ -316,6 +330,7 @@ gif_ioctl(ifp, cmd, data) case SIOCADDMULTI: case SIOCDELMULTI: +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) switch (ifr->ifr_addr.sa_family) { #ifdef INET case AF_INET: /* IP supports Multicast */ @@ -329,9 +344,11 @@ gif_ioctl(ifp, cmd, data) error = EAFNOSUPPORT; break; } +#endif /*not FreeBSD3*/ break; #ifdef SIOCSIFMTU /* xxx */ +#ifndef __OpenBSD__ case SIOCGIFMTU: break; case SIOCSIFMTU: @@ -349,21 +366,13 @@ gif_ioctl(ifp, cmd, data) ifp->if_mtu = mtu; } break; +#endif #endif /* SIOCSIFMTU */ case SIOCSIFPHYADDR: #ifdef INET6 case SIOCSIFPHYADDR_IN6: #endif /* INET6 */ -#ifdef INET6 - if (found_first_ifid) - in6_ifattach(ifp, IN6_IFT_P2P, NULL, 1); - else { - error = ENXIO; /* xxx */ - goto bad; - } -#endif /* INET6 */ - switch (ifr->ifr_addr.sa_family) { #ifdef INET case AF_INET: diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c index d83ea2aa3be..ee1f645c888 100644 --- a/sys/net/if_loop.c +++ b/sys/net/if_loop.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_loop.c,v 1.26 1999/07/01 08:12:48 itojun Exp $ */ +/* $NetBSD: if_loop.c,v 1.27 1999/12/13 15:17:19 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -204,39 +204,51 @@ looutput(ifp, m, dst, rt) rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); } -#ifdef INET6 +#ifndef PULLDOWN_TEST /* * KAME requires that the packet to be contiguous on the * mbuf. We need to make that sure. * this kind of code should be avoided. - * XXX: fails to join if interface MTU > MCLBYTES. jumbogram? + * XXX other conditions to avoid running this part? */ - if (m && m->m_next != NULL && m->m_pkthdr.len < MCLBYTES) { + if (m && m->m_next != NULL) { struct mbuf *n; MGETHDR(n, M_DONTWAIT, MT_HEADER); - if (!n) - goto contiguousfail; - MCLGET(n, M_DONTWAIT); - if (! (n->m_flags & M_EXT)) { - m_freem(n); - goto contiguousfail; + if (n) { + MCLGET(n, M_DONTWAIT); + if ((n->m_flags & M_EXT) == 0) { + m_free(n); + n = NULL; + } + } + if (!n) { + printf("looutput: mbuf allocation failed\n"); + m_freem(m); + return ENOBUFS; } - m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t)); - n->m_pkthdr.rcvif = m->m_pkthdr.rcvif; - n->m_pkthdr.len = m->m_pkthdr.len; - n->m_len = m->m_pkthdr.len; - m_freem(m); + M_COPY_PKTHDR(n, m); + if (m->m_pkthdr.len <= MCLBYTES) { + m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t)); + n->m_len = m->m_pkthdr.len; + n->m_next = NULL; + m_freem(m); + } else { + m_copydata(m, 0, MCLBYTES, mtod(n, caddr_t)); + m_adj(m, MCLBYTES); + n->m_len = MCLBYTES; + n->m_next = m; + m->m_flags &= ~M_PKTHDR; + } m = n; } - if (0) { -contiguousfail: - printf("looutput: mbuf allocation failed\n"); - } #if 0 - if (m && m->m_next != NULL) + if (m && m->m_next != NULL) { printf("loop: not contiguous...\n"); + m_freem(m); + return ENOBUFS; + } #endif #endif diff --git a/sys/net/net_osdep.c b/sys/net/net_osdep.c index 79ba9ad070a..dc5a57adc26 100644 --- a/sys/net/net_osdep.c +++ b/sys/net/net_osdep.c @@ -1,3 +1,5 @@ +/* $NetBSD: net_osdep.c,v 1.2 1999/12/13 15:17:19 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. diff --git a/sys/net/net_osdep.h b/sys/net/net_osdep.h index b90efeb6fa7..c3c62b61321 100644 --- a/sys/net/net_osdep.h +++ b/sys/net/net_osdep.h @@ -1,3 +1,5 @@ +/* $NetBSD: net_osdep.h,v 1.2 1999/12/13 15:17:19 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -74,7 +76,7 @@ * NetBSD, OpenBSD, BSDI [34], FreeBSD 2 * timeout() is a void function * FreeBSD 3 - * timeout() is non-void, must keep returned value for untimeuot() + * timeout() is non-void, must keep returned value for untimeout() * - sysctl * NetBSD, OpenBSD * foo_sysctl() diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 37001266186..0afb9b43d0e 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -1,4 +1,4 @@ -/* $NetBSD: in.h,v 1.43 1999/11/20 00:37:59 thorpej Exp $ */ +/* $NetBSD: in.h,v 1.44 1999/12/13 15:17:19 itojun Exp $ */ /* * Copyright (c) 1982, 1986, 1990, 1993 @@ -376,6 +376,7 @@ extern struct in_addr zeroin_addr; int in_broadcast __P((struct in_addr, struct ifnet *)); int in_canforward __P((struct in_addr)); int in_cksum __P((struct mbuf *, int)); +int in4_cksum __P((struct mbuf *, u_int8_t, int, int)); int in_localaddr __P((struct in_addr)); void in_socktrim __P((struct sockaddr_in *)); diff --git a/sys/netinet/in4_cksum.c b/sys/netinet/in4_cksum.c index 95b3529f467..a535848fe9e 100644 --- a/sys/netinet/in4_cksum.c +++ b/sys/netinet/in4_cksum.c @@ -1,4 +1,4 @@ -/* $NetBSD: in4_cksum.c,v 1.1.2.1 1999/11/30 13:35:24 itojun Exp $ */ +/* $NetBSD: in4_cksum.c,v 1.2 1999/12/13 15:17:19 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -67,11 +67,12 @@ #include <sys/param.h> #include <sys/mbuf.h> #include <sys/systm.h> +#include <sys/socket.h> +#include <net/route.h> #include <netinet/in.h> -#include <netinet/ip_var.h> - #include <netinet/in_systm.h> #include <netinet/ip.h> +#include <netinet/ip_var.h> /* * Checksum routine for Internet Protocol family headers (Portable Version). diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c index b64d752c68b..8d47e1e0e6a 100644 --- a/sys/netinet/in_gif.c +++ b/sys/netinet/in_gif.c @@ -1,4 +1,4 @@ -/* $NetBSD: in_gif.c,v 1.6 1999/08/20 10:07:40 itojun Exp $ */ +/* $NetBSD: in_gif.c,v 1.7 1999/12/13 15:17:20 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -38,8 +38,10 @@ #endif #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) #include "opt_inet.h" +#ifdef __NetBSD__ /*XXX*/ #include "opt_ipsec.h" #endif +#endif #include <sys/param.h> #include <sys/systm.h> @@ -47,6 +49,10 @@ #include <sys/sockio.h> #include <sys/mbuf.h> #include <sys/errno.h> +#ifdef __FreeBSD__ +#include <sys/kernel.h> +#include <sys/sysctl.h> +#endif #if !defined(__FreeBSD__) || __FreeBSD__ < 3 #include <sys/ioctl.h> #endif @@ -75,15 +81,19 @@ #include "gif.h" -#ifdef __NetBSD__ #include <machine/stdarg.h> -#endif + +#include <net/net_osdep.h> #if NGIF > 0 int ip_gif_ttl = GIF_TTL; #else int ip_gif_ttl = 0; #endif +#ifdef __FreeBSD__ +SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW, + &ip_gif_ttl, 0, ""); +#endif int in_gif_output(ifp, family, m, rt) @@ -155,6 +165,10 @@ in_gif_output(ifp, family, m, rt) if (sin_dst->sin_addr.s_addr != INADDR_ANY) iphdr.ip_dst = sin_dst->sin_addr; else if (rt) { + if (family != AF_INET) { + m_freem(m); + return EINVAL; /*XXX*/ + } iphdr.ip_dst = ((struct sockaddr_in *) (rt->rt_gateway))->sin_addr; } else { @@ -216,20 +230,19 @@ in_gif_output(ifp, family, m, rt) } #ifdef IPSEC +#ifndef __OpenBSD__ /*KAME IPSEC*/ m->m_pkthdr.rcvif = NULL; +#endif #endif /*IPSEC*/ - error = ip_output(m, 0, &sc->gif_ro, 0, 0); +#ifndef __OpenBSD__ + error = ip_output(m, NULL, &sc->gif_ro, 0, NULL); +#else + error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL); +#endif return(error); } void -#ifndef __NetBSD__ -in_gif_input(m, off, proto) - struct mbuf *m; - int off; - int proto; -{ -#else /* __NetBSD__ */ #if __STDC__ in_gif_input(struct mbuf *m, ...) #else @@ -239,22 +252,17 @@ in_gif_input(m, va_alist) #endif { int off, proto; -#endif /* __NetBSD__ */ struct gif_softc *sc; struct ifnet *gifp = NULL; struct ip *ip; int i, af; -#ifdef __NetBSD__ va_list ap; -#endif /* __NetBSD__ */ u_int8_t otos; -#ifdef __NetBSD__ va_start(ap, m); off = va_arg(ap, int); proto = va_arg(ap, int); va_end(ap); -#endif /* __NetBSD__ */ ip = mtod(m, struct ip *); diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 7ccc39f6b8a..7de281f9e77 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,4 +1,4 @@ -/* $NetBSD: in_pcb.c,v 1.60 1999/07/09 22:57:17 thorpej Exp $ */ +/* $NetBSD: in_pcb.c,v 1.61 1999/12/13 15:17:20 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -507,11 +507,6 @@ in_pcbdetach(v) int s; #ifdef IPSEC - if (so->so_pcb) { - KEYDEBUG(KEYDEBUG_KEY_STAMP, - printf("DP call free SO=%p from in_pcbdetach\n", so)); - key_freeso(so); - } ipsec4_delete_pcbpolicy(inp); #endif /*IPSEC*/ so->so_pcb = 0; diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c index 5c7fbff5cc6..a8f6900f6c1 100644 --- a/sys/netinet/in_proto.c +++ b/sys/netinet/in_proto.c @@ -1,4 +1,4 @@ -/* $NetBSD: in_proto.c,v 1.33 1999/07/09 22:57:18 thorpej Exp $ */ +/* $NetBSD: in_proto.c,v 1.34 1999/12/13 15:17:20 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -195,14 +195,14 @@ struct protosw inetsw[] = { #endif /* IPSEC */ #if NGIF > 0 { SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR, - in_gif_input, 0, 0, 0, - 0, + in_gif_input, rip_output, 0, rip_ctloutput, + rip_usrreq, /*XXX*/ 0, 0, 0, 0, }, #ifdef INET6 { SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR, - in_gif_input, 0, 0, 0, - 0, + in_gif_input, rip_output, 0, rip_ctloutput, + rip_usrreq, /*XXX*/ 0, 0, 0, 0, }, #endif /* INET6 */ diff --git a/sys/netinet/ip_ipip.c b/sys/netinet/ip_ipip.c index 1be4fb2c1b0..c75c76d94fc 100644 --- a/sys/netinet/ip_ipip.c +++ b/sys/netinet/ip_ipip.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip_ipip.c,v 1.7 1999/08/26 02:56:59 itojun Exp $ */ +/* $NetBSD: ip_ipip.c,v 1.8 1999/12/13 15:17:20 itojun Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -109,11 +109,12 @@ ipip_input(m, va_alist) #if NIPIP > 0 struct ipip_softc *sc; #endif - int hlen; + int hlen, proto; va_list ap; va_start(ap, m); hlen = va_arg(ap, int); + proto = va_arg(ap, int); va_end(ap); #if NIPIP > 0 @@ -163,7 +164,7 @@ ipip_input(m, va_alist) #endif /* MROUTING */ /* Last try: give it to raw IP. */ - rip_input(m); + rip_input(m, hlen, proto); } #if NIPIP > 0 diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 74c71ce94e6..967eabd3b0c 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip_output.c,v 1.62 1999/07/09 22:57:19 thorpej Exp $ */ +/* $NetBSD: ip_output.c,v 1.63 1999/12/13 15:17:20 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -549,6 +549,19 @@ skip_ipsec: * If small enough for mtu of path, can just send directly. */ if ((u_int16_t)ip->ip_len <= mtu) { +#if IFA_STATS + /* + * search for the source address structure to + * maintain output statistics. + */ + bzero((caddr_t*) &src, sizeof(src)); + src.sin_family = AF_INET; + src.sin_addr.s_addr = ip->ip_src.s_addr; + src.sin_len = sizeof(src); + ia = ifatoia(ifa_ifwithladdr(sintosa(&src))); + if (ia) + ia->ia_ifa.ifa_data.ifad_outbytes += ntohs(ip->ip_len); +#endif HTONS(ip->ip_len); HTONS(ip->ip_off); ip->ip_sum = 0; @@ -659,10 +672,25 @@ sendorfree: for (m = m0; m; m = m0) { m0 = m->m_nextpkt; m->m_nextpkt = 0; - if (error == 0) + if (error == 0) { +#if IFA_STATS + /* + * search for the source address structure to + * maintain output statistics. + */ + bzero((caddr_t*) &src, sizeof(src)); + src.sin_family = AF_INET; + src.sin_addr.s_addr = ip->ip_src.s_addr; + src.sin_len = sizeof(src); + ia = ifatoia(ifa_ifwithladdr(sintosa(&src))); + if (ia) { + ia->ia_ifa.ifa_data.ifad_outbytes += + ntohs(ip->ip_len); + } +#endif error = (*ifp->if_output)(ifp, m, sintosa(dst), ro->ro_rt); - else + } else m_freem(m); } @@ -674,19 +702,6 @@ done: RTFREE(ro->ro_rt); ro->ro_rt = 0; } -#if IFA_STATS - if (error == 0) { - /* search for the source address structure to maintain output - * statistics. */ - bzero((caddr_t*) &src, sizeof(src)); - src.sin_family = AF_INET; - src.sin_addr.s_addr = ip->ip_src.s_addr; - src.sin_len = sizeof(src); - ia = ifatoia(ifa_ifwithladdr(sintosa(&src))); - if (ia) - ia->ia_ifa.ifa_data.ifad_outbytes += ntohs(ip->ip_len); - } -#endif #ifdef IPSEC if (sp != NULL) { diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index ed3854bf660..58c208eacc0 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -1,4 +1,4 @@ -/* $NetBSD: raw_ip.c,v 1.46 1999/09/13 12:15:55 itojun Exp $ */ +/* $NetBSD: raw_ip.c,v 1.47 1999/12/13 15:17:20 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -207,7 +207,8 @@ rip_input(m, va_alist) sorwakeup(last->inp_socket); } else { if (inetsw[ip_protox[ip->ip_p]].pr_input == rip_input) { - icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL,0,0); + icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, + 0, 0); ipstat.ips_noproto++; ipstat.ips_delivered--; } else @@ -463,8 +464,11 @@ rip_usrreq(so, req, m, nam, control, p) inp = sotoinpcb(so); inp->inp_ip.ip_p = (long)nam; #ifdef IPSEC - if ((error = ipsec_init_policy(&inp->inp_sp)) != 0) + error = ipsec_init_policy(&inp->inp_sp); + if (error != 0) { in_pcbdetach(inp); + break; + } #endif /*IPSEC*/ break; diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 198ca0e1e38..ba03bd4a044 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_input.c,v 1.98 1999/12/11 09:55:14 itojun Exp $ */ +/* $NetBSD: tcp_input.c,v 1.99 1999/12/13 15:17:20 itojun Exp $ */ /* %%% portions-copyright-nrl-95 @@ -161,6 +161,13 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. #include <netinet6/nd6.h> #endif +#ifdef PULLDOWN_TEST +#ifndef INET6 +/* always need ip6.h for IP6_EXTHDR_GET */ +#include <netinet/ip6.h> +#endif +#endif + #include <netinet/tcp.h> #include <netinet/tcp_fsm.h> #include <netinet/tcp_seq.h> @@ -589,6 +596,7 @@ tcp_input(m, va_alist) case 4: af = AF_INET; iphlen = sizeof(struct ip); +#ifndef PULLDOWN_TEST /* would like to get rid of this... */ if (toff > sizeof (struct ip)) { ip_stripoptions(m, (struct mbuf *)0); @@ -602,12 +610,22 @@ tcp_input(m, va_alist) } ip = mtod(m, struct ip *); th = (struct tcphdr *)(mtod(m, caddr_t) + toff); +#else + ip = mtod(m, struct ip *); + IP6_EXTHDR_GET(th, struct tcphdr *, m, toff, + sizeof(struct tcphdr)); + if (th == NULL) { + tcpstat.tcps_rcvshort++; + return; + } +#endif /* * Checksum extended TCP header and data. */ len = ip->ip_len; tlen = len - toff; +#ifndef PULLDOWN_TEST { struct ipovly *ipov; ipov = (struct ipovly *)ip; @@ -618,12 +636,19 @@ tcp_input(m, va_alist) tcpstat.tcps_rcvbadsum++; goto drop; } +#else + if (in4_cksum(m, IPPROTO_TCP, toff, tlen) != 0) { + tcpstat.tcps_rcvbadsum++; + goto drop; + } +#endif break; #ifdef INET6 case 6: ip = NULL; iphlen = sizeof(struct ip6_hdr); af = AF_INET6; +#ifndef PULLDOWN_TEST if (m->m_len < toff + sizeof(struct tcphdr)) { m = m_pullup(m, toff + sizeof(struct tcphdr)); /*XXX*/ if (m == NULL) { @@ -633,6 +658,15 @@ tcp_input(m, va_alist) } ip6 = mtod(m, struct ip6_hdr *); th = (struct tcphdr *)(mtod(m, caddr_t) + toff); +#else + ip6 = mtod(m, struct ip6_hdr *); + IP6_EXTHDR_GET(th, struct tcphdr *, m, toff, + sizeof(struct tcphdr)); + if (th == NULL) { + tcpstat.tcps_rcvshort++; + return; + } +#endif /* * Checksum extended TCP header and data. @@ -669,6 +703,7 @@ tcp_input(m, va_alist) */ if (off > sizeof (struct tcphdr)) { +#ifndef PULLDOWN_TEST if (m->m_len < toff + off) { if ((m = m_pullup(m, toff + off)) == 0) { tcpstat.tcps_rcvshort++; @@ -686,8 +721,19 @@ tcp_input(m, va_alist) } th = (struct tcphdr *)(mtod(m, caddr_t) + toff); } +#else + IP6_EXTHDR_GET(th, struct tcphdr *, m, toff, off); + if (th == NULL) { + tcpstat.tcps_rcvshort++; + return; + } + /* + * NOTE: ip/ip6 will not be affected by m_pulldown() + * (as they're before toff) and we don't need to update those. + */ +#endif optlen = off - sizeof (struct tcphdr); - optp = mtod(m, caddr_t) + toff + sizeof (struct tcphdr); + optp = ((caddr_t)th) + sizeof(struct tcphdr); /* * Do quick retrieval of timestamp options ("options * prediction?"). If timestamp is the only option and it's @@ -3384,7 +3430,7 @@ syn_cache_respond(sc, m) case AF_INET6: ip6->ip6_vfc = IPV6_VERSION; ip6->ip6_plen = htons(tlen - hlen); - ip6->ip6_hlim = ip6_defhlim; + /* ip6_hlim will be initialized afterwards */ /* XXX flowlabel? */ break; #endif @@ -3429,8 +3475,11 @@ syn_cache_respond(sc, m) break; #ifdef INET6 case AF_INET6: + ip6->ip6_hlim = in6_selecthlim(NULL, + ro->ro_rt ? ro->ro_rt->rt_ifp : NULL); + error = ip6_output(m, NULL /*XXX*/, (struct route_in6 *)ro, - 0, NULL); + 0, NULL, NULL); break; #endif default: diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 779859e5761..2f807b51bf2 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_output.c,v 1.52 1999/09/23 02:21:31 itojun Exp $ */ +/* $NetBSD: tcp_output.c,v 1.53 1999/12/13 15:17:20 itojun Exp $ */ /* %%% portions-copyright-nrl-95 @@ -946,8 +946,16 @@ send: #ifdef INET6 case AF_INET6: ip6->ip6_nxt = IPPROTO_TCP; - if (tp->t_in6pcb) - ip6->ip6_hlim = tp->t_in6pcb->in6p_ip6.ip6_hlim; + if (tp->t_in6pcb) { + /* + * we separately set hoplimit for every segment, since + * the user might want to change the value via + * setsockopt. Also, desired default hop limit might + * be changed via Neighbor Discovery. + */ + ip6->ip6_hlim = in6_selecthlim(tp->t_in6pcb, + ro->ro_rt ? ro->ro_rt->rt_ifp : NULL); + } /* ip6->ip6_flow = ??? */ /* ip6_plen will be filled in ip6_output(). */ break; @@ -1043,18 +1051,12 @@ send: { struct ip6_pktopts *opts; -#if BSD >= 43 if (tp->t_in6pcb) opts = tp->t_in6pcb->in6p_outputopts; else opts = NULL; error = ip6_output(m, opts, (struct route_in6 *)ro, - so->so_options & SO_DONTROUTE, 0); -#else - opts = NULL; - error = ip6_output(m, opts, (struct route_in6 *)ro, - so->so_options & SO_DONTROUTE); -#endif + so->so_options & SO_DONTROUTE, 0, NULL); break; } #endif diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 621fd14c390..a01849a07bb 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_subr.c,v 1.83 1999/12/12 19:51:49 ragge Exp $ */ +/* $NetBSD: tcp_subr.c,v 1.84 1999/12/13 15:17:20 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -439,13 +439,12 @@ tcp_respond(tp, template, m, th0, ack, seq, flags) th = (struct tcphdr *)(ip6 + 1); break; #endif - default: /*pacify gcc*/ - ip = NULL; -#ifdef INET6 - ip6 = NULL; +#if 0 + default: + /* noone will visit here */ + m_freem(m); + return EAFNOSUPPORT; #endif - th = NULL; - break; } flags = TH_ACK; } else { @@ -462,8 +461,7 @@ tcp_respond(tp, template, m, th0, ack, seq, flags) break; #endif default: - if (m) - m_freem(m); + m_freem(m); return EAFNOSUPPORT; } @@ -494,9 +492,6 @@ tcp_respond(tp, template, m, th0, ack, seq, flags) ip6->ip6_nxt = IPPROTO_TCP; break; #endif - default: /*pacify gcc*/ - th = NULL; - break; } *th = *th0; xchg(th->th_dport, th->th_sport, u_int16_t); @@ -540,7 +535,13 @@ tcp_respond(tp, template, m, th0, ack, seq, flags) th->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(struct ip6_hdr), tlen); ip6->ip6_plen = ntohs(tlen); - ip6->ip6_hlim = ip6_defhlim; + if (tp && tp->t_in6pcb) { + struct ifnet *oifp; + ro = (struct route *)&tp->t_in6pcb->in6p_route; + oifp = ro->ro_rt ? ro->ro_rt->rt_ifp : NULL; + ip6->ip6_hlim = in6_selecthlim(tp->t_in6pcb, oifp); + } else + ip6->ip6_hlim = ip6_defhlim; ip6->ip6_flow &= ~IPV6_FLOWINFO_MASK; if (ip6_auto_flowlabel) { ip6->ip6_flow |= @@ -658,7 +659,8 @@ tcp_respond(tp, template, m, th0, ack, seq, flags) break; #ifdef INET6 case AF_INET6: - error = ip6_output(m, NULL, (struct route_in6 *)ro, 0, NULL); + error = ip6_output(m, NULL, (struct route_in6 *)ro, 0, NULL, + NULL); break; #endif default: @@ -749,7 +751,9 @@ tcp_newtcpcb(family, aux) #ifdef INET6 else if (family == AF_INET6) { struct in6pcb *in6p = (struct in6pcb *)aux; - in6p->in6p_ip6.ip6_hlim = ip6_defhlim; + in6p->in6p_ip6.ip6_hlim = in6_selecthlim(in6p, + in6p->in6p_route.ro_rt ? in6p->in6p_route.ro_rt->rt_ifp + : NULL); in6p->in6p_ppcb = (caddr_t)tp; } #endif @@ -1048,12 +1052,10 @@ tcp6_notify(in6p, error) #if defined(INET6) && !defined(TCP6) void -tcp6_ctlinput(cmd, sa, ip6, m, off) +tcp6_ctlinput(cmd, sa, d) int cmd; struct sockaddr *sa; - register struct ip6_hdr *ip6; - struct mbuf *m; - int off; + void *d; { register struct tcphdr *thp; struct tcphdr th; @@ -1061,16 +1063,25 @@ tcp6_ctlinput(cmd, sa, ip6, m, off) int nmatch; extern struct in6_addr zeroin6_addr; /* netinet6/in6_pcb.c */ struct sockaddr_in6 sa6; + register struct ip6_hdr *ip6; + struct mbuf *m; + int off; if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) return; - if (cmd == PRC_QUENCH) + if ((unsigned)cmd >= PRC_NCMDS) + return; + else if (cmd == PRC_QUENCH) { + /* XXX there's no PRC_QUENCH in IPv6 */ notify = tcp6_quench; + } else if (PRC_IS_REDIRECT(cmd)) + notify = in6_rtchange, d = NULL; else if (cmd == PRC_MSGSIZE) - notify = tcp6_mtudisc; - else if (!PRC_IS_REDIRECT(cmd) && - ((unsigned)cmd > PRC_NCMDS || inet6ctlerrmap[cmd] == 0)) + notify = tcp6_mtudisc, d = NULL; + else if (cmd == PRC_HOSTDEAD) + d = NULL; + else if (inet6ctlerrmap[cmd] == 0) return; /* translate addresses into internal form */ @@ -1078,6 +1089,17 @@ tcp6_ctlinput(cmd, sa, ip6, m, off) if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); + /* if the parameter is from icmp6, decode it. */ + if (d != NULL) { + struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + m = ip6cp->ip6c_m; + ip6 = ip6cp->ip6c_ip6; + off = ip6cp->ip6c_off; + } else { + m = NULL; + ip6 = NULL; + } + if (ip6) { /* * XXX: We assume that when ip6 is non NULL, diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index fbaa4e32ec2..deddd049ad0 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_usrreq.c,v 1.42 1999/07/09 22:57:23 thorpej Exp $ */ +/* $NetBSD: tcp_usrreq.c,v 1.43 1999/12/13 15:17:21 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -730,14 +730,20 @@ tcp_attach(so) return EAFNOSUPPORT; } #ifdef IPSEC - if (inp && (error = ipsec_init_policy(&inp->inp_sp)) != 0) { - in_pcbdetach(inp); - return (error); + if (inp) { + error = ipsec_init_policy(&inp->inp_sp); + if (error != 0) { + in_pcbdetach(inp); + return (error); + } } #ifdef INET6 - else if (in6p && (error = ipsec_init_policy(&in6p->in6p_sp)) != 0) { - in6_pcbdetach(in6p); - return (error); + else if (in6p) { + error = ipsec_init_policy(&in6p->in6p_sp); + if (error != 0) { + in6_pcbdetach(in6p); + return (error); + } } #endif #endif /*IPSEC*/ diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index bdce32eec01..786eba3262f 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_var.h,v 1.70 1999/12/08 16:22:20 itojun Exp $ */ +/* $NetBSD: tcp_var.h,v 1.71 1999/12/13 15:17:21 itojun Exp $ */ /* %%% portions-copyright-nrl-98 @@ -621,8 +621,7 @@ void tcp_canceltimers __P((struct tcpcb *)); struct tcpcb * tcp_close __P((struct tcpcb *)); #if defined(INET6) && !defined(TCP6) -void tcp6_ctlinput __P((int, struct sockaddr *, struct ip6_hdr *, - struct mbuf *, int)); +void tcp6_ctlinput __P((int, struct sockaddr *, void *)); #endif void *tcp_ctlinput __P((int, struct sockaddr *, void *)); int tcp_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 32296ddb215..4f532ea5239 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -1,4 +1,4 @@ -/* $NetBSD: udp_usrreq.c,v 1.52 1999/09/13 12:15:55 itojun Exp $ */ +/* $NetBSD: udp_usrreq.c,v 1.53 1999/12/13 15:17:21 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -68,14 +68,9 @@ #include "ipkdb.h" -/* XXX MAPPED_ADDR_ENABLED should be revisited */ - #include <sys/param.h> #include <sys/malloc.h> #include <sys/mbuf.h> -#ifdef MAPPED_ADDR_ENABLED -#include <sys/domain.h> -#endif /* MAPPED_ADDR_ENABLED */ #include <sys/protosw.h> #include <sys/socket.h> #include <sys/socketvar.h> @@ -83,6 +78,7 @@ #include <sys/stat.h> #include <sys/systm.h> #include <sys/proc.h> +#include <sys/domain.h> #include <vm/vm.h> #include <sys/sysctl.h> @@ -100,6 +96,21 @@ #include <netinet/udp.h> #include <netinet/udp_var.h> +#ifdef INET6 +#include <netinet/ip6.h> +#include <netinet/icmp6.h> +#include <netinet6/ip6_var.h> +#include <netinet6/in6_pcb.h> +#include <netinet6/udp6_var.h> +#endif + +#ifdef PULLDOWN_TEST +#ifndef INET6 +/* always need ip6.h for IP6_EXTHDR_GET */ +#include <netinet/ip6.h> +#endif +#endif + #include <machine/stdarg.h> #ifdef IPSEC @@ -118,6 +129,18 @@ int udpcksum = 1; int udpcksum = 0; /* XXX */ #endif +static void udp4_sendup __P((struct mbuf *, int, struct sockaddr *, + struct socket *)); +static int udp4_realinput __P((struct sockaddr_in *, struct sockaddr_in *, + struct mbuf *, int)); +#ifdef INET6 +static void udp6_sendup __P((struct mbuf *, int, struct sockaddr *, + struct socket *)); +static int in6_mcmatch __P((struct in6pcb *, struct in6_addr *, + struct ifnet *)); +static int udp6_realinput __P((int, struct sockaddr_in6 *, + struct sockaddr_in6 *, struct mbuf *, int)); +#endif static void udp_notify __P((struct inpcb *, int)); #ifndef UDBHASHSIZE @@ -141,6 +164,704 @@ udp_input(m, va_alist) va_dcl #endif { + va_list ap; + struct sockaddr_in src, dst; + struct ip *ip; + struct udphdr *uh; + int iphlen, proto; + int len; + int n; + + va_start(ap, m); + iphlen = va_arg(ap, int); + proto = va_arg(ap, int); + va_end(ap); + + udpstat.udps_ipackets++; + +#ifndef PULLDOWN_TEST + /* + * Strip IP options, if any; should skip this, + * make available to user, and use on returned packets, + * but we don't yet have a way to check the checksum + * with options still present. + */ + if (iphlen > sizeof (struct ip)) { + ip_stripoptions(m, (struct mbuf *)0); + iphlen = sizeof(struct ip); + } +#else + /* + * we may enable the above code if we save and pass IPv4 options + * to the userland. + */ +#endif + + /* + * Get IP and UDP header together in first mbuf. + */ + ip = mtod(m, struct ip *); +#ifndef PULLDOWN_TEST + if (m->m_len < iphlen + sizeof(struct udphdr)) { + if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { + udpstat.udps_hdrops++; + return; + } + ip = mtod(m, struct ip *); + } + uh = (struct udphdr *)((caddr_t)ip + iphlen); +#else + IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr)); + if (uh == NULL) { + udpstat.udps_hdrops++; + return; + } +#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->ip_len != iphlen + len) { + if (ip->ip_len < iphlen + len) { + udpstat.udps_badlen++; + goto bad; + } + m_adj(m, iphlen + len - ip->ip_len); + } + + /* + * Checksum extended UDP header and data. + */ + if (uh->uh_sum) { +#ifndef PULLDOWN_TEST + struct ip save_ip; + + /* + * Save a copy of the IP header in case we want restore it + * for sending an ICMP error message in response. + */ + save_ip = *ip; + + bzero(((struct ipovly *)ip)->ih_x1, + sizeof ((struct ipovly *)ip)->ih_x1); + ((struct ipovly *)ip)->ih_len = uh->uh_ulen; + if (in_cksum(m, len + sizeof (struct ip)) != 0) { + udpstat.udps_badsum++; + m_freem(m); + return; + } + + *ip = save_ip; +#else + if (in4_cksum(m, IPPROTO_UDP, iphlen, len) != 0) { + udpstat.udps_badsum++; + m_freem(m); + return; + } +#endif + } + + /* construct source and dst sockaddrs. */ + bzero(&src, sizeof(src)); + src.sin_family = AF_INET; + src.sin_len = sizeof(struct sockaddr_in); + bcopy(&ip->ip_src, &src.sin_addr, sizeof(src.sin_addr)); + src.sin_port = uh->uh_sport; + bzero(&dst, sizeof(dst)); + dst.sin_family = AF_INET; + dst.sin_len = sizeof(struct sockaddr_in); + bcopy(&ip->ip_dst, &dst.sin_addr, sizeof(dst.sin_addr)); + dst.sin_port = uh->uh_dport; + + n = udp4_realinput(&src, &dst, m, iphlen); +#ifdef INET6 + if (IN_MULTICAST(ip->ip_dst.s_addr) || n == 0) { + struct sockaddr_in6 src6, dst6; + + bzero(&src6, sizeof(src6)); + src6.sin6_family = AF_INET6; + src6.sin6_len = sizeof(struct sockaddr_in6); + src6.sin6_addr.s6_addr[10] = src6.sin6_addr.s6_addr[11] = 0xff; + bcopy(&ip->ip_src, &src6.sin6_addr.s6_addr[12], + sizeof(ip->ip_src)); + src6.sin6_port = uh->uh_sport; + bzero(&dst6, sizeof(dst6)); + dst6.sin6_family = AF_INET6; + dst6.sin6_len = sizeof(struct sockaddr_in6); + dst6.sin6_addr.s6_addr[10] = dst6.sin6_addr.s6_addr[11] = 0xff; + bcopy(&ip->ip_dst, &dst6.sin6_addr.s6_addr[12], + sizeof(ip->ip_dst)); + dst6.sin6_port = uh->uh_dport; + + n += udp6_realinput(AF_INET, &src6, &dst6, m, iphlen); + } +#endif + + if (n == 0) { + udpstat.udps_noport++; + if (m->m_flags & (M_BCAST | M_MCAST)) { + udpstat.udps_noportbcast++; + goto bad; + } +#if NIPKDB > 0 + if (checkipkdb(&ip->ip_src, uh->uh_sport, uh->uh_dport, + m, iphlen + sizeof(struct udphdr), + m->m_pkthdr.len - iphlen - sizeof(struct udphdr))) { + /* + * It was a debugger connect packet, + * just drop it now + */ + goto bad; + } +#endif + icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); + m = NULL; + } + +bad: + if (m) + m_freem(m); +} + +#ifdef INET6 +int +udp6_input(mp, offp, proto) + struct mbuf **mp; + int *offp, proto; +{ + struct mbuf *m = *mp; + int off = *offp; + struct sockaddr_in6 src, dst; + struct ip6_hdr *ip6; + struct udphdr *uh; + u_int32_t plen, ulen; + +#if defined(NFAITH) && 0 < NFAITH + if (m->m_pkthdr.rcvif) { + if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) { + /* send icmp6 host unreach? */ + m_freem(m); + return IPPROTO_DONE; + } + } +#endif + + udp6stat.udp6s_ipackets++; + +#ifndef PULLDOWN_TEST + IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); +#endif + + ip6 = mtod(m, struct ip6_hdr *); + /* check for jumbogram is done in ip6_input. we can trust pkthdr.len */ + plen = m->m_pkthdr.len - off; +#ifndef PULLDOWN_TEST + uh = (struct udphdr *)((caddr_t)ip6 + off); +#else + IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(struct udphdr)); + if (uh == NULL) { + ip6stat.ip6s_tooshort++; + return IPPROTO_DONE; + } +#endif + ulen = ntohs((u_short)uh->uh_ulen); + if (ulen == 0 && plen > 0xffff) + ulen = plen; + + if (plen != ulen) { + udp6stat.udp6s_badlen++; + goto bad; + } + + /* + * Checksum extended UDP header and data. + */ + if (uh->uh_sum == 0) + udp6stat.udp6s_nosum++; + else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) { + udp6stat.udp6s_badsum++; + goto bad; + } + + /* + * Construct source and dst sockaddrs. + * Note that ifindex (s6_addr16[1]) is already filled. + */ + bzero(&src, sizeof(src)); + src.sin6_family = AF_INET6; + src.sin6_len = sizeof(struct sockaddr_in6); + bcopy(&ip6->ip6_src, &src.sin6_addr, sizeof(src.sin6_addr)); + if (IN6_IS_SCOPE_LINKLOCAL(&src.sin6_addr)) + src.sin6_addr.s6_addr16[1] = 0; + if (m->m_pkthdr.rcvif) { + if (IN6_IS_SCOPE_LINKLOCAL(&src.sin6_addr)) + src.sin6_scope_id = m->m_pkthdr.rcvif->if_index; + else + src.sin6_scope_id = 0; + } + src.sin6_port = uh->uh_sport; + bzero(&dst, sizeof(dst)); + dst.sin6_family = AF_INET6; + dst.sin6_len = sizeof(struct sockaddr_in6); + bcopy(&ip6->ip6_dst, &dst.sin6_addr, sizeof(dst.sin6_addr)); + if (IN6_IS_SCOPE_LINKLOCAL(&dst.sin6_addr)) + dst.sin6_addr.s6_addr16[1] = 0; + if (m->m_pkthdr.rcvif) { + if (IN6_IS_SCOPE_LINKLOCAL(&dst.sin6_addr)) + dst.sin6_scope_id = m->m_pkthdr.rcvif->if_index; + else + dst.sin6_scope_id = 0; + } + dst.sin6_port = uh->uh_dport; + + if (udp6_realinput(AF_INET6, &src, &dst, m, off) == 0) { + udp6stat.udp6s_noport++; + if (m->m_flags & M_MCAST) { + udp6stat.udp6s_noportmcast++; + goto bad; + } + icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); + m = NULL; + } + +bad: + if (m) + m_freem(m); + return IPPROTO_DONE; +} +#endif + +static void +udp4_sendup(m, off, src, so) + struct mbuf *m; + int off; /* offset of data portion */ + struct sockaddr *src; + struct socket *so; +{ + struct mbuf *opts = NULL; + struct mbuf *n; + struct inpcb *inp = NULL; +#ifdef INET6 + struct in6pcb *in6p = NULL; +#endif + + if (!so) + return; + switch (so->so_proto->pr_domain->dom_family) { + case AF_INET: + inp = sotoinpcb(so); + break; +#ifdef INET6 + case AF_INET6: + in6p = sotoin6pcb(so); + break; +#endif + default: + return; + } + +#ifdef IPSEC + /* check AH/ESP integrity. */ + if (so != NULL && ipsec4_in_reject_so(m, so)) { + ipsecstat.in_polvio++; + return; + } +#endif /*IPSEC*/ + + if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { + if (inp && (inp->inp_flags & INP_CONTROLOPTS + || so->so_options & SO_TIMESTAMP)) { + struct ip *ip = mtod(n, struct ip *); + ip_savecontrol(inp, &opts, ip, n); + } + + m_adj(n, off); + if (sbappendaddr(&so->so_rcv, src, n, + opts) == 0) { + m_freem(n); + if (opts) + m_freem(opts); + } else + sorwakeup(so); + } +} + +#ifdef INET6 +static void +udp6_sendup(m, off, src, so) + struct mbuf *m; + int off; /* offset of data portion */ + struct sockaddr *src; + struct socket *so; +{ + struct mbuf *opts = NULL; + struct mbuf *n; + struct in6pcb *in6p = NULL; + + if (!so) + return; + if (so->so_proto->pr_domain->dom_family != AF_INET6) + return; + in6p = sotoin6pcb(so); + +#ifdef IPSEC + /* check AH/ESP integrity. */ + if (so != NULL && ipsec6_in_reject_so(m, so)) { + ipsec6stat.in_polvio++; + return; + } +#endif /*IPSEC*/ + + if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { + if (in6p && (in6p->in6p_flags & IN6P_CONTROLOPTS + || in6p->in6p_socket->so_options & SO_TIMESTAMP)) { + struct ip6_hdr *ip6 = mtod(n, struct ip6_hdr *); + ip6_savecontrol(in6p, &opts, ip6, n); + } + + m_adj(n, off); + if (sbappendaddr(&so->so_rcv, src, n, opts) == 0) { + m_freem(n); + if (opts) + m_freem(opts); + udp6stat.udp6s_fullsock++; + } else + sorwakeup(so); + } +} +#endif + +static int +udp4_realinput(src, dst, m, off) + struct sockaddr_in *src; + struct sockaddr_in *dst; + struct mbuf *m; + int off; /* offset of udphdr */ +{ + u_int16_t *sport, *dport; + int rcvcnt; + struct in_addr *src4, *dst4; + struct inpcb *inp; + + rcvcnt = 0; + off += sizeof(struct udphdr); /* now, offset of payload */ + + if (src->sin_family != AF_INET || dst->sin_family != AF_INET) + goto bad; + + src4 = &src->sin_addr; + sport = &src->sin_port; + dst4 = &dst->sin_addr; + dport = &dst->sin_port; + + if (IN_MULTICAST(src4->s_addr) || + in_broadcast(*dst4, m->m_pkthdr.rcvif)) { + 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?) + */ + + /* + * KAME note: usually we drop udpiphdr from mbuf here. + * we need udpiphdr for iPsec processing so we do that later. + */ + /* + * Locate pcb(s) for datagram. + */ + for (inp = udbtable.inpt_queue.cqh_first; + inp != (struct inpcb *)&udbtable.inpt_queue; + inp = inp->inp_queue.cqe_next) { + if (inp->inp_lport != *dport) + continue; + if (!in_nullhost(inp->inp_laddr)) { + if (!in_hosteq(inp->inp_laddr, *dst4)) + continue; + } + if (!in_nullhost(inp->inp_faddr)) { + if (!in_hosteq(inp->inp_faddr, *src4) || + inp->inp_fport != *sport) + continue; + } + + last = inp; + udp4_sendup(m, off, (struct sockaddr *)src, + inp->inp_socket); + rcvcnt++; + + /* + * 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 ((inp->inp_socket->so_options & + (SO_REUSEPORT|SO_REUSEADDR)) == 0) + break; + } + +#if 0 + if (last == NULL) { + /* + * No matching pcb found; discard datagram. + * (No need to send an ICMP Port Unreachable + * for a broadcast or multicast datgram.) + */ + udpstat.udps_noport++; + udpstat.udps_noportbcast++; + goto bad; + } +#endif + } else { + /* + * Locate pcb for datagram. + */ + inp = in_pcblookup_connect(&udbtable, *src4, *sport, *dst4, *dport); + if (inp == 0) { + ++udpstat.udps_pcbhashmiss; + inp = in_pcblookup_bind(&udbtable, *dst4, *dport); + if (inp == 0) { +#if 0 + struct mbuf *n; + + udpstat.udps_noport++; + if (m->m_flags & (M_BCAST | M_MCAST)) { + udpstat.udps_noportbcast++; + goto bad; + } +#if NIPKDB > 0 + if (checkipkdb(src4, *sport, *dport, m, off, + m->m_pkthdr.len - off)) { + /* + * It was a debugger connect packet, + * just drop it now + */ + goto bad; + } +#endif + if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { + icmp_error(n, ICMP_UNREACH, + ICMP_UNREACH_PORT, 0, 0); + } +#endif + return rcvcnt; + } + } + + udp4_sendup(m, off, (struct sockaddr *)src, inp->inp_socket); + rcvcnt++; + } + +bad: + return rcvcnt; +} + +#ifdef INET6 +static int +in6_mcmatch(in6p, ia6, ifp) + struct in6pcb *in6p; + register struct in6_addr *ia6; + struct ifnet *ifp; +{ + struct ip6_moptions *im6o = in6p->in6p_moptions; + struct in6_multi_mship *imm; + + if (im6o == NULL) + return 0; + + for (imm = im6o->im6o_memberships.lh_first; imm != NULL; + imm = imm->i6mm_chain.le_next) { + if ((ifp == NULL || + imm->i6mm_maddr->in6m_ifp == ifp) && + IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr, + ia6)) + return 1; + } + return 0; +} + +static int +udp6_realinput(af, src, dst, m, off) + int af; /* af on packet */ + struct sockaddr_in6 *src; + struct sockaddr_in6 *dst; + struct mbuf *m; + int off; /* offset of udphdr */ +{ + u_int16_t *sport, *dport; + int rcvcnt; + struct in6_addr *src6, *dst6; + struct in_addr *src4; + struct in6pcb *in6p; + + rcvcnt = 0; + off += sizeof(struct udphdr); /* now, offset of payload */ + + if (af != AF_INET && af != AF_INET6) + goto bad; + if (src->sin6_family != AF_INET6 || dst->sin6_family != AF_INET6) + goto bad; + + src6 = &src->sin6_addr; + sport = &src->sin6_port; + dst6 = &dst->sin6_addr; + dport = &dst->sin6_port; + src4 = (struct in_addr *)&src->sin6_addr.s6_addr32[12]; + + if (IN6_IS_ADDR_MULTICAST(dst6) + || (af == AF_INET && IN_MULTICAST(src4->s_addr))) { + struct in6pcb *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?) + */ + + /* + * KAME note: usually we drop udpiphdr from mbuf here. + * we need udpiphdr for iPsec processing so we do that later. + */ + /* + * Locate pcb(s) for datagram. + */ + for (in6p = udb6.in6p_next; in6p != &udb6; + in6p = in6p->in6p_next) { + if (in6p->in6p_lport != *dport) + continue; + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { + if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, dst6) + && !in6_mcmatch(in6p, dst6, m->m_pkthdr.rcvif)) + continue; + } + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { + if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, src6) + || in6p->in6p_fport != *sport) + continue; + } + + last = in6p; + udp6_sendup(m, off, (struct sockaddr *)src, + in6p->in6p_socket); + rcvcnt++; + + /* + * 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 ((in6p->in6p_socket->so_options & + (SO_REUSEPORT|SO_REUSEADDR)) == 0) + break; + } + +#if 0 + if (last == NULL) { + /* + * No matching pcb found; discard datagram. + * (No need to send an ICMP Port Unreachable + * for a broadcast or multicast datgram.) + */ + switch (af) { + case AF_INET: + udpstat.udps_noport++; + udpstat.udps_noportbcast++; + break; + case AF_INET6: + udp6stat.udp6s_noport++; + udp6stat.udp6s_noportmcast++; + break; + } + goto bad; + } +#endif + } else { + /* + * Locate pcb for datagram. + */ + in6p = in6_pcblookup_connect(&udb6, src6, *sport, + dst6, *dport, 0); + if (in6p == 0) { + ++udpstat.udps_pcbhashmiss; + in6p = in6_pcblookup_bind(&udb6, dst6, *dport, 0); + if (in6p == 0) { +#if 0 + struct mbuf *n; + n = m_copy(m, 0, M_COPYALL); + switch (af) { + case AF_INET: + udpstat.udps_noport++; + if (m->m_flags & (M_BCAST | M_MCAST)) { + udpstat.udps_noportbcast++; + goto bad; + } + if (n != NULL) + icmp_error(n, ICMP_UNREACH, + ICMP_UNREACH_PORT, 0, 0); + break; + case AF_INET6: + udp6stat.udp6s_noport++; + if (m->m_flags & M_MCAST) { + udp6stat.udp6s_noportmcast++; + goto bad; + } + if (n != NULL) + icmp6_error(n, ICMP6_DST_UNREACH, + ICMP6_DST_UNREACH_NOPORT, 0); + break; + } +#endif + + return rcvcnt; + } + } + + udp6_sendup(m, off, (struct sockaddr *)src, in6p->in6p_socket); + rcvcnt++; + } + +bad: + return rcvcnt; +} +#endif + +#if 0 +void +#if __STDC__ +udp_input(struct mbuf *m, ...) +#else +udp_input(m, va_alist) + struct mbuf *m; + va_dcl +#endif +{ int proto; register struct ip *ip; register struct udphdr *uh; @@ -151,9 +872,6 @@ udp_input(m, va_alist) int iphlen; va_list ap; struct sockaddr_in udpsrc; -#ifdef MAPPED_ADDR_ENABLED - struct sockaddr_in6 mapped; -#endif struct sockaddr *sa; va_start(ap, m); @@ -291,14 +1009,6 @@ udp_input(m, va_alist) } m_adj(n, iphlen); sa = (struct sockaddr *)&udpsrc; -#ifdef MAPPED_ADDR_ENABLED - if (last->inp_socket->so_proto-> - pr_domain->dom_family == AF_INET6) { - in6_sin_2_v4mapsin6(&udpsrc, - &mapped); - sa = (struct sockaddr *)&mapped; - } -#endif /* MAPPED_ADDR_ENABLED */ if (sbappendaddr( &last->inp_socket->so_rcv, sa, n, opts) == 0) { @@ -348,13 +1058,6 @@ udp_input(m, va_alist) m->m_pkthdr.len -= iphlen; m->m_data += iphlen; sa = (struct sockaddr *)&udpsrc; -#ifdef MAPPED_ADDR_ENABLED - if (last->inp_socket->so_proto->pr_domain->dom_family == - AF_INET6) { - in6_sin_2_v4mapsin6(&udpsrc, &mapped); - sa = (struct sockaddr *)&mapped; - } -#endif /* MAPPED_ADDR_ENABLED */ if (sbappendaddr(&last->inp_socket->so_rcv, sa, m, opts) == 0) { udpstat.udps_fullsock++; goto bad; @@ -409,12 +1112,6 @@ udp_input(m, va_alist) m->m_pkthdr.len -= iphlen; m->m_data += iphlen; sa = (struct sockaddr *)&udpsrc; -#ifdef MAPPED_ADDR_ENABLED - if (inp->inp_socket->so_proto->pr_domain->dom_family == AF_INET6) { - in6_sin_2_v4mapsin6(&udpsrc, &mapped); - sa = (struct sockaddr *)&mapped; - } -#endif /* MAPPED_ADDR_ENABLED */ if (sbappendaddr(&inp->inp_socket->so_rcv, sa, m, opts) == 0) { udpstat.udps_fullsock++; goto bad; @@ -426,6 +1123,7 @@ bad: if (opts) m_freem(opts); } +#endif /* * Notify a udp user of an asynchronous error; @@ -454,8 +1152,8 @@ udp_ctlinput(cmd, sa, v) void (*notify) __P((struct inpcb *, int)) = udp_notify; int errno; - if (sa->sa_family != AF_INET || - sa->sa_len != sizeof(struct sockaddr_in)) + if (sa->sa_family != AF_INET + || sa->sa_len != sizeof(struct sockaddr_in)) return NULL; if ((unsigned)cmd >= PRC_NCMDS) return NULL; @@ -470,6 +1168,8 @@ udp_ctlinput(cmd, sa, v) uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport, ip->ip_src, uh->uh_sport, errno, notify); + + /* XXX mapped address case */ } else in_pcbnotifyall(&udbtable, satosin(sa)->sin_addr, errno, notify); @@ -607,9 +1307,11 @@ udp_usrreq(so, req, m, nam, control, p) inp = sotoinpcb(so); inp->inp_ip.ip_ttl = ip_defttl; #ifdef IPSEC - inp = (struct inpcb *)so->so_pcb; - if ((error = ipsec_init_policy(&inp->inp_sp)) != 0) + error = ipsec_init_policy(&inp->inp_sp); + if (error != 0) { in_pcbdetach(inp); + break; + } #endif /*IPSEC*/ break; diff --git a/sys/netinet6/IMPLEMENTATION b/sys/netinet6/IMPLEMENTATION index 60c48e35cf0..9fc9edb4caa 100644 --- a/sys/netinet6/IMPLEMENTATION +++ b/sys/netinet6/IMPLEMENTATION @@ -1,14 +1,14 @@ -$NetBSD: IMPLEMENTATION,v 1.2 1999/07/03 21:30:17 thorpej Exp $ +$NetBSD: IMPLEMENTATION,v 1.3 1999/12/13 15:17:21 itojun Exp $ # NOTE: this is from original KAME distribution. # Some portion of this document is not applicable to the code merged into -# NetBSD-current (especially tcp part). Check sys/netinet6/TODO as well. +# NetBSD-current. Check sys/netinet6/TODO as well. Implementation Note KAME Project http://www.kame.net/ - $Date: 1999/07/03 21:30:17 $ + KAME Date: 1999/11/26 15:39:27 1. IPv6 @@ -20,18 +20,18 @@ below (NOTE: this is not a complete list - this is too hard to maintain...). For details please refer to specific chapter in the document, RFCs, manpages come with KAME, or comments in the source code. -Conformance tests have been performed on the previous KAME STABLE kit at -TAHI project. -Results can be viewed at http://www.tahi.org/report/KAME/freebsd-stable-9903/. +Conformance tests have been performed on the previous KAME STABLE kit +at TAHI project. Results can be viewed at http://www.tahi.org/report/KAME/. We also attended Univ. of New Hampshire IOL tests (http://www.iol.unh.edu/) in the past, with our past snapshots. RFC1639: FTP Operation Over Big Address Records (FOOBAR) * RFC2428 is preferred over RFC1639. ftp clients will first try RFC2428, then RFC1639 if failed. +RFC1886: DNS Extensions to support IPv6 RFC1933: Transition Mechanisms for IPv6 Hosts and Routers * IPv4 compatible address is not supported. - * automatic tunnelling (4.3) is not supported. + * automatic tunneling (4.3) is not supported. * "gif" interface implements IPv[46]-over-IPv[46] tunnel in a generic way, and it covers "configured tunnel" described in the spec. See 1.5 in this document for details. @@ -42,8 +42,7 @@ RFC2283: Multiprotocol Extensions for BGP-4 * so-called "BGP4+". * KAME-supplied bgpd supports this. RFC2292: Advanced Sockets API for IPv6 - * For supported library functions/kernel APIs, see sys/netinet6/ADVAPI - (KAME/FreeBSD228 only) + * For supported library functions/kernel APIs, see sys/netinet6/ADVAPI. RFC2362: Protocol Independent Multicast-Sparse Mode (PIM-SM) * RFC2362 defines packet formats for PIM-SM. draft-ietf-pim-ipv6-01.txt is written based on this. @@ -65,35 +64,45 @@ RFC2462: IPv6 Stateless Address Autoconfiguration RFC2463: ICMPv6 for IPv6 specification * See 1.8 in this document for details. RFC2464: Transmission of IPv6 Packets over Ethernet Networks +RFC2465: MIB for IPv6: Textual Conventions and General Group + * Necessary statistics are gathered by the kernel. Actual IPv6 MIB + support is provided as patchkit for ucd-snmp. +RFC2466: MIB for IPv6: ICMPv6 group + * Necessary statistics are gathered by the kernel. Actual IPv6 MIB + support is provided as patchkit for ucd-snmp. RFC2467: Transmission of IPv6 Packets over FDDI Networks RFC2472: IPv6 over PPP RFC2492: IPv6 over ATM Networks * only PVC is supported. +RFC2497: Transmission of IPv6 packet over ARCnet Networks RFC2545: Use of BGP-4 Multiprotocol Extensions for IPv6 Inter-Domain Routing RFC2553: Basic Socket Interface Extensions for IPv6 * IPv4 mapped address (3.7) and special behavior of IPv6 wildcard bind socket (3.8) are, - - supported on KAME/FreeBSD31 and it seems to be working well. - - also supported on KAME/FreeBSD228, but it is not tested well - so disabled by default. - - not supported on KAME/NetBSD and KAME/BSDI. + - supported on KAME/FreeBSD3x, + - supported on KAME/NetBSD, + - supported on KAME/OpenBSD and KAME/BSDI4, + - not supported on KAME/FreeBSD228 and KAME/BSDI3. see 1.12 in this document for details. -draft-ietf-ipngwg-ipv6router-alert-04: IPv6 router alert option +RFC2675: IPv6 Jumbograms + * See 1.7 in this document for details. +RFC2710: Multicast Listener Discovery for IPv6 +RFC2711: IPv6 router alert option draft-ietf-ipngwg-router-renum-08: Router renumbering for IPv6 draft-ietf-ipngwg-icmp-namelookups-02: IPv6 Name Lookups Through ICMP draft-ietf-ipngwg-icmp-name-lookups-03: IPv6 Name Lookups Through ICMP -draft-ietf-ipngwg-aaaa-03: DNS Extensions to support IPv6 -draft-ietf-ipngwg-mld-01: Multicast Listener Discovery for IPv6 -draft-ietf-ipngwg-jumbo-00: The IPv6 Jumbo Payload Option - * See 1.7 in this document for details. -draft-ietf-ipngwg-jumbograms-00: IPv6 Jumbograms - * See 1.7 in this document for details. draft-ietf-pim-ipv6-01.txt: PIM for IPv6 - * no sparse mode support. pim6dd implements dense mode only. + * pim6dd implements dense mode. pim6sd implements sparse mode. +draft-ietf-dhc-dhcpv6-14.txt: DHCPv6 +draft-ietf-dhc-v6exts-11.txt: Extensions for DHCPv6 + * kame/dhcp6 has test implementation, which will not be compiled in + default compilation. draft-itojun-ipv6-tcp-to-anycast-00: Disconnecting TCP connection toward IPv6 anycast address draft-yamamoto-wideipv6-comm-model-00 * See 1.6 in this document for details. +draft-ietf-ipngwg-scopedaddr-format-00.txt: + An Extension of Format for IPv6 Scoped Addresses 1.2 Neighbor Discovery @@ -105,7 +114,7 @@ transmission command as admin tool. If DAD fails, the address will be marked "duplicated" and message will be generated to syslog (and usually to console). The "duplicated" mark -can be cheked with ifconfig. It is administrators' responsibility to check +can be checked with ifconfig. It is administrators' responsibility to check for and recover from DAD failures. The behavior should be improved in the near future. @@ -113,21 +122,24 @@ Some of the network driver loops multicast packets back to itself, even if instructed not to do so (especially in promiscuous mode). In such cases DAD may fail, because DAD engine sees inbound NS packet (actually from the node itself) and considers it as a sign of duplicate. +You may want to look at #if condition marked "heuristics" in +sys/netinet6/nd6_nbr.c:nd6_dad_timer() as workaround (note that the code +fragment in "heuristics" section is not spec conformant). Neighbor Discovery specification (RFC2461) does not talk about neighbor cache handling in the following cases: -(1) there was no neighbor cache entry, and unsolicited RS/NS/NA/redirect - packet, without link-layer address was received +(1) when there was no neighbor cache entry, node received unsolicited + RS/NS/NA/redirect packet without link-layer address (2) neighbor cache handling on medium without link-layer address (we need a neighbor cache entry for IsRouter bit) For (1), we implemented workaround based on discussions on IETF ipngwg mailing list. For more details, see the comments in the source code and email thread started from (IPng 7155), dated Feb 6 1999. -IPv6 adderss autoconfiguration assumes that a host has only single network -interface (single non-loopback interface). This is because the spec assumes -that there's no routing table on IPv6 host (an IPv6 host has default router -list and prefix list only). +IPv6 address autoconfiguration assumes that a host has only single network +interface (more precisely, single non-loopback interface). This is because +the spec assumes that there's no routing table on IPv6 host (an IPv6 host +has default router list and prefix list only). Because of this, if you accept RAs on a node with multiple network interfaces, the node will not behave as you might expect. RFC2461 Appendix A talks little bit about this issue. @@ -142,7 +154,8 @@ To avoid possible DoS attacks and infinite loops, KAME stack will accept only 10 options on ND packet. Therefore, if you have 20 prefix options attached to RA, only the first 10 prefixes will be recognized. If this troubles you, please contact KAME team and/or modify -sys/netinet6/nd6.c:nd6_options(). +nd6_maxndopt in sys/netinet6/nd6.c. If there are high demands we may +provide sysctl knob for the variable. 1.3 Scope Index @@ -161,19 +174,19 @@ care about portability of your application, we suggest you to use advanced API rather than sin6_scope_id. In the kernel, an interface index for link-local scoped address is -embedded into in6_addr.s6_addr16[1]. For example, you may see -something like: +embedded into 2nd 16bit-word (3rd and 4th byte) in IPv6 address. +For example, you may see something like: fe80:1::200:f8ff:fe01:6317 in the routing table and interface address structure (struct in6_ifaddr). The address above is a link-local unicast address -which belongs to a network interface whose interface identifier is -1. The embedded index enables us to identify IPv6 link local +which belongs to a network interface whose interface identifier is 1. +The embedded index enables us to identify IPv6 link local addresses over multiple interfaces effectively and with only a little code change. Routing daemons and configuration programs, like route6d and ifconfig, will need to manipulate the "embedded" scope index. These programs use routing sockets and ioctls (like SIOCGIFADDR_IN6) -and the kernel API will return IPv6 addresses with in6_addr.s6_addr16[1] +and the kernel API will return IPv6 addresses with 2nd 16bit-word filled in. The APIs are for manipulating kernel internal structure. Programs that use these APIs have to be prepared about differences in kernels anyway. @@ -187,6 +200,16 @@ outgoing interface, that command is not ready to accept scoped address. This may seem to be opposite from IPv6's premise to support "dentist office" situation. We believe that specifications need some improvements for this. +Some of the userland tools support extended numeric IPv6 syntax, as +documented in draft-ietf-ipngwg-scopedaddr-format-00.txt. You can specify +outgoing link, by using name of the outgoing interface like "fe80::1@ne0". +This way you will be able to specify link-local scoped address without much +trouble. +To use this extension in your program, you'll need to use getaddrinfo(3), +and getnameinfo(3) with NI_WITHSCOPEID. +The implementation currently assumes 1-to-1 relationship between a link and an +interface, which is stronger than what specs say. + 1.4 Plug and Play The KAME kit implements most of the IPv6 stateless address @@ -197,31 +220,84 @@ kernel. Router Solicitation (RS) output for endhosts, RS input for routers, and RA output for routers are implemented in the userland. -When the kernel boots up, an IPv6 link-local address is assigned to each -interface. Also, direct route for the link-local address is added to -routing table. Here is an output of netstat command: +1.4.1 Assignment of link-local, and special addresses + +IPv6 link-local address is generated from IEEE802 adddress (ethernet MAC +address). Each of interface is assigned an IPv6 link-local address +automatically, when the interface becomes up (IFF_UP). Also, direct route +for the link-local address is added to routing table. + +Here is an output of netstat command: Internet6: Destination Gateway Flags Netif Expire fe80:1::/64 link#1 UC ed0 fe80:2::/64 link#2 UC ep0 +Interfaces that has no IEEE802 address (pseudo interfaces like tunnel +interfaces, or ppp interfaces) will borrow IEEE802 address from other +interfaces, such as ethernet interfaces, whenever possible. +If there is no IEEE802 hardware attached, last-resort pseudorandom value, +which is from MD5(hostname), will be used as source of link-local address. +If it is not suitable for your usage, you will need to configure the +link-local address manually. + +If an interface is not capable of handling IPv6 (such as lack of multicast +support), link-local address will not be assigned to that interface. +See section 2 for details. + Each interface joins the solicited multicast address and the -link-local all-nodes multicast addresses (e.g. fe80:1::1:ff01:6317 -and ff02:1::1, respectively). In addition to a link-local address, -the loopback address (::1) is assigned to the loopback interface. It -adds ::1/128 and ff01::/32 to routing table and joins ff01::1. - -When a host hears Router Advertisement from the router, default route -and network address prefix (usually global address prefix) are added. -To generate a Router Solicitation packet at any time, use the "rtsol" command. -Also, "rtsold" daemon is available. It generates Router Solicitation +link-local all-nodes multicast addresses (e.g. fe80::1:ff01:6317 +and ff02::1, respectively, on the link the interface is attached). +In addition to a link-local address, the loopback address (::1) will be +assigned to the loopback interface. Also, ::1/128 and ff01::/32 are +automatically added to routing table, and loopback interface joins +node-local multicast group ff01::1. + +1.4.2 Stateless address autoconfiguration on hosts + +In IPv6 specification, nodes are separated into two categories: +routers and hosts. Routers forward packets addressed to others, hosts does +not forward the packets. net.inet6.ip6.forwarding defines whether this +node is router or host (router if it is 1, host if it is 0). + +When a host hears Router Advertisement from the router, a host may +autoconfigure itself by stateless address autoconfiguration. +This behavior can be controlled by net.inet6.ip6.accept_rtadv +(host autoconfigures itself if it is set to 1). +By autoconfiguration, network address prefix for the receiving interface +(usually global address prefix) is added. Default route is also configured. +Routers periodically generate Router Advertisement packets. To request +an adjacent router to generate RA packet, a host can transmit Router +Solicitation. To generate a RS packet at any time, use the "rtsol" command. +"rtsold" daemon is also available. "rtsold" generates Router Solicitation whenever necessary, and it works great for nomadic usage (notebooks/laptops). If one wishes to ignore Router Advertisements, use sysctl to set net.inet6.ip6.accept_rtadv to 0. To generate Router Advertisement from a router, use the "rtadvd" daemon. +Note that, IPv6 specification assumes the following items, and nonconforming +cases are left unspecified: +- Only hosts will listen to router advertisements +- Hosts have single network interface (except loopback) +Therefore, this is unwise to enable net.inet6.ip6.accept_rtadv on routers, +or multi-interface host. A misconfigured node can behave strange +(KAME code allows nonconforming configuration, for those who would like +to do some experiments). + +To summarize the sysctl knob: + accept_rtadv forwarding role of the node + --- --- --- + 0 0 host (to be manually configured) + 0 1 router + 1 0 autoconfigured host + (spec assumes that host has single + interface only, autoconfigred host with + multiple interface is out-of-scope) + 1 1 invalid, or experimental + (out-of-scope of spec) + RFC2462 has validation rule against incoming RA prefix information option, in 5.5.3 (e). This is to protect hosts from malicious (or misconfigured) routers that advertise very short prefix lifetime. @@ -230,10 +306,17 @@ for "(ipng 6712)" in the archive) and KAME implements Jim's update. See 1.2 in the document for relationship between DAD and autoconfiguration. -DHCPv6 server/client is not implemented yet. "Managed" and "Other" bits in -RA have no special effect to stateful autoconfiguration procedure -("Managed" bit actually prevents stateless autoconfiguration, but no special -action will be taken for DHCPv6 client). +1.4.3 DHCPv6 + +We supply a tiny DHCPv6 server/client in kame/dhcp6. However, the +implementation is very premature (for example, this does NOT +implement address lease/release), and it is not in default compilation +tree. If you want to do some experiment, compile it on your own. + +DHCPv6 and autoconfiguration also needs more work. "Managed" and "Other" +bits in RA have no special effect to stateful autoconfiguration procedure +in DHCPv6 client program ("Managed" bit actually prevents stateless +autoconfiguration, but no special action will be taken for DHCPv6 client). 1.5 Generic tunnel interface @@ -254,6 +337,10 @@ of tunneling. Please be warned. gif can be configured to be ECN-friendly. See 4.5 for ECN-friendliness of tunnels, and gif(4) manpage for how to configure. +If you would like to configure an IPv4-in-IPv6 tunnel with gif interface, +read gif(4) carefully. You will need to remove IPv6 link-local address +automatically assigned to the gif interface. + 1.6 Source Address Selection Source selection of KAME is scope oriented (there are some exceptions - @@ -275,12 +362,14 @@ by the following rule: This is the last resort, which may cause scope violation. For instance, ::1 is selected for ff01::1, fe80:1::200:f8ff:fe01:6317 -for fe80:1::2a0:24ff:feab:839b. If the outgoing interface has -multiple address for the scope, a source is selected longest match -basis (rule 3). Suppose 3ffe:501:808:1:200:f8ff:fe01:6317 and -3ffe:2001:9:124:200:f8ff:fe01:6317 are given to the outgoing -interface. 3ffe:501:808:1:200:f8ff:fe01:6317 is chosen as the source -for the destination 3ffe:501:800::1. +for fe80:1::2a0:24ff:feab:839b (note that embedded interface index - +described in 1.3 - helps us choose the right source address. Those +embedded indices will not be on the wire). +If the outgoing interface has multiple address for the scope, +a source is selected longest match basis (rule 3). Suppose +3ffe:501:808:1:200:f8ff:fe01:6317 and 3ffe:2001:9:124:200:f8ff:fe01:6317 +are given to the outgoing interface. 3ffe:501:808:1:200:f8ff:fe01:6317 +is chosen as the source for the destination 3ffe:501:800::1. Note that the above rule is not documented in the IPv6 spec. It is considered "up to implementation" item. @@ -292,6 +381,17 @@ Under the spec (RFC2461 7.2.2) NA's source should be the target address of the corresponding NS's target. In this case we follow the spec rather than the above longest-match rule. +For new connections (when rule 1 does not apply), deprecated addresses +(addresses with preferred lifetime = 0) will not be chosen as source address +if other choises are available. If no other choices are available, +deprecated address will be used as a last resort. If there are multiple +choice of deprecated addresses, the above scope rule will be used to choose +from those deprecated addreses. If you would like to prohibit the use +of deprecated address for some reason, configure net.inet6.ip6.use_deprecated +to 0. The issue related to deprecated address is described in RFC2462 5.5.4 +(NOTE: there is some debate underway in IETF ipngwg on how to use +"deprecated" address). + 1.7 Jumbo Payload KAME supports the Jumbo Payload hop-by-hop option used to send IPv6 @@ -340,14 +440,32 @@ we have no medium (other than loopback) to test this. Contact us if you need this. IPsec does not work on jumbograms. This is due to some specification twists -in supporting AH with jumbograms. +in supporting AH with jumbograms (AH header size influences payload length, +and this makes it real hard to authenticate inbound packet with jumbo payload +option as well as AH). + +There are fundamental issues in *BSD support for jumbograms. We would like to +address those, but we need more time to finalize these. To name a few: +- mbuf pkthdr.len field is typed as "int" in 4.4BSD, so it will not hold + jumbogram with len > 2G on 32bit architecture CPUs. If we would like to + support jumbogram properly, the field must be expanded to hold 4G + + IPv6 header + link-layer header. Therefore, it must be expanded to at least + int64_t (u_int32_t is NOT enough). +- We mistakingly use "int" to hold packet length in many places. We need + to convert them into larger integral type. It needs a great care, as we may + experience overflow during packet length computation. +- We mistakingly check for ip6_plen field of IPv6 header for packet payload + length in various places. We should be checking mbuf pkthdr.len instead. + ip6_input() will perform sanity check on jumbo payload option on input, + and we can safely use mbuf pkthdr.len afterwards. +- TCP code needs a careful update in bunch of places, of course. 1.8 Loop prevention in header processing IPv6 specification allows arbitrary number of extension headers to be placed onto packets. If we implement IPv6 packet processing code in the way BSD IPv4 code is implemented, kernel stack may -overflow due to deep function call chain. KAME sys/netinet6 code +overflow due to long function call chain. KAME sys/netinet6 code is carefully designed to avoid kernel stack overflow. Because of this, KAME sys/netinet6 code defines its own protocol switch structure, as "struct ip6protosw" (see netinet6/ip6protosw.h). @@ -373,9 +491,8 @@ according to DNS. 1.11 Kernel Internals - (*) TCP stack is merged between netinet and netinet6 on KAME/FreeBSD31, - so if your platform is FreeBSD31, then there is no difference - between tcp6 and tcp in following description. + (*) TCP/UDP part is handled differently between operating system platforms. + See 1.12 for details. The current KAME has escaped from the IPv4 netinet logic. While ip_forward() calls ip_output(), ip6_forward() directly calls @@ -442,32 +559,29 @@ of IPv6 wildcard bind socket (3.8). The spec allows you to: - Transmit IPv4 packet over AF_INET6 socket by using special form of the address like ::ffff:10.1.1.1. - Accept IPv4 connections by AF_INET6 wildcard bind socket. -but it may look complicated spec. +but the spec itself is very complicated and does not specify how the +socket layer should behave. -We KAME team have 4 OS platforms right now, and behavior is silghtly +We KAME team have 4 OS platforms right now, and behavior is slightly different between them. To summarize: - All KAME implementations treat tcp/udp port number space separately between IPv4 and IPv6. -- KAME/NetBSD and KAME/BSDI does not support IPv4 mapped address, nor - special wildcard bind on AF_INET6. -- KAME/FreeBSD31 supports IPv4 mapped address, and special wildcard bind on - AF_INET6. They seem to be working well and enabled by default. - You can disable those two by runtime and kernel compile configuration. - (you can't enable only one of them: they comes together) -- KAME/FreeBSD228 supports both, but it is not tested well so disabled by - default. - You can enable those two by runtime and kernel compile configuration. - (you can't enable only one of them: they comes together) -- KAME/FreeBSD228 and KAME/FreeBSD31 implements slightly different behavior - for special wildcard bind on AF_INET6. +- KAME/BSDI3 and KAME/FreeBSD228 does not support IPv4 mapped address, + nor special wildcard bind on AF_INET6. +- KAME/FreeBSD3x supports IPv4 mapped address, and special wildcard bind on + AF_INET6. It is enabled by default. You can disable those two by runtime + and kernel compile configuration. + (you can't enable only one of them: they come together) +- KAME/NetBSD supports both. This is always enabled. +- KAME/OpenBSD and KAME/BSDI4 supports both. This is always enabled. The following sections will give you the details, and how you can -configure the behavior on KAME/FreeBSD{228,31}. +configure the behavior. Advise to application implementers: to implement a portable IPv6 application (which works on multiple IPv6 kernels), we believe that the following is the key to the success: -- NEVER hardcode AF_INET or AF_INET6. +- NEVER hardcode AF_INET nor AF_INET6. - Use getaddrinfo() and getnameinfo() throughout the system. Never use gethostby*(), getaddrby*(), inet_*() or getipnodeby*(). - If you would like to listen to connections, use getaddrinfo() (maybe @@ -476,6 +590,9 @@ is the key to the success: all the destination returned, like telnet does. - Some of the IPv6 stack is shipped with buggy getaddrinfo(). Ship a minimal working version with your application and use that as last resort. +- Try to avoid use of IPv4 mapped address (waiting for IPv4 connection on + AF_INET6 socket). Listen to both AF_INET socket and AF_INET6 socket, + if you support both address families. It looks that RFC2553 talks too little on wildcard bind issue, especially on the port space issue, failure mode and relationship between AF_INET/INET6 wildcard bind. There can be several separate @@ -488,9 +605,12 @@ on ipv6imp mailing list, in mid March 1999 and it looks that there's no concrete consensus (means, up to implementers). You may want to check the mailing list archives. -1.12.1 KAME/NetBSD and KAME/BSDI +We supply a tool called "bindtest" that explores the behavior of +kernel bind(2). The tool will not be compiled by default. + +1.12.1 KAME/BSDI3 and KAME/FreeBSD228 -The platforms do not support IPv4 mapped address. +The platform do not support IPv4 mapped address. The IPv4 mapped address support needs tweaked implementation in DNS support libraries, as documented in RFC2553 6.1. However, since the platforms do not support this, you do not need to worry about @@ -507,13 +627,13 @@ Applicsations should use proper socket for connections. IPv4 connections must be made on AF_INET socket, and IPv6 connections must be made on AF_INET6 socket. getaddrinfo() library helps you in writing AF-independent application, and managing sockets with different AFs. -(some of the implementers think that we should totaly get rid of gethostby* +(some of the implementers think that we should totally get rid of gethostby* family of the functions and migrate to get{addr,name}info, since it is very clean and helps you support new AFs in the future) -1.12.2 KAME/FreeBSD31 +1.12.2 KAME/FreeBSD3x -The platform can be configued to support IPv4 mapped address/special AF_INET6 +The platform can be configured to support IPv4 mapped address/special AF_INET6 wildcard bind (enabled by default). If you disable it, it behaves as described in 1.12.1. @@ -545,8 +665,6 @@ If you run two daemons, which binds to AF_INET6 wildcard socket and AF_INET socket (say, sendmail4 and sendmail6), story start to look a bit complicated. The next sections have the detail. -(* the following paragraphs are different between KAME/FreeBSD31 and 228) - Wildcard bind on AF_INET6 behaves like "wildcard bind between two address families". It will grab IPv4 connection if and only if there is no socket that binds to more specific destination. @@ -554,7 +672,7 @@ Here, wildcard bind on AF_INET is regarded as "more specific bind" than wildcard bind on AF_INET6. In other words, wildcard bind on AF_INET6 is the only thing that has special behavior. It will not affect wildcard bind on AF_INET. -If the folllowing events happen, IPv4 connection will be routed +If the following events happen, IPv4 connection will be routed to application B, and IPv6 connection will be routed to application A. - application A perform wildcard bind on AF_INET6, port X - application B perform wildcard bind on AF_INET, port X @@ -568,48 +686,40 @@ will be routed to application A. - IPv4 connection arrives - IPv6 connection arrives -If the following events happen, KAME/FreeBSD31 will behave like this: +If the following events happen, KAME/FreeBSD3x will behave like this: - sendmail4 is running. It is doing wildcard bind on AF_INET. - Invoke sendmail6. It will do a wildcard bind on AF_INET6. -- Stop sendmail4. Here, on KAME/FreeBSD31, IPv4 and IPv6 conections will +- Stop sendmail4. Here, on KAME/FreeBSD3x, IPv4 and IPv6 conections will be routed to sendmail6. This is different from KAME/FreeBSD228. -1.12.3 KAME/FreeBSD228 - -The platform can be configued to support IPv4 mapped address/special AF_INET6 -wildcard bind (disabled by default). If you disable it, it behaves as -described in 1.12.1. - -KAME/FreeBSD228 works mostly the same as KAME/FreeBSD31, except the paragraphs -under (*) mark in 1.12.2. Please refer to 1.12.2 for other parts. - - Wildcard bind on AF_INET6 affects the behavior of wildcard bind on - AF_INET. - If events happen in the following order, application B fails to - bind. Therefore, both IPv4 and IPv6 connections will be routed to - application A. - - application A perform wildcard bind on AF_INET6, port X - - application B perform wildcard bind on AF_INET, port X -> fail - - IPv4 connection arrives - - IPv6 connection arrives - If the following events happen, IPv4 connection will be routed to - application B, and IPv6 connection will be routed to application - A. This behavior is the same as described in 1.12.1. - - application B perform wildcard bind on AF_INET, port X - - application A perform wildcard bind on AF_INET6, port X - - IPv4 connection arrives - - IPv6 connection arrives - - If the following events happen, KAME/FreeBSD228 will behave like this: - - sendmail4 is running. It is doing wildcard bind on AF_INET. - - Invoke sendmail6. It will do a wildcard bind on AF_INET6. - - Stop sendmail4. Here, on KAME/FreeBSD228, sendmail6 will be able to - get IPv6 connections only. This is different from KAME/FreeBSD31. - -1.12.4 configuration and implementation - -On KAME/FreeBSD31 and KAME/FreeBSD228, the behavior is -configurable by following procedure. To enable it: +1.12.4 KAME/NetBSD + +KAME/NetBSD uses shared tcp4/6 code (from sys/netinet/tcp*) and shared +udp4/6 code (from sys/netinet/udp*). The implementation is made differently +from KAME/FreeBSD3x. KAME/NetBSD uses separate inpcb/in6pcb structures, +while KAME/FreeBSD3x uses merged inpcb structure. +Supports for IPv4 mapped address/special AF_INET6 wildcard bind are +enabled by default. At this moment there is no way to disable it. + +1.12.5 KAME/OpenBSD and KAME/BSDI4 + +KAME/OpenBSD and KAME/BSDI4 use NRL-based TCP/UDP stack and inpcb source code, +which was derived from NRL IPv6/IPsec stack. I guess it supports IPv4 mapped +address and speical AF_INET6 wildcard bind. The implementation is, again, +different from other KAME/*BSDs. +Note that NRL inpcb layer has different behavior than KAME implementation, +namely: +- If you bind(2) a socket to IPv6 wildcard address (::) then bind(2) + another socket to IPv4 wildcard address (0.0.0.0), the latter will fail + with EADDRINUSE. +- If you bind(2) to IPv4 wildcard address then IPv6 wildcard address, + both will success. However, all IPv4 traffic (and IPv6 traffic) will be + captured by IPv6 wildcard socket. + +1.12.6 configuration and implementation + +On KAME/FreeBSD3x, the behavior is configurable by following procedure. +To enable it: - Add the "MAPPED_ADDR_ENABLED" kernel config option into your kernel config file (see "sys/i386/conf/GENERIC.v6" sample file) and build your kernel, and @@ -618,15 +728,6 @@ configurable by following procedure. To enable it: Note that, to enable the behavior you'll need to do the both of the above. If you do not do the both, the behavior is disabled. -The behavior is enabled by default on KAME/FreeBSD31, but disabled -by default on KAME/FreeBSD228, because those functions are not well -tested on KAME/FreeBSD228. -Implementation is quite different between KAME/FreeBSD31 and -KAME/FreeBSD228, because tcp stack code and protocol contorol block -(pcb) implementation are merged between netinet and netinet6 in -KAME/FreeBSD31 code, but they are separate in KAME/FreeBSD228 code. -This is the reason for different behavior in two OSes. - 2. Network Drivers KAME requires three items to be added into the standard drivers: @@ -638,44 +739,43 @@ KAME requires three items to be added into the standard drivers: (2) multicast. If "ifmcstat" yields no multicast group for a interface, that interface has to be patched. -(3) If you are using notebook PCs, you'll need to be a one-liner for - initializing your interface when your card is plugged in. - (NOTE: KAME/NetBSD does not need this) - To avoid troubles, we suggest you to comment out the device drivers -for unsupported/unnecessary cards, from the configuration file. +for unsupported/unnecessary cards, from the kernel configuration file. If you accidentally enable unsupported drivers, some of the userland tools may not work correctly (routing daemons are typical example). In the following sections, "official support" means that KAME developers are using that ethernet card/driver frequently. +(NOTE: In the past we required all pcmcia drivers to have a call to +in6_ifattach(). We have no such requirement any more) + 2.1 FreeBSD 2.2.x-RELEASE Here is a list of FreeBSD 2.2.x-RELEASE drivers and its conditions: - driver mbuf(1) multicast(2) PCMCIA official - patch(3) support? - --- --- --- --- --- + driver mbuf(1) multicast(2) official + support? + --- --- --- --- (Ethernet) - ar looks ok - - - - cnw ok ok ok yes (*) - ed ok ok ok yes - ep ok ok ok yes - fe ok ok ok yes - sn looks ok - ok - (*) - vx looks ok - - - - wlp ok ok ok - (*) - xl ok ok - yes - zp ok ok - - + ar looks ok - - + cnw ok ok yes (*) + ed ok ok yes + ep ok ok yes + fe ok ok yes + sn looks ok - - (*) + vx looks ok - - + wlp ok ok - (*) + xl ok ok yes + zp ok ok - (FDDI) - fpa looks ok ? - - + fpa looks ok ? - (ATM) - en ok ok - yes + en ok ok yes (Serial) - lp ? - - not work - sl ? - - not work - sr looks ok ok - - (**) + lp ? - not work + sl ? - not work + sr looks ok ok - (**) You may want to add an invocation of "rtsol" in "/etc/pccard_ether", if you are using notebook computers and PCMCIA ethernet card. @@ -685,31 +785,33 @@ if you are using notebook computers and PCMCIA ethernet card. (**) There was some report says that, if you make sr driver up and down and then up, the kernel may hang up. We have disabled frame-relay support from sr driver and after that this looks to be working fine. If you need -frame-relay support to come back, please contact KAME deverlopers. +frame-relay support to come back, please contact KAME developers. -2.2 BSD/OS +2.2 BSD/OS 3.x -The following lists BSD/OS device drivers and its conditions: +The following lists BSD/OS 3.x device drivers and its conditions: - driver mbuf(1) multicast(2) PCMCIA official - patch(3) support? - --- --- --- --- --- + driver mbuf(1) multicast(2) official + support? + --- --- --- --- (Ethernet) - cnw ok ok ok yes - de ok ok no need - - ef ok ok ok yes - exp ok ok no need - - mz ok ok ok yes - ne ok ok ok yes - we ok ok ok - + cnw ok ok yes + de ok ok - + df ok ok - + eb ok ok - + ef ok ok yes + exp ok ok - + mz ok ok yes + ne ok ok yes + we ok ok - (FDDI) - fpa ok ok - - + fpa ok ok - (ATM) - en maybe ok - - + en maybe ok - (Serial) - ntwo ok ok - yes - sl ? - - not work - appp ? - - not work + ntwo ok ok yes + sl ? - not work + appp ? - not work You may want to use "@insert" directive in /etc/pccard.conf to invoke "rtsol" command right after dynamic insertion of PCMCIA ethernet cards. @@ -717,7 +819,6 @@ You may want to use "@insert" directive in /etc/pccard.conf to invoke 2.3 NetBSD The following table lists the network drivers we have tried so far. -Note that, for NetBSD, we do not need one-liner patch to PCMCIA driver. driver mbuf(1) multicast(2) official support? @@ -726,31 +827,48 @@ Note that, for NetBSD, we do not need one-liner patch to PCMCIA driver. ne pci/i386 ok ok yes ep pcmcia/i386 ok ok - le sbus/sparc ok ok yes + bah zbus/amiga NG(*) (ATM) en pci/i386 ok ok - +(*) This may need some fix, but I'm not sure what arcnet interfaces assume... + 2.4 FreeBSD 3.x-RELEASE Here is a list of FreeBSD 3.x-RELEASE drivers and its conditions: - driver mbuf(1) multicast(2) PCMCIA official - patch(3) support? + driver mbuf(1) multicast(2) official + support? --- --- --- --- (Ethernet) - fe ok ok ? yes - fxp ok ok - yes - lnc ? ok - - - cnw ok ok ok(*) -(**) - ep ok ok ok(*) - - sn ? ? ? -(**) - -(*) With PAO3 patch applied. (http://www.jp.freebsd.org/PAO/). -(**) These drivers are distributed with PAO as PAO3 - (http://www.jp.freebsd.org/PAO/). + fe ok ok yes + fxp ok ok yes + wi ok ok yes + lnc ? ok - + cnw ok ok -(*) + ep ok ok - + sn ? ? -(*) + xl ? ok - + ed ? ok - + +(*) These drivers are distributed with PAO as PAO3 + (http://www.jp.freebsd.org/PAO/). More drivers will just simply work on KAME FreeBSD 3.x-RELEASE but have not been checked yet. +2.5 OpenBSD 2.x + +Here is a list of OpenBSD 2.x drivers and its conditions: + + driver mbuf(1) multicast(2) official + support? + --- --- --- --- + (Ethernet) + ne pci/i386 ok ok yes + ne pcmcia/i386 ok ok yes + le sbus/sparc ok ok yes + 3. Translator We categorize IPv4/IPv6 translator into 4 types. @@ -794,7 +912,7 @@ the connection will be relayed toward IPv4 destination 163.221.202.12. faithd must be invoked on FAITH-relay dual stack node. -For more details, consult kit/src/faithd/README. +For more details, consult kame/kame/faithd/README. 3.2 IPv6-to-IPv4 header translator @@ -873,8 +991,10 @@ The key management code implemented in this kit (sys/netkey) is a home-brew PFKEY v2 implementation. This conforms to RFC2367. The home-brew IKE daemon, "racoon" is included in the kit -(kit/src/racoon). It can perform key exchanges in some limited -conditions, however, it may take some more time to be stabilized. +(kame/kame/racoon). +Basically you'll need to run racoon as daemon, then setup a policy +to require keys (like ping -P 'out ipsec esp/transport//use'). +The kernel will contact racoon daemon as necessary to exchange keys. 4.3 AH and ESP handling @@ -890,8 +1010,9 @@ and strips off daisy-chained header and padding for ESP/AH. It is safe to strip off the ESP/AH header on packet reception, since we will never use the received packet in "as is" form. -By using ESP/AH, TCP4/6 MSS will be affected by extra daisy-chained -headers inserted by ESP/AH. Our code takes care of the case. +By using ESP/AH, TCP4/6 effective data segment size will be affected by +extra daisy-chained headers inserted by ESP/AH. Our code takes care of +the case. Basic crypto functions can be found in directory "sys/crypto". ESP/AH transform are listed in {esp,ah}_core.c with wrapper functions. If you @@ -955,6 +1076,12 @@ The following algorithms are NOT supported: (rfc2085.txt) keyed SHA1 with 160bit crypto checksum + 32bit padding (rfc1852.txt) +IPsec (in kernel) and IKE (in userland as "racoon") has been tested +at several interoperability test events, and it is known to interoperate +with many other implementations well. Also, KAME IPsec has quite wide +coverage for IPsec crypto algorithms documented in RFC (we cover +algorithms without intellectual property issues only). + 4.5 ECN consideration on IPsec tunnels KAME IPsec implements ECN-friendly IPsec tunnel, described in @@ -1008,6 +1135,16 @@ For more information, please refer to: (Thanks goes to Kenjiro Cho <kjc@csl.sony.co.jp> for detailed analysis) +4.6 Interoperability + +Here are (some of) platforms we have tested IPsec/IKE interoperability +in the past. Note that both ends (KAME and others) may have modified their +implementation, so use the following list just for reference purposes. + Altiga, Ashley-laurent (vpcom.com), Data Fellows (F-Secure), Ericsson + ACC, FreeS/WAN, HITACHI, IBM AIX, IIJ, Intel, Microsoft WinNT, NIST + (linux IPsec + plutoplus), Netscreen, OpenBSD, RedCreek, Routerware, + SSH, Secure Computing, Soliton, Toshiba, VPNet, Yamaha RT100i + 5. IPComp IPComp stands for IP payload compression protocol. This is aimed for @@ -1031,15 +1168,19 @@ Here are some points to be noted: - pfkey is modified to support IPComp. However, there's no official SA type number assignment yet. Portability with other IPComp stack is questionable (anyway, who else implement IPComp on UN*X?). -- Spec says that IPComp output must be performed before IPsec output - processing. However, with manual SPD setting, you can violate this - ordering requirement (KAME code is too generic, maybe). +- Spec says that IPComp output processing must be performed before IPsec + output processing, to achieve better compression ratio and "stir" data + stream before encryption. However, with manual SPD setting, you are able to + violate the ordering requirement (KAME code is too generic, maybe). - Though MTU can be significantly decreased by using IPComp, no special consideration is made about path MTU (spec talks nothing about MTU consideration). IPComp is designed for serial links, not ethernet-like medium, it seems. - You can change compression ratio on outbound packet, by changing - deflate_policy in sys/netinet6/ipcomp_core.c (should it be sysctl accessible? - or per-SAD configurable?) + deflate_policy in sys/netinet6/ipcomp_core.c. You can also change history + buffer size by changing deflate_window in the same source code. + (should it be sysctl accessible? or per-SAD configurable?) +- Tunnel mode IPComp is not working right. KAME box can generate tunnelled + IPComp packet, however, cannot accept tunneled IPComp packet. - <end of IMPLEMENTATION> + <end of IMPLEMENTATION> diff --git a/sys/netinet6/dest6.c b/sys/netinet6/dest6.c index a2693e7c87b..8ac53f5b2b0 100644 --- a/sys/netinet6/dest6.c +++ b/sys/netinet6/dest6.c @@ -1,4 +1,4 @@ -/* $NetBSD: dest6.c,v 1.4 1999/07/30 10:35:35 itojun Exp $ */ +/* $NetBSD: dest6.c,v 1.5 1999/12/13 15:17:21 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -46,7 +46,7 @@ #include <netinet/in.h> #include <netinet/in_var.h> #include <netinet6/ip6.h> -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__) #include <netinet6/in6_pcb.h> #endif #include <netinet6/ip6_var.h> @@ -66,12 +66,24 @@ dest6_input(mp, offp, proto) u_int8_t *opt; /* validation of the length of the header */ +#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(*dstopts), IPPROTO_DONE); dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off); +#else + IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, sizeof(*dstopts)); + if (dstopts == NULL) + return IPPROTO_DONE; +#endif dstoptlen = (dstopts->ip6d_len + 1) << 3; +#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, dstoptlen, IPPROTO_DONE); dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off); +#else + IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, dstoptlen); + if (dstopts == NULL) + return IPPROTO_DONE; +#endif off += dstoptlen; dstoptlen -= sizeof(struct ip6_dest); opt = (u_int8_t *)dstopts + sizeof(struct ip6_dest); diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c index abd6585fc24..bbf1aa70491 100644 --- a/sys/netinet6/frag6.c +++ b/sys/netinet6/frag6.c @@ -1,4 +1,4 @@ -/* $NetBSD: frag6.c,v 1.6 1999/08/26 11:10:49 itojun Exp $ */ +/* $NetBSD: frag6.c,v 1.7 1999/12/13 15:17:21 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -47,12 +47,21 @@ #include <netinet/in.h> #include <netinet/in_var.h> #include <netinet6/ip6.h> -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__) #include <netinet6/in6_pcb.h> #endif #include <netinet6/ip6_var.h> #include <netinet6/icmp6.h> +#include <net/net_osdep.h> + +/* + * Define it to get a correct behavior on per-interface statistics. + * You will need to perform an extra routing table lookup, per fragment, + * to do it. This may, or may not be, a performance hit. + */ +#define IN6_IFSTAT_STRICT + static void frag6_enq __P((struct ip6asfrag *, struct ip6asfrag *)); static void frag6_deq __P((struct ip6asfrag *)); static void frag6_insque __P((struct ip6q *, struct ip6q *)); @@ -63,6 +72,11 @@ int frag6_doing_reass; u_int frag6_nfragpackets; struct ip6q ip6q; /* ip6 reassemble queue */ +/* FreeBSD tweak */ +#if !defined(M_FTABLE) && (defined(__FreeBSD__) && __FreeBSD__ >= 3) +MALLOC_DEFINE(M_FTABLE, "fragment", "fragment reassembly header"); +#endif + /* * Initialise reassembly queue and fragment identifier. */ @@ -96,15 +110,55 @@ frag6_input(mp, offp, proto) int offset = *offp, nxt, i, next; int first_frag = 0; u_short fragoff, frgpartlen; - - IP6_EXTHDR_CHECK(m, offset, sizeof(struct ip6_frag), IPPROTO_DONE); + struct ifnet *dstifp; +#ifdef IN6_IFSTAT_STRICT + static struct route_in6 ro; + struct sockaddr_in6 *dst; +#endif ip6 = mtod(m, struct ip6_hdr *); +#ifndef PULLDOWN_TEST + IP6_EXTHDR_CHECK(m, offset, sizeof(struct ip6_frag), IPPROTO_DONE); ip6f = (struct ip6_frag *)((caddr_t)ip6 + offset); +#else + IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f)); + if (ip6f == NULL) + return IPPROTO_DONE; +#endif + + dstifp = NULL; +#ifdef IN6_IFSTAT_STRICT + /* find the destination interface of the packet. */ + dst = (struct sockaddr_in6 *)&ro.ro_dst; + if (ro.ro_rt + && ((ro.ro_rt->rt_flags & RTF_UP) == 0 + || !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_dst))) { + RTFREE(ro.ro_rt); + ro.ro_rt = (struct rtentry *)0; + } + if (ro.ro_rt == NULL) { + bzero(dst, sizeof(*dst)); + dst->sin6_family = AF_INET6; + dst->sin6_len = sizeof(struct sockaddr_in6); + dst->sin6_addr = ip6->ip6_dst; + } +#ifndef __bsdi__ + rtalloc((struct route *)&ro); +#else + rtcalloc((struct route *)&ro); +#endif + if (ro.ro_rt != NULL && ro.ro_rt->rt_ifa != NULL) + dstifp = ((struct in6_ifaddr *)ro.ro_rt->rt_ifa)->ia_ifp; +#else + /* we are violating the spec, this is not the destination interface */ + if ((m->m_flags & M_PKTHDR) != 0) + dstifp = m->m_pkthdr.rcvif; +#endif /* jumbo payload can't contain a fragment header */ if (ip6->ip6_plen == 0) { icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset); + in6_ifstat_inc(dstifp, ifs6_reass_fail); return IPPROTO_DONE; } @@ -119,16 +173,20 @@ frag6_input(mp, offp, proto) icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, (caddr_t)&ip6->ip6_plen - (caddr_t)ip6); + in6_ifstat_inc(dstifp, ifs6_reass_fail); return IPPROTO_DONE; } ip6stat.ip6s_fragments++; + in6_ifstat_inc(dstifp, ifs6_reass_reqd); /* * Presence of header sizes in mbufs * would confuse code below. */ - +#ifdef PULLDOWN_TEST + /* XXX too strong mbuf requirement in m_pulldown() world */ +#endif offset += sizeof(struct ip6_frag); m->m_data += offset; m->m_len -= offset; @@ -154,6 +212,7 @@ frag6_input(mp, offp, proto) */ if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets) { ip6stat.ip6s_fragoverflow++; + in6_ifstat_inc(dstifp, ifs6_reass_fail); frag6_freef(ip6q.ip6q_prev); } q6 = (struct ip6q *)malloc(sizeof(struct ip6q), M_FTABLE, @@ -397,10 +456,10 @@ insert: */ if (offset < m->m_len) - bcopy((caddr_t)ip6, (caddr_t)ip6 + sizeof(struct ip6_frag), + ovbcopy((caddr_t)ip6, (caddr_t)ip6 + sizeof(struct ip6_frag), offset); else { - bcopy(mtod(m, caddr_t), (caddr_t)ip6 + offset, m->m_len); + ovbcopy(mtod(m, caddr_t), (caddr_t)ip6 + offset, m->m_len); m->m_data -= sizeof(struct ip6_frag); } m->m_data -= offset; @@ -426,6 +485,7 @@ insert: } ip6stat.ip6s_reassembled++; + in6_ifstat_inc(dstifp, ifs6_reass_ok); /* * Tell launch routine the next header @@ -438,6 +498,7 @@ insert: return nxt; dropfrag: + in6_ifstat_inc(dstifp, ifs6_reass_fail); ip6stat.ip6s_fragdropped++; m_freem(m); return IPPROTO_DONE; @@ -539,7 +600,11 @@ void frag6_slowtimo() { struct ip6q *q6; +#ifdef __NetBSD__ int s = splsoftnet(); +#else + int s = splnet(); +#endif #if 0 extern struct route_in6 ip6_forward_rt; #endif @@ -552,6 +617,7 @@ frag6_slowtimo() q6 = q6->ip6q_next; if (q6->ip6q_prev->ip6q_ttl == 0) { ip6stat.ip6s_fragtimeout++; + /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ frag6_freef(q6->ip6q_prev); } } @@ -562,6 +628,7 @@ frag6_slowtimo() */ while (frag6_nfragpackets > (u_int)ip6_maxfragpackets) { ip6stat.ip6s_fragoverflow++; + /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ frag6_freef(ip6q.ip6q_prev); } frag6_doing_reass = 0; @@ -595,6 +662,7 @@ frag6_drain() return; while (ip6q.ip6q_next != &ip6q) { ip6stat.ip6s_fragdropped++; + /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ frag6_freef(ip6q.ip6q_next); } } diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 9445a4814ea..43609e71838 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -1,4 +1,4 @@ -/* $NetBSD: icmp6.c,v 1.11 1999/10/01 10:16:16 itojun Exp $ */ +/* $NetBSD: icmp6.c,v 1.12 1999/12/13 15:17:21 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -81,6 +81,7 @@ #include <sys/time.h> #include <sys/kernel.h> #include <sys/syslog.h> +#include <sys/domain.h> #include <net/if.h> #include <net/route.h> @@ -89,11 +90,15 @@ #include <netinet/in.h> #include <netinet/in_var.h> +#ifdef __OpenBSD__ +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#endif #include <netinet6/ip6.h> #include <netinet6/ip6_var.h> #include <netinet6/icmp6.h> #include <netinet6/mld6_var.h> -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__) #include <netinet6/in6_pcb.h> #else #include <netinet/in_pcb.h> @@ -102,39 +107,49 @@ #include <netinet6/in6_ifattach.h> #include <netinet6/ip6protosw.h> +#ifdef __OpenBSD__ /*KAME IPSEC*/ +#undef IPSEC +#endif + #ifdef IPSEC +#include <netinet6/ipsec.h> #include <netkey/key.h> #include <netkey/key_debug.h> #endif #include "faith.h" +#include <net/net_osdep.h> + +extern struct domain inet6domain; extern struct ip6protosw inet6sw[]; extern u_char ip6_protox[]; struct icmp6stat icmp6stat; -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) extern struct in6pcb rawin6pcb; #else extern struct inpcbhead ripcb; #endif extern u_int icmp6errratelim; -#ifdef __NetBSD__ +#if defined(__NetBSD__) || defined(__OpenBSD__) static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL; extern int pmtu_expire; #endif +#ifndef HAVE_NRL_INPCB static int icmp6_rip6_input __P((struct mbuf **, int)); +#endif static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int)); -static void icmp6_redirect_diag __P((int, struct in6_addr *, struct in6_addr *, - struct in6_addr *)); +static const char *icmp6_redirect_diag __P((struct in6_addr *, + struct in6_addr *, struct in6_addr *)); static struct mbuf * ni6_input __P((struct mbuf *, int)); static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *, struct ifnet **)); static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *, struct ifnet *, int)); -#ifdef __NetBSD__ +#if defined(__NetBSD__) || defined(__OpenBSD__) static struct rtentry *icmp6_mtudisc_clone __P((struct sockaddr *)); static void icmp6_mtudisc_timeout __P((struct rtentry *, struct rttimer *)); #endif @@ -148,7 +163,7 @@ void icmp6_init() { mld6_init(); -#ifdef __NetBSD__ +#if defined(__NetBSD__) || defined(__OpenBSD__) icmp6_mtudisc_timeout_q = rt_timer_queue_create(pmtu_expire); #endif } @@ -169,9 +184,20 @@ icmp6_error(m, type, code, param) icmp6stat.icp6s_error++; +#ifdef M_DECRYPTED /*not openbsd*/ if (m->m_flags & M_DECRYPTED) goto freeit; +#endif +#ifndef PULLDOWN_TEST + IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), ); +#else + if (m->m_len < sizeof(struct ip6_hdr)) { + m = m_pullup(m, sizeof(struct ip6_hdr)); + if (m == NULL) + return; + } +#endif oip6 = mtod(m, struct ip6_hdr *); /* @@ -194,10 +220,9 @@ icmp6_error(m, type, code, param) /* * If the erroneous packet is also an ICMP error, discard it. */ - IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), ); off = sizeof(struct ip6_hdr); nxt = oip6->ip6_nxt; - while(1) { /* XXX: should avoid inf. loop explicitly? */ + while (1) { /* XXX: should avoid inf. loop explicitly? */ struct ip6_ext *ip6e; struct icmp6_hdr *icp; @@ -216,8 +241,17 @@ icmp6_error(m, type, code, param) /* What if unknown header followed by ICMP error? */ goto generate; case IPPROTO_ICMPV6: +#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct icmp6_hdr), ); icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); +#else + IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off, + sizeof(*icp)); + if (icp == NULL) { + icmp6stat.icp6s_tooshort++; + return; + } +#endif if (icp->icmp6_type < ICMP6_ECHO_REQUEST || icp->icmp6_type == ND_REDIRECT) { /* @@ -235,8 +269,17 @@ icmp6_error(m, type, code, param) case IPPROTO_DSTOPTS: case IPPROTO_ROUTING: case IPPROTO_AH: +#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct ip6_ext), ); ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off); +#else + IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off, + sizeof(*ip6e)); + if (ip6e == NULL) { + /*XXX stat */ + return; + } +#endif if (nxt == IPPROTO_AH) off += (ip6e->ip6e_len + 2) << 2; else @@ -312,8 +355,10 @@ icmp6_input(mp, offp, proto) int code, sum, noff; struct sockaddr_in6 icmp6src; +#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE); /* m might change if M_LOOP. So, call mtod after this */ +#endif /* * Locate icmp6 structure in mbuf, and check @@ -329,8 +374,15 @@ icmp6_input(mp, offp, proto) /* * calculate the checksum */ - +#ifndef PULLDOWN_TEST icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off); +#else + IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6)); + if (icmp6 == NULL) { + icmp6stat.icp6s_tooshort++; + return IPPROTO_DONE; + } +#endif code = icmp6->icmp6_code; if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) { @@ -370,15 +422,20 @@ icmp6_input(mp, offp, proto) #endif icmp6stat.icp6s_inhist[icmp6->icmp6_type]++; + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg); + if (icmp6->icmp6_type < ICMP6_INFOMSG_MASK) + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error); switch (icmp6->icmp6_type) { case ICMP6_DST_UNREACH: + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach); switch (code) { case ICMP6_DST_UNREACH_NOROUTE: code = PRC_UNREACH_NET; break; case ICMP6_DST_UNREACH_ADMIN: + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_adminprohib); case ICMP6_DST_UNREACH_ADDR: code = PRC_UNREACH_HOST; break; @@ -395,39 +452,61 @@ icmp6_input(mp, offp, proto) break; case ICMP6_PACKET_TOO_BIG: + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_pkttoobig); if (code != 0) goto badcode; { u_int mtu = ntohl(icmp6->icmp6_mtu); - struct rtentry *rt; + struct rtentry *rt = NULL; struct sockaddr_in6 sin6; #ifdef __bsdi__ struct route_in6 ro6; #endif + if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) { + icmp6stat.icp6s_tooshort++; + goto freeit; + } +#ifndef PULLDOWN_TEST + IP6_EXTHDR_CHECK(m, off, + sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr), + IPPROTO_DONE); + icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); +#else + IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, + sizeof(*icmp6) + sizeof(struct ip6_hdr)); + if (icmp6 == NULL) { + icmp6stat.icp6s_tooshort++; + return IPPROTO_DONE; + } +#endif code = PRC_MSGSIZE; bzero(&sin6, sizeof(sin6)); sin6.sin6_family = PF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_addr = ((struct ip6_hdr *)(icmp6 + 1))->ip6_dst; -#ifdef __NetBSD__ +#if defined(__NetBSD__) || defined(__OpenBSD__) rt = rtalloc1((struct sockaddr *)&sin6, 1); /*clone*/ if (!rt || (rt->rt_flags & RTF_HOST) == 0) { if (rt) RTFREE(rt); rt = icmp6_mtudisc_clone((struct sockaddr *)&sin6); } -#endif +#else #ifdef __FreeBSD__ rt = rtalloc1((struct sockaddr *)&sin6, 0, RTF_CLONING | RTF_PRCLONING); -#endif /*__FreeBSD__*/ +#else #ifdef __bsdi__ bcopy(&sin6, &ro6.ro_dst, sizeof(struct sockaddr_in6)); ro6.ro_rt = 0; rtcalloc((struct route *)&ro6); rt = ro6.ro_rt; -#endif /*__bsdi__*/ +#else +#error no case for this particular operating system +#endif +#endif +#endif if (rt && (rt->rt_flags & RTF_HOST) && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { @@ -447,6 +526,7 @@ icmp6_input(mp, offp, proto) break; case ICMP6_TIME_EXCEEDED: + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_timeexceed); switch (code) { case ICMP6_TIME_EXCEED_TRANSIT: case ICMP6_TIME_EXCEED_REASSEMBLY: @@ -459,6 +539,7 @@ icmp6_input(mp, offp, proto) break; case ICMP6_PARAM_PROB: + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_paramprob); switch (code) { case ICMP6_PARAMPROB_NEXTHEADER: code = PRC_UNREACH_PROTOCOL; @@ -474,14 +555,15 @@ icmp6_input(mp, offp, proto) break; case ICMP6_ECHO_REQUEST: + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echo); if (code != 0) goto badcode; if ((n = m_copy(m, 0, M_COPYALL)) == NULL) { /* Give up remote */ break; } - if (n->m_flags & M_EXT) { - int gap, move; + if ((n->m_flags & M_EXT) != 0 + || n->m_len < off + sizeof(struct icmp6_hdr)) { struct mbuf *n0 = n; /* @@ -495,8 +577,6 @@ icmp6_input(mp, offp, proto) break; } M_COPY_PKTHDR(n, n0); - n0->m_flags &= ~M_PKTHDR; - n->m_next = n0; /* * Copy IPv6 and ICMPv6 only. */ @@ -504,16 +584,17 @@ icmp6_input(mp, offp, proto) bcopy(ip6, nip6, sizeof(struct ip6_hdr)); nicmp6 = (struct icmp6_hdr *)(nip6 + 1); bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr)); + noff = sizeof(struct ip6_hdr); + n->m_pkthdr.len = n->m_len = + noff + sizeof(struct icmp6_hdr); /* - * Adjust mbuf. ip6_plen will be adjusted. + * Adjust mbuf. ip6_plen will be adjusted in + * ip6_output(). */ - noff = sizeof(struct ip6_hdr); - n->m_len = noff + sizeof(struct icmp6_hdr); - move = off + sizeof(struct icmp6_hdr); - n0->m_len -= move; - n0->m_data += move; - gap = off - noff; - n->m_pkthdr.len -= gap; + m_adj(n0, off + sizeof(struct icmp6_hdr)); + n->m_pkthdr.len += n0->m_pkthdr.len; + n->m_next = n0; + n0->m_flags &= ~M_PKTHDR; } else { nip6 = mtod(n, struct ip6_hdr *); nicmp6 = (struct icmp6_hdr *)((caddr_t)nip6 + off); @@ -529,6 +610,7 @@ icmp6_input(mp, offp, proto) break; case ICMP6_ECHO_REPLY: + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echoreply); if (code != 0) goto badcode; break; @@ -537,16 +619,27 @@ icmp6_input(mp, offp, proto) case MLD6_LISTENER_REPORT: if (icmp6len < sizeof(struct mld6_hdr)) goto badlen; + if (icmp6->icmp6_type == MLD6_LISTENER_QUERY) /* XXX: ugly... */ + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldquery); + else + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldreport); IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE); mld6_input(m, off); /* m stays. */ break; case MLD6_LISTENER_DONE: - if (icmp6len < sizeof(struct mld6_hdr)) + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mlddone); + if (icmp6len < sizeof(struct mld6_hdr)) /* necessary? */ goto badlen; break; /* nothing to be done in kernel */ + case MLD6_MTRACE_RESP: + case MLD6_MTRACE: + /* XXX: these two are experimental. not officially defind. */ + /* XXX: per-interface statistics? */ + break; /* just pass it to the userland daemon */ + case ICMP6_WRUREQUEST: /* ICMP6_FQDN_QUERY */ { enum { WRU, FQDN } mode; @@ -609,6 +702,7 @@ icmp6_input(mp, offp, proto) break; case ND_ROUTER_SOLICIT: + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routersolicit); if (code != 0) goto badcode; if (icmp6len < sizeof(struct nd_router_solicit)) @@ -619,6 +713,7 @@ icmp6_input(mp, offp, proto) break; case ND_ROUTER_ADVERT: + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routeradvert); if (code != 0) goto badcode; if (icmp6len < sizeof(struct nd_router_advert)) @@ -629,6 +724,7 @@ icmp6_input(mp, offp, proto) break; case ND_NEIGHBOR_SOLICIT: + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighborsolicit); if (code != 0) goto badcode; if (icmp6len < sizeof(struct nd_neighbor_solicit)) @@ -639,6 +735,7 @@ icmp6_input(mp, offp, proto) break; case ND_NEIGHBOR_ADVERT: + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighboradvert); if (code != 0) goto badcode; if (icmp6len < sizeof(struct nd_neighbor_advert)) @@ -649,6 +746,7 @@ icmp6_input(mp, offp, proto) break; case ND_REDIRECT: + icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_redirect); if (code != 0) goto badcode; if (icmp6len < sizeof(struct nd_redirect)) @@ -666,7 +764,10 @@ icmp6_input(mp, offp, proto) break; default: - printf("icmp6_input: unknown type %d\n", icmp6->icmp6_type); + printf("icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n", + icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&ip6->ip6_dst), + m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0); if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) { /* ICMPv6 error: MUST deliver it by spec... */ code = PRC_NCMDS; @@ -680,10 +781,19 @@ icmp6_input(mp, offp, proto) icmp6stat.icp6s_tooshort++; goto freeit; } +#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr), IPPROTO_DONE); icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); +#else + IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, + sizeof(*icmp6) + sizeof(struct ip6_hdr)); + if (icmp6 == NULL) { + icmp6stat.icp6s_tooshort++; + return IPPROTO_DONE; + } +#endif bzero(&icmp6src, sizeof(icmp6src)); icmp6src.sin6_len = sizeof(struct sockaddr_in6); icmp6src.sin6_family = AF_INET6; @@ -691,13 +801,12 @@ icmp6_input(mp, offp, proto) /* Detect the upper level protocol */ { - void (*ctlfunc) __P((int, struct sockaddr *, - struct ip6_hdr *, - struct mbuf *, int)); /* XXX */ + void (*ctlfunc) __P((int, struct sockaddr *, void *)); struct ip6_hdr *eip6 = (struct ip6_hdr *)(icmp6 + 1); u_int8_t nxt = eip6->ip6_nxt; int eoff = off + sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr); + struct ip6ctlparam ip6cp; while (1) { /* XXX: should avoid inf. loop explicitly? */ struct ip6_ext *eh; @@ -711,11 +820,20 @@ icmp6_input(mp, offp, proto) case IPPROTO_ROUTING: case IPPROTO_AH: case IPPROTO_FRAGMENT: +#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(struct ip6_ext), IPPROTO_DONE); eh = (struct ip6_ext *)(mtod(m, caddr_t) + eoff); +#else + IP6_EXTHDR_GET(eh, struct ip6_ext *, m, + eoff, sizeof(*eh)); + if (eh == NULL) { + icmp6stat.icp6s_tooshort++; + return IPPROTO_DONE; + } +#endif if (nxt == IPPROTO_AH) eoff += (eh->ip6e_len + 2) << 2; else if (nxt == IPPROTO_FRAGMENT) @@ -729,15 +847,24 @@ icmp6_input(mp, offp, proto) } } notify: +#ifndef PULLDOWN_TEST icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); - ctlfunc = (void (*) __P((int, struct sockaddr *, - struct ip6_hdr *, - struct mbuf *, int))) +#else + IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, + sizeof(*icmp6) + sizeof(struct ip6_hdr)); + if (icmp6 == NULL) { + icmp6stat.icp6s_tooshort++; + return IPPROTO_DONE; + } +#endif + ctlfunc = (void (*) __P((int, struct sockaddr *, void *))) (inet6sw[ip6_protox[nxt]].pr_ctlinput); - if (ctlfunc) - (*ctlfunc)(code, (struct sockaddr *)&icmp6src, - (struct ip6_hdr *)(icmp6 + 1), - m, eoff); + if (ctlfunc) { + ip6cp.ip6c_m = m; + ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1); + ip6cp.ip6c_off = eoff; + (*ctlfunc)(code, (struct sockaddr *)&icmp6src, &ip6cp); + } } break; @@ -751,7 +878,11 @@ icmp6_input(mp, offp, proto) } passit: +#ifdef HAVE_NRL_INPCB + rip6_input(&m, offp, IPPROTO_ICMPV6); +#else icmp6_rip6_input(&m, *offp); +#endif return IPPROTO_DONE; freeit: @@ -774,15 +905,24 @@ ni6_input(m, off) struct mbuf *m; int off; { - struct icmp6_nodeinfo *ni6 = - (struct icmp6_nodeinfo *)(mtod(m, caddr_t) + off), *nni6; + struct icmp6_nodeinfo *ni6, *nni6; struct mbuf *n = NULL; - u_int16_t qtype = ntohs(ni6->ni_qtype); + u_int16_t qtype; int replylen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo); struct ni_reply_fqdn *fqdn; int addrs; /* for NI_QTYPE_NODEADDR */ struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */ +#ifndef PULLDOWN_TEST + ni6 = (struct icmp6_nodeinfo *)(mtod(m, caddr_t) + off); +#else + IP6_EXTHDR_GET(ni6, struct icmp6_nodeinfo *, m, off, + sizeof(*ni6)); + if (ni6 == NULL) + return NULL; +#endif + qtype = ntohs(ni6->ni_qtype); + switch(qtype) { case NI_QTYPE_NOOP: break; /* no reply data */ @@ -837,7 +977,7 @@ ni6_input(m, off) /* copy mbuf header and IPv6 + Node Information base headers */ bcopy(mtod(m, caddr_t), mtod(n, caddr_t), sizeof(struct ip6_hdr)); nni6 = (struct icmp6_nodeinfo *)(mtod(n, struct ip6_hdr *) + 1); - bcopy(mtod(m, caddr_t) + off, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo)); + bcopy((caddr_t)ni6, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo)); /* qtype dependent procedure */ switch (qtype) { @@ -908,18 +1048,18 @@ ni6_addrs(ni6, m, ifpp) struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); int addrs = 0, addrsofif, iffound = 0; -#ifdef __NetBSD__ - for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) -#else +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) for (ifp = ifnet; ifp; ifp = ifp->if_next) +#else + for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) #endif { addrsofif = 0; -#ifdef __NetBSD__ +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#else for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#else - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) #endif { if (ifa->ifa_addr->sa_family != AF_INET6) @@ -974,10 +1114,10 @@ ni6_store_addrs(ni6, nni6, ifp0, resid) struct ifnet *ifp0; int resid; { -#ifdef __NetBSD__ - register struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet); -#else +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) register struct ifnet *ifp = ifp0 ? ifp0 : ifnet; +#else + register struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet); #endif register struct in6_ifaddr *ifa6; register struct ifaddr *ifa; @@ -987,17 +1127,17 @@ ni6_store_addrs(ni6, nni6, ifp0, resid) if (ifp0 == NULL && !(ni6->ni_flags & NI_NODEADDR_FLAG_ALL)) return(0); /* needless to copy */ -#ifdef __NetBSD__ - for (; ifp; ifp = TAILQ_NEXT(ifp, if_list)) -#else +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) for (; ifp; ifp = ifp->if_next) +#else + for (; ifp; ifp = TAILQ_NEXT(ifp, if_list)) #endif { -#ifdef __NetBSD__ +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#else for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#else - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) #endif { docopy = 0; @@ -1006,8 +1146,19 @@ ni6_store_addrs(ni6, nni6, ifp0, resid) continue; ifa6 = (struct in6_ifaddr *)ifa; - if (ifa6->ia6_flags & IN6_IFF_ANYCAST) - continue; /* we need only unicast addresses */ + if (ifa6->ia6_flags & IN6_IFF_ANYCAST) { + /* just experimental. not in the spec. */ + if (ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST) + docopy = 1; + else + continue; + } + else { /* unicast address */ + if (ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST) + continue; + else + docopy = 1; + } /* What do we have to do about ::1? */ switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) { @@ -1054,6 +1205,7 @@ ni6_store_addrs(ni6, nni6, ifp0, resid) return(copied); } +#ifndef HAVE_NRL_INPCB /* * XXX almost dup'ed code with rip6_input. */ @@ -1087,11 +1239,11 @@ icmp6_rip6_input(mp, off) } else rip6src.sin6_scope_id = 0; -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + LIST_FOREACH(in6p, &ripcb, inp_list) +#else for (in6p = rawin6pcb.in6p_next; in6p != &rawin6pcb; in6p = in6p->in6p_next) -#else - LIST_FOREACH(in6p, &ripcb, inp_list) #endif { #if defined(__FreeBSD__) && __FreeBSD__ >= 3 @@ -1100,10 +1252,10 @@ icmp6_rip6_input(mp, off) #endif if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6) continue; - if (!IN6_IS_ADDR_ANY(&in6p->in6p_laddr) && + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) continue; - if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr) && + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) continue; if (in6p->in6p_icmp6filt @@ -1149,6 +1301,7 @@ icmp6_rip6_input(mp, off) } return IPPROTO_DONE; } +#endif /*OpenBSD*/ /* * Reflect the ip6 packet back to the source. @@ -1163,52 +1316,57 @@ icmp6_reflect(m, off) struct mbuf *m; size_t off; { - struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + struct ip6_hdr *ip6; struct icmp6_hdr *icmp6; struct in6_ifaddr *ia; struct in6_addr t, *src = 0; - int plen = m->m_pkthdr.len - sizeof(struct ip6_hdr); + int plen; + int type, code; + struct ifnet *outif = NULL; #ifdef COMPAT_RFC1885 int mtu = IPV6_MMTU; struct sockaddr_in6 *sin6 = &icmp6_reflect_rt.ro_dst; #endif + /* too short to reflect */ + if (off < sizeof(struct ip6_hdr)) { + printf("sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n", + (u_long)off, (u_long)sizeof(struct ip6_hdr), + __FILE__, __LINE__); + goto bad; + } + /* * If there are extra headers between IPv6 and ICMPv6, strip * off that header first. */ - if (off != sizeof(struct ip6_hdr)) { - size_t siz; - - /* sanity checks */ - if (off < sizeof(struct ip6_hdr)) { - printf("sanity fail: off=%x, sizeof(ip6)=%x in %s:%d\n", - (unsigned int)off, - (unsigned int)sizeof(struct ip6_hdr), - __FILE__, __LINE__); - goto bad; + if (off > sizeof(struct ip6_hdr)) { + size_t l; + struct ip6_hdr nip6; + + l = off - sizeof(struct ip6_hdr); + m_copydata(m, 0, sizeof(nip6), (caddr_t)&nip6); + m_adj(m, l); + l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr); + if (m->m_len < l) { + if ((m = m_pullup(m, l)) == NULL) + return; } - siz = off - sizeof(struct ip6_hdr); - if (plen < siz) { - printf("sanity fail: siz=%x, payloadlen=%x in %s:%d\n", - (unsigned int)siz, plen, __FILE__, __LINE__); - goto bad; + bcopy((caddr_t)&nip6, mtod(m, caddr_t), sizeof(nip6)); + } else /* off == sizeof(struct ip6_hdr) */ { + size_t l; + l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr); + if (m->m_len < l) { + if ((m = m_pullup(m, l)) == NULL) + return; } - IP6_EXTHDR_CHECK(m, 0, off, /*nothing*/); - IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), /*nothing*/); - - bcopy((caddr_t)ip6, - (caddr_t)(mtod(m, u_char *) + siz), - sizeof(struct ip6_hdr)); - m->m_data += siz; - m->m_len -= siz; - m->m_pkthdr.len -= siz; - ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_nxt = IPPROTO_ICMPV6; - plen -= siz; } - + plen = m->m_pkthdr.len - sizeof(struct ip6_hdr); + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_nxt = IPPROTO_ICMPV6; icmp6 = (struct icmp6_hdr *)(ip6 + 1); + type = icmp6->icmp6_type; /* keep type for statistics */ + code = icmp6->icmp6_code; /* ditto. */ t = ip6->ip6_dst; /* @@ -1321,10 +1479,12 @@ icmp6_reflect(m, off) #endif /*IPSEC*/ #ifdef COMPAT_RFC1885 - ip6_output(m, NULL, &icmp6_reflect_rt, 0, NULL); + ip6_output(m, NULL, &icmp6_reflect_rt, 0, NULL, &outif); #else - ip6_output(m, NULL, NULL, 0, NULL); -#endif + ip6_output(m, NULL, NULL, 0, NULL, &outif); +#endif + if (outif) + icmp6_ifoutstat_inc(outif, type, code); return; @@ -1339,15 +1499,21 @@ icmp6_fasttimo() mld6_fasttimeo(); } -static void -icmp6_redirect_diag(level, src6, dst6, tgt6) - int level; +static const char * +icmp6_redirect_diag(src6, dst6, tgt6) struct in6_addr *src6; struct in6_addr *dst6; struct in6_addr *tgt6; { - log(level, "ICMP6 redirect: src=%s dst=%s tgt=%s\n", + static char buf[1024]; +#if !defined(__OpenBSD__) && !defined(__bsdi__) + snprintf(buf, sizeof(buf), "(src=%s dst=%s tgt=%s)", ip6_sprintf(src6), ip6_sprintf(dst6), ip6_sprintf(tgt6)); +#else + sprintf(buf, "(src=%s dst=%s tgt=%s)", + ip6_sprintf(src6), ip6_sprintf(dst6), ip6_sprintf(tgt6)); +#endif + return buf; } void @@ -1416,31 +1582,30 @@ icmp6_redirect_input(m, off) if (rt) { gw6 = &(((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr); if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) { - icmp6_redirect_diag(LOG_ERR, &src6, &reddst6, &redtgt6); log(LOG_ERR, - "ICMP6 redirect sent from %s rejected; " - "not equal to gw for src=%s (must be same)\n", - ip6_sprintf(&src6), ip6_sprintf(gw6)); + "ICMP6 redirect rejected; " + "not equal to gw-for-src=%s (must be same): " + "%s\n", + ip6_sprintf(gw6), + icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); RTFREE(rt); return; } } else { - icmp6_redirect_diag(LOG_ERR, &src6, &reddst6, &redtgt6); log(LOG_ERR, - "ICMP6 redirect sent from %s rejected; " - "no route found for redirect dst\n", - ip6_sprintf(&src6)); + "ICMP6 redirect rejected; " + "no route found for redirect dst: %s\n", + icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); return; } RTFREE(rt); rt = NULL; } if (IN6_IS_ADDR_MULTICAST(&reddst6)) { - icmp6_redirect_diag(LOG_ERR, &src6, &reddst6, &redtgt6); log(LOG_ERR, - "ICMP6 redirect sent from %s rejected; " - "redirect dst must be unicast\n", - ip6_sprintf(&src6)); + "ICMP6 redirect rejected; " + "redirect dst must be unicast: %s\n", + icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); return; } @@ -1450,11 +1615,10 @@ icmp6_redirect_input(m, off) if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0) is_onlink = 1; /* on-link destination case */ if (!is_router && !is_onlink) { - icmp6_redirect_diag(LOG_ERR, &src6, &reddst6, &redtgt6); log(LOG_ERR, - "ICMP6 redirect sent from %s rejected; " - "neither router case nor onlink case\n", - ip6_sprintf(&src6)); + "ICMP6 redirect rejected; " + "neither router case nor onlink case: %s\n", + icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); return; } /* validation passed */ @@ -1462,9 +1626,9 @@ icmp6_redirect_input(m, off) icmp6len -= sizeof(*nd_rd); nd6_option_init(nd_rd + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { - icmp6_redirect_diag(LOG_INFO, &src6, &reddst6, &redtgt6); log(LOG_INFO, "icmp6_redirect_input: " - "invalid ND option, rejected\n"); + "invalid ND option, rejected: %s\n", + icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); return; } @@ -1479,11 +1643,11 @@ icmp6_redirect_input(m, off) } if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { - icmp6_redirect_diag(LOG_INFO, &src6, &reddst6, &redtgt6); log(LOG_INFO, "icmp6_redirect_input: lladdrlen mismatch for %s " - "(if %d, icmp6 packet %d)\n", - ip6_sprintf(&redtgt6), ifp->if_addrlen, lladdrlen - 2); + "(if %d, icmp6 packet %d): %s\n", + ip6_sprintf(&redtgt6), ifp->if_addrlen, lladdrlen - 2, + icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); } /* RFC 2461 8.3 */ @@ -1511,26 +1675,45 @@ icmp6_redirect_input(m, off) rtredirect((struct sockaddr *)&sdst, (struct sockaddr *)&sgw, (struct sockaddr *)NULL, RTF_GATEWAY | RTF_HOST, (struct sockaddr *)&ssrc, -#if defined(__FreeBSD__) || defined(__NetBSD__) +#ifdef __bsdi__ + icmp_redirtimeout +#else (struct rtentry **)NULL -#elif defined(__bsdi__) - icmp_redirtimeout /*XXX*/ #endif /*__FreeBSD__, __NetBSD__, __bsdi__*/ ); } /* finally update cached route in each socket via pfctlinput */ - { - struct sockaddr_in6 sdst; + { + struct sockaddr_in6 sdst; +#if 1 +#else + struct ip6protosw *pr; +#endif - bzero(&sdst, sizeof(sdst)); - sdst.sin6_family = AF_INET6; - sdst.sin6_len = sizeof(struct sockaddr_in6); - bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr)); - pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst); + bzero(&sdst, sizeof(sdst)); + sdst.sin6_family = AF_INET6; + sdst.sin6_len = sizeof(struct sockaddr_in6); + bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr)); +#if 1 + pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst); +#else + /* + * do not use pfctlinput() here, we have different prototype for + * xx_ctlinput() in ip6proto. + */ + for (pr = (struct ip6protosw *)inet6domain.dom_protosw; + pr < (struct ip6protosw *)inet6domain.dom_protoswNPROTOSW; + pr++) { + if (pr->pr_ctlinput) { + (*pr->pr_ctlinput)(PRC_REDIRECT_HOST, + (struct sockaddr *)&sdst, NULL, NULL, 0); + } + } +#endif #ifdef IPSEC - key_sa_routechange((struct sockaddr *)&sdst); + key_sa_routechange((struct sockaddr *)&sdst); #endif - } + } } void @@ -1547,6 +1730,7 @@ icmp6_redirect_output(m0, rt) struct nd_redirect *nd_rd; size_t maxlen; u_char *p; + struct ifnet *outif = NULL; /* if we are not router, we don't send icmp6 redirect */ if (!ip6_forwarding || ip6_accept_rtadv) @@ -1657,10 +1841,11 @@ icmp6_redirect_output(m0, rt) rt_router = nd6_lookup(router_ll6, 0, ifp); if (!rt_router) goto nolladdropt; - if (!(rt_router->rt_flags & RTF_GATEWAY) - && (rt_router->rt_flags & RTF_LLINFO) - && (rt_router->rt_gateway->sa_family == AF_LINK) - && (sdl = (struct sockaddr_dl *)rt_router->rt_gateway)) { + if (!(rt_router->rt_flags & RTF_GATEWAY) && + (rt_router->rt_flags & RTF_LLINFO) && + (rt_router->rt_gateway->sa_family == AF_LINK) && + (sdl = (struct sockaddr_dl *)rt_router->rt_gateway) && + sdl->sdl_alen) { nd_opt = (struct nd_opt_hdr *)p; nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; len = 2 + ifp->if_addrlen; @@ -1676,8 +1861,10 @@ nolladdropt:; m->m_pkthdr.len = m->m_len = p - (u_char *)ip6; /* just to be safe */ +#ifdef M_DECRYPTED /*not openbsd*/ if (m0->m_flags & M_DECRYPTED) goto noredhdropt; +#endif { /* redirected header option */ @@ -1702,7 +1889,7 @@ nolladdropt:; /* * Redirected header option spec (RFC2461 4.6.3) talks nothing - * about padding/trancate rule for the original IP packet. + * about padding/truncate rule for the original IP packet. * From the discussion on IPv6imp in Feb 1999, the consensus was: * - "attach as much as possible" is the goal * - pad if not aligned (original size can be guessed by original @@ -1748,7 +1935,9 @@ nolladdropt:; m->m_next = m0; m->m_pkthdr.len = m->m_len + m0->m_len; } +#ifdef M_DECRYPTED /*not openbsd*/ noredhdropt:; +#endif if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_src)) sip6->ip6_src.s6_addr16[1] = 0; @@ -1775,7 +1964,11 @@ noredhdropt:; #ifdef IPSEC m->m_pkthdr.rcvif = NULL; #endif /*IPSEC*/ - ip6_output(m, NULL, NULL, 0, NULL); + ip6_output(m, NULL, NULL, 0, NULL, &outif); + if (outif) { + icmp6_ifstat_inc(outif, ifs6_out_msg); + icmp6_ifstat_inc(outif, ifs6_out_redirect); + } icmp6stat.icp6s_outhist[ND_REDIRECT]++; return; @@ -1903,7 +2096,7 @@ icmp6_ratelimit(dst, type, code) return 0; } -#ifdef __NetBSD__ +#if defined(__NetBSD__) || defined(__OpenBSD__) static struct rtentry * icmp6_mtudisc_clone(dst) struct sockaddr *dst; @@ -1959,7 +2152,7 @@ icmp6_mtudisc_timeout(rt, r) } } } -#endif /*__NetBSD__*/ +#endif /*__NetBSD__ || __OpenBSD__*/ #ifdef __bsdi__ void @@ -2005,7 +2198,7 @@ icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) } #endif /*__bsdi__*/ -#ifdef __NetBSD__ +#if defined(__NetBSD__) || defined(__OpenBSD__) #include <vm/vm.h> #include <sys/sysctl.h> int diff --git a/sys/netinet6/icmp6.h b/sys/netinet6/icmp6.h index 0abf210f199..3cb51b71b4a 100644 --- a/sys/netinet6/icmp6.h +++ b/sys/netinet6/icmp6.h @@ -1,4 +1,4 @@ -/* $NetBSD: icmp6.h,v 1.5 1999/11/19 10:41:43 bouyer Exp $ */ +/* $NetBSD: icmp6.h,v 1.6 1999/12/13 15:17:21 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -222,11 +222,13 @@ struct nd_neighbor_advert { /* neighbor advertisement */ #define ND_NA_FLAG_ROUTER 0x80000000 #define ND_NA_FLAG_SOLICITED 0x40000000 #define ND_NA_FLAG_OVERRIDE 0x20000000 -#elif BYTE_ORDER == LITTLE_ENDIAN +#else +#if BYTE_ORDER == LITTLE_ENDIAN #define ND_NA_FLAG_ROUTER 0x80 #define ND_NA_FLAG_SOLICITED 0x40 #define ND_NA_FLAG_OVERRIDE 0x20 #endif +#endif struct nd_redirect { /* redirect */ struct icmp6_hdr nd_rd_hdr; @@ -325,6 +327,7 @@ struct icmp6_nodeinfo { #define NI_NODEADDR_FLAG_GLOBAL 0x4 #define NI_NODEADDR_FLAG_ALL 0x8 #define NI_NODEADDR_FLAG_TRUNCATE 0x10 +#define NI_NODEADDR_FLAG_ANYCAST 0x20 /* just experimental. not in spec */ #elif BYTE_ORDER == LITTLE_ENDIAN #define NI_SUPTYPE_FLAG_COMPRESS 0x0100 #define NI_FQDN_FLAG_VALIDTTL 0x0100 @@ -333,6 +336,7 @@ struct icmp6_nodeinfo { #define NI_NODEADDR_FLAG_GLOBAL 0x0400 #define NI_NODEADDR_FLAG_ALL 0x0800 #define NI_NODEADDR_FLAG_TRUNCATE 0x1000 +#define NI_NODEADDR_FLAG_ANYCAST 0x2000 /* just experimental. not in spec */ #endif struct ni_reply_fqdn { @@ -489,8 +493,6 @@ struct icmp6_filter { #define ICMP6_FILTER_WILLBLOCK(type, filterp) \ ((((filterp)->icmp6_filter[(type) >> 5]) & (1 << ((type) & 31))) == 0) - -#if defined(__FreeBSD__) || defined(__NetBSD__) /* * Variables related to this implementation * of the internet control message protocol version 6. @@ -501,13 +503,14 @@ struct icmp6stat { u_quad_t icp6s_canterror; /* no error 'cuz old was icmp */ u_quad_t icp6s_toofreq; /* no error 'cuz rate limitation */ u_quad_t icp6s_outhist[256]; -/* statistics related to input messages proccesed */ +/* statistics related to input message processed */ u_quad_t icp6s_badcode; /* icmp6_code out of range */ u_quad_t icp6s_tooshort; /* packet < sizeof(struct icmp6_hdr) */ u_quad_t icp6s_checksum; /* bad checksum */ u_quad_t icp6s_badlen; /* calculated bound mismatch */ u_quad_t icp6s_reflect; /* number of responses */ u_quad_t icp6s_inhist[256]; + u_quad_t icp6s_nd_toomanyopt; /* too many ND options */ }; /* @@ -516,7 +519,6 @@ struct icmp6stat { #define ICMPV6CTL_STATS 1 #define ICMPV6CTL_REDIRACCEPT 2 /* accept/process redirects */ #define ICMPV6CTL_REDIRTIMEOUT 3 /* redirect cache time */ -#define ICMPV6CTL_PRINTFS 4 #define ICMPV6CTL_ERRRATELIMIT 5 /* ICMPv6 error rate limitation */ #define ICMPV6CTL_ND6_PRUNE 6 #define ICMPV6CTL_ND6_DELAY 8 @@ -531,7 +533,7 @@ struct icmp6stat { { 0, 0 }, \ { "rediraccept", CTLTYPE_INT }, \ { "redirtimeout", CTLTYPE_INT }, \ - { "printfs", CTLTYPE_INT }, \ + { 0, 0 }, \ { "errratelimit", CTLTYPE_INT }, \ { "nd6_prune", CTLTYPE_INT }, \ { 0, 0 }, \ @@ -541,72 +543,13 @@ struct icmp6stat { { "nd6_useloopback", CTLTYPE_INT }, \ { "nd6_proxyall", CTLTYPE_INT }, \ } -#endif /*__FreeBSD__*/ -#ifdef __bsdi__ -/* - * Variables related to this implementation - * of the internet control message protocol version 6. - */ -struct icmp6stat { -/* statistics related to icmp6 packets generated */ - u_quad_t icp6s_error; /* # of calls to icmp6_error */ - u_quad_t icp6s_canterror; /* no error 'cuz old was icmp */ - u_quad_t icp6s_toofreq; /* no error 'cuz rate limitation */ - u_quad_t icp6s_outhist[256]; -/* statistics related to input messages proccesed */ - u_quad_t icp6s_badcode; /* icmp6_code out of range */ - u_quad_t icp6s_tooshort; /* packet < sizeof(struct icmp6_hdr) */ - u_quad_t icp6s_checksum; /* bad checksum */ - u_quad_t icp6s_badlen; /* calculated bound mismatch */ - u_quad_t icp6s_reflect; /* number of responses */ - u_quad_t icp6s_inhist[256]; -}; - -/* - * Names for ICMP sysctl objects - */ -#define ICMPV6CTL_REDIRACCEPT 2 /* accept/process redirects */ -#define ICMPV6CTL_REDIRTIMEOUT 3 /* redirect cache time */ -#define ICMPV6CTL_PRINTFS 4 /* redirect cache time */ -#define ICMPV6CTL_STATS 5 /* statistics */ -#define ICMPV6CTL_ERRRATELIMIT 6 /* ICMPv6 error rate limitation */ -#define ICMPV6CTL_ND6_PRUNE 7 -#define ICMPV6CTL_ND6_DELAY 9 -#define ICMPV6CTL_ND6_UMAXTRIES 10 -#define ICMPV6CTL_ND6_MMAXTRIES 11 -#define ICMPV6CTL_ND6_USELOOPBACK 12 -#define ICMPV6CTL_ND6_PROXYALL 13 -#define ICMPV6CTL_MAXID 14 - -#ifdef ICMP6PRINTFS -#define __ICMP6PRINTFS &icmp6printfs -#else -#define __ICMP6PRINTFS 0 -#endif - -#define ICMPV6CTL_NAMES { \ - { 0, 0 }, \ - { 0, 0 }, \ - { "rediraccept", CTLTYPE_INT }, \ - { "redirtimeout", CTLTYPE_INT }, \ - { "printfs", CTLTYPE_INT }, \ - { 0, 0 }, \ - { "errratelimit", CTLTYPE_INT }, \ - { "nd6_prune", CTLTYPE_INT }, \ - { 0, 0 }, \ - { "nd6_delay", CTLTYPE_INT }, \ - { "nd6_umaxtries", CTLTYPE_INT }, \ - { "nd6_mmaxtries", CTLTYPE_INT }, \ - { "nd6_useloopback", CTLTYPE_INT }, \ - { "nd6_proxyall", CTLTYPE_INT }, \ -} #define ICMPV6CTL_VARS { \ 0, \ 0, \ &icmp6_rediraccept, \ &icmp6_redirtimeout, \ - __ICMP6PRINTFS, \ + 0, \ 0, \ &icmp6errratelim, \ &nd6_prune, \ @@ -617,7 +560,6 @@ struct icmp6stat { &nd6_useloopback, \ &nd6_proxyall, \ } -#endif /*__bsdi__*/ #define RTF_PROBEMTU RTF_PROTO1 @@ -640,11 +582,73 @@ void icmp6_redirect_output __P((struct mbuf *, struct rtentry *)); int icmp6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); void icmp6_mtuexpire __P((struct rtentry *, struct rttimer *)); #endif /*__bsdi__*/ -#ifdef __NetBSD__ +#if defined(__NetBSD__) || defined(__OpenBSD__) int icmp6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); -#endif /* __NetBSD__ */ +#endif + +/* XXX: is this the right place for these macros? */ +#define icmp6_ifstat_inc(ifp, tag) \ +do { \ + if ((ifp) && (ifp)->if_index <= if_index \ + && (ifp)->if_index < icmp6_ifstatmax \ + && icmp6_ifstat && icmp6_ifstat[(ifp)->if_index]) { \ + icmp6_ifstat[(ifp)->if_index]->tag++; \ + } \ +} while (0) + +#define icmp6_ifoutstat_inc(ifp, type, code) \ +do { \ + icmp6_ifstat_inc(ifp, ifs6_out_msg); \ + if (type < ICMP6_INFOMSG_MASK) \ + icmp6_ifstat_inc(ifp, ifs6_out_error); \ + switch(type) { \ + case ICMP6_DST_UNREACH: \ + icmp6_ifstat_inc(ifp, ifs6_out_dstunreach); \ + if (code == ICMP6_DST_UNREACH_ADMIN) \ + icmp6_ifstat_inc(ifp, ifs6_out_adminprohib); \ + break; \ + case ICMP6_PACKET_TOO_BIG: \ + icmp6_ifstat_inc(ifp, ifs6_out_pkttoobig); \ + break; \ + case ICMP6_TIME_EXCEEDED: \ + icmp6_ifstat_inc(ifp, ifs6_out_timeexceed); \ + break; \ + case ICMP6_PARAM_PROB: \ + icmp6_ifstat_inc(ifp, ifs6_out_paramprob); \ + break; \ + case ICMP6_ECHO_REQUEST: \ + icmp6_ifstat_inc(ifp, ifs6_out_echo); \ + break; \ + case ICMP6_ECHO_REPLY: \ + icmp6_ifstat_inc(ifp, ifs6_out_echoreply); \ + break; \ + case MLD6_LISTENER_QUERY: \ + icmp6_ifstat_inc(ifp, ifs6_out_mldquery); \ + break; \ + case MLD6_LISTENER_REPORT: \ + icmp6_ifstat_inc(ifp, ifs6_out_mldreport); \ + break; \ + case MLD6_LISTENER_DONE: \ + icmp6_ifstat_inc(ifp, ifs6_out_mlddone); \ + break; \ + case ND_ROUTER_SOLICIT: \ + icmp6_ifstat_inc(ifp, ifs6_out_routersolicit); \ + break; \ + case ND_ROUTER_ADVERT: \ + icmp6_ifstat_inc(ifp, ifs6_out_routeradvert); \ + break; \ + case ND_NEIGHBOR_SOLICIT: \ + icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit); \ + break; \ + case ND_NEIGHBOR_ADVERT: \ + icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert); \ + break; \ + case ND_REDIRECT: \ + icmp6_ifstat_inc(ifp, ifs6_out_redirect); \ + break; \ + } \ +} while (0) -extern struct icmp6stat icmp6stat; extern int icmp6_rediraccept; /* accept/process redirects */ extern int icmp6_redirtimeout; /* cache time for redirect routes */ #endif /* _KERNEL */ diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 79a08ab56d2..347ea36e6e3 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -1,4 +1,4 @@ -/* $NetBSD: in6.c,v 1.7 1999/09/26 20:08:15 is Exp $ */ +/* $NetBSD: in6.c,v 1.8 1999/12/13 15:17:21 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -69,21 +69,21 @@ #endif #include <sys/param.h> -#if !defined(__FreeBSD__) && __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) #include <sys/ioctl.h> #endif #include <sys/errno.h> #include <sys/malloc.h> -#include <sys/proc.h> #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/sockio.h> #include <sys/systm.h> -#ifdef __NetBSD__ +#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) #include <sys/proc.h> #endif #include <sys/time.h> #include <sys/kernel.h> +#include <sys/syslog.h> #include <net/if.h> #include <net/if_types.h> @@ -94,7 +94,6 @@ #endif #include <net/if_dl.h> -#include <net/if.h> #include <netinet/in.h> #include <netinet/in_var.h> #ifdef __NetBSD__ @@ -105,14 +104,15 @@ #include <netinet6/nd6.h> #include <netinet6/ip6.h> +#include <netinet6/ip6_var.h> #include <netinet6/mld6_var.h> #include <netinet6/ip6_mroute.h> #include <netinet6/in6_ifattach.h> +#include <net/net_osdep.h> + #if defined(__FreeBSD__) && __FreeBSD__ >= 3 MALLOC_DEFINE(M_IPMADDR, "in6_multi", "internet multicast address"); -#else -#define time_second time.tv_sec #endif /* @@ -133,9 +133,17 @@ const struct in6_addr in6mask64 = IN6MASK64; const struct in6_addr in6mask96 = IN6MASK96; const struct in6_addr in6mask128 = IN6MASK128; +#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t, struct ifnet *, struct proc *)); +#else +static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t, + struct ifnet *)); +#endif +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +struct in6_multihead in6_multihead; /* XXX BSS initialization */ +#else /* * This structure is used to keep track of in6_multi chains which belong to * deleted interface addresses. @@ -147,6 +155,7 @@ struct multi6_kludge { struct ifnet *mk_ifp; struct in6_multihead mk_head; }; +#endif /* * Determine whether an IP6 address is in a reserved set of addresses @@ -172,6 +181,9 @@ in6_canforward(src, dst) static int in6_is_ifloop_auto(struct ifaddr *ifa) { +#ifdef __OpenBSD__ + return 0; +#else #define SIN6(s) ((struct sockaddr_in6 *)s) /* * If RTF_CLONING is unset, or (IFF_LOOPBACK | IFF_POINTOPOINT), @@ -189,6 +201,7 @@ in6_is_ifloop_auto(struct ifaddr *ifa) else return 1; #undef SIN6 +#endif } /* @@ -269,7 +282,7 @@ in6_ifremloop(struct ifaddr *ifa) /* If only one ifa for the loopback entry, delete it. */ for (ia = in6_ifaddr; ia; ia = ia->ia_next) { - if (IN6_ARE_ADDR_EQUAL(&IFA_IN6(ifa), + if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr)) { ia_count++; if (ia_count > 1) @@ -366,6 +379,34 @@ in6_ifremproxy(struct in6_ifaddr *ia) } int +in6_ifindex2scopeid(idx) + int idx; +{ + struct ifnet *ifp; + struct ifaddr *ifa; + struct sockaddr_in6 *sin6; + + if (idx < 0 || if_index < idx) + return -1; + ifp = ifindex2ifnet[idx]; + +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#else + for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) +#endif + { + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; + if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) + return sin6->sin6_scope_id & 0xffff; + } + + return -1; +} + +int in6_mask2len(mask) struct in6_addr *mask; { @@ -405,18 +446,42 @@ int in6_interfaces; /* number of external internet interfaces */ #define ia62ifa(ia6) ((struct ifaddr *)(ia6)) int +#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) in6_control(so, cmd, data, ifp, p) struct socket *so; u_long cmd; caddr_t data; struct ifnet *ifp; struct proc *p; +#else +in6_control(so, cmd, data, ifp) + struct socket *so; + u_long cmd; + caddr_t data; + struct ifnet *ifp; +#endif { struct in6_ifreq *ifr = (struct in6_ifreq *)data; +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + struct ifaddr *ifa; +#endif struct in6_ifaddr *ia, *oia; struct in6_aliasreq *ifra = (struct in6_aliasreq *)data; struct sockaddr_in6 oldaddr, net; int error = 0, hostIsNew, prefixIsNew; +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) + time_t time_second = (time_t)time.tv_sec; +#endif + int privileged; + + privileged = 0; +#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3) + if (p && !suser(p->p_ucred, &p->p_acflag)) + privileged++; +#else + if ((so->so_state & SS_PRIV) != 0) + privileged++; +#endif /* * xxx should prevent processes for link-local addresses? @@ -425,7 +490,7 @@ in6_control(so, cmd, data, ifp, p) if (ifp && ifp->if_type == IFT_GIF) { switch (cmd) { case SIOCSIFPHYADDR_IN6: - if (p == 0 || suser(p->p_ucred, &p->p_acflag)) + if (!privileged) return(EPERM); /*fall through*/ case SIOCGIFPSRCADDR_IN6: @@ -447,13 +512,15 @@ in6_control(so, cmd, data, ifp, p) case SIOCSNDFLUSH_IN6: case SIOCSPFXFLUSH_IN6: case SIOCSRTRFLUSH_IN6: - if (p == 0 || suser(p->p_ucred, &p->p_acflag)) + case SIOCSDEFIFACE_IN6: + if (!privileged) return(EPERM); /*fall through*/ case SIOCGIFINFO_IN6: case SIOCGDRLST_IN6: case SIOCGPRLST_IN6: case SIOCGNBRINFO_IN6: + case SIOCGDEFIFACE_IN6: return(nd6_ioctl(cmd, data, ifp)); } @@ -463,36 +530,51 @@ in6_control(so, cmd, data, ifp, p) case SIOCAIFPREFIX_IN6: case SIOCCIFPREFIX_IN6: case SIOCSGIFPREFIX_IN6: - if (p == 0 || suser(p->p_ucred, &p->p_acflag)) + if (!privileged) return(EPERM); /*fall through*/ case SIOCGIFPREFIX_IN6: - return(in6_prefix_ioctl(cmd, data, ifp)); + return(in6_prefix_ioctl(so, cmd, data, ifp)); } switch (cmd) { case SIOCALIFADDR: case SIOCDLIFADDR: - if (p == 0 || suser(p->p_ucred, &p->p_acflag)) + if (!privileged) return(EPERM); /*fall through*/ case SIOCGLIFADDR: +#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) return in6_lifaddr_ioctl(so, cmd, data, ifp, p); +#else + return in6_lifaddr_ioctl(so, cmd, data, ifp); +#endif } /* * Find address for this interface, if it exists. */ { - struct in6_addr *addr = &ifra->ifra_addr.sin6_addr; - if (IN6_IS_ADDR_LINKLOCAL(addr)) { - if (addr->s6_addr16[1] == 0) { + + struct sockaddr_in6 *sa6 = + (struct sockaddr_in6 *)&ifra->ifra_addr; + + if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { + if (sa6->sin6_addr.s6_addr16[1] == 0) { /* interface ID is not embedded by the user */ - addr->s6_addr16[1] = htons(ifp->if_index); + sa6->sin6_addr.s6_addr16[1] = + htons(ifp->if_index); } else - if (addr->s6_addr16[1] != htons(ifp->if_index)) + if (sa6->sin6_addr.s6_addr16[1] != + htons(ifp->if_index)) return(EINVAL); /* ifid is contradict */ + if (sa6->sin6_scope_id) { + if (sa6->sin6_scope_id != + (u_int32_t)ifp->if_index) + return(EINVAL); + sa6->sin6_scope_id = 0; /* XXX: good way? */ + } } } #if 0 @@ -513,7 +595,7 @@ in6_control(so, cmd, data, ifp, p) case SIOCSIFADDR_IN6: case SIOCSIFNETMASK_IN6: case SIOCSIFDSTADDR_IN6: - if (p == 0 || suser(p->p_ucred, &p->p_acflag)) + if (!privileged) return(EPERM); if (ia == 0) { ia = (struct in6_ifaddr *) @@ -534,14 +616,17 @@ in6_control(so, cmd, data, ifp, p) oia->ia_next = ia; } else in6_ifaddr = ia; -#if 0 /* this search seems to be meaningless */ - if ((ifa = ifp->if_addrlist.tqh_first) != NULL) { - for ( ; ifa->ifa_list.tqe_next; ifa = ifa->ifa_list.tqe_next) +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + if ((ifa = ifp->if_addrlist) != NULL) { + for ( ; ifa->ifa_next; ifa = ifa->ifa_next) continue; - } -#endif + ifa->ifa_next = ia62ifa(ia); + } else + ifp->if_addrlist = ia62ifa(ia); +#else TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); +#endif if ((ifp->if_flags & IFF_LOOPBACK) == 0) in6_interfaces++; /*XXX*/ } @@ -567,6 +652,7 @@ in6_control(so, cmd, data, ifp, p) case SIOCGIFAFLAG_IN6: case SIOCGIFNETMASK_IN6: case SIOCGIFDSTADDR_IN6: + case SIOCGIFALIFETIME_IN6: /* must think again about its semantics */ if (ia == 0) return(EADDRNOTAVAIL); @@ -575,7 +661,7 @@ in6_control(so, cmd, data, ifp, p) { struct in6_addrlifetime *lt; - if (p == 0 || suser(p->p_ucred, &p->p_acflag)) + if (!privileged) return(EPERM); if (ia == 0) return(EADDRNOTAVAIL); @@ -613,6 +699,31 @@ in6_control(so, cmd, data, ifp, p) ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags; break; + case SIOCGIFSTAT_IN6: + if (ifp == NULL) + return EINVAL; + if (in6_ifstat == NULL || ifp->if_index >= in6_ifstatmax + || in6_ifstat[ifp->if_index] == NULL) { + /* return EAFNOSUPPORT? */ + bzero(&ifr->ifr_ifru.ifru_stat, + sizeof(ifr->ifr_ifru.ifru_stat)); + } else + ifr->ifr_ifru.ifru_stat = *in6_ifstat[ifp->if_index]; + break; + + case SIOCGIFSTAT_ICMP6: + if (ifp == NULL) + return EINVAL; + if (icmp6_ifstat == NULL || ifp->if_index >= icmp6_ifstatmax || + icmp6_ifstat[ifp->if_index] == NULL) { + /* return EAFNOSUPPORT? */ + bzero(&ifr->ifr_ifru.ifru_stat, + sizeof(ifr->ifr_ifru.ifru_icmp6stat)); + } else + ifr->ifr_ifru.ifru_icmp6stat = + *icmp6_ifstat[ifp->if_index]; + break; + case SIOCSIFDSTADDR_IN6: if ((ifp->if_flags & IFF_POINTOPOINT) == 0) return(EINVAL); @@ -796,12 +907,24 @@ in6_control(so, cmd, data, ifp, p) ia->ia6_flags |= IN6_IFF_TENTATIVE; nd6_dad_start((struct ifaddr *)ia, NULL); break; + case IFT_FAITH: case IFT_GIF: case IFT_LOOP: default: break; } + if (hostIsNew) { + int iilen; + int error_local = 0; + + iilen = (sizeof(ia->ia_prefixmask.sin6_addr) << 3) - + in6_mask2len(&ia->ia_prefixmask.sin6_addr); + error_local = in6_prefix_add_ifid(iilen, ia); + if (error == 0) + error = error_local; + } + return(error); case SIOCDIFADDR_IN6: @@ -830,7 +953,21 @@ in6_control(so, cmd, data, ifp, p) if (nd6_proxyall) in6_ifremproxy(ia); +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + if ((ifa = ifp->if_addrlist) == ia62ifa(ia)) + ifp->if_addrlist = ifa->ifa_next; + else { + while (ifa->ifa_next && + (ifa->ifa_next != ia62ifa(ia))) + ifa = ifa->ifa_next; + if (ifa->ifa_next) + ifa->ifa_next = ia62ifa(ia)->ifa_next; + else + printf("Couldn't unlink in6_ifaddr from ifp\n"); + } +#else TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); +#endif oia = ia; if (oia == (ia = in6_ifaddr)) in6_ifaddr = ia->ia_next; @@ -842,13 +979,21 @@ in6_control(so, cmd, data, ifp, p) else printf("Didn't unlink in6_ifaddr from list\n"); } + { + int iilen; + iilen = (sizeof(oia->ia_prefixmask.sin6_addr) << 3) - + in6_mask2len(&oia->ia_prefixmask.sin6_addr); + in6_prefix_remove_ifid(iilen, oia); + } +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) if (oia->ia6_multiaddrs.lh_first == NULL) { IFAFREE(&oia->ia_ifa); break; } else in6_savemkludge(oia); +#endif IFAFREE((&oia->ia_ifa)); break; @@ -885,15 +1030,24 @@ in6_control(so, cmd, data, ifp, p) * address encoding scheme. (see figure on page 8) */ static int +#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) in6_lifaddr_ioctl(so, cmd, data, ifp, p) struct socket *so; u_long cmd; caddr_t data; struct ifnet *ifp; struct proc *p; +#else +in6_lifaddr_ioctl(so, cmd, data, ifp) + struct socket *so; + u_long cmd; + caddr_t data; + struct ifnet *ifp; +#endif { struct if_laddrreq *iflr = (struct if_laddrreq *)data; struct ifaddr *ifa; + struct sockaddr *sa; /* sanity checks */ if (!data || !ifp) { @@ -910,16 +1064,16 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p) case SIOCALIFADDR: case SIOCDLIFADDR: /* address must be specified on ADD and DELETE */ - if (iflr->addr.__ss_family != AF_INET6) + sa = (struct sockaddr *)&iflr->addr; + if (sa->sa_family != AF_INET6) return EINVAL; - if (iflr->addr.__ss_len != sizeof(struct sockaddr_in6)) + if (sa->sa_len != sizeof(struct sockaddr_in6)) return EINVAL; /* XXX need improvement */ - if (iflr->dstaddr.__ss_family - && iflr->dstaddr.__ss_family != AF_INET6) + sa = (struct sockaddr *)&iflr->dstaddr; + if (sa->sa_family && sa->sa_family != AF_INET6) return EINVAL; - if (iflr->dstaddr.__ss_family - && iflr->dstaddr.__ss_len != sizeof(struct sockaddr_in6)) + if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6)) return EINVAL; break; default: /*shouldn't happen*/ @@ -951,7 +1105,7 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p) ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp); if (!ifa) return EADDRNOTAVAIL; - hostid = &IFA_IN6(ifa); + hostid = IFA_IN6(ifa); /* prefixlen must be <= 64. */ if (64 < iflr->prefixlen) @@ -972,7 +1126,8 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p) bcopy(iflr->iflr_name, ifra.ifra_name, sizeof(ifra.ifra_name)); - bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.__ss_len); + bcopy(&iflr->addr, &ifra.ifra_addr, + ((struct sockaddr *)&iflr->addr)->sa_len); if (hostid) { /* fill in hostid part */ ifra.ifra_addr.sin6_addr.s6_addr32[2] = @@ -981,9 +1136,9 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p) hostid->s6_addr32[3]; } - if (iflr->dstaddr.__ss_family) { /*XXX*/ + if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /*XXX*/ bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, - iflr->dstaddr.__ss_len); + ((struct sockaddr *)&iflr->dstaddr)->sa_len); if (hostid) { ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] = hostid->s6_addr32[2]; @@ -997,7 +1152,11 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p) in6_len2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen); ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX; +#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, p); +#else + return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp); +#endif } case SIOCGLIFADDR: case SIOCDLIFADDR: @@ -1038,14 +1197,19 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p) } } +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#else for (ifa = ifp->if_addrlist.tqh_first; ifa; - ifa = ifa->ifa_list.tqe_next) { + ifa = ifa->ifa_list.tqe_next) +#endif + { if (ifa->ifa_addr->sa_family != AF_INET6) continue; if (!cmp) break; - bcopy(&IFA_IN6(ifa), &candidate, sizeof(candidate)); + bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate)); candidate.s6_addr32[0] &= mask.s6_addr32[0]; candidate.s6_addr32[1] &= mask.s6_addr32[1]; candidate.s6_addr32[2] &= mask.s6_addr32[2]; @@ -1091,8 +1255,13 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p) ia->ia_prefixmask.sin6_len); ifra.ifra_flags = ia->ia6_flags; +#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, ifp, p); +#else + return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, + ifp); +#endif } } } @@ -1189,7 +1358,7 @@ in6_ifinit(ifp, ia, sin6, scrub) /* Add ownaddr as loopback rtentry, if necessary(ex. on p2p link). */ in6_ifaddloop(&(ia->ia_ifa)); -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) if (ifp->if_flags & IFF_MULTICAST) in6_restoremkludge(ia, ifp); #endif @@ -1282,7 +1451,11 @@ in6_addmulti(maddr6, ifp, errorp) struct in6_ifaddr *ia; struct in6_ifreq ifr; struct in6_multi *in6m; +#ifdef __NetBSD__ int s = splsoftnet(); +#else + int s = splnet(); +#endif *errorp = 0; /* @@ -1357,7 +1530,11 @@ in6_delmulti(in6m) struct in6_multi *in6m; { struct in6_ifreq ifr; +#ifdef __NetBSD__ int s = splsoftnet(); +#else + int s = splnet(); +#endif if (--in6m->in6m_refcount == 0) { /* @@ -1396,12 +1573,17 @@ in6ifa_ifpforlinklocal(ifp) { register struct ifaddr *ifa; - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#else + for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) +#endif + { if (ifa->ifa_addr == NULL) continue; /* just for safety */ if (ifa->ifa_addr->sa_family != AF_INET6) continue; - if (IN6_IS_ADDR_LINKLOCAL(&IFA_IN6(ifa))) + if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) break; } @@ -1419,12 +1601,17 @@ in6ifa_ifpwithaddr(ifp, addr) { register struct ifaddr *ifa; - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#else + for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) +#endif + { if (ifa->ifa_addr == NULL) continue; /* just for safety */ if (ifa->ifa_addr->sa_family != AF_INET6) continue; - if (IN6_ARE_ADDR_EQUAL(addr, &IFA_IN6(ifa))) + if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) break; } @@ -1586,6 +1773,56 @@ struct in6_addr *src, *dst; return match; } +int +in6_are_prefix_equal(p1, p2, len) + struct in6_addr *p1, *p2; + int len; +{ + int bytelen, bitlen; + + /* sanity check */ + if (0 > len || len > 128) { + log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n", + len); + return(0); + } + + bytelen = len / 8; + bitlen = len % 8; + + if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen)) + return(0); + if (p1->s6_addr[bytelen] >> (8 - bitlen) != + p2->s6_addr[bytelen] >> (8 - bitlen)) + return(0); + + return(1); +} + +void +in6_prefixlen2mask(maskp, len) + struct in6_addr *maskp; + int len; +{ + u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; + int bytelen, bitlen, i; + + /* sanity check */ + if (0 > len || len > 128) { + log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n", + len); + return; + } + + bzero(maskp, sizeof(*maskp)); + bytelen = len / 8; + bitlen = len % 8; + for (i = 0; i < bytelen; i++) + maskp->s6_addr[i] = 0xff; + if (bitlen) + maskp->s6_addr[bytelen] = maskarray[bitlen - 1]; +} + /* * return the best address out of the same scope */ @@ -1597,7 +1834,10 @@ in6_ifawithscope(ifp, dst) { int dst_scope = in6_addrscope(dst), blen = -1, tlen; struct ifaddr *ifa; - struct in6_ifaddr *besta = 0, *ia; + struct in6_ifaddr *besta = NULL, *ia; + struct in6_ifaddr *dep[2]; /*last-resort: deprecated*/ + + dep[0] = dep[1] = NULL; /* * We first look for addresses in the same scope. @@ -1605,7 +1845,12 @@ in6_ifawithscope(ifp, dst) * If two or more, return one which matches the dst longest. * If none, return one of global addresses assigned other ifs. */ - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#else + for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) +#endif + { if (ifa->ifa_addr->sa_family != AF_INET6) continue; if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) @@ -1614,17 +1859,20 @@ in6_ifawithscope(ifp, dst) continue; /* don't use this interface */ if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) continue; - if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) + if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { + if (ip6_use_deprecated) + dep[0] = (struct in6_ifaddr *)ifa; continue; + } - if (dst_scope == in6_addrscope(&IFA_IN6(ifa))) { + if (dst_scope == in6_addrscope(IFA_IN6(ifa))) { /* * call in6_matchlen() as few as possible */ if (besta) { if (blen == -1) blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst); - tlen = in6_matchlen(&IFA_IN6(ifa), dst); + tlen = in6_matchlen(IFA_IN6(ifa), dst); if (tlen > blen) { blen = tlen; besta = (struct in6_ifaddr *)ifa; @@ -1634,20 +1882,33 @@ in6_ifawithscope(ifp, dst) } } if (besta) - return(besta); + return besta; for (ia = in6_ifaddr; ia; ia = ia->ia_next) { - if (IPV6_ADDR_SCOPE_GLOBAL == - in6_addrscope(&(ia->ia_addr.sin6_addr)) - && (ia->ia6_flags & IN6_IFF_ANYCAST) == 0 - && (ia->ia6_flags & IN6_IFF_NOTREADY) == 0 - && (ia->ia6_flags & IN6_IFF_DETACHED) == 0 - && (ia->ia6_flags & IN6_IFF_DEPRECATED) == 0) { - /* XXX: is there any case to allow anycast? */ - return ia; + if (IPV6_ADDR_SCOPE_GLOBAL != + in6_addrscope(&(ia->ia_addr.sin6_addr))) + continue; + /* XXX: is there any case to allow anycast? */ + if ((ia->ia6_flags & IN6_IFF_ANYCAST) != 0) + continue; + if ((ia->ia6_flags & IN6_IFF_NOTREADY) != 0) + continue; + if ((ia->ia6_flags & IN6_IFF_DETACHED) != 0) + continue; + if ((ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) { + if (ip6_use_deprecated) + dep[1] = (struct in6_ifaddr *)ifa; + continue; } + return ia; } + /* use the last-resort values, that are, deprecated addresses */ + if (dep[0]) + return dep[0]; + if (dep[1]) + return dep[1]; + return NULL; } @@ -1664,6 +1925,9 @@ in6_ifawithifp(ifp, dst) int dst_scope = in6_addrscope(dst), blen = -1, tlen; struct ifaddr *ifa; struct in6_ifaddr *besta = 0; + struct in6_ifaddr *dep[2]; /*last-resort: deprecated*/ + + dep[0] = dep[1] = NULL; /* * We first look for addresses in the same scope. @@ -1671,7 +1935,12 @@ in6_ifawithifp(ifp, dst) * If two or more, return one which matches the dst longest. * If none, return one of global addresses assigned other ifs. */ - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#else + for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) +#endif + { if (ifa->ifa_addr->sa_family != AF_INET6) continue; if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) @@ -1680,17 +1949,20 @@ in6_ifawithifp(ifp, dst) continue; /* don't use this interface */ if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) continue; - if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) + if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { + if (ip6_use_deprecated) + dep[0] = (struct in6_ifaddr *)ifa; continue; + } - if (dst_scope == in6_addrscope(&IFA_IN6(ifa))) { + if (dst_scope == in6_addrscope(IFA_IN6(ifa))) { /* * call in6_matchlen() as few as possible */ if (besta) { if (blen == -1) blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst); - tlen = in6_matchlen(&IFA_IN6(ifa), dst); + tlen = in6_matchlen(IFA_IN6(ifa), dst); if (tlen > blen) { blen = tlen; besta = (struct in6_ifaddr *)ifa; @@ -1702,7 +1974,12 @@ in6_ifawithifp(ifp, dst) if (besta) return(besta); - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#else + for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) +#endif + { if (ifa->ifa_addr->sa_family != AF_INET6) continue; if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) @@ -1711,12 +1988,21 @@ in6_ifawithifp(ifp, dst) continue; /* don't use this interface */ if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) continue; - if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) + if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { + if (ip6_use_deprecated) + dep[1] = (struct in6_ifaddr *)ifa; continue; + } return (struct in6_ifaddr *)ifa; } + /* use the last-resort values, that are, deprecated addresses */ + if (dep[0]) + return dep[0]; + if (dep[1]) + return dep[1]; + return NULL; } @@ -1731,14 +2017,23 @@ in6_if_up(ifp) struct in6_ifaddr *ia; struct sockaddr_dl *sdl; int type; +#ifdef __bsdi__ + u_char ea[ETHER_ADDR_LEN]; +#else struct ether_addr ea; +#endif int off; int dad_delay; /* delay ticks before DAD output */ bzero(&ea, sizeof(ea)); sdl = NULL; - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#else + for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) +#endif + { if (ifa->ifa_addr->sa_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { goto dad; @@ -1750,6 +2045,9 @@ in6_if_up(ifp) } switch (ifp->if_type) { + case IFT_LOOP: + in6_ifattach(ifp, IN6_IFT_LOOP, NULL, 1); + break; case IFT_SLIP: case IFT_PPP: case IFT_GIF: @@ -1781,7 +2079,12 @@ in6_if_up(ifp) dad: dad_delay = 0; - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#else + for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) +#endif + { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ia = (struct in6_ifaddr *)ifa; @@ -1800,7 +2103,12 @@ in6_setmaxmtu() unsigned long maxmtu = 0; struct ifnet *ifp; - for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) { +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifp = ifnet; ifp; ifp = ifp->if_next) +#else + for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) +#endif + { if ((ifp->if_flags & IFF_LOOPBACK) == 0 && nd_ifinfo[ifp->if_index].linkmtu > maxmtu) maxmtu = nd_ifinfo[ifp->if_index].linkmtu; diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index 742917cf699..c8ec93b8afa 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -1,4 +1,4 @@ -/* $NetBSD: in6.h,v 1.6 1999/07/06 12:23:22 itojun Exp $ */ +/* $NetBSD: in6.h,v 1.7 1999/12/13 15:17:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -75,7 +75,7 @@ * Identification of the network protocol stack */ #define __KAME__ -#define __KAME_VERSION "SNAP 19990705/NetBSD-current" +#define __KAME_VERSION "19991213/NetBSD-current" /* * Local port number conventions: @@ -116,16 +116,18 @@ */ struct in6_addr { union { - u_int32_t __u6_addr32[4]; - u_int16_t __u6_addr16[8]; u_int8_t __u6_addr8[16]; + u_int16_t __u6_addr16[8]; + u_int32_t __u6_addr32[4]; } __u6_addr; /* 128-bit IP6 address */ }; -#define s6_addr32 __u6_addr.__u6_addr32 -#define s6_addr16 __u6_addr.__u6_addr16 -#define s6_addr8 __u6_addr.__u6_addr8 #define s6_addr __u6_addr.__u6_addr8 +#ifdef _KERNEL /*XXX nonstandard*/ +#define s6_addr8 __u6_addr.__u6_addr8 +#define s6_addr16 __u6_addr.__u6_addr16 +#define s6_addr32 __u6_addr.__u6_addr32 +#endif #define INET6_ADDRSTRLEN 46 @@ -147,11 +149,17 @@ struct sockaddr_in6 { /* * Local definition for masks */ -#define IN6MASK0 {{{ 0, 0, 0, 0 }}} -#define IN6MASK32 {{{ 0xffffffff, 0, 0, 0 }}} -#define IN6MASK64 {{{ 0xffffffff, 0xffffffff, 0, 0 }}} -#define IN6MASK96 {{{ 0xffffffff, 0xffffffff, 0xffffffff, 0 }}} -#define IN6MASK128 {{{ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }}} +#ifdef _KERNEL /*XXX nonstandard*/ +#define IN6MASK0 {{{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}} +#define IN6MASK32 {{{ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}} +#define IN6MASK64 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}} +#define IN6MASK96 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }}} +#define IN6MASK128 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}} +#endif #ifdef _KERNEL extern const struct in6_addr in6mask0; @@ -164,7 +172,7 @@ extern const struct in6_addr in6mask128; /* * Macros started with IPV6_ADDR is KAME local */ - +#ifdef _KERNEL /*XXX nonstandard*/ #if BYTE_ORDER == BIG_ENDIAN #define IPV6_ADDR_INT32_ONE 1 #define IPV6_ADDR_INT32_TWO 2 @@ -184,18 +192,26 @@ extern const struct in6_addr in6mask128; #define IPV6_ADDR_INT16_USL 0xc0fe #define IPV6_ADDR_INT16_MLL 0x02ff #endif +#endif /* * Definition of some useful macros to handle IP6 addresses */ -#define IN6ADDR_ANY_INIT {{{ 0, 0, 0, 0 }}} -#define IN6ADDR_LOOPBACK_INIT {{{ 0, 0, 0, IPV6_ADDR_INT32_ONE }}} -#define IN6ADDR_NODELOCAL_ALLNODES_INIT \ - {{{ IPV6_ADDR_INT32_MNL, 0, 0, IPV6_ADDR_INT32_ONE }}} -#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \ - {{{ IPV6_ADDR_INT32_MLL, 0, 0, IPV6_ADDR_INT32_ONE }}} +#define IN6ADDR_ANY_INIT \ + {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}} +#define IN6ADDR_LOOPBACK_INIT \ + {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}} +#define IN6ADDR_NODELOCAL_ALLNODES_INIT \ + {{{ 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}} +#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \ + {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}} #define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \ - {{{ IPV6_ADDR_INT32_MLL, 0, 0, IPV6_ADDR_INT32_TWO }}} + {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}} extern const struct in6_addr in6addr_any; extern const struct in6_addr in6addr_loopback; @@ -205,77 +221,96 @@ extern const struct in6_addr in6addr_linklocal_allrouters; /* * Equality + * NOTE: Some of kernel programming environment (for example, openbsd/sparc) + * does not supply memcmp(). For userland memcmp() is preferred as it is + * in ANSI standard. */ +#ifdef _KERNEL +#define IN6_ARE_ADDR_EQUAL(a, b) \ + (bcmp((a), (b), sizeof(struct in6_addr)) == 0) +#else #define IN6_ARE_ADDR_EQUAL(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])) + (memcmp((a), (b), sizeof(struct in6_addr)) == 0) +#endif /* * Unspecified */ #define IN6_IS_ADDR_UNSPECIFIED(a) \ - (((a)->s6_addr32[0] == 0) && \ - ((a)->s6_addr32[1] == 0) && \ - ((a)->s6_addr32[2] == 0) && \ - ((a)->s6_addr32[3] == 0)) + ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[8]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[12]) == 0)) /* * Loopback */ #define IN6_IS_ADDR_LOOPBACK(a) \ - (((a)->s6_addr32[0] == 0) && \ - ((a)->s6_addr32[1] == 0) && \ - ((a)->s6_addr32[2] == 0) && \ - ((a)->s6_addr32[3] == IPV6_ADDR_INT32_ONE)) + ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[8]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[12]) == ntohl(1))) /* * IPv4 compatible */ #define IN6_IS_ADDR_V4COMPAT(a) \ - (((a)->s6_addr32[0] == 0) && \ - ((a)->s6_addr32[1] == 0) && \ - ((a)->s6_addr32[2] == 0) && \ - ((a)->s6_addr32[3] != 0) && \ - ((a)->s6_addr32[3] != IPV6_ADDR_INT32_ONE)) + ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[8]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[12]) != 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[12]) != ntohl(1))) /* * Mapped */ #define IN6_IS_ADDR_V4MAPPED(a) \ - (((a)->s6_addr32[0] == 0) && \ - ((a)->s6_addr32[1] == 0) && \ - ((a)->s6_addr32[2] == IPV6_ADDR_INT32_SMP)) + ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) /* * KAME Scope Values */ +#ifdef _KERNEL /*XXX nonstandard*/ #define IPV6_ADDR_SCOPE_NODELOCAL 0x01 #define IPV6_ADDR_SCOPE_LINKLOCAL 0x02 #define IPV6_ADDR_SCOPE_SITELOCAL 0x05 #define IPV6_ADDR_SCOPE_ORGLOCAL 0x08 /* just used in this file */ #define IPV6_ADDR_SCOPE_GLOBAL 0x0e +#else +#define __IPV6_ADDR_SCOPE_NODELOCAL 0x01 +#define __IPV6_ADDR_SCOPE_LINKLOCAL 0x02 +#define __IPV6_ADDR_SCOPE_SITELOCAL 0x05 +#define __IPV6_ADDR_SCOPE_ORGLOCAL 0x08 /* just used in this file */ +#define __IPV6_ADDR_SCOPE_GLOBAL 0x0e +#endif /* * Unicast Scope + * Note that we must check topmost 10 bits only, not 16 bits (see RFC2373). */ #define IN6_IS_ADDR_LINKLOCAL(a) \ - ((a)->s6_addr16[0] == IPV6_ADDR_INT16_ULL) + (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80)) #define IN6_IS_ADDR_SITELOCAL(a) \ - ((a)->s6_addr16[0] == IPV6_ADDR_INT16_USL) + (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0)) /* * Multicast */ -#define IN6_IS_ADDR_MULTICAST(a) ((a)->s6_addr8[0] == 0xff) +#define IN6_IS_ADDR_MULTICAST(a) ((a)->s6_addr[0] == 0xff) -#define IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr8[1] & 0x0f) +#ifdef _KERNEL /*XXX nonstandard*/ +#define IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f) +#else +#define __IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f) +#endif /* * Multicast Scope */ +#ifdef _KERNEL /*refers nonstandard items */ #define IN6_IS_ADDR_MC_NODELOCAL(a) \ (IN6_IS_ADDR_MULTICAST(a) && \ (IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_NODELOCAL)) @@ -291,18 +326,39 @@ extern const struct in6_addr in6addr_linklocal_allrouters; #define IN6_IS_ADDR_MC_GLOBAL(a) \ (IN6_IS_ADDR_MULTICAST(a) && \ (IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_GLOBAL)) +#else +#define IN6_IS_ADDR_MC_NODELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && \ + (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_NODELOCAL)) +#define IN6_IS_ADDR_MC_LINKLOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && \ + (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_LINKLOCAL)) +#define IN6_IS_ADDR_MC_SITELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && \ + (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_SITELOCAL)) +#define IN6_IS_ADDR_MC_ORGLOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && \ + (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_ORGLOCAL)) +#define IN6_IS_ADDR_MC_GLOBAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && \ + (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_GLOBAL)) +#endif /* * Wildcard Socket */ +#if 0 /*pre-RFC2553*/ #define IN6_IS_ADDR_ANY(a) IN6_IS_ADDR_UNSPECIFIED(a) +#endif /* * KAME Scope */ +#ifdef _KERNEL /*nonstandard*/ #define IN6_IS_SCOPE_LINKLOCAL(a) \ ((IN6_IS_ADDR_LINKLOCAL(a)) || \ (IN6_IS_ADDR_MC_LINKLOCAL(a))) +#endif /* * IP6 route structure @@ -346,7 +402,7 @@ struct route_in6 { #if 1 /*IPSEC*/ #define IPV6_IPSEC_POLICY 28 /* struct; get/set security policy */ #endif -#define IPV6_FAITH 32 /* bool; accept FAITH'ed connections */ +#define IPV6_FAITH 29 /* bool; accept FAITH'ed connections */ #define IPV6_RTHDR_LOOSE 0 /* this hop need not be a neighbor. XXX old spec */ #define IPV6_RTHDR_STRICT 1 /* this hop must be a neighbor. XXX old spec */ @@ -463,8 +519,23 @@ struct in6_pktinfo { #define IPV6CTL_DEFMCASTHLIM 18 #define IPV6CTL_GIF_HLIM 19 /* default HLIM for gif encap packet */ #define IPV6CTL_KAME_VERSION 20 +#define IPV6CTL_USE_DEPRECATED 21 /* use deprecated addr (RFC2462 5.5.4) */ +#define IPV6CTL_RR_PRUNE 22 /* walk timer for router renumbering */ +#ifdef MAPPED_ADDR_ENABLED +#define IPV6CTL_MAPPED_ADDR 23 +#endif /* MAPPED_ADDR_ENABLED */ /* New entries should be added here from current IPV6CTL_MAXID value. */ -#define IPV6CTL_MAXID 21 +#define IPV6CTL_MAXID 24 + +#ifdef MAPPED_ADDR_ENABLED +#define IPV6CTL_NAMES_MAPPED_ADDR "mapped_addr" +#define IPV6CTL_TYPE_MAPPED_ADDR CTLTYPE_INT +#define IPV6CTL_VARS_MAPPED_ADDR &ip6_mapped_addr_on +#else /* MAPPED_ADDR_ENABLED */ +#define IPV6CTL_NAMES_MAPPED_ADDR 0 +#define IPV6CTL_TYPE_MAPPED_ADDR 0 +#define IPV6CTL_VARS_MAPPED_ADDR 0 +#endif /* MAPPED_ADDR_ENABLED */ #define IPV6CTL_NAMES { \ { 0, 0 }, \ @@ -488,6 +559,9 @@ struct in6_pktinfo { { "defmcasthlim", CTLTYPE_INT }, \ { "gifhlim", CTLTYPE_INT }, \ { "kame_version", CTLTYPE_STRING }, \ + { "use_deprecated", CTLTYPE_INT }, \ + { "rr_prune", CTLTYPE_INT }, \ + { IPV6CTL_NAMES_MAPPED_ADDR, IPV6CTL_TYPE_MAPPED_ADDR }, \ } #define IPV6CTL_VARS { \ @@ -508,10 +582,13 @@ struct in6_pktinfo { &ip6_log_interval, \ &ip6_hdrnestlimit, \ &ip6_dad_count, \ - &auto_flowlabel, \ + &ip6_auto_flowlabel, \ &ip6_defmcasthlim, \ &ip6_gif_hlim, \ 0, \ + &ip6_use_deprecated, \ + &ip6_rr_prune, \ + IPV6CTL_VARS_MAPPED_ADDR, \ } #endif /* !_XOPEN_SOURCE */ @@ -519,12 +596,22 @@ struct in6_pktinfo { struct cmsghdr; int in6_canforward __P((struct in6_addr *, struct in6_addr *)); -int in6_cksum __P((struct mbuf *, u_int8_t, int, int)); +int in6_cksum __P((struct mbuf *, u_int8_t, u_int32_t, u_int32_t)); int in6_localaddr __P((struct in6_addr *)); int in6_addrscope __P((struct in6_addr *)); struct in6_ifaddr *in6_ifawithscope __P((struct ifnet *, struct in6_addr *)); struct in6_ifaddr *in6_ifawithifp __P((struct ifnet *, struct in6_addr *)); extern void in6_if_up __P((struct ifnet *)); +#ifdef MAPPED_ADDR_ENABLED +struct sockaddr; + +void in6_sin6_2_sin __P((struct sockaddr_in *sin, + struct sockaddr_in6 *sin6)); +void in6_sin_2_v4mapsin6 __P((struct sockaddr_in *sin, + struct sockaddr_in6 *sin6)); +void in6_sin6_2_sin_in_sock __P((struct sockaddr *nam)); +void in6_sin_2_v4mapsin6_in_sock __P((struct sockaddr **nam)); +#endif /* MAPPED_ADDR_ENABLED */ #define satosin6(sa) ((struct sockaddr_in6 *)(sa)) #define sin6tosa(sin6) ((struct sockaddr *)(sin6)) diff --git a/sys/netinet6/in6_cksum.c b/sys/netinet6/in6_cksum.c index c6fe112d618..95337aa65b1 100644 --- a/sys/netinet6/in6_cksum.c +++ b/sys/netinet6/in6_cksum.c @@ -1,4 +1,4 @@ -/* $NetBSD: in6_cksum.c,v 1.5 1999/07/11 17:45:11 itojun Exp $ */ +/* $NetBSD: in6_cksum.c,v 1.6 1999/12/13 15:17:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -70,6 +70,8 @@ #include <netinet/in.h> #include <netinet6/ip6.h> +#include <net/net_osdep.h> + /* * Checksum routine for Internet Protocol family headers (Portable Version). * @@ -100,7 +102,7 @@ int in6_cksum(m, nxt, off, len) register struct mbuf *m; u_int8_t nxt; - register int off, len; + u_int32_t off, len; { register u_int16_t *w; register int sum = 0; diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c index 351ed4780be..2e9cb6da7bc 100644 --- a/sys/netinet6/in6_gif.c +++ b/sys/netinet6/in6_gif.c @@ -1,4 +1,4 @@ -/* $NetBSD: in6_gif.c,v 1.7 1999/08/20 10:07:41 itojun Exp $ */ +/* $NetBSD: in6_gif.c,v 1.8 1999/12/13 15:17:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -46,7 +46,7 @@ #include <sys/sockio.h> #include <sys/mbuf.h> #include <sys/errno.h> -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) #include <sys/ioctl.h> #endif #include <sys/protosw.h> @@ -69,6 +69,8 @@ #include <net/if_gif.h> +#include <net/net_osdep.h> + int in6_gif_output(ifp, family, m, rt) struct ifnet *ifp; @@ -153,6 +155,10 @@ in6_gif_output(ifp, family, m, rt) if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) ip6->ip6_dst = sin6_dst->sin6_addr; else if (rt) { + if (family != AF_INET6) { + m_freem(m); + return EINVAL; /*XXX*/ + } ip6->ip6_dst = ((struct sockaddr_in6 *)(rt->rt_gateway))->sin6_addr; } else { m_freem(m); @@ -202,9 +208,11 @@ in6_gif_output(ifp, family, m, rt) } #ifdef IPSEC +#ifndef __OpenBSD__ /*KAME IPSEC*/ m->m_pkthdr.rcvif = NULL; +#endif #endif /*IPSEC*/ - return(ip6_output(m, 0, &sc->gif_ro6, 0, 0)); + return(ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL)); } int in6_gif_input(mp, offp, proto) diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index 1344006480a..737c4d7673e 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -1,4 +1,4 @@ -/* $NetBSD: in6_ifattach.c,v 1.12 1999/09/26 20:04:08 is Exp $ */ +/* $NetBSD: in6_ifattach.c,v 1.13 1999/12/13 15:17:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -34,6 +34,14 @@ #include <sys/malloc.h> #include <sys/socket.h> #include <sys/sockio.h> +#include <sys/kernel.h> +#ifdef __bsdi__ +#include <crypto/md5.h> +#elif defined(__OpenBSD__) +#include <sys/md5k.h> +#else +#include <sys/md5.h> +#endif #include <net/if.h> #include <net/if_dl.h> @@ -46,7 +54,6 @@ #include <netinet/if_ether.h> #endif -#include <netinet6/in6.h> #include <netinet6/ip6.h> #include <netinet6/ip6_var.h> #include <netinet6/in6_ifattach.h> @@ -54,16 +61,22 @@ #include <netinet6/ip6_var.h> #include <netinet6/nd6.h> +#include <net/net_osdep.h> + static struct in6_addr llsol; -struct in6_addr **in6_iflladdr = NULL; +struct in6_ifstat **in6_ifstat = NULL; +struct icmp6_ifstat **icmp6_ifstat = NULL; +size_t in6_ifstatmax = 0; +size_t icmp6_ifstatmax = 0; unsigned long in6_maxmtu = 0; int found_first_ifid = 0; #define IFID_LEN 8 -static char first_ifid[IFID_LEN]; +static u_int8_t first_ifid[IFID_LEN]; static int laddr_to_eui64 __P((u_int8_t *, u_int8_t *, size_t)); +static int gen_rand_eui64 __P((u_int8_t *)); static int laddr_to_eui64(dst, src, len) @@ -71,8 +84,14 @@ laddr_to_eui64(dst, src, len) u_int8_t *src; size_t len; { + static u_int8_t zero[8]; + + bzero(zero, sizeof(zero)); + switch (len) { case 6: + if (bcmp(zero, src, 6) == 0) + return EINVAL; dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; @@ -83,6 +102,8 @@ laddr_to_eui64(dst, src, len) dst[7] = src[5]; break; case 8: + if (bcmp(zero, src, 8) == 0) + return EINVAL; bcopy(src, dst, len); break; default: @@ -93,6 +114,37 @@ laddr_to_eui64(dst, src, len) } /* + * Generate a last-resort interface identifier, when the machine has no + * IEEE802/EUI64 address sources. + * The address should be random, and should not change across reboot. + */ +static int +gen_rand_eui64(dst) + u_int8_t *dst; +{ + MD5_CTX ctxt; + u_int8_t digest[16]; +#ifdef __FreeBSD__ + int hostnamelen = strlen(hostname); +#endif + + /* generate 8bytes of pseudo-random value. */ + bzero(&ctxt, sizeof(ctxt)); + MD5Init(&ctxt); + MD5Update(&ctxt, hostname, hostnamelen); + MD5Final(digest, &ctxt); + + /* assumes sizeof(digest) > sizeof(first_ifid) */ + bcopy(digest, dst, 8); + + /* make sure to set "u" bit to local, and "g" bit to individual. */ + dst[0] &= 0xfe; + dst[0] |= 0x02; /* EUI64 "local" */ + + return 0; +} + +/* * Find first ifid on list of interfaces. * This is assumed that ifp0's interface token (for example, IEEE802 MAC) * is globally unique. We may need to have a flag parameter in the future. @@ -110,12 +162,22 @@ in6_ifattach_getifid(ifp0) if (found_first_ifid) return 0; - for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) { +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifp = ifnet; ifp; ifp = ifp->if_next) +#else + for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) +#endif + { if (ifp0 != NULL && ifp0 != ifp) continue; +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#else for (ifa = ifp->if_addrlist.tqh_first; ifa; - ifa = ifa->ifa_list.tqe_next) { + ifa = ifa->ifa_list.tqe_next) +#endif + { if (ifa->ifa_addr->sa_family != AF_LINK) continue; sdl = (struct sockaddr_dl *)ifa->ifa_addr; @@ -140,7 +202,7 @@ in6_ifattach_getifid(ifp0) case IFT_ARCNET: /* * ARCnet interface token cannot be used as - * globally unique identifier due to its + * globally unique identifier due to its * small bitwidth. */ break; @@ -161,11 +223,11 @@ found: if (found_first_ifid) { printf("%s: supplying EUI64: " "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - ifp->if_xname, - first_ifid[0] & 0xff, first_ifid[1] & 0xff, - first_ifid[2] & 0xff, first_ifid[3] & 0xff, - first_ifid[4] & 0xff, first_ifid[5] & 0xff, - first_ifid[6] & 0xff, first_ifid[7] & 0xff); + if_name(ifp), + first_ifid[0], first_ifid[1], + first_ifid[2], first_ifid[3], + first_ifid[4], first_ifid[5], + first_ifid[6], first_ifid[7]); /* invert u bit to convert EUI64 to RFC2373 interface ID. */ first_ifid[0] ^= 0x02; @@ -179,42 +241,6 @@ found: } } -/* - * add link-local address to *pseudo* p2p interfaces. - * get called when the first MAC address is made available in in6_ifattach(). - * - * XXX I start feeling this as a bad idea. (itojun) - */ -void -in6_ifattach_p2p() -{ - struct ifnet *ifp; - - /* prevent infinite loop. just in case. */ - if (found_first_ifid == 0) - return; - - for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) { - switch (ifp->if_type) { - case IFT_GIF: - /* pseudo interfaces - safe to initialize here */ - in6_ifattach(ifp, IN6_IFT_P2P, 0, 0); - break; - case IFT_FAITH: - /* this mistakingly becomes IFF_UP */ - break; - case IFT_SLIP: - /* IPv6 is not supported */ - break; - case IFT_PPP: - /* this is not a pseudo interface, skip it */ - break; - default: - break; - } - } -} - void in6_ifattach(ifp, type, laddr, noloop) struct ifnet *ifp; @@ -228,6 +254,9 @@ in6_ifattach(ifp, type, laddr, noloop) struct sockaddr_in6 mltmask; struct sockaddr_in6 gate; struct sockaddr_in6 mask; +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + struct ifaddr **ifap; +#endif struct in6_ifaddr *ia, *ib, *oia; struct ifaddr *ifa; @@ -235,22 +264,44 @@ in6_ifattach(ifp, type, laddr, noloop) if (type == IN6_IFT_P2P && found_first_ifid == 0) { printf("%s: no ifid available for IPv6 link-local address\n", - ifp->if_xname); + if_name(ifp)); +#if 0 return; +#else + /* last resort */ + if (gen_rand_eui64(first_ifid) == 0) { + printf("%s: using random value as EUI64: " + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + if_name(ifp), + first_ifid[0], first_ifid[1], + first_ifid[2], first_ifid[3], + first_ifid[4], first_ifid[5], + first_ifid[6], first_ifid[7]); + /* + * invert u bit to convert EUI64 to RFC2373 interface + * ID. + */ + first_ifid[0] ^= 0x02; + + found_first_ifid = 1; + } +#endif } if ((ifp->if_flags & IFF_MULTICAST) == 0) { printf("%s: not multicast capable, IPv6 not enabled\n", - ifp->if_xname); + if_name(ifp)); return; } - + /* * We have some arrays that should be indexed by if_index. * since if_index will grow dynamically, they should grow too. - * struct in6_addr **in6_iflladdr + * struct in6_ifstat **in6_ifstat + * struct icmp6_ifstat **icmp6_ifstat */ - if (in6_iflladdr == NULL || if_index >= if_indexlim) { + if (in6_ifstat == NULL || icmp6_ifstat == NULL + || if_index >= if_indexlim) { size_t n; caddr_t q; size_t olim; @@ -259,16 +310,29 @@ in6_ifattach(ifp, type, laddr, noloop) while (if_index >= if_indexlim) if_indexlim <<= 1; - /* grow in6_iflladdr */ - n = if_indexlim * sizeof(struct in6_addr *); + /* grow in6_ifstat */ + n = if_indexlim * sizeof(struct in6_ifstat *); + q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK); + bzero(q, n); + if (in6_ifstat) { + bcopy((caddr_t)in6_ifstat, q, + olim * sizeof(struct in6_ifstat *)); + free((caddr_t)in6_ifstat, M_IFADDR); + } + in6_ifstat = (struct in6_ifstat **)q; + in6_ifstatmax = if_indexlim; + + /* grow icmp6_ifstat */ + n = if_indexlim * sizeof(struct icmp6_ifstat *); q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK); bzero(q, n); - if (in6_iflladdr) { - bcopy((caddr_t)in6_iflladdr, q, - olim * sizeof(struct in6_addr *)); - free((caddr_t)in6_iflladdr, M_IFADDR); + if (icmp6_ifstat) { + bcopy((caddr_t)icmp6_ifstat, q, + olim * sizeof(struct icmp6_ifstat *)); + free((caddr_t)icmp6_ifstat, M_IFADDR); } - in6_iflladdr = (struct in6_addr **)q; + icmp6_ifstat = (struct icmp6_ifstat **)q; + icmp6_ifstatmax = if_indexlim; } /* @@ -276,6 +340,19 @@ in6_ifattach(ifp, type, laddr, noloop) * cards multiple times. * This is lengthy for P2P and LOOP but works. */ +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + ifa = ifp->if_addrlist; + if (ifa != NULL) { + for ( ; ifa; ifa = ifa->ifa_next) { + ifap = &ifa->ifa_next; + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr)) + return; + } + } else + ifap = &ifp->if_addrlist; +#else ifa = TAILQ_FIRST(&ifp->if_addrlist); if (ifa != NULL) { for ( ; ifa; ifa = TAILQ_NEXT(ifa, ifa_list)) { @@ -287,6 +364,7 @@ in6_ifattach(ifp, type, laddr, noloop) } else { TAILQ_INIT(&ifp->if_addrlist); } +#endif /* * link-local address @@ -297,7 +375,11 @@ in6_ifattach(ifp, type, laddr, noloop) ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; ia->ia_ifp = ifp; +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + *ifap = (struct ifaddr *)ia; +#else TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); +#endif /* * Also link into the IPv6 address chain beginning with in6_ifaddr. * kazu opposed it, but itojun & jinmei wanted. @@ -340,15 +422,19 @@ in6_ifattach(ifp, type, laddr, noloop) } /* invert u bit to convert EUI64 to RFC2373 interface ID. */ ia->ia_addr.sin6_addr.s6_addr8[8] ^= 0x02; - if (found_first_ifid == 0) { - if (in6_ifattach_getifid(ifp) == 0) - in6_ifattach_p2p(); - } + if (found_first_ifid == 0) + in6_ifattach_getifid(ifp); + bzero(&ia->ia_dstaddr, sizeof(struct sockaddr_in6)); + ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6); + ia->ia_dstaddr.sin6_family = AF_INET6; break; case IN6_IFT_P2P: bcopy((caddr_t)first_ifid, (caddr_t)&ia->ia_addr.sin6_addr.s6_addr8[8], IFID_LEN); + bzero(&ia->ia_dstaddr, sizeof(struct sockaddr_in6)); + ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6); + ia->ia_dstaddr.sin6_family = AF_INET6; break; case IN6_IFT_ARCNET: ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; @@ -380,16 +466,20 @@ in6_ifattach(ifp, type, laddr, noloop) switch (error) { case EAFNOSUPPORT: printf("%s: IPv6 not supported\n", - ifp->if_xname); + if_name(ifp)); break; default: printf("%s: SIOCSIFADDR error %d\n", - ifp->if_xname, error); + if_name(ifp), error); break; } /* undo changes */ +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + *ifap = NULL; +#else TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); +#endif if (oia) oia->ia_next = ia->ia_next; else @@ -442,8 +532,12 @@ in6_ifattach(ifp, type, laddr, noloop) ib->ia_ifp = ifp; ia->ia_next = ib; +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + ia->ia_ifa.ifa_next = (struct ifaddr *)ib; +#else TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ib, ifa_list); +#endif ib->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6); ib->ia_prefixmask.sin6_family = AF_INET6; @@ -461,7 +555,7 @@ in6_ifattach(ifp, type, laddr, noloop) ib->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6); ib->ia_dstaddr.sin6_family = AF_INET6; ib->ia_dstaddr.sin6_addr = in6addr_loopback; -#endif /* __bsdi__ */ +#endif ib->ia_ifa.ifa_metric = ifp->if_metric; @@ -535,10 +629,20 @@ in6_ifattach(ifp, type, laddr, noloop) } /* update dynamically. */ - in6_iflladdr[ifp->if_index] = &ia->ia_addr.sin6_addr; if (in6_maxmtu < ifp->if_mtu) in6_maxmtu = ifp->if_mtu; + if (in6_ifstat[ifp->if_index] == NULL) { + in6_ifstat[ifp->if_index] = (struct in6_ifstat *) + malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK); + bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat)); + } + if (icmp6_ifstat[ifp->if_index] == NULL) { + icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *) + malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK); + bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat)); + } + /* initialize NDP variables */ nd6_ifattach(ifp); @@ -555,7 +659,7 @@ in6_ifattach(ifp, type, laddr, noloop) ia->ia6_flags |= IN6_IFF_TENTATIVE; /* nd6_dad_start() will be called in in6_if_up */ break; - case IFT_GIF: + case IFT_GIF: /*XXX*/ case IFT_LOOP: case IFT_FAITH: default: @@ -571,12 +675,23 @@ in6_ifdetach(ifp) { struct in6_ifaddr *ia, *oia; struct ifaddr *ifa; +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + struct ifaddr *ifaprev = NULL; +#endif struct rtentry *rt; short rtflags; - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#else + for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) +#endif + { if (ifa->ifa_addr->sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) { +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + ifaprev = ifa; +#endif continue; } @@ -584,7 +699,11 @@ in6_ifdetach(ifp) /* remove from the routing table */ if ((ia->ia_flags & IFA_ROUTE) - && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) { + && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0 +#ifdef __FreeBSD__ + , 0UL +#endif + ))) { rtflags = rt->rt_flags; rtfree(rt); rtrequest(RTM_DELETE, @@ -595,7 +714,14 @@ in6_ifdetach(ifp) } /* remove from the linked list */ +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + if (ifaprev) + ifaprev->ifa_next = ifa->ifa_next; + else + ifp->if_addrlist = ifa->ifa_next; +#else TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); +#endif /* also remove from the IPv6 address chain(itojun&jinmei) */ oia = ia; @@ -609,7 +735,7 @@ in6_ifdetach(ifp) #ifdef DEBUG else printf("%s: didn't unlink in6ifaddr from " - "list\n", ifp->if_xname); + "list\n", if_name(ifp)); #endif } diff --git a/sys/netinet6/in6_ifattach.h b/sys/netinet6/in6_ifattach.h index 04b9edde676..60b947deff2 100644 --- a/sys/netinet6/in6_ifattach.h +++ b/sys/netinet6/in6_ifattach.h @@ -1,4 +1,4 @@ -/* $NetBSD: in6_ifattach.h,v 1.4 1999/09/19 21:31:34 is Exp $ */ +/* $NetBSD: in6_ifattach.h,v 1.5 1999/12/13 15:17:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -33,7 +33,6 @@ #define _NETINET6_IN6_IFATTACH_H_ #ifdef _KERNEL -extern struct in6_addr **in6_iflladdr; extern int found_first_ifid; int in6_ifattach_getifid __P((struct ifnet *)); diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index f4a4188f725..25c29c6a0a7 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -1,4 +1,4 @@ -/* $NetBSD: in6_pcb.c,v 1.9 1999/07/31 18:41:16 itojun Exp $ */ +/* $NetBSD: in6_pcb.c,v 1.10 1999/12/13 15:17:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -93,7 +93,9 @@ #include <netinet6/ip6_var.h> #include <netinet6/nd6.h> +#ifndef __bsdi__ #include "loop.h" +#endif #ifdef __NetBSD__ extern struct ifnet loif[NLOOP]; #endif @@ -147,7 +149,7 @@ in6_pcbbind(in6p, nam) int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); int error; - if (in6p->in6p_lport || !IN6_IS_ADDR_ANY(&in6p->in6p_laddr)) + if (in6p->in6p_lport || !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) return(EINVAL); if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || @@ -216,11 +218,16 @@ in6_pcbbind(in6p, nam) sizeof(sin.sin_addr)); if (ifa_ifwithaddr((struct sockaddr *)&sin) == 0) return EADDRNOTAVAIL; - } else if (!IN6_IS_ADDR_ANY(&sin6->sin6_addr)) { + } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { struct ifaddr *ia = NULL; sin6->sin6_port = 0; /* yech... */ +#if defined(NFAITH) && NFAITH > 0 + if ((in6p->in6p_flags & IN6P_FAITH) == 0 + && (ia = ifa_ifwithaddr((struct sockaddr *)sin6)) == 0) +#else if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6)) == 0) +#endif return(EADDRNOTAVAIL); /* @@ -262,47 +269,74 @@ in6_pcbbind(in6p, nam) } in6p->in6p_laddr = sin6->sin6_addr; } + if (lport == 0) { - u_short last_port; - void *t; + int e; + if ((e = in6_pcbsetport(&in6p->in6p_laddr, in6p)) != 0) + return(e); + } + else + in6p->in6p_lport = lport; - /* XXX IN6P_LOWPORT */ + in6p->in6p_flowinfo = sin6 ? sin6->sin6_flowinfo : 0; /*XXX*/ + return(0); +} - /* value out of range */ - if (head->in6p_lport < IPV6PORT_ANONMIN) - head->in6p_lport = IPV6PORT_ANONMIN; - else if (head->in6p_lport > IPV6PORT_ANONMAX) - head->in6p_lport = IPV6PORT_ANONMIN; - last_port = head->in6p_lport; - goto startover; /*to randomize*/ - for (;;) { - lport = htons(head->in6p_lport); - if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)) { +/* + * Find an empty port and set it to the specified PCB. + * XXX IN6P_LOWPORT + */ +int +in6_pcbsetport(laddr, in6p) + struct in6_addr *laddr; + struct in6pcb *in6p; +{ + struct socket *so = in6p->in6p_socket; + struct in6pcb *head = in6p->in6p_head; + u_short last_port, lport = 0; + int wild = 0; + void *t; + + /* XXX: this is redundant when called from in6_pcbbind */ + if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && + ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || + (so->so_options & SO_ACCEPTCONN) == 0)) + wild = IN6PLOOKUP_WILDCARD; + + /* value out of range */ + if (head->in6p_lport < IPV6PORT_ANONMIN) + head->in6p_lport = IPV6PORT_ANONMIN; + else if (head->in6p_lport > IPV6PORT_ANONMAX) + head->in6p_lport = IPV6PORT_ANONMIN; + last_port = head->in6p_lport; + goto startover; /*to randomize*/ + for (;;) { + lport = htons(head->in6p_lport); + if (IN6_IS_ADDR_V4MAPPED(laddr)) { #if 0 - t = in_pcblookup_bind(&tcbtable, - (struct in_addr *)&in6p->in6p_laddr.s6_addr32[3], - lport); + t = in_pcblookup_bind(&tcbtable, + (struct in_addr *)&in6p->in6p_laddr.s6_addr32[3], + lport); #else - t = NULL; + t = NULL; #endif - } else { - t = in6_pcblookup(head, &zeroin6_addr, 0, - &in6p->in6p_laddr, lport, wild); - } - if (t == 0) - break; -startover: - if (head->in6p_lport >= IPV6PORT_ANONMAX) - head->in6p_lport = IPV6PORT_ANONMIN; - else - head->in6p_lport++; - if (head->in6p_lport == last_port) - return (EADDRINUSE); + } else { + t = in6_pcblookup(head, &zeroin6_addr, 0, laddr, + lport, wild); } + if (t == 0) + break; + startover: + if (head->in6p_lport >= IPV6PORT_ANONMAX) + head->in6p_lport = IPV6PORT_ANONMIN; + else + head->in6p_lport++; + if (head->in6p_lport == last_port) + return (EADDRINUSE); } + in6p->in6p_lport = lport; - in6p->in6p_flowinfo = sin6 ? sin6->sin6_flowinfo : 0; /*XXX*/ - return(0); + return(0); /* success */ } /* @@ -395,10 +429,16 @@ in6_pcbconnect(in6p, nam) mapped.s6_addr16[5] = htons(0xffff); bcopy(&sinp->sin_addr, &mapped.s6_addr32[3], sizeof(sinp->sin_addr)); in6a = &mapped; - } else if (IN6_IS_ADDR_ANY(&in6p->in6p_laddr)) { + } else { + /* + * XXX: in6_selectsrc might replace the bound local address + * with the address specified by setsockopt(IPV6_PKTINFO). + * Is it the intended behavior? + */ in6a = in6_selectsrc(sin6, in6p->in6p_outputopts, - in6p->in6p_moptions, &in6p->in6p_route, - &error); + in6p->in6p_moptions, + &in6p->in6p_route, + &in6p->in6p_laddr, &error); if (in6a == 0) { if (error == 0) error = EADDRNOTAVAIL; @@ -408,29 +448,17 @@ in6_pcbconnect(in6p, nam) if (in6p->in6p_route.ro_rt) ifp = in6p->in6p_route.ro_rt->rt_ifp; - /* - * Default hop limit selection. If a hoplimit was specified via ioctl, - * use it. Else if the outgoing interface is detected and the current - * hop limit of the interface was specified by router advertisement, - * use the value. - * Otherwise, use the system default hoplimit. - */ - if (in6p->in6p_hops >= 0) - in6p->in6p_ip6.ip6_hlim = (u_int8_t)in6p->in6p_hops; - else if (ifp) - in6p->in6p_ip6.ip6_hlim = nd_ifinfo[ifp->if_index].chlim; - else - in6p->in6p_ip6.ip6_hlim = ip6_defhlim; + in6p->in6p_ip6.ip6_hlim = (u_int8_t)in6_selecthlim(in6p, ifp); if (in6_pcblookup(in6p->in6p_head, &sin6->sin6_addr, sin6->sin6_port, - IN6_IS_ADDR_ANY(&in6p->in6p_laddr) ? + IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) ? in6a : &in6p->in6p_laddr, in6p->in6p_lport, 0)) return(EADDRINUSE); - if (IN6_IS_ADDR_ANY(&in6p->in6p_laddr) + if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) || (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr) && in6p->in6p_laddr.s6_addr32[3] == 0)) { if (in6p->in6p_lport == 0) @@ -454,16 +482,17 @@ in6_pcbconnect(in6p, nam) * an entry to the caller for later use. */ struct in6_addr * -in6_selectsrc(dstsock, opts, mopts, ro, errorp) +in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp) struct sockaddr_in6 *dstsock; struct ip6_pktopts *opts; struct ip6_moptions *mopts; struct route_in6 *ro; + struct in6_addr *laddr; int *errorp; { struct in6_addr *dst; struct in6_ifaddr *ia6 = 0; - struct in6_pktinfo *pi; + struct in6_pktinfo *pi = NULL; dst = &dstsock->sin6_addr; *errorp = 0; @@ -471,23 +500,61 @@ in6_selectsrc(dstsock, opts, mopts, ro, errorp) /* * If the source address is explicitly specified by the caller, * use it. + */ + if (opts && (pi = opts->ip6po_pktinfo) && + !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) + return(&pi->ipi6_addr); + + /* + * If the source address is not specified but the socket(if any) + * is already bound, use the bound address. + */ + if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr)) + return(laddr); + + /* * If the caller doesn't specify the source address but * the outgoing interface, use an address associated with * the interface. */ - if (opts && (pi = opts->ip6po_pktinfo)) { - if (!IN6_IS_ADDR_ANY(&pi->ipi6_addr)) - return(&pi->ipi6_addr); - else if (pi->ipi6_ifindex) { - /* XXX boundary check is assumed to be already done. */ - ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex], - dst); - if (ia6 == 0) { - *errorp = EADDRNOTAVAIL; - return(0); - } - return(&satosin6(&ia6->ia_addr)->sin6_addr); + if (pi && pi->ipi6_ifindex) { + /* XXX boundary check is assumed to be already done. */ + ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex], + dst); + if (ia6 == 0) { + *errorp = EADDRNOTAVAIL; + return(0); + } + return(&satosin6(&ia6->ia_addr)->sin6_addr); + } + + /* + * If the destination address is a link-local unicast address or + * a multicast address, and if the outgoing interface is specified + * by the sin6_scope_id filed, use an address associated with the + * interface. + * XXX: We're now trying to define more specific semantics of + * sin6_scope_id field, so this part will be rewritten in + * the near future. + */ + if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MULTICAST(dst)) && + dstsock->sin6_scope_id) { + /* + * I'm not sure if boundary check for scope_id is done + * somewhere... + */ + if (dstsock->sin6_scope_id < 0 || + if_index < dstsock->sin6_scope_id) { + *errorp = ENXIO; /* XXX: better error? */ + return(0); + } + ia6 = in6_ifawithscope(ifindex2ifnet[dstsock->sin6_scope_id], + dst); + if (ia6 == 0) { + *errorp = EADDRNOTAVAIL; + return(0); } + return(&satosin6(&ia6->ia_addr)->sin6_addr); } /* @@ -524,10 +591,6 @@ in6_selectsrc(dstsock, opts, mopts, ro, errorp) } /* - * XXX How should we use sin6_scope_id??? - */ - - /* * If the next hop address for the packet is specified * by caller, use an address associated with the route * to the next hop. @@ -578,13 +641,8 @@ in6_selectsrc(dstsock, opts, mopts, ro, errorp) ro->ro_rt = rtalloc1(&((struct route *)ro) ->ro_dst, 0); #endif /*__bsdi__*/ - } else { -#if 0 /* XXX Is this correct? */ - rtcalloc((struct route *)ro); -#else + } else rtalloc((struct route *)ro); -#endif - } } /* @@ -629,6 +687,26 @@ in6_selectsrc(dstsock, opts, mopts, ro, errorp) return(0); } +/* + * Default hop limit selection. The precedence is as follows: + * 1. Hoplimit valued specified via ioctl. + * 2. (If the outgoing interface is detected) the current + * hop limit of the interface specified by router advertisement. + * 3. The system default hoplimit. +*/ +int +in6_selecthlim(in6p, ifp) + struct in6pcb *in6p; + struct ifnet *ifp; +{ + if (in6p && in6p->in6p_hops >= 0) + return(in6p->in6p_hops); + else if (ifp) + return(nd_ifinfo[ifp->if_index].chlim); + else + return(ip6_defhlim); +} + void in6_pcbdisconnect(in6p) struct in6pcb *in6p; @@ -748,7 +826,7 @@ in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify) if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6) return 0; faddr6 = ((struct sockaddr_in6 *)dst)->sin6_addr; - if (IN6_IS_ADDR_ANY(&faddr6)) + if (IN6_IS_ADDR_UNSPECIFIED(&faddr6)) return 0; /* @@ -772,7 +850,7 @@ in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify) if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,&faddr6) || in6p->in6p_socket == 0 || (lport && in6p->in6p_lport != lport) || - (!IN6_IS_ADDR_ANY(laddr6) && + (!IN6_IS_ADDR_UNSPECIFIED(laddr6) && !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6)) || (fport && in6p->in6p_fport != fport)) { in6p = in6p->in6p_next; @@ -854,23 +932,23 @@ in6_pcblookup(head, faddr6, fport_arg, laddr6, lport_arg, flags) if (in6p->in6p_lport != lport) continue; wildcard = 0; - if (!IN6_IS_ADDR_ANY(&in6p->in6p_laddr)) { - if (IN6_IS_ADDR_ANY(laddr6)) + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { + if (IN6_IS_ADDR_UNSPECIFIED(laddr6)) wildcard++; else if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6)) continue; } else { - if (!IN6_IS_ADDR_ANY(laddr6)) + if (!IN6_IS_ADDR_UNSPECIFIED(laddr6)) wildcard++; } - if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) { - if (IN6_IS_ADDR_ANY(faddr6)) + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { + if (IN6_IS_ADDR_UNSPECIFIED(faddr6)) wildcard++; else if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, faddr6) || in6p->in6p_fport != fport) continue; } else { - if (!IN6_IS_ADDR_ANY(faddr6)) + if (!IN6_IS_ADDR_UNSPECIFIED(faddr6)) wildcard++; } if (wildcard && (flags & IN6PLOOKUP_WILDCARD) == 0) diff --git a/sys/netinet6/in6_pcb.h b/sys/netinet6/in6_pcb.h index 98ba7b4728a..287c5e3771d 100644 --- a/sys/netinet6/in6_pcb.h +++ b/sys/netinet6/in6_pcb.h @@ -1,4 +1,4 @@ -/* $NetBSD: in6_pcb.h,v 1.5 1999/07/22 03:59:42 itojun Exp $ */ +/* $NetBSD: in6_pcb.h,v 1.6 1999/12/13 15:17:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -68,9 +68,6 @@ #define _NETINET6_IN6_PCB_H_ #include <sys/queue.h> -#if 1 /*IPSEC*/ -#include <netinet6/ipsec.h> -#endif /* * Common structure pcb for internet protocol implementation. @@ -158,12 +155,16 @@ struct in6pcb * int in6_pcbnotify __P((struct in6pcb *, struct sockaddr *, u_int, struct in6_addr *, u_int, int, void (*)(struct in6pcb *, int))); +int in6_pcbsetport __P((struct in6_addr *, struct in6pcb *)); void in6_rtchange __P((struct in6pcb *, int)); void in6_setpeeraddr __P((struct in6pcb *, struct mbuf *)); void in6_setsockaddr __P((struct in6pcb *, struct mbuf *)); struct in6_addr *in6_selectsrc __P((struct sockaddr_in6 *, - struct ip6_pktopts *, struct ip6_moptions *, - struct route_in6 *, int *)); + struct ip6_pktopts *, + struct ip6_moptions *, + struct route_in6 *, + struct in6_addr *, int *)); +int in6_selecthlim __P((struct in6pcb *, struct ifnet *)); #ifndef TCP6 extern struct rtentry * diff --git a/sys/netinet6/in6_prefix.c b/sys/netinet6/in6_prefix.c index 3d6c0bdc06d..24eb4ac4785 100644 --- a/sys/netinet6/in6_prefix.c +++ b/sys/netinet6/in6_prefix.c @@ -1,4 +1,4 @@ -/* $NetBSD: in6_prefix.c,v 1.3 1999/07/03 21:30:18 thorpej Exp $ */ +/* $NetBSD: in6_prefix.c,v 1.4 1999/12/13 15:17:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -65,22 +65,41 @@ */ #include <sys/param.h> -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) #include <sys/ioctl.h> #endif #include <sys/malloc.h> +#include <sys/kernel.h> #include <sys/socket.h> +#include <sys/socketvar.h> #include <sys/sockio.h> #include <sys/systm.h> #include <sys/syslog.h> +#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) +#include <sys/proc.h> +#endif #include <net/if.h> #include <netinet/in.h> #include <netinet/in_var.h> -#include <netinet6/nd6.h> +#include <netinet6/ip6.h> +#include <netinet6/in6_prefix.h> +#include <netinet6/ip6_var.h> + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +static MALLOC_DEFINE(M_IP6RR, "ip6rr", "IPv6 Router Renumbering Prefix"); +static MALLOC_DEFINE(M_RR_ADDR, "rp_addr", "IPv6 Router Renumbering Ifid"); +#endif + +struct rr_prhead rr_prefix; + +#include <net/net_osdep.h> -extern int in6_interfaces; +static int create_ra_entry __P((struct rp_addr **rapp)); +static int add_each_prefix __P((struct socket *so, struct rr_prefix *rpp)); +static void free_rp_entries __P((struct rr_prefix *rpp)); +static int link_stray_ia6s __P((struct rr_prefix *rpp)); /* * Copy bits from src to tgt, from off bit for len bits. @@ -132,56 +151,76 @@ bit_copy(char *tgt, u_int tgtsize, char *src, u_int srcsize, } } +static struct ifprefix * +in6_prefixwithifp(struct ifnet *ifp, int plen, struct in6_addr *dst) +{ + struct ifprefix *ifpr; + + /* search matched prefix */ + for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { + if (ifpr->ifpr_prefix->sa_family != AF_INET6 || + ifpr->ifpr_type != IN6_PREFIX_RR) + continue; + if (plen <= in6_matchlen(dst, IFPR_IN6(ifpr))) + break; + } + return (ifpr); +} + /* * Search prefix which matches arg prefix as specified in * draft-ietf-ipngwg-router-renum-08.txt */ -static struct nd_prefix * +static struct rr_prefix * search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr) { struct ifprefix *ifpr; + struct ifaddr *ifa; + struct rr_prefix *rpp; /* search matched prefix */ - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { - if (ifpr->ifpr_prefix->sa_family != AF_INET6) - continue; - if (ipr->ipr_plen <= in6_matchlen(&ipr->ipr_prefix.sin6_addr, - &IFPR_IN6(ifpr))) - break; - } + ifpr = in6_prefixwithifp(ifp, ipr->ipr_plen, + &ipr->ipr_prefix.sin6_addr); + if (ifpr != NULL) + return ifpr2rp(ifpr); + /* * search matched addr, and then search prefix * which matches the addr */ - if (ifpr == 0) { - struct ifaddr *ifa; -#ifndef __NetBSD__ - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) #else - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) + for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) #endif - { - if (ifa->ifa_addr->sa_family != AF_INET6) - continue; - if (ipr->ipr_plen <= - in6_matchlen(&ipr->ipr_prefix.sin6_addr, - &IFA_IN6(ifa))) - break; - } - if (ifa) { - for (ifpr = ifp->if_prefixlist; ifpr; - ifpr = ifpr->ifpr_next) { - if (ifpr->ifpr_prefix->sa_family != AF_INET6) - continue; - if (ifpr->ifpr_plen <= - in6_matchlen(&IFA_IN6(ifa), - &IFPR_IN6(ifpr))) - break; - } - } + { + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + if (ipr->ipr_plen <= + in6_matchlen(&ipr->ipr_prefix.sin6_addr, IFA_IN6(ifa))) + break; + } + if (ifa == NULL) + return NULL; + + rpp = ifpr2rp(((struct in6_ifaddr *)ifa)->ia6_ifpr); + if (rpp != 0) + return rpp; + + for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { + if (ifpr->ifpr_prefix->sa_family != AF_INET6 || + ifpr->ifpr_type != IN6_PREFIX_RR) + continue; + if (ifpr->ifpr_plen <= in6_matchlen(IFA_IN6(ifa), + IFPR_IN6(ifpr))) + break; } - return ifpr2ndpr(ifpr); + if (ifpr != NULL) + log(LOG_ERR, "in6_prefix.c: search_matched_prefix: addr %s" + "has no pointer to prefix %s", ip6_sprintf(IFA_IN6(ifa)), + ip6_sprintf(IFPR_IN6(ifpr))); + return ifpr2rp(ifpr); } /* @@ -198,55 +237,57 @@ mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr) /* search matched prefixes */ for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { - if (ifpr->ifpr_prefix->sa_family != AF_INET6) + if (ifpr->ifpr_prefix->sa_family != AF_INET6 || + ifpr->ifpr_type != IN6_PREFIX_RR) continue; matchlen = in6_matchlen(&irr->irr_matchprefix.sin6_addr, - &IFPR_IN6(ifpr)); + IFPR_IN6(ifpr)); if (irr->irr_m_minlen > ifpr->ifpr_plen || irr->irr_m_maxlen < ifpr->ifpr_plen || irr->irr_m_len > matchlen) continue; matched = 1; - ifpr2ndpr(ifpr)->ndpr_statef_addmark = 1; + ifpr2rp(ifpr)->rp_statef_addmark = 1; if (cmd == SIOCCIFPREFIX_IN6) - ifpr2ndpr(ifpr)->ndpr_statef_delmark = 1; + ifpr2rp(ifpr)->rp_statef_delmark = 1; } /* * search matched addr, and then search prefixes * which matche the addr */ -#ifndef __NetBSD__ +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) #else for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) #endif { + struct rr_prefix *rpp; + if (ifa->ifa_addr->sa_family != AF_INET6) continue; matchlen = in6_matchlen(&irr->irr_matchprefix.sin6_addr, - &IFA_IN6(ifa)); + IFA_IN6(ifa)); if (irr->irr_m_minlen > matchlen || irr->irr_m_maxlen < matchlen || irr->irr_m_len > matchlen) continue; - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { - if (ifpr->ifpr_prefix->sa_family != AF_INET6) - continue; - if (ifpr->ifpr_plen > in6_matchlen(&IFA_IN6(ifa), - &IFPR_IN6(ifpr))) - continue; + rpp = ifpr2rp(((struct in6_ifaddr *)ifa)->ia6_ifpr); + if (rpp != 0) { matched = 1; - ifpr2ndpr(ifpr)->ndpr_statef_addmark = 1; + rpp->rp_statef_addmark = 1; if (cmd == SIOCCIFPREFIX_IN6) - ifpr2ndpr(ifpr)->ndpr_statef_delmark = 1; - } + rpp->rp_statef_delmark = 1; + } else + log(LOG_WARNING, "in6_prefix.c: mark_matched_prefixes:" + "no back pointer to ifprefix for %s. " + "ND autoconfigured addr?", + ip6_sprintf(IFA_IN6(ifa))); } return matched; } /* * Mark global prefixes as to be deleted. - * Return 1 if anything matched, and 0 if nothing matched. */ static void delmark_global_prefixes(struct ifnet *ifp, struct in6_rrenumreq *irr) @@ -255,12 +296,13 @@ delmark_global_prefixes(struct ifnet *ifp, struct in6_rrenumreq *irr) /* search matched prefixes */ for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { - if (ifpr->ifpr_prefix->sa_family != AF_INET6) - continue; + if (ifpr->ifpr_prefix->sa_family != AF_INET6 || + ifpr->ifpr_type != IN6_PREFIX_RR) + continue; /* mark delete global prefix */ - if (in6_addrscope(&irr->irr_matchprefix.sin6_addr) == + if (in6_addrscope(RP_IN6(ifpr2rp(ifpr))) == IPV6_ADDR_SCOPE_GLOBAL) - ifpr2ndpr(ifpr)->ndpr_statef_delmark = 1; + ifpr2rp(ifpr)->rp_statef_delmark = 1; } } @@ -272,115 +314,694 @@ unmark_prefixes(struct ifnet *ifp) /* unmark all prefix */ for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { - if (ifpr->ifpr_prefix->sa_family != AF_INET6) + if (ifpr->ifpr_prefix->sa_family != AF_INET6 || + ifpr->ifpr_type != IN6_PREFIX_RR) continue; /* unmark prefix */ - ifpr2ndpr(ifpr)->ndpr_statef_addmark = 0; - ifpr2ndpr(ifpr)->ndpr_statef_delmark = 0; + ifpr2rp(ifpr)->rp_statef_addmark = 0; + ifpr2rp(ifpr)->rp_statef_delmark = 0; + } +} + +static void +init_prefix_ltimes(struct rr_prefix *rpp) +{ +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) + long time_second = time.tv_sec; +#endif + + if (rpp->rp_pltime == RR_INFINITE_LIFETIME || + rpp->rp_rrf_decrprefd == 0) + rpp->rp_preferred = 0; + else + rpp->rp_preferred = time_second + rpp->rp_pltime; + if (rpp->rp_vltime == RR_INFINITE_LIFETIME || + rpp->rp_rrf_decrvalid == 0) + rpp->rp_expire = 0; + else + rpp->rp_expire = time_second + rpp->rp_vltime; +} + +static int +rr_are_ifid_equal(struct in6_addr *ii1, struct in6_addr *ii2, int ii_len) +{ + int ii_bytelen, ii_bitlen; + int p_bytelen, p_bitlen; + + /* sanity check */ + if (1 > ii_len || + ii_len > 124) { /* as RFC2373, prefix is at least 4 bit */ + log(LOG_ERR, "rr_are_ifid_equal: invalid ifid length(%d)\n", + ii_len); + return(0); } + + ii_bytelen = ii_len / 8; + ii_bitlen = ii_len % 8; + + p_bytelen = sizeof(struct in6_addr) - ii_bytelen - 1; + p_bitlen = 8 - ii_bitlen; + + if (bcmp(ii1->s6_addr + p_bytelen + 1, ii2->s6_addr + p_bytelen + 1, + ii_bytelen)) + return(0); + if (((ii1->s6_addr[p_bytelen] << p_bitlen) & 0xff) != + ((ii2->s6_addr[p_bytelen] << p_bitlen) & 0xff)) + return(0); + + return(1); +} + +static struct rp_addr * +search_ifidwithprefix(struct rr_prefix *rpp, struct in6_addr *ifid) +{ + struct rp_addr *rap; + + for (rap = rpp->rp_addrhead.lh_first; rap != NULL; + rap = rap->ra_entry.le_next) + if (rr_are_ifid_equal(ifid, &rap->ra_ifid, + (sizeof(struct in6_addr) << 3) - + rpp->rp_plen)) + break; + return rap; } static int -add_each_prefix(struct nd_prefix *ndpr) +assigne_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia) { int error = 0; + struct rp_addr *rap; + int s; - if ((error = in6_init_prefix_ltimes(ndpr)) != 0) + if ((error = create_ra_entry(&rap)) != 0) return error; - if ((error = prelist_update(ndpr, 0, NULL)) != 0) - return error; - if ((ndpr->ndpr_ifp->if_flags & IFF_LOOPBACK) == 0) - in6_interfaces++; /*XXX*/ - return error; + /* copy interface id part */ + bit_copy((caddr_t)&rap->ra_ifid, sizeof(rap->ra_ifid) << 3, + (caddr_t)IA6_IN6(ia), + sizeof(*IA6_IN6(ia)) << 3, rpp->rp_plen, iilen); + /* link to ia, and put into list */ + rap->ra_addr = ia; +#if 0 /* Can't do this now, because rpp may be on th stack. should fix it? */ + ia->ia6_ifpr = rp2ifpr(rpp); +#endif + s = splnet(); + LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry); + splx(s); + + return 0; +} + +int +in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia) +{ + int plen = (sizeof(*IA6_IN6(ia)) << 3) - iilen; + struct ifprefix *ifpr; + struct rp_addr *rap; + int error = 0; + + ifpr = in6_prefixwithifp(ia->ia_ifp, plen, IA6_IN6(ia)); + if (ifpr == NULL) { + struct rr_prefix rp; + struct socket so; + int pplen = (plen == 128) ? 64 : plen; + + /* allocate a prefix for ia, with default properties */ + + /* init rp */ + bzero(&rp, sizeof(rp)); + rp.rp_type = IN6_PREFIX_RR; + rp.rp_ifp = ia->ia_ifp; + rp.rp_plen = pplen; + rp.rp_prefix.sin6_len = sizeof(rp.rp_prefix); + rp.rp_prefix.sin6_family = AF_INET6; + bit_copy((char *)RP_IN6(&rp), sizeof(*RP_IN6(&rp)) << 3, + (char *)&ia->ia_addr.sin6_addr, + sizeof(ia->ia_addr.sin6_addr) << 3, + 0, pplen); + rp.rp_vltime = rp.rp_pltime = RR_INFINITE_LIFETIME; + rp.rp_raf_onlink = 1; + rp.rp_raf_auto = 1; + /* Is some FlagMasks for rrf necessary? */ + rp.rp_rrf_decrvalid = rp.rp_rrf_decrprefd = 0; + rp.rp_origin = PR_ORIG_RR; /* can be renumbered */ + + /* create ra_entry */ + error = link_stray_ia6s(&rp); + if (error != 0) { + free_rp_entries(&rp); + return error; + } + + /* XXX: init dummy so */ + bzero(&so, sizeof(so)); +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__NetBSD__) + so.so_state |= SS_PRIV; +#endif + + error = add_each_prefix(&so, &rp); + + /* free each rp_addr entry */ + free_rp_entries(&rp); + + if (error != 0) + return error; + + /* search again */ + ifpr = in6_prefixwithifp(ia->ia_ifp, pplen, IA6_IN6(ia)); + if (ifpr == NULL) + return 0; + } + rap = search_ifidwithprefix(ifpr2rp(ifpr), IA6_IN6(ia)); + if (rap != NULL) { + if (rap->ra_addr == NULL) + rap->ra_addr = ia; + else if (rap->ra_addr != ia) { + /* There may be some inconsistencies between addrs. */ + log(LOG_ERR, "ip6_prefix.c: addr %s/%d matched prefix" + "has already another ia %p(%s) on its ifid list", + ip6_sprintf(IA6_IN6(ia)), plen, + rap->ra_addr, + ip6_sprintf(IA6_IN6(rap->ra_addr))); + return EADDRINUSE /* XXX */; + } + ia->ia6_ifpr = ifpr; + return 0; + } + error = assigne_ra_entry(ifpr2rp(ifpr), iilen, ia); + if (error == 0) + ia->ia6_ifpr = ifpr; + return (error); +} + +void +in6_prefix_remove_ifid(int iilen, struct in6_ifaddr *ia) +{ + struct rp_addr *rap; + + if (ia->ia6_ifpr == NULL) + return; + rap = search_ifidwithprefix(ifpr2rp(ia->ia6_ifpr), IA6_IN6(ia)); + if (rap != NULL) { + int s = splnet(); + LIST_REMOVE(rap, ra_entry); + splx(s); + free(rap, M_RR_ADDR); + } +} + +static void +add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap) +{ + struct in6_ifaddr *ia6; + struct in6_aliasreq ifra; + int error; + + /* init ifra */ + bzero(&ifra, sizeof(ifra)); + strncpy(ifra.ifra_name, if_name(rpp->rp_ifp), sizeof(ifra.ifra_name)); + ifra.ifra_addr.sin6_family = ifra.ifra_prefixmask.sin6_family = + AF_INET6; + ifra.ifra_addr.sin6_len = ifra.ifra_prefixmask.sin6_len = + sizeof(ifra.ifra_addr); + /* copy prefix part */ + bit_copy((char *)&ifra.ifra_addr.sin6_addr, + sizeof(ifra.ifra_addr.sin6_addr) << 3, + (char *)RP_IN6(rpp), sizeof(*RP_IN6(rpp)) << 3, + 0, rpp->rp_plen); + /* copy interface id part */ + bit_copy((char *)&ifra.ifra_addr.sin6_addr, + sizeof(ifra.ifra_addr.sin6_addr) << 3, + (char *)&rap->ra_ifid, sizeof(rap->ra_ifid) << 3, + rpp->rp_plen, (sizeof(rap->ra_ifid) << 3) - rpp->rp_plen); + in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, rpp->rp_plen); + /* don't care ifra_flags for now */ + + ia6 = in6ifa_ifpwithaddr(rpp->rp_ifp, &ifra.ifra_addr.sin6_addr); + if (ia6 != NULL) { + if (ia6->ia6_ifpr == NULL) { + /* link this addr and the prefix each other */ + rap->ra_addr = ia6; + ia6->ia6_ifpr = rp2ifpr(rpp); + return; + } + if (ia6->ia6_ifpr == rp2ifpr(rpp)) { + rap->ra_addr = ia6; + return; + } + /* + * The addr is already assigned to other + * prefix. + * There may be some inconsistencies between + * prefixes. + * e.g. overraped prefixes with common starting + * part and different plefixlen. + * Or, completely duplicated prefixes? + * log it and return. + */ + log(LOG_ERR, "in6_prefix.c: add_each_addr: addition of an addr" + "%s/%d failed because there is already another addr %s/%d", + ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen, + ip6_sprintf(IA6_IN6(ia6)), + in6_mask2len(&ia6->ia_prefixmask.sin6_addr)); + return; + } + /* propagate ANYCAST flag if it is set for ancestor addr */ + if (rap->ra_flags.anycast != 0) + ifra.ifra_flags |= IN6_IFF_ANYCAST; + error = in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, rpp->rp_ifp +#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) + , curproc +#endif + ); + if (error != 0) + log(LOG_ERR, "in6_prefix.c: add_each_addr: addition of an addr" + "%s/%d failed because in6_control failed for error %d", + ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen, + error); + return; + + /* + * link beween this addr and the prefix will be done + * in in6_prefix_add_ifid + */ +} + +static int +rrpr_update(struct socket *so, struct rr_prefix *new) +{ + struct rr_prefix *rpp; + struct ifprefix *ifpr; + struct rp_addr *rap; + int s; + + /* search existing prefix */ + for (ifpr = new->rp_ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { + if (ifpr->ifpr_prefix->sa_family != AF_INET6 || + ifpr->ifpr_type != IN6_PREFIX_RR) + continue; + if (ifpr->ifpr_plen == new->rp_plen && + in6_are_prefix_equal(IFPR_IN6(ifpr), RP_IN6(new), + ifpr->ifpr_plen)) + break; + } + rpp = ifpr2rp(ifpr); + if (rpp != NULL) { + /* + * We got a prefix which we have seen in the past. + */ + /* + * If the origin of the already-installed prefix is more + * preferable than the new one, ignore installation request. + */ + if (rpp->rp_origin > new->rp_origin) + return(EPERM); + + /* update prefix information */ + rpp->rp_flags.prf_ra = new->rp_flags.prf_ra; + if (rpp->rp_origin >= PR_ORIG_RR) + rpp->rp_flags.prf_rr = new->rp_flags.prf_rr; + rpp->rp_vltime = new->rp_vltime; + rpp->rp_pltime = new->rp_pltime; + rpp->rp_expire = new->rp_expire; + rpp->rp_preferred = new->rp_preferred; + rpp->rp_statef_delmark = 0; /* cancel deletion */ + /* + * Interface id related update. + * add rp_addr entries in new into rpp, if they have not + * been already included in rpp. + */ +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + while (!LIST_EMPTY(&new->rp_addrhead)) +#else + while (new->rp_addrhead.lh_first != NULL) +#endif + { + rap = LIST_FIRST(&new->rp_addrhead); + LIST_REMOVE(rap, ra_entry); + if (search_ifidwithprefix(rpp, &rap->ra_ifid) + != NULL) { + free(rap, M_RR_ADDR); + continue; + } + s = splnet(); + LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry); + splx(s); + } + } else { + /* + * We got a fresh prefix. + */ + /* create new prefix */ + rpp = (struct rr_prefix *)malloc(sizeof(*rpp), M_IP6RR, + M_NOWAIT); + if (rpp == NULL) { + log(LOG_ERR, "in6_prefix.c: rrpr_update:%d" + ": ENOBUFS for rr_prefix", __LINE__); + return(ENOBUFS); + } + /* initilization */ + *rpp = *new; + LIST_INIT(&rpp->rp_addrhead); + /* move rp_addr entries of new to rpp */ +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + while (!LIST_EMPTY(&new->rp_addrhead)) +#else + while (new->rp_addrhead.lh_first != NULL) +#endif + { + rap = LIST_FIRST(&new->rp_addrhead); + LIST_REMOVE(rap, ra_entry); + LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry); + } + + /* let rp_ifpr.ifpr_prefix point rr_prefix. */ + rpp->rp_ifpr.ifpr_prefix = (struct sockaddr *)&rpp->rp_prefix; + /* link rr_prefix entry to if_prefixlist */ + { + struct ifnet *ifp = rpp->rp_ifp; + struct ifprefix *ifpr; + + if ((ifpr = ifp->if_prefixlist) != NULL) { + for ( ; ifpr->ifpr_next; + ifpr = ifpr->ifpr_next) + continue; + ifpr->ifpr_next = rp2ifpr(rpp); + } + else + ifp->if_prefixlist = rp2ifpr(rpp); + rp2ifpr(rpp)->ifpr_type = IN6_PREFIX_RR; + } + /* link rr_prefix entry to rr_prefix list */ + s = splnet(); + LIST_INSERT_HEAD(&rr_prefix, rpp, rp_entry); + splx(s); + } + + if (!new->rp_raf_auto) + return 0; + + /* + * Add an address for each interface id, if it is not yet + * If it existed but not pointing to the prefix yet, + * init the prefix pointer. + */ + for (rap = rpp->rp_addrhead.lh_first; rap != NULL; + rap = rap->ra_entry.le_next) { + if (rap->ra_addr != NULL) { + if (rap->ra_addr->ia6_ifpr == NULL) + rap->ra_addr->ia6_ifpr = rp2ifpr(rpp); + continue; + } + add_each_addr(so, rpp, rap); + } + return 0; +} + +static int +add_each_prefix(struct socket *so, struct rr_prefix *rpp) +{ + init_prefix_ltimes(rpp); + return(rrpr_update(so, rpp)); } static void -add_useprefixes(struct ifnet *ifp, struct in6_rrenumreq *irr) +rp_remove(struct rr_prefix *rpp) +{ + int s; + + s = splnet(); + /* unlink rp_entry from if_prefixlist */ + { + struct ifnet *ifp = rpp->rp_ifp; + struct ifprefix *ifpr; + + if ((ifpr = ifp->if_prefixlist) == rp2ifpr(rpp)) + ifp->if_prefixlist = ifpr->ifpr_next; + else { + while (ifpr->ifpr_next && + (ifpr->ifpr_next != rp2ifpr(rpp))) + ifpr = ifpr->ifpr_next; + if (ifpr->ifpr_next) + ifpr->ifpr_next = rp2ifpr(rpp)->ifpr_next; + else + printf("Couldn't unlink rr_prefix from ifp\n"); + } + } + /* unlink rp_entry from rr_prefix list */ + LIST_REMOVE(rpp, rp_entry); + splx(s); + free(rpp, M_IP6RR); +} + +static int +create_ra_entry(struct rp_addr **rapp) +{ + *rapp = (struct rp_addr *)malloc(sizeof(struct rp_addr), M_RR_ADDR, + M_NOWAIT); + if (*rapp == NULL) { + log(LOG_ERR, "in6_prefix.c: init_newprefix:%d: ENOBUFS" + "for rp_addr", __LINE__); + return ENOBUFS; + } + bzero(*rapp, sizeof(*(*rapp))); + + return 0; +} + +static int +init_newprefix(struct in6_rrenumreq *irr, struct ifprefix *ifpr, + struct rr_prefix *rpp) +{ + struct rp_addr *orap; + + /* init rp */ + bzero(rpp, sizeof(*rpp)); + rpp->rp_type = IN6_PREFIX_RR; + rpp->rp_ifp = ifpr->ifpr_ifp; + rpp->rp_plen = ifpr->ifpr_plen; + rpp->rp_prefix.sin6_len = sizeof(rpp->rp_prefix); + rpp->rp_prefix.sin6_family = AF_INET6; + bit_copy((char *)RP_IN6(rpp), sizeof(*RP_IN6(rpp)) << 3, + (char *)&irr->irr_useprefix.sin6_addr, + sizeof(irr->irr_useprefix.sin6_addr) << 3, + 0, irr->irr_u_uselen); + /* copy keeplen part if necessary as necessary len */ + if (irr->irr_u_uselen < ifpr->ifpr_plen) + bit_copy((char *)RP_IN6(rpp), sizeof(*RP_IN6(rpp)) << 3, + (char *)IFPR_IN6(ifpr), sizeof(*IFPR_IN6(ifpr)) << 3, + irr->irr_u_uselen, + min(ifpr->ifpr_plen - irr->irr_u_uselen, + irr->irr_u_keeplen)); + for (orap = (ifpr2rp(ifpr)->rp_addrhead).lh_first; orap != NULL; + orap = orap->ra_entry.le_next) { + struct rp_addr *rap; + int error = 0; + + if ((error = create_ra_entry(&rap)) != 0) + return error; + rap->ra_ifid = orap->ra_ifid; + rap->ra_flags.anycast = (orap->ra_addr != NULL && + (orap->ra_addr->ia_flags & + IN6_IFF_ANYCAST) != 0) ? 1 : 0; + LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry); + } + rpp->rp_vltime = irr->irr_vltime; + rpp->rp_pltime = irr->irr_pltime; + rpp->rp_raf_onlink = irr->irr_raf_mask_onlink ? irr->irr_raf_onlink : + ifpr2rp(ifpr)->rp_raf_onlink; + rpp->rp_raf_auto = irr->irr_raf_mask_auto ? irr->irr_raf_auto : + ifpr2rp(ifpr)->rp_raf_auto; + /* Is some FlagMasks for rrf necessary? */ + rpp->rp_rrf = irr->irr_rrf; + rpp->rp_origin = irr->irr_origin; + + return 0; +} + +static void +free_rp_entries(struct rr_prefix *rpp) +{ + /* + * This func is only called with rpp on stack(not on list). + * So no splnet() here + */ +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + while (!LIST_EMPTY(&rpp->rp_addrhead)) +#else + while (rpp->rp_addrhead.lh_first != NULL) +#endif + { + struct rp_addr *rap; + + rap = LIST_FIRST(&rpp->rp_addrhead); + LIST_REMOVE(rap, ra_entry); + free(rap, M_RR_ADDR); + } +} + +static int +add_useprefixes(struct socket *so, struct ifnet *ifp, + struct in6_rrenumreq *irr) { struct ifprefix *ifpr, *nextifpr; + struct rr_prefix rp; + int error = 0; /* add prefixes to each of marked prefix */ for (ifpr = ifp->if_prefixlist; ifpr; ifpr = nextifpr) { nextifpr = ifpr->ifpr_next; - if (ifpr->ifpr_prefix->sa_family != AF_INET6) + if (ifpr->ifpr_prefix->sa_family != AF_INET6 || + ifpr->ifpr_type != IN6_PREFIX_RR) continue; - if (ifpr2ndpr(ifpr)->ndpr_statef_addmark) { - struct nd_prefix ndpr; - - /* init ndpr */ - bzero((caddr_t)&ndpr, sizeof(ndpr)); - ndpr.ndpr_ifp = ifp; - ndpr.ndpr_plen = irr->irr_u_uselen + - irr->irr_u_keeplen; - ndpr.ndpr_prefix.sin6_len = sizeof(ndpr.ndpr_prefix); - ndpr.ndpr_prefix.sin6_family = AF_INET6; - bit_copy((char *)&ndpr.ndpr_prefix.sin6_addr, - sizeof(ndpr.ndpr_prefix.sin6_addr) << 3, - (char *)&irr->irr_useprefix.sin6_addr, - sizeof(irr->irr_useprefix.sin6_addr) << 3, - 0, irr->irr_u_uselen); - bit_copy((char *)&ndpr.ndpr_prefix.sin6_addr, - sizeof(ndpr.ndpr_prefix.sin6_addr) << 3, - (char *)& - ifpr2ndpr(ifpr)->ndpr_prefix.sin6_addr, - sizeof(ifpr2ndpr(ifpr)->ndpr_prefix.sin6_addr) - << 3, - irr->irr_u_uselen, irr->irr_u_keeplen); - ndpr.ndpr_vltime = irr->irr_vltime; - ndpr.ndpr_pltime = irr->irr_pltime; - ndpr.ndpr_raf_onlink = irr->irr_raf_mask_onlink ? - irr->irr_raf_onlink : - ifpr2ndpr(ifpr)->ndpr_raf_onlink; - ndpr.ndpr_raf_auto = irr->irr_raf_mask_auto ? - irr->irr_raf_auto : - ifpr2ndpr(ifpr)->ndpr_raf_auto; - /* Is some FlagMasks for rrf necessary? */ - ndpr.ndpr_rrf = irr->irr_rrf; - ndpr.ndpr_origin = irr->irr_origin; - - (void)add_each_prefix(&ndpr); + if (ifpr2rp(ifpr)->rp_statef_addmark) { + if ((error = init_newprefix(irr, ifpr, &rp)) != 0) + break; + error = add_each_prefix(so, &rp); } } + /* free each rp_addr entry */ + free_rp_entries(&rp); + + return error; } -static int -delete_each_prefix(struct nd_prefix *ndpr, u_char origin) +static void +unprefer_prefix(struct rr_prefix *rpp) { + struct rp_addr *rap; +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) + long time_second = time.tv_sec; +#endif + + for (rap = rpp->rp_addrhead.lh_first; rap != NULL; + rap = rap->ra_entry.le_next) { + if (rap->ra_addr == NULL) + continue; + rap->ra_addr->ia6_lifetime.ia6t_preferred = time_second; + rap->ra_addr->ia6_lifetime.ia6t_pltime = 0; + } +} + +int +delete_each_prefix(struct socket *so, struct rr_prefix *rpp, u_char origin) +{ + struct in6_aliasreq ifra; int error = 0; - if (ndpr->ndpr_origin > origin) + if (rpp->rp_origin > origin) return(EPERM); - if (!IN6_IS_ADDR_UNSPECIFIED(&ndpr->ndpr_addr)) - in6_ifdel(ndpr->ndpr_ifp, &ndpr->ndpr_addr); - /* xxx ND_OPT_PI_FLAG_ONLINK processing */ - prelist_remove(ndpr); + while (rpp->rp_addrhead.lh_first != NULL) { + struct rp_addr *rap; + int s; + + s = splnet(); + rap = LIST_FIRST(&rpp->rp_addrhead); + if (rap == NULL) + break; + LIST_REMOVE(rap, ra_entry); + splx(s); + if (rap->ra_addr == NULL) { + free(rap, M_RR_ADDR); + continue; + } + rap->ra_addr->ia6_ifpr = NULL; + + bzero(&ifra, sizeof(ifra)); + strncpy(ifra.ifra_name, if_name(rpp->rp_ifp), + sizeof(ifra.ifra_name)); + ifra.ifra_addr = rap->ra_addr->ia_addr; + ifra.ifra_dstaddr = rap->ra_addr->ia_dstaddr; + ifra.ifra_prefixmask = rap->ra_addr->ia_prefixmask; + + error = in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, + rpp->rp_ifp +#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) + , curproc +#endif + ); + if (error != 0) + log(LOG_ERR, "in6_prefix.c: delete_each_prefix:" + "deletion of an addr %s/%d failed because" + "in6_control failed for error %d", + ip6_sprintf(&ifra.ifra_addr.sin6_addr), + rpp->rp_plen, error); + + free(rap, M_RR_ADDR); + } + rp_remove(rpp); return error; } static void -delete_prefixes(struct ifnet *ifp, u_char origin) +delete_prefixes(struct socket *so, struct ifnet *ifp, u_char origin) { struct ifprefix *ifpr, *nextifpr; /* delete prefixes marked as tobe deleted */ for (ifpr = ifp->if_prefixlist; ifpr; ifpr = nextifpr) { nextifpr = ifpr->ifpr_next; - if (ifpr->ifpr_prefix->sa_family != AF_INET6) + if (ifpr->ifpr_prefix->sa_family != AF_INET6 || + ifpr->ifpr_type != IN6_PREFIX_RR) continue; - if (ifpr2ndpr(ifpr)->ndpr_statef_delmark) - (void)delete_each_prefix(ifpr2ndpr(ifpr), origin); + if (ifpr2rp(ifpr)->rp_statef_delmark) + (void)delete_each_prefix(so, ifpr2rp(ifpr), origin); } } +static int +link_stray_ia6s(struct rr_prefix *rpp) +{ + struct ifaddr *ifa; + +#if (defined(__FreeBSD__) && __FreeBSD__ < 3) || defined(__bsdi__) + for (ifa = rpp->rp_ifp->if_addrlist; ifa; ifa = ifa->ifa_next) +#else + for (ifa = rpp->rp_ifp->if_addrlist.tqh_first; ifa; + ifa = ifa->ifa_list.tqe_next) +#endif + { + struct rp_addr *rap; + struct rr_prefix *orpp; + int error = 0; + + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + if (rpp->rp_plen > in6_matchlen(RP_IN6(rpp), IFA_IN6(ifa))) + continue; + + orpp = ifpr2rp(((struct in6_ifaddr *)ifa)->ia6_ifpr); + if (orpp != NULL) { + if (!in6_are_prefix_equal(RP_IN6(orpp), RP_IN6(rpp), + rpp->rp_plen)) + log(LOG_ERR, "in6_prefix.c: link_stray_ia6s:" + "addr %s/%d already linked to a prefix" + "and it matches also %s/%d", + ip6_sprintf(IFA_IN6(ifa)), orpp->rp_plen, + ip6_sprintf(RP_IN6(rpp)), + rpp->rp_plen); + continue; + } + if ((error = assigne_ra_entry(rpp, + (sizeof(rap->ra_ifid) << 3) - + rpp->rp_plen, + (struct in6_ifaddr *)ifa)) != 0) + return error; + } + return 0; +} + int -in6_prefix_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) +in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data, + struct ifnet *ifp) { - struct nd_prefix *ndpr, ndpr_tmp; + struct rr_prefix *rpp, rp_tmp; + struct rp_addr *rap; struct in6_prefixreq *ipr = (struct in6_prefixreq *)data; struct in6_rrenumreq *irr = (struct in6_rrenumreq *)data; + struct ifaddr *ifa; int error = 0; /* @@ -396,51 +1017,133 @@ in6_prefix_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) /* FALL THROUGH */ case SIOCAIFPREFIX_IN6: case SIOCCIFPREFIX_IN6: + /* check if preferred lifetime > valid lifetime */ + if (irr->irr_pltime > irr->irr_vltime) { + log(LOG_NOTICE, + "in6_prefix_ioctl: preferred lifetime" + "(%ld) is greater than valid lifetime(%ld)", + (u_long)irr->irr_pltime, (u_long)irr->irr_vltime); + error = EINVAL; + break; + } if (mark_matched_prefixes(cmd, ifp, irr)) { - if (irr->irr_u_uselen) - add_useprefixes(ifp, irr); + if (irr->irr_u_uselen != 0) + if ((error = add_useprefixes(so, ifp, irr)) + != 0) + goto failed; if (cmd != SIOCAIFPREFIX_IN6) - delete_prefixes(ifp, irr->irr_origin); - } - else + delete_prefixes(so, ifp, irr->irr_origin); + } else return (EADDRNOTAVAIL); - + failed: unmark_prefixes(ifp); break; case SIOCGIFPREFIX_IN6: - ndpr = search_matched_prefix(ifp, ipr); - if (ndpr == 0 || ifp != ndpr->ndpr_ifp) + rpp = search_matched_prefix(ifp, ipr); + if (rpp == NULL || ifp != rpp->rp_ifp) return (EADDRNOTAVAIL); - ipr->ipr_origin = ndpr->ndpr_origin; - ipr->ipr_plen = ndpr->ndpr_plen; - ipr->ipr_vltime = ndpr->ndpr_vltime; - ipr->ipr_pltime = ndpr->ndpr_pltime; - ipr->ipr_flags = ndpr->ndpr_flags; - ipr->ipr_prefix = ndpr->ndpr_prefix; + ipr->ipr_origin = rpp->rp_origin; + ipr->ipr_plen = rpp->rp_plen; + ipr->ipr_vltime = rpp->rp_vltime; + ipr->ipr_pltime = rpp->rp_pltime; + ipr->ipr_flags = rpp->rp_flags; + ipr->ipr_prefix = rpp->rp_prefix; break; case SIOCSIFPREFIX_IN6: - /* init ndpr_tmp */ - bzero((caddr_t)&ndpr_tmp, sizeof(ndpr_tmp)); - ndpr_tmp.ndpr_ifp = ifp; - ndpr_tmp.ndpr_plen = ipr->ipr_plen; - ndpr_tmp.ndpr_prefix = ipr->ipr_prefix; - ndpr_tmp.ndpr_vltime = ipr->ipr_vltime; - ndpr_tmp.ndpr_pltime = ipr->ipr_pltime; - ndpr_tmp.ndpr_flags = ipr->ipr_flags; - ndpr_tmp.ndpr_origin = ipr->ipr_origin; - - if ((error = add_each_prefix(&ndpr_tmp)) != 0) - return error; + /* check if preferred lifetime > valid lifetime */ + if (ipr->ipr_pltime > ipr->ipr_vltime) { + log(LOG_NOTICE, + "in6_prefix_ioctl: preferred lifetime" + "(%ld) is greater than valid lifetime(%ld)", + (u_long)ipr->ipr_pltime, (u_long)ipr->ipr_vltime); + error = EINVAL; + break; + } + + /* init rp_tmp */ + bzero((caddr_t)&rp_tmp, sizeof(rp_tmp)); + rp_tmp.rp_ifp = ifp; + rp_tmp.rp_plen = ipr->ipr_plen; + rp_tmp.rp_prefix = ipr->ipr_prefix; + rp_tmp.rp_vltime = ipr->ipr_vltime; + rp_tmp.rp_pltime = ipr->ipr_pltime; + rp_tmp.rp_flags = ipr->ipr_flags; + rp_tmp.rp_origin = ipr->ipr_origin; + + /* create rp_addr entries, usually at least for lladdr */ + if ((error = link_stray_ia6s(&rp_tmp)) != 0) { + free_rp_entries(&rp_tmp); + break; + } + ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp); + if (ifa != NULL) { + if ((error = create_ra_entry(&rap)) != 0) { + free_rp_entries(&rp_tmp); + break; + } + /* copy interface id part */ + bit_copy((caddr_t)&rap->ra_ifid, + sizeof(rap->ra_ifid) << 3, + (caddr_t)IFA_IN6(ifa), + sizeof(*IFA_IN6(ifa)) << 3, + rp_tmp.rp_plen, + (sizeof(rap->ra_ifid) << 3) - rp_tmp.rp_plen); + /* insert into list */ + LIST_INSERT_HEAD(&rp_tmp.rp_addrhead, rap, ra_entry); + } + + error = add_each_prefix(so, &rp_tmp); + + /* free each rp_addr entry */ + free_rp_entries(&rp_tmp); + break; case SIOCDIFPREFIX_IN6: - ndpr = search_matched_prefix(ifp, ipr); - if (ndpr == 0 || ifp != ndpr->ndpr_ifp) + rpp = search_matched_prefix(ifp, ipr); + if (rpp == NULL || ifp != rpp->rp_ifp) return (EADDRNOTAVAIL); - error = delete_each_prefix(ndpr, ipr->ipr_origin); + error = delete_each_prefix(so, rpp, ipr->ipr_origin); break; } return error; } + +void +in6_rr_timer(void *ignored_arg) +{ + int s; + struct rr_prefix *rpp; +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) + long time_second = time.tv_sec; +#endif + + timeout(in6_rr_timer, (caddr_t)0, ip6_rr_prune * hz); + + s = splnet(); + /* expire */ + rpp = LIST_FIRST(&rr_prefix); + while (rpp) { + if (rpp->rp_expire && rpp->rp_expire < time_second) { + struct rr_prefix *next_rpp; + struct socket so; + + /* XXX: init dummy so */ + bzero(&so, sizeof(so)); +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__NetBSD__) + so.so_state |= SS_PRIV; +#endif + + next_rpp = LIST_NEXT(rpp, rp_entry); + delete_each_prefix(&so, rpp, PR_ORIG_KERNEL); + rpp = next_rpp; + continue; + } + if (rpp->rp_preferred && rpp->rp_preferred < time_second) + unprefer_prefix(rpp); + rpp = LIST_NEXT(rpp, rp_entry); + } + splx(s); +} diff --git a/sys/netinet6/in6_prefix.h b/sys/netinet6/in6_prefix.h index 3d8d319e5ab..48400d2b9dd 100644 --- a/sys/netinet6/in6_prefix.h +++ b/sys/netinet6/in6_prefix.h @@ -1,3 +1,5 @@ +/* $NetBSD: in6_prefix.h,v 1.2 1999/12/13 15:17:22 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, 1998 and 1999 WIDE Project. * All rights reserved. diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index f744b374012..965dcd44f6d 100644 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -1,4 +1,4 @@ -/* $NetBSD: in6_proto.c,v 1.8 1999/07/31 18:41:16 itojun Exp $ */ +/* $NetBSD: in6_proto.c,v 1.9 1999/12/13 15:17:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -73,10 +73,17 @@ #include <sys/param.h> #include <sys/socket.h> +#if defined(__FreeBSD__) +#include <sys/socketvar.h> +#endif #include <sys/protosw.h> #include <sys/kernel.h> #include <sys/domain.h> #include <sys/mbuf.h> +#ifdef __FreeBSD__ +#include <sys/systm.h> +#include <sys/sysctl.h> +#endif #include <net/if.h> #include <net/radix.h> @@ -85,21 +92,21 @@ #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/in_var.h> -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || (defined(__NetBSD__) && !defined(TCP6)) +#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || (defined(__NetBSD__) && !defined(TCP6)) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) #include <netinet/ip.h> #include <netinet/ip_var.h> #endif -#if defined(__NetBSD__) && !defined(TCP6) +#if (defined(__NetBSD__) && !defined(TCP6)) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) #include <netinet/in_pcb.h> #endif #include <netinet6/ip6.h> #include <netinet6/ip6_var.h> #include <netinet6/icmp6.h> -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__) && !(defined(__bsdi__) && _BSDI_VERSION >= 199802) #include <netinet6/in6_pcb.h> #endif -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) +#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) #include <netinet/tcp.h> #include <netinet/tcp_timer.h> #include <netinet/tcp_var.h> @@ -123,14 +130,24 @@ #endif #endif +#if !defined(__OpenBSD__) && !(defined(__bsdi__) && _BSDI_VERSION >= 199802) #include <netinet6/udp6.h> #include <netinet6/udp6_var.h> +#endif #include <netinet6/pim6_var.h> #include <netinet6/nd6.h> +#ifdef __FreeBSD__ +#include <netinet6/in6_prefix.h> +#endif + +#ifdef __OpenBSD__ /*KAME IPSEC*/ +#undef IPSEC +#endif #ifdef IPSEC +#include <netinet6/ipsec.h> #include <netinet6/ah.h> #ifdef IPSEC_ESP #include <netinet6/esp.h> @@ -145,6 +162,8 @@ #include <netinet6/in6_gif.h> #endif +#include <net/net_osdep.h> + #define offsetof(type, member) ((size_t)(&((type *)0)->member)) /* @@ -152,78 +171,172 @@ */ extern struct domain inet6domain; +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +static struct pr_usrreqs nousrreqs; +#endif struct ip6protosw inet6sw[] = { { 0, &inet6domain, IPPROTO_IPV6, 0, 0, 0, 0, 0, 0, - ip6_init, 0, frag6_slowtimo, frag6_drain, ip6_sysctl + ip6_init, 0, frag6_slowtimo, frag6_drain, +#ifndef __FreeBSD__ + ip6_sysctl, +#else +# if __FreeBSD__ >= 3 + &nousrreqs, +# endif +#endif }, { SOCK_DGRAM, &inet6domain, IPPROTO_UDP, PR_ATOMIC | PR_ADDR, udp6_input, 0, udp6_ctlinput, ip6_ctloutput, - udp6_usrreq, - udp6_init, 0, 0, 0, udp6_sysctl +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + 0, 0, +#elif defined(HAVE_NRL_INPCB) + udp6_usrreq, 0, +#else + udp6_usrreq, udp6_init, +#endif + 0, 0, 0, +#ifndef __FreeBSD__ +#ifdef HAVE_NRL_INPCB + udp_sysctl, +#else + udp6_sysctl, +#endif +#else +# if __FreeBSD__ >= 3 + &udp6_usrreqs, +# endif +#endif }, #ifdef TCP6 -{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED | PR_WANTRCVD | PR_LISTEN, +{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD|PR_LISTEN, tcp6_input, 0, tcp6_ctlinput, tcp6_ctloutput, tcp6_usrreq, - tcp6_init, tcp6_fasttimo, tcp6_slowtimo, tcp6_drain, tcp6_sysctl + tcp6_init, tcp6_fasttimo, tcp6_slowtimo, tcp6_drain, +#ifndef __FreeBSD__ + tcp6_sysctl, +#else +# if __FreeBSD__ >= 3 + &tcp6_usrreqs, +# endif +#endif }, #else -{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED | PR_WANTRCVD | PR_LISTEN, +{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD|PR_LISTEN, tcp6_input, 0, tcp6_ctlinput, tcp_ctloutput, +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + 0, +#elif defined(HAVE_NRL_INPCB) + tcp6_usrreq, +#else tcp_usrreq, -#ifdef INET - /* If inet4, no need to have tcp_slowtimo and tcp_fasttimo happen TWICE */ - tcp_init, NULL, NULL, tcp_drain, tcp_sysctl +#endif +#ifdef INET /* don't call timeout routines twice */ + tcp_init, 0, 0, tcp_drain, #else - tcp_init, tcp_fasttimo, tcp_slowtimo, tcp_drain, tcp_sysctl + tcp_init, tcp_fasttimo, tcp_slowtimo, tcp_drain, #endif -}, +#ifndef __FreeBSD__ + tcp_sysctl, +#else +# if __FreeBSD__ >= 3 + &tcp6_usrreqs, +# endif #endif +}, +#endif /*TCP6*/ { SOCK_RAW, &inet6domain, IPPROTO_RAW, PR_ATOMIC | PR_ADDR, rip6_input, rip6_output, 0, rip6_ctloutput, +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + 0, +#else rip6_usrreq, - 0, 0, 0, 0, 0 +#endif + 0, 0, 0, 0, +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + &rip6_usrreqs +#endif }, { SOCK_RAW, &inet6domain, IPPROTO_ICMPV6, PR_ATOMIC | PR_ADDR, icmp6_input, rip6_output, 0, rip6_ctloutput, +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + 0, +#else rip6_usrreq, - icmp6_init, icmp6_fasttimo, 0, 0, icmp6_sysctl +#endif + icmp6_init, icmp6_fasttimo, 0, 0, +#ifndef __FreeBSD__ + icmp6_sysctl, +#else +# if __FreeBSD__ >= 3 + &rip6_usrreqs +# endif +#endif }, { SOCK_RAW, &inet6domain, IPPROTO_DSTOPTS,PR_ATOMIC|PR_ADDR, dest6_input, 0, 0, 0, 0, 0, 0, 0, 0, +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + &nousrreqs +#endif }, { SOCK_RAW, &inet6domain, IPPROTO_ROUTING,PR_ATOMIC|PR_ADDR, route6_input, 0, 0, 0, 0, 0, 0, 0, 0, +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + &nousrreqs +#endif }, { SOCK_RAW, &inet6domain, IPPROTO_FRAGMENT,PR_ATOMIC|PR_ADDR, frag6_input, 0, 0, 0, 0, 0, 0, 0, 0, +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + &nousrreqs +#endif }, #ifdef IPSEC { SOCK_RAW, &inet6domain, IPPROTO_AH, PR_ATOMIC|PR_ADDR, ah6_input, 0, 0, 0, 0, - 0, 0, 0, 0, ipsec6_sysctl + 0, 0, 0, 0, +#ifndef __FreeBSD__ + ipsec6_sysctl, +#else +# if __FreeBSD__ >= 3 + &nousrreqs, +# endif +#endif }, #ifdef IPSEC_ESP { SOCK_RAW, &inet6domain, IPPROTO_ESP, PR_ATOMIC|PR_ADDR, esp6_input, 0, 0, 0, 0, - 0, 0, 0, 0, ipsec6_sysctl + 0, 0, 0, 0, +#ifndef __FreeBSD__ + ipsec6_sysctl, +#else +# if __FreeBSD__ >= 3 + &nousrreqs, +# endif +#endif }, #endif { SOCK_RAW, &inet6domain, IPPROTO_IPCOMP, PR_ATOMIC|PR_ADDR, ipcomp6_input, 0, 0, 0, 0, - 0, 0, 0, 0, ipsec6_sysctl + 0, 0, 0, 0, +#ifndef __FreeBSD__ + ipsec6_sysctl, +#else +# if __FreeBSD__ >= 3 + &nousrreqs, +# endif +#endif }, #endif /* IPSEC */ #if NGIF > 0 @@ -231,33 +344,62 @@ struct ip6protosw inet6sw[] = { in6_gif_input,0, 0, 0, 0, 0, 0, 0, 0, +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + &nousrreqs +#endif }, #ifdef INET6 { SOCK_RAW, &inet6domain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR, in6_gif_input,0, 0, 0, 0, 0, 0, 0, 0, +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + &nousrreqs +#endif }, #endif /* INET6 */ #endif /* GIF */ { SOCK_RAW, &inet6domain, IPPROTO_PIM, PR_ATOMIC|PR_ADDR, pim6_input, rip6_output, 0, rip6_ctloutput, +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + 0, +#else rip6_usrreq, +#endif 0, 0, 0, 0, +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + &rip6_usrreqs +# endif }, /* raw wildcard */ { SOCK_RAW, &inet6domain, 0, PR_ATOMIC | PR_ADDR, rip6_input, rip6_output, 0, rip6_ctloutput, - rip6_usrreq, - rip6_init, 0, 0, 0, +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + 0, 0, +#else + rip6_usrreq, rip6_init, +#endif + 0, 0, 0, +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + &rip6_usrreqs +#endif }, }; +#ifdef __FreeBSD__ +extern int in6_inithead __P((void **, int)); +#endif + struct domain inet6domain = { AF_INET6, "internet6", 0, 0, 0, (struct protosw *)inet6sw, (struct protosw *)&inet6sw[sizeof(inet6sw)/sizeof(inet6sw[0])], 0, - rn_inithead, offsetof(struct sockaddr_in6, sin6_addr) << 3, +#ifdef __FreeBSD__ + in6_inithead, +#else + rn_inithead, +#endif + offsetof(struct sockaddr_in6, sin6_addr) << 3, sizeof(struct sockaddr_in6) }; #ifdef __FreeBSD__ @@ -295,14 +437,23 @@ int ip6_gif_hlim = GIF_HLIM; #else int ip6_gif_hlim = 0; #endif - +int ip6_use_deprecated = 1; /* allow deprecated addr (RFC2462 5.5.4) */ +int ip6_rr_prune = 5; /* router renumbering prefix + * walk list every 5 sec. */ u_int32_t ip6_id = 0UL; int ip6_keepfaith = 0; time_t ip6_log_time = (time_t)0L; /* icmp6 */ +#ifndef __bsdi__ +/* + * BSDI4 defines these variables in in_proto.c... + * XXX: what if we don't define INET? Should we define pmtu6_expire + * or so? (jinmei@kame.net 19990310) + */ int pmtu_expire = 60*10; int pmtu_probe = 60*2; +#endif /* raw IP6 parameters */ /* @@ -416,8 +567,50 @@ SYSCTL_NODE(_net_inet6, IPPROTO_ESP, ipsec6, CTLFLAG_RW, 0, "IPSEC6"); #endif /* IPSEC */ /* net.inet6.ip6 */ -SYSCTL_INT(_net_inet6_ip6, IPV6CTL_FORWARDING, - forwarding, CTLFLAG_RW, &ip6_forwarding, 0, ""); +static int +sysctl_ip6_forwarding SYSCTL_HANDLER_ARGS +{ + int error = 0; + int old_ip6_forwarding; + int changed; + + error = SYSCTL_OUT(req, arg1, sizeof(int)); + if (error || !req->newptr) + return (error); + old_ip6_forwarding = ip6_forwarding; + error = SYSCTL_IN(req, arg1, sizeof(int)); + if (error != 0) + return (error); + changed = (ip6_forwarding ? 1 : 0) ^ (old_ip6_forwarding ? 1 : 0); + if (changed == 0) + return (error); + if (ip6_forwarding != 0) { /* host becomes router */ + int s = splnet(); + struct nd_prefix *pr, *next; + + for (pr = nd_prefix.lh_first; pr; pr = next) { + next = pr->ndpr_next; + if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) + in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); + prelist_remove(pr); + } + splx(s); + } else { /* router becomes host */ + struct socket so; + + /* XXX: init dummy so */ + bzero(&so, sizeof(so)); + while(!LIST_EMPTY(&rr_prefix)) + delete_each_prefix(&so, LIST_FIRST(&rr_prefix), + PR_ORIG_KERNEL); + } + + return (error); +} + +SYSCTL_OID(_net_inet6_ip6, IPV6CTL_FORWARDING, forwarding, + CTLTYPE_INT|CTLFLAG_RW, &ip6_forwarding, 0, sysctl_ip6_forwarding, + "I", ""); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_SENDREDIRECTS, redirect, CTLFLAG_RW, &ip6_sendredirects, 0, ""); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_DEFHLIM, @@ -440,6 +633,12 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_DEFMCASTHLIM, defmcasthlim, CTLFLAG_RW, &ip6_defmcasthlim, 0, ""); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM, gifhlim, CTLFLAG_RW, &ip6_gif_hlim, 0, ""); +SYSCTL_STRING(_net_inet6_ip6, IPV6CTL_KAME_VERSION, + kame_version, CTLFLAG_RD, __KAME_VERSION, 0, ""); +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_USE_DEPRECATED, + use_deprecated, CTLFLAG_RW, &ip6_use_deprecated, 0, ""); +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_RR_PRUNE, + rr_prune, CTLFLAG_RW, &ip6_rr_prune, 0, ""); /* net.inet6.icmp6 */ SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_REDIRACCEPT, @@ -463,6 +662,7 @@ SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_USELOOPBACK, SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_PROXYALL, nd6_proxyall, CTLFLAG_RW, &nd6_proxyall, 0, ""); +#if __FreeBSD__ < 3 /* net.inet6.udp6 */ SYSCTL_INT(_net_inet6_udp6, UDP6CTL_SENDMAX, sendmax, CTLFLAG_RW, &udp6_sendspace, 0, ""); @@ -504,5 +704,6 @@ SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_SYN_BUCKET_LIMIT, syn_bucket_limit, CTLFLAG_RW, &tcp6_syn_bucket_limit, 0, ""); SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_SYN_CACHE_INTER, syn_cache_interval, CTLFLAG_RW, &tcp6_syn_cache_interval, 0, ""); +#endif /* !(defined(__FreeBSD__) && __FreeBSD__ >= 3) */ #endif /* __FreeBSD__ */ diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index f8aa61f10c0..b425447d4e6 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -1,4 +1,4 @@ -/* $NetBSD: in6_var.h,v 1.4 1999/07/22 03:59:42 itojun Exp $ */ +/* $NetBSD: in6_var.h,v 1.5 1999/12/13 15:17:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -99,11 +99,133 @@ struct in6_ifaddr { struct sockaddr_in6 ia_prefixmask; /* prefix mask */ u_int32_t ia_plen; /* prefix length */ struct in6_ifaddr *ia_next; /* next in6 list of IP6 addresses */ +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) LIST_HEAD(in6_multihead, in6_multi) ia6_multiaddrs; /* list of multicast addresses */ +#endif int ia6_flags; struct in6_addrlifetime ia6_lifetime; /* NULL = infty */ + struct ifprefix *ia6_ifpr; /* back pointer to ifprefix */ +}; + +/* + * IPv6 interface statistics, as defined in RFC2465 Ipv6IfStatsEntry (p12). + */ +struct in6_ifstat { + u_quad_t ifs6_in_receive; /* # of total input datagram */ + u_quad_t ifs6_in_hdrerr; /* # of datagrams with invalid hdr */ + u_quad_t ifs6_in_toobig; /* # of datagrams exceeded MTU */ + u_quad_t ifs6_in_noroute; /* # of datagrams with no route */ + u_quad_t ifs6_in_addrerr; /* # of datagrams with invalid dst */ + u_quad_t ifs6_in_protounknown; /* # of datagrams with unknown proto */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_in_truncated; /* # of truncated datagrams */ + u_quad_t ifs6_in_discard; /* # of discarded datagrams */ + /* NOTE: fragment timeout is not here */ + u_quad_t ifs6_in_deliver; /* # of datagrams delivered to ULP */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_out_forward; /* # of datagrams forwarded */ + /* NOTE: increment on outgoing if */ + u_quad_t ifs6_out_request; /* # of outgoing datagrams from ULP */ + /* NOTE: does not include forwrads */ + u_quad_t ifs6_out_discard; /* # of discarded datagrams */ + u_quad_t ifs6_out_fragok; /* # of datagrams fragmented */ + u_quad_t ifs6_out_fragfail; /* # of datagrams failed on fragment */ + u_quad_t ifs6_out_fragcreat; /* # of fragment datagrams */ + /* NOTE: this is # after fragment */ + u_quad_t ifs6_reass_reqd; /* # of incoming fragmented packets */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_reass_ok; /* # of reassembled packets */ + /* NOTE: this is # after reass */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_reass_fail; /* # of reass failures */ + /* NOTE: may not be packet count */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_in_mcast; /* # of inbound multicast datagrams */ + u_quad_t ifs6_out_mcast; /* # of outbound multicast datagrams */ +}; + +/* + * ICMPv6 interface statistics, as defined in RFC2466 Ipv6IfIcmpEntry. + * XXX: I'm not sure if this file is the right place for this structure... + */ +struct icmp6_ifstat { + /* + * Input statistics + */ + /* ipv6IfIcmpInMsgs, total # of input messages */ + u_quad_t ifs6_in_msg; + /* ipv6IfIcmpInErrors, # of input error messages */ + u_quad_t ifs6_in_error; + /* ipv6IfIcmpInDestUnreachs, # of input dest unreach errors */ + u_quad_t ifs6_in_dstunreach; + /* ipv6IfIcmpInAdminProhibs, # of input administratively prohibited errs */ + u_quad_t ifs6_in_adminprohib; + /* ipv6IfIcmpInTimeExcds, # of input time exceeded errors */ + u_quad_t ifs6_in_timeexceed; + /* ipv6IfIcmpInParmProblems, # of input parameter problem errors */ + u_quad_t ifs6_in_paramprob; + /* ipv6IfIcmpInPktTooBigs, # of input packet too big errors */ + u_quad_t ifs6_in_pkttoobig; + /* ipv6IfIcmpInEchos, # of input echo requests */ + u_quad_t ifs6_in_echo; + /* ipv6IfIcmpInEchoReplies, # of input echo replies */ + u_quad_t ifs6_in_echoreply; + /* ipv6IfIcmpInRouterSolicits, # of input router solicitations */ + u_quad_t ifs6_in_routersolicit; + /* ipv6IfIcmpInRouterAdvertisements, # of input router advertisements */ + u_quad_t ifs6_in_routeradvert; + /* ipv6IfIcmpInNeighborSolicits, # of input neighbor solicitations */ + u_quad_t ifs6_in_neighborsolicit; + /* ipv6IfIcmpInNeighborAdvertisements, # of input neighbor advertisements */ + u_quad_t ifs6_in_neighboradvert; + /* ipv6IfIcmpInRedirects, # of input redirects */ + u_quad_t ifs6_in_redirect; + /* ipv6IfIcmpInGroupMembQueries, # of input MLD queries */ + u_quad_t ifs6_in_mldquery; + /* ipv6IfIcmpInGroupMembResponses, # of input MLD reports */ + u_quad_t ifs6_in_mldreport; + /* ipv6IfIcmpInGroupMembReductions, # of input MLD done */ + u_quad_t ifs6_in_mlddone; + + /* + * Output statistics. We should solve unresolved routing problem... + */ + /* ipv6IfIcmpOutMsgs, total # of output messages */ + u_quad_t ifs6_out_msg; + /* ipv6IfIcmpOutErrors, # of output error messages */ + u_quad_t ifs6_out_error; + /* ipv6IfIcmpOutDestUnreachs, # of output dest unreach errors */ + u_quad_t ifs6_out_dstunreach; + /* ipv6IfIcmpOutAdminProhibs, # of output administratively prohibited errs */ + u_quad_t ifs6_out_adminprohib; + /* ipv6IfIcmpOutTimeExcds, # of output time exceeded errors */ + u_quad_t ifs6_out_timeexceed; + /* ipv6IfIcmpOutParmProblems, # of output parameter problem errors */ + u_quad_t ifs6_out_paramprob; + /* ipv6IfIcmpOutPktTooBigs, # of output packet too big errors */ + u_quad_t ifs6_out_pkttoobig; + /* ipv6IfIcmpOutEchos, # of output echo requests */ + u_quad_t ifs6_out_echo; + /* ipv6IfIcmpOutEchoReplies, # of output echo replies */ + u_quad_t ifs6_out_echoreply; + /* ipv6IfIcmpOutRouterSolicits, # of output router solicitations */ + u_quad_t ifs6_out_routersolicit; + /* ipv6IfIcmpOutRouterAdvertisements, # of output router advertisements */ + u_quad_t ifs6_out_routeradvert; + /* ipv6IfIcmpOutNeighborSolicits, # of output neighbor solicitations */ + u_quad_t ifs6_out_neighborsolicit; + /* ipv6IfIcmpOutNeighborAdvertisements, # of output neighbor advertisements */ + u_quad_t ifs6_out_neighboradvert; + /* ipv6IfIcmpOutRedirects, # of output redirects */ + u_quad_t ifs6_out_redirect; + /* ipv6IfIcmpOutGroupMembQueries, # of output MLD queries */ + u_quad_t ifs6_out_mldquery; + /* ipv6IfIcmpOutGroupMembResponses, # of output MLD reports */ + u_quad_t ifs6_out_mldreport; + /* ipv6IfIcmpOutGroupMembReductions, # of output MLD done */ + u_quad_t ifs6_out_mlddone; }; struct in6_ifreq { @@ -116,6 +238,8 @@ struct in6_ifreq { int ifru_metric; caddr_t ifru_data; struct in6_addrlifetime ifru_lifetime; + struct in6_ifstat ifru_stat; + struct icmp6_ifstat ifru_icmp6stat; } ifr_ifru; }; @@ -128,6 +252,10 @@ struct in6_aliasreq { struct in6_addrlifetime ifra_lifetime; }; +/* prefix type macro */ +#define IN6_PREFIX_ND 1 +#define IN6_PREFIX_RR 2 + /* * prefix related flags passed between kernel(NDP related part) and * user land command(ifconfig) and daemon(rtadvd). @@ -163,6 +291,7 @@ struct in6_prefixreq { #define PR_ORIG_RA 0 #define PR_ORIG_RR 1 #define PR_ORIG_STATIC 2 +#define PR_ORIG_KERNEL 3 #define ipr_raf_onlink ipr_flags.prf_ra.onlink #define ipr_raf_auto ipr_flags.prf_ra.autonomous @@ -209,20 +338,23 @@ struct in6_rrenumreq { * Given a pointer to an in6_ifaddr (ifaddr), * return a pointer to the addr as a sockaddr_in6 */ -#define IA6_IN6(ia) (&(((struct in6_ifaddr *)(ia))->ia_addr.sin6_addr)) -#define IA6_DSTIN6(ia) (&(((struct in6_ifaddr *)(ia))->ia_dstaddr.sin6_addr)) -#define IA6_MASKIN6(ia) (&(((struct in6_ifaddr *)(ia))->ia_prefixmask.sin6_addr)) -#define IA6_SIN6(ia) (&(((struct in6_ifaddr *)(ia))->ia_addr)) -#define IA6_DSTSIN6(ia) (&(((struct in6_ifaddr *)(ia))->ia_dstaddr)) -#define IFA_IN6(x) (((struct sockaddr_in6 *)((x)->ifa_addr))->sin6_addr) +#define IA6_IN6(ia) (&((ia)->ia_addr.sin6_addr)) +#define IA6_DSTIN6(ia) (&((ia)->ia_dstaddr.sin6_addr)) +#define IA6_MASKIN6(ia) (&((ia)->ia_prefixmask.sin6_addr)) +#define IA6_SIN6(ia) (&((ia)->ia_addr)) +#define IA6_DSTSIN6(ia) (&((ia)->ia_dstaddr)) +#define IFA_IN6(x) (&((struct sockaddr_in6 *)((x)->ifa_addr))->sin6_addr) +#define IFA_DSTIN6(x) (&((struct sockaddr_in6 *)((x)->ifa_dstaddr))->sin6_addr) -#define IFPR_IN6(x) (((struct sockaddr_in6 *)((x)->ifpr_prefix))->sin6_addr) +#define IFPR_IN6(x) (&((struct sockaddr_in6 *)((x)->ifpr_prefix))->sin6_addr) +#ifdef _KERNEL #define IN6_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \ (((d)->s6_addr32[0] ^ (a)->s6_addr32[0]) & (m)->s6_addr32[0]) == 0 && \ (((d)->s6_addr32[1] ^ (a)->s6_addr32[1]) & (m)->s6_addr32[1]) == 0 && \ (((d)->s6_addr32[2] ^ (a)->s6_addr32[2]) & (m)->s6_addr32[2]) == 0 && \ (((d)->s6_addr32[3] ^ (a)->s6_addr32[3]) & (m)->s6_addr32[3]) == 0 ) +#endif #define SIOCSIFADDR_IN6 _IOW('i', 12, struct in6_ifreq) #define SIOCGIFADDR_IN6 _IOWR('i', 33, struct in6_ifreq) @@ -250,6 +382,11 @@ struct in6_rrenumreq { #define SIOCGIFALIFETIME_IN6 _IOWR('i', 81, struct in6_ifreq) #define SIOCSIFALIFETIME_IN6 _IOWR('i', 82, struct in6_ifreq) +#define SIOCGIFSTAT_IN6 _IOWR('i', 83, struct in6_ifreq) +#define SIOCGIFSTAT_ICMP6 _IOWR('i', 84, struct in6_ifreq) + +#define SIOCSDEFIFACE_IN6 _IOWR('i', 85, struct in6_ndifreq) +#define SIOCGDEFIFACE_IN6 _IOWR('i', 86, struct in6_ndifreq) #define SIOCSIFPREFIX_IN6 _IOW('i', 100, struct in6_prefixreq) /* set */ #define SIOCGIFPREFIX_IN6 _IOWR('i', 101, struct in6_prefixreq) /* get */ @@ -276,6 +413,21 @@ struct in6_rrenumreq { #ifdef _KERNEL extern struct in6_ifaddr *in6_ifaddr; + +extern struct in6_ifstat **in6_ifstat; +extern size_t in6_ifstatmax; +extern struct icmp6stat icmp6stat; +extern struct icmp6_ifstat **icmp6_ifstat; +extern size_t icmp6_ifstatmax; +#define in6_ifstat_inc(ifp, tag) \ +do { \ + if ((ifp) && (ifp)->if_index <= if_index \ + && (ifp)->if_index < in6_ifstatmax \ + && in6_ifstat && in6_ifstat[(ifp)->if_index]) { \ + in6_ifstat[(ifp)->if_index]->tag++; \ + } \ +} while (0) + extern struct ifqueue ip6intrq; /* IP6 packet input queue */ extern struct in6_addr zeroin6_addr; extern u_char inet6ctlerrmap[]; @@ -290,10 +442,28 @@ MALLOC_DECLARE(M_IPMADDR); * Macro for finding the internet address structure (in6_ifaddr) corresponding * to a given interface (ifnet structure). */ +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) + #define IFP_TO_IA6(ifp, ia) \ /* struct ifnet *ifp; */ \ /* struct in6_ifaddr *ia; */ \ -{ \ +do { \ + struct ifaddr *ifa; \ + for (ifa = (ifp)->if_addrlist; ifa; ifa = ifa->ifa_next) { \ + if (!ifa->ifa_addr) \ + continue; \ + if (ifa->ifa_addr->sa_family == AF_INET6) \ + break; \ + } \ + (ia) = (struct in6_ifaddr *)ifa; \ +} while (0) + +#else + +#define IFP_TO_IA6(ifp, ia) \ +/* struct ifnet *ifp; */ \ +/* struct in6_ifaddr *ia; */ \ +do { \ struct ifaddr *ifa; \ for (ifa = (ifp)->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { \ if (!ifa->ifa_addr) \ @@ -302,9 +472,11 @@ MALLOC_DECLARE(M_IPMADDR); break; \ } \ (ia) = (struct in6_ifaddr *)ifa; \ -} +} while (0) #endif /* _KERNEL */ +#endif + /* * Multi-cast membership entry. One for each group/ifp that a PCB * belongs to. @@ -318,13 +490,21 @@ struct in6_multi { LIST_ENTRY(in6_multi) in6m_entry; /* list glue */ struct in6_addr in6m_addr; /* IP6 multicast address */ struct ifnet *in6m_ifp; /* back pointer to ifnet */ +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) struct in6_ifaddr *in6m_ia; /* back pointer to in6_ifaddr */ +#else + struct ifmultiaddr *in6m_ifma; /* back pointer to ifmultiaddr */ +#endif u_int in6m_refcount; /* # membership claims by sockets */ u_int in6m_state; /* state of the membership */ u_int in6m_timer; /* MLD6 listener report timer */ }; #ifdef _KERNEL +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +extern LIST_HEAD(in6_multihead, in6_multi) in6_multihead; +#endif + /* * Structure used by macros below to remember position when stepping through * all of eht in6_multi records. @@ -340,11 +520,54 @@ struct in6_multistep { * returns NLL. */ +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + +#define IN6_LOOKUP_MULTI(addr, ifp, in6m) \ +/* struct in6_addr addr; */ \ +/* struct ifnet *ifp; */ \ +/* struct in6_multi *in6m; */ \ +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 \ + && IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)ifma->ifma_addr)->sin6_addr, \ + &(addr))) \ + break; \ + } \ + (in6m) = (struct in6_multi *)(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 "in6m" when there + * are no remaining records. + */ +#define IN6_NEXT_MULTI(step, in6m) \ +/* struct in6_multistep step; */ \ +/* struct in6_multi *in6m; */ \ +do { \ + if (((in6m) = (step).i_in6m) != NULL) \ + (step).i_in6m = (step).i_in6m->in6m_entry.le_next; \ +} while(0) + +#define IN6_FIRST_MULTI(step, in6m) \ +/* struct in6_multistep step; */ \ +/* struct in6_multi *in6m */ \ +do { \ + (step).i_in6m = in6_multihead.lh_first; \ + IN6_NEXT_MULTI((step), (in6m)); \ +} while(0) + +#else /* not FreeBSD3 */ + #define IN6_LOOKUP_MULTI(addr, ifp, in6m) \ /* struct in6_addr addr; */ \ /* struct ifnet *ifp; */ \ /* struct in6_multi *in6m; */ \ -{ \ +do { \ register struct in6_ifaddr *ia; \ \ IFP_TO_IA6((ifp), ia); \ @@ -356,7 +579,7 @@ struct in6_multistep { !IN6_ARE_ADDR_EQUAL(&(in6m)->in6m_addr, &(addr)); \ (in6m) = in6m->in6m_entry.le_next) \ continue; \ -} +} while (0) /* * Macro to step through all of the in6_multi records, one at a time. @@ -368,7 +591,7 @@ struct in6_multistep { #define IN6_NEXT_MULTI(step, in6m) \ /* struct in6_multistep step; */ \ /* struct in6_multi *in6m; */ \ -{ \ +do { \ if (((in6m) = (step).i_in6m) != NULL) \ (step).i_in6m = (in6m)->in6m_entry.le_next; \ else \ @@ -380,16 +603,18 @@ struct in6_multistep { break; \ } \ } \ -} +} while (0) #define IN6_FIRST_MULTI(step, in6m) \ /* struct in6_multistep step; */ \ /* struct in6_multi *in6m */ \ -{ \ +do { \ (step).i_ia = in6_ifaddr; \ (step).i_in6m = NULL; \ IN6_NEXT_MULTI((step), (in6m)); \ -} +} while (0) + +#endif /* not FreeBSD3 */ int in6_ifinit __P((struct ifnet *, struct in6_ifaddr *, struct sockaddr_in6 *, int)); @@ -397,9 +622,10 @@ struct in6_multi *in6_addmulti __P((struct in6_addr *, struct ifnet *, int *)); void in6_delmulti __P((struct in6_multi *)); void in6_ifscrub __P((struct ifnet *, struct in6_ifaddr *)); +extern int in6_ifindex2scopeid __P((int)); extern int in6_mask2len __P((struct in6_addr *)); extern void in6_len2mask __P((struct in6_addr *, int)); -#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3) +#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) int in6_control __P((struct socket *, u_long, caddr_t, struct ifnet *, struct proc *)); #else @@ -413,7 +639,13 @@ struct in6_ifaddr *in6ifa_ifpwithaddr __P((struct ifnet *, struct in6_addr *)); char *ip6_sprintf __P((struct in6_addr *)); int in6_matchlen __P((struct in6_addr *, struct in6_addr *)); -int in6_prefix_ioctl __P((u_long cmd, caddr_t data, struct ifnet *ifp)); +int in6_are_prefix_equal __P((struct in6_addr *p1, struct in6_addr *p2, + int len)); +void in6_prefixlen2mask __P((struct in6_addr *maskp, int len)); +int in6_prefix_ioctl __P((struct socket *so, u_long cmd, caddr_t data, + struct ifnet *ifp)); +int in6_prefix_add_ifid __P((int iilen, struct in6_ifaddr *ia)); +void in6_prefix_remove_ifid __P((int iilen, struct in6_ifaddr *ia)); #endif /* _KERNEL */ #endif /* _NETINET6_IN6_VAR_H_ */ diff --git a/sys/netinet6/ip6.h b/sys/netinet6/ip6.h index 550454669c6..7baa88afceb 100644 --- a/sys/netinet6/ip6.h +++ b/sys/netinet6/ip6.h @@ -1,4 +1,4 @@ -/* $NetBSD: ip6.h,v 1.5 1999/10/01 10:15:16 itojun Exp $ */ +/* $NetBSD: ip6.h,v 1.6 1999/12/13 15:17:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -99,11 +99,12 @@ struct ip6_hdr { #if BYTE_ORDER == BIG_ENDIAN #define IPV6_FLOWINFO_MASK 0x0fffffff /* flow info (28 bits) */ #define IPV6_FLOWLABEL_MASK 0x000fffff /* flow label (20 bits) */ -#endif /* BIG_ENDIAN */ +#else #if BYTE_ORDER == LITTLE_ENDIAN #define IPV6_FLOWINFO_MASK 0xffffff0f /* flow info (28 bits) */ #define IPV6_FLOWLABEL_MASK 0xffff0f00 /* flow label (20 bits) */ #endif /* LITTLE_ENDIAN */ +#endif #if 1 /* ECN bits proposed by Sally Floyd */ #define IP6TOS_CE 0x01 /* congestion experienced */ @@ -237,11 +238,50 @@ do { \ } \ else { \ if ((m)->m_len < (off) + (hlen)) { \ - ip6stat.ip6s_toosmall++; \ + ip6stat.ip6s_tooshort++; \ + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); \ m_freem(m); \ return ret; \ } \ } \ } while (0) +#ifdef __NetBSD__ +/* + * IP6_EXTHDR_GET ensures that intermediate protocol header (from "off" to + * "len") is located in single mbuf, on contiguous memory region. + * The pointer to the region will be returned to pointer variable "val", + * with type "typ". + * IP6_EXTHDR_GET0 does the same, except that it aligns the structure at the + * very top of mbuf. GET0 is likely to make memory copy than GET. + * + * XXX we're now testing this, needs m_pulldown() + */ +#define IP6_EXTHDR_GET(val, typ, m, off, len) \ +do { \ + struct mbuf *t; \ + int tmp; \ + t = m_pulldown((m), (off), (len), &tmp); \ + if (t) { \ + if (t->m_len < tmp + (len)) \ + panic("m_pulldown malfunction"); \ + (val) = (typ)(mtod(t, caddr_t) + tmp); \ + } else \ + (val) = (typ)NULL; \ +} while (0) + +#define IP6_EXTHDR_GET0(val, typ, m, off, len) \ +do { \ + struct mbuf *t; \ + t = m_pulldown((m), (off), (len), NULL); \ + if (t) { \ + if (t->m_len < (len)) \ + panic("m_pulldown malfunction"); \ + (val) = (typ)mtod(t, caddr_t); \ + } else \ + (val) = (typ)NULL; \ +} while (0) + +#endif /*NetBSD*/ + #endif /* not _NETINET_IPV6_H_ */ diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index 4cbfa727063..d58da2d9341 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_forward.c,v 1.4 1999/07/30 10:35:36 itojun Exp $ */ +/* $NetBSD: ip6_forward.c,v 1.5 1999/12/13 15:17:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -29,6 +29,11 @@ * SUCH DAMAGE. */ +#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) +#include "opt_ip6fw.h" +#include "opt_inet.h" +#endif + #include <sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> @@ -47,11 +52,25 @@ #include <netinet/in.h> #include <netinet/in_var.h> #include <netinet6/ip6.h> -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 -#include <netinet6/in6_pcb.h> -#endif #include <netinet6/ip6_var.h> #include <netinet6/icmp6.h> +#include <netinet6/nd6.h> + +#ifdef __OpenBSD__ /*KAME IPSEC*/ +#undef IPSEC +#endif + +#ifdef IPSEC_IPV6FWD +#include <netinet6/ipsec.h> +#include <netkey/key.h> +#include <netkey/key_debug.h> +#endif /* IPSEC_IPV6FWD */ + +#ifdef IPV6FIREWALL +#include <netinet6/ip6_fw.h> +#endif + +#include <net/net_osdep.h> struct route_in6 ip6_forward_rt; @@ -73,42 +92,199 @@ ip6_forward(m, srcrt) struct mbuf *m; int srcrt; { - register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); register struct sockaddr_in6 *dst; register struct rtentry *rt; int error, type = 0, code = 0; - struct mbuf *mcopy; + struct mbuf *mcopy = NULL; +#ifdef IPSEC_IPV6FWD + struct secpolicy *sp = NULL; +#endif +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) + long time_second = time.tv_sec; +#endif + +#ifdef IPSEC_IPV6FWD + /* + * Check AH/ESP integrity. + */ + /* + * Don't increment ip6s_cantforward because this is the check + * before forwarding packet actually. + */ + if (ipsec6_in_reject(m, NULL)) { + ipsec6stat.in_polvio++; + m_freem(m); + return; + } +#endif /*IPSEC_IPV6FWD*/ if (m->m_flags & (M_BCAST|M_MCAST) || in6_canforward(&ip6->ip6_src, &ip6->ip6_dst) == 0) { ip6stat.ip6s_cantforward++; ip6stat.ip6s_badscope++; -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 - if (ip6_log_time + ip6_log_interval < time.tv_sec) { - ip6_log_time = time.tv_sec; -#else + /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */ if (ip6_log_time + ip6_log_interval < time_second) { + char addr[INET6_ADDRSTRLEN]; ip6_log_time = time_second; -#endif + strncpy(addr, ip6_sprintf(&ip6->ip6_src), sizeof(addr)); log(LOG_DEBUG, "cannot forward " "from %s to %s nxt %d received on %s\n", - ip6_sprintf(&ip6->ip6_src), /* XXX meaningless */ - ip6_sprintf(&ip6->ip6_dst), + addr, ip6_sprintf(&ip6->ip6_dst), ip6->ip6_nxt, - m->m_pkthdr.rcvif->if_xname); + if_name(m->m_pkthdr.rcvif)); } m_freem(m); return; } if (ip6->ip6_hlim <= IPV6_HLIMDEC) { + /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */ icmp6_error(m, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT, 0); return; } ip6->ip6_hlim -= IPV6_HLIMDEC; + /* + * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU - + * size of IPv6 + ICMPv6 headers) bytes of the packet in case + * we need to generate an ICMP6 message to the src. + * Thanks to M_EXT, in most cases copy will not occur. + * + * It is important to save it before IPsec processing as IPsec + * processing may modify the mbuf. + */ + mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN)); + +#ifdef IPSEC_IPV6FWD + /* get a security policy for this packet */ + sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error); + if (sp == NULL) { + ipsec6stat.out_inval++; + ip6stat.ip6s_cantforward++; + if (mcopy) { +#if 0 + /* XXX: what icmp ? */ +#else + m_freem(mcopy); +#endif + } + m_freem(m); + return; + } + + error = 0; + + /* check policy */ + switch (sp->policy) { + case IPSEC_POLICY_DISCARD: + /* + * This packet is just discarded. + */ + ipsec6stat.out_polvio++; + ip6stat.ip6s_cantforward++; + key_freesp(sp); + if (mcopy) { +#if 0 + /* XXX: what icmp ? */ +#else + m_freem(mcopy); +#endif + } + m_freem(m); + return; + + case IPSEC_POLICY_BYPASS: + case IPSEC_POLICY_NONE: + /* no need to do IPsec. */ + key_freesp(sp); + goto skip_ipsec; + + case IPSEC_POLICY_IPSEC: + if (sp->req == NULL) { + /* XXX should be panic ? */ + printf("ip6_forward: No IPsec request specified.\n"); + ip6stat.ip6s_cantforward++; + key_freesp(sp); + if (mcopy) { +#if 0 + /* XXX: what icmp ? */ +#else + m_freem(mcopy); +#endif + } + m_freem(m); + return; + } + /* do IPsec */ + break; + + case IPSEC_POLICY_ENTRUST: + default: + /* should be panic ?? */ + printf("ip6_forward: Invalid policy found. %d\n", sp->policy); + key_freesp(sp); + goto skip_ipsec; + } + + { + struct ipsec_output_state state; + + /* + * All the extension headers will become inaccessible + * (since they can be encrypted). + * Don't panic, we need no more updates to extension headers + * on inner IPv6 packet (since they are now encapsulated). + * + * IPv6 [ESP|AH] IPv6 [extension headers] payload + */ + bzero(&state, sizeof(state)); + state.m = m; + state.ro = NULL; /* update at ipsec6_output_tunnel() */ + state.dst = NULL; /* update at ipsec6_output_tunnel() */ + + error = ipsec6_output_tunnel(&state, sp, 0); + + m = state.m; +#if 0 /* XXX allocate a route (ro, dst) again later */ + ro = (struct route_in6 *)state.ro; + dst = (struct sockaddr_in6 *)state.dst; +#endif + key_freesp(sp); + + if (error) { + /* mbuf is already reclaimed in ipsec6_output_tunnel. */ + switch (error) { + case EHOSTUNREACH: + case ENETUNREACH: + case EMSGSIZE: + case ENOBUFS: + case ENOMEM: + break; + default: + printf("ip6_output (ipsec): error code %d\n", error); + /*fall through*/ + case ENOENT: + /* don't show these error codes to the user */ + break; + } + ip6stat.ip6s_cantforward++; + if (mcopy) { +#if 0 + /* XXX: what icmp ? */ +#else + m_freem(mcopy); +#endif + } + m_freem(m); + return; + } + } + skip_ipsec: +#endif /* IPSEC_IPV6FWD */ + dst = &ip6_forward_rt.ro_dst; if (!srcrt) { /* @@ -121,18 +297,22 @@ ip6_forward(m, srcrt) ip6_forward_rt.ro_rt = 0; } /* this probably fails but give it a try again */ -#ifdef __NetBSD__ - rtalloc((struct route *)&ip6_forward_rt); -#else +#ifdef __FreeBSD__ rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING); +#else + rtalloc((struct route *)&ip6_forward_rt); #endif } if (ip6_forward_rt.ro_rt == 0) { ip6stat.ip6s_noroute++; - icmp6_error(m, ICMP6_DST_UNREACH, - ICMP6_DST_UNREACH_NOROUTE, 0); + /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */ + if (mcopy) { + icmp6_error(mcopy, ICMP6_DST_UNREACH, + ICMP6_DST_UNREACH_NOROUTE, 0); + } + m_freem(m); return; } } else if ((rt = ip6_forward_rt.ro_rt) == 0 || @@ -146,32 +326,37 @@ ip6_forward(m, srcrt) dst->sin6_family = AF_INET6; dst->sin6_addr = ip6->ip6_dst; -#ifdef __NetBSD__ - rtalloc((struct route *)&ip6_forward_rt); -#else +#ifdef __FreeBSD__ rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING); +#else + rtalloc((struct route *)&ip6_forward_rt); #endif if (ip6_forward_rt.ro_rt == 0) { ip6stat.ip6s_noroute++; - icmp6_error(m, ICMP6_DST_UNREACH, - ICMP6_DST_UNREACH_NOROUTE, 0); + /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */ + if (mcopy) { + icmp6_error(mcopy, ICMP6_DST_UNREACH, + ICMP6_DST_UNREACH_NOROUTE, 0); + } + m_freem(m); return; } } rt = ip6_forward_rt.ro_rt; - if (m->m_pkthdr.len > rt->rt_ifp->if_mtu){ - icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, rt->rt_ifp->if_mtu); + if (m->m_pkthdr.len > rt->rt_ifp->if_mtu) { + in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig); + if (mcopy) { + u_long mtu; + + mtu = rt->rt_ifp->if_mtu; + icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu); + } + m_freem(m); return; } if (rt->rt_flags & RTF_GATEWAY) dst = (struct sockaddr_in6 *)rt->rt_gateway; - /* - * Save at most 528 bytes of the packet in case - * we need to generate an ICMP6 message to the src. - * Thanks to M_EXT, in most cases copy will not occur. - */ - mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN)); /* * If we are to forward the packet using the same interface @@ -186,13 +371,35 @@ ip6_forward(m, srcrt) (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) type = ND_REDIRECT; +#ifdef IPV6FIREWALL + /* + * Check with the firewall... + */ + if (ip6_fw_chk_ptr) { + u_short port = 0; + /* If ipfw says divert, we have to just drop packet */ + if ((*ip6_fw_chk_ptr)(&ip6, rt->rt_ifp, &port, &m)) { + m_freem(m); + goto freecopy; + } + if (!m) + goto freecopy; + } +#endif + +#ifdef OLDIP6OUTPUT error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m, (struct sockaddr *)dst, ip6_forward_rt.ro_rt); - if (error) +#else + error = nd6_output(rt->rt_ifp, m, dst, rt); +#endif + if (error) { + in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard); ip6stat.ip6s_cantforward++; - else { + } else { ip6stat.ip6s_forward++; + in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward); if (type) ip6stat.ip6s_redirectsent++; else { @@ -235,4 +442,5 @@ ip6_forward(m, srcrt) freecopy: m_freem(mcopy); + return; } diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index ace4a02aae9..59d82c7b4d3 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_input.c,v 1.8 1999/10/01 10:15:16 itojun Exp $ */ +/* $NetBSD: ip6_input.c,v 1.9 1999/12/13 15:17:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -86,7 +86,7 @@ #include <sys/time.h> #include <sys/kernel.h> #include <sys/syslog.h> -#ifdef __NetBSD__ +#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) #include <sys/proc.h> #endif @@ -97,37 +97,54 @@ #include <net/netisr.h> #include <netinet/in.h> -#include <netinet6/in6_var.h> #include <netinet/in_systm.h> +#ifdef INET +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#endif /*INET*/ +#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) +#include <netinet/in_pcb.h> +#endif +#include <netinet6/in6_var.h> #include <netinet6/ip6.h> -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !((defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802)) #include <netinet6/in6_pcb.h> -#else -#include <netinet/in_pcb.h> #endif #include <netinet6/ip6_var.h> #include <netinet6/icmp6.h> #include <netinet6/in6_ifattach.h> #include <netinet6/nd6.h> +#include <netinet6/in6_prefix.h> -#ifdef INET -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#endif /*INET*/ +#ifdef IPV6FIREWALL +#include <netinet6/ip6_fw.h> +#endif #include <netinet6/ip6protosw.h> /* we need it for NLOOP. */ +#ifndef __bsdi__ #include "loop.h" +#endif #include "faith.h" #include "gif.h" #include "bpfilter.h" +#include <net/net_osdep.h> + +#ifdef __OpenBSD__ /*KAME IPSEC*/ +#undef IPSEC +#endif + extern struct domain inet6domain; extern struct ip6protosw inet6sw[]; #ifdef __bsdi__ +#if _BSDI_VERSION < 199802 extern struct ifnet loif; +#else +extern struct ifnet *loifp; +#endif #endif u_char ip6_protox[IPPROTO_MAX]; @@ -135,11 +152,17 @@ static int ip6qmaxlen = IFQ_MAXLEN; struct in6_ifaddr *in6_ifaddr; struct ifqueue ip6intrq; -#ifdef __NetBSD__ +#if defined(__NetBSD__) || defined(__OpenBSD__) extern struct ifnet loif[NLOOP]; +#endif int ip6_forward_srcrt; /* XXX */ int ip6_sourcecheck; /* XXX */ int ip6_sourcecheck_interval; /* XXX */ + +#ifdef IPV6FIREWALL +/* firewall hooks */ +ip6_fw_chk_t *ip6_fw_chk_ptr; +ip6_fw_ctl_t *ip6_fw_ctl_ptr; #endif struct ip6stat ip6stat; @@ -148,6 +171,13 @@ static void ip6_init2 __P((void *)); static int ip6_hopopts_input __P((u_int32_t *, u_int32_t *, struct mbuf **, int *)); +#if defined(PTR) +extern int ip6_protocol_tr; + +int ptr_in6 __P((struct mbuf *, struct mbuf **)); +extern void ip_forward __P((struct mbuf *, int)); +#endif + /* * IP6 initialization: fill in IP6 protocol switch table. * All protocols not implemented in kernel go to raw IP6 protocol handler. @@ -172,6 +202,9 @@ ip6_init() ip6intrq.ifq_maxlen = ip6qmaxlen; nd6_init(); frag6_init(); +#ifdef IPV6FIREWALL + ip6_fw_init(); +#endif /* * in many cases, random() here does NOT return random number * as initialization during bootstrap time occur in fixed order. @@ -179,28 +212,37 @@ ip6_init() microtime(&tv); ip6_flow_seq = random() ^ tv.tv_usec; +#ifndef __FreeBSD__ ip6_init2((void *)0); +#endif } static void ip6_init2(dummy) void *dummy; { - int i; + int ret; +#if defined(__bsdi__) && _BSDI_VERSION < 199802 + struct ifnet *loifp = &loif; +#endif + + /* get EUI64 from somewhere */ + ret = in6_ifattach_getifid(NULL); /* * to route local address of p2p link to loopback, * assign loopback address first. */ - for (i = 0; i < NLOOP; i++) - in6_ifattach(&loif[i], IN6_IFT_LOOP, NULL, 0); - - /* get EUI64 from somewhere, attach pseudo interfaces */ - if (in6_ifattach_getifid(NULL) == 0) - in6_ifattach_p2p(); +#ifdef __bsdi__ + in6_ifattach(loifp, IN6_IFT_LOOP, NULL, 0); +#else + in6_ifattach(&loif[0], IN6_IFT_LOOP, NULL, 0); +#endif /* nd6_timer_init */ timeout(nd6_timer, (caddr_t)0, hz); + /* router renumbering prefix list maintenance */ + timeout(in6_rr_timer, (caddr_t)0, hz); } #ifdef __FreeBSD__ @@ -237,11 +279,15 @@ void ip6_input(m) struct mbuf *m; { - register struct ip6_hdr *ip6; + struct ip6_hdr *ip6; int off = sizeof(struct ip6_hdr), nest; u_int32_t plen; u_int32_t rtalert = ~0; int nxt, ours = 0; + struct ifnet *deliverifp = NULL; +#if defined(__bsdi__) && _BSDI_VERSION < 199802 + struct ifnet *loifp = &loif; +#endif #ifdef IPSEC /* @@ -253,6 +299,7 @@ ip6_input(m) m->m_flags &= ~M_AUTHIPDGM; } #endif + /* * mbuf statistics by kazu */ @@ -263,8 +310,13 @@ ip6_input(m) ip6stat.ip6s_mext1++; } else { if (m->m_next) { - if (m->m_flags & M_LOOP) + if (m->m_flags & M_LOOP) { +#ifdef __bsdi__ + ip6stat.ip6s_m2m[loifp->if_index]++; /*XXX*/ +#else ip6stat.ip6s_m2m[loif[0].if_index]++; /*XXX*/ +#endif + } else if (m->m_pkthdr.rcvif->if_index <= 31) ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++; else @@ -273,40 +325,69 @@ ip6_input(m) ip6stat.ip6s_m1++; } - IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /*nothing*/); - + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive); ip6stat.ip6s_total++; - if (m->m_len < sizeof(struct ip6_hdr) && - (m = m_pullup(m, sizeof(struct ip6_hdr))) == 0) { - ip6stat.ip6s_toosmall++; - return; +#ifndef PULLDOWN_TEST + /* XXX is the line really necessary? */ + IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /*nothing*/); +#endif + + if (m->m_len < sizeof(struct ip6_hdr)) { + struct ifnet *inifp; + inifp = m->m_pkthdr.rcvif; + if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == 0) { + ip6stat.ip6s_toosmall++; + in6_ifstat_inc(inifp, ifs6_in_hdrerr); + return; + } } ip6 = mtod(m, struct ip6_hdr *); if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { ip6stat.ip6s_badvers++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); goto bad; } ip6stat.ip6s_nxthist[ip6->ip6_nxt]++; +#ifdef IPV6FIREWALL + /* + * Check with the firewall... + */ + if (ip6_fw_chk_ptr) { + u_short port = 0; + /* If ipfw says divert, we have to just drop packet */ + /* use port as a dummy argument */ + if ((*ip6_fw_chk_ptr)(&ip6, NULL, &port, &m)) { + m_freem(m); + m = NULL; + } + if (!m) + return; + } +#endif + /* * Scope check */ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) || IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) { ip6stat.ip6s_badscope++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) || IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) { if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) { ours = 1; + deliverifp = m->m_pkthdr.rcvif; goto hbhcheck; } else { ip6stat.ip6s_badscope++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } } @@ -314,6 +395,7 @@ ip6_input(m) if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) { if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) { ours = 1; + deliverifp = m->m_pkthdr.rcvif; goto hbhcheck; } } else { @@ -325,11 +407,39 @@ ip6_input(m) = htons(m->m_pkthdr.rcvif->if_index); } +#if defined(PTR) + /* + * + */ + if (ip6_protocol_tr) + { + struct mbuf *m1 = NULL; + + switch (ptr_in6(m, &m1)) + { + case IPPROTO_IP: goto mcastcheck; + case IPPROTO_IPV4: ip_forward(m1, 0); break; + case IPPROTO_IPV6: ip6_forward(m1, 0); break; + case IPPROTO_MAX: /* discard this packet */ + default: + } + + if (m != m1) + m_freem(m); + + return; + } + + mcastcheck: +#endif + /* * Multicast check */ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { struct in6_multi *in6m = 0; + + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mcast); /* * See if we belong to the destination multicast group on the * arrival interface. @@ -340,8 +450,10 @@ ip6_input(m) else if (!ip6_mrouter) { ip6stat.ip6s_notmember++; ip6stat.ip6s_cantforward++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); goto bad; } + deliverifp = m->m_pkthdr.rcvif; goto hbhcheck; } @@ -360,11 +472,10 @@ ip6_input(m) ip6_forward_rt.ro_dst.sin6_family = AF_INET6; ip6_forward_rt.ro_dst.sin6_addr = ip6->ip6_dst; -#if defined(__bsdi__) || defined(__NetBSD__) - rtalloc((struct route *)&ip6_forward_rt); -#endif #ifdef __FreeBSD__ rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING); +#else + rtalloc((struct route *)&ip6_forward_rt); #endif } @@ -391,12 +502,7 @@ ip6_input(m) IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &rt6_key(ip6_forward_rt.ro_rt)->sin6_addr) && #endif -#ifdef __bsdi__ - ip6_foward.rt.ro_rt->rt_ifp == &loif -#else - ip6_forward_rt.ro_rt->rt_ifp == &loif[0] -#endif - ) { + ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_LOOP) { struct in6_ifaddr *ia6 = (struct in6_ifaddr *)ip6_forward_rt.ro_rt->rt_ifa; /* packet to tentative address must not be received */ @@ -405,6 +511,7 @@ ip6_input(m) if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) { /* this interface is ready */ ours = 1; + deliverifp = ia6->ia_ifp; /* correct? */ goto hbhcheck; } else { /* this interface is not ready, fall through */ @@ -420,9 +527,34 @@ ip6_input(m) && ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_FAITH) { /* XXX do we need more sanity checks? */ ours = 1; + deliverifp = ip6_forward_rt.ro_rt->rt_ifp; /*faith*/ + goto hbhcheck; + } + } +#endif + +#if 0 + { + /* + * Last resort: check in6_ifaddr for incoming interface. + * The code is here until I update the "goto ours hack" code above + * working right. + */ + struct ifaddr *ifa; + for (ifa = m->m_pkthdr.rcvif->if_addrlist.tqh_first; + ifa; + ifa = ifa->ifa_list.tqe_next) { + if (ifa->ifa_addr == NULL) + continue; /* just for safety */ + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ip6->ip6_dst)) { + ours = 1; + deliverifp = ifa->ifa_ifp; goto hbhcheck; } } + } #endif /* @@ -431,6 +563,7 @@ ip6_input(m) */ if (!ip6_forwarding) { ip6stat.ip6s_cantforward++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); goto bad; } @@ -442,11 +575,28 @@ ip6_input(m) */ plen = (u_int32_t)ntohs(ip6->ip6_plen); if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { - if (ip6_hopopts_input(&plen, &rtalert, &m, &off)) + struct ip6_hbh *hbh; + + if (ip6_hopopts_input(&plen, &rtalert, &m, &off)) { +#if 0 /*touches NULL pointer*/ + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); +#endif return; /* m have already been freed */ + } /* adjust pointer */ ip6 = mtod(m, struct ip6_hdr *); - nxt = ((struct ip6_hbh *)(ip6 + 1))->ip6h_nxt; +#ifndef PULLDOWN_TEST + /* ip6_hopopts_input() ensures that mbuf is contiguous */ + hbh = (struct ip6_hbh *)(ip6 + 1); +#else + IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), + sizeof(struct ip6_hbh)); + if (hbh == NULL) { + ip6stat.ip6s_tooshort++; + return; + } +#endif + nxt = hbh->ip6h_nxt; /* * accept the packet if a router alert option is included @@ -465,6 +615,7 @@ ip6_input(m) */ if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { ip6stat.ip6s_tooshort++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); goto bad; } if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) { @@ -505,7 +656,17 @@ ip6_input(m) /* * Tell launch routine the next header */ +#if defined(__NetBSD__) && defined(IFA_STATS) + if (IFA_STATS && deliverifp != NULL) { + struct in6_ifaddr *ia6; + ip6 = mtod(m, struct ip6_hdr *); + ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst); + if (ia6) + ia6->ia_ifa.ifa_data.ifad_inbytes += m->m_pkthdr.len; + } +#endif ip6stat.ip6s_delivered++; + in6_ifstat_inc(deliverifp, ifs6_in_deliver); nest = 0; while (nxt != IPPROTO_DONE) { if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) { @@ -519,6 +680,7 @@ ip6_input(m) */ if (m->m_pkthdr.len < off) { ip6stat.ip6s_tooshort++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); goto bad; } @@ -546,12 +708,28 @@ ip6_hopopts_input(plenp, rtalertp, mp, offp) u_int8_t *opt; /* validation of the length of the header */ +#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(*hbh), -1); hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); hbhlen = (hbh->ip6h_len + 1) << 3; IP6_EXTHDR_CHECK(m, off, hbhlen, -1); hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); +#else + IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, + sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); + if (hbh == NULL) { + ip6stat.ip6s_tooshort++; + return -1; + } + hbhlen = (hbh->ip6h_len + 1) << 3; + IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), + hbhlen); + if (hbh == NULL) { + ip6stat.ip6s_tooshort++; + return -1; + } +#endif off += hbhlen; hbhlen -= sizeof(struct ip6_hbh); opt = (u_int8_t *)hbh + sizeof(struct ip6_hbh); @@ -725,22 +903,53 @@ ip6_unknown_opt(optp, m, off) } /* - * Create the "control" list for this pcb + * Create the "control" list for this pcb. + * + * The routine will be called from upper layer handlers like tcp6_input(). + * Thus the routine assumes that the caller (tcp6_input) have already + * called IP6_EXTHDR_CHECK() and all the extension headers are located in the + * very first mbuf on the mbuf chain. + * We may want to add some infinite loop prevention or sanity checks for safety. + * (This applies only when you are using KAME mbuf chain restriction, i.e. + * you are using IP6_EXTHDR_CHECK() not m_pulldown()) */ void ip6_savecontrol(in6p, mp, ip6, m) +#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(HAVE_NRL_INPCB) + register struct inpcb *in6p; +#else register struct in6pcb *in6p; +#endif register struct mbuf **mp; register struct ip6_hdr *ip6; register struct mbuf *m; { -#ifdef __NetBSD__ +#ifdef HAVE_NRL_INPCB +# define in6p_flags inp_flags +#endif +#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3) struct proc *p = curproc; /* XXX */ #endif #ifdef __bsdi__ # define sbcreatecontrol so_cmsg #endif + int privileged; + + privileged = 0; +#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3) + if (p && !suser(p->p_ucred, &p->p_acflag)) + privileged++; +#else +#ifdef HAVE_NRL_INPCB + if ((in6p->inp_socket->so_state & SS_PRIV) != 0) + privileged++; +#else + if ((in6p->in6p_socket->so_state & SS_PRIV) != 0) + privileged++; +#endif +#endif +#ifdef SO_TIMESTAMP if (in6p->in6p_socket->so_options & SO_TIMESTAMP) { struct timeval tv; @@ -750,6 +959,7 @@ ip6_savecontrol(in6p, mp, ip6, m) if (*mp) mp = &(*mp)->m_next; } +#endif if (in6p->in6p_flags & IN6P_RECVDSTADDR) { *mp = sbcreatecontrol((caddr_t) &ip6->ip6_dst, sizeof(struct in6_addr), IPV6_RECVDSTADDR, @@ -797,8 +1007,7 @@ ip6_savecontrol(in6p, mp, ip6, m) * be some hop-by-hop options which can be returned to normal user. * See RFC 2292 section 6. */ - if ((in6p->in6p_flags & IN6P_HOPOPTS) && - p && !suser(p->p_ucred, &p->p_acflag)) { + if ((in6p->in6p_flags & IN6P_HOPOPTS) && privileged) { /* * Check if a hop-by-hop options header is contatined in the * received packet, and if so, store the options as ancillary @@ -808,7 +1017,27 @@ ip6_savecontrol(in6p, mp, ip6, m) */ struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { - struct ip6_hbh *hbh = (struct ip6_hbh *)(ip6 + 1); + struct ip6_hbh *hbh; + int hbhlen; + +#ifndef PULLDOWN_TEST + hbh = (struct ip6_hbh *)(ip6 + 1); + hbhlen = (hbh->ip6h_len + 1) << 3; +#else + IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, + sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); + if (hbh == NULL) { + ip6stat.ip6s_tooshort++; + return; + } + hbhlen = (hbh->ip6h_len + 1) << 3; + IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, + sizeof(struct ip6_hdr), hbhlen); + if (hbh == NULL) { + ip6stat.ip6s_tooshort++; + return; + } +#endif /* * XXX: We copy whole the header even if a jumbo @@ -816,8 +1045,7 @@ ip6_savecontrol(in6p, mp, ip6, m) * be removed before returning in the RFC 2292. * But it's too painful operation... */ - *mp = sbcreatecontrol((caddr_t)hbh, - (hbh->ip6h_len + 1) << 3, + *mp = sbcreatecontrol((caddr_t)hbh, hbhlen, IPV6_HOPOPTS, IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; @@ -837,8 +1065,32 @@ ip6_savecontrol(in6p, mp, ip6, m) * the chain of ancillary data. */ while(1) { /* is explicit loop prevention necessary? */ - struct ip6_ext *ip6e = - (struct ip6_ext *)(mtod(m, caddr_t) + off); + struct ip6_ext *ip6e; + int elen; + +#ifndef PULLDOWN_TEST + ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off); + if (nxt == IPPROTO_AH) + elen = (ip6e->ip6e_len + 2) << 2; + else + elen = (ip6e->ip6e_len + 1) << 3; +#else + IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off, + sizeof(struct ip6_ext)); + if (ip6e == NULL) { + ip6stat.ip6s_tooshort++; + return; + } + if (nxt == IPPROTO_AH) + elen = (ip6e->ip6e_len + 2) << 2; + else + elen = (ip6e->ip6e_len + 1) << 3; + IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off, elen); + if (ip6e == NULL) { + ip6stat.ip6s_tooshort++; + return; + } +#endif switch(nxt) { case IPPROTO_DSTOPTS: @@ -850,11 +1102,10 @@ ip6_savecontrol(in6p, mp, ip6, m) * the option. * See the comments on IN6_HOPOPTS. */ - if (!p || !suser(p->p_ucred, &p->p_acflag)) + if (!privileged) break; - *mp = sbcreatecontrol((caddr_t)ip6e, - (ip6e->ip6e_len + 1) << 3, + *mp = sbcreatecontrol((caddr_t)ip6e, elen, IPV6_DSTOPTS, IPPROTO_IPV6); if (*mp) @@ -865,8 +1116,7 @@ ip6_savecontrol(in6p, mp, ip6, m) if (!in6p->in6p_flags & IN6P_RTHDR) break; - *mp = sbcreatecontrol((caddr_t)ip6e, - (ip6e->ip6e_len + 1) << 3, + *mp = sbcreatecontrol((caddr_t)ip6e, elen, IPV6_RTHDR, IPPROTO_IPV6); if (*mp) @@ -889,20 +1139,15 @@ ip6_savecontrol(in6p, mp, ip6, m) } /* proceed with the next header. */ - if (nxt == IPPROTO_AH) - off += (ip6e->ip6e_len + 2) << 2; - else - off += (ip6e->ip6e_len + 1) << 3; + off += elen; nxt = ip6e->ip6e_nxt; } loopend: } - if ((in6p->in6p_flags & IN6P_HOPOPTS) - && p && !suser(p->p_ucred, &p->p_acflag)) { + if ((in6p->in6p_flags & IN6P_HOPOPTS) && privileged) { /* to be done */ } - if ((in6p->in6p_flags & IN6P_DSTOPTS) - && p && !suser(p->p_ucred, &p->p_acflag)) { + if ((in6p->in6p_flags & IN6P_DSTOPTS) && privileged) { /* to be done */ } /* IN6P_RTHDR - to be done */ @@ -910,6 +1155,9 @@ ip6_savecontrol(in6p, mp, ip6, m) #ifdef __bsdi__ # undef sbcreatecontrol #endif +#ifdef __OpenBSD__ +# undef in6p_flags +#endif } /* @@ -975,7 +1223,7 @@ u_char inet6ctlerrmap[PRC_NCMDS] = { ENOPROTOOPT }; -#ifdef __NetBSD__ +#if defined(__NetBSD__) || defined(__OpenBSD__) #include <vm/vm.h> #include <sys/sysctl.h> @@ -1029,9 +1277,40 @@ ip6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) &ip6_gif_hlim); case IPV6CTL_KAME_VERSION: return sysctl_rdstring(oldp, oldlenp, newp, __KAME_VERSION); + case IPV6CTL_USE_DEPRECATED: + return sysctl_int(oldp, oldlenp, newp, newlen, + &ip6_use_deprecated); default: return EOPNOTSUPP; } /* NOTREACHED */ } -#endif /* __NetBSD__ */ +#endif /* __NetBSD__ || __OpenBSD__ */ + +#ifdef __bsdi__ +int *ip6_sysvars[] = IPV6CTL_VARS; + +int +ip6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; +{ + if (name[0] >= IPV6CTL_MAXID) + return (EOPNOTSUPP); + + switch (name[0]) { + case IPV6CTL_STATS: + return sysctl_rdtrunc(oldp, oldlenp, newp, &ip6stat, + sizeof(ip6stat)); + case IPV6CTL_KAME_VERSION: + return sysctl_rdstring(oldp, oldlenp, newp, __KAME_VERSION); + default: + return (sysctl_int_arr(ip6_sysvars, name, namelen, + oldp, oldlenp, newp, newlen)); + } +} +#endif /* __bsdi__ */ diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c index 77e8cf09828..5614f2eb0d3 100644 --- a/sys/netinet6/ip6_mroute.c +++ b/sys/netinet6/ip6_mroute.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_mroute.c,v 1.7 1999/07/22 15:46:13 itojun Exp $ */ +/* $NetBSD: ip6_mroute.c,v 1.8 1999/12/13 15:17:22 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -48,8 +48,17 @@ #include "opt_inet.h" #endif +#ifndef _KERNEL +# ifdef KERNEL +# define _KERNEL +# endif +#endif + #include <sys/param.h> #include <sys/systm.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/malloc.h> +#endif #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/socketvar.h> @@ -58,7 +67,7 @@ #include <sys/errno.h> #include <sys/time.h> #include <sys/kernel.h> -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) #include <sys/ioctl.h> #endif #include <sys/syslog.h> @@ -76,13 +85,19 @@ #include <netinet6/pim6.h> #include <netinet6/pim6_var.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +static MALLOC_DEFINE(M_MRTABLE, "mf6c", "multicast forwarding cache entry"); +#endif + #define M_HASCL(m) ((m)->m_flags & M_EXT) static int ip6_mdq __P((struct mbuf *, struct ifnet *, struct mf6c *)); static void phyint_send __P((struct ip6_hdr *, struct mif6 *, struct mbuf *)); static int set_pim6 __P((int *)); +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) static int get_pim6 __P((struct mbuf *)); +#endif static int socket_send __P((struct socket *, struct mbuf *, struct sockaddr_in6 *)); static int register_send __P((struct ip6_hdr *, struct mif6 *, @@ -142,6 +157,10 @@ static mifi_t reg_mif_num = (mifi_t)-1; static struct pim6stat pim6stat; +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +static struct callout_handle expire_upcalls_ch; +#endif + /* * one-back cache used by ipip_input to locate a tunnel's mif * given a datagram's src ip address. @@ -221,6 +240,54 @@ static int del_m6fc __P((struct mf6cctl *)); /* * Handle MRT setsockopt commands to modify the multicast routing tables. */ +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +int +ip6_mrouter_set(so, sopt) + struct socket *so; + struct sockopt *sopt; +{ + int error = 0; + struct mbuf *m; + + if (so != ip6_mrouter && sopt->sopt_name != MRT6_INIT) + return (EACCES); + + if (error = soopt_getm(sopt, &m)) /* XXX */ + return (error); + if (error = soopt_mcopyin(sopt, m)) /* XXX */ + return (error); + + switch (sopt->sopt_name) { + case MRT6_INIT: + error = ip6_mrouter_init(so, m); + break; + case MRT6_DONE: + error = ip6_mrouter_done(); + break; + case MRT6_ADD_MIF: + error = add_m6if(mtod(m, struct mif6ctl *)); + break; + case MRT6_DEL_MIF: + error = del_m6if(mtod(m, mifi_t *)); + break; + case MRT6_ADD_MFC: + error = add_m6fc(mtod(m, struct mf6cctl *)); + break; + case MRT6_DEL_MFC: + error = del_m6fc(mtod(m, struct mf6cctl *)); + break; + case MRT6_PIM: + error = set_pim6(mtod(m, int *)); + break; + default: + error = EOPNOTSUPP; + break; + } + + (void)m_freem(m); + return(error); +} +#else int ip6_mrouter_set(cmd, so, m) int cmd; @@ -241,10 +308,29 @@ ip6_mrouter_set(cmd, so, m) default: return EOPNOTSUPP; } } +#endif /* * Handle MRT getsockopt commands */ +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +int +ip6_mrouter_get(so, sopt) + struct socket *so; + struct sockopt *sopt; +{ + int error = 0; + + if (so != ip6_mrouter) return EACCES; + + switch (sopt->sopt_name) { + case MRT6_PIM: + error = sooptcopyout(sopt, &pim6, sizeof(pim6)); + break; + } + return (error); +} +#else int ip6_mrouter_get(cmd, so, m) int cmd; @@ -264,6 +350,7 @@ ip6_mrouter_get(cmd, so, m) return EOPNOTSUPP; } } +#endif /* * Handle ioctl commands to obtain information from the cache @@ -299,7 +386,11 @@ get_sg_cnt(req) register struct mf6c *rt; int s; +#ifdef __NetBSD__ s = splsoftnet(); +#else + s = splnet(); +#endif MF6CFIND(req->src.sin6_addr, req->grp.sin6_addr, rt); splx(s); if (rt != NULL) { @@ -335,6 +426,7 @@ get_mif6_cnt(req) return 0; } +#if !(defined(__FreeBSD__) && __FreeBSD__ >=3) /* * Get PIM processiong global */ @@ -350,6 +442,7 @@ get_pim6(m) return 0; } +#endif static int set_pim6(i) @@ -400,6 +493,9 @@ ip6_mrouter_init(so, m) pim6 = 0;/* used for stubbing out/in pim stuff */ +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + expire_upcalls_ch = +#endif timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT); #ifdef MRT6DEBUG @@ -424,7 +520,11 @@ ip6_mrouter_done() struct rtdetq *rte; int s; +#ifdef __NetBSD__ s = splsoftnet(); +#else + s = splnet(); +#endif /* * For each phyint in use, disable promiscuous reception of all IPv6 @@ -462,7 +562,11 @@ ip6_mrouter_done() pim6 = 0; /* used to stub out/in pim specific code */ - untimeout(expire_upcalls, (caddr_t)NULL); + untimeout(expire_upcalls, (caddr_t)NULL +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + , expire_upcalls_ch +#endif + ); /* * Free all multicast forwarding cache entries. @@ -515,7 +619,9 @@ add_m6if(mifcp) { register struct mif6 *mifp; struct ifnet *ifp; +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) struct in6_ifreq ifr; +#endif int error, s; #ifdef notyet struct tbf *m_tbf = tbftable + mifcp->mif6c_mifi; @@ -532,7 +638,7 @@ add_m6if(mifcp) if (mifcp->mif6c_flags & MIFF_REGISTER) { if (reg_mif_num == (mifi_t)-1) { -#ifdef __NetBSD__ +#if defined(__NetBSD__) || defined(__OpenBSD__) strcpy(multicast_register_if.if_xname, "register_mif"); /* XXX */ #else @@ -551,20 +657,32 @@ add_m6if(mifcp) if ((ifp->if_flags & IFF_MULTICAST) == 0) return EOPNOTSUPP; +#ifdef __NetBSD__ + s = splsoftnet(); +#else + s = splnet(); +#endif +#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) + error = if_allmulti(ifp, 1); +#else /* * Enable promiscuous reception of all IPv6 multicasts - * from the if + * from the interface. */ ifr.ifr_addr.sin6_family = AF_INET6; ifr.ifr_addr.sin6_addr = in6addr_any; - s = splsoftnet(); error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr); +#endif splx(s); if (error) return error; } +#ifdef __NetBSD__ s = splsoftnet(); +#else + s = splnet(); +#endif mifp->m6_flags = mifcp->mif6c_flags; mifp->m6_ifp = ifp; #ifdef notyet @@ -603,7 +721,9 @@ del_m6if(mifip) register struct mif6 *mifp = mif6table + *mifip; register mifi_t mifi; struct ifnet *ifp; +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) struct in6_ifreq ifr; +#endif int s; if (*mifip >= nummifs) @@ -611,17 +731,26 @@ del_m6if(mifip) if (mifp->m6_ifp == NULL) return EINVAL; +#ifdef __NetBSD__ s = splsoftnet(); +#else + s = splnet(); +#endif if (!(mifp->m6_flags & MIFF_REGISTER)) { /* * XXX: what if there is yet IPv4 multicast daemon * using the interface? */ + ifp = mifp->m6_ifp; + +#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) + if_allmulti(ifp, 0); +#else ifr.ifr_addr.sin6_family = AF_INET6; ifr.ifr_addr.sin6_addr = in6addr_any; - ifp = mifp->m6_ifp; (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr); +#endif } #ifdef notyet @@ -672,7 +801,11 @@ add_m6fc(mfccp) mfccp->mf6cc_parent); #endif +#ifdef __NetBSD__ s = splsoftnet(); +#else + s = splnet(); +#endif rt->mf6c_parent = mfccp->mf6cc_parent; rt->mf6c_ifset = mfccp->mf6cc_ifset; splx(s); @@ -682,7 +815,11 @@ add_m6fc(mfccp) /* * Find the entry for which the upcall was made and update */ +#ifdef __NetBSD__ s = splsoftnet(); +#else + s = splnet(); +#endif hash = MF6CHASH(mfccp->mf6cc_origin.sin6_addr, mfccp->mf6cc_mcastgrp.sin6_addr); for (rt = mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) { @@ -850,7 +987,11 @@ del_m6fc(mfccp) ip6_sprintf(&mcastgrp.sin6_addr)); #endif +#ifdef __NetBSD__ s = splsoftnet(); +#else + s = splnet(); +#endif nptr = &mf6ctable[hash]; while ((rt = *nptr) != NULL) { @@ -936,7 +1077,11 @@ ip6_mforward(ip6, ifp, m) /* * Determine forwarding mifs from the forwarding cache table */ +#ifdef __NetBSD__ s = splsoftnet(); +#else + s = splnet(); +#endif MF6CFIND(ip6->ip6_src, ip6->ip6_dst, rt); /* Entry exists, so forward if necessary */ @@ -1066,7 +1211,11 @@ ip6_mforward(ip6, ifp, m) /* insert new entry at head of hash chain */ bzero(rt, sizeof(*rt)); + rt->mf6c_origin.sin6_family = AF_INET6; + rt->mf6c_origin.sin6_len = sizeof(struct sockaddr_in6); rt->mf6c_origin.sin6_addr = ip6->ip6_src; + rt->mf6c_mcastgrp.sin6_family = AF_INET6; + rt->mf6c_mcastgrp.sin6_len = sizeof(struct sockaddr_in6); rt->mf6c_mcastgrp.sin6_addr = ip6->ip6_dst; rt->mf6c_expire = UPCALL_EXPIRE; nexpire[hash]++; @@ -1121,7 +1270,11 @@ expire_upcalls(unused) int i; int s; +#ifdef __NetBSD__ s = splsoftnet(); +#else + s = splnet(); +#endif for (i = 0; i < MF6CTBLSIZ; i++) { if (nexpire[i] == 0) continue; @@ -1163,6 +1316,9 @@ expire_upcalls(unused) } } splx(s); +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + expire_upcalls_ch = +#endif timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT); } @@ -1300,7 +1456,11 @@ phyint_send(ip6, mifp, m) register struct mbuf *mb_copy; struct ifnet *ifp = mifp->m6_ifp; int error = 0; +#ifdef __NetBSD__ int s = splsoftnet(); +#else + int s = splnet(); +#endif static struct route_in6 ro6; struct in6_multi *in6m; @@ -1333,7 +1493,7 @@ phyint_send(ip6, mifp, m) im6o.im6o_multicast_hlim = ip6->ip6_hlim; im6o.im6o_multicast_loop = 1; error = ip6_output(mb_copy, NULL, &ro6, - IPV6_FORWARDING, &im6o); + IPV6_FORWARDING, &im6o, NULL); #ifdef MRT6DEBUG if (mrt6debug & DEBUG_XMIT) @@ -1363,6 +1523,10 @@ phyint_send(ip6, mifp, m) ro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6); ro6.ro_dst.sin6_family = AF_INET6; ro6.ro_dst.sin6_addr = ip6->ip6_dst; + /* + * We just call if_output instead of nd6_output here, since + * we need no ND for a multicast forwarded packet...right? + */ error = (*ifp->if_output)(ifp, mb_copy, (struct sockaddr *)&ro6.ro_dst, NULL); @@ -1521,12 +1685,20 @@ pim6_input(mp, offp, proto) * Make sure that the IP6 and PIM headers in contiguous memory, and * possibly the PIM REGISTER header */ +#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, minlen, IPPROTO_DONE); - /* adjust pointer */ + /* adjust pointer */ ip6 = mtod(m, struct ip6_hdr *); /* adjust mbuf to point to the PIM header */ pim = (struct pim *)((caddr_t)ip6 + off); +#else + IP6_EXTHDR_GET(pim, struct pim *, m, off, minlen); + if (pim == NULL) { + pim6stat.pim6s_rcv_tooshort++; + return IPPROTO_DONE; + } +#endif #define PIM6_CHECKSUM #ifdef PIM6_CHECKSUM diff --git a/sys/netinet6/ip6_mroute.h b/sys/netinet6/ip6_mroute.h index 7eb5c55ec6d..d0c09b77674 100644 --- a/sys/netinet6/ip6_mroute.h +++ b/sys/netinet6/ip6_mroute.h @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_mroute.h,v 1.5 1999/12/02 05:25:47 itojun Exp $ */ +/* $NetBSD: ip6_mroute.h,v 1.6 1999/12/13 15:17:23 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -119,7 +119,6 @@ struct mf6cctl { /* * The kernel's multicast routing statistics. */ -#if defined(__bsdi__) || defined(__NetBSD__) struct mrt6stat { u_quad_t mrt6s_mfc_lookups; /* # forw. cache hash table hits */ u_quad_t mrt6s_mfc_misses; /* # forw. cache hash table misses */ @@ -135,23 +134,6 @@ struct mrt6stat { u_quad_t mrt6s_pkt2large; /* pkts dropped - size > BKT SIZE */ u_quad_t mrt6s_upq_sockfull; /* upcalls dropped - socket full */ }; -#else -struct mrt6stat { - u_long mrt6s_mfc_lookups; /* # forw. cache hash table hits */ - u_long mrt6s_mfc_misses; /* # forw. cache hash table misses */ - u_long mrt6s_upcalls; /* # calls to mrouted */ - u_long mrt6s_no_route; /* no route for packet's origin */ - u_long mrt6s_bad_tunnel; /* malformed tunnel options */ - u_long mrt6s_cant_tunnel; /* no room for tunnel options */ - u_long mrt6s_wrong_if; /* arrived on wrong interface */ - u_long mrt6s_upq_ovflw; /* upcall Q overflow */ - u_long mrt6s_cache_cleanups; /* # entries with no upcalls */ - u_long mrt6s_drop_sel; /* pkts dropped selectively */ - u_long mrt6s_q_overflow; /* pkts dropped - Q overflow */ - u_long mrt6s_pkt2large; /* pkts dropped - size > BKT SIZE */ - u_long mrt6s_upq_sockfull; /* upcalls dropped - socket full */ -}; -#endif /* * Struct used to communicate from kernel to multicast router @@ -170,26 +152,15 @@ struct mrt6msg { }; /* - * Argument structure used by mrouted to get src-grp pkt counts - */ -struct sioc6_sg_req { - struct in6_addr src; - struct in6_addr grp; - u_long pktcnt; - u_long bytecnt; - u_long wrong_if; -}; - -/* * Argument structure used by multicast routing daemon to get src-grp * packet counts */ struct sioc_sg_req6 { struct sockaddr_in6 src; struct sockaddr_in6 grp; - u_long pktcnt; - u_long bytecnt; - u_long wrong_if; + u_quad_t pktcnt; + u_quad_t bytecnt; + u_quad_t wrong_if; }; /* @@ -197,10 +168,10 @@ struct sioc_sg_req6 { */ struct sioc_mif_req6 { mifi_t mifi; /* mif number */ - u_long icount; /* Input packet count on mif */ - u_long ocount; /* Output packet count on mif */ - u_long ibytes; /* Input byte count on mif */ - u_long obytes; /* Output byte count on mif */ + u_quad_t icount; /* Input packet count on mif */ + u_quad_t ocount; /* Output packet count on mif */ + u_quad_t ibytes; /* Input byte count on mif */ + u_quad_t obytes; /* Output byte count on mif */ }; #ifdef _KERNEL @@ -215,10 +186,10 @@ struct mif6 { #endif struct in6_addr m6_lcl_addr; /* local interface address */ struct ifnet *m6_ifp; /* pointer to interface */ - u_long m6_pkt_in; /* # pkts in on interface */ - u_long m6_pkt_out; /* # pkts out on interface */ - u_long m6_bytes_in; /* # bytes in on interface */ - u_long m6_bytes_out; /* # bytes out on interface */ + u_quad_t m6_pkt_in; /* # pkts in on interface */ + u_quad_t m6_pkt_out; /* # pkts out on interface */ + u_quad_t m6_bytes_in; /* # bytes in on interface */ + u_quad_t m6_bytes_out; /* # bytes out on interface */ struct route_in6 m6_route;/* cached route if this is a tunnel */ #ifdef notyet u_int m6_rsvp_on; /* RSVP listening on this vif */ @@ -235,9 +206,9 @@ struct mf6c { mifi_t mf6c_parent; /* incoming IF */ struct if_set mf6c_ifset; /* set of outgoing IFs */ - u_long mf6c_pkt_cnt; /* pkt count for src-grp */ - u_long mf6c_byte_cnt; /* byte count for src-grp */ - u_long mf6c_wrong_if; /* wrong if for src-grp */ + u_quad_t mf6c_pkt_cnt; /* pkt count for src-grp */ + u_quad_t mf6c_byte_cnt; /* byte count for src-grp */ + u_quad_t mf6c_wrong_if; /* wrong if for src-grp */ int mf6c_expire; /* time to clean entry up */ struct timeval mf6c_last_assert; /* last time I sent an assert*/ struct rtdetq *mf6c_stall; /* pkts waiting for route */ diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 86ad6ec08f1..b539a512d66 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_output.c,v 1.8 1999/07/31 18:41:16 itojun Exp $ */ +/* $NetBSD: ip6_output.c,v 1.9 1999/12/13 15:17:23 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -82,6 +82,12 @@ #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/systm.h> +#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) +#include <sys/kernel.h> +#endif +#if defined(__bsdi__) && _BSDI_VERSION >= 199802 +#include <machine/pcpu.h> +#endif #include <sys/proc.h> #include <net/if.h> @@ -89,23 +95,43 @@ #include <netinet/in.h> #include <netinet/in_var.h> +#if defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#endif #include <netinet6/ip6.h> #include <netinet6/icmp6.h> -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 -#include <netinet6/in6_pcb.h> -#else +#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) #include <netinet/in_pcb.h> +#else +#include <netinet6/in6_pcb.h> #endif #include <netinet6/ip6_var.h> #include <netinet6/nd6.h> +#ifdef __OpenBSD__ /*KAME IPSEC*/ +#undef IPSEC +#endif + #ifdef IPSEC #include <netinet6/ipsec.h> #include <netkey/key.h> #include <netkey/key_debug.h> #endif /* IPSEC */ +#ifndef __bsdi__ #include "loop.h" +#endif + +#include <net/net_osdep.h> + +#ifdef IPV6FIREWALL +#include <netinet6/ip6_fw.h> +#endif + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +static MALLOC_DEFINE(M_IPMOPTS, "ip6_moptions", "internet multicast options"); +#endif struct ip6_exthdrs { struct mbuf *ip6e_ip6; @@ -124,8 +150,12 @@ static int ip6_insertfraghdr __P((struct mbuf *, struct mbuf *, int, struct ip6_frag **)); static int ip6_insert_jumboopt __P((struct ip6_exthdrs *, u_int32_t)); static int ip6_splithdr __P((struct mbuf *, struct ip6_exthdrs *)); -#ifdef __bsdi__ +#if (defined(__bsdi__) && _BSDI_VERSION < 199802) || defined(__OpenBSD__) extern struct ifnet loif; +struct ifnet *loifp = &loif; +#endif +#if defined(__bsdi__) && _BSDI_VERSION >= 199802 +extern struct ifnet *loifp; #endif #ifdef __NetBSD__ @@ -141,12 +171,13 @@ extern struct ifnet loif[NLOOP]; * The mbuf opt, if present, will not be freed. */ int -ip6_output(m0, opt, ro, flags, im6o) +ip6_output(m0, opt, ro, flags, im6o, ifpp) struct mbuf *m0; struct ip6_pktopts *opt; struct route_in6 *ro; int flags; struct ip6_moptions *im6o; + struct ifnet **ifpp; /* XXX: just for statistics */ { struct ip6_hdr *ip6, *mhip6; struct ifnet *ifp; @@ -246,10 +277,11 @@ ip6_output(m0, opt, ro, flags, im6o) * Calculate the total length of the extension header chain. * Keep the length of the unfragmentable part for fragmentation. */ + optlen = 0; if (exthdrs.ip6e_hbh) optlen += exthdrs.ip6e_hbh->m_len; if (exthdrs.ip6e_dest1) optlen += exthdrs.ip6e_dest1->m_len; if (exthdrs.ip6e_rthdr) optlen += exthdrs.ip6e_rthdr->m_len; - unfragpartlen = plen + sizeof(struct ip6_hdr); + unfragpartlen = optlen + sizeof(struct ip6_hdr); /* NOTE: we don't add AH/ESP length here. do that later. */ if (exthdrs.ip6e_dest2) optlen += exthdrs.ip6e_dest2->m_len; @@ -294,11 +326,12 @@ ip6_output(m0, opt, ro, flags, im6o) /* * Concatenate headers and fill in next header fields. * Here we have, on "m" - * IPv6 payload or - * IPv6 [esp* dest2 payload] + * IPv6 payload * and we insert headers accordingly. Finally, we should be getting: - * IPv6 hbh dest1 rthdr ah* dest2 payload or * IPv6 hbh dest1 rthdr ah* [esp* dest2 payload] + * + * during the header composing process, "m" points to IPv6 header. + * "mprev" points to an extension header prior to esp. */ { u_char *nexthdrp = &ip6->ip6_nxt; @@ -307,10 +340,15 @@ ip6_output(m0, opt, ro, flags, im6o) /* * we treat dest2 specially. this makes IPsec processing * much easier. + * + * result: IPv6 dest2 payload + * m and mprev will point to IPv6 header. */ if (exthdrs.ip6e_dest2) { if (!hdrsplit) panic("assumption failed: hdr not split"); + exthdrs.ip6e_dest2->m_next = m->m_next; + m->m_next = exthdrs.ip6e_dest2; *mtod(exthdrs.ip6e_dest2, u_char *) = ip6->ip6_nxt; ip6->ip6_nxt = IPPROTO_DSTOPTS; } @@ -328,6 +366,11 @@ ip6_output(m0, opt, ro, flags, im6o) (mp) = (m);\ }\ } + /* + * result: IPv6 hbh dest1 rthdr dest2 payload + * m will point to IPv6 header. mprev will point to the + * extension header prior to dest2 (rthdr in the above case). + */ MAKE_CHAIN(exthdrs.ip6e_hbh, mprev, nexthdrp, IPPROTO_HOPOPTS); MAKE_CHAIN(exthdrs.ip6e_dest1, mprev, @@ -522,9 +565,9 @@ skip_ipsec2:; * ifp must point it. */ if (ro->ro_rt == 0) { -#ifdef __NetBSD__ +#if defined(__NetBSD__) || defined(__OpenBSD__) /* - * NetBSD always clones routes, if parent is + * NetBSD/OpenBSD always clones routes, if parent is * PRF_CLONING. */ rtalloc((struct route *)ro); @@ -538,6 +581,7 @@ skip_ipsec2:; if (ro->ro_rt == 0) { ip6stat.ip6s_noroute++; error = EHOSTUNREACH; + /* XXX in6_ifstat_inc(ifp, ifs6_out_discard); */ goto bad; } ia = ifatoia6(ro->ro_rt->rt_ifa); @@ -547,6 +591,8 @@ skip_ipsec2:; dst = (struct sockaddr_in6 *)ro->ro_rt->rt_gateway; m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */ + in6_ifstat_inc(ifp, ifs6_out_request); + /* * Check if there is the outgoing interface conflicts with * the interface specified by ifi6_ifindex(if specified). @@ -559,6 +605,7 @@ skip_ipsec2:; if (!(ifp->if_flags & IFF_LOOPBACK) && ifp->if_index != opt->ip6po_pktinfo->ipi6_ifindex) { ip6stat.ip6s_noroute++; + in6_ifstat_inc(ifp, ifs6_out_discard); error = EHOSTUNREACH; goto bad; } @@ -603,6 +650,8 @@ skip_ipsec2:; if (ifp && (ifp->if_flags & IFF_LOOPBACK) == 0) { ip6stat.ip6s_badscope++; error = ENETUNREACH; /* XXX: better error? */ + /* XXX correct ifp? */ + in6_ifstat_inc(ifp, ifs6_out_discard); goto bad; } else { @@ -626,29 +675,34 @@ skip_ipsec2:; */ if (ifp == NULL) { if (ro->ro_rt == 0) { -#ifdef __FreeBSD__ - ro->ro_rt = rtalloc1((struct sockaddr *) - &ro->ro_dst, 0, 0UL); -#endif /*__FreeBSD__*/ -#if defined(__bsdi__) || defined(__NetBSD__) ro->ro_rt = rtalloc1((struct sockaddr *) - &ro->ro_dst, 0); -#endif /*__bsdi__*/ + &ro->ro_dst, 0 +#ifdef __FreeBSD__ + , 0UL +#endif + ); } if (ro->ro_rt == 0) { ip6stat.ip6s_noroute++; error = EHOSTUNREACH; + /* XXX in6_ifstat_inc(ifp, ifs6_out_discard) */ goto bad; } ia = ifatoia6(ro->ro_rt->rt_ifa); ifp = ro->ro_rt->rt_ifp; ro->ro_rt->rt_use++; } + + if ((flags & IPV6_FORWARDING) == 0) + in6_ifstat_inc(ifp, ifs6_out_request); + in6_ifstat_inc(ifp, ifs6_out_mcast); + /* * Confirm that the outgoing interface supports multicast. */ if ((ifp->if_flags & IFF_MULTICAST) == 0) { ip6stat.ip6s_noroute++; + in6_ifstat_inc(ifp, ifs6_out_discard); error = ENETUNREACH; goto bad; } @@ -696,6 +750,13 @@ skip_ipsec2:; } /* + * Fill the outgoing inteface to tell the upper layer + * to increment per-interface statistics. + */ + if (ifpp) + *ifpp = ifp; + + /* * Determine path MTU. */ if (ro_pmtu != ro) { @@ -714,7 +775,7 @@ skip_ipsec2:; sin6_fin->sin6_len = sizeof(struct sockaddr_in6); sin6_fin->sin6_addr = finaldst; -#if 0 +#ifdef __FreeBSD__ rtcalloc((struct route *)ro_pmtu); #else rtalloc((struct route *)ro_pmtu); @@ -805,11 +866,22 @@ skip_ipsec2:; #endif ) { -#ifdef NEWIP6OUTPUT - error = nd6_output(ifp, m, dst, ro->ro_rt); -#else +#if defined(__NetBSD__) && defined(IFA_STATS) + if (IFA_STATS) { + struct in6_ifaddr *ia6; + ip6 = mtod(m, struct ip6_hdr *); + ia6 = in6_ifawithifp(ifp, &ip6->ip6_src); + if (ia6) { + ia->ia_ifa.ifa_data.ifad_outbytes += + m->m_pkthdr.len; + } + } +#endif +#ifdef OLDIP6OUTPUT error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, ro->ro_rt); +#else + error = nd6_output(ifp, m, dst, ro->ro_rt); #endif goto done; } else if (mtu < IPV6_MMTU) { @@ -818,9 +890,11 @@ skip_ipsec2:; * (see icmp6_input). */ error = EMSGSIZE; + in6_ifstat_inc(ifp, ifs6_out_fragfail); goto bad; } else if (ip6->ip6_plen == 0) { /* jumbo payload cannot be fragmented */ error = EMSGSIZE; + in6_ifstat_inc(ifp, ifs6_out_fragfail); goto bad; } else { struct mbuf **mnext, *m_frgpart; @@ -839,6 +913,7 @@ skip_ipsec2:; len = (mtu - hlen - sizeof(struct ip6_frag)) & ~7; if (len < 8) { error = EMSGSIZE; + in6_ifstat_inc(ifp, ifs6_out_fragfail); goto bad; } @@ -909,7 +984,10 @@ skip_ipsec2:; ip6f->ip6f_ident = id; ip6f->ip6f_nxt = nextproto; ip6stat.ip6s_ofragments++; + in6_ifstat_inc(ifp, ifs6_out_fragcreat); } + + in6_ifstat_inc(ifp, ifs6_out_fragok); } /* @@ -923,12 +1001,23 @@ sendorfree: m0 = m->m_nextpkt; m->m_nextpkt = 0; if (error == 0) { -#ifdef NEWIP6OUTPUT - error = nd6_output(ifp, m, dst, ro->ro_rt); -#else +#if defined(__NetBSD__) && defined(IFA_STATS) + if (IFA_STATS) { + struct in6_ifaddr *ia6; + ip6 = mtod(m, struct ip6_hdr *); + ia6 = in6_ifawithifp(ifp, &ip6->ip6_src); + if (ia6) { + ia->ia_ifa.ifa_data.ifad_outbytes += + m->m_pkthdr.len; + } + } +#endif +#ifdef OLDIP6OUTPUT error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, ro->ro_rt); +#else + error = nd6_output(ifp, m, dst, ro->ro_rt); #endif } else @@ -1535,7 +1624,7 @@ ip6_setmoptions(optname, im6op, m) break; } mreq = mtod(m, struct ipv6_mreq *); - if (IN6_IS_ADDR_ANY(&mreq->ipv6mr_multiaddr)) { + if (IN6_IS_ADDR_UNSPECIFIED(&mreq->ipv6mr_multiaddr)) { /* * We use the unspecified address to specify to accept * all multicast addresses. Only super user is allowed @@ -1651,7 +1740,7 @@ ip6_setmoptions(optname, im6op, m) break; } mreq = mtod(m, struct ipv6_mreq *); - if (IN6_IS_ADDR_ANY(&mreq->ipv6mr_multiaddr)) { + if (IN6_IS_ADDR_UNSPECIFIED(&mreq->ipv6mr_multiaddr)) { if (suser(p->p_ucred, &p->p_acflag)) { error = EACCES; break; @@ -1839,7 +1928,7 @@ ip6_setpktoptions(control, opt, priv) return(ENXIO); } - if (!IN6_IS_ADDR_ANY(&opt->ip6po_pktinfo->ipi6_addr)) { + if (!IN6_IS_ADDR_UNSPECIFIED(&opt->ip6po_pktinfo->ipi6_addr)) { struct ifaddr *ia; struct sockaddr_in6 sin6; diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 3847a693f07..6ee312f1ab8 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_var.h,v 1.5 1999/11/19 10:41:43 bouyer Exp $ */ +/* $NetBSD: ip6_var.h,v 1.6 1999/12/13 15:17:23 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -149,7 +149,7 @@ struct ip6stat { u_quad_t ip6s_forward; /* packets forwarded */ u_quad_t ip6s_cantforward; /* packets rcvd for unreachable dest */ u_quad_t ip6s_redirectsent; /* packets forwarded on same net */ - u_quad_t ip6s_delivered; /* datagrams delivered to upper level*/ + u_quad_t ip6s_delivered; /* datagrams delivered to upper level*/ u_quad_t ip6s_localout; /* total ip packets generated here */ u_quad_t ip6s_odropped; /* lost packets due to nobufs, etc. */ u_quad_t ip6s_reassembled; /* total packets reassembled ok */ @@ -170,6 +170,10 @@ struct ip6stat { u_quad_t ip6s_exthdrtoolong; /* ext hdr are not continuous */ u_quad_t ip6s_nogif; /* no match gif found */ u_quad_t ip6s_toomanyhdr; /* discarded due to too many headers */ + /* XXX the following two items are not really AF_INET6 thing */ + u_quad_t ip6s_pulldown; /* # of calls to m_pulldown */ + u_quad_t ip6s_pulldown_copy; /* # of mbuf copies in m_pulldown */ + u_quad_t ip6s_pulldown_alloc; /* # of mbuf allocs in m_pulldown */ }; #ifdef _KERNEL @@ -184,6 +188,13 @@ extern int ip6_defmcasthlim; /* default multicast hop limit */ extern int ip6_forwarding; /* act as router? */ extern int ip6_forward_srcrt; /* forward src-routed? */ extern int ip6_gif_hlim; /* Hop limit for gif encap packet */ +extern int ip6_use_deprecated; /* allow deprecated addr as source */ +extern int ip6_rr_prune; /* router renumbering prefix + * walk list every 5 sec. */ +#ifdef MAPPED_ADDR_ENABLED +extern int ip6_mapped_addr_on; +#endif /* MAPPED_ADDR_ENABLED */ + extern struct socket *ip6_mrouter; /* multicast routing daemon */ extern int ip6_sendredirects; /* send IP redirects when forwarding? */ extern int ip6_maxfragpackets; /* Maximum packets in reassembly queue */ @@ -199,11 +210,24 @@ extern int ip6_dad_count; /* DupAddrDetectionTransmits */ extern u_int32_t ip6_flow_seq; extern int ip6_auto_flowlabel; -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) struct in6pcb; #endif +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +extern struct pr_usrreqs rip6_usrreqs; +struct sockopt; +#endif + +#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) +struct inpcb; +#endif +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +int icmp6_ctloutput __P((struct socket *, struct sockopt *sopt)); +#else int icmp6_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); +#endif + void ip6_init __P((void)); void ip6intr __P((void)); void ip6_input __P((struct mbuf *)); @@ -213,8 +237,13 @@ char * ip6_get_prevhdr __P((struct mbuf *, int)); int ip6_mforward __P((struct ip6_hdr *, struct ifnet *, struct mbuf *)); int ip6_process_hopopts __P((struct mbuf *, u_int8_t *, int, u_int32_t *, u_int32_t *)); +#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) +void ip6_savecontrol __P((struct inpcb *, struct mbuf **, struct ip6_hdr *, + struct mbuf *)); +#else void ip6_savecontrol __P((struct in6pcb *, struct mbuf **, struct ip6_hdr *, struct mbuf *)); +#endif int ip6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); void ip6_forward __P((struct mbuf *, int)); @@ -222,10 +251,18 @@ void ip6_forward __P((struct mbuf *, int)); void ip6_mloopback __P((struct ifnet *, struct mbuf *, struct sockaddr_in6 *)); int ip6_output __P((struct mbuf *, struct ip6_pktopts *, struct route_in6 *, int, - struct ip6_moptions *)); + struct ip6_moptions *, struct ifnet **)); +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +int ip6_ctloutput __P((struct socket *, struct sockopt *sopt)); +#else int ip6_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); +#endif int ip6_setpktoptions __P((struct mbuf *, struct ip6_pktopts *, int)); +#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) +int ip6_optlen __P((struct inpcb *)); +#else int ip6_optlen __P((struct in6pcb *)); +#endif int route6_input __P((struct mbuf **, int *, int)); @@ -236,7 +273,11 @@ void frag6_drain __P((void)); void rip6_init __P((void)); int rip6_input __P((struct mbuf **mp, int *offp, int proto)); +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +int rip6_ctloutput __P((struct socket *so, struct sockopt *sopt)); +#else int rip6_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); +#endif int rip6_output __P((struct mbuf *, ...)); int rip6_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *)); diff --git a/sys/netinet6/ip6protosw.h b/sys/netinet6/ip6protosw.h index b5d7b2a7232..87a1b2f7dd1 100644 --- a/sys/netinet6/ip6protosw.h +++ b/sys/netinet6/ip6protosw.h @@ -1,4 +1,4 @@ -/* $NetBSD: ip6protosw.h,v 1.3 1999/07/03 21:30:19 thorpej Exp $ */ +/* $NetBSD: ip6protosw.h,v 1.4 1999/12/13 15:17:23 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -81,9 +81,26 @@ struct socket; struct domain; struct proc; struct ip6_hdr; +#ifdef __FreeBSD__ +struct pr_usrreqs; +#endif + +/* + * argument type for the last arg of pr_ctlinput(). + * should be consulted only with AF_INET6 family. + */ +struct ip6ctlparam { + struct mbuf *ip6c_m; /* start of mbuf chain */ + struct ip6_hdr *ip6c_ip6; /* ip6 header of target packet */ + int ip6c_off; /* offset of the target proto header */ +}; struct ip6protosw { +#if (defined(__FreeBSD__) && __FreeBSD__ < 3) || defined(__OpenBSD__) + short pr_type; /* socket type used for */ +#else int pr_type; /* socket type used for */ +#endif struct domain *pr_domain; /* domain protocol a member of */ short pr_protocol; /* protocol number */ short pr_flags; /* see below */ @@ -91,18 +108,27 @@ struct ip6protosw { /* protocol-protocol hooks */ int (*pr_input) /* input to protocol (from below) */ __P((struct mbuf **, int *, int)); +#ifdef __bsdi__ + int (*pr_output)(); /* output to protocol (from above) */ +#else int (*pr_output) /* output to protocol (from above) */ __P((struct mbuf *, ...)); +#endif void (*pr_ctlinput) /* control input (from below) */ - __P((int, struct sockaddr *, struct ip6_hdr *, - struct mbuf *, int)); + __P((int, struct sockaddr *, void *)); int (*pr_ctloutput) /* control output (from above) */ __P((int, struct socket *, int, int, struct mbuf **)); /* user-protocol hook */ +#if !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined(__bsdi__) int (*pr_usrreq) /* user request: see list below */ __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *)); +#else + int (*pr_usrreq) /* user request: see list below */ + __P((struct socket *, int, struct mbuf *, + struct mbuf *, struct mbuf *)); +#endif /* utility hooks */ void (*pr_init) /* initialization hook */ @@ -114,9 +140,12 @@ struct ip6protosw { __P((void)); void (*pr_drain) /* flush any excess space possible */ __P((void)); +#ifdef __FreeBSD__ + struct pr_usrreqs *pr_usrreqs; /* supersedes pr_usrreq() */ +#else int (*pr_sysctl) /* sysctl for protocol */ __P((int *, u_int, void *, size_t *, void *, size_t)); +#endif }; - #endif /* !_NETINET6_IP6PROTOSW_H_ */ diff --git a/sys/netinet6/ipcomp_core.c b/sys/netinet6/ipcomp_core.c index 292e4c76f1c..d7c65f36864 100644 --- a/sys/netinet6/ipcomp_core.c +++ b/sys/netinet6/ipcomp_core.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipcomp_core.c,v 1.4 1999/11/05 14:56:26 itojun Exp $ */ +/* $NetBSD: ipcomp_core.c,v 1.5 1999/12/13 15:17:23 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -69,27 +69,12 @@ static int deflate_policy = Z_DEFAULT_COMPRESSION; static int deflate_window = 12; /* 2^12 = 4Kbytes */ static int deflate_memlevel = MAX_MEM_LEVEL; -#if 1 struct ipcomp_algorithm ipcomp_algorithms[] = { { NULL, NULL, -1 }, { NULL, NULL, -1 }, { deflate_compress, deflate_decompress, 90 }, { NULL, NULL, 90 }, }; -#else -struct ipcomp_algorithm ipcomp_algorithms_dummy[] = { - { NULL, NULL, -1 }, - { NULL, NULL, -1 }, - { deflate_compress, deflate_decompress, 90 }, - { NULL, NULL, 90 }, -}; -struct ipcomp_algorithm ipcomp_algorithms[] = { - { NULL, NULL, -1 }, - { NULL, NULL, -1 }, - { NULL, NULL, -1 }, - { NULL, NULL, -1 }, -}; -#endif #ifdef __NetBSD__ #define ovbcopy bcopy diff --git a/sys/netinet6/ipsec.c b/sys/netinet6/ipsec.c index caa540335f6..42144476d4b 100644 --- a/sys/netinet6/ipsec.c +++ b/sys/netinet6/ipsec.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipsec.c,v 1.10 1999/08/25 12:56:38 itojun Exp $ */ +/* $NetBSD: ipsec.c,v 1.11 1999/12/13 15:17:23 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -2069,7 +2069,9 @@ ipsec4_output(state, sp, flags) struct ipsecrequest *isr = NULL; int s; int error; +#ifdef IPSEC_SRCSEL struct in_ifaddr *ia; +#endif struct sockaddr_in *dst4; if (!state) @@ -2226,12 +2228,19 @@ ipsec4_output(state, sp, flags) goto bad; } +#ifdef IPSEC_SRCSEL + /* + * Which address in SA or in routing table should I + * select from ? But I had set from SA at + * ipsec4_encapsulate(). + */ ia = (struct in_ifaddr *)(state->ro->ro_rt->rt_ifa); if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) { state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway; dst4 = (struct sockaddr_in *)state->dst; } ip->ip_src = IA_SIN(ia)->sin_addr; +#endif } else splx(s); @@ -2424,7 +2433,9 @@ ipsec6_output_tunnel(state, sp, flags) struct ipsecrequest *isr = NULL; int error = 0; int plen; +#ifdef IPSEC_SRCSEL struct in6_addr *ia6; +#endif struct sockaddr_in6* dst6; int s; @@ -2580,12 +2591,14 @@ ipsec6_output_tunnel(state, sp, flags) dst6 = (struct sockaddr_in6 *)state->dst; } #endif +#ifdef IPSEC_SELSRC ia6 = in6_selectsrc(dst6, NULL, NULL, (struct route_in6 *)state->ro, - &error); + NULL, &error); if (ia6 == NULL) goto bad; ip6->ip6_src = *ia6; +#endif } else splx(s); diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c index a547f261fad..11c77febd7e 100644 --- a/sys/netinet6/mld6.c +++ b/sys/netinet6/mld6.c @@ -1,4 +1,4 @@ -/* $NetBSD: mld6.c,v 1.6 1999/07/31 18:41:17 itojun Exp $ */ +/* $NetBSD: mld6.c,v 1.7 1999/12/13 15:17:23 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -86,12 +86,13 @@ #include <netinet/in.h> #include <netinet/in_var.h> -#include <netinet6/in6.h> #include <netinet6/ip6.h> #include <netinet6/ip6_var.h> #include <netinet6/icmp6.h> #include <netinet6/mld6_var.h> +#include <net/net_osdep.h> + /* * Protocol constants */ @@ -140,7 +141,11 @@ void mld6_start_listening(in6m) struct in6_multi *in6m; { +#ifdef __NetBSD__ int s = splsoftnet(); +#else + int s = splnet(); +#endif /* * (draft-ietf-ipngwg-mld, page 10) @@ -191,6 +196,9 @@ mld6_input(m, off) struct ifnet *ifp = m->m_pkthdr.rcvif; struct in6_multi *in6m; struct in6_ifaddr *ia; +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + struct ifmultiaddr *ifma; +#endif int timer; /* timer value in the MLD query header */ /* source address validation */ @@ -218,109 +226,126 @@ mld6_input(m, off) * if we sent the last report. */ switch(mldh->mld6_type) { - case MLD6_LISTENER_QUERY: - if (ifp->if_flags & IFF_LOOPBACK) - break; + case MLD6_LISTENER_QUERY: + if (ifp->if_flags & IFF_LOOPBACK) + break; - if (!IN6_IS_ADDR_UNSPECIFIED(&mldh->mld6_addr) && - !IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr)) - break; /* print error or log stat? */ - if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) - mldh->mld6_addr.s6_addr16[1] = - htons(ifp->if_index); /* XXX */ + if (!IN6_IS_ADDR_UNSPECIFIED(&mldh->mld6_addr) && + !IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr)) + break; /* print error or log stat? */ + if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) + mldh->mld6_addr.s6_addr16[1] = + htons(ifp->if_index); /* XXX */ /* - * - Start the timers in all of our membership records - * that the query applies to for the interface on - * which the query arrived excl. those that belong - * to the "all-nodes" group (ff02::1). - * - Restart any timer that is already running but has - * A value longer than the requested timeout. - * - Use the value specified in the query message as - * the maximum timeout. - */ - IFP_TO_IA6(ifp, ia); - if (ia == NULL) - break; + * - Start the timers in all of our membership records + * that the query applies to for the interface on + * which the query arrived excl. those that belong + * to the "all-nodes" group (ff02::1). + * - Restart any timer that is already running but has + * A value longer than the requested timeout. + * - Use the value specified in the query message as + * the maximum timeout. + */ + IFP_TO_IA6(ifp, ia); + if (ia == NULL) + break; - /* - * XXX: System timer resolution is too low to handle Max - * Response Delay, so set 1 to the internal timer even if - * the calculated value equals to zero when Max Response - * Delay is positive. - */ - timer = ntohs(mldh->mld6_maxdelay)*PR_FASTHZ/MLD6_TIMER_SCALE; - if (timer == 0 && mldh->mld6_maxdelay) - timer = 1; - mld6_all_nodes_linklocal.s6_addr16[1] = - htons(ifp->if_index); /* XXX */ - - for (in6m = ia->ia6_multiaddrs.lh_first; - in6m; - in6m = in6m->in6m_entry.le_next) { - if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, - &mld6_all_nodes_linklocal) || - IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < - IPV6_ADDR_SCOPE_LINKLOCAL) - continue; - - if (IN6_IS_ADDR_UNSPECIFIED(&mldh->mld6_addr) || - IN6_ARE_ADDR_EQUAL(&mldh->mld6_addr, - &in6m->in6m_addr)) { - if (timer == 0) { - /* send a report immediately */ - mld6_sendpkt(in6m, MLD6_LISTENER_REPORT, - NULL); - in6m->in6m_timer = 0; /* reset timer */ - in6m->in6m_state = MLD6_IREPORTEDLAST; - } - else if (in6m->in6m_timer == 0 || /*idle state*/ - in6m->in6m_timer > timer) { - in6m->in6m_timer = - MLD6_RANDOM_DELAY(timer); - mld6_timers_are_running = 1; - } - } - } - - if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) - mldh->mld6_addr.s6_addr16[1] = 0; /* XXX */ - break; - case MLD6_LISTENER_REPORT: /* - * For fast leave to work, we have to know that we are the - * last person to send a report for this group. Reports - * can potentially get looped back if we are a multicast - * router, so discard reports sourced by me. - * Note that it is impossible to check IFF_LOOPBACK flag of - * ifp for this purpose, since ip6_mloopback pass the physical - * interface to looutput. - */ - if (m->m_flags & M_LOOP) /* XXX: grotty flag, but efficient */ - break; + * XXX: System timer resolution is too low to handle Max + * Response Delay, so set 1 to the internal timer even if + * the calculated value equals to zero when Max Response + * Delay is positive. + */ + timer = ntohs(mldh->mld6_maxdelay)*PR_FASTHZ/MLD6_TIMER_SCALE; + if (timer == 0 && mldh->mld6_maxdelay) + timer = 1; + mld6_all_nodes_linklocal.s6_addr16[1] = + htons(ifp->if_index); /* XXX */ + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) +#else + for (in6m = ia->ia6_multiaddrs.lh_first; + in6m; + in6m = in6m->in6m_entry.le_next) +#endif + { +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + if (ifma->ifma_addr->sa_family != AF_INET6) + continue; + in6m = (struct in6_multi *)ifma->ifma_protospec; + if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, + &mld6_all_nodes_linklocal) || + IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < + IPV6_ADDR_SCOPE_LINKLOCAL) + continue; +#else + if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, + &mld6_all_nodes_linklocal) || + IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < + IPV6_ADDR_SCOPE_LINKLOCAL) + continue; +#endif - if (!IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr)) - break; + if (IN6_IS_ADDR_UNSPECIFIED(&mldh->mld6_addr) || + IN6_ARE_ADDR_EQUAL(&mldh->mld6_addr, + &in6m->in6m_addr)) + { + if (timer == 0) { + /* send a report immediately */ + mld6_sendpkt(in6m, MLD6_LISTENER_REPORT, + NULL); + in6m->in6m_timer = 0; /* reset timer */ + in6m->in6m_state = MLD6_IREPORTEDLAST; + } + else if (in6m->in6m_timer == 0 || /*idle state*/ + in6m->in6m_timer > timer) { + in6m->in6m_timer = + MLD6_RANDOM_DELAY(timer); + mld6_timers_are_running = 1; + } + } + } - if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) - mldh->mld6_addr.s6_addr16[1] = - htons(ifp->if_index); /* XXX */ + if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) + mldh->mld6_addr.s6_addr16[1] = 0; /* XXX */ + break; + case MLD6_LISTENER_REPORT: /* - * If we belong to the group being reported, stop - * our timer for that group. - */ - IN6_LOOKUP_MULTI(mldh->mld6_addr, ifp, in6m); - if (in6m) { - in6m->in6m_timer = 0; /* transit to idle state */ - in6m->in6m_state = MLD6_OTHERLISTENER; /* clear flag */ - } - - if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) - mldh->mld6_addr.s6_addr16[1] = 0; /* XXX */ - break; - default: /* this is impossible */ - log(LOG_ERR, "mld6_input: illegal type(%d)", mldh->mld6_type); - break; + * For fast leave to work, we have to know that we are the + * last person to send a report for this group. Reports + * can potentially get looped back if we are a multicast + * router, so discard reports sourced by me. + * Note that it is impossible to check IFF_LOOPBACK flag of + * ifp for this purpose, since ip6_mloopback pass the physical + * interface to looutput. + */ + if (m->m_flags & M_LOOP) /* XXX: grotty flag, but efficient */ + break; + + if (!IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr)) + break; + + if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) + mldh->mld6_addr.s6_addr16[1] = + htons(ifp->if_index); /* XXX */ + /* + * If we belong to the group being reported, stop + * our timer for that group. + */ + IN6_LOOKUP_MULTI(mldh->mld6_addr, ifp, in6m); + if (in6m) { + in6m->in6m_timer = 0; /* transit to idle state */ + in6m->in6m_state = MLD6_OTHERLISTENER; /* clear flag */ + } + + if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) + mldh->mld6_addr.s6_addr16[1] = 0; /* XXX */ + break; + default: /* this is impossible */ + log(LOG_ERR, "mld6_input: illegal type(%d)", mldh->mld6_type); + break; } } @@ -338,7 +363,11 @@ mld6_fasttimeo() if (!mld6_timers_are_running) return; +#ifdef __NetBSD__ s = splsoftnet(); +#else + s = splnet(); +#endif mld6_timers_are_running = 0; IN6_FIRST_MULTI(step, in6m); while (in6m != NULL) { @@ -367,6 +396,7 @@ mld6_sendpkt(in6m, type, dst) struct ip6_moptions im6o; struct in6_ifaddr *ia; struct ifnet *ifp = in6m->in6m_ifp; + struct ifnet *outif = NULL; /* * At first, find a link local address on the outgoing interface @@ -391,7 +421,9 @@ mld6_sendpkt(in6m, type, dst) mh->m_next = md; #ifdef IPSEC +#ifndef __OpenBSD__ /*KAME IPSEC*/ mh->m_pkthdr.rcvif = NULL; +#endif #endif mh->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld6_hdr); mh->m_len = sizeof(struct ip6_hdr); @@ -436,5 +468,19 @@ mld6_sendpkt(in6m, type, dst) /* increment output statictics */ icmp6stat.icp6s_outhist[type]++; - ip6_output(mh, &ip6_opts, NULL, 0, &im6o); + ip6_output(mh, &ip6_opts, NULL, 0, &im6o, &outif); + if (outif) { + icmp6_ifstat_inc(outif, ifs6_out_msg); + switch(type) { + case MLD6_LISTENER_QUERY: + icmp6_ifstat_inc(outif, ifs6_out_mldquery); + break; + case MLD6_LISTENER_REPORT: + icmp6_ifstat_inc(outif, ifs6_out_mldreport); + break; + case MLD6_LISTENER_DONE: + icmp6_ifstat_inc(outif, ifs6_out_mlddone); + break; + } + } } diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 703b1e8a519..020409fa40f 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -1,4 +1,4 @@ -/* $NetBSD: nd6.c,v 1.11 1999/12/10 17:56:13 itojun Exp $ */ +/* $NetBSD: nd6.c,v 1.12 1999/12/13 15:17:23 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -46,7 +46,7 @@ #include <sys/time.h> #include <sys/kernel.h> #include <sys/errno.h> -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) #include <sys/ioctl.h> #endif #include <sys/syslog.h> @@ -55,7 +55,9 @@ #include <net/if.h> #include <net/if_dl.h> #include <net/if_types.h> +#if !(defined(__bsdi__) && _BSDI_VERSION >= 199802) #include <net/if_atm.h> +#endif #include <net/route.h> #include <netinet/in.h> @@ -76,20 +78,21 @@ #include <netinet6/ip6.h> #include <netinet6/ip6_var.h> #include <netinet6/nd6.h> +#include <netinet6/in6_prefix.h> #include <netinet6/icmp6.h> +#ifndef __bsdi__ #include "loop.h" -#ifdef __NetBSD__ +#endif +#if defined(__NetBSD__) || defined(__OpenBSD__) extern struct ifnet loif[NLOOP]; #endif +#include <net/net_osdep.h> + #define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */ #define ND6_RECALC_REACHTM_INTERVAL (60 * 120) /* 2 hours */ -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 -#define time_second time.tv_sec -#endif - #define SIN6(s) ((struct sockaddr_in6 *)s) #define SDL(s) ((struct sockaddr_dl *)s) @@ -101,18 +104,22 @@ int nd6_mmaxtries = 3; /* maximum multicast query */ int nd6_useloopback = 1; /* use loopback interface for local traffic */ int nd6_proxyall = 0; /* enable Proxy Neighbor Advertisement */ +/* preventing too many loops in ND option parsing */ +int nd6_maxndopt = 10; /* max # of ND options allowed */ + /* for debugging? */ static int nd6_inuse, nd6_allocated; struct llinfo_nd6 llinfo_nd6 = {&llinfo_nd6, &llinfo_nd6}; -struct nd_ifinfo *nd_ifinfo; -struct nd_drhead nd_defrouter = { 0 }; +struct nd_ifinfo *nd_ifinfo = NULL; +struct nd_drhead nd_defrouter; struct nd_prhead nd_prefix = { 0 }; int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL; #if 0 extern int ip6_forwarding; #endif +static struct sockaddr_in6 all1_sa; static void nd6_slowtimo __P((void *)); @@ -120,11 +127,21 @@ void nd6_init() { static int nd6_init_done = 0; + int i; if (nd6_init_done) { log(LOG_NOTICE, "nd6_init called more than once(ignored)\n"); return; } + + all1_sa.sin6_family = AF_INET6; + all1_sa.sin6_len = sizeof(struct sockaddr_in6); + for (i = 0; i < sizeof(all1_sa.sin6_addr); i++) + all1_sa.sin6_addr.s6_addr[i] = 0xff; + + /* initialization of the default router list */ + TAILQ_INIT(&nd_defrouter); + nd6_init_done = 1; /* start timer */ @@ -192,12 +209,18 @@ nd6_setmtu(ifp) break; #if defined(__FreeBSD__) || defined(__bsdi__) case IFT_FDDI: +#if defined(__bsdi__) && _BSDI_VERSION >= 199802 + ndi->maxmtu = MIN(FDDIMTU, ifp->if_mtu); +#else ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); +#endif break; #endif +#if !(defined(__bsdi__) && _BSDI_VERSION >= 199802) case IFT_ATM: ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu); break; +#endif default: ndi->maxmtu = ifp->if_mtu; break; @@ -353,7 +376,8 @@ nd6_options(ndopts) skip1: i++; - if (i > 10) { + if (i > nd6_maxndopt) { + icmp6stat.icp6s_nd_toomanyopt++; printf("too many loop in nd opt\n"); break; } @@ -376,8 +400,15 @@ nd6_timer(ignored_arg) register struct llinfo_nd6 *ln; register struct nd_defrouter *dr; register struct nd_prefix *pr; +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) + long time_second = time.tv_sec; +#endif +#ifdef __NetBSD__ s = splsoftnet(); +#else + s = splnet(); +#endif timeout(nd6_timer, (caddr_t)0, nd6_prune * hz); ln = llinfo_nd6.ln_next; @@ -474,15 +505,15 @@ nd6_timer(ignored_arg) } /* expire */ - dr = nd_defrouter.lh_first; + dr = TAILQ_FIRST(&nd_defrouter); while (dr) { if (dr->expire && dr->expire < time_second) { struct nd_defrouter *t; - t = dr->dr_next; + t = TAILQ_NEXT(dr, dr_entry); defrtrlist_del(dr); dr = t; } else - dr = dr->dr_next; + dr = TAILQ_NEXT(dr, dr_entry); } pr = nd_prefix.lh_first; while (pr) { @@ -534,10 +565,6 @@ nd6_timer(ignored_arg) splx(s); } -static struct sockaddr_in6 all1_sa = { - sizeof(struct sockaddr_in6), AF_INET6, 0, 0, - {{{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}}}, 0}; - struct rtentry * nd6_lookup(addr6, create, ifp) struct in6_addr *addr6; @@ -609,11 +636,19 @@ nd6_lookup(addr6, create, ifp) return(NULL); } rt->rt_refcnt--; + /* + * Validation for the entry. + * XXX: we can't use rt->rt_ifp to check for the interface, since + * it might be the loopback interface if the entry is for our + * own address on a non-loopback interface. Instead, we should + * use rt->rt_ifa->ifa_ifp, which would specify the REAL interface. + */ if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || - rt->rt_gateway->sa_family != AF_LINK) { + rt->rt_gateway->sa_family != AF_LINK || + (ifp && rt->rt_ifa->ifa_ifp != ifp)) { if (create) { - log(LOG_DEBUG, "nd6_lookup: failed to lookup %s\n", - ip6_sprintf(addr6)); + log(LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n", + ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec"); /* xxx more logs... kazu */ } return(0); @@ -644,7 +679,7 @@ nd6_is_addr_neighbor(addr, ifp) * If the address matches one of our addresses, * it should be a neighbor. */ -#ifdef __bsdi__ +#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) #else for (ifa = ifp->if_addrlist.tqh_first; @@ -684,40 +719,72 @@ nd6_free(rt) { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; struct sockaddr_dl *sdl; + struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; + struct nd_defrouter *dr; - if (ln->ln_router) { - /* remove from default router list */ - struct nd_defrouter *dr; - struct in6_addr *in6; + if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */ int s; - in6 = &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; - +#ifdef __NetBSD__ s = splsoftnet(); - dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))-> - sin6_addr, +#else + s = splnet(); +#endif + dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, rt->rt_ifp); - if (dr) - defrtrlist_del(dr); - else if (!ip6_forwarding && ip6_accept_rtadv) { + if (ln->ln_router || dr) { /* - * rt6_flush must be called in any case. - * see the comment in nd6_na_input(). + * rt6_flush must be called whether or not the neighbor + * is in the Default Router List. + * See a corresponding comment in nd6_na_input(). */ - rt6_flush(in6, rt->rt_ifp); + rt6_flush(&in6, rt->rt_ifp); + } + + if (dr) { + /* + * Unreachablity of a router might affect the default + * router selection and on-link detection of advertised + * prefixes. + */ + + /* + * Temporarily fake the state to choose a new default + * router and to perform on-link determination of + * prefixes coreectly. + * Below the state will be set correctly, + * or the entry itself will be deleted. + */ + ln->ln_state = ND6_LLINFO_INCOMPLETE; + + if (dr == TAILQ_FIRST(&nd_defrouter)) { + /* + * It is used as the current default router, + * so we have to move it to the end of the + * list and choose a new one. + * XXX: it is not very efficient if this is + * the only router. + */ + TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); + TAILQ_INSERT_TAIL(&nd_defrouter, dr, dr_entry); + + defrouter_select(); + } + pfxlist_onlink_check(); } splx(s); } - + if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && - sdl->sdl_family == AF_LINK) { + sdl->sdl_family == AF_LINK) { sdl->sdl_alen = 0; ln->ln_state = ND6_LLINFO_WAITDELETE; ln->ln_asked = 0; rt->rt_flags &= ~RTF_REJECT; return; } - rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), - 0, (struct rtentry **)0); + + rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, + rt_mask(rt), 0, (struct rtentry **)0); } /* @@ -731,6 +798,9 @@ nd6_nud_hint(rt, dst6) struct in6_addr *dst6; { struct llinfo_nd6 *ln; +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) + long time_second = time.tv_sec; +#endif /* * If the caller specified "rt", use that. Otherwise, resolve the @@ -762,6 +832,7 @@ nd6_nud_hint(rt, dst6) nd_ifinfo[rt->rt_ifp->if_index].reachable; } +#ifdef OLDIP6OUTPUT /* * Resolve an IP6 address into an ethernet address. If success, * desten is filled in. If there is no entry in ndptab, @@ -782,6 +853,9 @@ nd6_resolve(ifp, rt, m, dst, desten) { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL; struct sockaddr_dl *sdl; +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) + long time_second = time.tv_sec; +#endif if (m->m_flags & M_MCAST) { switch (ifp->if_type) { @@ -794,6 +868,7 @@ nd6_resolve(ifp, rt, m, dst, desten) case IFT_ARCNET: *desten = 0; return(1); + break; default: return(0); } @@ -853,18 +928,29 @@ nd6_resolve(ifp, rt, m, dst, desten) } return(0); } +#endif /* OLDIP6OUTPUT */ void +#if defined(__bsdi__) && _BSDI_VERSION >= 199802 +nd6_rtrequest(req, rt, info) + int req; + struct rtentry *rt; + struct rt_addrinfo *info; /* xxx unused */ +#else nd6_rtrequest(req, rt, sa) int req; struct rtentry *rt; struct sockaddr *sa; /* xxx unused */ +#endif { struct sockaddr *gate = rt->rt_gateway; struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; struct ifnet *ifp = rt->rt_ifp; struct ifaddr *ifa; +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) + long time_second = time.tv_sec; +#endif if (rt->rt_flags & RTF_GATEWAY) return; @@ -950,7 +1036,7 @@ nd6_rtrequest(req, rt, sa) * When req == RTM_RESOLVE, rt is created and * initialized in rtrequest(), so rt_expire is 0. */ - ln->ln_state = ND6_LLINFO_INCOMPLETE; + ln->ln_state = ND6_LLINFO_NOSTATE; ln->ln_expire = time_second; } rt->rt_flags |= RTF_LLINFO; @@ -979,10 +1065,14 @@ nd6_rtrequest(req, rt, sa) } if (nd6_useloopback) { #ifdef __bsdi__ +#if _BSDI_VERSION >= 199802 + extern struct ifnet *loifp; + rt->rt_ifp = loifp; /*XXX*/ +#else extern struct ifnet loif; rt->rt_ifp = &loif; /*XXX*/ -#endif /*__bsdi__*/ -#if defined(__FreeBSD__) || defined(__NetBSD__) +#endif +#else /* non-bsdi */ rt->rt_ifp = &loif[0]; /*XXX*/ #endif /* @@ -1022,10 +1112,17 @@ nd6_rtrequest(req, rt, sa) } void +#if defined(__bsdi__) && _BSDI_VERSION >= 199802 +nd6_p2p_rtrequest(req, rt, info) + int req; + struct rtentry *rt; + struct rt_addrinfo *info; /* xxx unused */ +#else nd6_p2p_rtrequest(req, rt, sa) int req; struct rtentry *rt; struct sockaddr *sa; /* xxx unused */ +#endif { struct sockaddr *gate = rt->rt_gateway; static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; @@ -1056,7 +1153,7 @@ nd6_p2p_rtrequest(req, rt, sa) SDL(gate)->sdl_index = ifp->if_index; break; } - /* Announce a new entry if rqquested. */ + /* Announce a new entry if requested. */ if (rt->rt_flags & RTF_ANNOUNCE) nd6_na_output(ifp, &SIN6(rt_key(rt))->sin6_addr, @@ -1074,12 +1171,16 @@ nd6_p2p_rtrequest(req, rt, sa) if (ifa) { if (nd6_useloopback) { #ifdef __bsdi__ +#if _BSDI_VERSION >= 199802 + extern struct ifnet *loifp; + rt->rt_ifp = loifp; /*XXX*/ +#else extern struct ifnet loif; rt->rt_ifp = &loif; /*XXX*/ -#endif /*__bsdi__*/ -#if defined(__FreeBSD__) || defined(__NetBSD__) - rt->rt_ifp = &loif[0]; /*XXX*/ #endif +#else + rt->rt_ifp = &loif[0]; /*XXX*/ +#endif /*__bsdi__*/ } } break; @@ -1096,6 +1197,7 @@ nd6_ioctl(cmd, data, ifp) struct in6_prlist *prl = (struct in6_prlist *)data; struct in6_ndireq *ndi = (struct in6_ndireq *)data; struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data; + struct in6_ndifreq *ndif = (struct in6_ndifreq *)data; struct nd_defrouter *dr, any; struct nd_prefix *pr; struct rtentry *rt; @@ -1105,8 +1207,12 @@ nd6_ioctl(cmd, data, ifp) switch (cmd) { case SIOCGDRLST_IN6: bzero(drl, sizeof(*drl)); +#ifdef __NetBSD__ s = splsoftnet(); - dr = nd_defrouter.lh_first; +#else + s = splnet(); +#endif + dr = TAILQ_FIRST(&nd_defrouter); while (dr && i < DRLSTSIZ) { drl->defrouter[i].rtaddr = dr->rtaddr; if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) { @@ -1124,13 +1230,17 @@ nd6_ioctl(cmd, data, ifp) drl->defrouter[i].expire = dr->expire; drl->defrouter[i].if_index = dr->ifp->if_index; i++; - dr = dr->dr_next; + dr = TAILQ_NEXT(dr, dr_entry); } splx(s); break; case SIOCGPRLST_IN6: bzero(prl, sizeof(*prl)); +#ifdef __NetBSD__ s = splsoftnet(); +#else + s = splnet(); +#endif pr = nd_prefix.lh_first; while (pr && i < PRLSTSIZ) { struct nd_pfxrouter *pfr; @@ -1171,11 +1281,30 @@ nd6_ioctl(cmd, data, ifp) pr = pr->ndpr_next; } splx(s); + { + struct rr_prefix *rpp; + + for (rpp = LIST_FIRST(&rr_prefix); rpp; + rpp = LIST_NEXT(rpp, rp_entry)) { + if (i >= PRLSTSIZ) + break; + prl->prefix[i].prefix = rpp->rp_prefix.sin6_addr; + prl->prefix[i].raflags = rpp->rp_raf; + prl->prefix[i].prefixlen = rpp->rp_plen; + prl->prefix[i].vltime = rpp->rp_vltime; + prl->prefix[i].pltime = rpp->rp_pltime; + prl->prefix[i].if_index = rpp->rp_ifp->if_index; + prl->prefix[i].expire = rpp->rp_expire; + prl->prefix[i].advrtrs = 0; + i++; + } + } + break; case SIOCGIFINFO_IN6: ndi->ndi = nd_ifinfo[ifp->if_index]; break; - case SIOCSNDFLUSH_IN6: + case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */ /* flush default router list */ /* * xxx sumikawa: should not delete route if default @@ -1183,6 +1312,7 @@ nd6_ioctl(cmd, data, ifp) */ bzero(&any, sizeof(any)); defrouter_delreq(&any, 0); + defrouter_select(); /* xxx sumikawa: flush prefix list */ break; case SIOCSPFXFLUSH_IN6: @@ -1190,7 +1320,11 @@ nd6_ioctl(cmd, data, ifp) /* flush all the prefix advertised by routers */ struct nd_prefix *pr, *next; +#ifdef __NetBSD__ s = splsoftnet(); +#else + s = splnet(); +#endif for (pr = nd_prefix.lh_first; pr; pr = next) { next = pr->ndpr_next; if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) @@ -1205,40 +1339,67 @@ nd6_ioctl(cmd, data, ifp) /* flush all the default routers */ struct nd_defrouter *dr, *next; +#ifdef __NetBSD__ s = splsoftnet(); - if ((dr = nd_defrouter.lh_first) != NULL) { +#else + s = splnet(); +#endif + if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) { /* * The first entry of the list may be stored in * the routing table, so we'll delete it later. */ - for (dr = dr->dr_next; dr; dr = next) { - next = dr->dr_next; + for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = next) { + next = TAILQ_NEXT(dr, dr_entry); defrtrlist_del(dr); } - defrtrlist_del(nd_defrouter.lh_first); + defrtrlist_del(TAILQ_FIRST(&nd_defrouter)); } splx(s); break; } case SIOCGNBRINFO_IN6: { - struct llinfo_nd6 *ln; - - s = splsoftnet(); - if ((rt = nd6_lookup(&nbi->addr, 0, ifp)) == NULL) { - error = EINVAL; - splx(s); - break; - } - ln = (struct llinfo_nd6 *)rt->rt_llinfo; - nbi->state = ln->ln_state; - nbi->asked = ln->ln_asked; - nbi->isrouter = ln->ln_router; - nbi->expire = ln->ln_expire; - splx(s); - - break; + struct llinfo_nd6 *ln; + struct in6_addr nb_addr = nbi->addr; /* make local for safety */ + + /* + * XXX: KAME specific hack for scoped addresses + * XXXX: for other scopes than link-local? + */ + if (IN6_IS_ADDR_LINKLOCAL(&nbi->addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&nbi->addr)) { + u_int16_t *idp = (u_int16_t *)&nb_addr.s6_addr[2]; + + if (*idp == 0) + *idp = htons(ifp->if_index); + } + +#ifdef __NetBSD__ + s = splsoftnet(); +#else + s = splnet(); +#endif + if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL) { + error = EINVAL; + splx(s); + break; + } + ln = (struct llinfo_nd6 *)rt->rt_llinfo; + nbi->state = ln->ln_state; + nbi->asked = ln->ln_asked; + nbi->isrouter = ln->ln_router; + nbi->expire = ln->ln_expire; + splx(s); + + break; } + case SIOCGDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ + ndif->ifindex = nd6_defifindex; + break; + case SIOCSDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ + return(nd6_setdefaultiface(ndif->ifindex)); + break; } return(error); } @@ -1264,6 +1425,9 @@ nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type, code) int olladdr; int llchange; int newstate = 0; +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) + long time_second = time.tv_sec; +#endif if (!ifp) panic("ifp == NULL in nd6_cache_lladdr"); @@ -1366,8 +1530,14 @@ fail: if (ln->ln_state == ND6_LLINFO_STALE) { rt->rt_flags &= ~RTF_REJECT; if (ln->ln_hold) { +#ifdef OLDIP6OUTPUT (*ifp->if_output)(ifp, ln->ln_hold, rt_key(rt), rt); +#else + nd6_output(ifp, ln->ln_hold, + (struct sockaddr_in6 *)rt_key(rt), + rt); +#endif ln->ln_hold = 0; } } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { @@ -1449,7 +1619,11 @@ static void nd6_slowtimo(ignored_arg) void *ignored_arg; { +#ifdef __NetBSD__ int s = splsoftnet(); +#else + int s = splnet(); +#endif register int i; register struct nd_ifinfo *nd6if; @@ -1471,8 +1645,6 @@ nd6_slowtimo(ignored_arg) splx(s); } -#ifdef NEWIP6OUTPUT -/* for experimental */ #define senderr(e) { error = (e); goto bad;} int nd6_output(ifp, m0, dst, rt0) @@ -1485,6 +1657,9 @@ nd6_output(ifp, m0, dst, rt0) register struct rtentry *rt = rt0; struct llinfo_nd6 *ln = NULL; int error = 0; +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) + long time_second = time.tv_sec; +#endif if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) goto sendpkt; @@ -1509,11 +1684,12 @@ nd6_output(ifp, m0, dst, rt0) if ((rt->rt_flags & RTF_UP) == 0) { #ifdef __FreeBSD__ if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1, 0UL)) != - NULL) { + NULL) #else if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1)) != - NULL) { + NULL) #endif + { rt->rt_refcnt--; if (rt->rt_ifp != ifp) return nd6_output(ifp, m0, dst, rt); /* XXX: loop care? */ @@ -1647,7 +1823,6 @@ nd6_storelladdr(ifp, rt, m, dst, desten) case IFT_ARCNET: *desten = 0; return(1); - break; default: return(0); } @@ -1664,4 +1839,3 @@ nd6_storelladdr(ifp, rt, m, dst, desten) return(1); } -#endif /* NEWIP6OUTPUT */ diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index 015dd523b4d..67ad8a0a8a3 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -1,4 +1,4 @@ -/* $NetBSD: nd6.h,v 1.5 1999/07/31 18:41:17 itojun Exp $ */ +/* $NetBSD: nd6.h,v 1.6 1999/12/13 15:17:23 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -53,13 +53,15 @@ struct llinfo_nd6 { #define ND6_LLINFO_DELAY 3 #define ND6_LLINFO_PROBE 4 +#define ND6_IS_LLINFO_PROBREACH(n) ((n)->ln_state > ND6_LLINFO_INCOMPLETE) + struct nd_ifinfo { u_int32_t linkmtu; /* LinkMTU */ u_int32_t maxmtu; /* Upper bound of LinkMTU */ u_int32_t basereachable; /* BaseReachableTime */ u_int32_t reachable; /* Reachable Time */ u_int32_t retrans; /* Retrans Timer */ - int recalctm; /* BaseReacable re-calculation timer */ + int recalctm; /* BaseReacable re-calculation timer */ u_int8_t chlim; /* CurHopLimit */ u_int8_t receivedra; }; @@ -106,6 +108,12 @@ struct in6_ndireq { struct nd_ifinfo ndi; }; +struct in6_ndifreq { + char ifname[IFNAMSIZ]; + u_long ifindex; +}; + + /* protocol constants */ #define MAX_RTR_SOLICITATION_DELAY 1 /*1sec*/ #define RTR_SOLICITATION_INTERVAL 4 /*4sec*/ @@ -124,9 +132,9 @@ struct in6_ndireq { (((MIN_RANDOM_FACTOR * (x >> 10)) + (random() & \ ((MAX_RANDOM_FACTOR - MIN_RANDOM_FACTOR) * (x >> 10)))) /1000) +TAILQ_HEAD(nd_drhead, nd_defrouter); struct nd_defrouter { - LIST_ENTRY(nd_defrouter) dr_entry; -#define dr_next dr_entry.le_next + TAILQ_ENTRY(nd_defrouter) dr_entry; struct in6_addr rtaddr; u_char flags; u_short rtlifetime; @@ -135,7 +143,7 @@ struct nd_defrouter { }; struct nd_prefix { - struct ifprefix ndpr_ifpr; + struct ifnet *ndpr_ifp; LIST_ENTRY(nd_prefix) ndpr_entry; struct sockaddr_in6 ndpr_prefix; /* prefix */ struct in6_addr ndpr_mask; /* netmask derived from the prefix */ @@ -144,34 +152,24 @@ struct nd_prefix { u_int32_t ndpr_pltime; /* advertised preferred lifetime */ time_t ndpr_expire; /* expiration time of the prefix */ time_t ndpr_preferred; /* preferred time of the prefix */ - struct in6_prflags ndpr_flags; + struct prf_ra ndpr_flags; /* list of routers that advertise the prefix: */ LIST_HEAD(pr_rtrhead, nd_pfxrouter) ndpr_advrtrs; - u_char ndpr_origin; /* from where this prefix info is obtained */ + u_char ndpr_plen; struct ndpr_stateflags { /* if this prefix can be regarded as on-link */ u_char onlink : 1; - /* if some prefix should be added to this prefix */ - u_char addmark : 1; - u_char delmark : 1; /* if this prefix will be deleted */ } ndpr_stateflags; }; #define ndpr_next ndpr_entry.le_next -#define ndpr_ifp ndpr_ifpr.ifpr_ifp -#define ndpr_plen ndpr_ifpr.ifpr_plen -#define ndpr_raf ndpr_flags.prf_ra -#define ndpr_raf_onlink ndpr_flags.prf_ra.onlink -#define ndpr_raf_auto ndpr_flags.prf_ra.autonomous +#define ndpr_raf ndpr_flags +#define ndpr_raf_onlink ndpr_flags.onlink +#define ndpr_raf_auto ndpr_flags.autonomous #define ndpr_statef_onlink ndpr_stateflags.onlink #define ndpr_statef_addmark ndpr_stateflags.addmark -#define ndpr_statef_delmark ndpr_stateflags.delmark - -#define ndpr_rrf ndpr_flags.prf_rr -#define ndpr_rrf_decrvalid ndpr_flags.prf_rr.decrvalid -#define ndpr_rrf_decrprefd ndpr_flags.prf_rr.decrprefd /* * We keep expired prefix for certain amount of time, for validation purposes. @@ -214,7 +212,6 @@ struct nd_pfxrouter { struct nd_defrouter *router; }; -LIST_HEAD(nd_drhead, nd_defrouter); LIST_HEAD(nd_prhead, nd_prefix); /* nd6.c */ @@ -229,6 +226,9 @@ extern struct nd_ifinfo *nd_ifinfo; extern struct nd_drhead nd_defrouter; extern struct nd_prhead nd_prefix; +/* nd6_rtr.c */ +extern int nd6_defifindex; + union nd_opts { struct nd_opt_hdr *nd_opt_array[9]; struct { @@ -269,8 +269,13 @@ void nd6_free __P((struct rtentry *)); void nd6_nud_hint __P((struct rtentry *, struct in6_addr *)); int nd6_resolve __P((struct ifnet *, struct rtentry *, struct mbuf *, struct sockaddr *, u_char *)); +#if defined(__bsdi__) && _BSDI_VERSION >= 199802 +void nd6_rtrequest __P((int, struct rtentry *, struct rt_addrinfo *)); +void nd6_p2p_rtrequest __P((int, struct rtentry *, struct rt_addrinfo *)); +#else void nd6_rtrequest __P((int, struct rtentry *, struct sockaddr *)); void nd6_p2p_rtrequest __P((int, struct rtentry *, struct sockaddr *)); +#endif int nd6_ioctl __P((u_long, caddr_t, struct ifnet *)); struct rtentry *nd6_cache_lladdr __P((struct ifnet *, struct in6_addr *, char *, int, int, int)); @@ -297,15 +302,18 @@ void nd6_ra_input __P((struct mbuf *, int, int)); void prelist_del __P((struct nd_prefix *)); void defrouter_addreq __P((struct nd_defrouter *)); void defrouter_delreq __P((struct nd_defrouter *, int)); +void defrouter_select __P((void)); void defrtrlist_del __P((struct nd_defrouter *)); void prelist_remove __P((struct nd_prefix *)); int prelist_update __P((struct nd_prefix *, struct nd_defrouter *, struct mbuf *)); +void pfxlist_onlink_check __P((void)); struct nd_defrouter *defrouter_lookup __P((struct in6_addr *, struct ifnet *)); int in6_ifdel __P((struct ifnet *, struct in6_addr *)); int in6_init_prefix_ltimes __P((struct nd_prefix *ndpr)); void rt6_flush __P((struct in6_addr *, struct ifnet *)); +int nd6_setdefaultiface __P((int)); #endif /* _KERNEL */ diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index 1d473e4dc1b..c8e8fbe25ea 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -1,4 +1,4 @@ -/* $NetBSD: nd6_nbr.c,v 1.8 1999/09/19 21:31:35 is Exp $ */ +/* $NetBSD: nd6_nbr.c,v 1.9 1999/12/13 15:17:23 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -45,7 +45,7 @@ #include <sys/time.h> #include <sys/kernel.h> #include <sys/errno.h> -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) #include <sys/ioctl.h> #endif #include <sys/syslog.h> @@ -64,6 +64,8 @@ #include <netinet6/nd6.h> #include <netinet6/icmp6.h> +#include <net/net_osdep.h> + #define SDL(s) ((struct sockaddr_dl *)s) #if 0 @@ -73,11 +75,12 @@ extern struct timeval time; struct dadq; static struct dadq *nd6_dad_find __P((struct ifaddr *)); static void nd6_dad_timer __P((struct ifaddr *)); +static void nd6_dad_ns_output __P((struct dadq *, struct ifaddr *)); static void nd6_dad_ns_input __P((struct ifaddr *)); static void nd6_dad_na_input __P((struct ifaddr *)); -/* ignore NS in DAD - specwise incorrect, */ -int dad_ignore_ns = 0; +static int dad_ignore_ns = 0; /* ignore NS in DAD - specwise incorrect*/ +static int dad_maxtry = 15; /* max # of *tries* to transmit DAD packet */ /* * Input an Neighbor Solicitation Message. @@ -218,7 +221,7 @@ nd6_ns_input(m, off, icmp6len) */ return; } - myaddr6 = IFA_IN6(ifa); + myaddr6 = *IFA_IN6(ifa); anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST; tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE; if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED) @@ -322,6 +325,7 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad) struct ip6_moptions im6o; int icmp6len; caddr_t mac; + struct ifnet *outif = NULL; if (IN6_IS_ADDR_MULTICAST(taddr6)) return; @@ -459,9 +463,15 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad) = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len); #ifdef IPSEC +#ifndef __OpenBSD__ /*KAME IPSEC*/ m->m_pkthdr.rcvif = NULL; +#endif #endif /*IPSEC*/ - ip6_output(m, NULL, NULL, dad ? IPV6_DADOUTPUT : 0, &im6o); + ip6_output(m, NULL, NULL, dad ? IPV6_DADOUTPUT : 0, &im6o, &outif); + if (outif) { + icmp6_ifstat_inc(outif, ifs6_out_msg); + icmp6_ifstat_inc(outif, ifs6_out_neighborsolicit); + } icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]++; } @@ -588,7 +598,7 @@ nd6_na_input(m, off, icmp6len) if (is_solicited) { ln->ln_state = ND6_LLINFO_REACHABLE; if (ln->ln_expire) -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) ln->ln_expire = time.tv_sec + #else ln->ln_expire = time_second + @@ -661,7 +671,7 @@ nd6_na_input(m, off, icmp6len) if (is_solicited) { ln->ln_state = ND6_LLINFO_REACHABLE; if (ln->ln_expire) { -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) ln->ln_expire = time.tv_sec + #else ln->ln_expire = time_second + @@ -685,7 +695,11 @@ nd6_na_input(m, off, icmp6len) int s; in6 = &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; +#ifdef __NetBSD__ s = splsoftnet(); +#else + s = splnet(); +#endif dr = defrouter_lookup(in6, rt->rt_ifp); if (dr) defrtrlist_del(dr); @@ -706,7 +720,12 @@ nd6_na_input(m, off, icmp6len) rt->rt_flags &= ~RTF_REJECT; ln->ln_asked = 0; if (ln->ln_hold) { +#ifdef OLDIP6OUTPUT (*ifp->if_output)(ifp, ln->ln_hold, rt_key(rt), rt); +#else + nd6_output(ifp, ln->ln_hold, + (struct sockaddr_in6 *)rt_key(rt), rt); +#endif ln->ln_hold = 0; } } @@ -734,6 +753,7 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr) struct ip6_moptions im6o; int icmp6len; caddr_t mac; + struct ifnet *outif = NULL; if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) return; @@ -812,9 +832,15 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr) in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len); #ifdef IPSEC +#ifndef __OpenBSD__ /*KAME IPSEC*/ m->m_pkthdr.rcvif = NULL; +#endif #endif /*IPSEC*/ - ip6_output(m, NULL, NULL, 0, &im6o); + ip6_output(m, NULL, NULL, 0, &im6o, &outif); + if (outif) { + icmp6_ifstat_inc(outif, ifs6_out_msg); + icmp6_ifstat_inc(outif, ifs6_out_neighboradvert); + } icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]++; } @@ -842,6 +868,7 @@ struct dadq { TAILQ_ENTRY(dadq) dad_list; struct ifaddr *dad_ifa; int dad_count; /* max NS to send */ + int dad_ns_tcount; /* # of trials to send NS */ int dad_ns_ocount; /* NS sent so far */ int dad_ns_icount; int dad_na_icount; @@ -892,7 +919,7 @@ nd6_dad_start(ifa, tick) printf("nd6_dad_start: called with non-tentative address " "%s(%s)\n", ip6_sprintf(&ia->ia_addr.sin6_addr), - ifa->ifa_ifp ? ifa->ifa_ifp->if_xname : "???"); + ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); return; } if (ia->ia6_flags & IN6_IFF_ANYCAST) { @@ -917,14 +944,14 @@ nd6_dad_start(ifa, tick) printf("nd6_dad_start: memory allocation failed for " "%s(%s)\n", ip6_sprintf(&ia->ia_addr.sin6_addr), - ifa->ifa_ifp ? ifa->ifa_ifp->if_xname : "???"); + ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); return; } bzero(dp, sizeof(*dp)); TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list); /* XXXJRT This is probably a purely debugging message. */ - printf("%s: starting DAD for %s\n", ifa->ifa_ifp->if_xname, + printf("%s: starting DAD for %s\n", if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr)); /* @@ -937,11 +964,9 @@ nd6_dad_start(ifa, tick) ifa->ifa_refcnt++; /*just for safety*/ dp->dad_count = ip6_dad_count; dp->dad_ns_icount = dp->dad_na_icount = 0; - dp->dad_ns_ocount = 0; + dp->dad_ns_ocount = dp->dad_ns_tcount = 0; if (!tick) { - dp->dad_ns_ocount++; - nd6_ns_output(ifa->ifa_ifp, NULL, &ia->ia_addr.sin6_addr, - NULL, 1); + nd6_dad_ns_output(dp, ifa); #if defined(__FreeBSD__) && __FreeBSD__ >= 3 dp->dad_timer = #endif @@ -971,7 +996,11 @@ nd6_dad_timer(ifa) struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; struct dadq *dp; +#ifdef __NetBSD__ s = splsoftnet(); /*XXX*/ +#else + s = splnet(); /*XXX*/ +#endif /* Sanity check */ if (ia == NULL) { @@ -987,14 +1016,26 @@ nd6_dad_timer(ifa) printf("nd6_dad_timer: called with duplicated address " "%s(%s)\n", ip6_sprintf(&ia->ia_addr.sin6_addr), - ifa->ifa_ifp ? ifa->ifa_ifp->if_xname : "???"); + ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); goto done; } if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) { printf("nd6_dad_timer: called with non-tentative address " "%s(%s)\n", ip6_sprintf(&ia->ia_addr.sin6_addr), - ifa->ifa_ifp ? ifa->ifa_ifp->if_xname : "???"); + ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); + goto done; + } + + /* timeouted with IFF_{RUNNING,UP} check */ + if (dp->dad_ns_tcount > dad_maxtry) { + printf("%s: could not run DAD, driver problem?\n", + if_name(ifa->ifa_ifp)); + + TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list); + free(dp, M_IP6NDP); + dp = NULL; + ifa->ifa_refcnt--; goto done; } @@ -1003,9 +1044,7 @@ nd6_dad_timer(ifa) /* * We have more NS to go. Send NS packet for DAD. */ - dp->dad_ns_ocount++; - nd6_ns_output(ifa->ifa_ifp, NULL, &ia->ia_addr.sin6_addr, - NULL, 1); + nd6_dad_ns_output(dp, ifa); #if defined(__FreeBSD__) && __FreeBSD__ >= 3 dp->dad_timer = #endif @@ -1045,7 +1084,7 @@ nd6_dad_timer(ifa) log(LOG_INFO, "DAD questionable for %s(%s): " "network card loops back multicast?\n", ip6_sprintf(&ia->ia_addr.sin6_addr), - ifa->ifa_ifp->if_xname); + if_name(ifa->ifa_ifp)); /* XXX consider it a duplicate or not? */ /* duplicate++; */ } else { @@ -1071,7 +1110,7 @@ nd6_dad_timer(ifa) /* XXXJRT This is probably a purely debugging message */ printf("%s: DAD complete for %s - no duplicates " - "found\n", ifa->ifa_ifp->if_xname, + "found\n", if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr)); TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list); @@ -1099,7 +1138,7 @@ nd6_dad_duplicated(ifa) } log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: %d NS, " - "%d NA\n", ifa->ifa_ifp->if_xname, + "%d NA\n", if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr), dp->dad_ns_icount, dp->dad_na_icount); @@ -1113,10 +1152,9 @@ nd6_dad_duplicated(ifa) #endif ); - /* XXXJRT This is probably a purely debugging message. */ printf("%s: DAD complete for %s - duplicate found\n", - ifa->ifa_ifp->if_xname, ip6_sprintf(&ia->ia_addr.sin6_addr)); - printf("%s: manual intervention required\n", ifa->ifa_ifp->if_xname); + if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr)); + printf("%s: manual intervention required\n", if_name(ifa->ifa_ifp)); TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list); free(dp, M_IP6NDP); @@ -1124,7 +1162,33 @@ nd6_dad_duplicated(ifa) ifa->ifa_refcnt--; } -void +static void +nd6_dad_ns_output(dp, ifa) + struct dadq *dp; + struct ifaddr *ifa; +{ + struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; + struct ifnet *ifp = ifa->ifa_ifp; + + dp->dad_ns_tcount++; + if ((ifp->if_flags & IFF_UP) == 0) { +#if 0 + printf("%s: interface down?\n", if_name(ifp)); +#endif + return; + } + if ((ifp->if_flags & IFF_RUNNING) == 0) { +#if 0 + printf("%s: interface not running?\n", if_name(ifp)); +#endif + return; + } + + dp->dad_ns_ocount++; + nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1); +} + +static void nd6_dad_ns_input(ifa) struct ifaddr *ifa; { @@ -1153,7 +1217,7 @@ nd6_dad_ns_input(ifa) if (dad_ignore_ns) { log(LOG_INFO, "nd6_dad_ns_input: ignoring DAD NS packet for " "address %s(%s)\n", ip6_sprintf(taddr6), - ifa->ifa_ifp->if_xname); + if_name(ifa->ifa_ifp)); return; } @@ -1179,7 +1243,7 @@ nd6_dad_ns_input(ifa) } } -void +static void nd6_dad_na_input(ifa) struct ifaddr *ifa; { diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index 7bdb5b21a83..438ecdc9909 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -1,4 +1,4 @@ -/* $NetBSD: nd6_rtr.c,v 1.6 1999/07/31 18:41:17 itojun Exp $ */ +/* $NetBSD: nd6_rtr.c,v 1.7 1999/12/13 15:17:23 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -38,7 +38,7 @@ #include <sys/time.h> #include <sys/kernel.h> #include <sys/errno.h> -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) #include <sys/ioctl.h> #endif #include <sys/syslog.h> @@ -56,9 +56,7 @@ #include <netinet6/nd6.h> #include <netinet6/icmp6.h> -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 -#define time_second time.tv_sec -#endif +#include <net/net_osdep.h> #define SDL(s) ((struct sockaddr_dl *)s) @@ -71,14 +69,14 @@ static struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *, struct nd_defrouter *)); static void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *)); static void pfxrtr_del __P((struct nd_pfxrouter *)); -static void pfxlist_onlink_check __P((void)); +static struct nd_pfxrouter *find_pfxlist_reachable_router __P((struct nd_prefix *)); static void nd6_detach_prefix __P((struct nd_prefix *)); static void nd6_attach_prefix __P((struct nd_prefix *)); +static void defrouter_addifreq __P((struct ifnet *)); -static int in6_are_prefix_equal __P((struct in6_addr *, struct in6_addr *, int)); -static void in6_prefixlen2mask __P((struct in6_addr *, int)); static void in6_init_address_ltimes __P((struct nd_prefix *ndpr, - struct in6_addrlifetime *lt6)); + struct in6_addrlifetime *lt6, + int update_vltime)); static int rt6_deleteroute __P((struct radix_node *, void *)); @@ -93,6 +91,9 @@ static u_char bmask [] = { }; #endif +struct ifnet *nd6_defifp; +int nd6_defifindex; + /* * Receive Router Solicitation Message - just for routers. * Router solicitation/advertisement is mostly managed by userland program @@ -216,6 +217,9 @@ nd6_ra_input(m, off, icmp6len) { struct nd_defrouter dr0; u_int32_t advreachable = nd_ra->nd_ra_reachable; +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) + long time_second = time.tv_sec; +#endif dr0.rtaddr = saddr6; dr0.flags = nd_ra->nd_ra_flags_reserved; @@ -291,19 +295,12 @@ nd6_ra_input(m, off, icmp6len) pr.ndpr_prefix.sin6_family = AF_INET6; pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix); pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix; - pr.ndpr_ifpr.ifpr_prefix = - (struct sockaddr *)&pr.ndpr_prefix; - /* TODO: link into interface prefix list */ - pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif; pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) ? 1 : 0; pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) ? 1 : 0; - pr.ndpr_rrf_decrvalid = 1; - pr.ndpr_rrf_decrprefd = 1; - pr.ndpr_origin = PR_ORIG_RA; pr.ndpr_plen = pi->nd_opt_pi_prefix_len; pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time); pr.ndpr_pltime = @@ -375,6 +372,13 @@ nd6_ra_input(m, off, icmp6len) } nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0); + + /* + * Installing a link-layer address might change the state of the + * router's neighbor cache, which might also affect our on-link + * detection of adveritsed prefixes. + */ + pfxlist_onlink_check(); } } @@ -407,7 +411,11 @@ defrouter_addreq(new) gate.sin6_addr = new->rtaddr; #if 1 +#ifdef __NetBSD__ s = splsoftnet(); +#else + s = splnet(); +#endif (void)rtrequest(RTM_ADD, (struct sockaddr *)&def, (struct sockaddr *)&gate, (struct sockaddr *)&mask, RTF_GATEWAY, NULL); @@ -420,11 +428,15 @@ defrouter_addreq(new) if ((rnh = rt_tables[AF_INET6]) == 0) return; +#ifdef __NetBSD__ s = splsoftnet(); -#if 0 - R_Malloc(rt, struct rtentry *, sizeof(*rt)); #else + s = splnet(); +#endif +#ifdef __NetBSD__ rt = pool_get(&rtentry_pool, PR_NOWAIT); +#else + R_Malloc(rt, struct rtentry *, sizeof(*rt)); #endif if (!rt) goto bad; @@ -456,6 +468,46 @@ bad: #endif } +/* Add a route to a given interface as default */ +static void +defrouter_addifreq(ifp) + struct ifnet *ifp; +{ + struct sockaddr_in6 def, mask; + struct ifaddr *ifa; + int error, flags; + + bzero(&def, sizeof(def)); + bzero(&mask, sizeof(mask)); + + def.sin6_len = mask.sin6_len = sizeof(struct sockaddr_in6); + def.sin6_family = mask.sin6_family = AF_INET6; + + /* + * Search for an ifaddr beloging to the specified interface. + * XXX: An IPv6 address are required to be assigned on the interface. + */ + if ((ifa = ifaof_ifpforaddr((struct sockaddr *)&def, ifp)) == NULL) { + log(LOG_ERR, /* better error? */ + "defrouter_addifreq: failed to find an ifaddr " + "to install a route to interface %s\n", + if_name(ifp)); + return; + } + + flags = ifa->ifa_flags; + if ((ifp->if_flags & IFF_POINTOPOINT) != 0) + flags &= ~RTF_CLONING; + if ((error = rtrequest(RTM_ADD, (struct sockaddr *)&def, + ifa->ifa_addr, (struct sockaddr *)&mask, + flags, NULL)) != 0) { + log(LOG_ERR, + "defrouter_addifreq: failed to install a route to " + "interface %s (errno = %d)\n", + if_name(ifp), error); + } +} + struct nd_defrouter * defrouter_lookup(addr, ifp) struct in6_addr *addr; @@ -463,9 +515,11 @@ defrouter_lookup(addr, ifp) { struct nd_defrouter *dr; - for(dr = nd_defrouter.lh_first; dr; dr = dr->dr_next) + for (dr = TAILQ_FIRST(&nd_defrouter); dr; + dr = TAILQ_NEXT(dr, dr_entry)) { if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) return(dr); + } return(NULL); /* search failed */ } @@ -491,16 +545,8 @@ defrouter_delreq(dr, dofree) (struct sockaddr *)&mask, RTF_GATEWAY, (struct rtentry **)0); - if (dofree) + if (dofree) /* XXX: necessary? */ free(dr, M_IP6NDP); - - if (nd_defrouter.lh_first) - defrouter_addreq(nd_defrouter.lh_first); - - /* - * xxx update the Destination Cache entries for all - * destinations using that neighbor as a router (7.2.5) - */ } void @@ -519,10 +565,10 @@ defrtrlist_del(dr) rt6_flush(&dr->rtaddr, dr->ifp); } - if (dr == nd_defrouter.lh_first) + if (dr == TAILQ_FIRST(&nd_defrouter)) deldr = dr; /* The router is primary. */ - LIST_REMOVE(dr, dr_entry); + TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); /* * Also delete all the pointers to the router in each prefix lists. @@ -535,20 +581,108 @@ defrtrlist_del(dr) pfxlist_onlink_check(); /* - * If the router is the primary one, delete the default route - * entry in the routing table. + * If the router is the primary one, choose a new one. + * Note that defrouter_select() will remove the current gateway + * from the routing table. */ if (deldr) - defrouter_delreq(deldr, 0); + defrouter_select(); + free(dr, M_IP6NDP); } +/* + * Default Router Selection according to Section 6.3.6 of RFC 2461: + * 1) Routers that are reachable or probably reachable should be + * preferred. + * 2) When no routers on the list are known to be reachable or + * probably reachable, routers SHOULD be selected in a round-robin + * fashion. + * 3) If the Default Router List is empty, assume that all + * destinations are on-link. + */ +void +defrouter_select() +{ +#ifdef __NetBSD__ + int s = splsoftnet(); +#else + int s = splnet(); +#endif + struct nd_defrouter *dr, anydr; + struct rtentry *rt = NULL; + struct llinfo_nd6 *ln = NULL; + + /* + * Search for a (probably) reachable router from the list. + */ + for (dr = TAILQ_FIRST(&nd_defrouter); dr; + dr = TAILQ_NEXT(dr, dr_entry)) { + if ((rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && + (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && + ND6_IS_LLINFO_PROBREACH(ln)) { + /* Got it, and move it to the head */ + TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); + TAILQ_INSERT_HEAD(&nd_defrouter, dr, dr_entry); + break; + } + } + + if ((dr = TAILQ_FIRST(&nd_defrouter))) { + /* + * De-install the previous default gateway and install + * a new one. + * Note that if there is no reachable router in the list, + * the head entry will be used anyway. + * XXX: do we have to check the current routing table entry? + */ + bzero(&anydr, sizeof(anydr)); + defrouter_delreq(&anydr, 0); + defrouter_addreq(dr); + } + else { + /* + * The Default Router List is empty, so install the default + * route to an inteface. + * XXX: The specification does not say this mechanism should + * be restricted to hosts, but this would be not useful + * (even harmful) for routers. + */ + if (!ip6_forwarding) { + /* + * De-install the current default route + * in advance. + */ + bzero(&anydr, sizeof(anydr)); + defrouter_delreq(&anydr, 0); + if (nd6_defifp) { + /* + * Install a route to the default interface + * as default route. + */ + defrouter_addifreq(nd6_defifp); + } + else /* noisy log? */ + log(LOG_INFO, "defrouter_select: " + "there's no default router and no default" + " interface\n"); + } + } + + splx(s); + return; +} + static struct nd_defrouter * defrtrlist_update(new) struct nd_defrouter *new; { struct nd_defrouter *dr, *n; +#ifdef __NetBSD__ int s = splsoftnet(); +#else + int s = splnet(); +#endif if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) { /* entry exists */ @@ -578,13 +712,15 @@ defrtrlist_update(new) } bzero(n, sizeof(*n)); *n = *new; - if (nd_defrouter.lh_first == NULL) { - LIST_INSERT_HEAD(&nd_defrouter, n, dr_entry); - defrouter_addreq(n); - } else { - LIST_INSERT_AFTER(nd_defrouter.lh_first, n, dr_entry); - defrouter_addreq(n); - } + + /* + * Insert the new router at the end of the Default Router List. + * If there is no other router, install it anyway. Otherwise, + * just continue to use the current default router. + */ + TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry); + if (TAILQ_FIRST(&nd_defrouter) == n) + defrouter_select(); splx(s); return(n); @@ -664,8 +800,6 @@ prelist_add(pr, dr) return ENOMEM; bzero(new, sizeof(*new)); *new = *pr; - /* let ndpr_ifpr.ifpr_prefix point ndpr_prefix. */ - new->ndpr_ifpr.ifpr_prefix = (struct sockaddr *)&new->ndpr_prefix; /* initilization */ new->ndpr_statef_onlink = pr->ndpr_statef_onlink; @@ -678,20 +812,11 @@ prelist_add(pr, dr) /* xxx ND_OPT_PI_FLAG_ONLINK processing */ +#ifdef __NetBSD__ s = splsoftnet(); - /* link ndpr_entry to if_prefixlist */ - { - struct ifnet *ifp = new->ndpr_ifp; - struct ifprefix *ifpr; - - if ((ifpr = ifp->if_prefixlist) != NULL) { - for ( ; ifpr->ifpr_next; ifpr = ifpr->ifpr_next) - continue; - ifpr->ifpr_next = ndpr2ifpr(new); - } - else - ifp->if_prefixlist = ndpr2ifpr(new); - } +#else + s = splnet(); +#endif /* link ndpr_entry to nd_prefix list */ LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry); splx(s); @@ -709,24 +834,11 @@ prelist_remove(pr) struct nd_pfxrouter *pfr, *next; int s; +#ifdef __NetBSD__ s = splsoftnet(); - /* unlink ndpr_entry from if_prefixlist */ - { - struct ifnet *ifp = pr->ndpr_ifp; - struct ifprefix *ifpr; - - if ((ifpr = ifp->if_prefixlist) == ndpr2ifpr(pr)) - ifp->if_prefixlist = ifpr->ifpr_next; - else { - while (ifpr->ifpr_next && - (ifpr->ifpr_next != ndpr2ifpr(pr))) - ifpr = ifpr->ifpr_next; - if (ifpr->ifpr_next) - ifpr->ifpr_next = ndpr2ifpr(pr)->ifpr_next; - else - printf("Couldn't unlink nd_prefix from ifp\n"); - } - } +#else + s = splnet(); +#endif /* unlink ndpr_entry from nd_prefix list */ LIST_REMOVE(pr, ndpr_entry); splx(s); @@ -756,45 +868,38 @@ prelist_update(new, dr, m) { struct in6_ifaddr *ia6 = NULL; struct nd_prefix *pr; +#ifdef __NetBSD__ int s = splsoftnet(); +#else + int s = splnet(); +#endif int error = 0; int auth; struct in6_addrlifetime *lt6; + auth = 0; if (m) { /* * Authenticity for NA consists authentication for * both IP header and IP datagrams, doesn't it ? */ +#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM) auth = (m->m_flags & M_AUTHIPHDR && m->m_flags & M_AUTHIPDGM) ? 1 : 0; - } else - auth = 0; +#endif + } if ((pr = prefix_lookup(new)) != NULL) { if (pr->ndpr_ifp != new->ndpr_ifp) { error = EADDRNOTAVAIL; goto end; } - - /* - * If the origin of the already-installed prefix is more - * preferable than the new one, ignore installation request. - */ - if (pr->ndpr_origin > new->ndpr_origin) { - error = EPERM; - goto end; - } - /* update prefix information */ - pr->ndpr_flags.prf_ra = new->ndpr_flags.prf_ra; - if (pr->ndpr_origin >= PR_ORIG_RR) - pr->ndpr_flags.prf_rr = new->ndpr_flags.prf_rr; + pr->ndpr_flags = new->ndpr_flags; pr->ndpr_vltime = new->ndpr_vltime; pr->ndpr_pltime = new->ndpr_pltime; pr->ndpr_preferred = new->ndpr_preferred; pr->ndpr_expire = new->ndpr_expire; - pr->ndpr_statef_delmark = 0; /* cancel deletion */ /* * RFC 2462 5.5.3 (d) or (e) @@ -840,7 +945,7 @@ prelist_update(new, dr, m) /* address lifetime <= prefix lifetime */ lt6->ia6t_vltime = new->ndpr_vltime; lt6->ia6t_pltime = new->ndpr_pltime; - in6_init_address_ltimes(new, lt6); + in6_init_address_ltimes(new, lt6, 1); } else { #define TWOHOUR (120*60) /* @@ -870,41 +975,24 @@ prelist_update(new, dr, m) lt6->ia6t_vltime = TWOHOUR; update++; } - if (TWOHOUR < new->ndpr_pltime - || lt6->ia6t_pltime < new->ndpr_pltime) { - new->ndpr_apltime = new->ndpr_pltime; - lt6->ia6t_pltime = new->ndpr_pltime; - update++; - } else if (auth - && lt6->ia6t_pltime <= TWOHOUR - && new->ndpr_pltime <= lt6->ia6t_pltime) { - lt6->ia6t_pltime = new->ndpr_pltime; - update++; - } else { - lt6->ia6t_pltime = TWOHOUR; - update++; - } + /* 2 hour rule is not imposed for pref lifetime */ + new->ndpr_apltime = new->ndpr_pltime; + lt6->ia6t_pltime = new->ndpr_pltime; #else /* update from Jim Bound, (ipng 6712) */ if (TWOHOUR < new->ndpr_vltime || lt6->ia6t_vltime < new->ndpr_vltime) { lt6->ia6t_vltime = new->ndpr_vltime; update++; } else if (auth) { - lt6->ia6t_pltime = new->ndpr_pltime; - update++; - } - if (TWOHOUR < new->ndpr_pltime - || lt6->ia6t_pltime < new->ndpr_pltime) { - lt6->ia6t_pltime = new->ndpr_pltime; - update++; - } else if (auth) { - lt6->ia6t_pltime = new->ndpr_pltime; + lt6->ia6t_vltime = new->ndpr_vltime; update++; } + + /* jim bound rule is not imposed for pref lifetime */ + lt6->ia6t_pltime = new->ndpr_pltime; #endif - if (update) - in6_init_address_ltimes(new, lt6); + in6_init_address_ltimes(new, lt6, update); } noautoconf1: @@ -954,7 +1042,7 @@ prelist_update(new, dr, m) /* address lifetime <= prefix lifetime */ lt6->ia6t_vltime = new->ndpr_vltime; lt6->ia6t_pltime = new->ndpr_pltime; - in6_init_address_ltimes(new, lt6); + in6_init_address_ltimes(new, lt6, 1); noautoconf2: error_tmp = prelist_add(new, dr); @@ -967,49 +1055,81 @@ prelist_update(new, dr, m) } /* + * A supplement function used in the on-link detection below; + * detect if a given prefix has a (probably) reachable advertising router. + * XXX: lengthy function name... + */ +static struct nd_pfxrouter * +find_pfxlist_reachable_router(pr) + struct nd_prefix *pr; +{ + struct nd_pfxrouter *pfxrtr; + struct rtentry *rt; + struct llinfo_nd6 *ln; + + for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr; + pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) { + if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0, + pfxrtr->router->ifp)) && + (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && + ND6_IS_LLINFO_PROBREACH(ln)) + break; /* found */ + } + + return(pfxrtr); + +} + +/* * Check if each prefix in the prefix list has at least one available router - * that advertised the prefix. - * If the check fails, the prefix may be off-link because, for example, + * that advertised the prefix (A router is "available" if its neighbor cache + * entry has reachable or probably reachable). + * If the check fails, the prefix may be off-link, because, for example, * we have moved from the network but the lifetime of the prefix has not * been expired yet. So we should not use the prefix if there is another * prefix that has an available router. - * But if there is no prefix that has an availble router, we still regards + * But if there is no prefix that has an available router, we still regards * all the prefixes as on-link. This is because we can't tell if all the * routers are simply dead or if we really moved from the network and there * is no router around us. */ -static void +void pfxlist_onlink_check() { struct nd_prefix *pr; - for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) - if (pr->ndpr_advrtrs.lh_first) /* pr has an available router */ + /* + * Check if there is a prefix that has a reachable advertising + * router. + */ + for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { + if (find_pfxlist_reachable_router(pr)) break; + } if (pr) { /* - * There is at least one prefix that has a router. First, - * detach prefixes which has no advertising router and then - * attach other prefixes. The order is important since an - * attached prefix and a detached prefix may have a same - * interface route. + * There is at least one prefix that has a reachable router. + * First, detach prefixes which has no reachable advertising + * router and then attach other prefixes. + * The order is important since an attached prefix and a + * detached prefix may have a same interface route. */ for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { - if (pr->ndpr_advrtrs.lh_first == NULL && + if (find_pfxlist_reachable_router(pr) == NULL && pr->ndpr_statef_onlink) { pr->ndpr_statef_onlink = 0; nd6_detach_prefix(pr); } } for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { - if (pr->ndpr_advrtrs.lh_first && - pr->ndpr_statef_onlink == 0) + if (find_pfxlist_reachable_router(pr) && + pr->ndpr_statef_onlink == 0) nd6_attach_prefix(pr); } } else { - /* there is no prefix that has a router */ + /* there is no prefix that has a reachable router */ for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) if (pr->ndpr_statef_onlink == 0) nd6_attach_prefix(pr); @@ -1045,7 +1165,7 @@ nd6_detach_prefix(pr) "nd6_detach_prefix: failed to delete route: " "%s/%d (errno = %d)\n", ip6_sprintf(&sa6.sin6_addr), - pr->ndpr_ifpr.ifpr_plen, + pr->ndpr_plen, e); } } @@ -1149,7 +1269,7 @@ in6_ifadd(ifp, in6, addr, prefixlen) /* prefixlen + ifidlen must be equal to 128 */ if (prefixlen != in6_mask2len(&ib->ia_prefixmask.sin6_addr)) { log(LOG_ERR, "in6_ifadd: wrong prefixlen for %s" - "(prefix=%d ifid=%d)\n", ifp->if_xname, + "(prefix=%d ifid=%d)\n", if_name(ifp), prefixlen, 128 - in6_mask2len(&ib->ia_prefixmask.sin6_addr)); return NULL; @@ -1224,17 +1344,10 @@ in6_ifadd(ifp, in6, addr, prefixlen) /* add interface route */ if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP|RTF_CLONING))) { -#ifdef __NetBSD__ log(LOG_NOTICE, "in6_ifadd: failed to add an interface route " "for %s/%d on %s, errno = %d\n", ip6_sprintf(&ia->ia_addr.sin6_addr), prefixlen, - ifp->if_xname, error); -#else - log(LOG_NOTICE, "in6_ifadd: failed to add an interface route " - "for %s/%d on %s%d, errno = %d\n", - ip6_sprintf(&ia->ia_addr.sin6_addr), prefixlen, - ifp->if_name, ifp->if_unit, error); -#endif + if_name(ifp), error); } else ia->ia_flags |= IFA_ROUTE; @@ -1245,7 +1358,7 @@ in6_ifadd(ifp, in6, addr, prefixlen) int error; /* not used */ struct in6_addr sol6; -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) /* Restore saved multicast addresses(if any). */ in6_restoremkludge(ia, ifp); #endif @@ -1334,7 +1447,7 @@ in6_ifdel(ifp, in6) return -1; } -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) in6_savemkludge(oia); #endif IFAFREE((&oia->ia_ifa)); @@ -1349,59 +1462,13 @@ in6_ifdel(ifp, in6) return 0; } -static int -in6_are_prefix_equal(p1, p2, len) - struct in6_addr *p1, *p2; - int len; -{ - int bytelen, bitlen; - - /* sanity check */ - if (0 > len || len > 128) { - log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n", - len); - return(0); - } - - bytelen = len / 8; - bitlen = len % 8; - - if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen)) - return(0); - if (p1->s6_addr[bytelen] >> (8 - bitlen) != - p2->s6_addr[bytelen] >> (8 - bitlen)) - return(0); - - return(1); -} - -static void -in6_prefixlen2mask(maskp, len) - struct in6_addr *maskp; - int len; -{ - u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; - int bytelen, bitlen, i; - - /* sanity check */ - if (0 > len || len > 128) { - log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n", - len); - return; - } - - bzero(maskp, sizeof(*maskp)); - bytelen = len / 8; - bitlen = len % 8; - for (i = 0; i < bytelen; i++) - maskp->s6_addr[i] = 0xff; - if (bitlen) - maskp->s6_addr[bytelen] = maskarray[bitlen - 1]; -} - int in6_init_prefix_ltimes(struct nd_prefix *ndpr) { +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) + long time_second = time.tv_sec; +#endif + /* check if preferred lifetime > valid lifetime */ if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) { log(LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime" @@ -1409,13 +1476,11 @@ in6_init_prefix_ltimes(struct nd_prefix *ndpr) (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime); return (EINVAL); } - if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME || - ndpr->ndpr_rrf_decrprefd == 0) + if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME) ndpr->ndpr_preferred = 0; else ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime; - if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME || - ndpr->ndpr_rrf_decrvalid == 0) + if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME) ndpr->ndpr_expire = 0; else ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime; @@ -1424,28 +1489,37 @@ in6_init_prefix_ltimes(struct nd_prefix *ndpr) } static void -in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) +in6_init_address_ltimes(struct nd_prefix *new, + struct in6_addrlifetime *lt6, + int update_vltime) { - /* init ia6t_expire */ - if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME || - (new->ndpr_origin >= PR_ORIG_RR && new->ndpr_rrf_decrvalid == 0)) - lt6->ia6t_expire = 0; - else { - lt6->ia6t_expire = time_second; - lt6->ia6t_expire += lt6->ia6t_vltime; +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) + long time_second = time.tv_sec; +#endif + + /* Valid lifetime must not be updated unless explicitly specified. */ + if (update_vltime) { + /* init ia6t_expire */ + if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) + lt6->ia6t_expire = 0; + else { + lt6->ia6t_expire = time_second; + lt6->ia6t_expire += lt6->ia6t_vltime; + } + /* Ensure addr lifetime <= prefix lifetime. */ + if (new->ndpr_expire && lt6->ia6t_expire && + new->ndpr_expire < lt6->ia6t_expire) + lt6->ia6t_expire = new->ndpr_expire; } + /* init ia6t_preferred */ - if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME || - (new->ndpr_origin >= PR_ORIG_RR && new->ndpr_rrf_decrprefd == 0)) + if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME) lt6->ia6t_preferred = 0; else { lt6->ia6t_preferred = time_second; lt6->ia6t_preferred += lt6->ia6t_pltime; } - /* ensure addr lifetime <= prefix lifetime */ - if (new->ndpr_expire && lt6->ia6t_expire && - new->ndpr_expire < lt6->ia6t_expire) - lt6->ia6t_expire = new->ndpr_expire; + /* Ensure addr lifetime <= prefix lifetime. */ if (new->ndpr_preferred && lt6->ia6t_preferred && new->ndpr_preferred < lt6->ia6t_preferred) lt6->ia6t_preferred = new->ndpr_preferred; @@ -1502,3 +1576,35 @@ rt6_deleteroute(rn, arg) rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0)); #undef SIN6 } + +int +nd6_setdefaultiface(ifindex) + int ifindex; +{ + int error = 0; + + if (ifindex < 0 || if_index < ifindex) + return(EINVAL); + + if (nd6_defifindex != ifindex) { + nd6_defifindex = ifindex; + if (nd6_defifindex > 0) + nd6_defifp = ifindex2ifnet[nd6_defifindex]; + else + nd6_defifp = NULL; + + /* + * If the Default Router List is empty, install a route + * to the specified interface as default or remove the default + * route when the default interface becomes canceled. + * The check for the queue is actually redundant, but + * we do this here to avoid re-install the default route + * if the list is NOT empty. + */ + if (TAILQ_FIRST(&nd_defrouter) == NULL) + defrouter_select(); + } + + return(error); +} + diff --git a/sys/netinet6/pim6_var.h b/sys/netinet6/pim6_var.h index d2a81d601a5..93b141de746 100644 --- a/sys/netinet6/pim6_var.h +++ b/sys/netinet6/pim6_var.h @@ -1,4 +1,4 @@ -/* $NetBSD: pim6_var.h,v 1.5 1999/11/19 10:41:43 bouyer Exp $ */ +/* $NetBSD: pim6_var.h,v 1.6 1999/12/13 15:17:23 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -/* KAME Id: pim6_var.h,v 1.1.4.2.6.2 1999/05/20 06:11:08 itojun Exp */ +/* KAME Id: pim6_var.h,v 1.3 1999/12/02 04:45:02 itojun Exp */ #ifndef _NETINET6_PIM6_VAR_H_ #define _NETINET6_PIM6_VAR_H_ diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index 465628ddf61..cada49e77b8 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -1,4 +1,4 @@ -/* $NetBSD: raw_ip6.c,v 1.11 1999/09/13 12:15:56 itojun Exp $ */ +/* $NetBSD: raw_ip6.c,v 1.12 1999/12/13 15:17:24 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -162,10 +162,10 @@ rip6_input(mp, offp, proto) if (in6p->in6p_ip6.ip6_nxt && in6p->in6p_ip6.ip6_nxt != proto) continue; - if (!IN6_IS_ADDR_ANY(&in6p->in6p_laddr) && + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) continue; - if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr) && + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) continue; if (in6p->in6p_cksum != -1 @@ -244,7 +244,8 @@ rip6_output(m, va_alist) int error = 0; struct ip6_pktopts opt, *optp = NULL; struct ifnet *oifp = NULL; - int priv = 0; + int type, code; /* for ICMPv6 output statistics only */ + int priv; va_list ap; va_start(ap, m); @@ -255,12 +256,13 @@ rip6_output(m, va_alist) in6p = sotoin6pcb(so); - { - struct proc *p = curproc; /* XXX */ + priv = 0; + { + struct proc *p = curproc; /* XXX */ - if (p && !suser(p->p_ucred, &p->p_acflag)) - priv = 1; - } + if (p && !suser(p->p_ucred, &p->p_acflag)) + priv = 1; + } dst = &dstsock->sin6_addr; if (control) { if ((error = ip6_setpktoptions(control, &opt, priv)) != 0) @@ -269,6 +271,22 @@ rip6_output(m, va_alist) } else optp = in6p->in6p_outputopts; + /* + * For an ICMPv6 packet, we should know its type and code + * to update statistics. + */ + if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { + struct icmp6_hdr *icmp6; + if (m->m_len < sizeof(struct icmp6_hdr) && + (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) { + error = ENOBUFS; + goto bad; + } + icmp6 = mtod(m, struct icmp6_hdr *); + type = icmp6->icmp6_type; + code = icmp6->icmp6_code; + } + M_PREPEND(m, sizeof(*ip6), M_WAIT); ip6 = mtod(m, struct ip6_hdr *); @@ -283,12 +301,13 @@ rip6_output(m, va_alist) * * XXX advanced-api value overrides sin6_scope_id */ - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { + if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst) || + IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst)) { struct in6_pktinfo *pi; /* * XXX Boundary check is assumed to be already done in - * in6_setpktoptions(). + * ip6_setpktoptions(). */ if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) { ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex); @@ -297,9 +316,8 @@ rip6_output(m, va_alist) else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && in6p->in6p_moptions && in6p->in6p_moptions->im6o_multicast_ifp) { - ip6->ip6_dst.s6_addr16[1] = - htons(in6p->in6p_moptions->im6o_multicast_ifp->if_index); - oifp = ifindex2ifnet[in6p->in6p_moptions->im6o_multicast_ifp->if_index]; + oifp = in6p->in6p_moptions->im6o_multicast_ifp; + ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index); } else if (dstsock->sin6_scope_id) { /* boundary check */ if (dstsock->sin6_scope_id < 0 @@ -312,12 +330,16 @@ rip6_output(m, va_alist) } } - if (IN6_IS_ADDR_ANY(&in6p->in6p_laddr)) { + /* + * Source address selection. + */ + { struct in6_addr *in6a; if ((in6a = in6_selectsrc(dstsock, optp, in6p->in6p_moptions, &in6p->in6p_route, + &in6p->in6p_laddr, &error)) == 0) { if (error == 0) error = EADDRNOTAVAIL; @@ -326,8 +348,7 @@ rip6_output(m, va_alist) ip6->ip6_src = *in6a; if (in6p->in6p_route.ro_rt) oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index]; - } else - ip6->ip6_src = in6p->in6p_laddr; + } ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; ip6->ip6_vfc = IPV6_VERSION; @@ -335,10 +356,7 @@ rip6_output(m, va_alist) ip6->ip6_plen = htons((u_short)plen); #endif ip6->ip6_nxt = in6p->in6p_ip6.ip6_nxt; - if (oifp) - ip6->ip6_hlim = nd_ifinfo[oifp->if_index].chlim; - else - ip6->ip6_hlim = in6p->in6p_ip6.ip6_hlim; + ip6->ip6_hlim = in6_selecthlim(in6p, oifp); if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || in6p->in6p_cksum != -1) { @@ -374,8 +392,15 @@ rip6_output(m, va_alist) #ifdef IPSEC m->m_pkthdr.rcvif = (struct ifnet *)so; #endif /*IPSEC*/ + + error = ip6_output(m, optp, &in6p->in6p_route, 0, in6p->in6p_moptions, + &oifp); + if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { + if (oifp) + icmp6_ifoutstat_inc(oifp, type, code); + icmp6stat.icp6s_outhist[type]++; + } - error = ip6_output(m, optp, &in6p->in6p_route, 0, in6p->in6p_moptions); goto freectl; bad: @@ -453,6 +478,11 @@ rip6_usrreq(so, req, m, nam, control, p) int s; int error = 0; /* extern struct socket *ip6_mrouter; */ /* xxx */ + int priv; + + priv = 0; + if (p && !suser(p->p_ucred, &p->p_acflag)) + priv++; if (req == PRU_CONTROL) return (in6_control(so, (u_long)m, (caddr_t)nam, @@ -462,7 +492,7 @@ rip6_usrreq(so, req, m, nam, control, p) case PRU_ATTACH: if (in6p) panic("rip6_attach"); - if (p == 0 || suser(p->p_ucred, &p->p_acflag)) { + if (!priv) { error = EACCES; break; } @@ -475,10 +505,10 @@ rip6_usrreq(so, req, m, nam, control, p) splx(s); in6p = sotoin6pcb(so); in6p->in6p_ip6.ip6_nxt = (long)nam; - in6p->in6p_ip6.ip6_hlim = ip6_defhlim; in6p->in6p_cksum = -1; #ifdef IPSEC - if ((error = ipsec_init_policy(&in6p->in6p_sp)) != 0) { + error = ipsec_init_policy(&in6p->in6p_sp); + if (error != 0) { in6_pcbdetach(in6p); break; } @@ -486,6 +516,11 @@ rip6_usrreq(so, req, m, nam, control, p) MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *, sizeof(struct icmp6_filter), M_PCB, M_NOWAIT); + if (in6p->in6p_icmp6filt == NULL) { + in6_pcbdetach(in6p); + error = ENOMEM; + break; + } ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt); break; @@ -525,7 +560,7 @@ rip6_usrreq(so, req, m, nam, control, p) } if ((ifnet.tqh_first == 0) || (addr->sin6_family != AF_INET6) || - (!IN6_IS_ADDR_ANY(&addr->sin6_addr) && + (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)) { error = EADDRNOTAVAIL; break; @@ -560,11 +595,12 @@ rip6_usrreq(so, req, m, nam, control, p) } /* Source address selection. XXX: need pcblookup? */ - in6a = &in6p->in6p_laddr; - if (IN6_IS_ADDR_ANY(in6a) && - (in6a = in6_selectsrc(addr, in6p->in6p_outputopts, - in6p->in6p_moptions, &in6p->in6p_route, - &error)) == NULL) { + in6a = in6_selectsrc(addr, in6p->in6p_outputopts, + in6p->in6p_moptions, + &in6p->in6p_route, + &in6p->in6p_laddr, + &error); + if (in6a == NULL) { if (error == 0) error = EADDRNOTAVAIL; break; diff --git a/sys/netinet6/route6.c b/sys/netinet6/route6.c index 38182289dc2..3856645f0f6 100644 --- a/sys/netinet6/route6.c +++ b/sys/netinet6/route6.c @@ -1,4 +1,4 @@ -/* $NetBSD: route6.c,v 1.3 1999/07/03 21:30:20 thorpej Exp $ */ +/* $NetBSD: route6.c,v 1.4 1999/12/13 15:17:24 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -32,11 +32,12 @@ #include <sys/param.h> #include <sys/mbuf.h> #include <sys/socket.h> +#include <sys/systm.h> #include <net/if.h> #include <netinet/in.h> -#include <netinet6/in6.h> +#include <netinet6/in6_var.h> #include <netinet6/ip6.h> #include <netinet6/ip6_var.h> @@ -54,14 +55,31 @@ route6_input(mp, offp, proto) register struct ip6_rthdr *rh; int off = *offp, rhlen; +#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(*rh), IPPROTO_DONE); ip6 = mtod(m, struct ip6_hdr *); rh = (struct ip6_rthdr *)((caddr_t)ip6 + off); +#else + ip6 = mtod(m, struct ip6_hdr *); + IP6_EXTHDR_GET(rh, struct ip6_rthdr *, m, off, sizeof(*rh)); + if (rh == NULL) { + ip6stat.ip6s_tooshort++; + return IPPROTO_DONE; + } +#endif switch(rh->ip6r_type) { case IPV6_RTHDR_TYPE_0: rhlen = (rh->ip6r_len + 1) << 3; +#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, rhlen, IPPROTO_DONE); +#else + IP6_EXTHDR_GET(rh, struct ip6_rthdr *, m, off, rhlen); + if (rh == NULL) { + ip6stat.ip6s_tooshort++; + return IPPROTO_DONE; + } +#endif if (ip6_rthdr0(m, ip6, (struct ip6_rthdr0 *)rh)) return(IPPROTO_DONE); break; diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index 629a76150e3..1418565bc03 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -1,4 +1,4 @@ -/* $NetBSD: udp6_usrreq.c,v 1.13 1999/09/13 12:15:56 itojun Exp $ */ +/* $NetBSD: udp6_usrreq.c,v 1.14 1999/12/13 15:17:24 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -88,12 +88,18 @@ #include <netinet/in.h> #include <netinet/in_var.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/in_pcb.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> #include <netinet6/ip6.h> #include <netinet6/in6_pcb.h> #include <netinet6/ip6_var.h> #include <netinet6/icmp6.h> -#include <netinet6/udp6.h> #include <netinet6/udp6_var.h> +#include <netinet6/ip6protosw.h> #ifdef IPSEC #include <netinet6/ipsec.h> @@ -108,7 +114,9 @@ struct in6pcb *udp6_last_in6pcb = &udb6; +#ifndef __NetBSD__ static int in6_mcmatch __P((struct in6pcb *, struct in6_addr *, struct ifnet *)); +#endif static void udp6_detach __P((struct in6pcb *)); static void udp6_notify __P((struct in6pcb *, int)); @@ -118,6 +126,7 @@ udp6_init() udb6.in6p_next = udb6.in6p_prev = &udb6; } +#ifndef __NetBSD__ static int in6_mcmatch(in6p, ia6, ifp) struct in6pcb *in6p; @@ -152,7 +161,7 @@ udp6_input(mp, offp, proto) register struct in6pcb *in6p; struct mbuf *opts = 0; int off = *offp; - int plen, ulen; + u_int32_t plen, ulen; struct sockaddr_in6 udp_in6; #if defined(NFAITH) && 0 < NFAITH @@ -166,12 +175,22 @@ udp6_input(mp, offp, proto) #endif udp6stat.udp6s_ipackets++; - IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); - ip6 = mtod(m, struct ip6_hdr *); - plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); + /* check for jumbogram is done in ip6_input. we can trust pkthdr.len */ + plen = m->m_pkthdr.len - off; +#ifndef PULLDOWN_TEST + IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); uh = (struct udphdr *)((caddr_t)ip6 + off); +#else + IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(struct udhpdr)); + if (uh == NULL) { + udp6stat.udp6s_hdrops++; + return IPPROTO_DONE; + } +#endif ulen = ntohs((u_short)uh->uh_ulen); + if (ulen == 0 && plen > 0xffff) /* jumbogram */ + ulen = plen; if (plen != ulen) { udp6stat.udp6s_badlen++; @@ -250,14 +269,14 @@ udp6_input(mp, offp, proto) in6p = in6p->in6p_next) { if (in6p->in6p_lport != uh->uh_dport) continue; - if (!IN6_IS_ADDR_ANY(&in6p->in6p_laddr)) { + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst) && !in6_mcmatch(in6p, &ip6->ip6_dst, m->m_pkthdr.rcvif)) continue; } - if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) { + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src) || in6p->in6p_fport != uh->uh_sport) @@ -426,6 +445,7 @@ bad: m_freem(opts); return IPPROTO_DONE; } +#endif /* * Notify a udp user of an asynchronous error; @@ -442,20 +462,22 @@ udp6_notify(in6p, errno) } void -udp6_ctlinput(cmd, sa, ip6, m, off) +udp6_ctlinput(cmd, sa, d) int cmd; struct sockaddr *sa; - register struct ip6_hdr *ip6; - struct mbuf *m; - int off; + void *d; { register struct udphdr *uhp; struct udphdr uh; struct sockaddr_in6 sa6; + register struct ip6_hdr *ip6; + struct mbuf *m; + int off; if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) return; + #if 0 if (cmd == PRC_IFNEWADDR) in6_mrejoin(&udb6); @@ -465,6 +487,17 @@ udp6_ctlinput(cmd, sa, ip6, m, off) ((unsigned)cmd >= PRC_NCMDS || inet6ctlerrmap[cmd] == 0)) return; + /* if the parameter is from icmp6, decode it. */ + if (d != NULL) { + struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + m = ip6cp->ip6c_m; + ip6 = ip6cp->ip6c_ip6; + off = ip6cp->ip6c_off; + } else { + m = NULL; + ip6 = NULL; + } + /* translate addresses into internal form */ sa6 = *(struct sockaddr_in6 *)sa; if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) @@ -506,16 +539,22 @@ udp6_output(in6p, m, addr6, control) register struct mbuf *m; struct mbuf *addr6, *control; { - register int ulen = m->m_pkthdr.len; - int plen = sizeof(struct udphdr) + ulen; + register u_int32_t ulen = m->m_pkthdr.len; + u_int32_t plen = sizeof(struct udphdr) + ulen; struct ip6_hdr *ip6; struct udphdr *udp6; - struct in6_addr laddr6; - int s = 0, error = 0; + struct in6_addr *laddr, *faddr; + u_short fport; + int error = 0; struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts; - int priv = 0; + int priv; struct proc *p = curproc; /* XXX */ + int af, hlen; +#ifdef INET + struct ip *ip; +#endif + priv = 0; if (p && !suser(p->p_ucred, &p->p_acflag)) priv = 1; if (control) { @@ -525,75 +564,190 @@ udp6_output(in6p, m, addr6, control) } if (addr6) { - laddr6 = in6p->in6p_laddr; - if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) { + /* + * IPv4 version of udp_output calls in_pcbconnect in this case, + * which needs splnet and affects performance. + * Since we saw no essential reason for calling in_pcbconnect, + * we get rid of such kind of logic, and call in6_selectsrc + * and In6_pcbsetport in order to fill in the local address + * and the local port. + */ + struct sockaddr_in6 *sin6 = mtod(addr6, struct sockaddr_in6 *); + + if (addr6->m_len != sizeof(*sin6)) { + error = EINVAL; + goto release; + } + if (sin6->sin6_family != AF_INET6) { + error = EAFNOSUPPORT; + goto release; + } + if (sin6->sin6_port == 0) { + error = EADDRNOTAVAIL; + goto release; + } + + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { error = EISCONN; goto release; } + + faddr = &sin6->sin6_addr; + fport = sin6->sin6_port; /* allow 0 port */ /* - * Must block input while temporarily connected. + * If the scope of the destination is link-local, + * embed the interface + * index in the address. + * + * XXX advanced-api value overrides sin6_scope_id */ - s = splsoftnet(); - error = in6_pcbconnect(in6p, addr6); - if (error) { - splx(s); + if (IN6_IS_ADDR_LINKLOCAL(faddr) || + IN6_IS_ADDR_MC_LINKLOCAL(faddr)) { + struct ip6_pktopts *optp = in6p->in6p_outputopts; + struct in6_pktinfo *pi = NULL; + struct ifnet *oifp = NULL; + struct ip6_moptions *mopt = NULL; + + /* + * XXX Boundary check is assumed to be already done in + * ip6_setpktoptions(). + */ + if (optp && (pi = optp->ip6po_pktinfo) && + pi->ipi6_ifindex) { + faddr->s6_addr16[1] = htons(pi->ipi6_ifindex); + oifp = ifindex2ifnet[pi->ipi6_ifindex]; + } + else if (IN6_IS_ADDR_MULTICAST(faddr) && + (mopt = in6p->in6p_moptions) && + mopt->im6o_multicast_ifp) { + oifp = mopt->im6o_multicast_ifp; + faddr->s6_addr16[1] = oifp->if_index; + } else if (sin6->sin6_scope_id) { + /* boundary check */ + if (sin6->sin6_scope_id < 0 + || if_index < sin6->sin6_scope_id) { + error = ENXIO; /* XXX EINVAL? */ + goto release; + } + /* XXX */ + faddr->s6_addr16[1] = + htons(sin6->sin6_scope_id & 0xffff); + } + } + + if (!IN6_IS_ADDR_V4MAPPED(faddr)) { + laddr = in6_selectsrc(sin6, in6p->in6p_outputopts, + in6p->in6p_moptions, + &in6p->in6p_route, + &in6p->in6p_laddr, &error); + } else + laddr = &in6p->in6p_laddr; /*XXX*/ + if (laddr == NULL) { + if (error == 0) + error = EADDRNOTAVAIL; goto release; } + if (in6p->in6p_lport == 0 && + (error = in6_pcbsetport(laddr, in6p)) != 0) + goto release; } else { - if (IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) { + if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { error = ENOTCONN; goto release; } + laddr = &in6p->in6p_laddr; + faddr = &in6p->in6p_faddr; + fport = in6p->in6p_fport; } + + if (!IN6_IS_ADDR_V4MAPPED(faddr)) { + af = AF_INET6; + hlen = sizeof(struct ip6_hdr); + } else { + af = AF_INET; + hlen = sizeof(struct ip); + } + /* * Calculate data length and get a mbuf * for UDP and IP6 headers. */ - M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr), M_DONTWAIT); + M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT); if (m == 0) { error = ENOBUFS; - if (addr6) - splx(s); goto release; } /* * Stuff checksum and output datagram. */ - ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; - ip6->ip6_vfc = IPV6_VERSION; + udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen); + udp6->uh_sport = in6p->in6p_lport; /* lport is always set in the PCB */ + udp6->uh_dport = fport; + if (plen <= 0xffff) + udp6->uh_ulen = htons((u_short)plen); + else + udp6->uh_ulen = 0; + udp6->uh_sum = 0; + + switch (af) { + case AF_INET6: + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; + ip6->ip6_vfc = IPV6_VERSION; #if 0 /* ip6_plen will be filled in ip6_output. */ - ip6->ip6_plen = htons((u_short)plen); + ip6->ip6_plen = htons((u_short)plen); #endif - ip6->ip6_nxt = IPPROTO_UDP; - ip6->ip6_hlim = in6p->in6p_ip6.ip6_hlim; /* XXX */ - ip6->ip6_src = in6p->in6p_laddr; - ip6->ip6_dst = in6p->in6p_faddr; - - udp6 = (struct udphdr *)(ip6 + 1); - udp6->uh_sport = in6p->in6p_lport; - udp6->uh_dport = in6p->in6p_fport; - udp6->uh_ulen = htons((u_short)plen); - udp6->uh_sum = 0; - - if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP, - sizeof(struct ip6_hdr), plen)) == 0) { - udp6->uh_sum = 0xffff; - } - - udp6stat.udp6s_opackets++; + ip6->ip6_nxt = IPPROTO_UDP; + ip6->ip6_hlim = in6_selecthlim(in6p, + in6p->in6p_route.ro_rt ? + in6p->in6p_route.ro_rt->rt_ifp : NULL); + ip6->ip6_src = *laddr; + ip6->ip6_dst = *faddr; + + if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP, + sizeof(struct ip6_hdr), plen)) == 0) { + udp6->uh_sum = 0xffff; + } + udp6stat.udp6s_opackets++; #ifdef IPSEC - m->m_pkthdr.rcvif = (struct ifnet *)in6p->in6p_socket; + m->m_pkthdr.rcvif = (struct ifnet *)in6p->in6p_socket; #endif /*IPSEC*/ - error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, - 0, in6p->in6p_moptions); + error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, + 0, in6p->in6p_moptions, NULL); + break; + case AF_INET: +#ifdef INET + /* can't transmit jumbogram over IPv4 */ + if (plen > 0xffff) { + error = EMSGSIZE; + goto release; + } - if (addr6) { - in6_pcbdisconnect(in6p); - in6p->in6p_laddr = laddr6; - splx(s); + ip = mtod(m, struct ip *); + + ip->ip_len = plen; + ip->ip_p = IPPROTO_UDP; + ip->ip_ttl = in6p->in6p_hops; /*XXX*/ + ip->ip_tos = 0; /*XXX*/ + bcopy(&laddr->s6_addr[12], &ip->ip_src, sizeof(ip->ip_src)); + bcopy(&faddr->s6_addr[12], &ip->ip_dst, sizeof(ip->ip_dst)); + + udp6->uh_sum = 0; + if ((udp6->uh_sum = in_cksum(m, ulen)) == 0) + udp6->uh_sum = 0xffff; + + udpstat.udps_opackets++; +#ifdef IPSEC + m->m_pkthdr.rcvif = NULL; /*XXX*/ +#endif /*IPSEC*/ + error = ip_output(m, NULL, &in6p->in6p_route, 0 /*XXX*/); + break; +#else + error = EAFNOSUPPORT; + goto release; +#endif } goto releaseopt; @@ -661,11 +815,13 @@ udp6_usrreq(so, req, m, addr6, control, p) if (error) break; in6p = sotoin6pcb(so); - in6p->in6p_ip6.ip6_hlim = ip6_defhlim; in6p->in6p_cksum = -1; /* just to be sure */ #ifdef IPSEC - if ((error = ipsec_init_policy(&in6p->in6p_sp)) != 0) + error = ipsec_init_policy(&in6p->in6p_sp); + if (error != 0) { in6_pcbdetach(in6p); + break; + } #endif /*IPSEC*/ break; @@ -684,7 +840,7 @@ udp6_usrreq(so, req, m, addr6, control, p) break; case PRU_CONNECT: - if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) { + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { error = EISCONN; break; } diff --git a/sys/netinet6/udp6_var.h b/sys/netinet6/udp6_var.h index 92642b244e1..f51fa836ce3 100644 --- a/sys/netinet6/udp6_var.h +++ b/sys/netinet6/udp6_var.h @@ -1,4 +1,4 @@ -/* $NetBSD: udp6_var.h,v 1.4 1999/11/19 10:41:43 bouyer Exp $ */ +/* $NetBSD: udp6_var.h,v 1.5 1999/12/13 15:17:24 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -67,7 +67,6 @@ #ifndef _NETINET6_UDP6_VAR_H_ #define _NETINET6_UDP6_VAR_H_ -#if defined(__FreeBSD__) || defined(__NetBSD__) /* * UDP Kernel structures and variables. */ @@ -86,6 +85,7 @@ struct udp6stat { u_quad_t udp6s_opackets; /* total output packets */ }; +#if defined(__FreeBSD__) || defined(__NetBSD__) /* * Names for UDP sysctl objects */ @@ -107,24 +107,6 @@ struct udp6stat { #endif /*__FreeBSD__||__NetBSD__*/ #ifdef __bsdi__ /* - * UDP Kernel structures and variables. - */ -struct udp6stat { - /* input statistics: */ - u_quad_t udp6s_ipackets; /* total input packets */ - u_quad_t udp6s_hdrops; /* packet shorter than header */ - u_quad_t udp6s_badsum; /* checksum error */ - u_quad_t udp6s_nosum; /* no checksum */ - u_quad_t udp6s_badlen; /* data length larger than packet */ - u_quad_t udp6s_noport; /* no socket on port */ - u_quad_t udp6s_noportmcast; /* of above, arrived as broadcast */ - u_quad_t udp6s_fullsock; /* not delivered, input socket full */ - u_quad_t udp6ps_pcbcachemiss; /* input packets missing pcb cache */ - /* output statistics: */ - u_quad_t udp6s_opackets; /* total output packets */ -}; - -/* * Names for UDP sysctl objects */ #define UDP6CTL_SENDMAX 2 /* default send buffer */ @@ -153,15 +135,20 @@ struct udp6stat { struct in6pcb udb6; struct udp6stat udp6stat; -void udp6_ctlinput __P((int, struct sockaddr *, struct ip6_hdr *, - struct mbuf *, int)); +void udp6_ctlinput __P((int, struct sockaddr *, void *)); void udp6_init __P((void)); int udp6_input __P((struct mbuf **, int *, int)); int udp6_output __P((struct in6pcb *, struct mbuf *, struct mbuf *, struct mbuf *)); int udp6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); +#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3) +int udp6_usrreq __P((struct socket *, + int, struct mbuf *, struct mbuf *, struct mbuf *, + struct proc *)); +#else int udp6_usrreq __P((struct socket *, - int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *)); + int, struct mbuf *, struct mbuf *, struct mbuf *)); +#endif #endif /* _KERNEL */ #endif /*_NETINET6_UDP6_VAR_H_*/ diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index 3cc6d016977..d43bab2737d 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -1,4 +1,4 @@ -/* $NetBSD: mbuf.h,v 1.47 1999/10/27 14:23:26 itojun Exp $ */ +/* $NetBSD: mbuf.h,v 1.48 1999/12/13 15:17:24 itojun Exp $ */ /*- * Copyright (c) 1996, 1997, 1999 The NetBSD Foundation, Inc. @@ -540,6 +540,7 @@ struct mbuf *m_get __P((int, int)); struct mbuf *m_getclr __P((int, int)); struct mbuf *m_gethdr __P((int, int)); struct mbuf *m_prepend __P((struct mbuf *,int,int)); +struct mbuf *m_pulldown __P((struct mbuf *, int, int, int *)); struct mbuf *m_pullup __P((struct mbuf *, int)); struct mbuf *m_retry __P((int, int)); struct mbuf *m_retryhdr __P((int, int)); |
