4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/types.h>
28 #include <sys/param.h>
30 #include <sys/errno.h>
33 #include <sys/modctl.h>
37 #include <sys/cmn_err.h>
39 #include <sys/sunddi.h>
40 #include <sys/mac_provider.h>
41 #include <sys/dls_impl.h>
42 #include <inet/ipnet.h>
44 extern int bpfopen(dev_t
*devp
, int flag
, int otyp
, cred_t
*cred
);
45 extern int bpfclose(dev_t dev
, int flag
, int otyp
, cred_t
*cred
);
46 extern int bpfread(dev_t dev
, struct uio
*uio_p
, cred_t
*cred_p
);
47 extern int bpfwrite(dev_t dev
, struct uio
*uio
, cred_t
*cred
);
48 extern int bpfchpoll(dev_t
, short, int, short *, struct pollhead
**);
49 extern int bpfioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
50 extern int bpfilterattach(void);
51 extern int bpfilterdetach(void);
53 extern bpf_provider_t bpf_mac
;
54 extern bpf_provider_t bpf_ipnet
;
56 static int bpf_attach(dev_info_t
*, ddi_attach_cmd_t
);
57 static void *bpf_create_inst(const netid_t
);
58 static void bpf_destroy_inst(const netid_t
, void *);
59 static int bpf_detach(dev_info_t
*, ddi_detach_cmd_t
);
60 static int bpf_getinfo(dev_info_t
*, ddi_info_cmd_t
, void *, void **);
61 static int bpf_provider_add(bpf_provider_t
*);
62 static int bpf_provider_remove(bpf_provider_t
*);
63 static void bpf_shutdown_inst(const netid_t
, void *);
65 extern void bpfdetach(uintptr_t);
66 extern int bpf_bufsize
;
67 extern int bpf_maxbufsize
;
69 bpf_provider_head_t bpf_providers
;
71 static struct cb_ops bpf_cb_ops
= {
92 static struct dev_ops bpf_ops
= {
105 extern struct mod_ops mod_driverops
;
106 static struct modldrv bpfmod
= {
107 &mod_driverops
, "Berkely Packet Filter", &bpf_ops
109 static struct modlinkage modlink1
= { MODREV_1
, &bpfmod
, NULL
};
111 static dev_info_t
*bpf_dev_info
= NULL
;
112 static net_instance_t
*bpf_inst
= NULL
;
119 bpfinst
= mod_install(&modlink1
);
128 bpfinst
= mod_remove(&modlink1
);
133 _info(struct modinfo
*modinfop
)
137 bpfinst
= mod_info(&modlink1
, modinfop
);
142 bpf_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
148 * Default buffer size from bpf's driver.conf file
150 bpf_bufsize
= ddi_prop_get_int(DDI_DEV_T_ANY
, dip
, 0,
151 "buf_size", 32 * 1024);
153 * Maximum buffer size from bpf's driver.conf file
155 bpf_maxbufsize
= ddi_prop_get_int(DDI_DEV_T_ANY
, dip
, 0,
156 "max_buf_size", 16 * 1024 * 1024);
158 if (ddi_create_minor_node(dip
, "bpf", S_IFCHR
, 0,
159 DDI_PSEUDO
, 0) == DDI_FAILURE
) {
160 ddi_remove_minor_node(dip
, NULL
);
166 LIST_INIT(&bpf_providers
);
168 if (bpfilterattach() != 0)
171 ipnet_set_itap(bpf_itap
);
172 VERIFY(bpf_provider_add(&bpf_ipnet
) == 0);
173 VERIFY(bpf_provider_add(&bpf_mac
) == 0);
176 * Set up to be notified about zones coming and going
177 * so that proper interaction with ipnet is possible.
179 bpf_inst
= net_instance_alloc(NETINFO_VERSION
);
180 if (bpf_inst
== NULL
)
182 bpf_inst
->nin_name
= "bpf";
183 bpf_inst
->nin_create
= bpf_create_inst
;
184 bpf_inst
->nin_destroy
= bpf_destroy_inst
;
185 bpf_inst
->nin_shutdown
= bpf_shutdown_inst
;
186 if (net_instance_register(bpf_inst
) != 0) {
187 net_instance_free(bpf_inst
);
191 return (DDI_SUCCESS
);
194 return (DDI_SUCCESS
);
203 * Use our own detach routine to toss
204 * away any stuff we allocated above.
206 (void) bpfilterdetach();
207 (void) bpf_detach(dip
, DDI_DETACH
);
208 return (DDI_FAILURE
);
212 bpf_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
218 if (net_instance_unregister(bpf_inst
) != 0)
219 return (DDI_FAILURE
);
220 net_instance_free(bpf_inst
);
222 ipnet_set_itap(NULL
);
223 error
= bpfilterdetach();
225 return (DDI_FAILURE
);
226 VERIFY(bpf_provider_remove(&bpf_ipnet
) == 0);
227 VERIFY(bpf_provider_remove(&bpf_mac
) == 0);
229 ASSERT(LIST_EMPTY(&bpf_providers
));
231 ddi_prop_remove_all(dip
);
233 return (DDI_SUCCESS
);
237 return (DDI_SUCCESS
);
242 return (DDI_FAILURE
);
247 bpf_getinfo(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
249 int error
= DDI_FAILURE
;
252 case DDI_INFO_DEVT2DEVINFO
:
253 *result
= bpf_dev_info
;
256 case DDI_INFO_DEVT2INSTANCE
:
267 * The two functions below work with and manage a list of providers that
268 * supply BPF with packets. Their addition and removal is only happens
269 * when the bpf module is attaching/detaching, thus there is no race
270 * condition to guard against with using locks as the kernel module system
271 * takes care of this for us. Similarly, bpf_provider_tickle() is called
272 * from bpf_setif, which implies an open file descriptor that would get
273 * in the way of detach being active.
276 bpf_provider_add(bpf_provider_t
*provider
)
278 bpf_provider_list_t
*bp
;
280 LIST_FOREACH(bp
, &bpf_providers
, bpl_next
) {
281 if (bp
->bpl_what
== provider
)
286 bp
= kmem_alloc(sizeof (*bp
), KM_SLEEP
);
287 bp
->bpl_what
= provider
;
288 LIST_INSERT_HEAD(&bpf_providers
, bp
, bpl_next
);
294 bpf_provider_remove(bpf_provider_t
*provider
)
296 bpf_provider_list_t
*bp
;
298 LIST_FOREACH(bp
, &bpf_providers
, bpl_next
) {
299 if (bp
->bpl_what
== provider
)
306 LIST_REMOVE(bp
, bpl_next
);
308 kmem_free(bp
, sizeof (*bp
));
314 * return a pointer to the structure that holds all of the functions
315 * available to be used to support a particular packet provider.
318 bpf_find_provider_by_id(int who
)
320 bpf_provider_list_t
*b
;
322 LIST_FOREACH(b
, &bpf_providers
, bpl_next
) {
323 if (b
->bpl_what
->bpr_unit
== who
)
324 return (b
->bpl_what
);
331 * This function is used by bpf_setif() to force an open() to be called on
332 * a given device name. If a device has been unloaded by the kernel, but it
333 * is still recognised, then calling this function will hopefully cause it
334 * to be loaded back into the kernel. When this function is called, it is
335 * not known which packet provider the name belongs to so all are tried.
338 bpf_provider_tickle(char *name
, zoneid_t zone
)
340 bpf_provider_list_t
*bp
;
344 LIST_FOREACH(bp
, &bpf_providers
, bpl_next
) {
346 if (bp
->bpl_what
->bpr_open(name
, &handle
, zone
) == 0) {
347 bp
->bpl_what
->bpr_close(handle
);
349 } else if (bp
->bpl_what
->bpr_unit
== BPR_MAC
) {
351 * For mac devices, sometimes the open/close is not
352 * enough. In that case, further provocation is
353 * attempted by fetching the linkid and trying to
354 * use that as the key for open, rather than the
359 if (bp
->bpl_what
->bpr_getlinkid(name
, &id
,
361 if (bp
->bpl_what
->bpr_open(name
, &handle
,
363 bp
->bpl_what
->bpr_close(handle
);
368 if (mac_open_by_linkid(id
, &mh
) == 0) {
379 return (EWOULDBLOCK
);
385 * The following three functions provide the necessary callbacks into
386 * the netinfo API. This API is primarily used to trigger awareness of
387 * when a zone is being torn down, allowing BPF to drive IPNET to
388 * tell it which interfaces need to go away.
392 bpf_create_inst(const netid_t netid
)
395 * BPF does not keep any per-instance state, its list of
396 * interfaces is global, as is its device hash table.
398 return ((void *)bpf_itap
);
403 bpf_shutdown_inst(const netid_t netid
, void *arg
)
409 bpf_destroy_inst(const netid_t netid
, void *arg
)