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