1 /*
   2  * Copyright (C) 1993-2001, 2003 by Darren Reed.
   3  *
   4  * See the IPFILTER.LICENCE file for details on licencing.
   5  *
   6  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
   7  * Use is subject to license terms.
   8  *
   9  * Copyright (c) 2014, Joyent, Inc.  All rights reserved.
  10  */
  11 
  12 /*
  13  * ipfilter kernel module mutexes and locking:
  14  *
  15  * Enabling ipfilter creates a per-netstack ipf_stack_t object that is
  16  * stored in the ipf_stacks list, which is protected by ipf_stack_lock.
  17  * ipf_stack_t objects are accessed in three contexts:
  18  *
  19  * 1) administering that filter (eg: ioctls handled with iplioctl())
  20  * 2) reading log data (eg: iplread() / iplwrite())
  21  * 3) filtering packets (eg: ipf_hook4_* and ipf_hook6_* pfhooks
  22  *    functions)
  23  *
  24  * Each ipf_stack_t has a RW lock, ifs_ipf_global, protecting access to the
  25  * whole structure. The structure also has locks protecting the various
  26  * data structures used for filtering. The following guidelines should be
  27  * followed for ipf_stack_t locks:
  28  *
  29  * - ipf_stack_lock must be held when accessing the ipf_stacks list
  30  * - ipf_stack_lock should be held before acquiring ifs_ipf_global for
  31  *   a stack (the exception to this is ipf_stack_destroy(), which removes
  32  *   the ipf_stack_t from the list, then drops ipf_stack_lock before
  33  *   acquiring ifs_ipf_global)
  34  * - ifs_ipf_global must be held when accessing an ipf_stack_t in that list:
  35  *   - The write lock is held only during stack creation / destruction
  36  *   - The read lock should be held for all other accesses
  37  * - To alter the filtering data in the administrative context, one must:
  38  *   - acquire the read lock for ifs_ipf_global
  39  *   - then acquire the write lock for the data in question
  40  * - In the filtering path, the read lock needs to be held for each type of
  41  *   filtering data used
  42  * - ifs_ipf_global does not need to be held in the filtering path:
  43  *   - The filtering hooks don't need to modify the stack itself
  44  *   - The ipf_stack_t will not be destroyed until the hooks are unregistered.
  45  *     This requires a write lock on the hook, ensuring that no active hooks
  46  *     (eg: the filtering path) are running, and that the hooks won't be run
  47  *     afterward.
  48  *
  49  * Note that there is a deadlock possible when calling net_hook_register()
  50  * or net_hook_unregister() with ifs_ipf_global held: see the comments in
  51  * iplattach() and ipldetach() for details.
  52  */
  53 
  54 #include <sys/systm.h>
  55 #include <sys/types.h>
  56 #include <sys/param.h>
  57 #include <sys/errno.h>
  58 #include <sys/uio.h>
  59 #include <sys/buf.h>
  60 #include <sys/modctl.h>
  61 #include <sys/open.h>
  62 #include <sys/kmem.h>
  63 #include <sys/conf.h>
  64 #include <sys/cmn_err.h>
  65 #include <sys/stat.h>
  66 #include <sys/cred.h>
  67 #include <sys/dditypes.h>
  68 #include <sys/poll.h>
  69 #include <sys/autoconf.h>
  70 #include <sys/byteorder.h>
  71 #include <sys/socket.h>
  72 #include <sys/dlpi.h>
  73 #include <sys/stropts.h>
  74 #include <sys/kstat.h>
  75 #include <sys/sockio.h>
  76 #include <sys/neti.h>
  77 #include <sys/hook.h>
  78 #include <net/if.h>
  79 #if SOLARIS2 >= 6
  80 #include <net/if_types.h>
  81 #endif
  82 #include <net/af.h>
  83 #include <net/route.h>
  84 #include <netinet/in.h>
  85 #include <netinet/in_systm.h>
  86 #include <netinet/if_ether.h>
  87 #include <netinet/ip.h>
  88 #include <netinet/ip_var.h>
  89 #include <netinet/tcp.h>
  90 #include <netinet/udp.h>
  91 #include <netinet/tcpip.h>
  92 #include <netinet/ip_icmp.h>
  93 #include <sys/ddi.h>
  94 #include <sys/sunddi.h>
  95 #include "netinet/ip_compat.h"
  96 #include "netinet/ipl.h"
  97 #include "netinet/ip_fil.h"
  98 #include "netinet/ip_nat.h"
  99 #include "netinet/ip_frag.h"
 100 #include "netinet/ip_auth.h"
 101 #include "netinet/ip_state.h"
 102 #include "netinet/ipf_stack.h"
 103 
 104 extern  int     iplwrite __P((dev_t, struct uio *, cred_t *));
 105 
 106 static  int     ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t,
 107                     void *, void **));
 108 #if SOLARIS2 < 10
 109 static  int     ipf_identify __P((dev_info_t *));
 110 #endif
 111 static  int     ipf_attach __P((dev_info_t *, ddi_attach_cmd_t));
 112 static  int     ipf_detach __P((dev_info_t *, ddi_detach_cmd_t));
 113 static  void    *ipf_stack_create __P((const netid_t));
 114 static  void    ipf_stack_destroy __P((const netid_t, void *));
 115 static  void    ipf_stack_shutdown __P((const netid_t, void *));
 116 static  int     ipf_property_g_update __P((dev_info_t *));
 117 static  char    *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
 118                                     IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
 119                                     IPLOOKUP_NAME, NULL };
 120 extern void     *ipf_state;     /* DDI state */
 121 extern vmem_t   *ipf_minor;     /* minor number arena */
 122 
 123 static struct cb_ops ipf_cb_ops = {
 124         iplopen,
 125         iplclose,
 126         nodev,          /* strategy */
 127         nodev,          /* print */
 128         nodev,          /* dump */
 129         iplread,
 130         iplwrite,       /* write */
 131         iplioctl,       /* ioctl */
 132         nodev,          /* devmap */
 133         nodev,          /* mmap */
 134         nodev,          /* segmap */
 135         nochpoll,       /* poll */
 136         ddi_prop_op,
 137         NULL,
 138         D_MTSAFE,
 139 #if SOLARIS2 > 4
 140         CB_REV,
 141         nodev,          /* aread */
 142         nodev,          /* awrite */
 143 #endif
 144 };
 145 
 146 static struct dev_ops ipf_ops = {
 147         DEVO_REV,
 148         0,
 149         ipf_getinfo,
 150 #if SOLARIS2 >= 10
 151         nulldev,
 152 #else
 153         ipf_identify,
 154 #endif
 155         nulldev,
 156         ipf_attach,
 157         ipf_detach,
 158         nodev,          /* reset */
 159         &ipf_cb_ops,
 160         (struct bus_ops *)0,
 161         NULL,
 162         ddi_quiesce_not_needed,         /* quiesce */
 163 };
 164 
 165 
 166 static net_instance_t *ipfncb = NULL;
 167 static ipf_stack_t *ipf_stacks = NULL;
 168 static kmutex_t ipf_stack_lock;
 169 extern struct mod_ops mod_driverops;
 170 static struct modldrv iplmod = {
 171         &mod_driverops, IPL_VERSION, &ipf_ops };
 172 static struct modlinkage modlink1 = { MODREV_1, { &iplmod, NULL } };
 173 
 174 #if SOLARIS2 >= 6
 175 static  size_t  hdrsizes[57][2] = {
 176         { 0, 0 },
 177         { IFT_OTHER, 0 },
 178         { IFT_1822, 0 },
 179         { IFT_HDH1822, 0 },
 180         { IFT_X25DDN, 0 },
 181         { IFT_X25, 0 },
 182         { IFT_ETHER, 14 },
 183         { IFT_ISO88023, 0 },
 184         { IFT_ISO88024, 0 },
 185         { IFT_ISO88025, 0 },
 186         { IFT_ISO88026, 0 },
 187         { IFT_STARLAN, 0 },
 188         { IFT_P10, 0 },
 189         { IFT_P80, 0 },
 190         { IFT_HY, 0 },
 191         { IFT_FDDI, 24 },
 192         { IFT_LAPB, 0 },
 193         { IFT_SDLC, 0 },
 194         { IFT_T1, 0 },
 195         { IFT_CEPT, 0 },
 196         { IFT_ISDNBASIC, 0 },
 197         { IFT_ISDNPRIMARY, 0 },
 198         { IFT_PTPSERIAL, 0 },
 199         { IFT_PPP, 0 },
 200         { IFT_LOOP, 0 },
 201         { IFT_EON, 0 },
 202         { IFT_XETHER, 0 },
 203         { IFT_NSIP, 0 },
 204         { IFT_SLIP, 0 },
 205         { IFT_ULTRA, 0 },
 206         { IFT_DS3, 0 },
 207         { IFT_SIP, 0 },
 208         { IFT_FRELAY, 0 },
 209         { IFT_RS232, 0 },
 210         { IFT_PARA, 0 },
 211         { IFT_ARCNET, 0 },
 212         { IFT_ARCNETPLUS, 0 },
 213         { IFT_ATM, 0 },
 214         { IFT_MIOX25, 0 },
 215         { IFT_SONET, 0 },
 216         { IFT_X25PLE, 0 },
 217         { IFT_ISO88022LLC, 0 },
 218         { IFT_LOCALTALK, 0 },
 219         { IFT_SMDSDXI, 0 },
 220         { IFT_FRELAYDCE, 0 },
 221         { IFT_V35, 0 },
 222         { IFT_HSSI, 0 },
 223         { IFT_HIPPI, 0 },
 224         { IFT_MODEM, 0 },
 225         { IFT_AAL5, 0 },
 226         { IFT_SONETPATH, 0 },
 227         { IFT_SONETVT, 0 },
 228         { IFT_SMDSICIP, 0 },
 229         { IFT_PROPVIRTUAL, 0 },
 230         { IFT_PROPMUX, 0 },
 231 };
 232 #endif /* SOLARIS2 >= 6 */
 233 
 234 dev_info_t *ipf_dev_info = NULL;
 235 
 236 static const filter_kstats_t ipf_kstat_tmp = {
 237         { "pass",                       KSTAT_DATA_ULONG },
 238         { "block",                      KSTAT_DATA_ULONG },
 239         { "nomatch",                    KSTAT_DATA_ULONG },
 240         { "short",                      KSTAT_DATA_ULONG },
 241         { "pass, logged",               KSTAT_DATA_ULONG },
 242         { "block, logged",              KSTAT_DATA_ULONG },
 243         { "nomatch, logged",            KSTAT_DATA_ULONG },
 244         { "logged",                     KSTAT_DATA_ULONG },
 245         { "skip",                       KSTAT_DATA_ULONG },
 246         { "return sent",                KSTAT_DATA_ULONG },
 247         { "acct",                       KSTAT_DATA_ULONG },
 248         { "bad frag state alloc",       KSTAT_DATA_ULONG },
 249         { "new frag state kept",        KSTAT_DATA_ULONG },
 250         { "new frag state compl. pkt",  KSTAT_DATA_ULONG },
 251         { "bad pkt state alloc",        KSTAT_DATA_ULONG },
 252         { "new pkt kept state",         KSTAT_DATA_ULONG },
 253         { "cachehit",                   KSTAT_DATA_ULONG },
 254         { "tcp cksum bad",              KSTAT_DATA_ULONG },
 255         {{ "pullup ok",                 KSTAT_DATA_ULONG },
 256         { "pullup nok",                 KSTAT_DATA_ULONG }},
 257         { "src != route",               KSTAT_DATA_ULONG },
 258         { "ttl invalid",                KSTAT_DATA_ULONG },
 259         { "bad ip pkt",                 KSTAT_DATA_ULONG },
 260         { "ipv6 pkt",                   KSTAT_DATA_ULONG },
 261         { "dropped:pps ceiling",        KSTAT_DATA_ULONG },
 262         { "ip upd. fail",               KSTAT_DATA_ULONG }
 263 };
 264 
 265 
 266 static int      ipf_kstat_update(kstat_t *ksp, int rwflag);
 267 
 268 static void
 269 ipf_kstat_init(ipf_stack_t *ifs, boolean_t from_gz)
 270 {
 271         ifs->ifs_kstatp[0] = net_kstat_create(ifs->ifs_netid,
 272             (from_gz ? "ipf_gz" : "ipf"),
 273             0, "inbound", "net", KSTAT_TYPE_NAMED,
 274             sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0);
 275         if (ifs->ifs_kstatp[0] != NULL) {
 276                 bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[0]->ks_data,
 277                     sizeof (filter_kstats_t));
 278                 ifs->ifs_kstatp[0]->ks_update = ipf_kstat_update;
 279                 ifs->ifs_kstatp[0]->ks_private = &ifs->ifs_frstats[0];
 280                 kstat_install(ifs->ifs_kstatp[0]);
 281         }
 282 
 283         ifs->ifs_kstatp[1] = net_kstat_create(ifs->ifs_netid,
 284             (from_gz ? "ipf_gz" : "ipf"),
 285             0, "outbound", "net", KSTAT_TYPE_NAMED,
 286             sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0);
 287         if (ifs->ifs_kstatp[1] != NULL) {
 288                 bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[1]->ks_data,
 289                     sizeof (filter_kstats_t));
 290                 ifs->ifs_kstatp[1]->ks_update = ipf_kstat_update;
 291                 ifs->ifs_kstatp[1]->ks_private = &ifs->ifs_frstats[1];
 292                 kstat_install(ifs->ifs_kstatp[1]);
 293         }
 294 
 295 #ifdef  IPFDEBUG
 296         cmn_err(CE_NOTE, "IP Filter: ipf_kstat_init(%p) installed %p, %p",
 297             ifs, ifs->ifs_kstatp[0], ifs->ifs_kstatp[1]);
 298 #endif
 299 }
 300 
 301 
 302 static void
 303 ipf_kstat_fini(ipf_stack_t *ifs)
 304 {
 305         int i;
 306 
 307         for (i = 0; i < 2; i++) {
 308                 if (ifs->ifs_kstatp[i] != NULL) {
 309                         net_kstat_delete(ifs->ifs_netid, ifs->ifs_kstatp[i]);
 310                         ifs->ifs_kstatp[i] = NULL;
 311                 }
 312         }
 313 }
 314 
 315 
 316 static int
 317 ipf_kstat_update(kstat_t *ksp, int rwflag)
 318 {
 319         filter_kstats_t *fkp;
 320         filterstats_t   *fsp;
 321 
 322         if (ksp == NULL || ksp->ks_data == NULL)
 323                 return (EIO);
 324 
 325         if (rwflag == KSTAT_WRITE)
 326                 return (EACCES);
 327 
 328         fkp = ksp->ks_data;
 329         fsp = ksp->ks_private;
 330 
 331         fkp->fks_pass.value.ul               = fsp->fr_pass;
 332         fkp->fks_block.value.ul              = fsp->fr_block;
 333         fkp->fks_nom.value.ul                = fsp->fr_nom;
 334         fkp->fks_short.value.ul              = fsp->fr_short;
 335         fkp->fks_ppkl.value.ul               = fsp->fr_ppkl;
 336         fkp->fks_bpkl.value.ul               = fsp->fr_bpkl;
 337         fkp->fks_npkl.value.ul               = fsp->fr_npkl;
 338         fkp->fks_pkl.value.ul                = fsp->fr_pkl;
 339         fkp->fks_skip.value.ul               = fsp->fr_skip;
 340         fkp->fks_ret.value.ul                = fsp->fr_ret;
 341         fkp->fks_acct.value.ul               = fsp->fr_acct;
 342         fkp->fks_bnfr.value.ul               = fsp->fr_bnfr;
 343         fkp->fks_nfr.value.ul                = fsp->fr_nfr;
 344         fkp->fks_cfr.value.ul                = fsp->fr_cfr;
 345         fkp->fks_bads.value.ul               = fsp->fr_bads;
 346         fkp->fks_ads.value.ul                = fsp->fr_ads;
 347         fkp->fks_chit.value.ul               = fsp->fr_chit;
 348         fkp->fks_tcpbad.value.ul     = fsp->fr_tcpbad;
 349         fkp->fks_pull[0].value.ul    = fsp->fr_pull[0];
 350         fkp->fks_pull[1].value.ul    = fsp->fr_pull[1];
 351         fkp->fks_badsrc.value.ul     = fsp->fr_badsrc;
 352         fkp->fks_badttl.value.ul     = fsp->fr_badttl;
 353         fkp->fks_bad.value.ul                = fsp->fr_bad;
 354         fkp->fks_ipv6.value.ul               = fsp->fr_ipv6;
 355         fkp->fks_ppshit.value.ul     = fsp->fr_ppshit;
 356         fkp->fks_ipud.value.ul               = fsp->fr_ipud;
 357 
 358         return (0);
 359 }
 360 
 361 int
 362 _init()
 363 {
 364         int ipfinst;
 365 
 366         ipfinst = mod_install(&modlink1);
 367 #ifdef  IPFDEBUG
 368         cmn_err(CE_NOTE, "IP Filter: _init() = %d", ipfinst);
 369 #endif
 370         mutex_init(&ipf_stack_lock, NULL, MUTEX_DRIVER, NULL);
 371         return (ipfinst);
 372 }
 373 
 374 
 375 int
 376 _fini(void)
 377 {
 378         int ipfinst;
 379 
 380         ipfinst = mod_remove(&modlink1);
 381 #ifdef  IPFDEBUG
 382         cmn_err(CE_NOTE, "IP Filter: _fini() = %d", ipfinst);
 383 #endif
 384         return (ipfinst);
 385 }
 386 
 387 
 388 int
 389 _info(modinfop)
 390 struct modinfo *modinfop;
 391 {
 392         int ipfinst;
 393 
 394         ipfinst = mod_info(&modlink1, modinfop);
 395 #ifdef  IPFDEBUG
 396         cmn_err(CE_NOTE, "IP Filter: _info(%p) = %d", modinfop, ipfinst);
 397 #endif
 398         return (ipfinst);
 399 }
 400 
 401 
 402 #if SOLARIS2 < 10
 403 static int ipf_identify(dip)
 404 dev_info_t *dip;
 405 {
 406 #ifdef  IPFDEBUG
 407         cmn_err(CE_NOTE, "IP Filter: ipf_identify(%p)", dip);
 408 #endif
 409         if (strcmp(ddi_get_name(dip), "ipf") == 0)
 410                 return (DDI_IDENTIFIED);
 411         return (DDI_NOT_IDENTIFIED);
 412 }
 413 #endif
 414 
 415 /*
 416  * Initialize things for IPF for each stack instance
 417  */
 418 static void *
 419 ipf_stack_create_one(const netid_t id, const zoneid_t zid, boolean_t from_gz,
 420     ipf_stack_t *ifs_gz)
 421 {
 422         ipf_stack_t     *ifs;
 423 
 424 #ifdef IPFDEBUG
 425         cmn_err(CE_NOTE, "IP Filter:stack_create_one id=%d global=%d", id,
 426             global);
 427 #endif
 428 
 429         ifs = (ipf_stack_t *)kmem_alloc(sizeof (*ifs), KM_SLEEP);
 430         bzero(ifs, sizeof (*ifs));
 431 
 432         ifs->ifs_hook4_physical_in   = B_FALSE;
 433         ifs->ifs_hook4_physical_out  = B_FALSE;
 434         ifs->ifs_hook4_nic_events    = B_FALSE;
 435         ifs->ifs_hook4_loopback_in   = B_FALSE;
 436         ifs->ifs_hook4_loopback_out  = B_FALSE;
 437         ifs->ifs_hook6_physical_in   = B_FALSE;
 438         ifs->ifs_hook6_physical_out  = B_FALSE;
 439         ifs->ifs_hook6_nic_events    = B_FALSE;
 440         ifs->ifs_hook6_loopback_in   = B_FALSE;
 441         ifs->ifs_hook6_loopback_out  = B_FALSE;
 442 
 443         /*
 444          * Initialize mutex's
 445          */
 446         RWLOCK_INIT(&ifs->ifs_ipf_global, "ipf filter load/unload mutex");
 447         RWLOCK_INIT(&ifs->ifs_ipf_mutex, "ipf filter rwlock");
 448         RWLOCK_INIT(&ifs->ifs_ipf_frcache, "ipf cache rwlock");
 449         ifs->ifs_netid = id;
 450         ifs->ifs_zone = zid;
 451         ifs->ifs_gz_controlled = from_gz;
 452         ifs->ifs_gz_cont_ifs = ifs_gz;
 453 
 454         ipf_kstat_init(ifs, from_gz);
 455 
 456 #ifdef IPFDEBUG
 457         cmn_err(CE_CONT, "IP Filter:stack_create zone=%d", ifs->ifs_zone);
 458 #endif
 459 
 460         /*
 461          * Lock people out while we set things up.
 462          */
 463         WRITE_ENTER(&ifs->ifs_ipf_global);
 464         ipftuneable_alloc(ifs);
 465         RWLOCK_EXIT(&ifs->ifs_ipf_global);
 466 
 467         /* Limit to global stack */
 468         if (ifs->ifs_zone == GLOBAL_ZONEID)
 469                 cmn_err(CE_CONT, "!%s, running.\n", ipfilter_version);
 470 
 471         mutex_enter(&ipf_stack_lock);
 472         if (ipf_stacks != NULL)
 473                 ipf_stacks->ifs_pnext = &ifs->ifs_next;
 474         ifs->ifs_next = ipf_stacks;
 475         ifs->ifs_pnext = &ipf_stacks;
 476         ipf_stacks = ifs;
 477         mutex_exit(&ipf_stack_lock);
 478 
 479         return (ifs);
 480 }
 481 
 482 static void *
 483 ipf_stack_create(const netid_t id)
 484 {
 485         ipf_stack_t     *ifs = NULL;
 486         zoneid_t        zid = net_getzoneidbynetid(id);
 487 
 488         /*
 489          * Create two ipfilter stacks for a zone - the first can only be
 490          * controlled from the global zone, and the second is owned by
 491          * the zone itself. There is no need to create a GZ-controlled
 492          * stack for the global zone, since we're already in the global
 493          * zone. See the "GZ-controlled and per-zone stacks" comment block in
 494          * ip_fil_solaris.c for details.
 495          */
 496         if (zid != GLOBAL_ZONEID)
 497                 ifs = ipf_stack_create_one(id, zid, B_TRUE, NULL);
 498 
 499         return (ipf_stack_create_one(id, zid, B_FALSE, ifs));
 500 }
 501 
 502 /*
 503  * Find an ipfilter stack for the given zone. Return the GZ-controlled or
 504  * per-zone stack if set by an earlier SIOCIPFZONESET ioctl call. See the
 505  * "GZ-controlled and per-zone stacks" comment block in ip_fil_solaris.c for
 506  * details.
 507  *
 508  * This function returns with the ipf_stack_t's ifs_ipf_global
 509  * read lock held (if the stack is found). See the "ipfilter kernel module
 510  * mutexes and locking" comment block at the top of this file.
 511  */
 512 ipf_stack_t *
 513 ipf_find_stack(const zoneid_t orig_zone, ipf_devstate_t *isp)
 514 {
 515         ipf_stack_t *ifs;
 516         boolean_t gz_stack;
 517         zoneid_t zone;
 518 
 519         /*
 520          * If we're in the GZ, determine if we're acting on a zone's stack,
 521          * and whether or not that stack is the GZ-controlled or in-zone
 522          * one.  See the "GZ and per-zone stacks" note at the top of this
 523          * file.
 524          */
 525         if (orig_zone == GLOBAL_ZONEID &&
 526             (isp->ipfs_zoneid != IPFS_ZONE_UNSET)) {
 527                 /* Global zone, and we've set the zoneid for this fd already */
 528 
 529                 if (orig_zone == isp->ipfs_zoneid) {
 530                         /* There's only a per-zone stack for the GZ */
 531                         gz_stack = B_FALSE;
 532                 } else {
 533                         gz_stack = isp->ipfs_gz;
 534                 }
 535 
 536                 zone = isp->ipfs_zoneid;
 537         } else {
 538                 /*
 539                  * Non-global zone or GZ without having set a zoneid: act on
 540                  * the per-zone stack of the zone that this ioctl originated
 541                  * from.
 542                  */
 543                 gz_stack = B_FALSE;
 544                 zone = orig_zone;
 545         }
 546 
 547         mutex_enter(&ipf_stack_lock);
 548         for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next) {
 549                 if (ifs->ifs_zone == zone && ifs->ifs_gz_controlled == gz_stack)
 550                         break;
 551         }
 552 
 553         if (ifs != NULL) {
 554                 READ_ENTER(&ifs->ifs_ipf_global);
 555         }
 556         mutex_exit(&ipf_stack_lock);
 557         return (ifs);
 558 }
 559 
 560 static int ipf_detach_check_zone(ipf_stack_t *ifs)
 561 {
 562         /*
 563          * Make sure we're the only one's modifying things.  With
 564          * this lock others should just fall out of the loop.
 565          */
 566         READ_ENTER(&ifs->ifs_ipf_global);
 567         if (ifs->ifs_fr_running == 1) {
 568                 RWLOCK_EXIT(&ifs->ifs_ipf_global);
 569                 return (-1);
 570         }
 571 
 572         /*
 573          * Make sure there is no active filter rule.
 574          */
 575         if (ifs->ifs_ipfilter[0][ifs->ifs_fr_active] ||
 576             ifs->ifs_ipfilter[1][ifs->ifs_fr_active] ||
 577             ifs->ifs_ipfilter6[0][ifs->ifs_fr_active] ||
 578             ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]) {
 579                 RWLOCK_EXIT(&ifs->ifs_ipf_global);
 580                 return (-1);
 581         }
 582 
 583         RWLOCK_EXIT(&ifs->ifs_ipf_global);
 584 
 585         return (0);
 586 }
 587 
 588 
 589 static int ipf_detach_check_all()
 590 {
 591         ipf_stack_t *ifs;
 592 
 593         mutex_enter(&ipf_stack_lock);
 594         for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next)
 595                 if (ipf_detach_check_zone(ifs) != 0)
 596                         break;
 597         mutex_exit(&ipf_stack_lock);
 598         return ((ifs == NULL) ? 0 : -1);
 599 }
 600 
 601 
 602 /*
 603  * Remove ipf kstats for both the per-zone ipf stack and the
 604  * GZ-controlled stack for the same zone, if it exists.
 605  */
 606 /* ARGSUSED */
 607 static void
 608 ipf_stack_shutdown(const netid_t id, void *arg)
 609 {
 610         ipf_stack_t *ifs = (ipf_stack_t *)arg;
 611 
 612         /*
 613          * The GZ-controlled stack
 614          */
 615         if (ifs->ifs_gz_cont_ifs != NULL)
 616                 ipf_kstat_fini(ifs->ifs_gz_cont_ifs);
 617 
 618         /*
 619          * The per-zone stack
 620          */
 621         ipf_kstat_fini(ifs);
 622 }
 623 
 624 
 625 /*
 626  * Destroy things for ipf for one stack.
 627  */
 628 /* ARGSUSED */
 629 static void
 630 ipf_stack_destroy_one(const netid_t id, ipf_stack_t *ifs)
 631 {
 632         timeout_id_t tid;
 633 
 634 #ifdef IPFDEBUG
 635         (void) printf("ipf_stack_destroy_one(%p)\n", (void *)ifs);
 636 #endif
 637 
 638         /*
 639          * Make sure we're the only one's modifying things.  With
 640          * this lock others should just fall out of the loop.
 641          */
 642         WRITE_ENTER(&ifs->ifs_ipf_global);
 643         if (ifs->ifs_fr_running == -2) {
 644                 RWLOCK_EXIT(&ifs->ifs_ipf_global);
 645                 return;
 646         }
 647         ifs->ifs_fr_running = -2;
 648         tid = ifs->ifs_fr_timer_id;
 649         ifs->ifs_fr_timer_id = NULL;
 650         RWLOCK_EXIT(&ifs->ifs_ipf_global);
 651 
 652         mutex_enter(&ipf_stack_lock);
 653         if (ifs->ifs_next != NULL)
 654                 ifs->ifs_next->ifs_pnext = ifs->ifs_pnext;
 655         *ifs->ifs_pnext = ifs->ifs_next;
 656         mutex_exit(&ipf_stack_lock);
 657 
 658         if (tid != NULL)
 659                 (void) untimeout(tid);
 660 
 661         WRITE_ENTER(&ifs->ifs_ipf_global);
 662         if (ipldetach(ifs) != 0) {
 663                 printf("ipf_stack_destroy_one: ipldetach failed\n");
 664         }
 665 
 666         ipftuneable_free(ifs);
 667 
 668         RWLOCK_EXIT(&ifs->ifs_ipf_global);
 669         RW_DESTROY(&ifs->ifs_ipf_mutex);
 670         RW_DESTROY(&ifs->ifs_ipf_frcache);
 671         RW_DESTROY(&ifs->ifs_ipf_global);
 672 
 673         KFREE(ifs);
 674 }
 675 
 676 
 677 /*
 678  * Destroy things for ipf for both the per-zone ipf stack and the
 679  * GZ-controlled stack for the same zone, if it exists. See the "GZ-controlled
 680  * and per-zone stacks" comment block in ip_fil_solaris.c for details.
 681  */
 682 /* ARGSUSED */
 683 static void
 684 ipf_stack_destroy(const netid_t id, void *arg)
 685 {
 686         ipf_stack_t *ifs = (ipf_stack_t *)arg;
 687 
 688         /*
 689          * The GZ-controlled stack
 690          */
 691         if (ifs->ifs_gz_cont_ifs != NULL)
 692                 ipf_stack_destroy_one(id, ifs->ifs_gz_cont_ifs);
 693 
 694         /*
 695          * The per-zone stack
 696          */
 697         ipf_stack_destroy_one(id, ifs);
 698 }
 699 
 700 
 701 static int ipf_attach(dip, cmd)
 702 dev_info_t *dip;
 703 ddi_attach_cmd_t cmd;
 704 {
 705         char *s;
 706         int i;
 707         int instance;
 708 
 709 #ifdef  IPFDEBUG
 710         cmn_err(CE_NOTE, "IP Filter: ipf_attach(%p,%x)", dip, cmd);
 711 #endif
 712 
 713         switch (cmd)
 714         {
 715         case DDI_ATTACH:
 716                 instance = ddi_get_instance(dip);
 717                 /* Only one instance of ipf (instance 0) can be attached. */
 718                 if (instance > 0)
 719                         return (DDI_FAILURE);
 720 
 721 #ifdef  IPFDEBUG
 722                 cmn_err(CE_CONT, "IP Filter: attach ipf instance %d", instance);
 723 #endif
 724 
 725                 (void) ipf_property_g_update(dip);
 726 
 727                 if (ddi_soft_state_init(&ipf_state, sizeof (ipf_devstate_t), 1)
 728                     != 0) {
 729                         ddi_prop_remove_all(dip);
 730                         return (DDI_FAILURE);
 731                 }
 732 
 733                 for (i = 0; ((s = ipf_devfiles[i]) != NULL); i++) {
 734                         s = strrchr(s, '/');
 735                         if (s == NULL)
 736                                 continue;
 737                         s++;
 738                         if (ddi_create_minor_node(dip, s, S_IFCHR, i,
 739                             DDI_PSEUDO, 0) == DDI_FAILURE)
 740                                 goto attach_failed;
 741                 }
 742 
 743                 ipf_dev_info = dip;
 744 
 745                 ipfncb = net_instance_alloc(NETINFO_VERSION);
 746                 if (ipfncb == NULL)
 747                         goto attach_failed;
 748 
 749                 ipfncb->nin_name = "ipf";
 750                 ipfncb->nin_create = ipf_stack_create;
 751                 ipfncb->nin_destroy = ipf_stack_destroy;
 752                 ipfncb->nin_shutdown = ipf_stack_shutdown;
 753                 if (net_instance_register(ipfncb) == DDI_FAILURE) {
 754                         net_instance_free(ipfncb);
 755                         goto attach_failed;
 756                 }
 757 
 758                 ipf_minor = vmem_create("ipf_minor", (void *)1, UINT32_MAX - 1,
 759                     1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER);
 760 
 761 #ifdef IPFDEBUG
 762                 cmn_err(CE_CONT, "IP Filter:stack_create callback_reg=%d", i);
 763 #endif
 764 
 765                 return (DDI_SUCCESS);
 766                 /* NOTREACHED */
 767         default:
 768                 break;
 769         }
 770 
 771 attach_failed:
 772         ddi_remove_minor_node(dip, NULL);
 773         ddi_prop_remove_all(dip);
 774         ddi_soft_state_fini(&ipf_state);
 775         return (DDI_FAILURE);
 776 }
 777 
 778 
 779 static int ipf_detach(dip, cmd)
 780 dev_info_t *dip;
 781 ddi_detach_cmd_t cmd;
 782 {
 783         int i;
 784 
 785 #ifdef  IPFDEBUG
 786         cmn_err(CE_NOTE, "IP Filter: ipf_detach(%p,%x)", dip, cmd);
 787 #endif
 788         switch (cmd) {
 789         case DDI_DETACH:
 790                 if (ipf_detach_check_all() != 0)
 791                         return (DDI_FAILURE);
 792 
 793                 /*
 794                  * Undo what we did in ipf_attach, freeing resources
 795                  * and removing things we installed.  The system
 796                  * framework guarantees we are not active with this devinfo
 797                  * node in any other entry points at this time.
 798                  */
 799                 ddi_prop_remove_all(dip);
 800                 i = ddi_get_instance(dip);
 801                 ddi_remove_minor_node(dip, NULL);
 802                 if (i > 0) {
 803                         cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i);
 804                         return (DDI_FAILURE);
 805                 }
 806 
 807                 vmem_destroy(ipf_minor);
 808                 ddi_soft_state_fini(&ipf_state);
 809 
 810                 (void) net_instance_unregister(ipfncb);
 811                 net_instance_free(ipfncb);
 812 
 813                 return (DDI_SUCCESS);
 814                 /* NOTREACHED */
 815         default:
 816                 break;
 817         }
 818         cmn_err(CE_NOTE, "IP Filter: failed to detach\n");
 819         return (DDI_FAILURE);
 820 }
 821 
 822 
 823 /*ARGSUSED*/
 824 static int ipf_getinfo(dip, infocmd, arg, result)
 825 dev_info_t *dip;
 826 ddi_info_cmd_t infocmd;
 827 void *arg, **result;
 828 {
 829         int error;
 830 
 831         error = DDI_FAILURE;
 832 #ifdef  IPFDEBUG
 833         cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%p,%x,%p)", dip, infocmd, arg);
 834 #endif
 835         switch (infocmd) {
 836         case DDI_INFO_DEVT2DEVINFO:
 837                 *result = ipf_dev_info;
 838                 error = DDI_SUCCESS;
 839                 break;
 840         case DDI_INFO_DEVT2INSTANCE:
 841                 *result = (void *)0;
 842                 error = DDI_SUCCESS;
 843                 break;
 844         default:
 845                 break;
 846         }
 847         return (error);
 848 }
 849 
 850 
 851 /*
 852  * Fetch configuration file values that have been entered into the ipf.conf
 853  * driver file.
 854  */
 855 static int ipf_property_g_update(dip)
 856 dev_info_t *dip;
 857 {
 858 #ifdef DDI_NO_AUTODETACH
 859         if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
 860                                 DDI_NO_AUTODETACH, 1) != DDI_PROP_SUCCESS) {
 861                 cmn_err(CE_WARN, "!updating DDI_NO_AUTODETACH failed");
 862                 return (DDI_FAILURE);
 863         }
 864 #else
 865         if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
 866                                 "ddi-no-autodetach", 1) != DDI_PROP_SUCCESS) {
 867                 cmn_err(CE_WARN, "!updating ddi-no-autodetach failed");
 868                 return (DDI_FAILURE);
 869         }
 870 #endif
 871 
 872         return (DDI_SUCCESS);
 873 }
 874 
 875 int
 876 ipf_property_update(dip, ifs)
 877 dev_info_t *dip;
 878 ipf_stack_t *ifs;
 879 {
 880         ipftuneable_t *ipft;
 881         char *name;
 882         uint_t one;
 883         int *i32p;
 884         int err, rv = 0;
 885 
 886         for (ipft = ifs->ifs_ipf_tuneables;
 887                 (name = ipft->ipft_name) != NULL; ipft++) {
 888                 one = 1;
 889                 i32p = NULL;
 890                 err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
 891                                                 0, name, &i32p, &one);
 892                 if (err == DDI_PROP_NOT_FOUND)
 893                         continue;
 894 #ifdef  IPFDEBUG
 895                 cmn_err(CE_CONT, "IP Filter: lookup_int(%s) = %d\n",
 896                         name, err);
 897 #endif
 898                 if (err != DDI_PROP_SUCCESS) {
 899                         rv = err;
 900                         continue;
 901                 }
 902 
 903                 if (*i32p >= ipft->ipft_min &&
 904                     *i32p <= ipft->ipft_max) {
 905                         if (ipft->ipft_sz == sizeof (uint32_t)) {
 906                                 *ipft->ipft_pint = *i32p;
 907                         } else if (ipft->ipft_sz == sizeof (uint64_t)) {
 908                                 *ipft->ipft_plong = *i32p;
 909                         }
 910                 }
 911 
 912                 ddi_prop_free(i32p);
 913         }
 914 
 915         return (rv);
 916 }