1/* $KAME: if_faith.c,v 1.23 2001/12/17 13:55:29 sumikawa Exp $ */ 2 3/*- 4 * Copyright (c) 1982, 1986, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 4. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33/* 34 * derived from 35 * @(#)if_loop.c 8.1 (Berkeley) 6/10/93 36 * Id: if_loop.c,v 1.22 1996/06/19 16:24:10 wollman Exp 37 */ 38 39/* 40 * Loopback interface driver for protocol testing and timing. 41 */ 42#include "opt_inet.h" 43#include "opt_inet6.h" 44 45#include <sys/param.h> 46#include <sys/systm.h> 47#include <sys/kernel.h> 48#include <sys/mbuf.h> 49#include <sys/module.h> 50#include <sys/socket.h> 51#include <sys/errno.h> 52#include <sys/sockio.h> 53#include <sys/time.h> 54#include <sys/queue.h> 55#include <sys/types.h> 56#include <sys/malloc.h> 57 58#include <net/if.h> 59#include <net/if_clone.h> 60#include <net/if_types.h> 61#include <net/netisr.h> 62#include <net/route.h> 63#include <net/bpf.h> 64#include <net/vnet.h> 65 66#ifdef INET 67#include <netinet/in.h> 68#include <netinet/in_systm.h> 69#include <netinet/in_var.h> 70#include <netinet/ip.h> 71#endif 72 73#ifdef INET6 74#ifndef INET 75#include <netinet/in.h> 76#endif 77#include <netinet6/in6_var.h> 78#include <netinet/ip6.h> 79#include <netinet6/ip6_var.h> 80#endif 81 82struct faith_softc { 83 struct ifnet *sc_ifp; 84}; 85 86static int faithioctl(struct ifnet *, u_long, caddr_t); 87static int faithoutput(struct ifnet *, struct mbuf *, const struct sockaddr *, 88 struct route *); 89static void faithrtrequest(int, struct rtentry *, struct rt_addrinfo *); 90#ifdef INET6 91static int faithprefix(struct in6_addr *); 92#endif 93 94static int faithmodevent(module_t, int, void *); 95 96static const char faithname[] = "faith"; 97static MALLOC_DEFINE(M_FAITH, faithname, "Firewall Assisted Tunnel Interface"); 98 99static int faith_clone_create(struct if_clone *, int, caddr_t); 100static void faith_clone_destroy(struct ifnet *); 101static struct if_clone *faith_cloner; 102 103#define FAITHMTU 1500 104 105static int 106faithmodevent(mod, type, data) 107 module_t mod; 108 int type; 109 void *data; 110{ 111 112 switch (type) { 113 case MOD_LOAD: 114 faith_cloner = if_clone_simple(faithname, faith_clone_create, 115 faith_clone_destroy, 0); 116#ifdef INET6 117 faithprefix_p = faithprefix; 118#endif 119 120 break; 121 case MOD_UNLOAD: 122#ifdef INET6 123 faithprefix_p = NULL; 124#endif 125 126 if_clone_detach(faith_cloner); 127 break; 128 default: 129 return EOPNOTSUPP; 130 } 131 return 0; 132} 133 134static moduledata_t faith_mod = { 135 "if_faith", 136 faithmodevent, 137 0 138}; 139 140DECLARE_MODULE(if_faith, faith_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 141MODULE_VERSION(if_faith, 1); 142 143static int 144faith_clone_create(ifc, unit, params) 145 struct if_clone *ifc; 146 int unit; 147 caddr_t params; 148{ 149 struct ifnet *ifp; 150 struct faith_softc *sc; 151 152 sc = malloc(sizeof(struct faith_softc), M_FAITH, M_WAITOK | M_ZERO); 153 ifp = sc->sc_ifp = if_alloc(IFT_FAITH); 154 if (ifp == NULL) { 155 free(sc, M_FAITH); 156 return (ENOSPC); 157 } 158 159 ifp->if_softc = sc; 160 if_initname(sc->sc_ifp, faithname, unit); 161 162 ifp->if_mtu = FAITHMTU; 163 /* Change to BROADCAST experimentaly to announce its prefix. */ 164 ifp->if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST; 165 ifp->if_ioctl = faithioctl; 166 ifp->if_output = faithoutput; 167 ifp->if_hdrlen = 0; 168 ifp->if_addrlen = 0; 169 ifp->if_snd.ifq_maxlen = ifqmaxlen; 170 if_attach(ifp); 171 bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); 172 return (0); 173} 174 175static void 176faith_clone_destroy(ifp) 177 struct ifnet *ifp; 178{ 179 struct faith_softc *sc = ifp->if_softc; 180 181 bpfdetach(ifp); 182 if_detach(ifp); 183 if_free(ifp); 184 free(sc, M_FAITH); 185} 186 187static int 188faithoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 189 struct route *ro) 190{ 191 int isr; 192 u_int32_t af; 193 struct rtentry *rt = NULL; 194 195 M_ASSERTPKTHDR(m); 196 197 if (ro != NULL) 198 rt = ro->ro_rt; 199 /* BPF writes need to be handled specially. */ 200 if (dst->sa_family == AF_UNSPEC) 201 bcopy(dst->sa_data, &af, sizeof(af)); 202 else 203 af = dst->sa_family; 204 205 if (bpf_peers_present(ifp->if_bpf)) 206 bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); 207 208 if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 209 m_freem(m); 210 return (rt->rt_flags & RTF_BLACKHOLE ? 0 : 211 rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 212 } 213 ifp->if_opackets++; 214 ifp->if_obytes += m->m_pkthdr.len; 215 switch (af) { 216#ifdef INET 217 case AF_INET: 218 isr = NETISR_IP; 219 break; 220#endif 221#ifdef INET6 222 case AF_INET6: 223 isr = NETISR_IPV6; 224 break; 225#endif 226 default: 227 m_freem(m); 228 return EAFNOSUPPORT; 229 } 230 231 /* XXX do we need more sanity checks? */ 232 233 m->m_pkthdr.rcvif = ifp; 234 ifp->if_ipackets++; 235 ifp->if_ibytes += m->m_pkthdr.len; 236 netisr_dispatch(isr, m); 237 return (0); 238} 239 240/* ARGSUSED */ 241static void 242faithrtrequest(cmd, rt, info) 243 int cmd; 244 struct rtentry *rt; 245 struct rt_addrinfo *info; 246{ 247 RT_LOCK_ASSERT(rt); 248 rt->rt_mtu = rt->rt_ifp->if_mtu; 249} 250 251/* 252 * Process an ioctl request. 253 */ 254/* ARGSUSED */ 255static int 256faithioctl(ifp, cmd, data) 257 struct ifnet *ifp; 258 u_long cmd; 259 caddr_t data; 260{ 261 struct ifaddr *ifa; 262 struct ifreq *ifr = (struct ifreq *)data; 263 int error = 0; 264 265 switch (cmd) { 266 267 case SIOCSIFADDR: 268 ifp->if_flags |= IFF_UP; 269 ifp->if_drv_flags |= IFF_DRV_RUNNING; 270 ifa = (struct ifaddr *)data; 271 ifa->ifa_rtrequest = faithrtrequest; 272 /* 273 * Everything else is done at a higher level. 274 */ 275 break; 276 277 case SIOCADDMULTI: 278 case SIOCDELMULTI: 279 if (ifr == 0) { 280 error = EAFNOSUPPORT; /* XXX */ 281 break; 282 } 283 switch (ifr->ifr_addr.sa_family) { 284#ifdef INET 285 case AF_INET: 286 break; 287#endif 288#ifdef INET6 289 case AF_INET6: 290 break; 291#endif 292 293 default: 294 error = EAFNOSUPPORT; 295 break; 296 } 297 break; 298 299#ifdef SIOCSIFMTU 300 case SIOCSIFMTU: 301 ifp->if_mtu = ifr->ifr_mtu; 302 break; 303#endif 304 305 case SIOCSIFFLAGS: 306 break; 307 308 default: 309 error = EINVAL; 310 } 311 return (error); 312} 313 314#ifdef INET6 315/* 316 * XXX could be slow 317 * XXX could be layer violation to call sys/net from sys/netinet6 318 */ 319static int 320faithprefix(in6) 321 struct in6_addr *in6; 322{ 323 struct rtentry *rt; 324 struct sockaddr_in6 sin6; 325 int ret; 326 327 if (V_ip6_keepfaith == 0) 328 return 0; 329 330 bzero(&sin6, sizeof(sin6)); 331 sin6.sin6_family = AF_INET6; 332 sin6.sin6_len = sizeof(struct sockaddr_in6); 333 sin6.sin6_addr = *in6; 334 rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL, RT_DEFAULT_FIB); 335 if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH && 336 (rt->rt_ifp->if_flags & IFF_UP) != 0) 337 ret = 1; 338 else 339 ret = 0; 340 if (rt) 341 RTFREE_LOCKED(rt); 342 return ret; 343} 344#endif 345