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