1/*
2 * Copyright (c) 2012-2021 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
48#include <netinet/in_pcb.h>
49#include <netinet/tcp.h>
50#include <netinet/tcp_var.h>
51#define _IP_VHL
52#include <netinet/ip.h>
53#include <netinet/ip_var.h>
54#include <netinet/udp.h>
55#include <netinet/udp_var.h>
56
57#include <netinet/ip6.h>
58#include <netinet6/in6_pcb.h>
59
60#include <libkern/OSAtomic.h>
61
62#include <kern/debug.h>
63
64#include <sys/mcache.h>
65
66#include <string.h>
67
68extern struct inpcbinfo ripcbinfo;
69
70struct pktap_softc {
71 LIST_ENTRY(pktap_softc) pktp_link;
72 uint32_t pktp_unit;
73 uint32_t pktp_dlt_raw_count;
74 uint32_t pktp_dlt_pkttap_count;
75 struct ifnet *pktp_ifp;
76 struct pktap_filter pktp_filters[PKTAP_MAX_FILTERS];
77};
78
79#ifndef PKTAP_DEBUG
80#define PKTAP_DEBUG 0
81#endif /* PKTAP_DEBUG */
82
83#define PKTAP_FILTER_OK 0 /* Packet passes filter checks */
84#define PKTAP_FILTER_SKIP 1 /* Do not tap this packet */
85
86static int pktap_inited = 0;
87
88SYSCTL_DECL(_net_link);
89SYSCTL_NODE(_net_link, IFT_PKTAP, pktap,
90 CTLFLAG_RW | CTLFLAG_LOCKED, 0, "pktap virtual interface");
91
92uint32_t pktap_total_tap_count = 0;
93SYSCTL_UINT(_net_link_pktap, OID_AUTO, total_tap_count,
94 CTLFLAG_RD | CTLFLAG_LOCKED, &pktap_total_tap_count, 0, "");
95
96static u_int64_t pktap_count_unknown_if_type = 0;
97SYSCTL_QUAD(_net_link_pktap, OID_AUTO, count_unknown_if_type,
98 CTLFLAG_RD | CTLFLAG_LOCKED, &pktap_count_unknown_if_type, "");
99
100static int pktap_log = 0;
101SYSCTL_INT(_net_link_pktap, OID_AUTO, log,
102 CTLFLAG_RW | CTLFLAG_LOCKED, &pktap_log, 0, "");
103
104#define PKTAP_LOG(mask, fmt, ...) \
105do { \
106 if ((pktap_log & mask)) \
107 printf("%s:%d " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
108} while (false)
109
110#define PKTP_LOG_FUNC 0x01
111#define PKTP_LOG_FILTER 0x02
112#define PKTP_LOG_INPUT 0x04
113#define PKTP_LOG_OUTPUT 0x08
114#define PKTP_LOG_ERROR 0x10
115#define PKTP_LOG_NOPCB 0x20
116
117/*
118 * pktap_lck_rw protects the global list of pktap interfaces
119 */
120static LCK_GRP_DECLARE(pktap_lck_grp, "pktap");
121#if PKTAP_DEBUG
122static LCK_ATTR_DECLARE(pktap_lck_attr, LCK_ATTR_DEBUG, 0);
123#else
124static LCK_ATTR_DECLARE(pktap_lck_attr, 0, 0);
125#endif
126static LCK_RW_DECLARE_ATTR(pktap_lck_rw, &pktap_lck_grp, &pktap_lck_attr);
127
128
129static LIST_HEAD(pktap_list, pktap_softc) pktap_list =
130 LIST_HEAD_INITIALIZER(pktap_list);
131
132int pktap_clone_create(struct if_clone *, u_int32_t, void *);
133int pktap_clone_destroy(struct ifnet *);
134
135#define PKTAP_MAXUNIT IF_MAXUNIT
136#define PKTAP_ZONE_MAX_ELEM MIN(IFNETS_MAX, PKTAP_MAXUNIT)
137
138static struct if_clone pktap_cloner =
139 IF_CLONE_INITIALIZER(PKTAP_IFNAME,
140 pktap_clone_create,
141 pktap_clone_destroy,
142 0,
143 PKTAP_MAXUNIT);
144
145errno_t pktap_if_output(ifnet_t, mbuf_t);
146errno_t pktap_demux(ifnet_t, mbuf_t, char *, protocol_family_t *);
147errno_t pktap_add_proto(ifnet_t, protocol_family_t,
148 const struct ifnet_demux_desc *, u_int32_t);
149errno_t pktap_del_proto(ifnet_t, protocol_family_t);
150errno_t pktap_getdrvspec(ifnet_t, struct ifdrv64 *);
151errno_t pktap_setdrvspec(ifnet_t, struct ifdrv64 *);
152errno_t pktap_ioctl(ifnet_t, unsigned long, void *);
153void pktap_detach(ifnet_t);
154int pktap_filter_evaluate(struct pktap_softc *, struct ifnet *);
155void pktap_bpf_tap(struct ifnet *, protocol_family_t, struct mbuf *,
156 u_int32_t, u_int32_t, int);
157errno_t pktap_tap_callback(ifnet_t, u_int32_t, bpf_tap_mode);
158
159static void
160pktap_hexdump(int mask, void *addr, size_t len)
161{
162 unsigned char *buf = addr;
163 size_t i;
164
165 if (!(pktap_log & mask)) {
166 return;
167 }
168
169 for (i = 0; i < len; i++) {
170 unsigned char h = (buf[i] & 0xf0) >> 4;
171 unsigned char l = buf[i] & 0x0f;
172
173 if (i != 0) {
174 if (i % 32 == 0) {
175 printf("\n");
176 } else if (i % 4 == 0) {
177 printf(" ");
178 }
179 }
180 printf("%c%c",
181 h < 10 ? h + '0' : h - 10 + 'a',
182 l < 10 ? l + '0' : l - 10 + 'a');
183 }
184 if (i % 32 != 0) {
185 printf("\n");
186 }
187}
188
189#define _CASSERT_OFFFSETOF_FIELD(s1, s2, f) \
190 _CASSERT(offsetof(struct s1, f) == offsetof(struct s2, f))
191
192__private_extern__ void
193pktap_init(void)
194{
195 int error = 0;
196
197 _CASSERT_OFFFSETOF_FIELD(pktap_header, pktap_v2_hdr, pth_flags);
198
199 /* Make sure we're called only once */
200 VERIFY(pktap_inited == 0);
201
202 pktap_inited = 1;
203
204 LIST_INIT(&pktap_list);
205
206 error = if_clone_attach(&pktap_cloner);
207 if (error != 0) {
208 panic("%s: if_clone_attach() failed, error %d",
209 __func__, error);
210 }
211}
212
213__private_extern__ int
214pktap_clone_create(struct if_clone *ifc, u_int32_t unit, __unused void *params)
215{
216 int error = 0;
217 struct pktap_softc *pktap = NULL;
218 struct ifnet_init_eparams if_init;
219
220 PKTAP_LOG(PKTP_LOG_FUNC, "unit %u\n", unit);
221
222 pktap = kalloc_type(struct pktap_softc, Z_WAITOK_ZERO_NOFAIL);
223 pktap->pktp_unit = unit;
224
225 /*
226 * By default accept packet from physical interfaces
227 */
228 pktap->pktp_filters[0].filter_op = PKTAP_FILTER_OP_PASS;
229 pktap->pktp_filters[0].filter_param = PKTAP_FILTER_PARAM_IF_TYPE;
230 pktap->pktp_filters[0].filter_param_if_type = IFT_ETHER;
231
232#if !XNU_TARGET_OS_OSX
233 pktap->pktp_filters[1].filter_op = PKTAP_FILTER_OP_PASS;
234 pktap->pktp_filters[1].filter_param = PKTAP_FILTER_PARAM_IF_TYPE;
235 pktap->pktp_filters[1].filter_param_if_type = IFT_CELLULAR;
236#else /* XNU_TARGET_OS_OSX */
237 pktap->pktp_filters[1].filter_op = PKTAP_FILTER_OP_PASS;
238 pktap->pktp_filters[1].filter_param = PKTAP_FILTER_PARAM_IF_TYPE;
239 pktap->pktp_filters[1].filter_param_if_type = IFT_IEEE1394;
240#endif /* XNU_TARGET_OS_OSX */
241
242 pktap->pktp_filters[2].filter_op = PKTAP_FILTER_OP_PASS;
243 pktap->pktp_filters[2].filter_param = PKTAP_FILTER_PARAM_IF_TYPE;
244 pktap->pktp_filters[2].filter_param_if_type = IFT_OTHER;
245
246 /*
247 * We do not use a set_bpf_tap() function as we rather rely on the more
248 * accurate callback passed to bpf_attach()
249 */
250 bzero(s: &if_init, n: sizeof(if_init));
251 if_init.ver = IFNET_INIT_CURRENT_VERSION;
252 if_init.len = sizeof(if_init);
253 if_init.flags = IFNET_INIT_LEGACY;
254 if_init.name = ifc->ifc_name;
255 if_init.unit = unit;
256 if_init.type = IFT_PKTAP;
257 if_init.family = IFNET_FAMILY_LOOPBACK;
258 if_init.output = pktap_if_output;
259 if_init.demux = pktap_demux;
260 if_init.add_proto = pktap_add_proto;
261 if_init.del_proto = pktap_del_proto;
262 if_init.softc = pktap;
263 if_init.ioctl = pktap_ioctl;
264 if_init.detach = pktap_detach;
265
266 error = ifnet_allocate_extended(init: &if_init, interface: &pktap->pktp_ifp);
267 if (error != 0) {
268 printf("%s: ifnet_allocate failed, error %d\n",
269 __func__, error);
270 goto done;
271 }
272
273 ifnet_set_flags(interface: pktap->pktp_ifp, IFF_UP, IFF_UP);
274
275 error = ifnet_attach(interface: pktap->pktp_ifp, NULL);
276 if (error != 0) {
277 printf("%s: ifnet_attach failed - error %d\n", __func__, error);
278 ifnet_release(interface: pktap->pktp_ifp);
279 goto done;
280 }
281
282 /* Attach DLT_PKTAP as the default DLT */
283 bpf_attach(interface: pktap->pktp_ifp, DLT_PKTAP, header_length: sizeof(struct pktap_header),
284 NULL, tap: pktap_tap_callback);
285 bpf_attach(interface: pktap->pktp_ifp, DLT_RAW, header_length: 0, NULL, tap: pktap_tap_callback);
286
287 /* Take a reference and add to the global list */
288 ifnet_reference(interface: pktap->pktp_ifp);
289 lck_rw_lock_exclusive(lck: &pktap_lck_rw);
290 LIST_INSERT_HEAD(&pktap_list, pktap, pktp_link);
291 lck_rw_done(lck: &pktap_lck_rw);
292done:
293 if (error != 0 && pktap != NULL) {
294 kfree_type(struct pktap_softc, pktap);
295 }
296 return error;
297}
298
299__private_extern__ int
300pktap_clone_destroy(struct ifnet *ifp)
301{
302 int error = 0;
303
304 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
305
306 (void) ifnet_detach(interface: ifp);
307
308 return error;
309}
310
311/*
312 * This function is called whenever a DLT is set on the interface:
313 * - When interface is attached to a BPF device via BIOCSETIF for the
314 * default DLT
315 * - Whenever a new DLT is selected via BIOCSDLT
316 * - When the interface is detached from a BPF device (direction is zero)
317 */
318__private_extern__ errno_t
319pktap_tap_callback(ifnet_t ifp, u_int32_t dlt, bpf_tap_mode direction)
320{
321 struct pktap_softc *pktap;
322
323 pktap = ifp->if_softc;
324 if (pktap == NULL) {
325 printf("%s: if_softc is NULL for ifp %s\n", __func__,
326 ifp->if_xname);
327 goto done;
328 }
329 switch (dlt) {
330 case DLT_RAW:
331 if (direction == 0) {
332 if (pktap->pktp_dlt_raw_count > 0) {
333 pktap->pktp_dlt_raw_count--;
334 OSAddAtomic(-1, &pktap_total_tap_count);
335 }
336 } else {
337 pktap->pktp_dlt_raw_count++;
338 OSAddAtomic(1, &pktap_total_tap_count);
339 }
340 break;
341 case DLT_PKTAP:
342 if (direction == 0) {
343 if (pktap->pktp_dlt_pkttap_count > 0) {
344 pktap->pktp_dlt_pkttap_count--;
345 OSAddAtomic(-1, &pktap_total_tap_count);
346 }
347 } else {
348 pktap->pktp_dlt_pkttap_count++;
349 OSAddAtomic(1, &pktap_total_tap_count);
350 }
351 break;
352 }
353done:
354 /*
355 * Attachements count must be positive and we're in trouble
356 * if we have more that 2**31 attachements
357 */
358 VERIFY(pktap_total_tap_count >= 0);
359
360 return 0;
361}
362
363__private_extern__ errno_t
364pktap_if_output(ifnet_t ifp, mbuf_t m)
365{
366 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
367 mbuf_freem(mbuf: m);
368 return ENOTSUP;
369}
370
371__private_extern__ errno_t
372pktap_demux(ifnet_t ifp, __unused mbuf_t m, __unused char *header,
373 __unused protocol_family_t *ppf)
374{
375 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
376 return ENOTSUP;
377}
378
379__private_extern__ errno_t
380pktap_add_proto(__unused ifnet_t ifp, protocol_family_t pf,
381 __unused const struct ifnet_demux_desc *dmx, __unused u_int32_t cnt)
382{
383 PKTAP_LOG(PKTP_LOG_FUNC, "%s pf %u\n", ifp->if_xname, pf);
384 return 0;
385}
386
387__private_extern__ errno_t
388pktap_del_proto(__unused ifnet_t ifp, __unused protocol_family_t pf)
389{
390 PKTAP_LOG(PKTP_LOG_FUNC, "%s pf %u\n", ifp->if_xname, pf);
391 return 0;
392}
393
394__private_extern__ errno_t
395pktap_getdrvspec(ifnet_t ifp, struct ifdrv64 *ifd)
396{
397 errno_t error = 0;
398 struct pktap_softc *pktap;
399 int i;
400
401 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
402
403 pktap = ifp->if_softc;
404 if (pktap == NULL) {
405 error = ENOENT;
406 printf("%s: pktap NULL - error %d\n", __func__, error);
407 goto done;
408 }
409
410 switch (ifd->ifd_cmd) {
411 case PKTP_CMD_FILTER_GET: {
412 struct x_pktap_filter x_filters[PKTAP_MAX_FILTERS];
413
414 bzero(s: &x_filters, n: sizeof(x_filters));
415
416 if (ifd->ifd_len < PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter)) {
417 printf("%s: PKTP_CMD_FILTER_GET ifd_len %llu too small - error %d\n",
418 __func__, ifd->ifd_len, error);
419 error = EINVAL;
420 break;
421 }
422 for (i = 0; i < PKTAP_MAX_FILTERS; i++) {
423 struct pktap_filter *pktap_filter = pktap->pktp_filters + i;
424 struct x_pktap_filter *x_filter = x_filters + i;
425
426 x_filter->filter_op = pktap_filter->filter_op;
427 x_filter->filter_param = pktap_filter->filter_param;
428
429 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) {
430 x_filter->filter_param_if_type = pktap_filter->filter_param_if_type;
431 } else if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) {
432 strlcpy(dst: x_filter->filter_param_if_name,
433 src: pktap_filter->filter_param_if_name,
434 n: sizeof(x_filter->filter_param_if_name));
435 }
436 }
437 error = copyout(x_filters, CAST_USER_ADDR_T(ifd->ifd_data),
438 PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter));
439 if (error) {
440 printf("%s: PKTP_CMD_FILTER_GET copyout - error %d\n", __func__, error);
441 goto done;
442 }
443 break;
444 }
445 case PKTP_CMD_TAP_COUNT: {
446 uint32_t tap_count = pktap->pktp_dlt_raw_count + pktap->pktp_dlt_pkttap_count;
447
448 if (ifd->ifd_len < sizeof(tap_count)) {
449 printf("%s: PKTP_CMD_TAP_COUNT ifd_len %llu too small - error %d\n",
450 __func__, ifd->ifd_len, error);
451 error = EINVAL;
452 break;
453 }
454 error = copyout(&tap_count, CAST_USER_ADDR_T(ifd->ifd_data), sizeof(tap_count));
455 if (error) {
456 printf("%s: PKTP_CMD_TAP_COUNT copyout - error %d\n", __func__, error);
457 goto done;
458 }
459 break;
460 }
461 default:
462 error = EINVAL;
463 break;
464 }
465
466done:
467 return error;
468}
469
470__private_extern__ errno_t
471pktap_setdrvspec(ifnet_t ifp, struct ifdrv64 *ifd)
472{
473 errno_t error = 0;
474 struct pktap_softc *pktap;
475
476 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
477
478 pktap = ifp->if_softc;
479 if (pktap == NULL) {
480 error = ENOENT;
481 printf("%s: pktap NULL - error %d\n", __func__, error);
482 goto done;
483 }
484
485 switch (ifd->ifd_cmd) {
486 case PKTP_CMD_FILTER_SET: {
487 struct x_pktap_filter user_filters[PKTAP_MAX_FILTERS];
488 int i;
489 int got_op_none = 0;
490
491 if (ifd->ifd_len != PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter)) {
492 printf("%s: PKTP_CMD_FILTER_SET bad ifd_len %llu - error %d\n",
493 __func__, ifd->ifd_len, error);
494 error = EINVAL;
495 break;
496 }
497 error = copyin(CAST_USER_ADDR_T(ifd->ifd_data), &user_filters, (size_t)ifd->ifd_len);
498 if (error) {
499 printf("%s: copyin - error %d\n", __func__, error);
500 goto done;
501 }
502 /*
503 * Validate user provided parameters
504 */
505 for (i = 0; i < PKTAP_MAX_FILTERS; i++) {
506 struct x_pktap_filter *x_filter = user_filters + i;
507
508 switch (x_filter->filter_op) {
509 case PKTAP_FILTER_OP_NONE:
510 /* Following entries must be PKTAP_FILTER_OP_NONE */
511 got_op_none = 1;
512 break;
513 case PKTAP_FILTER_OP_PASS:
514 case PKTAP_FILTER_OP_SKIP:
515 /* Invalid after PKTAP_FILTER_OP_NONE */
516 if (got_op_none) {
517 error = EINVAL;
518 break;
519 }
520 break;
521 default:
522 error = EINVAL;
523 break;
524 }
525 if (error != 0) {
526 break;
527 }
528
529 switch (x_filter->filter_param) {
530 case PKTAP_FILTER_OP_NONE:
531 if (x_filter->filter_op != PKTAP_FILTER_OP_NONE) {
532 error = EINVAL;
533 break;
534 }
535 break;
536
537 /*
538 * Do not allow to tap a pktap from a pktap
539 */
540 case PKTAP_FILTER_PARAM_IF_TYPE:
541 if (x_filter->filter_param_if_type == IFT_PKTAP ||
542 x_filter->filter_param_if_type > 0xff) {
543 error = EINVAL;
544 break;
545 }
546 break;
547
548 case PKTAP_FILTER_PARAM_IF_NAME:
549 if (strncmp(s1: x_filter->filter_param_if_name, PKTAP_IFNAME,
550 n: strlen(PKTAP_IFNAME)) == 0) {
551 error = EINVAL;
552 break;
553 }
554 break;
555
556 default:
557 error = EINVAL;
558 break;
559 }
560 if (error != 0) {
561 break;
562 }
563 }
564 if (error != 0) {
565 break;
566 }
567 for (i = 0; i < PKTAP_MAX_FILTERS; i++) {
568 struct pktap_filter *pktap_filter = pktap->pktp_filters + i;
569 struct x_pktap_filter *x_filter = user_filters + i;
570
571 pktap_filter->filter_op = x_filter->filter_op;
572 pktap_filter->filter_param = x_filter->filter_param;
573
574 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) {
575 pktap_filter->filter_param_if_type = x_filter->filter_param_if_type;
576 } else if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) {
577 size_t len;
578
579 strlcpy(dst: pktap_filter->filter_param_if_name,
580 src: x_filter->filter_param_if_name,
581 n: sizeof(pktap_filter->filter_param_if_name));
582 /*
583 * If name does not end with a number then it's a "wildcard" match
584 * where we compare the prefix of the interface name
585 */
586 len = strlen(s: pktap_filter->filter_param_if_name);
587 if (pktap_filter->filter_param_if_name[len] < '0' ||
588 pktap_filter->filter_param_if_name[len] > '9') {
589 pktap_filter->filter_ifname_prefix_len = len;
590 }
591 }
592 }
593 break;
594 }
595 default:
596 error = EINVAL;
597 break;
598 }
599
600done:
601 return error;
602}
603
604__private_extern__ errno_t
605pktap_ioctl(ifnet_t ifp, unsigned long cmd, void *data)
606{
607 errno_t error = 0;
608
609 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
610
611 if ((cmd & IOC_IN)) {
612 error = kauth_authorize_generic(credential: kauth_cred_get(), KAUTH_GENERIC_ISSUSER);
613 if (error) {
614 PKTAP_LOG(PKTP_LOG_ERROR,
615 "%s: kauth_authorize_generic(KAUTH_GENERIC_ISSUSER) - error %d\n",
616 __func__, error);
617 goto done;
618 }
619 }
620
621 switch (cmd) {
622 case SIOCGDRVSPEC32: {
623 struct ifdrv64 ifd;
624 struct ifdrv32 *ifd32 = (struct ifdrv32 *)data;
625
626 memcpy(dst: ifd.ifd_name, src: ifd32->ifd_name, n: sizeof(ifd.ifd_name));
627 ifd.ifd_cmd = ifd32->ifd_cmd;
628 ifd.ifd_len = ifd32->ifd_len;
629 ifd.ifd_data = ifd32->ifd_data;
630
631 error = pktap_getdrvspec(ifp, ifd: &ifd);
632
633 break;
634 }
635 case SIOCGDRVSPEC64: {
636 struct ifdrv64 *ifd64 = (struct ifdrv64 *)data;
637
638 error = pktap_getdrvspec(ifp, ifd: ifd64);
639
640 break;
641 }
642 case SIOCSDRVSPEC32: {
643 struct ifdrv64 ifd;
644 struct ifdrv32 *ifd32 = (struct ifdrv32 *)data;
645
646 memcpy(dst: ifd.ifd_name, src: ifd32->ifd_name, n: sizeof(ifd.ifd_name));
647 ifd.ifd_cmd = ifd32->ifd_cmd;
648 ifd.ifd_len = ifd32->ifd_len;
649 ifd.ifd_data = ifd32->ifd_data;
650
651 error = pktap_setdrvspec(ifp, ifd: &ifd);
652 break;
653 }
654 case SIOCSDRVSPEC64: {
655 struct ifdrv64 *ifd64 = (struct ifdrv64 *)data;
656
657 error = pktap_setdrvspec(ifp, ifd: ifd64);
658
659 break;
660 }
661 default:
662 error = ENOTSUP;
663 break;
664 }
665done:
666 return error;
667}
668
669__private_extern__ void
670pktap_detach(ifnet_t ifp)
671{
672 struct pktap_softc *pktap;
673
674 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
675
676 lck_rw_lock_exclusive(lck: &pktap_lck_rw);
677
678 pktap = ifp->if_softc;
679 ifp->if_softc = NULL;
680 LIST_REMOVE(pktap, pktp_link);
681
682 lck_rw_done(lck: &pktap_lck_rw);
683
684 /* Drop reference as it's no more on the global list */
685 ifnet_release(interface: ifp);
686
687 kfree_type(struct pktap_softc, pktap);
688 /* This is for the reference taken by ifnet_attach() */
689 (void) ifnet_release(interface: ifp);
690}
691
692__private_extern__ int
693pktap_filter_evaluate(struct pktap_softc *pktap, struct ifnet *ifp)
694{
695 int i;
696 int result = PKTAP_FILTER_SKIP; /* Need positive matching rule to pass */
697 int match = 0;
698
699 for (i = 0; i < PKTAP_MAX_FILTERS; i++) {
700 struct pktap_filter *pktap_filter = pktap->pktp_filters + i;
701 size_t len = pktap_filter->filter_ifname_prefix_len != 0 ?
702 pktap_filter->filter_ifname_prefix_len : PKTAP_IFXNAMESIZE;
703
704 switch (pktap_filter->filter_op) {
705 case PKTAP_FILTER_OP_NONE:
706 match = 1;
707 break;
708
709 case PKTAP_FILTER_OP_PASS:
710 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) {
711 if (pktap_filter->filter_param_if_type == 0 ||
712 ifp->if_type == pktap_filter->filter_param_if_type) {
713 result = PKTAP_FILTER_OK;
714 match = 1;
715 PKTAP_LOG(PKTP_LOG_FILTER, "pass %s match type %u\n",
716 ifp->if_xname, pktap_filter->filter_param_if_type);
717 break;
718 }
719 }
720 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) {
721 if (strncmp(s1: ifp->if_xname, s2: pktap_filter->filter_param_if_name,
722 n: len) == 0) {
723 result = PKTAP_FILTER_OK;
724 match = 1;
725 PKTAP_LOG(PKTP_LOG_FILTER, "pass %s match name %s\n",
726 ifp->if_xname, pktap_filter->filter_param_if_name);
727 break;
728 }
729 }
730 break;
731
732 case PKTAP_FILTER_OP_SKIP:
733 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) {
734 if (pktap_filter->filter_param_if_type == 0 ||
735 ifp->if_type == pktap_filter->filter_param_if_type) {
736 result = PKTAP_FILTER_SKIP;
737 match = 1;
738 PKTAP_LOG(PKTP_LOG_FILTER, "skip %s match type %u\n",
739 ifp->if_xname, pktap_filter->filter_param_if_type);
740 break;
741 }
742 }
743 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) {
744 if (strncmp(s1: ifp->if_xname, s2: pktap_filter->filter_param_if_name,
745 n: len) == 0) {
746 result = PKTAP_FILTER_SKIP;
747 match = 1;
748 PKTAP_LOG(PKTP_LOG_FILTER, "skip %s match name %s\n",
749 ifp->if_xname, pktap_filter->filter_param_if_name);
750 break;
751 }
752 }
753 break;
754 }
755 if (match) {
756 break;
757 }
758 }
759
760 if (match == 0) {
761 PKTAP_LOG(PKTP_LOG_FILTER, "%s no match\n",
762 ifp->if_xname);
763 }
764 return result;
765}
766
767static void
768pktap_set_procinfo(struct pktap_header *hdr, struct so_procinfo *soprocinfo)
769{
770 hdr->pth_pid = soprocinfo->spi_pid;
771 if (hdr->pth_comm[0] == 0) {
772 proc_name(pid: soprocinfo->spi_pid, buf: hdr->pth_comm, MAXCOMLEN);
773 }
774 strlcpy(dst: &hdr->pth_comm[0], src: &soprocinfo->spi_proc_name[0], n: sizeof(hdr->pth_comm));
775
776 if (soprocinfo->spi_pid != 0) {
777 uuid_copy(dst: hdr->pth_uuid, src: soprocinfo->spi_uuid);
778 }
779
780 if (soprocinfo->spi_delegated != 0) {
781 hdr->pth_flags |= PTH_FLAG_PROC_DELEGATED;
782 hdr->pth_epid = soprocinfo->spi_epid;
783 strlcpy(dst: &hdr->pth_ecomm[0], src: &soprocinfo->spi_e_proc_name[0], n: sizeof(hdr->pth_ecomm));
784 uuid_copy(dst: hdr->pth_euuid, src: soprocinfo->spi_euuid);
785 }
786}
787
788__private_extern__ void
789pktap_finalize_proc_info(struct pktap_header *hdr)
790{
791 int found;
792 struct so_procinfo soprocinfo;
793
794 if (!(hdr->pth_flags & PTH_FLAG_DELAY_PKTAP)) {
795 return;
796 }
797
798 if (hdr->pth_ipproto == IPPROTO_TCP) {
799 found = inp_findinpcb_procinfo(&tcbinfo, hdr->pth_flowid,
800 &soprocinfo);
801 } else if (hdr->pth_ipproto == IPPROTO_UDP) {
802 found = inp_findinpcb_procinfo(&udbinfo, hdr->pth_flowid,
803 &soprocinfo);
804 } else {
805 found = inp_findinpcb_procinfo(&ripcbinfo, hdr->pth_flowid,
806 &soprocinfo);
807 }
808
809 if (found == 1) {
810 pktap_set_procinfo(hdr, soprocinfo: &soprocinfo);
811 }
812}
813
814static void
815pktap_v2_set_procinfo(struct pktap_v2_hdr *pktap_v2_hdr,
816 struct so_procinfo *soprocinfo)
817{
818 pktap_v2_hdr->pth_pid = soprocinfo->spi_pid;
819
820 if (soprocinfo->spi_pid != 0 && soprocinfo->spi_pid != -1) {
821 if (pktap_v2_hdr->pth_comm_offset != 0) {
822 char *ptr = ((char *)pktap_v2_hdr) +
823 pktap_v2_hdr->pth_comm_offset;
824
825 strlcpy(dst: ptr, src: &soprocinfo->spi_proc_name[0], PKTAP_MAX_COMM_SIZE);
826 }
827 if (pktap_v2_hdr->pth_uuid_offset != 0) {
828 uuid_t *ptr = (uuid_t *) (((char *)pktap_v2_hdr) +
829 pktap_v2_hdr->pth_uuid_offset);
830
831 uuid_copy(dst: *ptr, src: soprocinfo->spi_uuid);
832 }
833 }
834
835 if (!(pktap_v2_hdr->pth_flags & PTH_FLAG_PROC_DELEGATED)) {
836 return;
837 }
838
839 /*
840 * The effective UUID may be set independently from the effective pid
841 */
842 if (soprocinfo->spi_delegated != 0) {
843 pktap_v2_hdr->pth_flags |= PTH_FLAG_PROC_DELEGATED;
844 pktap_v2_hdr->pth_e_pid = soprocinfo->spi_epid;
845
846 if (soprocinfo->spi_pid != 0 && soprocinfo->spi_pid != -1 &&
847 pktap_v2_hdr->pth_e_comm_offset != 0) {
848 char *ptr = ((char *)pktap_v2_hdr) +
849 pktap_v2_hdr->pth_e_comm_offset;
850
851 strlcpy(dst: ptr, src: &soprocinfo->spi_e_proc_name[0], PKTAP_MAX_COMM_SIZE);
852 }
853 if (pktap_v2_hdr->pth_e_uuid_offset != 0) {
854 uuid_t *ptr = (uuid_t *) (((char *)pktap_v2_hdr) +
855 pktap_v2_hdr->pth_e_uuid_offset);
856
857 uuid_copy(dst: *ptr, src: soprocinfo->spi_euuid);
858 }
859 }
860}
861
862__private_extern__ void
863pktap_v2_finalize_proc_info(struct pktap_v2_hdr *pktap_v2_hdr)
864{
865 int found;
866 struct so_procinfo soprocinfo;
867
868 if (!(pktap_v2_hdr->pth_flags & PTH_FLAG_DELAY_PKTAP)) {
869 return;
870 }
871
872 if (pktap_v2_hdr->pth_ipproto == IPPROTO_TCP) {
873 found = inp_findinpcb_procinfo(&tcbinfo,
874 pktap_v2_hdr->pth_flowid, &soprocinfo);
875 } else if (pktap_v2_hdr->pth_ipproto == IPPROTO_UDP) {
876 found = inp_findinpcb_procinfo(&udbinfo,
877 pktap_v2_hdr->pth_flowid, &soprocinfo);
878 } else {
879 found = inp_findinpcb_procinfo(&ripcbinfo,
880 pktap_v2_hdr->pth_flowid, &soprocinfo);
881 }
882 if (found == 1) {
883 pktap_v2_set_procinfo(pktap_v2_hdr, soprocinfo: &soprocinfo);
884 }
885}
886
887__private_extern__ void
888pktap_fill_proc_info(struct pktap_header *hdr, protocol_family_t proto,
889 struct mbuf *m, u_int32_t pre, int outgoing, struct ifnet *ifp)
890{
891 /*
892 * Getting the pid and procname is expensive
893 * For outgoing, do the lookup only if there's an
894 * associated socket as indicated by the flowhash
895 */
896 if (outgoing != 0 && m->m_pkthdr.pkt_flowsrc == FLOWSRC_INPCB) {
897 /*
898 * To avoid lock ordering issues we delay the proc UUID lookup
899 * to the BPF read as we cannot
900 * assume the socket lock is unlocked on output
901 */
902 hdr->pth_flags |= PTH_FLAG_DELAY_PKTAP;
903 hdr->pth_flags |= PTH_FLAG_SOCKET;
904 hdr->pth_flowid = m->m_pkthdr.pkt_flowid;
905
906 if (m->m_pkthdr.pkt_flags & PKTF_FLOW_RAWSOCK) {
907 hdr->pth_ipproto = IPPROTO_RAW;
908 } else {
909 hdr->pth_ipproto = m->m_pkthdr.pkt_proto;
910 }
911
912 if (hdr->pth_ipproto == IPPROTO_TCP) {
913 hdr->pth_pid = m->m_pkthdr.tx_tcp_pid;
914 hdr->pth_epid = m->m_pkthdr.tx_tcp_e_pid;
915 } else if (hdr->pth_ipproto == IPPROTO_UDP) {
916 hdr->pth_pid = m->m_pkthdr.tx_udp_pid;
917 hdr->pth_epid = m->m_pkthdr.tx_udp_e_pid;
918 } else if (hdr->pth_ipproto == IPPROTO_RAW) {
919 hdr->pth_pid = m->m_pkthdr.tx_rawip_pid;
920 hdr->pth_epid = m->m_pkthdr.tx_rawip_e_pid;
921 }
922
923 if (hdr->pth_pid != 0 && hdr->pth_pid != -1) {
924 proc_name(pid: hdr->pth_pid, buf: hdr->pth_comm, MAXCOMLEN);
925 } else {
926 hdr->pth_pid = -1;
927 }
928
929 if (hdr->pth_epid != 0 && hdr->pth_epid != -1) {
930 hdr->pth_flags |= PTH_FLAG_PROC_DELEGATED;
931 proc_name(pid: hdr->pth_epid, buf: hdr->pth_ecomm, MAXCOMLEN);
932 } else {
933 hdr->pth_epid = -1;
934 }
935
936 if (m->m_pkthdr.pkt_flags & PKTF_NEW_FLOW) {
937 hdr->pth_flags |= PTH_FLAG_NEW_FLOW;
938 }
939 } else if (outgoing == 0) {
940 int found = 0;
941 struct so_procinfo soprocinfo;
942 struct inpcb *inp = NULL;
943
944 memset(s: &soprocinfo, c: 0, n: sizeof(struct so_procinfo));
945
946 if (proto == PF_INET) {
947 struct ip ip;
948 errno_t error;
949 size_t hlen;
950 struct in_addr faddr, laddr;
951 u_short fport = 0, lport = 0;
952 struct inpcbinfo *pcbinfo = NULL;
953 int wildcard = 0;
954
955 error = mbuf_copydata(mbuf: m, offset: pre, length: sizeof(struct ip), out_data: &ip);
956 if (error != 0) {
957 PKTAP_LOG(PKTP_LOG_ERROR,
958 "mbuf_copydata tcp v4 failed for %s\n",
959 hdr->pth_ifname);
960 goto done;
961 }
962 hlen = IP_VHL_HL(ip.ip_vhl) << 2;
963
964 faddr = ip.ip_src;
965 laddr = ip.ip_dst;
966
967 if (ip.ip_p == IPPROTO_TCP) {
968 struct tcphdr th;
969
970 error = mbuf_copydata(mbuf: m, offset: pre + hlen,
971 length: sizeof(struct tcphdr), out_data: &th);
972 if (error != 0) {
973 goto done;
974 }
975
976 fport = th.th_sport;
977 lport = th.th_dport;
978
979 pcbinfo = &tcbinfo;
980 } else if (ip.ip_p == IPPROTO_UDP) {
981 struct udphdr uh;
982
983 error = mbuf_copydata(mbuf: m, offset: pre + hlen,
984 length: sizeof(struct udphdr), out_data: &uh);
985 if (error != 0) {
986 PKTAP_LOG(PKTP_LOG_ERROR,
987 "mbuf_copydata udp v4 failed for %s\n",
988 hdr->pth_ifname);
989 goto done;
990 }
991 fport = uh.uh_sport;
992 lport = uh.uh_dport;
993
994 pcbinfo = &udbinfo;
995 wildcard = 1;
996 }
997 if (pcbinfo != NULL) {
998 inp = in_pcblookup_hash(pcbinfo, faddr, fport,
999 laddr, lport, wildcard, outgoing ? NULL : ifp);
1000
1001 if (inp == NULL && hdr->pth_iftype != IFT_LOOP) {
1002 PKTAP_LOG(PKTP_LOG_NOPCB,
1003 "in_pcblookup_hash no pcb %s\n",
1004 hdr->pth_ifname);
1005 }
1006 } else {
1007 PKTAP_LOG(PKTP_LOG_NOPCB,
1008 "unknown ip_p %u on %s\n",
1009 ip.ip_p, hdr->pth_ifname);
1010 pktap_hexdump(PKTP_LOG_NOPCB, addr: &ip, len: sizeof(struct ip));
1011 }
1012 } else if (proto == PF_INET6) {
1013 struct ip6_hdr ip6;
1014 errno_t error;
1015 struct in6_addr *faddr;
1016 struct in6_addr *laddr;
1017 u_short fport = 0, lport = 0;
1018 struct inpcbinfo *pcbinfo = NULL;
1019 int wildcard = 0;
1020
1021 error = mbuf_copydata(mbuf: m, offset: pre, length: sizeof(struct ip6_hdr), out_data: &ip6);
1022 if (error != 0) {
1023 goto done;
1024 }
1025
1026 faddr = &ip6.ip6_src;
1027 laddr = &ip6.ip6_dst;
1028
1029 if (ip6.ip6_nxt == IPPROTO_TCP) {
1030 struct tcphdr th;
1031
1032 error = mbuf_copydata(mbuf: m, offset: pre + sizeof(struct ip6_hdr),
1033 length: sizeof(struct tcphdr), out_data: &th);
1034 if (error != 0) {
1035 PKTAP_LOG(PKTP_LOG_ERROR,
1036 "mbuf_copydata tcp v6 failed for %s\n",
1037 hdr->pth_ifname);
1038 goto done;
1039 }
1040
1041 fport = th.th_sport;
1042 lport = th.th_dport;
1043
1044 pcbinfo = &tcbinfo;
1045 } else if (ip6.ip6_nxt == IPPROTO_UDP) {
1046 struct udphdr uh;
1047
1048 error = mbuf_copydata(mbuf: m, offset: pre + sizeof(struct ip6_hdr),
1049 length: sizeof(struct udphdr), out_data: &uh);
1050 if (error != 0) {
1051 PKTAP_LOG(PKTP_LOG_ERROR,
1052 "mbuf_copydata udp v6 failed for %s\n",
1053 hdr->pth_ifname);
1054 goto done;
1055 }
1056
1057 fport = uh.uh_sport;
1058 lport = uh.uh_dport;
1059
1060 pcbinfo = &udbinfo;
1061 wildcard = 1;
1062 }
1063 if (pcbinfo != NULL) {
1064 inp = in6_pcblookup_hash(pcbinfo, faddr, fport, ip6_input_getdstifscope(m),
1065 laddr, lport, ip6_input_getsrcifscope(m), wildcard, outgoing ? NULL : ifp);
1066
1067 if (inp == NULL && hdr->pth_iftype != IFT_LOOP) {
1068 PKTAP_LOG(PKTP_LOG_NOPCB,
1069 "in6_pcblookup_hash no pcb %s\n",
1070 hdr->pth_ifname);
1071 }
1072 } else {
1073 PKTAP_LOG(PKTP_LOG_NOPCB,
1074 "unknown ip6.ip6_nxt %u on %s\n",
1075 ip6.ip6_nxt, hdr->pth_ifname);
1076 pktap_hexdump(PKTP_LOG_NOPCB, addr: &ip6, len: sizeof(struct ip6_hdr));
1077 }
1078 }
1079 if (inp != NULL) {
1080 hdr->pth_flags |= PTH_FLAG_SOCKET;
1081 if (inp->inp_state != INPCB_STATE_DEAD && inp->inp_socket != NULL) {
1082 found = 1;
1083 inp_get_soprocinfo(inp, &soprocinfo);
1084 }
1085 in_pcb_checkstate(inp, WNT_RELEASE, 0);
1086 }
1087done:
1088 /*
1089 * -1 means PID not found
1090 */
1091 hdr->pth_pid = -1;
1092 hdr->pth_epid = -1;
1093
1094 if (found != 0) {
1095 pktap_set_procinfo(hdr, soprocinfo: &soprocinfo);
1096 }
1097 }
1098}
1099
1100__private_extern__ void
1101pktap_bpf_tap(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m,
1102 u_int32_t pre, u_int32_t post, int outgoing)
1103{
1104 struct pktap_softc *pktap;
1105 void (*bpf_tap_func)(ifnet_t, u_int32_t, mbuf_t, void *, size_t) =
1106 outgoing ? bpf_tap_out : bpf_tap_in;
1107
1108 /*
1109 * Skip the coprocessor interface
1110 */
1111 if (!intcoproc_unrestricted && IFNET_IS_INTCOPROC(ifp)) {
1112 return;
1113 }
1114
1115 lck_rw_lock_shared(lck: &pktap_lck_rw);
1116
1117 /*
1118 * No need to take the ifnet_lock as the struct ifnet field if_bpf is
1119 * protected by the BPF subsystem
1120 */
1121 LIST_FOREACH(pktap, &pktap_list, pktp_link) {
1122 int filter_result;
1123
1124 filter_result = pktap_filter_evaluate(pktap, ifp);
1125 if (filter_result == PKTAP_FILTER_SKIP) {
1126 continue;
1127 }
1128
1129 if (pktap->pktp_dlt_raw_count > 0) {
1130 /* We accept only IPv4 and IPv6 packets for the raw DLT */
1131 if ((proto == AF_INET || proto == AF_INET6) &&
1132 !(m->m_pkthdr.pkt_flags & PKTF_INET_RESOLVE)) {
1133 /*
1134 * We can play just with the length of the first mbuf in the
1135 * chain because bpf_tap_imp() disregard the packet length
1136 * of the mbuf packet header.
1137 */
1138 if (mbuf_setdata(mbuf: m, data: m_mtod_current(m) + pre, len: m->m_len - pre) == 0) {
1139 bpf_tap_func(pktap->pktp_ifp, DLT_RAW, m, NULL, 0);
1140 mbuf_setdata(mbuf: m, data: m_mtod_current(m) - pre, len: m->m_len + pre);
1141 }
1142 }
1143 }
1144
1145 if (pktap->pktp_dlt_pkttap_count > 0) {
1146 struct {
1147 struct pktap_header hdr;
1148 u_int32_t proto;
1149 } hdr_buffer;
1150 struct pktap_header *hdr = &hdr_buffer.hdr;
1151 size_t hdr_size = sizeof(struct pktap_header);
1152 int unknown_if_type = 0;
1153 size_t data_adjust = 0;
1154 u_int32_t pre_adjust = 0;
1155
1156 /* Verify the structure is packed */
1157 _CASSERT(sizeof(hdr_buffer) == sizeof(struct pktap_header) + sizeof(u_int32_t));
1158
1159 bzero(s: &hdr_buffer, n: sizeof(hdr_buffer));
1160 hdr->pth_length = sizeof(struct pktap_header);
1161 hdr->pth_type_next = PTH_TYPE_PACKET;
1162
1163 /*
1164 * Set DLT of packet based on interface type
1165 */
1166 switch (ifp->if_type) {
1167 case IFT_LOOP:
1168 case IFT_GIF:
1169 case IFT_STF:
1170 case IFT_CELLULAR:
1171 /*
1172 * Packets from pdp interfaces have no loopback
1173 * header that contain the protocol number.
1174 * As BPF just concatenate the header and the
1175 * packet content in a single buffer,
1176 * stash the protocol after the pktap header
1177 * and adjust the size of the header accordingly
1178 */
1179 hdr->pth_dlt = DLT_NULL;
1180 if (pre == 0) {
1181 hdr_buffer.proto = proto;
1182 hdr_size = sizeof(hdr_buffer);
1183 pre_adjust = sizeof(hdr_buffer.proto);
1184 }
1185 break;
1186 case IFT_ETHER:
1187 case IFT_BRIDGE:
1188 case IFT_L2VLAN:
1189 case IFT_IEEE8023ADLAG:
1190 hdr->pth_dlt = DLT_EN10MB;
1191 break;
1192 case IFT_PPP:
1193 hdr->pth_dlt = DLT_PPP;
1194 break;
1195 case IFT_IEEE1394:
1196 hdr->pth_dlt = DLT_APPLE_IP_OVER_IEEE1394;
1197 break;
1198 case IFT_OTHER:
1199 if (ifp->if_family == IFNET_FAMILY_IPSEC ||
1200 ifp->if_family == IFNET_FAMILY_UTUN) {
1201 /*
1202 * For utun:
1203 * - incoming packets do not have the prefix set to four
1204 * - some packets are as small as two bytes!
1205 */
1206 if (m_pktlen(m) < 4) {
1207 goto done;
1208 }
1209 if (proto != AF_INET && proto != AF_INET6) {
1210 goto done;
1211 }
1212 if (proto == AF_INET && (size_t) m_pktlen(m) - 4 < sizeof(struct ip)) {
1213 goto done;
1214 }
1215 if (proto == AF_INET6 && (size_t) m_pktlen(m) - 4 < sizeof(struct ip6_hdr)) {
1216 goto done;
1217 }
1218
1219 /*
1220 * Handle two cases:
1221 * - The old utun encapsulation with the protocol family in network order
1222 * - A raw IPv4 or IPv6 packet
1223 */
1224 uint8_t data = *(uint8_t *)mbuf_data(mbuf: m);
1225 if ((data >> 4) == 4 || (data >> 4) == 6) {
1226 pre = 4;
1227 } else {
1228 /*
1229 * Skip the protocol in the mbuf as it's in network order
1230 */
1231 pre = 4;
1232 data_adjust = 4;
1233 }
1234 }
1235 hdr->pth_dlt = DLT_NULL;
1236 hdr_buffer.proto = proto;
1237 hdr_size = sizeof(hdr_buffer);
1238 break;
1239 default:
1240 if (pre == 0) {
1241 hdr->pth_dlt = DLT_RAW;
1242 } else {
1243 unknown_if_type = 1;
1244 }
1245 break;
1246 }
1247 if (unknown_if_type) {
1248 PKTAP_LOG(PKTP_LOG_FUNC,
1249 "unknown if_type %u for %s\n",
1250 ifp->if_type, ifp->if_xname);
1251 pktap_count_unknown_if_type += 1;
1252 } else {
1253 strlcpy(dst: hdr->pth_ifname, src: ifp->if_xname,
1254 n: sizeof(hdr->pth_ifname));
1255 hdr->pth_flags |= outgoing ? PTH_FLAG_DIR_OUT : PTH_FLAG_DIR_IN;
1256 hdr->pth_protocol_family = proto;
1257 hdr->pth_frame_pre_length = pre + pre_adjust;
1258 hdr->pth_frame_post_length = post;
1259 hdr->pth_iftype = ifp->if_type;
1260 hdr->pth_ifunit = ifp->if_unit;
1261
1262 if (m->m_pkthdr.pkt_flags & PKTF_KEEPALIVE) {
1263 hdr->pth_flags |= PTH_FLAG_KEEP_ALIVE;
1264 }
1265 if (m->m_pkthdr.pkt_flags & PKTF_TCP_REXMT) {
1266 hdr->pth_flags |= PTH_FLAG_REXMIT;
1267 }
1268 if (m->m_pkthdr.pkt_flags & PKTF_WAKE_PKT) {
1269 hdr->pth_flags |= PTH_FLAG_WAKE_PKT;
1270 }
1271
1272 pktap_fill_proc_info(hdr, proto, m, pre, outgoing, ifp);
1273
1274 hdr->pth_svc = so_svc2tc(m->m_pkthdr.pkt_svc);
1275
1276 if (data_adjust == 0) {
1277 bpf_tap_func(pktap->pktp_ifp, DLT_PKTAP, m, hdr, hdr_size);
1278 } else {
1279 /*
1280 * We can play just with the length of the first mbuf in the
1281 * chain because bpf_tap_imp() disregard the packet length
1282 * of the mbuf packet header.
1283 */
1284 if (mbuf_setdata(mbuf: m, data: m_mtod_current(m) + data_adjust, len: m->m_len - data_adjust) == 0) {
1285 bpf_tap_func(pktap->pktp_ifp, DLT_PKTAP, m, hdr, hdr_size);
1286 mbuf_setdata(mbuf: m, data: m_mtod_current(m) - data_adjust, len: m->m_len + data_adjust);
1287 }
1288 }
1289 }
1290 }
1291 }
1292done:
1293 lck_rw_done(lck: &pktap_lck_rw);
1294}
1295
1296__private_extern__ void
1297pktap_input(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m,
1298 char *frame_header)
1299{
1300 char *hdr;
1301 char *start;
1302
1303 /* Fast path */
1304 if (pktap_total_tap_count == 0 ||
1305 (m->m_pkthdr.pkt_flags & PKTF_SKIP_PKTAP) != 0) {
1306 return;
1307 }
1308
1309 hdr = (char *)mbuf_data(mbuf: m);
1310 start = (char *)mbuf_datastart(mbuf: m);
1311 /* Make sure the frame header is fully contained in the mbuf */
1312 if (frame_header != NULL && frame_header >= start && frame_header <= hdr) {
1313 size_t o_len = m->m_len;
1314 u_int32_t pre = (u_int32_t)(hdr - frame_header);
1315
1316 if (mbuf_setdata(mbuf: m, data: frame_header, len: o_len + pre) == 0) {
1317 PKTAP_LOG(PKTP_LOG_INPUT, "ifp %s proto %u pre %u post %u\n",
1318 ifp->if_xname, proto, pre, 0);
1319
1320 pktap_bpf_tap(ifp, proto, m, pre, post: 0, outgoing: 0);
1321 mbuf_setdata(mbuf: m, data: hdr, len: o_len);
1322 }
1323 } else {
1324 PKTAP_LOG(PKTP_LOG_INPUT, "ifp %s proto %u pre %u post %u\n",
1325 ifp->if_xname, proto, 0, 0);
1326
1327 pktap_bpf_tap(ifp, proto, m, pre: 0, post: 0, outgoing: 0);
1328 }
1329}
1330
1331__private_extern__ void
1332pktap_output(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m,
1333 u_int32_t pre, u_int32_t post)
1334{
1335 /* Fast path */
1336 if (pktap_total_tap_count == 0 ||
1337 (m->m_pkthdr.pkt_flags & PKTF_SKIP_PKTAP) != 0) {
1338 return;
1339 }
1340
1341 PKTAP_LOG(PKTP_LOG_OUTPUT, "ifp %s proto %u pre %u post %u\n",
1342 ifp->if_xname, proto, pre, post);
1343
1344 pktap_bpf_tap(ifp, proto, m, pre, post, outgoing: 1);
1345}
1346
1347#if SKYWALK
1348
1349typedef void (*tap_packet_func)(ifnet_t interface, u_int32_t dlt,
1350 kern_packet_t packet, void *header, size_t header_len);
1351
1352static void
1353pktap_bpf_tap_packet(struct ifnet *ifp, protocol_family_t proto, uint32_t dlt,
1354 pid_t pid, const char * pname, pid_t epid, const char * epname,
1355 kern_packet_t pkt, const void * header, size_t header_length,
1356 uint8_t ipproto, uint32_t flowid, uint32_t flags, tap_packet_func tap_func)
1357{
1358 struct {
1359 struct pktap_header pkth;
1360 union {
1361 uint8_t llhdr[16];
1362 uint32_t proto;
1363 } extra;
1364 } hdr_buffer;
1365 struct pktap_header *hdr;
1366 size_t hdr_size;
1367 struct pktap_softc *pktap;
1368 uint32_t pre_length = 0;
1369
1370 /*
1371 * Skip the coprocessor interface
1372 */
1373 if (!intcoproc_unrestricted && IFNET_IS_INTCOPROC(ifp)) {
1374 return;
1375 }
1376
1377 if (proto != AF_INET && proto != AF_INET6) {
1378 PKTAP_LOG(PKTP_LOG_ERROR,
1379 "unsupported protocol %d\n",
1380 proto);
1381 return;
1382 }
1383
1384 /* assume that we'll be tapping using PKTAP */
1385 hdr = &hdr_buffer.pkth;
1386 bzero(s: &hdr_buffer, n: sizeof(hdr_buffer));
1387 hdr->pth_length = sizeof(struct pktap_header);
1388 hdr->pth_type_next = PTH_TYPE_PACKET;
1389 hdr->pth_dlt = dlt;
1390 hdr->pth_pid = pid;
1391 if (pid != epid) {
1392 hdr->pth_epid = epid;
1393 } else {
1394 hdr->pth_epid = -1;
1395 }
1396 if (pname != NULL) {
1397 strlcpy(dst: hdr->pth_comm, src: pname, n: sizeof(hdr->pth_comm));
1398 }
1399 if (epname != NULL) {
1400 strlcpy(dst: hdr->pth_ecomm, src: epname, n: sizeof(hdr->pth_ecomm));
1401 }
1402 strlcpy(dst: hdr->pth_ifname, src: ifp->if_xname, n: sizeof(hdr->pth_ifname));
1403 hdr->pth_flags |= flags;
1404 hdr->pth_ipproto = ipproto;
1405 hdr->pth_flowid = flowid;
1406 /*
1407 * Do the same as pktap_fill_proc_info() to defer looking up inpcb.
1408 * We do it for both inbound and outbound packets unlike the mbuf case.
1409 */
1410 if ((flags & PTH_FLAG_SOCKET) != 0 && ipproto != 0 && flowid != 0) {
1411 hdr->pth_flags |= PTH_FLAG_DELAY_PKTAP;
1412 }
1413 if (kern_packet_get_wake_flag(pkt)) {
1414 hdr->pth_flags |= PTH_FLAG_WAKE_PKT;
1415 }
1416 hdr->pth_trace_tag = kern_packet_get_trace_tag(ph: pkt);
1417 hdr->pth_protocol_family = proto;
1418 hdr->pth_svc = so_svc2tc((mbuf_svc_class_t)
1419 kern_packet_get_service_class(pkt));
1420 hdr->pth_iftype = ifp->if_type;
1421 hdr->pth_ifunit = ifp->if_unit;
1422 hdr_size = sizeof(struct pktap_header);
1423 if (header != NULL && header_length != 0) {
1424 if (header_length > sizeof(hdr_buffer.extra.llhdr)) {
1425 PKTAP_LOG(PKTP_LOG_ERROR,
1426 "%s: header %d > %d\n",
1427 if_name(ifp), (int)header_length,
1428 (int)sizeof(hdr_buffer.extra.llhdr));
1429 return;
1430 }
1431 bcopy(src: header, dst: hdr_buffer.extra.llhdr, n: header_length);
1432 hdr_size += header_length;
1433 pre_length = (uint32_t)header_length;
1434 } else if (dlt == DLT_RAW) {
1435 /*
1436 * Use the same DLT as has been used for the mbuf path
1437 */
1438 hdr->pth_dlt = DLT_NULL;
1439 hdr_buffer.extra.proto = proto;
1440 hdr_size = sizeof(struct pktap_header) + sizeof(u_int32_t);
1441 pre_length = sizeof(hdr_buffer.extra.proto);
1442 } else if (dlt == DLT_EN10MB) {
1443 pre_length = ETHER_HDR_LEN;
1444 }
1445 hdr->pth_frame_pre_length = pre_length;
1446
1447 lck_rw_lock_shared(lck: &pktap_lck_rw);
1448 /*
1449 * No need to take the ifnet_lock as the struct ifnet field if_bpf is
1450 * protected by the BPF subsystem
1451 */
1452 LIST_FOREACH(pktap, &pktap_list, pktp_link) {
1453 int filter_result;
1454
1455 filter_result = pktap_filter_evaluate(pktap, ifp);
1456 if (filter_result == PKTAP_FILTER_SKIP) {
1457 continue;
1458 }
1459
1460 if (dlt == DLT_RAW && pktap->pktp_dlt_raw_count > 0) {
1461 (*tap_func)(pktap->pktp_ifp, DLT_RAW, pkt, NULL, 0);
1462 }
1463 if (pktap->pktp_dlt_pkttap_count > 0) {
1464 (*tap_func)(pktap->pktp_ifp, DLT_PKTAP,
1465 pkt, hdr, hdr_size);
1466 }
1467 }
1468 lck_rw_done(lck: &pktap_lck_rw);
1469}
1470
1471void
1472pktap_input_packet(struct ifnet *ifp, protocol_family_t proto, uint32_t dlt,
1473 pid_t pid, const char * pname, pid_t epid, const char * epname,
1474 kern_packet_t pkt, const void * header, size_t header_length,
1475 uint8_t ipproto, uint32_t flowid, uint32_t flags)
1476{
1477 /* Fast path */
1478 if (pktap_total_tap_count == 0) {
1479 return;
1480 }
1481
1482 PKTAP_LOG(PKTP_LOG_INPUT, "IN %s proto %u pid %d epid %d\n",
1483 ifp->if_xname, proto, pid, epid);
1484 pktap_bpf_tap_packet(ifp, proto, dlt, pid, pname, epid, epname, pkt,
1485 header, header_length, ipproto, flowid,
1486 PTH_FLAG_DIR_IN | (flags & ~(PTH_FLAG_DIR_IN | PTH_FLAG_DIR_OUT)),
1487 tap_func: bpf_tap_packet_in);
1488}
1489
1490void
1491pktap_output_packet(struct ifnet *ifp, protocol_family_t proto, uint32_t dlt,
1492 pid_t pid, const char * pname, pid_t epid, const char * epname,
1493 kern_packet_t pkt, const void * header, size_t header_length,
1494 uint8_t ipproto, uint32_t flowid, uint32_t flags)
1495{
1496 /* Fast path */
1497 if (pktap_total_tap_count == 0) {
1498 return;
1499 }
1500
1501 PKTAP_LOG(PKTP_LOG_OUTPUT, "OUT %s proto %u pid %d epid %d\n",
1502 ifp->if_xname, proto, pid, epid);
1503 pktap_bpf_tap_packet(ifp, proto, dlt, pid, pname, epid, epname, pkt,
1504 header, header_length, ipproto, flowid,
1505 PTH_FLAG_DIR_OUT | (flags & ~(PTH_FLAG_DIR_IN | PTH_FLAG_DIR_OUT)),
1506 tap_func: bpf_tap_packet_out);
1507}
1508
1509#endif /* SKYWALK */
1510
1511void
1512convert_to_pktap_header_to_v2(struct bpf_packet *bpf_pkt, bool truncate)
1513{
1514 struct pktap_header *pktap_header;
1515 size_t extra_src_size;
1516 struct pktap_buffer_v2_hdr_extra pktap_buffer_v2_hdr_extra;
1517 struct pktap_v2_hdr_space *pktap_v2_hdr_space;
1518 struct pktap_v2_hdr *pktap_v2_hdr;
1519 uint8_t *ptr;
1520
1521 pktap_header = (struct pktap_header *)bpf_pkt->bpfp_header;
1522
1523 if (pktap_header->pth_type_next != PTH_TYPE_PACKET) {
1524 return;
1525 }
1526
1527 VERIFY(bpf_pkt->bpfp_header_length >= sizeof(struct pktap_header));
1528
1529 /*
1530 * extra_src_size is the length of the optional link layer header
1531 */
1532 extra_src_size = bpf_pkt->bpfp_header_length -
1533 sizeof(struct pktap_header);
1534
1535 VERIFY(extra_src_size <= sizeof(union pktap_header_extra));
1536
1537 pktap_v2_hdr_space = &pktap_buffer_v2_hdr_extra.hdr_space;
1538 pktap_v2_hdr = &pktap_v2_hdr_space->pth_hdr;
1539 ptr = (uint8_t *) (pktap_v2_hdr + 1);
1540
1541 COPY_PKTAP_COMMON_FIELDS_TO_V2(pktap_v2_hdr, pktap_header);
1542
1543 /*
1544 * When truncating don't bother with the process UUIDs
1545 */
1546 if (!truncate) {
1547 if ((pktap_header->pth_flags & PTH_FLAG_DELAY_PKTAP)) {
1548 pktap_v2_hdr->pth_uuid_offset = pktap_v2_hdr->pth_length;
1549 pktap_v2_hdr->pth_length += sizeof(uuid_t);
1550 uuid_clear(uu: *(uuid_t *)ptr);
1551 ptr += sizeof(uuid_t);
1552 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1553 } else if (!uuid_is_null(uu: pktap_header->pth_uuid)) {
1554 pktap_v2_hdr->pth_uuid_offset = pktap_v2_hdr->pth_length;
1555 uuid_copy(dst: *(uuid_t *)ptr, src: pktap_header->pth_uuid);
1556 pktap_v2_hdr->pth_length += sizeof(uuid_t);
1557 ptr += sizeof(uuid_t);
1558 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1559 }
1560
1561 if ((pktap_header->pth_flags & PTH_FLAG_DELAY_PKTAP)) {
1562 if (pktap_header->pth_flags & PTH_FLAG_PROC_DELEGATED) {
1563 pktap_v2_hdr->pth_e_uuid_offset = pktap_v2_hdr->pth_length;
1564 uuid_clear(uu: *(uuid_t *)ptr);
1565 pktap_v2_hdr->pth_length += sizeof(uuid_t);
1566 ptr += sizeof(uuid_t);
1567 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1568 }
1569 } else if (!uuid_is_null(uu: pktap_header->pth_euuid)) {
1570 pktap_v2_hdr->pth_e_uuid_offset = pktap_v2_hdr->pth_length;
1571 uuid_copy(dst: *(uuid_t *)ptr, src: pktap_header->pth_euuid);
1572 pktap_v2_hdr->pth_length += sizeof(uuid_t);
1573 ptr += sizeof(uuid_t);
1574 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1575 }
1576 }
1577
1578 if (pktap_header->pth_ifname[0] != 0) {
1579 size_t strsize;
1580
1581 pktap_v2_hdr->pth_ifname_offset = pktap_v2_hdr->pth_length;
1582
1583 /*
1584 * Note: strlcpy() returns the length of the string so we need
1585 * to add one for the end-of-string
1586 */
1587 strsize = 1 + strlcpy(dst: (char *)ptr, src: pktap_header->pth_ifname,
1588 n: sizeof(pktap_v2_hdr_space->pth_ifname));
1589 pktap_v2_hdr->pth_length += strsize;
1590 ptr += strsize;
1591 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1592 }
1593
1594 /*
1595 * Do not waste space with the process name if we do not have a pid
1596 */
1597 if (pktap_header->pth_pid != 0 && pktap_header->pth_pid != -1) {
1598 if (pktap_header->pth_comm[0] != 0) {
1599 size_t strsize;
1600
1601 pktap_v2_hdr->pth_comm_offset = pktap_v2_hdr->pth_length;
1602
1603 strsize = 1 + strlcpy(dst: (char *)ptr, src: pktap_header->pth_comm,
1604 n: sizeof(pktap_v2_hdr_space->pth_comm));
1605 pktap_v2_hdr->pth_length += strsize;
1606 ptr += strsize;
1607 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1608 } else if ((pktap_header->pth_flags & PTH_FLAG_DELAY_PKTAP)) {
1609 size_t strsize = sizeof(pktap_v2_hdr_space->pth_comm);
1610
1611 pktap_v2_hdr->pth_comm_offset = pktap_v2_hdr->pth_length;
1612
1613 *ptr = 0; /* empty string by default */
1614 pktap_v2_hdr->pth_length += strsize;
1615 ptr += strsize;
1616 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1617 }
1618 }
1619
1620 /*
1621 * Do not waste space with the effective process name if we do not have
1622 * an effective pid or it's the same as the pid
1623 */
1624 if (pktap_header->pth_epid != 0 && pktap_header->pth_epid != -1 &&
1625 pktap_header->pth_epid != pktap_header->pth_pid) {
1626 if (pktap_header->pth_ecomm[0] != 0) {
1627 size_t strsize;
1628
1629 pktap_v2_hdr->pth_e_comm_offset = pktap_v2_hdr->pth_length;
1630
1631 strsize = 1 + strlcpy(dst: (char *)ptr, src: pktap_header->pth_ecomm,
1632 n: sizeof(pktap_v2_hdr_space->pth_e_comm));
1633 pktap_v2_hdr->pth_length += strsize;
1634 ptr += strsize;
1635 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1636 } else if ((pktap_header->pth_flags & PTH_FLAG_DELAY_PKTAP)) {
1637 size_t strsize = sizeof(pktap_v2_hdr_space->pth_e_comm);
1638
1639 pktap_v2_hdr->pth_e_comm_offset = pktap_v2_hdr->pth_length;
1640 *ptr = 0; /* empty string by default */
1641 pktap_v2_hdr->pth_length += strsize;
1642 ptr += strsize;
1643 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1644 }
1645 }
1646
1647 if (extra_src_size > 0) {
1648 char *extra_src_ptr = (char *)(pktap_header + 1);
1649 char *extra_dst_ptr = ((char *)pktap_v2_hdr) +
1650 pktap_v2_hdr->pth_length;
1651
1652 VERIFY(pktap_v2_hdr->pth_length + extra_src_size <=
1653 sizeof(struct pktap_buffer_v2_hdr_extra));
1654
1655 memcpy(dst: extra_dst_ptr, src: extra_src_ptr, n: extra_src_size);
1656 }
1657
1658 VERIFY(pktap_v2_hdr->pth_length + extra_src_size <=
1659 bpf_pkt->bpfp_header_length);
1660
1661 memcpy(dst: bpf_pkt->bpfp_header, src: pktap_v2_hdr,
1662 n: pktap_v2_hdr->pth_length + extra_src_size);
1663
1664 bpf_pkt->bpfp_total_length += pktap_v2_hdr->pth_length -
1665 sizeof(struct pktap_header);
1666 bpf_pkt->bpfp_header_length += pktap_v2_hdr->pth_length -
1667 sizeof(struct pktap_header);
1668}
1669