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