diff options
author | Jun-ichiro itojun Hagino <itojun@FreeBSD.org> | 2000-07-04 16:35:15 +0000 |
---|---|---|
committer | Jun-ichiro itojun Hagino <itojun@FreeBSD.org> | 2000-07-04 16:35:15 +0000 |
commit | 686cdd19b1b182f2257bc158116e78c5fef84980 (patch) | |
tree | 22136d6c52358a61b8b21d1cda50d53ec766ab1e /sys/net/if_gif.c | |
parent | 2d311b79cdb0da87624d7791e2fc72067edc5217 (diff) | |
download | src-686cdd19b1b182f2257bc158116e78c5fef84980.tar.gz src-686cdd19b1b182f2257bc158116e78c5fef84980.zip |
sync with kame tree as of july00. tons of bug fixes/improvements.
API changes:
- additional IPv6 ioctls
- IPsec PF_KEY API was changed, it is mandatory to upgrade setkey(8).
(also syntax change)
Notes
Notes:
svn path=/head/; revision=62587
Diffstat (limited to 'sys/net/if_gif.c')
-rw-r--r-- | sys/net/if_gif.c | 335 |
1 files changed, 239 insertions, 96 deletions
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c index 0b326574f5f9..0337a61e80fa 100644 --- a/sys/net/if_gif.c +++ b/sys/net/if_gif.c @@ -1,3 +1,6 @@ +/* $FreeBSD$ */ +/* $KAME: if_gif.c,v 1.28 2000/06/20 12:30:03 jinmei Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -25,12 +28,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * gif.c */ #include "opt_inet.h" @@ -46,6 +43,7 @@ #include <sys/errno.h> #include <sys/time.h> #include <sys/syslog.h> +#include <sys/protosw.h> #include <machine/cpu.h> #include <net/if.h> @@ -70,21 +68,47 @@ #include <netinet/ip6.h> #include <netinet6/ip6_var.h> #include <netinet6/in6_gif.h> +#include <netinet6/ip6protosw.h> #endif /* INET6 */ +#include <netinet/ip_encap.h> #include <net/if_gif.h> #include "gif.h" +#include "bpf.h" +#define NBPFILTER NBPF #include <net/net_osdep.h> +#if NGIF > 0 + void gifattach __P((void *)); +static int gif_encapcheck __P((const struct mbuf *, int, int, void *)); +#ifdef INET +extern struct protosw in_gif_protosw; +#endif +#ifdef INET6 +extern struct ip6protosw in6_gif_protosw; +#endif /* * gif global variable definitions */ -int ngif = NGIF + 1; /* number of interfaces. +1 for stf. */ -struct gif_softc *gif = 0; +static int ngif; /* number of interfaces */ +static struct gif_softc *gif = 0; + +#ifndef MAX_GIF_NEST +/* + * This macro controls the upper limitation on nesting of gif tunnels. + * Since, setting a large value to this macro with a careless configuration + * may introduce system crash, we don't allow any nestings by default. + * If you need to configure nested gif tunnels, you can define this macro + * in your kernel configuration file. However, if you do so, please be + * careful to configure the tunnels so that it won't make a loop. + */ +#define MAX_GIF_NEST 1 +#endif +static int max_gif_nesting = MAX_GIF_NEST; void gifattach(dummy) @@ -93,34 +117,111 @@ gifattach(dummy) register struct gif_softc *sc; register int i; + ngif = NGIF; gif = sc = malloc (ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAIT); bzero(sc, ngif * sizeof(struct gif_softc)); - for (i = 0; i < ngif - 1; sc++, i++) { /* leave last one for stf */ + for (i = 0; i < ngif; sc++, i++) { sc->gif_if.if_name = "gif"; sc->gif_if.if_unit = i; + + sc->encap_cookie4 = sc->encap_cookie6 = NULL; +#ifdef INET + sc->encap_cookie4 = encap_attach_func(AF_INET, -1, + gif_encapcheck, &in_gif_protosw, sc); + if (sc->encap_cookie4 == NULL) { + printf("%s: attach failed\n", if_name(&sc->gif_if)); + continue; + } +#endif +#ifdef INET6 + sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, + gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc); + if (sc->encap_cookie6 == NULL) { + if (sc->encap_cookie4) { + encap_detach(sc->encap_cookie4); + sc->encap_cookie4 = NULL; + } + printf("%s: attach failed\n", if_name(&sc->gif_if)); + continue; + } +#endif + sc->gif_if.if_mtu = GIF_MTU; sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; sc->gif_if.if_ioctl = gif_ioctl; sc->gif_if.if_output = gif_output; sc->gif_if.if_type = IFT_GIF; - sc->gif_if.if_snd.ifq_maxlen = ifqmaxlen; + sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN; if_attach(&sc->gif_if); +#if NBPFILTER > 0 +#ifdef HAVE_OLD_BPF bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); +#else + bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_NULL, sizeof(u_int)); +#endif +#endif } - sc->gif_if.if_name = "stf"; - sc->gif_if.if_unit = 0; - sc->gif_if.if_mtu = GIF_MTU; - sc->gif_if.if_flags = IFF_MULTICAST; - sc->gif_if.if_ioctl = gif_ioctl; - sc->gif_if.if_output = gif_output; - sc->gif_if.if_type = IFT_GIF; - sc->gif_if.if_snd.ifq_maxlen = ifqmaxlen; - if_attach(&sc->gif_if); - bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); } PSEUDO_SET(gifattach, if_gif); +static int +gif_encapcheck(m, off, proto, arg) + const struct mbuf *m; + int off; + int proto; + void *arg; +{ + struct ip ip; + struct gif_softc *sc; + + sc = (struct gif_softc *)arg; + if (sc == NULL) + return 0; + + if ((sc->gif_if.if_flags & IFF_UP) == 0) + return 0; + + /* no physical address */ + if (!sc->gif_psrc || !sc->gif_pdst) + return 0; + + switch (proto) { +#ifdef INET + case IPPROTO_IPV4: + break; +#endif +#ifdef INET6 + case IPPROTO_IPV6: + break; +#endif + default: + return 0; + } + + /* LINTED const cast */ + m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip); + + switch (ip.ip_v) { +#ifdef INET + case 4: + if (sc->gif_psrc->sa_family != AF_INET || + sc->gif_pdst->sa_family != AF_INET) + return 0; + return gif_encapcheck4(m, off, proto, arg); +#endif +#ifdef INET6 + case 6: + if (sc->gif_psrc->sa_family != AF_INET6 || + sc->gif_pdst->sa_family != AF_INET6) + return 0; + return gif_encapcheck6(m, off, proto, arg); +#endif + default: + return 0; + } +} + int gif_output(ifp, m, dst, rt) struct ifnet *ifp; @@ -131,7 +232,6 @@ gif_output(ifp, m, dst, rt) register struct gif_softc *sc = (struct gif_softc*)ifp; int error = 0; static int called = 0; /* XXX: MUTEX */ - int calllimit = 10; /* XXX: adhoc */ /* * gif may cause infinite recursion calls when misconfigured. @@ -140,7 +240,7 @@ gif_output(ifp, m, dst, rt) * mutual exclusion of the variable CALLED, especially if we * use kernel thread. */ - if (++called >= calllimit) { + if (++called > max_gif_nesting) { log(LOG_NOTICE, "gif_output: recursively called too many times(%d)\n", called); @@ -148,6 +248,7 @@ gif_output(ifp, m, dst, rt) error = EIO; /* is there better errno? */ goto end; } + getmicrotime(&ifp->if_lastchange); m->m_flags &= ~(M_BCAST|M_MCAST); if (!(ifp->if_flags & IFF_UP) || @@ -157,6 +258,7 @@ gif_output(ifp, m, dst, rt) goto end; } +#if NBPFILTER > 0 if (ifp->if_bpf) { /* * We need to prepend the address family as @@ -171,12 +273,19 @@ gif_output(ifp, m, dst, rt) 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 } - ifp->if_opackets++; +#endif + ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; + /* XXX should we check if our outer source is legal? */ + switch (sc->gif_psrc->sa_family) { #ifdef INET case AF_INET: @@ -189,7 +298,7 @@ gif_output(ifp, m, dst, rt) break; #endif default: - m_freem(m); + m_freem(m); error = ENETDOWN; } @@ -214,9 +323,9 @@ gif_input(m, af, gifp) return; } - if (m->m_pkthdr.rcvif) - m->m_pkthdr.rcvif = gifp; - + m->m_pkthdr.rcvif = gifp; + +#if NBPFILTER > 0 if (gifp->if_bpf) { /* * We need to prepend the address family as @@ -227,13 +336,18 @@ gif_input(m, af, gifp) */ struct mbuf m0; u_int af = AF_INET6; - + m0.m_next = m; m0.m_len = 4; m0.m_data = (char *)⁡ - + +#ifdef HAVE_OLD_BPF bpf_mtap(gifp, &m0); +#else + bpf_mtap(gifp->if_bpf, &m0); +#endif } +#endif /*NBPFILTER > 0*/ /* * Put the packet to the network layer input queue according to the @@ -282,7 +396,7 @@ gif_input(m, af, gifp) return; } - +/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ int gif_ioctl(ifp, cmd, data) struct ifnet *ifp; @@ -292,12 +406,15 @@ gif_ioctl(ifp, cmd, data) struct gif_softc *sc = (struct gif_softc*)ifp; struct ifreq *ifr = (struct ifreq*)data; int error = 0, size; - struct sockaddr *sa, *dst, *src; - + struct sockaddr *dst, *src; + struct sockaddr *sa; + int i; + struct gif_softc *sc2; + switch (cmd) { case SIOCSIFADDR: break; - + case SIOCSIFDSTADDR: break; @@ -305,8 +422,10 @@ gif_ioctl(ifp, cmd, data) case SIOCDELMULTI: break; +#ifdef SIOCSIFMTU /* xxx */ case SIOCGIFMTU: break; + case SIOCSIFMTU: { u_long mtu; @@ -317,103 +436,125 @@ gif_ioctl(ifp, cmd, data) ifp->if_mtu = mtu; } break; +#endif /* SIOCSIFMTU */ case SIOCSIFPHYADDR: #ifdef INET6 case SIOCSIFPHYADDR_IN6: #endif /* INET6 */ - switch (ifr->ifr_addr.sa_family) { -#ifdef INET - case AF_INET: + switch (cmd) { + case SIOCSIFPHYADDR: src = (struct sockaddr *) &(((struct in_aliasreq *)data)->ifra_addr); dst = (struct sockaddr *) &(((struct in_aliasreq *)data)->ifra_dstaddr); + break; +#ifdef INET6 + case SIOCSIFPHYADDR_IN6: + src = (struct sockaddr *) + &(((struct in6_aliasreq *)data)->ifra_addr); + dst = (struct sockaddr *) + &(((struct in6_aliasreq *)data)->ifra_dstaddr); + break; +#endif + } - /* only one gif can have dst = INADDR_ANY */ -#define satosaddr(sa) (((struct sockaddr_in *)(sa))->sin_addr.s_addr) + for (i = 0; i < ngif; i++) { + sc2 = gif + i; + if (sc2 == sc) + continue; + if (!sc2->gif_pdst || !sc2->gif_psrc) + continue; + if (sc2->gif_pdst->sa_family != dst->sa_family || + sc2->gif_pdst->sa_len != dst->sa_len || + sc2->gif_psrc->sa_family != src->sa_family || + sc2->gif_psrc->sa_len != src->sa_len) + continue; + /* can't configure same pair of address onto two gifs */ + if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && + bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { + error = EADDRNOTAVAIL; + goto bad; + } + /* can't configure multiple multi-dest interfaces */ +#define multidest(x) \ + (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY) #ifdef INET6 - if (bcmp(ifp->if_name, "stf", 3) == 0) - satosaddr(dst) = INADDR_BROADCAST; +#define multidest6(x) \ + (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr)) #endif - - if (satosaddr(dst) == INADDR_ANY) { - int i; - struct gif_softc *sc2; - - for (i = 0, sc2 = gif; i < ngif; i++, sc2++) { - if (sc2 == sc) continue; - if (sc2->gif_pdst && - satosaddr(sc2->gif_pdst) - == INADDR_ANY) { - error = EADDRNOTAVAIL; - goto bad; - } - } + if (dst->sa_family == AF_INET && + multidest(dst) && multidest(sc2->gif_pdst)) { + error = EADDRNOTAVAIL; + goto bad; } +#ifdef INET6 + if (dst->sa_family == AF_INET6 && + multidest6(dst) && multidest6(sc2->gif_pdst)) { + error = EADDRNOTAVAIL; + goto bad; + } +#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 /* INET */ +#endif #ifdef INET6 case AF_INET6: - src = (struct sockaddr *) - &(((struct in6_aliasreq *)data)->ifra_addr); - dst = (struct sockaddr *) - &(((struct in6_aliasreq *)data)->ifra_dstaddr); - - /* only one gif can have dst = in6addr_any */ -#define satoin6(sa) (&((struct sockaddr_in6 *)(sa))->sin6_addr) - - if (IN6_IS_ADDR_UNSPECIFIED(satoin6(dst))) { - int i; - struct gif_softc *sc2; - - for (i = 0, sc2 = gif; i < ngif; i++, sc2++) { - if (sc2 == sc) continue; - if (sc2->gif_pdst && - IN6_IS_ADDR_UNSPECIFIED( - satoin6(sc2->gif_pdst) - )) { - error = EADDRNOTAVAIL; - goto bad; - } - } - } size = sizeof(struct sockaddr_in6); break; -#endif /* INET6 */ +#endif default: - error = EPROTOTYPE; + error = EAFNOSUPPORT; goto bad; + } + if (src->sa_len != size) { + error = EINVAL; break; } - if (sc->gif_psrc != NULL) - free((caddr_t)sc->gif_psrc, M_IFADDR); - if (sc->gif_pdst != NULL) - free((caddr_t)sc->gif_pdst, M_IFADDR); + if (sc->gif_psrc) + free((caddr_t)sc->gif_psrc, M_IFADDR); sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK); - bzero((caddr_t)sa, size); bcopy((caddr_t)src, (caddr_t)sa, size); 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); - bzero((caddr_t)sa, size); bcopy((caddr_t)dst, (caddr_t)sa, size); sc->gif_pdst = sa; - ifp->if_flags |= (IFF_UP|IFF_RUNNING); - { - int s; - - s = splnet(); - if_up(ifp); /* send up RTM_IFINFO */ - splx(s); - } + ifp->if_flags |= IFF_UP; + if_up(ifp); /* send up RTM_IFINFO */ + error = 0; break; +#ifdef SIOCDIFPHYADDR + case SIOCDIFPHYADDR: + if (sc->gif_psrc) { + free((caddr_t)sc->gif_psrc, M_IFADDR); + sc->gif_psrc = NULL; + } + if (sc->gif_pdst) { + free((caddr_t)sc->gif_pdst, M_IFADDR); + sc->gif_pdst = NULL; + } + /* change the IFF_UP flag as well? */ + break; +#endif + case SIOCGIFPSRCADDR: #ifdef INET6 case SIOCGIFPSRCADDR_IN6: @@ -443,7 +584,7 @@ gif_ioctl(ifp, cmd, data) } bcopy((caddr_t)src, (caddr_t)dst, size); break; - + case SIOCGIFPDSTADDR: #ifdef INET6 case SIOCGIFPDSTADDR_IN6: @@ -475,6 +616,7 @@ gif_ioctl(ifp, cmd, data) break; case SIOCSIFFLAGS: + /* if_ioctl() takes care of it */ break; default: @@ -484,3 +626,4 @@ gif_ioctl(ifp, cmd, data) bad: return error; } +#endif /*NGIF > 0*/ |