blob: c3ebfa0e47a63f34b72d0eafff52acea8730eed6 [file] [log] [blame]
dr146992381a2a92006-10-20 16:37:58 -07001/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
Darren Reed7ddc9b12008-09-08 14:46:50 -070022 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
dr146992381a2a92006-10-20 16:37:58 -070023 * Use is subject to license terms.
Rob Gulewich652fb502013-10-31 00:30:55 +000024 *
Jason King68c34d02018-10-22 00:53:14 +000025 * Copyright 2018 Joyent, Inc. All rights reserved.
Daniel Hoffman48bbca82017-02-17 11:48:20 -080026 * Copyright (c) 2016 by Delphix. All rights reserved.
dr146992381a2a92006-10-20 16:37:58 -070027 */
dr146992381a2a92006-10-20 16:37:58 -070028#include <sys/param.h>
29#include <sys/types.h>
30#include <sys/systm.h>
31#include <sys/errno.h>
32#include <sys/kmem.h>
33#include <sys/mutex.h>
34#include <sys/condvar.h>
35#include <sys/modctl.h>
36#include <sys/hook_impl.h>
37#include <sys/sdt.h>
Darren Reed7ddc9b12008-09-08 14:46:50 -070038#include <sys/cmn_err.h>
dr146992381a2a92006-10-20 16:37:58 -070039
40/*
41 * This file provides kernel hook framework.
42 */
43
44static struct modldrv modlmisc = {
45 &mod_miscops, /* drv_modops */
46 "Hooks Interface v1.0", /* drv_linkinfo */
47};
48
49static struct modlinkage modlinkage = {
50 MODREV_1, /* ml_rev */
51 &modlmisc, /* ml_linkage */
52 NULL
53};
54
Rob Gulewich652fb502013-10-31 00:30:55 +000055static const char *hook_hintvalue_none = "<none>";
56
dr146992381a2a92006-10-20 16:37:58 -070057/*
Darren Reed7ddc9b12008-09-08 14:46:50 -070058 * How it works.
59 * =============
60 * Use of the hook framework here is tied up with zones - when a new zone
61 * is created, we create a new hook_stack_t and are open to business for
62 * allowing new hook families and their events.
63 *
64 * A consumer of these hooks is expected to operate in this fashion:
65 * 1) call hook_family_add() to create a new family of hooks. It is a
66 * current requirement that this call must be made with the value
67 * returned from hook_stack_init, by way of infrastructure elsewhere.
68 * 2) add events to the registered family with calls to hook_event_add.
69 *
70 * At this point, the structures in place should be open to others to
71 * add hooks to the event or add notifiers for when the contents of the
72 * hook stack changes.
73 *
74 * The interesting stuff happens on teardown.
75 *
76 * It is a requirement that the provider of hook events work in the reverse
77 * order to the above, so that the first step is:
78 * 1) remove events from each hook family created earlier
79 * 2) remove hook families from the hook stack.
80 *
81 * When doing teardown of both events and families, a check is made to see
Darren Reed4a9b8372010-04-26 17:05:56 -070082 * 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."
Darren Reed7ddc9b12008-09-08 14:46:50 -070092 *
93 * ONLY the caller that adds the family and the events ever has a direct
94 * reference to the internal structures and thus ONLY it should be doing
95 * the removal of either the event or family. In practise, what this means
96 * is that in ip_netinfo.c, we have calls to net_protocol_register(), followed
97 * by net_event_register() (these interface to hook_family_add() and
98 * hook_event_add(), respectively) that are made when we create an instance
99 * of IP and when the IP instance is shutdown/destroyed, it calls
100 * net_event_unregister() and net_protocol_unregister(), which in turn call
101 * hook_event_remove() and hook_family_remove() respectively. Nobody else
102 * is entitled to call the _unregister() functions. It is imperative that
103 * there be only one _remove() call for every _add() call.
104 *
105 * It is possible that code which is interfacing with this hook framework
106 * won't do all the cleaning up that it needs to at the right time. While
107 * we can't prevent programmers from creating memory leaks, we can synchronise
108 * when we clean up data structures to prevent code accessing free'd memory.
109 *
110 * A simple diagram showing the ownership is as follows:
111 *
112 * Owned +--------------+
113 * by | hook_stack_t |
114 * the +--------------+
115 * Instance |
116 * - - - - - - - -|- - - - - - - - - - - - - - - - - -
117 * V
118 * Owned +-------------------+ +-------------------+
119 * | hook_family_int_t |---->| hook_family_int_t |
120 * by +-------------------+ +-------------------+
121 * | \+---------------+ \+---------------+
122 * network | | hook_family_t | | hook_family_t |
123 * V +---------------+ +---------------+
124 * protocol +------------------+ +------------------+
125 * | hook_event_int_t |---->| hook_event_int_t |
126 * (ipv4,ipv6) +------------------+ +------------------+
127 * | \+--------------+ \+--------------+
128 * | | hook_event_t | | hook_event_t |
129 * | +--------------+ +--------------+
130 * - - - - - - - -|- - - - - - - - - - - - - - - - - -
131 * V
132 * Owned +------------+
133 * | hook_int_t |
134 * by +------------+
135 * \+--------+
136 * the consumer | hook_t |
137 * +--------+
138 *
139 * The consumers, such as IPFilter, do not have any pointers or hold any
140 * references to hook_int_t, hook_event_t or hook_event_int_t. By placing
141 * a hook on an event through net_hook_register(), an implicit reference
142 * to the hook_event_int_t is returned with a successful call. Additionally,
143 * IPFilter does not see the hook_family_int_t or hook_family_t directly.
144 * Rather it is returned a net_handle_t (from net_protocol_lookup()) that
145 * contains a pointer to hook_family_int_t. The structure behind the
146 * net_handle_t (struct net_data) *is* reference counted and managed
147 * appropriately.
148 *
149 * A more detailed picture that describes how the family/event structures
150 * are linked together can be found in <sys/hook_impl.h>
Darren Reed4a9b8372010-04-26 17:05:56 -0700151 *
152 * Notification callbacks.
153 * =======================
154 * For each of the hook stack, hook family and hook event, it is possible
155 * to request notificatin of change to them. Why?
156 * First, lets equate the hook stack to an IP instance, a hook family to
157 * a network protocol and a hook event to IP packets on the input path.
158 * If a kernel module wants to apply security from the very start of
159 * things, it needs to know as soon as a new instance of networking
160 * is initiated. Whilst for the global zone, it is taken for granted that
161 * this instance will always exist before any interaction takes place,
162 * that is not true for zones running with an exclusive networking instance.
163 * Thus when a local zone is started and a new instance is created to support
164 * that, parties that wish to monitor it and apply a security policy from
165 * the onset need to be informed as early as possible - quite probably
166 * before any networking is started by the zone's boot scripts.
167 * Inside each instance, it is possible to have a number of network protocols
168 * (hook families) in operation. Inside the context of the global zone,
169 * it is possible to have code run before the kernel module providing the
170 * IP networking is loaded. From here, to apply the appropriate security,
171 * it is necessary to become informed of when IP is being configured into
172 * the zone and this is done by registering a notification callback with
173 * the hook stack for changes to it. The next step is to know when packets
174 * can be received through the physical_in, etc, events. This is achieved
175 * by registering a callback with the appropriate network protocol (or in
176 * this file, the correct hook family.) Thus when IP finally attaches a
177 * physical_in event to inet, the module looking to enforce a security
178 * policy can become aware of it being present. Of course there's no
179 * requirement for such a module to be present before all of the above
180 * happens and in such a case, it is reasonable for the same module to
181 * work after everything has been put in place. For this reason, when
182 * a notification callback is added, a series of fake callback events
183 * is generated to simulate the arrival of those entities. There is one
184 * final series of callbacks that can be registered - those to monitor
185 * actual hooks that are added or removed from an event. In practice,
186 * this is useful when there are multiple kernel modules participating
187 * in the processing of packets and there are behaviour dependencies
188 * involved, such that one kernel module might only register its hook
189 * if another is already present and also might want to remove its hook
190 * when the other disappears.
191 *
192 * If you know a kernel module will not be loaded before the infrastructure
193 * used in this file is present then it is not necessary to use this
194 * notification callback mechanism.
Darren Reed7ddc9b12008-09-08 14:46:50 -0700195 */
196
197/*
198 * Locking
199 * =======
200 * The use of CVW_* macros to do locking is driven by the need to allow
201 * recursive locking with read locks when we're processing packets. This
202 * is necessary because various netinfo functions need to hold read locks,
203 * by design, as they can be called in or out of packet context.
204 */
205/*
dr146992381a2a92006-10-20 16:37:58 -0700206 * Hook internal functions
207 */
208static hook_int_t *hook_copy(hook_t *src);
dh155122f4b3ec62007-01-19 16:59:38 -0800209static hook_event_int_t *hook_event_checkdup(hook_event_t *he,
210 hook_stack_t *hks);
dr146992381a2a92006-10-20 16:37:58 -0700211static hook_event_int_t *hook_event_copy(hook_event_t *src);
212static hook_event_int_t *hook_event_find(hook_family_int_t *hfi, char *event);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700213static void hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi);
dr146992381a2a92006-10-20 16:37:58 -0700214static hook_family_int_t *hook_family_copy(hook_family_t *src);
dh155122f4b3ec62007-01-19 16:59:38 -0800215static hook_family_int_t *hook_family_find(char *family, hook_stack_t *hks);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700216static void hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks);
dr146992381a2a92006-10-20 16:37:58 -0700217static hook_int_t *hook_find(hook_event_int_t *hei, hook_t *h);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700218static void hook_int_free(hook_int_t *hi, netstackid_t);
dr146992381a2a92006-10-20 16:37:58 -0700219static void hook_init(void);
dh155122f4b3ec62007-01-19 16:59:38 -0800220static void hook_fini(void);
221static void *hook_stack_init(netstackid_t stackid, netstack_t *ns);
222static void hook_stack_fini(netstackid_t stackid, void *arg);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700223static void hook_stack_shutdown(netstackid_t stackid, void *arg);
224static int hook_insert(hook_int_head_t *head, hook_int_t *new);
225static void hook_insert_plain(hook_int_head_t *head, hook_int_t *new);
226static int hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new);
227static hook_int_t *hook_find_byname(hook_int_head_t *head, char *name);
228static void hook_event_init_kstats(hook_family_int_t *, hook_event_int_t *);
229static void hook_event_notify_run(hook_event_int_t *, hook_family_int_t *,
230 char *event, char *name, hook_notify_cmd_t cmd);
231static void hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei,
232 hook_int_t *hi);
Darren Reed4a9b8372010-04-26 17:05:56 -0700233static int hook_notify_register(hook_notify_head_t *head,
Darren Reed7ddc9b12008-09-08 14:46:50 -0700234 hook_notify_fn_t callback, void *arg);
Darren Reed4a9b8372010-04-26 17:05:56 -0700235static int hook_notify_unregister(hook_notify_head_t *head,
236 hook_notify_fn_t callback, void **);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700237static void hook_notify_run(hook_notify_head_t *head, char *family,
238 char *event, char *name, hook_notify_cmd_t cmd);
239static void hook_stack_notify_run(hook_stack_t *hks, char *name,
240 hook_notify_cmd_t cmd);
241static void hook_stack_remove(hook_stack_t *hks);
242
243/*
244 * A list of the hook stacks is kept here because we need to enable
245 * net_instance_notify_register() to be called during the creation
246 * of a new instance. Previously hook_stack_get() would just use
247 * the netstack functions for this work but they will return NULL
248 * until the zone has been fully initialised.
249 */
250static hook_stack_head_t hook_stacks;
251static kmutex_t hook_stack_lock;
dr146992381a2a92006-10-20 16:37:58 -0700252
253/*
254 * Module entry points.
255 */
256int
257_init(void)
258{
dh155122f4b3ec62007-01-19 16:59:38 -0800259 int error;
260
dr146992381a2a92006-10-20 16:37:58 -0700261 hook_init();
dh155122f4b3ec62007-01-19 16:59:38 -0800262 error = mod_install(&modlinkage);
263 if (error != 0)
264 hook_fini();
265
266 return (error);
dr146992381a2a92006-10-20 16:37:58 -0700267}
268
dr146992381a2a92006-10-20 16:37:58 -0700269int
270_fini(void)
271{
dh155122f4b3ec62007-01-19 16:59:38 -0800272 int error;
273
274 error = mod_remove(&modlinkage);
275 if (error == 0)
276 hook_fini();
277
278 return (error);
dr146992381a2a92006-10-20 16:37:58 -0700279}
280
dr146992381a2a92006-10-20 16:37:58 -0700281int
282_info(struct modinfo *modinfop)
283{
284 return (mod_info(&modlinkage, modinfop));
285}
286
dr146992381a2a92006-10-20 16:37:58 -0700287/*
288 * Function: hook_init
289 * Returns: None
290 * Parameters: None
291 *
292 * Initialize hooks
293 */
294static void
295hook_init(void)
296{
Darren Reed7ddc9b12008-09-08 14:46:50 -0700297 mutex_init(&hook_stack_lock, NULL, MUTEX_DRIVER, NULL);
298 SLIST_INIT(&hook_stacks);
299
dh155122f4b3ec62007-01-19 16:59:38 -0800300 /*
301 * We want to be informed each time a stack is created or
302 * destroyed in the kernel.
303 */
Darren Reed7ddc9b12008-09-08 14:46:50 -0700304 netstack_register(NS_HOOK, hook_stack_init, hook_stack_shutdown,
dh155122f4b3ec62007-01-19 16:59:38 -0800305 hook_stack_fini);
dr146992381a2a92006-10-20 16:37:58 -0700306}
307
dh155122f4b3ec62007-01-19 16:59:38 -0800308/*
309 * Function: hook_fini
310 * Returns: None
311 * Parameters: None
312 *
313 * Deinitialize hooks
314 */
315static void
316hook_fini(void)
317{
318 netstack_unregister(NS_HOOK);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700319
320 mutex_destroy(&hook_stack_lock);
321 ASSERT(SLIST_EMPTY(&hook_stacks));
322}
323
324/*
325 * Function: hook_wait_setflag
326 * Returns: -1 = setting flag is disallowed, 0 = flag set and did
327 * not have to wait (ie no lock droped), 1 = flag set but
328 * it was necessary to drop locks to set it.
329 * Parameters: waiter(I) - control data structure
330 * busyset(I) - set of flags that we don't want set while
331 * we are active.
332 * wanted(I) - flag associated with newflag to indicate
333 * what we want to do.
334 * newflag(I) - the new ACTIVE flag we want to set that
335 * indicates what we are doing.
336 *
337 * The set of functions hook_wait_* implement an API that builds on top of
338 * the kcondvar_t to provide controlled execution through a critical region.
339 * For each flag that indicates work is being done (FWF_*_ACTIVE) there is
340 * also a flag that we set to indicate that we want to do it (FWF_*_WANTED).
341 * The combination of flags is required as when this function exits to do
342 * the task, the structure is then free for another caller to use and
Darren Reed4a9b8372010-04-26 17:05:56 -0700343 * to indicate that it wants to do work. The flags used when a caller wants
344 * to destroy an object take precedence over those that are used for making
345 * changes to it (add/remove.) In this case, we don't try to secure the
346 * ability to run and return with an error.
347 *
348 * "wantedset" is used here to determine who has the right to clear the
Daniel Hoffman48bbca82017-02-17 11:48:20 -0800349 * wanted bit from the fw_flags set: only whomever sets the flag has the
Darren Reed4a9b8372010-04-26 17:05:56 -0700350 * right to clear it at the bottom of the loop, even if someone else
351 * wants to set it.
Darren Reed7ddc9b12008-09-08 14:46:50 -0700352 *
353 * wanted - the FWF_*_WANTED flag that describes the action being requested
354 * busyset- the set of FWF_* flags we don't want set when we run
355 * newflag- the FWF_*_ACTIVE flag we will set to indicate we are busy
356 */
357int
358hook_wait_setflag(flagwait_t *waiter, uint32_t busyset, fwflag_t wanted,
359 fwflag_t newflag)
360{
Darren Reed4a9b8372010-04-26 17:05:56 -0700361 boolean_t wantedset;
Darren Reed7ddc9b12008-09-08 14:46:50 -0700362 int waited = 0;
363
364 mutex_enter(&waiter->fw_lock);
365 if (waiter->fw_flags & FWF_DESTROY) {
Darren Reed4a9b8372010-04-26 17:05:56 -0700366 cv_signal(&waiter->fw_cv);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700367 mutex_exit(&waiter->fw_lock);
368 return (-1);
369 }
370 while (waiter->fw_flags & busyset) {
Darren Reed4a9b8372010-04-26 17:05:56 -0700371 wantedset = ((waiter->fw_flags & wanted) == wanted);
372 if (!wantedset)
373 waiter->fw_flags |= wanted;
Darren Reed7ddc9b12008-09-08 14:46:50 -0700374 CVW_EXIT_WRITE(waiter->fw_owner);
375 cv_wait(&waiter->fw_cv, &waiter->fw_lock);
Darren Reed4a9b8372010-04-26 17:05:56 -0700376 /*
377 * This lock needs to be dropped here to preserve the order
378 * of acquisition that is fw_owner followed by fw_lock, else
379 * we can deadlock.
380 */
381 mutex_exit(&waiter->fw_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700382 waited = 1;
383 CVW_ENTER_WRITE(waiter->fw_owner);
Darren Reed4a9b8372010-04-26 17:05:56 -0700384 mutex_enter(&waiter->fw_lock);
385 if (!wantedset)
Darren Reed7ddc9b12008-09-08 14:46:50 -0700386 waiter->fw_flags &= ~wanted;
Darren Reed4a9b8372010-04-26 17:05:56 -0700387 if (waiter->fw_flags & FWF_DESTROY) {
388 cv_signal(&waiter->fw_cv);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700389 mutex_exit(&waiter->fw_lock);
390 return (-1);
391 }
Darren Reed7ddc9b12008-09-08 14:46:50 -0700392 }
393 waiter->fw_flags &= ~wanted;
Darren Reed4a9b8372010-04-26 17:05:56 -0700394 ASSERT((waiter->fw_flags & wanted) == 0);
395 ASSERT((waiter->fw_flags & newflag) == 0);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700396 waiter->fw_flags |= newflag;
397 mutex_exit(&waiter->fw_lock);
398 return (waited);
399}
400
401/*
402 * Function: hook_wait_unsetflag
403 * Returns: None
404 * Parameters: waiter(I) - control data structure
405 * oldflag(I) - flag to reset
406 *
407 * Turn off the bit that we had set to run and let others know that
408 * they should now check to see if they can run.
409 */
410void
Darren Reed4a9b8372010-04-26 17:05:56 -0700411hook_wait_unsetflag(flagwait_t *waiter, fwflag_t oldflag)
Darren Reed7ddc9b12008-09-08 14:46:50 -0700412{
413 mutex_enter(&waiter->fw_lock);
414 waiter->fw_flags &= ~oldflag;
415 cv_signal(&waiter->fw_cv);
416 mutex_exit(&waiter->fw_lock);
417}
418
419/*
420 * Function: hook_wait_destroy
421 * Returns: None
422 * Parameters: waiter(I) - control data structure
423 *
424 * Since outer locking (on fw_owner) should ensure that only one function
425 * at a time gets to call hook_wait_destroy() on a given object, there is
426 * no need to guard against setting FWF_DESTROY_WANTED already being set.
427 * It is, however, necessary to wait for all activity on the owning
428 * structure to cease.
429 */
Darren Reed4a9b8372010-04-26 17:05:56 -0700430int
Darren Reed7ddc9b12008-09-08 14:46:50 -0700431hook_wait_destroy(flagwait_t *waiter)
432{
433 ASSERT((waiter->fw_flags & FWF_DESTROY_WANTED) == 0);
Darren Reed4a9b8372010-04-26 17:05:56 -0700434 mutex_enter(&waiter->fw_lock);
435 if (waiter->fw_flags & FWF_DESTROY_WANTED) {
436 cv_signal(&waiter->fw_cv);
437 mutex_exit(&waiter->fw_lock);
438 return (EINPROGRESS);
439 }
Darren Reed7ddc9b12008-09-08 14:46:50 -0700440 waiter->fw_flags |= FWF_DESTROY_WANTED;
441 while (!FWF_DESTROY_OK(waiter)) {
442 CVW_EXIT_WRITE(waiter->fw_owner);
443 cv_wait(&waiter->fw_cv, &waiter->fw_lock);
444 CVW_ENTER_WRITE(waiter->fw_owner);
445 }
446 /*
447 * There should now be nothing else using "waiter" or its
448 * owner, so we can safely assign here without risk of wiiping
449 * out someone's bit.
450 */
451 waiter->fw_flags = FWF_DESTROY_ACTIVE;
Darren Reed4a9b8372010-04-26 17:05:56 -0700452 cv_signal(&waiter->fw_cv);
453 mutex_exit(&waiter->fw_lock);
454
455 return (0);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700456}
457
458/*
459 * Function: hook_wait_init
460 * Returns: None
461 * Parameters: waiter(I) - control data structure
462 * ownder(I) - pointer to lock that the owner of this
463 * waiter uses
464 *
465 * "owner" gets passed in here so that when we need to call cv_wait,
466 * for example in hook_wait_setflag(), we can drop the lock for the
467 * next layer out, which is likely to be held in an exclusive manner.
468 */
469void
470hook_wait_init(flagwait_t *waiter, cvwaitlock_t *owner)
471{
472 cv_init(&waiter->fw_cv, NULL, CV_DRIVER, NULL);
473 mutex_init(&waiter->fw_lock, NULL, MUTEX_DRIVER, NULL);
474 waiter->fw_flags = FWF_NONE;
475 waiter->fw_owner = owner;
dh155122f4b3ec62007-01-19 16:59:38 -0800476}
477
478/*
Darren Reed4a9b8372010-04-26 17:05:56 -0700479 * Function: hook_stack_init
480 * Returns: void * - pointer to new hook stack structure
481 * Parameters: stackid(I) - identifier for the network instance that owns this
482 * ns(I) - pointer to the network instance data structure
483 *
484 * Allocate and initialize the hook stack instance. This function is not
485 * allowed to fail, so KM_SLEEP is used here when allocating memory. The
486 * value returned is passed back into the shutdown and destroy hooks.
dh155122f4b3ec62007-01-19 16:59:38 -0800487 */
488/*ARGSUSED*/
489static void *
490hook_stack_init(netstackid_t stackid, netstack_t *ns)
491{
492 hook_stack_t *hks;
493
494#ifdef NS_DEBUG
495 printf("hook_stack_init(stack %d)\n", stackid);
496#endif
497
498 hks = (hook_stack_t *)kmem_zalloc(sizeof (*hks), KM_SLEEP);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700499 hks->hks_netstack = ns;
500 hks->hks_netstackid = stackid;
dh155122f4b3ec62007-01-19 16:59:38 -0800501
Darren Reed7ddc9b12008-09-08 14:46:50 -0700502 CVW_INIT(&hks->hks_lock);
503 TAILQ_INIT(&hks->hks_nhead);
dh155122f4b3ec62007-01-19 16:59:38 -0800504 SLIST_INIT(&hks->hks_familylist);
505
Darren Reed7ddc9b12008-09-08 14:46:50 -0700506 hook_wait_init(&hks->hks_waiter, &hks->hks_lock);
507
508 mutex_enter(&hook_stack_lock);
509 SLIST_INSERT_HEAD(&hook_stacks, hks, hks_entry);
510 mutex_exit(&hook_stack_lock);
511
dh155122f4b3ec62007-01-19 16:59:38 -0800512 return (hks);
513}
514
Darren Reed8ad74182008-10-23 10:33:00 -0700515/*
Darren Reed4a9b8372010-04-26 17:05:56 -0700516 * Function: hook_stack_shutdown
517 * Returns: void
518 * Parameters: stackid(I) - identifier for the network instance that owns this
519 * arg(I) - pointer returned by hook_stack_init
520 *
Darren Reed8ad74182008-10-23 10:33:00 -0700521 * Set the shutdown flag to indicate that we should stop accepting new
Darren Reed4a9b8372010-04-26 17:05:56 -0700522 * register calls as we're now in the cleanup process. The cleanup is a
523 * two stage process and we're not required to free any memory here.
524 *
525 * The curious would wonder why isn't there any code that walks through
526 * all of the data structures and sets the flag(s) there? The answer is
527 * that it is expected that this will happen when the zone shutdown calls
528 * the shutdown callbacks for other modules that they will initiate the
Rob Gulewich652fb502013-10-31 00:30:55 +0000529 * free'ing and shutdown of the hooks themselves.
Darren Reed8ad74182008-10-23 10:33:00 -0700530 */
Darren Reed7ddc9b12008-09-08 14:46:50 -0700531/*ARGSUSED*/
532static void
533hook_stack_shutdown(netstackid_t stackid, void *arg)
534{
535 hook_stack_t *hks = (hook_stack_t *)arg;
536
537 mutex_enter(&hook_stack_lock);
538 /*
539 * Once this flag gets set to one, no more additions are allowed
540 * to any of the structures that make up this stack.
541 */
542 hks->hks_shutdown = 1;
543 mutex_exit(&hook_stack_lock);
544}
545
dh155122f4b3ec62007-01-19 16:59:38 -0800546/*
Darren Reed4a9b8372010-04-26 17:05:56 -0700547 * Function: hook_stack_destroy
548 * Returns: void
549 * Parameters: stackid(I) - identifier for the network instance that owns this
550 * arg(I) - pointer returned by hook_stack_init
551 *
dh155122f4b3ec62007-01-19 16:59:38 -0800552 * Free the hook stack instance.
Darren Reed4a9b8372010-04-26 17:05:56 -0700553 *
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.
dh155122f4b3ec62007-01-19 16:59:38 -0800558 */
559/*ARGSUSED*/
560static void
561hook_stack_fini(netstackid_t stackid, void *arg)
562{
Darren Reed7ddc9b12008-09-08 14:46:50 -0700563 hook_stack_t *hks = (hook_stack_t *)arg;
564
565 mutex_enter(&hook_stack_lock);
566 hks->hks_shutdown = 2;
567 hook_stack_remove(hks);
568 mutex_exit(&hook_stack_lock);
569}
570
571/*
Darren Reed4a9b8372010-04-26 17:05:56 -0700572 * Function: hook_stack_remove
573 * Returns: void
574 * Parameters: hks(I) - pointer to an instance of a hook_stack_t
575 *
Darren Reed7ddc9b12008-09-08 14:46:50 -0700576 * This function assumes that it is called with hook_stack_lock held.
577 * It functions differently to hook_family/event_remove in that it does
578 * the checks to see if it can be removed. This difference exists
579 * because this structure has nothing higher up that depends on it.
580 */
581static void
582hook_stack_remove(hook_stack_t *hks)
583{
584
585 ASSERT(mutex_owned(&hook_stack_lock));
586
587 /*
588 * Is the structure still in use?
589 */
590 if (!SLIST_EMPTY(&hks->hks_familylist) ||
591 !TAILQ_EMPTY(&hks->hks_nhead))
592 return;
593
594 SLIST_REMOVE(&hook_stacks, hks, hook_stack, hks_entry);
595
Darren Reed4a9b8372010-04-26 17:05:56 -0700596 VERIFY(hook_wait_destroy(&hks->hks_waiter) == 0);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700597 CVW_DESTROY(&hks->hks_lock);
dh155122f4b3ec62007-01-19 16:59:38 -0800598 kmem_free(hks, sizeof (*hks));
599}
dr146992381a2a92006-10-20 16:37:58 -0700600
Darren Reed4a9b8372010-04-26 17:05:56 -0700601/*
602 * Function: hook_stack_get
603 * Returns: hook_stack_t * - NULL if not found, else matching instance
604 * Parameters: stackid(I) - instance id to search for
605 *
606 * Search the list of currently active hook_stack_t structures for one that
607 * has a matching netstackid_t to the value passed in. The linked list can
608 * only ever have at most one match for this value.
609 */
Darren Reed7ddc9b12008-09-08 14:46:50 -0700610static hook_stack_t *
611hook_stack_get(netstackid_t stackid)
612{
613 hook_stack_t *hks;
614
615 SLIST_FOREACH(hks, &hook_stacks, hks_entry) {
616 if (hks->hks_netstackid == stackid)
617 break;
618 }
619
620 return (hks);
621}
622
623/*
624 * Function: hook_stack_notify_register
Darren Reed4a9b8372010-04-26 17:05:56 -0700625 * Returns: int - 0 = success, else failure
Darren Reed7ddc9b12008-09-08 14:46:50 -0700626 * Parameters: stackid(I) - netstack identifier
627 * callback(I)- function to be called
628 * arg(I) - arg to provide callback when it is called
629 *
630 * If we're not shutting down this instance, append a new function to the
631 * list of those to call when a new family of hooks is added to this stack.
Darren Reed4a9b8372010-04-26 17:05:56 -0700632 * 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.)
Darren Reed7ddc9b12008-09-08 14:46:50 -0700637 */
638int
639hook_stack_notify_register(netstackid_t stackid, hook_notify_fn_t callback,
640 void *arg)
641{
Darren Reed4a9b8372010-04-26 17:05:56 -0700642 hook_family_int_t *hfi;
Darren Reed7ddc9b12008-09-08 14:46:50 -0700643 hook_stack_t *hks;
Darren Reed4a9b8372010-04-26 17:05:56 -0700644 boolean_t canrun;
645 char buffer[16];
Darren Reed7ddc9b12008-09-08 14:46:50 -0700646 int error;
647
Darren Reed4a9b8372010-04-26 17:05:56 -0700648 ASSERT(callback != NULL);
649
650 canrun = B_FALSE;
Darren Reed7ddc9b12008-09-08 14:46:50 -0700651 mutex_enter(&hook_stack_lock);
652 hks = hook_stack_get(stackid);
653 if (hks != NULL) {
654 if (hks->hks_shutdown != 0) {
655 error = ESHUTDOWN;
656 } else {
Darren Reed4a9b8372010-04-26 17:05:56 -0700657 CVW_ENTER_WRITE(&hks->hks_lock);
658 canrun = (hook_wait_setflag(&hks->hks_waiter,
659 FWF_ADD_WAIT_MASK, FWF_ADD_WANTED,
660 FWF_ADD_ACTIVE) != -1);
661 error = hook_notify_register(&hks->hks_nhead,
662 callback, arg);
663 CVW_EXIT_WRITE(&hks->hks_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700664 }
665 } else {
666 error = ESRCH;
667 }
668 mutex_exit(&hook_stack_lock);
669
Darren Reed4a9b8372010-04-26 17:05:56 -0700670 if (error == 0 && canrun) {
671 /*
672 * Generate fake register event for callback that
673 * is being added, letting it know everything that
674 * already exists.
675 */
676 (void) snprintf(buffer, sizeof (buffer), "%u",
677 hks->hks_netstackid);
678
679 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
680 if (hfi->hfi_condemned || hfi->hfi_shutdown)
681 continue;
682 callback(HN_REGISTER, arg, buffer, NULL,
683 hfi->hfi_family.hf_name);
684 }
685 }
686
687 if (canrun)
688 hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE);
689
Darren Reed7ddc9b12008-09-08 14:46:50 -0700690 return (error);
691}
692
693/*
694 * Function: hook_stack_notify_unregister
Darren Reed4a9b8372010-04-26 17:05:56 -0700695 * Returns: int - 0 = success, else failure
696 * Parameters: stackid(I) - netstack identifier
Darren Reed7ddc9b12008-09-08 14:46:50 -0700697 * callback(I) - function to be called
698 *
699 * Attempt to remove a registered function from a hook stack's list of
700 * callbacks to activiate when protocols are added/deleted.
Darren Reed4a9b8372010-04-26 17:05:56 -0700701 * 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.
Darren Reed7ddc9b12008-09-08 14:46:50 -0700704 */
705int
706hook_stack_notify_unregister(netstackid_t stackid, hook_notify_fn_t callback)
707{
Darren Reed4a9b8372010-04-26 17:05:56 -0700708 hook_family_int_t *hfi;
Darren Reed7ddc9b12008-09-08 14:46:50 -0700709 hook_stack_t *hks;
Darren Reed4a9b8372010-04-26 17:05:56 -0700710 char buffer[16];
711 void *arg;
Darren Reed7ddc9b12008-09-08 14:46:50 -0700712 int error;
713
714 mutex_enter(&hook_stack_lock);
715 hks = hook_stack_get(stackid);
Jason King68c34d02018-10-22 00:53:14 +0000716 if (hks == NULL) {
717 mutex_exit(&hook_stack_lock);
718 return (ESRCH);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700719 }
Jason King68c34d02018-10-22 00:53:14 +0000720
721 CVW_ENTER_WRITE(&hks->hks_lock);
722 /*
723 * If hook_wait_setflag returns -1, another thread has flagged that it
724 * is attempting to destroy this hook stack. Before it can flag that
725 * it's destroying the hook stack, it must first verify (with
726 * hook_stack_lock held) that the hook stack is empty. If we
727 * encounter this, it means we should have nothing to do and we
728 * just snuck in.
729 */
730 if (hook_wait_setflag(&hks->hks_waiter, FWF_DEL_WAIT_MASK,
731 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
732 VERIFY(TAILQ_EMPTY(&hks->hks_nhead));
733 CVW_EXIT_WRITE(&hks->hks_lock);
734 mutex_exit(&hook_stack_lock);
735 return (ESRCH);
736 }
737
738 error = hook_notify_unregister(&hks->hks_nhead, callback, &arg);
739 CVW_EXIT_WRITE(&hks->hks_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700740 mutex_exit(&hook_stack_lock);
741
Darren Reed4a9b8372010-04-26 17:05:56 -0700742 if (error == 0) {
Jason King68c34d02018-10-22 00:53:14 +0000743 /*
744 * Generate fake unregister event for callback that
745 * is being removed, letting it know everything that
746 * currently exists is now "disappearing."
747 */
748 (void) snprintf(buffer, sizeof (buffer), "%u",
749 hks->hks_netstackid);
Darren Reed4a9b8372010-04-26 17:05:56 -0700750
Jason King68c34d02018-10-22 00:53:14 +0000751 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
752 callback(HN_UNREGISTER, arg, buffer, NULL,
753 hfi->hfi_family.hf_name);
Darren Reed4a9b8372010-04-26 17:05:56 -0700754 }
Jason King68c34d02018-10-22 00:53:14 +0000755 } else {
756 /*
757 * hook_notify_unregister() should only fail if the callback has
758 * already been deleted (ESRCH).
759 */
760 VERIFY3S(error, ==, ESRCH);
Darren Reed4a9b8372010-04-26 17:05:56 -0700761 }
762
Jason King68c34d02018-10-22 00:53:14 +0000763 mutex_enter(&hook_stack_lock);
764 hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE);
765 if (hks->hks_shutdown == 2)
766 hook_stack_remove(hks);
767 mutex_exit(&hook_stack_lock);
768
Darren Reed7ddc9b12008-09-08 14:46:50 -0700769 return (error);
770}
771
772/*
773 * Function: hook_stack_notify_run
774 * Returns: None
775 * Parameters: hks(I) - hook stack pointer to execute callbacks for
776 * name(I) - name of a hook family
777 * cmd(I) - either HN_UNREGISTER or HN_REGISTER
778 *
779 * Run through the list of callbacks on the hook stack to be called when
780 * a new hook family is added
781 *
Darren Reed4a9b8372010-04-26 17:05:56 -0700782 * 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.
Darren Reed7ddc9b12008-09-08 14:46:50 -0700787 */
788static void
789hook_stack_notify_run(hook_stack_t *hks, char *name,
790 hook_notify_cmd_t cmd)
791{
792 char buffer[16];
793
Darren Reed4a9b8372010-04-26 17:05:56 -0700794 ASSERT(hks != NULL);
795 ASSERT(name != NULL);
796
Darren Reed7ddc9b12008-09-08 14:46:50 -0700797 (void) snprintf(buffer, sizeof (buffer), "%u", hks->hks_netstackid);
798
799 hook_notify_run(&hks->hks_nhead, buffer, NULL, name, cmd);
800}
801
dr146992381a2a92006-10-20 16:37:58 -0700802/*
803 * Function: hook_run
Darren Reed4a9b8372010-04-26 17:05:56 -0700804 * Returns: int - return value according to callback func
dr146992381a2a92006-10-20 16:37:58 -0700805 * Parameters: token(I) - event pointer
Darren Reed4a9b8372010-04-26 17:05:56 -0700806 * info(I) - message
dr146992381a2a92006-10-20 16:37:58 -0700807 *
808 * Run hooks for specific provider. The hooks registered are stepped through
809 * until either the end of the list is reached or a hook function returns a
810 * non-zero value. If a non-zero value is returned from a hook function, we
811 * return that value back to our caller. By design, a hook function can be
812 * called more than once, simultaneously.
813 */
814int
Darren Reed7ddc9b12008-09-08 14:46:50 -0700815hook_run(hook_family_int_t *hfi, hook_event_token_t token, hook_data_t info)
dr146992381a2a92006-10-20 16:37:58 -0700816{
dr146992381a2a92006-10-20 16:37:58 -0700817 hook_event_int_t *hei;
Darren Reed7ddc9b12008-09-08 14:46:50 -0700818 hook_int_t *hi;
dr146992381a2a92006-10-20 16:37:58 -0700819 int rval = 0;
820
821 ASSERT(token != NULL);
822
823 hei = (hook_event_int_t *)token;
824 DTRACE_PROBE2(hook__run__start,
825 hook_event_token_t, token,
826 hook_data_t, info);
827
Darren Reed7ddc9b12008-09-08 14:46:50 -0700828 /*
Darren Reed4a9b8372010-04-26 17:05:56 -0700829 * If we consider that this function is only called from within the
Rob Gulewich652fb502013-10-31 00:30:55 +0000830 * stack while an instance is currently active,
Darren Reed7ddc9b12008-09-08 14:46:50 -0700831 */
832 CVW_ENTER_READ(&hfi->hfi_lock);
dr146992381a2a92006-10-20 16:37:58 -0700833
834 TAILQ_FOREACH(hi, &hei->hei_head, hi_entry) {
835 ASSERT(hi->hi_hook.h_func != NULL);
836 DTRACE_PROBE3(hook__func__start,
837 hook_event_token_t, token,
838 hook_data_t, info,
839 hook_int_t *, hi);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700840 rval = (*hi->hi_hook.h_func)(token, info, hi->hi_hook.h_arg);
dr146992381a2a92006-10-20 16:37:58 -0700841 DTRACE_PROBE4(hook__func__end,
842 hook_event_token_t, token,
843 hook_data_t, info,
844 hook_int_t *, hi,
845 int, rval);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700846 hi->hi_kstats.hook_hits.value.ui64++;
dr146992381a2a92006-10-20 16:37:58 -0700847 if (rval != 0)
848 break;
849 }
850
Darren Reed7ddc9b12008-09-08 14:46:50 -0700851 hei->hei_kstats.events.value.ui64++;
852
853 CVW_EXIT_READ(&hfi->hfi_lock);
dr146992381a2a92006-10-20 16:37:58 -0700854
855 DTRACE_PROBE3(hook__run__end,
856 hook_event_token_t, token,
857 hook_data_t, info,
858 hook_int_t *, hi);
859
860 return (rval);
861}
862
dr146992381a2a92006-10-20 16:37:58 -0700863/*
864 * Function: hook_family_add
865 * Returns: internal family pointer - NULL = Fail
Darren Reed4a9b8372010-04-26 17:05:56 -0700866 * 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
dr146992381a2a92006-10-20 16:37:58 -0700869 *
Darren Reed4a9b8372010-04-26 17:05:56 -0700870 * 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.
dr146992381a2a92006-10-20 16:37:58 -0700880 */
881hook_family_int_t *
Darren Reed4a9b8372010-04-26 17:05:56 -0700882hook_family_add(hook_family_t *hf, hook_stack_t *hks, void **store)
dr146992381a2a92006-10-20 16:37:58 -0700883{
884 hook_family_int_t *hfi, *new;
885
886 ASSERT(hf != NULL);
887 ASSERT(hf->hf_name != NULL);
888
889 new = hook_family_copy(hf);
890 if (new == NULL)
891 return (NULL);
892
Darren Reed7ddc9b12008-09-08 14:46:50 -0700893 mutex_enter(&hook_stack_lock);
894 CVW_ENTER_WRITE(&hks->hks_lock);
895
896 if (hks->hks_shutdown != 0) {
897 CVW_EXIT_WRITE(&hks->hks_lock);
898 mutex_exit(&hook_stack_lock);
899 hook_family_free(new, NULL);
900 return (NULL);
901 }
dr146992381a2a92006-10-20 16:37:58 -0700902
903 /* search family list */
dh155122f4b3ec62007-01-19 16:59:38 -0800904 hfi = hook_family_find(hf->hf_name, hks);
dr146992381a2a92006-10-20 16:37:58 -0700905 if (hfi != NULL) {
Darren Reed7ddc9b12008-09-08 14:46:50 -0700906 CVW_EXIT_WRITE(&hks->hks_lock);
907 mutex_exit(&hook_stack_lock);
908 hook_family_free(new, NULL);
dr146992381a2a92006-10-20 16:37:58 -0700909 return (NULL);
910 }
911
Darren Reed4a9b8372010-04-26 17:05:56 -0700912 /*
913 * Try and set the FWF_ADD_ACTIVE flag so that we can drop all the
914 * lock further down when calling all of the functions registered
915 * for notification when a new hook family is added.
916 */
917 if (hook_wait_setflag(&hks->hks_waiter, FWF_ADD_WAIT_MASK,
Darren Reed7ddc9b12008-09-08 14:46:50 -0700918 FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) {
919 CVW_EXIT_WRITE(&hks->hks_lock);
920 mutex_exit(&hook_stack_lock);
921 hook_family_free(new, NULL);
922 return (NULL);
923 }
924
925 CVW_INIT(&new->hfi_lock);
926 SLIST_INIT(&new->hfi_head);
927 TAILQ_INIT(&new->hfi_nhead);
928
929 hook_wait_init(&new->hfi_waiter, &new->hfi_lock);
930
931 new->hfi_stack = hks;
Darren Reed4a9b8372010-04-26 17:05:56 -0700932 if (store != NULL)
933 *store = new;
dr146992381a2a92006-10-20 16:37:58 -0700934
dh155122f4b3ec62007-01-19 16:59:38 -0800935 /* Add to family list head */
936 SLIST_INSERT_HEAD(&hks->hks_familylist, new, hfi_entry);
937
Darren Reed7ddc9b12008-09-08 14:46:50 -0700938 CVW_EXIT_WRITE(&hks->hks_lock);
939 mutex_exit(&hook_stack_lock);
940
941 hook_stack_notify_run(hks, hf->hf_name, HN_REGISTER);
942
943 hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE);
944
dr146992381a2a92006-10-20 16:37:58 -0700945 return (new);
946}
947
dr146992381a2a92006-10-20 16:37:58 -0700948/*
949 * Function: hook_family_remove
Darren Reed4a9b8372010-04-26 17:05:56 -0700950 * Returns: int - 0 = success, else = failure
dr146992381a2a92006-10-20 16:37:58 -0700951 * Parameters: hfi(I) - internal family pointer
952 *
Darren Reed7ddc9b12008-09-08 14:46:50 -0700953 * 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.
dr146992381a2a92006-10-20 16:37:58 -0700956 */
957int
958hook_family_remove(hook_family_int_t *hfi)
959{
dh155122f4b3ec62007-01-19 16:59:38 -0800960 hook_stack_t *hks;
Darren Reed8ad74182008-10-23 10:33:00 -0700961 boolean_t notifydone;
dr146992381a2a92006-10-20 16:37:58 -0700962
963 ASSERT(hfi != NULL);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700964 hks = hfi->hfi_stack;
dr146992381a2a92006-10-20 16:37:58 -0700965
Darren Reed4a9b8372010-04-26 17:05:56 -0700966 CVW_ENTER_WRITE(&hfi->hfi_lock);
967 notifydone = hfi->hfi_shutdown;
968 hfi->hfi_shutdown = B_TRUE;
969 CVW_EXIT_WRITE(&hfi->hfi_lock);
970
Darren Reed7ddc9b12008-09-08 14:46:50 -0700971 CVW_ENTER_WRITE(&hks->hks_lock);
dr146992381a2a92006-10-20 16:37:58 -0700972
Darren Reed4a9b8372010-04-26 17:05:56 -0700973 if (hook_wait_setflag(&hks->hks_waiter, FWF_DEL_WAIT_MASK,
Darren Reed7ddc9b12008-09-08 14:46:50 -0700974 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
975 /*
976 * If we're trying to destroy the hook_stack_t...
977 */
Darren Reed8ad74182008-10-23 10:33:00 -0700978 CVW_EXIT_WRITE(&hks->hks_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700979 return (ENXIO);
dr146992381a2a92006-10-20 16:37:58 -0700980 }
981
Darren Reed7ddc9b12008-09-08 14:46:50 -0700982 /*
983 * Check if the family is in use by the presence of either events
984 * or notify callbacks on the hook family.
985 */
986 if (!SLIST_EMPTY(&hfi->hfi_head) || !TAILQ_EMPTY(&hfi->hfi_nhead)) {
987 hfi->hfi_condemned = B_TRUE;
988 } else {
Darren Reed4a9b8372010-04-26 17:05:56 -0700989 VERIFY(hook_wait_destroy(&hfi->hfi_waiter) == 0);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700990 /*
991 * Although hfi_condemned = B_FALSE is implied from creation,
992 * putting a comment here inside the else upsets lint.
993 */
994 hfi->hfi_condemned = B_FALSE;
995 }
Darren Reed7ddc9b12008-09-08 14:46:50 -0700996 CVW_EXIT_WRITE(&hks->hks_lock);
997
Darren Reed8ad74182008-10-23 10:33:00 -0700998 if (!notifydone)
999 hook_stack_notify_run(hks, hfi->hfi_family.hf_name,
1000 HN_UNREGISTER);
Darren Reed7ddc9b12008-09-08 14:46:50 -07001001
1002 hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE);
1003
1004 /*
1005 * If we don't have to wait for anything else to disappear from this
1006 * structure then we can free it up.
1007 */
1008 if (!hfi->hfi_condemned)
1009 hook_family_free(hfi, hks);
dr146992381a2a92006-10-20 16:37:58 -07001010
1011 return (0);
1012}
1013
1014
1015/*
Darren Reed7ddc9b12008-09-08 14:46:50 -07001016 * Function: hook_family_free
1017 * Returns: None
1018 * Parameters: hfi(I) - internal family pointer
1019 *
1020 * Free alloc memory for family
1021 */
1022static void
1023hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks)
1024{
1025
1026 /*
1027 * This lock gives us possession of the hks pointer after the
1028 * SLIST_REMOVE, for which it is not needed, when hks_shutdown
1029 * is checked and hook_stack_remove called.
1030 */
1031 mutex_enter(&hook_stack_lock);
1032
1033 ASSERT(hfi != NULL);
1034
1035 if (hks != NULL) {
1036 CVW_ENTER_WRITE(&hks->hks_lock);
1037 /* Remove from family list */
1038 SLIST_REMOVE(&hks->hks_familylist, hfi, hook_family_int,
1039 hfi_entry);
1040
1041 CVW_EXIT_WRITE(&hks->hks_lock);
1042 }
1043
1044 /* Free name space */
1045 if (hfi->hfi_family.hf_name != NULL) {
1046 kmem_free(hfi->hfi_family.hf_name,
1047 strlen(hfi->hfi_family.hf_name) + 1);
1048 }
1049
1050 /* Free container */
1051 kmem_free(hfi, sizeof (*hfi));
1052
1053 if (hks->hks_shutdown == 2)
1054 hook_stack_remove(hks);
1055
1056 mutex_exit(&hook_stack_lock);
1057}
1058
Darren Reed8ad74182008-10-23 10:33:00 -07001059/*
1060 * Function: hook_family_shutdown
Darren Reed4a9b8372010-04-26 17:05:56 -07001061 * Returns: int - 0 = success, else = failure
Darren Reed8ad74182008-10-23 10:33:00 -07001062 * Parameters: hfi(I) - internal family pointer
1063 *
1064 * As an alternative to removing a family, we may desire to just generate
1065 * a series of callbacks to indicate that we will be going away in the
1066 * future. The hfi_condemned flag isn't set because we aren't trying to
1067 * remove the structure.
1068 */
1069int
1070hook_family_shutdown(hook_family_int_t *hfi)
1071{
1072 hook_stack_t *hks;
1073 boolean_t notifydone;
1074
1075 ASSERT(hfi != NULL);
1076 hks = hfi->hfi_stack;
1077
Darren Reed4a9b8372010-04-26 17:05:56 -07001078 CVW_ENTER_WRITE(&hfi->hfi_lock);
1079 notifydone = hfi->hfi_shutdown;
1080 hfi->hfi_shutdown = B_TRUE;
1081 CVW_EXIT_WRITE(&hfi->hfi_lock);
1082
Darren Reed8ad74182008-10-23 10:33:00 -07001083 CVW_ENTER_WRITE(&hks->hks_lock);
1084
Darren Reed4a9b8372010-04-26 17:05:56 -07001085 if (hook_wait_setflag(&hks->hks_waiter, FWF_DEL_WAIT_MASK,
Darren Reed8ad74182008-10-23 10:33:00 -07001086 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
1087 /*
1088 * If we're trying to destroy the hook_stack_t...
1089 */
1090 CVW_EXIT_WRITE(&hks->hks_lock);
1091 return (ENXIO);
1092 }
1093
Darren Reed8ad74182008-10-23 10:33:00 -07001094 CVW_EXIT_WRITE(&hks->hks_lock);
1095
1096 if (!notifydone)
1097 hook_stack_notify_run(hks, hfi->hfi_family.hf_name,
1098 HN_UNREGISTER);
1099
1100 hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE);
1101
1102 return (0);
1103}
Darren Reed7ddc9b12008-09-08 14:46:50 -07001104
1105/*
dr146992381a2a92006-10-20 16:37:58 -07001106 * Function: hook_family_copy
1107 * Returns: internal family pointer - NULL = Failed
1108 * Parameters: src(I) - family pointer
1109 *
1110 * Allocate internal family block and duplicate incoming family
1111 * No locks should be held across this function as it may sleep.
1112 */
1113static hook_family_int_t *
1114hook_family_copy(hook_family_t *src)
1115{
1116 hook_family_int_t *new;
1117 hook_family_t *dst;
1118
1119 ASSERT(src != NULL);
1120 ASSERT(src->hf_name != NULL);
1121
1122 new = (hook_family_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
1123
1124 /* Copy body */
dr146992381a2a92006-10-20 16:37:58 -07001125 dst = &new->hfi_family;
1126 *dst = *src;
1127
Darren Reed7ddc9b12008-09-08 14:46:50 -07001128 SLIST_INIT(&new->hfi_head);
1129 TAILQ_INIT(&new->hfi_nhead);
1130
dr146992381a2a92006-10-20 16:37:58 -07001131 /* Copy name */
1132 dst->hf_name = (char *)kmem_alloc(strlen(src->hf_name) + 1, KM_SLEEP);
1133 (void) strcpy(dst->hf_name, src->hf_name);
1134
1135 return (new);
1136}
1137
dr146992381a2a92006-10-20 16:37:58 -07001138/*
Darren Reed7ddc9b12008-09-08 14:46:50 -07001139 * Function: hook_family_find
dr146992381a2a92006-10-20 16:37:58 -07001140 * Returns: internal family pointer - NULL = Not match
1141 * Parameters: family(I) - family name string
1142 *
1143 * Search family list with family name
Jason King68c34d02018-10-22 00:53:14 +00001144 * A lock on hfi_lock must be held when called.
dr146992381a2a92006-10-20 16:37:58 -07001145 */
1146static hook_family_int_t *
dh155122f4b3ec62007-01-19 16:59:38 -08001147hook_family_find(char *family, hook_stack_t *hks)
dr146992381a2a92006-10-20 16:37:58 -07001148{
1149 hook_family_int_t *hfi = NULL;
1150
1151 ASSERT(family != NULL);
1152
dh155122f4b3ec62007-01-19 16:59:38 -08001153 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
dr146992381a2a92006-10-20 16:37:58 -07001154 if (strcmp(hfi->hfi_family.hf_name, family) == 0)
1155 break;
1156 }
1157 return (hfi);
1158}
1159
dr146992381a2a92006-10-20 16:37:58 -07001160/*
Darren Reed7ddc9b12008-09-08 14:46:50 -07001161 * Function: hook_family_notify_register
Darren Reed4a9b8372010-04-26 17:05:56 -07001162 * Returns: int - 0 = success, else failure
Darren Reed7ddc9b12008-09-08 14:46:50 -07001163 * Parameters: hfi(I) - hook family
1164 * callback(I) - function to be called
1165 * arg(I) - arg to provide callback when it is called
dr146992381a2a92006-10-20 16:37:58 -07001166 *
Darren Reed7ddc9b12008-09-08 14:46:50 -07001167 * So long as this hook stack isn't being shut down, register a new
1168 * callback to be activated each time a new event is added to this
1169 * family.
1170 *
1171 * To call this function we must have an active handle in use on the family,
1172 * so if we take this into account, then neither the hook_family_int_t nor
1173 * the hook_stack_t that owns it can disappear. We have to put some trust
1174 * in the callers to be properly synchronised...
1175 *
1176 * Holding hks_lock is required to provide synchronisation for hks_shutdown.
dr146992381a2a92006-10-20 16:37:58 -07001177 */
Darren Reed7ddc9b12008-09-08 14:46:50 -07001178int
1179hook_family_notify_register(hook_family_int_t *hfi,
1180 hook_notify_fn_t callback, void *arg)
dr146992381a2a92006-10-20 16:37:58 -07001181{
Darren Reed4a9b8372010-04-26 17:05:56 -07001182 hook_event_int_t *hei;
Darren Reed7ddc9b12008-09-08 14:46:50 -07001183 hook_stack_t *hks;
Darren Reed4a9b8372010-04-26 17:05:56 -07001184 boolean_t canrun;
Darren Reed7ddc9b12008-09-08 14:46:50 -07001185 int error;
dr146992381a2a92006-10-20 16:37:58 -07001186
Darren Reed4a9b8372010-04-26 17:05:56 -07001187 ASSERT(hfi != NULL);
1188 canrun = B_FALSE;
Darren Reed7ddc9b12008-09-08 14:46:50 -07001189 hks = hfi->hfi_stack;
1190
1191 CVW_ENTER_READ(&hks->hks_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -07001192
Darren Reed8ad74182008-10-23 10:33:00 -07001193 if ((hfi->hfi_stack->hks_shutdown != 0) ||
1194 hfi->hfi_condemned || hfi->hfi_shutdown) {
Darren Reed7ddc9b12008-09-08 14:46:50 -07001195 CVW_EXIT_READ(&hks->hks_lock);
1196 return (ESHUTDOWN);
dr146992381a2a92006-10-20 16:37:58 -07001197 }
1198
Darren Reed4a9b8372010-04-26 17:05:56 -07001199 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);
Darren Reed7ddc9b12008-09-08 14:46:50 -07001203 CVW_EXIT_WRITE(&hfi->hfi_lock);
Darren Reed4a9b8372010-04-26 17:05:56 -07001204
Darren Reed7ddc9b12008-09-08 14:46:50 -07001205 CVW_EXIT_READ(&hks->hks_lock);
1206
Darren Reed4a9b8372010-04-26 17:05:56 -07001207 if (error == 0 && canrun) {
1208 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
1209 callback(HN_REGISTER, arg,
1210 hfi->hfi_family.hf_name, NULL,
1211 hei->hei_event->he_name);
1212 }
1213 }
1214
1215 if (canrun)
1216 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_ADD_ACTIVE);
1217
Darren Reed7ddc9b12008-09-08 14:46:50 -07001218 return (error);
dr146992381a2a92006-10-20 16:37:58 -07001219}
1220
Darren Reed7ddc9b12008-09-08 14:46:50 -07001221/*
1222 * Function: hook_family_notify_unregister
Darren Reed4a9b8372010-04-26 17:05:56 -07001223 * Returns: int - 0 = success, else failure
Darren Reed7ddc9b12008-09-08 14:46:50 -07001224 * Parameters: hfi(I) - hook family
1225 * callback(I) - function to be called
1226 *
1227 * Remove a callback from the list of those executed when a new event is
Darren Reed4a9b8372010-04-26 17:05:56 -07001228 * added to a hook family. If the family is not in the process of being
1229 * destroyed then simulate an unregister callback for each event that is
1230 * on the family. This pairs up with the hook_family_notify_register
1231 * action that simulates register events.
1232 * The order of what happens here is important and goes like this.
1233 * 1) Remove the callback from the list of functions to be called as part
1234 * of the notify operation when an event is added or removed from the
1235 * hook family.
1236 * 2) If the hook_family_int_t structure is on death row (free_family will
1237 * be set to true) then there's nothing else to do than let it be free'd.
1238 * 3) If the structure isn't about to die, mark it up as being busy using
1239 * hook_wait_setflag and then drop the lock so the loop can be run.
1240 * 4) if hook_wait_setflag was successful, tell all of the notify callback
1241 * functions that this family has been unregistered.
1242 * 5) Cleanup
Darren Reed7ddc9b12008-09-08 14:46:50 -07001243 */
1244int
1245hook_family_notify_unregister(hook_family_int_t *hfi,
1246 hook_notify_fn_t callback)
1247{
Darren Reed4a9b8372010-04-26 17:05:56 -07001248 hook_event_int_t *hei;
Darren Reed7ddc9b12008-09-08 14:46:50 -07001249 boolean_t free_family;
Darren Reed4a9b8372010-04-26 17:05:56 -07001250 boolean_t canrun;
Darren Reed7ddc9b12008-09-08 14:46:50 -07001251 int error;
Darren Reed4a9b8372010-04-26 17:05:56 -07001252 void *arg;
1253
1254 canrun = B_FALSE;
Darren Reed7ddc9b12008-09-08 14:46:50 -07001255
1256 CVW_ENTER_WRITE(&hfi->hfi_lock);
1257
Darren Reed4a9b8372010-04-26 17:05:56 -07001258 (void) hook_wait_setflag(&hfi->hfi_waiter, FWF_DEL_WAIT_MASK,
1259 FWF_DEL_WANTED, FWF_DEL_ACTIVE);
1260
1261 error = hook_notify_unregister(&hfi->hfi_nhead, callback, &arg);
1262
1263 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
Darren Reed7ddc9b12008-09-08 14:46:50 -07001264
1265 /*
1266 * If hook_family_remove has been called but the structure was still
1267 * "busy" ... but we might have just made it "unbusy"...
1268 */
1269 if ((error == 0) && hfi->hfi_condemned &&
1270 SLIST_EMPTY(&hfi->hfi_head) && TAILQ_EMPTY(&hfi->hfi_nhead)) {
1271 free_family = B_TRUE;
1272 } else {
1273 free_family = B_FALSE;
1274 }
1275
Darren Reed4a9b8372010-04-26 17:05:56 -07001276 if (error == 0 && !free_family) {
1277 canrun = (hook_wait_setflag(&hfi->hfi_waiter, FWF_ADD_WAIT_MASK,
1278 FWF_ADD_WANTED, FWF_ADD_ACTIVE) != -1);
1279 }
1280
Darren Reed7ddc9b12008-09-08 14:46:50 -07001281 CVW_EXIT_WRITE(&hfi->hfi_lock);
1282
Darren Reed4a9b8372010-04-26 17:05:56 -07001283 if (canrun) {
1284 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
1285 callback(HN_UNREGISTER, arg,
1286 hfi->hfi_family.hf_name, NULL,
1287 hei->hei_event->he_name);
1288 }
1289
1290 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_ADD_ACTIVE);
1291 } else if (free_family) {
Darren Reed7ddc9b12008-09-08 14:46:50 -07001292 hook_family_free(hfi, hfi->hfi_stack);
Darren Reed4a9b8372010-04-26 17:05:56 -07001293 }
Darren Reed7ddc9b12008-09-08 14:46:50 -07001294
1295 return (error);
1296}
dr146992381a2a92006-10-20 16:37:58 -07001297
1298/*
1299 * Function: hook_event_add
1300 * Returns: internal event pointer - NULL = Fail
1301 * Parameters: hfi(I) - internal family pointer
Darren Reed4a9b8372010-04-26 17:05:56 -07001302 * he(I) - event pointer
dr146992381a2a92006-10-20 16:37:58 -07001303 *
1304 * Add new event to event list on specific family.
1305 * This function can fail to return successfully if (1) it cannot allocate
1306 * enough memory for its own internal data structures, (2) the event has
1307 * already been registered (for any hook family.)
1308 */
1309hook_event_int_t *
1310hook_event_add(hook_family_int_t *hfi, hook_event_t *he)
1311{
1312 hook_event_int_t *hei, *new;
Darren Reed7ddc9b12008-09-08 14:46:50 -07001313 hook_stack_t *hks;
dr146992381a2a92006-10-20 16:37:58 -07001314
1315 ASSERT(hfi != NULL);
1316 ASSERT(he != NULL);
1317 ASSERT(he->he_name != NULL);
1318
1319 new = hook_event_copy(he);
1320 if (new == NULL)
1321 return (NULL);
1322
Darren Reed7ddc9b12008-09-08 14:46:50 -07001323 hks = hfi->hfi_stack;
1324 CVW_ENTER_READ(&hks->hks_lock);
1325
1326 hks = hfi->hfi_stack;
1327 if (hks->hks_shutdown != 0) {
1328 CVW_EXIT_READ(&hks->hks_lock);
1329 hook_event_free(new, NULL);
1330 return (NULL);
1331 }
dr146992381a2a92006-10-20 16:37:58 -07001332
1333 /* Check whether this event pointer is already registered */
dh155122f4b3ec62007-01-19 16:59:38 -08001334 hei = hook_event_checkdup(he, hks);
dr146992381a2a92006-10-20 16:37:58 -07001335 if (hei != NULL) {
Darren Reed7ddc9b12008-09-08 14:46:50 -07001336 CVW_EXIT_READ(&hks->hks_lock);
1337 hook_event_free(new, NULL);
dr146992381a2a92006-10-20 16:37:58 -07001338 return (NULL);
1339 }
1340
Darren Reed7ddc9b12008-09-08 14:46:50 -07001341 CVW_ENTER_WRITE(&hfi->hfi_lock);
1342
Darren Reed8ad74182008-10-23 10:33:00 -07001343 if (hfi->hfi_condemned || hfi->hfi_shutdown) {
Darren Reed7ddc9b12008-09-08 14:46:50 -07001344 CVW_EXIT_WRITE(&hfi->hfi_lock);
1345 CVW_EXIT_READ(&hks->hks_lock);
1346 hook_event_free(new, NULL);
1347 return (NULL);
1348 }
Darren Reed4a9b8372010-04-26 17:05:56 -07001349 CVW_EXIT_READ(&hks->hks_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -07001350
Darren Reed4a9b8372010-04-26 17:05:56 -07001351 if (hook_wait_setflag(&hfi->hfi_waiter, FWF_ADD_WAIT_MASK,
Darren Reed7ddc9b12008-09-08 14:46:50 -07001352 FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) {
1353 CVW_EXIT_WRITE(&hfi->hfi_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -07001354 hook_event_free(new, NULL);
1355 return (NULL);
1356 }
1357
1358 TAILQ_INIT(&new->hei_nhead);
1359
1360 hook_event_init_kstats(hfi, new);
1361 hook_wait_init(&new->hei_waiter, &new->hei_lock);
1362
dr146992381a2a92006-10-20 16:37:58 -07001363 /* Add to event list head */
1364 SLIST_INSERT_HEAD(&hfi->hfi_head, new, hei_entry);
1365
Darren Reed7ddc9b12008-09-08 14:46:50 -07001366 CVW_EXIT_WRITE(&hfi->hfi_lock);
1367
Darren Reed7ddc9b12008-09-08 14:46:50 -07001368 hook_notify_run(&hfi->hfi_nhead,
1369 hfi->hfi_family.hf_name, NULL, he->he_name, HN_REGISTER);
1370
1371 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_ADD_ACTIVE);
1372
dr146992381a2a92006-10-20 16:37:58 -07001373 return (new);
1374}
1375
Darren Reed7ddc9b12008-09-08 14:46:50 -07001376/*
1377 * Function: hook_event_init_kstats
1378 * Returns: None
1379 * Parameters: hfi(I) - pointer to the family that owns this event.
1380 * hei(I) - pointer to the hook event that needs some kstats.
1381 *
1382 * Create a set of kstats that relate to each event registered with
1383 * the hook framework. A counter is kept for each time the event is
1384 * activated and for each time a hook is added or removed. As the
1385 * kstats just count the events as they happen, the total number of
1386 * hooks registered must be obtained by subtractived removed from added.
1387 */
1388static void
1389hook_event_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei)
1390{
1391 hook_event_kstat_t template = {
1392 { "hooksAdded", KSTAT_DATA_UINT64 },
1393 { "hooksRemoved", KSTAT_DATA_UINT64 },
1394 { "events", KSTAT_DATA_UINT64 }
1395 };
1396 hook_stack_t *hks;
1397
1398 hks = hfi->hfi_stack;
1399 hei->hei_kstatp = kstat_create_netstack(hfi->hfi_family.hf_name, 0,
1400 hei->hei_event->he_name, "hook_event", KSTAT_TYPE_NAMED,
1401 sizeof (hei->hei_kstats) / sizeof (kstat_named_t),
1402 KSTAT_FLAG_VIRTUAL, hks->hks_netstackid);
1403
1404 bcopy((char *)&template, &hei->hei_kstats, sizeof (template));
1405
1406 if (hei->hei_kstatp != NULL) {
1407 hei->hei_kstatp->ks_data = (void *)&hei->hei_kstats;
1408 hei->hei_kstatp->ks_private =
1409 (void *)(uintptr_t)hks->hks_netstackid;
1410
1411 kstat_install(hei->hei_kstatp);
1412 }
1413}
dr146992381a2a92006-10-20 16:37:58 -07001414
1415/*
1416 * Function: hook_event_remove
Darren Reed4a9b8372010-04-26 17:05:56 -07001417 * Returns: int - 0 = success, else = failure
dr146992381a2a92006-10-20 16:37:58 -07001418 * Parameters: hfi(I) - internal family pointer
Darren Reed4a9b8372010-04-26 17:05:56 -07001419 * he(I) - event pointer
dr146992381a2a92006-10-20 16:37:58 -07001420 *
1421 * Remove event from event list on specific family
Darren Reed7ddc9b12008-09-08 14:46:50 -07001422 *
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.
dr146992381a2a92006-10-20 16:37:58 -07001428 */
1429int
1430hook_event_remove(hook_family_int_t *hfi, hook_event_t *he)
1431{
Darren Reed7ddc9b12008-09-08 14:46:50 -07001432 boolean_t free_family;
dr146992381a2a92006-10-20 16:37:58 -07001433 hook_event_int_t *hei;
Darren Reed8ad74182008-10-23 10:33:00 -07001434 boolean_t notifydone;
dr146992381a2a92006-10-20 16:37:58 -07001435
1436 ASSERT(hfi != NULL);
1437 ASSERT(he != NULL);
1438
Darren Reed7ddc9b12008-09-08 14:46:50 -07001439 CVW_ENTER_WRITE(&hfi->hfi_lock);
dr146992381a2a92006-10-20 16:37:58 -07001440
Darren Reed7ddc9b12008-09-08 14:46:50 -07001441 /*
1442 * Set the flag so that we can call hook_event_notify_run without
1443 * holding any locks but at the same time prevent other changes to
1444 * the event at the same time.
1445 */
Darren Reed4a9b8372010-04-26 17:05:56 -07001446 if (hook_wait_setflag(&hfi->hfi_waiter, FWF_DEL_WAIT_MASK,
Darren Reed7ddc9b12008-09-08 14:46:50 -07001447 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
1448 CVW_EXIT_WRITE(&hfi->hfi_lock);
dr146992381a2a92006-10-20 16:37:58 -07001449 return (ENXIO);
1450 }
1451
Darren Reed7ddc9b12008-09-08 14:46:50 -07001452 hei = hook_event_find(hfi, he->he_name);
1453 if (hei == NULL) {
1454 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
1455 CVW_EXIT_WRITE(&hfi->hfi_lock);
1456 return (ESRCH);
dr146992381a2a92006-10-20 16:37:58 -07001457 }
1458
Darren Reed7ddc9b12008-09-08 14:46:50 -07001459 free_family = B_FALSE;
dr146992381a2a92006-10-20 16:37:58 -07001460
Darren Reed7ddc9b12008-09-08 14:46:50 -07001461 CVW_ENTER_WRITE(&hei->hei_lock);
1462 /*
Darren Reed8ad74182008-10-23 10:33:00 -07001463 * The hei_shutdown flag is used to indicate whether or not we have
1464 * done a shutdown and thus already walked through the notify list.
1465 */
1466 notifydone = hei->hei_shutdown;
1467 hei->hei_shutdown = B_TRUE;
1468 /*
Darren Reed7ddc9b12008-09-08 14:46:50 -07001469 * If there are any hooks still registered for this event or
1470 * there are any notifiers registered, return an error indicating
1471 * that the event is still busy.
1472 */
1473 if (!TAILQ_EMPTY(&hei->hei_head) || !TAILQ_EMPTY(&hei->hei_nhead)) {
1474 hei->hei_condemned = B_TRUE;
1475 CVW_EXIT_WRITE(&hei->hei_lock);
1476 } else {
1477 /* hei_condemned = B_FALSE is implied from creation */
1478 /*
1479 * Even though we know the notify list is empty, we call
1480 * hook_wait_destroy here to synchronise wait removing a
1481 * hook from an event.
1482 */
Darren Reed4a9b8372010-04-26 17:05:56 -07001483 VERIFY(hook_wait_destroy(&hei->hei_waiter) == 0);
Darren Reed7ddc9b12008-09-08 14:46:50 -07001484
1485 CVW_EXIT_WRITE(&hei->hei_lock);
1486
1487 if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) &&
1488 TAILQ_EMPTY(&hfi->hfi_nhead))
1489 free_family = B_TRUE;
1490 }
1491
1492 CVW_EXIT_WRITE(&hfi->hfi_lock);
1493
Darren Reed8ad74182008-10-23 10:33:00 -07001494 if (!notifydone)
1495 hook_notify_run(&hfi->hfi_nhead,
1496 hfi->hfi_family.hf_name, NULL, he->he_name, HN_UNREGISTER);
Darren Reed7ddc9b12008-09-08 14:46:50 -07001497
1498 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
1499
1500 if (!hei->hei_condemned) {
1501 hook_event_free(hei, hfi);
1502 if (free_family)
1503 hook_family_free(hfi, hfi->hfi_stack);
1504 }
dr146992381a2a92006-10-20 16:37:58 -07001505
1506 return (0);
1507}
1508
Darren Reed7ddc9b12008-09-08 14:46:50 -07001509/*
Darren Reed8ad74182008-10-23 10:33:00 -07001510 * Function: hook_event_shutdown
Darren Reed4a9b8372010-04-26 17:05:56 -07001511 * Returns: int - 0 = success, else = failure
Darren Reed8ad74182008-10-23 10:33:00 -07001512 * Parameters: hfi(I) - internal family pointer
1513 * he(I) - event pointer
1514 *
1515 * As with hook_family_shutdown, we want to generate the notify callbacks
1516 * as if the event was being removed but not actually do the remove.
1517 */
1518int
1519hook_event_shutdown(hook_family_int_t *hfi, hook_event_t *he)
1520{
1521 hook_event_int_t *hei;
1522 boolean_t notifydone;
1523
1524 ASSERT(hfi != NULL);
1525 ASSERT(he != NULL);
1526
1527 CVW_ENTER_WRITE(&hfi->hfi_lock);
1528
1529 /*
1530 * Set the flag so that we can call hook_event_notify_run without
1531 * holding any locks but at the same time prevent other changes to
1532 * the event at the same time.
1533 */
Darren Reed4a9b8372010-04-26 17:05:56 -07001534 if (hook_wait_setflag(&hfi->hfi_waiter, FWF_DEL_WAIT_MASK,
Darren Reed8ad74182008-10-23 10:33:00 -07001535 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
1536 CVW_EXIT_WRITE(&hfi->hfi_lock);
1537 return (ENXIO);
1538 }
1539
1540 hei = hook_event_find(hfi, he->he_name);
1541 if (hei == NULL) {
1542 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
1543 CVW_EXIT_WRITE(&hfi->hfi_lock);
1544 return (ESRCH);
1545 }
1546
1547 CVW_ENTER_WRITE(&hei->hei_lock);
1548 notifydone = hei->hei_shutdown;
1549 hei->hei_shutdown = B_TRUE;
1550 CVW_EXIT_WRITE(&hei->hei_lock);
1551
1552 CVW_EXIT_WRITE(&hfi->hfi_lock);
1553
1554 if (!notifydone)
1555 hook_notify_run(&hfi->hfi_nhead,
1556 hfi->hfi_family.hf_name, NULL, he->he_name, HN_UNREGISTER);
1557
1558 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
1559
1560 return (0);
1561}
1562
1563/*
Darren Reed7ddc9b12008-09-08 14:46:50 -07001564 * Function: hook_event_free
1565 * Returns: None
1566 * Parameters: hei(I) - internal event pointer
1567 *
1568 * Free alloc memory for event
1569 */
1570static void
1571hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi)
1572{
1573 boolean_t free_family;
1574
1575 ASSERT(hei != NULL);
1576
1577 if (hfi != NULL) {
1578 CVW_ENTER_WRITE(&hfi->hfi_lock);
1579 /*
1580 * Remove the event from the hook family's list.
1581 */
1582 SLIST_REMOVE(&hfi->hfi_head, hei, hook_event_int, hei_entry);
1583 if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) &&
1584 TAILQ_EMPTY(&hfi->hfi_nhead)) {
1585 free_family = B_TRUE;
1586 } else {
1587 free_family = B_FALSE;
1588 }
1589 CVW_EXIT_WRITE(&hfi->hfi_lock);
1590 }
1591
1592 if (hei->hei_kstatp != NULL) {
1593 ASSERT(hfi != NULL);
1594
1595 kstat_delete_netstack(hei->hei_kstatp,
1596 hfi->hfi_stack->hks_netstackid);
1597 hei->hei_kstatp = NULL;
1598 }
1599
1600 /* Free container */
1601 kmem_free(hei, sizeof (*hei));
1602
1603 if (free_family)
1604 hook_family_free(hfi, hfi->hfi_stack);
1605}
dr146992381a2a92006-10-20 16:37:58 -07001606
1607/*
1608 * Function: hook_event_checkdup
1609 * Returns: internal event pointer - NULL = Not match
1610 * Parameters: he(I) - event pointer
1611 *
Darren Reed7ddc9b12008-09-08 14:46:50 -07001612 * Search all of the hook families to see if the event being passed in
1613 * has already been associated with one.
dr146992381a2a92006-10-20 16:37:58 -07001614 */
1615static hook_event_int_t *
dh155122f4b3ec62007-01-19 16:59:38 -08001616hook_event_checkdup(hook_event_t *he, hook_stack_t *hks)
dr146992381a2a92006-10-20 16:37:58 -07001617{
1618 hook_family_int_t *hfi;
1619 hook_event_int_t *hei;
1620
1621 ASSERT(he != NULL);
1622
Darren Reed7ddc9b12008-09-08 14:46:50 -07001623 CVW_ENTER_READ(&hks->hks_lock);
dh155122f4b3ec62007-01-19 16:59:38 -08001624 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
dr146992381a2a92006-10-20 16:37:58 -07001625 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
Darren Reed7ddc9b12008-09-08 14:46:50 -07001626 if (hei->hei_event == he) {
1627 CVW_EXIT_READ(&hks->hks_lock);
dr146992381a2a92006-10-20 16:37:58 -07001628 return (hei);
Darren Reed7ddc9b12008-09-08 14:46:50 -07001629 }
dr146992381a2a92006-10-20 16:37:58 -07001630 }
1631 }
Darren Reed7ddc9b12008-09-08 14:46:50 -07001632 CVW_EXIT_READ(&hks->hks_lock);
dr146992381a2a92006-10-20 16:37:58 -07001633
1634 return (NULL);
1635}
1636
dr146992381a2a92006-10-20 16:37:58 -07001637/*
1638 * Function: hook_event_copy
1639 * Returns: internal event pointer - NULL = Failed
1640 * Parameters: src(I) - event pointer
1641 *
1642 * Allocate internal event block and duplicate incoming event
1643 * No locks should be held across this function as it may sleep.
1644 */
1645static hook_event_int_t *
1646hook_event_copy(hook_event_t *src)
1647{
1648 hook_event_int_t *new;
1649
1650 ASSERT(src != NULL);
1651 ASSERT(src->he_name != NULL);
1652
1653 new = (hook_event_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
1654
1655 /* Copy body */
1656 TAILQ_INIT(&new->hei_head);
1657 new->hei_event = src;
1658
1659 return (new);
1660}
1661
dr146992381a2a92006-10-20 16:37:58 -07001662/*
1663 * Function: hook_event_find
1664 * Returns: internal event pointer - NULL = Not match
Darren Reed4a9b8372010-04-26 17:05:56 -07001665 * Parameters: hfi(I) - internal family pointer
dr146992381a2a92006-10-20 16:37:58 -07001666 * event(I) - event name string
1667 *
1668 * Search event list with event name
Jason King68c34d02018-10-22 00:53:14 +00001669 * A lock on hfi->hfi_lock must be held when called.
dr146992381a2a92006-10-20 16:37:58 -07001670 */
1671static hook_event_int_t *
1672hook_event_find(hook_family_int_t *hfi, char *event)
1673{
1674 hook_event_int_t *hei = NULL;
1675
1676 ASSERT(hfi != NULL);
1677 ASSERT(event != NULL);
1678
1679 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
Darren Reed7ddc9b12008-09-08 14:46:50 -07001680 if ((strcmp(hei->hei_event->he_name, event) == 0) &&
1681 ((hei->hei_waiter.fw_flags & FWF_UNSAFE) == 0))
dr146992381a2a92006-10-20 16:37:58 -07001682 break;
1683 }
1684 return (hei);
1685}
1686
dr146992381a2a92006-10-20 16:37:58 -07001687/*
Darren Reed7ddc9b12008-09-08 14:46:50 -07001688 * Function: hook_event_notify_register
Darren Reed4a9b8372010-04-26 17:05:56 -07001689 * Returns: int - 0 = success, else failure
Darren Reed7ddc9b12008-09-08 14:46:50 -07001690 * 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
dr146992381a2a92006-10-20 16:37:58 -07001694 *
Darren Reed7ddc9b12008-09-08 14:46:50 -07001695 * 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.
dr146992381a2a92006-10-20 16:37:58 -07001698 */
Darren Reed7ddc9b12008-09-08 14:46:50 -07001699int
1700hook_event_notify_register(hook_family_int_t *hfi, char *event,
1701 hook_notify_fn_t callback, void *arg)
dr146992381a2a92006-10-20 16:37:58 -07001702{
Darren Reed7ddc9b12008-09-08 14:46:50 -07001703 hook_event_int_t *hei;
1704 hook_stack_t *hks;
Darren Reed4a9b8372010-04-26 17:05:56 -07001705 boolean_t canrun;
1706 hook_int_t *h;
Darren Reed7ddc9b12008-09-08 14:46:50 -07001707 int error;
dr146992381a2a92006-10-20 16:37:58 -07001708
Darren Reed4a9b8372010-04-26 17:05:56 -07001709 canrun = B_FALSE;
Darren Reed7ddc9b12008-09-08 14:46:50 -07001710 hks = hfi->hfi_stack;
1711 CVW_ENTER_READ(&hks->hks_lock);
1712 if (hks->hks_shutdown != 0) {
1713 CVW_EXIT_READ(&hks->hks_lock);
1714 return (ESHUTDOWN);
1715 }
1716
1717 CVW_ENTER_READ(&hfi->hfi_lock);
1718
Darren Reed8ad74182008-10-23 10:33:00 -07001719 if (hfi->hfi_condemned || hfi->hfi_shutdown) {
Darren Reed7ddc9b12008-09-08 14:46:50 -07001720 CVW_EXIT_READ(&hfi->hfi_lock);
1721 CVW_EXIT_READ(&hks->hks_lock);
1722 return (ESHUTDOWN);
1723 }
1724
1725 hei = hook_event_find(hfi, event);
1726 if (hei == NULL) {
1727 CVW_EXIT_READ(&hfi->hfi_lock);
1728 CVW_EXIT_READ(&hks->hks_lock);
1729 return (ESRCH);
1730 }
1731
Darren Reed8ad74182008-10-23 10:33:00 -07001732 if (hei->hei_condemned || hei->hei_shutdown) {
Darren Reed7ddc9b12008-09-08 14:46:50 -07001733 CVW_EXIT_READ(&hfi->hfi_lock);
1734 CVW_EXIT_READ(&hks->hks_lock);
1735 return (ESHUTDOWN);
1736 }
1737
Darren Reed4a9b8372010-04-26 17:05:56 -07001738 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);
Darren Reed7ddc9b12008-09-08 14:46:50 -07001742 CVW_EXIT_WRITE(&hei->hei_lock);
Darren Reed4a9b8372010-04-26 17:05:56 -07001743
Darren Reed7ddc9b12008-09-08 14:46:50 -07001744 CVW_EXIT_READ(&hfi->hfi_lock);
1745 CVW_EXIT_READ(&hks->hks_lock);
1746
Darren Reed4a9b8372010-04-26 17:05:56 -07001747 if (error == 0 && canrun) {
1748 TAILQ_FOREACH(h, &hei->hei_head, hi_entry) {
1749 callback(HN_REGISTER, arg,
1750 hfi->hfi_family.hf_name, hei->hei_event->he_name,
1751 h->hi_hook.h_name);
1752 }
1753 }
1754
1755 if (canrun)
1756 hook_wait_unsetflag(&hei->hei_waiter, FWF_ADD_ACTIVE);
1757
Darren Reed7ddc9b12008-09-08 14:46:50 -07001758 return (error);
dr146992381a2a92006-10-20 16:37:58 -07001759}
1760
Darren Reed7ddc9b12008-09-08 14:46:50 -07001761/*
1762 * Function: hook_event_notify_unregister
Darren Reed4a9b8372010-04-26 17:05:56 -07001763 * Returns: int - 0 = success, else failure
Darren Reed7ddc9b12008-09-08 14:46:50 -07001764 * Parameters: hfi(I) - hook family
1765 * event(I) - name of the event
1766 * callback(I) - function to be called
1767 *
1768 * Remove the given callback from the named event's list of functions
1769 * to call when a hook is added or removed.
1770 */
1771int
1772hook_event_notify_unregister(hook_family_int_t *hfi, char *event,
1773 hook_notify_fn_t callback)
1774{
1775 hook_event_int_t *hei;
1776 boolean_t free_event;
Darren Reed4a9b8372010-04-26 17:05:56 -07001777 boolean_t canrun;
1778 hook_int_t *h;
1779 void *arg;
Darren Reed7ddc9b12008-09-08 14:46:50 -07001780 int error;
1781
Darren Reed4a9b8372010-04-26 17:05:56 -07001782 canrun = B_FALSE;
1783
Darren Reed7ddc9b12008-09-08 14:46:50 -07001784 CVW_ENTER_READ(&hfi->hfi_lock);
1785
1786 hei = hook_event_find(hfi, event);
1787 if (hei == NULL) {
1788 CVW_EXIT_READ(&hfi->hfi_lock);
1789 return (ESRCH);
1790 }
1791
1792 CVW_ENTER_WRITE(&hei->hei_lock);
1793
Darren Reed4a9b8372010-04-26 17:05:56 -07001794 (void) hook_wait_setflag(&hei->hei_waiter, FWF_DEL_WAIT_MASK,
1795 FWF_DEL_WANTED, FWF_DEL_ACTIVE);
1796
1797 error = hook_notify_unregister(&hei->hei_nhead, callback, &arg);
1798
1799 hook_wait_unsetflag(&hei->hei_waiter, FWF_DEL_ACTIVE);
Darren Reed7ddc9b12008-09-08 14:46:50 -07001800
1801 /*
1802 * hei_condemned has been set if someone tried to remove the
1803 * event but couldn't because there were still things attached to
1804 * it. Now that we've done a successful remove, if it is now empty
1805 * then by all rights we should be free'ing it too. Note that the
1806 * expectation is that only the caller of hook_event_add will ever
1807 * call hook_event_remove.
1808 */
1809 if ((error == 0) && hei->hei_condemned &&
1810 TAILQ_EMPTY(&hei->hei_head) && TAILQ_EMPTY(&hei->hei_nhead)) {
1811 free_event = B_TRUE;
1812 } else {
1813 free_event = B_FALSE;
1814 }
1815
Darren Reed4a9b8372010-04-26 17:05:56 -07001816 if (error == 0 && !free_event) {
1817 canrun = (hook_wait_setflag(&hei->hei_waiter, FWF_ADD_WAIT_MASK,
1818 FWF_ADD_WANTED, FWF_ADD_ACTIVE) != -1);
1819 }
1820
Darren Reed7ddc9b12008-09-08 14:46:50 -07001821 CVW_EXIT_WRITE(&hei->hei_lock);
1822 CVW_EXIT_READ(&hfi->hfi_lock);
1823
Darren Reed4a9b8372010-04-26 17:05:56 -07001824 if (canrun) {
1825 TAILQ_FOREACH(h, &hei->hei_head, hi_entry) {
1826 callback(HN_UNREGISTER, arg,
1827 hfi->hfi_family.hf_name, hei->hei_event->he_name,
1828 h->hi_hook.h_name);
1829 }
1830
1831 hook_wait_unsetflag(&hei->hei_waiter, FWF_ADD_ACTIVE);
1832 }
1833
Darren Reed7ddc9b12008-09-08 14:46:50 -07001834 if (free_event) {
1835 /*
1836 * It is safe to pass in hfi here, without a lock, because
1837 * our structure (hei) is still on one of its lists and thus
1838 * it won't be able to disappear yet...
1839 */
1840 hook_event_free(hei, hfi);
1841 }
1842
1843 return (error);
1844}
1845
1846/*
1847 * Function: hook_event_notify_run
1848 * Returns: None
1849 * Parameters: nrun(I) - pointer to the list of callbacks to execute
1850 * hfi(I) - hook stack pointer to execute callbacks for
1851 * name(I) - name of a hook family
1852 * cmd(I) - either HN_UNREGISTER or HN_REGISTER
1853 *
1854 * Execute all of the callbacks registered for this event.
1855 */
1856static void
1857hook_event_notify_run(hook_event_int_t *hei, hook_family_int_t *hfi,
1858 char *event, char *name, hook_notify_cmd_t cmd)
1859{
1860
1861 hook_notify_run(&hei->hei_nhead, hfi->hfi_family.hf_name,
1862 event, name, cmd);
1863}
dr146992381a2a92006-10-20 16:37:58 -07001864
1865/*
1866 * Function: hook_register
Darren Reed4a9b8372010-04-26 17:05:56 -07001867 * Returns: int - 0 = success, else = failure
1868 * Parameters: hfi(I) - internal family pointer
dr146992381a2a92006-10-20 16:37:58 -07001869 * event(I) - event name string
Darren Reed4a9b8372010-04-26 17:05:56 -07001870 * h(I) - hook pointer
dr146992381a2a92006-10-20 16:37:58 -07001871 *
Darren Reed7ddc9b12008-09-08 14:46:50 -07001872 * Add new hook to hook list on the specified family and event.
dr146992381a2a92006-10-20 16:37:58 -07001873 */
1874int
1875hook_register(hook_family_int_t *hfi, char *event, hook_t *h)
1876{
1877 hook_event_int_t *hei;
1878 hook_int_t *hi, *new;
Darren Reed7ddc9b12008-09-08 14:46:50 -07001879 int error;
dr146992381a2a92006-10-20 16:37:58 -07001880
1881 ASSERT(hfi != NULL);
1882 ASSERT(event != NULL);
1883 ASSERT(h != NULL);
Darren Reed7ddc9b12008-09-08 14:46:50 -07001884
1885 if (hfi->hfi_stack->hks_shutdown)
1886 return (NULL);
dr146992381a2a92006-10-20 16:37:58 -07001887
1888 /* Alloc hook_int_t and copy hook */
1889 new = hook_copy(h);
1890 if (new == NULL)
1891 return (ENOMEM);
1892
1893 /*
1894 * Since hook add/remove only impact event, so it is unnecessary
1895 * to hold global family write lock. Just get read lock here to
1896 * ensure event will not be removed when doing hooks operation
1897 */
Darren Reed7ddc9b12008-09-08 14:46:50 -07001898 CVW_ENTER_WRITE(&hfi->hfi_lock);
dr146992381a2a92006-10-20 16:37:58 -07001899
1900 hei = hook_event_find(hfi, event);
1901 if (hei == NULL) {
Darren Reed7ddc9b12008-09-08 14:46:50 -07001902 CVW_EXIT_WRITE(&hfi->hfi_lock);
1903 hook_int_free(new, hfi->hfi_stack->hks_netstackid);
dr146992381a2a92006-10-20 16:37:58 -07001904 return (ENXIO);
1905 }
1906
1907 CVW_ENTER_WRITE(&hei->hei_lock);
1908
Darren Reed8ad74182008-10-23 10:33:00 -07001909 /*
1910 * If we've run either the remove() or shutdown(), do not allow any
1911 * more hooks to be added to this event.
1912 */
1913 if (hei->hei_shutdown) {
1914 error = ESHUTDOWN;
1915 goto bad_add;
1916 }
1917
dr146992381a2a92006-10-20 16:37:58 -07001918 hi = hook_find(hei, h);
1919 if (hi != NULL) {
Darren Reed7ddc9b12008-09-08 14:46:50 -07001920 error = EEXIST;
1921 goto bad_add;
1922 }
1923
Darren Reed4a9b8372010-04-26 17:05:56 -07001924 if (hook_wait_setflag(&hei->hei_waiter, FWF_ADD_WAIT_MASK,
Darren Reed7ddc9b12008-09-08 14:46:50 -07001925 FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) {
1926 error = ENOENT;
1927bad_add:
dr146992381a2a92006-10-20 16:37:58 -07001928 CVW_EXIT_WRITE(&hei->hei_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -07001929 CVW_EXIT_WRITE(&hfi->hfi_lock);
1930 hook_int_free(new, hfi->hfi_stack->hks_netstackid);
1931 return (error);
dr146992381a2a92006-10-20 16:37:58 -07001932 }
1933
1934 /* Add to hook list head */
Darren Reed7ddc9b12008-09-08 14:46:50 -07001935 error = hook_insert(&hei->hei_head, new);
1936 if (error == 0) {
1937 hei->hei_event->he_interested = B_TRUE;
1938 hei->hei_kstats.hooks_added.value.ui64++;
1939
1940 hook_init_kstats(hfi, hei, new);
1941 }
dr146992381a2a92006-10-20 16:37:58 -07001942
1943 CVW_EXIT_WRITE(&hei->hei_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -07001944 CVW_EXIT_WRITE(&hfi->hfi_lock);
1945
1946 /*
1947 * Note that the name string passed through to the notify callbacks
1948 * is from the original hook being registered, not the copy being
1949 * inserted.
1950 */
Darren Reed4a9b8372010-04-26 17:05:56 -07001951 if (error == 0)
Darren Reed7ddc9b12008-09-08 14:46:50 -07001952 hook_event_notify_run(hei, hfi, event, h->h_name, HN_REGISTER);
Darren Reed4a9b8372010-04-26 17:05:56 -07001953
1954 hook_wait_unsetflag(&hei->hei_waiter, FWF_ADD_ACTIVE);
Darren Reed7ddc9b12008-09-08 14:46:50 -07001955
1956 return (error);
1957}
1958
1959/*
1960 * Function: hook_insert
Darren Reed4a9b8372010-04-26 17:05:56 -07001961 * Returns: int - 0 = success, else = failure
Darren Reed7ddc9b12008-09-08 14:46:50 -07001962 * Parameters: head(I) - pointer to hook list to insert hook onto
1963 * new(I) - pointer to hook to be inserted
1964 *
1965 * Try to insert the hook onto the list of hooks according to the hints
1966 * given in the hook to be inserted and those that already exist on the
1967 * list. For now, the implementation permits only a single hook to be
1968 * either first or last and names provided with before or after are only
1969 * loosely coupled with the action.
1970 */
1971static int
1972hook_insert(hook_int_head_t *head, hook_int_t *new)
1973{
1974 hook_int_t *before;
1975 hook_int_t *hi;
1976 hook_t *hih;
1977 hook_t *h = &new->hi_hook;
1978
1979 switch (new->hi_hook.h_hint) {
1980 case HH_NONE :
1981 before = NULL;
1982 /*
1983 * If there is no hint present (or not one that can be
1984 * satisfied now) then try to at least respect the wishes
1985 * of those that want to be last. If there are none wanting
1986 * to be last then add the new hook to the tail of the
1987 * list - this means we keep any wanting to be first
1988 * happy without having to search for HH_FIRST.
1989 */
1990 TAILQ_FOREACH(hi, head, hi_entry) {
1991 hih = &hi->hi_hook;
1992 if ((hih->h_hint == HH_AFTER) &&
1993 (strcmp(h->h_name,
1994 (char *)hih->h_hintvalue) == 0)) {
1995 TAILQ_INSERT_BEFORE(hi, new, hi_entry);
1996 return (0);
1997 }
1998 if ((hih->h_hint == HH_BEFORE) && (before == NULL) &&
1999 (strcmp(h->h_name,
2000 (char *)hih->h_hintvalue) == 0)) {
2001 before = hi;
2002 }
2003 }
2004 if (before != NULL) {
2005 TAILQ_INSERT_AFTER(head, before, new, hi_entry);
2006 return (0);
2007 }
2008 hook_insert_plain(head, new);
2009 break;
2010
2011 case HH_FIRST :
2012 hi = TAILQ_FIRST(head);
2013 if ((hi != NULL) && (hi->hi_hook.h_hint == HH_FIRST))
2014 return (EBUSY);
2015 TAILQ_INSERT_HEAD(head, new, hi_entry);
2016 break;
2017
2018 case HH_LAST :
2019 hi = TAILQ_LAST(head, hook_int_head);
2020 if ((hi != NULL) && (hi->hi_hook.h_hint == HH_LAST))
2021 return (EBUSY);
2022 TAILQ_INSERT_TAIL(head, new, hi_entry);
2023 break;
2024
2025 case HH_BEFORE :
2026 hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue);
2027 if (hi == NULL)
2028 return (hook_insert_afterbefore(head, new));
2029
2030 if (hi->hi_hook.h_hint == HH_FIRST)
2031 return (EBUSY);
2032
2033 TAILQ_INSERT_BEFORE(hi, new, hi_entry);
2034 break;
2035
2036 case HH_AFTER :
2037 hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue);
2038 if (hi == NULL)
2039 return (hook_insert_afterbefore(head, new));
2040
2041 if (hi->hi_hook.h_hint == HH_LAST)
2042 return (EBUSY);
2043
2044 TAILQ_INSERT_AFTER(head, hi, new, hi_entry);
2045 break;
2046
2047 default :
2048 return (EINVAL);
2049 }
2050
dr146992381a2a92006-10-20 16:37:58 -07002051 return (0);
2052}
2053
Darren Reed7ddc9b12008-09-08 14:46:50 -07002054/*
2055 * Function: hook_insert_plain
Darren Reed4a9b8372010-04-26 17:05:56 -07002056 * Returns: int - 0 = success, else = failure
Darren Reed7ddc9b12008-09-08 14:46:50 -07002057 * Parameters: head(I) - pointer to hook list to insert hook onto
2058 * new(I) - pointer to hook to be inserted
2059 *
2060 * Insert a hook such that it respects the wishes of those that want to
2061 * be last. If there are none wanting to be last then add the new hook
2062 * to the tail of the list - this means we keep any wanting to be first
2063 * happy without having to search for HH_FIRST.
2064 */
2065static void
2066hook_insert_plain(hook_int_head_t *head, hook_int_t *new)
2067{
2068 hook_int_t *hi;
2069
2070 hi = TAILQ_FIRST(head);
2071 if (hi != NULL) {
2072 if (hi->hi_hook.h_hint == HH_LAST) {
2073 TAILQ_INSERT_BEFORE(hi, new, hi_entry);
2074 } else {
2075 TAILQ_INSERT_TAIL(head, new, hi_entry);
2076 }
2077 } else {
2078 TAILQ_INSERT_TAIL(head, new, hi_entry);
2079 }
2080}
2081
2082/*
2083 * Function: hook_insert_afterbefore
Darren Reed4a9b8372010-04-26 17:05:56 -07002084 * Returns: int - 0 = success, else = failure
Darren Reed7ddc9b12008-09-08 14:46:50 -07002085 * Parameters: head(I) - pointer to hook list to insert hook onto
2086 * new(I) - pointer to hook to be inserted
2087 *
2088 * Simple insertion of a hook specifying a HH_BEFORE or HH_AFTER was not
2089 * possible, so now we need to be more careful. The first pass is to go
2090 * through the list and look for any other hooks that also specify the
2091 * same hint name as the new one. The object of this exercise is to make
2092 * sure that hooks with HH_BEFORE always appear on the list before those
2093 * with HH_AFTER so that when said hook arrives, it can be placed in the
2094 * middle of the BEFOREs and AFTERs. If this condition does not arise,
2095 * just use hook_insert_plain() to try and insert the hook somewhere that
2096 * is innocuous to existing efforts.
2097 */
2098static int
2099hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new)
2100{
2101 hook_int_t *hi;
2102 hook_t *nh;
2103 hook_t *h;
2104
2105 nh = &new->hi_hook;
2106 ASSERT(new->hi_hook.h_hint != HH_NONE);
2107 ASSERT(new->hi_hook.h_hint != HH_LAST);
2108 ASSERT(new->hi_hook.h_hint != HH_FIRST);
2109
2110 /*
2111 * First, look through the list to see if there are any other
2112 * before's or after's that have a matching hint name.
2113 */
2114 TAILQ_FOREACH(hi, head, hi_entry) {
2115 h = &hi->hi_hook;
2116 switch (h->h_hint) {
2117 case HH_FIRST :
2118 case HH_LAST :
2119 case HH_NONE :
2120 break;
2121 case HH_BEFORE :
2122 if ((nh->h_hint == HH_BEFORE) &&
2123 (strcmp((char *)h->h_hintvalue,
2124 (char *)nh->h_hintvalue) == 0)) {
2125 TAILQ_INSERT_AFTER(head, hi, new, hi_entry);
2126 return (0);
2127 }
2128 if ((nh->h_hint == HH_AFTER) &&
2129 (strcmp((char *)h->h_hintvalue,
2130 (char *)nh->h_hintvalue) == 0)) {
2131 TAILQ_INSERT_BEFORE(hi, new, hi_entry);
2132 return (0);
2133 }
2134 break;
2135 case HH_AFTER :
2136 if ((nh->h_hint == HH_AFTER) &&
2137 (strcmp((char *)h->h_hintvalue,
2138 (char *)nh->h_hintvalue) == 0)) {
2139 TAILQ_INSERT_AFTER(head, hi, new, hi_entry);
2140 return (0);
2141 }
2142 if ((nh->h_hint == HH_BEFORE) &&
2143 (strcmp((char *)h->h_hintvalue,
2144 (char *)nh->h_hintvalue) == 0)) {
2145 TAILQ_INSERT_BEFORE(hi, new, hi_entry);
2146 return (0);
2147 }
2148 break;
2149 }
2150 }
2151
2152 hook_insert_plain(head, new);
2153
2154 return (0);
2155}
dr146992381a2a92006-10-20 16:37:58 -07002156
2157/*
2158 * Function: hook_unregister
Darren Reed4a9b8372010-04-26 17:05:56 -07002159 * Returns: int - 0 = success, else = failure
2160 * Parameters: hfi(I) - internal family pointer
dr146992381a2a92006-10-20 16:37:58 -07002161 * event(I) - event name string
Darren Reed4a9b8372010-04-26 17:05:56 -07002162 * h(I) - hook pointer
dr146992381a2a92006-10-20 16:37:58 -07002163 *
2164 * Remove hook from hook list on specific family, event
2165 */
2166int
2167hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h)
2168{
2169 hook_event_int_t *hei;
2170 hook_int_t *hi;
Darren Reed7ddc9b12008-09-08 14:46:50 -07002171 boolean_t free_event;
dr146992381a2a92006-10-20 16:37:58 -07002172
2173 ASSERT(hfi != NULL);
2174 ASSERT(h != NULL);
2175
Darren Reed7ddc9b12008-09-08 14:46:50 -07002176 CVW_ENTER_WRITE(&hfi->hfi_lock);
dr146992381a2a92006-10-20 16:37:58 -07002177
2178 hei = hook_event_find(hfi, event);
2179 if (hei == NULL) {
Darren Reed7ddc9b12008-09-08 14:46:50 -07002180 CVW_EXIT_WRITE(&hfi->hfi_lock);
dr146992381a2a92006-10-20 16:37:58 -07002181 return (ENXIO);
2182 }
2183
2184 /* Hold write lock for event */
2185 CVW_ENTER_WRITE(&hei->hei_lock);
2186
2187 hi = hook_find(hei, h);
2188 if (hi == NULL) {
2189 CVW_EXIT_WRITE(&hei->hei_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -07002190 CVW_EXIT_WRITE(&hfi->hfi_lock);
dr146992381a2a92006-10-20 16:37:58 -07002191 return (ENXIO);
2192 }
2193
Darren Reed4a9b8372010-04-26 17:05:56 -07002194 if (hook_wait_setflag(&hei->hei_waiter, FWF_DEL_WAIT_MASK,
Darren Reed7ddc9b12008-09-08 14:46:50 -07002195 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
2196 CVW_EXIT_WRITE(&hei->hei_lock);
2197 CVW_EXIT_WRITE(&hfi->hfi_lock);
2198 return (ENOENT);
2199 }
2200
dr146992381a2a92006-10-20 16:37:58 -07002201 /* Remove from hook list */
2202 TAILQ_REMOVE(&hei->hei_head, hi, hi_entry);
Darren Reed7ddc9b12008-09-08 14:46:50 -07002203
2204 free_event = B_FALSE;
dr146992381a2a92006-10-20 16:37:58 -07002205 if (TAILQ_EMPTY(&hei->hei_head)) {
2206 hei->hei_event->he_interested = B_FALSE;
Darren Reed7ddc9b12008-09-08 14:46:50 -07002207 /*
2208 * If the delete pending flag has been set and there are
2209 * no notifiers on the event (and we've removed the last
2210 * hook) then we need to free this event after we're done.
2211 */
2212 if (hei->hei_condemned && TAILQ_EMPTY(&hei->hei_nhead))
2213 free_event = B_TRUE;
dr146992381a2a92006-10-20 16:37:58 -07002214 }
Darren Reed7ddc9b12008-09-08 14:46:50 -07002215 hei->hei_kstats.hooks_removed.value.ui64++;
dr146992381a2a92006-10-20 16:37:58 -07002216
2217 CVW_EXIT_WRITE(&hei->hei_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -07002218 CVW_EXIT_WRITE(&hfi->hfi_lock);
2219 /*
2220 * While the FWF_DEL_ACTIVE flag is set, the hook_event_int_t
2221 * will not be free'd and thus the hook_family_int_t wil not
2222 * be free'd either.
2223 */
2224 hook_event_notify_run(hei, hfi, event, h->h_name, HN_UNREGISTER);
2225 hook_wait_unsetflag(&hei->hei_waiter, FWF_DEL_ACTIVE);
dr146992381a2a92006-10-20 16:37:58 -07002226
Darren Reed7ddc9b12008-09-08 14:46:50 -07002227 hook_int_free(hi, hfi->hfi_stack->hks_netstackid);
2228
2229 if (free_event)
2230 hook_event_free(hei, hfi);
2231
dr146992381a2a92006-10-20 16:37:58 -07002232 return (0);
2233}
2234
Darren Reed7ddc9b12008-09-08 14:46:50 -07002235/*
2236 * Function: hook_find_byname
2237 * Returns: internal hook pointer - NULL = Not match
2238 * Parameters: hei(I) - internal event pointer
2239 * name(I)- hook name
2240 *
2241 * Search an event's list of hooks to see if there is a hook present that
2242 * has a matching name to the one being looked for.
2243 */
2244static hook_int_t *
2245hook_find_byname(hook_int_head_t *head, char *name)
2246{
2247 hook_int_t *hi;
2248
2249 TAILQ_FOREACH(hi, head, hi_entry) {
2250 if (strcmp(hi->hi_hook.h_name, name) == 0)
2251 return (hi);
2252 }
2253
2254 return (NULL);
2255}
dr146992381a2a92006-10-20 16:37:58 -07002256
2257/*
2258 * Function: hook_find
2259 * Returns: internal hook pointer - NULL = Not match
2260 * Parameters: hei(I) - internal event pointer
Darren Reed4a9b8372010-04-26 17:05:56 -07002261 * h(I) - hook pointer
dr146992381a2a92006-10-20 16:37:58 -07002262 *
Darren Reed7ddc9b12008-09-08 14:46:50 -07002263 * 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.
dr146992381a2a92006-10-20 16:37:58 -07002266 */
2267static hook_int_t *
2268hook_find(hook_event_int_t *hei, hook_t *h)
2269{
dr146992381a2a92006-10-20 16:37:58 -07002270
2271 ASSERT(hei != NULL);
2272 ASSERT(h != NULL);
2273
Darren Reed7ddc9b12008-09-08 14:46:50 -07002274 return (hook_find_byname(&hei->hei_head, h->h_name));
dr146992381a2a92006-10-20 16:37:58 -07002275}
2276
dr146992381a2a92006-10-20 16:37:58 -07002277/*
2278 * Function: hook_copy
2279 * Returns: internal hook pointer - NULL = Failed
2280 * Parameters: src(I) - hook pointer
2281 *
2282 * Allocate internal hook block and duplicate incoming hook.
2283 * No locks should be held across this function as it may sleep.
Darren Reed7ddc9b12008-09-08 14:46:50 -07002284 * 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.
dr146992381a2a92006-10-20 16:37:58 -07002288 */
2289static hook_int_t *
2290hook_copy(hook_t *src)
2291{
2292 hook_int_t *new;
2293 hook_t *dst;
Darren Reed7ddc9b12008-09-08 14:46:50 -07002294 int len;
dr146992381a2a92006-10-20 16:37:58 -07002295
2296 ASSERT(src != NULL);
2297 ASSERT(src->h_name != NULL);
2298
2299 new = (hook_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
2300
2301 /* Copy body */
2302 dst = &new->hi_hook;
2303 *dst = *src;
2304
2305 /* Copy name */
Darren Reed7ddc9b12008-09-08 14:46:50 -07002306 len = strlen(src->h_name);
2307 dst->h_name = (char *)kmem_alloc(len + 1, KM_SLEEP);
dr146992381a2a92006-10-20 16:37:58 -07002308 (void) strcpy(dst->h_name, src->h_name);
2309
Darren Reed7ddc9b12008-09-08 14:46:50 -07002310 /*
2311 * This is initialised in this manner to make it safer to use the
2312 * same pointer in the kstats field.
2313 */
2314 dst->h_hintvalue = (uintptr_t)"";
2315
2316 if (dst->h_hint == HH_BEFORE || dst->h_hint == HH_AFTER) {
2317 len = strlen((char *)src->h_hintvalue);
2318 if (len > 0) {