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