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