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