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