xref: /dragonfly/sys/net/if_loop.c (revision a4c31683)
1 /*
2  * Copyright (c) 1982, 1986, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *	@(#)if_loop.c	8.1 (Berkeley) 6/10/93
30  * $FreeBSD: src/sys/net/if_loop.c,v 1.47.2.9 2004/02/08 08:40:24 silby Exp $
31  */
32 
33 /*
34  * Loopback interface driver for protocol testing and timing.
35  */
36 #include "use_loop.h"
37 
38 #include "opt_inet.h"
39 #include "opt_inet6.h"
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/lock.h>
45 #include <sys/mbuf.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 
49 #include <sys/mplock2.h>
50 
51 #include <net/if.h>
52 #include <net/if_types.h>
53 #include <net/if_clone.h>
54 #include <net/ifq_var.h>
55 #include <net/netisr.h>
56 #include <net/route.h>
57 #include <net/bpf.h>
58 #include <net/bpfdesc.h>
59 
60 #ifdef	INET
61 #include <netinet/in.h>
62 #include <netinet/in_var.h>
63 #endif
64 
65 #ifdef INET6
66 #ifndef INET
67 #include <netinet/in.h>
68 #endif
69 #include <netinet6/in6_var.h>
70 #include <netinet/ip6.h>
71 #endif
72 
73 static int	lo_clone_create(struct if_clone *, int, caddr_t);
74 static int	lo_clone_destroy(struct ifnet *);
75 
76 static int	lo_output(struct ifnet *, struct mbuf *, struct sockaddr *,
77 		    struct rtentry *);
78 static int	lo_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
79 static void	lo_rtrequest(int, struct rtentry *);
80 #ifdef ALTQ
81 static void	lo_altqstart(struct ifnet *, struct ifaltq_subque *);
82 #endif
83 
84 #ifdef TINY_LOMTU
85 #define	LOMTU	(1024+512)
86 #elif defined(LARGE_LOMTU)
87 #define LOMTU	131072
88 #else
89 #define LOMTU	16384
90 #endif
91 
92 #define LO_CSUM_FEATURES	(CSUM_IP | CSUM_UDP | CSUM_TCP)
93 
94 struct ifnet	*loif;
95 
96 static struct if_clone lo_cloner = IF_CLONE_INITIALIZER("lo",
97     lo_clone_create, lo_clone_destroy, NLOOP, IF_MAXUNIT);
98 
99 static void
100 lo_sysinit(void *dummy __unused)
101 {
102 
103 	if_clone_attach(&lo_cloner);
104 }
105 SYSINIT(lo_sysinit, SI_SUB_PSEUDO, SI_ORDER_ANY, lo_sysinit, NULL);
106 
107 static int
108 lo_clone_create(struct if_clone *ifc __unused, int unit, caddr_t param __unused)
109 {
110 	struct ifnet *ifp;
111 
112 	ifp = kmalloc(sizeof(*ifp), M_IFNET, M_WAITOK | M_ZERO);
113 
114 	if_initname(ifp, "lo", unit);
115 	ifp->if_mtu = LOMTU;
116 	ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
117 	ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_RSS;
118 	ifp->if_hwassist = LO_CSUM_FEATURES;
119 	ifp->if_capenable = ifp->if_capabilities;
120 	ifp->if_ioctl = lo_ioctl;
121 	ifp->if_output = lo_output;
122 	ifp->if_type = IFT_LOOP;
123 	ifq_set_maxlen(&ifp->if_snd, ifqmaxlen);
124 	ifq_set_ready(&ifp->if_snd);
125 #ifdef ALTQ
126 	ifp->if_start = lo_altqstart;
127 #endif
128 	if_attach(ifp, NULL);
129 	bpfattach(ifp, DLT_NULL, sizeof(u_int));
130 
131 	if (loif == NULL) {
132 		KASSERT(unit == 0, ("loif is %s", ifp->if_xname));
133 		loif = ifp;
134 	}
135 	return (0);
136 }
137 
138 static int
139 lo_clone_destroy(struct ifnet *ifp)
140 {
141 
142 	if (loif == ifp)
143 		return (EPERM);
144 
145 	bpfdetach(ifp);
146 	if_detach(ifp);
147 	kfree(ifp, M_IFNET);
148 	return (0);
149 }
150 
151 static int
152 lo_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
153     struct rtentry *rt)
154 {
155 	M_ASSERTPKTHDR(m);
156 
157 	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
158 		m_freem(m);
159 		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
160 		        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
161 	}
162 
163 	IFNET_STAT_INC(ifp, opackets, 1);
164 	IFNET_STAT_INC(ifp, obytes, m->m_pkthdr.len);
165 #if 1	/* XXX */
166 	switch (dst->sa_family) {
167 	case AF_INET:
168 	case AF_INET6:
169 		break;
170 	default:
171 		kprintf("lo_output: af=%d unexpected\n", dst->sa_family);
172 		m_freem(m);
173 		return (EAFNOSUPPORT);
174 	}
175 #endif
176 
177 	if (ifp->if_capenable & IFCAP_RXCSUM) {
178 		int csum_flags = 0;
179 
180 		if (m->m_pkthdr.csum_flags & CSUM_IP)
181 			csum_flags |= (CSUM_IP_CHECKED | CSUM_IP_VALID);
182 		if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA)
183 			csum_flags |= (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
184 
185 		m->m_pkthdr.csum_flags |= csum_flags;
186 		if (csum_flags & CSUM_DATA_VALID)
187 			m->m_pkthdr.csum_data = 0xffff;
188 	}
189 	if ((ifp->if_capenable & IFCAP_RSS) == 0)
190 		m->m_flags &= ~M_HASH;
191 	return (if_simloop(ifp, m, dst->sa_family, 0));
192 }
193 
194 /*
195  * if_simloop()
196  *
197  * This function is to support software emulation of hardware loopback,
198  * i.e., for interfaces with the IFF_SIMPLEX attribute. Since they can't
199  * hear their own broadcasts, we create a copy of the packet that we
200  * would normally receive via a hardware loopback.
201  *
202  * This function expects the packet to include the media header of length hlen.
203  */
204 int
205 if_simloop(struct ifnet *ifp, struct mbuf *m, int af, int hlen)
206 {
207 	int isr;
208 
209 	KASSERT((m->m_flags & M_PKTHDR) != 0, ("if_simloop: no HDR"));
210 	m->m_pkthdr.rcvif = ifp;
211 
212 	/* BPF write needs to be handled specially */
213 	if (af == AF_UNSPEC) {
214 		KASSERT(m->m_len >= sizeof(int), ("if_simloop: m_len"));
215 		af = *(mtod(m, int *));
216 		m->m_len -= sizeof(int);
217 		m->m_pkthdr.len -= sizeof(int);
218 		m->m_data += sizeof(int);
219 	}
220 
221 	if (ifp->if_bpf) {
222 		bpf_gettoken();
223 
224 		/* Re-check */
225 		if (ifp->if_bpf == NULL)
226 			goto rel;
227 
228 		if (ifp->if_bpf->bif_dlt == DLT_NULL) {
229 			uint32_t bpf_af = (uint32_t)af;
230 			bpf_ptap(ifp->if_bpf, m, &bpf_af, 4);
231 		} else {
232 			bpf_mtap(ifp->if_bpf, m);
233 		}
234 rel:
235 		bpf_reltoken();
236 	}
237 
238 	/* Strip away media header */
239 	if (hlen > 0)
240 		m_adj(m, hlen);
241 
242 #ifdef ALTQ
243 	/*
244 	 * altq for loop is just for debugging.
245 	 * only used when called for loop interface (not for
246 	 * a simplex interface).
247 	 */
248 	if (ifq_is_enabled(&ifp->if_snd) && ifp->if_start == lo_altqstart) {
249 		struct altq_pktattr pktattr;
250 		int32_t *afp;
251 
252 		/*
253 		 * if the queueing discipline needs packet classification,
254 		 * do it before prepending link headers.
255 		 */
256 		ifq_classify(&ifp->if_snd, m, af, &pktattr);
257 
258 		M_PREPEND(m, sizeof(int32_t), M_NOWAIT);
259 		if (m == NULL)
260 			return(ENOBUFS);
261 		afp = mtod(m, int32_t *);
262 		*afp = (int32_t)af;
263 
264 		return ifq_dispatch(ifp, m, &pktattr);
265 	}
266 #endif /* ALTQ */
267 
268 	/* Deliver to upper layer protocol */
269 	switch (af) {
270 #ifdef INET
271 	case AF_INET:
272 		isr = NETISR_IP;
273 		break;
274 #endif
275 #ifdef INET6
276 	case AF_INET6:
277 		m->m_flags |= M_LOOP;
278 		isr = NETISR_IPV6;
279 		break;
280 #endif
281 	default:
282 		kprintf("if_simloop: can't handle af=%d\n", af);
283 		m_freem(m);
284 		return (EAFNOSUPPORT);
285 	}
286 
287 	IFNET_STAT_INC(ifp, ipackets, 1);
288 	IFNET_STAT_INC(ifp, ibytes, m->m_pkthdr.len);
289 	netisr_queue(isr, m);
290 	return (0);
291 }
292 
293 #ifdef ALTQ
294 static void
295 lo_altqstart(struct ifnet *ifp, struct ifaltq_subque *ifsq)
296 {
297 	struct mbuf *m;
298 	int32_t af, *afp;
299 	int isr;
300 
301 	while (1) {
302 		crit_enter();
303 		m = ifsq_dequeue(ifsq);
304 		crit_exit();
305 		if (m == NULL)
306 			return;
307 
308 		afp = mtod(m, int32_t *);
309 		af = *afp;
310 		m_adj(m, sizeof(int32_t));
311 
312 		switch (af) {
313 #ifdef INET
314 		case AF_INET:
315 			isr = NETISR_IP;
316 			break;
317 #endif
318 #ifdef INET6
319 		case AF_INET6:
320 			m->m_flags |= M_LOOP;
321 			isr = NETISR_IPV6;
322 			break;
323 #endif
324 		default:
325 			kprintf("lo_altqstart: can't handle af%d\n", af);
326 			m_freem(m);
327 			return;
328 		}
329 
330 		IFNET_STAT_INC(ifp, ipackets, 1);
331 		IFNET_STAT_INC(ifp, ibytes, m->m_pkthdr.len);
332 		netisr_queue(isr, m);
333 	}
334 }
335 #endif /* ALTQ */
336 
337 /* ARGSUSED */
338 static void
339 lo_rtrequest(int cmd, struct rtentry *rt)
340 {
341 	if (rt) {
342 		rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
343 		/*
344 		 * For optimal performance, the send and receive buffers
345 		 * should be at least twice the MTU plus a little more for
346 		 * overhead.
347 		 */
348 		rt->rt_rmx.rmx_recvpipe = rt->rt_rmx.rmx_sendpipe = 3 * LOMTU;
349 	}
350 }
351 
352 /*
353  * Process an ioctl request.
354  */
355 /* ARGSUSED */
356 static int
357 lo_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
358 {
359 	struct ifaddr *ifa;
360 	struct ifreq *ifr = (struct ifreq *)data;
361 	int error = 0, mask;
362 
363 	switch (cmd) {
364 	case SIOCSIFADDR:
365 		ifp->if_flags |= IFF_UP | IFF_RUNNING;
366 		ifa = (struct ifaddr *)data;
367 		ifa->ifa_rtrequest = lo_rtrequest;
368 		/*
369 		 * Everything else is done at a higher level.
370 		 */
371 		break;
372 
373 	case SIOCADDMULTI:
374 	case SIOCDELMULTI:
375 		if (ifr == NULL) {
376 			error = EAFNOSUPPORT;		/* XXX */
377 			break;
378 		}
379 		switch (ifr->ifr_addr.sa_family) {
380 
381 #ifdef INET
382 		case AF_INET:
383 			break;
384 #endif
385 #ifdef INET6
386 		case AF_INET6:
387 			break;
388 #endif
389 
390 		default:
391 			error = EAFNOSUPPORT;
392 			break;
393 		}
394 		break;
395 
396 	case SIOCSIFMTU:
397 		ifp->if_mtu = ifr->ifr_mtu;
398 		break;
399 
400 	case SIOCSIFFLAGS:
401 		break;
402 
403 	case SIOCSIFCAP:
404 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
405 		if (mask & IFCAP_HWCSUM) {
406 			ifp->if_capenable ^= (mask & IFCAP_HWCSUM);
407 			if (IFCAP_TXCSUM & ifp->if_capenable)
408 				ifp->if_hwassist = LO_CSUM_FEATURES;
409 			else
410 				ifp->if_hwassist = 0;
411 		}
412 		if (mask & IFCAP_RSS)
413 			ifp->if_capenable ^= IFCAP_RSS;
414 		break;
415 
416 	default:
417 		error = EINVAL;
418 	}
419 	return (error);
420 }
421