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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2018 Joyent, Inc. All rights reserved.
26 * Copyright (c) 2016 by Delphix. All rights reserved.
28 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/systm.h>
31 #include <sys/errno.h>
33 #include <sys/mutex.h>
34 #include <sys/condvar.h>
35 #include <sys/modctl.h>
36 #include <sys/hook_impl.h>
38 #include <sys/cmn_err.h>
41 * This file provides kernel hook framework.
44 static struct modldrv modlmisc
= {
45 &mod_miscops
, /* drv_modops */
46 "Hooks Interface v1.0", /* drv_linkinfo */
49 static struct modlinkage modlinkage
= {
50 MODREV_1
, /* ml_rev */
51 &modlmisc
, /* ml_linkage */
55 static const char *hook_hintvalue_none
= "<none>";
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.
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.
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
74 * The interesting stuff happens on teardown.
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.
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."
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.
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.
110 * A simple diagram showing the ownership is as follows:
112 * Owned +--------------+
113 * by | hook_stack_t |
114 * the +--------------+
116 * - - - - - - - -|- - - - - - - - - - - - - - - - - -
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 * - - - - - - - -|- - - - - - - - - - - - - - - - - -
132 * Owned +------------+
136 * the consumer | hook_t |
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
149 * A more detailed picture that describes how the family/event structures
150 * are linked together can be found in <sys/hook_impl.h>
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.
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.
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.
206 * Hook internal functions
208 static hook_int_t
*hook_copy(hook_t
*src
);
209 static hook_event_int_t
*hook_event_checkdup(hook_event_t
*he
,
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
,
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
);
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.
250 static hook_stack_head_t hook_stacks
;
251 static kmutex_t hook_stack_lock
;
254 * Module entry points.
262 error
= mod_install(&modlinkage
);
274 error
= mod_remove(&modlinkage
);
282 _info(struct modinfo
*modinfop
)
284 return (mod_info(&modlinkage
, modinfop
));
288 * Function: hook_init
297 mutex_init(&hook_stack_lock
, NULL
, MUTEX_DRIVER
, NULL
);
298 SLIST_INIT(&hook_stacks
);
301 * We want to be informed each time a stack is created or
302 * destroyed in the kernel.
304 netstack_register(NS_HOOK
, hook_stack_init
, hook_stack_shutdown
,
309 * Function: hook_fini
318 netstack_unregister(NS_HOOK
);
320 mutex_destroy(&hook_stack_lock
);
321 ASSERT(SLIST_EMPTY(&hook_stacks
));
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
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.
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.
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
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
358 hook_wait_setflag(flagwait_t
*waiter
, uint32_t busyset
, fwflag_t wanted
,
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
);
370 while (waiter
->fw_flags
& busyset
) {
371 wantedset
= ((waiter
->fw_flags
& wanted
) == wanted
);
373 waiter
->fw_flags
|= wanted
;
374 CVW_EXIT_WRITE(waiter
->fw_owner
);
375 cv_wait(&waiter
->fw_cv
, &waiter
->fw_lock
);
377 * This lock needs to be dropped here to preserve the order
378 * of acquisition that is fw_owner followed by fw_lock, else
381 mutex_exit(&waiter
->fw_lock
);
383 CVW_ENTER_WRITE(waiter
->fw_owner
);
384 mutex_enter(&waiter
->fw_lock
);
386 waiter
->fw_flags
&= ~wanted
;
387 if (waiter
->fw_flags
& FWF_DESTROY
) {
388 cv_signal(&waiter
->fw_cv
);
389 mutex_exit(&waiter
->fw_lock
);
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
);
402 * Function: hook_wait_unsetflag
404 * Parameters: waiter(I) - control data structure
405 * oldflag(I) - flag to reset
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.
411 hook_wait_unsetflag(flagwait_t
*waiter
, fwflag_t oldflag
)
413 mutex_enter(&waiter
->fw_lock
);
414 waiter
->fw_flags
&= ~oldflag
;
415 cv_signal(&waiter
->fw_cv
);
416 mutex_exit(&waiter
->fw_lock
);
420 * Function: hook_wait_destroy
422 * Parameters: waiter(I) - control data structure
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.
431 hook_wait_destroy(flagwait_t
*waiter
)
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
);
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
);
447 * There should now be nothing else using "waiter" or its
448 * owner, so we can safely assign here without risk of wiiping
451 waiter
->fw_flags
= FWF_DESTROY_ACTIVE
;
452 cv_signal(&waiter
->fw_cv
);
453 mutex_exit(&waiter
->fw_lock
);
459 * Function: hook_wait_init
461 * Parameters: waiter(I) - control data structure
462 * ownder(I) - pointer to lock that the owner of this
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.
470 hook_wait_init(flagwait_t
*waiter
, cvwaitlock_t
*owner
)
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
;
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
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.
490 hook_stack_init(netstackid_t stackid
, netstack_t
*ns
)
495 printf("hook_stack_init(stack %d)\n", stackid
);
498 hks
= (hook_stack_t
*)kmem_zalloc(sizeof (*hks
), KM_SLEEP
);
499 hks
->hks_netstack
= ns
;
500 hks
->hks_netstackid
= stackid
;
502 CVW_INIT(&hks
->hks_lock
);
503 TAILQ_INIT(&hks
->hks_nhead
);
504 SLIST_INIT(&hks
->hks_familylist
);
506 hook_wait_init(&hks
->hks_waiter
, &hks
->hks_lock
);
508 mutex_enter(&hook_stack_lock
);
509 SLIST_INSERT_HEAD(&hook_stacks
, hks
, hks_entry
);
510 mutex_exit(&hook_stack_lock
);
516 * Function: hook_stack_shutdown
518 * Parameters: stackid(I) - identifier for the network instance that owns this
519 * arg(I) - pointer returned by hook_stack_init
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.
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.
533 hook_stack_shutdown(netstackid_t stackid
, void *arg
)
535 hook_stack_t
*hks
= (hook_stack_t
*)arg
;
537 mutex_enter(&hook_stack_lock
);
539 * Once this flag gets set to one, no more additions are allowed
540 * to any of the structures that make up this stack.
542 hks
->hks_shutdown
= 1;
543 mutex_exit(&hook_stack_lock
);
547 * Function: hook_stack_destroy
549 * Parameters: stackid(I) - identifier for the network instance that owns this
550 * arg(I) - pointer returned by hook_stack_init
552 * Free the hook stack instance.
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.
561 hook_stack_fini(netstackid_t stackid
, void *arg
)
563 hook_stack_t
*hks
= (hook_stack_t
*)arg
;
565 mutex_enter(&hook_stack_lock
);
566 hks
->hks_shutdown
= 2;
567 hook_stack_remove(hks
);
568 mutex_exit(&hook_stack_lock
);
572 * Function: hook_stack_remove
574 * Parameters: hks(I) - pointer to an instance of a hook_stack_t
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.
582 hook_stack_remove(hook_stack_t
*hks
)
585 ASSERT(mutex_owned(&hook_stack_lock
));
588 * Is the structure still in use?
590 if (!SLIST_EMPTY(&hks
->hks_familylist
) ||
591 !TAILQ_EMPTY(&hks
->hks_nhead
))
594 SLIST_REMOVE(&hook_stacks
, hks
, hook_stack
, hks_entry
);
596 VERIFY(hook_wait_destroy(&hks
->hks_waiter
) == 0);
597 CVW_DESTROY(&hks
->hks_lock
);
598 kmem_free(hks
, sizeof (*hks
));
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
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.
610 static hook_stack_t
*
611 hook_stack_get(netstackid_t stackid
)
615 SLIST_FOREACH(hks
, &hook_stacks
, hks_entry
) {
616 if (hks
->hks_netstackid
== stackid
)
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
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.)
639 hook_stack_notify_register(netstackid_t stackid
, hook_notify_fn_t callback
,
642 hook_family_int_t
*hfi
;
648 ASSERT(callback
!= NULL
);
651 mutex_enter(&hook_stack_lock
);
652 hks
= hook_stack_get(stackid
);
654 if (hks
->hks_shutdown
!= 0) {
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
,
663 CVW_EXIT_WRITE(&hks
->hks_lock
);
668 mutex_exit(&hook_stack_lock
);
670 if (error
== 0 && canrun
) {
672 * Generate fake register event for callback that
673 * is being added, letting it know everything that
676 (void) snprintf(buffer
, sizeof (buffer
), "%u",
677 hks
->hks_netstackid
);
679 SLIST_FOREACH(hfi
, &hks
->hks_familylist
, hfi_entry
) {
680 if (hfi
->hfi_condemned
|| hfi
->hfi_shutdown
)
682 callback(HN_REGISTER
, arg
, buffer
, NULL
,
683 hfi
->hfi_family
.hf_name
);
688 hook_wait_unsetflag(&hks
->hks_waiter
, FWF_ADD_ACTIVE
);
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
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.
706 hook_stack_notify_unregister(netstackid_t stackid
, hook_notify_fn_t callback
)
708 hook_family_int_t
*hfi
;
714 mutex_enter(&hook_stack_lock
);
715 hks
= hook_stack_get(stackid
);
717 mutex_exit(&hook_stack_lock
);
721 CVW_ENTER_WRITE(&hks
->hks_lock
);
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
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
);
738 error
= hook_notify_unregister(&hks
->hks_nhead
, callback
, &arg
);
739 CVW_EXIT_WRITE(&hks
->hks_lock
);
740 mutex_exit(&hook_stack_lock
);
744 * Generate fake unregister event for callback that
745 * is being removed, letting it know everything that
746 * currently exists is now "disappearing."
748 (void) snprintf(buffer
, sizeof (buffer
), "%u",
749 hks
->hks_netstackid
);
751 SLIST_FOREACH(hfi
, &hks
->hks_familylist
, hfi_entry
) {
752 callback(HN_UNREGISTER
, arg
, buffer
, NULL
,
753 hfi
->hfi_family
.hf_name
);
757 * hook_notify_unregister() should only fail if the callback has
758 * already been deleted (ESRCH).
760 VERIFY3S(error
, ==, ESRCH
);
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
);
773 * Function: hook_stack_notify_run
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
779 * Run through the list of callbacks on the hook stack to be called when
780 * a new hook family is added
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.
789 hook_stack_notify_run(hook_stack_t
*hks
, char *name
,
790 hook_notify_cmd_t cmd
)
795 ASSERT(name
!= NULL
);
797 (void) snprintf(buffer
, sizeof (buffer
), "%u", hks
->hks_netstackid
);
799 hook_notify_run(&hks
->hks_nhead
, buffer
, NULL
, name
, cmd
);
804 * Returns: int - return value according to callback func
805 * Parameters: token(I) - event pointer
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.
815 hook_run(hook_family_int_t
*hfi
, hook_event_token_t token
, hook_data_t info
)
817 hook_event_int_t
*hei
;
821 ASSERT(token
!= NULL
);
823 hei
= (hook_event_int_t
*)token
;
824 DTRACE_PROBE2(hook__run__start
,
825 hook_event_token_t
, token
,
829 * If we consider that this function is only called from within the
830 * stack while an instance is currently active,
832 CVW_ENTER_READ(&hfi
->hfi_lock
);
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
,
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
,
846 hi
->hi_kstats
.hook_hits
.value
.ui64
++;
851 hei
->hei_kstats
.events
.value
.ui64
++;
853 CVW_EXIT_READ(&hfi
->hfi_lock
);
855 DTRACE_PROBE3(hook__run__end
,
856 hook_event_token_t
, token
,
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
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.
882 hook_family_add(hook_family_t
*hf
, hook_stack_t
*hks
, void **store
)
884 hook_family_int_t
*hfi
, *new;
887 ASSERT(hf
->hf_name
!= NULL
);
889 new = hook_family_copy(hf
);
893 mutex_enter(&hook_stack_lock
);
894 CVW_ENTER_WRITE(&hks
->hks_lock
);
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
);
903 /* search family list */
904 hfi
= hook_family_find(hf
->hf_name
, hks
);
906 CVW_EXIT_WRITE(&hks
->hks_lock
);
907 mutex_exit(&hook_stack_lock
);
908 hook_family_free(new, NULL
);
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.
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
);
925 CVW_INIT(&new->hfi_lock
);
926 SLIST_INIT(&new->hfi_head
);
927 TAILQ_INIT(&new->hfi_nhead
);
929 hook_wait_init(&new->hfi_waiter
, &new->hfi_lock
);
931 new->hfi_stack
= hks
;
935 /* Add to family list head */
936 SLIST_INSERT_HEAD(&hks
->hks_familylist
, new, hfi_entry
);
938 CVW_EXIT_WRITE(&hks
->hks_lock
);
939 mutex_exit(&hook_stack_lock
);
941 hook_stack_notify_run(hks
, hf
->hf_name
, HN_REGISTER
);
943 hook_wait_unsetflag(&hks
->hks_waiter
, FWF_ADD_ACTIVE
);
949 * Function: hook_family_remove
950 * Returns: int - 0 = success, else = failure
951 * Parameters: hfi(I) - internal family pointer
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.
958 hook_family_remove(hook_family_int_t
*hfi
)
961 boolean_t notifydone
;
964 hks
= hfi
->hfi_stack
;
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
);
971 CVW_ENTER_WRITE(&hks
->hks_lock
);
973 if (hook_wait_setflag(&hks
->hks_waiter
, FWF_DEL_WAIT_MASK
,
974 FWF_DEL_WANTED
, FWF_DEL_ACTIVE
) == -1) {
976 * If we're trying to destroy the hook_stack_t...
978 CVW_EXIT_WRITE(&hks
->hks_lock
);
983 * Check if the family is in use by the presence of either events
984 * or notify callbacks on the hook family.
986 if (!SLIST_EMPTY(&hfi
->hfi_head
) || !TAILQ_EMPTY(&hfi
->hfi_nhead
)) {
987 hfi
->hfi_condemned
= B_TRUE
;
989 VERIFY(hook_wait_destroy(&hfi
->hfi_waiter
) == 0);
991 * Although hfi_condemned = B_FALSE is implied from creation,
992 * putting a comment here inside the else upsets lint.
994 hfi
->hfi_condemned
= B_FALSE
;
996 CVW_EXIT_WRITE(&hks
->hks_lock
);
999 hook_stack_notify_run(hks
, hfi
->hfi_family
.hf_name
,
1002 hook_wait_unsetflag(&hks
->hks_waiter
, FWF_DEL_ACTIVE
);
1005 * If we don't have to wait for anything else to disappear from this
1006 * structure then we can free it up.
1008 if (!hfi
->hfi_condemned
)
1009 hook_family_free(hfi
, hks
);
1016 * Function: hook_family_free
1018 * Parameters: hfi(I) - internal family pointer
1020 * Free alloc memory for family
1023 hook_family_free(hook_family_int_t
*hfi
, hook_stack_t
*hks
)
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.
1031 mutex_enter(&hook_stack_lock
);
1033 ASSERT(hfi
!= NULL
);
1036 CVW_ENTER_WRITE(&hks
->hks_lock
);
1037 /* Remove from family list */
1038 SLIST_REMOVE(&hks
->hks_familylist
, hfi
, hook_family_int
,
1041 CVW_EXIT_WRITE(&hks
->hks_lock
);
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);
1050 /* Free container */
1051 kmem_free(hfi
, sizeof (*hfi
));
1053 if (hks
->hks_shutdown
== 2)
1054 hook_stack_remove(hks
);
1056 mutex_exit(&hook_stack_lock
);
1060 * Function: hook_family_shutdown
1061 * Returns: int - 0 = success, else = failure
1062 * Parameters: hfi(I) - internal family pointer
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.
1070 hook_family_shutdown(hook_family_int_t
*hfi
)
1073 boolean_t notifydone
;
1075 ASSERT(hfi
!= NULL
);
1076 hks
= hfi
->hfi_stack
;
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
);
1083 CVW_ENTER_WRITE(&hks
->hks_lock
);
1085 if (hook_wait_setflag(&hks
->hks_waiter
, FWF_DEL_WAIT_MASK
,
1086 FWF_DEL_WANTED
, FWF_DEL_ACTIVE
) == -1) {
1088 * If we're trying to destroy the hook_stack_t...
1090 CVW_EXIT_WRITE(&hks
->hks_lock
);
1094 CVW_EXIT_WRITE(&hks
->hks_lock
);
1097 hook_stack_notify_run(hks
, hfi
->hfi_family
.hf_name
,
1100 hook_wait_unsetflag(&hks
->hks_waiter
, FWF_DEL_ACTIVE
);
1106 * Function: hook_family_copy
1107 * Returns: internal family pointer - NULL = Failed
1108 * Parameters: src(I) - family pointer
1110 * Allocate internal family block and duplicate incoming family
1111 * No locks should be held across this function as it may sleep.
1113 static hook_family_int_t
*
1114 hook_family_copy(hook_family_t
*src
)
1116 hook_family_int_t
*new;
1119 ASSERT(src
!= NULL
);
1120 ASSERT(src
->hf_name
!= NULL
);
1122 new = (hook_family_int_t
*)kmem_zalloc(sizeof (*new), KM_SLEEP
);
1125 dst
= &new->hfi_family
;
1128 SLIST_INIT(&new->hfi_head
);
1129 TAILQ_INIT(&new->hfi_nhead
);
1132 dst
->hf_name
= kmem_alloc(strlen(src
->hf_name
) + 1, KM_SLEEP
);
1133 (void) strcpy(dst
->hf_name
, src
->hf_name
);
1139 * Function: hook_family_find
1140 * Returns: internal family pointer - NULL = Not match
1141 * Parameters: family(I) - family name string
1143 * Search family list with family name
1144 * A lock on hfi_lock must be held when called.
1146 static hook_family_int_t
*
1147 hook_family_find(char *family
, hook_stack_t
*hks
)
1149 hook_family_int_t
*hfi
= NULL
;
1151 ASSERT(family
!= NULL
);
1153 SLIST_FOREACH(hfi
, &hks
->hks_familylist
, hfi_entry
) {
1154 if (strcmp(hfi
->hfi_family
.hf_name
, family
) == 0)
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
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
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...
1176 * Holding hks_lock is required to provide synchronisation for hks_shutdown.
1179 hook_family_notify_register(hook_family_int_t
*hfi
,
1180 hook_notify_fn_t callback
, void *arg
)
1182 hook_event_int_t
*hei
;
1187 ASSERT(hfi
!= NULL
);
1189 hks
= hfi
->hfi_stack
;
1191 CVW_ENTER_READ(&hks
->hks_lock
);
1193 if ((hfi
->hfi_stack
->hks_shutdown
!= 0) ||
1194 hfi
->hfi_condemned
|| hfi
->hfi_shutdown
) {
1195 CVW_EXIT_READ(&hks
->hks_lock
);
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
);
1205 CVW_EXIT_READ(&hks
->hks_lock
);
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
);
1216 hook_wait_unsetflag(&hfi
->hfi_waiter
, FWF_ADD_ACTIVE
);
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
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
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.
1245 hook_family_notify_unregister(hook_family_int_t
*hfi
,
1246 hook_notify_fn_t callback
)
1248 hook_event_int_t
*hei
;
1249 boolean_t free_family
;
1256 CVW_ENTER_WRITE(&hfi
->hfi_lock
);
1258 (void) hook_wait_setflag(&hfi
->hfi_waiter
, FWF_DEL_WAIT_MASK
,
1259 FWF_DEL_WANTED
, FWF_DEL_ACTIVE
);
1261 error
= hook_notify_unregister(&hfi
->hfi_nhead
, callback
, &arg
);
1263 hook_wait_unsetflag(&hfi
->hfi_waiter
, FWF_DEL_ACTIVE
);
1266 * If hook_family_remove has been called but the structure was still
1267 * "busy" ... but we might have just made it "unbusy"...
1269 if ((error
== 0) && hfi
->hfi_condemned
&&
1270 SLIST_EMPTY(&hfi
->hfi_head
) && TAILQ_EMPTY(&hfi
->hfi_nhead
)) {
1271 free_family
= B_TRUE
;
1273 free_family
= B_FALSE
;
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);
1281 CVW_EXIT_WRITE(&hfi
->hfi_lock
);
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
);
1290 hook_wait_unsetflag(&hfi
->hfi_waiter
, FWF_ADD_ACTIVE
);
1291 } else if (free_family
) {
1292 hook_family_free(hfi
, hfi
->hfi_stack
);
1299 * Function: hook_event_add
1300 * Returns: internal event pointer - NULL = Fail
1301 * Parameters: hfi(I) - internal family pointer
1302 * he(I) - event pointer
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.)
1310 hook_event_add(hook_family_int_t
*hfi
, hook_event_t
*he
)
1312 hook_event_int_t
*hei
, *new;
1315 ASSERT(hfi
!= NULL
);
1317 ASSERT(he
->he_name
!= NULL
);
1319 new = hook_event_copy(he
);
1323 hks
= hfi
->hfi_stack
;
1324 CVW_ENTER_READ(&hks
->hks_lock
);
1326 hks
= hfi
->hfi_stack
;
1327 if (hks
->hks_shutdown
!= 0) {
1328 CVW_EXIT_READ(&hks
->hks_lock
);
1329 hook_event_free(new, NULL
);
1333 /* Check whether this event pointer is already registered */
1334 hei
= hook_event_checkdup(he
, hks
);
1336 CVW_EXIT_READ(&hks
->hks_lock
);
1337 hook_event_free(new, NULL
);
1341 CVW_ENTER_WRITE(&hfi
->hfi_lock
);
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
);
1349 CVW_EXIT_READ(&hks
->hks_lock
);
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
);
1358 TAILQ_INIT(&new->hei_nhead
);
1360 hook_event_init_kstats(hfi
, new);
1361 hook_wait_init(&new->hei_waiter
, &new->hei_lock
);
1363 /* Add to event list head */
1364 SLIST_INSERT_HEAD(&hfi
->hfi_head
, new, hei_entry
);
1366 CVW_EXIT_WRITE(&hfi
->hfi_lock
);
1368 hook_notify_run(&hfi
->hfi_nhead
,
1369 hfi
->hfi_family
.hf_name
, NULL
, he
->he_name
, HN_REGISTER
);
1371 hook_wait_unsetflag(&hfi
->hfi_waiter
, FWF_ADD_ACTIVE
);
1377 * Function: hook_event_init_kstats
1379 * Parameters: hfi(I) - pointer to the family that owns this event.
1380 * hei(I) - pointer to the hook event that needs some kstats.
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.
1389 hook_event_init_kstats(hook_family_int_t
*hfi
, hook_event_int_t
*hei
)
1391 hook_event_kstat_t
template = {
1392 { "hooksAdded", KSTAT_DATA_UINT64
},
1393 { "hooksRemoved", KSTAT_DATA_UINT64
},
1394 { "events", KSTAT_DATA_UINT64
}
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
);
1404 bcopy((char *)&template, &hei
->hei_kstats
, sizeof (template));
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
;
1411 kstat_install(hei
->hei_kstatp
);
1416 * Function: hook_event_remove
1417 * Returns: int - 0 = success, else = failure
1418 * Parameters: hfi(I) - internal family pointer
1419 * he(I) - event pointer
1421 * Remove event from event list on specific family
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.
1430 hook_event_remove(hook_family_int_t
*hfi
, hook_event_t
*he
)
1432 boolean_t free_family
;
1433 hook_event_int_t
*hei
;
1434 boolean_t notifydone
;
1436 ASSERT(hfi
!= NULL
);
1439 CVW_ENTER_WRITE(&hfi
->hfi_lock
);
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.
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
);
1452 hei
= hook_event_find(hfi
, he
->he_name
);
1454 hook_wait_unsetflag(&hfi
->hfi_waiter
, FWF_DEL_ACTIVE
);
1455 CVW_EXIT_WRITE(&hfi
->hfi_lock
);
1459 free_family
= B_FALSE
;
1461 CVW_ENTER_WRITE(&hei
->hei_lock
);
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.
1466 notifydone
= hei
->hei_shutdown
;
1467 hei
->hei_shutdown
= B_TRUE
;
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.
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
);
1477 /* hei_condemned = B_FALSE is implied from creation */
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.
1483 VERIFY(hook_wait_destroy(&hei
->hei_waiter
) == 0);
1485 CVW_EXIT_WRITE(&hei
->hei_lock
);
1487 if (hfi
->hfi_condemned
&& SLIST_EMPTY(&hfi
->hfi_head
) &&
1488 TAILQ_EMPTY(&hfi
->hfi_nhead
))
1489 free_family
= B_TRUE
;
1492 CVW_EXIT_WRITE(&hfi
->hfi_lock
);
1495 hook_notify_run(&hfi
->hfi_nhead
,
1496 hfi
->hfi_family
.hf_name
, NULL
, he
->he_name
, HN_UNREGISTER
);
1498 hook_wait_unsetflag(&hfi
->hfi_waiter
, FWF_DEL_ACTIVE
);
1500 if (!hei
->hei_condemned
) {
1501 hook_event_free(hei
, hfi
);
1503 hook_family_free(hfi
, hfi
->hfi_stack
);
1510 * Function: hook_event_shutdown
1511 * Returns: int - 0 = success, else = failure
1512 * Parameters: hfi(I) - internal family pointer
1513 * he(I) - event pointer
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.
1519 hook_event_shutdown(hook_family_int_t
*hfi
, hook_event_t
*he
)
1521 hook_event_int_t
*hei
;
1522 boolean_t notifydone
;
1524 ASSERT(hfi
!= NULL
);
1527 CVW_ENTER_WRITE(&hfi
->hfi_lock
);
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.
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
);
1540 hei
= hook_event_find(hfi
, he
->he_name
);
1542 hook_wait_unsetflag(&hfi
->hfi_waiter
, FWF_DEL_ACTIVE
);
1543 CVW_EXIT_WRITE(&hfi
->hfi_lock
);
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
);
1552 CVW_EXIT_WRITE(&hfi
->hfi_lock
);
1555 hook_notify_run(&hfi
->hfi_nhead
,
1556 hfi
->hfi_family
.hf_name
, NULL
, he
->he_name
, HN_UNREGISTER
);
1558 hook_wait_unsetflag(&hfi
->hfi_waiter
, FWF_DEL_ACTIVE
);
1564 * Function: hook_event_free
1566 * Parameters: hei(I) - internal event pointer
1568 * Free alloc memory for event
1571 hook_event_free(hook_event_int_t
*hei
, hook_family_int_t
*hfi
)
1573 boolean_t free_family
;
1575 ASSERT(hei
!= NULL
);
1578 CVW_ENTER_WRITE(&hfi
->hfi_lock
);
1580 * Remove the event from the hook family's list.
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
;
1587 free_family
= B_FALSE
;
1589 CVW_EXIT_WRITE(&hfi
->hfi_lock
);
1592 if (hei
->hei_kstatp
!= NULL
) {
1593 ASSERT(hfi
!= NULL
);
1595 kstat_delete_netstack(hei
->hei_kstatp
,
1596 hfi
->hfi_stack
->hks_netstackid
);
1597 hei
->hei_kstatp
= NULL
;
1600 /* Free container */
1601 kmem_free(hei
, sizeof (*hei
));
1604 hook_family_free(hfi
, hfi
->hfi_stack
);
1608 * Function: hook_event_checkdup
1609 * Returns: internal event pointer - NULL = Not match
1610 * Parameters: he(I) - event pointer
1612 * Search all of the hook families to see if the event being passed in
1613 * has already been associated with one.
1615 static hook_event_int_t
*
1616 hook_event_checkdup(hook_event_t
*he
, hook_stack_t
*hks
)
1618 hook_family_int_t
*hfi
;
1619 hook_event_int_t
*hei
;
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
);
1632 CVW_EXIT_READ(&hks
->hks_lock
);
1638 * Function: hook_event_copy
1639 * Returns: internal event pointer - NULL = Failed
1640 * Parameters: src(I) - event pointer
1642 * Allocate internal event block and duplicate incoming event
1643 * No locks should be held across this function as it may sleep.
1645 static hook_event_int_t
*
1646 hook_event_copy(hook_event_t
*src
)
1648 hook_event_int_t
*new;
1650 ASSERT(src
!= NULL
);
1651 ASSERT(src
->he_name
!= NULL
);
1653 new = (hook_event_int_t
*)kmem_zalloc(sizeof (*new), KM_SLEEP
);
1656 TAILQ_INIT(&new->hei_head
);
1657 new->hei_event
= src
;
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
1668 * Search event list with event name
1669 * A lock on hfi->hfi_lock must be held when called.
1671 static hook_event_int_t
*
1672 hook_event_find(hook_family_int_t
*hfi
, char *event
)
1674 hook_event_int_t
*hei
= NULL
;
1676 ASSERT(hfi
!= NULL
);
1677 ASSERT(event
!= NULL
);
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))
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
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.
1700 hook_event_notify_register(hook_family_int_t
*hfi
, char *event
,
1701 hook_notify_fn_t callback
, void *arg
)
1703 hook_event_int_t
*hei
;
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
);
1717 CVW_ENTER_READ(&hfi
->hfi_lock
);
1719 if (hfi
->hfi_condemned
|| hfi
->hfi_shutdown
) {
1720 CVW_EXIT_READ(&hfi
->hfi_lock
);
1721 CVW_EXIT_READ(&hks
->hks_lock
);
1725 hei
= hook_event_find(hfi
, event
);
1727 CVW_EXIT_READ(&hfi
->hfi_lock
);
1728 CVW_EXIT_READ(&hks
->hks_lock
);
1732 if (hei
->hei_condemned
|| hei
->hei_shutdown
) {
1733 CVW_EXIT_READ(&hfi
->hfi_lock
);
1734 CVW_EXIT_READ(&hks
->hks_lock
);
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
);
1744 CVW_EXIT_READ(&hfi
->hfi_lock
);
1745 CVW_EXIT_READ(&hks
->hks_lock
);
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
,
1756 hook_wait_unsetflag(&hei
->hei_waiter
, FWF_ADD_ACTIVE
);
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
1768 * Remove the given callback from the named event's list of functions
1769 * to call when a hook is added or removed.
1772 hook_event_notify_unregister(hook_family_int_t
*hfi
, char *event
,
1773 hook_notify_fn_t callback
)
1775 hook_event_int_t
*hei
;
1776 boolean_t free_event
;
1784 CVW_ENTER_READ(&hfi
->hfi_lock
);
1786 hei
= hook_event_find(hfi
, event
);
1788 CVW_EXIT_READ(&hfi
->hfi_lock
);
1792 CVW_ENTER_WRITE(&hei
->hei_lock
);
1794 (void) hook_wait_setflag(&hei
->hei_waiter
, FWF_DEL_WAIT_MASK
,
1795 FWF_DEL_WANTED
, FWF_DEL_ACTIVE
);
1797 error
= hook_notify_unregister(&hei
->hei_nhead
, callback
, &arg
);
1799 hook_wait_unsetflag(&hei
->hei_waiter
, FWF_DEL_ACTIVE
);
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.
1809 if ((error
== 0) && hei
->hei_condemned
&&
1810 TAILQ_EMPTY(&hei
->hei_head
) && TAILQ_EMPTY(&hei
->hei_nhead
)) {
1811 free_event
= B_TRUE
;
1813 free_event
= B_FALSE
;
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);
1821 CVW_EXIT_WRITE(&hei
->hei_lock
);
1822 CVW_EXIT_READ(&hfi
->hfi_lock
);
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
,
1831 hook_wait_unsetflag(&hei
->hei_waiter
, FWF_ADD_ACTIVE
);
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...
1840 hook_event_free(hei
, hfi
);
1847 * Function: hook_event_notify_run
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
1854 * Execute all of the callbacks registered for this event.
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
)
1861 hook_notify_run(&hei
->hei_nhead
, hfi
->hfi_family
.hf_name
,
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
1872 * Add new hook to hook list on the specified family and event.
1875 hook_register(hook_family_int_t
*hfi
, char *event
, hook_t
*h
)
1877 hook_event_int_t
*hei
;
1878 hook_int_t
*hi
, *new;
1881 ASSERT(hfi
!= NULL
);
1882 ASSERT(event
!= NULL
);
1885 if (hfi
->hfi_stack
->hks_shutdown
)
1888 /* Alloc hook_int_t and copy hook */
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
1898 CVW_ENTER_WRITE(&hfi
->hfi_lock
);
1900 hei
= hook_event_find(hfi
, event
);
1902 CVW_EXIT_WRITE(&hfi
->hfi_lock
);
1903 hook_int_free(new, hfi
->hfi_stack
->hks_netstackid
);
1907 CVW_ENTER_WRITE(&hei
->hei_lock
);
1910 * If we've run either the remove() or shutdown(), do not allow any
1911 * more hooks to be added to this event.
1913 if (hei
->hei_shutdown
) {
1918 hi
= hook_find(hei
, h
);
1924 if (hook_wait_setflag(&hei
->hei_waiter
, FWF_ADD_WAIT_MASK
,
1925 FWF_ADD_WANTED
, FWF_ADD_ACTIVE
) == -1) {
1928 CVW_EXIT_WRITE(&hei
->hei_lock
);
1929 CVW_EXIT_WRITE(&hfi
->hfi_lock
);
1930 hook_int_free(new, hfi
->hfi_stack
->hks_netstackid
);
1934 /* Add to hook list head */
1935 error
= hook_insert(&hei
->hei_head
, new);
1937 hei
->hei_event
->he_interested
= B_TRUE
;
1938 hei
->hei_kstats
.hooks_added
.value
.ui64
++;
1940 hook_init_kstats(hfi
, hei
, new);
1943 CVW_EXIT_WRITE(&hei
->hei_lock
);
1944 CVW_EXIT_WRITE(&hfi
->hfi_lock
);
1947 * Note that the name string passed through to the notify callbacks
1948 * is from the original hook being registered, not the copy being
1952 hook_event_notify_run(hei
, hfi
, event
, h
->h_name
, HN_REGISTER
);
1954 hook_wait_unsetflag(&hei
->hei_waiter
, FWF_ADD_ACTIVE
);
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
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.
1972 hook_insert(hook_int_head_t
*head
, hook_int_t
*new)
1977 hook_t
*h
= &new->hi_hook
;
1979 switch (new->hi_hook
.h_hint
) {
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.
1990 TAILQ_FOREACH(hi
, head
, hi_entry
) {
1992 if ((hih
->h_hint
== HH_AFTER
) &&
1994 (char *)hih
->h_hintvalue
) == 0)) {
1995 TAILQ_INSERT_BEFORE(hi
, new, hi_entry
);
1998 if ((hih
->h_hint
== HH_BEFORE
) && (before
== NULL
) &&
2000 (char *)hih
->h_hintvalue
) == 0)) {
2004 if (before
!= NULL
) {
2005 TAILQ_INSERT_AFTER(head
, before
, new, hi_entry
);
2008 hook_insert_plain(head
, new);
2012 hi
= TAILQ_FIRST(head
);
2013 if ((hi
!= NULL
) && (hi
->hi_hook
.h_hint
== HH_FIRST
))
2015 TAILQ_INSERT_HEAD(head
, new, hi_entry
);
2019 hi
= TAILQ_LAST(head
, hook_int_head
);
2020 if ((hi
!= NULL
) && (hi
->hi_hook
.h_hint
== HH_LAST
))
2022 TAILQ_INSERT_TAIL(head
, new, hi_entry
);
2026 hi
= hook_find_byname(head
, (char *)new->hi_hook
.h_hintvalue
);
2028 return (hook_insert_afterbefore(head
, new));
2030 if (hi
->hi_hook
.h_hint
== HH_FIRST
)
2033 TAILQ_INSERT_BEFORE(hi
, new, hi_entry
);
2037 hi
= hook_find_byname(head
, (char *)new->hi_hook
.h_hintvalue
);
2039 return (hook_insert_afterbefore(head
, new));
2041 if (hi
->hi_hook
.h_hint
== HH_LAST
)
2044 TAILQ_INSERT_AFTER(head
, hi
, new, hi_entry
);
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
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.
2066 hook_insert_plain(hook_int_head_t
*head
, hook_int_t
*new)
2070 hi
= TAILQ_FIRST(head
);
2072 if (hi
->hi_hook
.h_hint
== HH_LAST
) {
2073 TAILQ_INSERT_BEFORE(hi
, new, hi_entry
);
2075 TAILQ_INSERT_TAIL(head
, new, hi_entry
);
2078 TAILQ_INSERT_TAIL(head
, new, hi_entry
);
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
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.
2099 hook_insert_afterbefore(hook_int_head_t
*head
, hook_int_t
*new)
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
);
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.
2114 TAILQ_FOREACH(hi
, head
, hi_entry
) {
2116 switch (h
->h_hint
) {
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
);
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
);
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
);
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
);
2152 hook_insert_plain(head
, new);
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
2164 * Remove hook from hook list on specific family, event
2167 hook_unregister(hook_family_int_t
*hfi
, char *event
, hook_t
*h
)
2169 hook_event_int_t
*hei
;
2171 boolean_t free_event
;
2173 ASSERT(hfi
!= NULL
);
2176 CVW_ENTER_WRITE(&hfi
->hfi_lock
);
2178 hei
= hook_event_find(hfi
, event
);
2180 CVW_EXIT_WRITE(&hfi
->hfi_lock
);
2184 /* Hold write lock for event */
2185 CVW_ENTER_WRITE(&hei
->hei_lock
);
2187 hi
= hook_find(hei
, h
);
2189 CVW_EXIT_WRITE(&hei
->hei_lock
);
2190 CVW_EXIT_WRITE(&hfi
->hfi_lock
);
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
);
2201 /* Remove from hook list */
2202 TAILQ_REMOVE(&hei
->hei_head
, hi
, hi_entry
);
2204 free_event
= B_FALSE
;
2205 if (TAILQ_EMPTY(&hei
->hei_head
)) {
2206 hei
->hei_event
->he_interested
= B_FALSE
;
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.
2212 if (hei
->hei_condemned
&& TAILQ_EMPTY(&hei
->hei_nhead
))
2213 free_event
= B_TRUE
;
2215 hei
->hei_kstats
.hooks_removed
.value
.ui64
++;
2217 CVW_EXIT_WRITE(&hei
->hei_lock
);
2218 CVW_EXIT_WRITE(&hfi
->hfi_lock
);
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
2224 hook_event_notify_run(hei
, hfi
, event
, h
->h_name
, HN_UNREGISTER
);
2225 hook_wait_unsetflag(&hei
->hei_waiter
, FWF_DEL_ACTIVE
);
2227 hook_int_free(hi
, hfi
->hfi_stack
->hks_netstackid
);
2230 hook_event_free(hei
, hfi
);
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
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.
2245 hook_find_byname(hook_int_head_t
*head
, char *name
)
2249 TAILQ_FOREACH(hi
, head
, hi_entry
) {
2250 if (strcmp(hi
->hi_hook
.h_name
, name
) == 0)
2258 * Function: hook_find
2259 * Returns: internal hook pointer - NULL = Not match
2260 * Parameters: hei(I) - internal event pointer
2261 * h(I) - hook pointer
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.
2268 hook_find(hook_event_int_t
*hei
, hook_t
*h
)
2271 ASSERT(hei
!= NULL
);
2274 return (hook_find_byname(&hei
->hei_head
, h
->h_name
));
2278 * Function: hook_copy
2279 * Returns: internal hook pointer - NULL = Failed
2280 * Parameters: src(I) - hook pointer
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.
2290 hook_copy(hook_t
*src
)
2296 ASSERT(src
!= NULL
);
2297 ASSERT(src
->h_name
!= NULL
);
2299 new = (hook_int_t
*)kmem_zalloc(sizeof (*new), KM_SLEEP
);
2302 dst
= &new->hi_hook
;
2306 len
= strlen(src
->h_name
);
2307 dst
->h_name
= kmem_alloc(len
+ 1, KM_SLEEP
);
2308 (void) strcpy(dst
->h_name
, src
->h_name
);
2311 * This is initialised in this manner to make it safer to use the
2312 * same pointer in the kstats field.
2314 dst
->h_hintvalue
= (uintptr_t)"";
2316 if (dst
->h_hint
== HH_BEFORE
|| dst
->h_hint
== HH_AFTER
) {
2317 len
= strlen((char *)src
->h_hintvalue
);
2319 dst
->h_hintvalue
= (uintptr_t)kmem_alloc(len
+ 1,
2321 (void) strcpy((char *)dst
->h_hintvalue
,
2322 (char *)src
->h_hintvalue
);
2330 * Function: hook_init_kstats
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
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
2343 hook_init_kstats(hook_family_int_t
*hfi
, hook_event_int_t
*hei
, hook_int_t
*hi
)
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
}
2358 kslen
= strlen(hfi
->hfi_family
.hf_name
) +
2359 strlen(hei
->hei_event
->he_name
) + 2;
2361 hi
->hi_ksname
= 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
);
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
);
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;
2379 switch (hi
->hi_hook
.h_hint
) {
2382 kstat_named_setstr(&(hi
->hi_kstats
.hook_hintvalue
),
2383 (const char *)hi
->hi_hook
.h_hintvalue
);
2386 kstat_named_setstr(&(hi
->hi_kstats
.hook_hintvalue
),
2387 hook_hintvalue_none
);
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;
2398 kstat_install(hi
->hi_kstatp
);
2402 TAILQ_FOREACH(h
, &hei
->hei_head
, hi_entry
) {
2403 h
->hi_kstats
.hook_position
.value
.ui32
= position
++;
2408 * Function: hook_int_free
2410 * Parameters: hi(I) - internal hook pointer
2412 * Free memory allocated to support a hook.
2415 hook_int_free(hook_int_t
*hi
, netstackid_t stackid
)
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);
2425 if (hi
->hi_ksname
!= NULL
) {
2426 kmem_free(hi
->hi_ksname
, strlen(hi
->hi_ksname
) + 1);
2429 /* Free the name used with the before/after hints. */
2430 switch (hi
->hi_hook
.h_hint
) {
2433 len
= strlen((char *)hi
->hi_hook
.h_hintvalue
);
2435 kmem_free((void *)hi
->hi_hook
.h_hintvalue
, len
+ 1);
2441 if (hi
->hi_kstatp
!= NULL
)
2442 kstat_delete_netstack(hi
->hi_kstatp
, stackid
);
2444 /* Free container */
2445 kmem_free(hi
, sizeof (*hi
));
2449 * Function: hook_alloc
2450 * Returns: hook_t * - pointer to new hook structure
2451 * Parameters: version(I) - version number of the API when compiled
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
2460 hook_alloc(const int h_version
)
2464 h
= kmem_zalloc(sizeof (hook_t
), KM_SLEEP
);
2465 h
->h_version
= h_version
;
2470 * Function: hook_free
2472 * Parameters: h(I) - external hook pointer
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().
2479 hook_free(hook_t
*h
)
2481 kmem_free(h
, sizeof (*h
));
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
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.
2496 hook_notify_register(hook_notify_head_t
*head
, hook_notify_fn_t callback
,
2501 TAILQ_FOREACH(hn
, head
, hn_entry
) {
2502 if (hn
->hn_func
== callback
) {
2507 hn
= (hook_notify_t
*)kmem_alloc(sizeof (*hn
), KM_SLEEP
);
2508 hn
->hn_func
= callback
;
2510 TAILQ_INSERT_TAIL(head
, hn
, hn_entry
);
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
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.
2528 hook_notify_unregister(hook_notify_head_t
*head
,
2529 hook_notify_fn_t callback
, void **parg
)
2533 ASSERT(parg
!= NULL
);
2535 TAILQ_FOREACH(hn
, head
, hn_entry
) {
2536 if (hn
->hn_func
== callback
)
2545 TAILQ_REMOVE(head
, hn
, hn_entry
);
2547 kmem_free(hn
, sizeof (*hn
));
2553 * Function: hook_notify_run
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
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.
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.
2573 hook_notify_run(hook_notify_head_t
*head
, char *family
, char *event
,
2574 char *name
, hook_notify_cmd_t cmd
)
2578 TAILQ_FOREACH(hn
, head
, hn_entry
) {
2579 (*hn
->hn_func
)(cmd
, hn
->hn_arg
, family
, event
, name
);