if_faith.c revision 130933
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: head/sys/net/if_faith.c 130933 2004-06-22 20:13:25Z brooks $ 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 65#ifdef INET 66#include <netinet/in.h> 67#include <netinet/in_systm.h> 68#include <netinet/in_var.h> 69#include <netinet/ip.h> 70#endif 71 72#ifdef INET6 73#ifndef INET 74#include <netinet/in.h> 75#endif 76#include <netinet6/in6_var.h> 77#include <netinet/ip6.h> 78#include <netinet6/ip6_var.h> 79#endif 80 81#include <net/net_osdep.h> 82 83#define FAITHNAME "faith" 84 85struct faith_softc { 86 struct ifnet sc_if; /* must be first */ 87 LIST_ENTRY(faith_softc) sc_list; 88}; 89 90static int faithioctl(struct ifnet *, u_long, caddr_t); 91int faithoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 92 struct rtentry *); 93static void faithrtrequest(int, struct rtentry *, struct rt_addrinfo *); 94#ifdef INET6 95static int faithprefix(struct in6_addr *); 96#endif 97 98static int faithmodevent(module_t, int, void *); 99 100static struct mtx faith_mtx; 101static MALLOC_DEFINE(M_FAITH, FAITHNAME, "Firewall Assisted Tunnel Interface"); 102static LIST_HEAD(, faith_softc) faith_softc_list; 103 104static int faith_clone_create(struct if_clone *, int); 105static void faith_clone_destroy(struct ifnet *); 106static void faith_destroy(struct faith_softc *); 107 108IFC_SIMPLE_DECLARE(faith, 0); 109 110#define FAITHMTU 1500 111 112static int 113faithmodevent(mod, type, data) 114 module_t mod; 115 int type; 116 void *data; 117{ 118 struct faith_softc *sc; 119 120 switch (type) { 121 case MOD_LOAD: 122 mtx_init(&faith_mtx, "faith_mtx", NULL, MTX_DEF); 123 LIST_INIT(&faith_softc_list); 124 if_clone_attach(&faith_cloner); 125 126#ifdef INET6 127 faithprefix_p = faithprefix; 128#endif 129 130 break; 131 case MOD_UNLOAD: 132#ifdef INET6 133 faithprefix_p = NULL; 134#endif 135 136 if_clone_detach(&faith_cloner); 137 138 mtx_lock(&faith_mtx); 139 while ((sc = LIST_FIRST(&faith_softc_list)) != NULL) { 140 LIST_REMOVE(sc, sc_list); 141 mtx_unlock(&faith_mtx); 142 faith_destroy(sc); 143 mtx_lock(&faith_mtx); 144 } 145 mtx_unlock(&faith_mtx); 146 mtx_destroy(&faith_mtx); 147 break; 148 } 149 return 0; 150} 151 152static moduledata_t faith_mod = { 153 "if_faith", 154 faithmodevent, 155 0 156}; 157 158DECLARE_MODULE(if_faith, faith_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 159MODULE_VERSION(if_faith, 1); 160 161static int 162faith_clone_create(ifc, unit) 163 struct if_clone *ifc; 164 int unit; 165{ 166 struct faith_softc *sc; 167 168 sc = malloc(sizeof(struct faith_softc), M_FAITH, M_WAITOK); 169 bzero(sc, sizeof(struct faith_softc)); 170 171 sc->sc_if.if_softc = sc; 172 if_initname(&sc->sc_if, ifc->ifc_name, unit); 173 174 sc->sc_if.if_mtu = FAITHMTU; 175 /* Change to BROADCAST experimentaly to announce its prefix. */ 176 sc->sc_if.if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST; 177 sc->sc_if.if_ioctl = faithioctl; 178 sc->sc_if.if_output = faithoutput; 179 sc->sc_if.if_type = IFT_FAITH; 180 sc->sc_if.if_hdrlen = 0; 181 sc->sc_if.if_addrlen = 0; 182 sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen; 183 if_attach(&sc->sc_if); 184 bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int)); 185 mtx_lock(&faith_mtx); 186 LIST_INSERT_HEAD(&faith_softc_list, sc, sc_list); 187 mtx_unlock(&faith_mtx); 188 return (0); 189} 190 191static void 192faith_destroy(struct faith_softc *sc) 193{ 194 195 bpfdetach(&sc->sc_if); 196 if_detach(&sc->sc_if); 197 free(sc, M_FAITH); 198} 199 200static void 201faith_clone_destroy(ifp) 202 struct ifnet *ifp; 203{ 204 struct faith_softc *sc = (void *) ifp; 205 206 mtx_lock(&faith_mtx); 207 LIST_REMOVE(sc, sc_list); 208 mtx_unlock(&faith_mtx); 209 210 faith_destroy(sc); 211} 212 213int 214faithoutput(ifp, m, dst, rt) 215 struct ifnet *ifp; 216 struct mbuf *m; 217 struct sockaddr *dst; 218 struct rtentry *rt; 219{ 220 int isr; 221 222 M_ASSERTPKTHDR(m); 223 224 /* BPF write needs to be handled specially */ 225 if (dst->sa_family == AF_UNSPEC) { 226 dst->sa_family = *(mtod(m, int *)); 227 m->m_len -= sizeof(int); 228 m->m_pkthdr.len -= sizeof(int); 229 m->m_data += sizeof(int); 230 } 231 232 if (ifp->if_bpf) { 233 u_int32_t af = dst->sa_family; 234 bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); 235 } 236 237 if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 238 m_freem(m); 239 return (rt->rt_flags & RTF_BLACKHOLE ? 0 : 240 rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 241 } 242 ifp->if_opackets++; 243 ifp->if_obytes += m->m_pkthdr.len; 244 switch (dst->sa_family) { 245#ifdef INET 246 case AF_INET: 247 isr = NETISR_IP; 248 break; 249#endif 250#ifdef INET6 251 case AF_INET6: 252 isr = NETISR_IPV6; 253 break; 254#endif 255 default: 256 m_freem(m); 257 return EAFNOSUPPORT; 258 } 259 260 /* XXX do we need more sanity checks? */ 261 262 m->m_pkthdr.rcvif = ifp; 263 ifp->if_ipackets++; 264 ifp->if_ibytes += m->m_pkthdr.len; 265 netisr_dispatch(isr, m); 266 return (0); 267} 268 269/* ARGSUSED */ 270static void 271faithrtrequest(cmd, rt, info) 272 int cmd; 273 struct rtentry *rt; 274 struct rt_addrinfo *info; 275{ 276 RT_LOCK_ASSERT(rt); 277 if (rt) 278 rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; 279} 280 281/* 282 * Process an ioctl request. 283 */ 284/* ARGSUSED */ 285static int 286faithioctl(ifp, cmd, data) 287 struct ifnet *ifp; 288 u_long cmd; 289 caddr_t data; 290{ 291 struct ifaddr *ifa; 292 struct ifreq *ifr = (struct ifreq *)data; 293 int error = 0; 294 295 switch (cmd) { 296 297 case SIOCSIFADDR: 298 ifp->if_flags |= IFF_UP | IFF_RUNNING; 299 ifa = (struct ifaddr *)data; 300 ifa->ifa_rtrequest = faithrtrequest; 301 /* 302 * Everything else is done at a higher level. 303 */ 304 break; 305 306 case SIOCADDMULTI: 307 case SIOCDELMULTI: 308 if (ifr == 0) { 309 error = EAFNOSUPPORT; /* XXX */ 310 break; 311 } 312 switch (ifr->ifr_addr.sa_family) { 313#ifdef INET 314 case AF_INET: 315 break; 316#endif 317#ifdef INET6 318 case AF_INET6: 319 break; 320#endif 321 322 default: 323 error = EAFNOSUPPORT; 324 break; 325 } 326 break; 327 328#ifdef SIOCSIFMTU 329 case SIOCSIFMTU: 330 ifp->if_mtu = ifr->ifr_mtu; 331 break; 332#endif 333 334 case SIOCSIFFLAGS: 335 break; 336 337 default: 338 error = EINVAL; 339 } 340 return (error); 341} 342 343#ifdef INET6 344/* 345 * XXX could be slow 346 * XXX could be layer violation to call sys/net from sys/netinet6 347 */ 348static int 349faithprefix(in6) 350 struct in6_addr *in6; 351{ 352 struct rtentry *rt; 353 struct sockaddr_in6 sin6; 354 int ret; 355 356 if (ip6_keepfaith == 0) 357 return 0; 358 359 bzero(&sin6, sizeof(sin6)); 360 sin6.sin6_family = AF_INET6; 361 sin6.sin6_len = sizeof(struct sockaddr_in6); 362 sin6.sin6_addr = *in6; 363 rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); 364 if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH && 365 (rt->rt_ifp->if_flags & IFF_UP) != 0) 366 ret = 1; 367 else 368 ret = 0; 369 if (rt) 370 RTFREE_LOCKED(rt); 371 return ret; 372} 373#endif 374