xref: /netbsd-src/sys/net/if_loop.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: if_loop.c,v 1.51 2004/08/19 20:58:24 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5  * 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. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1982, 1986, 1993
34  *	The Regents of the University of California.  All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. Neither the name of the University nor the names of its contributors
45  *    may be used to endorse or promote products derived from this software
46  *    without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58  * SUCH DAMAGE.
59  *
60  *	@(#)if_loop.c	8.2 (Berkeley) 1/9/95
61  */
62 
63 /*
64  * Loopback interface driver for protocol testing and timing.
65  */
66 
67 #include <sys/cdefs.h>
68 __KERNEL_RCSID(0, "$NetBSD: if_loop.c,v 1.51 2004/08/19 20:58:24 christos Exp $");
69 
70 #include "opt_inet.h"
71 #include "opt_atalk.h"
72 #include "opt_iso.h"
73 #include "opt_ns.h"
74 #include "opt_ipx.h"
75 #include "opt_mbuftrace.h"
76 
77 #include "bpfilter.h"
78 #include "loop.h"
79 
80 #include <sys/param.h>
81 #include <sys/systm.h>
82 #include <sys/kernel.h>
83 #include <sys/mbuf.h>
84 #include <sys/socket.h>
85 #include <sys/errno.h>
86 #include <sys/ioctl.h>
87 #include <sys/time.h>
88 
89 #include <machine/cpu.h>
90 
91 #include <net/if.h>
92 #include <net/if_types.h>
93 #include <net/netisr.h>
94 #include <net/route.h>
95 
96 #ifdef	INET
97 #include <netinet/in.h>
98 #include <netinet/in_systm.h>
99 #include <netinet/in_var.h>
100 #include <netinet/ip.h>
101 #endif
102 
103 #ifdef INET6
104 #ifndef INET
105 #include <netinet/in.h>
106 #endif
107 #include <netinet6/in6_var.h>
108 #include <netinet/ip6.h>
109 #endif
110 
111 #ifdef NS
112 #include <netns/ns.h>
113 #include <netns/ns_if.h>
114 #endif
115 
116 #ifdef IPX
117 #include <netipx/ipx.h>
118 #include <netipx/ipx_if.h>
119 #endif
120 
121 #ifdef ISO
122 #include <netiso/iso.h>
123 #include <netiso/iso_var.h>
124 #endif
125 
126 #ifdef NETATALK
127 #include <netatalk/at.h>
128 #include <netatalk/at_var.h>
129 #endif
130 
131 #if NBPFILTER > 0
132 #include <net/bpf.h>
133 #endif
134 
135 #if defined(LARGE_LOMTU)
136 #define LOMTU	(131072 +  MHLEN + MLEN)
137 #define LOMTU_MAX LOMTU
138 #else
139 #define	LOMTU	(32768 +  MHLEN + MLEN)
140 #define	LOMTU_MAX	(65536 +  MHLEN + MLEN)
141 #endif
142 
143 struct	ifnet loif[NLOOP];
144 #ifdef MBUFTRACE
145 struct	mowner lomowner[NLOOP];
146 #endif
147 
148 #ifdef ALTQ
149 void	lostart(struct ifnet *);
150 #endif
151 
152 void
153 loopattach(n)
154 	int n;
155 {
156 	int i;
157 	struct ifnet *ifp;
158 
159 	for (i = 0; i < NLOOP; i++) {
160 		ifp = &loif[i];
161 		snprintf(ifp->if_xname, sizeof(ifp->if_xname), "lo%d", i);
162 		ifp->if_softc = NULL;
163 		ifp->if_mtu = LOMTU;
164 		ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
165 		ifp->if_ioctl = loioctl;
166 		ifp->if_output = looutput;
167 #ifdef ALTQ
168 		ifp->if_start = lostart;
169 #endif
170 		ifp->if_type = IFT_LOOP;
171 		ifp->if_hdrlen = 0;
172 		ifp->if_addrlen = 0;
173 		ifp->if_dlt = DLT_NULL;
174 		IFQ_SET_READY(&ifp->if_snd);
175 		if_attach(ifp);
176 		if_alloc_sadl(ifp);
177 #if NBPFILTER > 0
178 		bpfattach(ifp, DLT_NULL, sizeof(u_int));
179 #endif
180 #ifdef MBUFTRACE
181 		ifp->if_mowner = &lomowner[i];
182 		strlcpy(ifp->if_mowner->mo_name, ifp->if_xname,
183 		    sizeof(ifp->if_mowner->mo_name));
184 		MOWNER_ATTACH(&lomowner[i]);
185 #endif
186 	}
187 }
188 
189 int
190 looutput(ifp, m, dst, rt)
191 	struct ifnet *ifp;
192 	struct mbuf *m;
193 	struct sockaddr *dst;
194 	struct rtentry *rt;
195 {
196 	int s, isr;
197 	struct ifqueue *ifq = 0;
198 
199 	MCLAIM(m, ifp->if_mowner);
200 	if ((m->m_flags & M_PKTHDR) == 0)
201 		panic("looutput: no header mbuf");
202 #if NBPFILTER > 0
203 	if (ifp->if_bpf && (ifp->if_flags & IFF_LOOPBACK))
204 		bpf_mtap_af(ifp->if_bpf, dst->sa_family, m);
205 #endif
206 	m->m_pkthdr.rcvif = ifp;
207 
208 	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
209 		m_freem(m);
210 		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
211 			rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
212 	}
213 
214 	ifp->if_opackets++;
215 	ifp->if_obytes += m->m_pkthdr.len;
216 
217 #ifdef ALTQ
218 	/*
219 	 * ALTQ on the loopback interface is just for debugging.  It's
220 	 * used only for loopback interfaces, not for a simplex interface.
221 	 */
222 	if ((ALTQ_IS_ENABLED(&ifp->if_snd) || TBR_IS_ENABLED(&ifp->if_snd)) &&
223 	    ifp->if_start == lostart) {
224 		struct altq_pktattr pktattr;
225 		int error;
226 
227 		/*
228 		 * If the queueing discipline needs packet classification,
229 		 * do it before prepending the link headers.
230 		 */
231 		IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
232 
233 		M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT);
234 		if (m == NULL)
235 			return (ENOBUFS);
236 		*(mtod(m, uint32_t *)) = dst->sa_family;
237 
238 		s = splnet();
239 		IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
240 		(*ifp->if_start)(ifp);
241 		splx(s);
242 		return (error);
243 	}
244 #endif /* ALTQ */
245 
246 	m_tag_delete_nonpersistent(m);
247 
248 	switch (dst->sa_family) {
249 
250 #ifdef INET
251 	case AF_INET:
252 		ifq = &ipintrq;
253 		isr = NETISR_IP;
254 		break;
255 #endif
256 #ifdef INET6
257 	case AF_INET6:
258 		m->m_flags |= M_LOOP;
259 		ifq = &ip6intrq;
260 		isr = NETISR_IPV6;
261 		break;
262 #endif
263 #ifdef NS
264 	case AF_NS:
265 		ifq = &nsintrq;
266 		isr = NETISR_NS;
267 		break;
268 #endif
269 #ifdef ISO
270 	case AF_ISO:
271 		ifq = &clnlintrq;
272 		isr = NETISR_ISO;
273 		break;
274 #endif
275 #ifdef IPX
276 	case AF_IPX:
277 		ifq = &ipxintrq;
278 		isr = NETISR_IPX;
279 		break;
280 #endif
281 #ifdef NETATALK
282 	case AF_APPLETALK:
283 	        ifq = &atintrq2;
284 		isr = NETISR_ATALK;
285 		break;
286 #endif
287 	default:
288 		printf("%s: can't handle af%d\n", ifp->if_xname,
289 		    dst->sa_family);
290 		m_freem(m);
291 		return (EAFNOSUPPORT);
292 	}
293 	s = splnet();
294 	if (IF_QFULL(ifq)) {
295 		IF_DROP(ifq);
296 		m_freem(m);
297 		splx(s);
298 		return (ENOBUFS);
299 	}
300 	IF_ENQUEUE(ifq, m);
301 	schednetisr(isr);
302 	ifp->if_ipackets++;
303 	ifp->if_ibytes += m->m_pkthdr.len;
304 	splx(s);
305 	return (0);
306 }
307 
308 #ifdef ALTQ
309 void
310 lostart(struct ifnet *ifp)
311 {
312 	struct ifqueue *ifq;
313 	struct mbuf *m;
314 	uint32_t af;
315 	int s, isr;
316 
317 	for (;;) {
318 		IFQ_DEQUEUE(&ifp->if_snd, m);
319 		if (m == NULL)
320 			return;
321 
322 		af = *(mtod(m, uint32_t *));
323 		m_adj(m, sizeof(uint32_t));
324 
325 		switch (af) {
326 #ifdef INET
327 		case AF_INET:
328 			ifq = &ipintrq;
329 			isr = NETISR_IP;
330 			break;
331 #endif
332 #ifdef INET6
333 		case AF_INET6:
334 			m->m_flags |= M_LOOP;
335 			ifq = &ip6intrq;
336 			isr = NETISR_IPV6;
337 			break;
338 #endif
339 #ifdef IPX
340 		case AF_IPX:
341 			ifq = &ipxintrq;
342 			isr = NETISR_IPX;
343 			break;
344 #endif
345 #ifdef NS
346 		case AF_NS:
347 			ifq = &nsintrq;
348 			isr = NETISR_NS;
349 			break;
350 #endif
351 #ifdef ISO
352 		case AF_ISO:
353 			ifq = &clnlintrq;
354 			isr = NETISR_ISO;
355 			break;
356 #endif
357 #ifdef NETATALK
358 		case AF_APPLETALK:
359 			ifq = &atintrq2;
360 			isr = NETISR_ATALK;
361 			break;
362 #endif
363 		default:
364 			printf("%s: can't handle af%d\n", ifp->if_xname, af);
365 			m_freem(m);
366 			return;
367 		}
368 
369 		s = splnet();
370 		if (IF_QFULL(ifq)) {
371 			IF_DROP(ifq);
372 			splx(s);
373 			m_freem(m);
374 			return;
375 		}
376 		IF_ENQUEUE(ifq, m);
377 		schednetisr(isr);
378 		ifp->if_ipackets++;
379 		ifp->if_ibytes += m->m_pkthdr.len;
380 		splx(s);
381 	}
382 }
383 #endif /* ALTQ */
384 
385 /* ARGSUSED */
386 void
387 lortrequest(cmd, rt, info)
388 	int cmd;
389 	struct rtentry *rt;
390 	struct rt_addrinfo *info;
391 {
392 
393 	struct ifnet *ifp = &loif[0];
394 	if (rt)
395 		rt->rt_rmx.rmx_mtu = ifp->if_mtu;
396 
397 }
398 
399 /*
400  * Process an ioctl request.
401  */
402 /* ARGSUSED */
403 int
404 loioctl(ifp, cmd, data)
405 	struct ifnet *ifp;
406 	u_long cmd;
407 	caddr_t data;
408 {
409 	struct ifaddr *ifa;
410 	struct ifreq *ifr;
411 	int error = 0;
412 
413 	switch (cmd) {
414 
415 	case SIOCSIFADDR:
416 		ifp->if_flags |= IFF_UP;
417 		ifa = (struct ifaddr *)data;
418 		if (ifa != 0 /*&& ifa->ifa_addr->sa_family == AF_ISO*/)
419 			ifa->ifa_rtrequest = lortrequest;
420 		/*
421 		 * Everything else is done at a higher level.
422 		 */
423 		break;
424 
425 	case SIOCSIFMTU:
426 		ifr = (struct ifreq *)data;
427 		if ((unsigned)ifr->ifr_mtu > LOMTU_MAX)
428 			error = EINVAL;
429 		else {
430 			/* XXX update rt mtu for AF_ISO? */
431 			ifp->if_mtu = ifr->ifr_mtu;
432 		}
433 		break;
434 
435 	case SIOCADDMULTI:
436 	case SIOCDELMULTI:
437 		ifr = (struct ifreq *)data;
438 		if (ifr == 0) {
439 			error = EAFNOSUPPORT;		/* XXX */
440 			break;
441 		}
442 		switch (ifr->ifr_addr.sa_family) {
443 
444 #ifdef INET
445 		case AF_INET:
446 			break;
447 #endif
448 #ifdef INET6
449 		case AF_INET6:
450 			break;
451 #endif
452 
453 		default:
454 			error = EAFNOSUPPORT;
455 			break;
456 		}
457 		break;
458 
459 	default:
460 		error = EINVAL;
461 	}
462 	return (error);
463 }
464