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