xref: /illumos-gate/usr/src/uts/common/io/bpf/bpf_mod.c (revision b7ea883b)
10a0e9771SDarren Reed /*
20a0e9771SDarren Reed  * CDDL HEADER START
30a0e9771SDarren Reed  *
40a0e9771SDarren Reed  * The contents of this file are subject to the terms of the
50a0e9771SDarren Reed  * Common Development and Distribution License (the "License").
60a0e9771SDarren Reed  * You may not use this file except in compliance with the License.
70a0e9771SDarren Reed  *
80a0e9771SDarren Reed  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90a0e9771SDarren Reed  * or http://www.opensolaris.org/os/licensing.
100a0e9771SDarren Reed  * See the License for the specific language governing permissions
110a0e9771SDarren Reed  * and limitations under the License.
120a0e9771SDarren Reed  *
130a0e9771SDarren Reed  * When distributing Covered Code, include this CDDL HEADER in each
140a0e9771SDarren Reed  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150a0e9771SDarren Reed  * If applicable, add the following below this CDDL HEADER, with the
160a0e9771SDarren Reed  * fields enclosed by brackets "[]" replaced with your own identifying
170a0e9771SDarren Reed  * information: Portions Copyright [yyyy] [name of copyright owner]
180a0e9771SDarren Reed  *
190a0e9771SDarren Reed  * CDDL HEADER END
200a0e9771SDarren Reed  */
210a0e9771SDarren Reed 
220a0e9771SDarren Reed /*
230a0e9771SDarren Reed  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240a0e9771SDarren Reed  * Use is subject to license terms.
250a0e9771SDarren Reed  */
260a0e9771SDarren Reed 
270a0e9771SDarren Reed #include <sys/types.h>
280a0e9771SDarren Reed #include <sys/param.h>
290a0e9771SDarren Reed #include <sys/stat.h>
300a0e9771SDarren Reed #include <sys/errno.h>
310a0e9771SDarren Reed #include <sys/uio.h>
320a0e9771SDarren Reed #include <sys/buf.h>
330a0e9771SDarren Reed #include <sys/modctl.h>
340a0e9771SDarren Reed #include <sys/open.h>
350a0e9771SDarren Reed #include <sys/kmem.h>
360a0e9771SDarren Reed #include <sys/conf.h>
370a0e9771SDarren Reed #include <sys/cmn_err.h>
380a0e9771SDarren Reed #include <sys/cred.h>
390a0e9771SDarren Reed #include <sys/sunddi.h>
400a0e9771SDarren Reed #include <sys/mac_provider.h>
410a0e9771SDarren Reed #include <sys/dls_impl.h>
420a0e9771SDarren Reed #include <inet/ipnet.h>
430a0e9771SDarren Reed 
440a0e9771SDarren Reed extern	int	bpfopen(dev_t *devp, int flag, int otyp, cred_t *cred);
450a0e9771SDarren Reed extern	int	bpfclose(dev_t dev, int flag, int otyp, cred_t *cred);
460a0e9771SDarren Reed extern	int	bpfread(dev_t dev, struct uio *uio_p, cred_t *cred_p);
470a0e9771SDarren Reed extern	int	bpfwrite(dev_t dev, struct uio *uio, cred_t *cred);
480a0e9771SDarren Reed extern	int	bpfchpoll(dev_t, short, int, short *, struct pollhead **);
490a0e9771SDarren Reed extern	int	bpfioctl(dev_t, int, intptr_t, int, cred_t *, int *);
500a0e9771SDarren Reed extern	int	bpfilterattach(void);
510a0e9771SDarren Reed extern	int	bpfilterdetach(void);
520a0e9771SDarren Reed 
530a0e9771SDarren Reed extern	bpf_provider_t	bpf_mac;
540a0e9771SDarren Reed extern	bpf_provider_t	bpf_ipnet;
550a0e9771SDarren Reed 
560a0e9771SDarren Reed static	int	bpf_attach(dev_info_t *, ddi_attach_cmd_t);
570a0e9771SDarren Reed static	void	*bpf_create_inst(const netid_t);
580a0e9771SDarren Reed static	void	bpf_destroy_inst(const netid_t, void *);
590a0e9771SDarren Reed static	int	bpf_detach(dev_info_t *, ddi_detach_cmd_t);
600a0e9771SDarren Reed static	int	bpf_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
610a0e9771SDarren Reed static	int	bpf_provider_add(bpf_provider_t *);
620a0e9771SDarren Reed static	int	bpf_provider_remove(bpf_provider_t *);
630a0e9771SDarren Reed static	void	bpf_shutdown_inst(const netid_t, void *);
640a0e9771SDarren Reed 
650a0e9771SDarren Reed extern	void	bpfdetach(uintptr_t);
660a0e9771SDarren Reed extern	int	bpf_bufsize;
670a0e9771SDarren Reed extern	int	bpf_maxbufsize;
680a0e9771SDarren Reed 
69*b7ea883bSDarren Reed bpf_provider_head_t bpf_providers;
700a0e9771SDarren Reed 
710a0e9771SDarren Reed static struct cb_ops bpf_cb_ops = {
720a0e9771SDarren Reed 	bpfopen,
730a0e9771SDarren Reed 	bpfclose,
740a0e9771SDarren Reed 	nodev,		/* strategy */
750a0e9771SDarren Reed 	nodev,		/* print */
760a0e9771SDarren Reed 	nodev,		/* dump */
770a0e9771SDarren Reed 	bpfread,
780a0e9771SDarren Reed 	bpfwrite,	/* write */
790a0e9771SDarren Reed 	bpfioctl,	/* ioctl */
800a0e9771SDarren Reed 	nodev,		/* devmap */
810a0e9771SDarren Reed 	nodev,		/* mmap */
820a0e9771SDarren Reed 	nodev,		/* segmap */
830a0e9771SDarren Reed 	bpfchpoll,	/* poll */
840a0e9771SDarren Reed 	ddi_prop_op,
850a0e9771SDarren Reed 	NULL,
860a0e9771SDarren Reed 	D_MTSAFE,
870a0e9771SDarren Reed 	CB_REV,
880a0e9771SDarren Reed 	nodev,		/* aread */
890a0e9771SDarren Reed 	nodev,		/* awrite */
900a0e9771SDarren Reed };
910a0e9771SDarren Reed 
920a0e9771SDarren Reed static struct dev_ops bpf_ops = {
930a0e9771SDarren Reed 	DEVO_REV,
940a0e9771SDarren Reed 	0,
950a0e9771SDarren Reed 	bpf_getinfo,
960a0e9771SDarren Reed 	nulldev,
970a0e9771SDarren Reed 	nulldev,
980a0e9771SDarren Reed 	bpf_attach,
990a0e9771SDarren Reed 	bpf_detach,
1000a0e9771SDarren Reed 	nodev,		/* reset */
1010a0e9771SDarren Reed 	&bpf_cb_ops,
1020a0e9771SDarren Reed 	(struct bus_ops *)0
1030a0e9771SDarren Reed };
1040a0e9771SDarren Reed 
1050a0e9771SDarren Reed extern struct mod_ops mod_driverops;
1060a0e9771SDarren Reed static struct modldrv bpfmod = {
1070a0e9771SDarren Reed 	&mod_driverops, "Berkely Packet Filter", &bpf_ops
1080a0e9771SDarren Reed };
1090a0e9771SDarren Reed static struct modlinkage modlink1 = { MODREV_1, &bpfmod, NULL };
1100a0e9771SDarren Reed 
1110a0e9771SDarren Reed static dev_info_t *bpf_dev_info = NULL;
1120a0e9771SDarren Reed static net_instance_t *bpf_inst = NULL;
1130a0e9771SDarren Reed 
1140a0e9771SDarren Reed int
_init()1150a0e9771SDarren Reed _init()
1160a0e9771SDarren Reed {
1170a0e9771SDarren Reed 	int bpfinst;
1180a0e9771SDarren Reed 
1190a0e9771SDarren Reed 	bpfinst = mod_install(&modlink1);
1200a0e9771SDarren Reed 	return (bpfinst);
1210a0e9771SDarren Reed }
1220a0e9771SDarren Reed 
1230a0e9771SDarren Reed int
_fini(void)1240a0e9771SDarren Reed _fini(void)
1250a0e9771SDarren Reed {
1260a0e9771SDarren Reed 	int bpfinst;
1270a0e9771SDarren Reed 
1280a0e9771SDarren Reed 	bpfinst = mod_remove(&modlink1);
1290a0e9771SDarren Reed 	return (bpfinst);
1300a0e9771SDarren Reed }
1310a0e9771SDarren Reed 
1320a0e9771SDarren Reed int
_info(struct modinfo * modinfop)1330a0e9771SDarren Reed _info(struct modinfo *modinfop)
1340a0e9771SDarren Reed {
1350a0e9771SDarren Reed 	int bpfinst;
1360a0e9771SDarren Reed 
1370a0e9771SDarren Reed 	bpfinst = mod_info(&modlink1, modinfop);
1380a0e9771SDarren Reed 	return (bpfinst);
1390a0e9771SDarren Reed }
1400a0e9771SDarren Reed 
1410a0e9771SDarren Reed static int
bpf_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1420a0e9771SDarren Reed bpf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1430a0e9771SDarren Reed {
1440a0e9771SDarren Reed 
1450a0e9771SDarren Reed 	switch (cmd) {
1460a0e9771SDarren Reed 	case DDI_ATTACH:
1470a0e9771SDarren Reed 		/*
1480a0e9771SDarren Reed 		 * Default buffer size from bpf's driver.conf file
1490a0e9771SDarren Reed 		 */
1500a0e9771SDarren Reed 		bpf_bufsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
1510a0e9771SDarren Reed 		    "buf_size", 32 * 1024);
1520a0e9771SDarren Reed 		/*
1530a0e9771SDarren Reed 		 * Maximum buffer size from bpf's driver.conf file
1540a0e9771SDarren Reed 		 */
1550a0e9771SDarren Reed 		bpf_maxbufsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
1560a0e9771SDarren Reed 		    "max_buf_size", 16 * 1024 * 1024);
1570a0e9771SDarren Reed 
1580a0e9771SDarren Reed 		if (ddi_create_minor_node(dip, "bpf", S_IFCHR, 0,
1590a0e9771SDarren Reed 		    DDI_PSEUDO, 0) == DDI_FAILURE) {
1600a0e9771SDarren Reed 			ddi_remove_minor_node(dip, NULL);
1610a0e9771SDarren Reed 			goto attach_failed;
1620a0e9771SDarren Reed 		}
1630a0e9771SDarren Reed 		bpf_dev_info = dip;
1640a0e9771SDarren Reed 		ddi_report_dev(dip);
1650a0e9771SDarren Reed 
1660a0e9771SDarren Reed 		LIST_INIT(&bpf_providers);
1670a0e9771SDarren Reed 
1680a0e9771SDarren Reed 		if (bpfilterattach() != 0)
1690a0e9771SDarren Reed 			goto attach_failed;
1700a0e9771SDarren Reed 
171*b7ea883bSDarren Reed 		ipnet_set_itap(bpf_itap);
172*b7ea883bSDarren Reed 		VERIFY(bpf_provider_add(&bpf_ipnet) == 0);
173*b7ea883bSDarren Reed 		VERIFY(bpf_provider_add(&bpf_mac) == 0);
1740a0e9771SDarren Reed 
1750a0e9771SDarren Reed 		/*
1760a0e9771SDarren Reed 		 * Set up to be notified about zones coming and going
1770a0e9771SDarren Reed 		 * so that proper interaction with ipnet is possible.
1780a0e9771SDarren Reed 		 */
1790a0e9771SDarren Reed 		bpf_inst = net_instance_alloc(NETINFO_VERSION);
1800a0e9771SDarren Reed 		if (bpf_inst == NULL)
1810a0e9771SDarren Reed 			goto attach_failed;
1820a0e9771SDarren Reed 		bpf_inst->nin_name = "bpf";
1830a0e9771SDarren Reed 		bpf_inst->nin_create = bpf_create_inst;
1840a0e9771SDarren Reed 		bpf_inst->nin_destroy = bpf_destroy_inst;
1850a0e9771SDarren Reed 		bpf_inst->nin_shutdown = bpf_shutdown_inst;
1860a0e9771SDarren Reed 		if (net_instance_register(bpf_inst) != 0) {
1870a0e9771SDarren Reed 			net_instance_free(bpf_inst);
1880a0e9771SDarren Reed 			goto attach_failed;
1890a0e9771SDarren Reed 		}
1900a0e9771SDarren Reed 
1910a0e9771SDarren Reed 		return (DDI_SUCCESS);
1920a0e9771SDarren Reed 		/* NOTREACHED */
1930a0e9771SDarren Reed 	case DDI_RESUME:
1940a0e9771SDarren Reed 		return (DDI_SUCCESS);
1950a0e9771SDarren Reed 		/* NOTREACHED */
1960a0e9771SDarren Reed 	default:
1970a0e9771SDarren Reed 		break;
1980a0e9771SDarren Reed 	}
1990a0e9771SDarren Reed 
2000a0e9771SDarren Reed attach_failed:
2010a0e9771SDarren Reed 
2020a0e9771SDarren Reed 	/*
2030a0e9771SDarren Reed 	 * Use our own detach routine to toss
2040a0e9771SDarren Reed 	 * away any stuff we allocated above.
2050a0e9771SDarren Reed 	 */
2060a0e9771SDarren Reed 	(void) bpfilterdetach();
2070a0e9771SDarren Reed 	(void) bpf_detach(dip, DDI_DETACH);
2080a0e9771SDarren Reed 	return (DDI_FAILURE);
2090a0e9771SDarren Reed }
2100a0e9771SDarren Reed 
2110a0e9771SDarren Reed static int
bpf_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2120a0e9771SDarren Reed bpf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2130a0e9771SDarren Reed {
2140a0e9771SDarren Reed 	int error;
2150a0e9771SDarren Reed 
2160a0e9771SDarren Reed 	switch (cmd) {
2170a0e9771SDarren Reed 	case DDI_DETACH:
2180a0e9771SDarren Reed 		if (net_instance_unregister(bpf_inst) != 0)
2190a0e9771SDarren Reed 			return (DDI_FAILURE);
2200a0e9771SDarren Reed 		net_instance_free(bpf_inst);
2210a0e9771SDarren Reed 
222*b7ea883bSDarren Reed 		ipnet_set_itap(NULL);
2230a0e9771SDarren Reed 		error = bpfilterdetach();
2240a0e9771SDarren Reed 		if (error != 0)
2250a0e9771SDarren Reed 			return (DDI_FAILURE);
226*b7ea883bSDarren Reed 		VERIFY(bpf_provider_remove(&bpf_ipnet) == 0);
227*b7ea883bSDarren Reed 		VERIFY(bpf_provider_remove(&bpf_mac) == 0);
2280a0e9771SDarren Reed 
2290a0e9771SDarren Reed 		ASSERT(LIST_EMPTY(&bpf_providers));
2300a0e9771SDarren Reed 
2310a0e9771SDarren Reed 		ddi_prop_remove_all(dip);
2320a0e9771SDarren Reed 
2330a0e9771SDarren Reed 		return (DDI_SUCCESS);
2340a0e9771SDarren Reed 		/* NOTREACHED */
2350a0e9771SDarren Reed 	case DDI_SUSPEND:
2360a0e9771SDarren Reed 	case DDI_PM_SUSPEND:
2370a0e9771SDarren Reed 		return (DDI_SUCCESS);
2380a0e9771SDarren Reed 		/* NOTREACHED */
2390a0e9771SDarren Reed 	default:
2400a0e9771SDarren Reed 		break;
2410a0e9771SDarren Reed 	}
2420a0e9771SDarren Reed 	return (DDI_FAILURE);
2430a0e9771SDarren Reed }
2440a0e9771SDarren Reed 
2450a0e9771SDarren Reed /*ARGSUSED*/
2460a0e9771SDarren Reed static int
bpf_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)2470a0e9771SDarren Reed bpf_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2480a0e9771SDarren Reed {
2490a0e9771SDarren Reed 	int error = DDI_FAILURE;
2500a0e9771SDarren Reed 
2510a0e9771SDarren Reed 	switch (infocmd) {
2520a0e9771SDarren Reed 	case DDI_INFO_DEVT2DEVINFO:
2530a0e9771SDarren Reed 		*result = bpf_dev_info;
2540a0e9771SDarren Reed 		error = DDI_SUCCESS;
2550a0e9771SDarren Reed 		break;
2560a0e9771SDarren Reed 	case DDI_INFO_DEVT2INSTANCE:
2570a0e9771SDarren Reed 		*result = (void *)0;
2580a0e9771SDarren Reed 		error = DDI_SUCCESS;
2590a0e9771SDarren Reed 		break;
2600a0e9771SDarren Reed 	default:
2610a0e9771SDarren Reed 		break;
2620a0e9771SDarren Reed 	}
2630a0e9771SDarren Reed 	return (error);
2640a0e9771SDarren Reed }
2650a0e9771SDarren Reed 
2660a0e9771SDarren Reed /*
2670a0e9771SDarren Reed  * The two functions below work with and manage a list of providers that
2680a0e9771SDarren Reed  * supply BPF with packets. Their addition and removal is only happens
2690a0e9771SDarren Reed  * when the bpf module is attaching/detaching, thus there is no race
2700a0e9771SDarren Reed  * condition to guard against with using locks as the kernel module system
2710a0e9771SDarren Reed  * takes care of this for us. Similarly, bpf_provider_tickle() is called
2720a0e9771SDarren Reed  * from bpf_setif, which implies an open file descriptor that would get
2730a0e9771SDarren Reed  * in the way of detach being active.
2740a0e9771SDarren Reed  */
2750a0e9771SDarren Reed static int
bpf_provider_add(bpf_provider_t * provider)2760a0e9771SDarren Reed bpf_provider_add(bpf_provider_t *provider)
2770a0e9771SDarren Reed {
2780a0e9771SDarren Reed 	bpf_provider_list_t *bp;
2790a0e9771SDarren Reed 
2800a0e9771SDarren Reed 	LIST_FOREACH(bp, &bpf_providers, bpl_next) {
2810a0e9771SDarren Reed 		if (bp->bpl_what == provider)
2820a0e9771SDarren Reed 			return (EEXIST);
2830a0e9771SDarren Reed 	}
2840a0e9771SDarren Reed 
2850a0e9771SDarren Reed 
2860a0e9771SDarren Reed 	bp = kmem_alloc(sizeof (*bp), KM_SLEEP);
2870a0e9771SDarren Reed 	bp->bpl_what = provider;
2880a0e9771SDarren Reed 	LIST_INSERT_HEAD(&bpf_providers, bp, bpl_next);
2890a0e9771SDarren Reed 
2900a0e9771SDarren Reed 	return (0);
2910a0e9771SDarren Reed }
2920a0e9771SDarren Reed 
2930a0e9771SDarren Reed static int
bpf_provider_remove(bpf_provider_t * provider)2940a0e9771SDarren Reed bpf_provider_remove(bpf_provider_t *provider)
2950a0e9771SDarren Reed {
2960a0e9771SDarren Reed 	bpf_provider_list_t *bp;
2970a0e9771SDarren Reed 
2980a0e9771SDarren Reed 	LIST_FOREACH(bp, &bpf_providers, bpl_next) {
2990a0e9771SDarren Reed 		if (bp->bpl_what == provider)
3000a0e9771SDarren Reed 			break;
3010a0e9771SDarren Reed 	}
3020a0e9771SDarren Reed 
3030a0e9771SDarren Reed 	if (bp == NULL)
3040a0e9771SDarren Reed 		return (ESRCH);
3050a0e9771SDarren Reed 
3060a0e9771SDarren Reed 	LIST_REMOVE(bp, bpl_next);
3070a0e9771SDarren Reed 
3080a0e9771SDarren Reed 	kmem_free(bp, sizeof (*bp));
3090a0e9771SDarren Reed 
3100a0e9771SDarren Reed 	return (0);
3110a0e9771SDarren Reed }
3120a0e9771SDarren Reed 
3130a0e9771SDarren Reed /*
3140a0e9771SDarren Reed  * return a pointer to the structure that holds all of the functions
3150a0e9771SDarren Reed  * available to be used to support a particular packet provider.
3160a0e9771SDarren Reed  */
3170a0e9771SDarren Reed bpf_provider_t *
bpf_find_provider_by_id(int who)3180a0e9771SDarren Reed bpf_find_provider_by_id(int who)
3190a0e9771SDarren Reed {
3200a0e9771SDarren Reed 	bpf_provider_list_t *b;
3210a0e9771SDarren Reed 
3220a0e9771SDarren Reed 	LIST_FOREACH(b, &bpf_providers, bpl_next) {
3230a0e9771SDarren Reed 		if (b->bpl_what->bpr_unit == who)
3240a0e9771SDarren Reed 			return (b->bpl_what);
3250a0e9771SDarren Reed 	}
3260a0e9771SDarren Reed 
3270a0e9771SDarren Reed 	return (NULL);
3280a0e9771SDarren Reed }
3290a0e9771SDarren Reed 
3300a0e9771SDarren Reed /*
3310a0e9771SDarren Reed  * This function is used by bpf_setif() to force an open() to be called on
3320a0e9771SDarren Reed  * a given device name. If a device has been unloaded by the kernel, but it
3330a0e9771SDarren Reed  * is still recognised, then calling this function will hopefully cause it
3340a0e9771SDarren Reed  * to be loaded back into the kernel. When this function is called, it is
3350a0e9771SDarren Reed  * not known which packet provider the name belongs to so all are tried.
3360a0e9771SDarren Reed  */
3370a0e9771SDarren Reed int
bpf_provider_tickle(char * name,zoneid_t zone)3380a0e9771SDarren Reed bpf_provider_tickle(char *name, zoneid_t zone)
3390a0e9771SDarren Reed {
3400a0e9771SDarren Reed 	bpf_provider_list_t *bp;
3410a0e9771SDarren Reed 	uintptr_t handle;
3420a0e9771SDarren Reed 	int tickled = 0;
3430a0e9771SDarren Reed 
3440a0e9771SDarren Reed 	LIST_FOREACH(bp, &bpf_providers, bpl_next) {
3450a0e9771SDarren Reed 		handle = 0;
3460a0e9771SDarren Reed 		if (bp->bpl_what->bpr_open(name, &handle, zone) == 0) {
3470a0e9771SDarren Reed 			bp->bpl_what->bpr_close(handle);
3480a0e9771SDarren Reed 			tickled++;
3490a0e9771SDarren Reed 		} else if (bp->bpl_what->bpr_unit == BPR_MAC) {
3500a0e9771SDarren Reed 			/*
3510a0e9771SDarren Reed 			 * For mac devices, sometimes the open/close is not
3520a0e9771SDarren Reed 			 * enough. In that case, further provocation is
3530a0e9771SDarren Reed 			 * attempted by fetching the linkid and trying to
3540a0e9771SDarren Reed 			 * use that as the key for open, rather than the
3550a0e9771SDarren Reed 			 * name.
3560a0e9771SDarren Reed 			 */
3570a0e9771SDarren Reed 			datalink_id_t id;
3580a0e9771SDarren Reed 
3590a0e9771SDarren Reed 			if (bp->bpl_what->bpr_getlinkid(name, &id,
3600a0e9771SDarren Reed 			    zone) == 0) {
3610a0e9771SDarren Reed 				if (bp->bpl_what->bpr_open(name, &handle,
3620a0e9771SDarren Reed 				    zone) == 0) {
3630a0e9771SDarren Reed 					bp->bpl_what->bpr_close(handle);
3640a0e9771SDarren Reed 					tickled++;
3650a0e9771SDarren Reed 				} else {
3660a0e9771SDarren Reed 					mac_handle_t mh;
3670a0e9771SDarren Reed 
3680a0e9771SDarren Reed 					if (mac_open_by_linkid(id, &mh) == 0) {
3690a0e9771SDarren Reed 						mac_close(mh);
3700a0e9771SDarren Reed 						tickled++;
3710a0e9771SDarren Reed 					}
3720a0e9771SDarren Reed 				}
3730a0e9771SDarren Reed 			}
3740a0e9771SDarren Reed 		}
3750a0e9771SDarren Reed 
3760a0e9771SDarren Reed 	}
3770a0e9771SDarren Reed 
3780a0e9771SDarren Reed 	if (tickled != 0)
3790a0e9771SDarren Reed 		return (EWOULDBLOCK);
3800a0e9771SDarren Reed 
3810a0e9771SDarren Reed 	return (ENXIO);
3820a0e9771SDarren Reed }
3830a0e9771SDarren Reed 
3840a0e9771SDarren Reed /*
3850a0e9771SDarren Reed  * The following three functions provide the necessary callbacks into
3860a0e9771SDarren Reed  * the netinfo API. This API is primarily used to trigger awareness of
3870a0e9771SDarren Reed  * when a zone is being torn down, allowing BPF to drive IPNET to
3880a0e9771SDarren Reed  * tell it which interfaces need to go away.
3890a0e9771SDarren Reed  */
3900a0e9771SDarren Reed /*ARGSUSED*/
3910a0e9771SDarren Reed static void *
bpf_create_inst(const netid_t netid)3920a0e9771SDarren Reed bpf_create_inst(const netid_t netid)
3930a0e9771SDarren Reed {
3940a0e9771SDarren Reed 	/*
3950a0e9771SDarren Reed 	 * BPF does not keep any per-instance state, its list of
3960a0e9771SDarren Reed 	 * interfaces is global, as is its device hash table.
3970a0e9771SDarren Reed 	 */
3980a0e9771SDarren Reed 	return ((void *)bpf_itap);
3990a0e9771SDarren Reed }
4000a0e9771SDarren Reed 
4010a0e9771SDarren Reed /*ARGSUSED*/
4020a0e9771SDarren Reed static void
bpf_shutdown_inst(const netid_t netid,void * arg)4030a0e9771SDarren Reed bpf_shutdown_inst(const netid_t netid, void *arg)
4040a0e9771SDarren Reed {
4050a0e9771SDarren Reed }
4060a0e9771SDarren Reed 
4070a0e9771SDarren Reed /*ARGSUSED*/
4080a0e9771SDarren Reed static void
bpf_destroy_inst(const netid_t netid,void * arg)4090a0e9771SDarren Reed bpf_destroy_inst(const netid_t netid, void *arg)
4100a0e9771SDarren Reed {
4110a0e9771SDarren Reed }
412