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 3451a53488SBruce Evans * $Id: if_loop.c,v 1.25 1997/02/22 09:41:02 peter 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 43df8bae1dSRodney W. Grimes #include <sys/param.h> 44df8bae1dSRodney W. Grimes #include <sys/systm.h> 45df8bae1dSRodney W. Grimes #include <sys/kernel.h> 46df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 47df8bae1dSRodney W. Grimes #include <sys/socket.h> 48df8bae1dSRodney W. Grimes #include <sys/errno.h> 4951a53488SBruce Evans #include <sys/sockio.h> 50df8bae1dSRodney W. Grimes #include <sys/time.h> 51df8bae1dSRodney W. Grimes 52df8bae1dSRodney W. Grimes #include <net/if.h> 53df8bae1dSRodney W. Grimes #include <net/if_types.h> 54df8bae1dSRodney W. Grimes #include <net/netisr.h> 55df8bae1dSRodney W. Grimes #include <net/route.h> 56df8bae1dSRodney W. Grimes #include <net/bpf.h> 57df8bae1dSRodney W. Grimes 58df8bae1dSRodney W. Grimes #ifdef INET 59df8bae1dSRodney W. Grimes #include <netinet/in.h> 60df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 61df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 62df8bae1dSRodney W. Grimes #include <netinet/ip.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 <netinet/if_ether.h> 82655929bfSJulian Elischer #include <netatalk/at.h> 83655929bfSJulian Elischer #include <netatalk/at_var.h> 84655929bfSJulian Elischer #endif NETATALK 85655929bfSJulian Elischer 86df8bae1dSRodney W. Grimes #include "bpfilter.h" 87df8bae1dSRodney W. Grimes 883bda9f9bSPoul-Henning Kamp static int loioctl __P((struct ifnet *, int, caddr_t)); 893bda9f9bSPoul-Henning Kamp static void lortrequest __P((int, struct rtentry *, struct sockaddr *)); 903bda9f9bSPoul-Henning Kamp 914590fd3aSDavid Greenman static void loopattach __P((void *)); 92b6f5c0b8SBruce Evans PSEUDO_SET(loopattach, if_loop); 93b6f5c0b8SBruce Evans 94db8889c6SDavid Greenman #ifdef TINY_LOMTU 95df8bae1dSRodney W. Grimes #define LOMTU (1024+512) 96db8889c6SDavid Greenman #else 97af78195eSDavid Greenman #define LOMTU 16384 98db8889c6SDavid Greenman #endif 99df8bae1dSRodney W. Grimes 100f5fea3ddSPaul Traina struct ifnet loif[NLOOP]; 101df8bae1dSRodney W. Grimes 102df8bae1dSRodney W. Grimes /* ARGSUSED */ 103b6f5c0b8SBruce Evans static void 104d841aaa7SBruce Evans loopattach(dummy) 105d841aaa7SBruce Evans void *dummy; 106df8bae1dSRodney W. Grimes { 107f5fea3ddSPaul Traina register struct ifnet *ifp; 108f5fea3ddSPaul Traina register int i = 0; 109df8bae1dSRodney W. Grimes 110f5fea3ddSPaul Traina for (ifp = loif; i < NLOOP; ifp++) { 111df8bae1dSRodney W. Grimes ifp->if_name = "lo"; 112f5fea3ddSPaul Traina ifp->if_unit = i++; 113df8bae1dSRodney W. Grimes ifp->if_mtu = LOMTU; 114df8bae1dSRodney W. Grimes ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; 115df8bae1dSRodney W. Grimes ifp->if_ioctl = loioctl; 116df8bae1dSRodney W. Grimes ifp->if_output = looutput; 117df8bae1dSRodney W. Grimes ifp->if_type = IFT_LOOP; 118df8bae1dSRodney W. Grimes if_attach(ifp); 119df8bae1dSRodney W. Grimes #if NBPFILTER > 0 1209b44ff22SGarrett Wollman bpfattach(ifp, DLT_NULL, sizeof(u_int)); 121df8bae1dSRodney W. Grimes #endif 122df8bae1dSRodney W. Grimes } 123f5fea3ddSPaul Traina } 124df8bae1dSRodney W. Grimes 125df8bae1dSRodney W. Grimes int 126df8bae1dSRodney W. Grimes looutput(ifp, m, dst, rt) 127df8bae1dSRodney W. Grimes struct ifnet *ifp; 128df8bae1dSRodney W. Grimes register struct mbuf *m; 129df8bae1dSRodney W. Grimes struct sockaddr *dst; 130df8bae1dSRodney W. Grimes register struct rtentry *rt; 131df8bae1dSRodney W. Grimes { 132df8bae1dSRodney W. Grimes int s, isr; 133df8bae1dSRodney W. Grimes register struct ifqueue *ifq = 0; 134df8bae1dSRodney W. Grimes 135df8bae1dSRodney W. Grimes if ((m->m_flags & M_PKTHDR) == 0) 136df8bae1dSRodney W. Grimes panic("looutput no HDR"); 137df8bae1dSRodney W. Grimes #if NBPFILTER > 0 138963e4c2aSGarrett Wollman /* BPF write needs to be handled specially */ 139963e4c2aSGarrett Wollman if (dst->sa_family == AF_UNSPEC) { 140963e4c2aSGarrett Wollman dst->sa_family = *(mtod(m, int *)); 141963e4c2aSGarrett Wollman m->m_len -= sizeof(int); 142963e4c2aSGarrett Wollman m->m_pkthdr.len -= sizeof(int); 143963e4c2aSGarrett Wollman m->m_data += sizeof(int); 144963e4c2aSGarrett Wollman } 145963e4c2aSGarrett Wollman 146f5fea3ddSPaul Traina if (ifp->if_bpf) { 147df8bae1dSRodney W. Grimes /* 148df8bae1dSRodney W. Grimes * We need to prepend the address family as 149df8bae1dSRodney W. Grimes * a four byte field. Cons up a dummy header 150df8bae1dSRodney W. Grimes * to pacify bpf. This is safe because bpf 151df8bae1dSRodney W. Grimes * will only read from the mbuf (i.e., it won't 152df8bae1dSRodney W. Grimes * try to free it or keep a pointer a to it). 153df8bae1dSRodney W. Grimes */ 154df8bae1dSRodney W. Grimes struct mbuf m0; 155df8bae1dSRodney W. Grimes u_int af = dst->sa_family; 156df8bae1dSRodney W. Grimes 157df8bae1dSRodney W. Grimes m0.m_next = m; 158df8bae1dSRodney W. Grimes m0.m_len = 4; 159df8bae1dSRodney W. Grimes m0.m_data = (char *)⁡ 160df8bae1dSRodney W. Grimes 1619b44ff22SGarrett Wollman bpf_mtap(ifp, &m0); 162df8bae1dSRodney W. Grimes } 163df8bae1dSRodney W. Grimes #endif 164df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif = ifp; 165df8bae1dSRodney W. Grimes 166df8bae1dSRodney W. Grimes if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 167df8bae1dSRodney W. Grimes m_freem(m); 168df8bae1dSRodney W. Grimes return (rt->rt_flags & RTF_BLACKHOLE ? 0 : 169df8bae1dSRodney W. Grimes rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 170df8bae1dSRodney W. Grimes } 171df8bae1dSRodney W. Grimes ifp->if_opackets++; 172df8bae1dSRodney W. Grimes ifp->if_obytes += m->m_pkthdr.len; 173df8bae1dSRodney W. Grimes switch (dst->sa_family) { 174df8bae1dSRodney W. Grimes 175df8bae1dSRodney W. Grimes #ifdef INET 176df8bae1dSRodney W. Grimes case AF_INET: 177df8bae1dSRodney W. Grimes ifq = &ipintrq; 178df8bae1dSRodney W. Grimes isr = NETISR_IP; 179df8bae1dSRodney W. Grimes break; 180df8bae1dSRodney W. Grimes #endif 181cc6a66f2SJulian Elischer #ifdef IPX 182cc6a66f2SJulian Elischer case AF_IPX: 183cc6a66f2SJulian Elischer ifq = &ipxintrq; 184cc6a66f2SJulian Elischer isr = NETISR_IPX; 185cc6a66f2SJulian Elischer break; 186cc6a66f2SJulian Elischer #endif 187df8bae1dSRodney W. Grimes #ifdef NS 188df8bae1dSRodney W. Grimes case AF_NS: 189df8bae1dSRodney W. Grimes ifq = &nsintrq; 190df8bae1dSRodney W. Grimes isr = NETISR_NS; 191df8bae1dSRodney W. Grimes break; 192df8bae1dSRodney W. Grimes #endif 193df8bae1dSRodney W. Grimes #ifdef ISO 194df8bae1dSRodney W. Grimes case AF_ISO: 195df8bae1dSRodney W. Grimes ifq = &clnlintrq; 196df8bae1dSRodney W. Grimes isr = NETISR_ISO; 197df8bae1dSRodney W. Grimes break; 198df8bae1dSRodney W. Grimes #endif 199655929bfSJulian Elischer #ifdef NETATALK 200655929bfSJulian Elischer case AF_APPLETALK: 201655929bfSJulian Elischer ifq = &atintrq2; 202655929bfSJulian Elischer isr = NETISR_ATALK; 203655929bfSJulian Elischer break; 204655929bfSJulian Elischer #endif NETATALK 205df8bae1dSRodney W. Grimes default: 206df8bae1dSRodney W. Grimes printf("lo%d: can't handle af%d\n", ifp->if_unit, 207df8bae1dSRodney W. Grimes dst->sa_family); 208df8bae1dSRodney W. Grimes m_freem(m); 209df8bae1dSRodney W. Grimes return (EAFNOSUPPORT); 210df8bae1dSRodney W. Grimes } 211df8bae1dSRodney W. Grimes s = splimp(); 212df8bae1dSRodney W. Grimes if (IF_QFULL(ifq)) { 213df8bae1dSRodney W. Grimes IF_DROP(ifq); 214df8bae1dSRodney W. Grimes m_freem(m); 215df8bae1dSRodney W. Grimes splx(s); 216df8bae1dSRodney W. Grimes return (ENOBUFS); 217df8bae1dSRodney W. Grimes } 218df8bae1dSRodney W. Grimes IF_ENQUEUE(ifq, m); 219df8bae1dSRodney W. Grimes schednetisr(isr); 220df8bae1dSRodney W. Grimes ifp->if_ipackets++; 221df8bae1dSRodney W. Grimes ifp->if_ibytes += m->m_pkthdr.len; 222df8bae1dSRodney W. Grimes splx(s); 223df8bae1dSRodney W. Grimes return (0); 224df8bae1dSRodney W. Grimes } 225df8bae1dSRodney W. Grimes 226df8bae1dSRodney W. Grimes /* ARGSUSED */ 2273bda9f9bSPoul-Henning Kamp static void 228df8bae1dSRodney W. Grimes lortrequest(cmd, rt, sa) 229df8bae1dSRodney W. Grimes int cmd; 230df8bae1dSRodney W. Grimes struct rtentry *rt; 231df8bae1dSRodney W. Grimes struct sockaddr *sa; 232df8bae1dSRodney W. Grimes { 2335eb1d25aSGarrett Wollman if (rt) { 2345eb1d25aSGarrett Wollman rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */ 2355eb1d25aSGarrett Wollman /* 2365eb1d25aSGarrett Wollman * For optimal performance, the send and receive buffers 2375eb1d25aSGarrett Wollman * should be at least twice the MTU plus a little more for 2385eb1d25aSGarrett Wollman * overhead. 2395eb1d25aSGarrett Wollman */ 2405eb1d25aSGarrett Wollman rt->rt_rmx.rmx_recvpipe = 2415eb1d25aSGarrett Wollman rt->rt_rmx.rmx_sendpipe = 3 * LOMTU; 2425eb1d25aSGarrett Wollman } 243df8bae1dSRodney W. Grimes } 244df8bae1dSRodney W. Grimes 245df8bae1dSRodney W. Grimes /* 246df8bae1dSRodney W. Grimes * Process an ioctl request. 247df8bae1dSRodney W. Grimes */ 248df8bae1dSRodney W. Grimes /* ARGSUSED */ 2493bda9f9bSPoul-Henning Kamp static int 250df8bae1dSRodney W. Grimes loioctl(ifp, cmd, data) 251df8bae1dSRodney W. Grimes register struct ifnet *ifp; 252df8bae1dSRodney W. Grimes int cmd; 253df8bae1dSRodney W. Grimes caddr_t data; 254df8bae1dSRodney W. Grimes { 255df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 25690fd8c38SDavid Greenman register struct ifreq *ifr = (struct ifreq *)data; 257df8bae1dSRodney W. Grimes register int error = 0; 258df8bae1dSRodney W. Grimes 259df8bae1dSRodney W. Grimes switch (cmd) { 260df8bae1dSRodney W. Grimes 261df8bae1dSRodney W. Grimes case SIOCSIFADDR: 262b8dc74a3SGarrett Wollman ifp->if_flags |= IFF_UP | IFF_RUNNING; 263df8bae1dSRodney W. Grimes ifa = (struct ifaddr *)data; 264df8bae1dSRodney W. Grimes ifa->ifa_rtrequest = lortrequest; 265df8bae1dSRodney W. Grimes /* 266df8bae1dSRodney W. Grimes * Everything else is done at a higher level. 267df8bae1dSRodney W. Grimes */ 268df8bae1dSRodney W. Grimes break; 269df8bae1dSRodney W. Grimes 270df8bae1dSRodney W. Grimes case SIOCADDMULTI: 271df8bae1dSRodney W. Grimes case SIOCDELMULTI: 272df8bae1dSRodney W. Grimes if (ifr == 0) { 273df8bae1dSRodney W. Grimes error = EAFNOSUPPORT; /* XXX */ 274df8bae1dSRodney W. Grimes break; 275df8bae1dSRodney W. Grimes } 276df8bae1dSRodney W. Grimes switch (ifr->ifr_addr.sa_family) { 277df8bae1dSRodney W. Grimes 278df8bae1dSRodney W. Grimes #ifdef INET 279df8bae1dSRodney W. Grimes case AF_INET: 280df8bae1dSRodney W. Grimes break; 281df8bae1dSRodney W. Grimes #endif 282df8bae1dSRodney W. Grimes 283df8bae1dSRodney W. Grimes default: 284df8bae1dSRodney W. Grimes error = EAFNOSUPPORT; 285df8bae1dSRodney W. Grimes break; 286df8bae1dSRodney W. Grimes } 287df8bae1dSRodney W. Grimes break; 288df8bae1dSRodney W. Grimes 28990fd8c38SDavid Greenman case SIOCSIFMTU: 29090fd8c38SDavid Greenman ifp->if_mtu = ifr->ifr_mtu; 29190fd8c38SDavid Greenman break; 29290fd8c38SDavid Greenman 293df8bae1dSRodney W. Grimes default: 294df8bae1dSRodney W. Grimes error = EINVAL; 295df8bae1dSRodney W. Grimes } 296df8bae1dSRodney W. Grimes return (error); 297df8bae1dSRodney W. Grimes } 298f5fea3ddSPaul Traina #endif /* NLOOP > 0 */ 299