1 /*
   2  * CDDL HEADER START
   3  *
   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.
   7  *
   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.
  12  *
  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]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <sys/types.h>
  28 #include <sys/param.h>
  29 #include <sys/stat.h>
  30 #include <sys/errno.h>
  31 #include <sys/uio.h>
  32 #include <sys/buf.h>
  33 #include <sys/modctl.h>
  34 #include <sys/open.h>
  35 #include <sys/kmem.h>
  36 #include <sys/conf.h>
  37 #include <sys/cmn_err.h>
  38 #include <sys/cred.h>
  39 #include <sys/sunddi.h>
  40 #include <sys/mac_provider.h>
  41 #include <sys/dls_impl.h>
  42 #include <inet/ipnet.h>
  43 
  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);
  52 
  53 extern  bpf_provider_t  bpf_mac;
  54 extern  bpf_provider_t  bpf_ipnet;
  55 
  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 *);
  64 
  65 extern  void    bpfdetach(uintptr_t);
  66 extern  int     bpf_bufsize;
  67 extern  int     bpf_maxbufsize;
  68 
  69 bpf_provider_head_t bpf_providers;
  70 
  71 static struct cb_ops bpf_cb_ops = {
  72         bpfopen,
  73         bpfclose,
  74         nodev,          /* strategy */
  75         nodev,          /* print */
  76         nodev,          /* dump */
  77         bpfread,
  78         bpfwrite,       /* write */
  79         bpfioctl,       /* ioctl */
  80         nodev,          /* devmap */
  81         nodev,          /* mmap */
  82         nodev,          /* segmap */
  83         bpfchpoll,      /* poll */
  84         ddi_prop_op,
  85         NULL,
  86         D_MTSAFE,
  87         CB_REV,
  88         nodev,          /* aread */
  89         nodev,          /* awrite */
  90 };
  91 
  92 static struct dev_ops bpf_ops = {
  93         DEVO_REV,
  94         0,
  95         bpf_getinfo,
  96         nulldev,
  97         nulldev,
  98         bpf_attach,
  99         bpf_detach,
 100         nodev,          /* reset */
 101         &bpf_cb_ops,
 102         (struct bus_ops *)0
 103 };
 104 
 105 extern struct mod_ops mod_driverops;
 106 static struct modldrv bpfmod = {
 107         &mod_driverops, "Berkely Packet Filter", &bpf_ops
 108 };
 109 static struct modlinkage modlink1 = { MODREV_1, &bpfmod, NULL };
 110 
 111 static dev_info_t *bpf_dev_info = NULL;
 112 static net_instance_t *bpf_inst = NULL;
 113 
 114 int
 115 _init()
 116 {
 117         int bpfinst;
 118 
 119         bpfinst = mod_install(&modlink1);
 120         return (bpfinst);
 121 }
 122 
 123 int
 124 _fini(void)
 125 {
 126         int bpfinst;
 127 
 128         bpfinst = mod_remove(&modlink1);
 129         return (bpfinst);
 130 }
 131 
 132 int
 133 _info(struct modinfo *modinfop)
 134 {
 135         int bpfinst;
 136 
 137         bpfinst = mod_info(&modlink1, modinfop);
 138         return (bpfinst);
 139 }
 140 
 141 static int
 142 bpf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 143 {
 144 
 145         switch (cmd) {
 146         case DDI_ATTACH:
 147                 /*
 148                  * Default buffer size from bpf's driver.conf file
 149                  */
 150                 bpf_bufsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
 151                     "buf_size", 32 * 1024);
 152                 /*
 153                  * Maximum buffer size from bpf's driver.conf file
 154                  */
 155                 bpf_maxbufsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
 156                     "max_buf_size", 16 * 1024 * 1024);
 157 
 158                 if (ddi_create_minor_node(dip, "bpf", S_IFCHR, 0,
 159                     DDI_PSEUDO, 0) == DDI_FAILURE) {
 160                         ddi_remove_minor_node(dip, NULL);
 161                         goto attach_failed;
 162                 }
 163                 bpf_dev_info = dip;
 164                 ddi_report_dev(dip);
 165 
 166                 LIST_INIT(&bpf_providers);
 167 
 168                 if (bpfilterattach() != 0)
 169                         goto attach_failed;
 170 
 171                 ipnet_set_itap(bpf_itap);
 172                 VERIFY(bpf_provider_add(&bpf_ipnet) == 0);
 173                 VERIFY(bpf_provider_add(&bpf_mac) == 0);
 174 
 175                 /*
 176                  * Set up to be notified about zones coming and going
 177                  * so that proper interaction with ipnet is possible.
 178                  */
 179                 bpf_inst = net_instance_alloc(NETINFO_VERSION);
 180                 if (bpf_inst == NULL)
 181                         goto attach_failed;
 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);
 188                         goto attach_failed;
 189                 }
 190 
 191                 return (DDI_SUCCESS);
 192                 /* NOTREACHED */
 193         case DDI_RESUME:
 194                 return (DDI_SUCCESS);
 195                 /* NOTREACHED */
 196         default:
 197                 break;
 198         }
 199 
 200 attach_failed:
 201 
 202         /*
 203          * Use our own detach routine to toss
 204          * away any stuff we allocated above.
 205          */
 206         (void) bpfilterdetach();
 207         (void) bpf_detach(dip, DDI_DETACH);
 208         return (DDI_FAILURE);
 209 }
 210 
 211 static int
 212 bpf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 213 {
 214         int error;
 215 
 216         switch (cmd) {
 217         case DDI_DETACH:
 218                 if (net_instance_unregister(bpf_inst) != 0)
 219                         return (DDI_FAILURE);
 220                 net_instance_free(bpf_inst);
 221 
 222                 ipnet_set_itap(NULL);
 223                 error = bpfilterdetach();
 224                 if (error != 0)
 225                         return (DDI_FAILURE);
 226                 VERIFY(bpf_provider_remove(&bpf_ipnet) == 0);
 227                 VERIFY(bpf_provider_remove(&bpf_mac) == 0);
 228 
 229                 ASSERT(LIST_EMPTY(&bpf_providers));
 230 
 231                 ddi_prop_remove_all(dip);
 232 
 233                 return (DDI_SUCCESS);
 234                 /* NOTREACHED */
 235         case DDI_SUSPEND:
 236         case DDI_PM_SUSPEND:
 237                 return (DDI_SUCCESS);
 238                 /* NOTREACHED */
 239         default:
 240                 break;
 241         }
 242         return (DDI_FAILURE);
 243 }
 244 
 245 /*ARGSUSED*/
 246 static int
 247 bpf_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
 248 {
 249         int error = DDI_FAILURE;
 250 
 251         switch (infocmd) {
 252         case DDI_INFO_DEVT2DEVINFO:
 253                 *result = bpf_dev_info;
 254                 error = DDI_SUCCESS;
 255                 break;
 256         case DDI_INFO_DEVT2INSTANCE:
 257                 *result = (void *)0;
 258                 error = DDI_SUCCESS;
 259                 break;
 260         default:
 261                 break;
 262         }
 263         return (error);
 264 }
 265 
 266 /*
 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.
 274  */
 275 static int
 276 bpf_provider_add(bpf_provider_t *provider)
 277 {
 278         bpf_provider_list_t *bp;
 279 
 280         LIST_FOREACH(bp, &bpf_providers, bpl_next) {
 281                 if (bp->bpl_what == provider)
 282                         return (EEXIST);
 283         }
 284 
 285 
 286         bp = kmem_alloc(sizeof (*bp), KM_SLEEP);
 287         bp->bpl_what = provider;
 288         LIST_INSERT_HEAD(&bpf_providers, bp, bpl_next);
 289 
 290         return (0);
 291 }
 292 
 293 static int
 294 bpf_provider_remove(bpf_provider_t *provider)
 295 {
 296         bpf_provider_list_t *bp;
 297 
 298         LIST_FOREACH(bp, &bpf_providers, bpl_next) {
 299                 if (bp->bpl_what == provider)
 300                         break;
 301         }
 302 
 303         if (bp == NULL)
 304                 return (ESRCH);
 305 
 306         LIST_REMOVE(bp, bpl_next);
 307 
 308         kmem_free(bp, sizeof (*bp));
 309 
 310         return (0);
 311 }
 312 
 313 /*
 314  * return a pointer to the structure that holds all of the functions
 315  * available to be used to support a particular packet provider.
 316  */
 317 bpf_provider_t *
 318 bpf_find_provider_by_id(int who)
 319 {
 320         bpf_provider_list_t *b;
 321 
 322         LIST_FOREACH(b, &bpf_providers, bpl_next) {
 323                 if (b->bpl_what->bpr_unit == who)
 324                         return (b->bpl_what);
 325         }
 326 
 327         return (NULL);
 328 }
 329 
 330 /*
 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.
 336  */
 337 int
 338 bpf_provider_tickle(char *name, zoneid_t zone)
 339 {
 340         bpf_provider_list_t *bp;
 341         uintptr_t handle;
 342         int tickled = 0;
 343 
 344         LIST_FOREACH(bp, &bpf_providers, bpl_next) {
 345                 handle = 0;
 346                 if (bp->bpl_what->bpr_open(name, &handle, zone) == 0) {
 347                         bp->bpl_what->bpr_close(handle);
 348                         tickled++;
 349                 } else if (bp->bpl_what->bpr_unit == BPR_MAC) {
 350                         /*
 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
 355                          * name.
 356                          */
 357                         datalink_id_t id;
 358 
 359                         if (bp->bpl_what->bpr_getlinkid(name, &id,
 360                             zone) == 0) {
 361                                 if (bp->bpl_what->bpr_open(name, &handle,
 362                                     zone) == 0) {
 363                                         bp->bpl_what->bpr_close(handle);
 364                                         tickled++;
 365                                 } else {
 366                                         mac_handle_t mh;
 367 
 368                                         if (mac_open_by_linkid(id, &mh) == 0) {
 369                                                 mac_close(mh);
 370                                                 tickled++;
 371                                         }
 372                                 }
 373                         }
 374                 }
 375 
 376         }
 377 
 378         if (tickled != 0)
 379                 return (EWOULDBLOCK);
 380 
 381         return (ENXIO);
 382 }
 383 
 384 /*
 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.
 389  */
 390 /*ARGSUSED*/
 391 static void *
 392 bpf_create_inst(const netid_t netid)
 393 {
 394         /*
 395          * BPF does not keep any per-instance state, its list of
 396          * interfaces is global, as is its device hash table.
 397          */
 398         return ((void *)bpf_itap);
 399 }
 400 
 401 /*ARGSUSED*/
 402 static void
 403 bpf_shutdown_inst(const netid_t netid, void *arg)
 404 {
 405 }
 406 
 407 /*ARGSUSED*/
 408 static void
 409 bpf_destroy_inst(const netid_t netid, void *arg)
 410 {
 411 }