xref: /netbsd-src/sys/net/if_loop.c (revision b8c616269f5ebf18ab2e35cb8099d683130a177c)
1 /*	$NetBSD: if_loop.c,v 1.41 2002/09/26 16:07:03 darrenr 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. All advertising materials mentioning features or use of this software
45  *    must display the following acknowledgement:
46  *	This product includes software developed by the University of
47  *	California, Berkeley and its contributors.
48  * 4. Neither the name of the University nor the names of its contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  *
64  *	@(#)if_loop.c	8.2 (Berkeley) 1/9/95
65  */
66 
67 /*
68  * Loopback interface driver for protocol testing and timing.
69  */
70 
71 #include <sys/cdefs.h>
72 __KERNEL_RCSID(0, "$NetBSD: if_loop.c,v 1.41 2002/09/26 16:07:03 darrenr Exp $");
73 
74 #include "opt_inet.h"
75 #include "opt_atalk.h"
76 #include "opt_iso.h"
77 #include "opt_ns.h"
78 
79 #include "bpfilter.h"
80 #include "loop.h"
81 
82 #include <sys/param.h>
83 #include <sys/systm.h>
84 #include <sys/kernel.h>
85 #include <sys/mbuf.h>
86 #include <sys/socket.h>
87 #include <sys/errno.h>
88 #include <sys/ioctl.h>
89 #include <sys/time.h>
90 
91 #include <machine/cpu.h>
92 
93 #include <net/if.h>
94 #include <net/if_types.h>
95 #include <net/netisr.h>
96 #include <net/route.h>
97 
98 #ifdef	INET
99 #include <netinet/in.h>
100 #include <netinet/in_systm.h>
101 #include <netinet/in_var.h>
102 #include <netinet/ip.h>
103 #endif
104 
105 #ifdef INET6
106 #ifndef INET
107 #include <netinet/in.h>
108 #endif
109 #include <netinet6/in6_var.h>
110 #include <netinet/ip6.h>
111 #endif
112 
113 #ifdef NS
114 #include <netns/ns.h>
115 #include <netns/ns_if.h>
116 #endif
117 
118 #ifdef IPX
119 #include <netipx/ipx.h>
120 #include <netipx/ipx_if.h>
121 #endif
122 
123 #ifdef ISO
124 #include <netiso/iso.h>
125 #include <netiso/iso_var.h>
126 #endif
127 
128 #ifdef NETATALK
129 #include <netatalk/at.h>
130 #include <netatalk/at_var.h>
131 #endif
132 
133 #if NBPFILTER > 0
134 #include <net/bpf.h>
135 #endif
136 
137 #if defined(LARGE_LOMTU)
138 #define LOMTU	(131072 +  MHLEN + MLEN)
139 #else
140 #define	LOMTU	(32768 +  MHLEN + MLEN)
141 #endif
142 
143 struct	ifnet loif[NLOOP];
144 
145 #ifdef ALTQ
146 void	lostart(struct ifnet *);
147 #endif
148 
149 void
150 loopattach(n)
151 	int n;
152 {
153 	int i;
154 	struct ifnet *ifp;
155 
156 	for (i = 0; i < NLOOP; i++) {
157 		ifp = &loif[i];
158 		sprintf(ifp->if_xname, "lo%d", i);
159 		ifp->if_softc = NULL;
160 		ifp->if_mtu = LOMTU;
161 		ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
162 		ifp->if_ioctl = loioctl;
163 		ifp->if_output = looutput;
164 #ifdef ALTQ
165 		ifp->if_start = lostart;
166 #endif
167 		ifp->if_type = IFT_LOOP;
168 		ifp->if_hdrlen = 0;
169 		ifp->if_addrlen = 0;
170 		ifp->if_dlt = DLT_NULL;
171 		IFQ_SET_READY(&ifp->if_snd);
172 		if_attach(ifp);
173 		if_alloc_sadl(ifp);
174 #if NBPFILTER > 0
175 		bpfattach(ifp, DLT_NULL, sizeof(u_int));
176 #endif
177 	}
178 }
179 
180 int
181 looutput(ifp, m, dst, rt)
182 	struct ifnet *ifp;
183 	struct mbuf *m;
184 	struct sockaddr *dst;
185 	struct rtentry *rt;
186 {
187 	int s, isr;
188 	struct ifqueue *ifq = 0;
189 
190 	if ((m->m_flags & M_PKTHDR) == 0)
191 		panic("looutput: no header mbuf");
192 #if NBPFILTER > 0
193 	if (ifp->if_bpf && (ifp->if_flags & IFF_LOOPBACK)) {
194 		/*
195 		 * We need to prepend the address family as
196 		 * a four byte field.  Cons up a dummy header
197 		 * to pacify bpf.  This is safe because bpf
198 		 * will only read from the mbuf (i.e., it won't
199 		 * try to free it or keep a pointer to it).
200 		 */
201 		struct mbuf m0;
202 		u_int32_t af = dst->sa_family;
203 
204 		M_COPY_PKTHDR(&m0, m);
205 		m0.m_next = m;
206 		m0.m_len = 4;
207 		m0.m_data = (char *)&af;
208 		m0.m_pkthdr.len += m0.m_len;
209 
210 		bpf_mtap(ifp->if_bpf, &m0);
211 	}
212 #endif
213 	m->m_pkthdr.rcvif = ifp;
214 
215 	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
216 		m_freem(m);
217 		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
218 			rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
219 	}
220 
221 #ifndef PULLDOWN_TEST
222 	/*
223 	 * KAME requires that the packet to be contiguous on the
224 	 * mbuf.  We need to make that sure.
225 	 * this kind of code should be avoided.
226 	 * XXX other conditions to avoid running this part?
227 	 */
228 	if (m->m_len != m->m_pkthdr.len) {
229 		struct mbuf *n = NULL;
230 		int maxlen;
231 
232 		MGETHDR(n, M_DONTWAIT, MT_HEADER);
233 		maxlen = MHLEN;
234 		if (n)
235 			M_COPY_PKTHDR(n, m);
236 		if (n && m->m_pkthdr.len > maxlen) {
237 			MCLGET(n, M_DONTWAIT);
238 			maxlen = MCLBYTES;
239 			if ((n->m_flags & M_EXT) == 0) {
240 				m_free(n);
241 				n = NULL;
242 			}
243 		}
244 		if (!n) {
245 			printf("looutput: mbuf allocation failed\n");
246 			m_freem(m);
247 			return ENOBUFS;
248 		}
249 
250 		if (m->m_pkthdr.len <= maxlen) {
251 			m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t));
252 			n->m_len = m->m_pkthdr.len;
253 			n->m_next = NULL;
254 			m_freem(m);
255 		} else {
256 			m_copydata(m, 0, maxlen, mtod(n, caddr_t));
257 			m_adj(m, maxlen);
258 			n->m_len = maxlen;
259 			n->m_next = m;
260 			m->m_flags &= ~M_PKTHDR;
261 		}
262 		m = n;
263 	}
264 #if 0
265 	if (m && m->m_next != NULL) {
266 		printf("loop: not contiguous...\n");
267 		m_freem(m);
268 		return ENOBUFS;
269 	}
270 #endif
271 #endif
272 
273 	ifp->if_opackets++;
274 	ifp->if_obytes += m->m_pkthdr.len;
275 
276 #ifdef ALTQ
277 	/*
278 	 * ALTQ on the loopback interface is just for debugging.  It's
279 	 * used only for loopback interfaces, not for a simplex interface.
280 	 */
281 	if ((ALTQ_IS_ENABLED(&ifp->if_snd) || TBR_IS_ENABLED(&ifp->if_snd)) &&
282 	    ifp->if_start == lostart) {
283 		struct altq_pktattr pktattr;
284 		int error;
285 
286 		/*
287 		 * If the queueing discipline needs packet classification,
288 		 * do it before prepending the link headers.
289 		 */
290 		IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
291 
292 		M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT);
293 		if (m == NULL)
294 			return (ENOBUFS);
295 		*(mtod(m, uint32_t *)) = dst->sa_family;
296 
297 		s = splnet();
298 		IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
299 		(*ifp->if_start)(ifp);
300 		splx(s);
301 		return (error);
302 	}
303 #endif /* ALTQ */
304 
305 	switch (dst->sa_family) {
306 
307 #ifdef INET
308 	case AF_INET:
309 		ifq = &ipintrq;
310 		isr = NETISR_IP;
311 		break;
312 #endif
313 #ifdef INET6
314 	case AF_INET6:
315 		m->m_flags |= M_LOOP;
316 		ifq = &ip6intrq;
317 		isr = NETISR_IPV6;
318 		break;
319 #endif
320 #ifdef NS
321 	case AF_NS:
322 		ifq = &nsintrq;
323 		isr = NETISR_NS;
324 		break;
325 #endif
326 #ifdef ISO
327 	case AF_ISO:
328 		ifq = &clnlintrq;
329 		isr = NETISR_ISO;
330 		break;
331 #endif
332 #ifdef IPX
333 	case AF_IPX:
334 		ifq = &ipxintrq;
335 		isr = NETISR_IPX;
336 		break;
337 #endif
338 #ifdef NETATALK
339 	case AF_APPLETALK:
340 	        ifq = &atintrq2;
341 		isr = NETISR_ATALK;
342 		break;
343 #endif
344 	default:
345 		printf("%s: can't handle af%d\n", ifp->if_xname,
346 		    dst->sa_family);
347 		m_freem(m);
348 		return (EAFNOSUPPORT);
349 	}
350 	s = splnet();
351 	if (IF_QFULL(ifq)) {
352 		IF_DROP(ifq);
353 		m_freem(m);
354 		splx(s);
355 		return (ENOBUFS);
356 	}
357 	IF_ENQUEUE(ifq, m);
358 	schednetisr(isr);
359 	ifp->if_ipackets++;
360 	ifp->if_ibytes += m->m_pkthdr.len;
361 	splx(s);
362 	return (0);
363 }
364 
365 #ifdef ALTQ
366 void
367 lostart(struct ifnet *ifp)
368 {
369 	struct ifqueue *ifq;
370 	struct mbuf *m;
371 	uint32_t af;
372 	int s, isr;
373 
374 	for (;;) {
375 		IFQ_DEQUEUE(&ifp->if_snd, m);
376 		if (m == NULL)
377 			return;
378 
379 		af = *(mtod(m, uint32_t *));
380 		m_adj(m, sizeof(uint32_t));
381 
382 		switch (af) {
383 #ifdef INET
384 		case AF_INET:
385 			ifq = &ipintrq;
386 			isr = NETISR_IP;
387 			break;
388 #endif
389 #ifdef INET6
390 		case AF_INET6:
391 			m->m_flags |= M_LOOP;
392 			ifq = &ip6intrq;
393 			isr = NETISR_IPV6;
394 			break;
395 #endif
396 #ifdef IPX
397 		case AF_IPX:
398 			ifq = &ipxintrq;
399 			isr = NETISR_IPX;
400 			break;
401 #endif
402 #ifdef NS
403 		case AF_NS:
404 			ifq = &nsintrq;
405 			isr = NETISR_NS;
406 			break;
407 #endif
408 #ifdef ISO
409 		case AF_ISO:
410 			ifq = &clnlintrq;
411 			isr = NETISR_ISO;
412 			break;
413 #endif
414 #ifdef NETATALK
415 		case AF_APPLETALK:
416 			ifq = &atintrq2;
417 			isr = NETISR_ATALK;
418 			break;
419 #endif
420 		default:
421 			printf("%s: can't handle af%d\n", ifp->if_xname, af);
422 			m_freem(m);
423 			return;
424 		}
425 
426 		s = splnet();
427 		if (IF_QFULL(ifq)) {
428 			IF_DROP(ifq);
429 			splx(s);
430 			m_freem(m);
431 			return;
432 		}
433 		IF_ENQUEUE(ifq, m);
434 		schednetisr(isr);
435 		ifp->if_ipackets++;
436 		ifp->if_ibytes += m->m_pkthdr.len;
437 		splx(s);
438 	}
439 }
440 #endif /* ALTQ */
441 
442 /* ARGSUSED */
443 void
444 lortrequest(cmd, rt, info)
445 	int cmd;
446 	struct rtentry *rt;
447 	struct rt_addrinfo *info;
448 {
449 
450 	if (rt)
451 		rt->rt_rmx.rmx_mtu = LOMTU;
452 }
453 
454 /*
455  * Process an ioctl request.
456  */
457 /* ARGSUSED */
458 int
459 loioctl(ifp, cmd, data)
460 	struct ifnet *ifp;
461 	u_long cmd;
462 	caddr_t data;
463 {
464 	struct ifaddr *ifa;
465 	struct ifreq *ifr;
466 	int error = 0;
467 
468 	switch (cmd) {
469 
470 	case SIOCSIFADDR:
471 		ifp->if_flags |= IFF_UP;
472 		ifa = (struct ifaddr *)data;
473 		if (ifa != 0 /*&& ifa->ifa_addr->sa_family == AF_ISO*/)
474 			ifa->ifa_rtrequest = lortrequest;
475 		/*
476 		 * Everything else is done at a higher level.
477 		 */
478 		break;
479 
480 	case SIOCADDMULTI:
481 	case SIOCDELMULTI:
482 		ifr = (struct ifreq *)data;
483 		if (ifr == 0) {
484 			error = EAFNOSUPPORT;		/* XXX */
485 			break;
486 		}
487 		switch (ifr->ifr_addr.sa_family) {
488 
489 #ifdef INET
490 		case AF_INET:
491 			break;
492 #endif
493 #ifdef INET6
494 		case AF_INET6:
495 			break;
496 #endif
497 
498 		default:
499 			error = EAFNOSUPPORT;
500 			break;
501 		}
502 		break;
503 
504 	default:
505 		error = EINVAL;
506 	}
507 	return (error);
508 }
509