diff options
author | ume <ume@FreeBSD.org> | 2001-06-11 12:39:29 +0000 |
---|---|---|
committer | ume <ume@FreeBSD.org> | 2001-06-11 12:39:29 +0000 |
commit | 832f8d224926758a9ae0b23a6b45353e44fbc87a (patch) | |
tree | a79fc7ad2b97862c4a404f352f0211ad93a7b5f1 /sys/net | |
parent | 2693854b01a52b0395a91322aa3edf926bddff38 (diff) | |
download | FreeBSD-src-832f8d224926758a9ae0b23a6b45353e44fbc87a.zip FreeBSD-src-832f8d224926758a9ae0b23a6b45353e44fbc87a.tar.gz |
Sync with recent KAME.
This work was based on kame-20010528-freebsd43-snap.tgz and some
critical problem after the snap was out were fixed.
There are many many changes since last KAME merge.
TODO:
- The definitions of SADB_* in sys/net/pfkeyv2.h are still different
from RFC2407/IANA assignment because of binary compatibility
issue. It should be fixed under 5-CURRENT.
- ip6po_m member of struct ip6_pktopts is no longer used. But, it
is still there because of binary compatibility issue. It should
be removed under 5-CURRENT.
Reviewed by: itojun
Obtained from: KAME
MFC after: 3 weeks
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if.c | 21 | ||||
-rw-r--r-- | sys/net/if_faith.c | 241 | ||||
-rw-r--r-- | sys/net/if_faith.h | 41 | ||||
-rw-r--r-- | sys/net/if_gif.c | 184 | ||||
-rw-r--r-- | sys/net/if_gif.h | 4 | ||||
-rw-r--r-- | sys/net/if_loop.c | 29 | ||||
-rw-r--r-- | sys/net/if_sppp.h | 14 | ||||
-rw-r--r-- | sys/net/if_spppsubr.c | 795 | ||||
-rw-r--r-- | sys/net/if_stf.c | 93 | ||||
-rw-r--r-- | sys/net/net_osdep.c | 16 | ||||
-rw-r--r-- | sys/net/net_osdep.h | 111 | ||||
-rw-r--r-- | sys/net/pfkeyv2.h | 46 | ||||
-rw-r--r-- | sys/net/ppp_defs.h | 2 | ||||
-rw-r--r-- | sys/net/rtsock.c | 15 |
14 files changed, 1435 insertions, 177 deletions
diff --git a/sys/net/if.c b/sys/net/if.c index f98d85e..f52d74d 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -269,7 +269,7 @@ if_detach(ifp) #endif /* INET */ #ifdef INET6 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { - in6_purgeaddr(ifa, ifp); + in6_purgeaddr(ifa); /* ifp_addrhead is already updated */ continue; } @@ -278,6 +278,16 @@ if_detach(ifp) IFAFREE(ifa); } +#ifdef INET6 + /* + * Remove all IPv6 kernel structs related to ifp. This should be done + * before removing routing entries below, since IPv6 interface direct + * routes are expected to be removed by the IPv6-specific kernel API. + * Otherwise, the kernel will detect some inconsistency and bark it. + */ + in6_ifdetach(ifp); +#endif + /* * Delete all remaining routes using this interface * Unfortuneatly the only way to do this is to slog through @@ -290,11 +300,6 @@ if_detach(ifp) (void) rnh->rnh_walktree(rnh, if_rtdel, ifp); } -#ifdef INET6 - /* nuke all IPv6 kernel structs related to ifp */ - in6_ifdetach(ifp); -#endif - TAILQ_REMOVE(&ifnet, ifp, if_link); mtx_destroy(&ifp->if_snd.ifq_mtx); splx(s); @@ -897,6 +902,7 @@ ifioctl(so, cmd, data, p) #ifdef INET6 case SIOCSIFPHYADDR_IN6: #endif + case SIOCSLIFPHYADDR: case SIOCSIFMEDIA: case SIOCSIFGENERIC: error = suser(p); @@ -913,6 +919,9 @@ ifioctl(so, cmd, data, p) ifs = (struct ifstat *)data; ifs->ascii[0] = '\0'; + case SIOCGIFPSRCADDR: + case SIOCGIFPDSTADDR: + case SIOCGLIFPHYADDR: case SIOCGIFMEDIA: case SIOCGIFGENERIC: if (ifp->if_ioctl == 0) diff --git a/sys/net/if_faith.c b/sys/net/if_faith.c index b28fecd..840b77b 100644 --- a/sys/net/if_faith.c +++ b/sys/net/if_faith.c @@ -1,3 +1,5 @@ +/* $KAME: if_faith.c,v 1.21 2001/02/20 07:59:26 itojun Exp $ */ + /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. @@ -41,30 +43,58 @@ /* * Loopback interface driver for protocol testing and timing. */ +#include "opt_inet.h" +#include "opt_inet6.h" #include "faith.h" +#if NFAITH > 0 #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/mbuf.h> #include <sys/socket.h> +#include <sys/errno.h> #include <sys/sockio.h> +#include <sys/time.h> +#include <sys/queue.h> #include <net/if.h> #include <net/if_types.h> #include <net/netisr.h> #include <net/route.h> #include <net/bpf.h> +#include <net/if_faith.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#endif + +#ifdef INET6 +#ifndef INET +#include <netinet/in.h> +#endif +#include <netinet6/in6_var.h> +#include <netinet/ip6.h> +#include <netinet6/ip6_var.h> +#endif + +#include "bpf.h" +#define NBPFILTER NBPF #include <net/net_osdep.h> -extern int loioctl __P((struct ifnet *, u_long, caddr_t)); -extern int looutput __P((struct ifnet *ifp, - struct mbuf *m, struct sockaddr *dst, struct rtentry *rt)); +static int faithioctl __P((struct ifnet *, u_long, caddr_t)); +int faithoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *, + struct rtentry *)); +static void faithrtrequest __P((int, struct rtentry *, struct sockaddr *)); void faithattach __P((void *)); PSEUDO_SET(faithattach, if_faith); + static struct ifnet faithif[NFAITH]; #define FAITHMTU 1500 @@ -74,8 +104,8 @@ void faithattach(faith) void *faith; { - register struct ifnet *ifp; - register int i; + struct ifnet *ifp; + int i; for (i = 0; i < NFAITH; i++) { ifp = &faithif[i]; @@ -85,13 +115,210 @@ faithattach(faith) ifp->if_mtu = FAITHMTU; /* LOOPBACK commented out to announce IPv6 routes to faith */ ifp->if_flags = /* IFF_LOOPBACK | */ IFF_MULTICAST; - ifp->if_ioctl = loioctl; - ifp->if_output = looutput; + ifp->if_ioctl = faithioctl; + ifp->if_output = faithoutput; ifp->if_type = IFT_FAITH; ifp->if_snd.ifq_maxlen = ifqmaxlen; ifp->if_hdrlen = 0; ifp->if_addrlen = 0; if_attach(ifp); +#if NBPFILTER > 0 +#ifdef HAVE_OLD_BPF bpfattach(ifp, DLT_NULL, sizeof(u_int)); +#else + bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int)); +#endif +#endif + } +} + +int +faithoutput(ifp, m, dst, rt) + struct ifnet *ifp; + struct mbuf *m; + struct sockaddr *dst; + struct rtentry *rt; +{ + int isr; + struct ifqueue *ifq = 0; + + if ((m->m_flags & M_PKTHDR) == 0) + panic("faithoutput no HDR"); +#if NBPFILTER > 0 + /* BPF write needs to be handled specially */ + if (dst->sa_family == AF_UNSPEC) { + dst->sa_family = *(mtod(m, int *)); + m->m_len -= sizeof(int); + m->m_pkthdr.len -= sizeof(int); + m->m_data += sizeof(int); } + + if (ifp->if_bpf) { + /* + * We need to prepend the address family as + * a four byte field. Cons up a faith header + * to pacify bpf. This is safe because bpf + * will only read from the mbuf (i.e., it won't + * try to free it or keep a pointer a to it). + */ + struct mbuf m0; + u_int32_t af = dst->sa_family; + + m0.m_next = m; + m0.m_len = 4; + m0.m_data = (char *)⁡ + +#ifdef HAVE_OLD_BPF + bpf_mtap(ifp, &m0); +#else + bpf_mtap(ifp->if_bpf, &m0); +#endif + } +#endif + + if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { + m_freem(m); + return (rt->rt_flags & RTF_BLACKHOLE ? 0 : + rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); + } + 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; + isr = NETISR_IPV6; + break; +#endif + default: + m_freem(m); + return EAFNOSUPPORT; + } + + /* XXX do we need more sanity checks? */ + + m->m_pkthdr.rcvif = ifp; + ifp->if_ipackets++; + ifp->if_ibytes += m->m_pkthdr.len; + (void) IF_HANDOFF(ifq, m, NULL); + schednetisr(isr); + return (0); +} + +/* ARGSUSED */ +static void +faithrtrequest(cmd, rt, sa) + int cmd; + struct rtentry *rt; + struct sockaddr *sa; +{ + if (rt) { + rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */ + /* + * For optimal performance, the send and receive buffers + * should be at least twice the MTU plus a little more for + * overhead. + */ + rt->rt_rmx.rmx_recvpipe = + rt->rt_rmx.rmx_sendpipe = 3 * FAITHMTU; + } +} + +/* + * Process an ioctl request. + */ +/* ARGSUSED */ +static int +faithioctl(ifp, cmd, data) + struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + struct ifaddr *ifa; + struct ifreq *ifr = (struct ifreq *)data; + int error = 0; + + switch (cmd) { + + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP | IFF_RUNNING; + ifa = (struct ifaddr *)data; + ifa->ifa_rtrequest = faithrtrequest; + /* + * Everything else is done at a higher level. + */ + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + if (ifr == 0) { + error = EAFNOSUPPORT; /* XXX */ + break; + } + switch (ifr->ifr_addr.sa_family) { +#ifdef INET + case AF_INET: + break; +#endif +#ifdef INET6 + case AF_INET6: + break; +#endif + + default: + error = EAFNOSUPPORT; + break; + } + break; + +#ifdef SIOCSIFMTU + case SIOCSIFMTU: + ifp->if_mtu = ifr->ifr_mtu; + break; +#endif + + case SIOCSIFFLAGS: + break; + + default: + error = EINVAL; + } + return (error); +} + +/* + * XXX could be slow + * XXX could be layer violation to call sys/net from sys/netinet6 + */ +int +faithprefix(in6) + struct in6_addr *in6; +{ + struct rtentry *rt; + struct sockaddr_in6 sin6; + int ret; + + if (ip6_keepfaith == 0) + return 0; + + bzero(&sin6, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_addr = *in6; + rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); + if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH && + (rt->rt_ifp->if_flags & IFF_UP) != 0) + ret = 1; + else + ret = 0; + if (rt) + RTFREE(rt); + return ret; } +#endif /* NFAITH > 0 */ diff --git a/sys/net/if_faith.h b/sys/net/if_faith.h new file mode 100644 index 0000000..1e30bfb --- /dev/null +++ b/sys/net/if_faith.h @@ -0,0 +1,41 @@ +/* $FreeBSD$ */ +/* $KAME: if_faith.h,v 1.1 2000/07/26 05:49:21 itojun Exp $ */ + +/* + * Copyright (C) 2000 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NET_IF_FAITH_H_ +#define _NET_IF_FAITH_H_ + +#ifdef _KERNEL +struct in6_addr; +int faithprefix __P((struct in6_addr *)); +#endif + +#endif /* _NET_IF_FAITH_H_ */ diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c index 68031cb..465063c 100644 --- a/sys/net/if_gif.c +++ b/sys/net/if_gif.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: if_gif.c,v 1.28 2000/06/20 12:30:03 jinmei Exp $ */ +/* $KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -52,11 +52,11 @@ #include <net/route.h> #include <net/bpf.h> -#ifdef INET #include <netinet/in.h> #include <netinet/in_systm.h> -#include <netinet/in_var.h> #include <netinet/ip.h> +#ifdef INET +#include <netinet/in_var.h> #include <netinet/in_gif.h> #endif /* INET */ @@ -114,11 +114,11 @@ void gifattach(dummy) void *dummy; { - register struct gif_softc *sc; - register int i; + struct gif_softc *sc; + int i; ngif = NGIF; - gif = sc = malloc (ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAITOK); + gif = sc = malloc(ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAITOK); bzero(sc, ngif * sizeof(struct gif_softc)); for (i = 0; i < ngif; sc++, i++) { sc->gif_if.if_name = "gif"; @@ -148,6 +148,10 @@ gifattach(dummy) sc->gif_if.if_mtu = GIF_MTU; sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; +#if 0 + /* turn off ingress filter */ + sc->gif_if.if_flags |= IFF_LINK2; +#endif sc->gif_if.if_ioctl = gif_ioctl; sc->gif_if.if_output = gif_output; sc->gif_if.if_type = IFT_GIF; @@ -229,7 +233,7 @@ gif_output(ifp, m, dst, rt) struct sockaddr *dst; struct rtentry *rt; /* added in net2 */ { - register struct gif_softc *sc = (struct gif_softc*)ifp; + struct gif_softc *sc = (struct gif_softc*)ifp; int error = 0; static int called = 0; /* XXX: MUTEX */ @@ -268,7 +272,7 @@ gif_output(ifp, m, dst, rt) * try to free it or keep a pointer a to it). */ struct mbuf m0; - u_int af = dst->sa_family; + u_int32_t af = dst->sa_family; m0.m_next = m; m0.m_len = 4; @@ -284,8 +288,11 @@ gif_output(ifp, m, dst, rt) ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; + /* inner AF-specific encapsulation */ + /* XXX should we check if our outer source is legal? */ + /* dispatch to output logic based on outer AF */ switch (sc->gif_psrc->sa_family) { #ifdef INET case AF_INET: @@ -300,11 +307,13 @@ gif_output(ifp, m, dst, rt) default: m_freem(m); error = ENETDOWN; + goto end; } end: called = 0; /* reset recursion counter */ - if (error) ifp->if_oerrors++; + if (error) + ifp->if_oerrors++; return error; } @@ -315,7 +324,7 @@ gif_input(m, af, gifp) struct ifnet *gifp; { int isr; - register struct ifqueue *ifq = 0; + struct ifqueue *ifq = 0; if (gifp == NULL) { /* just in case */ @@ -335,11 +344,11 @@ gif_input(m, af, gifp) * try to free it or keep a pointer a to it). */ struct mbuf m0; - u_int af = AF_INET6; + u_int32_t af1 = af; m0.m_next = m; m0.m_len = 4; - m0.m_data = (char *)⁡ + m0.m_data = (char *)&af1; #ifdef HAVE_OLD_BPF bpf_mtap(gifp, &m0); @@ -435,13 +444,16 @@ gif_ioctl(ifp, cmd, data) #ifdef INET6 case SIOCSIFPHYADDR_IN6: #endif /* INET6 */ + case SIOCSLIFPHYADDR: switch (cmd) { +#ifdef INET case SIOCSIFPHYADDR: src = (struct sockaddr *) &(((struct in_aliasreq *)data)->ifra_addr); dst = (struct sockaddr *) &(((struct in_aliasreq *)data)->ifra_dstaddr); break; +#endif #ifdef INET6 case SIOCSIFPHYADDR_IN6: src = (struct sockaddr *) @@ -450,6 +462,66 @@ gif_ioctl(ifp, cmd, data) &(((struct in6_aliasreq *)data)->ifra_dstaddr); break; #endif + case SIOCSLIFPHYADDR: + src = (struct sockaddr *) + &(((struct if_laddrreq *)data)->addr); + dst = (struct sockaddr *) + &(((struct if_laddrreq *)data)->dstaddr); + } + + /* sa_family must be equal */ + if (src->sa_family != dst->sa_family) + return EINVAL; + + /* validate sa_len */ + switch (src->sa_family) { +#ifdef INET + case AF_INET: + if (src->sa_len != sizeof(struct sockaddr_in)) + return EINVAL; + break; +#endif +#ifdef INET6 + case AF_INET6: + if (src->sa_len != sizeof(struct sockaddr_in6)) + return EINVAL; + break; +#endif + default: + return EAFNOSUPPORT; + } + switch (dst->sa_family) { +#ifdef INET + case AF_INET: + if (dst->sa_len != sizeof(struct sockaddr_in)) + return EINVAL; + break; +#endif +#ifdef INET6 + case AF_INET6: + if (dst->sa_len != sizeof(struct sockaddr_in6)) + return EINVAL; + break; +#endif + default: + return EAFNOSUPPORT; + } + + /* check sa_family looks sane for the cmd */ + switch (cmd) { + case SIOCSIFPHYADDR: + if (src->sa_family == AF_INET) + break; + return EAFNOSUPPORT; +#ifdef INET6 + case SIOCSIFPHYADDR_IN6: + if (src->sa_family == AF_INET6) + break; + return EAFNOSUPPORT; +#endif /* INET6 */ + case SIOCSLIFPHYADDR: + /* checks done in the above */ + break; } for (i = 0; i < ngif; i++) { @@ -493,41 +565,16 @@ gif_ioctl(ifp, cmd, data) #endif } - if (src->sa_family != dst->sa_family || - src->sa_len != dst->sa_len) { - error = EINVAL; - break; - } - switch (src->sa_family) { -#ifdef INET - case AF_INET: - size = sizeof(struct sockaddr_in); - break; -#endif -#ifdef INET6 - case AF_INET6: - size = sizeof(struct sockaddr_in6); - break; -#endif - default: - error = EAFNOSUPPORT; - goto bad; - } - if (src->sa_len != size) { - error = EINVAL; - break; - } - if (sc->gif_psrc) free((caddr_t)sc->gif_psrc, M_IFADDR); - sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK); - bcopy((caddr_t)src, (caddr_t)sa, size); + sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); + bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); sc->gif_psrc = sa; if (sc->gif_pdst) free((caddr_t)sc->gif_pdst, M_IFADDR); - sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK); - bcopy((caddr_t)dst, (caddr_t)sa, size); + sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); + bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); sc->gif_pdst = sa; ifp->if_flags |= IFF_RUNNING; @@ -548,7 +595,7 @@ gif_ioctl(ifp, cmd, data) free((caddr_t)sc->gif_pdst, M_IFADDR); sc->gif_pdst = NULL; } - /* change the IFF_UP flag as well? */ + /* change the IFF_{UP, RUNNING} flag as well? */ break; #endif @@ -561,25 +608,27 @@ gif_ioctl(ifp, cmd, data) goto bad; } src = sc->gif_psrc; - switch (sc->gif_psrc->sa_family) { + switch (cmd) { #ifdef INET - case AF_INET: + case SIOCGIFPSRCADDR: dst = &ifr->ifr_addr; - size = sizeof(struct sockaddr_in); + size = sizeof(ifr->ifr_addr); break; #endif /* INET */ #ifdef INET6 - case AF_INET6: + case SIOCGIFPSRCADDR_IN6: dst = (struct sockaddr *) &(((struct in6_ifreq *)data)->ifr_addr); - size = sizeof(struct sockaddr_in6); + size = sizeof(((struct in6_ifreq *)data)->ifr_addr); break; #endif /* INET6 */ default: error = EADDRNOTAVAIL; goto bad; } - bcopy((caddr_t)src, (caddr_t)dst, size); + if (src->sa_len > size) + return EINVAL; + bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); break; case SIOCGIFPDSTADDR: @@ -591,25 +640,52 @@ gif_ioctl(ifp, cmd, data) goto bad; } src = sc->gif_pdst; - switch (sc->gif_pdst->sa_family) { + switch (cmd) { #ifdef INET - case AF_INET: + case SIOCGIFPDSTADDR: dst = &ifr->ifr_addr; - size = sizeof(struct sockaddr_in); + size = sizeof(ifr->ifr_addr); break; #endif /* INET */ #ifdef INET6 - case AF_INET6: + case SIOCGIFPDSTADDR_IN6: dst = (struct sockaddr *) &(((struct in6_ifreq *)data)->ifr_addr); - size = sizeof(struct sockaddr_in6); + size = sizeof(((struct in6_ifreq *)data)->ifr_addr); break; #endif /* INET6 */ default: error = EADDRNOTAVAIL; goto bad; } - bcopy((caddr_t)src, (caddr_t)dst, size); + if (src->sa_len > size) + return EINVAL; + bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); + break; + + case SIOCGLIFPHYADDR: + if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { + error = EADDRNOTAVAIL; + goto bad; + } + + /* copy src */ + src = sc->gif_psrc; + dst = (struct sockaddr *) + &(((struct if_laddrreq *)data)->addr); + size = sizeof(((struct if_laddrreq *)data)->addr); + if (src->sa_len > size) + return EINVAL; + bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); + + /* copy dst */ + src = sc->gif_pdst; + dst = (struct sockaddr *) + &(((struct if_laddrreq *)data)->dstaddr); + size = sizeof(((struct if_laddrreq *)data)->dstaddr); + if (src->sa_len > size) + return EINVAL; + bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); break; case SIOCSIFFLAGS: diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h index 3699286..3978e7b 100644 --- a/sys/net/if_gif.h +++ b/sys/net/if_gif.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: if_gif.h,v 1.13 2000/06/17 20:34:24 itojun Exp $ */ +/* $KAME: if_gif.h,v 1.17 2000/09/11 11:36:41 sumikawa Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -38,11 +38,9 @@ #define _NET_IF_GIF_H_ -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) #if defined(_KERNEL) && !defined(_LKM) #include "opt_inet.h" #endif -#endif #include <netinet/in.h> /* xxx sigh, why route have struct route instead of pointer? */ diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c index 0e9ac65..f8e11f7 100644 --- a/sys/net/if_loop.c +++ b/sys/net/if_loop.c @@ -58,6 +58,7 @@ #include <net/netisr.h> #include <net/route.h> #include <net/bpf.h> +#include <net/bpfdesc.h> #ifdef INET #include <netinet/in.h> @@ -236,6 +237,8 @@ looutput(ifp, m, dst, rt) m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t)); n->m_pkthdr = m->m_pkthdr; n->m_len = m->m_pkthdr.len; + n->m_pkthdr.aux = m->m_pkthdr.aux; + m->m_pkthdr.aux = (struct mbuf *)NULL; m_freem(m); m = n; } @@ -277,7 +280,7 @@ contiguousfail: int if_simloop(ifp, m, af, hlen) struct ifnet *ifp; - register struct mbuf *m; + struct mbuf *m; int af; int hlen; { @@ -300,17 +303,19 @@ if_simloop(ifp, m, af, hlen) if (ifp->if_bpf) { struct mbuf m0, *n = m; - /* - * We need to prepend the address family as - * a four byte field. Cons up a dummy header - * to pacify bpf. This is safe because bpf - * will only read from the mbuf (i.e., it won't - * try to free it or keep a pointer a to it). - */ - m0.m_next = m; - m0.m_len = 4; - m0.m_data = (char *)⁡ - n = &m0; + if (ifp->if_bpf->bif_dlt == DLT_NULL) { + /* + * We need to prepend the address family as + * a four byte field. Cons up a dummy header + * to pacify bpf. This is safe because bpf + * will only read from the mbuf (i.e., it won't + * try to free it or keep a pointer a to it). + */ + m0.m_next = m; + m0.m_len = 4; + m0.m_data = (char *)⁡ + n = &m0; + } bpf_mtap(ifp, n); } diff --git a/sys/net/if_sppp.h b/sys/net/if_sppp.h index 84fede3..0c2a201 100644 --- a/sys/net/if_sppp.h +++ b/sys/net/if_sppp.h @@ -39,6 +39,7 @@ struct slcp { }; #define IDX_IPCP 1 /* idx into state table */ +#define IDX_IPV6CP 2 /* idx into state table */ struct sipcp { u_long opts; /* IPCP options to send (bitfield) */ @@ -46,6 +47,10 @@ struct sipcp { #define IPCP_HISADDR_SEEN 1 /* have seen his address already */ #define IPCP_MYADDR_DYN 2 /* my address is dynamically assigned */ #define IPCP_MYADDR_SEEN 4 /* have seen his address already */ +#ifdef notdef +#define IPV6CP_MYIFID_DYN 2 /* my ifid is dynamically assigned */ +#endif +#define IPV6CP_MYIFID_SEEN 4 /* have seen his ifid already */ }; #define AUTHNAMELEN 32 @@ -62,8 +67,8 @@ struct sauth { u_char challenge[AUTHKEYLEN]; /* random challenge */ }; -#define IDX_PAP 2 -#define IDX_CHAP 3 +#define IDX_PAP 3 +#define IDX_CHAP 4 #define IDX_COUNT (IDX_CHAP + 1) /* bump this when adding cp's! */ @@ -87,8 +92,8 @@ struct sppp { u_int pp_flags; /* sub modes */ u_short pp_alivecnt; /* keepalive packets counter */ u_short pp_loopcnt; /* loopback detection counter */ - u_long pp_seq; /* local sequence number */ - u_long pp_rseq; /* remote sequence number */ + u_long pp_seq[IDX_COUNT]; /* local sequence number */ + u_long pp_rseq[IDX_COUNT]; /* remote sequence number */ enum ppp_phase pp_phase; /* phase we're currently in */ int state[IDX_COUNT]; /* state machine */ u_char confid[IDX_COUNT]; /* id of last configuration request */ @@ -98,6 +103,7 @@ struct sppp { struct callout_handle pap_my_to_ch; /* PAP needs one more... */ struct slcp lcp; /* LCP params */ struct sipcp ipcp; /* IPCP params */ + struct sipcp ipv6cp; /* IPv6CP params */ struct sauth myauth; /* auth params, i'm peer */ struct sauth hisauth; /* auth params, i'm authenticator */ /* diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c index 6928c95..e489c58 100644 --- a/sys/net/if_spppsubr.c +++ b/sys/net/if_spppsubr.c @@ -135,10 +135,12 @@ #define PPP_ISO 0x0023 /* ISO OSI Protocol */ #define PPP_XNS 0x0025 /* Xerox NS Protocol */ #define PPP_IPX 0x002b /* Novell IPX Protocol */ +#define PPP_IPV6 0x0057 /* Internet Protocol Version 6 */ #define PPP_LCP 0xc021 /* Link Control Protocol */ #define PPP_PAP 0xc023 /* Password Authentication Protocol */ #define PPP_CHAP 0xc223 /* Challenge-Handshake Auth Protocol */ #define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ #define CONF_REQ 1 /* PPP configure request */ #define CONF_ACK 2 /* PPP configure acknowledge */ @@ -165,6 +167,9 @@ #define IPCP_OPT_COMPRESSION 2 /* IP compression protocol (VJ) */ #define IPCP_OPT_ADDRESS 3 /* local IP address */ +#define IPV6CP_OPT_IFID 1 /* interface identifier */ +#define IPV6CP_OPT_COMPRESSION 2 /* IPv6 compression protocol */ + #define PAP_REQ 1 /* PAP name/password request */ #define PAP_ACK 2 /* PAP acknowledge */ #define PAP_NAK 3 /* PAP fail */ @@ -340,6 +345,21 @@ static void sppp_ipcp_tls(struct sppp *sp); static void sppp_ipcp_tlf(struct sppp *sp); static void sppp_ipcp_scr(struct sppp *sp); +static void sppp_ipv6cp_init(struct sppp *sp); +static void sppp_ipv6cp_up(struct sppp *sp); +static void sppp_ipv6cp_down(struct sppp *sp); +static void sppp_ipv6cp_open(struct sppp *sp); +static void sppp_ipv6cp_close(struct sppp *sp); +static void sppp_ipv6cp_TO(void *sp); +static int sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len); +static void sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len); +static void sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len); +static void sppp_ipv6cp_tlu(struct sppp *sp); +static void sppp_ipv6cp_tld(struct sppp *sp); +static void sppp_ipv6cp_tls(struct sppp *sp); +static void sppp_ipv6cp_tlf(struct sppp *sp); +static void sppp_ipv6cp_scr(struct sppp *sp); + static void sppp_pap_input(struct sppp *sp, struct mbuf *m); static void sppp_pap_init(struct sppp *sp); static void sppp_pap_open(struct sppp *sp); @@ -363,6 +383,9 @@ static const char *sppp_auth_type_name(u_short proto, u_char type); static const char *sppp_cp_type_name(u_char type); static const char *sppp_dotted_quad(u_long addr); static const char *sppp_ipcp_opt_name(u_char opt); +#ifdef INET6 +static const char *sppp_ipv6cp_opt_name(u_char opt); +#endif static const char *sppp_lcp_opt_name(u_char opt); static const char *sppp_phase_name(enum ppp_phase phase); static const char *sppp_proto_name(u_short proto); @@ -377,6 +400,15 @@ static void sppp_print_bytes(const u_char *p, u_short len); static void sppp_print_string(const char *p, u_short len); static void sppp_qflush(struct ifqueue *ifq); static void sppp_set_ip_addr(struct sppp *sp, u_long src); +#ifdef INET6 +static void sppp_get_ip6_addrs(struct sppp *sp, struct in6_addr *src, + struct in6_addr *dst, struct in6_addr *srcmask); +#ifdef IPV6CP_MYIFID_DYN +static void sppp_set_ip6_addr(struct sppp *sp, const struct in6_addr *src); +static void sppp_gen_ip6_addr(struct sppp *sp, const struct in6_addr *src); +#endif +static void sppp_suggest_ip6_addr(struct sppp *sp, struct in6_addr *src); +#endif /* our control protocol descriptors */ static const struct cp lcp = { @@ -395,6 +427,20 @@ static const struct cp ipcp = { sppp_ipcp_scr }; +static const struct cp ipv6cp = { + PPP_IPV6CP, IDX_IPV6CP, +#ifdef INET6 /*don't run IPv6CP if there's no IPv6 support*/ + CP_NCP, +#else + 0, +#endif + "ipv6cp", + sppp_ipv6cp_up, sppp_ipv6cp_down, sppp_ipv6cp_open, sppp_ipv6cp_close, + sppp_ipv6cp_TO, sppp_ipv6cp_RCR, sppp_ipv6cp_RCN_rej, sppp_ipv6cp_RCN_nak, + sppp_ipv6cp_tlu, sppp_ipv6cp_tld, sppp_ipv6cp_tls, sppp_ipv6cp_tlf, + sppp_ipv6cp_scr +}; + static const struct cp pap = { PPP_PAP, IDX_PAP, CP_AUTH, "pap", sppp_null, sppp_null, sppp_pap_open, sppp_pap_close, @@ -414,6 +460,7 @@ static const struct cp chap = { static const struct cp *cps[IDX_COUNT] = { &lcp, /* IDX_LCP */ &ipcp, /* IDX_IPCP */ + &ipv6cp, /* IDX_IPV6CP */ &pap, /* IDX_PAP */ &chap, /* IDX_CHAP */ }; @@ -499,7 +546,7 @@ sppp_input(struct ifnet *ifp, struct mbuf *m) h->address, h->control, ntohs(h->protocol)); if (sp->state[IDX_LCP] == STATE_OPENED) sppp_cp_send (sp, PPP_LCP, PROTO_REJ, - ++sp->pp_seq, m->m_pkthdr.len + 2, + ++sp->pp_seq[IDX_LCP], m->m_pkthdr.len + 2, &h->protocol); ++ifp->if_noproto; goto drop; @@ -530,6 +577,20 @@ sppp_input(struct ifnet *ifp, struct mbuf *m) } break; #endif +#ifdef INET6 + case PPP_IPV6CP: + if (sp->pp_phase == PHASE_NETWORK) + sppp_cp_input(&ipv6cp, sp, m); + m_freem (m); + return; + + case PPP_IPV6: + if (sp->state[IDX_IPV6CP] == STATE_OPENED) { + schednetisr (NETISR_IPV6); + inq = &ip6intrq; + } + break; +#endif #ifdef IPX case PPP_IPX: /* IPX IPXCP not implemented yet */ @@ -628,7 +689,7 @@ sppp_output(struct ifnet *ifp, struct mbuf *m, { struct sppp *sp = (struct sppp*) ifp; struct ppp_header *h; - struct ifqueue *ifq; + struct ifqueue *ifq = NULL; int s, rv = 0; int debug = ifp->if_flags & IFF_DEBUG; @@ -652,7 +713,6 @@ sppp_output(struct ifnet *ifp, struct mbuf *m, s = splimp(); } - ifq = &ifp->if_snd; #ifdef INET if (dst->sa_family == AF_INET) { /* XXX Check mbuf length here? */ @@ -699,6 +759,12 @@ sppp_output(struct ifnet *ifp, struct mbuf *m, } #endif +#ifdef INET6 + if (dst->sa_family == AF_INET6) { + /* XXX do something tricky here? */ + } +#endif + /* * Prepend general data packet PPP header. For now, IP only. */ @@ -750,7 +816,18 @@ sppp_output(struct ifnet *ifp, struct mbuf *m, if (sp->pp_mode == IFF_CISCO) h->protocol = htons (ETHERTYPE_IPV6); else { - goto nosupport; + /* + * Don't choke with an ENETDOWN early. It's + * possible that we just started dialing out, + * so don't drop the packet immediately. If + * we notice that we run out of buffer space + * below, we will however remember that we are + * not ready to carry IP packets, and return + * ENETDOWN, as opposed to ENOBUFS. + */ + h->protocol = htons(PPP_IPV6); + if (sp->state[IDX_IPV6CP] != STATE_OPENED) + rv = ENETDOWN; } break; #endif @@ -812,8 +889,8 @@ sppp_attach(struct ifnet *ifp) sp->pp_cpq.ifq_maxlen = 20; sp->pp_loopcnt = 0; sp->pp_alivecnt = 0; - sp->pp_seq = 0; - sp->pp_rseq = 0; + bzero(&sp->pp_seq[0], sizeof(sp->pp_seq)); + bzero(&sp->pp_rseq[0], sizeof(sp->pp_rseq)); sp->pp_phase = PHASE_DEAD; sp->pp_up = lcp.Up; sp->pp_down = lcp.Down; @@ -822,6 +899,7 @@ sppp_attach(struct ifnet *ifp) sppp_lcp_init(sp); sppp_ipcp_init(sp); + sppp_ipv6cp_init(sp); sppp_pap_init(sp); sppp_chap_init(sp); } @@ -1079,8 +1157,8 @@ sppp_cisco_input(struct sppp *sp, struct mbuf *m) break; case CISCO_KEEPALIVE_REQ: sp->pp_alivecnt = 0; - sp->pp_rseq = ntohl (h->par1); - if (sp->pp_seq == sp->pp_rseq) { + sp->pp_rseq[IDX_LCP] = ntohl (h->par1); + if (sp->pp_seq[IDX_LCP] == sp->pp_rseq[IDX_LCP]) { /* Local and remote sequence numbers are equal. * Probably, the line is in loopback mode. */ if (sp->pp_loopcnt >= MAXALIVECNT) { @@ -1096,9 +1174,9 @@ sppp_cisco_input(struct sppp *sp, struct mbuf *m) /* Generate new local sequence number */ #if defined(__FreeBSD__) && __FreeBSD__ >= 3 - sp->pp_seq = random(); + sp->pp_seq[IDX_LCP] = random(); #else - sp->pp_seq ^= time.tv_sec ^ time.tv_usec; + sp->pp_seq[IDX_LCP] ^= time.tv_sec ^ time.tv_usec; #endif break; } @@ -1574,8 +1652,8 @@ sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m) if (debug) log(-1, SPP_FMT "%s send code-rej for 0x%x\n", SPP_ARGS(ifp), cp->name, h->type); - sppp_cp_send(sp, cp->proto, CODE_REJ, ++sp->pp_seq, - m->m_pkthdr.len, h); + sppp_cp_send(sp, cp->proto, CODE_REJ, + ++sp->pp_seq[cp->protoidx], m->m_pkthdr.len, h); ++ifp->if_ierrors; } } @@ -1730,7 +1808,8 @@ sppp_close_event(const struct cp *cp, struct sppp *sp) case STATE_ACK_RCVD: case STATE_ACK_SENT: sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate; - sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 0, 0); + sppp_cp_send(sp, cp->proto, TERM_REQ, + ++sp->pp_seq[cp->protoidx], 0, 0); sppp_cp_change_state(cp, sp, STATE_CLOSING); break; } @@ -1772,8 +1851,8 @@ sppp_to_event(const struct cp *cp, struct sppp *sp) switch (sp->state[cp->protoidx]) { case STATE_CLOSING: case STATE_STOPPING: - sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, - 0, 0); + sppp_cp_send(sp, cp->proto, TERM_REQ, + ++sp->pp_seq[cp->protoidx], 0, 0); TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout, sp->ch[cp->protoidx]); break; @@ -1835,6 +1914,8 @@ sppp_lcp_init(struct sppp *sp) sp->lcp.magic = 0; sp->state[IDX_LCP] = STATE_INITIAL; sp->fail_counter[IDX_LCP] = 0; + sp->pp_seq[IDX_LCP] = 0; + sp->pp_rseq[IDX_LCP] = 0; sp->lcp.protos = 0; sp->lcp.mru = sp->lcp.their_mru = PP_MTU; @@ -2468,7 +2549,7 @@ sppp_lcp_scr(struct sppp *sp) opt[i++] = CHAP_MD5; } - sp->confid[IDX_LCP] = ++sp->pp_seq; + sp->confid[IDX_LCP] = ++sp->pp_seq[IDX_LCP]; sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt); } @@ -2519,6 +2600,8 @@ sppp_ipcp_init(struct sppp *sp) sp->ipcp.flags = 0; sp->state[IDX_IPCP] = STATE_INITIAL; sp->fail_counter[IDX_IPCP] = 0; + sp->pp_seq[IDX_IPCP] = 0; + sp->pp_rseq[IDX_IPCP] = 0; #if defined(__FreeBSD__) && __FreeBSD__ >= 3 callout_handle_init(&sp->ch[IDX_IPCP]); #endif @@ -2894,13 +2977,516 @@ sppp_ipcp_scr(struct sppp *sp) opt[i++] = ouraddr; } - sp->confid[IDX_IPCP] = ++sp->pp_seq; + sp->confid[IDX_IPCP] = ++sp->pp_seq[IDX_IPCP]; sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt); } /* *--------------------------------------------------------------------------* * * + * The IPv6CP implementation. * + * * + *--------------------------------------------------------------------------* + */ + +#ifdef INET6 +static void +sppp_ipv6cp_init(struct sppp *sp) +{ + sp->ipv6cp.opts = 0; + sp->ipv6cp.flags = 0; + sp->state[IDX_IPV6CP] = STATE_INITIAL; + sp->fail_counter[IDX_IPV6CP] = 0; + sp->pp_seq[IDX_IPV6CP] = 0; + sp->pp_rseq[IDX_IPV6CP] = 0; +#if defined(__NetBSD__) + callout_init(&sp->ch[IDX_IPV6CP]); +#endif +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + callout_handle_init(&sp->ch[IDX_IPV6CP]); +#endif +} + +static void +sppp_ipv6cp_up(struct sppp *sp) +{ + sppp_up_event(&ipv6cp, sp); +} + +static void +sppp_ipv6cp_down(struct sppp *sp) +{ + sppp_down_event(&ipv6cp, sp); +} + +static void +sppp_ipv6cp_open(struct sppp *sp) +{ + STDDCL; + struct in6_addr myaddr, hisaddr; + +#ifdef IPV6CP_MYIFID_DYN + sp->ipv6cp.flags &= ~(IPV6CP_MYIFID_SEEN|IPV6CP_MYIFID_DYN); +#else + sp->ipv6cp.flags &= ~IPV6CP_MYIFID_SEEN; +#endif + + sppp_get_ip6_addrs(sp, &myaddr, &hisaddr, 0); + /* + * If we don't have our address, this probably means our + * interface doesn't want to talk IPv6 at all. (This could + * be the case if somebody wants to speak only IPX, for + * example.) Don't open IPv6CP in this case. + */ + if (IN6_IS_ADDR_UNSPECIFIED(&myaddr)) { + /* XXX this message should go away */ + if (debug) + log(LOG_DEBUG, SPP_FMT "ipv6cp_open(): no IPv6 interface\n", + SPP_ARGS(ifp)); + return; + } + + sp->ipv6cp.flags |= IPV6CP_MYIFID_SEEN; + sp->ipv6cp.opts |= (1 << IPV6CP_OPT_IFID); + sppp_open_event(&ipv6cp, sp); +} + +static void +sppp_ipv6cp_close(struct sppp *sp) +{ + sppp_close_event(&ipv6cp, sp); +} + +static void +sppp_ipv6cp_TO(void *cookie) +{ + sppp_to_event(&ipv6cp, (struct sppp *)cookie); +} + +/* + * Analyze a configure request. Return true if it was agreeable, and + * caused action sca, false if it has been rejected or nak'ed, and + * caused action scn. (The return value is used to make the state + * transition decision in the state automaton.) + */ +static int +sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len) +{ + u_char *buf, *r, *p; + struct ifnet *ifp = &sp->pp_if; + int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG; + struct in6_addr myaddr, desiredaddr, suggestaddr; + int ifidcount; + int type; + int collision, nohisaddr; + + len -= 4; + origlen = len; + /* + * Make sure to allocate a buf that can at least hold a + * conf-nak with an `address' option. We might need it below. + */ + buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT); + if (! buf) + return (0); + + /* pass 1: see if we can recognize them */ + if (debug) + log(LOG_DEBUG, SPP_FMT "ipv6cp parse opts:", + SPP_ARGS(ifp)); + p = (void*) (h+1); + ifidcount = 0; + for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { + if (debug) + addlog(" %s", sppp_ipv6cp_opt_name(*p)); + switch (*p) { + case IPV6CP_OPT_IFID: + if (len >= 10 && p[1] == 10 && ifidcount == 0) { + /* correctly formed address option */ + ifidcount++; + continue; + } + if (debug) + addlog(" [invalid]"); + break; +#ifdef notyet + case IPV6CP_OPT_COMPRESSION: + if (len >= 4 && p[1] >= 4) { + /* correctly formed compress option */ + continue; + } + if (debug) + addlog(" [invalid]"); + break; +#endif + default: + /* Others not supported. */ + if (debug) + addlog(" [rej]"); + break; + } + /* Add the option to rejected list. */ + bcopy (p, r, p[1]); + r += p[1]; + rlen += p[1]; + } + if (rlen) { + if (debug) + addlog(" send conf-rej\n"); + sppp_cp_send (sp, PPP_IPV6CP, CONF_REJ, h->ident, rlen, buf); + goto end; + } else if (debug) + addlog("\n"); + + /* pass 2: parse option values */ + sppp_get_ip6_addrs(sp, &myaddr, 0, 0); + if (debug) + log(LOG_DEBUG, SPP_FMT "ipv6cp parse opt values: ", + SPP_ARGS(ifp)); + p = (void*) (h+1); + len = origlen; + type = CONF_ACK; + for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { + if (debug) + addlog(" %s", sppp_ipv6cp_opt_name(*p)); + switch (*p) { +#ifdef notyet + case IPV6CP_OPT_COMPRESSION: + continue; +#endif + case IPV6CP_OPT_IFID: + bzero(&desiredaddr, sizeof(desiredaddr)); + bcopy(&p[2], &desiredaddr.s6_addr[8], 8); + collision = (bcmp(&desiredaddr.s6_addr[8], + &myaddr.s6_addr[8], 8) == 0); + nohisaddr = IN6_IS_ADDR_UNSPECIFIED(&desiredaddr); + + desiredaddr.s6_addr16[0] = htons(0xfe80); + desiredaddr.s6_addr16[1] = htons(sp->pp_if.if_index); + + if (!collision && !nohisaddr) { + /* no collision, hisaddr known - Conf-Ack */ + type = CONF_ACK; + + if (debug) { + addlog(" %s [%s]", + ip6_sprintf(&desiredaddr), + sppp_cp_type_name(type)); + } + continue; + } + + bzero(&suggestaddr, sizeof(&suggestaddr)); + if (collision && nohisaddr) { + /* collision, hisaddr unknown - Conf-Rej */ + type = CONF_REJ; + bzero(&p[2], 8); + } else { + /* + * - no collision, hisaddr unknown, or + * - collision, hisaddr known + * Conf-Nak, suggest hisaddr + */ + type = CONF_NAK; + sppp_suggest_ip6_addr(sp, &suggestaddr); + bcopy(&suggestaddr.s6_addr[8], &p[2], 8); + } + if (debug) + addlog(" %s [%s]", ip6_sprintf(&desiredaddr), + sppp_cp_type_name(type)); + break; + } + /* Add the option to nak'ed list. */ + bcopy (p, r, p[1]); + r += p[1]; + rlen += p[1]; + } + + if (rlen == 0 && type == CONF_ACK) { + if (debug) + addlog(" send %s\n", sppp_cp_type_name(type)); + sppp_cp_send (sp, PPP_IPV6CP, type, h->ident, origlen, h+1); + } else { +#ifdef DIAGNOSTIC + if (type == CONF_ACK) + panic("IPv6CP RCR: CONF_ACK with non-zero rlen"); +#endif + + if (debug) { + addlog(" send %s suggest %s\n", + sppp_cp_type_name(type), ip6_sprintf(&suggestaddr)); + } + sppp_cp_send (sp, PPP_IPV6CP, type, h->ident, rlen, buf); + } + + end: + free (buf, M_TEMP); + return (rlen == 0); +} + +/* + * Analyze the IPv6CP Configure-Reject option list, and adjust our + * negotiation. + */ +static void +sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) +{ + u_char *buf, *p; + struct ifnet *ifp = &sp->pp_if; + int debug = ifp->if_flags & IFF_DEBUG; + + len -= 4; + buf = malloc (len, M_TEMP, M_NOWAIT); + if (!buf) + return; + + if (debug) + log(LOG_DEBUG, SPP_FMT "ipv6cp rej opts:", + SPP_ARGS(ifp)); + + p = (void*) (h+1); + for (; len > 1 && p[1]; len -= p[1], p += p[1]) { + if (debug) + addlog(" %s", sppp_ipv6cp_opt_name(*p)); + switch (*p) { + case IPV6CP_OPT_IFID: + /* + * Peer doesn't grok address option. This is + * bad. XXX Should we better give up here? + */ + sp->ipv6cp.opts &= ~(1 << IPV6CP_OPT_IFID); + break; +#ifdef notyet + case IPV6CP_OPT_COMPRESS: + sp->ipv6cp.opts &= ~(1 << IPV6CP_OPT_COMPRESS); + break; +#endif + } + } + if (debug) + addlog("\n"); + free (buf, M_TEMP); + return; +} + +/* + * Analyze the IPv6CP Configure-NAK option list, and adjust our + * negotiation. + */ +static void +sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) +{ + u_char *buf, *p; + struct ifnet *ifp = &sp->pp_if; + int debug = ifp->if_flags & IFF_DEBUG; + struct in6_addr suggestaddr; + + len -= 4; + buf = malloc (len, M_TEMP, M_NOWAIT); + if (!buf) + return; + + if (debug) + log(LOG_DEBUG, SPP_FMT "ipv6cp nak opts:", + SPP_ARGS(ifp)); + + p = (void*) (h+1); + for (; len > 1 && p[1]; len -= p[1], p += p[1]) { + if (debug) + addlog(" %s", sppp_ipv6cp_opt_name(*p)); + switch (*p) { + case IPV6CP_OPT_IFID: + /* + * Peer doesn't like our local ifid. See + * if we can do something for him. We'll drop + * him our address then. + */ + if (len < 10 || p[1] != 10) + break; + bzero(&suggestaddr, sizeof(suggestaddr)); + suggestaddr.s6_addr16[0] = htons(0xfe80); + suggestaddr.s6_addr16[1] = htons(sp->pp_if.if_index); + bcopy(&p[2], &suggestaddr.s6_addr[8], 8); + + sp->ipv6cp.opts |= (1 << IPV6CP_OPT_IFID); + if (debug) + addlog(" [suggestaddr %s]", + ip6_sprintf(&suggestaddr)); +#ifdef IPV6CP_MYIFID_DYN + /* + * When doing dynamic address assignment, + * we accept his offer. + */ + if (sp->ipv6cp.flags & IPV6CP_MYIFID_DYN) { + struct in6_addr lastsuggest; + /* + * If <suggested myaddr from peer> equals to + * <hisaddr we have suggested last time>, + * we have a collision. generate new random + * ifid. + */ + sppp_suggest_ip6_addr(&lastsuggest); + if (IN6_ARE_ADDR_EQUAL(&suggestaddr, + lastsuggest)) { + if (debug) + addlog(" [random]"); + sppp_gen_ip6_addr(sp, &suggestaddr); + } + sppp_set_ip6_addr(sp, &suggestaddr, 0); + if (debug) + addlog(" [agree]"); + sp->ipv6cp.flags |= IPV6CP_MYIFID_SEEN; + } +#else + /* + * Since we do not do dynamic address assignment, + * we ignore it and thus continue to negotiate + * our already existing value. This can possibly + * go into infinite request-reject loop. + * + * This is not likely because we normally use + * ifid based on MAC-address. + * If you have no ethernet card on the node, too bad. + * XXX should we use fail_counter? + */ +#endif + break; +#ifdef notyet + case IPV6CP_OPT_COMPRESS: + /* + * Peer wants different compression parameters. + */ + break; +#endif + } + } + if (debug) + addlog("\n"); + free (buf, M_TEMP); + return; +} +static void +sppp_ipv6cp_tlu(struct sppp *sp) +{ + /* we are up - notify isdn daemon */ + if (sp->pp_con) + sp->pp_con(sp); +} + +static void +sppp_ipv6cp_tld(struct sppp *sp) +{ +} + +static void +sppp_ipv6cp_tls(struct sppp *sp) +{ + /* indicate to LCP that it must stay alive */ + sp->lcp.protos |= (1 << IDX_IPV6CP); +} + +static void +sppp_ipv6cp_tlf(struct sppp *sp) +{ + +#if 0 /* need #if 0 to close IPv6CP properly */ + /* we no longer need LCP */ + sp->lcp.protos &= ~(1 << IDX_IPV6CP); + sppp_lcp_check_and_close(sp); +#endif +} + +static void +sppp_ipv6cp_scr(struct sppp *sp) +{ + char opt[10 /* ifid */ + 4 /* compression, minimum */]; + struct in6_addr ouraddr; + int i = 0; + + if (sp->ipv6cp.opts & (1 << IPV6CP_OPT_IFID)) { + sppp_get_ip6_addrs(sp, &ouraddr, 0, 0); + opt[i++] = IPV6CP_OPT_IFID; + opt[i++] = 10; + bcopy(&ouraddr.s6_addr[8], &opt[i], 8); + i += 8; + } + +#ifdef notyet + if (sp->ipv6cp.opts & (1 << IPV6CP_OPT_COMPRESSION)) { + opt[i++] = IPV6CP_OPT_COMPRESSION; + opt[i++] = 4; + opt[i++] = 0; /* TBD */ + opt[i++] = 0; /* TBD */ + /* variable length data may follow */ + } +#endif + + sp->confid[IDX_IPV6CP] = ++sp->pp_seq[IDX_IPV6CP]; + sppp_cp_send(sp, PPP_IPV6CP, CONF_REQ, sp->confid[IDX_IPV6CP], i, &opt); +} +#else /*INET6*/ +static void sppp_ipv6cp_init(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_up(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_down(struct sppp *sp) +{ +} + + +static void sppp_ipv6cp_open(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_close(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_TO(void *sp) +{ +} + +static int sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len) +{ + return 0; +} + +static void sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) +{ +} + +static void sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) +{ +} + +static void sppp_ipv6cp_tlu(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_tld(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_tls(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_tlf(struct sppp *sp) +{ +} + +static void sppp_ipv6cp_scr(struct sppp *sp) +{ +} +#endif /*INET6*/ + +/* + *--------------------------------------------------------------------------* + * * * The CHAP implementation. * * * *--------------------------------------------------------------------------* @@ -3213,6 +3799,8 @@ sppp_chap_init(struct sppp *sp) /* Chap doesn't have STATE_INITIAL at all. */ sp->state[IDX_CHAP] = STATE_CLOSED; sp->fail_counter[IDX_CHAP] = 0; + sp->pp_seq[IDX_CHAP] = 0; + sp->pp_rseq[IDX_CHAP] = 0; #if defined(__FreeBSD__) && __FreeBSD__ >= 3 callout_handle_init(&sp->ch[IDX_CHAP]); #endif @@ -3371,7 +3959,7 @@ sppp_chap_scr(struct sppp *sp) ch[3] = seed ^ random(); clen = AUTHKEYLEN; - sp->confid[IDX_CHAP] = ++sp->pp_seq; + sp->confid[IDX_CHAP] = ++sp->pp_seq[IDX_CHAP]; sppp_auth_send(&chap, sp, CHAP_CHALLENGE, sp->confid[IDX_CHAP], sizeof clen, (const char *)&clen, @@ -3544,6 +4132,8 @@ sppp_pap_init(struct sppp *sp) /* PAP doesn't have STATE_INITIAL at all. */ sp->state[IDX_PAP] = STATE_CLOSED; sp->fail_counter[IDX_PAP] = 0; + sp->pp_seq[IDX_PAP] = 0; + sp->pp_rseq[IDX_PAP] = 0; #if defined(__FreeBSD__) && __FreeBSD__ >= 3 callout_handle_init(&sp->ch[IDX_PAP]); callout_handle_init(&sp->pap_my_to_ch); @@ -3678,7 +4268,7 @@ sppp_pap_scr(struct sppp *sp) { u_char idlen, pwdlen; - sp->confid[IDX_PAP] = ++sp->pp_seq; + sp->confid[IDX_PAP] = ++sp->pp_seq[IDX_PAP]; pwdlen = sppp_strnlen(sp->myauth.secret, AUTHKEYLEN); idlen = sppp_strnlen(sp->myauth.name, AUTHNAMELEN); @@ -3824,11 +4414,11 @@ sppp_keepalive(void *dummy) if (sp->pp_alivecnt <= MAXALIVECNT) ++sp->pp_alivecnt; if (sp->pp_mode == IFF_CISCO) - sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, - sp->pp_rseq); + sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, + ++sp->pp_seq[IDX_LCP], sp->pp_rseq[IDX_LCP]); else if (sp->pp_phase >= PHASE_AUTHENTICATE) { long nmagic = htonl (sp->lcp.magic); - sp->lcp.echoid = ++sp->pp_seq; + sp->lcp.echoid = ++sp->pp_seq[IDX_LCP]; sppp_cp_send (sp, PPP_LCP, ECHO_REQ, sp->lcp.echoid, 4, &nmagic); } @@ -3957,8 +4547,154 @@ sppp_set_ip_addr(struct sppp *sp, u_long src) } #endif } +} + +#ifdef INET6 +/* + * Get both IPv6 addresses. + */ +static void +sppp_get_ip6_addrs(struct sppp *sp, struct in6_addr *src, struct in6_addr *dst, + struct in6_addr *srcmask) +{ + struct ifnet *ifp = &sp->pp_if; + struct ifaddr *ifa; + struct sockaddr_in6 *si, *sm; + struct in6_addr ssrc, ddst; + + sm = NULL; + bzero(&ssrc, sizeof(ssrc)); + bzero(&ddst, sizeof(ddst)); + /* + * Pick the first link-local AF_INET6 address from the list, + * aliases don't make any sense on a p2p link anyway. + */ +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + for (ifa = ifp->if_addrhead.tqh_first, si = 0; + ifa; + ifa = ifa->ifa_link.tqe_next) +#elif defined(__NetBSD__) || defined (__OpenBSD__) + for (ifa = ifp->if_addrlist.tqh_first, si = 0; + ifa; + ifa = ifa->ifa_list.tqe_next) +#else + for (ifa = ifp->if_addrlist, si = 0; + ifa; + ifa = ifa->ifa_next) +#endif + if (ifa->ifa_addr->sa_family == AF_INET6) { + si = (struct sockaddr_in6 *)ifa->ifa_addr; + sm = (struct sockaddr_in6 *)ifa->ifa_netmask; + if (si && IN6_IS_ADDR_LINKLOCAL(&si->sin6_addr)) + break; + } + if (ifa) { + if (si && !IN6_IS_ADDR_UNSPECIFIED(&si->sin6_addr)) { + bcopy(&si->sin6_addr, &ssrc, sizeof(ssrc)); + if (srcmask) { + bcopy(&sm->sin6_addr, srcmask, + sizeof(*srcmask)); + } + } + + si = (struct sockaddr_in6 *)ifa->ifa_dstaddr; + if (si && !IN6_IS_ADDR_UNSPECIFIED(&si->sin6_addr)) + bcopy(&si->sin6_addr, &ddst, sizeof(ddst)); + } + + if (dst) + bcopy(&ddst, dst, sizeof(*dst)); + if (src) + bcopy(&ssrc, src, sizeof(*src)); } +#ifdef IPV6CP_MYIFID_DYN +/* + * Generate random ifid. + */ +static void +sppp_gen_ip6_addr(struct sppp *sp, struct in6_addr *addr) +{ + /* TBD */ +} + +/* + * Set my IPv6 address. Must be called at splimp. + */ +static void +sppp_set_ip6_addr(struct sppp *sp, const struct in6_addr *src) +{ + STDDCL; + struct ifaddr *ifa; + struct sockaddr_in6 *sin6; + + /* + * Pick the first link-local AF_INET6 address from the list, + * aliases don't make any sense on a p2p link anyway. + */ + + sin6 = NULL; +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + for (ifa = ifp->if_addrhead.tqh_first; + ifa; + ifa = ifa->ifa_link.tqe_next) +#elif defined(__NetBSD__) || defined (__OpenBSD__) + 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) + { + sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; + if (sin6 && IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + break; + } + } + + if (ifa && sin6) + { + int error; + struct sockaddr_in6 new_sin6 = *sin6; + + bcopy(src, &new_sin6.sin6_addr, sizeof(new_sin6.sin6_addr)); + error = in6_ifinit(ifp, ifatoia6(ifa), &new_sin6, 1); + if (debug && error) + { + log(LOG_DEBUG, SPP_FMT "sppp_set_ip6_addr: in6_ifinit " + " failed, error=%d\n", SPP_ARGS(ifp), error); + } + } +} +#endif + +/* + * Suggest a candidate address to be used by peer. + */ +static void +sppp_suggest_ip6_addr(struct sppp *sp, struct in6_addr *suggest) +{ + struct in6_addr myaddr; + struct timeval tv; + + sppp_get_ip6_addrs(sp, &myaddr, 0, 0); + + myaddr.s6_addr[8] &= ~0x02; /* u bit to "local" */ + microtime(&tv); + if ((tv.tv_usec & 0xff) == 0 && (tv.tv_sec & 0xff) == 0) { + myaddr.s6_addr[14] ^= 0xff; + myaddr.s6_addr[15] ^= 0xff; + } else { + myaddr.s6_addr[14] ^= (tv.tv_usec & 0xff); + myaddr.s6_addr[15] ^= (tv.tv_sec & 0xff); + } + if (suggest) + bcopy(&myaddr, suggest, sizeof(myaddr)); +} +#endif /*INET6*/ + static int sppp_params(struct sppp *sp, u_long cmd, void *data) { @@ -4165,6 +4901,20 @@ sppp_ipcp_opt_name(u_char opt) return buf; } +#ifdef INET6 +static const char * +sppp_ipv6cp_opt_name(u_char opt) +{ + static char buf[12]; + switch (opt) { + case IPV6CP_OPT_IFID: return "ifid"; + case IPV6CP_OPT_COMPRESSION: return "compression"; + } + sprintf (buf, "0x%x", opt); + return buf; +} +#endif + static const char * sppp_state_name(int state) { @@ -4205,6 +4955,7 @@ sppp_proto_name(u_short proto) case PPP_IPCP: return "ipcp"; case PPP_PAP: return "pap"; case PPP_CHAP: return "chap"; + case PPP_IPV6CP: return "ipv6cp"; } snprintf(buf, sizeof(buf), "proto/0x%x", (unsigned)proto); return buf; diff --git a/sys/net/if_stf.c b/sys/net/if_stf.c index d6a6495..979e6c5 100644 --- a/sys/net/if_stf.c +++ b/sys/net/if_stf.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: if_stf.c,v 1.42 2000/08/15 07:24:23 itojun Exp $ */ +/* $KAME: if_stf.c,v 1.60 2001/05/03 14:51:47 itojun Exp $ */ /* * Copyright (C) 2000 WIDE Project. @@ -31,7 +31,7 @@ */ /* - * 6to4 interface, based on draft-ietf-ngtrans-6to4-06.txt. + * 6to4 interface, based on RFC3056. * * 6to4 interface is NOT capable of link-layer (I mean, IPv4) multicasting. * There is no address mapping defined from IPv6 multicast address to IPv4 @@ -60,12 +60,13 @@ * ICMPv6: * - Redirects cannot be used due to the lack of link-local address. * - * Starting from 04 draft, the specification suggests how to construct - * link-local address for 6to4 interface. - * However, it seems to have no real use and does not help the above symptom - * much. Even if we assign link-locals to interface, we cannot really - * use link-local unicast/multicast on top of 6to4 cloud, and the above - * analysis does not change. + * stf interface does not have, and will not need, a link-local address. + * It seems to have no real benefit and does not help the above symptoms much. + * Even if we assign link-locals to interface, we cannot really + * use link-local unicast/multicast on top of 6to4 cloud (since there's no + * encapsulation defined for link-local address), and the above analysis does + * not change. RFC3056 does not mandate the assignment of link-local address + * either. * * 6to4 interface has security issues. Refer to * http://playground.iijlab.net/i-d/draft-itojun-ipv6-transition-abuse-00.txt @@ -159,8 +160,10 @@ static int stf_encapcheck __P((const struct mbuf *, int, int, void *)); static struct in6_ifaddr *stf_getsrcifa6 __P((struct ifnet *)); static int stf_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); -static int stf_checkaddr4 __P((struct in_addr *, struct ifnet *)); -static int stf_checkaddr6 __P((struct in6_addr *, struct ifnet *)); +static int stf_checkaddr4 __P((struct stf_softc *, struct in_addr *, + struct ifnet *)); +static int stf_checkaddr6 __P((struct stf_softc *, struct in6_addr *, + struct ifnet *)); static void stf_rtrequest __P((int, struct rtentry *, struct sockaddr *)); static int stf_ioctl __P((struct ifnet *, u_long, caddr_t)); @@ -197,6 +200,10 @@ stfattach(dummy) sc->sc_if.if_ioctl = stf_ioctl; sc->sc_if.if_output = stf_output; sc->sc_if.if_type = IFT_STF; +#if 0 + /* turn off ingress filter */ + sc->sc_if.if_flags |= IFF_LINK2; +#endif sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; if_attach(&sc->sc_if); #if NBPFILTER > 0 @@ -230,6 +237,10 @@ stf_encapcheck(m, off, proto, arg) if ((sc->sc_if.if_flags & IFF_UP) == 0) return 0; + /* IFF_LINK0 means "no decapsulation" */ + if ((sc->sc_if.if_flags & IFF_LINK0) != 0) + return 0; + if (proto != IPPROTO_IPV6) return 0; @@ -317,6 +328,7 @@ stf_output(ifp, m, dst, rt) { struct stf_softc *sc; struct sockaddr_in6 *dst6; + struct in_addr *in4; struct sockaddr_in *dst4; u_int8_t tos; struct ip *ip; @@ -351,6 +363,19 @@ stf_output(ifp, m, dst, rt) ip6 = mtod(m, struct ip6_hdr *); tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; + /* + * Pickup the right outer dst addr from the list of candidates. + * ip6_dst has priority as it may be able to give us shorter IPv4 hops. + */ + if (IN6_IS_ADDR_6TO4(&ip6->ip6_dst)) + in4 = GET_V4(&ip6->ip6_dst); + else if (IN6_IS_ADDR_6TO4(&dst6->sin6_addr)) + in4 = GET_V4(&dst6->sin6_addr); + else { + m_freem(m); + return ENETUNREACH; + } + M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); if (m && m->m_len < sizeof(struct ip)) m = m_pullup(m, sizeof(struct ip)); @@ -362,12 +387,14 @@ stf_output(ifp, m, dst, rt) bcopy(GET_V4(&((struct sockaddr_in6 *)&ia6->ia_addr)->sin6_addr), &ip->ip_src, sizeof(ip->ip_src)); - bcopy(GET_V4(&dst6->sin6_addr), &ip->ip_dst, sizeof(ip->ip_dst)); + bcopy(in4, &ip->ip_dst, sizeof(ip->ip_dst)); ip->ip_p = IPPROTO_IPV6; ip->ip_ttl = ip_gif_ttl; /*XXX*/ ip->ip_len = m->m_pkthdr.len; /*host order*/ if (ifp->if_flags & IFF_LINK1) ip_ecn_ingress(ECN_ALLOWED, &ip->ip_tos, &tos); + else + ip_ecn_ingress(ECN_NOCARE, &ip->ip_tos, &tos); dst4 = (struct sockaddr_in *)&sc->sc_ro.ro_dst; if (dst4->sin_family != AF_INET || @@ -394,9 +421,10 @@ stf_output(ifp, m, dst, rt) } static int -stf_checkaddr4(in, ifp) +stf_checkaddr4(sc, in, inifp) + struct stf_softc *sc; struct in_addr *in; - struct ifnet *ifp; /* incoming interface */ + struct ifnet *inifp; /* incoming interface */ { struct in_ifaddr *ia4; @@ -427,7 +455,7 @@ stf_checkaddr4(in, ifp) /* * perform ingress filter */ - if (ifp) { + if (sc && (sc->sc_if.if_flags & IFF_LINK2) == 0 && inifp) { struct sockaddr_in sin; struct rtentry *rt; @@ -436,10 +464,14 @@ stf_checkaddr4(in, ifp) sin.sin_len = sizeof(struct sockaddr_in); sin.sin_addr = *in; rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); - if (!rt) - return -1; - if (rt->rt_ifp != ifp) { - rtfree(rt); + if (!rt || rt->rt_ifp != inifp) { +#if 0 + log(LOG_WARNING, "%s: packet from 0x%x dropped " + "due to ingress filter\n", if_name(&sc->sc_if), + (u_int32_t)ntohl(sin.sin_addr.s_addr)); +#endif + if (rt) + rtfree(rt); return -1; } rtfree(rt); @@ -449,15 +481,16 @@ stf_checkaddr4(in, ifp) } static int -stf_checkaddr6(in6, ifp) +stf_checkaddr6(sc, in6, inifp) + struct stf_softc *sc; struct in6_addr *in6; - struct ifnet *ifp; /* incoming interface */ + struct ifnet *inifp; /* incoming interface */ { /* * check 6to4 addresses */ if (IN6_IS_ADDR_6TO4(in6)) - return stf_checkaddr4(GET_V4(in6), ifp); + return stf_checkaddr4(sc, GET_V4(in6), inifp); /* * reject anything that look suspicious. the test is implemented @@ -476,7 +509,7 @@ void in_stf_input(struct mbuf *m, ...) #else in_stf_input(m, va_alist) - register struct mbuf *m; + struct mbuf *m; #endif { int off, proto; @@ -514,8 +547,8 @@ in_stf_input(m, va_alist) * perform sanity check against outer src/dst. * for source, perform ingress filter as well. */ - if (stf_checkaddr4(&ip->ip_dst, NULL) < 0 || - stf_checkaddr4(&ip->ip_src, m->m_pkthdr.rcvif) < 0) { + if (stf_checkaddr4(sc, &ip->ip_dst, NULL) < 0 || + stf_checkaddr4(sc, &ip->ip_src, m->m_pkthdr.rcvif) < 0) { m_freem(m); return; } @@ -534,8 +567,8 @@ in_stf_input(m, va_alist) * perform sanity check against inner src/dst. * for source, perform ingress filter as well. */ - if (stf_checkaddr6(&ip6->ip6_dst, NULL) < 0 || - stf_checkaddr6(&ip6->ip6_src, m->m_pkthdr.rcvif) < 0) { + if (stf_checkaddr6(sc, &ip6->ip6_dst, NULL) < 0 || + stf_checkaddr6(sc, &ip6->ip6_src, m->m_pkthdr.rcvif) < 0) { m_freem(m); return; } @@ -543,6 +576,8 @@ in_stf_input(m, va_alist) itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; if ((ifp->if_flags & IFF_LINK1) != 0) ip_ecn_egress(ECN_ALLOWED, &otos, &itos); + else + ip_ecn_egress(ECN_NOCARE, &otos, &itos); ip6->ip6_flow &= ~htonl(0xff << 20); ip6->ip6_flow |= htonl((u_int32_t)itos << 20); @@ -558,7 +593,7 @@ in_stf_input(m, va_alist) * try to free it or keep a pointer a to it). */ struct mbuf m0; - u_int af = AF_INET6; + u_int32_t af = AF_INET6; m0.m_next = m; m0.m_len = 4; @@ -594,11 +629,7 @@ static void stf_rtrequest(cmd, rt, sa) int cmd; struct rtentry *rt; -#if defined(__bsdi__) && _BSDI_VERSION >= 199802 - struct rt_addrinfo *sa; -#else struct sockaddr *sa; -#endif { if (rt) diff --git a/sys/net/net_osdep.c b/sys/net/net_osdep.c index 02000f6..ef3bb01 100644 --- a/sys/net/net_osdep.c +++ b/sys/net/net_osdep.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: net_osdep.c,v 1.4 2000/03/25 07:23:34 sumikawa Exp $ */ +/* $KAME: net_osdep.c,v 1.9 2001/04/06 09:22:05 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -32,6 +32,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/kernel.h> #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/sockio.h> @@ -52,8 +53,15 @@ const char * if_name(ifp) struct ifnet *ifp; { - static char nam[IFNAMSIZ + 10]; /*enough?*/ +#define MAXNUMBUF 8 + static char nam[MAXNUMBUF][IFNAMSIZ + 10]; /*enough?*/ + static int ifbufround = 0; + char *cp; - snprintf(nam, sizeof(nam), "%s%d", ifp->if_name, ifp->if_unit); - return nam; + ifbufround = (ifbufround + 1) % MAXNUMBUF; + cp = nam[ifbufround]; + + snprintf(cp, sizeof(nam), "%s%d", ifp->if_name, ifp->if_unit); + return((const char *)cp); +#undef MAXNUMBUF } diff --git a/sys/net/net_osdep.h b/sys/net/net_osdep.h index 3bb3c18..399dd31 100644 --- a/sys/net/net_osdep.h +++ b/sys/net/net_osdep.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: net_osdep.h,v 1.22 2000/08/15 07:23:10 itojun Exp $ */ +/* $KAME: net_osdep.h,v 1.44 2001/05/16 03:13:40 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -36,16 +36,40 @@ /* * OS dependencies: * + * - whether the IPv4 input routine convert the byte order of some fileds + * of the IP header (x: convert to the host byte order, s: strip the header + * length for possible reassembly) + * ip_len ip_id ip_off + * bsdi3: xs x x + * bsdi4: xs x + * FreeBSD: xs x + * NetBSD: x x + * OpenBSD: xs x x + * + * - ifa_ifwithaf() + * bsdi[34], netbsd, and openbsd define it in sys/net/if.c + * freebsd (all versions) does not have it. + * * - struct rt_addrinfo - * all *BSDs except bsdi4 only have two members; rti_addrs and rti_info[]. - * bsdi4 has additional members; rti_flags, rti_ifa, rti_ifp, and rti_rtm. + * bsdi4, netbsd 1.5R and beyond: rti_addrs, rti_info[], rti_flags, rti_ifa, + * rti_ifp, and rti_rtm. + * others: rti_addrs and rti_info[] only. + * + * - ifa->ifa_rtrequest + * bsdi4, netbsd 1.5R and beyond: rt_addrinfo * + * others: sockaddr * (note that sys/net/route.c:rtrequest() has an unsafe + * typecast code, from 4.3BSD-reno) * - * - side effects of rtrequest[1](RTM_DELETE) + * - side effects of rtrequest{,1}(RTM_DELETE) * BSDI[34]: delete all cloned routes underneath the route. * FreeBSD[234]: delete all protocol-cloned routes underneath the route. * note that cloned routes from an interface direct route * still remain. - * NetBSD, OpenBSD: no side effects. + * NetBSD: 1.5 have no side effects. KAME/netbsd15, and post-1.5R, have + * the same effects as of BSDI. + * OpenBSD: have no side effects. KAME/openbsd has the same effects as + * of BSDI (the change is not merged - yet). + * * - privileged process * NetBSD, FreeBSD 3 * struct proc *p; @@ -64,11 +88,13 @@ * needs to give struct proc * as argument * OpenBSD, BSDI [34], FreeBSD 2 * do not need struct proc * + * * - bpf: - * OpenBSD, NetBSD, BSDI [34] + * OpenBSD, NetBSD 1.5, BSDI [34] * need caddr_t * (= if_bpf **) and struct ifnet * - * FreeBSD 2, FreeBSD 3 + * FreeBSD 2, FreeBSD 3, NetBSD post-1.5N * need only struct ifnet * as argument + * * - struct ifnet * use queue.h? member names if name * --- --- --- @@ -77,34 +103,57 @@ * OpenBSD yes standard if_xname * NetBSD yes standard if_xname * BSDI [34] no old standard if_name+unit + * * - usrreq * NetBSD, OpenBSD, BSDI [34], FreeBSD 2 * single function with PRU_xx, arguments are mbuf * FreeBSD 3 * separates functions, non-mbuf arguments + * * - {set,get}sockopt * NetBSD, OpenBSD, BSDI [34], FreeBSD 2 * manipulation based on mbuf * FreeBSD 3 * non-mbuf manipulation using sooptcopy{in,out}() + * * - timeout() and untimeout() - * NetBSD, OpenBSD, BSDI [34], FreeBSD 2 + * NetBSD 1.4.x, OpenBSD, BSDI [34], FreeBSD 2 * timeout() is a void function * FreeBSD 3 * timeout() is non-void, must keep returned value for untimeout() + * callout_xx is also available (sys/callout.h) + * NetBSD 1.5 + * timeout() is obsoleted, use callout_xx (sys/callout.h) + * OpenBSD 2.8 + * timeout_{add,set,del} is encouraged (sys/timeout.h) + * * - sysctl * NetBSD, OpenBSD * foo_sysctl() * BSDI [34] - * foo_sysctl() but with different style - * FreeBSD 2, FreeBSD 3 - * linker hack + * foo_sysctl() but with different style. sysctl_int_arr() takes + * care of most of the cases. + * FreeBSD + * linker hack. however, there are freebsd version differences + * (how wonderful!). + * on FreeBSD[23] function arg #define includes paren. + * int foo SYSCTL_HANDLER_ARGS; + * on FreeBSD4, function arg #define does not include paren. + * int foo(SYSCTL_HANDLER_ARGS); + * on some versions, forward reference to the tree is okay. + * on some versions, you need SYSCTL_DECL(). you need things + * like this. + * #ifdef SYSCTL_DECL + * SYSCTL_DECL(net_inet_ip6); + * #endif + * it is hard to share functions between freebsd and non-freebsd. * * - if_ioctl * NetBSD, FreeBSD 3, BSDI [34] * 2nd argument is u_long cmd * FreeBSD 2 * 2nd argument is int cmd + * * - if attach routines * NetBSD * void xxattach(int); @@ -115,6 +164,7 @@ * - ovbcopy() * in NetBSD 1.4 or later, ovbcopy() is not supplied in the kernel. * bcopy() is safe against overwrites. + * * - splnet() * NetBSD 1.4 or later requires splsoftnet(). * other operating systems use splnet(). @@ -125,7 +175,8 @@ * - struct ifnet for loopback interface * BSDI3: struct ifnet loif; * BSDI4: struct ifnet *loifp; - * NetBSD, OpenBSD, FreeBSD2: struct ifnet loif[NLOOP]; + * NetBSD, OpenBSD 2.8, FreeBSD2: struct ifnet loif[NLOOP]; + * OpenBSD 2.9: struct ifnet *lo0ifp; * * odd thing is that many of them refers loif as ifnet *loif, * not loif[NLOOP], from outside of if_loop.c. @@ -145,6 +196,12 @@ * FreeBSD4: struct ipprotosw in netinet/ipprotosw.h * others: struct protosw in sys/protosw.h * + * - protosw in general. + * NetBSD 1.5 has extra member for ipfilter (netbsd-current dropped + * it so it will go away in 1.6). + * NetBSD 1.5 requires PR_LISTEN flag bit with protocols that permit + * listen/accept (like tcp). + * * - header files with defopt (opt_xx.h) * FreeBSD3: opt_{inet,ipsec,ip6fw,altq}.h * FreeBSD4: opt_{inet,inet6,ipsec,ip6fw,altq}.h @@ -154,6 +211,23 @@ * - IN_MULTICAST/IN_CLASS[A-D] macro. * OpenBSD and NetBSD: net endian (kernel) or host endian (userland) * others: always host endian + * + * - (m->m_flags & M_EXT) != 0 does *not* mean that the max data length of + * the mbuf == MCLBYTES. + * + * - sys/kern/uipc_mbuf.c:m_dup() + * freebsd[34]: copies the whole mbuf chain. + * netbsd: similar arg with m_copym(). + * others: no m_dup(). + * + * - ifa_refcnt (struct ifaddr) management (IFAREF/IFAFREE). + * NetBSD 1.5: always use IFAREF whenever reference gets added. + * always use IFAFREE whenever reference gets freed. + * IFAFREE frees ifaddr when ifa_refcnt reaches 0. + * others: do not increase refcnt for ifp->if_addrlist and in_ifaddr. + * use IFAFREE once when ifaddr is disconnected from + * ifp->if_addrlist and in_ifaddr. IFAFREE frees ifaddr when + * ifa_refcnt goes negative. */ #ifndef __NET_NET_OSDEP_H_DEFINED_ @@ -165,6 +239,19 @@ extern const char *if_name __P((struct ifnet *)); #define HAVE_OLD_BPF +#define ifa_list ifa_link +#define if_addrlist if_addrhead +#define if_list if_link + +/* sys/net/if.h */ +#define IFAREF(ifa) do { ++(ifa)->ifa_refcnt; } while (0) + +#define WITH_CONVERT_AND_STRIP_IP_LEN + +#if 1 /* at this moment, all OSes do this */ +#define WITH_CONVERT_IP_OFF +#endif + /* * Deprecated. */ diff --git a/sys/net/pfkeyv2.h b/sys/net/pfkeyv2.h index 4c41c80..f1c22ad 100644 --- a/sys/net/pfkeyv2.h +++ b/sys/net/pfkeyv2.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: pfkeyv2.h,v 1.17 2000/06/22 08:38:33 sakane Exp $ */ +/* $KAME: pfkeyv2.h,v 1.25 2001/03/12 08:34:06 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -73,7 +73,7 @@ you leave this credit intact on any copies of this file. #define SADB_X_SPDDUMP 18 #define SADB_X_SPDFLUSH 19 #define SADB_X_SPDSETIDX 20 -#define SADB_X_SPDEXPIRE 21 /* not yet */ +#define SADB_X_SPDEXPIRE 21 #define SADB_X_SPDDELETE2 22 /* by policy id */ #define SADB_MAX 22 @@ -298,22 +298,32 @@ struct sadb_x_ipsecrequest { #define SADB_SAFLAGS_PFS 1 -#define SADB_AALG_NONE 0 -#define SADB_AALG_MD5HMAC 1 /* 2 */ -#define SADB_AALG_SHA1HMAC 2 /* 3 */ -#define SADB_AALG_MD5 3 /* Keyed MD5 */ -#define SADB_AALG_SHA 4 /* Keyed SHA */ -#define SADB_AALG_NULL 5 /* null authentication */ -#define SADB_AALG_MAX 6 - -#define SADB_EALG_NONE 0 -#define SADB_EALG_DESCBC 1 /* 2 */ -#define SADB_EALG_3DESCBC 2 /* 3 */ -#define SADB_EALG_NULL 3 /* 11 */ -#define SADB_EALG_BLOWFISHCBC 4 -#define SADB_EALG_CAST128CBC 5 -#define SADB_EALG_RC5CBC 6 -#define SADB_EALG_MAX 7 +/* RFC2367 numbers - meets RFC2407 */ +#define SADB_AALG_NONE 0 +#define SADB_AALG_MD5HMAC 1 /*2*/ +#define SADB_AALG_SHA1HMAC 2 /*3*/ +#define SADB_AALG_MAX 8 +/* private allocations - based on RFC2407/IANA assignment */ +#define SADB_X_AALG_SHA2_256 6 /*5*/ +#define SADB_X_AALG_SHA2_384 7 /*6*/ +#define SADB_X_AALG_SHA2_512 8 /*7*/ +/* private allocations should use 249-255 (RFC2407) */ +#define SADB_X_AALG_MD5 3 /*249*/ /* Keyed MD5 */ +#define SADB_X_AALG_SHA 4 /*250*/ /* Keyed SHA */ +#define SADB_X_AALG_NULL 5 /*251*/ /* null authentication */ + +/* RFC2367 numbers - meets RFC2407 */ +#define SADB_EALG_NONE 0 +#define SADB_EALG_DESCBC 1 /*2*/ +#define SADB_EALG_3DESCBC 2 /*3*/ +#define SADB_EALG_NULL 3 /*11*/ +#define SADB_EALG_MAX 12 +/* private allocations - based on RFC2407/IANA assignment */ +#define SADB_X_EALG_CAST128CBC 5 /*6*/ +#define SADB_X_EALG_BLOWFISHCBC 4 /*7*/ +#define SADB_X_EALG_RIJNDAELCBC 12 +#define SADB_X_EALG_AES 12 +/* private allocations should use 249-255 (RFC2407) */ #if 1 /*nonstandard */ #define SADB_X_CALG_NONE 0 diff --git a/sys/net/ppp_defs.h b/sys/net/ppp_defs.h index ac86be2..be891ee 100644 --- a/sys/net/ppp_defs.h +++ b/sys/net/ppp_defs.h @@ -69,6 +69,8 @@ #define PPP_LQR 0xc025 /* Link Quality Report protocol */ #define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ #define PPP_CBCP 0xc029 /* Callback Control Protocol */ +#define PPP_IPV6 0x57 /* Internet Protocol version 6*/ +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ /* * Values for FCS calculations. diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index dc4ae26..6588f56 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -573,9 +573,6 @@ rt_msg1(type, rtinfo) register struct sockaddr *sa; int len, dlen; - m = m_gethdr(M_DONTWAIT, MT_DATA); - if (m == 0) - return (m); switch (type) { case RTM_DELADDR: @@ -595,8 +592,18 @@ rt_msg1(type, rtinfo) default: len = sizeof(struct rt_msghdr); } - if (len > MHLEN) + if (len > MCLBYTES) panic("rt_msg1"); + m = m_gethdr(M_DONTWAIT, MT_DATA); + if (m && len > MHLEN) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_free(m); + m = NULL; + } + } + if (m == 0) + return (m); m->m_pkthdr.len = m->m_len = len; m->m_pkthdr.rcvif = 0; rtm = mtod(m, struct rt_msghdr *); |