From cad488d032fdb6d94c8d1030581112f6fe1892ad Mon Sep 17 00:00:00 2001 From: itojun Date: Sun, 29 Jul 2001 05:08:32 +0000 Subject: [PATCH] sync gif interface code with latest kame. IFF_RUNNING is clearified. attach/detach logic is more clearner. the old code mistakenly set IFF_UP by itself, now the behavior is gone. --- sys/net/if_gif.c | 319 +++++++++++++++++++++++------------------ sys/net/if_gif.h | 14 +- sys/netinet/in_gif.c | 142 +++++++++++------- sys/netinet/in_gif.h | 7 +- sys/netinet6/in6_gif.c | 132 ++++++++++++----- sys/netinet6/in6_gif.h | 9 +- 6 files changed, 381 insertions(+), 242 deletions(-) diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c index 607521bd9ad9..b465480ae667 100644 --- a/sys/net/if_gif.c +++ b/sys/net/if_gif.c @@ -1,5 +1,5 @@ -/* $NetBSD: if_gif.c,v 1.30 2001/07/18 16:43:09 thorpej Exp $ */ -/* $KAME: if_gif.c,v 1.49 2001/06/04 12:03:41 itojun Exp $ */ +/* $NetBSD: if_gif.c,v 1.31 2001/07/29 05:08:32 itojun Exp $ */ +/* $KAME: if_gif.c,v 1.66 2001/07/29 04:36:16 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -88,16 +88,9 @@ #if NGIF > 0 void gifattach __P((int)); -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 #ifdef ISO -static int gif_eon_encap(struct mbuf **); -static int gif_eon_decap(struct ifnet *, struct mbuf **); +static struct mbuf *gif_eon_encap(struct mbuf *); +static struct mbuf *gif_eon_decap(struct ifnet *, struct mbuf *); #endif /* @@ -111,15 +104,13 @@ void gif_clone_destroy __P((struct ifnet *)); struct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy); -void gif_delete_tunnel __P((struct gif_softc *)); - #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 + * 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 @@ -148,30 +139,20 @@ gif_clone_create(ifc, unit) sprintf(sc->gif_if.if_xname, "%s%d", ifc->ifc_name, unit); - 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: unable to attach encap4\n", if_name(&sc->gif_if)); - free(sc, M_DEVBUF); - return (EIO); /* XXX */ - } -#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: unable to attach encap6\n", if_name(&sc->gif_if)); - free(sc, M_DEVBUF); - return (EIO); /* XXX */ - } -#endif + gifattach0(sc); + LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list); + return (0); +} + +void +gifattach0(sc) + struct gif_softc *sc; +{ + + sc->encap_cookie4 = sc->encap_cookie6 = NULL; + + sc->gif_if.if_addrlen = 0; sc->gif_if.if_mtu = GIF_MTU; sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; sc->gif_if.if_ioctl = gif_ioctl; @@ -183,8 +164,6 @@ gif_clone_create(ifc, unit) #if NBPFILTER > 0 bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); #endif - LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list); - return (0); } void @@ -193,7 +172,7 @@ gif_clone_destroy(ifp) { struct gif_softc *sc = (void *) ifp; - gif_delete_tunnel(sc); + gif_delete_tunnel(&sc->gif_if); LIST_REMOVE(sc, gif_list); #ifdef INET6 encap_detach(sc->encap_cookie6); @@ -210,7 +189,7 @@ gif_clone_destroy(ifp) free(sc, M_DEVBUF); } -static int +int gif_encapcheck(m, off, proto, arg) const struct mbuf *m; int off; @@ -336,9 +315,12 @@ gif_output(ifp, m, dst, rt) switch (dst->sa_family) { #ifdef ISO case AF_ISO: - error = gif_eon_encap(&m); - if (error) + m = gif_eon_encap(m); + if (!m) { + error = ENOBUFS; goto end; + } + break; #endif default: break; @@ -361,11 +343,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; } @@ -414,13 +398,12 @@ gif_input(m, af, gifp) * Put the packet to the network layer input queue according to the * specified address family. * Note: older versions of gif_input directly called network layer - * input functions, e.g. ip6_input, here. We changed the policy to + * input functions, e.g. ip6_input, here. We changed the policy to * prevent too many recursive calls of such input functions, which - * might cause kernel panic. But the change may introduce another + * might cause kernel panic. But the change may introduce another * problem; if the input queue is full, packets are discarded. - * We believed it rarely occurs and changed the policy. If we find - * it occurs more times than we thought, we may change the policy - * again. + * The kernel stack overflow really happened, and we believed + * queue-full rarely occurs, so we changed the policy. */ switch (af) { #ifdef INET @@ -437,11 +420,9 @@ gif_input(m, af, gifp) #endif #ifdef ISO case AF_ISO: - if (gif_eon_decap(gifp, &m)) { - if (m) - m_freem(m); + m = gif_eon_decap(gifp, m); + if (!m) return; - } ifq = &clnlintrq; isr = NETISR_ISO; break; @@ -458,11 +439,11 @@ gif_input(m, af, gifp) splx(s); return; } + gifp->if_ipackets++; + gifp->if_ibytes += m->m_pkthdr.len; IF_ENQUEUE(ifq, m); /* we need schednetisr since the address family may change */ schednetisr(isr); - gifp->if_ipackets++; - gifp->if_ibytes += m->m_pkthdr.len; splx(s); return; @@ -480,10 +461,7 @@ gif_ioctl(ifp, cmd, data) struct ifreq *ifr = (struct ifreq*)data; int error = 0, size; struct sockaddr *dst, *src; - struct sockaddr *sa; - int s; - struct gif_softc *sc2; - + switch (cmd) { case SIOCSIFADDR: break; @@ -528,7 +506,9 @@ gif_ioctl(ifp, cmd, data) break; #endif /* SIOCSIFMTU */ +#ifdef INET case SIOCSIFPHYADDR: +#endif #ifdef INET6 case SIOCSIFPHYADDR_IN6: #endif /* INET6 */ @@ -557,6 +537,9 @@ gif_ioctl(ifp, cmd, data) &(((struct if_laddrreq *)data)->addr); dst = (struct sockaddr *) &(((struct if_laddrreq *)data)->dstaddr); + break; + default: + return EINVAL; } /* sa_family must be equal */ @@ -614,71 +597,14 @@ gif_ioctl(ifp, cmd, data) break; } - for (sc2 = LIST_FIRST(&gif_softc_list); sc2 != NULL; - sc2 = LIST_NEXT(sc2, gif_list)) { - 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 -#define multidest6(x) \ - (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr)) -#endif - 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 (sc->gif_psrc) - free((caddr_t)sc->gif_psrc, M_IFADDR); - 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(dst->sa_len, M_IFADDR, M_WAITOK); - bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); - sc->gif_pdst = sa; - - s = splsoftnet(); - ifp->if_flags |= IFF_RUNNING; - if_up(ifp); /* send up RTM_IFINFO */ - splx(s); - - error = 0; + error = gif_set_tunnel(&sc->gif_if, src, dst); break; #ifdef SIOCDIFPHYADDR case SIOCDIFPHYADDR: if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) break; - gif_delete_tunnel(sc); + gif_delete_tunnel(&sc->gif_if); break; #endif @@ -783,10 +709,109 @@ gif_ioctl(ifp, cmd, data) return error; } -void -gif_delete_tunnel(sc) - struct gif_softc *sc; +int +gif_set_tunnel(ifp, src, dst) + struct ifnet *ifp; + struct sockaddr *src; + struct sockaddr *dst; { + struct gif_softc *sc = (struct gif_softc *)ifp; + struct gif_softc *sc2; + struct sockaddr *osrc, *odst, *sa; + int s; + int error; + + s = splsoftnet(); + + for (sc2 = LIST_FIRST(&gif_softc_list); sc2 != NULL; + sc2 = LIST_NEXT(sc2, gif_list)) { + 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; + } + + /* XXX both end must be valid? (I mean, not 0.0.0.0) */ + } + + /* XXX we can detach from both, but be polite just in case */ + if (sc->gif_psrc) + switch (sc->gif_psrc->sa_family) { +#ifdef INET + case AF_INET: + (void)in_gif_detach(sc); + break; +#endif +#ifdef INET6 + case AF_INET6: + (void)in6_gif_detach(sc); + break; +#endif + } + + osrc = sc->gif_psrc; + 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; + + odst = sc->gif_pdst; + 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; + + switch (sc->gif_psrc->sa_family) { +#ifdef INET + case AF_INET: + error = in_gif_attach(sc); + break; +#endif +#ifdef INET6 + case AF_INET6: + error = in6_gif_attach(sc); + break; +#endif + } + if (error) { + /* rollback */ + free((caddr_t)sc->gif_psrc, M_IFADDR); + free((caddr_t)sc->gif_pdst, M_IFADDR); + sc->gif_psrc = osrc; + sc->gif_pdst = odst; + goto bad; + } + + if (osrc) + free((caddr_t)osrc, M_IFADDR); + if (odst) + free((caddr_t)odst, M_IFADDR); + + error = 0; + + bad: + if (sc->gif_psrc && sc->gif_pdst) + ifp->if_flags |= IFF_RUNNING; + else + ifp->if_flags &= ~IFF_RUNNING; + splx(s); + + return error; +} + +void +gif_delete_tunnel(ifp) + struct ifnet *ifp; +{ + struct gif_softc *sc = (struct gif_softc *)ifp; int s; s = splsoftnet(); @@ -799,8 +824,18 @@ gif_delete_tunnel(sc) free((caddr_t)sc->gif_pdst, M_IFADDR); sc->gif_pdst = NULL; } - /* change the IFF_UP flag as well? */ + /* it is safe to detach from both */ +#ifdef INET + (void)in_gif_detach(sc); +#endif +#ifdef INET6 + (void)in6_gif_detach(sc); +#endif + if (sc->gif_psrc && sc->gif_pdst) + ifp->if_flags |= IFF_RUNNING; + else + ifp->if_flags &= ~IFF_RUNNING; splx(s); } @@ -814,19 +849,17 @@ struct eonhdr { /* * prepend EON header to ISO PDU */ -static int -gif_eon_encap(struct mbuf **m) +static struct mbuf * +gif_eon_encap(struct mbuf *m) { struct eonhdr *ehdr; - M_PREPEND(*m, sizeof(*ehdr), M_DONTWAIT); - if (*m && (*m)->m_len < sizeof(*ehdr)) - *m = m_pullup(*m, sizeof(*ehdr)); - if (*m == NULL) { - printf("ENOBUFS in gif_eon_encap %d\n", __LINE__); - return ENOBUFS; - } - ehdr = mtod(*m, struct eonhdr *); + M_PREPEND(m, sizeof(*ehdr), M_DONTWAIT); + if (m && m->m_len < sizeof(*ehdr)) + m = m_pullup(m, sizeof(*ehdr)); + if (m == NULL) + return NULL; + ehdr = mtod(m, struct eonhdr *); ehdr->version = 1; ehdr->class = 0; /* always unicast */ #if 0 @@ -845,26 +878,28 @@ gif_eon_encap(struct mbuf **m) /* since the data is always constant we'll just plug the value in */ ehdr->cksum = htons(0xfc02); #endif - return (0); + return m; } /* * remove EON header and check checksum */ -static int -gif_eon_decap(struct ifnet *gifp, struct mbuf **m) +static struct mbuf * +gif_eon_decap(struct ifnet *gifp, struct mbuf *m) { struct eonhdr *ehdr; - if ((*m)->m_len < sizeof(*ehdr) && - (*m = m_pullup(*m, sizeof(*ehdr))) == 0) { + if (m->m_len < sizeof(*ehdr) && + (m = m_pullup(m, sizeof(*ehdr))) == NULL) { gifp->if_ierrors++; - return (EINVAL); + return NULL; } - if (iso_check_csum(*m, sizeof(struct eonhdr))) - return (EINVAL); - m_adj(*m, sizeof(*ehdr)); - return (0); + if (iso_check_csum(m, sizeof(struct eonhdr))) { + m_freem(m); + return NULL; + } + m_adj(m, sizeof(*ehdr)); + return m; } #endif /*ISO*/ #endif /*NGIF > 0*/ diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h index 8b7a9dbfcf32..01897338f3ab 100644 --- a/sys/net/if_gif.h +++ b/sys/net/if_gif.h @@ -1,5 +1,5 @@ -/* $NetBSD: if_gif.h,v 1.6 2000/07/02 00:21:42 thorpej Exp $ */ -/* $KAME: if_gif.h,v 1.12 2000/04/19 06:20:11 itojun Exp $ */ +/* $NetBSD: if_gif.h,v 1.7 2001/07/29 05:08:32 itojun Exp $ */ +/* $KAME: if_gif.h,v 1.23 2001/07/27 09:21:42 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -39,11 +39,9 @@ #include -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) #if defined(_KERNEL) && !defined(_LKM) #include "opt_inet.h" #endif -#endif #include /* xxx sigh, why route have struct route instead of pointer? */ @@ -76,13 +74,13 @@ struct gif_softc { #define GIF_MTU_MAX (8192) /* Maximum MTU */ /* Prototypes */ +void gifattach0 __P((struct gif_softc *)); void gif_input __P((struct mbuf *, int, struct ifnet *)); int gif_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); -#if defined(__FreeBSD__) && __FreeBSD__ < 3 -int gif_ioctl __P((struct ifnet *, int, caddr_t)); -#else int gif_ioctl __P((struct ifnet *, u_long, caddr_t)); -#endif +int gif_set_tunnel __P((struct ifnet *, struct sockaddr *, struct sockaddr *)); +void gif_delete_tunnel __P((struct ifnet *)); +int gif_encapcheck __P((const struct mbuf *, int, int, void *)); #endif /* _NET_IF_GIF_H_ */ diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c index aed4d3284b01..a4a4cd57dc36 100644 --- a/sys/netinet/in_gif.c +++ b/sys/netinet/in_gif.c @@ -1,5 +1,5 @@ -/* $NetBSD: in_gif.c,v 1.21 2001/05/14 13:35:21 itojun Exp $ */ -/* $KAME: in_gif.c,v 1.53 2001/05/03 14:51:48 itojun Exp $ */ +/* $NetBSD: in_gif.c,v 1.22 2001/07/29 05:08:33 itojun Exp $ */ +/* $KAME: in_gif.c,v 1.66 2001/07/29 04:46:09 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -33,6 +33,9 @@ #include "opt_inet.h" #include "opt_iso.h" +/* define it if you want to use encap_attach_func (it helps *BSD merge) */ +#define USE_ENCAPCHECK + #include #include #include @@ -53,18 +56,11 @@ #include #include #include -#ifdef __OpenBSD__ -#include -#endif #ifdef INET6 #include #endif -#ifdef MROUTING -#include -#endif /* MROUTING */ - #include #include "gif.h" @@ -73,12 +69,17 @@ #include +static int gif_validate4 __P((const struct ip *, struct gif_softc *, + struct ifnet *)); + #if NGIF > 0 int ip_gif_ttl = GIF_TTL; #else int ip_gif_ttl = 0; #endif +extern struct protosw in_gif_protosw; + int in_gif_output(ifp, family, m, rt) struct ifnet *ifp; @@ -170,10 +171,8 @@ in_gif_output(ifp, family, m, rt) M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); if (m && m->m_len < sizeof(struct ip)) m = m_pullup(m, sizeof(struct ip)); - if (m == NULL) { - printf("ENOBUFS in in_gif_output %d\n", __LINE__); + if (m == NULL) return ENOBUFS; - } bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip)); if (dst->sin_family != sin_dst->sin_family || @@ -186,9 +185,6 @@ in_gif_output(ifp, family, m, rt) RTFREE(sc->gif_ro.ro_rt); sc->gif_ro.ro_rt = NULL; } -#if 0 - sc->gif_if.if_mtu = GIF_MTU; -#endif } if (sc->gif_ro.ro_rt == NULL) { @@ -203,10 +199,6 @@ in_gif_output(ifp, family, m, rt) m_freem(m); return ENETUNREACH; /*XXX*/ } -#if 0 - ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu - - sizeof(struct ip); -#endif } error = ip_output(m, NULL, &sc->gif_ro, 0, NULL); @@ -243,6 +235,13 @@ in_gif_input(m, va_alist) ipstat.ips_nogif++; return; } +#ifndef USE_ENCAPCHECK + if (!gif_validate4(ip, (struct gif_softc *)gifp, m->m_pkthdr.rcvif)) { + m_freem(m); + ipstat.ips_nogif++; + return; + } +#endif otos = ip->ip_tos; m_adj(m, off); @@ -303,43 +302,29 @@ in_gif_input(m, va_alist) } /* - * we know that we are in IFF_UP, outer address available, and outer family - * matched the physical addr family. see gif_encapcheck(). + * validate outer address. */ -int -gif_encapcheck4(m, off, proto, arg) - const struct mbuf *m; - int off; - int proto; - void *arg; -{ - struct ip ip; +static int +gif_validate4(ip, sc, ifp) + const struct ip *ip; struct gif_softc *sc; + struct ifnet *ifp; +{ struct sockaddr_in *src, *dst; - int addrmatch; struct in_ifaddr *ia4; - /* sanity check done in caller */ - sc = (struct gif_softc *)arg; src = (struct sockaddr_in *)sc->gif_psrc; dst = (struct sockaddr_in *)sc->gif_pdst; - /* LINTED const cast */ - m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip); - /* check for address match */ - addrmatch = 0; - if (src->sin_addr.s_addr == ip.ip_dst.s_addr) - addrmatch |= 1; - if (dst->sin_addr.s_addr == ip.ip_src.s_addr) - addrmatch |= 2; - if (addrmatch != 3) + if (src->sin_addr.s_addr != ip->ip_dst.s_addr || + dst->sin_addr.s_addr != ip->ip_src.s_addr) return 0; /* martian filters on outer source - NOT done in ip_input! */ - if (IN_MULTICAST(ip.ip_src.s_addr)) + if (IN_MULTICAST(ip->ip_src.s_addr)) return 0; - switch ((ntohl(ip.ip_src.s_addr) & 0xff000000) >> 24) { + switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) { case 0: case 127: case 255: return 0; } @@ -348,22 +333,21 @@ gif_encapcheck4(m, off, proto, arg) { if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) continue; - if (ip.ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) + if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) return 0; } /* ingress filters on outer source */ - if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && - (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) { + if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) { struct sockaddr_in sin; struct rtentry *rt; bzero(&sin, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_addr = ip.ip_src; + sin.sin_addr = ip->ip_src; rt = rtalloc1((struct sockaddr *)&sin, 0); - if (!rt || rt->rt_ifp != m->m_pkthdr.rcvif) { + if (!rt || rt->rt_ifp != ifp) { #if 0 log(LOG_WARNING, "%s: packet from 0x%x dropped " "due to ingress filter\n", if_name(&sc->gif_if), @@ -378,3 +362,65 @@ gif_encapcheck4(m, off, proto, arg) return 32 * 2; } + +/* + * we know that we are in IFF_UP, outer address available, and outer family + * matched the physical addr family. see gif_encapcheck(). + */ +int +gif_encapcheck4(m, off, proto, arg) + const struct mbuf *m; + int off; + int proto; + void *arg; +{ + struct ip ip; + struct gif_softc *sc; + struct ifnet *ifp; + + /* sanity check done in caller */ + sc = (struct gif_softc *)arg; + + /* LINTED const cast */ + m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip); + ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; + + return gif_validate4(&ip, sc, ifp); +} + +int +in_gif_attach(sc) + struct gif_softc *sc; +{ +#ifndef USE_ENCAPCHECK + struct sockaddr_in mask4; + + bzero(&mask4, sizeof(mask4)); + mask4.sin_len = sizeof(struct sockaddr_in); + mask4.sin_addr.s_addr = ~0; + + if (!sc->gif_psrc || !sc->gif_pdst) + return EINVAL; + sc->encap_cookie4 = encap_attach(AF_INET, -1, sc->gif_psrc, + (struct sockaddr *)&mask4, sc->gif_pdst, (struct sockaddr *)&mask4, + (struct protosw *)&in_gif_protosw, sc); +#else + sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck, + &in_gif_protosw, sc); +#endif + if (sc->encap_cookie4 == NULL) + return EEXIST; + return 0; +} + +int +in_gif_detach(sc) + struct gif_softc *sc; +{ + int error; + + error = encap_detach(sc->encap_cookie4); + if (error == 0) + sc->encap_cookie4 = NULL; + return error; +} diff --git a/sys/netinet/in_gif.h b/sys/netinet/in_gif.h index b252dabff3c9..aef94bd6a712 100644 --- a/sys/netinet/in_gif.h +++ b/sys/netinet/in_gif.h @@ -1,5 +1,5 @@ -/* $NetBSD: in_gif.h,v 1.5 2000/04/19 06:30:54 itojun Exp $ */ -/* $KAME: in_gif.h,v 1.5 2000/04/14 08:36:02 itojun Exp $ */ +/* $NetBSD: in_gif.h,v 1.6 2001/07/29 05:08:33 itojun Exp $ */ +/* $KAME: in_gif.h,v 1.6 2001/07/25 00:55:48 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -37,8 +37,11 @@ extern int ip_gif_ttl; +struct gif_softc; void in_gif_input __P((struct mbuf *, ...)); int in_gif_output __P((struct ifnet *, int, struct mbuf *, struct rtentry *)); int gif_encapcheck4 __P((const struct mbuf *, int, int, void *)); +int in_gif_attach __P((struct gif_softc *)); +int in_gif_detach __P((struct gif_softc *)); #endif /*_NETINET_IN_GIF_H_*/ diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c index 56484d0b8e68..620733caa2d6 100644 --- a/sys/netinet6/in6_gif.c +++ b/sys/netinet6/in6_gif.c @@ -1,5 +1,5 @@ -/* $NetBSD: in6_gif.c,v 1.20 2001/05/14 13:35:21 itojun Exp $ */ -/* $KAME: in6_gif.c,v 1.48 2001/05/03 14:51:48 itojun Exp $ */ +/* $NetBSD: in6_gif.c,v 1.21 2001/07/29 05:08:33 itojun Exp $ */ +/* $KAME: in6_gif.c,v 1.62 2001/07/29 04:27:25 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -33,6 +33,9 @@ #include "opt_inet.h" #include "opt_iso.h" +/* define it if you want to use encap_attach_func (it helps *BSD merge) */ +#define USE_ENCAPCHECK + #include #include #include @@ -64,6 +67,11 @@ #include +static int gif_validate6 __P((const struct ip6_hdr *, struct gif_softc *, + struct ifnet *)); + +extern struct ip6protosw in6_gif_protosw; + int in6_gif_output(ifp, family, m, rt) struct ifnet *ifp; @@ -137,10 +145,8 @@ in6_gif_output(ifp, family, m, rt) M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); if (m && m->m_len < sizeof(struct ip6_hdr)) m = m_pullup(m, sizeof(struct ip6_hdr)); - if (m == NULL) { - printf("ENOBUFS in in6_gif_output %d\n", __LINE__); + if (m == NULL) return ENOBUFS; - } ip6 = mtod(m, struct ip6_hdr *); ip6->ip6_flow = 0; @@ -175,9 +181,6 @@ in6_gif_output(ifp, family, m, rt) RTFREE(sc->gif_ro6.ro_rt); sc->gif_ro6.ro_rt = NULL; } -#if 0 - sc->gif_if.if_mtu = GIF_MTU; -#endif } if (sc->gif_ro6.ro_rt == NULL) { @@ -190,12 +193,8 @@ in6_gif_output(ifp, family, m, rt) /* if it constitutes infinite encapsulation, punt. */ if (sc->gif_ro.ro_rt->rt_ifp == ifp) { m_freem(m); - return ENETUNREACH; /*XXX*/ + return ENETUNREACH; /* XXX */ } -#if 0 - ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu - - sizeof(struct ip6_hdr); -#endif } #ifdef IPV6_MINMTU @@ -229,6 +228,13 @@ int in6_gif_input(mp, offp, proto) ip6stat.ip6s_nogif++; return IPPROTO_DONE; } +#ifndef USE_ENCAPCHECK + if (!gif_validate6(ip6, (struct gif_softc *)gifp, m->m_pkthdr.rcvif)) { + m_freem(m); + ip6stat.ip6s_nogif++; + return IPPROTO_DONE; + } +#endif otos = ip6->ip6_flow; m_adj(m, *offp); @@ -288,53 +294,38 @@ int in6_gif_input(mp, offp, proto) } /* - * we know that we are in IFF_UP, outer address available, and outer family - * matched the physical addr family. see gif_encapcheck(). + * validate outer address. */ -int -gif_encapcheck6(m, off, proto, arg) - const struct mbuf *m; - int off; - int proto; - void *arg; -{ - struct ip6_hdr ip6; +static int +gif_validate6(ip6, sc, ifp) + const struct ip6_hdr *ip6; struct gif_softc *sc; + struct ifnet *ifp; +{ struct sockaddr_in6 *src, *dst; - int addrmatch; - /* sanity check done in caller */ - sc = (struct gif_softc *)arg; src = (struct sockaddr_in6 *)sc->gif_psrc; dst = (struct sockaddr_in6 *)sc->gif_pdst; - /* LINTED const cast */ - m_copydata((struct mbuf *)m, 0, sizeof(ip6), (caddr_t)&ip6); - /* check for address match */ - addrmatch = 0; - if (IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6.ip6_dst)) - addrmatch |= 1; - if (IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6.ip6_src)) - addrmatch |= 2; - if (addrmatch != 3) + if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) || + !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src)) return 0; /* martian filters on outer source - done in ip6_input */ /* ingress filters on outer source */ - if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && - (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) { + if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) { struct sockaddr_in6 sin6; struct rtentry *rt; bzero(&sin6, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_addr = ip6.ip6_src; + sin6.sin6_addr = ip6->ip6_src; /* XXX scopeid */ rt = rtalloc1((struct sockaddr *)&sin6, 0); - if (!rt || rt->rt_ifp != m->m_pkthdr.rcvif) { + if (!rt || rt->rt_ifp != ifp) { #if 0 log(LOG_WARNING, "%s: packet from %s dropped " "due to ingress filter\n", if_name(&sc->gif_if), @@ -349,3 +340,66 @@ gif_encapcheck6(m, off, proto, arg) return 128 * 2; } + +/* + * we know that we are in IFF_UP, outer address available, and outer family + * matched the physical addr family. see gif_encapcheck(). + */ +int +gif_encapcheck6(m, off, proto, arg) + const struct mbuf *m; + int off; + int proto; + void *arg; +{ + struct ip6_hdr ip6; + struct gif_softc *sc; + struct ifnet *ifp; + + /* sanity check done in caller */ + sc = (struct gif_softc *)arg; + + /* LINTED const cast */ + m_copydata((struct mbuf *)m, 0, sizeof(ip6), (caddr_t)&ip6); + ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; + + return gif_validate6(&ip6, sc, ifp); +} + +int +in6_gif_attach(sc) + struct gif_softc *sc; +{ +#ifndef USE_ENCAPCHECK + struct sockaddr_in6 mask6; + + bzero(&mask6, sizeof(mask6)); + mask6.sin6_len = sizeof(struct sockaddr_in6); + mask6.sin6_addr.s6_addr32[0] = mask6.sin6_addr.s6_addr32[1] = + mask6.sin6_addr.s6_addr32[2] = mask6.sin6_addr.s6_addr32[3] = ~0; + + if (!sc->gif_psrc || !sc->gif_pdst) + return EINVAL; + sc->encap_cookie6 = encap_attach(AF_INET6, -1, sc->gif_psrc, + (struct sockaddr *)&mask6, sc->gif_pdst, (struct sockaddr *)&mask6, + (struct protosw *)&in6_gif_protosw, sc); +#else + sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck, + (struct protosw *)&in6_gif_protosw, sc); +#endif + if (sc->encap_cookie6 == NULL) + return EEXIST; + return 0; +} + +int +in6_gif_detach(sc) + struct gif_softc *sc; +{ + int error; + + error = encap_detach(sc->encap_cookie6); + if (error == 0) + sc->encap_cookie6 = NULL; + return error; +} diff --git a/sys/netinet6/in6_gif.h b/sys/netinet6/in6_gif.h index bfddaf1369e4..c3bec2217619 100644 --- a/sys/netinet6/in6_gif.h +++ b/sys/netinet6/in6_gif.h @@ -1,5 +1,5 @@ -/* $NetBSD: in6_gif.h,v 1.4 2000/04/19 06:30:56 itojun Exp $ */ -/* $KAME: in6_gif.h,v 1.5 2000/04/14 08:36:03 itojun Exp $ */ +/* $NetBSD: in6_gif.h,v 1.5 2001/07/29 05:08:33 itojun Exp $ */ +/* $KAME: in6_gif.h,v 1.7 2001/07/26 06:53:16 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -35,8 +35,11 @@ #define GIF_HLIM 30 +struct gif_softc; int in6_gif_input __P((struct mbuf **, int *, int)); int in6_gif_output __P((struct ifnet *, int, struct mbuf *, struct rtentry *)); int gif_encapcheck6 __P((const struct mbuf *, int, int, void *)); +int in6_gif_attach __P((struct gif_softc *)); +int in6_gif_detach __P((struct gif_softc *)); -#endif /*_NETINET6_IN6_GIF_H_*/ +#endif /* _NETINET6_IN6_GIF_H_ */