if_loop.c revision 36992
1/* 2 * Copyright (c) 1982, 1986, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)if_loop.c 8.1 (Berkeley) 6/10/93 34 * $Id: if_loop.c,v 1.34 1998/06/12 20:03:26 julian Exp $ 35 */ 36 37/* 38 * Loopback interface driver for protocol testing and timing. 39 */ 40#include "loop.h" 41#if NLOOP > 0 42 43#include "opt_atalk.h" 44#include "opt_inet.h" 45#include "opt_ipx.h" 46 47#include <sys/param.h> 48#include <sys/systm.h> 49#include <sys/kernel.h> 50#include <sys/mbuf.h> 51#include <sys/socket.h> 52#include <sys/sockio.h> 53 54#include <net/if.h> 55#include <net/if_types.h> 56#include <net/netisr.h> 57#include <net/route.h> 58#include <net/bpf.h> 59 60#ifdef INET 61#include <netinet/in.h> 62#include <netinet/in_var.h> 63#endif 64 65#ifdef IPX 66#include <netipx/ipx.h> 67#include <netipx/ipx_if.h> 68#endif 69 70#ifdef NS 71#include <netns/ns.h> 72#include <netns/ns_if.h> 73#endif 74 75#ifdef ISO 76#include <netiso/iso.h> 77#include <netiso/iso_var.h> 78#endif 79 80#ifdef NETATALK 81#include <netatalk/at.h> 82#include <netatalk/at_var.h> 83#endif NETATALK 84 85#include "bpfilter.h" 86#if NBPFILTER > 0 87#include <net/bpfdesc.h> 88#endif 89 90static int loioctl __P((struct ifnet *, u_long, caddr_t)); 91static void lortrequest __P((int, struct rtentry *, struct sockaddr *)); 92 93static void loopattach __P((void *)); 94PSEUDO_SET(loopattach, if_loop); 95 96static int looutput __P((struct ifnet *ifp, 97 struct mbuf *m, struct sockaddr *dst, struct rtentry *rt)); 98 99#ifdef TINY_LOMTU 100#define LOMTU (1024+512) 101#else 102#define LOMTU 16384 103#endif 104 105struct ifnet loif[NLOOP]; 106 107/* ARGSUSED */ 108static void 109loopattach(dummy) 110 void *dummy; 111{ 112 register struct ifnet *ifp; 113 register int i = 0; 114 115 for (ifp = loif; i < NLOOP; ifp++) { 116 ifp->if_name = "lo"; 117 ifp->if_unit = i++; 118 ifp->if_mtu = LOMTU; 119 ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; 120 ifp->if_ioctl = loioctl; 121 ifp->if_output = looutput; 122 ifp->if_type = IFT_LOOP; 123 if_attach(ifp); 124#if NBPFILTER > 0 125 bpfattach(ifp, DLT_NULL, sizeof(u_int)); 126#endif 127 } 128} 129 130static int 131looutput(ifp, m, dst, rt) 132 struct ifnet *ifp; 133 register struct mbuf *m; 134 struct sockaddr *dst; 135 register struct rtentry *rt; 136{ 137 if ((m->m_flags & M_PKTHDR) == 0) 138 panic("looutput no HDR"); 139 140 if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 141 m_freem(m); 142 return (rt->rt_flags & RTF_BLACKHOLE ? 0 : 143 rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 144 } 145 ifp->if_opackets++; 146 ifp->if_obytes += m->m_pkthdr.len; 147#if 1 /* XXX */ 148 switch (dst->sa_family) { 149 case AF_INET: 150 case AF_IPX: 151 case AF_NS: 152 case AF_ISO: 153 case AF_APPLETALK: 154 default: 155 printf("looutput: af=%d unexpected", dst->sa_family); 156 m_freem(m); 157 return (EAFNOSUPPORT); 158 } 159#endif 160 return(if_simloop(ifp, m, dst, 0)); 161} 162 163/* 164 * if_simloop() 165 * 166 * This function is to support software emulation of hardware loopback, 167 * i.e., for interfaces with the IFF_SIMPLEX attribute. Since they can't 168 * hear their own broadcasts, we create a copy of the packet that we 169 * would normally receive via a hardware loopback. 170 * 171 * This function expects the packet to include the media header of length hlen. 172 */ 173 174int 175if_simloop(ifp, m, dst, hlen) 176 struct ifnet *ifp; 177 register struct mbuf *m; 178 struct sockaddr *dst; 179 int hlen; 180{ 181 int s, isr; 182 register struct ifqueue *ifq = 0; 183 184 if ((m->m_flags & M_PKTHDR) == 0) 185 panic("if_simloop: no HDR"); 186 m->m_pkthdr.rcvif = ifp; 187#if NBPFILTER > 0 188 /* BPF write needs to be handled specially */ 189 if (dst->sa_family == AF_UNSPEC) { 190 dst->sa_family = *(mtod(m, int *)); 191 m->m_len -= sizeof(int); 192 m->m_pkthdr.len -= sizeof(int); 193 m->m_data += sizeof(int); 194 } 195 196 if (ifp->if_bpf) { 197 struct mbuf m0, *n = m; 198 u_int af = dst->sa_family; 199 200 if (ifp->if_bpf->bif_dlt == DLT_NULL) { 201 /* 202 * We need to prepend the address family as 203 * a four byte field. Cons up a dummy header 204 * to pacify bpf. This is safe because bpf 205 * will only read from the mbuf (i.e., it won't 206 * try to free it or keep a pointer a to it). 207 */ 208 m0.m_next = m; 209 m0.m_len = 4; 210 m0.m_data = (char *)⁡ 211 n = &m0; 212 } 213 bpf_mtap(ifp, n); 214 } 215#endif 216 217 /* Strip away media header */ 218 if (hlen > 0) 219 m_adj(m, hlen); 220 221 switch (dst->sa_family) { 222#ifdef INET 223 case AF_INET: 224 ifq = &ipintrq; 225 isr = NETISR_IP; 226 break; 227#endif 228#ifdef IPX 229 case AF_IPX: 230 ifq = &ipxintrq; 231 isr = NETISR_IPX; 232 break; 233#endif 234#ifdef NS 235 case AF_NS: 236 ifq = &nsintrq; 237 isr = NETISR_NS; 238 break; 239#endif 240#ifdef ISO 241 case AF_ISO: 242 ifq = &clnlintrq; 243 isr = NETISR_ISO; 244 break; 245#endif 246#ifdef NETATALK 247 case AF_APPLETALK: 248 ifq = &atintrq2; 249 isr = NETISR_ATALK; 250 break; 251#endif NETATALK 252 default: 253 printf("if_simloop: can't handle af=%d\n", dst->sa_family); 254 m_freem(m); 255 return (EAFNOSUPPORT); 256 } 257 s = splimp(); 258 if (IF_QFULL(ifq)) { 259 IF_DROP(ifq); 260 m_freem(m); 261 splx(s); 262 return (ENOBUFS); 263 } 264 IF_ENQUEUE(ifq, m); 265 schednetisr(isr); 266 ifp->if_ipackets++; 267 ifp->if_ibytes += m->m_pkthdr.len; 268 splx(s); 269 return (0); 270} 271 272/* ARGSUSED */ 273static void 274lortrequest(cmd, rt, sa) 275 int cmd; 276 struct rtentry *rt; 277 struct sockaddr *sa; 278{ 279 if (rt) { 280 rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */ 281 /* 282 * For optimal performance, the send and receive buffers 283 * should be at least twice the MTU plus a little more for 284 * overhead. 285 */ 286 rt->rt_rmx.rmx_recvpipe = 287 rt->rt_rmx.rmx_sendpipe = 3 * LOMTU; 288 } 289} 290 291/* 292 * Process an ioctl request. 293 */ 294/* ARGSUSED */ 295static int 296loioctl(ifp, cmd, data) 297 register struct ifnet *ifp; 298 u_long cmd; 299 caddr_t data; 300{ 301 register struct ifaddr *ifa; 302 register struct ifreq *ifr = (struct ifreq *)data; 303 register int error = 0; 304 305 switch (cmd) { 306 307 case SIOCSIFADDR: 308 ifp->if_flags |= IFF_UP | IFF_RUNNING; 309 ifa = (struct ifaddr *)data; 310 ifa->ifa_rtrequest = lortrequest; 311 /* 312 * Everything else is done at a higher level. 313 */ 314 break; 315 316 case SIOCADDMULTI: 317 case SIOCDELMULTI: 318 if (ifr == 0) { 319 error = EAFNOSUPPORT; /* XXX */ 320 break; 321 } 322 switch (ifr->ifr_addr.sa_family) { 323 324#ifdef INET 325 case AF_INET: 326 break; 327#endif 328 329 default: 330 error = EAFNOSUPPORT; 331 break; 332 } 333 break; 334 335 case SIOCSIFMTU: 336 ifp->if_mtu = ifr->ifr_mtu; 337 break; 338 339 case SIOCSIFFLAGS: 340 break; 341 342 default: 343 error = EINVAL; 344 } 345 return (error); 346} 347#endif /* NLOOP > 0 */ 348