1/*
2 * Copyright (c) 2012-2013 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
31#include <sys/types.h>
32#include <sys/kernel_types.h>
33#include <sys/kauth.h>
34#include <sys/socket.h>
35#include <sys/socketvar.h>
36#include <sys/sockio.h>
37#include <sys/sysctl.h>
38#include <sys/proc.h>
39
40#include <net/if.h>
41#include <net/if_var.h>
42#include <net/if_types.h>
43#include <net/bpf.h>
44#include <net/net_osdep.h>
45#include <net/pktap.h>
46
47#include <netinet/in_pcb.h>
48#include <netinet/tcp.h>
49#include <netinet/tcp_var.h>
50#define _IP_VHL
51#include <netinet/ip.h>
52#include <netinet/ip_var.h>
53#include <netinet/udp.h>
54#include <netinet/udp_var.h>
55
56#include <netinet/ip6.h>
57#include <netinet6/in6_pcb.h>
58
59#include <libkern/OSAtomic.h>
60
61#include <kern/debug.h>
62
63#include <sys/mcache.h>
64
65#include <string.h>
66
67extern struct inpcbinfo ripcbinfo;
68
69struct pktap_softc {
70	LIST_ENTRY(pktap_softc)		pktp_link;
71	uint32_t					pktp_unit;
72	uint32_t					pktp_dlt_raw_count;
73	uint32_t					pktp_dlt_pkttap_count;
74	struct ifnet				*pktp_ifp;
75	struct pktap_filter			pktp_filters[PKTAP_MAX_FILTERS];
76};
77
78#ifndef PKTAP_DEBUG
79#define PKTAP_DEBUG 1
80#endif /* PKTAP_DEBUG */
81
82#define PKTAP_FILTER_OK	0		/* Packet passes filter checks */
83#define PKTAP_FILTER_SKIP 1		/* Do not tap this packet */
84
85static int pktap_inited = 0;
86
87SYSCTL_DECL(_net_link);
88SYSCTL_NODE(_net_link, IFT_PKTAP, pktap, CTLFLAG_RW|CTLFLAG_LOCKED, 0,
89    "pktap virtual interface");
90
91static int pktap_total_tap_count = 0;
92SYSCTL_INT(_net_link_pktap, OID_AUTO, total_tap_count,  CTLFLAG_RD | CTLFLAG_LOCKED,
93	&pktap_total_tap_count, 0, "");
94
95static u_int64_t pktap_count_unknown_if_type = 0;
96SYSCTL_QUAD(_net_link_pktap, OID_AUTO, count_unknown_if_type, CTLFLAG_RD | CTLFLAG_LOCKED,
97	 &pktap_count_unknown_if_type, "");
98
99static int pktap_log = 0;
100SYSCTL_INT(_net_link_pktap, OID_AUTO, log, CTLFLAG_RW | CTLFLAG_LOCKED,
101	&pktap_log, 0, "");
102
103#define PKTAP_LOG(mask, fmt, ...) \
104do { \
105    if ((pktap_log & mask)) \
106        printf("%s:%d " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
107} while(false)
108
109#define PKTP_LOG_FUNC 0x01
110#define PKTP_LOG_FILTER 0x02
111#define PKTP_LOG_INPUT 0x04
112#define PKTP_LOG_OUTPUT 0x08
113#define PKTP_LOG_ERROR 0x10
114#define PKTP_LOG_NOPCB 0x20
115
116/*
117 * pktap_lck_rw protects the global list of pktap interfaces
118 */
119decl_lck_rw_data(static, pktap_lck_rw_data);
120static lck_rw_t *pktap_lck_rw = &pktap_lck_rw_data;
121static lck_grp_t *pktap_lck_grp = NULL;
122static lck_attr_t *pktap_lck_attr = NULL;
123
124static LIST_HEAD(pktap_list, pktap_softc) pktap_list = LIST_HEAD_INITIALIZER(pktap_list);
125
126int pktap_clone_create(struct if_clone *, u_int32_t, void *);
127int pktap_clone_destroy(struct ifnet *);
128
129static struct if_clone pktap_cloner =
130	IF_CLONE_INITIALIZER(PKTAP_IFNAME,
131		pktap_clone_create,
132		pktap_clone_destroy,
133		0,
134		IF_MAXUNIT);
135
136errno_t pktap_if_output(ifnet_t, mbuf_t);
137errno_t pktap_demux(ifnet_t , mbuf_t, char *, protocol_family_t *);
138errno_t pktap_add_proto(ifnet_t, protocol_family_t, const struct ifnet_demux_desc *,
139	 u_int32_t);
140errno_t pktap_del_proto(ifnet_t, protocol_family_t);
141errno_t pktap_getdrvspec(ifnet_t, struct ifdrv64 *);
142errno_t pktap_setdrvspec(ifnet_t, struct ifdrv64 *);
143errno_t pktap_ioctl(ifnet_t, unsigned long, void *);
144void pktap_detach(ifnet_t);
145int pktap_filter_evaluate(struct pktap_softc *, struct ifnet *);
146void pktap_bpf_tap(struct ifnet *, protocol_family_t , struct mbuf *,
147    u_int32_t , u_int32_t , int );
148errno_t pktap_tap_callback(ifnet_t , u_int32_t , bpf_tap_mode );
149
150static void
151pktap_hexdump(int mask, void *addr, size_t len)
152{
153	unsigned char *buf = addr;
154	size_t i;
155
156	if (!(pktap_log & mask))
157		return;
158
159	for (i = 0; i < len; i++) {
160		unsigned char  h = (buf[i] & 0xf0) >> 4;
161		unsigned char  l = buf[i] & 0x0f;
162
163		if (i != 0) {
164			if (i % 32 == 0)
165				printf("\n");
166			else if (i % 4 == 0)
167				printf(" ");
168		}
169		printf("%c%c",
170			h < 10 ? h + '0' : h - 10 + 'a',
171			l < 10 ? l + '0' : l - 10 + 'a');
172	}
173	if (i % 32 != 0)
174		printf("\n");
175
176	return;
177}
178
179__private_extern__ void
180pktap_init(void)
181{
182	int error = 0;
183	lck_grp_attr_t *lck_grp_attr = NULL;
184
185	/* Make sure we're called only once */
186	VERIFY(pktap_inited == 0);
187
188	pktap_inited = 1;
189
190	lck_grp_attr = lck_grp_attr_alloc_init();
191	pktap_lck_grp = lck_grp_alloc_init("pktap", lck_grp_attr);
192	pktap_lck_attr = lck_attr_alloc_init();
193#if PKTAP_DEBUG
194	lck_attr_setdebug(pktap_lck_attr);
195#endif /* PKTAP_DEBUG */
196	lck_rw_init(pktap_lck_rw, pktap_lck_grp, pktap_lck_attr);
197	lck_grp_attr_free(lck_grp_attr);
198
199	LIST_INIT(&pktap_list);
200
201	error = if_clone_attach(&pktap_cloner);
202	if (error != 0)
203		panic("%s: if_clone_attach() failed, error %d\n", __func__, error);
204}
205
206__private_extern__ int
207pktap_clone_create(struct if_clone *ifc, u_int32_t unit, __unused void *params)
208{
209	int error = 0;
210	struct pktap_softc *pktap = NULL;
211	struct ifnet_init_params if_init;
212
213	PKTAP_LOG(PKTP_LOG_FUNC, "unit %u\n", unit);
214
215	pktap = _MALLOC(sizeof(struct pktap_softc), M_DEVBUF, M_WAITOK | M_ZERO);
216	if (pktap == NULL) {
217		printf("%s: _MALLOC failed\n", __func__);
218		error = ENOMEM;
219		goto done;
220	}
221	pktap->pktp_unit = unit;
222
223	/*
224	 * By default accept packet from physical interfaces
225	 */
226	pktap->pktp_filters[0].filter_op = PKTAP_FILTER_OP_PASS;
227	pktap->pktp_filters[0].filter_param = PKTAP_FILTER_PARAM_IF_TYPE;
228	pktap->pktp_filters[0].filter_param_if_type = IFT_ETHER;
229
230	pktap->pktp_filters[1].filter_op = PKTAP_FILTER_OP_PASS;
231	pktap->pktp_filters[1].filter_param = PKTAP_FILTER_PARAM_IF_TYPE;
232	pktap->pktp_filters[1].filter_param_if_type = IFT_IEEE1394;
233	/*
234	 * We do not use a set_bpf_tap() function as we rather rely on the more
235	 * accurate callback passed to bpf_attach()
236	 */
237	bzero(&if_init, sizeof(struct ifnet_init_params));
238	if_init.name = ifc->ifc_name;
239	if_init.unit = unit;
240	if_init.type = IFT_PKTAP;
241	if_init.family = IFNET_FAMILY_LOOPBACK;
242	if_init.output = pktap_if_output;
243	if_init.demux = pktap_demux;
244	if_init.add_proto = pktap_add_proto;
245	if_init.del_proto = pktap_del_proto;
246	if_init.softc = pktap;
247	if_init.ioctl = pktap_ioctl;
248	if_init.detach = pktap_detach;
249
250	error = ifnet_allocate(&if_init, &pktap->pktp_ifp);
251	if (error != 0) {
252		printf("%s: ifnet_allocate failed, error %d\n", __func__, error);
253		goto done;
254	}
255
256	ifnet_set_flags(pktap->pktp_ifp, IFF_UP, IFF_UP);
257
258	error = ifnet_attach(pktap->pktp_ifp, NULL);
259	if (error != 0) {
260		printf("%s: ifnet_attach failed - error %d\n", __func__, error);
261		ifnet_release(pktap->pktp_ifp);
262		goto done;
263	}
264
265	/* Attach DLT_PKTAP as the default DLT */
266	bpf_attach(pktap->pktp_ifp, DLT_PKTAP, sizeof(struct pktap_header), NULL,
267		pktap_tap_callback);
268	bpf_attach(pktap->pktp_ifp, DLT_RAW, 0, NULL, pktap_tap_callback);
269
270	/* Take a reference and add to the global list */
271	ifnet_reference(pktap->pktp_ifp);
272	lck_rw_lock_exclusive(pktap_lck_rw);
273	LIST_INSERT_HEAD(&pktap_list, pktap, pktp_link);
274	lck_rw_done(pktap_lck_rw);
275done:
276	if (error != 0) {
277		if (pktap != NULL)
278			_FREE(pktap, M_DEVBUF);
279	}
280	return (error);
281}
282
283__private_extern__ int
284pktap_clone_destroy(struct ifnet *ifp)
285{
286	int error = 0;
287
288	PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
289
290	(void) ifnet_detach(ifp);
291
292	return (error);
293}
294
295/*
296 * This function is called whenever a DLT is set on the interface:
297 * - When interface is attached to a BPF device via BIOCSETIF for the default DLT
298 * - Whenever a new DLT is selected via BIOCSDLT
299 * - When the interface is detached from a BPF device (direction is zero)
300 */
301__private_extern__ errno_t
302pktap_tap_callback(ifnet_t ifp, u_int32_t dlt, bpf_tap_mode direction)
303{
304	struct pktap_softc *pktap;
305
306	pktap = ifp->if_softc;
307	if (pktap == NULL) {
308		printf("%s: if_softc is NULL for ifp %s\n", __func__,
309		    ifp->if_xname);
310		goto done;
311	}
312	switch (dlt) {
313		case DLT_RAW:
314			if (direction == 0) {
315				if (pktap->pktp_dlt_raw_count > 0) {
316					pktap->pktp_dlt_raw_count--;
317					OSAddAtomic(-1, &pktap_total_tap_count);
318
319				}
320			} else {
321				pktap->pktp_dlt_raw_count++;
322				OSAddAtomic(1, &pktap_total_tap_count);
323			}
324			break;
325		case DLT_PKTAP:
326			if (direction == 0) {
327				if (pktap->pktp_dlt_pkttap_count > 0) {
328					pktap->pktp_dlt_pkttap_count--;
329					OSAddAtomic(-1, &pktap_total_tap_count);
330				}
331			} else {
332				pktap->pktp_dlt_pkttap_count++;
333				OSAddAtomic(1, &pktap_total_tap_count);
334			}
335			break;
336	}
337done:
338	/*
339	 * Attachements count must be positive and we're in trouble
340	 * if we have more that 2**31 attachements
341	 */
342	VERIFY(pktap_total_tap_count >= 0);
343
344	return (0);
345}
346
347__private_extern__ errno_t
348pktap_if_output(ifnet_t ifp, mbuf_t m)
349{
350	PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
351	mbuf_freem(m);
352	return (ENOTSUP);
353}
354
355__private_extern__ errno_t
356pktap_demux(ifnet_t ifp, __unused mbuf_t m, __unused char *header,
357	__unused protocol_family_t *ppf)
358{
359	PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
360	return (ENOTSUP);
361}
362
363__private_extern__ errno_t
364pktap_add_proto(__unused ifnet_t ifp, protocol_family_t pf,
365    __unused const struct ifnet_demux_desc *dmx, __unused u_int32_t cnt)
366{
367	PKTAP_LOG(PKTP_LOG_FUNC, "%s pf %u\n", ifp->if_xname, pf);
368	return (0);
369}
370
371__private_extern__ errno_t
372pktap_del_proto(__unused ifnet_t ifp, __unused protocol_family_t pf)
373{
374	PKTAP_LOG(PKTP_LOG_FUNC, "%s pf %u\n", ifp->if_xname, pf);
375	return (0);
376}
377
378__private_extern__ errno_t
379pktap_getdrvspec(ifnet_t ifp, struct ifdrv64 *ifd)
380{
381	errno_t error = 0;
382	struct pktap_softc *pktap;
383	int i;
384
385	PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
386
387	pktap = ifp->if_softc;
388	if (pktap == NULL) {
389		error = ENOENT;
390		printf("%s: pktap NULL - error %d\n", __func__, error);
391		goto done;
392	}
393
394	switch (ifd->ifd_cmd) {
395	case PKTP_CMD_FILTER_GET: {
396		struct x_pktap_filter x_filters[PKTAP_MAX_FILTERS];
397
398		bzero(&x_filters, sizeof(x_filters));
399
400		if (ifd->ifd_len < PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter)) {
401			printf("%s: PKTP_CMD_FILTER_GET ifd_len %llu too small - error %d\n",
402				__func__, ifd->ifd_len, error);
403			error = EINVAL;
404			break;
405		}
406		for (i = 0; i < PKTAP_MAX_FILTERS; i++) {
407			struct pktap_filter *pktap_filter = pktap->pktp_filters + i;
408			struct x_pktap_filter *x_filter = x_filters + i;
409
410			x_filter->filter_op = pktap_filter->filter_op;
411			x_filter->filter_param = pktap_filter->filter_param;
412
413			if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE)
414				x_filter->filter_param_if_type = pktap_filter->filter_param_if_type;
415			else if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME)
416				strlcpy(x_filter->filter_param_if_name,
417						pktap_filter->filter_param_if_name,
418						sizeof(x_filter->filter_param_if_name));
419		}
420		error = copyout(x_filters, ifd->ifd_data,
421			PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter));
422		if (error) {
423			printf("%s: PKTP_CMD_FILTER_GET copyout - error %d\n", __func__, error);
424			goto done;
425		}
426		break;
427	}
428	case PKTP_CMD_TAP_COUNT: {
429		uint32_t tap_count = pktap->pktp_dlt_raw_count + pktap->pktp_dlt_pkttap_count;
430
431		if (ifd->ifd_len < sizeof(tap_count)) {
432			printf("%s: PKTP_CMD_TAP_COUNT ifd_len %llu too small - error %d\n",
433				__func__, ifd->ifd_len, error);
434			error = EINVAL;
435			break;
436		}
437		error = copyout(&tap_count, ifd->ifd_data, sizeof(tap_count));
438		if (error) {
439			printf("%s: PKTP_CMD_TAP_COUNT copyout - error %d\n", __func__, error);
440			goto done;
441		}
442		break;
443	}
444	default:
445		error = EINVAL;
446		break;
447	}
448
449done:
450	return (error);
451}
452
453__private_extern__ errno_t
454pktap_setdrvspec(ifnet_t ifp, struct ifdrv64 *ifd)
455{
456	errno_t error = 0;
457	struct pktap_softc *pktap;
458
459	PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
460
461	pktap = ifp->if_softc;
462	if (pktap == NULL) {
463		error = ENOENT;
464		printf("%s: pktap NULL - error %d\n", __func__, error);
465		goto done;
466	}
467
468	switch (ifd->ifd_cmd) {
469	case PKTP_CMD_FILTER_SET: {
470		struct x_pktap_filter user_filters[PKTAP_MAX_FILTERS];
471		int i;
472		int got_op_none = 0;
473
474		if (ifd->ifd_len != PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter)) {
475			printf("%s: PKTP_CMD_FILTER_SET bad ifd_len %llu - error %d\n",
476				__func__, ifd->ifd_len, error);
477			error = EINVAL;
478			break;
479		}
480		error = copyin(ifd->ifd_data, &user_filters, ifd->ifd_len);
481		if (error) {
482			printf("%s: copyin - error %d\n", __func__, error);
483			goto done;
484		}
485		/*
486		 * Validate user provided parameters
487		 */
488		for (i = 0; i < PKTAP_MAX_FILTERS; i++) {
489			struct x_pktap_filter *x_filter = user_filters + i;
490
491			switch (x_filter->filter_op) {
492				case PKTAP_FILTER_OP_NONE:
493					/* Following entries must be PKTAP_FILTER_OP_NONE */
494					got_op_none = 1;
495					break;
496				case PKTAP_FILTER_OP_PASS:
497				case PKTAP_FILTER_OP_SKIP:
498					/* Invalid after PKTAP_FILTER_OP_NONE */
499					if (got_op_none) {
500						error = EINVAL;
501						break;
502					}
503					break;
504				default:
505					error = EINVAL;
506					break;
507			}
508			if (error != 0)
509				break;
510
511			switch (x_filter->filter_param) {
512				case PKTAP_FILTER_OP_NONE:
513					if (x_filter->filter_op != PKTAP_FILTER_OP_NONE) {
514						error = EINVAL;
515						break;
516					}
517					break;
518
519				/*
520				 * Do not allow to tap a pktap from a pktap
521				 */
522				case PKTAP_FILTER_PARAM_IF_TYPE:
523					if (x_filter->filter_param_if_type == IFT_PKTAP ||
524						x_filter->filter_param_if_type > 0xff) {
525						error = EINVAL;
526						break;
527					}
528					break;
529
530				case PKTAP_FILTER_PARAM_IF_NAME:
531					if (x_filter->filter_param_if_name == 0 ||
532						strncmp(x_filter->filter_param_if_name, PKTAP_IFNAME,
533							strlen(PKTAP_IFNAME)) == 0) {
534						error = EINVAL;
535						break;
536					}
537					break;
538
539				default:
540					error = EINVAL;
541					break;
542			}
543			if (error != 0)
544				break;
545		}
546		if (error != 0)
547			break;
548		for (i = 0; i < PKTAP_MAX_FILTERS; i++) {
549			struct pktap_filter *pktap_filter = pktap->pktp_filters + i;
550			struct x_pktap_filter *x_filter = user_filters + i;
551
552			pktap_filter->filter_op = x_filter->filter_op;
553			pktap_filter->filter_param = x_filter->filter_param;
554
555			if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE)
556				pktap_filter->filter_param_if_type = x_filter->filter_param_if_type;
557			else if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) {
558				size_t len;
559
560				strlcpy(pktap_filter->filter_param_if_name,
561						x_filter->filter_param_if_name,
562						sizeof(pktap_filter->filter_param_if_name));
563				/*
564				 * If name does not end with a number then it's a "wildcard" match
565				 * where we compare the prefix of the interface name
566				 */
567				len = strlen(pktap_filter->filter_param_if_name);
568				if (pktap_filter->filter_param_if_name[len] < '0' ||
569					pktap_filter->filter_param_if_name[len] > '9')
570					pktap_filter->filter_ifname_prefix_len = len;
571			}
572		}
573		break;
574	}
575	default:
576		error = EINVAL;
577		break;
578	}
579
580done:
581	return (error);
582}
583
584__private_extern__ errno_t
585pktap_ioctl(ifnet_t ifp, unsigned long cmd, void *data)
586{
587	errno_t error = 0;
588
589	PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
590
591	if ((cmd & IOC_IN)) {
592		error = kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER);
593		if (error) {
594			PKTAP_LOG(PKTP_LOG_ERROR,
595				"%s: kauth_authorize_generic(KAUTH_GENERIC_ISSUSER) - error %d\n",
596				__func__, error);
597			goto done;
598		}
599	}
600
601	switch (cmd) {
602	case SIOCGDRVSPEC32: {
603		struct ifdrv64 ifd;
604		struct ifdrv32 *ifd32 = (struct ifdrv32 *)data;
605
606		memcpy(ifd.ifd_name, ifd32->ifd_name, sizeof(ifd.ifd_name));
607		ifd.ifd_cmd = ifd32->ifd_cmd;
608		ifd.ifd_len = ifd32->ifd_len;
609		ifd.ifd_data = ifd32->ifd_data;
610
611		error = pktap_getdrvspec(ifp, &ifd);
612
613		break;
614	}
615	case SIOCGDRVSPEC64: {
616		struct ifdrv64 *ifd64 = (struct ifdrv64 *)data;
617
618		error = pktap_getdrvspec(ifp, ifd64);
619
620		break;
621	}
622	case SIOCSDRVSPEC32: {
623		struct ifdrv64 ifd;
624		struct ifdrv32 *ifd32 = (struct ifdrv32 *)data;
625
626		memcpy(ifd.ifd_name, ifd32->ifd_name, 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_setdrvspec(ifp, &ifd);
632		break;
633	}
634	case SIOCSDRVSPEC64: {
635		struct ifdrv64 *ifd64 = (struct ifdrv64 *)data;
636
637		error = pktap_setdrvspec(ifp, ifd64);
638
639		break;
640	}
641	default:
642		error = ENOTSUP;
643		break;
644	}
645done:
646	return (error);
647}
648
649__private_extern__ void
650pktap_detach(ifnet_t ifp)
651{
652	struct pktap_softc *pktap;
653
654	PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
655
656	lck_rw_lock_exclusive(pktap_lck_rw);
657
658	pktap = ifp->if_softc;
659	ifp->if_softc = NULL;
660	LIST_REMOVE(pktap, pktp_link);
661
662	lck_rw_done(pktap_lck_rw);
663
664	/* Drop reference as it's no more on the global list */
665	ifnet_release(ifp);
666
667	_FREE(pktap, M_DEVBUF);
668
669	/* This is for the reference taken by ifnet_attach() */
670	(void) ifnet_release(ifp);
671}
672
673__private_extern__ int
674pktap_filter_evaluate(struct pktap_softc *pktap, struct ifnet *ifp)
675{
676	int i;
677	int result = PKTAP_FILTER_SKIP; /* Need positive matching rule to pass */
678	int match = 0;
679
680	for (i = 0; i < PKTAP_MAX_FILTERS; i++) {
681		struct pktap_filter *pktap_filter = pktap->pktp_filters + i;
682		size_t len = pktap_filter->filter_ifname_prefix_len != 0 ?
683			pktap_filter->filter_ifname_prefix_len : PKTAP_IFXNAMESIZE;
684
685		switch (pktap_filter->filter_op) {
686			case PKTAP_FILTER_OP_NONE:
687				match = 1;
688				break;
689
690			case PKTAP_FILTER_OP_PASS:
691				if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) {
692					if (pktap_filter->filter_param_if_type == 0 ||
693						ifp->if_type == pktap_filter->filter_param_if_type) {
694						result = PKTAP_FILTER_OK;
695						match = 1;
696						PKTAP_LOG(PKTP_LOG_FILTER, "pass %s match type %u\n",
697							ifp->if_xname, pktap_filter->filter_param_if_type);
698						break;
699					}
700				}
701				if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) {
702					if (strncmp(ifp->if_xname, pktap_filter->filter_param_if_name,
703							len) == 0) {
704						result = PKTAP_FILTER_OK;
705						match = 1;
706						PKTAP_LOG(PKTP_LOG_FILTER, "pass %s match name %s\n",
707							ifp->if_xname, pktap_filter->filter_param_if_name);
708						break;
709					}
710				}
711				break;
712
713			case PKTAP_FILTER_OP_SKIP:
714				if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) {
715					if (pktap_filter->filter_param_if_type == 0 ||
716						ifp->if_type == pktap_filter->filter_param_if_type) {
717						result = PKTAP_FILTER_SKIP;
718						match = 1;
719						PKTAP_LOG(PKTP_LOG_FILTER, "skip %s match type %u\n",
720							ifp->if_xname, pktap_filter->filter_param_if_type);
721						break;
722					}
723				}
724				if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) {
725					if (strncmp(ifp->if_xname, pktap_filter->filter_param_if_name,
726							len) == 0) {
727						result = PKTAP_FILTER_SKIP;
728						match = 1;
729						PKTAP_LOG(PKTP_LOG_FILTER, "skip %s match name %s\n",
730							ifp->if_xname, pktap_filter->filter_param_if_name);
731						break;
732					}
733				}
734				break;
735		}
736		if (match)
737			break;
738	}
739
740	if (match == 0) {
741		PKTAP_LOG(PKTP_LOG_FILTER, "%s no match\n",
742			ifp->if_xname);
743	}
744	return (result);
745}
746
747__private_extern__ void
748pktap_fill_proc_info(struct pktap_header *hdr, protocol_family_t proto,
749	struct mbuf *m, u_int32_t pre, int outgoing, struct ifnet *ifp)
750{
751	int found = 0;
752	struct so_procinfo soprocinfo;
753
754	/*
755	 * Getting the pid and procname is expensive
756	 * For outgoing, do the lookup only if there's an
757	 * associated socket as indicated by the flowhash
758	 */
759	if (outgoing != 0 && (m->m_pkthdr.pkt_flags &
760		(PKTF_FLOW_ID|PKTF_FLOW_LOCALSRC)) == (PKTF_FLOW_ID|PKTF_FLOW_LOCALSRC) &&
761		m->m_pkthdr.pkt_flowsrc == FLOWSRC_INPCB) {
762		if (m->m_pkthdr.pkt_flags & PKTF_FLOW_RAWSOCK)
763			found = inp_findinpcb_procinfo(&ripcbinfo, m->m_pkthdr.pkt_flowid, &soprocinfo);
764		else if (m->m_pkthdr.pkt_proto == IPPROTO_TCP)
765			found = inp_findinpcb_procinfo(&tcbinfo, m->m_pkthdr.pkt_flowid, &soprocinfo);
766		else if (m->m_pkthdr.pkt_proto == IPPROTO_UDP)
767			found = inp_findinpcb_procinfo(&udbinfo, m->m_pkthdr.pkt_flowid, &soprocinfo);
768	} else if (outgoing == 0) {
769		struct inpcb *inp = NULL;
770
771		if (proto == PF_INET) {
772			struct ip ip;
773			errno_t error;
774			size_t hlen;
775			struct in_addr faddr, laddr;
776			u_short fport, lport;
777			struct inpcbinfo *pcbinfo = NULL;
778			int wildcard = 0;
779
780			error = mbuf_copydata(m, pre, sizeof(struct ip), &ip);
781			if (error != 0) {
782					PKTAP_LOG(PKTP_LOG_ERROR, "mbuf_copydata tcp v4 failed for %s\n",
783					hdr->pth_ifname);
784				goto done;
785			}
786			hlen = IP_VHL_HL(ip.ip_vhl) << 2;
787
788			faddr = ip.ip_src;
789			laddr = ip.ip_dst;
790
791			if (ip.ip_p == IPPROTO_TCP) {
792				struct tcphdr th;
793
794				error = mbuf_copydata(m, pre + hlen,
795					sizeof(struct tcphdr), &th);
796				if (error != 0)
797					goto done;
798
799				fport = th.th_sport;
800				lport = th.th_dport;
801
802				pcbinfo = &tcbinfo;
803			} else if (ip.ip_p == IPPROTO_UDP) {
804				struct udphdr uh;
805
806				error = mbuf_copydata(m, pre + hlen,
807					sizeof(struct udphdr), &uh);
808				if (error != 0) {
809					PKTAP_LOG(PKTP_LOG_ERROR, "mbuf_copydata udp v4 failed for %s\n",
810						hdr->pth_ifname);
811					goto done;
812				}
813				fport = uh.uh_sport;
814				lport = uh.uh_dport;
815
816				pcbinfo = &udbinfo;
817				wildcard = 1;
818			}
819			if (pcbinfo != NULL) {
820				inp = in_pcblookup_hash(pcbinfo, faddr, fport,
821					laddr, lport, wildcard, outgoing ? NULL : ifp);
822
823				if (inp == NULL && hdr->pth_iftype != IFT_LOOP)
824					PKTAP_LOG(PKTP_LOG_NOPCB, "in_pcblookup_hash no pcb %s\n",
825						hdr->pth_ifname);
826			} else {
827				PKTAP_LOG(PKTP_LOG_NOPCB, "unknown ip_p %u on %s\n",
828					ip.ip_p,
829					hdr->pth_ifname);
830				pktap_hexdump(PKTP_LOG_NOPCB, &ip, sizeof(struct ip));
831			}
832		} else if (proto == PF_INET6) {
833			struct ip6_hdr ip6;
834			errno_t error;
835			struct in6_addr *faddr;
836			struct in6_addr *laddr;
837			u_short fport, lport;
838			struct inpcbinfo *pcbinfo = NULL;
839			int wildcard = 0;
840
841			error = mbuf_copydata(m, pre, sizeof(struct ip6_hdr), &ip6);
842			if (error != 0)
843				goto done;
844
845			faddr = &ip6.ip6_src;
846			laddr = &ip6.ip6_dst;
847
848			if (ip6.ip6_nxt == IPPROTO_TCP) {
849				struct tcphdr th;
850
851				error = mbuf_copydata(m, pre + sizeof(struct ip6_hdr),
852					sizeof(struct tcphdr), &th);
853				if (error != 0) {
854					PKTAP_LOG(PKTP_LOG_ERROR, "mbuf_copydata tcp v6 failed for %s\n",
855						hdr->pth_ifname);
856					goto done;
857				}
858
859				fport = th.th_sport;
860				lport = th.th_dport;
861
862				pcbinfo = &tcbinfo;
863			} else if (ip6.ip6_nxt == IPPROTO_UDP) {
864				struct udphdr uh;
865
866				error = mbuf_copydata(m, pre + sizeof(struct ip6_hdr),
867					sizeof(struct udphdr), &uh);
868				if (error != 0) {
869					PKTAP_LOG(PKTP_LOG_ERROR, "mbuf_copydata udp v6 failed for %s\n",
870						hdr->pth_ifname);
871					goto done;
872				}
873
874				fport = uh.uh_sport;
875				lport = uh.uh_dport;
876
877				pcbinfo = &udbinfo;
878				wildcard = 1;
879			}
880			if (pcbinfo != NULL) {
881				inp = in6_pcblookup_hash(pcbinfo, faddr, fport,
882					laddr, lport, wildcard, outgoing ? NULL : ifp);
883
884				if (inp == NULL && hdr->pth_iftype != IFT_LOOP)
885					PKTAP_LOG(PKTP_LOG_NOPCB, "in6_pcblookup_hash no pcb %s\n",
886						hdr->pth_ifname);
887			} else {
888				PKTAP_LOG(PKTP_LOG_NOPCB, "unknown ip6.ip6_nxt %u on %s\n",
889					ip6.ip6_nxt,
890					hdr->pth_ifname);
891				pktap_hexdump(PKTP_LOG_NOPCB, &ip6, sizeof(struct ip6_hdr));
892			}
893		}
894		if (inp != NULL) {
895			if (inp->inp_state != INPCB_STATE_DEAD && inp->inp_socket != NULL) {
896				found = 1;
897				inp_get_soprocinfo(inp, &soprocinfo);
898			}
899			in_pcb_checkstate(inp, WNT_RELEASE, 0);
900		}
901	}
902	/*
903	 * -1 means PID not found
904	 */
905	hdr->pth_pid = -1;
906	hdr->pth_epid = -1;
907	if (found != 0) {
908		hdr->pth_pid = soprocinfo.spi_pid;
909		if (soprocinfo.spi_pid == 0)
910			strlcpy(hdr->pth_comm, "mach_kernel", sizeof(hdr->pth_comm));
911		else
912			proc_name(soprocinfo.spi_pid, hdr->pth_comm, MAXCOMLEN);
913
914		/*
915		 * When not delegated, the effective pid is the same as the real pid
916		 */
917		if (soprocinfo.spi_epid != soprocinfo.spi_pid) {
918			hdr->pth_flags |= PTH_FLAG_PROC_DELEGATED;
919			hdr->pth_epid = soprocinfo.spi_epid;
920			if (soprocinfo.spi_epid == 0)
921				strlcpy(hdr->pth_ecomm, "mach_kernel", sizeof(hdr->pth_ecomm));
922			else
923				proc_name(soprocinfo.spi_epid, hdr->pth_ecomm, MAXCOMLEN);
924		}
925	}
926done:
927	return;
928}
929
930__private_extern__ void
931pktap_bpf_tap(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m,
932    u_int32_t pre, u_int32_t post, int outgoing)
933{
934	struct pktap_softc *pktap;
935	void (*bpf_tap_func)(ifnet_t , u_int32_t , mbuf_t , void * , size_t ) =
936		outgoing ? bpf_tap_out : bpf_tap_in;
937
938	lck_rw_lock_shared(pktap_lck_rw);
939
940	/*
941	 * No need to take the ifnet_lock as the struct ifnet field if_bpf is
942	 * protected by the BPF subsystem
943	 */
944	LIST_FOREACH(pktap, &pktap_list, pktp_link) {
945		int filter_result;
946
947		filter_result = pktap_filter_evaluate(pktap, ifp);
948		if (filter_result == PKTAP_FILTER_SKIP)
949			continue;
950
951		if (pktap->pktp_dlt_raw_count > 0) {
952			/* We accept only IPv4 and IPv6 packets for the raw DLT */
953			if ((proto == AF_INET ||proto == AF_INET6) &&
954				!(m->m_pkthdr.pkt_flags & PKTF_INET_RESOLVE)) {
955				/*
956				 * We can play just with the length of the first mbuf in the
957				 * chain because bpf_tap_imp() disregard the packet length
958				 * of the mbuf packet header.
959				 */
960				if (mbuf_setdata(m, m->m_data + pre,  m->m_len - pre) == 0) {
961					bpf_tap_func(pktap->pktp_ifp, DLT_RAW, m, NULL, 0);
962					mbuf_setdata(m, m->m_data - pre, m->m_len + pre);
963				}
964			}
965		}
966
967		if (pktap->pktp_dlt_pkttap_count > 0) {
968			struct {
969				struct pktap_header hdr;
970				u_int32_t proto;
971			} hdr_buffer;
972			struct pktap_header *hdr = &hdr_buffer.hdr;
973			size_t hdr_size = sizeof(struct pktap_header);
974			int unknown_if_type = 0;
975			size_t data_adjust = 0;
976			u_int32_t pre_adjust = 0;
977
978			/* Verify the structure is packed */
979			_CASSERT(sizeof(hdr_buffer) == sizeof(struct pktap_header) + sizeof(u_int32_t));
980
981			bzero(&hdr_buffer, sizeof(hdr_buffer));
982			hdr->pth_length = sizeof(struct pktap_header);
983			hdr->pth_type_next = PTH_TYPE_PACKET;
984
985			/*
986			 * Set DLT of packet based on interface type
987			 */
988			switch (ifp->if_type) {
989				case IFT_LOOP:
990				case IFT_GIF:
991				case IFT_STF:
992				case IFT_CELLULAR:
993					/*
994					 * Packets from pdp interfaces have no loopback
995					 * header that contain the protocol number.
996					 * As BPF just concatenate the header and the
997					 * packet content in a single buffer,
998					 * stash the protocol after the pktap header
999					 * and adjust the size of the header accordingly
1000					 */
1001					hdr->pth_dlt = DLT_NULL;
1002					if (pre == 0) {
1003						hdr_buffer.proto = proto;
1004						hdr_size = sizeof(hdr_buffer);
1005						pre_adjust = sizeof(hdr_buffer.proto);
1006					}
1007					break;
1008				case IFT_ETHER:
1009				case IFT_BRIDGE:
1010				case IFT_L2VLAN:
1011				case IFT_IEEE8023ADLAG:
1012					hdr->pth_dlt = DLT_EN10MB;
1013					break;
1014				case IFT_PPP:
1015					hdr->pth_dlt = DLT_PPP;
1016					break;
1017				case IFT_IEEE1394:
1018					hdr->pth_dlt = DLT_APPLE_IP_OVER_IEEE1394;
1019					break;
1020				case IFT_OTHER:
1021					if (strncmp(ifp->if_name, "utun", strlen("utun")) == 0) {
1022						/*
1023						 * For utun:
1024						 * - incoming packets do not have the prefix set to four
1025						 * - some packets are as small as two bytes!
1026						 */
1027						if (m_pktlen(m) < 4)
1028							goto done;
1029						if (proto != AF_INET && proto != AF_INET6)
1030							goto done;
1031						if (proto == AF_INET && (size_t) m_pktlen(m) - 4 < sizeof(struct ip))
1032							goto done;
1033						if (proto == AF_INET6 && (size_t) m_pktlen(m) - 4 < sizeof(struct ip6_hdr))
1034							goto done;
1035						/*
1036						 * Skip the protocol in the mbuf as it's in network order
1037						 */
1038						pre = 4;
1039						data_adjust = 4;
1040						hdr->pth_dlt = DLT_NULL;
1041						hdr_buffer.proto = proto;
1042						hdr_size = sizeof(hdr_buffer);
1043						break;
1044					}
1045				default:
1046					if (pre == 0)
1047						hdr->pth_dlt = DLT_RAW;
1048					else
1049						unknown_if_type = 1;
1050					break;
1051			}
1052			if (unknown_if_type) {
1053				PKTAP_LOG(PKTP_LOG_FUNC, "unknown if_type %u for %s\n",
1054					ifp->if_type,ifp->if_xname);
1055				pktap_count_unknown_if_type += 1;
1056			} else {
1057				snprintf(hdr->pth_ifname, sizeof(hdr->pth_ifname), "%s",
1058					ifp->if_xname);
1059				hdr->pth_flags |= outgoing ? PTH_FLAG_DIR_OUT : PTH_FLAG_DIR_IN;
1060				hdr->pth_protocol_family = proto;
1061				hdr->pth_frame_pre_length = pre + pre_adjust;
1062				hdr->pth_frame_post_length = post;
1063				hdr->pth_iftype = ifp->if_type;
1064				hdr->pth_ifunit = ifp->if_unit;
1065
1066				pktap_fill_proc_info(hdr, proto, m, pre, outgoing, ifp);
1067
1068				hdr->pth_svc = so_svc2tc(m->m_pkthdr.pkt_svc);
1069
1070				if (data_adjust == 0) {
1071					bpf_tap_func(pktap->pktp_ifp, DLT_PKTAP, m, hdr, hdr_size);
1072				} else {
1073					/*
1074					 * We can play just with the length of the first mbuf in the
1075					 * chain because bpf_tap_imp() disregard the packet length
1076					 * of the mbuf packet header.
1077					 */
1078					if (mbuf_setdata(m, m->m_data + data_adjust,  m->m_len - data_adjust) == 0) {
1079						bpf_tap_func(pktap->pktp_ifp, DLT_PKTAP, m, hdr, hdr_size);
1080						mbuf_setdata(m, m->m_data - data_adjust, m->m_len + data_adjust);
1081					}
1082				}
1083			}
1084		}
1085	}
1086done:
1087	lck_rw_done(pktap_lck_rw);
1088}
1089
1090__private_extern__ void
1091pktap_input(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m,
1092    char *frame_header)
1093{
1094	char *hdr = (char *)mbuf_data(m);
1095	char *start = (char *)mbuf_datastart(m);
1096
1097	/* Fast path */
1098	if (pktap_total_tap_count == 0)
1099		return;
1100
1101	/* Make sure the frame header is fully contained in the  mbuf */
1102	if (frame_header != NULL && frame_header >= start && frame_header <= hdr) {
1103		size_t o_len = m->m_len;
1104		u_int32_t pre = hdr - frame_header;
1105
1106		if (mbuf_setdata(m, frame_header, o_len + pre) == 0) {
1107			PKTAP_LOG(PKTP_LOG_INPUT, "ifp %s proto %u pre %u post %u\n",
1108				ifp->if_xname, proto, pre, 0);
1109
1110			pktap_bpf_tap(ifp, proto, m,  pre, 0, 0);
1111			mbuf_setdata(m, hdr, o_len);
1112		}
1113	} else {
1114		PKTAP_LOG(PKTP_LOG_INPUT, "ifp %s proto %u pre %u post %u\n",
1115			ifp->if_xname, proto, 0, 0);
1116
1117		pktap_bpf_tap(ifp, proto, m, 0, 0, 0);
1118	}
1119}
1120
1121__private_extern__ void
1122pktap_output(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m,
1123     u_int32_t pre, u_int32_t post)
1124{
1125	/* Fast path */
1126	if (pktap_total_tap_count == 0)
1127		return;
1128
1129	PKTAP_LOG(PKTP_LOG_OUTPUT, "ifp %s proto %u pre %u post %u\n",
1130		ifp->if_xname, proto, pre, post);
1131
1132	pktap_bpf_tap(ifp, proto, m, pre, post, 1);
1133}
1134