1 | /* |
2 | * Copyright (c) 1999-2018 Apple Inc. All rights reserved. |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
5 | * |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License |
8 | * Version 2.0 (the 'License'). You may not use this file except in |
9 | * compliance with the License. The rights granted to you under the License |
10 | * may not be used to create, or enable the creation or redistribution of, |
11 | * unlawful or unlicensed copies of an Apple operating system, or to |
12 | * circumvent, violate, or enable the circumvention or violation of, any |
13 | * terms of an Apple operating system software license agreement. |
14 | * |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. |
17 | * |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and |
24 | * limitations under the License. |
25 | * |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ |
28 | |
29 | #include <kern/locks.h> |
30 | #include <kern/zalloc.h> |
31 | |
32 | #include <sys/types.h> |
33 | #include <sys/kernel_types.h> |
34 | #include <sys/kauth.h> |
35 | #include <sys/socket.h> |
36 | #include <sys/socketvar.h> |
37 | #include <sys/sockio.h> |
38 | #include <sys/sysctl.h> |
39 | #include <sys/proc.h> |
40 | |
41 | #include <net/if.h> |
42 | #include <net/if_var.h> |
43 | #include <net/if_types.h> |
44 | #include <net/bpf.h> |
45 | #include <net/net_osdep.h> |
46 | #include <net/pktap.h> |
47 | #include <net/iptap.h> |
48 | |
49 | #include <netinet/in_pcb.h> |
50 | #include <netinet/tcp.h> |
51 | #include <netinet/tcp_var.h> |
52 | #define _IP_VHL |
53 | #include <netinet/ip.h> |
54 | #include <netinet/ip_var.h> |
55 | #include <netinet/udp.h> |
56 | #include <netinet/udp_var.h> |
57 | |
58 | #include <netinet/ip6.h> |
59 | #include <netinet6/in6_pcb.h> |
60 | |
61 | #include <netinet/kpi_ipfilter.h> |
62 | |
63 | #include <libkern/OSAtomic.h> |
64 | |
65 | #include <kern/debug.h> |
66 | |
67 | #include <sys/mcache.h> |
68 | |
69 | #include <string.h> |
70 | |
71 | struct iptap_softc { |
72 | LIST_ENTRY(iptap_softc) iptap_link; |
73 | uint32_t iptap_unit; |
74 | uint32_t iptap_dlt_raw_count; |
75 | uint32_t iptap_dlt_pkttap_count; |
76 | struct ifnet *iptap_ifp; |
77 | }; |
78 | |
79 | static LIST_HEAD(iptap_list, iptap_softc) iptap_list = LIST_HEAD_INITIALIZER(iptap_list); |
80 | |
81 | static void iptap_lock_shared(void); |
82 | static void iptap_lock_exclusive(void); |
83 | static void iptap_lock_done(void); |
84 | static void iptap_alloc_lock(void); |
85 | |
86 | decl_lck_rw_data(static, iptap_lck_rw); |
87 | static lck_grp_t *iptap_grp; |
88 | |
89 | errno_t iptap_if_output(ifnet_t, mbuf_t); |
90 | errno_t iptap_demux(ifnet_t , mbuf_t, char *, protocol_family_t *); |
91 | errno_t iptap_add_proto(ifnet_t, protocol_family_t, const struct ifnet_demux_desc *, |
92 | u_int32_t); |
93 | errno_t iptap_del_proto(ifnet_t, protocol_family_t); |
94 | errno_t iptap_getdrvspec(ifnet_t , struct ifdrv64 *); |
95 | errno_t iptap_ioctl(ifnet_t, unsigned long, void *); |
96 | void iptap_detach(ifnet_t); |
97 | errno_t iptap_tap_callback(ifnet_t , u_int32_t , bpf_tap_mode ); |
98 | int iptap_clone_create(struct if_clone *, u_int32_t, void *); |
99 | int iptap_clone_destroy(struct ifnet *); |
100 | |
101 | static int iptap_ipf_register(void); |
102 | static int iptap_ipf_unregister(void); |
103 | static errno_t iptap_ipf_input(void *, mbuf_t *, int, u_int8_t); |
104 | static errno_t iptap_ipf_output(void *, mbuf_t *, ipf_pktopts_t); |
105 | static void iptap_ipf_detach(void *); |
106 | |
107 | static ipfilter_t iptap_ipf4, iptap_ipf6; |
108 | |
109 | void iptap_bpf_tap(struct mbuf *m, u_int32_t proto, int outgoing); |
110 | |
111 | #define IPTAP_MAXUNIT IF_MAXUNIT |
112 | #define IPTAP_ZONE_MAX_ELEM MIN(IFNETS_MAX, IPTAP_MAXUNIT) |
113 | |
114 | static struct if_clone iptap_cloner = |
115 | IF_CLONE_INITIALIZER(IPTAP_IFNAME, |
116 | iptap_clone_create, |
117 | iptap_clone_destroy, |
118 | 0, |
119 | IPTAP_MAXUNIT, |
120 | IPTAP_ZONE_MAX_ELEM, |
121 | sizeof(struct iptap_softc)); |
122 | |
123 | SYSCTL_DECL(_net_link); |
124 | SYSCTL_NODE(_net_link, OID_AUTO, iptap, CTLFLAG_RW|CTLFLAG_LOCKED, 0, |
125 | "iptap virtual interface" ); |
126 | |
127 | static int iptap_total_tap_count = 0; |
128 | SYSCTL_INT(_net_link_iptap, OID_AUTO, total_tap_count, CTLFLAG_RD | CTLFLAG_LOCKED, |
129 | &iptap_total_tap_count, 0, "" ); |
130 | |
131 | static int iptap_log = 0; |
132 | SYSCTL_INT(_net_link_iptap, OID_AUTO, log, CTLFLAG_RW | CTLFLAG_LOCKED, |
133 | &iptap_log, 0, "" ); |
134 | |
135 | #define IPTAP_LOG(fmt, ...) \ |
136 | do { \ |
137 | if ((iptap_log)) \ |
138 | printf("%s:%d " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ |
139 | } while(false) |
140 | |
141 | __private_extern__ void |
142 | iptap_init(void) |
143 | { |
144 | errno_t error; |
145 | |
146 | iptap_alloc_lock(); |
147 | |
148 | error = if_clone_attach(&iptap_cloner); |
149 | if (error != 0) |
150 | panic("%s: if_clone_attach() failed, error %d\n" , __func__, error); |
151 | } |
152 | |
153 | static void |
154 | iptap_alloc_lock(void) |
155 | { |
156 | lck_grp_attr_t *grp_attr; |
157 | lck_attr_t *attr; |
158 | |
159 | grp_attr = lck_grp_attr_alloc_init(); |
160 | lck_grp_attr_setdefault(grp_attr); |
161 | iptap_grp = lck_grp_alloc_init(IPTAP_IFNAME, grp_attr); |
162 | lck_grp_attr_free(grp_attr); |
163 | |
164 | attr = lck_attr_alloc_init(); |
165 | lck_attr_setdefault(attr); |
166 | |
167 | lck_rw_init(&iptap_lck_rw, iptap_grp, attr); |
168 | lck_attr_free(attr); |
169 | } |
170 | |
171 | static void |
172 | iptap_lock_shared(void) |
173 | { |
174 | lck_rw_lock_shared(&iptap_lck_rw); |
175 | } |
176 | |
177 | static void |
178 | iptap_lock_exclusive(void) |
179 | { |
180 | lck_rw_lock_exclusive(&iptap_lck_rw); |
181 | } |
182 | |
183 | static void |
184 | iptap_lock_done(void) |
185 | { |
186 | lck_rw_done(&iptap_lck_rw); |
187 | } |
188 | |
189 | __private_extern__ int |
190 | iptap_clone_create(struct if_clone *ifc, u_int32_t unit, void *params) |
191 | { |
192 | #pragma unused(params) |
193 | |
194 | int error = 0; |
195 | struct iptap_softc *iptap = NULL; |
196 | struct ifnet_init_eparams if_init; |
197 | |
198 | iptap = if_clone_softc_allocate(&iptap_cloner); |
199 | if (iptap == NULL) { |
200 | printf("%s: _MALLOC failed\n" , __func__); |
201 | error = ENOMEM; |
202 | goto done; |
203 | } |
204 | iptap->iptap_unit = unit; |
205 | |
206 | /* |
207 | * We do not use a set_bpf_tap() function as we rather rely on the more |
208 | * accurate callback passed to bpf_attach() |
209 | */ |
210 | bzero(&if_init, sizeof(if_init)); |
211 | if_init.ver = IFNET_INIT_CURRENT_VERSION; |
212 | if_init.len = sizeof (if_init); |
213 | if_init.flags = IFNET_INIT_LEGACY; |
214 | if_init.name = ifc->ifc_name; |
215 | if_init.unit = unit; |
216 | if_init.type = IFT_OTHER; |
217 | if_init.family = IFNET_FAMILY_LOOPBACK; |
218 | if_init.output = iptap_if_output; |
219 | if_init.demux = iptap_demux; |
220 | if_init.add_proto = iptap_add_proto; |
221 | if_init.del_proto = iptap_del_proto; |
222 | if_init.softc = iptap; |
223 | if_init.ioctl = iptap_ioctl; |
224 | if_init.detach = iptap_detach; |
225 | |
226 | error = ifnet_allocate_extended(&if_init, &iptap->iptap_ifp); |
227 | if (error != 0) { |
228 | printf("%s: ifnet_allocate failed, error %d\n" , __func__, error); |
229 | goto done; |
230 | } |
231 | |
232 | ifnet_set_flags(iptap->iptap_ifp, IFF_UP, IFF_UP); |
233 | |
234 | error = ifnet_attach(iptap->iptap_ifp, NULL); |
235 | if (error != 0) { |
236 | printf("%s: ifnet_attach failed - error %d\n" , __func__, error); |
237 | ifnet_release(iptap->iptap_ifp); |
238 | goto done; |
239 | } |
240 | |
241 | /* |
242 | * Attach by default as DLT_PKTAP for packet metadata |
243 | * Provide DLT_RAW for legacy |
244 | */ |
245 | bpf_attach(iptap->iptap_ifp, DLT_PKTAP, sizeof(struct pktap_header), NULL, |
246 | iptap_tap_callback); |
247 | bpf_attach(iptap->iptap_ifp, DLT_RAW, 0, NULL, |
248 | iptap_tap_callback); |
249 | |
250 | /* Take a reference and add to the global list */ |
251 | ifnet_reference(iptap->iptap_ifp); |
252 | |
253 | iptap_lock_exclusive(); |
254 | |
255 | if (LIST_EMPTY(&iptap_list)) |
256 | iptap_ipf_register(); |
257 | LIST_INSERT_HEAD(&iptap_list, iptap, iptap_link); |
258 | iptap_lock_done(); |
259 | done: |
260 | if (error != 0) { |
261 | if (iptap != NULL) |
262 | if_clone_softc_deallocate(&iptap_cloner, iptap); |
263 | } |
264 | return (error); |
265 | } |
266 | |
267 | __private_extern__ int |
268 | iptap_clone_destroy(struct ifnet *ifp) |
269 | { |
270 | int error = 0; |
271 | |
272 | (void) ifnet_detach(ifp); |
273 | |
274 | return (error); |
275 | } |
276 | |
277 | /* |
278 | * This function is called whenever a DLT is set on the interface: |
279 | * - When interface is attached to a BPF device via BIOCSETIF for the default DLT |
280 | * - Whenever a new DLT is selected via BIOCSDLT |
281 | * - When the interface is detached from a BPF device (direction is zero) |
282 | */ |
283 | __private_extern__ errno_t |
284 | iptap_tap_callback(ifnet_t ifp, u_int32_t dlt, bpf_tap_mode direction) |
285 | { |
286 | struct iptap_softc *iptap; |
287 | |
288 | iptap = ifp->if_softc; |
289 | if (iptap == NULL) { |
290 | printf("%s: if_softc is NULL for ifp %s\n" , __func__, |
291 | ifp->if_xname); |
292 | goto done; |
293 | } |
294 | switch (dlt) { |
295 | case DLT_RAW: |
296 | if (direction == 0) { |
297 | if (iptap->iptap_dlt_raw_count > 0) { |
298 | iptap->iptap_dlt_raw_count--; |
299 | OSAddAtomic(-1, &iptap_total_tap_count); |
300 | |
301 | } |
302 | } else { |
303 | iptap->iptap_dlt_raw_count++; |
304 | OSAddAtomic(1, &iptap_total_tap_count); |
305 | } |
306 | break; |
307 | case DLT_PKTAP: |
308 | if (direction == 0) { |
309 | if (iptap->iptap_dlt_pkttap_count > 0) { |
310 | iptap->iptap_dlt_pkttap_count--; |
311 | OSAddAtomic(-1, &iptap_total_tap_count); |
312 | } |
313 | } else { |
314 | iptap->iptap_dlt_pkttap_count++; |
315 | OSAddAtomic(1, &iptap_total_tap_count); |
316 | } |
317 | break; |
318 | } |
319 | done: |
320 | /* |
321 | * Attachements count must be positive and we're in trouble |
322 | * if we have more that 2**31 attachements |
323 | */ |
324 | VERIFY(iptap_total_tap_count >= 0); |
325 | |
326 | return (0); |
327 | } |
328 | |
329 | __private_extern__ errno_t |
330 | iptap_if_output(ifnet_t ifp, mbuf_t m) |
331 | { |
332 | #pragma unused(ifp) |
333 | |
334 | mbuf_freem(m); |
335 | return (ENOTSUP); |
336 | } |
337 | |
338 | __private_extern__ errno_t |
339 | iptap_demux(ifnet_t ifp, mbuf_t m, char *, |
340 | protocol_family_t *ppf) |
341 | { |
342 | #pragma unused(ifp) |
343 | #pragma unused(m) |
344 | #pragma unused(header) |
345 | #pragma unused(ppf) |
346 | |
347 | return (ENOTSUP); |
348 | } |
349 | |
350 | __private_extern__ errno_t |
351 | iptap_add_proto(ifnet_t ifp, protocol_family_t pf, |
352 | const struct ifnet_demux_desc *dmx, u_int32_t cnt) |
353 | { |
354 | #pragma unused(ifp) |
355 | #pragma unused(pf) |
356 | #pragma unused(dmx) |
357 | #pragma unused(cnt) |
358 | |
359 | return (0); |
360 | } |
361 | |
362 | __private_extern__ errno_t |
363 | iptap_del_proto(ifnet_t ifp, protocol_family_t pf) |
364 | { |
365 | #pragma unused(ifp) |
366 | #pragma unused(pf) |
367 | |
368 | return (0); |
369 | } |
370 | |
371 | __private_extern__ errno_t |
372 | iptap_getdrvspec(ifnet_t ifp, struct ifdrv64 *ifd) |
373 | { |
374 | errno_t error = 0; |
375 | struct iptap_softc *iptap; |
376 | |
377 | iptap = ifp->if_softc; |
378 | if (iptap == NULL) { |
379 | error = ENOENT; |
380 | printf("%s: iptap NULL - error %d\n" , __func__, error); |
381 | goto done; |
382 | } |
383 | |
384 | switch (ifd->ifd_cmd) { |
385 | case PKTP_CMD_TAP_COUNT: { |
386 | uint32_t tap_count = iptap->iptap_dlt_raw_count + iptap->iptap_dlt_pkttap_count; |
387 | |
388 | if (ifd->ifd_len < sizeof(tap_count)) { |
389 | printf("%s: PKTP_CMD_TAP_COUNT ifd_len %llu too small - error %d\n" , |
390 | __func__, ifd->ifd_len, error); |
391 | error = EINVAL; |
392 | break; |
393 | } |
394 | error = copyout(&tap_count, ifd->ifd_data, sizeof(tap_count)); |
395 | if (error) { |
396 | printf("%s: PKTP_CMD_TAP_COUNT copyout - error %d\n" , __func__, error); |
397 | goto done; |
398 | } |
399 | break; |
400 | } |
401 | default: |
402 | error = EINVAL; |
403 | break; |
404 | } |
405 | |
406 | done: |
407 | return (error); |
408 | } |
409 | |
410 | __private_extern__ errno_t |
411 | iptap_ioctl(ifnet_t ifp, unsigned long cmd, void *data) |
412 | { |
413 | errno_t error = 0; |
414 | |
415 | if ((cmd & IOC_IN)) { |
416 | error = kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER); |
417 | if (error) { |
418 | goto done; |
419 | } |
420 | } |
421 | |
422 | switch (cmd) { |
423 | case SIOCGDRVSPEC32: { |
424 | struct ifdrv64 ifd; |
425 | struct ifdrv32 *ifd32 = (struct ifdrv32 *)data; |
426 | |
427 | memcpy(ifd.ifd_name, ifd32->ifd_name, sizeof(ifd.ifd_name)); |
428 | ifd.ifd_cmd = ifd32->ifd_cmd; |
429 | ifd.ifd_len = ifd32->ifd_len; |
430 | ifd.ifd_data = ifd32->ifd_data; |
431 | |
432 | error = iptap_getdrvspec(ifp, &ifd); |
433 | |
434 | break; |
435 | } |
436 | case SIOCGDRVSPEC64: { |
437 | struct ifdrv64 *ifd64 = (struct ifdrv64 *)data; |
438 | |
439 | error = iptap_getdrvspec(ifp, ifd64); |
440 | |
441 | break; |
442 | } |
443 | default: |
444 | error = ENOTSUP; |
445 | break; |
446 | } |
447 | done: |
448 | return (error); |
449 | } |
450 | |
451 | __private_extern__ void |
452 | iptap_detach(ifnet_t ifp) |
453 | { |
454 | struct iptap_softc *iptap = NULL; |
455 | |
456 | iptap_lock_exclusive(); |
457 | |
458 | iptap = ifp->if_softc; |
459 | ifp->if_softc = NULL; |
460 | LIST_REMOVE(iptap, iptap_link); |
461 | |
462 | if (LIST_EMPTY(&iptap_list)) |
463 | iptap_ipf_unregister(); |
464 | |
465 | iptap_lock_done(); |
466 | |
467 | /* Drop reference as it's no more on the global list */ |
468 | ifnet_release(ifp); |
469 | if_clone_softc_deallocate(&iptap_cloner, iptap); |
470 | |
471 | /* This is for the reference taken by ifnet_attach() */ |
472 | (void) ifnet_release(ifp); |
473 | } |
474 | |
475 | static int |
476 | iptap_ipf_register(void) |
477 | { |
478 | struct ipf_filter iptap_ipfinit; |
479 | int err = 0; |
480 | |
481 | IPTAP_LOG("\n" ); |
482 | |
483 | bzero(&iptap_ipfinit, sizeof (iptap_ipfinit)); |
484 | iptap_ipfinit.name = IPTAP_IFNAME; |
485 | iptap_ipfinit.cookie = &iptap_ipf4; |
486 | iptap_ipfinit.ipf_input = iptap_ipf_input; |
487 | iptap_ipfinit.ipf_output = iptap_ipf_output; |
488 | iptap_ipfinit.ipf_detach = iptap_ipf_detach; |
489 | |
490 | err = ipf_addv4(&iptap_ipfinit, &iptap_ipf4); |
491 | if (err != 0) { |
492 | printf("%s: ipf_addv4 for %s0 failed - %d\n" , |
493 | __func__, IPTAP_IFNAME, err); |
494 | goto done; |
495 | } |
496 | |
497 | iptap_ipfinit.cookie = &iptap_ipf6; |
498 | err = ipf_addv6(&iptap_ipfinit, &iptap_ipf6); |
499 | if (err != 0) { |
500 | printf("%s: ipf_addv6 for %s0 failed - %d\n" , |
501 | __func__, IPTAP_IFNAME, err); |
502 | (void) ipf_remove(iptap_ipf4); |
503 | iptap_ipf4 = NULL; |
504 | goto done; |
505 | } |
506 | |
507 | done: |
508 | return (err); |
509 | } |
510 | |
511 | static int |
512 | iptap_ipf_unregister(void) |
513 | { |
514 | int err = 0; |
515 | |
516 | IPTAP_LOG("\n" ); |
517 | |
518 | if (iptap_ipf4 != NULL) { |
519 | err = ipf_remove(iptap_ipf4); |
520 | if (err != 0) { |
521 | printf("%s: ipf_remove (ipv4) for %s0 failed - %d\n" , |
522 | __func__, IPTAP_IFNAME, err); |
523 | goto done; |
524 | } |
525 | iptap_ipf4 = NULL; |
526 | } |
527 | |
528 | if (iptap_ipf6 != NULL) { |
529 | err = ipf_remove(iptap_ipf6); |
530 | if (err != 0) { |
531 | printf("%s: ipf_remove (ipv6) for %s0 failed - %d\n" , |
532 | __func__, IPTAP_IFNAME, err); |
533 | goto done; |
534 | } |
535 | iptap_ipf6 = NULL; |
536 | } |
537 | done: |
538 | return (err); |
539 | } |
540 | |
541 | static errno_t |
542 | iptap_ipf_input(void *arg, mbuf_t *mp, int off, u_int8_t proto) |
543 | { |
544 | #pragma unused(off) |
545 | #pragma unused(proto) |
546 | |
547 | if (arg == (void *)&iptap_ipf4) |
548 | iptap_bpf_tap(*mp, AF_INET, 0); |
549 | else if (arg == (void *)&iptap_ipf6) |
550 | iptap_bpf_tap(*mp, AF_INET6, 0); |
551 | else |
552 | IPTAP_LOG("%s:%d bad cookie 0x%llx &iptap_ipf4 0x%llx " |
553 | "&iptap_ipf6 0x%llx\n" , __func__, __LINE__, |
554 | (uint64_t)VM_KERNEL_ADDRPERM(arg), |
555 | (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf4), |
556 | (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf6)); |
557 | |
558 | return (0); |
559 | } |
560 | |
561 | static errno_t |
562 | iptap_ipf_output(void *arg, mbuf_t *mp, ipf_pktopts_t opt) |
563 | { |
564 | #pragma unused(opt) |
565 | |
566 | if (arg == (void *)&iptap_ipf4) |
567 | iptap_bpf_tap(*mp, AF_INET, 1); |
568 | else if (arg == (void *)&iptap_ipf6) |
569 | iptap_bpf_tap(*mp, AF_INET6, 1); |
570 | else |
571 | IPTAP_LOG("%s:%d bad cookie 0x%llx &iptap_ipf4 0x%llx " |
572 | "&iptap_ipf6 0x%llx\n" , __func__, __LINE__, |
573 | (uint64_t)VM_KERNEL_ADDRPERM(arg), |
574 | (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf4), |
575 | (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf6)); |
576 | |
577 | return (0); |
578 | } |
579 | |
580 | static void |
581 | iptap_ipf_detach(void *arg) |
582 | { |
583 | #pragma unused(arg) |
584 | } |
585 | |
586 | __private_extern__ void |
587 | iptap_bpf_tap(struct mbuf *m, u_int32_t proto, int outgoing) |
588 | { |
589 | struct iptap_softc *iptap; |
590 | void (*bpf_tap_func)(ifnet_t , u_int32_t , mbuf_t , void * , size_t ) = |
591 | outgoing ? bpf_tap_out : bpf_tap_in; |
592 | uint16_t src_scope_id = 0; |
593 | uint16_t dst_scope_id = 0; |
594 | |
595 | if (proto == AF_INET6) { |
596 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); |
597 | /* |
598 | * Clear the embedded scope ID |
599 | */ |
600 | if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) { |
601 | src_scope_id = ip6->ip6_src.s6_addr16[1]; |
602 | ip6->ip6_src.s6_addr16[1] = 0; |
603 | } |
604 | if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) { |
605 | dst_scope_id = ip6->ip6_dst.s6_addr16[1]; |
606 | ip6->ip6_dst.s6_addr16[1] = 0; |
607 | } |
608 | } |
609 | |
610 | iptap_lock_shared(); |
611 | |
612 | LIST_FOREACH(iptap, &iptap_list, iptap_link) { |
613 | if (iptap->iptap_dlt_raw_count > 0) { |
614 | bpf_tap_func(iptap->iptap_ifp, DLT_RAW, m, |
615 | NULL, 0); |
616 | } |
617 | if (iptap->iptap_dlt_pkttap_count > 0) { |
618 | struct { |
619 | struct pktap_header hdr; |
620 | u_int32_t proto; |
621 | } hdr_buffer; |
622 | struct pktap_header *hdr = &hdr_buffer.hdr; |
623 | size_t hdr_size = sizeof(hdr_buffer); |
624 | struct ifnet *ifp = outgoing ? NULL : m->m_pkthdr.rcvif; |
625 | |
626 | /* Verify the structure is packed */ |
627 | _CASSERT(sizeof(hdr_buffer) == sizeof(struct pktap_header) + sizeof(u_int32_t)); |
628 | |
629 | bzero(hdr, sizeof(hdr_buffer)); |
630 | hdr->pth_length = sizeof(struct pktap_header); |
631 | hdr->pth_type_next = PTH_TYPE_PACKET; |
632 | hdr->pth_dlt = DLT_NULL; |
633 | if (ifp != NULL) |
634 | snprintf(hdr->pth_ifname, sizeof(hdr->pth_ifname), "%s" , |
635 | ifp->if_xname); |
636 | hdr_buffer.proto = proto; |
637 | hdr->pth_flags = outgoing ? PTH_FLAG_DIR_OUT : PTH_FLAG_DIR_IN; |
638 | hdr->pth_protocol_family = proto; |
639 | hdr->pth_frame_pre_length = 0; |
640 | hdr->pth_frame_post_length = 0; |
641 | hdr->pth_iftype = ifp != NULL ? ifp->if_type : 0; |
642 | hdr->pth_ifunit = ifp != NULL ? ifp->if_unit : 0; |
643 | |
644 | pktap_fill_proc_info(hdr, proto, m, 0, outgoing, ifp); |
645 | |
646 | hdr->pth_svc = so_svc2tc(m->m_pkthdr.pkt_svc); |
647 | |
648 | bpf_tap_func(iptap->iptap_ifp, DLT_PKTAP, m, hdr, hdr_size); |
649 | } |
650 | } |
651 | |
652 | iptap_lock_done(); |
653 | |
654 | if (proto == AF_INET6) { |
655 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); |
656 | |
657 | /* |
658 | * Restore the embedded scope ID |
659 | */ |
660 | if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) { |
661 | ip6->ip6_src.s6_addr16[1] = src_scope_id; |
662 | } |
663 | if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) { |
664 | ip6->ip6_dst.s6_addr16[1] = dst_scope_id; |
665 | } |
666 | } |
667 | } |
668 | |