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