Home | History | Annotate | Line # | Download | only in net
if_loop.c revision 1.24
      1 /*	$NetBSD: if_loop.c,v 1.24 1998/07/05 04:37:41 jonathan 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  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  *
     35  *	@(#)if_loop.c	8.2 (Berkeley) 1/9/95
     36  */
     37 
     38 /*
     39  * Loopback interface driver for protocol testing and timing.
     40  */
     41 
     42 #include "opt_inet.h"
     43 #include "opt_atalk.h"
     44 #include "opt_iso.h"
     45 
     46 #include "bpfilter.h"
     47 #include "loop.h"
     48 
     49 #include <sys/param.h>
     50 #include <sys/systm.h>
     51 #include <sys/kernel.h>
     52 #include <sys/mbuf.h>
     53 #include <sys/socket.h>
     54 #include <sys/errno.h>
     55 #include <sys/ioctl.h>
     56 #include <sys/time.h>
     57 
     58 #include <machine/cpu.h>
     59 
     60 #include <net/if.h>
     61 #include <net/if_types.h>
     62 #include <net/netisr.h>
     63 #include <net/route.h>
     64 
     65 #ifdef	INET
     66 #include <netinet/in.h>
     67 #include <netinet/in_systm.h>
     68 #include <netinet/in_var.h>
     69 #include <netinet/ip.h>
     70 #endif
     71 
     72 #ifdef NS
     73 #include <netns/ns.h>
     74 #include <netns/ns_if.h>
     75 #endif
     76 
     77 #ifdef IPX
     78 #include <netipx/ipx.h>
     79 #include <netipx/ipx_if.h>
     80 #endif
     81 
     82 #ifdef ISO
     83 #include <netiso/iso.h>
     84 #include <netiso/iso_var.h>
     85 #endif
     86 
     87 #ifdef NETATALK
     88 #include <netatalk/at.h>
     89 #include <netatalk/at_var.h>
     90 #endif
     91 
     92 #if NBPFILTER > 0
     93 #include <net/bpf.h>
     94 #endif
     95 
     96 #define	LOMTU	(32768 +  MHLEN + MLEN)
     97 
     98 struct	ifnet loif[NLOOP];
     99 
    100 void
    101 loopattach(n)
    102 	int n;
    103 {
    104 	register int i;
    105 	register struct ifnet *ifp;
    106 
    107 	for (i = 0; i < NLOOP; i++) {
    108 		ifp = &loif[i];
    109 		sprintf(ifp->if_xname, "lo%d", i);
    110 		ifp->if_softc = NULL;
    111 		ifp->if_mtu = LOMTU;
    112 		ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
    113 		ifp->if_ioctl = loioctl;
    114 		ifp->if_output = looutput;
    115 		ifp->if_type = IFT_LOOP;
    116 		ifp->if_hdrlen = 0;
    117 		ifp->if_addrlen = 0;
    118 		if_attach(ifp);
    119 #if NBPFILTER > 0
    120 		bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
    121 #endif
    122 	}
    123 }
    124 
    125 int
    126 looutput(ifp, m, dst, rt)
    127 	struct ifnet *ifp;
    128 	register struct mbuf *m;
    129 	struct sockaddr *dst;
    130 	register struct rtentry *rt;
    131 {
    132 	int s, isr;
    133 	register struct ifqueue *ifq = 0;
    134 
    135 	if ((m->m_flags & M_PKTHDR) == 0)
    136 		panic("looutput: no header mbuf");
    137 	ifp->if_lastchange = time;
    138 #if NBPFILTER > 0
    139 	if (ifp->if_bpf && (ifp->if_flags & IFF_LOOPBACK)) {
    140 		/*
    141 		 * We need to prepend the address family as
    142 		 * a four byte field.  Cons up a dummy header
    143 		 * to pacify bpf.  This is safe because bpf
    144 		 * will only read from the mbuf (i.e., it won't
    145 		 * try to free it or keep a pointer to it).
    146 		 */
    147 		struct mbuf m0;
    148 		u_int af = dst->sa_family;
    149 
    150 		m0.m_next = m;
    151 		m0.m_len = 4;
    152 		m0.m_data = (char *)&af;
    153 
    154 		bpf_mtap(ifp->if_bpf, &m0);
    155 	}
    156 #endif
    157 	m->m_pkthdr.rcvif = ifp;
    158 
    159 	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
    160 		m_freem(m);
    161 		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
    162 			rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
    163 	}
    164 	ifp->if_opackets++;
    165 	ifp->if_obytes += m->m_pkthdr.len;
    166 	switch (dst->sa_family) {
    167 
    168 #ifdef INET
    169 	case AF_INET:
    170 		ifq = &ipintrq;
    171 		isr = NETISR_IP;
    172 		break;
    173 #endif
    174 #ifdef NS
    175 	case AF_NS:
    176 		ifq = &nsintrq;
    177 		isr = NETISR_NS;
    178 		break;
    179 #endif
    180 #ifdef ISO
    181 	case AF_ISO:
    182 		ifq = &clnlintrq;
    183 		isr = NETISR_ISO;
    184 		break;
    185 #endif
    186 #ifdef IPX
    187 	case AF_IPX:
    188 		ifq = &ipxintrq;
    189 		isr = NETISR_IPX;
    190 		break;
    191 #endif
    192 #ifdef NETATALK
    193 	case AF_APPLETALK:
    194 	        ifq = &atintrq2;
    195 		isr = NETISR_ATALK;
    196 		break;
    197 #endif
    198 	default:
    199 		printf("%s: can't handle af%d\n", ifp->if_xname,
    200 		    dst->sa_family);
    201 		m_freem(m);
    202 		return (EAFNOSUPPORT);
    203 	}
    204 	s = splimp();
    205 	if (IF_QFULL(ifq)) {
    206 		IF_DROP(ifq);
    207 		m_freem(m);
    208 		splx(s);
    209 		return (ENOBUFS);
    210 	}
    211 	IF_ENQUEUE(ifq, m);
    212 	schednetisr(isr);
    213 	ifp->if_ipackets++;
    214 	ifp->if_ibytes += m->m_pkthdr.len;
    215 	splx(s);
    216 	return (0);
    217 }
    218 
    219 /* ARGSUSED */
    220 void
    221 lortrequest(cmd, rt, sa)
    222 	int cmd;
    223 	struct rtentry *rt;
    224 	struct sockaddr *sa;
    225 {
    226 
    227 	if (rt)
    228 		rt->rt_rmx.rmx_mtu = LOMTU;
    229 }
    230 
    231 /*
    232  * Process an ioctl request.
    233  */
    234 /* ARGSUSED */
    235 int
    236 loioctl(ifp, cmd, data)
    237 	register struct ifnet *ifp;
    238 	u_long cmd;
    239 	caddr_t data;
    240 {
    241 	register struct ifaddr *ifa;
    242 	register struct ifreq *ifr;
    243 	register int error = 0;
    244 
    245 	switch (cmd) {
    246 
    247 	case SIOCSIFADDR:
    248 		ifp->if_flags |= IFF_UP;
    249 		ifa = (struct ifaddr *)data;
    250 		if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO)
    251 			ifa->ifa_rtrequest = lortrequest;
    252 		/*
    253 		 * Everything else is done at a higher level.
    254 		 */
    255 		break;
    256 
    257 	case SIOCADDMULTI:
    258 	case SIOCDELMULTI:
    259 		ifr = (struct ifreq *)data;
    260 		if (ifr == 0) {
    261 			error = EAFNOSUPPORT;		/* XXX */
    262 			break;
    263 		}
    264 		switch (ifr->ifr_addr.sa_family) {
    265 
    266 #ifdef INET
    267 		case AF_INET:
    268 			break;
    269 #endif
    270 
    271 		default:
    272 			error = EAFNOSUPPORT;
    273 			break;
    274 		}
    275 		break;
    276 
    277 	default:
    278 		error = EINVAL;
    279 	}
    280 	return (error);
    281 }
    282