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