832 need Intel 82579 Gigabit Ethernet PHY support in e1000g
[illumos-gate.git] / usr / src / uts / common / io / hook.c
blob2c774094e9f048e8d7c3528101f784a7fb9a756d
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 #include <sys/param.h>
26 #include <sys/types.h>
27 #include <sys/systm.h>
28 #include <sys/errno.h>
29 #include <sys/kmem.h>
30 #include <sys/mutex.h>
31 #include <sys/condvar.h>
32 #include <sys/modctl.h>
33 #include <sys/hook_impl.h>
34 #include <sys/sdt.h>
35 #include <sys/cmn_err.h>
38 * This file provides kernel hook framework.
41 static struct modldrv modlmisc = {
42 &mod_miscops, /* drv_modops */
43 "Hooks Interface v1.0", /* drv_linkinfo */
46 static struct modlinkage modlinkage = {
47 MODREV_1, /* ml_rev */
48 &modlmisc, /* ml_linkage */
49 NULL
53 * How it works.
54 * =============
55 * Use of the hook framework here is tied up with zones - when a new zone
56 * is created, we create a new hook_stack_t and are open to business for
57 * allowing new hook families and their events.
59 * A consumer of these hooks is expected to operate in this fashion:
60 * 1) call hook_family_add() to create a new family of hooks. It is a
61 * current requirement that this call must be made with the value
62 * returned from hook_stack_init, by way of infrastructure elsewhere.
63 * 2) add events to the registered family with calls to hook_event_add.
65 * At this point, the structures in place should be open to others to
66 * add hooks to the event or add notifiers for when the contents of the
67 * hook stack changes.
69 * The interesting stuff happens on teardown.
71 * It is a requirement that the provider of hook events work in the reverse
72 * order to the above, so that the first step is:
73 * 1) remove events from each hook family created earlier
74 * 2) remove hook families from the hook stack.
76 * When doing teardown of both events and families, a check is made to see
77 * if either structure is still "busy". If so then a boolean flag (FWF_DESTROY)
78 * is set to say that the structure is condemned. The presence of this flag
79 * being set must be checked for in _add()/_register()/ functions and a
80 * failure returned if it is set. It is ignored by the _find() functions
81 * because they're used by _remove()/_unregister().
82 * While setting the condemned flag when trying to delete a structure would
83 * normally be keyed from the presence of a reference count being greater
84 * than 1, in this implementation there are no reference counts required:
85 * instead the presence of objects on linked lists is taken to mean
86 * something is still "busy."
88 * ONLY the caller that adds the family and the events ever has a direct
89 * reference to the internal structures and thus ONLY it should be doing
90 * the removal of either the event or family. In practise, what this means
91 * is that in ip_netinfo.c, we have calls to net_protocol_register(), followed
92 * by net_event_register() (these interface to hook_family_add() and
93 * hook_event_add(), respectively) that are made when we create an instance
94 * of IP and when the IP instance is shutdown/destroyed, it calls
95 * net_event_unregister() and net_protocol_unregister(), which in turn call
96 * hook_event_remove() and hook_family_remove() respectively. Nobody else
97 * is entitled to call the _unregister() functions. It is imperative that
98 * there be only one _remove() call for every _add() call.
100 * It is possible that code which is interfacing with this hook framework
101 * won't do all the cleaning up that it needs to at the right time. While
102 * we can't prevent programmers from creating memory leaks, we can synchronise
103 * when we clean up data structures to prevent code accessing free'd memory.
105 * A simple diagram showing the ownership is as follows:
107 * Owned +--------------+
108 * by | hook_stack_t |
109 * the +--------------+
110 * Instance |
111 * - - - - - - - -|- - - - - - - - - - - - - - - - - -
113 * Owned +-------------------+ +-------------------+
114 * | hook_family_int_t |---->| hook_family_int_t |
115 * by +-------------------+ +-------------------+
116 * | \+---------------+ \+---------------+
117 * network | | hook_family_t | | hook_family_t |
118 * V +---------------+ +---------------+
119 * protocol +------------------+ +------------------+
120 * | hook_event_int_t |---->| hook_event_int_t |
121 * (ipv4,ipv6) +------------------+ +------------------+
122 * | \+--------------+ \+--------------+
123 * | | hook_event_t | | hook_event_t |
124 * | +--------------+ +--------------+
125 * - - - - - - - -|- - - - - - - - - - - - - - - - - -
127 * Owned +------------+
128 * | hook_int_t |
129 * by +------------+
130 * \+--------+
131 * the consumer | hook_t |
132 * +--------+
134 * The consumers, such as IPFilter, do not have any pointers or hold any
135 * references to hook_int_t, hook_event_t or hook_event_int_t. By placing
136 * a hook on an event through net_hook_register(), an implicit reference
137 * to the hook_event_int_t is returned with a successful call. Additionally,
138 * IPFilter does not see the hook_family_int_t or hook_family_t directly.
139 * Rather it is returned a net_handle_t (from net_protocol_lookup()) that
140 * contains a pointer to hook_family_int_t. The structure behind the
141 * net_handle_t (struct net_data) *is* reference counted and managed
142 * appropriately.
144 * A more detailed picture that describes how the family/event structures
145 * are linked together can be found in <sys/hook_impl.h>
147 * Notification callbacks.
148 * =======================
149 * For each of the hook stack, hook family and hook event, it is possible
150 * to request notificatin of change to them. Why?
151 * First, lets equate the hook stack to an IP instance, a hook family to
152 * a network protocol and a hook event to IP packets on the input path.
153 * If a kernel module wants to apply security from the very start of
154 * things, it needs to know as soon as a new instance of networking
155 * is initiated. Whilst for the global zone, it is taken for granted that
156 * this instance will always exist before any interaction takes place,
157 * that is not true for zones running with an exclusive networking instance.
158 * Thus when a local zone is started and a new instance is created to support
159 * that, parties that wish to monitor it and apply a security policy from
160 * the onset need to be informed as early as possible - quite probably
161 * before any networking is started by the zone's boot scripts.
162 * Inside each instance, it is possible to have a number of network protocols
163 * (hook families) in operation. Inside the context of the global zone,
164 * it is possible to have code run before the kernel module providing the
165 * IP networking is loaded. From here, to apply the appropriate security,
166 * it is necessary to become informed of when IP is being configured into
167 * the zone and this is done by registering a notification callback with
168 * the hook stack for changes to it. The next step is to know when packets
169 * can be received through the physical_in, etc, events. This is achieved
170 * by registering a callback with the appropriate network protocol (or in
171 * this file, the correct hook family.) Thus when IP finally attaches a
172 * physical_in event to inet, the module looking to enforce a security
173 * policy can become aware of it being present. Of course there's no
174 * requirement for such a module to be present before all of the above
175 * happens and in such a case, it is reasonable for the same module to
176 * work after everything has been put in place. For this reason, when
177 * a notification callback is added, a series of fake callback events
178 * is generated to simulate the arrival of those entities. There is one
179 * final series of callbacks that can be registered - those to monitor
180 * actual hooks that are added or removed from an event. In practice,
181 * this is useful when there are multiple kernel modules participating
182 * in the processing of packets and there are behaviour dependencies
183 * involved, such that one kernel module might only register its hook
184 * if another is already present and also might want to remove its hook
185 * when the other disappears.
187 * If you know a kernel module will not be loaded before the infrastructure
188 * used in this file is present then it is not necessary to use this
189 * notification callback mechanism.
193 * Locking
194 * =======
195 * The use of CVW_* macros to do locking is driven by the need to allow
196 * recursive locking with read locks when we're processing packets. This
197 * is necessary because various netinfo functions need to hold read locks,
198 * by design, as they can be called in or out of packet context.
201 * Hook internal functions
203 static hook_int_t *hook_copy(hook_t *src);
204 static hook_event_int_t *hook_event_checkdup(hook_event_t *he,
205 hook_stack_t *hks);
206 static hook_event_int_t *hook_event_copy(hook_event_t *src);
207 static hook_event_int_t *hook_event_find(hook_family_int_t *hfi, char *event);
208 static void hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi);
209 static hook_family_int_t *hook_family_copy(hook_family_t *src);
210 static hook_family_int_t *hook_family_find(char *family, hook_stack_t *hks);
211 static void hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks);
212 static hook_int_t *hook_find(hook_event_int_t *hei, hook_t *h);
213 static void hook_int_free(hook_int_t *hi, netstackid_t);
214 static void hook_init(void);
215 static void hook_fini(void);
216 static void *hook_stack_init(netstackid_t stackid, netstack_t *ns);
217 static void hook_stack_fini(netstackid_t stackid, void *arg);
218 static void hook_stack_shutdown(netstackid_t stackid, void *arg);
219 static int hook_insert(hook_int_head_t *head, hook_int_t *new);
220 static void hook_insert_plain(hook_int_head_t *head, hook_int_t *new);
221 static int hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new);
222 static hook_int_t *hook_find_byname(hook_int_head_t *head, char *name);
223 static void hook_event_init_kstats(hook_family_int_t *, hook_event_int_t *);
224 static void hook_event_notify_run(hook_event_int_t *, hook_family_int_t *,
225 char *event, char *name, hook_notify_cmd_t cmd);
226 static void hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei,
227 hook_int_t *hi);
228 static int hook_notify_register(hook_notify_head_t *head,
229 hook_notify_fn_t callback, void *arg);
230 static int hook_notify_unregister(hook_notify_head_t *head,
231 hook_notify_fn_t callback, void **);
232 static void hook_notify_run(hook_notify_head_t *head, char *family,
233 char *event, char *name, hook_notify_cmd_t cmd);
234 static void hook_stack_notify_run(hook_stack_t *hks, char *name,
235 hook_notify_cmd_t cmd);
236 static void hook_stack_remove(hook_stack_t *hks);
239 * A list of the hook stacks is kept here because we need to enable
240 * net_instance_notify_register() to be called during the creation
241 * of a new instance. Previously hook_stack_get() would just use
242 * the netstack functions for this work but they will return NULL
243 * until the zone has been fully initialised.
245 static hook_stack_head_t hook_stacks;
246 static kmutex_t hook_stack_lock;
249 * Module entry points.
252 _init(void)
254 int error;
256 hook_init();
257 error = mod_install(&modlinkage);
258 if (error != 0)
259 hook_fini();
261 return (error);
265 _fini(void)
267 int error;
269 error = mod_remove(&modlinkage);
270 if (error == 0)
271 hook_fini();
273 return (error);
277 _info(struct modinfo *modinfop)
279 return (mod_info(&modlinkage, modinfop));
283 * Function: hook_init
284 * Returns: None
285 * Parameters: None
287 * Initialize hooks
289 static void
290 hook_init(void)
292 mutex_init(&hook_stack_lock, NULL, MUTEX_DRIVER, NULL);
293 SLIST_INIT(&hook_stacks);
296 * We want to be informed each time a stack is created or
297 * destroyed in the kernel.
299 netstack_register(NS_HOOK, hook_stack_init, hook_stack_shutdown,
300 hook_stack_fini);
304 * Function: hook_fini
305 * Returns: None
306 * Parameters: None
308 * Deinitialize hooks
310 static void
311 hook_fini(void)
313 netstack_unregister(NS_HOOK);
315 mutex_destroy(&hook_stack_lock);
316 ASSERT(SLIST_EMPTY(&hook_stacks));
320 * Function: hook_wait_setflag
321 * Returns: -1 = setting flag is disallowed, 0 = flag set and did
322 * not have to wait (ie no lock droped), 1 = flag set but
323 * it was necessary to drop locks to set it.
324 * Parameters: waiter(I) - control data structure
325 * busyset(I) - set of flags that we don't want set while
326 * we are active.
327 * wanted(I) - flag associated with newflag to indicate
328 * what we want to do.
329 * newflag(I) - the new ACTIVE flag we want to set that
330 * indicates what we are doing.
332 * The set of functions hook_wait_* implement an API that builds on top of
333 * the kcondvar_t to provide controlled execution through a critical region.
334 * For each flag that indicates work is being done (FWF_*_ACTIVE) there is
335 * also a flag that we set to indicate that we want to do it (FWF_*_WANTED).
336 * The combination of flags is required as when this function exits to do
337 * the task, the structure is then free for another caller to use and
338 * to indicate that it wants to do work. The flags used when a caller wants
339 * to destroy an object take precedence over those that are used for making
340 * changes to it (add/remove.) In this case, we don't try to secure the
341 * ability to run and return with an error.
343 * "wantedset" is used here to determine who has the right to clear the
344 * wanted but from the fw_flags set: only he that sets the flag has the
345 * right to clear it at the bottom of the loop, even if someone else
346 * wants to set it.
348 * wanted - the FWF_*_WANTED flag that describes the action being requested
349 * busyset- the set of FWF_* flags we don't want set when we run
350 * newflag- the FWF_*_ACTIVE flag we will set to indicate we are busy
353 hook_wait_setflag(flagwait_t *waiter, uint32_t busyset, fwflag_t wanted,
354 fwflag_t newflag)
356 boolean_t wantedset;
357 int waited = 0;
359 mutex_enter(&waiter->fw_lock);
360 if (waiter->fw_flags & FWF_DESTROY) {
361 cv_signal(&waiter->fw_cv);
362 mutex_exit(&waiter->fw_lock);
363 return (-1);
365 while (waiter->fw_flags & busyset) {
366 wantedset = ((waiter->fw_flags & wanted) == wanted);
367 if (!wantedset)
368 waiter->fw_flags |= wanted;
369 CVW_EXIT_WRITE(waiter->fw_owner);
370 cv_wait(&waiter->fw_cv, &waiter->fw_lock);
372 * This lock needs to be dropped here to preserve the order
373 * of acquisition that is fw_owner followed by fw_lock, else
374 * we can deadlock.
376 mutex_exit(&waiter->fw_lock);
377 waited = 1;
378 CVW_ENTER_WRITE(waiter->fw_owner);
379 mutex_enter(&waiter->fw_lock);
380 if (!wantedset)
381 waiter->fw_flags &= ~wanted;
382 if (waiter->fw_flags & FWF_DESTROY) {
383 cv_signal(&waiter->fw_cv);
384 mutex_exit(&waiter->fw_lock);
385 return (-1);
388 waiter->fw_flags &= ~wanted;
389 ASSERT((waiter->fw_flags & wanted) == 0);
390 ASSERT((waiter->fw_flags & newflag) == 0);
391 waiter->fw_flags |= newflag;
392 mutex_exit(&waiter->fw_lock);
393 return (waited);
397 * Function: hook_wait_unsetflag
398 * Returns: None
399 * Parameters: waiter(I) - control data structure
400 * oldflag(I) - flag to reset
402 * Turn off the bit that we had set to run and let others know that
403 * they should now check to see if they can run.
405 void
406 hook_wait_unsetflag(flagwait_t *waiter, fwflag_t oldflag)
408 mutex_enter(&waiter->fw_lock);
409 waiter->fw_flags &= ~oldflag;
410 cv_signal(&waiter->fw_cv);
411 mutex_exit(&waiter->fw_lock);
415 * Function: hook_wait_destroy
416 * Returns: None
417 * Parameters: waiter(I) - control data structure
419 * Since outer locking (on fw_owner) should ensure that only one function
420 * at a time gets to call hook_wait_destroy() on a given object, there is
421 * no need to guard against setting FWF_DESTROY_WANTED already being set.
422 * It is, however, necessary to wait for all activity on the owning
423 * structure to cease.
426 hook_wait_destroy(flagwait_t *waiter)
428 ASSERT((waiter->fw_flags & FWF_DESTROY_WANTED) == 0);
429 mutex_enter(&waiter->fw_lock);
430 if (waiter->fw_flags & FWF_DESTROY_WANTED) {
431 cv_signal(&waiter->fw_cv);
432 mutex_exit(&waiter->fw_lock);
433 return (EINPROGRESS);
435 waiter->fw_flags |= FWF_DESTROY_WANTED;
436 while (!FWF_DESTROY_OK(waiter)) {
437 CVW_EXIT_WRITE(waiter->fw_owner);
438 cv_wait(&waiter->fw_cv, &waiter->fw_lock);
439 CVW_ENTER_WRITE(waiter->fw_owner);
442 * There should now be nothing else using "waiter" or its
443 * owner, so we can safely assign here without risk of wiiping
444 * out someone's bit.
446 waiter->fw_flags = FWF_DESTROY_ACTIVE;
447 cv_signal(&waiter->fw_cv);
448 mutex_exit(&waiter->fw_lock);
450 return (0);
454 * Function: hook_wait_init
455 * Returns: None
456 * Parameters: waiter(I) - control data structure
457 * ownder(I) - pointer to lock that the owner of this
458 * waiter uses
460 * "owner" gets passed in here so that when we need to call cv_wait,
461 * for example in hook_wait_setflag(), we can drop the lock for the
462 * next layer out, which is likely to be held in an exclusive manner.
464 void
465 hook_wait_init(flagwait_t *waiter, cvwaitlock_t *owner)
467 cv_init(&waiter->fw_cv, NULL, CV_DRIVER, NULL);
468 mutex_init(&waiter->fw_lock, NULL, MUTEX_DRIVER, NULL);
469 waiter->fw_flags = FWF_NONE;
470 waiter->fw_owner = owner;
474 * Function: hook_stack_init
475 * Returns: void * - pointer to new hook stack structure
476 * Parameters: stackid(I) - identifier for the network instance that owns this
477 * ns(I) - pointer to the network instance data structure
479 * Allocate and initialize the hook stack instance. This function is not
480 * allowed to fail, so KM_SLEEP is used here when allocating memory. The
481 * value returned is passed back into the shutdown and destroy hooks.
483 /*ARGSUSED*/
484 static void *
485 hook_stack_init(netstackid_t stackid, netstack_t *ns)
487 hook_stack_t *hks;
489 #ifdef NS_DEBUG
490 printf("hook_stack_init(stack %d)\n", stackid);
491 #endif
493 hks = (hook_stack_t *)kmem_zalloc(sizeof (*hks), KM_SLEEP);
494 hks->hks_netstack = ns;
495 hks->hks_netstackid = stackid;
497 CVW_INIT(&hks->hks_lock);
498 TAILQ_INIT(&hks->hks_nhead);
499 SLIST_INIT(&hks->hks_familylist);
501 hook_wait_init(&hks->hks_waiter, &hks->hks_lock);
503 mutex_enter(&hook_stack_lock);
504 SLIST_INSERT_HEAD(&hook_stacks, hks, hks_entry);
505 mutex_exit(&hook_stack_lock);
507 return (hks);
511 * Function: hook_stack_shutdown
512 * Returns: void
513 * Parameters: stackid(I) - identifier for the network instance that owns this
514 * arg(I) - pointer returned by hook_stack_init
516 * Set the shutdown flag to indicate that we should stop accepting new
517 * register calls as we're now in the cleanup process. The cleanup is a
518 * two stage process and we're not required to free any memory here.
520 * The curious would wonder why isn't there any code that walks through
521 * all of the data structures and sets the flag(s) there? The answer is
522 * that it is expected that this will happen when the zone shutdown calls
523 * the shutdown callbacks for other modules that they will initiate the
524 * free'ing and shutdown of the hooks themselves.
526 /*ARGSUSED*/
527 static void
528 hook_stack_shutdown(netstackid_t stackid, void *arg)
530 hook_stack_t *hks = (hook_stack_t *)arg;
532 mutex_enter(&hook_stack_lock);
534 * Once this flag gets set to one, no more additions are allowed
535 * to any of the structures that make up this stack.
537 hks->hks_shutdown = 1;
538 mutex_exit(&hook_stack_lock);
542 * Function: hook_stack_destroy
543 * Returns: void
544 * Parameters: stackid(I) - identifier for the network instance that owns this
545 * arg(I) - pointer returned by hook_stack_init
547 * Free the hook stack instance.
549 * The rationale for the shutdown being lazy (see the comment above for
550 * hook_stack_shutdown) also applies to the destroy being lazy. Only if
551 * the hook_stack_t data structure is unused will it go away. Else it
552 * is left up to the last user of a data structure to actually free it.
554 /*ARGSUSED*/
555 static void
556 hook_stack_fini(netstackid_t stackid, void *arg)
558 hook_stack_t *hks = (hook_stack_t *)arg;
560 mutex_enter(&hook_stack_lock);
561 hks->hks_shutdown = 2;
562 hook_stack_remove(hks);
563 mutex_exit(&hook_stack_lock);
567 * Function: hook_stack_remove
568 * Returns: void
569 * Parameters: hks(I) - pointer to an instance of a hook_stack_t
571 * This function assumes that it is called with hook_stack_lock held.
572 * It functions differently to hook_family/event_remove in that it does
573 * the checks to see if it can be removed. This difference exists
574 * because this structure has nothing higher up that depends on it.
576 static void
577 hook_stack_remove(hook_stack_t *hks)
580 ASSERT(mutex_owned(&hook_stack_lock));
583 * Is the structure still in use?
585 if (!SLIST_EMPTY(&hks->hks_familylist) ||
586 !TAILQ_EMPTY(&hks->hks_nhead))
587 return;
589 SLIST_REMOVE(&hook_stacks, hks, hook_stack, hks_entry);
591 VERIFY(hook_wait_destroy(&hks->hks_waiter) == 0);
592 CVW_DESTROY(&hks->hks_lock);
593 kmem_free(hks, sizeof (*hks));
597 * Function: hook_stack_get
598 * Returns: hook_stack_t * - NULL if not found, else matching instance
599 * Parameters: stackid(I) - instance id to search for
601 * Search the list of currently active hook_stack_t structures for one that
602 * has a matching netstackid_t to the value passed in. The linked list can
603 * only ever have at most one match for this value.
605 static hook_stack_t *
606 hook_stack_get(netstackid_t stackid)
608 hook_stack_t *hks;
610 SLIST_FOREACH(hks, &hook_stacks, hks_entry) {
611 if (hks->hks_netstackid == stackid)
612 break;
615 return (hks);
619 * Function: hook_stack_notify_register
620 * Returns: int - 0 = success, else failure
621 * Parameters: stackid(I) - netstack identifier
622 * callback(I)- function to be called
623 * arg(I) - arg to provide callback when it is called
625 * If we're not shutting down this instance, append a new function to the
626 * list of those to call when a new family of hooks is added to this stack.
627 * If the function can be successfully added to the list of callbacks
628 * activated when there is a change to the stack (addition or removal of
629 * a hook family) then generate a fake HN_REGISTER event by directly
630 * calling the callback with the relevant information for each hook
631 * family that currently exists (and isn't being shutdown.)
634 hook_stack_notify_register(netstackid_t stackid, hook_notify_fn_t callback,
635 void *arg)
637 hook_family_int_t *hfi;
638 hook_stack_t *hks;
639 boolean_t canrun;
640 char buffer[16];
641 int error;
643 ASSERT(callback != NULL);
645 canrun = B_FALSE;
646 mutex_enter(&hook_stack_lock);
647 hks = hook_stack_get(stackid);
648 if (hks != NULL) {
649 if (hks->hks_shutdown != 0) {
650 error = ESHUTDOWN;
651 } else {
652 CVW_ENTER_WRITE(&hks->hks_lock);
653 canrun = (hook_wait_setflag(&hks->hks_waiter,
654 FWF_ADD_WAIT_MASK, FWF_ADD_WANTED,
655 FWF_ADD_ACTIVE) != -1);
656 error = hook_notify_register(&hks->hks_nhead,
657 callback, arg);
658 CVW_EXIT_WRITE(&hks->hks_lock);
660 } else {
661 error = ESRCH;
663 mutex_exit(&hook_stack_lock);
665 if (error == 0 && canrun) {
667 * Generate fake register event for callback that
668 * is being added, letting it know everything that
669 * already exists.
671 (void) snprintf(buffer, sizeof (buffer), "%u",
672 hks->hks_netstackid);
674 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
675 if (hfi->hfi_condemned || hfi->hfi_shutdown)
676 continue;
677 callback(HN_REGISTER, arg, buffer, NULL,
678 hfi->hfi_family.hf_name);
682 if (canrun)
683 hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE);
685 return (error);
689 * Function: hook_stack_notify_unregister
690 * Returns: int - 0 = success, else failure
691 * Parameters: stackid(I) - netstack identifier
692 * callback(I) - function to be called
694 * Attempt to remove a registered function from a hook stack's list of
695 * callbacks to activiate when protocols are added/deleted.
696 * As with hook_stack_notify_register, if all things are going well then
697 * a fake unregister event is delivered to the callback being removed
698 * for each hook family that presently exists.
701 hook_stack_notify_unregister(netstackid_t stackid, hook_notify_fn_t callback)
703 hook_family_int_t *hfi;
704 hook_stack_t *hks;
705 boolean_t canrun;
706 char buffer[16];
707 void *arg;
708 int error;
710 mutex_enter(&hook_stack_lock);
711 hks = hook_stack_get(stackid);
712 if (hks != NULL) {
713 CVW_ENTER_WRITE(&hks->hks_lock);
714 canrun = (hook_wait_setflag(&hks->hks_waiter, FWF_ADD_WAIT_MASK,
715 FWF_ADD_WANTED, FWF_ADD_ACTIVE) != -1);
717 error = hook_notify_unregister(&hks->hks_nhead, callback, &arg);
718 CVW_EXIT_WRITE(&hks->hks_lock);
719 } else {
720 error = ESRCH;
722 mutex_exit(&hook_stack_lock);
724 if (error == 0) {
725 if (canrun) {
727 * Generate fake unregister event for callback that
728 * is being removed, letting it know everything that
729 * currently exists is now "disappearing."
731 (void) snprintf(buffer, sizeof (buffer), "%u",
732 hks->hks_netstackid);
734 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
735 callback(HN_UNREGISTER, arg, buffer, NULL,
736 hfi->hfi_family.hf_name);
739 hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE);
742 mutex_enter(&hook_stack_lock);
743 hks = hook_stack_get(stackid);
744 if ((error == 0) && (hks->hks_shutdown == 2))
745 hook_stack_remove(hks);
746 mutex_exit(&hook_stack_lock);
749 return (error);
753 * Function: hook_stack_notify_run
754 * Returns: None
755 * Parameters: hks(I) - hook stack pointer to execute callbacks for
756 * name(I) - name of a hook family
757 * cmd(I) - either HN_UNREGISTER or HN_REGISTER
759 * Run through the list of callbacks on the hook stack to be called when
760 * a new hook family is added
762 * As hook_notify_run() expects 3 names, one for the family that is associated
763 * with the cmd (HN_REGISTER or HN_UNREGISTER), one for the event and one
764 * for the object being introduced and we really only have one name (that
765 * of the new hook family), fake the hook stack's name by converting the
766 * integer to a string and for the event just pass NULL.
768 static void
769 hook_stack_notify_run(hook_stack_t *hks, char *name,
770 hook_notify_cmd_t cmd)
772 char buffer[16];
774 ASSERT(hks != NULL);
775 ASSERT(name != NULL);
777 (void) snprintf(buffer, sizeof (buffer), "%u", hks->hks_netstackid);
779 hook_notify_run(&hks->hks_nhead, buffer, NULL, name, cmd);
783 * Function: hook_run
784 * Returns: int - return value according to callback func
785 * Parameters: token(I) - event pointer
786 * info(I) - message
788 * Run hooks for specific provider. The hooks registered are stepped through
789 * until either the end of the list is reached or a hook function returns a
790 * non-zero value. If a non-zero value is returned from a hook function, we
791 * return that value back to our caller. By design, a hook function can be
792 * called more than once, simultaneously.
795 hook_run(hook_family_int_t *hfi, hook_event_token_t token, hook_data_t info)
797 hook_event_int_t *hei;
798 hook_int_t *hi;
799 int rval = 0;
801 ASSERT(token != NULL);
803 hei = (hook_event_int_t *)token;
804 DTRACE_PROBE2(hook__run__start,
805 hook_event_token_t, token,
806 hook_data_t, info);
809 * If we consider that this function is only called from within the
810 * stack while an instance is currently active,
812 CVW_ENTER_READ(&hfi->hfi_lock);
814 TAILQ_FOREACH(hi, &hei->hei_head, hi_entry) {
815 ASSERT(hi->hi_hook.h_func != NULL);
816 DTRACE_PROBE3(hook__func__start,
817 hook_event_token_t, token,
818 hook_data_t, info,
819 hook_int_t *, hi);
820 rval = (*hi->hi_hook.h_func)(token, info, hi->hi_hook.h_arg);
821 DTRACE_PROBE4(hook__func__end,
822 hook_event_token_t, token,
823 hook_data_t, info,
824 hook_int_t *, hi,
825 int, rval);
826 hi->hi_kstats.hook_hits.value.ui64++;
827 if (rval != 0)
828 break;
831 hei->hei_kstats.events.value.ui64++;
833 CVW_EXIT_READ(&hfi->hfi_lock);
835 DTRACE_PROBE3(hook__run__end,
836 hook_event_token_t, token,
837 hook_data_t, info,
838 hook_int_t *, hi);
840 return (rval);
844 * Function: hook_family_add
845 * Returns: internal family pointer - NULL = Fail
846 * Parameters: hf(I) - family pointer
847 * hks(I) - pointer to an instance of a hook_stack_t
848 * store(O) - where returned pointer will be stored
850 * Add new family to the family list. The requirements for the addition to
851 * succeed are that the family name must not already be registered and that
852 * the hook stack is not being shutdown.
853 * If store is non-NULL, it is expected to be a pointer to the same variable
854 * that is awaiting to be assigned the return value of this function.
855 * In its current use, the returned value is assigned to netd_hooks in
856 * net_family_register. The use of "store" allows the return value to be
857 * used before this function returns. How can this happen? Through the
858 * callbacks that can be activated at the bottom of this function, when
859 * hook_stack_notify_run is called.
861 hook_family_int_t *
862 hook_family_add(hook_family_t *hf, hook_stack_t *hks, void **store)
864 hook_family_int_t *hfi, *new;
866 ASSERT(hf != NULL);
867 ASSERT(hf->hf_name != NULL);
869 new = hook_family_copy(hf);
870 if (new == NULL)
871 return (NULL);
873 mutex_enter(&hook_stack_lock);
874 CVW_ENTER_WRITE(&hks->hks_lock);
876 if (hks->hks_shutdown != 0) {
877 CVW_EXIT_WRITE(&hks->hks_lock);
878 mutex_exit(&hook_stack_lock);
879 hook_family_free(new, NULL);
880 return (NULL);
883 /* search family list */
884 hfi = hook_family_find(hf->hf_name, hks);
885 if (hfi != NULL) {
886 CVW_EXIT_WRITE(&hks->hks_lock);
887 mutex_exit(&hook_stack_lock);
888 hook_family_free(new, NULL);
889 return (NULL);
893 * Try and set the FWF_ADD_ACTIVE flag so that we can drop all the
894 * lock further down when calling all of the functions registered
895 * for notification when a new hook family is added.
897 if (hook_wait_setflag(&hks->hks_waiter, FWF_ADD_WAIT_MASK,
898 FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) {
899 CVW_EXIT_WRITE(&hks->hks_lock);
900 mutex_exit(&hook_stack_lock);
901 hook_family_free(new, NULL);
902 return (NULL);
905 CVW_INIT(&new->hfi_lock);
906 SLIST_INIT(&new->hfi_head);
907 TAILQ_INIT(&new->hfi_nhead);
909 hook_wait_init(&new->hfi_waiter, &new->hfi_lock);
911 new->hfi_stack = hks;
912 if (store != NULL)
913 *store = new;
915 /* Add to family list head */
916 SLIST_INSERT_HEAD(&hks->hks_familylist, new, hfi_entry);
918 CVW_EXIT_WRITE(&hks->hks_lock);
919 mutex_exit(&hook_stack_lock);
921 hook_stack_notify_run(hks, hf->hf_name, HN_REGISTER);
923 hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE);
925 return (new);
929 * Function: hook_family_remove
930 * Returns: int - 0 = success, else = failure
931 * Parameters: hfi(I) - internal family pointer
933 * Remove family from family list. This function has been designed to be
934 * called once and once only per hook_family_int_t. Thus when cleaning up
935 * this structure as an orphan, callers should only call hook_family_free.
938 hook_family_remove(hook_family_int_t *hfi)
940 hook_stack_t *hks;
941 boolean_t notifydone;
943 ASSERT(hfi != NULL);
944 hks = hfi->hfi_stack;
946 CVW_ENTER_WRITE(&hfi->hfi_lock);
947 notifydone = hfi->hfi_shutdown;
948 hfi->hfi_shutdown = B_TRUE;
949 CVW_EXIT_WRITE(&hfi->hfi_lock);
951 CVW_ENTER_WRITE(&hks->hks_lock);
953 if (hook_wait_setflag(&hks->hks_waiter, FWF_DEL_WAIT_MASK,
954 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
956 * If we're trying to destroy the hook_stack_t...
958 CVW_EXIT_WRITE(&hks->hks_lock);
959 return (ENXIO);
963 * Check if the family is in use by the presence of either events
964 * or notify callbacks on the hook family.
966 if (!SLIST_EMPTY(&hfi->hfi_head) || !TAILQ_EMPTY(&hfi->hfi_nhead)) {
967 hfi->hfi_condemned = B_TRUE;
968 } else {
969 VERIFY(hook_wait_destroy(&hfi->hfi_waiter) == 0);
971 * Although hfi_condemned = B_FALSE is implied from creation,
972 * putting a comment here inside the else upsets lint.
974 hfi->hfi_condemned = B_FALSE;
976 CVW_EXIT_WRITE(&hks->hks_lock);
978 if (!notifydone)
979 hook_stack_notify_run(hks, hfi->hfi_family.hf_name,
980 HN_UNREGISTER);
982 hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE);
985 * If we don't have to wait for anything else to disappear from this
986 * structure then we can free it up.
988 if (!hfi->hfi_condemned)
989 hook_family_free(hfi, hks);
991 return (0);
996 * Function: hook_family_free
997 * Returns: None
998 * Parameters: hfi(I) - internal family pointer
1000 * Free alloc memory for family
1002 static void
1003 hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks)
1007 * This lock gives us possession of the hks pointer after the
1008 * SLIST_REMOVE, for which it is not needed, when hks_shutdown
1009 * is checked and hook_stack_remove called.
1011 mutex_enter(&hook_stack_lock);
1013 ASSERT(hfi != NULL);
1015 if (hks != NULL) {
1016 CVW_ENTER_WRITE(&hks->hks_lock);
1017 /* Remove from family list */
1018 SLIST_REMOVE(&hks->hks_familylist, hfi, hook_family_int,
1019 hfi_entry);
1021 CVW_EXIT_WRITE(&hks->hks_lock);
1024 /* Free name space */
1025 if (hfi->hfi_family.hf_name != NULL) {
1026 kmem_free(hfi->hfi_family.hf_name,
1027 strlen(hfi->hfi_family.hf_name) + 1);
1030 /* Free container */
1031 kmem_free(hfi, sizeof (*hfi));
1033 if (hks->hks_shutdown == 2)
1034 hook_stack_remove(hks);
1036 mutex_exit(&hook_stack_lock);
1040 * Function: hook_family_shutdown
1041 * Returns: int - 0 = success, else = failure
1042 * Parameters: hfi(I) - internal family pointer
1044 * As an alternative to removing a family, we may desire to just generate
1045 * a series of callbacks to indicate that we will be going away in the
1046 * future. The hfi_condemned flag isn't set because we aren't trying to
1047 * remove the structure.
1050 hook_family_shutdown(hook_family_int_t *hfi)
1052 hook_stack_t *hks;
1053 boolean_t notifydone;
1055 ASSERT(hfi != NULL);
1056 hks = hfi->hfi_stack;
1058 CVW_ENTER_WRITE(&hfi->hfi_lock);
1059 notifydone = hfi->hfi_shutdown;
1060 hfi->hfi_shutdown = B_TRUE;
1061 CVW_EXIT_WRITE(&hfi->hfi_lock);
1063 CVW_ENTER_WRITE(&hks->hks_lock);
1065 if (hook_wait_setflag(&hks->hks_waiter, FWF_DEL_WAIT_MASK,
1066 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
1068 * If we're trying to destroy the hook_stack_t...
1070 CVW_EXIT_WRITE(&hks->hks_lock);
1071 return (ENXIO);
1074 CVW_EXIT_WRITE(&hks->hks_lock);
1076 if (!notifydone)
1077 hook_stack_notify_run(hks, hfi->hfi_family.hf_name,
1078 HN_UNREGISTER);
1080 hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE);
1082 return (0);
1086 * Function: hook_family_copy
1087 * Returns: internal family pointer - NULL = Failed
1088 * Parameters: src(I) - family pointer
1090 * Allocate internal family block and duplicate incoming family
1091 * No locks should be held across this function as it may sleep.
1093 static hook_family_int_t *
1094 hook_family_copy(hook_family_t *src)
1096 hook_family_int_t *new;
1097 hook_family_t *dst;
1099 ASSERT(src != NULL);
1100 ASSERT(src->hf_name != NULL);
1102 new = (hook_family_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
1104 /* Copy body */
1105 dst = &new->hfi_family;
1106 *dst = *src;
1108 SLIST_INIT(&new->hfi_head);
1109 TAILQ_INIT(&new->hfi_nhead);
1111 /* Copy name */
1112 dst->hf_name = (char *)kmem_alloc(strlen(src->hf_name) + 1, KM_SLEEP);
1113 (void) strcpy(dst->hf_name, src->hf_name);
1115 return (new);
1119 * Function: hook_family_find
1120 * Returns: internal family pointer - NULL = Not match
1121 * Parameters: family(I) - family name string
1123 * Search family list with family name
1124 * A lock on hfi_lock must be held when called.
1126 static hook_family_int_t *
1127 hook_family_find(char *family, hook_stack_t *hks)
1129 hook_family_int_t *hfi = NULL;
1131 ASSERT(family != NULL);
1133 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
1134 if (strcmp(hfi->hfi_family.hf_name, family) == 0)
1135 break;
1137 return (hfi);
1141 * Function: hook_family_notify_register
1142 * Returns: int - 0 = success, else failure
1143 * Parameters: hfi(I) - hook family
1144 * callback(I) - function to be called
1145 * arg(I) - arg to provide callback when it is called
1147 * So long as this hook stack isn't being shut down, register a new
1148 * callback to be activated each time a new event is added to this
1149 * family.
1151 * To call this function we must have an active handle in use on the family,
1152 * so if we take this into account, then neither the hook_family_int_t nor
1153 * the hook_stack_t that owns it can disappear. We have to put some trust
1154 * in the callers to be properly synchronised...
1156 * Holding hks_lock is required to provide synchronisation for hks_shutdown.
1159 hook_family_notify_register(hook_family_int_t *hfi,
1160 hook_notify_fn_t callback, void *arg)
1162 hook_event_int_t *hei;
1163 hook_stack_t *hks;
1164 boolean_t canrun;
1165 int error;
1167 ASSERT(hfi != NULL);
1168 canrun = B_FALSE;
1169 hks = hfi->hfi_stack;
1171 CVW_ENTER_READ(&hks->hks_lock);
1173 if ((hfi->hfi_stack->hks_shutdown != 0) ||
1174 hfi->hfi_condemned || hfi->hfi_shutdown) {
1175 CVW_EXIT_READ(&hks->hks_lock);
1176 return (ESHUTDOWN);
1179 CVW_ENTER_WRITE(&hfi->hfi_lock);
1180 canrun = (hook_wait_setflag(&hfi->hfi_waiter, FWF_ADD_WAIT_MASK,
1181 FWF_ADD_WANTED, FWF_ADD_ACTIVE) != -1);
1182 error = hook_notify_register(&hfi->hfi_nhead, callback, arg);
1183 CVW_EXIT_WRITE(&hfi->hfi_lock);
1185 CVW_EXIT_READ(&hks->hks_lock);
1187 if (error == 0 && canrun) {
1188 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
1189 callback(HN_REGISTER, arg,
1190 hfi->hfi_family.hf_name, NULL,
1191 hei->hei_event->he_name);
1195 if (canrun)
1196 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_ADD_ACTIVE);
1198 return (error);
1202 * Function: hook_family_notify_unregister
1203 * Returns: int - 0 = success, else failure
1204 * Parameters: hfi(I) - hook family
1205 * callback(I) - function to be called
1207 * Remove a callback from the list of those executed when a new event is
1208 * added to a hook family. If the family is not in the process of being
1209 * destroyed then simulate an unregister callback for each event that is
1210 * on the family. This pairs up with the hook_family_notify_register
1211 * action that simulates register events.
1212 * The order of what happens here is important and goes like this.
1213 * 1) Remove the callback from the list of functions to be called as part
1214 * of the notify operation when an event is added or removed from the
1215 * hook family.
1216 * 2) If the hook_family_int_t structure is on death row (free_family will
1217 * be set to true) then there's nothing else to do than let it be free'd.
1218 * 3) If the structure isn't about to die, mark it up as being busy using
1219 * hook_wait_setflag and then drop the lock so the loop can be run.
1220 * 4) if hook_wait_setflag was successful, tell all of the notify callback
1221 * functions that this family has been unregistered.
1222 * 5) Cleanup
1225 hook_family_notify_unregister(hook_family_int_t *hfi,
1226 hook_notify_fn_t callback)
1228 hook_event_int_t *hei;
1229 boolean_t free_family;
1230 boolean_t canrun;
1231 int error;
1232 void *arg;
1234 canrun = B_FALSE;
1236 CVW_ENTER_WRITE(&hfi->hfi_lock);
1238 (void) hook_wait_setflag(&hfi->hfi_waiter, FWF_DEL_WAIT_MASK,
1239 FWF_DEL_WANTED, FWF_DEL_ACTIVE);
1241 error = hook_notify_unregister(&hfi->hfi_nhead, callback, &arg);
1243 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
1246 * If hook_family_remove has been called but the structure was still
1247 * "busy" ... but we might have just made it "unbusy"...
1249 if ((error == 0) && hfi->hfi_condemned &&
1250 SLIST_EMPTY(&hfi->hfi_head) && TAILQ_EMPTY(&hfi->hfi_nhead)) {
1251 free_family = B_TRUE;
1252 } else {
1253 free_family = B_FALSE;
1256 if (error == 0 && !free_family) {
1257 canrun = (hook_wait_setflag(&hfi->hfi_waiter, FWF_ADD_WAIT_MASK,
1258 FWF_ADD_WANTED, FWF_ADD_ACTIVE) != -1);
1261 CVW_EXIT_WRITE(&hfi->hfi_lock);
1263 if (canrun) {
1264 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
1265 callback(HN_UNREGISTER, arg,
1266 hfi->hfi_family.hf_name, NULL,
1267 hei->hei_event->he_name);
1270 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_ADD_ACTIVE);
1271 } else if (free_family) {
1272 hook_family_free(hfi, hfi->hfi_stack);
1275 return (error);
1279 * Function: hook_event_add
1280 * Returns: internal event pointer - NULL = Fail
1281 * Parameters: hfi(I) - internal family pointer
1282 * he(I) - event pointer
1284 * Add new event to event list on specific family.
1285 * This function can fail to return successfully if (1) it cannot allocate
1286 * enough memory for its own internal data structures, (2) the event has
1287 * already been registered (for any hook family.)
1289 hook_event_int_t *
1290 hook_event_add(hook_family_int_t *hfi, hook_event_t *he)
1292 hook_event_int_t *hei, *new;
1293 hook_stack_t *hks;
1295 ASSERT(hfi != NULL);
1296 ASSERT(he != NULL);
1297 ASSERT(he->he_name != NULL);
1299 new = hook_event_copy(he);
1300 if (new == NULL)
1301 return (NULL);
1303 hks = hfi->hfi_stack;
1304 CVW_ENTER_READ(&hks->hks_lock);
1306 hks = hfi->hfi_stack;
1307 if (hks->hks_shutdown != 0) {
1308 CVW_EXIT_READ(&hks->hks_lock);
1309 hook_event_free(new, NULL);
1310 return (NULL);
1313 /* Check whether this event pointer is already registered */
1314 hei = hook_event_checkdup(he, hks);
1315 if (hei != NULL) {
1316 CVW_EXIT_READ(&hks->hks_lock);
1317 hook_event_free(new, NULL);
1318 return (NULL);
1321 CVW_ENTER_WRITE(&hfi->hfi_lock);
1323 if (hfi->hfi_condemned || hfi->hfi_shutdown) {
1324 CVW_EXIT_WRITE(&hfi->hfi_lock);
1325 CVW_EXIT_READ(&hks->hks_lock);
1326 hook_event_free(new, NULL);
1327 return (NULL);
1329 CVW_EXIT_READ(&hks->hks_lock);
1331 if (hook_wait_setflag(&hfi->hfi_waiter, FWF_ADD_WAIT_MASK,
1332 FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) {
1333 CVW_EXIT_WRITE(&hfi->hfi_lock);
1334 hook_event_free(new, NULL);
1335 return (NULL);
1338 TAILQ_INIT(&new->hei_nhead);
1340 hook_event_init_kstats(hfi, new);
1341 hook_wait_init(&new->hei_waiter, &new->hei_lock);
1343 /* Add to event list head */
1344 SLIST_INSERT_HEAD(&hfi->hfi_head, new, hei_entry);
1346 CVW_EXIT_WRITE(&hfi->hfi_lock);
1348 hook_notify_run(&hfi->hfi_nhead,
1349 hfi->hfi_family.hf_name, NULL, he->he_name, HN_REGISTER);
1351 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_ADD_ACTIVE);
1353 return (new);
1357 * Function: hook_event_init_kstats
1358 * Returns: None
1359 * Parameters: hfi(I) - pointer to the family that owns this event.
1360 * hei(I) - pointer to the hook event that needs some kstats.
1362 * Create a set of kstats that relate to each event registered with
1363 * the hook framework. A counter is kept for each time the event is
1364 * activated and for each time a hook is added or removed. As the
1365 * kstats just count the events as they happen, the total number of
1366 * hooks registered must be obtained by subtractived removed from added.
1368 static void
1369 hook_event_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei)
1371 hook_event_kstat_t template = {
1372 { "hooksAdded", KSTAT_DATA_UINT64 },
1373 { "hooksRemoved", KSTAT_DATA_UINT64 },
1374 { "events", KSTAT_DATA_UINT64 }
1376 hook_stack_t *hks;
1378 hks = hfi->hfi_stack;
1379 hei->hei_kstatp = kstat_create_netstack(hfi->hfi_family.hf_name, 0,
1380 hei->hei_event->he_name, "hook_event", KSTAT_TYPE_NAMED,
1381 sizeof (hei->hei_kstats) / sizeof (kstat_named_t),
1382 KSTAT_FLAG_VIRTUAL, hks->hks_netstackid);
1384 bcopy((char *)&template, &hei->hei_kstats, sizeof (template));
1386 if (hei->hei_kstatp != NULL) {
1387 hei->hei_kstatp->ks_data = (void *)&hei->hei_kstats;
1388 hei->hei_kstatp->ks_private =
1389 (void *)(uintptr_t)hks->hks_netstackid;
1391 kstat_install(hei->hei_kstatp);
1396 * Function: hook_event_remove
1397 * Returns: int - 0 = success, else = failure
1398 * Parameters: hfi(I) - internal family pointer
1399 * he(I) - event pointer
1401 * Remove event from event list on specific family
1403 * This function assumes that the caller has received a pointer to a the
1404 * hook_family_int_t via a call to net_protocol_lookup or net_protocol_unreg'.
1405 * This the hook_family_int_t is guaranteed to be around for the life of this
1406 * call, unless the caller has decided to call net_protocol_release or
1407 * net_protocol_unregister before calling net_event_unregister - an error.
1410 hook_event_remove(hook_family_int_t *hfi, hook_event_t *he)
1412 boolean_t free_family;
1413 hook_event_int_t *hei;
1414 boolean_t notifydone;
1416 ASSERT(hfi != NULL);
1417 ASSERT(he != NULL);
1419 CVW_ENTER_WRITE(&hfi->hfi_lock);
1422 * Set the flag so that we can call hook_event_notify_run without
1423 * holding any locks but at the same time prevent other changes to
1424 * the event at the same time.
1426 if (hook_wait_setflag(&hfi->hfi_waiter, FWF_DEL_WAIT_MASK,
1427 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
1428 CVW_EXIT_WRITE(&hfi->hfi_lock);
1429 return (ENXIO);
1432 hei = hook_event_find(hfi, he->he_name);
1433 if (hei == NULL) {
1434 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
1435 CVW_EXIT_WRITE(&hfi->hfi_lock);
1436 return (ESRCH);
1439 free_family = B_FALSE;
1441 CVW_ENTER_WRITE(&hei->hei_lock);
1443 * The hei_shutdown flag is used to indicate whether or not we have
1444 * done a shutdown and thus already walked through the notify list.
1446 notifydone = hei->hei_shutdown;
1447 hei->hei_shutdown = B_TRUE;
1449 * If there are any hooks still registered for this event or
1450 * there are any notifiers registered, return an error indicating
1451 * that the event is still busy.
1453 if (!TAILQ_EMPTY(&hei->hei_head) || !TAILQ_EMPTY(&hei->hei_nhead)) {
1454 hei->hei_condemned = B_TRUE;
1455 CVW_EXIT_WRITE(&hei->hei_lock);
1456 } else {
1457 /* hei_condemned = B_FALSE is implied from creation */
1459 * Even though we know the notify list is empty, we call
1460 * hook_wait_destroy here to synchronise wait removing a
1461 * hook from an event.
1463 VERIFY(hook_wait_destroy(&hei->hei_waiter) == 0);
1465 CVW_EXIT_WRITE(&hei->hei_lock);
1467 if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) &&
1468 TAILQ_EMPTY(&hfi->hfi_nhead))
1469 free_family = B_TRUE;
1472 CVW_EXIT_WRITE(&hfi->hfi_lock);
1474 if (!notifydone)
1475 hook_notify_run(&hfi->hfi_nhead,
1476 hfi->hfi_family.hf_name, NULL, he->he_name, HN_UNREGISTER);
1478 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
1480 if (!hei->hei_condemned) {
1481 hook_event_free(hei, hfi);
1482 if (free_family)
1483 hook_family_free(hfi, hfi->hfi_stack);
1486 return (0);
1490 * Function: hook_event_shutdown
1491 * Returns: int - 0 = success, else = failure
1492 * Parameters: hfi(I) - internal family pointer
1493 * he(I) - event pointer
1495 * As with hook_family_shutdown, we want to generate the notify callbacks
1496 * as if the event was being removed but not actually do the remove.
1499 hook_event_shutdown(hook_family_int_t *hfi, hook_event_t *he)
1501 hook_event_int_t *hei;
1502 boolean_t notifydone;
1504 ASSERT(hfi != NULL);
1505 ASSERT(he != NULL);
1507 CVW_ENTER_WRITE(&hfi->hfi_lock);
1510 * Set the flag so that we can call hook_event_notify_run without
1511 * holding any locks but at the same time prevent other changes to
1512 * the event at the same time.
1514 if (hook_wait_setflag(&hfi->hfi_waiter, FWF_DEL_WAIT_MASK,
1515 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
1516 CVW_EXIT_WRITE(&hfi->hfi_lock);
1517 return (ENXIO);
1520 hei = hook_event_find(hfi, he->he_name);
1521 if (hei == NULL) {
1522 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
1523 CVW_EXIT_WRITE(&hfi->hfi_lock);
1524 return (ESRCH);
1527 CVW_ENTER_WRITE(&hei->hei_lock);
1528 notifydone = hei->hei_shutdown;
1529 hei->hei_shutdown = B_TRUE;
1530 CVW_EXIT_WRITE(&hei->hei_lock);
1532 CVW_EXIT_WRITE(&hfi->hfi_lock);
1534 if (!notifydone)
1535 hook_notify_run(&hfi->hfi_nhead,
1536 hfi->hfi_family.hf_name, NULL, he->he_name, HN_UNREGISTER);
1538 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
1540 return (0);
1544 * Function: hook_event_free
1545 * Returns: None
1546 * Parameters: hei(I) - internal event pointer
1548 * Free alloc memory for event
1550 static void
1551 hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi)
1553 boolean_t free_family;
1555 ASSERT(hei != NULL);
1557 if (hfi != NULL) {
1558 CVW_ENTER_WRITE(&hfi->hfi_lock);
1560 * Remove the event from the hook family's list.
1562 SLIST_REMOVE(&hfi->hfi_head, hei, hook_event_int, hei_entry);
1563 if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) &&
1564 TAILQ_EMPTY(&hfi->hfi_nhead)) {
1565 free_family = B_TRUE;
1566 } else {
1567 free_family = B_FALSE;
1569 CVW_EXIT_WRITE(&hfi->hfi_lock);
1572 if (hei->hei_kstatp != NULL) {
1573 ASSERT(hfi != NULL);
1575 kstat_delete_netstack(hei->hei_kstatp,
1576 hfi->hfi_stack->hks_netstackid);
1577 hei->hei_kstatp = NULL;
1580 /* Free container */
1581 kmem_free(hei, sizeof (*hei));
1583 if (free_family)
1584 hook_family_free(hfi, hfi->hfi_stack);
1588 * Function: hook_event_checkdup
1589 * Returns: internal event pointer - NULL = Not match
1590 * Parameters: he(I) - event pointer
1592 * Search all of the hook families to see if the event being passed in
1593 * has already been associated with one.
1595 static hook_event_int_t *
1596 hook_event_checkdup(hook_event_t *he, hook_stack_t *hks)
1598 hook_family_int_t *hfi;
1599 hook_event_int_t *hei;
1601 ASSERT(he != NULL);
1603 CVW_ENTER_READ(&hks->hks_lock);
1604 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
1605 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
1606 if (hei->hei_event == he) {
1607 CVW_EXIT_READ(&hks->hks_lock);
1608 return (hei);
1612 CVW_EXIT_READ(&hks->hks_lock);
1614 return (NULL);
1618 * Function: hook_event_copy
1619 * Returns: internal event pointer - NULL = Failed
1620 * Parameters: src(I) - event pointer
1622 * Allocate internal event block and duplicate incoming event
1623 * No locks should be held across this function as it may sleep.
1625 static hook_event_int_t *
1626 hook_event_copy(hook_event_t *src)
1628 hook_event_int_t *new;
1630 ASSERT(src != NULL);
1631 ASSERT(src->he_name != NULL);
1633 new = (hook_event_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
1635 /* Copy body */
1636 TAILQ_INIT(&new->hei_head);
1637 new->hei_event = src;
1639 return (new);
1643 * Function: hook_event_find
1644 * Returns: internal event pointer - NULL = Not match
1645 * Parameters: hfi(I) - internal family pointer
1646 * event(I) - event name string
1648 * Search event list with event name
1649 * A lock on hfi->hfi_lock must be held when called.
1651 static hook_event_int_t *
1652 hook_event_find(hook_family_int_t *hfi, char *event)
1654 hook_event_int_t *hei = NULL;
1656 ASSERT(hfi != NULL);
1657 ASSERT(event != NULL);
1659 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
1660 if ((strcmp(hei->hei_event->he_name, event) == 0) &&
1661 ((hei->hei_waiter.fw_flags & FWF_UNSAFE) == 0))
1662 break;
1664 return (hei);
1668 * Function: hook_event_notify_register
1669 * Returns: int - 0 = success, else failure
1670 * Parameters: hfi(I) - hook family
1671 * event(I) - name of the event
1672 * callback(I) - function to be called
1673 * arg(I) - arg to provide callback when it is called
1675 * Adds a new callback to the event named by "event" (we must find it)
1676 * that will be executed each time a new hook is added to the event.
1677 * Of course, if the stack is being shut down, this call should fail.
1680 hook_event_notify_register(hook_family_int_t *hfi, char *event,
1681 hook_notify_fn_t callback, void *arg)
1683 hook_event_int_t *hei;
1684 hook_stack_t *hks;
1685 boolean_t canrun;
1686 hook_int_t *h;
1687 int error;
1689 canrun = B_FALSE;
1690 hks = hfi->hfi_stack;
1691 CVW_ENTER_READ(&hks->hks_lock);
1692 if (hks->hks_shutdown != 0) {
1693 CVW_EXIT_READ(&hks->hks_lock);
1694 return (ESHUTDOWN);
1697 CVW_ENTER_READ(&hfi->hfi_lock);
1699 if (hfi->hfi_condemned || hfi->hfi_shutdown) {
1700 CVW_EXIT_READ(&hfi->hfi_lock);
1701 CVW_EXIT_READ(&hks->hks_lock);
1702 return (ESHUTDOWN);
1705 hei = hook_event_find(hfi, event);
1706 if (hei == NULL) {
1707 CVW_EXIT_READ(&hfi->hfi_lock);
1708 CVW_EXIT_READ(&hks->hks_lock);
1709 return (ESRCH);
1712 if (hei->hei_condemned || hei->hei_shutdown) {
1713 CVW_EXIT_READ(&hfi->hfi_lock);
1714 CVW_EXIT_READ(&hks->hks_lock);
1715 return (ESHUTDOWN);
1718 CVW_ENTER_WRITE(&hei->hei_lock);
1719 canrun = (hook_wait_setflag(&hei->hei_waiter, FWF_ADD_WAIT_MASK,
1720 FWF_ADD_WANTED, FWF_ADD_ACTIVE) != -1);
1721 error = hook_notify_register(&hei->hei_nhead, callback, arg);
1722 CVW_EXIT_WRITE(&hei->hei_lock);
1724 CVW_EXIT_READ(&hfi->hfi_lock);
1725 CVW_EXIT_READ(&hks->hks_lock);
1727 if (error == 0 && canrun) {
1728 TAILQ_FOREACH(h, &hei->hei_head, hi_entry) {
1729 callback(HN_REGISTER, arg,
1730 hfi->hfi_family.hf_name, hei->hei_event->he_name,
1731 h->hi_hook.h_name);
1735 if (canrun)
1736 hook_wait_unsetflag(&hei->hei_waiter, FWF_ADD_ACTIVE);
1738 return (error);
1742 * Function: hook_event_notify_unregister
1743 * Returns: int - 0 = success, else failure
1744 * Parameters: hfi(I) - hook family
1745 * event(I) - name of the event
1746 * callback(I) - function to be called
1748 * Remove the given callback from the named event's list of functions
1749 * to call when a hook is added or removed.
1752 hook_event_notify_unregister(hook_family_int_t *hfi, char *event,
1753 hook_notify_fn_t callback)
1755 hook_event_int_t *hei;
1756 boolean_t free_event;
1757 boolean_t canrun;
1758 hook_int_t *h;
1759 void *arg;
1760 int error;
1762 canrun = B_FALSE;
1764 CVW_ENTER_READ(&hfi->hfi_lock);
1766 hei = hook_event_find(hfi, event);
1767 if (hei == NULL) {
1768 CVW_EXIT_READ(&hfi->hfi_lock);
1769 return (ESRCH);
1772 CVW_ENTER_WRITE(&hei->hei_lock);
1774 (void) hook_wait_setflag(&hei->hei_waiter, FWF_DEL_WAIT_MASK,
1775 FWF_DEL_WANTED, FWF_DEL_ACTIVE);
1777 error = hook_notify_unregister(&hei->hei_nhead, callback, &arg);
1779 hook_wait_unsetflag(&hei->hei_waiter, FWF_DEL_ACTIVE);
1782 * hei_condemned has been set if someone tried to remove the
1783 * event but couldn't because there were still things attached to
1784 * it. Now that we've done a successful remove, if it is now empty
1785 * then by all rights we should be free'ing it too. Note that the
1786 * expectation is that only the caller of hook_event_add will ever
1787 * call hook_event_remove.
1789 if ((error == 0) && hei->hei_condemned &&
1790 TAILQ_EMPTY(&hei->hei_head) && TAILQ_EMPTY(&hei->hei_nhead)) {
1791 free_event = B_TRUE;
1792 } else {
1793 free_event = B_FALSE;
1796 if (error == 0 && !free_event) {
1797 canrun = (hook_wait_setflag(&hei->hei_waiter, FWF_ADD_WAIT_MASK,
1798 FWF_ADD_WANTED, FWF_ADD_ACTIVE) != -1);
1801 CVW_EXIT_WRITE(&hei->hei_lock);
1802 CVW_EXIT_READ(&hfi->hfi_lock);
1804 if (canrun) {
1805 TAILQ_FOREACH(h, &hei->hei_head, hi_entry) {
1806 callback(HN_UNREGISTER, arg,
1807 hfi->hfi_family.hf_name, hei->hei_event->he_name,
1808 h->hi_hook.h_name);
1811 hook_wait_unsetflag(&hei->hei_waiter, FWF_ADD_ACTIVE);
1814 if (free_event) {
1816 * It is safe to pass in hfi here, without a lock, because
1817 * our structure (hei) is still on one of its lists and thus
1818 * it won't be able to disappear yet...
1820 hook_event_free(hei, hfi);
1823 return (error);
1827 * Function: hook_event_notify_run
1828 * Returns: None
1829 * Parameters: nrun(I) - pointer to the list of callbacks to execute
1830 * hfi(I) - hook stack pointer to execute callbacks for
1831 * name(I) - name of a hook family
1832 * cmd(I) - either HN_UNREGISTER or HN_REGISTER
1834 * Execute all of the callbacks registered for this event.
1836 static void
1837 hook_event_notify_run(hook_event_int_t *hei, hook_family_int_t *hfi,
1838 char *event, char *name, hook_notify_cmd_t cmd)
1841 hook_notify_run(&hei->hei_nhead, hfi->hfi_family.hf_name,
1842 event, name, cmd);
1846 * Function: hook_register
1847 * Returns: int - 0 = success, else = failure
1848 * Parameters: hfi(I) - internal family pointer
1849 * event(I) - event name string
1850 * h(I) - hook pointer
1852 * Add new hook to hook list on the specified family and event.
1855 hook_register(hook_family_int_t *hfi, char *event, hook_t *h)
1857 hook_event_int_t *hei;
1858 hook_int_t *hi, *new;
1859 int error;
1861 ASSERT(hfi != NULL);
1862 ASSERT(event != NULL);
1863 ASSERT(h != NULL);
1865 if (hfi->hfi_stack->hks_shutdown)
1866 return (NULL);
1868 /* Alloc hook_int_t and copy hook */
1869 new = hook_copy(h);
1870 if (new == NULL)
1871 return (ENOMEM);
1874 * Since hook add/remove only impact event, so it is unnecessary
1875 * to hold global family write lock. Just get read lock here to
1876 * ensure event will not be removed when doing hooks operation
1878 CVW_ENTER_WRITE(&hfi->hfi_lock);
1880 hei = hook_event_find(hfi, event);
1881 if (hei == NULL) {
1882 CVW_EXIT_WRITE(&hfi->hfi_lock);
1883 hook_int_free(new, hfi->hfi_stack->hks_netstackid);
1884 return (ENXIO);
1887 CVW_ENTER_WRITE(&hei->hei_lock);
1890 * If we've run either the remove() or shutdown(), do not allow any
1891 * more hooks to be added to this event.
1893 if (hei->hei_shutdown) {
1894 error = ESHUTDOWN;
1895 goto bad_add;
1898 hi = hook_find(hei, h);
1899 if (hi != NULL) {
1900 error = EEXIST;
1901 goto bad_add;
1904 if (hook_wait_setflag(&hei->hei_waiter, FWF_ADD_WAIT_MASK,
1905 FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) {
1906 error = ENOENT;
1907 bad_add:
1908 CVW_EXIT_WRITE(&hei->hei_lock);
1909 CVW_EXIT_WRITE(&hfi->hfi_lock);
1910 hook_int_free(new, hfi->hfi_stack->hks_netstackid);
1911 return (error);
1914 /* Add to hook list head */
1915 error = hook_insert(&hei->hei_head, new);
1916 if (error == 0) {
1917 hei->hei_event->he_interested = B_TRUE;
1918 hei->hei_kstats.hooks_added.value.ui64++;
1920 hook_init_kstats(hfi, hei, new);
1923 CVW_EXIT_WRITE(&hei->hei_lock);
1924 CVW_EXIT_WRITE(&hfi->hfi_lock);
1927 * Note that the name string passed through to the notify callbacks
1928 * is from the original hook being registered, not the copy being
1929 * inserted.
1931 if (error == 0)
1932 hook_event_notify_run(hei, hfi, event, h->h_name, HN_REGISTER);
1934 hook_wait_unsetflag(&hei->hei_waiter, FWF_ADD_ACTIVE);
1936 return (error);
1940 * Function: hook_insert
1941 * Returns: int - 0 = success, else = failure
1942 * Parameters: head(I) - pointer to hook list to insert hook onto
1943 * new(I) - pointer to hook to be inserted
1945 * Try to insert the hook onto the list of hooks according to the hints
1946 * given in the hook to be inserted and those that already exist on the
1947 * list. For now, the implementation permits only a single hook to be
1948 * either first or last and names provided with before or after are only
1949 * loosely coupled with the action.
1951 static int
1952 hook_insert(hook_int_head_t *head, hook_int_t *new)
1954 hook_int_t *before;
1955 hook_int_t *hi;
1956 hook_t *hih;
1957 hook_t *h = &new->hi_hook;
1959 switch (new->hi_hook.h_hint) {
1960 case HH_NONE :
1961 before = NULL;
1963 * If there is no hint present (or not one that can be
1964 * satisfied now) then try to at least respect the wishes
1965 * of those that want to be last. If there are none wanting
1966 * to be last then add the new hook to the tail of the
1967 * list - this means we keep any wanting to be first
1968 * happy without having to search for HH_FIRST.
1970 TAILQ_FOREACH(hi, head, hi_entry) {
1971 hih = &hi->hi_hook;
1972 if ((hih->h_hint == HH_AFTER) &&
1973 (strcmp(h->h_name,
1974 (char *)hih->h_hintvalue) == 0)) {
1975 TAILQ_INSERT_BEFORE(hi, new, hi_entry);
1976 return (0);
1978 if ((hih->h_hint == HH_BEFORE) && (before == NULL) &&
1979 (strcmp(h->h_name,
1980 (char *)hih->h_hintvalue) == 0)) {
1981 before = hi;
1984 if (before != NULL) {
1985 TAILQ_INSERT_AFTER(head, before, new, hi_entry);
1986 return (0);
1988 hook_insert_plain(head, new);
1989 break;
1991 case HH_FIRST :
1992 hi = TAILQ_FIRST(head);
1993 if ((hi != NULL) && (hi->hi_hook.h_hint == HH_FIRST))
1994 return (EBUSY);
1995 TAILQ_INSERT_HEAD(head, new, hi_entry);
1996 break;
1998 case HH_LAST :
1999 hi = TAILQ_LAST(head, hook_int_head);
2000 if ((hi != NULL) && (hi->hi_hook.h_hint == HH_LAST))
2001 return (EBUSY);
2002 TAILQ_INSERT_TAIL(head, new, hi_entry);
2003 break;
2005 case HH_BEFORE :
2006 hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue);
2007 if (hi == NULL)
2008 return (hook_insert_afterbefore(head, new));
2010 if (hi->hi_hook.h_hint == HH_FIRST)
2011 return (EBUSY);
2013 TAILQ_INSERT_BEFORE(hi, new, hi_entry);
2014 break;
2016 case HH_AFTER :
2017 hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue);
2018 if (hi == NULL)
2019 return (hook_insert_afterbefore(head, new));
2021 if (hi->hi_hook.h_hint == HH_LAST)
2022 return (EBUSY);
2024 TAILQ_INSERT_AFTER(head, hi, new, hi_entry);
2025 break;
2027 default :
2028 return (EINVAL);
2031 return (0);
2035 * Function: hook_insert_plain
2036 * Returns: int - 0 = success, else = failure
2037 * Parameters: head(I) - pointer to hook list to insert hook onto
2038 * new(I) - pointer to hook to be inserted
2040 * Insert a hook such that it respects the wishes of those that want to
2041 * be last. If there are none wanting to be last then add the new hook
2042 * to the tail of the list - this means we keep any wanting to be first
2043 * happy without having to search for HH_FIRST.
2045 static void
2046 hook_insert_plain(hook_int_head_t *head, hook_int_t *new)
2048 hook_int_t *hi;
2050 hi = TAILQ_FIRST(head);
2051 if (hi != NULL) {
2052 if (hi->hi_hook.h_hint == HH_LAST) {
2053 TAILQ_INSERT_BEFORE(hi, new, hi_entry);
2054 } else {
2055 TAILQ_INSERT_TAIL(head, new, hi_entry);
2057 } else {
2058 TAILQ_INSERT_TAIL(head, new, hi_entry);
2063 * Function: hook_insert_afterbefore
2064 * Returns: int - 0 = success, else = failure
2065 * Parameters: head(I) - pointer to hook list to insert hook onto
2066 * new(I) - pointer to hook to be inserted
2068 * Simple insertion of a hook specifying a HH_BEFORE or HH_AFTER was not
2069 * possible, so now we need to be more careful. The first pass is to go
2070 * through the list and look for any other hooks that also specify the
2071 * same hint name as the new one. The object of this exercise is to make
2072 * sure that hooks with HH_BEFORE always appear on the list before those
2073 * with HH_AFTER so that when said hook arrives, it can be placed in the
2074 * middle of the BEFOREs and AFTERs. If this condition does not arise,
2075 * just use hook_insert_plain() to try and insert the hook somewhere that
2076 * is innocuous to existing efforts.
2078 static int
2079 hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new)
2081 hook_int_t *hi;
2082 hook_t *nh;
2083 hook_t *h;
2085 nh = &new->hi_hook;
2086 ASSERT(new->hi_hook.h_hint != HH_NONE);
2087 ASSERT(new->hi_hook.h_hint != HH_LAST);
2088 ASSERT(new->hi_hook.h_hint != HH_FIRST);
2091 * First, look through the list to see if there are any other
2092 * before's or after's that have a matching hint name.
2094 TAILQ_FOREACH(hi, head, hi_entry) {
2095 h = &hi->hi_hook;
2096 switch (h->h_hint) {
2097 case HH_FIRST :
2098 case HH_LAST :
2099 case HH_NONE :
2100 break;
2101 case HH_BEFORE :
2102 if ((nh->h_hint == HH_BEFORE) &&
2103 (strcmp((char *)h->h_hintvalue,
2104 (char *)nh->h_hintvalue) == 0)) {
2105 TAILQ_INSERT_AFTER(head, hi, new, hi_entry);
2106 return (0);
2108 if ((nh->h_hint == HH_AFTER) &&
2109 (strcmp((char *)h->h_hintvalue,
2110 (char *)nh->h_hintvalue) == 0)) {
2111 TAILQ_INSERT_BEFORE(hi, new, hi_entry);
2112 return (0);
2114 break;
2115 case HH_AFTER :
2116 if ((nh->h_hint == HH_AFTER) &&
2117 (strcmp((char *)h->h_hintvalue,
2118 (char *)nh->h_hintvalue) == 0)) {
2119 TAILQ_INSERT_AFTER(head, hi, new, hi_entry);
2120 return (0);
2122 if ((nh->h_hint == HH_BEFORE) &&
2123 (strcmp((char *)h->h_hintvalue,
2124 (char *)nh->h_hintvalue) == 0)) {
2125 TAILQ_INSERT_BEFORE(hi, new, hi_entry);
2126 return (0);
2128 break;
2132 hook_insert_plain(head, new);
2134 return (0);
2138 * Function: hook_unregister
2139 * Returns: int - 0 = success, else = failure
2140 * Parameters: hfi(I) - internal family pointer
2141 * event(I) - event name string
2142 * h(I) - hook pointer
2144 * Remove hook from hook list on specific family, event
2147 hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h)
2149 hook_event_int_t *hei;
2150 hook_int_t *hi;
2151 boolean_t free_event;
2153 ASSERT(hfi != NULL);
2154 ASSERT(h != NULL);
2156 CVW_ENTER_WRITE(&hfi->hfi_lock);
2158 hei = hook_event_find(hfi, event);
2159 if (hei == NULL) {
2160 CVW_EXIT_WRITE(&hfi->hfi_lock);
2161 return (ENXIO);
2164 /* Hold write lock for event */
2165 CVW_ENTER_WRITE(&hei->hei_lock);
2167 hi = hook_find(hei, h);
2168 if (hi == NULL) {
2169 CVW_EXIT_WRITE(&hei->hei_lock);
2170 CVW_EXIT_WRITE(&hfi->hfi_lock);
2171 return (ENXIO);
2174 if (hook_wait_setflag(&hei->hei_waiter, FWF_DEL_WAIT_MASK,
2175 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
2176 CVW_EXIT_WRITE(&hei->hei_lock);
2177 CVW_EXIT_WRITE(&hfi->hfi_lock);
2178 return (ENOENT);
2181 /* Remove from hook list */
2182 TAILQ_REMOVE(&hei->hei_head, hi, hi_entry);
2184 free_event = B_FALSE;
2185 if (TAILQ_EMPTY(&hei->hei_head)) {
2186 hei->hei_event->he_interested = B_FALSE;
2188 * If the delete pending flag has been set and there are
2189 * no notifiers on the event (and we've removed the last
2190 * hook) then we need to free this event after we're done.
2192 if (hei->hei_condemned && TAILQ_EMPTY(&hei->hei_nhead))
2193 free_event = B_TRUE;
2195 hei->hei_kstats.hooks_removed.value.ui64++;
2197 CVW_EXIT_WRITE(&hei->hei_lock);
2198 CVW_EXIT_WRITE(&hfi->hfi_lock);
2200 * While the FWF_DEL_ACTIVE flag is set, the hook_event_int_t
2201 * will not be free'd and thus the hook_family_int_t wil not
2202 * be free'd either.
2204 hook_event_notify_run(hei, hfi, event, h->h_name, HN_UNREGISTER);
2205 hook_wait_unsetflag(&hei->hei_waiter, FWF_DEL_ACTIVE);
2207 hook_int_free(hi, hfi->hfi_stack->hks_netstackid);
2209 if (free_event)
2210 hook_event_free(hei, hfi);
2212 return (0);
2216 * Function: hook_find_byname
2217 * Returns: internal hook pointer - NULL = Not match
2218 * Parameters: hei(I) - internal event pointer
2219 * name(I)- hook name
2221 * Search an event's list of hooks to see if there is a hook present that
2222 * has a matching name to the one being looked for.
2224 static hook_int_t *
2225 hook_find_byname(hook_int_head_t *head, char *name)
2227 hook_int_t *hi;
2229 TAILQ_FOREACH(hi, head, hi_entry) {
2230 if (strcmp(hi->hi_hook.h_name, name) == 0)
2231 return (hi);
2234 return (NULL);
2238 * Function: hook_find
2239 * Returns: internal hook pointer - NULL = Not match
2240 * Parameters: hei(I) - internal event pointer
2241 * h(I) - hook pointer
2243 * Search an event's list of hooks to see if there is already one that
2244 * matches the hook being passed in. Currently the only criteria for a
2245 * successful search here is for the names to be the same.
2247 static hook_int_t *
2248 hook_find(hook_event_int_t *hei, hook_t *h)
2251 ASSERT(hei != NULL);
2252 ASSERT(h != NULL);
2254 return (hook_find_byname(&hei->hei_head, h->h_name));
2258 * Function: hook_copy
2259 * Returns: internal hook pointer - NULL = Failed
2260 * Parameters: src(I) - hook pointer
2262 * Allocate internal hook block and duplicate incoming hook.
2263 * No locks should be held across this function as it may sleep.
2264 * Because hook_copy() is responsible for the creation of the internal
2265 * hook structure that is used here, it takes on population the structure
2266 * with the kstat information. Note that while the kstat bits are
2267 * seeded here, their installation of the kstats is handled elsewhere.
2269 static hook_int_t *
2270 hook_copy(hook_t *src)
2272 hook_int_t *new;
2273 hook_t *dst;
2274 int len;
2276 ASSERT(src != NULL);
2277 ASSERT(src->h_name != NULL);
2279 new = (hook_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
2281 /* Copy body */
2282 dst = &new->hi_hook;
2283 *dst = *src;
2285 /* Copy name */
2286 len = strlen(src->h_name);
2287 dst->h_name = (char *)kmem_alloc(len + 1, KM_SLEEP);
2288 (void) strcpy(dst->h_name, src->h_name);
2291 * This is initialised in this manner to make it safer to use the
2292 * same pointer in the kstats field.
2294 dst->h_hintvalue = (uintptr_t)"";
2296 if (dst->h_hint == HH_BEFORE || dst->h_hint == HH_AFTER) {
2297 len = strlen((char *)src->h_hintvalue);
2298 if (len > 0) {
2299 dst->h_hintvalue = (uintptr_t)kmem_alloc(len + 1,
2300 KM_SLEEP);
2301 (void) strcpy((char *)dst->h_hintvalue,
2302 (char *)src->h_hintvalue);
2306 return (new);
2310 * Function: hook_init_kstats
2311 * Returns: None
2312 * Parameters: hfi(I) - pointer to the family that owns the event.
2313 * hei(I) - pointer to the event that owns this hook
2314 * hi(I) - pointer to the hook for which we create kstats for
2316 * Each hook that is registered with this framework has its own kstats
2317 * set up so that we can provide an easy way in which to observe the
2318 * look of hooks (using the kstat command.) The position is set to 0
2319 * here but is recalculated after we know the insertion has been a
2320 * success.
2322 static void
2323 hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei, hook_int_t *hi)
2325 hook_hook_kstat_t template = {
2326 { "version", KSTAT_DATA_INT32 },
2327 { "flags", KSTAT_DATA_UINT32 },
2328 { "hint", KSTAT_DATA_INT32 },
2329 { "hint_value", KSTAT_DATA_UINT64 },
2330 { "position", KSTAT_DATA_INT32 },
2331 { "hook_hits", KSTAT_DATA_UINT64 }
2333 hook_stack_t *hks;
2334 size_t kslen;
2335 int position;
2336 hook_int_t *h;
2338 kslen = strlen(hfi->hfi_family.hf_name) +
2339 strlen(hei->hei_event->he_name) + 2;
2341 hi->hi_ksname = (char *)kmem_zalloc(kslen, KM_SLEEP);
2342 (void) snprintf(hi->hi_ksname, kslen, "%s/%s",
2343 hfi->hfi_family.hf_name, hei->hei_event->he_name);
2345 hks = hfi->hfi_stack;
2346 hi->hi_kstatp = kstat_create_netstack(hi->hi_ksname, 0,
2347 hi->hi_hook.h_name, "hook", KSTAT_TYPE_NAMED,
2348 sizeof (hi->hi_kstats) / sizeof (kstat_named_t),
2349 KSTAT_FLAG_VIRTUAL, hks->hks_netstackid);
2351 /* Initialise the kstats for the structure */
2352 bcopy(&template, &hi->hi_kstats, sizeof (template));
2353 hi->hi_kstats.hook_version.value.i32 = hi->hi_hook.h_version;
2354 hi->hi_kstats.hook_flags.value.ui32 = hi->hi_hook.h_flags;
2355 hi->hi_kstats.hook_hint.value.i32 = hi->hi_hook.h_hint;
2356 hi->hi_kstats.hook_position.value.i32 = 0;
2357 hi->hi_kstats.hook_hits.value.ui64 = 0;
2359 switch (hi->hi_hook.h_hint) {
2360 case HH_BEFORE :
2361 case HH_AFTER :
2362 hi->hi_kstats.hook_hintvalue.data_type = KSTAT_DATA_STRING;
2363 hi->hi_kstats.hook_hintvalue.value.ui64 =
2364 hi->hi_hook.h_hintvalue;
2365 break;
2366 default :
2367 break;
2370 if (hi->hi_kstatp != NULL) {
2371 hi->hi_kstatp->ks_data = (void *)&hi->hi_kstats;
2372 hi->hi_kstatp->ks_private =
2373 (void *)(uintptr_t)hks->hks_netstackid;
2375 kstat_install(hi->hi_kstatp);
2378 position = 1;
2379 TAILQ_FOREACH(h, &hei->hei_head, hi_entry) {
2380 h->hi_kstats.hook_position.value.ui32 = position++;
2385 * Function: hook_int_free
2386 * Returns: None
2387 * Parameters: hi(I) - internal hook pointer
2389 * Free memory allocated to support a hook.
2391 static void
2392 hook_int_free(hook_int_t *hi, netstackid_t stackid)
2394 int len;
2396 ASSERT(hi != NULL);
2398 /* Free name space */
2399 if (hi->hi_hook.h_name != NULL) {
2400 kmem_free(hi->hi_hook.h_name, strlen(hi->hi_hook.h_name) + 1);
2402 if (hi->hi_ksname != NULL) {
2403 kmem_free(hi->hi_ksname, strlen(hi->hi_ksname) + 1);
2406 /* Free the name used with the before/after hints. */
2407 switch (hi->hi_hook.h_hint) {
2408 case HH_BEFORE :
2409 case HH_AFTER :
2410 len = strlen((char *)hi->hi_hook.h_hintvalue);
2411 if (len > 0)
2412 kmem_free((void *)hi->hi_hook.h_hintvalue, len + 1);
2413 break;
2414 default :
2415 break;
2418 if (hi->hi_kstatp != NULL)
2419 kstat_delete_netstack(hi->hi_kstatp, stackid);
2421 /* Free container */
2422 kmem_free(hi, sizeof (*hi));
2426 * Function: hook_alloc
2427 * Returns: hook_t * - pointer to new hook structure
2428 * Parameters: version(I) - version number of the API when compiled
2430 * This function serves as the interface for consumers to obtain a hook_t
2431 * structure. At this point in time, there is only a single "version" of
2432 * it, leading to a straight forward function. In a perfect world the
2433 * h_vesion would be a protected data structure member, but C isn't that
2434 * advanced...
2436 hook_t *
2437 hook_alloc(const int h_version)
2439 hook_t *h;
2441 h = kmem_zalloc(sizeof (hook_t), KM_SLEEP);
2442 h->h_version = h_version;
2443 return (h);
2447 * Function: hook_free
2448 * Returns: None
2449 * Parameters: h(I) - external hook pointer
2451 * This function only free's memory allocated with hook_alloc(), so that if
2452 * (for example) kernel memory was allocated for h_name, this needs to be
2453 * free'd before calling hook_free().
2455 void
2456 hook_free(hook_t *h)
2458 kmem_free(h, sizeof (*h));
2462 * Function: hook_notify_register
2463 * Returns: int - 0 = success, else failure
2464 * Parameters: head(I) - top of the list of callbacks
2465 * callback(I) - function to be called
2466 * arg(I) - arg to pass back to the function
2468 * This function implements the modification of the list of callbacks
2469 * that are registered when someone wants to be advised of a change
2470 * that has happened.
2472 static int
2473 hook_notify_register(hook_notify_head_t *head, hook_notify_fn_t callback,
2474 void *arg)
2476 hook_notify_t *hn;
2478 TAILQ_FOREACH(hn, head, hn_entry) {
2479 if (hn->hn_func == callback) {
2480 return (EEXIST);
2484 hn = (hook_notify_t *)kmem_alloc(sizeof (*hn), KM_SLEEP);
2485 hn->hn_func = callback;
2486 hn->hn_arg = arg;
2487 TAILQ_INSERT_TAIL(head, hn, hn_entry);
2489 return (0);
2493 * Function: hook_notify_unregister
2494 * Returns: int - 0 = success, else failure
2495 * Parameters: stackid(I) - netstack identifier
2496 * callback(I) - function to be called
2497 * parg(O) - pointer to storage for pointer
2499 * When calling this function, the provision of a valid pointer in parg
2500 * allows the caller to be made aware of what argument the hook function
2501 * was expecting. This then allows the simulation of HN_UNREGISTER events
2502 * when a notify-unregister is performed.
2504 static int
2505 hook_notify_unregister(hook_notify_head_t *head,
2506 hook_notify_fn_t callback, void **parg)
2508 hook_notify_t *hn;
2510 ASSERT(parg != NULL);
2512 TAILQ_FOREACH(hn, head, hn_entry) {
2513 if (hn->hn_func == callback)
2514 break;
2517 if (hn == NULL)
2518 return (ESRCH);
2520 *parg = hn->hn_arg;
2522 TAILQ_REMOVE(head, hn, hn_entry);
2524 kmem_free(hn, sizeof (*hn));
2526 return (0);
2530 * Function: hook_notify_run
2531 * Returns: None
2532 * Parameters: head(I) - top of the list of callbacks
2533 * family(I) - name of the hook family that owns the event
2534 * event(I) - name of the event being changed
2535 * name(I) - name of the object causing change
2536 * cmd(I) - either HN_UNREGISTER or HN_REGISTER
2538 * This function walks through the list of registered callbacks and
2539 * executes each one, passing back the arg supplied when registered
2540 * and the name of the family (that owns the event), event (the thing
2541 * to which we're making a change) and finally a name that describes
2542 * what is being added or removed, as indicated by cmd.
2544 * This function does not acquire or release any lock as it is required
2545 * that code calling it do so before hand. The use of hook_notify_head_t
2546 * is protected by the use of flagwait_t in the structures that own this
2547 * list and with the use of the FWF_ADD/DEL_ACTIVE flags.
2549 static void
2550 hook_notify_run(hook_notify_head_t *head, char *family, char *event,
2551 char *name, hook_notify_cmd_t cmd)
2553 hook_notify_t *hn;
2555 TAILQ_FOREACH(hn, head, hn_entry) {
2556 (*hn->hn_func)(cmd, hn->hn_arg, family, event, name);