xref: /onnv-gate/usr/src/uts/common/io/bpf/bpf_mod.c (revision 11179:bfcb8daf999a)
110639SDarren.Reed@Sun.COM /*
210639SDarren.Reed@Sun.COM  * CDDL HEADER START
310639SDarren.Reed@Sun.COM  *
410639SDarren.Reed@Sun.COM  * The contents of this file are subject to the terms of the
510639SDarren.Reed@Sun.COM  * Common Development and Distribution License (the "License").
610639SDarren.Reed@Sun.COM  * You may not use this file except in compliance with the License.
710639SDarren.Reed@Sun.COM  *
810639SDarren.Reed@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910639SDarren.Reed@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010639SDarren.Reed@Sun.COM  * See the License for the specific language governing permissions
1110639SDarren.Reed@Sun.COM  * and limitations under the License.
1210639SDarren.Reed@Sun.COM  *
1310639SDarren.Reed@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410639SDarren.Reed@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510639SDarren.Reed@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610639SDarren.Reed@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710639SDarren.Reed@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810639SDarren.Reed@Sun.COM  *
1910639SDarren.Reed@Sun.COM  * CDDL HEADER END
2010639SDarren.Reed@Sun.COM  */
2110639SDarren.Reed@Sun.COM 
2210639SDarren.Reed@Sun.COM /*
2310639SDarren.Reed@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2410639SDarren.Reed@Sun.COM  * Use is subject to license terms.
2510639SDarren.Reed@Sun.COM  */
2610639SDarren.Reed@Sun.COM 
2710639SDarren.Reed@Sun.COM #include <sys/types.h>
2810639SDarren.Reed@Sun.COM #include <sys/param.h>
2910639SDarren.Reed@Sun.COM #include <sys/stat.h>
3010639SDarren.Reed@Sun.COM #include <sys/errno.h>
3110639SDarren.Reed@Sun.COM #include <sys/uio.h>
3210639SDarren.Reed@Sun.COM #include <sys/buf.h>
3310639SDarren.Reed@Sun.COM #include <sys/modctl.h>
3410639SDarren.Reed@Sun.COM #include <sys/open.h>
3510639SDarren.Reed@Sun.COM #include <sys/kmem.h>
3610639SDarren.Reed@Sun.COM #include <sys/conf.h>
3710639SDarren.Reed@Sun.COM #include <sys/cmn_err.h>
3810639SDarren.Reed@Sun.COM #include <sys/cred.h>
3910639SDarren.Reed@Sun.COM #include <sys/sunddi.h>
4010639SDarren.Reed@Sun.COM #include <sys/mac_provider.h>
4110639SDarren.Reed@Sun.COM #include <sys/dls_impl.h>
4210639SDarren.Reed@Sun.COM #include <inet/ipnet.h>
4310639SDarren.Reed@Sun.COM 
4410639SDarren.Reed@Sun.COM extern	int	bpfopen(dev_t *devp, int flag, int otyp, cred_t *cred);
4510639SDarren.Reed@Sun.COM extern	int	bpfclose(dev_t dev, int flag, int otyp, cred_t *cred);
4610639SDarren.Reed@Sun.COM extern	int	bpfread(dev_t dev, struct uio *uio_p, cred_t *cred_p);
4710639SDarren.Reed@Sun.COM extern	int	bpfwrite(dev_t dev, struct uio *uio, cred_t *cred);
4810639SDarren.Reed@Sun.COM extern	int	bpfchpoll(dev_t, short, int, short *, struct pollhead **);
4910639SDarren.Reed@Sun.COM extern	int	bpfioctl(dev_t, int, intptr_t, int, cred_t *, int *);
5010639SDarren.Reed@Sun.COM extern	int	bpfilterattach(void);
5110639SDarren.Reed@Sun.COM extern	int	bpfilterdetach(void);
5210639SDarren.Reed@Sun.COM 
5310639SDarren.Reed@Sun.COM extern	bpf_provider_t	bpf_mac;
5410639SDarren.Reed@Sun.COM extern	bpf_provider_t	bpf_ipnet;
5510639SDarren.Reed@Sun.COM 
5610639SDarren.Reed@Sun.COM static	int	bpf_attach(dev_info_t *, ddi_attach_cmd_t);
5710639SDarren.Reed@Sun.COM static	void	*bpf_create_inst(const netid_t);
5810639SDarren.Reed@Sun.COM static	void	bpf_destroy_inst(const netid_t, void *);
5910639SDarren.Reed@Sun.COM static	int	bpf_detach(dev_info_t *, ddi_detach_cmd_t);
6010639SDarren.Reed@Sun.COM static	int	bpf_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
6110639SDarren.Reed@Sun.COM static	int	bpf_provider_add(bpf_provider_t *);
6210639SDarren.Reed@Sun.COM static	int	bpf_provider_remove(bpf_provider_t *);
6310639SDarren.Reed@Sun.COM static	void	bpf_shutdown_inst(const netid_t, void *);
6410639SDarren.Reed@Sun.COM 
6510639SDarren.Reed@Sun.COM extern	void	bpfdetach(uintptr_t);
6610639SDarren.Reed@Sun.COM extern	int	bpf_bufsize;
6710639SDarren.Reed@Sun.COM extern	int	bpf_maxbufsize;
6810639SDarren.Reed@Sun.COM 
69*11179SDarren.Reed@Sun.COM bpf_provider_head_t bpf_providers;
7010639SDarren.Reed@Sun.COM 
7110639SDarren.Reed@Sun.COM static struct cb_ops bpf_cb_ops = {
7210639SDarren.Reed@Sun.COM 	bpfopen,
7310639SDarren.Reed@Sun.COM 	bpfclose,
7410639SDarren.Reed@Sun.COM 	nodev,		/* strategy */
7510639SDarren.Reed@Sun.COM 	nodev,		/* print */
7610639SDarren.Reed@Sun.COM 	nodev,		/* dump */
7710639SDarren.Reed@Sun.COM 	bpfread,
7810639SDarren.Reed@Sun.COM 	bpfwrite,	/* write */
7910639SDarren.Reed@Sun.COM 	bpfioctl,	/* ioctl */
8010639SDarren.Reed@Sun.COM 	nodev,		/* devmap */
8110639SDarren.Reed@Sun.COM 	nodev,		/* mmap */
8210639SDarren.Reed@Sun.COM 	nodev,		/* segmap */
8310639SDarren.Reed@Sun.COM 	bpfchpoll,	/* poll */
8410639SDarren.Reed@Sun.COM 	ddi_prop_op,
8510639SDarren.Reed@Sun.COM 	NULL,
8610639SDarren.Reed@Sun.COM 	D_MTSAFE,
8710639SDarren.Reed@Sun.COM 	CB_REV,
8810639SDarren.Reed@Sun.COM 	nodev,		/* aread */
8910639SDarren.Reed@Sun.COM 	nodev,		/* awrite */
9010639SDarren.Reed@Sun.COM };
9110639SDarren.Reed@Sun.COM 
9210639SDarren.Reed@Sun.COM static struct dev_ops bpf_ops = {
9310639SDarren.Reed@Sun.COM 	DEVO_REV,
9410639SDarren.Reed@Sun.COM 	0,
9510639SDarren.Reed@Sun.COM 	bpf_getinfo,
9610639SDarren.Reed@Sun.COM 	nulldev,
9710639SDarren.Reed@Sun.COM 	nulldev,
9810639SDarren.Reed@Sun.COM 	bpf_attach,
9910639SDarren.Reed@Sun.COM 	bpf_detach,
10010639SDarren.Reed@Sun.COM 	nodev,		/* reset */
10110639SDarren.Reed@Sun.COM 	&bpf_cb_ops,
10210639SDarren.Reed@Sun.COM 	(struct bus_ops *)0
10310639SDarren.Reed@Sun.COM };
10410639SDarren.Reed@Sun.COM 
10510639SDarren.Reed@Sun.COM extern struct mod_ops mod_driverops;
10610639SDarren.Reed@Sun.COM static struct modldrv bpfmod = {
10710639SDarren.Reed@Sun.COM 	&mod_driverops, "Berkely Packet Filter", &bpf_ops
10810639SDarren.Reed@Sun.COM };
10910639SDarren.Reed@Sun.COM static struct modlinkage modlink1 = { MODREV_1, &bpfmod, NULL };
11010639SDarren.Reed@Sun.COM 
11110639SDarren.Reed@Sun.COM static dev_info_t *bpf_dev_info = NULL;
11210639SDarren.Reed@Sun.COM static net_instance_t *bpf_inst = NULL;
11310639SDarren.Reed@Sun.COM 
11410639SDarren.Reed@Sun.COM int
_init()11510639SDarren.Reed@Sun.COM _init()
11610639SDarren.Reed@Sun.COM {
11710639SDarren.Reed@Sun.COM 	int bpfinst;
11810639SDarren.Reed@Sun.COM 
11910639SDarren.Reed@Sun.COM 	bpfinst = mod_install(&modlink1);
12010639SDarren.Reed@Sun.COM 	return (bpfinst);
12110639SDarren.Reed@Sun.COM }
12210639SDarren.Reed@Sun.COM 
12310639SDarren.Reed@Sun.COM int
_fini(void)12410639SDarren.Reed@Sun.COM _fini(void)
12510639SDarren.Reed@Sun.COM {
12610639SDarren.Reed@Sun.COM 	int bpfinst;
12710639SDarren.Reed@Sun.COM 
12810639SDarren.Reed@Sun.COM 	bpfinst = mod_remove(&modlink1);
12910639SDarren.Reed@Sun.COM 	return (bpfinst);
13010639SDarren.Reed@Sun.COM }
13110639SDarren.Reed@Sun.COM 
13210639SDarren.Reed@Sun.COM int
_info(struct modinfo * modinfop)13310639SDarren.Reed@Sun.COM _info(struct modinfo *modinfop)
13410639SDarren.Reed@Sun.COM {
13510639SDarren.Reed@Sun.COM 	int bpfinst;
13610639SDarren.Reed@Sun.COM 
13710639SDarren.Reed@Sun.COM 	bpfinst = mod_info(&modlink1, modinfop);
13810639SDarren.Reed@Sun.COM 	return (bpfinst);
13910639SDarren.Reed@Sun.COM }
14010639SDarren.Reed@Sun.COM 
14110639SDarren.Reed@Sun.COM static int
bpf_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)14210639SDarren.Reed@Sun.COM bpf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
14310639SDarren.Reed@Sun.COM {
14410639SDarren.Reed@Sun.COM 
14510639SDarren.Reed@Sun.COM 	switch (cmd) {
14610639SDarren.Reed@Sun.COM 	case DDI_ATTACH:
14710639SDarren.Reed@Sun.COM 		/*
14810639SDarren.Reed@Sun.COM 		 * Default buffer size from bpf's driver.conf file
14910639SDarren.Reed@Sun.COM 		 */
15010639SDarren.Reed@Sun.COM 		bpf_bufsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
15110639SDarren.Reed@Sun.COM 		    "buf_size", 32 * 1024);
15210639SDarren.Reed@Sun.COM 		/*
15310639SDarren.Reed@Sun.COM 		 * Maximum buffer size from bpf's driver.conf file
15410639SDarren.Reed@Sun.COM 		 */
15510639SDarren.Reed@Sun.COM 		bpf_maxbufsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
15610639SDarren.Reed@Sun.COM 		    "max_buf_size", 16 * 1024 * 1024);
15710639SDarren.Reed@Sun.COM 
15810639SDarren.Reed@Sun.COM 		if (ddi_create_minor_node(dip, "bpf", S_IFCHR, 0,
15910639SDarren.Reed@Sun.COM 		    DDI_PSEUDO, 0) == DDI_FAILURE) {
16010639SDarren.Reed@Sun.COM 			ddi_remove_minor_node(dip, NULL);
16110639SDarren.Reed@Sun.COM 			goto attach_failed;
16210639SDarren.Reed@Sun.COM 		}
16310639SDarren.Reed@Sun.COM 		bpf_dev_info = dip;
16410639SDarren.Reed@Sun.COM 		ddi_report_dev(dip);
16510639SDarren.Reed@Sun.COM 
16610639SDarren.Reed@Sun.COM 		LIST_INIT(&bpf_providers);
16710639SDarren.Reed@Sun.COM 
16810639SDarren.Reed@Sun.COM 		if (bpfilterattach() != 0)
16910639SDarren.Reed@Sun.COM 			goto attach_failed;
17010639SDarren.Reed@Sun.COM 
171*11179SDarren.Reed@Sun.COM 		ipnet_set_itap(bpf_itap);
172*11179SDarren.Reed@Sun.COM 		VERIFY(bpf_provider_add(&bpf_ipnet) == 0);
173*11179SDarren.Reed@Sun.COM 		VERIFY(bpf_provider_add(&bpf_mac) == 0);
17410639SDarren.Reed@Sun.COM 
17510639SDarren.Reed@Sun.COM 		/*
17610639SDarren.Reed@Sun.COM 		 * Set up to be notified about zones coming and going
17710639SDarren.Reed@Sun.COM 		 * so that proper interaction with ipnet is possible.
17810639SDarren.Reed@Sun.COM 		 */
17910639SDarren.Reed@Sun.COM 		bpf_inst = net_instance_alloc(NETINFO_VERSION);
18010639SDarren.Reed@Sun.COM 		if (bpf_inst == NULL)
18110639SDarren.Reed@Sun.COM 			goto attach_failed;
18210639SDarren.Reed@Sun.COM 		bpf_inst->nin_name = "bpf";
18310639SDarren.Reed@Sun.COM 		bpf_inst->nin_create = bpf_create_inst;
18410639SDarren.Reed@Sun.COM 		bpf_inst->nin_destroy = bpf_destroy_inst;
18510639SDarren.Reed@Sun.COM 		bpf_inst->nin_shutdown = bpf_shutdown_inst;
18610639SDarren.Reed@Sun.COM 		if (net_instance_register(bpf_inst) != 0) {
18710639SDarren.Reed@Sun.COM 			net_instance_free(bpf_inst);
18810639SDarren.Reed@Sun.COM 			goto attach_failed;
18910639SDarren.Reed@Sun.COM 		}
19010639SDarren.Reed@Sun.COM 
19110639SDarren.Reed@Sun.COM 		return (DDI_SUCCESS);
19210639SDarren.Reed@Sun.COM 		/* NOTREACHED */
19310639SDarren.Reed@Sun.COM 	case DDI_RESUME:
19410639SDarren.Reed@Sun.COM 		return (DDI_SUCCESS);
19510639SDarren.Reed@Sun.COM 		/* NOTREACHED */
19610639SDarren.Reed@Sun.COM 	default:
19710639SDarren.Reed@Sun.COM 		break;
19810639SDarren.Reed@Sun.COM 	}
19910639SDarren.Reed@Sun.COM 
20010639SDarren.Reed@Sun.COM attach_failed:
20110639SDarren.Reed@Sun.COM 
20210639SDarren.Reed@Sun.COM 	/*
20310639SDarren.Reed@Sun.COM 	 * Use our own detach routine to toss
20410639SDarren.Reed@Sun.COM 	 * away any stuff we allocated above.
20510639SDarren.Reed@Sun.COM 	 */
20610639SDarren.Reed@Sun.COM 	(void) bpfilterdetach();
20710639SDarren.Reed@Sun.COM 	(void) bpf_detach(dip, DDI_DETACH);
20810639SDarren.Reed@Sun.COM 	return (DDI_FAILURE);
20910639SDarren.Reed@Sun.COM }
21010639SDarren.Reed@Sun.COM 
21110639SDarren.Reed@Sun.COM static int
bpf_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)21210639SDarren.Reed@Sun.COM bpf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
21310639SDarren.Reed@Sun.COM {
21410639SDarren.Reed@Sun.COM 	int error;
21510639SDarren.Reed@Sun.COM 
21610639SDarren.Reed@Sun.COM 	switch (cmd) {
21710639SDarren.Reed@Sun.COM 	case DDI_DETACH:
21810639SDarren.Reed@Sun.COM 		if (net_instance_unregister(bpf_inst) != 0)
21910639SDarren.Reed@Sun.COM 			return (DDI_FAILURE);
22010639SDarren.Reed@Sun.COM 		net_instance_free(bpf_inst);
22110639SDarren.Reed@Sun.COM 
222*11179SDarren.Reed@Sun.COM 		ipnet_set_itap(NULL);
22310639SDarren.Reed@Sun.COM 		error = bpfilterdetach();
22410639SDarren.Reed@Sun.COM 		if (error != 0)
22510639SDarren.Reed@Sun.COM 			return (DDI_FAILURE);
226*11179SDarren.Reed@Sun.COM 		VERIFY(bpf_provider_remove(&bpf_ipnet) == 0);
227*11179SDarren.Reed@Sun.COM 		VERIFY(bpf_provider_remove(&bpf_mac) == 0);
22810639SDarren.Reed@Sun.COM 
22910639SDarren.Reed@Sun.COM 		ASSERT(LIST_EMPTY(&bpf_providers));
23010639SDarren.Reed@Sun.COM 
23110639SDarren.Reed@Sun.COM 		ddi_prop_remove_all(dip);
23210639SDarren.Reed@Sun.COM 
23310639SDarren.Reed@Sun.COM 		return (DDI_SUCCESS);
23410639SDarren.Reed@Sun.COM 		/* NOTREACHED */
23510639SDarren.Reed@Sun.COM 	case DDI_SUSPEND:
23610639SDarren.Reed@Sun.COM 	case DDI_PM_SUSPEND:
23710639SDarren.Reed@Sun.COM 		return (DDI_SUCCESS);
23810639SDarren.Reed@Sun.COM 		/* NOTREACHED */
23910639SDarren.Reed@Sun.COM 	default:
24010639SDarren.Reed@Sun.COM 		break;
24110639SDarren.Reed@Sun.COM 	}
24210639SDarren.Reed@Sun.COM 	return (DDI_FAILURE);
24310639SDarren.Reed@Sun.COM }
24410639SDarren.Reed@Sun.COM 
24510639SDarren.Reed@Sun.COM /*ARGSUSED*/
24610639SDarren.Reed@Sun.COM static int
bpf_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)24710639SDarren.Reed@Sun.COM bpf_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
24810639SDarren.Reed@Sun.COM {
24910639SDarren.Reed@Sun.COM 	int error = DDI_FAILURE;
25010639SDarren.Reed@Sun.COM 
25110639SDarren.Reed@Sun.COM 	switch (infocmd) {
25210639SDarren.Reed@Sun.COM 	case DDI_INFO_DEVT2DEVINFO:
25310639SDarren.Reed@Sun.COM 		*result = bpf_dev_info;
25410639SDarren.Reed@Sun.COM 		error = DDI_SUCCESS;
25510639SDarren.Reed@Sun.COM 		break;
25610639SDarren.Reed@Sun.COM 	case DDI_INFO_DEVT2INSTANCE:
25710639SDarren.Reed@Sun.COM 		*result = (void *)0;
25810639SDarren.Reed@Sun.COM 		error = DDI_SUCCESS;
25910639SDarren.Reed@Sun.COM 		break;
26010639SDarren.Reed@Sun.COM 	default:
26110639SDarren.Reed@Sun.COM 		break;
26210639SDarren.Reed@Sun.COM 	}
26310639SDarren.Reed@Sun.COM 	return (error);
26410639SDarren.Reed@Sun.COM }
26510639SDarren.Reed@Sun.COM 
26610639SDarren.Reed@Sun.COM /*
26710639SDarren.Reed@Sun.COM  * The two functions below work with and manage a list of providers that
26810639SDarren.Reed@Sun.COM  * supply BPF with packets. Their addition and removal is only happens
26910639SDarren.Reed@Sun.COM  * when the bpf module is attaching/detaching, thus there is no race
27010639SDarren.Reed@Sun.COM  * condition to guard against with using locks as the kernel module system
27110639SDarren.Reed@Sun.COM  * takes care of this for us. Similarly, bpf_provider_tickle() is called
27210639SDarren.Reed@Sun.COM  * from bpf_setif, which implies an open file descriptor that would get
27310639SDarren.Reed@Sun.COM  * in the way of detach being active.
27410639SDarren.Reed@Sun.COM  */
27510639SDarren.Reed@Sun.COM static int
bpf_provider_add(bpf_provider_t * provider)27610639SDarren.Reed@Sun.COM bpf_provider_add(bpf_provider_t *provider)
27710639SDarren.Reed@Sun.COM {
27810639SDarren.Reed@Sun.COM 	bpf_provider_list_t *bp;
27910639SDarren.Reed@Sun.COM 
28010639SDarren.Reed@Sun.COM 	LIST_FOREACH(bp, &bpf_providers, bpl_next) {
28110639SDarren.Reed@Sun.COM 		if (bp->bpl_what == provider)
28210639SDarren.Reed@Sun.COM 			return (EEXIST);
28310639SDarren.Reed@Sun.COM 	}
28410639SDarren.Reed@Sun.COM 
28510639SDarren.Reed@Sun.COM 
28610639SDarren.Reed@Sun.COM 	bp = kmem_alloc(sizeof (*bp), KM_SLEEP);
28710639SDarren.Reed@Sun.COM 	bp->bpl_what = provider;
28810639SDarren.Reed@Sun.COM 	LIST_INSERT_HEAD(&bpf_providers, bp, bpl_next);
28910639SDarren.Reed@Sun.COM 
29010639SDarren.Reed@Sun.COM 	return (0);
29110639SDarren.Reed@Sun.COM }
29210639SDarren.Reed@Sun.COM 
29310639SDarren.Reed@Sun.COM static int
bpf_provider_remove(bpf_provider_t * provider)29410639SDarren.Reed@Sun.COM bpf_provider_remove(bpf_provider_t *provider)
29510639SDarren.Reed@Sun.COM {
29610639SDarren.Reed@Sun.COM 	bpf_provider_list_t *bp;
29710639SDarren.Reed@Sun.COM 
29810639SDarren.Reed@Sun.COM 	LIST_FOREACH(bp, &bpf_providers, bpl_next) {
29910639SDarren.Reed@Sun.COM 		if (bp->bpl_what == provider)
30010639SDarren.Reed@Sun.COM 			break;
30110639SDarren.Reed@Sun.COM 	}
30210639SDarren.Reed@Sun.COM 
30310639SDarren.Reed@Sun.COM 	if (bp == NULL)
30410639SDarren.Reed@Sun.COM 		return (ESRCH);
30510639SDarren.Reed@Sun.COM 
30610639SDarren.Reed@Sun.COM 	LIST_REMOVE(bp, bpl_next);
30710639SDarren.Reed@Sun.COM 
30810639SDarren.Reed@Sun.COM 	kmem_free(bp, sizeof (*bp));
30910639SDarren.Reed@Sun.COM 
31010639SDarren.Reed@Sun.COM 	return (0);
31110639SDarren.Reed@Sun.COM }
31210639SDarren.Reed@Sun.COM 
31310639SDarren.Reed@Sun.COM /*
31410639SDarren.Reed@Sun.COM  * return a pointer to the structure that holds all of the functions
31510639SDarren.Reed@Sun.COM  * available to be used to support a particular packet provider.
31610639SDarren.Reed@Sun.COM  */
31710639SDarren.Reed@Sun.COM bpf_provider_t *
bpf_find_provider_by_id(int who)31810639SDarren.Reed@Sun.COM bpf_find_provider_by_id(int who)
31910639SDarren.Reed@Sun.COM {
32010639SDarren.Reed@Sun.COM 	bpf_provider_list_t *b;
32110639SDarren.Reed@Sun.COM 
32210639SDarren.Reed@Sun.COM 	LIST_FOREACH(b, &bpf_providers, bpl_next) {
32310639SDarren.Reed@Sun.COM 		if (b->bpl_what->bpr_unit == who)
32410639SDarren.Reed@Sun.COM 			return (b->bpl_what);
32510639SDarren.Reed@Sun.COM 	}
32610639SDarren.Reed@Sun.COM 
32710639SDarren.Reed@Sun.COM 	return (NULL);
32810639SDarren.Reed@Sun.COM }
32910639SDarren.Reed@Sun.COM 
33010639SDarren.Reed@Sun.COM /*
33110639SDarren.Reed@Sun.COM  * This function is used by bpf_setif() to force an open() to be called on
33210639SDarren.Reed@Sun.COM  * a given device name. If a device has been unloaded by the kernel, but it
33310639SDarren.Reed@Sun.COM  * is still recognised, then calling this function will hopefully cause it
33410639SDarren.Reed@Sun.COM  * to be loaded back into the kernel. When this function is called, it is
33510639SDarren.Reed@Sun.COM  * not known which packet provider the name belongs to so all are tried.
33610639SDarren.Reed@Sun.COM  */
33710639SDarren.Reed@Sun.COM int
bpf_provider_tickle(char * name,zoneid_t zone)33810639SDarren.Reed@Sun.COM bpf_provider_tickle(char *name, zoneid_t zone)
33910639SDarren.Reed@Sun.COM {
34010639SDarren.Reed@Sun.COM 	bpf_provider_list_t *bp;
34110639SDarren.Reed@Sun.COM 	uintptr_t handle;
34210639SDarren.Reed@Sun.COM 	int tickled = 0;
34310639SDarren.Reed@Sun.COM 
34410639SDarren.Reed@Sun.COM 	LIST_FOREACH(bp, &bpf_providers, bpl_next) {
34510639SDarren.Reed@Sun.COM 		handle = 0;
34610639SDarren.Reed@Sun.COM 		if (bp->bpl_what->bpr_open(name, &handle, zone) == 0) {
34710639SDarren.Reed@Sun.COM 			bp->bpl_what->bpr_close(handle);
34810639SDarren.Reed@Sun.COM 			tickled++;
34910639SDarren.Reed@Sun.COM 		} else if (bp->bpl_what->bpr_unit == BPR_MAC) {
35010639SDarren.Reed@Sun.COM 			/*
35110639SDarren.Reed@Sun.COM 			 * For mac devices, sometimes the open/close is not
35210639SDarren.Reed@Sun.COM 			 * enough. In that case, further provocation is
35310639SDarren.Reed@Sun.COM 			 * attempted by fetching the linkid and trying to
35410639SDarren.Reed@Sun.COM 			 * use that as the key for open, rather than the
35510639SDarren.Reed@Sun.COM 			 * name.
35610639SDarren.Reed@Sun.COM 			 */
35710639SDarren.Reed@Sun.COM 			datalink_id_t id;
35810639SDarren.Reed@Sun.COM 
35910639SDarren.Reed@Sun.COM 			if (bp->bpl_what->bpr_getlinkid(name, &id,
36010639SDarren.Reed@Sun.COM 			    zone) == 0) {
36110639SDarren.Reed@Sun.COM 				if (bp->bpl_what->bpr_open(name, &handle,
36210639SDarren.Reed@Sun.COM 				    zone) == 0) {
36310639SDarren.Reed@Sun.COM 					bp->bpl_what->bpr_close(handle);
36410639SDarren.Reed@Sun.COM 					tickled++;
36510639SDarren.Reed@Sun.COM 				} else {
36610639SDarren.Reed@Sun.COM 					mac_handle_t mh;
36710639SDarren.Reed@Sun.COM 
36810639SDarren.Reed@Sun.COM 					if (mac_open_by_linkid(id, &mh) == 0) {
36910639SDarren.Reed@Sun.COM 						mac_close(mh);
37010639SDarren.Reed@Sun.COM 						tickled++;
37110639SDarren.Reed@Sun.COM 					}
37210639SDarren.Reed@Sun.COM 				}
37310639SDarren.Reed@Sun.COM 			}
37410639SDarren.Reed@Sun.COM 		}
37510639SDarren.Reed@Sun.COM 
37610639SDarren.Reed@Sun.COM 	}
37710639SDarren.Reed@Sun.COM 
37810639SDarren.Reed@Sun.COM 	if (tickled != 0)
37910639SDarren.Reed@Sun.COM 		return (EWOULDBLOCK);
38010639SDarren.Reed@Sun.COM 
38110639SDarren.Reed@Sun.COM 	return (ENXIO);
38210639SDarren.Reed@Sun.COM }
38310639SDarren.Reed@Sun.COM 
38410639SDarren.Reed@Sun.COM /*
38510639SDarren.Reed@Sun.COM  * The following three functions provide the necessary callbacks into
38610639SDarren.Reed@Sun.COM  * the netinfo API. This API is primarily used to trigger awareness of
38710639SDarren.Reed@Sun.COM  * when a zone is being torn down, allowing BPF to drive IPNET to
38810639SDarren.Reed@Sun.COM  * tell it which interfaces need to go away.
38910639SDarren.Reed@Sun.COM  */
39010639SDarren.Reed@Sun.COM /*ARGSUSED*/
39110639SDarren.Reed@Sun.COM static void *
bpf_create_inst(const netid_t netid)39210639SDarren.Reed@Sun.COM bpf_create_inst(const netid_t netid)
39310639SDarren.Reed@Sun.COM {
39410639SDarren.Reed@Sun.COM 	/*
39510639SDarren.Reed@Sun.COM 	 * BPF does not keep any per-instance state, its list of
39610639SDarren.Reed@Sun.COM 	 * interfaces is global, as is its device hash table.
39710639SDarren.Reed@Sun.COM 	 */
39810639SDarren.Reed@Sun.COM 	return ((void *)bpf_itap);
39910639SDarren.Reed@Sun.COM }
40010639SDarren.Reed@Sun.COM 
40110639SDarren.Reed@Sun.COM /*ARGSUSED*/
40210639SDarren.Reed@Sun.COM static void
bpf_shutdown_inst(const netid_t netid,void * arg)40310639SDarren.Reed@Sun.COM bpf_shutdown_inst(const netid_t netid, void *arg)
40410639SDarren.Reed@Sun.COM {
40510639SDarren.Reed@Sun.COM }
40610639SDarren.Reed@Sun.COM 
40710639SDarren.Reed@Sun.COM /*ARGSUSED*/
40810639SDarren.Reed@Sun.COM static void
bpf_destroy_inst(const netid_t netid,void * arg)40910639SDarren.Reed@Sun.COM bpf_destroy_inst(const netid_t netid, void *arg)
41010639SDarren.Reed@Sun.COM {
41110639SDarren.Reed@Sun.COM }
412