Home | History | Annotate | Download | only in io
      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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 #include <sys/param.h>
     26 #include <sys/types.h>
     27 #include <sys/systm.h>
     28 #include <sys/errno.h>
     29 #include <sys/kmem.h>
     30 #include <sys/mutex.h>
     31 #include <sys/condvar.h>
     32 #include <sys/modctl.h>
     33 #include <sys/hook_impl.h>
     34 #include <sys/sdt.h>
     35 #include <sys/cmn_err.h>
     36 
     37 /*
     38  * This file provides kernel hook framework.
     39  */
     40 
     41 static struct modldrv modlmisc = {
     42 	&mod_miscops,				/* drv_modops */
     43 	"Hooks Interface v1.0",			/* drv_linkinfo */
     44 };
     45 
     46 static struct modlinkage modlinkage = {
     47 	MODREV_1,				/* ml_rev */
     48 	&modlmisc,				/* ml_linkage */
     49 	NULL
     50 };
     51 
     52 /*
     53  * How it works.
     54  * =============
     55  * Use of the hook framework here is tied up with zones - when a new zone
     56  * is created, we create a new hook_stack_t and are open to business for
     57  * allowing new hook families and their events.
     58  *
     59  * A consumer of these hooks is expected to operate in this fashion:
     60  * 1) call hook_family_add() to create a new family of hooks. It is a
     61  *    current requirement that this call must be made with the value
     62  *    returned from hook_stack_init, by way of infrastructure elsewhere.
     63  * 2) add events to the registered family with calls to hook_event_add.
     64  *
     65  * At this point, the structures in place should be open to others to
     66  * add hooks to the event or add notifiers for when the contents of the
     67  * hook stack changes.
     68  *
     69  * The interesting stuff happens on teardown.
     70  *
     71  * It is a requirement that the provider of hook events work in the reverse
     72  * order to the above, so that the first step is:
     73  * 1) remove events from each hook family created earlier
     74  * 2) remove hook families from the hook stack.
     75  *
     76  * When doing teardown of both events and families, a check is made to see
     77  * if either structure is still "busy". If so then a boolean flag is set to
     78  * say that the structure is condemned. The presence of this flag being set
     79  * must be checked for in _add()/_register()/ functions and a failure returned
     80  * if it is set. It is ignored by the _find() functions because they're
     81  * used by _remove()/_unregister().  While setting the condemned flag when
     82  * trying to delete a structure would normally be keyed from the presence
     83  * of a reference count being greater than 1, in this implementation there
     84  * are no reference counts required: instead the presence of objects on
     85  * linked lists is taken to mean something is still "busy."
     86  *
     87  * ONLY the caller that adds the family and the events ever has a direct
     88  * reference to the internal structures and thus ONLY it should be doing
     89  * the removal of either the event or family.  In practise, what this means
     90  * is that in ip_netinfo.c, we have calls to net_protocol_register(), followed
     91  * by net_event_register() (these interface to hook_family_add() and
     92  * hook_event_add(), respectively) that are made when we create an instance
     93  * of IP and when the IP instance is shutdown/destroyed, it calls
     94  * net_event_unregister() and net_protocol_unregister(), which in turn call
     95  * hook_event_remove() and hook_family_remove() respectively. Nobody else
     96  * is entitled to call the _unregister() functions.  It is imperative that
     97  * there be only one _remove() call for every _add() call.
     98  *
     99  * It is possible that code which is interfacing with this hook framework
    100  * won't do all the cleaning up that it needs to at the right time. While
    101  * we can't prevent programmers from creating memory leaks, we can synchronise
    102  * when we clean up data structures to prevent code accessing free'd memory.
    103  *
    104  * A simple diagram showing the ownership is as follows:
    105  *
    106  *  Owned       +--------------+
    107  *   by         | hook_stack_t |
    108  *   the        +--------------+
    109  *  Instance      |
    110  * - - - - - - - -|- - - - - - - - - - - - - - - - - -
    111  *                V
    112  *  Owned       +-------------------+     +-------------------+
    113  *              | hook_family_int_t |---->| hook_family_int_t |
    114  *   by         +-------------------+     +-------------------+
    115  *                | \+---------------+        \+---------------+
    116  *  network       |  | hook_family_t |         | hook_family_t |
    117  *                V  +---------------+         +---------------+
    118  *  protocol   +------------------+     +------------------+
    119  *             | hook_event_int_t |---->| hook_event_int_t |
    120  * (ipv4,ipv6) +------------------+     +------------------+
    121  *                | \+--------------+        \+--------------+
    122  *                |  | hook_event_t |         | hook_event_t |
    123  *                |  +--------------+         +--------------+
    124  * - - - - - - - -|- - - - - - - - - - - - - - - - - -
    125  *                V
    126  *  Owned      +------------+
    127  *             | hook_int_t |
    128  *   by        +------------+
    129  *                  \+--------+
    130  * the consumer      | hook_t |
    131  *                   +--------+
    132  *
    133  * The consumers, such as IPFilter, do not have any pointers or hold any
    134  * references to hook_int_t, hook_event_t or hook_event_int_t. By placing
    135  * a hook on an event through net_hook_register(), an implicit reference
    136  * to the hook_event_int_t is returned with a successful call.  Additionally,
    137  * IPFilter does not see the hook_family_int_t or hook_family_t directly.
    138  * Rather it is returned a net_handle_t (from net_protocol_lookup()) that
    139  * contains a pointer to hook_family_int_t.  The structure behind the
    140  * net_handle_t (struct net_data) *is* reference counted and managed
    141  * appropriately.
    142  *
    143  * A more detailed picture that describes how the family/event structures
    144  * are linked together can be found in <sys/hook_impl.h>
    145  */
    146 
    147 /*
    148  * Locking
    149  * =======
    150  * The use of CVW_* macros to do locking is driven by the need to allow
    151  * recursive locking with read locks when we're processing packets. This
    152  * is necessary because various netinfo functions need to hold read locks,
    153  * by design, as they can be called in or out of packet context.
    154  */
    155 /*
    156  * Hook internal functions
    157  */
    158 static hook_int_t *hook_copy(hook_t *src);
    159 static hook_event_int_t *hook_event_checkdup(hook_event_t *he,
    160     hook_stack_t *hks);
    161 static hook_event_int_t *hook_event_copy(hook_event_t *src);
    162 static hook_event_int_t *hook_event_find(hook_family_int_t *hfi, char *event);
    163 static void hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi);
    164 static hook_family_int_t *hook_family_copy(hook_family_t *src);
    165 static hook_family_int_t *hook_family_find(char *family, hook_stack_t *hks);
    166 static void hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks);
    167 static hook_int_t *hook_find(hook_event_int_t *hei, hook_t *h);
    168 static void hook_int_free(hook_int_t *hi, netstackid_t);
    169 static void hook_init(void);
    170 static void hook_fini(void);
    171 static void *hook_stack_init(netstackid_t stackid, netstack_t *ns);
    172 static void hook_stack_fini(netstackid_t stackid, void *arg);
    173 static void hook_stack_shutdown(netstackid_t stackid, void *arg);
    174 static int hook_insert(hook_int_head_t *head, hook_int_t *new);
    175 static void hook_insert_plain(hook_int_head_t *head, hook_int_t *new);
    176 static int hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new);
    177 static hook_int_t *hook_find_byname(hook_int_head_t *head, char *name);
    178 static void hook_event_init_kstats(hook_family_int_t *, hook_event_int_t *);
    179 static void hook_event_notify_run(hook_event_int_t *, hook_family_int_t *,
    180     char *event, char *name, hook_notify_cmd_t cmd);
    181 static void hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei,
    182     hook_int_t *hi);
    183 static int hook_notify_register(cvwaitlock_t *lock, hook_notify_head_t *head,
    184     hook_notify_fn_t callback, void *arg);
    185 static int hook_notify_unregister(cvwaitlock_t *lock,
    186     hook_notify_head_t *head, hook_notify_fn_t callback);
    187 static void hook_notify_run(hook_notify_head_t *head, char *family,
    188     char *event, char *name, hook_notify_cmd_t cmd);
    189 static void hook_stack_notify_run(hook_stack_t *hks, char *name,
    190     hook_notify_cmd_t cmd);
    191 static void hook_stack_remove(hook_stack_t *hks);
    192 
    193 /*
    194  * A list of the hook stacks is kept here because we need to enable
    195  * net_instance_notify_register() to be called during the creation
    196  * of a new instance. Previously hook_stack_get() would just use
    197  * the netstack functions for this work but they will return NULL
    198  * until the zone has been fully initialised.
    199  */
    200 static hook_stack_head_t hook_stacks;
    201 static kmutex_t hook_stack_lock;
    202 
    203 /*
    204  * Module entry points.
    205  */
    206 int
    207 _init(void)
    208 {
    209 	int error;
    210 
    211 	hook_init();
    212 	error = mod_install(&modlinkage);
    213 	if (error != 0)
    214 		hook_fini();
    215 
    216 	return (error);
    217 }
    218 
    219 int
    220 _fini(void)
    221 {
    222 	int error;
    223 
    224 	error = mod_remove(&modlinkage);
    225 	if (error == 0)
    226 		hook_fini();
    227 
    228 	return (error);
    229 }
    230 
    231 int
    232 _info(struct modinfo *modinfop)
    233 {
    234 	return (mod_info(&modlinkage, modinfop));
    235 }
    236 
    237 /*
    238  * Function:	hook_init
    239  * Returns:	None
    240  * Parameters:	None
    241  *
    242  * Initialize hooks
    243  */
    244 static void
    245 hook_init(void)
    246 {
    247 	mutex_init(&hook_stack_lock, NULL, MUTEX_DRIVER, NULL);
    248 	SLIST_INIT(&hook_stacks);
    249 
    250 	/*
    251 	 * We want to be informed each time a stack is created or
    252 	 * destroyed in the kernel.
    253 	 */
    254 	netstack_register(NS_HOOK, hook_stack_init, hook_stack_shutdown,
    255 	    hook_stack_fini);
    256 }
    257 
    258 /*
    259  * Function:	hook_fini
    260  * Returns:	None
    261  * Parameters:	None
    262  *
    263  * Deinitialize hooks
    264  */
    265 static void
    266 hook_fini(void)
    267 {
    268 	netstack_unregister(NS_HOOK);
    269 
    270 	mutex_destroy(&hook_stack_lock);
    271 	ASSERT(SLIST_EMPTY(&hook_stacks));
    272 }
    273 
    274 /*
    275  * Function:	hook_wait_setflag
    276  * Returns:     -1 = setting flag is disallowed, 0 = flag set and did
    277  *              not have to wait (ie no lock droped), 1 = flag set but
    278  *              it was necessary to drop locks to set it.
    279  * Parameters:  waiter(I)  - control data structure
    280  *              busyset(I) - set of flags that we don't want set while
    281  *                           we are active.
    282  *              wanted(I)  - flag associated with newflag to indicate
    283  *                           what we want to do.
    284  *              newflag(I) - the new ACTIVE flag we want to set that
    285  *                           indicates what we are doing.
    286  *
    287  * The set of functions hook_wait_* implement an API that builds on top of
    288  * the kcondvar_t to provide controlled execution through a critical region.
    289  * For each flag that indicates work is being done (FWF_*_ACTIVE) there is
    290  * also a flag that we set to indicate that we want to do it (FWF_*_WANTED).
    291  * The combination of flags is required as when this function exits to do
    292  * the task, the structure is then free for another caller to use and
    293  * to indicate that it wants to do work.  The trump flags here are those
    294  * that indicate someone wants to destroy the structure that owns this
    295  * flagwait_t.  In this case, we don't try to secure the ability to run
    296  * and return with an error.
    297  *
    298  * wanted - the FWF_*_WANTED flag that describes the action being requested
    299  * busyset- the set of FWF_* flags we don't want set when we run
    300  * newflag- the FWF_*_ACTIVE flag we will set to indicate we are busy
    301  */
    302 int
    303 hook_wait_setflag(flagwait_t *waiter, uint32_t busyset, fwflag_t wanted,
    304     fwflag_t newflag)
    305 {
    306 	int waited = 0;
    307 
    308 	mutex_enter(&waiter->fw_lock);
    309 	if (waiter->fw_flags & FWF_DESTROY) {
    310 		mutex_exit(&waiter->fw_lock);
    311 		return (-1);
    312 	}
    313 	while (waiter->fw_flags & busyset) {
    314 		waiter->fw_flags |= wanted;
    315 		CVW_EXIT_WRITE(waiter->fw_owner);
    316 		cv_wait(&waiter->fw_cv, &waiter->fw_lock);
    317 		waited = 1;
    318 		CVW_ENTER_WRITE(waiter->fw_owner);
    319 		if (waiter->fw_flags & FWF_DESTROY) {
    320 			waiter->fw_flags &= ~wanted;
    321 			mutex_exit(&waiter->fw_lock);
    322 			return (-1);
    323 		}
    324 		waiter->fw_flags |= wanted;
    325 	}
    326 	waiter->fw_flags &= ~wanted;
    327 	waiter->fw_flags |= newflag;
    328 	mutex_exit(&waiter->fw_lock);
    329 	return (waited);
    330 }
    331 
    332 /*
    333  * Function:	hook_wait_unsetflag
    334  * Returns:     None
    335  * Parameters:  waiter(I)  - control data structure
    336  *              oldflag(I) - flag to reset
    337  *
    338  * Turn off the bit that we had set to run and let others know that
    339  * they should now check to see if they can run.
    340  */
    341 void
    342 hook_wait_unsetflag(flagwait_t *waiter, uint32_t oldflag)
    343 {
    344 	mutex_enter(&waiter->fw_lock);
    345 	waiter->fw_flags &= ~oldflag;
    346 	cv_signal(&waiter->fw_cv);
    347 	mutex_exit(&waiter->fw_lock);
    348 }
    349 
    350 /*
    351  * Function:	hook_wait_destroy
    352  * Returns:     None
    353  * Parameters:  waiter(I)  - control data structure
    354  *
    355  * Since outer locking (on fw_owner) should ensure that only one function
    356  * at a time gets to call hook_wait_destroy() on a given object, there is
    357  * no need to guard against setting FWF_DESTROY_WANTED already being set.
    358  * It is, however, necessary to wait for all activity on the owning
    359  * structure to cease.
    360  */
    361 void
    362 hook_wait_destroy(flagwait_t *waiter)
    363 {
    364 	ASSERT((waiter->fw_flags & FWF_DESTROY_WANTED) == 0);
    365 	waiter->fw_flags |= FWF_DESTROY_WANTED;
    366 	while (!FWF_DESTROY_OK(waiter)) {
    367 		CVW_EXIT_WRITE(waiter->fw_owner);
    368 		cv_wait(&waiter->fw_cv, &waiter->fw_lock);
    369 		CVW_ENTER_WRITE(waiter->fw_owner);
    370 	}
    371 	/*
    372 	 * There should now be nothing else using "waiter" or its
    373 	 * owner, so we can safely assign here without risk of wiiping
    374 	 * out someone's bit.
    375 	 */
    376 	waiter->fw_flags = FWF_DESTROY_ACTIVE;
    377 }
    378 
    379 /*
    380  * Function:	hook_wait_init
    381  * Returns:     None
    382  * Parameters:  waiter(I)  - control data structure
    383  *              ownder(I)  - pointer to lock that the owner of this
    384  *                           waiter uses
    385  *
    386  * "owner" gets passed in here so that when we need to call cv_wait,
    387  * for example in hook_wait_setflag(), we can drop the lock for the
    388  * next layer out, which is likely to be held in an exclusive manner.
    389  */
    390 void
    391 hook_wait_init(flagwait_t *waiter, cvwaitlock_t *owner)
    392 {
    393 	cv_init(&waiter->fw_cv, NULL, CV_DRIVER, NULL);
    394 	mutex_init(&waiter->fw_lock, NULL, MUTEX_DRIVER, NULL);
    395 	waiter->fw_flags = FWF_NONE;
    396 	waiter->fw_owner = owner;
    397 }
    398 
    399 /*
    400  * Initialize the hook stack instance.
    401  */
    402 /*ARGSUSED*/
    403 static void *
    404 hook_stack_init(netstackid_t stackid, netstack_t *ns)
    405 {
    406 	hook_stack_t	*hks;
    407 
    408 #ifdef NS_DEBUG
    409 	printf("hook_stack_init(stack %d)\n", stackid);
    410 #endif
    411 
    412 	hks = (hook_stack_t *)kmem_zalloc(sizeof (*hks), KM_SLEEP);
    413 	hks->hks_netstack = ns;
    414 	hks->hks_netstackid = stackid;
    415 
    416 	CVW_INIT(&hks->hks_lock);
    417 	TAILQ_INIT(&hks->hks_nhead);
    418 	SLIST_INIT(&hks->hks_familylist);
    419 
    420 	hook_wait_init(&hks->hks_waiter, &hks->hks_lock);
    421 
    422 	mutex_enter(&hook_stack_lock);
    423 	SLIST_INSERT_HEAD(&hook_stacks, hks, hks_entry);
    424 	mutex_exit(&hook_stack_lock);
    425 
    426 	return (hks);
    427 }
    428 
    429 /*
    430  * Set the shutdown flag to indicate that we should stop accepting new
    431  * register calls as we're now in the cleanup process.
    432  */
    433 /*ARGSUSED*/
    434 static void
    435 hook_stack_shutdown(netstackid_t stackid, void *arg)
    436 {
    437 	hook_stack_t *hks = (hook_stack_t *)arg;
    438 
    439 	mutex_enter(&hook_stack_lock);
    440 	/*
    441 	 * Once this flag gets set to one, no more additions are allowed
    442 	 * to any of the structures that make up this stack.
    443 	 */
    444 	hks->hks_shutdown = 1;
    445 	mutex_exit(&hook_stack_lock);
    446 }
    447 
    448 /*
    449  * Free the hook stack instance.
    450  */
    451 /*ARGSUSED*/
    452 static void
    453 hook_stack_fini(netstackid_t stackid, void *arg)
    454 {
    455 	hook_stack_t *hks = (hook_stack_t *)arg;
    456 
    457 	mutex_enter(&hook_stack_lock);
    458 	hks->hks_shutdown = 2;
    459 	hook_stack_remove(hks);
    460 	mutex_exit(&hook_stack_lock);
    461 }
    462 
    463 /*
    464  * This function assumes that it is called with hook_stack_lock held.
    465  * It functions differently to hook_family/event_remove in that it does
    466  * the checks to see if it can be removed. This difference exists
    467  * because this structure has nothing higher up that depends on it.
    468  */
    469 static void
    470 hook_stack_remove(hook_stack_t *hks)
    471 {
    472 
    473 	ASSERT(mutex_owned(&hook_stack_lock));
    474 
    475 	/*
    476 	 * Is the structure still in use?
    477 	 */
    478 	if (!SLIST_EMPTY(&hks->hks_familylist) ||
    479 	    !TAILQ_EMPTY(&hks->hks_nhead))
    480 		return;
    481 
    482 	SLIST_REMOVE(&hook_stacks, hks, hook_stack, hks_entry);
    483 
    484 	hook_wait_destroy(&hks->hks_waiter);
    485 	CVW_DESTROY(&hks->hks_lock);
    486 	kmem_free(hks, sizeof (*hks));
    487 }
    488 
    489 static hook_stack_t *
    490 hook_stack_get(netstackid_t stackid)
    491 {
    492 	hook_stack_t *hks;
    493 
    494 	SLIST_FOREACH(hks, &hook_stacks, hks_entry) {
    495 		if (hks->hks_netstackid == stackid)
    496 			break;
    497 	}
    498 
    499 	return (hks);
    500 }
    501 
    502 /*
    503  * Function:	hook_stack_notify_register
    504  * Returns:	0 = success, else failure
    505  * Parameters:	stackid(I) - netstack identifier
    506  *              callback(I)- function to be called
    507  *              arg(I)     - arg to provide callback when it is called
    508  *
    509  * If we're not shutting down this instance, append a new function to the
    510  * list of those to call when a new family of hooks is added to this stack.
    511  */
    512 int
    513 hook_stack_notify_register(netstackid_t stackid, hook_notify_fn_t callback,
    514     void *arg)
    515 {
    516 	hook_stack_t *hks;
    517 	int error;
    518 
    519 	mutex_enter(&hook_stack_lock);
    520 	hks = hook_stack_get(stackid);
    521 	if (hks != NULL) {
    522 		if (hks->hks_shutdown != 0) {
    523 			error = ESHUTDOWN;
    524 		} else {
    525 			error = hook_notify_register(&hks->hks_lock,
    526 			    &hks->hks_nhead, callback, arg);
    527 		}
    528 	} else {
    529 		error = ESRCH;
    530 	}
    531 	mutex_exit(&hook_stack_lock);
    532 
    533 	return (error);
    534 }
    535 
    536 /*
    537  * Function:	hook_stack_notify_unregister
    538  * Returns:	0 = success, else failure
    539  * Parameters:	stackid(I) - netstack identifier
    540  *              callback(I) - function to be called
    541  *
    542  * Attempt to remove a registered function from a hook stack's list of
    543  * callbacks to activiate when protocols are added/deleted.
    544  */
    545 int
    546 hook_stack_notify_unregister(netstackid_t stackid, hook_notify_fn_t callback)
    547 {
    548 	hook_stack_t *hks;
    549 	int error;
    550 
    551 	mutex_enter(&hook_stack_lock);
    552 	hks = hook_stack_get(stackid);
    553 	if (hks != NULL) {
    554 		error = hook_notify_unregister(&hks->hks_lock,
    555 		    &hks->hks_nhead, callback);
    556 		if ((error == 0) && (hks->hks_shutdown == 2))
    557 			hook_stack_remove(hks);
    558 	} else {
    559 		error = ESRCH;
    560 	}
    561 	mutex_exit(&hook_stack_lock);
    562 
    563 	return (error);
    564 }
    565 
    566 /*
    567  * Function:	hook_stack_notify_run
    568  * Returns:	None
    569  * Parameters:	hks(I)  - hook stack pointer to execute callbacks for
    570  *              name(I) - name of a hook family
    571  *              cmd(I)  - either HN_UNREGISTER or HN_REGISTER
    572  *
    573  * Run through the list of callbacks on the hook stack to be called when
    574  * a new hook family is added
    575  *
    576  * As hook_notify_run() expects 3 names, one for the family, one for the
    577  * event and one for the object being introduced and we really only have
    578  * one name (that of the new hook family), fake the hook stack's name by
    579  * converting the integer to a string and for the event just pass NULL.
    580  */
    581 static void
    582 hook_stack_notify_run(hook_stack_t *hks, char *name,
    583     hook_notify_cmd_t cmd)
    584 {
    585 	char buffer[16];
    586 
    587 	(void) snprintf(buffer, sizeof (buffer), "%u", hks->hks_netstackid);
    588 
    589 	hook_notify_run(&hks->hks_nhead, buffer, NULL, name, cmd);
    590 }
    591 
    592 /*
    593  * Function:	hook_run
    594  * Returns:	int - return value according to callback func
    595  * Parameters:	token(I) - event pointer
    596  *		info(I) - message
    597  *
    598  * Run hooks for specific provider.  The hooks registered are stepped through
    599  * until either the end of the list is reached or a hook function returns a
    600  * non-zero value.  If a non-zero value is returned from a hook function, we
    601  * return that value back to our caller.  By design, a hook function can be
    602  * called more than once, simultaneously.
    603  */
    604 int
    605 hook_run(hook_family_int_t *hfi, hook_event_token_t token, hook_data_t info)
    606 {
    607 	hook_event_int_t *hei;
    608 	hook_int_t *hi;
    609 	int rval = 0;
    610 
    611 	ASSERT(token != NULL);
    612 
    613 	hei = (hook_event_int_t *)token;
    614 	DTRACE_PROBE2(hook__run__start,
    615 	    hook_event_token_t, token,
    616 	    hook_data_t, info);
    617 
    618 	/*
    619 	 * Hold global read lock to ensure event will not be deleted.
    620 	 * While it might be expected that we should also hold a read lock
    621 	 * on the event lock (hei_lock) to prevent the hook list from
    622 	 * changing while we're executing this function, both addition
    623 	 * to and removal from the hook list on the event is done with
    624 	 * a write lock held on hfi_lock. This is by design so that we
    625 	 * only need to get one of these locks to process a packet.
    626 	 * - locking is not a cheap thing to do for every packet.
    627 	 */
    628 	CVW_ENTER_READ(&hfi->hfi_lock);
    629 
    630 	TAILQ_FOREACH(hi, &hei->hei_head, hi_entry) {
    631 		ASSERT(hi->hi_hook.h_func != NULL);
    632 		DTRACE_PROBE3(hook__func__start,
    633 		    hook_event_token_t, token,
    634 		    hook_data_t, info,
    635 		    hook_int_t *, hi);
    636 		rval = (*hi->hi_hook.h_func)(token, info, hi->hi_hook.h_arg);
    637 		DTRACE_PROBE4(hook__func__end,
    638 		    hook_event_token_t, token,
    639 		    hook_data_t, info,
    640 		    hook_int_t *, hi,
    641 		    int, rval);
    642 		hi->hi_kstats.hook_hits.value.ui64++;
    643 		if (rval != 0)
    644 			break;
    645 	}
    646 
    647 	hei->hei_kstats.events.value.ui64++;
    648 
    649 	CVW_EXIT_READ(&hfi->hfi_lock);
    650 
    651 	DTRACE_PROBE3(hook__run__end,
    652 	    hook_event_token_t, token,
    653 	    hook_data_t, info,
    654 	    hook_int_t *, hi);
    655 
    656 	return (rval);
    657 }
    658 
    659 /*
    660  * Function:	hook_family_add
    661  * Returns:	internal family pointer - NULL = Fail
    662  * Parameters:	hf(I) - family pointer
    663  *
    664  * Add new family to family list
    665  */
    666 hook_family_int_t *
    667 hook_family_add(hook_family_t *hf, hook_stack_t *hks)
    668 {
    669 	hook_family_int_t *hfi, *new;
    670 
    671 	ASSERT(hf != NULL);
    672 	ASSERT(hf->hf_name != NULL);
    673 
    674 	new = hook_family_copy(hf);
    675 	if (new == NULL)
    676 		return (NULL);
    677 
    678 	mutex_enter(&hook_stack_lock);
    679 	CVW_ENTER_WRITE(&hks->hks_lock);
    680 
    681 	if (hks->hks_shutdown != 0) {
    682 		CVW_EXIT_WRITE(&hks->hks_lock);
    683 		mutex_exit(&hook_stack_lock);
    684 		hook_family_free(new, NULL);
    685 		return (NULL);
    686 	}
    687 
    688 	/* search family list */
    689 	hfi = hook_family_find(hf->hf_name, hks);
    690 	if (hfi != NULL) {
    691 		CVW_EXIT_WRITE(&hks->hks_lock);
    692 		mutex_exit(&hook_stack_lock);
    693 		hook_family_free(new, NULL);
    694 		return (NULL);
    695 	}
    696 
    697 	if (hook_wait_setflag(&hks->hks_waiter, FWF_WAIT_MASK,
    698 	    FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) {
    699 		CVW_EXIT_WRITE(&hks->hks_lock);
    700 		mutex_exit(&hook_stack_lock);
    701 		hook_family_free(new, NULL);
    702 		return (NULL);
    703 	}
    704 
    705 	CVW_INIT(&new->hfi_lock);
    706 	SLIST_INIT(&new->hfi_head);
    707 	TAILQ_INIT(&new->hfi_nhead);
    708 
    709 	hook_wait_init(&new->hfi_waiter, &new->hfi_lock);
    710 
    711 	new->hfi_stack = hks;
    712 
    713 	/* Add to family list head */
    714 	SLIST_INSERT_HEAD(&hks->hks_familylist, new, hfi_entry);
    715 
    716 	CVW_EXIT_WRITE(&hks->hks_lock);
    717 	mutex_exit(&hook_stack_lock);
    718 
    719 	hook_stack_notify_run(hks, hf->hf_name, HN_REGISTER);
    720 
    721 	hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE);
    722 
    723 	return (new);
    724 }
    725 
    726 /*
    727  * Function:	hook_family_remove
    728  * Returns:	int - 0 = Succ, Else = Fail
    729  * Parameters:	hfi(I) - internal family pointer
    730  *
    731  * Remove family from family list. This function has been designed to be
    732  * called once and once only per hook_family_int_t. Thus when cleaning up
    733  * this structure as an orphan, callers should only call hook_family_free.
    734  */
    735 int
    736 hook_family_remove(hook_family_int_t *hfi)
    737 {
    738 	hook_stack_t *hks;
    739 	boolean_t notifydone;
    740 
    741 	ASSERT(hfi != NULL);
    742 	hks = hfi->hfi_stack;
    743 
    744 	CVW_ENTER_WRITE(&hks->hks_lock);
    745 
    746 	if (hook_wait_setflag(&hks->hks_waiter, FWF_WAIT_MASK,
    747 	    FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
    748 		/*
    749 		 * If we're trying to destroy the hook_stack_t...
    750 		 */
    751 		CVW_EXIT_WRITE(&hks->hks_lock);
    752 		return (ENXIO);
    753 	}
    754 
    755 	/*
    756 	 * Check if the family is in use by the presence of either events
    757 	 * or notify callbacks on the hook family.
    758 	 */
    759 	if (!SLIST_EMPTY(&hfi->hfi_head) || !TAILQ_EMPTY(&hfi->hfi_nhead)) {
    760 		hfi->hfi_condemned = B_TRUE;
    761 	} else {
    762 		/*
    763 		 * Although hfi_condemned = B_FALSE is implied from creation,
    764 		 * putting a comment here inside the else upsets lint.
    765 		 */
    766 		hfi->hfi_condemned = B_FALSE;
    767 	}
    768 
    769 	CVW_ENTER_WRITE(&hfi->hfi_lock);
    770 	hook_wait_destroy(&hfi->hfi_waiter);
    771 	notifydone = hfi->hfi_shutdown;
    772 	hfi->hfi_shutdown = B_TRUE;
    773 	CVW_EXIT_WRITE(&hfi->hfi_lock);
    774 
    775 	CVW_EXIT_WRITE(&hks->hks_lock);
    776 
    777 	if (!notifydone)
    778 		hook_stack_notify_run(hks, hfi->hfi_family.hf_name,
    779 		    HN_UNREGISTER);
    780 
    781 	hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE);
    782 
    783 	/*
    784 	 * If we don't have to wait for anything else to disappear from this
    785 	 * structure then we can free it up.
    786 	 */
    787 	if (!hfi->hfi_condemned)
    788 		hook_family_free(hfi, hks);
    789 
    790 	return (0);
    791 }
    792 
    793 
    794 /*
    795  * Function:	hook_family_free
    796  * Returns:	None
    797  * Parameters:	hfi(I) - internal family pointer
    798  *
    799  * Free alloc memory for family
    800  */
    801 static void
    802 hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks)
    803 {
    804 
    805 	/*
    806 	 * This lock gives us possession of the hks pointer after the
    807 	 * SLIST_REMOVE, for which it is not needed, when hks_shutdown
    808 	 * is checked and hook_stack_remove called.
    809 	 */
    810 	mutex_enter(&hook_stack_lock);
    811 
    812 	ASSERT(hfi != NULL);
    813 
    814 	if (hks != NULL) {
    815 		CVW_ENTER_WRITE(&hks->hks_lock);
    816 		/* Remove from family list */
    817 		SLIST_REMOVE(&hks->hks_familylist, hfi, hook_family_int,
    818 		    hfi_entry);
    819 
    820 		CVW_EXIT_WRITE(&hks->hks_lock);
    821 	}
    822 
    823 	/* Free name space */
    824 	if (hfi->hfi_family.hf_name != NULL) {
    825 		kmem_free(hfi->hfi_family.hf_name,
    826 		    strlen(hfi->hfi_family.hf_name) + 1);
    827 	}
    828 
    829 	/* Free container */
    830 	kmem_free(hfi, sizeof (*hfi));
    831 
    832 	if (hks->hks_shutdown == 2)
    833 		hook_stack_remove(hks);
    834 
    835 	mutex_exit(&hook_stack_lock);
    836 }
    837 
    838 /*
    839  * Function:	hook_family_shutdown
    840  * Returns:	int - 0 = Succ, Else = Fail
    841  * Parameters:	hfi(I) - internal family pointer
    842  *
    843  * As an alternative to removing a family, we may desire to just generate
    844  * a series of callbacks to indicate that we will be going away in the
    845  * future. The hfi_condemned flag isn't set because we aren't trying to
    846  * remove the structure.
    847  */
    848 int
    849 hook_family_shutdown(hook_family_int_t *hfi)
    850 {
    851 	hook_stack_t *hks;
    852 	boolean_t notifydone;
    853 
    854 	ASSERT(hfi != NULL);
    855 	hks = hfi->hfi_stack;
    856 
    857 	CVW_ENTER_WRITE(&hks->hks_lock);
    858 
    859 	if (hook_wait_setflag(&hks->hks_waiter, FWF_WAIT_MASK,
    860 	    FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
    861 		/*
    862 		 * If we're trying to destroy the hook_stack_t...
    863 		 */
    864 		CVW_EXIT_WRITE(&hks->hks_lock);
    865 		return (ENXIO);
    866 	}
    867 
    868 	CVW_ENTER_WRITE(&hfi->hfi_lock);
    869 	notifydone = hfi->hfi_shutdown;
    870 	hfi->hfi_shutdown = B_TRUE;
    871 	CVW_EXIT_WRITE(&hfi->hfi_lock);
    872 	CVW_EXIT_WRITE(&hks->hks_lock);
    873 
    874 	if (!notifydone)
    875 		hook_stack_notify_run(hks, hfi->hfi_family.hf_name,
    876 		    HN_UNREGISTER);
    877 
    878 	hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE);
    879 
    880 	return (0);
    881 }
    882 
    883 /*
    884  * Function:	hook_family_copy
    885  * Returns:	internal family pointer - NULL = Failed
    886  * Parameters:	src(I) - family pointer
    887  *
    888  * Allocate internal family block and duplicate incoming family
    889  * No locks should be held across this function as it may sleep.
    890  */
    891 static hook_family_int_t *
    892 hook_family_copy(hook_family_t *src)
    893 {
    894 	hook_family_int_t *new;
    895 	hook_family_t *dst;
    896 
    897 	ASSERT(src != NULL);
    898 	ASSERT(src->hf_name != NULL);
    899 
    900 	new = (hook_family_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
    901 
    902 	/* Copy body */
    903 	dst = &new->hfi_family;
    904 	*dst = *src;
    905 
    906 	SLIST_INIT(&new->hfi_head);
    907 	TAILQ_INIT(&new->hfi_nhead);
    908 
    909 	/* Copy name */
    910 	dst->hf_name = (char *)kmem_alloc(strlen(src->hf_name) + 1, KM_SLEEP);
    911 	(void) strcpy(dst->hf_name, src->hf_name);
    912 
    913 	return (new);
    914 }
    915 
    916 /*
    917  * Function:	hook_family_find
    918  * Returns:	internal family pointer - NULL = Not match
    919  * Parameters:	family(I) - family name string
    920  *
    921  * Search family list with family name
    922  * 	A lock on hfi_lock must be held when called.
    923  */
    924 static hook_family_int_t *
    925 hook_family_find(char *family, hook_stack_t *hks)
    926 {
    927 	hook_family_int_t *hfi = NULL;
    928 
    929 	ASSERT(family != NULL);
    930 
    931 	SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
    932 		if (strcmp(hfi->hfi_family.hf_name, family) == 0)
    933 			break;
    934 	}
    935 	return (hfi);
    936 }
    937 
    938 /*
    939  * Function:	hook_family_notify_register
    940  * Returns:	0 = success, else failure
    941  * Parameters:	hfi(I)      - hook family
    942  *              callback(I) - function to be called
    943  *              arg(I)      - arg to provide callback when it is called
    944  *
    945  * So long as this hook stack isn't being shut down, register a new
    946  * callback to be activated each time a new event is added to this
    947  * family.
    948  *
    949  * To call this function we must have an active handle in use on the family,
    950  * so if we take this into account, then neither the hook_family_int_t nor
    951  * the hook_stack_t that owns it can disappear. We have to put some trust
    952  * in the callers to be properly synchronised...
    953  *
    954  * Holding hks_lock is required to provide synchronisation for hks_shutdown.
    955  */
    956 int
    957 hook_family_notify_register(hook_family_int_t *hfi,
    958     hook_notify_fn_t callback, void *arg)
    959 {
    960 	hook_stack_t *hks;
    961 	int error;
    962 
    963 	hks = hfi->hfi_stack;
    964 
    965 	CVW_ENTER_READ(&hks->hks_lock);
    966 	CVW_ENTER_WRITE(&hfi->hfi_lock);
    967 
    968 	if ((hfi->hfi_stack->hks_shutdown != 0) ||
    969 	    hfi->hfi_condemned || hfi->hfi_shutdown) {
    970 		CVW_EXIT_WRITE(&hfi->hfi_lock);
    971 		CVW_EXIT_READ(&hks->hks_lock);
    972 		return (ESHUTDOWN);
    973 	}
    974 
    975 	error = hook_notify_register(&hfi->hfi_lock, &hfi->hfi_nhead,
    976 	    callback, arg);
    977 
    978 	CVW_EXIT_WRITE(&hfi->hfi_lock);
    979 	CVW_EXIT_READ(&hks->hks_lock);
    980 
    981 	return (error);
    982 }
    983 
    984 /*
    985  * Function:	hook_family_notify_unregister
    986  * Returns:	0 = success, else failure
    987  * Parameters:	hfi(I)      - hook family
    988  *              callback(I) - function to be called
    989  *
    990  * Remove a callback from the list of those executed when a new event is
    991  * added to a hook family.
    992  */
    993 int
    994 hook_family_notify_unregister(hook_family_int_t *hfi,
    995     hook_notify_fn_t callback)
    996 {
    997 	boolean_t free_family;
    998 	int error;
    999 
   1000 	CVW_ENTER_WRITE(&hfi->hfi_lock);
   1001 
   1002 	error = hook_notify_unregister(&hfi->hfi_lock, &hfi->hfi_nhead,
   1003 	    callback);
   1004 
   1005 	/*
   1006 	 * If hook_family_remove has been called but the structure was still
   1007 	 * "busy" ... but we might have just made it "unbusy"...
   1008 	 */
   1009 	if ((error == 0) && hfi->hfi_condemned &&
   1010 	    SLIST_EMPTY(&hfi->hfi_head) && TAILQ_EMPTY(&hfi->hfi_nhead)) {
   1011 		free_family = B_TRUE;
   1012 	} else {
   1013 		free_family = B_FALSE;
   1014 	}
   1015 
   1016 	CVW_EXIT_WRITE(&hfi->hfi_lock);
   1017 
   1018 	if (free_family)
   1019 		hook_family_free(hfi, hfi->hfi_stack);
   1020 
   1021 	return (error);
   1022 }
   1023 
   1024 /*
   1025  * Function:	hook_event_add
   1026  * Returns:	internal event pointer - NULL = Fail
   1027  * Parameters:	hfi(I) - internal family pointer
   1028  *		he(I) - event pointer
   1029  *
   1030  * Add new event to event list on specific family.
   1031  * This function can fail to return successfully if (1) it cannot allocate
   1032  * enough memory for its own internal data structures, (2) the event has
   1033  * already been registered (for any hook family.)
   1034  */
   1035 hook_event_int_t *
   1036 hook_event_add(hook_family_int_t *hfi, hook_event_t *he)
   1037 {
   1038 	hook_event_int_t *hei, *new;
   1039 	hook_stack_t *hks;
   1040 
   1041 	ASSERT(hfi != NULL);
   1042 	ASSERT(he != NULL);
   1043 	ASSERT(he->he_name != NULL);
   1044 
   1045 	new = hook_event_copy(he);
   1046 	if (new == NULL)
   1047 		return (NULL);
   1048 
   1049 	hks = hfi->hfi_stack;
   1050 	CVW_ENTER_READ(&hks->hks_lock);
   1051 
   1052 	hks = hfi->hfi_stack;
   1053 	if (hks->hks_shutdown != 0) {
   1054 		CVW_EXIT_READ(&hks->hks_lock);
   1055 		hook_event_free(new, NULL);
   1056 		return (NULL);
   1057 	}
   1058 
   1059 	/* Check whether this event pointer is already registered */
   1060 	hei = hook_event_checkdup(he, hks);
   1061 	if (hei != NULL) {
   1062 		CVW_EXIT_READ(&hks->hks_lock);
   1063 		hook_event_free(new, NULL);
   1064 		return (NULL);
   1065 	}
   1066 
   1067 	CVW_ENTER_WRITE(&hfi->hfi_lock);
   1068 
   1069 	if (hfi->hfi_condemned || hfi->hfi_shutdown) {
   1070 		CVW_EXIT_WRITE(&hfi->hfi_lock);
   1071 		CVW_EXIT_READ(&hks->hks_lock);
   1072 		hook_event_free(new, NULL);
   1073 		return (NULL);
   1074 	}
   1075 
   1076 	if (hook_wait_setflag(&hfi->hfi_waiter, FWF_WAIT_MASK,
   1077 	    FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) {
   1078 		CVW_EXIT_WRITE(&hfi->hfi_lock);
   1079 		CVW_EXIT_READ(&hks->hks_lock);
   1080 		hook_event_free(new, NULL);
   1081 		return (NULL);
   1082 	}
   1083 
   1084 	TAILQ_INIT(&new->hei_nhead);
   1085 
   1086 	hook_event_init_kstats(hfi, new);
   1087 	hook_wait_init(&new->hei_waiter, &new->hei_lock);
   1088 
   1089 	/* Add to event list head */
   1090 	SLIST_INSERT_HEAD(&hfi->hfi_head, new, hei_entry);
   1091 
   1092 	CVW_EXIT_WRITE(&hfi->hfi_lock);
   1093 
   1094 	CVW_EXIT_READ(&hks->hks_lock);
   1095 
   1096 	hook_notify_run(&hfi->hfi_nhead,
   1097 	    hfi->hfi_family.hf_name, NULL, he->he_name, HN_REGISTER);
   1098 
   1099 	hook_wait_unsetflag(&hfi->hfi_waiter, FWF_ADD_ACTIVE);
   1100 
   1101 	return (new);
   1102 }
   1103 
   1104 /*
   1105  * Function:	hook_event_init_kstats
   1106  * Returns:	None
   1107  * Parameters:  hfi(I) - pointer to the family that owns this event.
   1108  *              hei(I) - pointer to the hook event that needs some kstats.
   1109  *
   1110  * Create a set of kstats that relate to each event registered with
   1111  * the hook framework.  A counter is kept for each time the event is
   1112  * activated and for each time a hook is added or removed.  As the
   1113  * kstats just count the events as they happen, the total number of
   1114  * hooks registered must be obtained by subtractived removed from added.
   1115  */
   1116 static void
   1117 hook_event_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei)
   1118 {
   1119 	hook_event_kstat_t template = {
   1120 		{ "hooksAdded",		KSTAT_DATA_UINT64 },
   1121 		{ "hooksRemoved",	KSTAT_DATA_UINT64 },
   1122 		{ "events",		KSTAT_DATA_UINT64 }
   1123 	};
   1124 	hook_stack_t *hks;
   1125 
   1126 	hks = hfi->hfi_stack;
   1127 	hei->hei_kstatp = kstat_create_netstack(hfi->hfi_family.hf_name, 0,
   1128 	    hei->hei_event->he_name, "hook_event", KSTAT_TYPE_NAMED,
   1129 	    sizeof (hei->hei_kstats) / sizeof (kstat_named_t),
   1130 	    KSTAT_FLAG_VIRTUAL, hks->hks_netstackid);
   1131 
   1132 	bcopy((char *)&template, &hei->hei_kstats, sizeof (template));
   1133 
   1134 	if (hei->hei_kstatp != NULL) {
   1135 		hei->hei_kstatp->ks_data = (void *)&hei->hei_kstats;
   1136 		hei->hei_kstatp->ks_private =
   1137 		    (void *)(uintptr_t)hks->hks_netstackid;
   1138 
   1139 		kstat_install(hei->hei_kstatp);
   1140 	}
   1141 }
   1142 
   1143 /*
   1144  * Function:	hook_event_remove
   1145  * Returns:	int - 0 = Succ, Else = Fail
   1146  * Parameters:	hfi(I) - internal family pointer
   1147  *		he(I) - event pointer
   1148  *
   1149  * Remove event from event list on specific family
   1150  *
   1151  * This function assumes that the caller has received a pointer to a the
   1152  * hook_family_int_t via a call to net_protocol_lookup or net_protocol_unreg'.
   1153  * This the hook_family_int_t is guaranteed to be around for the life of this
   1154  * call, unless the caller has decided to call net_protocol_release or
   1155  * net_protocol_unregister before calling net_event_unregister - an error.
   1156  */
   1157 int
   1158 hook_event_remove(hook_family_int_t *hfi, hook_event_t *he)
   1159 {
   1160 	boolean_t free_family;
   1161 	hook_event_int_t *hei;
   1162 	boolean_t notifydone;
   1163 
   1164 	ASSERT(hfi != NULL);
   1165 	ASSERT(he != NULL);
   1166 
   1167 	CVW_ENTER_WRITE(&hfi->hfi_lock);
   1168 
   1169 	/*
   1170 	 * Set the flag so that we can call hook_event_notify_run without
   1171 	 * holding any locks but at the same time prevent other changes to
   1172 	 * the event at the same time.
   1173 	 */
   1174 	if (hook_wait_setflag(&hfi->hfi_waiter, FWF_WAIT_MASK,
   1175 	    FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
   1176 		CVW_EXIT_WRITE(&hfi->hfi_lock);
   1177 		return (ENXIO);
   1178 	}
   1179 
   1180 	hei = hook_event_find(hfi, he->he_name);
   1181 	if (hei == NULL) {
   1182 		hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
   1183 		CVW_EXIT_WRITE(&hfi->hfi_lock);
   1184 		return (ESRCH);
   1185 	}
   1186 
   1187 	free_family = B_FALSE;
   1188 
   1189 	CVW_ENTER_WRITE(&hei->hei_lock);
   1190 	/*
   1191 	 * The hei_shutdown flag is used to indicate whether or not we have
   1192 	 * done a shutdown and thus already walked through the notify list.
   1193 	 */
   1194 	notifydone = hei->hei_shutdown;
   1195 	hei->hei_shutdown = B_TRUE;
   1196 	/*
   1197 	 * If there are any hooks still registered for this event or
   1198 	 * there are any notifiers registered, return an error indicating
   1199 	 * that the event is still busy.
   1200 	 */
   1201 	if (!TAILQ_EMPTY(&hei->hei_head) || !TAILQ_EMPTY(&hei->hei_nhead)) {
   1202 		hei->hei_condemned = B_TRUE;
   1203 		CVW_EXIT_WRITE(&hei->hei_lock);
   1204 	} else {
   1205 		/* hei_condemned = B_FALSE is implied from creation */
   1206 		/*
   1207 		 * Even though we know the notify list is empty, we call
   1208 		 * hook_wait_destroy here to synchronise wait removing a
   1209 		 * hook from an event.
   1210 		 */
   1211 		hook_wait_destroy(&hei->hei_waiter);
   1212 
   1213 		CVW_EXIT_WRITE(&hei->hei_lock);
   1214 
   1215 		if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) &&
   1216 		    TAILQ_EMPTY(&hfi->hfi_nhead))
   1217 			free_family = B_TRUE;
   1218 	}
   1219 
   1220 	CVW_EXIT_WRITE(&hfi->hfi_lock);
   1221 
   1222 	if (!notifydone)
   1223 		hook_notify_run(&hfi->hfi_nhead,
   1224 		    hfi->hfi_family.hf_name, NULL, he->he_name, HN_UNREGISTER);
   1225 
   1226 	hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
   1227 
   1228 	if (!hei->hei_condemned) {
   1229 		hook_event_free(hei, hfi);
   1230 		if (free_family)
   1231 			hook_family_free(hfi, hfi->hfi_stack);
   1232 	}
   1233 
   1234 	return (0);
   1235 }
   1236 
   1237 /*
   1238  * Function:	hook_event_shutdown
   1239  * Returns:	int - 0 = Succ, Else = Fail
   1240  * Parameters:	hfi(I) - internal family pointer
   1241  *		he(I)  - event pointer
   1242  *
   1243  * As with hook_family_shutdown, we want to generate the notify callbacks
   1244  * as if the event was being removed but not actually do the remove.
   1245  */
   1246 int
   1247 hook_event_shutdown(hook_family_int_t *hfi, hook_event_t *he)
   1248 {
   1249 	hook_event_int_t *hei;
   1250 	boolean_t notifydone;
   1251 
   1252 	ASSERT(hfi != NULL);
   1253 	ASSERT(he != NULL);
   1254 
   1255 	CVW_ENTER_WRITE(&hfi->hfi_lock);
   1256 
   1257 	/*
   1258 	 * Set the flag so that we can call hook_event_notify_run without
   1259 	 * holding any locks but at the same time prevent other changes to
   1260 	 * the event at the same time.
   1261 	 */
   1262 	if (hook_wait_setflag(&hfi->hfi_waiter, FWF_WAIT_MASK,
   1263 	    FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
   1264 		CVW_EXIT_WRITE(&hfi->hfi_lock);
   1265 		return (ENXIO);
   1266 	}
   1267 
   1268 	hei = hook_event_find(hfi, he->he_name);
   1269 	if (hei == NULL) {
   1270 		hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
   1271 		CVW_EXIT_WRITE(&hfi->hfi_lock);
   1272 		return (ESRCH);
   1273 	}
   1274 
   1275 	CVW_ENTER_WRITE(&hei->hei_lock);
   1276 	notifydone = hei->hei_shutdown;
   1277 	hei->hei_shutdown = B_TRUE;
   1278 	CVW_EXIT_WRITE(&hei->hei_lock);
   1279 
   1280 	CVW_EXIT_WRITE(&hfi->hfi_lock);
   1281 
   1282 	if (!notifydone)
   1283 		hook_notify_run(&hfi->hfi_nhead,
   1284 		    hfi->hfi_family.hf_name, NULL, he->he_name, HN_UNREGISTER);
   1285 
   1286 	hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
   1287 
   1288 	return (0);
   1289 }
   1290 
   1291 /*
   1292  * Function:	hook_event_free
   1293  * Returns:	None
   1294  * Parameters:	hei(I) - internal event pointer
   1295  *
   1296  * Free alloc memory for event
   1297  */
   1298 static void
   1299 hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi)
   1300 {
   1301 	boolean_t free_family;
   1302 
   1303 	ASSERT(hei != NULL);
   1304 
   1305 	if (hfi != NULL) {
   1306 		CVW_ENTER_WRITE(&hfi->hfi_lock);
   1307 		/*
   1308 		 * Remove the event from the hook family's list.
   1309 		 */
   1310 		SLIST_REMOVE(&hfi->hfi_head, hei, hook_event_int, hei_entry);
   1311 		if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) &&
   1312 		    TAILQ_EMPTY(&hfi->hfi_nhead)) {
   1313 			free_family = B_TRUE;
   1314 		} else {
   1315 			free_family = B_FALSE;
   1316 		}
   1317 		CVW_EXIT_WRITE(&hfi->hfi_lock);
   1318 	}
   1319 
   1320 	if (hei->hei_kstatp != NULL) {
   1321 		ASSERT(hfi != NULL);
   1322 
   1323 		kstat_delete_netstack(hei->hei_kstatp,
   1324 		    hfi->hfi_stack->hks_netstackid);
   1325 		hei->hei_kstatp = NULL;
   1326 	}
   1327 
   1328 	/* Free container */
   1329 	kmem_free(hei, sizeof (*hei));
   1330 
   1331 	if (free_family)
   1332 		hook_family_free(hfi, hfi->hfi_stack);
   1333 }
   1334 
   1335 /*
   1336  * Function:    hook_event_checkdup
   1337  * Returns:     internal event pointer - NULL = Not match
   1338  * Parameters:  he(I) - event pointer
   1339  *
   1340  * Search all of the hook families to see if the event being passed in
   1341  * has already been associated with one.
   1342  */
   1343 static hook_event_int_t *
   1344 hook_event_checkdup(hook_event_t *he, hook_stack_t *hks)
   1345 {
   1346 	hook_family_int_t *hfi;
   1347 	hook_event_int_t *hei;
   1348 
   1349 	ASSERT(he != NULL);
   1350 
   1351 	CVW_ENTER_READ(&hks->hks_lock);
   1352 	SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
   1353 		SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
   1354 			if (hei->hei_event == he) {
   1355 				CVW_EXIT_READ(&hks->hks_lock);
   1356 				return (hei);
   1357 			}
   1358 		}
   1359 	}
   1360 	CVW_EXIT_READ(&hks->hks_lock);
   1361 
   1362 	return (NULL);
   1363 }
   1364 
   1365 /*
   1366  * Function:	hook_event_copy
   1367  * Returns:	internal event pointer - NULL = Failed
   1368  * Parameters:	src(I) - event pointer
   1369  *
   1370  * Allocate internal event block and duplicate incoming event
   1371  * No locks should be held across this function as it may sleep.
   1372  */
   1373 static hook_event_int_t *
   1374 hook_event_copy(hook_event_t *src)
   1375 {
   1376 	hook_event_int_t *new;
   1377 
   1378 	ASSERT(src != NULL);
   1379 	ASSERT(src->he_name != NULL);
   1380 
   1381 	new = (hook_event_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
   1382 
   1383 	/* Copy body */
   1384 	TAILQ_INIT(&new->hei_head);
   1385 	new->hei_event = src;
   1386 
   1387 	return (new);
   1388 }
   1389 
   1390 /*
   1391  * Function:	hook_event_find
   1392  * Returns:	internal event pointer - NULL = Not match
   1393  * Parameters:	hfi(I) - internal family pointer
   1394  *		event(I) - event name string
   1395  *
   1396  * Search event list with event name
   1397  * 	A lock on hfi->hfi_lock must be held when called.
   1398  */
   1399 static hook_event_int_t *
   1400 hook_event_find(hook_family_int_t *hfi, char *event)
   1401 {
   1402 	hook_event_int_t *hei = NULL;
   1403 
   1404 	ASSERT(hfi != NULL);
   1405 	ASSERT(event != NULL);
   1406 
   1407 	SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
   1408 		if ((strcmp(hei->hei_event->he_name, event) == 0) &&
   1409 		    ((hei->hei_waiter.fw_flags & FWF_UNSAFE) == 0))
   1410 			break;
   1411 	}
   1412 	return (hei);
   1413 }
   1414 
   1415 /*
   1416  * Function:	hook_event_notify_register
   1417  * Returns:	0 = success, else failure
   1418  * Parameters:	hfi(I)      - hook family
   1419  *              event(I)    - name of the event
   1420  *              callback(I) - function to be called
   1421  *              arg(I)      - arg to provide callback when it is called
   1422  *
   1423  * Adds a new callback to the event named by "event" (we must find it)
   1424  * that will be executed each time a new hook is added to the event.
   1425  * Of course, if the stack is being shut down, this call should fail.
   1426  */
   1427 int
   1428 hook_event_notify_register(hook_family_int_t *hfi, char *event,
   1429     hook_notify_fn_t callback, void *arg)
   1430 {
   1431 	hook_event_int_t *hei;
   1432 	hook_stack_t *hks;
   1433 	int error;
   1434 
   1435 	hks = hfi->hfi_stack;
   1436 	CVW_ENTER_READ(&hks->hks_lock);
   1437 	if (hks->hks_shutdown != 0) {
   1438 		CVW_EXIT_READ(&hks->hks_lock);
   1439 		return (ESHUTDOWN);
   1440 	}
   1441 
   1442 	CVW_ENTER_READ(&hfi->hfi_lock);
   1443 
   1444 	if (hfi->hfi_condemned || hfi->hfi_shutdown) {
   1445 		CVW_EXIT_READ(&hfi->hfi_lock);
   1446 		CVW_EXIT_READ(&hks->hks_lock);
   1447 		return (ESHUTDOWN);
   1448 	}
   1449 
   1450 	hei = hook_event_find(hfi, event);
   1451 	if (hei == NULL) {
   1452 		CVW_EXIT_READ(&hfi->hfi_lock);
   1453 		CVW_EXIT_READ(&hks->hks_lock);
   1454 		return (ESRCH);
   1455 	}
   1456 
   1457 	/*
   1458 	 * Grabbing the read lock on hei_lock is only so that we can
   1459 	 * synchronise access to hei_condemned.
   1460 	 */
   1461 	CVW_ENTER_WRITE(&hei->hei_lock);
   1462 	if (hei->hei_condemned || hei->hei_shutdown) {
   1463 		CVW_EXIT_WRITE(&hei->hei_lock);
   1464 		CVW_EXIT_READ(&hfi->hfi_lock);
   1465 		CVW_EXIT_READ(&hks->hks_lock);
   1466 		return (ESHUTDOWN);
   1467 	}
   1468 
   1469 	error = hook_notify_register(&hei->hei_lock, &hei->hei_nhead,
   1470 	    callback, arg);
   1471 
   1472 	CVW_EXIT_WRITE(&hei->hei_lock);
   1473 	CVW_EXIT_READ(&hfi->hfi_lock);
   1474 	CVW_EXIT_READ(&hks->hks_lock);
   1475 
   1476 	return (error);
   1477 }
   1478 
   1479 /*
   1480  * Function:	hook_event_notify_unregister
   1481  * Returns:	0 = success, else failure
   1482  * Parameters:	hfi(I)      - hook family
   1483  *              event(I)    - name of the event
   1484  *              callback(I) - function to be called
   1485  *
   1486  * Remove the given callback from the named event's list of functions
   1487  * to call when a hook is added or removed.
   1488  */
   1489 int
   1490 hook_event_notify_unregister(hook_family_int_t *hfi, char *event,
   1491     hook_notify_fn_t callback)
   1492 {
   1493 	hook_event_int_t *hei;
   1494 	boolean_t free_event;
   1495 	int error;
   1496 
   1497 	CVW_ENTER_READ(&hfi->hfi_lock);
   1498 
   1499 	hei = hook_event_find(hfi, event);
   1500 	if (hei == NULL) {
   1501 		CVW_EXIT_READ(&hfi->hfi_lock);
   1502 		return (ESRCH);
   1503 	}
   1504 
   1505 	CVW_ENTER_WRITE(&hei->hei_lock);
   1506 
   1507 	error = hook_notify_unregister(&hei->hei_lock, &hei->hei_nhead,
   1508 	    callback);
   1509 
   1510 	/*
   1511 	 * hei_condemned has been set if someone tried to remove the
   1512 	 * event but couldn't because there were still things attached to
   1513 	 * it. Now that we've done a successful remove, if it is now empty
   1514 	 * then by all rights we should be free'ing it too.  Note that the
   1515 	 * expectation is that only the caller of hook_event_add will ever
   1516 	 * call hook_event_remove.
   1517 	 */
   1518 	if ((error == 0) && hei->hei_condemned &&
   1519 	    TAILQ_EMPTY(&hei->hei_head) && TAILQ_EMPTY(&hei->hei_nhead)) {
   1520 		free_event = B_TRUE;
   1521 	} else {
   1522 		free_event = B_FALSE;
   1523 	}
   1524 
   1525 	CVW_EXIT_WRITE(&hei->hei_lock);
   1526 	CVW_EXIT_READ(&hfi->hfi_lock);
   1527 
   1528 	if (free_event) {
   1529 		/*
   1530 		 * It is safe to pass in hfi here, without a lock, because
   1531 		 * our structure (hei) is still on one of its lists and thus
   1532 		 * it won't be able to disappear yet...
   1533 		 */
   1534 		hook_event_free(hei, hfi);
   1535 	}
   1536 
   1537 	return (error);
   1538 }
   1539 
   1540 /*
   1541  * Function:	hook_event_notify_run
   1542  * Returns:	None
   1543  * Parameters:	nrun(I) - pointer to the list of callbacks to execute
   1544  *              hfi(I)  - hook stack pointer to execute callbacks for
   1545  *              name(I) - name of a hook family
   1546  *              cmd(I)  - either HN_UNREGISTER or HN_REGISTER
   1547  *
   1548  * Execute all of the callbacks registered for this event.
   1549  */
   1550 static void
   1551 hook_event_notify_run(hook_event_int_t *hei, hook_family_int_t *hfi,
   1552     char *event, char *name, hook_notify_cmd_t cmd)
   1553 {
   1554 
   1555 	hook_notify_run(&hei->hei_nhead, hfi->hfi_family.hf_name,
   1556 	    event, name, cmd);
   1557 }
   1558 
   1559 /*
   1560  * Function:	hook_register
   1561  * Returns:	int- 0 = Succ, Else = Fail
   1562  * Parameters:	hfi(I) - internal family pointer
   1563  *		event(I) - event name string
   1564  *		h(I) - hook pointer
   1565  *
   1566  * Add new hook to hook list on the specified family and event.
   1567  */
   1568 int
   1569 hook_register(hook_family_int_t *hfi, char *event, hook_t *h)
   1570 {
   1571 	hook_event_int_t *hei;
   1572 	hook_int_t *hi, *new;
   1573 	int error;
   1574 
   1575 	ASSERT(hfi != NULL);
   1576 	ASSERT(event != NULL);
   1577 	ASSERT(h != NULL);
   1578 
   1579 	if (hfi->hfi_stack->hks_shutdown)
   1580 		return (NULL);
   1581 
   1582 	/* Alloc hook_int_t and copy hook */
   1583 	new = hook_copy(h);
   1584 	if (new == NULL)
   1585 		return (ENOMEM);
   1586 
   1587 	/*
   1588 	 * Since hook add/remove only impact event, so it is unnecessary
   1589 	 * to hold global family write lock. Just get read lock here to
   1590 	 * ensure event will not be removed when doing hooks operation
   1591 	 */
   1592 	CVW_ENTER_WRITE(&hfi->hfi_lock);
   1593 
   1594 	hei = hook_event_find(hfi, event);
   1595 	if (hei == NULL) {
   1596 		CVW_EXIT_WRITE(&hfi->hfi_lock);
   1597 		hook_int_free(new, hfi->hfi_stack->hks_netstackid);
   1598 		return (ENXIO);
   1599 	}
   1600 
   1601 	CVW_ENTER_WRITE(&hei->hei_lock);
   1602 
   1603 	/*
   1604 	 * If we've run either the remove() or shutdown(), do not allow any
   1605 	 * more hooks to be added to this event.
   1606 	 */
   1607 	if (hei->hei_shutdown) {
   1608 		error = ESHUTDOWN;
   1609 		goto bad_add;
   1610 	}
   1611 
   1612 	hi = hook_find(hei, h);
   1613 	if (hi != NULL) {
   1614 		error = EEXIST;
   1615 		goto bad_add;
   1616 	}
   1617 
   1618 	if (hook_wait_setflag(&hei->hei_waiter, FWF_WAIT_MASK,
   1619 	    FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) {
   1620 		error = ENOENT;
   1621 bad_add:
   1622 		CVW_EXIT_WRITE(&hei->hei_lock);
   1623 		CVW_EXIT_WRITE(&hfi->hfi_lock);
   1624 		hook_int_free(new, hfi->hfi_stack->hks_netstackid);
   1625 		return (error);
   1626 	}
   1627 
   1628 	/* Add to hook list head */
   1629 	error = hook_insert(&hei->hei_head, new);
   1630 	if (error == 0) {
   1631 		hei->hei_event->he_interested = B_TRUE;
   1632 		hei->hei_kstats.hooks_added.value.ui64++;
   1633 
   1634 		hook_init_kstats(hfi, hei, new);
   1635 	}
   1636 
   1637 	CVW_EXIT_WRITE(&hei->hei_lock);
   1638 	CVW_EXIT_WRITE(&hfi->hfi_lock);
   1639 
   1640 	/*
   1641 	 * Note that the name string passed through to the notify callbacks
   1642 	 * is from the original hook being registered, not the copy being
   1643 	 * inserted.
   1644 	 */
   1645 	if (error == 0) {
   1646 		hook_event_notify_run(hei, hfi, event, h->h_name, HN_REGISTER);
   1647 		hook_wait_unsetflag(&hei->hei_waiter, FWF_ADD_ACTIVE);
   1648 	}
   1649 
   1650 	return (error);
   1651 }
   1652 
   1653 /*
   1654  * Function:	hook_insert
   1655  * Returns:	int- 0 = Succ, else = Fail
   1656  * Parameters:	head(I) - pointer to hook list to insert hook onto
   1657  *		new(I)  - pointer to hook to be inserted
   1658  *
   1659  * Try to insert the hook onto the list of hooks according to the hints
   1660  * given in the hook to be inserted and those that already exist on the
   1661  * list.  For now, the implementation permits only a single hook to be
   1662  * either first or last and names provided with before or after are only
   1663  * loosely coupled with the action.
   1664  */
   1665 static int
   1666 hook_insert(hook_int_head_t *head, hook_int_t *new)
   1667 {
   1668 	hook_int_t *before;
   1669 	hook_int_t *hi;
   1670 	hook_t *hih;
   1671 	hook_t *h = &new->hi_hook;
   1672 
   1673 	switch (new->hi_hook.h_hint) {
   1674 	case HH_NONE :
   1675 		before = NULL;
   1676 		/*
   1677 		 * If there is no hint present (or not one that can be
   1678 		 * satisfied now) then try to at least respect the wishes
   1679 		 * of those that want to be last.  If there are none wanting
   1680 		 * to be last then add the new hook to the tail of the
   1681 		 * list - this means we keep any wanting to be first
   1682 		 * happy without having to search for HH_FIRST.
   1683 		 */
   1684 		TAILQ_FOREACH(hi, head, hi_entry) {
   1685 			hih = &hi->hi_hook;
   1686 			if ((hih->h_hint == HH_AFTER) &&
   1687 			    (strcmp(h->h_name,
   1688 			    (char *)hih->h_hintvalue) == 0)) {
   1689 				TAILQ_INSERT_BEFORE(hi, new, hi_entry);
   1690 				return (0);
   1691 			}
   1692 			if ((hih->h_hint == HH_BEFORE) && (before == NULL) &&
   1693 			    (strcmp(h->h_name,
   1694 			    (char *)hih->h_hintvalue) == 0)) {
   1695 				before = hi;
   1696 			}
   1697 		}
   1698 		if (before != NULL) {
   1699 			TAILQ_INSERT_AFTER(head, before, new, hi_entry);
   1700 			return (0);
   1701 		}
   1702 		hook_insert_plain(head, new);
   1703 		break;
   1704 
   1705 	case HH_FIRST :
   1706 		hi = TAILQ_FIRST(head);
   1707 		if ((hi != NULL) && (hi->hi_hook.h_hint == HH_FIRST))
   1708 			return (EBUSY);
   1709 		TAILQ_INSERT_HEAD(head, new, hi_entry);
   1710 		break;
   1711 
   1712 	case HH_LAST :
   1713 		hi = TAILQ_LAST(head, hook_int_head);
   1714 		if ((hi != NULL) && (hi->hi_hook.h_hint == HH_LAST))
   1715 			return (EBUSY);
   1716 		TAILQ_INSERT_TAIL(head, new, hi_entry);
   1717 		break;
   1718 
   1719 	case HH_BEFORE :
   1720 		hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue);
   1721 		if (hi == NULL)
   1722 			return (hook_insert_afterbefore(head, new));
   1723 
   1724 		if (hi->hi_hook.h_hint == HH_FIRST)
   1725 			return (EBUSY);
   1726 
   1727 		TAILQ_INSERT_BEFORE(hi, new, hi_entry);
   1728 		break;
   1729 
   1730 	case HH_AFTER :
   1731 		hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue);
   1732 		if (hi == NULL)
   1733 			return (hook_insert_afterbefore(head, new));
   1734 
   1735 		if (hi->hi_hook.h_hint == HH_LAST)
   1736 			return (EBUSY);
   1737 
   1738 		TAILQ_INSERT_AFTER(head, hi, new, hi_entry);
   1739 		break;
   1740 
   1741 	default :
   1742 		return (EINVAL);
   1743 	}
   1744 
   1745 	return (0);
   1746 }
   1747 
   1748 /*
   1749  * Function:	hook_insert_plain
   1750  * Returns:	int- 0 = success, else = failure
   1751  * Parameters:	head(I) - pointer to hook list to insert hook onto
   1752  *		new(I)  - pointer to hook to be inserted
   1753  *
   1754  * Insert a hook such that it respects the wishes of those that want to
   1755  * be last.  If there are none wanting to be last then add the new hook
   1756  * to the tail of the list - this means we keep any wanting to be first
   1757  * happy without having to search for HH_FIRST.
   1758  */
   1759 static void
   1760 hook_insert_plain(hook_int_head_t *head, hook_int_t *new)
   1761 {
   1762 	hook_int_t *hi;
   1763 
   1764 	hi = TAILQ_FIRST(head);
   1765 	if (hi != NULL) {
   1766 		if (hi->hi_hook.h_hint == HH_LAST) {
   1767 			TAILQ_INSERT_BEFORE(hi, new, hi_entry);
   1768 		} else {
   1769 			TAILQ_INSERT_TAIL(head, new, hi_entry);
   1770 		}
   1771 	} else {
   1772 		TAILQ_INSERT_TAIL(head, new, hi_entry);
   1773 	}
   1774 }
   1775 
   1776 /*
   1777  * Function:	hook_insert_afterbefore
   1778  * Returns:	int- 0 = success, else = failure
   1779  * Parameters:	head(I) - pointer to hook list to insert hook onto
   1780  *		new(I)  - pointer to hook to be inserted
   1781  *
   1782  * Simple insertion of a hook specifying a HH_BEFORE or HH_AFTER was not
   1783  * possible, so now we need to be more careful.  The first pass is to go
   1784  * through the list and look for any other hooks that also specify the
   1785  * same hint name as the new one.  The object of this exercise is to make
   1786  * sure that hooks with HH_BEFORE always appear on the list before those
   1787  * with HH_AFTER so that when said hook arrives, it can be placed in the
   1788  * middle of the BEFOREs and AFTERs.  If this condition does not arise,
   1789  * just use hook_insert_plain() to try and insert the hook somewhere that
   1790  * is innocuous to existing efforts.
   1791  */
   1792 static int
   1793 hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new)
   1794 {
   1795 	hook_int_t *hi;
   1796 	hook_t *nh;
   1797 	hook_t *h;
   1798 
   1799 	nh = &new->hi_hook;
   1800 	ASSERT(new->hi_hook.h_hint != HH_NONE);
   1801 	ASSERT(new->hi_hook.h_hint != HH_LAST);
   1802 	ASSERT(new->hi_hook.h_hint != HH_FIRST);
   1803 
   1804 	/*
   1805 	 * First, look through the list to see if there are any other
   1806 	 * before's or after's that have a matching hint name.
   1807 	 */
   1808 	TAILQ_FOREACH(hi, head, hi_entry) {
   1809 		h = &hi->hi_hook;
   1810 		switch (h->h_hint) {
   1811 		case HH_FIRST :
   1812 		case HH_LAST :
   1813 		case HH_NONE :
   1814 			break;
   1815 		case HH_BEFORE :
   1816 			if ((nh->h_hint == HH_BEFORE) &&
   1817 			    (strcmp((char *)h->h_hintvalue,
   1818 			    (char *)nh->h_hintvalue) == 0)) {
   1819 				TAILQ_INSERT_AFTER(head, hi, new, hi_entry);
   1820 				return (0);
   1821 			}
   1822 			if ((nh->h_hint == HH_AFTER) &&
   1823 			    (strcmp((char *)h->h_hintvalue,
   1824 			    (char *)nh->h_hintvalue) == 0)) {
   1825 				TAILQ_INSERT_BEFORE(hi, new, hi_entry);
   1826 				return (0);
   1827 			}
   1828 			break;
   1829 		case HH_AFTER :
   1830 			if ((nh->h_hint == HH_AFTER) &&
   1831 			    (strcmp((char *)h->h_hintvalue,
   1832 			    (char *)nh->h_hintvalue) == 0)) {
   1833 				TAILQ_INSERT_AFTER(head, hi, new, hi_entry);
   1834 				return (0);
   1835 			}
   1836 			if ((nh->h_hint == HH_BEFORE) &&
   1837 			    (strcmp((char *)h->h_hintvalue,
   1838 			    (char *)nh->h_hintvalue) == 0)) {
   1839 				TAILQ_INSERT_BEFORE(hi, new, hi_entry);
   1840 				return (0);
   1841 			}
   1842 			break;
   1843 		}
   1844 	}
   1845 
   1846 	hook_insert_plain(head, new);
   1847 
   1848 	return (0);
   1849 }
   1850 
   1851 /*
   1852  * Function:	hook_unregister
   1853  * Returns:	int - 0 = Succ, Else = Fail
   1854  * Parameters:	hfi(I) - internal family pointer
   1855  *		event(I) - event name string
   1856  *		h(I) - hook pointer
   1857  *
   1858  * Remove hook from hook list on specific family, event
   1859  */
   1860 int
   1861 hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h)
   1862 {
   1863 	hook_event_int_t *hei;
   1864 	hook_int_t *hi;
   1865 	boolean_t free_event;
   1866 
   1867 	ASSERT(hfi != NULL);
   1868 	ASSERT(h != NULL);
   1869 
   1870 	CVW_ENTER_WRITE(&hfi->hfi_lock);
   1871 
   1872 	hei = hook_event_find(hfi, event);
   1873 	if (hei == NULL) {
   1874 		CVW_EXIT_WRITE(&hfi->hfi_lock);
   1875 		return (ENXIO);
   1876 	}
   1877 
   1878 	/* Hold write lock for event */
   1879 	CVW_ENTER_WRITE(&hei->hei_lock);
   1880 
   1881 	hi = hook_find(hei, h);
   1882 	if (hi == NULL) {
   1883 		CVW_EXIT_WRITE(&hei->hei_lock);
   1884 		CVW_EXIT_WRITE(&hfi->hfi_lock);
   1885 		return (ENXIO);
   1886 	}
   1887 
   1888 	if (hook_wait_setflag(&hei->hei_waiter, FWF_WAIT_MASK,
   1889 	    FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
   1890 		CVW_EXIT_WRITE(&hei->hei_lock);
   1891 		CVW_EXIT_WRITE(&hfi->hfi_lock);
   1892 		return (ENOENT);
   1893 	}
   1894 
   1895 	/* Remove from hook list */
   1896 	TAILQ_REMOVE(&hei->hei_head, hi, hi_entry);
   1897 
   1898 	free_event = B_FALSE;
   1899 	if (TAILQ_EMPTY(&hei->hei_head)) {
   1900 		hei->hei_event->he_interested = B_FALSE;
   1901 		/*
   1902 		 * If the delete pending flag has been set and there are
   1903 		 * no notifiers on the event (and we've removed the last
   1904 		 * hook) then we need to free this event after we're done.
   1905 		 */
   1906 		if (hei->hei_condemned && TAILQ_EMPTY(&hei->hei_nhead))
   1907 			free_event = B_TRUE;
   1908 	}
   1909 	hei->hei_kstats.hooks_removed.value.ui64++;
   1910 
   1911 	CVW_EXIT_WRITE(&hei->hei_lock);
   1912 	CVW_EXIT_WRITE(&hfi->hfi_lock);
   1913 	/*
   1914 	 * While the FWF_DEL_ACTIVE flag is set, the hook_event_int_t
   1915 	 * will not be free'd and thus the hook_family_int_t wil not
   1916 	 * be free'd either.
   1917 	 */
   1918 	hook_event_notify_run(hei, hfi, event, h->h_name, HN_UNREGISTER);
   1919 	hook_wait_unsetflag(&hei->hei_waiter, FWF_DEL_ACTIVE);
   1920 
   1921 	hook_int_free(hi, hfi->hfi_stack->hks_netstackid);
   1922 
   1923 	if (free_event)
   1924 		hook_event_free(hei, hfi);
   1925 
   1926 	return (0);
   1927 }
   1928 
   1929 /*
   1930  * Function:	hook_find_byname
   1931  * Returns:	internal hook pointer - NULL = Not match
   1932  * Parameters:	hei(I) - internal event pointer
   1933  *		name(I)- hook name
   1934  *
   1935  * Search an event's list of hooks to see if there is a hook present that
   1936  * has a matching name to the one being looked for.
   1937  */
   1938 static hook_int_t *
   1939 hook_find_byname(hook_int_head_t *head, char *name)
   1940 {
   1941 	hook_int_t *hi;
   1942 
   1943 	TAILQ_FOREACH(hi, head, hi_entry) {
   1944 		if (strcmp(hi->hi_hook.h_name, name) == 0)
   1945 			return (hi);
   1946 	}
   1947 
   1948 	return (NULL);
   1949 }
   1950 
   1951 /*
   1952  * Function:	hook_find
   1953  * Returns:	internal hook pointer - NULL = Not match
   1954  * Parameters:	hei(I) - internal event pointer
   1955  *		h(I) - hook pointer
   1956  *
   1957  * Search an event's list of hooks to see if there is already one that
   1958  * matches the hook being passed in.  Currently the only criteria for a
   1959  * successful search here is for the names to be the same.
   1960  */
   1961 static hook_int_t *
   1962 hook_find(hook_event_int_t *hei, hook_t *h)
   1963 {
   1964 
   1965 	ASSERT(hei != NULL);
   1966 	ASSERT(h != NULL);
   1967 
   1968 	return (hook_find_byname(&hei->hei_head, h->h_name));
   1969 }
   1970 
   1971 /*
   1972  * Function:	hook_copy
   1973  * Returns:	internal hook pointer - NULL = Failed
   1974  * Parameters:	src(I) - hook pointer
   1975  *
   1976  * Allocate internal hook block and duplicate incoming hook.
   1977  * No locks should be held across this function as it may sleep.
   1978  * Because hook_copy() is responsible for the creation of the internal
   1979  * hook structure that is used here, it takes on population the structure
   1980  * with the kstat information.  Note that while the kstat bits are
   1981  * seeded here, their installation of the kstats is handled elsewhere.
   1982  */
   1983 static hook_int_t *
   1984 hook_copy(hook_t *src)
   1985 {
   1986 	hook_int_t *new;
   1987 	hook_t *dst;
   1988 	int len;
   1989 
   1990 	ASSERT(src != NULL);
   1991 	ASSERT(src->h_name != NULL);
   1992 
   1993 	new = (hook_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
   1994 
   1995 	/* Copy body */
   1996 	dst = &new->hi_hook;
   1997 	*dst = *src;
   1998 
   1999 	/* Copy name */
   2000 	len = strlen(src->h_name);
   2001 	dst->h_name = (char *)kmem_alloc(len + 1, KM_SLEEP);
   2002 	(void) strcpy(dst->h_name, src->h_name);
   2003 
   2004 	/*
   2005 	 * This is initialised in this manner to make it safer to use the
   2006 	 * same pointer in the kstats field.
   2007 	 */
   2008 	dst->h_hintvalue = (uintptr_t)"";
   2009 
   2010 	if (dst->h_hint == HH_BEFORE || dst->h_hint == HH_AFTER) {
   2011 		len = strlen((char *)src->h_hintvalue);
   2012 		if (len > 0) {
   2013 			dst->h_hintvalue = (uintptr_t)kmem_alloc(len + 1,
   2014 			    KM_SLEEP);
   2015 			(void) strcpy((char *)dst->h_hintvalue,
   2016 			    (char *)src->h_hintvalue);
   2017 		}
   2018 	}
   2019 
   2020 	return (new);
   2021 }
   2022 
   2023 /*
   2024  * Function:	hook_init_kstats
   2025  * Returns:	None
   2026  * Parameters:  hfi(I) - pointer to the family that owns the event.
   2027  *              hei(I) - pointer to the event that owns this hook
   2028  *              hi(I)  - pointer to the hook for which we create kstats for
   2029  *
   2030  * Each hook that is registered with this framework has its own kstats
   2031  * set up so that we can provide an easy way in which to observe the
   2032  * look of hooks (using the kstat command.) The position is set to 0
   2033  * here but is recalculated after we know the insertion has been a
   2034  * success.
   2035  */
   2036 static void
   2037 hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei, hook_int_t *hi)
   2038 {
   2039 	hook_hook_kstat_t template = {
   2040 		{ "version",			KSTAT_DATA_INT32 },
   2041 		{ "flags",			KSTAT_DATA_UINT32 },
   2042 		{ "hint",			KSTAT_DATA_INT32 },
   2043 		{ "hint_value",			KSTAT_DATA_UINT64 },
   2044 		{ "position",			KSTAT_DATA_INT32 },
   2045 		{ "hook_hits",			KSTAT_DATA_UINT64 }
   2046 	};
   2047 	hook_stack_t *hks;
   2048 	size_t kslen;
   2049 	int position;
   2050 	hook_int_t *h;
   2051 
   2052 	kslen = strlen(hfi->hfi_family.hf_name) +
   2053 	    strlen(hei->hei_event->he_name) + 2;
   2054 
   2055 	hi->hi_ksname = (char *)kmem_zalloc(kslen, KM_SLEEP);
   2056 	(void) snprintf(hi->hi_ksname, kslen, "%s/%s",
   2057 	    hfi->hfi_family.hf_name, hei->hei_event->he_name);
   2058 
   2059 	hks = hfi->hfi_stack;
   2060 	hi->hi_kstatp = kstat_create_netstack(hi->hi_ksname, 0,
   2061 	    hi->hi_hook.h_name, "hook", KSTAT_TYPE_NAMED,
   2062 	    sizeof (hi->hi_kstats) / sizeof (kstat_named_t),
   2063 	    KSTAT_FLAG_VIRTUAL, hks->hks_netstackid);
   2064 
   2065 	/* Initialise the kstats for the structure */
   2066 	bcopy(&template, &hi->hi_kstats, sizeof (template));
   2067 	hi->hi_kstats.hook_version.value.i32 = hi->hi_hook.h_version;
   2068 	hi->hi_kstats.hook_flags.value.ui32 = hi->hi_hook.h_flags;
   2069 	hi->hi_kstats.hook_hint.value.i32 = hi->hi_hook.h_hint;
   2070 	hi->hi_kstats.hook_position.value.i32 = 0;
   2071 	hi->hi_kstats.hook_hits.value.ui64 = 0;
   2072 
   2073 	switch (hi->hi_hook.h_hint) {
   2074 	case HH_BEFORE :
   2075 	case HH_AFTER :
   2076 		hi->hi_kstats.hook_hintvalue.data_type = KSTAT_DATA_STRING;
   2077 		hi->hi_kstats.hook_hintvalue.value.ui64 =
   2078 		    hi->hi_hook.h_hintvalue;
   2079 		break;
   2080 	default :
   2081 		break;
   2082 	}
   2083 
   2084 	if (hi->hi_kstatp != NULL) {
   2085 		hi->hi_kstatp->ks_data = (void *)&hi->hi_kstats;
   2086 		hi->hi_kstatp->ks_private =
   2087 		    (void *)(uintptr_t)hks->hks_netstackid;
   2088 
   2089 		kstat_install(hi->hi_kstatp);
   2090 	}
   2091 
   2092 	position = 1;
   2093 	TAILQ_FOREACH(h, &hei->hei_head, hi_entry) {
   2094 		h->hi_kstats.hook_position.value.ui32 = position++;
   2095 	}
   2096 }
   2097 
   2098 /*
   2099  * Function:	hook_int_free
   2100  * Returns:	None
   2101  * Parameters:	hi(I) - internal hook pointer
   2102  *
   2103  * Free alloc memory for hook
   2104  */
   2105 static void
   2106 hook_int_free(hook_int_t *hi, netstackid_t stackid)
   2107 {
   2108 	int len;
   2109 
   2110 	ASSERT(hi != NULL);
   2111 
   2112 	/* Free name space */
   2113 	if (hi->hi_hook.h_name != NULL) {
   2114 		kmem_free(hi->hi_hook.h_name, strlen(hi->hi_hook.h_name) + 1);
   2115 	}
   2116 	if (hi->hi_ksname != NULL) {
   2117 		kmem_free(hi->hi_ksname, strlen(hi->hi_ksname) + 1);
   2118 	}
   2119 
   2120 	/* Free the name used with the before/after hints. */
   2121 	switch (hi->hi_hook.h_hint) {
   2122 	case HH_BEFORE :
   2123 	case HH_AFTER :
   2124 		len = strlen((char *)hi->hi_hook.h_hintvalue);
   2125 		if (len > 0)
   2126 			kmem_free((void *)hi->hi_hook.h_hintvalue, len + 1);
   2127 		break;
   2128 	default :
   2129 		break;
   2130 	}
   2131 
   2132 	if (hi->hi_kstatp != NULL)
   2133 		kstat_delete_netstack(hi->hi_kstatp, stackid);
   2134 
   2135 	/* Free container */
   2136 	kmem_free(hi, sizeof (*hi));
   2137 }
   2138 
   2139 /*
   2140  * Function:	hook_alloc
   2141  * Returns:	hook_t * - pointer to new hook structure
   2142  * Parameters:	version(I) - version number of the API when compiled
   2143  *
   2144  * This function serves as the interface for consumers to obtain a hook_t
   2145  * structure.  At this point in time, there is only a single "version" of
   2146  * it, leading to a straight forward function.  In a perfect world the
   2147  * h_vesion would be a protected data structure member, but C isn't that
   2148  * advanced...
   2149  */
   2150 hook_t *
   2151 hook_alloc(const int h_version)
   2152 {
   2153 	hook_t *h;
   2154 
   2155 	h = kmem_zalloc(sizeof (hook_t), KM_SLEEP);
   2156 	h->h_version = h_version;
   2157 	return (h);
   2158 }
   2159 
   2160 /*
   2161  * Function:	hook_free
   2162  * Returns:	None
   2163  * Parameters:	h(I) - external hook pointer
   2164  *
   2165  * This function only free's memory allocated with hook_alloc(), so that if
   2166  * (for example) kernel memory was allocated for h_name, this needs to be
   2167  * free'd before calling hook_free().
   2168  */
   2169 void
   2170 hook_free(hook_t *h)
   2171 {
   2172 	kmem_free(h, sizeof (*h));
   2173 }
   2174 
   2175 /*
   2176  * Function:	hook_notify_register
   2177  * Returns:	0 = success, else failure
   2178  * Parameters:	lock(I)     - netstack identifier
   2179  *              head(I)     - top of the list of callbacks
   2180  *              callback(I) - function to be called
   2181  *              arg(I)      - arg to pass back to the function
   2182  *
   2183  * This function implements the modification of the list of callbacks
   2184  * that are registered when someone wants to be advised of a change
   2185  * that has happened.
   2186  */
   2187 static int
   2188 hook_notify_register(cvwaitlock_t *lock, hook_notify_head_t *head,
   2189     hook_notify_fn_t callback, void *arg)
   2190 {
   2191 	hook_notify_t *hn;
   2192 
   2193 	CVW_ENTER_WRITE(lock);
   2194 
   2195 	TAILQ_FOREACH(hn, head, hn_entry) {
   2196 		if (hn->hn_func == callback) {
   2197 			CVW_EXIT_WRITE(lock);
   2198 			return (EEXIST);
   2199 		}
   2200 	}
   2201 
   2202 	hn = (hook_notify_t *)kmem_alloc(sizeof (*hn), KM_SLEEP);
   2203 	hn->hn_func = callback;
   2204 	hn->hn_arg = arg;
   2205 	TAILQ_INSERT_TAIL(head, hn, hn_entry);
   2206 
   2207 	CVW_EXIT_WRITE(lock);
   2208 
   2209 	return (0);
   2210 }
   2211 
   2212 /*
   2213  * Function:	hook_stack_notify_register
   2214  * Returns:	0 = success, else failure
   2215  * Parameters:	stackid(I) - netstack identifier
   2216  *              callback(I) - function to be called
   2217  *
   2218  */
   2219 static int
   2220 hook_notify_unregister(cvwaitlock_t *lock, hook_notify_head_t *head,
   2221     hook_notify_fn_t callback)
   2222 {
   2223 	hook_notify_t *hn;
   2224 
   2225 	CVW_ENTER_WRITE(lock);
   2226 
   2227 	TAILQ_FOREACH(hn, head, hn_entry) {
   2228 		if (hn->hn_func == callback)
   2229 			break;
   2230 	}
   2231 	if (hn == NULL) {
   2232 		CVW_EXIT_WRITE(lock);
   2233 		return (ESRCH);
   2234 	}
   2235 
   2236 	TAILQ_REMOVE(head, hn, hn_entry);
   2237 
   2238 	CVW_EXIT_WRITE(lock);
   2239 
   2240 	kmem_free(hn, sizeof (*hn));
   2241 
   2242 	return (0);
   2243 }
   2244 
   2245 /*
   2246  * Function:	hook_notify_run
   2247  * Returns:	None
   2248  * Parameters:	head(I)   - top of the list of callbacks
   2249  *              family(I) - name of the hook family that owns the event
   2250  *              event(I)  - name of the event being changed
   2251  *              name(I)   - name of the object causing change
   2252  *              cmd(I)    - either HN_UNREGISTER or HN_REGISTER
   2253  *
   2254  * This function walks through the list of registered callbacks and
   2255  * executes each one, passing back the arg supplied when registered
   2256  * and the name of the family (that owns the event), event (the thing
   2257  * to which we're making a change) and finally a name that describes
   2258  * what is being added or removed, as indicated by cmd.
   2259  *
   2260  * This function does not acquire or release any lock as it is required
   2261  * that code calling it do so before hand.  The use of hook_notify_head_t
   2262  * is protected by the use of flagwait_t in the structures that own this
   2263  * list and with the use of the FWF_ADD/DEL_ACTIVE flags.
   2264  */
   2265 static void
   2266 hook_notify_run(hook_notify_head_t *head, char *family, char *event,
   2267     char *name, hook_notify_cmd_t cmd)
   2268 {
   2269 	hook_notify_t *hn;
   2270 
   2271 	TAILQ_FOREACH(hn, head, hn_entry) {
   2272 		(*hn->hn_func)(cmd, hn->hn_arg, family, event, name);
   2273 	}
   2274 }
   2275