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