if_loop.c revision 36908
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1982, 1986, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 3. All advertising materials mentioning features or use of this software 141541Srgrimes * must display the following acknowledgement: 151541Srgrimes * This product includes software developed by the University of 161541Srgrimes * California, Berkeley and its contributors. 171541Srgrimes * 4. Neither the name of the University nor the names of its contributors 181541Srgrimes * may be used to endorse or promote products derived from this software 191541Srgrimes * without specific prior written permission. 201541Srgrimes * 211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311541Srgrimes * SUCH DAMAGE. 321541Srgrimes * 331541Srgrimes * @(#)if_loop.c 8.1 (Berkeley) 6/10/93 3436908Sjulian * $Id: if_loop.c,v 1.32 1998/06/07 17:12:03 dfr Exp $ 351541Srgrimes */ 361541Srgrimes 371541Srgrimes/* 381541Srgrimes * Loopback interface driver for protocol testing and timing. 391541Srgrimes */ 408090Spst#include "loop.h" 418090Spst#if NLOOP > 0 421541Srgrimes 4332356Seivind#include "opt_atalk.h" 4432350Seivind#include "opt_inet.h" 4531742Seivind#include "opt_ipx.h" 4631742Seivind 471541Srgrimes#include <sys/param.h> 481541Srgrimes#include <sys/systm.h> 491541Srgrimes#include <sys/kernel.h> 501541Srgrimes#include <sys/mbuf.h> 511541Srgrimes#include <sys/socket.h> 5224204Sbde#include <sys/sockio.h> 531541Srgrimes 541541Srgrimes#include <net/if.h> 551541Srgrimes#include <net/if_types.h> 561541Srgrimes#include <net/netisr.h> 571541Srgrimes#include <net/route.h> 581541Srgrimes#include <net/bpf.h> 591541Srgrimes 601541Srgrimes#ifdef INET 611541Srgrimes#include <netinet/in.h> 621541Srgrimes#include <netinet/in_var.h> 631541Srgrimes#endif 641541Srgrimes 6511819Sjulian#ifdef IPX 6611819Sjulian#include <netipx/ipx.h> 6711819Sjulian#include <netipx/ipx_if.h> 6811819Sjulian#endif 6911819Sjulian 701541Srgrimes#ifdef NS 711541Srgrimes#include <netns/ns.h> 721541Srgrimes#include <netns/ns_if.h> 731541Srgrimes#endif 741541Srgrimes 751541Srgrimes#ifdef ISO 761541Srgrimes#include <netiso/iso.h> 771541Srgrimes#include <netiso/iso_var.h> 781541Srgrimes#endif 791541Srgrimes 8015885Sjulian#ifdef NETATALK 8115885Sjulian#include <netatalk/at.h> 8215885Sjulian#include <netatalk/at_var.h> 8315885Sjulian#endif NETATALK 8415885Sjulian 851541Srgrimes#include "bpfilter.h" 8636908Sjulian#if NBPFILTER > 0 8736908Sjulian#include <net/bpfdesc.h> 8836908Sjulian#endif 891541Srgrimes 9036735Sdfrstatic int loioctl __P((struct ifnet *, u_long, caddr_t)); 9112706Sphkstatic void lortrequest __P((int, struct rtentry *, struct sockaddr *)); 9212706Sphk 9310653Sdgstatic void loopattach __P((void *)); 9410429SbdePSEUDO_SET(loopattach, if_loop); 9510429Sbde 9636908Sjulianstatic int looutput __P((struct ifnet *ifp, 9736908Sjulian struct mbuf *m, struct sockaddr *dst, struct rtentry *rt)); 9836908Sjulian 991622Sdg#ifdef TINY_LOMTU 1001541Srgrimes#define LOMTU (1024+512) 1011622Sdg#else 1026876Sdg#define LOMTU 16384 1031622Sdg#endif 1041541Srgrimes 1058090Spststruct ifnet loif[NLOOP]; 1061541Srgrimes 1071541Srgrimes/* ARGSUSED */ 10810429Sbdestatic void 10912569Sbdeloopattach(dummy) 11012569Sbde void *dummy; 1111541Srgrimes{ 1128090Spst register struct ifnet *ifp; 1138090Spst register int i = 0; 1141541Srgrimes 1158090Spst for (ifp = loif; i < NLOOP; ifp++) { 1168090Spst ifp->if_name = "lo"; 1178090Spst ifp->if_unit = i++; 1188090Spst ifp->if_mtu = LOMTU; 1198090Spst ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; 1208090Spst ifp->if_ioctl = loioctl; 1218090Spst ifp->if_output = looutput; 1228090Spst ifp->if_type = IFT_LOOP; 1238090Spst if_attach(ifp); 1241541Srgrimes#if NBPFILTER > 0 12513937Swollman bpfattach(ifp, DLT_NULL, sizeof(u_int)); 1261541Srgrimes#endif 1278090Spst } 1281541Srgrimes} 1291541Srgrimes 13036908Sjulianstatic int 1311541Srgrimeslooutput(ifp, m, dst, rt) 1321541Srgrimes struct ifnet *ifp; 1331541Srgrimes register struct mbuf *m; 1341541Srgrimes struct sockaddr *dst; 1351541Srgrimes register struct rtentry *rt; 1361541Srgrimes{ 13736908Sjulian if ((m->m_flags & M_PKTHDR) == 0) 13836908Sjulian panic("looutput no HDR"); 13936908Sjulian 14036908Sjulian if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 14136908Sjulian m_freem(m); 14236908Sjulian return (rt->rt_flags & RTF_BLACKHOLE ? 0 : 14336908Sjulian rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 14436908Sjulian } 14536908Sjulian ifp->if_opackets++; 14636908Sjulian ifp->if_obytes += m->m_pkthdr.len; 14736908Sjulian return(if_simloop(ifp, m, dst, 0)); 14836908Sjulian} 14936908Sjulian 15036908Sjulian/* 15136908Sjulian * if_simloop() 15236908Sjulian * 15336908Sjulian * This function is to support software emulation of hardware loopback, 15436908Sjulian * i.e., for interfaces with the IFF_SIMPLEX attribute. Since they can't 15536908Sjulian * hear their own broadcasts, we create a copy of the packet that we 15636908Sjulian * would normally receive via a hardware loopback. 15736908Sjulian * 15836908Sjulian * This function expects the packet to include the media header of length hlen. 15936908Sjulian */ 16036908Sjulian 16136908Sjulianint 16236908Sjulianif_simloop(ifp, m, dst, hlen) 16336908Sjulian struct ifnet *ifp; 16436908Sjulian register struct mbuf *m; 16536908Sjulian struct sockaddr *dst; 16636908Sjulian int hlen; 16736908Sjulian{ 1681541Srgrimes int s, isr; 1691541Srgrimes register struct ifqueue *ifq = 0; 1701541Srgrimes 1711541Srgrimes if ((m->m_flags & M_PKTHDR) == 0) 17236908Sjulian panic("%s: no HDR", __FUNCTION__); 17336908Sjulian m->m_pkthdr.rcvif = ifp; 1741541Srgrimes#if NBPFILTER > 0 17510957Swollman /* BPF write needs to be handled specially */ 17610957Swollman if (dst->sa_family == AF_UNSPEC) { 17710957Swollman dst->sa_family = *(mtod(m, int *)); 17810957Swollman m->m_len -= sizeof(int); 17910957Swollman m->m_pkthdr.len -= sizeof(int); 18010957Swollman m->m_data += sizeof(int); 18110957Swollman } 18210957Swollman 1838090Spst if (ifp->if_bpf) { 18436908Sjulian struct mbuf m0, *n = m; 1851541Srgrimes u_int af = dst->sa_family; 1861541Srgrimes 18736908Sjulian if (ifp->if_bpf->bif_dlt == DLT_NULL) { 18836908Sjulian /* 18936908Sjulian * We need to prepend the address family as 19036908Sjulian * a four byte field. Cons up a dummy header 19136908Sjulian * to pacify bpf. This is safe because bpf 19236908Sjulian * will only read from the mbuf (i.e., it won't 19336908Sjulian * try to free it or keep a pointer a to it). 19436908Sjulian */ 19536908Sjulian m0.m_next = m; 19636908Sjulian m0.m_len = 4; 19736908Sjulian m0.m_data = (char *)⁡ 19836908Sjulian n = &m0; 19936908Sjulian } 20036908Sjulian bpf_mtap(ifp, n); 2011541Srgrimes } 2021541Srgrimes#endif 2031541Srgrimes 20436908Sjulian /* Strip away media header */ 20536908Sjulian if (hlen > 0) 20636908Sjulian m_adj(m, hlen); 20736908Sjulian 2081541Srgrimes switch (dst->sa_family) { 2091541Srgrimes#ifdef INET 2101541Srgrimes case AF_INET: 2111541Srgrimes ifq = &ipintrq; 2121541Srgrimes isr = NETISR_IP; 2131541Srgrimes break; 2141541Srgrimes#endif 21511819Sjulian#ifdef IPX 21611819Sjulian case AF_IPX: 21711819Sjulian ifq = &ipxintrq; 21811819Sjulian isr = NETISR_IPX; 21911819Sjulian break; 22011819Sjulian#endif 2211541Srgrimes#ifdef NS 2221541Srgrimes case AF_NS: 2231541Srgrimes ifq = &nsintrq; 2241541Srgrimes isr = NETISR_NS; 2251541Srgrimes break; 2261541Srgrimes#endif 2271541Srgrimes#ifdef ISO 2281541Srgrimes case AF_ISO: 2291541Srgrimes ifq = &clnlintrq; 2301541Srgrimes isr = NETISR_ISO; 2311541Srgrimes break; 2321541Srgrimes#endif 23315885Sjulian#ifdef NETATALK 23415885Sjulian case AF_APPLETALK: 23515885Sjulian ifq = &atintrq2; 23615885Sjulian isr = NETISR_ATALK; 23715885Sjulian break; 23815885Sjulian#endif NETATALK 2391541Srgrimes default: 24036908Sjulian printf("%s: can't handle af=%d\n", 24136908Sjulian __FUNCTION__, dst->sa_family); 2421541Srgrimes m_freem(m); 2431541Srgrimes return (EAFNOSUPPORT); 2441541Srgrimes } 2451541Srgrimes s = splimp(); 2461541Srgrimes if (IF_QFULL(ifq)) { 2471541Srgrimes IF_DROP(ifq); 2481541Srgrimes m_freem(m); 2491541Srgrimes splx(s); 2501541Srgrimes return (ENOBUFS); 2511541Srgrimes } 2521541Srgrimes IF_ENQUEUE(ifq, m); 2531541Srgrimes schednetisr(isr); 2541541Srgrimes ifp->if_ipackets++; 2551541Srgrimes ifp->if_ibytes += m->m_pkthdr.len; 2561541Srgrimes splx(s); 2571541Srgrimes return (0); 2581541Srgrimes} 2591541Srgrimes 2601541Srgrimes/* ARGSUSED */ 26112706Sphkstatic void 2621541Srgrimeslortrequest(cmd, rt, sa) 2631541Srgrimes int cmd; 2641541Srgrimes struct rtentry *rt; 2651541Srgrimes struct sockaddr *sa; 2661541Srgrimes{ 26713928Swollman if (rt) { 26813928Swollman rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */ 26913928Swollman /* 27013928Swollman * For optimal performance, the send and receive buffers 27113928Swollman * should be at least twice the MTU plus a little more for 27213928Swollman * overhead. 27313928Swollman */ 27413928Swollman rt->rt_rmx.rmx_recvpipe = 27513928Swollman rt->rt_rmx.rmx_sendpipe = 3 * LOMTU; 27613928Swollman } 2771541Srgrimes} 2781541Srgrimes 2791541Srgrimes/* 2801541Srgrimes * Process an ioctl request. 2811541Srgrimes */ 2821541Srgrimes/* ARGSUSED */ 28312706Sphkstatic int 2841541Srgrimesloioctl(ifp, cmd, data) 2851541Srgrimes register struct ifnet *ifp; 28636735Sdfr u_long cmd; 2871541Srgrimes caddr_t data; 2881541Srgrimes{ 2891541Srgrimes register struct ifaddr *ifa; 2901944Sdg register struct ifreq *ifr = (struct ifreq *)data; 2911541Srgrimes register int error = 0; 2921541Srgrimes 2931541Srgrimes switch (cmd) { 2941541Srgrimes 2951541Srgrimes case SIOCSIFADDR: 29616512Swollman ifp->if_flags |= IFF_UP | IFF_RUNNING; 2971541Srgrimes ifa = (struct ifaddr *)data; 29813928Swollman ifa->ifa_rtrequest = lortrequest; 2991541Srgrimes /* 3001541Srgrimes * Everything else is done at a higher level. 3011541Srgrimes */ 3021541Srgrimes break; 3031541Srgrimes 3041541Srgrimes case SIOCADDMULTI: 3051541Srgrimes case SIOCDELMULTI: 3061541Srgrimes if (ifr == 0) { 3071541Srgrimes error = EAFNOSUPPORT; /* XXX */ 3081541Srgrimes break; 3091541Srgrimes } 3101541Srgrimes switch (ifr->ifr_addr.sa_family) { 3111541Srgrimes 3121541Srgrimes#ifdef INET 3131541Srgrimes case AF_INET: 3141541Srgrimes break; 3151541Srgrimes#endif 3161541Srgrimes 3171541Srgrimes default: 3181541Srgrimes error = EAFNOSUPPORT; 3191541Srgrimes break; 3201541Srgrimes } 3211541Srgrimes break; 3221541Srgrimes 3231944Sdg case SIOCSIFMTU: 3241944Sdg ifp->if_mtu = ifr->ifr_mtu; 3251944Sdg break; 3261944Sdg 32735563Sphk case SIOCSIFFLAGS: 32835563Sphk break; 32935563Sphk 3301541Srgrimes default: 3311541Srgrimes error = EINVAL; 3321541Srgrimes } 3331541Srgrimes return (error); 3341541Srgrimes} 3358090Spst#endif /* NLOOP > 0 */ 336