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