xref: /netbsd-src/sys/net/if_loop.c (revision dc306354b0b29af51801a7632f1e95265a68cd81)
1 /*	$NetBSD: if_loop.c,v 1.25 1998/07/05 06:49:17 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 #include "opt_ns.h"
46 
47 #include "bpfilter.h"
48 #include "loop.h"
49 
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/kernel.h>
53 #include <sys/mbuf.h>
54 #include <sys/socket.h>
55 #include <sys/errno.h>
56 #include <sys/ioctl.h>
57 #include <sys/time.h>
58 
59 #include <machine/cpu.h>
60 
61 #include <net/if.h>
62 #include <net/if_types.h>
63 #include <net/netisr.h>
64 #include <net/route.h>
65 
66 #ifdef	INET
67 #include <netinet/in.h>
68 #include <netinet/in_systm.h>
69 #include <netinet/in_var.h>
70 #include <netinet/ip.h>
71 #endif
72 
73 #ifdef NS
74 #include <netns/ns.h>
75 #include <netns/ns_if.h>
76 #endif
77 
78 #ifdef IPX
79 #include <netipx/ipx.h>
80 #include <netipx/ipx_if.h>
81 #endif
82 
83 #ifdef ISO
84 #include <netiso/iso.h>
85 #include <netiso/iso_var.h>
86 #endif
87 
88 #ifdef NETATALK
89 #include <netatalk/at.h>
90 #include <netatalk/at_var.h>
91 #endif
92 
93 #if NBPFILTER > 0
94 #include <net/bpf.h>
95 #endif
96 
97 #define	LOMTU	(32768 +  MHLEN + MLEN)
98 
99 struct	ifnet loif[NLOOP];
100 
101 void
102 loopattach(n)
103 	int n;
104 {
105 	register int i;
106 	register struct ifnet *ifp;
107 
108 	for (i = 0; i < NLOOP; i++) {
109 		ifp = &loif[i];
110 		sprintf(ifp->if_xname, "lo%d", i);
111 		ifp->if_softc = NULL;
112 		ifp->if_mtu = LOMTU;
113 		ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
114 		ifp->if_ioctl = loioctl;
115 		ifp->if_output = looutput;
116 		ifp->if_type = IFT_LOOP;
117 		ifp->if_hdrlen = 0;
118 		ifp->if_addrlen = 0;
119 		if_attach(ifp);
120 #if NBPFILTER > 0
121 		bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
122 #endif
123 	}
124 }
125 
126 int
127 looutput(ifp, m, dst, rt)
128 	struct ifnet *ifp;
129 	register struct mbuf *m;
130 	struct sockaddr *dst;
131 	register struct rtentry *rt;
132 {
133 	int s, isr;
134 	register struct ifqueue *ifq = 0;
135 
136 	if ((m->m_flags & M_PKTHDR) == 0)
137 		panic("looutput: no header mbuf");
138 	ifp->if_lastchange = time;
139 #if NBPFILTER > 0
140 	if (ifp->if_bpf && (ifp->if_flags & IFF_LOOPBACK)) {
141 		/*
142 		 * We need to prepend the address family as
143 		 * a four byte field.  Cons up a dummy header
144 		 * to pacify bpf.  This is safe because bpf
145 		 * will only read from the mbuf (i.e., it won't
146 		 * try to free it or keep a pointer to it).
147 		 */
148 		struct mbuf m0;
149 		u_int af = dst->sa_family;
150 
151 		m0.m_next = m;
152 		m0.m_len = 4;
153 		m0.m_data = (char *)&af;
154 
155 		bpf_mtap(ifp->if_bpf, &m0);
156 	}
157 #endif
158 	m->m_pkthdr.rcvif = ifp;
159 
160 	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
161 		m_freem(m);
162 		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
163 			rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
164 	}
165 	ifp->if_opackets++;
166 	ifp->if_obytes += m->m_pkthdr.len;
167 	switch (dst->sa_family) {
168 
169 #ifdef INET
170 	case AF_INET:
171 		ifq = &ipintrq;
172 		isr = NETISR_IP;
173 		break;
174 #endif
175 #ifdef NS
176 	case AF_NS:
177 		ifq = &nsintrq;
178 		isr = NETISR_NS;
179 		break;
180 #endif
181 #ifdef ISO
182 	case AF_ISO:
183 		ifq = &clnlintrq;
184 		isr = NETISR_ISO;
185 		break;
186 #endif
187 #ifdef IPX
188 	case AF_IPX:
189 		ifq = &ipxintrq;
190 		isr = NETISR_IPX;
191 		break;
192 #endif
193 #ifdef NETATALK
194 	case AF_APPLETALK:
195 	        ifq = &atintrq2;
196 		isr = NETISR_ATALK;
197 		break;
198 #endif
199 	default:
200 		printf("%s: can't handle af%d\n", ifp->if_xname,
201 		    dst->sa_family);
202 		m_freem(m);
203 		return (EAFNOSUPPORT);
204 	}
205 	s = splimp();
206 	if (IF_QFULL(ifq)) {
207 		IF_DROP(ifq);
208 		m_freem(m);
209 		splx(s);
210 		return (ENOBUFS);
211 	}
212 	IF_ENQUEUE(ifq, m);
213 	schednetisr(isr);
214 	ifp->if_ipackets++;
215 	ifp->if_ibytes += m->m_pkthdr.len;
216 	splx(s);
217 	return (0);
218 }
219 
220 /* ARGSUSED */
221 void
222 lortrequest(cmd, rt, sa)
223 	int cmd;
224 	struct rtentry *rt;
225 	struct sockaddr *sa;
226 {
227 
228 	if (rt)
229 		rt->rt_rmx.rmx_mtu = LOMTU;
230 }
231 
232 /*
233  * Process an ioctl request.
234  */
235 /* ARGSUSED */
236 int
237 loioctl(ifp, cmd, data)
238 	register struct ifnet *ifp;
239 	u_long cmd;
240 	caddr_t data;
241 {
242 	register struct ifaddr *ifa;
243 	register struct ifreq *ifr;
244 	register int error = 0;
245 
246 	switch (cmd) {
247 
248 	case SIOCSIFADDR:
249 		ifp->if_flags |= IFF_UP;
250 		ifa = (struct ifaddr *)data;
251 		if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO)
252 			ifa->ifa_rtrequest = lortrequest;
253 		/*
254 		 * Everything else is done at a higher level.
255 		 */
256 		break;
257 
258 	case SIOCADDMULTI:
259 	case SIOCDELMULTI:
260 		ifr = (struct ifreq *)data;
261 		if (ifr == 0) {
262 			error = EAFNOSUPPORT;		/* XXX */
263 			break;
264 		}
265 		switch (ifr->ifr_addr.sa_family) {
266 
267 #ifdef INET
268 		case AF_INET:
269 			break;
270 #endif
271 
272 		default:
273 			error = EAFNOSUPPORT;
274 			break;
275 		}
276 		break;
277 
278 	default:
279 		error = EINVAL;
280 	}
281 	return (error);
282 }
283