1 | /* $NetBSD: if_loop.c,v 1.93 2016/11/22 02:06:00 ozaki-r 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.93 2016/11/22 02:06:00 ozaki-r Exp $" ); |
69 | |
70 | #ifdef _KERNEL_OPT |
71 | #include "opt_inet.h" |
72 | #include "opt_atalk.h" |
73 | #include "opt_mbuftrace.h" |
74 | #include "opt_mpls.h" |
75 | #include "opt_net_mpsafe.h" |
76 | #endif |
77 | |
78 | #include <sys/param.h> |
79 | #include <sys/systm.h> |
80 | #include <sys/kernel.h> |
81 | #include <sys/mbuf.h> |
82 | #include <sys/socket.h> |
83 | #include <sys/errno.h> |
84 | #include <sys/ioctl.h> |
85 | #include <sys/time.h> |
86 | #include <sys/device.h> |
87 | #include <sys/module.h> |
88 | |
89 | #include <sys/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/in_offload.h> |
101 | #include <netinet/ip.h> |
102 | #endif |
103 | |
104 | #ifdef INET6 |
105 | #ifndef INET |
106 | #include <netinet/in.h> |
107 | #endif |
108 | #include <netinet6/in6_var.h> |
109 | #include <netinet6/in6_offload.h> |
110 | #include <netinet/ip6.h> |
111 | #endif |
112 | |
113 | #ifdef MPLS |
114 | #include <netmpls/mpls.h> |
115 | #include <netmpls/mpls_var.h> |
116 | #endif |
117 | |
118 | #ifdef NETATALK |
119 | #include <netatalk/at.h> |
120 | #include <netatalk/at_var.h> |
121 | #endif |
122 | |
123 | #include <net/bpf.h> |
124 | |
125 | #if defined(LARGE_LOMTU) |
126 | #define LOMTU (131072 + MHLEN + MLEN) |
127 | #define LOMTU_MAX LOMTU |
128 | #else |
129 | #define LOMTU (32768 + MHLEN + MLEN) |
130 | #define LOMTU_MAX (65536 + MHLEN + MLEN) |
131 | #endif |
132 | |
133 | #ifdef ALTQ |
134 | static void lostart(struct ifnet *); |
135 | #endif |
136 | |
137 | static int loop_clone_create(struct if_clone *, int); |
138 | static int loop_clone_destroy(struct ifnet *); |
139 | |
140 | static void loop_rtrequest(int, struct rtentry *, const struct rt_addrinfo *); |
141 | |
142 | static struct if_clone loop_cloner = |
143 | IF_CLONE_INITIALIZER("lo" , loop_clone_create, loop_clone_destroy); |
144 | |
145 | void |
146 | loopattach(int n) |
147 | { |
148 | |
149 | /* |
150 | * Nothing to do here, initialization is handled by the |
151 | * module initialization code in loopnit() below). |
152 | */ |
153 | } |
154 | |
155 | void |
156 | loopinit(void) |
157 | { |
158 | |
159 | if (lo0ifp != NULL) /* can happen in rump kernel */ |
160 | return; |
161 | |
162 | (void)loop_clone_create(&loop_cloner, 0); /* lo0 always exists */ |
163 | if_clone_attach(&loop_cloner); |
164 | } |
165 | |
166 | static int |
167 | loopdetach(void) |
168 | { |
169 | /* no detach for now; we don't allow lo0 to be deleted */ |
170 | return EBUSY; |
171 | } |
172 | |
173 | static int |
174 | loop_clone_create(struct if_clone *ifc, int unit) |
175 | { |
176 | struct ifnet *ifp; |
177 | |
178 | ifp = if_alloc(IFT_LOOP); |
179 | |
180 | if_initname(ifp, ifc->ifc_name, unit); |
181 | |
182 | ifp->if_mtu = LOMTU; |
183 | ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST | IFF_RUNNING; |
184 | ifp->if_extflags = IFEF_OUTPUT_MPSAFE; |
185 | ifp->if_ioctl = loioctl; |
186 | ifp->if_output = looutput; |
187 | #ifdef ALTQ |
188 | ifp->if_start = lostart; |
189 | #endif |
190 | ifp->if_type = IFT_LOOP; |
191 | ifp->if_hdrlen = 0; |
192 | ifp->if_addrlen = 0; |
193 | ifp->if_dlt = DLT_NULL; |
194 | IFQ_SET_READY(&ifp->if_snd); |
195 | if (unit == 0) |
196 | lo0ifp = ifp; |
197 | if_attach(ifp); |
198 | if_alloc_sadl(ifp); |
199 | bpf_attach(ifp, DLT_NULL, sizeof(u_int)); |
200 | #ifdef MBUFTRACE |
201 | ifp->if_mowner = malloc(sizeof(struct mowner), M_DEVBUF, |
202 | M_WAITOK | M_ZERO); |
203 | strlcpy(ifp->if_mowner->mo_name, ifp->if_xname, |
204 | sizeof(ifp->if_mowner->mo_name)); |
205 | MOWNER_ATTACH(ifp->if_mowner); |
206 | #endif |
207 | |
208 | return (0); |
209 | } |
210 | |
211 | static int |
212 | loop_clone_destroy(struct ifnet *ifp) |
213 | { |
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 | bpf_detach(ifp); |
224 | if_detach(ifp); |
225 | |
226 | if_free(ifp); |
227 | |
228 | return (0); |
229 | } |
230 | |
231 | int |
232 | looutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, |
233 | const struct rtentry *rt) |
234 | { |
235 | pktqueue_t *pktq = NULL; |
236 | struct ifqueue *ifq = NULL; |
237 | int s, isr = -1; |
238 | int csum_flags; |
239 | int error = 0; |
240 | size_t pktlen; |
241 | |
242 | MCLAIM(m, ifp->if_mowner); |
243 | |
244 | KERNEL_LOCK(1, NULL); |
245 | |
246 | if ((m->m_flags & M_PKTHDR) == 0) |
247 | panic("looutput: no header mbuf" ); |
248 | if (ifp->if_flags & IFF_LOOPBACK) |
249 | bpf_mtap_af(ifp, dst->sa_family, m); |
250 | m_set_rcvif(m, ifp); |
251 | |
252 | if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { |
253 | m_freem(m); |
254 | error = (rt->rt_flags & RTF_BLACKHOLE ? 0 : |
255 | rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); |
256 | goto out; |
257 | } |
258 | |
259 | pktlen = m->m_pkthdr.len; |
260 | ifp->if_opackets++; |
261 | ifp->if_obytes += pktlen; |
262 | |
263 | #ifdef ALTQ |
264 | /* |
265 | * ALTQ on the loopback interface is just for debugging. It's |
266 | * used only for loopback interfaces, not for a simplex interface. |
267 | */ |
268 | if ((ALTQ_IS_ENABLED(&ifp->if_snd) || TBR_IS_ENABLED(&ifp->if_snd)) && |
269 | ifp->if_start == lostart) { |
270 | /* |
271 | * If the queueing discipline needs packet classification, |
272 | * do it before prepending the link headers. |
273 | */ |
274 | IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family); |
275 | |
276 | M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT); |
277 | if (m == NULL) { |
278 | error = ENOBUFS; |
279 | goto out; |
280 | } |
281 | *(mtod(m, uint32_t *)) = dst->sa_family; |
282 | |
283 | error = if_transmit_lock(ifp, m); |
284 | goto out; |
285 | } |
286 | #endif /* ALTQ */ |
287 | |
288 | m_tag_delete_nonpersistent(m); |
289 | |
290 | #ifdef MPLS |
291 | if (rt != NULL && rt_gettag(rt) != NULL && |
292 | rt_gettag(rt)->sa_family == AF_MPLS && |
293 | (m->m_flags & (M_MCAST | M_BCAST)) == 0) { |
294 | union mpls_shim msh; |
295 | msh.s_addr = MPLS_GETSADDR(rt); |
296 | if (msh.shim.label != MPLS_LABEL_IMPLNULL) { |
297 | ifq = &mplsintrq; |
298 | isr = NETISR_MPLS; |
299 | } |
300 | } |
301 | if (isr != NETISR_MPLS) |
302 | #endif |
303 | switch (dst->sa_family) { |
304 | |
305 | #ifdef INET |
306 | case AF_INET: |
307 | csum_flags = m->m_pkthdr.csum_flags; |
308 | KASSERT((csum_flags & ~(M_CSUM_IPv4|M_CSUM_UDPv4)) == 0); |
309 | if (csum_flags != 0 && IN_LOOPBACK_NEED_CHECKSUM(csum_flags)) { |
310 | ip_undefer_csum(m, 0, csum_flags); |
311 | } |
312 | m->m_pkthdr.csum_flags = 0; |
313 | pktq = ip_pktq; |
314 | break; |
315 | #endif |
316 | #ifdef INET6 |
317 | case AF_INET6: |
318 | csum_flags = m->m_pkthdr.csum_flags; |
319 | KASSERT((csum_flags & ~M_CSUM_UDPv6) == 0); |
320 | if (csum_flags != 0 && |
321 | IN6_LOOPBACK_NEED_CHECKSUM(csum_flags)) { |
322 | ip6_undefer_csum(m, 0, csum_flags); |
323 | } |
324 | m->m_pkthdr.csum_flags = 0; |
325 | m->m_flags |= M_LOOP; |
326 | pktq = ip6_pktq; |
327 | break; |
328 | #endif |
329 | #ifdef NETATALK |
330 | case AF_APPLETALK: |
331 | ifq = &atintrq2; |
332 | isr = NETISR_ATALK; |
333 | break; |
334 | #endif |
335 | default: |
336 | printf("%s: can't handle af%d\n" , ifp->if_xname, |
337 | dst->sa_family); |
338 | m_freem(m); |
339 | error = EAFNOSUPPORT; |
340 | goto out; |
341 | } |
342 | |
343 | s = splnet(); |
344 | if (__predict_true(pktq)) { |
345 | error = 0; |
346 | |
347 | if (__predict_true(pktq_enqueue(pktq, m, 0))) { |
348 | ifp->if_ipackets++; |
349 | ifp->if_ibytes += pktlen; |
350 | } else { |
351 | m_freem(m); |
352 | error = ENOBUFS; |
353 | } |
354 | splx(s); |
355 | goto out; |
356 | } |
357 | if (IF_QFULL(ifq)) { |
358 | IF_DROP(ifq); |
359 | m_freem(m); |
360 | splx(s); |
361 | error = ENOBUFS; |
362 | goto out; |
363 | } |
364 | IF_ENQUEUE(ifq, m); |
365 | schednetisr(isr); |
366 | ifp->if_ipackets++; |
367 | ifp->if_ibytes += m->m_pkthdr.len; |
368 | splx(s); |
369 | out: |
370 | KERNEL_UNLOCK_ONE(NULL); |
371 | return error; |
372 | } |
373 | |
374 | #ifdef ALTQ |
375 | static void |
376 | lostart(struct ifnet *ifp) |
377 | { |
378 | for (;;) { |
379 | pktqueue_t *pktq = NULL; |
380 | struct ifqueue *ifq = NULL; |
381 | struct mbuf *m; |
382 | size_t pktlen; |
383 | uint32_t af; |
384 | int s, isr = 0; |
385 | |
386 | IFQ_DEQUEUE(&ifp->if_snd, m); |
387 | if (m == NULL) |
388 | return; |
389 | |
390 | af = *(mtod(m, uint32_t *)); |
391 | m_adj(m, sizeof(uint32_t)); |
392 | |
393 | switch (af) { |
394 | #ifdef INET |
395 | case AF_INET: |
396 | pktq = ip_pktq; |
397 | break; |
398 | #endif |
399 | #ifdef INET6 |
400 | case AF_INET6: |
401 | m->m_flags |= M_LOOP; |
402 | pktq = ip6_pktq; |
403 | break; |
404 | #endif |
405 | #ifdef NETATALK |
406 | case AF_APPLETALK: |
407 | ifq = &atintrq2; |
408 | isr = NETISR_ATALK; |
409 | break; |
410 | #endif |
411 | default: |
412 | printf("%s: can't handle af%d\n" , ifp->if_xname, af); |
413 | m_freem(m); |
414 | return; |
415 | } |
416 | pktlen = m->m_pkthdr.len; |
417 | |
418 | s = splnet(); |
419 | if (__predict_true(pktq)) { |
420 | if (__predict_false(pktq_enqueue(pktq, m, 0))) { |
421 | m_freem(m); |
422 | splx(s); |
423 | return; |
424 | } |
425 | ifp->if_ipackets++; |
426 | ifp->if_ibytes += pktlen; |
427 | splx(s); |
428 | continue; |
429 | } |
430 | if (IF_QFULL(ifq)) { |
431 | IF_DROP(ifq); |
432 | splx(s); |
433 | m_freem(m); |
434 | return; |
435 | } |
436 | IF_ENQUEUE(ifq, m); |
437 | schednetisr(isr); |
438 | ifp->if_ipackets++; |
439 | ifp->if_ibytes += pktlen; |
440 | splx(s); |
441 | } |
442 | } |
443 | #endif /* ALTQ */ |
444 | |
445 | /* ARGSUSED */ |
446 | static void |
447 | loop_rtrequest(int cmd, struct rtentry *rt, |
448 | const struct rt_addrinfo *info) |
449 | { |
450 | |
451 | if (rt) |
452 | rt->rt_rmx.rmx_mtu = lo0ifp->if_mtu; |
453 | } |
454 | |
455 | /* |
456 | * Process an ioctl request. |
457 | */ |
458 | /* ARGSUSED */ |
459 | int |
460 | loioctl(struct ifnet *ifp, u_long cmd, void *data) |
461 | { |
462 | struct ifaddr *ifa; |
463 | struct ifreq *ifr = data; |
464 | int error = 0; |
465 | |
466 | switch (cmd) { |
467 | |
468 | case SIOCINITIFADDR: |
469 | ifp->if_flags |= IFF_UP; |
470 | ifa = (struct ifaddr *)data; |
471 | if (ifa != NULL) |
472 | ifa->ifa_rtrequest = loop_rtrequest; |
473 | /* |
474 | * Everything else is done at a higher level. |
475 | */ |
476 | break; |
477 | |
478 | case SIOCSIFMTU: |
479 | if ((unsigned)ifr->ifr_mtu > LOMTU_MAX) |
480 | error = EINVAL; |
481 | else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET){ |
482 | error = 0; |
483 | } |
484 | break; |
485 | |
486 | case SIOCADDMULTI: |
487 | case SIOCDELMULTI: |
488 | if (ifr == NULL) { |
489 | error = EAFNOSUPPORT; /* XXX */ |
490 | break; |
491 | } |
492 | switch (ifreq_getaddr(cmd, ifr)->sa_family) { |
493 | |
494 | #ifdef INET |
495 | case AF_INET: |
496 | break; |
497 | #endif |
498 | #ifdef INET6 |
499 | case AF_INET6: |
500 | break; |
501 | #endif |
502 | |
503 | default: |
504 | error = EAFNOSUPPORT; |
505 | break; |
506 | } |
507 | break; |
508 | |
509 | default: |
510 | error = ifioctl_common(ifp, cmd, data); |
511 | } |
512 | return (error); |
513 | } |
514 | |
515 | /* |
516 | * Module infrastructure |
517 | */ |
518 | #include "if_module.h" |
519 | |
520 | IF_MODULE(MODULE_CLASS_DRIVER, loop, "" ) |
521 | |