xref: /netbsd-src/sys/net/if_loop.c (revision d48f14661dda8638fee055ba15d35bdfb29b9fa8)
1 /*	$NetBSD: if_loop.c,v 1.57 2005/12/11 23:05:25 thorpej 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.57 2005/12/11 23:05:25 thorpej 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 
79 #include <sys/param.h>
80 #include <sys/systm.h>
81 #include <sys/kernel.h>
82 #include <sys/mbuf.h>
83 #include <sys/socket.h>
84 #include <sys/errno.h>
85 #include <sys/ioctl.h>
86 #include <sys/time.h>
87 
88 #include <machine/cpu.h>
89 
90 #include <net/if.h>
91 #include <net/if_types.h>
92 #include <net/netisr.h>
93 #include <net/route.h>
94 
95 #ifdef	INET
96 #include <netinet/in.h>
97 #include <netinet/in_systm.h>
98 #include <netinet/in_var.h>
99 #include <netinet/ip.h>
100 #endif
101 
102 #ifdef INET6
103 #ifndef INET
104 #include <netinet/in.h>
105 #endif
106 #include <netinet6/in6_var.h>
107 #include <netinet/ip6.h>
108 #endif
109 
110 #ifdef NS
111 #include <netns/ns.h>
112 #include <netns/ns_if.h>
113 #endif
114 
115 #ifdef IPX
116 #include <netipx/ipx.h>
117 #include <netipx/ipx_if.h>
118 #endif
119 
120 #ifdef ISO
121 #include <netiso/iso.h>
122 #include <netiso/iso_var.h>
123 #endif
124 
125 #ifdef NETATALK
126 #include <netatalk/at.h>
127 #include <netatalk/at_var.h>
128 #endif
129 
130 #if NBPFILTER > 0
131 #include <net/bpf.h>
132 #endif
133 
134 #if defined(LARGE_LOMTU)
135 #define LOMTU	(131072 +  MHLEN + MLEN)
136 #define LOMTU_MAX LOMTU
137 #else
138 #define	LOMTU	(32768 +  MHLEN + MLEN)
139 #define	LOMTU_MAX	(65536 +  MHLEN + MLEN)
140 #endif
141 
142 #ifdef ALTQ
143 static void	lostart(struct ifnet *);
144 #endif
145 
146 struct loop_softc {
147 	LIST_ENTRY(loop_softc) sc_list;
148 	struct ifnet sc_if;
149 };
150 
151 static LIST_HEAD(, loop_softc) loop_softc_list;
152 
153 static int	loop_clone_create(struct if_clone *, int);
154 static int	loop_clone_destroy(struct ifnet *);
155 
156 static struct if_clone loop_cloner =
157     IF_CLONE_INITIALIZER("lo", loop_clone_create, loop_clone_destroy);
158 
159 void
160 loopattach(int n)
161 {
162 	LIST_INIT(&loop_softc_list);
163 
164 	(void)loop_clone_create(&loop_cloner, 0);	/* lo0 always exists */
165 	if_clone_attach(&loop_cloner);
166 }
167 
168 static int
169 loop_clone_create(struct if_clone *ifc, int unit)
170 {
171 	struct loop_softc *sc;
172 
173 	sc = malloc(sizeof(struct loop_softc), M_DEVBUF, M_WAITOK | M_ZERO);
174 
175 	snprintf(sc->sc_if.if_xname, sizeof(sc->sc_if.if_xname), "%s%d",
176 	    ifc->ifc_name, unit);
177 
178 	sc->sc_if.if_softc = sc;
179 	sc->sc_if.if_mtu = LOMTU;
180 	sc->sc_if.if_flags = IFF_LOOPBACK | IFF_MULTICAST;
181 	sc->sc_if.if_ioctl = loioctl;
182 	sc->sc_if.if_output = looutput;
183 #ifdef ALTQ
184 	sc->sc_if.if_start = lostart;
185 #endif
186 	sc->sc_if.if_type = IFT_LOOP;
187 	sc->sc_if.if_hdrlen = 0;
188 	sc->sc_if.if_addrlen = 0;
189 	sc->sc_if.if_dlt = DLT_NULL;
190 	IFQ_SET_READY(&sc->sc_if.if_snd);
191 	if (unit == 0)
192 		lo0ifp = &sc->sc_if;
193 	if_attach(&sc->sc_if);
194 	if_alloc_sadl(&sc->sc_if);
195 #if NBPFILTER > 0
196 	bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
197 #endif
198 #ifdef MBUFTRACE
199 	sc->sc_if.if_mowner = malloc(sizeof(struct mowner), M_DEVBUF,
200 	    M_WAITOK | M_ZERO);
201 	strlcpy(sc->sc_if.if_mowner->mo_name, sc->sc_if.if_xname,
202 	    sizeof(sc->sc_if.if_mowner->mo_name));
203 	MOWNER_ATTACH(sc->sc_if.if_mowner);
204 #endif
205 	LIST_INSERT_HEAD(&loop_softc_list, sc, sc_list);
206 
207 	return (0);
208 }
209 
210 static int
211 loop_clone_destroy(struct ifnet *ifp)
212 {
213 	struct loop_softc *sc = ifp->if_softc;
214 
215 	if (ifp == lo0ifp)
216 		return (EPERM);
217 
218 #ifdef MBUFTRACE
219 	MOWNER_DETACH(ifp->if_mowner);
220 	free(ifp->if_mowner, M_DEVBUF);
221 #endif
222 
223 #if NBPFILTER > 0
224 	bpfdetach(ifp);
225 #endif
226 	if_detach(ifp);
227 
228 	LIST_REMOVE(sc, sc_list);
229 	free(sc, M_DEVBUF);
230 
231 	return (0);
232 }
233 
234 int
235 looutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
236     struct rtentry *rt)
237 {
238 	int s, isr;
239 	struct ifqueue *ifq = NULL;
240 
241 	MCLAIM(m, ifp->if_mowner);
242 	if ((m->m_flags & M_PKTHDR) == 0)
243 		panic("looutput: no header mbuf");
244 #if NBPFILTER > 0
245 	if (ifp->if_bpf && (ifp->if_flags & IFF_LOOPBACK))
246 		bpf_mtap_af(ifp->if_bpf, dst->sa_family, m);
247 #endif
248 	m->m_pkthdr.rcvif = ifp;
249 
250 	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
251 		m_freem(m);
252 		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
253 			rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
254 	}
255 
256 	ifp->if_opackets++;
257 	ifp->if_obytes += m->m_pkthdr.len;
258 
259 #ifdef ALTQ
260 	/*
261 	 * ALTQ on the loopback interface is just for debugging.  It's
262 	 * used only for loopback interfaces, not for a simplex interface.
263 	 */
264 	if ((ALTQ_IS_ENABLED(&ifp->if_snd) || TBR_IS_ENABLED(&ifp->if_snd)) &&
265 	    ifp->if_start == lostart) {
266 		struct altq_pktattr pktattr;
267 		int error;
268 
269 		/*
270 		 * If the queueing discipline needs packet classification,
271 		 * do it before prepending the link headers.
272 		 */
273 		IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
274 
275 		M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT);
276 		if (m == NULL)
277 			return (ENOBUFS);
278 		*(mtod(m, uint32_t *)) = dst->sa_family;
279 
280 		s = splnet();
281 		IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
282 		(*ifp->if_start)(ifp);
283 		splx(s);
284 		return (error);
285 	}
286 #endif /* ALTQ */
287 
288 	m_tag_delete_nonpersistent(m);
289 
290 	switch (dst->sa_family) {
291 
292 #ifdef INET
293 	case AF_INET:
294 		ifq = &ipintrq;
295 		isr = NETISR_IP;
296 		break;
297 #endif
298 #ifdef INET6
299 	case AF_INET6:
300 		m->m_flags |= M_LOOP;
301 		ifq = &ip6intrq;
302 		isr = NETISR_IPV6;
303 		break;
304 #endif
305 #ifdef NS
306 	case AF_NS:
307 		ifq = &nsintrq;
308 		isr = NETISR_NS;
309 		break;
310 #endif
311 #ifdef ISO
312 	case AF_ISO:
313 		ifq = &clnlintrq;
314 		isr = NETISR_ISO;
315 		break;
316 #endif
317 #ifdef IPX
318 	case AF_IPX:
319 		ifq = &ipxintrq;
320 		isr = NETISR_IPX;
321 		break;
322 #endif
323 #ifdef NETATALK
324 	case AF_APPLETALK:
325 	        ifq = &atintrq2;
326 		isr = NETISR_ATALK;
327 		break;
328 #endif
329 	default:
330 		printf("%s: can't handle af%d\n", ifp->if_xname,
331 		    dst->sa_family);
332 		m_freem(m);
333 		return (EAFNOSUPPORT);
334 	}
335 	s = splnet();
336 	if (IF_QFULL(ifq)) {
337 		IF_DROP(ifq);
338 		m_freem(m);
339 		splx(s);
340 		return (ENOBUFS);
341 	}
342 	IF_ENQUEUE(ifq, m);
343 	schednetisr(isr);
344 	ifp->if_ipackets++;
345 	ifp->if_ibytes += m->m_pkthdr.len;
346 	splx(s);
347 	return (0);
348 }
349 
350 #ifdef ALTQ
351 static void
352 lostart(struct ifnet *ifp)
353 {
354 	struct ifqueue *ifq;
355 	struct mbuf *m;
356 	uint32_t af;
357 	int s, isr;
358 
359 	for (;;) {
360 		IFQ_DEQUEUE(&ifp->if_snd, m);
361 		if (m == NULL)
362 			return;
363 
364 		af = *(mtod(m, uint32_t *));
365 		m_adj(m, sizeof(uint32_t));
366 
367 		switch (af) {
368 #ifdef INET
369 		case AF_INET:
370 			ifq = &ipintrq;
371 			isr = NETISR_IP;
372 			break;
373 #endif
374 #ifdef INET6
375 		case AF_INET6:
376 			m->m_flags |= M_LOOP;
377 			ifq = &ip6intrq;
378 			isr = NETISR_IPV6;
379 			break;
380 #endif
381 #ifdef IPX
382 		case AF_IPX:
383 			ifq = &ipxintrq;
384 			isr = NETISR_IPX;
385 			break;
386 #endif
387 #ifdef NS
388 		case AF_NS:
389 			ifq = &nsintrq;
390 			isr = NETISR_NS;
391 			break;
392 #endif
393 #ifdef ISO
394 		case AF_ISO:
395 			ifq = &clnlintrq;
396 			isr = NETISR_ISO;
397 			break;
398 #endif
399 #ifdef NETATALK
400 		case AF_APPLETALK:
401 			ifq = &atintrq2;
402 			isr = NETISR_ATALK;
403 			break;
404 #endif
405 		default:
406 			printf("%s: can't handle af%d\n", ifp->if_xname, af);
407 			m_freem(m);
408 			return;
409 		}
410 
411 		s = splnet();
412 		if (IF_QFULL(ifq)) {
413 			IF_DROP(ifq);
414 			splx(s);
415 			m_freem(m);
416 			return;
417 		}
418 		IF_ENQUEUE(ifq, m);
419 		schednetisr(isr);
420 		ifp->if_ipackets++;
421 		ifp->if_ibytes += m->m_pkthdr.len;
422 		splx(s);
423 	}
424 }
425 #endif /* ALTQ */
426 
427 /* ARGSUSED */
428 void
429 lortrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
430 {
431 
432 	if (rt)
433 		rt->rt_rmx.rmx_mtu = lo0ifp->if_mtu;
434 }
435 
436 /*
437  * Process an ioctl request.
438  */
439 /* ARGSUSED */
440 int
441 loioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
442 {
443 	struct ifaddr *ifa;
444 	struct ifreq *ifr;
445 	int error = 0;
446 
447 	switch (cmd) {
448 
449 	case SIOCSIFADDR:
450 		ifp->if_flags |= IFF_UP;
451 		ifa = (struct ifaddr *)data;
452 		if (ifa != NULL /*&& ifa->ifa_addr->sa_family == AF_ISO*/)
453 			ifa->ifa_rtrequest = lortrequest;
454 		/*
455 		 * Everything else is done at a higher level.
456 		 */
457 		break;
458 
459 	case SIOCSIFMTU:
460 		ifr = (struct ifreq *)data;
461 		if ((unsigned)ifr->ifr_mtu > LOMTU_MAX)
462 			error = EINVAL;
463 		else {
464 			/* XXX update rt mtu for AF_ISO? */
465 			ifp->if_mtu = ifr->ifr_mtu;
466 		}
467 		break;
468 
469 	case SIOCADDMULTI:
470 	case SIOCDELMULTI:
471 		ifr = (struct ifreq *)data;
472 		if (ifr == NULL) {
473 			error = EAFNOSUPPORT;		/* XXX */
474 			break;
475 		}
476 		switch (ifr->ifr_addr.sa_family) {
477 
478 #ifdef INET
479 		case AF_INET:
480 			break;
481 #endif
482 #ifdef INET6
483 		case AF_INET6:
484 			break;
485 #endif
486 
487 		default:
488 			error = EAFNOSUPPORT;
489 			break;
490 		}
491 		break;
492 
493 	default:
494 		error = EINVAL;
495 	}
496 	return (error);
497 }
498