xref: /onnv-gate/usr/src/uts/common/io/bpf/bpf_mod.c (revision 10639:368f1335a058)
1*10639SDarren.Reed@Sun.COM /*
2*10639SDarren.Reed@Sun.COM  * CDDL HEADER START
3*10639SDarren.Reed@Sun.COM  *
4*10639SDarren.Reed@Sun.COM  * The contents of this file are subject to the terms of the
5*10639SDarren.Reed@Sun.COM  * Common Development and Distribution License (the "License").
6*10639SDarren.Reed@Sun.COM  * You may not use this file except in compliance with the License.
7*10639SDarren.Reed@Sun.COM  *
8*10639SDarren.Reed@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*10639SDarren.Reed@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*10639SDarren.Reed@Sun.COM  * See the License for the specific language governing permissions
11*10639SDarren.Reed@Sun.COM  * and limitations under the License.
12*10639SDarren.Reed@Sun.COM  *
13*10639SDarren.Reed@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*10639SDarren.Reed@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*10639SDarren.Reed@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*10639SDarren.Reed@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*10639SDarren.Reed@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*10639SDarren.Reed@Sun.COM  *
19*10639SDarren.Reed@Sun.COM  * CDDL HEADER END
20*10639SDarren.Reed@Sun.COM  */
21*10639SDarren.Reed@Sun.COM 
22*10639SDarren.Reed@Sun.COM /*
23*10639SDarren.Reed@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*10639SDarren.Reed@Sun.COM  * Use is subject to license terms.
25*10639SDarren.Reed@Sun.COM  */
26*10639SDarren.Reed@Sun.COM 
27*10639SDarren.Reed@Sun.COM #include <sys/types.h>
28*10639SDarren.Reed@Sun.COM #include <sys/param.h>
29*10639SDarren.Reed@Sun.COM #include <sys/stat.h>
30*10639SDarren.Reed@Sun.COM #include <sys/errno.h>
31*10639SDarren.Reed@Sun.COM #include <sys/uio.h>
32*10639SDarren.Reed@Sun.COM #include <sys/buf.h>
33*10639SDarren.Reed@Sun.COM #include <sys/modctl.h>
34*10639SDarren.Reed@Sun.COM #include <sys/open.h>
35*10639SDarren.Reed@Sun.COM #include <sys/kmem.h>
36*10639SDarren.Reed@Sun.COM #include <sys/conf.h>
37*10639SDarren.Reed@Sun.COM #include <sys/cmn_err.h>
38*10639SDarren.Reed@Sun.COM #include <sys/cred.h>
39*10639SDarren.Reed@Sun.COM #include <sys/sunddi.h>
40*10639SDarren.Reed@Sun.COM #include <sys/mac_provider.h>
41*10639SDarren.Reed@Sun.COM #include <sys/dls_impl.h>
42*10639SDarren.Reed@Sun.COM #include <inet/ipnet.h>
43*10639SDarren.Reed@Sun.COM 
44*10639SDarren.Reed@Sun.COM extern	int	bpfopen(dev_t *devp, int flag, int otyp, cred_t *cred);
45*10639SDarren.Reed@Sun.COM extern	int	bpfclose(dev_t dev, int flag, int otyp, cred_t *cred);
46*10639SDarren.Reed@Sun.COM extern	int	bpfread(dev_t dev, struct uio *uio_p, cred_t *cred_p);
47*10639SDarren.Reed@Sun.COM extern	int	bpfwrite(dev_t dev, struct uio *uio, cred_t *cred);
48*10639SDarren.Reed@Sun.COM extern	int	bpfchpoll(dev_t, short, int, short *, struct pollhead **);
49*10639SDarren.Reed@Sun.COM extern	int	bpfioctl(dev_t, int, intptr_t, int, cred_t *, int *);
50*10639SDarren.Reed@Sun.COM extern	int	bpfilterattach(void);
51*10639SDarren.Reed@Sun.COM extern	int	bpfilterdetach(void);
52*10639SDarren.Reed@Sun.COM 
53*10639SDarren.Reed@Sun.COM extern	bpf_provider_t	bpf_mac;
54*10639SDarren.Reed@Sun.COM extern	bpf_provider_t	bpf_ipnet;
55*10639SDarren.Reed@Sun.COM 
56*10639SDarren.Reed@Sun.COM static	int	bpf_attach(dev_info_t *, ddi_attach_cmd_t);
57*10639SDarren.Reed@Sun.COM static	void	*bpf_create_inst(const netid_t);
58*10639SDarren.Reed@Sun.COM static	void	bpf_destroy_inst(const netid_t, void *);
59*10639SDarren.Reed@Sun.COM static	int	bpf_detach(dev_info_t *, ddi_detach_cmd_t);
60*10639SDarren.Reed@Sun.COM static	int	bpf_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
61*10639SDarren.Reed@Sun.COM static	int	bpf_provider_add(bpf_provider_t *);
62*10639SDarren.Reed@Sun.COM static	int	bpf_provider_remove(bpf_provider_t *);
63*10639SDarren.Reed@Sun.COM static	void	bpf_shutdown_inst(const netid_t, void *);
64*10639SDarren.Reed@Sun.COM 
65*10639SDarren.Reed@Sun.COM extern	void	bpfdetach(uintptr_t);
66*10639SDarren.Reed@Sun.COM extern	int	bpf_bufsize;
67*10639SDarren.Reed@Sun.COM extern	int	bpf_maxbufsize;
68*10639SDarren.Reed@Sun.COM 
69*10639SDarren.Reed@Sun.COM static LIST_HEAD(, bpf_provider_list) bpf_providers;
70*10639SDarren.Reed@Sun.COM 
71*10639SDarren.Reed@Sun.COM static struct cb_ops bpf_cb_ops = {
72*10639SDarren.Reed@Sun.COM 	bpfopen,
73*10639SDarren.Reed@Sun.COM 	bpfclose,
74*10639SDarren.Reed@Sun.COM 	nodev,		/* strategy */
75*10639SDarren.Reed@Sun.COM 	nodev,		/* print */
76*10639SDarren.Reed@Sun.COM 	nodev,		/* dump */
77*10639SDarren.Reed@Sun.COM 	bpfread,
78*10639SDarren.Reed@Sun.COM 	bpfwrite,	/* write */
79*10639SDarren.Reed@Sun.COM 	bpfioctl,	/* ioctl */
80*10639SDarren.Reed@Sun.COM 	nodev,		/* devmap */
81*10639SDarren.Reed@Sun.COM 	nodev,		/* mmap */
82*10639SDarren.Reed@Sun.COM 	nodev,		/* segmap */
83*10639SDarren.Reed@Sun.COM 	bpfchpoll,	/* poll */
84*10639SDarren.Reed@Sun.COM 	ddi_prop_op,
85*10639SDarren.Reed@Sun.COM 	NULL,
86*10639SDarren.Reed@Sun.COM 	D_MTSAFE,
87*10639SDarren.Reed@Sun.COM 	CB_REV,
88*10639SDarren.Reed@Sun.COM 	nodev,		/* aread */
89*10639SDarren.Reed@Sun.COM 	nodev,		/* awrite */
90*10639SDarren.Reed@Sun.COM };
91*10639SDarren.Reed@Sun.COM 
92*10639SDarren.Reed@Sun.COM static struct dev_ops bpf_ops = {
93*10639SDarren.Reed@Sun.COM 	DEVO_REV,
94*10639SDarren.Reed@Sun.COM 	0,
95*10639SDarren.Reed@Sun.COM 	bpf_getinfo,
96*10639SDarren.Reed@Sun.COM 	nulldev,
97*10639SDarren.Reed@Sun.COM 	nulldev,
98*10639SDarren.Reed@Sun.COM 	bpf_attach,
99*10639SDarren.Reed@Sun.COM 	bpf_detach,
100*10639SDarren.Reed@Sun.COM 	nodev,		/* reset */
101*10639SDarren.Reed@Sun.COM 	&bpf_cb_ops,
102*10639SDarren.Reed@Sun.COM 	(struct bus_ops *)0
103*10639SDarren.Reed@Sun.COM };
104*10639SDarren.Reed@Sun.COM 
105*10639SDarren.Reed@Sun.COM extern struct mod_ops mod_driverops;
106*10639SDarren.Reed@Sun.COM static struct modldrv bpfmod = {
107*10639SDarren.Reed@Sun.COM 	&mod_driverops, "Berkely Packet Filter", &bpf_ops
108*10639SDarren.Reed@Sun.COM };
109*10639SDarren.Reed@Sun.COM static struct modlinkage modlink1 = { MODREV_1, &bpfmod, NULL };
110*10639SDarren.Reed@Sun.COM 
111*10639SDarren.Reed@Sun.COM static dev_info_t *bpf_dev_info = NULL;
112*10639SDarren.Reed@Sun.COM static net_instance_t *bpf_inst = NULL;
113*10639SDarren.Reed@Sun.COM 
114*10639SDarren.Reed@Sun.COM int
115*10639SDarren.Reed@Sun.COM _init()
116*10639SDarren.Reed@Sun.COM {
117*10639SDarren.Reed@Sun.COM 	int bpfinst;
118*10639SDarren.Reed@Sun.COM 
119*10639SDarren.Reed@Sun.COM 	bpfinst = mod_install(&modlink1);
120*10639SDarren.Reed@Sun.COM 	return (bpfinst);
121*10639SDarren.Reed@Sun.COM }
122*10639SDarren.Reed@Sun.COM 
123*10639SDarren.Reed@Sun.COM int
124*10639SDarren.Reed@Sun.COM _fini(void)
125*10639SDarren.Reed@Sun.COM {
126*10639SDarren.Reed@Sun.COM 	int bpfinst;
127*10639SDarren.Reed@Sun.COM 
128*10639SDarren.Reed@Sun.COM 	bpfinst = mod_remove(&modlink1);
129*10639SDarren.Reed@Sun.COM 	return (bpfinst);
130*10639SDarren.Reed@Sun.COM }
131*10639SDarren.Reed@Sun.COM 
132*10639SDarren.Reed@Sun.COM int
133*10639SDarren.Reed@Sun.COM _info(struct modinfo *modinfop)
134*10639SDarren.Reed@Sun.COM {
135*10639SDarren.Reed@Sun.COM 	int bpfinst;
136*10639SDarren.Reed@Sun.COM 
137*10639SDarren.Reed@Sun.COM 	bpfinst = mod_info(&modlink1, modinfop);
138*10639SDarren.Reed@Sun.COM 	return (bpfinst);
139*10639SDarren.Reed@Sun.COM }
140*10639SDarren.Reed@Sun.COM 
141*10639SDarren.Reed@Sun.COM static int
142*10639SDarren.Reed@Sun.COM bpf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
143*10639SDarren.Reed@Sun.COM {
144*10639SDarren.Reed@Sun.COM 
145*10639SDarren.Reed@Sun.COM 	switch (cmd) {
146*10639SDarren.Reed@Sun.COM 	case DDI_ATTACH:
147*10639SDarren.Reed@Sun.COM 		/*
148*10639SDarren.Reed@Sun.COM 		 * Default buffer size from bpf's driver.conf file
149*10639SDarren.Reed@Sun.COM 		 */
150*10639SDarren.Reed@Sun.COM 		bpf_bufsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
151*10639SDarren.Reed@Sun.COM 		    "buf_size", 32 * 1024);
152*10639SDarren.Reed@Sun.COM 		/*
153*10639SDarren.Reed@Sun.COM 		 * Maximum buffer size from bpf's driver.conf file
154*10639SDarren.Reed@Sun.COM 		 */
155*10639SDarren.Reed@Sun.COM 		bpf_maxbufsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
156*10639SDarren.Reed@Sun.COM 		    "max_buf_size", 16 * 1024 * 1024);
157*10639SDarren.Reed@Sun.COM 
158*10639SDarren.Reed@Sun.COM 		if (ddi_create_minor_node(dip, "bpf", S_IFCHR, 0,
159*10639SDarren.Reed@Sun.COM 		    DDI_PSEUDO, 0) == DDI_FAILURE) {
160*10639SDarren.Reed@Sun.COM 			ddi_remove_minor_node(dip, NULL);
161*10639SDarren.Reed@Sun.COM 			goto attach_failed;
162*10639SDarren.Reed@Sun.COM 		}
163*10639SDarren.Reed@Sun.COM 		bpf_dev_info = dip;
164*10639SDarren.Reed@Sun.COM 		ddi_report_dev(dip);
165*10639SDarren.Reed@Sun.COM 
166*10639SDarren.Reed@Sun.COM 		LIST_INIT(&bpf_providers);
167*10639SDarren.Reed@Sun.COM 
168*10639SDarren.Reed@Sun.COM 		if (bpfilterattach() != 0)
169*10639SDarren.Reed@Sun.COM 			goto attach_failed;
170*10639SDarren.Reed@Sun.COM 
171*10639SDarren.Reed@Sun.COM 		ASSERT(bpf_provider_add(&bpf_mac) == 0);
172*10639SDarren.Reed@Sun.COM 		dls_set_bpfattach(bpfattach, bpfdetach);
173*10639SDarren.Reed@Sun.COM 		ipnet_set_bpfattach(bpfattach, bpfdetach, GLOBAL_ZONEID,
174*10639SDarren.Reed@Sun.COM 		    bpf_itap, bpf_provider_add);
175*10639SDarren.Reed@Sun.COM 
176*10639SDarren.Reed@Sun.COM 		/*
177*10639SDarren.Reed@Sun.COM 		 * Set up to be notified about zones coming and going
178*10639SDarren.Reed@Sun.COM 		 * so that proper interaction with ipnet is possible.
179*10639SDarren.Reed@Sun.COM 		 */
180*10639SDarren.Reed@Sun.COM 		bpf_inst = net_instance_alloc(NETINFO_VERSION);
181*10639SDarren.Reed@Sun.COM 		if (bpf_inst == NULL)
182*10639SDarren.Reed@Sun.COM 			goto attach_failed;
183*10639SDarren.Reed@Sun.COM 		bpf_inst->nin_name = "bpf";
184*10639SDarren.Reed@Sun.COM 		bpf_inst->nin_create = bpf_create_inst;
185*10639SDarren.Reed@Sun.COM 		bpf_inst->nin_destroy = bpf_destroy_inst;
186*10639SDarren.Reed@Sun.COM 		bpf_inst->nin_shutdown = bpf_shutdown_inst;
187*10639SDarren.Reed@Sun.COM 		if (net_instance_register(bpf_inst) != 0) {
188*10639SDarren.Reed@Sun.COM 			net_instance_free(bpf_inst);
189*10639SDarren.Reed@Sun.COM 			goto attach_failed;
190*10639SDarren.Reed@Sun.COM 		}
191*10639SDarren.Reed@Sun.COM 
192*10639SDarren.Reed@Sun.COM 		return (DDI_SUCCESS);
193*10639SDarren.Reed@Sun.COM 		/* NOTREACHED */
194*10639SDarren.Reed@Sun.COM 	case DDI_RESUME:
195*10639SDarren.Reed@Sun.COM 		return (DDI_SUCCESS);
196*10639SDarren.Reed@Sun.COM 		/* NOTREACHED */
197*10639SDarren.Reed@Sun.COM 	default:
198*10639SDarren.Reed@Sun.COM 		break;
199*10639SDarren.Reed@Sun.COM 	}
200*10639SDarren.Reed@Sun.COM 
201*10639SDarren.Reed@Sun.COM attach_failed:
202*10639SDarren.Reed@Sun.COM 
203*10639SDarren.Reed@Sun.COM 	/*
204*10639SDarren.Reed@Sun.COM 	 * Use our own detach routine to toss
205*10639SDarren.Reed@Sun.COM 	 * away any stuff we allocated above.
206*10639SDarren.Reed@Sun.COM 	 */
207*10639SDarren.Reed@Sun.COM 	(void) bpfilterdetach();
208*10639SDarren.Reed@Sun.COM 	(void) bpf_detach(dip, DDI_DETACH);
209*10639SDarren.Reed@Sun.COM 	return (DDI_FAILURE);
210*10639SDarren.Reed@Sun.COM }
211*10639SDarren.Reed@Sun.COM 
212*10639SDarren.Reed@Sun.COM static int
213*10639SDarren.Reed@Sun.COM bpf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
214*10639SDarren.Reed@Sun.COM {
215*10639SDarren.Reed@Sun.COM 	int error;
216*10639SDarren.Reed@Sun.COM 
217*10639SDarren.Reed@Sun.COM 	switch (cmd) {
218*10639SDarren.Reed@Sun.COM 	case DDI_DETACH:
219*10639SDarren.Reed@Sun.COM 		if (net_instance_unregister(bpf_inst) != 0)
220*10639SDarren.Reed@Sun.COM 			return (DDI_FAILURE);
221*10639SDarren.Reed@Sun.COM 		net_instance_free(bpf_inst);
222*10639SDarren.Reed@Sun.COM 
223*10639SDarren.Reed@Sun.COM 		ipnet_set_bpfattach(NULL, NULL, GLOBAL_ZONEID, NULL,
224*10639SDarren.Reed@Sun.COM 		    bpf_provider_remove);
225*10639SDarren.Reed@Sun.COM 		/*
226*10639SDarren.Reed@Sun.COM 		 * Whilst we don't want to be notified about new devices that
227*10639SDarren.Reed@Sun.COM 		 * are being detached, to set the bpf detach function to NULL
228*10639SDarren.Reed@Sun.COM 		 * introduces a race condition between this kernel module
229*10639SDarren.Reed@Sun.COM 		 * unloading and a network interface driver also unloading.
230*10639SDarren.Reed@Sun.COM 		 */
231*10639SDarren.Reed@Sun.COM 		dls_set_bpfattach(NULL, bpfdetach);
232*10639SDarren.Reed@Sun.COM 		error = bpfilterdetach();
233*10639SDarren.Reed@Sun.COM 		if (error != 0)
234*10639SDarren.Reed@Sun.COM 			return (DDI_FAILURE);
235*10639SDarren.Reed@Sun.COM 		/*
236*10639SDarren.Reed@Sun.COM 		 * Now everything is clean, set the detach to NULL too.
237*10639SDarren.Reed@Sun.COM 		 */
238*10639SDarren.Reed@Sun.COM 		dls_set_bpfattach(NULL, NULL);
239*10639SDarren.Reed@Sun.COM 		ASSERT(bpf_provider_remove(&bpf_mac) == 0);
240*10639SDarren.Reed@Sun.COM 
241*10639SDarren.Reed@Sun.COM 		ASSERT(LIST_EMPTY(&bpf_providers));
242*10639SDarren.Reed@Sun.COM 
243*10639SDarren.Reed@Sun.COM 		ddi_prop_remove_all(dip);
244*10639SDarren.Reed@Sun.COM 
245*10639SDarren.Reed@Sun.COM 		return (DDI_SUCCESS);
246*10639SDarren.Reed@Sun.COM 		/* NOTREACHED */
247*10639SDarren.Reed@Sun.COM 	case DDI_SUSPEND:
248*10639SDarren.Reed@Sun.COM 	case DDI_PM_SUSPEND:
249*10639SDarren.Reed@Sun.COM 		return (DDI_SUCCESS);
250*10639SDarren.Reed@Sun.COM 		/* NOTREACHED */
251*10639SDarren.Reed@Sun.COM 	default:
252*10639SDarren.Reed@Sun.COM 		break;
253*10639SDarren.Reed@Sun.COM 	}
254*10639SDarren.Reed@Sun.COM 	return (DDI_FAILURE);
255*10639SDarren.Reed@Sun.COM }
256*10639SDarren.Reed@Sun.COM 
257*10639SDarren.Reed@Sun.COM /*ARGSUSED*/
258*10639SDarren.Reed@Sun.COM static int
259*10639SDarren.Reed@Sun.COM bpf_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
260*10639SDarren.Reed@Sun.COM {
261*10639SDarren.Reed@Sun.COM 	int error = DDI_FAILURE;
262*10639SDarren.Reed@Sun.COM 
263*10639SDarren.Reed@Sun.COM 	switch (infocmd) {
264*10639SDarren.Reed@Sun.COM 	case DDI_INFO_DEVT2DEVINFO:
265*10639SDarren.Reed@Sun.COM 		*result = bpf_dev_info;
266*10639SDarren.Reed@Sun.COM 		error = DDI_SUCCESS;
267*10639SDarren.Reed@Sun.COM 		break;
268*10639SDarren.Reed@Sun.COM 	case DDI_INFO_DEVT2INSTANCE:
269*10639SDarren.Reed@Sun.COM 		*result = (void *)0;
270*10639SDarren.Reed@Sun.COM 		error = DDI_SUCCESS;
271*10639SDarren.Reed@Sun.COM 		break;
272*10639SDarren.Reed@Sun.COM 	default:
273*10639SDarren.Reed@Sun.COM 		break;
274*10639SDarren.Reed@Sun.COM 	}
275*10639SDarren.Reed@Sun.COM 	return (error);
276*10639SDarren.Reed@Sun.COM }
277*10639SDarren.Reed@Sun.COM 
278*10639SDarren.Reed@Sun.COM /*
279*10639SDarren.Reed@Sun.COM  * The two functions below work with and manage a list of providers that
280*10639SDarren.Reed@Sun.COM  * supply BPF with packets. Their addition and removal is only happens
281*10639SDarren.Reed@Sun.COM  * when the bpf module is attaching/detaching, thus there is no race
282*10639SDarren.Reed@Sun.COM  * condition to guard against with using locks as the kernel module system
283*10639SDarren.Reed@Sun.COM  * takes care of this for us. Similarly, bpf_provider_tickle() is called
284*10639SDarren.Reed@Sun.COM  * from bpf_setif, which implies an open file descriptor that would get
285*10639SDarren.Reed@Sun.COM  * in the way of detach being active.
286*10639SDarren.Reed@Sun.COM  */
287*10639SDarren.Reed@Sun.COM static int
288*10639SDarren.Reed@Sun.COM bpf_provider_add(bpf_provider_t *provider)
289*10639SDarren.Reed@Sun.COM {
290*10639SDarren.Reed@Sun.COM 	bpf_provider_list_t *bp;
291*10639SDarren.Reed@Sun.COM 
292*10639SDarren.Reed@Sun.COM 	LIST_FOREACH(bp, &bpf_providers, bpl_next) {
293*10639SDarren.Reed@Sun.COM 		if (bp->bpl_what == provider)
294*10639SDarren.Reed@Sun.COM 			return (EEXIST);
295*10639SDarren.Reed@Sun.COM 	}
296*10639SDarren.Reed@Sun.COM 
297*10639SDarren.Reed@Sun.COM 
298*10639SDarren.Reed@Sun.COM 	bp = kmem_alloc(sizeof (*bp), KM_SLEEP);
299*10639SDarren.Reed@Sun.COM 	bp->bpl_what = provider;
300*10639SDarren.Reed@Sun.COM 	LIST_INSERT_HEAD(&bpf_providers, bp, bpl_next);
301*10639SDarren.Reed@Sun.COM 
302*10639SDarren.Reed@Sun.COM 	return (0);
303*10639SDarren.Reed@Sun.COM }
304*10639SDarren.Reed@Sun.COM 
305*10639SDarren.Reed@Sun.COM static int
306*10639SDarren.Reed@Sun.COM bpf_provider_remove(bpf_provider_t *provider)
307*10639SDarren.Reed@Sun.COM {
308*10639SDarren.Reed@Sun.COM 	bpf_provider_list_t *bp;
309*10639SDarren.Reed@Sun.COM 
310*10639SDarren.Reed@Sun.COM 	LIST_FOREACH(bp, &bpf_providers, bpl_next) {
311*10639SDarren.Reed@Sun.COM 		if (bp->bpl_what == provider)
312*10639SDarren.Reed@Sun.COM 			break;
313*10639SDarren.Reed@Sun.COM 	}
314*10639SDarren.Reed@Sun.COM 
315*10639SDarren.Reed@Sun.COM 	if (bp == NULL)
316*10639SDarren.Reed@Sun.COM 		return (ESRCH);
317*10639SDarren.Reed@Sun.COM 
318*10639SDarren.Reed@Sun.COM 	LIST_REMOVE(bp, bpl_next);
319*10639SDarren.Reed@Sun.COM 
320*10639SDarren.Reed@Sun.COM 	kmem_free(bp, sizeof (*bp));
321*10639SDarren.Reed@Sun.COM 
322*10639SDarren.Reed@Sun.COM 	return (0);
323*10639SDarren.Reed@Sun.COM }
324*10639SDarren.Reed@Sun.COM 
325*10639SDarren.Reed@Sun.COM /*
326*10639SDarren.Reed@Sun.COM  * return a pointer to the structure that holds all of the functions
327*10639SDarren.Reed@Sun.COM  * available to be used to support a particular packet provider.
328*10639SDarren.Reed@Sun.COM  */
329*10639SDarren.Reed@Sun.COM bpf_provider_t *
330*10639SDarren.Reed@Sun.COM bpf_find_provider_by_id(int who)
331*10639SDarren.Reed@Sun.COM {
332*10639SDarren.Reed@Sun.COM 	bpf_provider_list_t *b;
333*10639SDarren.Reed@Sun.COM 
334*10639SDarren.Reed@Sun.COM 	LIST_FOREACH(b, &bpf_providers, bpl_next) {
335*10639SDarren.Reed@Sun.COM 		if (b->bpl_what->bpr_unit == who)
336*10639SDarren.Reed@Sun.COM 			return (b->bpl_what);
337*10639SDarren.Reed@Sun.COM 	}
338*10639SDarren.Reed@Sun.COM 
339*10639SDarren.Reed@Sun.COM 	return (NULL);
340*10639SDarren.Reed@Sun.COM }
341*10639SDarren.Reed@Sun.COM 
342*10639SDarren.Reed@Sun.COM /*
343*10639SDarren.Reed@Sun.COM  * This function is used by bpf_setif() to force an open() to be called on
344*10639SDarren.Reed@Sun.COM  * a given device name. If a device has been unloaded by the kernel, but it
345*10639SDarren.Reed@Sun.COM  * is still recognised, then calling this function will hopefully cause it
346*10639SDarren.Reed@Sun.COM  * to be loaded back into the kernel. When this function is called, it is
347*10639SDarren.Reed@Sun.COM  * not known which packet provider the name belongs to so all are tried.
348*10639SDarren.Reed@Sun.COM  */
349*10639SDarren.Reed@Sun.COM int
350*10639SDarren.Reed@Sun.COM bpf_provider_tickle(char *name, zoneid_t zone)
351*10639SDarren.Reed@Sun.COM {
352*10639SDarren.Reed@Sun.COM 	bpf_provider_list_t *bp;
353*10639SDarren.Reed@Sun.COM 	uintptr_t handle;
354*10639SDarren.Reed@Sun.COM 	int tickled = 0;
355*10639SDarren.Reed@Sun.COM 
356*10639SDarren.Reed@Sun.COM 	LIST_FOREACH(bp, &bpf_providers, bpl_next) {
357*10639SDarren.Reed@Sun.COM 		handle = 0;
358*10639SDarren.Reed@Sun.COM 		if (bp->bpl_what->bpr_open(name, &handle, zone) == 0) {
359*10639SDarren.Reed@Sun.COM 			bp->bpl_what->bpr_close(handle);
360*10639SDarren.Reed@Sun.COM 			tickled++;
361*10639SDarren.Reed@Sun.COM 		} else if (bp->bpl_what->bpr_unit == BPR_MAC) {
362*10639SDarren.Reed@Sun.COM 			/*
363*10639SDarren.Reed@Sun.COM 			 * For mac devices, sometimes the open/close is not
364*10639SDarren.Reed@Sun.COM 			 * enough. In that case, further provocation is
365*10639SDarren.Reed@Sun.COM 			 * attempted by fetching the linkid and trying to
366*10639SDarren.Reed@Sun.COM 			 * use that as the key for open, rather than the
367*10639SDarren.Reed@Sun.COM 			 * name.
368*10639SDarren.Reed@Sun.COM 			 */
369*10639SDarren.Reed@Sun.COM 			datalink_id_t id;
370*10639SDarren.Reed@Sun.COM 
371*10639SDarren.Reed@Sun.COM 			if (bp->bpl_what->bpr_getlinkid(name, &id,
372*10639SDarren.Reed@Sun.COM 			    zone) == 0) {
373*10639SDarren.Reed@Sun.COM 				if (bp->bpl_what->bpr_open(name, &handle,
374*10639SDarren.Reed@Sun.COM 				    zone) == 0) {
375*10639SDarren.Reed@Sun.COM 					bp->bpl_what->bpr_close(handle);
376*10639SDarren.Reed@Sun.COM 					tickled++;
377*10639SDarren.Reed@Sun.COM 				} else {
378*10639SDarren.Reed@Sun.COM 					mac_handle_t mh;
379*10639SDarren.Reed@Sun.COM 
380*10639SDarren.Reed@Sun.COM 					if (mac_open_by_linkid(id, &mh) == 0) {
381*10639SDarren.Reed@Sun.COM 						mac_close(mh);
382*10639SDarren.Reed@Sun.COM 						tickled++;
383*10639SDarren.Reed@Sun.COM 					}
384*10639SDarren.Reed@Sun.COM 				}
385*10639SDarren.Reed@Sun.COM 			}
386*10639SDarren.Reed@Sun.COM 		}
387*10639SDarren.Reed@Sun.COM 
388*10639SDarren.Reed@Sun.COM 	}
389*10639SDarren.Reed@Sun.COM 
390*10639SDarren.Reed@Sun.COM 	if (tickled != 0)
391*10639SDarren.Reed@Sun.COM 		return (EWOULDBLOCK);
392*10639SDarren.Reed@Sun.COM 
393*10639SDarren.Reed@Sun.COM 	return (ENXIO);
394*10639SDarren.Reed@Sun.COM }
395*10639SDarren.Reed@Sun.COM 
396*10639SDarren.Reed@Sun.COM /*
397*10639SDarren.Reed@Sun.COM  * The following three functions provide the necessary callbacks into
398*10639SDarren.Reed@Sun.COM  * the netinfo API. This API is primarily used to trigger awareness of
399*10639SDarren.Reed@Sun.COM  * when a zone is being torn down, allowing BPF to drive IPNET to
400*10639SDarren.Reed@Sun.COM  * tell it which interfaces need to go away.
401*10639SDarren.Reed@Sun.COM  */
402*10639SDarren.Reed@Sun.COM /*ARGSUSED*/
403*10639SDarren.Reed@Sun.COM static void *
404*10639SDarren.Reed@Sun.COM bpf_create_inst(const netid_t netid)
405*10639SDarren.Reed@Sun.COM {
406*10639SDarren.Reed@Sun.COM 	/*
407*10639SDarren.Reed@Sun.COM 	 * BPF does not keep any per-instance state, its list of
408*10639SDarren.Reed@Sun.COM 	 * interfaces is global, as is its device hash table.
409*10639SDarren.Reed@Sun.COM 	 */
410*10639SDarren.Reed@Sun.COM 	return ((void *)bpf_itap);
411*10639SDarren.Reed@Sun.COM }
412*10639SDarren.Reed@Sun.COM 
413*10639SDarren.Reed@Sun.COM /*ARGSUSED*/
414*10639SDarren.Reed@Sun.COM static void
415*10639SDarren.Reed@Sun.COM bpf_shutdown_inst(const netid_t netid, void *arg)
416*10639SDarren.Reed@Sun.COM {
417*10639SDarren.Reed@Sun.COM 	zoneid_t zoneid;
418*10639SDarren.Reed@Sun.COM 
419*10639SDarren.Reed@Sun.COM 	zoneid = net_getzoneidbynetid(netid);
420*10639SDarren.Reed@Sun.COM 	if (zoneid != GLOBAL_ZONEID) {
421*10639SDarren.Reed@Sun.COM 		ipnet_set_bpfattach(NULL, NULL, zoneid, NULL, NULL);
422*10639SDarren.Reed@Sun.COM 	}
423*10639SDarren.Reed@Sun.COM }
424*10639SDarren.Reed@Sun.COM 
425*10639SDarren.Reed@Sun.COM /*ARGSUSED*/
426*10639SDarren.Reed@Sun.COM static void
427*10639SDarren.Reed@Sun.COM bpf_destroy_inst(const netid_t netid, void *arg)
428*10639SDarren.Reed@Sun.COM {
429*10639SDarren.Reed@Sun.COM }
430*10639SDarren.Reed@Sun.COM 
431*10639SDarren.Reed@Sun.COM /*
432*10639SDarren.Reed@Sun.COM  * This function is required, and is called from bpfopen, rather than
433*10639SDarren.Reed@Sun.COM  * bpf_create_inst() for the simple reason that when bpf_create_inst()
434*10639SDarren.Reed@Sun.COM  * is called, the zone is not fully initialised yet. This leads fo
435*10639SDarren.Reed@Sun.COM  * functions that map the zoneid to pointers failing (when they should
436*10639SDarren.Reed@Sun.COM  * not be failing) and thus the system panic'ing.
437*10639SDarren.Reed@Sun.COM  */
438*10639SDarren.Reed@Sun.COM void
439*10639SDarren.Reed@Sun.COM bpf_open_zone(const zoneid_t zoneid)
440*10639SDarren.Reed@Sun.COM {
441*10639SDarren.Reed@Sun.COM 	ipnet_set_bpfattach(bpfattach, bpfdetach,
442*10639SDarren.Reed@Sun.COM 	    zoneid, bpf_itap, bpf_provider_add);
443*10639SDarren.Reed@Sun.COM }
444