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