diff options
Diffstat (limited to 'sys/net/if_faith.c')
-rw-r--r-- | sys/net/if_faith.c | 241 |
1 files changed, 234 insertions, 7 deletions
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 */ |