diff options
Diffstat (limited to 'sys/net/if_gif.c')
-rw-r--r-- | sys/net/if_gif.c | 184 |
1 files changed, 130 insertions, 54 deletions
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c index 68031cb2cfe2..465063cd27f0 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: |