12958Sdr146992 /* 22958Sdr146992 * CDDL HEADER START 32958Sdr146992 * 42958Sdr146992 * The contents of this file are subject to the terms of the 52958Sdr146992 * Common Development and Distribution License (the "License"). 62958Sdr146992 * You may not use this file except in compliance with the License. 72958Sdr146992 * 82958Sdr146992 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92958Sdr146992 * or http://www.opensolaris.org/os/licensing. 102958Sdr146992 * See the License for the specific language governing permissions 112958Sdr146992 * and limitations under the License. 122958Sdr146992 * 132958Sdr146992 * When distributing Covered Code, include this CDDL HEADER in each 142958Sdr146992 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152958Sdr146992 * If applicable, add the following below this CDDL HEADER, with the 162958Sdr146992 * fields enclosed by brackets "[]" replaced with your own identifying 172958Sdr146992 * information: Portions Copyright [yyyy] [name of copyright owner] 182958Sdr146992 * 192958Sdr146992 * CDDL HEADER END 202958Sdr146992 */ 212958Sdr146992 /* 22*7513SDarren.Reed@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 232958Sdr146992 * Use is subject to license terms. 242958Sdr146992 */ 252958Sdr146992 #include <sys/param.h> 262958Sdr146992 #include <sys/types.h> 272958Sdr146992 #include <sys/systm.h> 282958Sdr146992 #include <sys/errno.h> 292958Sdr146992 #include <sys/kmem.h> 302958Sdr146992 #include <sys/mutex.h> 312958Sdr146992 #include <sys/condvar.h> 322958Sdr146992 #include <sys/modctl.h> 332958Sdr146992 #include <sys/hook_impl.h> 342958Sdr146992 #include <sys/sdt.h> 35*7513SDarren.Reed@Sun.COM #include <sys/cmn_err.h> 362958Sdr146992 372958Sdr146992 /* 382958Sdr146992 * This file provides kernel hook framework. 392958Sdr146992 */ 402958Sdr146992 412958Sdr146992 static struct modldrv modlmisc = { 422958Sdr146992 &mod_miscops, /* drv_modops */ 432958Sdr146992 "Hooks Interface v1.0", /* drv_linkinfo */ 442958Sdr146992 }; 452958Sdr146992 462958Sdr146992 static struct modlinkage modlinkage = { 472958Sdr146992 MODREV_1, /* ml_rev */ 482958Sdr146992 &modlmisc, /* ml_linkage */ 492958Sdr146992 NULL 502958Sdr146992 }; 512958Sdr146992 522958Sdr146992 /* 53*7513SDarren.Reed@Sun.COM * How it works. 54*7513SDarren.Reed@Sun.COM * ============= 55*7513SDarren.Reed@Sun.COM * Use of the hook framework here is tied up with zones - when a new zone 56*7513SDarren.Reed@Sun.COM * is created, we create a new hook_stack_t and are open to business for 57*7513SDarren.Reed@Sun.COM * allowing new hook families and their events. 58*7513SDarren.Reed@Sun.COM * 59*7513SDarren.Reed@Sun.COM * A consumer of these hooks is expected to operate in this fashion: 60*7513SDarren.Reed@Sun.COM * 1) call hook_family_add() to create a new family of hooks. It is a 61*7513SDarren.Reed@Sun.COM * current requirement that this call must be made with the value 62*7513SDarren.Reed@Sun.COM * returned from hook_stack_init, by way of infrastructure elsewhere. 63*7513SDarren.Reed@Sun.COM * 2) add events to the registered family with calls to hook_event_add. 64*7513SDarren.Reed@Sun.COM * 65*7513SDarren.Reed@Sun.COM * At this point, the structures in place should be open to others to 66*7513SDarren.Reed@Sun.COM * add hooks to the event or add notifiers for when the contents of the 67*7513SDarren.Reed@Sun.COM * hook stack changes. 68*7513SDarren.Reed@Sun.COM * 69*7513SDarren.Reed@Sun.COM * The interesting stuff happens on teardown. 70*7513SDarren.Reed@Sun.COM * 71*7513SDarren.Reed@Sun.COM * It is a requirement that the provider of hook events work in the reverse 72*7513SDarren.Reed@Sun.COM * order to the above, so that the first step is: 73*7513SDarren.Reed@Sun.COM * 1) remove events from each hook family created earlier 74*7513SDarren.Reed@Sun.COM * 2) remove hook families from the hook stack. 75*7513SDarren.Reed@Sun.COM * 76*7513SDarren.Reed@Sun.COM * When doing teardown of both events and families, a check is made to see 77*7513SDarren.Reed@Sun.COM * if either structure is still "busy". If so then a boolean flag is set to 78*7513SDarren.Reed@Sun.COM * say that the structure is condemned. The presence of this flag being set 79*7513SDarren.Reed@Sun.COM * must be checked for in _add()/_register()/ functions and a failure returned 80*7513SDarren.Reed@Sun.COM * if it is set. It is ignored by the _find() functions because they're 81*7513SDarren.Reed@Sun.COM * used by _remove()/_unregister(). While setting the condemned flag when 82*7513SDarren.Reed@Sun.COM * trying to delete a structure would normally be keyed from the presence 83*7513SDarren.Reed@Sun.COM * of a reference count being greater than 1, in this implementation there 84*7513SDarren.Reed@Sun.COM * are no reference counts required: instead the presence of objects on 85*7513SDarren.Reed@Sun.COM * linked lists is taken to mean something is still "busy." 86*7513SDarren.Reed@Sun.COM * 87*7513SDarren.Reed@Sun.COM * ONLY the caller that adds the family and the events ever has a direct 88*7513SDarren.Reed@Sun.COM * reference to the internal structures and thus ONLY it should be doing 89*7513SDarren.Reed@Sun.COM * the removal of either the event or family. In practise, what this means 90*7513SDarren.Reed@Sun.COM * is that in ip_netinfo.c, we have calls to net_protocol_register(), followed 91*7513SDarren.Reed@Sun.COM * by net_event_register() (these interface to hook_family_add() and 92*7513SDarren.Reed@Sun.COM * hook_event_add(), respectively) that are made when we create an instance 93*7513SDarren.Reed@Sun.COM * of IP and when the IP instance is shutdown/destroyed, it calls 94*7513SDarren.Reed@Sun.COM * net_event_unregister() and net_protocol_unregister(), which in turn call 95*7513SDarren.Reed@Sun.COM * hook_event_remove() and hook_family_remove() respectively. Nobody else 96*7513SDarren.Reed@Sun.COM * is entitled to call the _unregister() functions. It is imperative that 97*7513SDarren.Reed@Sun.COM * there be only one _remove() call for every _add() call. 98*7513SDarren.Reed@Sun.COM * 99*7513SDarren.Reed@Sun.COM * It is possible that code which is interfacing with this hook framework 100*7513SDarren.Reed@Sun.COM * won't do all the cleaning up that it needs to at the right time. While 101*7513SDarren.Reed@Sun.COM * we can't prevent programmers from creating memory leaks, we can synchronise 102*7513SDarren.Reed@Sun.COM * when we clean up data structures to prevent code accessing free'd memory. 103*7513SDarren.Reed@Sun.COM * 104*7513SDarren.Reed@Sun.COM * A simple diagram showing the ownership is as follows: 105*7513SDarren.Reed@Sun.COM * 106*7513SDarren.Reed@Sun.COM * Owned +--------------+ 107*7513SDarren.Reed@Sun.COM * by | hook_stack_t | 108*7513SDarren.Reed@Sun.COM * the +--------------+ 109*7513SDarren.Reed@Sun.COM * Instance | 110*7513SDarren.Reed@Sun.COM * - - - - - - - -|- - - - - - - - - - - - - - - - - - 111*7513SDarren.Reed@Sun.COM * V 112*7513SDarren.Reed@Sun.COM * Owned +-------------------+ +-------------------+ 113*7513SDarren.Reed@Sun.COM * | hook_family_int_t |---->| hook_family_int_t | 114*7513SDarren.Reed@Sun.COM * by +-------------------+ +-------------------+ 115*7513SDarren.Reed@Sun.COM * | \+---------------+ \+---------------+ 116*7513SDarren.Reed@Sun.COM * network | | hook_family_t | | hook_family_t | 117*7513SDarren.Reed@Sun.COM * V +---------------+ +---------------+ 118*7513SDarren.Reed@Sun.COM * protocol +------------------+ +------------------+ 119*7513SDarren.Reed@Sun.COM * | hook_event_int_t |---->| hook_event_int_t | 120*7513SDarren.Reed@Sun.COM * (ipv4,ipv6) +------------------+ +------------------+ 121*7513SDarren.Reed@Sun.COM * | \+--------------+ \+--------------+ 122*7513SDarren.Reed@Sun.COM * | | hook_event_t | | hook_event_t | 123*7513SDarren.Reed@Sun.COM * | +--------------+ +--------------+ 124*7513SDarren.Reed@Sun.COM * - - - - - - - -|- - - - - - - - - - - - - - - - - - 125*7513SDarren.Reed@Sun.COM * V 126*7513SDarren.Reed@Sun.COM * Owned +------------+ 127*7513SDarren.Reed@Sun.COM * | hook_int_t | 128*7513SDarren.Reed@Sun.COM * by +------------+ 129*7513SDarren.Reed@Sun.COM * \+--------+ 130*7513SDarren.Reed@Sun.COM * the consumer | hook_t | 131*7513SDarren.Reed@Sun.COM * +--------+ 132*7513SDarren.Reed@Sun.COM * 133*7513SDarren.Reed@Sun.COM * The consumers, such as IPFilter, do not have any pointers or hold any 134*7513SDarren.Reed@Sun.COM * references to hook_int_t, hook_event_t or hook_event_int_t. By placing 135*7513SDarren.Reed@Sun.COM * a hook on an event through net_hook_register(), an implicit reference 136*7513SDarren.Reed@Sun.COM * to the hook_event_int_t is returned with a successful call. Additionally, 137*7513SDarren.Reed@Sun.COM * IPFilter does not see the hook_family_int_t or hook_family_t directly. 138*7513SDarren.Reed@Sun.COM * Rather it is returned a net_handle_t (from net_protocol_lookup()) that 139*7513SDarren.Reed@Sun.COM * contains a pointer to hook_family_int_t. The structure behind the 140*7513SDarren.Reed@Sun.COM * net_handle_t (struct net_data) *is* reference counted and managed 141*7513SDarren.Reed@Sun.COM * appropriately. 142*7513SDarren.Reed@Sun.COM * 143*7513SDarren.Reed@Sun.COM * A more detailed picture that describes how the family/event structures 144*7513SDarren.Reed@Sun.COM * are linked together can be found in <sys/hook_impl.h> 145*7513SDarren.Reed@Sun.COM */ 146*7513SDarren.Reed@Sun.COM 147*7513SDarren.Reed@Sun.COM /* 148*7513SDarren.Reed@Sun.COM * Locking 149*7513SDarren.Reed@Sun.COM * ======= 150*7513SDarren.Reed@Sun.COM * The use of CVW_* macros to do locking is driven by the need to allow 151*7513SDarren.Reed@Sun.COM * recursive locking with read locks when we're processing packets. This 152*7513SDarren.Reed@Sun.COM * is necessary because various netinfo functions need to hold read locks, 153*7513SDarren.Reed@Sun.COM * by design, as they can be called in or out of packet context. 154*7513SDarren.Reed@Sun.COM */ 155*7513SDarren.Reed@Sun.COM /* 1562958Sdr146992 * Hook internal functions 1572958Sdr146992 */ 1582958Sdr146992 static hook_int_t *hook_copy(hook_t *src); 1593448Sdh155122 static hook_event_int_t *hook_event_checkdup(hook_event_t *he, 1603448Sdh155122 hook_stack_t *hks); 1612958Sdr146992 static hook_event_int_t *hook_event_copy(hook_event_t *src); 1622958Sdr146992 static hook_event_int_t *hook_event_find(hook_family_int_t *hfi, char *event); 163*7513SDarren.Reed@Sun.COM static void hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi); 1642958Sdr146992 static hook_family_int_t *hook_family_copy(hook_family_t *src); 1653448Sdh155122 static hook_family_int_t *hook_family_find(char *family, hook_stack_t *hks); 166*7513SDarren.Reed@Sun.COM static void hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks); 1672958Sdr146992 static hook_int_t *hook_find(hook_event_int_t *hei, hook_t *h); 168*7513SDarren.Reed@Sun.COM static void hook_int_free(hook_int_t *hi, netstackid_t); 1692958Sdr146992 static void hook_init(void); 1703448Sdh155122 static void hook_fini(void); 1713448Sdh155122 static void *hook_stack_init(netstackid_t stackid, netstack_t *ns); 1723448Sdh155122 static void hook_stack_fini(netstackid_t stackid, void *arg); 173*7513SDarren.Reed@Sun.COM static void hook_stack_shutdown(netstackid_t stackid, void *arg); 174*7513SDarren.Reed@Sun.COM static int hook_insert(hook_int_head_t *head, hook_int_t *new); 175*7513SDarren.Reed@Sun.COM static void hook_insert_plain(hook_int_head_t *head, hook_int_t *new); 176*7513SDarren.Reed@Sun.COM static int hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new); 177*7513SDarren.Reed@Sun.COM static hook_int_t *hook_find_byname(hook_int_head_t *head, char *name); 178*7513SDarren.Reed@Sun.COM static void hook_event_init_kstats(hook_family_int_t *, hook_event_int_t *); 179*7513SDarren.Reed@Sun.COM static void hook_event_notify_run(hook_event_int_t *, hook_family_int_t *, 180*7513SDarren.Reed@Sun.COM char *event, char *name, hook_notify_cmd_t cmd); 181*7513SDarren.Reed@Sun.COM static void hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei, 182*7513SDarren.Reed@Sun.COM hook_int_t *hi); 183*7513SDarren.Reed@Sun.COM static int hook_notify_register(cvwaitlock_t *lock, hook_notify_head_t *head, 184*7513SDarren.Reed@Sun.COM hook_notify_fn_t callback, void *arg); 185*7513SDarren.Reed@Sun.COM static int hook_notify_unregister(cvwaitlock_t *lock, 186*7513SDarren.Reed@Sun.COM hook_notify_head_t *head, hook_notify_fn_t callback); 187*7513SDarren.Reed@Sun.COM static void hook_notify_run(hook_notify_head_t *head, char *family, 188*7513SDarren.Reed@Sun.COM char *event, char *name, hook_notify_cmd_t cmd); 189*7513SDarren.Reed@Sun.COM static void hook_stack_notify_run(hook_stack_t *hks, char *name, 190*7513SDarren.Reed@Sun.COM hook_notify_cmd_t cmd); 191*7513SDarren.Reed@Sun.COM static void hook_stack_remove(hook_stack_t *hks); 192*7513SDarren.Reed@Sun.COM 193*7513SDarren.Reed@Sun.COM /* 194*7513SDarren.Reed@Sun.COM * A list of the hook stacks is kept here because we need to enable 195*7513SDarren.Reed@Sun.COM * net_instance_notify_register() to be called during the creation 196*7513SDarren.Reed@Sun.COM * of a new instance. Previously hook_stack_get() would just use 197*7513SDarren.Reed@Sun.COM * the netstack functions for this work but they will return NULL 198*7513SDarren.Reed@Sun.COM * until the zone has been fully initialised. 199*7513SDarren.Reed@Sun.COM */ 200*7513SDarren.Reed@Sun.COM static hook_stack_head_t hook_stacks; 201*7513SDarren.Reed@Sun.COM static kmutex_t hook_stack_lock; 2022958Sdr146992 2032958Sdr146992 /* 2042958Sdr146992 * Module entry points. 2052958Sdr146992 */ 2062958Sdr146992 int 2072958Sdr146992 _init(void) 2082958Sdr146992 { 2093448Sdh155122 int error; 2103448Sdh155122 2112958Sdr146992 hook_init(); 2123448Sdh155122 error = mod_install(&modlinkage); 2133448Sdh155122 if (error != 0) 2143448Sdh155122 hook_fini(); 2153448Sdh155122 2163448Sdh155122 return (error); 2172958Sdr146992 } 2182958Sdr146992 2192958Sdr146992 int 2202958Sdr146992 _fini(void) 2212958Sdr146992 { 2223448Sdh155122 int error; 2233448Sdh155122 2243448Sdh155122 error = mod_remove(&modlinkage); 2253448Sdh155122 if (error == 0) 2263448Sdh155122 hook_fini(); 2273448Sdh155122 2283448Sdh155122 return (error); 2292958Sdr146992 } 2302958Sdr146992 2312958Sdr146992 int 2322958Sdr146992 _info(struct modinfo *modinfop) 2332958Sdr146992 { 2342958Sdr146992 return (mod_info(&modlinkage, modinfop)); 2352958Sdr146992 } 2362958Sdr146992 2372958Sdr146992 /* 2382958Sdr146992 * Function: hook_init 2392958Sdr146992 * Returns: None 2402958Sdr146992 * Parameters: None 2412958Sdr146992 * 2422958Sdr146992 * Initialize hooks 2432958Sdr146992 */ 2442958Sdr146992 static void 2452958Sdr146992 hook_init(void) 2462958Sdr146992 { 247*7513SDarren.Reed@Sun.COM mutex_init(&hook_stack_lock, NULL, MUTEX_DRIVER, NULL); 248*7513SDarren.Reed@Sun.COM SLIST_INIT(&hook_stacks); 249*7513SDarren.Reed@Sun.COM 2503448Sdh155122 /* 2513448Sdh155122 * We want to be informed each time a stack is created or 2523448Sdh155122 * destroyed in the kernel. 2533448Sdh155122 */ 254*7513SDarren.Reed@Sun.COM netstack_register(NS_HOOK, hook_stack_init, hook_stack_shutdown, 2553448Sdh155122 hook_stack_fini); 2563448Sdh155122 } 2573448Sdh155122 2583448Sdh155122 /* 2593448Sdh155122 * Function: hook_fini 2603448Sdh155122 * Returns: None 2613448Sdh155122 * Parameters: None 2623448Sdh155122 * 2633448Sdh155122 * Deinitialize hooks 2643448Sdh155122 */ 2653448Sdh155122 static void 2663448Sdh155122 hook_fini(void) 2673448Sdh155122 { 2683448Sdh155122 netstack_unregister(NS_HOOK); 269*7513SDarren.Reed@Sun.COM 270*7513SDarren.Reed@Sun.COM mutex_destroy(&hook_stack_lock); 271*7513SDarren.Reed@Sun.COM ASSERT(SLIST_EMPTY(&hook_stacks)); 272*7513SDarren.Reed@Sun.COM } 273*7513SDarren.Reed@Sun.COM 274*7513SDarren.Reed@Sun.COM /* 275*7513SDarren.Reed@Sun.COM * Function: hook_wait_setflag 276*7513SDarren.Reed@Sun.COM * Returns: -1 = setting flag is disallowed, 0 = flag set and did 277*7513SDarren.Reed@Sun.COM * not have to wait (ie no lock droped), 1 = flag set but 278*7513SDarren.Reed@Sun.COM * it was necessary to drop locks to set it. 279*7513SDarren.Reed@Sun.COM * Parameters: waiter(I) - control data structure 280*7513SDarren.Reed@Sun.COM * busyset(I) - set of flags that we don't want set while 281*7513SDarren.Reed@Sun.COM * we are active. 282*7513SDarren.Reed@Sun.COM * wanted(I) - flag associated with newflag to indicate 283*7513SDarren.Reed@Sun.COM * what we want to do. 284*7513SDarren.Reed@Sun.COM * newflag(I) - the new ACTIVE flag we want to set that 285*7513SDarren.Reed@Sun.COM * indicates what we are doing. 286*7513SDarren.Reed@Sun.COM * 287*7513SDarren.Reed@Sun.COM * The set of functions hook_wait_* implement an API that builds on top of 288*7513SDarren.Reed@Sun.COM * the kcondvar_t to provide controlled execution through a critical region. 289*7513SDarren.Reed@Sun.COM * For each flag that indicates work is being done (FWF_*_ACTIVE) there is 290*7513SDarren.Reed@Sun.COM * also a flag that we set to indicate that we want to do it (FWF_*_WANTED). 291*7513SDarren.Reed@Sun.COM * The combination of flags is required as when this function exits to do 292*7513SDarren.Reed@Sun.COM * the task, the structure is then free for another caller to use and 293*7513SDarren.Reed@Sun.COM * to indicate that it wants to do work. The trump flags here are those 294*7513SDarren.Reed@Sun.COM * that indicate someone wants to destroy the structure that owns this 295*7513SDarren.Reed@Sun.COM * flagwait_t. In this case, we don't try to secure the ability to run 296*7513SDarren.Reed@Sun.COM * and return with an error. 297*7513SDarren.Reed@Sun.COM * 298*7513SDarren.Reed@Sun.COM * wanted - the FWF_*_WANTED flag that describes the action being requested 299*7513SDarren.Reed@Sun.COM * busyset- the set of FWF_* flags we don't want set when we run 300*7513SDarren.Reed@Sun.COM * newflag- the FWF_*_ACTIVE flag we will set to indicate we are busy 301*7513SDarren.Reed@Sun.COM */ 302*7513SDarren.Reed@Sun.COM int 303*7513SDarren.Reed@Sun.COM hook_wait_setflag(flagwait_t *waiter, uint32_t busyset, fwflag_t wanted, 304*7513SDarren.Reed@Sun.COM fwflag_t newflag) 305*7513SDarren.Reed@Sun.COM { 306*7513SDarren.Reed@Sun.COM int waited = 0; 307*7513SDarren.Reed@Sun.COM 308*7513SDarren.Reed@Sun.COM mutex_enter(&waiter->fw_lock); 309*7513SDarren.Reed@Sun.COM if (waiter->fw_flags & FWF_DESTROY) { 310*7513SDarren.Reed@Sun.COM mutex_exit(&waiter->fw_lock); 311*7513SDarren.Reed@Sun.COM return (-1); 312*7513SDarren.Reed@Sun.COM } 313*7513SDarren.Reed@Sun.COM while (waiter->fw_flags & busyset) { 314*7513SDarren.Reed@Sun.COM waiter->fw_flags |= wanted; 315*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(waiter->fw_owner); 316*7513SDarren.Reed@Sun.COM cv_wait(&waiter->fw_cv, &waiter->fw_lock); 317*7513SDarren.Reed@Sun.COM waited = 1; 318*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(waiter->fw_owner); 319*7513SDarren.Reed@Sun.COM if (waiter->fw_flags & FWF_DESTROY) { 320*7513SDarren.Reed@Sun.COM waiter->fw_flags &= ~wanted; 321*7513SDarren.Reed@Sun.COM mutex_exit(&waiter->fw_lock); 322*7513SDarren.Reed@Sun.COM return (-1); 323*7513SDarren.Reed@Sun.COM } 324*7513SDarren.Reed@Sun.COM waiter->fw_flags |= wanted; 325*7513SDarren.Reed@Sun.COM } 326*7513SDarren.Reed@Sun.COM waiter->fw_flags &= ~wanted; 327*7513SDarren.Reed@Sun.COM waiter->fw_flags |= newflag; 328*7513SDarren.Reed@Sun.COM mutex_exit(&waiter->fw_lock); 329*7513SDarren.Reed@Sun.COM return (waited); 330*7513SDarren.Reed@Sun.COM } 331*7513SDarren.Reed@Sun.COM 332*7513SDarren.Reed@Sun.COM /* 333*7513SDarren.Reed@Sun.COM * Function: hook_wait_unsetflag 334*7513SDarren.Reed@Sun.COM * Returns: None 335*7513SDarren.Reed@Sun.COM * Parameters: waiter(I) - control data structure 336*7513SDarren.Reed@Sun.COM * oldflag(I) - flag to reset 337*7513SDarren.Reed@Sun.COM * 338*7513SDarren.Reed@Sun.COM * Turn off the bit that we had set to run and let others know that 339*7513SDarren.Reed@Sun.COM * they should now check to see if they can run. 340*7513SDarren.Reed@Sun.COM */ 341*7513SDarren.Reed@Sun.COM void 342*7513SDarren.Reed@Sun.COM hook_wait_unsetflag(flagwait_t *waiter, uint32_t oldflag) 343*7513SDarren.Reed@Sun.COM { 344*7513SDarren.Reed@Sun.COM mutex_enter(&waiter->fw_lock); 345*7513SDarren.Reed@Sun.COM waiter->fw_flags &= ~oldflag; 346*7513SDarren.Reed@Sun.COM cv_signal(&waiter->fw_cv); 347*7513SDarren.Reed@Sun.COM mutex_exit(&waiter->fw_lock); 348*7513SDarren.Reed@Sun.COM } 349*7513SDarren.Reed@Sun.COM 350*7513SDarren.Reed@Sun.COM /* 351*7513SDarren.Reed@Sun.COM * Function: hook_wait_destroy 352*7513SDarren.Reed@Sun.COM * Returns: None 353*7513SDarren.Reed@Sun.COM * Parameters: waiter(I) - control data structure 354*7513SDarren.Reed@Sun.COM * 355*7513SDarren.Reed@Sun.COM * Since outer locking (on fw_owner) should ensure that only one function 356*7513SDarren.Reed@Sun.COM * at a time gets to call hook_wait_destroy() on a given object, there is 357*7513SDarren.Reed@Sun.COM * no need to guard against setting FWF_DESTROY_WANTED already being set. 358*7513SDarren.Reed@Sun.COM * It is, however, necessary to wait for all activity on the owning 359*7513SDarren.Reed@Sun.COM * structure to cease. 360*7513SDarren.Reed@Sun.COM */ 361*7513SDarren.Reed@Sun.COM void 362*7513SDarren.Reed@Sun.COM hook_wait_destroy(flagwait_t *waiter) 363*7513SDarren.Reed@Sun.COM { 364*7513SDarren.Reed@Sun.COM ASSERT((waiter->fw_flags & FWF_DESTROY_WANTED) == 0); 365*7513SDarren.Reed@Sun.COM waiter->fw_flags |= FWF_DESTROY_WANTED; 366*7513SDarren.Reed@Sun.COM while (!FWF_DESTROY_OK(waiter)) { 367*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(waiter->fw_owner); 368*7513SDarren.Reed@Sun.COM cv_wait(&waiter->fw_cv, &waiter->fw_lock); 369*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(waiter->fw_owner); 370*7513SDarren.Reed@Sun.COM } 371*7513SDarren.Reed@Sun.COM /* 372*7513SDarren.Reed@Sun.COM * There should now be nothing else using "waiter" or its 373*7513SDarren.Reed@Sun.COM * owner, so we can safely assign here without risk of wiiping 374*7513SDarren.Reed@Sun.COM * out someone's bit. 375*7513SDarren.Reed@Sun.COM */ 376*7513SDarren.Reed@Sun.COM waiter->fw_flags = FWF_DESTROY_ACTIVE; 377*7513SDarren.Reed@Sun.COM } 378*7513SDarren.Reed@Sun.COM 379*7513SDarren.Reed@Sun.COM /* 380*7513SDarren.Reed@Sun.COM * Function: hook_wait_init 381*7513SDarren.Reed@Sun.COM * Returns: None 382*7513SDarren.Reed@Sun.COM * Parameters: waiter(I) - control data structure 383*7513SDarren.Reed@Sun.COM * ownder(I) - pointer to lock that the owner of this 384*7513SDarren.Reed@Sun.COM * waiter uses 385*7513SDarren.Reed@Sun.COM * 386*7513SDarren.Reed@Sun.COM * "owner" gets passed in here so that when we need to call cv_wait, 387*7513SDarren.Reed@Sun.COM * for example in hook_wait_setflag(), we can drop the lock for the 388*7513SDarren.Reed@Sun.COM * next layer out, which is likely to be held in an exclusive manner. 389*7513SDarren.Reed@Sun.COM */ 390*7513SDarren.Reed@Sun.COM void 391*7513SDarren.Reed@Sun.COM hook_wait_init(flagwait_t *waiter, cvwaitlock_t *owner) 392*7513SDarren.Reed@Sun.COM { 393*7513SDarren.Reed@Sun.COM cv_init(&waiter->fw_cv, NULL, CV_DRIVER, NULL); 394*7513SDarren.Reed@Sun.COM mutex_init(&waiter->fw_lock, NULL, MUTEX_DRIVER, NULL); 395*7513SDarren.Reed@Sun.COM waiter->fw_flags = FWF_NONE; 396*7513SDarren.Reed@Sun.COM waiter->fw_owner = owner; 3972958Sdr146992 } 3982958Sdr146992 3993448Sdh155122 /* 4003448Sdh155122 * Initialize the hook stack instance. 4013448Sdh155122 */ 4023448Sdh155122 /*ARGSUSED*/ 4033448Sdh155122 static void * 4043448Sdh155122 hook_stack_init(netstackid_t stackid, netstack_t *ns) 4053448Sdh155122 { 4063448Sdh155122 hook_stack_t *hks; 4073448Sdh155122 4083448Sdh155122 #ifdef NS_DEBUG 4093448Sdh155122 printf("hook_stack_init(stack %d)\n", stackid); 4103448Sdh155122 #endif 4113448Sdh155122 4123448Sdh155122 hks = (hook_stack_t *)kmem_zalloc(sizeof (*hks), KM_SLEEP); 413*7513SDarren.Reed@Sun.COM hks->hks_netstack = ns; 414*7513SDarren.Reed@Sun.COM hks->hks_netstackid = stackid; 4153448Sdh155122 416*7513SDarren.Reed@Sun.COM CVW_INIT(&hks->hks_lock); 417*7513SDarren.Reed@Sun.COM TAILQ_INIT(&hks->hks_nhead); 4183448Sdh155122 SLIST_INIT(&hks->hks_familylist); 4193448Sdh155122 420*7513SDarren.Reed@Sun.COM hook_wait_init(&hks->hks_waiter, &hks->hks_lock); 421*7513SDarren.Reed@Sun.COM 422*7513SDarren.Reed@Sun.COM mutex_enter(&hook_stack_lock); 423*7513SDarren.Reed@Sun.COM SLIST_INSERT_HEAD(&hook_stacks, hks, hks_entry); 424*7513SDarren.Reed@Sun.COM mutex_exit(&hook_stack_lock); 425*7513SDarren.Reed@Sun.COM 4263448Sdh155122 return (hks); 4273448Sdh155122 } 4283448Sdh155122 429*7513SDarren.Reed@Sun.COM /*ARGSUSED*/ 430*7513SDarren.Reed@Sun.COM static void 431*7513SDarren.Reed@Sun.COM hook_stack_shutdown(netstackid_t stackid, void *arg) 432*7513SDarren.Reed@Sun.COM { 433*7513SDarren.Reed@Sun.COM hook_stack_t *hks = (hook_stack_t *)arg; 434*7513SDarren.Reed@Sun.COM 435*7513SDarren.Reed@Sun.COM mutex_enter(&hook_stack_lock); 436*7513SDarren.Reed@Sun.COM /* 437*7513SDarren.Reed@Sun.COM * Once this flag gets set to one, no more additions are allowed 438*7513SDarren.Reed@Sun.COM * to any of the structures that make up this stack. 439*7513SDarren.Reed@Sun.COM */ 440*7513SDarren.Reed@Sun.COM hks->hks_shutdown = 1; 441*7513SDarren.Reed@Sun.COM mutex_exit(&hook_stack_lock); 442*7513SDarren.Reed@Sun.COM } 443*7513SDarren.Reed@Sun.COM 4443448Sdh155122 /* 4453448Sdh155122 * Free the hook stack instance. 4463448Sdh155122 */ 4473448Sdh155122 /*ARGSUSED*/ 4483448Sdh155122 static void 4493448Sdh155122 hook_stack_fini(netstackid_t stackid, void *arg) 4503448Sdh155122 { 451*7513SDarren.Reed@Sun.COM hook_stack_t *hks = (hook_stack_t *)arg; 452*7513SDarren.Reed@Sun.COM 453*7513SDarren.Reed@Sun.COM mutex_enter(&hook_stack_lock); 454*7513SDarren.Reed@Sun.COM hks->hks_shutdown = 2; 455*7513SDarren.Reed@Sun.COM hook_stack_remove(hks); 456*7513SDarren.Reed@Sun.COM mutex_exit(&hook_stack_lock); 457*7513SDarren.Reed@Sun.COM } 458*7513SDarren.Reed@Sun.COM 459*7513SDarren.Reed@Sun.COM /* 460*7513SDarren.Reed@Sun.COM * This function assumes that it is called with hook_stack_lock held. 461*7513SDarren.Reed@Sun.COM * It functions differently to hook_family/event_remove in that it does 462*7513SDarren.Reed@Sun.COM * the checks to see if it can be removed. This difference exists 463*7513SDarren.Reed@Sun.COM * because this structure has nothing higher up that depends on it. 464*7513SDarren.Reed@Sun.COM */ 465*7513SDarren.Reed@Sun.COM static void 466*7513SDarren.Reed@Sun.COM hook_stack_remove(hook_stack_t *hks) 467*7513SDarren.Reed@Sun.COM { 468*7513SDarren.Reed@Sun.COM 469*7513SDarren.Reed@Sun.COM ASSERT(mutex_owned(&hook_stack_lock)); 470*7513SDarren.Reed@Sun.COM 471*7513SDarren.Reed@Sun.COM /* 472*7513SDarren.Reed@Sun.COM * Is the structure still in use? 473*7513SDarren.Reed@Sun.COM */ 474*7513SDarren.Reed@Sun.COM if (!SLIST_EMPTY(&hks->hks_familylist) || 475*7513SDarren.Reed@Sun.COM !TAILQ_EMPTY(&hks->hks_nhead)) 476*7513SDarren.Reed@Sun.COM return; 477*7513SDarren.Reed@Sun.COM 478*7513SDarren.Reed@Sun.COM SLIST_REMOVE(&hook_stacks, hks, hook_stack, hks_entry); 479*7513SDarren.Reed@Sun.COM 480*7513SDarren.Reed@Sun.COM hook_wait_destroy(&hks->hks_waiter); 481*7513SDarren.Reed@Sun.COM CVW_DESTROY(&hks->hks_lock); 4823448Sdh155122 kmem_free(hks, sizeof (*hks)); 4833448Sdh155122 } 4842958Sdr146992 485*7513SDarren.Reed@Sun.COM static hook_stack_t * 486*7513SDarren.Reed@Sun.COM hook_stack_get(netstackid_t stackid) 487*7513SDarren.Reed@Sun.COM { 488*7513SDarren.Reed@Sun.COM hook_stack_t *hks; 489*7513SDarren.Reed@Sun.COM 490*7513SDarren.Reed@Sun.COM SLIST_FOREACH(hks, &hook_stacks, hks_entry) { 491*7513SDarren.Reed@Sun.COM if (hks->hks_netstackid == stackid) 492*7513SDarren.Reed@Sun.COM break; 493*7513SDarren.Reed@Sun.COM } 494*7513SDarren.Reed@Sun.COM 495*7513SDarren.Reed@Sun.COM return (hks); 496*7513SDarren.Reed@Sun.COM } 497*7513SDarren.Reed@Sun.COM 498*7513SDarren.Reed@Sun.COM /* 499*7513SDarren.Reed@Sun.COM * Function: hook_stack_notify_register 500*7513SDarren.Reed@Sun.COM * Returns: 0 = success, else failure 501*7513SDarren.Reed@Sun.COM * Parameters: stackid(I) - netstack identifier 502*7513SDarren.Reed@Sun.COM * callback(I)- function to be called 503*7513SDarren.Reed@Sun.COM * arg(I) - arg to provide callback when it is called 504*7513SDarren.Reed@Sun.COM * 505*7513SDarren.Reed@Sun.COM * If we're not shutting down this instance, append a new function to the 506*7513SDarren.Reed@Sun.COM * list of those to call when a new family of hooks is added to this stack. 507*7513SDarren.Reed@Sun.COM */ 508*7513SDarren.Reed@Sun.COM int 509*7513SDarren.Reed@Sun.COM hook_stack_notify_register(netstackid_t stackid, hook_notify_fn_t callback, 510*7513SDarren.Reed@Sun.COM void *arg) 511*7513SDarren.Reed@Sun.COM { 512*7513SDarren.Reed@Sun.COM hook_stack_t *hks; 513*7513SDarren.Reed@Sun.COM int error; 514*7513SDarren.Reed@Sun.COM 515*7513SDarren.Reed@Sun.COM mutex_enter(&hook_stack_lock); 516*7513SDarren.Reed@Sun.COM hks = hook_stack_get(stackid); 517*7513SDarren.Reed@Sun.COM if (hks != NULL) { 518*7513SDarren.Reed@Sun.COM if (hks->hks_shutdown != 0) { 519*7513SDarren.Reed@Sun.COM error = ESHUTDOWN; 520*7513SDarren.Reed@Sun.COM } else { 521*7513SDarren.Reed@Sun.COM error = hook_notify_register(&hks->hks_lock, 522*7513SDarren.Reed@Sun.COM &hks->hks_nhead, callback, arg); 523*7513SDarren.Reed@Sun.COM } 524*7513SDarren.Reed@Sun.COM } else { 525*7513SDarren.Reed@Sun.COM error = ESRCH; 526*7513SDarren.Reed@Sun.COM } 527*7513SDarren.Reed@Sun.COM mutex_exit(&hook_stack_lock); 528*7513SDarren.Reed@Sun.COM 529*7513SDarren.Reed@Sun.COM return (error); 530*7513SDarren.Reed@Sun.COM } 531*7513SDarren.Reed@Sun.COM 532*7513SDarren.Reed@Sun.COM /* 533*7513SDarren.Reed@Sun.COM * Function: hook_stack_notify_unregister 534*7513SDarren.Reed@Sun.COM * Returns: 0 = success, else failure 535*7513SDarren.Reed@Sun.COM * Parameters: stackid(I) - netstack identifier 536*7513SDarren.Reed@Sun.COM * callback(I) - function to be called 537*7513SDarren.Reed@Sun.COM * 538*7513SDarren.Reed@Sun.COM * Attempt to remove a registered function from a hook stack's list of 539*7513SDarren.Reed@Sun.COM * callbacks to activiate when protocols are added/deleted. 540*7513SDarren.Reed@Sun.COM */ 541*7513SDarren.Reed@Sun.COM int 542*7513SDarren.Reed@Sun.COM hook_stack_notify_unregister(netstackid_t stackid, hook_notify_fn_t callback) 543*7513SDarren.Reed@Sun.COM { 544*7513SDarren.Reed@Sun.COM hook_stack_t *hks; 545*7513SDarren.Reed@Sun.COM int error; 546*7513SDarren.Reed@Sun.COM 547*7513SDarren.Reed@Sun.COM mutex_enter(&hook_stack_lock); 548*7513SDarren.Reed@Sun.COM hks = hook_stack_get(stackid); 549*7513SDarren.Reed@Sun.COM if (hks != NULL) { 550*7513SDarren.Reed@Sun.COM error = hook_notify_unregister(&hks->hks_lock, 551*7513SDarren.Reed@Sun.COM &hks->hks_nhead, callback); 552*7513SDarren.Reed@Sun.COM if ((error == 0) && (hks->hks_shutdown == 2)) 553*7513SDarren.Reed@Sun.COM hook_stack_remove(hks); 554*7513SDarren.Reed@Sun.COM } else { 555*7513SDarren.Reed@Sun.COM error = ESRCH; 556*7513SDarren.Reed@Sun.COM } 557*7513SDarren.Reed@Sun.COM mutex_exit(&hook_stack_lock); 558*7513SDarren.Reed@Sun.COM 559*7513SDarren.Reed@Sun.COM return (error); 560*7513SDarren.Reed@Sun.COM } 561*7513SDarren.Reed@Sun.COM 562*7513SDarren.Reed@Sun.COM /* 563*7513SDarren.Reed@Sun.COM * Function: hook_stack_notify_run 564*7513SDarren.Reed@Sun.COM * Returns: None 565*7513SDarren.Reed@Sun.COM * Parameters: hks(I) - hook stack pointer to execute callbacks for 566*7513SDarren.Reed@Sun.COM * name(I) - name of a hook family 567*7513SDarren.Reed@Sun.COM * cmd(I) - either HN_UNREGISTER or HN_REGISTER 568*7513SDarren.Reed@Sun.COM * 569*7513SDarren.Reed@Sun.COM * Run through the list of callbacks on the hook stack to be called when 570*7513SDarren.Reed@Sun.COM * a new hook family is added 571*7513SDarren.Reed@Sun.COM * 572*7513SDarren.Reed@Sun.COM * As hook_notify_run() expects 3 names, one for the family, one for the 573*7513SDarren.Reed@Sun.COM * event and one for the object being introduced and we really only have 574*7513SDarren.Reed@Sun.COM * one name (that of the new hook family), fake the hook stack's name by 575*7513SDarren.Reed@Sun.COM * converting the integer to a string and for the event just pass NULL. 576*7513SDarren.Reed@Sun.COM */ 577*7513SDarren.Reed@Sun.COM static void 578*7513SDarren.Reed@Sun.COM hook_stack_notify_run(hook_stack_t *hks, char *name, 579*7513SDarren.Reed@Sun.COM hook_notify_cmd_t cmd) 580*7513SDarren.Reed@Sun.COM { 581*7513SDarren.Reed@Sun.COM char buffer[16]; 582*7513SDarren.Reed@Sun.COM 583*7513SDarren.Reed@Sun.COM (void) snprintf(buffer, sizeof (buffer), "%u", hks->hks_netstackid); 584*7513SDarren.Reed@Sun.COM 585*7513SDarren.Reed@Sun.COM hook_notify_run(&hks->hks_nhead, buffer, NULL, name, cmd); 586*7513SDarren.Reed@Sun.COM } 587*7513SDarren.Reed@Sun.COM 5882958Sdr146992 /* 5892958Sdr146992 * Function: hook_run 5902958Sdr146992 * Returns: int - return value according to callback func 5912958Sdr146992 * Parameters: token(I) - event pointer 5922958Sdr146992 * info(I) - message 5932958Sdr146992 * 5942958Sdr146992 * Run hooks for specific provider. The hooks registered are stepped through 5952958Sdr146992 * until either the end of the list is reached or a hook function returns a 5962958Sdr146992 * non-zero value. If a non-zero value is returned from a hook function, we 5972958Sdr146992 * return that value back to our caller. By design, a hook function can be 5982958Sdr146992 * called more than once, simultaneously. 5992958Sdr146992 */ 6002958Sdr146992 int 601*7513SDarren.Reed@Sun.COM hook_run(hook_family_int_t *hfi, hook_event_token_t token, hook_data_t info) 6022958Sdr146992 { 603*7513SDarren.Reed@Sun.COM hook_event_int_t *hei; 6042958Sdr146992 hook_int_t *hi; 6052958Sdr146992 int rval = 0; 6062958Sdr146992 6072958Sdr146992 ASSERT(token != NULL); 6082958Sdr146992 6092958Sdr146992 hei = (hook_event_int_t *)token; 6102958Sdr146992 DTRACE_PROBE2(hook__run__start, 6112958Sdr146992 hook_event_token_t, token, 6122958Sdr146992 hook_data_t, info); 6132958Sdr146992 614*7513SDarren.Reed@Sun.COM /* 615*7513SDarren.Reed@Sun.COM * Hold global read lock to ensure event will not be deleted. 616*7513SDarren.Reed@Sun.COM * While it might be expected that we should also hold a read lock 617*7513SDarren.Reed@Sun.COM * on the event lock (hei_lock) to prevent the hook list from 618*7513SDarren.Reed@Sun.COM * changing while we're executing this function, both addition 619*7513SDarren.Reed@Sun.COM * to and removal from the hook list on the event is done with 620*7513SDarren.Reed@Sun.COM * a write lock held on hfi_lock. This is by design so that we 621*7513SDarren.Reed@Sun.COM * only need to get one of these locks to process a packet. 622*7513SDarren.Reed@Sun.COM * - locking is not a cheap thing to do for every packet. 623*7513SDarren.Reed@Sun.COM */ 624*7513SDarren.Reed@Sun.COM CVW_ENTER_READ(&hfi->hfi_lock); 6252958Sdr146992 6262958Sdr146992 TAILQ_FOREACH(hi, &hei->hei_head, hi_entry) { 6272958Sdr146992 ASSERT(hi->hi_hook.h_func != NULL); 6282958Sdr146992 DTRACE_PROBE3(hook__func__start, 6292958Sdr146992 hook_event_token_t, token, 6302958Sdr146992 hook_data_t, info, 6312958Sdr146992 hook_int_t *, hi); 632*7513SDarren.Reed@Sun.COM rval = (*hi->hi_hook.h_func)(token, info, hi->hi_hook.h_arg); 6332958Sdr146992 DTRACE_PROBE4(hook__func__end, 6342958Sdr146992 hook_event_token_t, token, 6352958Sdr146992 hook_data_t, info, 6362958Sdr146992 hook_int_t *, hi, 6372958Sdr146992 int, rval); 638*7513SDarren.Reed@Sun.COM hi->hi_kstats.hook_hits.value.ui64++; 6392958Sdr146992 if (rval != 0) 6402958Sdr146992 break; 6412958Sdr146992 } 6422958Sdr146992 643*7513SDarren.Reed@Sun.COM hei->hei_kstats.events.value.ui64++; 644*7513SDarren.Reed@Sun.COM 645*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hfi->hfi_lock); 6462958Sdr146992 6472958Sdr146992 DTRACE_PROBE3(hook__run__end, 6482958Sdr146992 hook_event_token_t, token, 6492958Sdr146992 hook_data_t, info, 6502958Sdr146992 hook_int_t *, hi); 6512958Sdr146992 6522958Sdr146992 return (rval); 6532958Sdr146992 } 6542958Sdr146992 6552958Sdr146992 /* 6562958Sdr146992 * Function: hook_family_add 6572958Sdr146992 * Returns: internal family pointer - NULL = Fail 6582958Sdr146992 * Parameters: hf(I) - family pointer 6592958Sdr146992 * 6602958Sdr146992 * Add new family to family list 6612958Sdr146992 */ 6622958Sdr146992 hook_family_int_t * 6633448Sdh155122 hook_family_add(hook_family_t *hf, hook_stack_t *hks) 6642958Sdr146992 { 6652958Sdr146992 hook_family_int_t *hfi, *new; 6662958Sdr146992 6672958Sdr146992 ASSERT(hf != NULL); 6682958Sdr146992 ASSERT(hf->hf_name != NULL); 6692958Sdr146992 6702958Sdr146992 new = hook_family_copy(hf); 6712958Sdr146992 if (new == NULL) 6722958Sdr146992 return (NULL); 6732958Sdr146992 674*7513SDarren.Reed@Sun.COM mutex_enter(&hook_stack_lock); 675*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(&hks->hks_lock); 676*7513SDarren.Reed@Sun.COM 677*7513SDarren.Reed@Sun.COM if (hks->hks_shutdown != 0) { 678*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hks->hks_lock); 679*7513SDarren.Reed@Sun.COM mutex_exit(&hook_stack_lock); 680*7513SDarren.Reed@Sun.COM hook_family_free(new, NULL); 681*7513SDarren.Reed@Sun.COM return (NULL); 682*7513SDarren.Reed@Sun.COM } 6832958Sdr146992 6842958Sdr146992 /* search family list */ 6853448Sdh155122 hfi = hook_family_find(hf->hf_name, hks); 6862958Sdr146992 if (hfi != NULL) { 687*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hks->hks_lock); 688*7513SDarren.Reed@Sun.COM mutex_exit(&hook_stack_lock); 689*7513SDarren.Reed@Sun.COM hook_family_free(new, NULL); 6902958Sdr146992 return (NULL); 6912958Sdr146992 } 6922958Sdr146992 693*7513SDarren.Reed@Sun.COM if (hook_wait_setflag(&hks->hks_waiter, FWF_WAIT_MASK, 694*7513SDarren.Reed@Sun.COM FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) { 695*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hks->hks_lock); 696*7513SDarren.Reed@Sun.COM mutex_exit(&hook_stack_lock); 697*7513SDarren.Reed@Sun.COM hook_family_free(new, NULL); 698*7513SDarren.Reed@Sun.COM return (NULL); 699*7513SDarren.Reed@Sun.COM } 700*7513SDarren.Reed@Sun.COM 701*7513SDarren.Reed@Sun.COM CVW_INIT(&new->hfi_lock); 702*7513SDarren.Reed@Sun.COM SLIST_INIT(&new->hfi_head); 703*7513SDarren.Reed@Sun.COM TAILQ_INIT(&new->hfi_nhead); 704*7513SDarren.Reed@Sun.COM 705*7513SDarren.Reed@Sun.COM hook_wait_init(&new->hfi_waiter, &new->hfi_lock); 706*7513SDarren.Reed@Sun.COM 707*7513SDarren.Reed@Sun.COM new->hfi_stack = hks; 7083448Sdh155122 7092958Sdr146992 /* Add to family list head */ 7103448Sdh155122 SLIST_INSERT_HEAD(&hks->hks_familylist, new, hfi_entry); 7112958Sdr146992 712*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hks->hks_lock); 713*7513SDarren.Reed@Sun.COM mutex_exit(&hook_stack_lock); 714*7513SDarren.Reed@Sun.COM 715*7513SDarren.Reed@Sun.COM hook_stack_notify_run(hks, hf->hf_name, HN_REGISTER); 716*7513SDarren.Reed@Sun.COM 717*7513SDarren.Reed@Sun.COM hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE); 718*7513SDarren.Reed@Sun.COM 7192958Sdr146992 return (new); 7202958Sdr146992 } 7212958Sdr146992 7222958Sdr146992 /* 7232958Sdr146992 * Function: hook_family_remove 7242958Sdr146992 * Returns: int - 0 = Succ, Else = Fail 7252958Sdr146992 * Parameters: hfi(I) - internal family pointer 7262958Sdr146992 * 727*7513SDarren.Reed@Sun.COM * Remove family from family list. This function has been designed to be 728*7513SDarren.Reed@Sun.COM * called once and once only per hook_family_int_t. Thus when cleaning up 729*7513SDarren.Reed@Sun.COM * this structure as an orphan, callers should only call hook_family_free. 7302958Sdr146992 */ 7312958Sdr146992 int 7322958Sdr146992 hook_family_remove(hook_family_int_t *hfi) 7332958Sdr146992 { 7343448Sdh155122 hook_stack_t *hks; 7352958Sdr146992 7362958Sdr146992 ASSERT(hfi != NULL); 737*7513SDarren.Reed@Sun.COM hks = hfi->hfi_stack; 738*7513SDarren.Reed@Sun.COM 739*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(&hks->hks_lock); 7402958Sdr146992 741*7513SDarren.Reed@Sun.COM if (hook_wait_setflag(&hks->hks_waiter, FWF_WAIT_MASK, 742*7513SDarren.Reed@Sun.COM FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) { 743*7513SDarren.Reed@Sun.COM /* 744*7513SDarren.Reed@Sun.COM * If we're trying to destroy the hook_stack_t... 745*7513SDarren.Reed@Sun.COM */ 746*7513SDarren.Reed@Sun.COM return (ENXIO); 747*7513SDarren.Reed@Sun.COM } 7482958Sdr146992 749*7513SDarren.Reed@Sun.COM /* 750*7513SDarren.Reed@Sun.COM * Check if the family is in use by the presence of either events 751*7513SDarren.Reed@Sun.COM * or notify callbacks on the hook family. 752*7513SDarren.Reed@Sun.COM */ 753*7513SDarren.Reed@Sun.COM if (!SLIST_EMPTY(&hfi->hfi_head) || !TAILQ_EMPTY(&hfi->hfi_nhead)) { 754*7513SDarren.Reed@Sun.COM hfi->hfi_condemned = B_TRUE; 755*7513SDarren.Reed@Sun.COM } else { 756*7513SDarren.Reed@Sun.COM /* 757*7513SDarren.Reed@Sun.COM * Although hfi_condemned = B_FALSE is implied from creation, 758*7513SDarren.Reed@Sun.COM * putting a comment here inside the else upsets lint. 759*7513SDarren.Reed@Sun.COM */ 760*7513SDarren.Reed@Sun.COM hfi->hfi_condemned = B_FALSE; 7612958Sdr146992 } 7622958Sdr146992 763*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(&hfi->hfi_lock); 764*7513SDarren.Reed@Sun.COM hook_wait_destroy(&hfi->hfi_waiter); 765*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 766*7513SDarren.Reed@Sun.COM 767*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hks->hks_lock); 768*7513SDarren.Reed@Sun.COM 769*7513SDarren.Reed@Sun.COM hook_stack_notify_run(hks, hfi->hfi_family.hf_name, HN_UNREGISTER); 7702958Sdr146992 771*7513SDarren.Reed@Sun.COM hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE); 772*7513SDarren.Reed@Sun.COM 773*7513SDarren.Reed@Sun.COM /* 774*7513SDarren.Reed@Sun.COM * If we don't have to wait for anything else to disappear from this 775*7513SDarren.Reed@Sun.COM * structure then we can free it up. 776*7513SDarren.Reed@Sun.COM */ 777*7513SDarren.Reed@Sun.COM if (!hfi->hfi_condemned) 778*7513SDarren.Reed@Sun.COM hook_family_free(hfi, hks); 7792958Sdr146992 7802958Sdr146992 return (0); 7812958Sdr146992 } 7822958Sdr146992 7832958Sdr146992 7842958Sdr146992 /* 785*7513SDarren.Reed@Sun.COM * Function: hook_family_free 786*7513SDarren.Reed@Sun.COM * Returns: None 787*7513SDarren.Reed@Sun.COM * Parameters: hfi(I) - internal family pointer 788*7513SDarren.Reed@Sun.COM * 789*7513SDarren.Reed@Sun.COM * Free alloc memory for family 790*7513SDarren.Reed@Sun.COM */ 791*7513SDarren.Reed@Sun.COM static void 792*7513SDarren.Reed@Sun.COM hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks) 793*7513SDarren.Reed@Sun.COM { 794*7513SDarren.Reed@Sun.COM 795*7513SDarren.Reed@Sun.COM /* 796*7513SDarren.Reed@Sun.COM * This lock gives us possession of the hks pointer after the 797*7513SDarren.Reed@Sun.COM * SLIST_REMOVE, for which it is not needed, when hks_shutdown 798*7513SDarren.Reed@Sun.COM * is checked and hook_stack_remove called. 799*7513SDarren.Reed@Sun.COM */ 800*7513SDarren.Reed@Sun.COM mutex_enter(&hook_stack_lock); 801*7513SDarren.Reed@Sun.COM 802*7513SDarren.Reed@Sun.COM ASSERT(hfi != NULL); 803*7513SDarren.Reed@Sun.COM 804*7513SDarren.Reed@Sun.COM if (hks != NULL) { 805*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(&hks->hks_lock); 806*7513SDarren.Reed@Sun.COM /* Remove from family list */ 807*7513SDarren.Reed@Sun.COM SLIST_REMOVE(&hks->hks_familylist, hfi, hook_family_int, 808*7513SDarren.Reed@Sun.COM hfi_entry); 809*7513SDarren.Reed@Sun.COM 810*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hks->hks_lock); 811*7513SDarren.Reed@Sun.COM } 812*7513SDarren.Reed@Sun.COM 813*7513SDarren.Reed@Sun.COM /* Free name space */ 814*7513SDarren.Reed@Sun.COM if (hfi->hfi_family.hf_name != NULL) { 815*7513SDarren.Reed@Sun.COM kmem_free(hfi->hfi_family.hf_name, 816*7513SDarren.Reed@Sun.COM strlen(hfi->hfi_family.hf_name) + 1); 817*7513SDarren.Reed@Sun.COM } 818*7513SDarren.Reed@Sun.COM 819*7513SDarren.Reed@Sun.COM /* Free container */ 820*7513SDarren.Reed@Sun.COM kmem_free(hfi, sizeof (*hfi)); 821*7513SDarren.Reed@Sun.COM 822*7513SDarren.Reed@Sun.COM if (hks->hks_shutdown == 2) 823*7513SDarren.Reed@Sun.COM hook_stack_remove(hks); 824*7513SDarren.Reed@Sun.COM 825*7513SDarren.Reed@Sun.COM mutex_exit(&hook_stack_lock); 826*7513SDarren.Reed@Sun.COM } 827*7513SDarren.Reed@Sun.COM 828*7513SDarren.Reed@Sun.COM 829*7513SDarren.Reed@Sun.COM /* 8302958Sdr146992 * Function: hook_family_copy 8312958Sdr146992 * Returns: internal family pointer - NULL = Failed 8322958Sdr146992 * Parameters: src(I) - family pointer 8332958Sdr146992 * 8342958Sdr146992 * Allocate internal family block and duplicate incoming family 8352958Sdr146992 * No locks should be held across this function as it may sleep. 8362958Sdr146992 */ 8372958Sdr146992 static hook_family_int_t * 8382958Sdr146992 hook_family_copy(hook_family_t *src) 8392958Sdr146992 { 8402958Sdr146992 hook_family_int_t *new; 8412958Sdr146992 hook_family_t *dst; 8422958Sdr146992 8432958Sdr146992 ASSERT(src != NULL); 8442958Sdr146992 ASSERT(src->hf_name != NULL); 8452958Sdr146992 8462958Sdr146992 new = (hook_family_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP); 8472958Sdr146992 8482958Sdr146992 /* Copy body */ 8492958Sdr146992 dst = &new->hfi_family; 8502958Sdr146992 *dst = *src; 8512958Sdr146992 852*7513SDarren.Reed@Sun.COM SLIST_INIT(&new->hfi_head); 853*7513SDarren.Reed@Sun.COM TAILQ_INIT(&new->hfi_nhead); 854*7513SDarren.Reed@Sun.COM 8552958Sdr146992 /* Copy name */ 8562958Sdr146992 dst->hf_name = (char *)kmem_alloc(strlen(src->hf_name) + 1, KM_SLEEP); 8572958Sdr146992 (void) strcpy(dst->hf_name, src->hf_name); 8582958Sdr146992 8592958Sdr146992 return (new); 8602958Sdr146992 } 8612958Sdr146992 8622958Sdr146992 /* 863*7513SDarren.Reed@Sun.COM * Function: hook_family_find 8642958Sdr146992 * Returns: internal family pointer - NULL = Not match 8652958Sdr146992 * Parameters: family(I) - family name string 8662958Sdr146992 * 8672958Sdr146992 * Search family list with family name 868*7513SDarren.Reed@Sun.COM * A lock on hfi_lock must be held when called. 8692958Sdr146992 */ 8702958Sdr146992 static hook_family_int_t * 8713448Sdh155122 hook_family_find(char *family, hook_stack_t *hks) 8722958Sdr146992 { 8732958Sdr146992 hook_family_int_t *hfi = NULL; 8742958Sdr146992 8752958Sdr146992 ASSERT(family != NULL); 8762958Sdr146992 8773448Sdh155122 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) { 8782958Sdr146992 if (strcmp(hfi->hfi_family.hf_name, family) == 0) 8792958Sdr146992 break; 8802958Sdr146992 } 8812958Sdr146992 return (hfi); 8822958Sdr146992 } 8832958Sdr146992 884*7513SDarren.Reed@Sun.COM /* 885*7513SDarren.Reed@Sun.COM * Function: hook_family_notify_register 886*7513SDarren.Reed@Sun.COM * Returns: 0 = success, else failure 887*7513SDarren.Reed@Sun.COM * Parameters: hfi(I) - hook family 888*7513SDarren.Reed@Sun.COM * callback(I) - function to be called 889*7513SDarren.Reed@Sun.COM * arg(I) - arg to provide callback when it is called 890*7513SDarren.Reed@Sun.COM * 891*7513SDarren.Reed@Sun.COM * So long as this hook stack isn't being shut down, register a new 892*7513SDarren.Reed@Sun.COM * callback to be activated each time a new event is added to this 893*7513SDarren.Reed@Sun.COM * family. 894*7513SDarren.Reed@Sun.COM * 895*7513SDarren.Reed@Sun.COM * To call this function we must have an active handle in use on the family, 896*7513SDarren.Reed@Sun.COM * so if we take this into account, then neither the hook_family_int_t nor 897*7513SDarren.Reed@Sun.COM * the hook_stack_t that owns it can disappear. We have to put some trust 898*7513SDarren.Reed@Sun.COM * in the callers to be properly synchronised... 899*7513SDarren.Reed@Sun.COM * 900*7513SDarren.Reed@Sun.COM * Holding hks_lock is required to provide synchronisation for hks_shutdown. 901*7513SDarren.Reed@Sun.COM */ 902*7513SDarren.Reed@Sun.COM int 903*7513SDarren.Reed@Sun.COM hook_family_notify_register(hook_family_int_t *hfi, 904*7513SDarren.Reed@Sun.COM hook_notify_fn_t callback, void *arg) 905*7513SDarren.Reed@Sun.COM { 906*7513SDarren.Reed@Sun.COM hook_stack_t *hks; 907*7513SDarren.Reed@Sun.COM int error; 908*7513SDarren.Reed@Sun.COM 909*7513SDarren.Reed@Sun.COM hks = hfi->hfi_stack; 910*7513SDarren.Reed@Sun.COM 911*7513SDarren.Reed@Sun.COM CVW_ENTER_READ(&hks->hks_lock); 912*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(&hfi->hfi_lock); 913*7513SDarren.Reed@Sun.COM 914*7513SDarren.Reed@Sun.COM if (hfi->hfi_stack->hks_shutdown != 0) { 915*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 916*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hks->hks_lock); 917*7513SDarren.Reed@Sun.COM return (ESHUTDOWN); 918*7513SDarren.Reed@Sun.COM } 919*7513SDarren.Reed@Sun.COM 920*7513SDarren.Reed@Sun.COM error = hook_notify_register(&hfi->hfi_lock, &hfi->hfi_nhead, 921*7513SDarren.Reed@Sun.COM callback, arg); 922*7513SDarren.Reed@Sun.COM 923*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 924*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hks->hks_lock); 925*7513SDarren.Reed@Sun.COM 926*7513SDarren.Reed@Sun.COM return (error); 927*7513SDarren.Reed@Sun.COM } 9282958Sdr146992 9292958Sdr146992 /* 930*7513SDarren.Reed@Sun.COM * Function: hook_family_notify_unregister 931*7513SDarren.Reed@Sun.COM * Returns: 0 = success, else failure 932*7513SDarren.Reed@Sun.COM * Parameters: hfi(I) - hook family 933*7513SDarren.Reed@Sun.COM * callback(I) - function to be called 9342958Sdr146992 * 935*7513SDarren.Reed@Sun.COM * Remove a callback from the list of those executed when a new event is 936*7513SDarren.Reed@Sun.COM * added to a hook family. 9372958Sdr146992 */ 938*7513SDarren.Reed@Sun.COM int 939*7513SDarren.Reed@Sun.COM hook_family_notify_unregister(hook_family_int_t *hfi, 940*7513SDarren.Reed@Sun.COM hook_notify_fn_t callback) 9412958Sdr146992 { 942*7513SDarren.Reed@Sun.COM boolean_t free_family; 943*7513SDarren.Reed@Sun.COM int error; 944*7513SDarren.Reed@Sun.COM 945*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(&hfi->hfi_lock); 9462958Sdr146992 947*7513SDarren.Reed@Sun.COM error = hook_notify_unregister(&hfi->hfi_lock, &hfi->hfi_nhead, 948*7513SDarren.Reed@Sun.COM callback); 949*7513SDarren.Reed@Sun.COM 950*7513SDarren.Reed@Sun.COM /* 951*7513SDarren.Reed@Sun.COM * If hook_family_remove has been called but the structure was still 952*7513SDarren.Reed@Sun.COM * "busy" ... but we might have just made it "unbusy"... 953*7513SDarren.Reed@Sun.COM */ 954*7513SDarren.Reed@Sun.COM if ((error == 0) && hfi->hfi_condemned && 955*7513SDarren.Reed@Sun.COM SLIST_EMPTY(&hfi->hfi_head) && TAILQ_EMPTY(&hfi->hfi_nhead)) { 956*7513SDarren.Reed@Sun.COM free_family = B_TRUE; 957*7513SDarren.Reed@Sun.COM } else { 958*7513SDarren.Reed@Sun.COM free_family = B_FALSE; 9592958Sdr146992 } 9602958Sdr146992 961*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 962*7513SDarren.Reed@Sun.COM 963*7513SDarren.Reed@Sun.COM if (free_family) 964*7513SDarren.Reed@Sun.COM hook_family_free(hfi, hfi->hfi_stack); 965*7513SDarren.Reed@Sun.COM 966*7513SDarren.Reed@Sun.COM return (error); 9672958Sdr146992 } 9682958Sdr146992 9692958Sdr146992 /* 9702958Sdr146992 * Function: hook_event_add 9712958Sdr146992 * Returns: internal event pointer - NULL = Fail 9722958Sdr146992 * Parameters: hfi(I) - internal family pointer 9732958Sdr146992 * he(I) - event pointer 9742958Sdr146992 * 9752958Sdr146992 * Add new event to event list on specific family. 9762958Sdr146992 * This function can fail to return successfully if (1) it cannot allocate 9772958Sdr146992 * enough memory for its own internal data structures, (2) the event has 9782958Sdr146992 * already been registered (for any hook family.) 9792958Sdr146992 */ 9802958Sdr146992 hook_event_int_t * 9812958Sdr146992 hook_event_add(hook_family_int_t *hfi, hook_event_t *he) 9822958Sdr146992 { 983*7513SDarren.Reed@Sun.COM hook_event_int_t *hei, *new; 9843448Sdh155122 hook_stack_t *hks; 9852958Sdr146992 9862958Sdr146992 ASSERT(hfi != NULL); 9872958Sdr146992 ASSERT(he != NULL); 9882958Sdr146992 ASSERT(he->he_name != NULL); 9892958Sdr146992 9902958Sdr146992 new = hook_event_copy(he); 9912958Sdr146992 if (new == NULL) 9922958Sdr146992 return (NULL); 9932958Sdr146992 994*7513SDarren.Reed@Sun.COM hks = hfi->hfi_stack; 995*7513SDarren.Reed@Sun.COM CVW_ENTER_READ(&hks->hks_lock); 996*7513SDarren.Reed@Sun.COM 997*7513SDarren.Reed@Sun.COM hks = hfi->hfi_stack; 998*7513SDarren.Reed@Sun.COM if (hks->hks_shutdown != 0) { 999*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hks->hks_lock); 1000*7513SDarren.Reed@Sun.COM hook_event_free(new, NULL); 1001*7513SDarren.Reed@Sun.COM return (NULL); 1002*7513SDarren.Reed@Sun.COM } 10032958Sdr146992 10042958Sdr146992 /* Check whether this event pointer is already registered */ 10053448Sdh155122 hei = hook_event_checkdup(he, hks); 10062958Sdr146992 if (hei != NULL) { 1007*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hks->hks_lock); 1008*7513SDarren.Reed@Sun.COM hook_event_free(new, NULL); 1009*7513SDarren.Reed@Sun.COM return (NULL); 1010*7513SDarren.Reed@Sun.COM } 1011*7513SDarren.Reed@Sun.COM 1012*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(&hfi->hfi_lock); 1013*7513SDarren.Reed@Sun.COM 1014*7513SDarren.Reed@Sun.COM if (hfi->hfi_condemned) { 1015*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 1016*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hks->hks_lock); 1017*7513SDarren.Reed@Sun.COM hook_event_free(new, NULL); 10182958Sdr146992 return (NULL); 10192958Sdr146992 } 10202958Sdr146992 1021*7513SDarren.Reed@Sun.COM if (hook_wait_setflag(&hfi->hfi_waiter, FWF_WAIT_MASK, 1022*7513SDarren.Reed@Sun.COM FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) { 1023*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 1024*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hks->hks_lock); 1025*7513SDarren.Reed@Sun.COM hook_event_free(new, NULL); 1026*7513SDarren.Reed@Sun.COM return (NULL); 1027*7513SDarren.Reed@Sun.COM } 1028*7513SDarren.Reed@Sun.COM 1029*7513SDarren.Reed@Sun.COM TAILQ_INIT(&new->hei_nhead); 1030*7513SDarren.Reed@Sun.COM 1031*7513SDarren.Reed@Sun.COM hook_event_init_kstats(hfi, new); 1032*7513SDarren.Reed@Sun.COM hook_wait_init(&new->hei_waiter, &new->hei_lock); 1033*7513SDarren.Reed@Sun.COM 10342958Sdr146992 /* Add to event list head */ 10352958Sdr146992 SLIST_INSERT_HEAD(&hfi->hfi_head, new, hei_entry); 10362958Sdr146992 1037*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 1038*7513SDarren.Reed@Sun.COM 1039*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hks->hks_lock); 1040*7513SDarren.Reed@Sun.COM 1041*7513SDarren.Reed@Sun.COM hook_notify_run(&hfi->hfi_nhead, 1042*7513SDarren.Reed@Sun.COM hfi->hfi_family.hf_name, NULL, he->he_name, HN_REGISTER); 1043*7513SDarren.Reed@Sun.COM 1044*7513SDarren.Reed@Sun.COM hook_wait_unsetflag(&hfi->hfi_waiter, FWF_ADD_ACTIVE); 1045*7513SDarren.Reed@Sun.COM 10462958Sdr146992 return (new); 10472958Sdr146992 } 10482958Sdr146992 1049*7513SDarren.Reed@Sun.COM /* 1050*7513SDarren.Reed@Sun.COM * Function: hook_event_init_kstats 1051*7513SDarren.Reed@Sun.COM * Returns: None 1052*7513SDarren.Reed@Sun.COM * Parameters: hfi(I) - pointer to the family that owns this event. 1053*7513SDarren.Reed@Sun.COM * hei(I) - pointer to the hook event that needs some kstats. 1054*7513SDarren.Reed@Sun.COM * 1055*7513SDarren.Reed@Sun.COM * Create a set of kstats that relate to each event registered with 1056*7513SDarren.Reed@Sun.COM * the hook framework. A counter is kept for each time the event is 1057*7513SDarren.Reed@Sun.COM * activated and for each time a hook is added or removed. As the 1058*7513SDarren.Reed@Sun.COM * kstats just count the events as they happen, the total number of 1059*7513SDarren.Reed@Sun.COM * hooks registered must be obtained by subtractived removed from added. 1060*7513SDarren.Reed@Sun.COM */ 1061*7513SDarren.Reed@Sun.COM static void 1062*7513SDarren.Reed@Sun.COM hook_event_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei) 1063*7513SDarren.Reed@Sun.COM { 1064*7513SDarren.Reed@Sun.COM hook_event_kstat_t template = { 1065*7513SDarren.Reed@Sun.COM { "hooksAdded", KSTAT_DATA_UINT64 }, 1066*7513SDarren.Reed@Sun.COM { "hooksRemoved", KSTAT_DATA_UINT64 }, 1067*7513SDarren.Reed@Sun.COM { "events", KSTAT_DATA_UINT64 } 1068*7513SDarren.Reed@Sun.COM }; 1069*7513SDarren.Reed@Sun.COM hook_stack_t *hks; 1070*7513SDarren.Reed@Sun.COM 1071*7513SDarren.Reed@Sun.COM hks = hfi->hfi_stack; 1072*7513SDarren.Reed@Sun.COM hei->hei_kstatp = kstat_create_netstack(hfi->hfi_family.hf_name, 0, 1073*7513SDarren.Reed@Sun.COM hei->hei_event->he_name, "hook_event", KSTAT_TYPE_NAMED, 1074*7513SDarren.Reed@Sun.COM sizeof (hei->hei_kstats) / sizeof (kstat_named_t), 1075*7513SDarren.Reed@Sun.COM KSTAT_FLAG_VIRTUAL, hks->hks_netstackid); 1076*7513SDarren.Reed@Sun.COM 1077*7513SDarren.Reed@Sun.COM bcopy((char *)&template, &hei->hei_kstats, sizeof (template)); 1078*7513SDarren.Reed@Sun.COM 1079*7513SDarren.Reed@Sun.COM if (hei->hei_kstatp != NULL) { 1080*7513SDarren.Reed@Sun.COM hei->hei_kstatp->ks_data = (void *)&hei->hei_kstats; 1081*7513SDarren.Reed@Sun.COM hei->hei_kstatp->ks_private = 1082*7513SDarren.Reed@Sun.COM (void *)(uintptr_t)hks->hks_netstackid; 1083*7513SDarren.Reed@Sun.COM 1084*7513SDarren.Reed@Sun.COM kstat_install(hei->hei_kstatp); 1085*7513SDarren.Reed@Sun.COM } 1086*7513SDarren.Reed@Sun.COM } 10872958Sdr146992 10882958Sdr146992 /* 10892958Sdr146992 * Function: hook_event_remove 10902958Sdr146992 * Returns: int - 0 = Succ, Else = Fail 10912958Sdr146992 * Parameters: hfi(I) - internal family pointer 10922958Sdr146992 * he(I) - event pointer 10932958Sdr146992 * 10942958Sdr146992 * Remove event from event list on specific family 1095*7513SDarren.Reed@Sun.COM * 1096*7513SDarren.Reed@Sun.COM * This function assumes that the caller has received a pointer to a the 1097*7513SDarren.Reed@Sun.COM * hook_family_int_t via a call to net_protocol_lookup or net_protocol_unreg'. 1098*7513SDarren.Reed@Sun.COM * This the hook_family_int_t is guaranteed to be around for the life of this 1099*7513SDarren.Reed@Sun.COM * call, unless the caller has decided to call net_protocol_release or 1100*7513SDarren.Reed@Sun.COM * net_protocol_unregister before calling net_event_unregister - an error. 11012958Sdr146992 */ 11022958Sdr146992 int 11032958Sdr146992 hook_event_remove(hook_family_int_t *hfi, hook_event_t *he) 11042958Sdr146992 { 1105*7513SDarren.Reed@Sun.COM boolean_t free_family; 11062958Sdr146992 hook_event_int_t *hei; 11072958Sdr146992 11082958Sdr146992 ASSERT(hfi != NULL); 11092958Sdr146992 ASSERT(he != NULL); 11102958Sdr146992 1111*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(&hfi->hfi_lock); 11122958Sdr146992 1113*7513SDarren.Reed@Sun.COM /* 1114*7513SDarren.Reed@Sun.COM * Set the flag so that we can call hook_event_notify_run without 1115*7513SDarren.Reed@Sun.COM * holding any locks but at the same time prevent other changes to 1116*7513SDarren.Reed@Sun.COM * the event at the same time. 1117*7513SDarren.Reed@Sun.COM */ 1118*7513SDarren.Reed@Sun.COM if (hook_wait_setflag(&hfi->hfi_waiter, FWF_WAIT_MASK, 1119*7513SDarren.Reed@Sun.COM FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) { 1120*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 11212958Sdr146992 return (ENXIO); 11222958Sdr146992 } 11232958Sdr146992 1124*7513SDarren.Reed@Sun.COM hei = hook_event_find(hfi, he->he_name); 1125*7513SDarren.Reed@Sun.COM if (hei == NULL) { 1126*7513SDarren.Reed@Sun.COM hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE); 1127*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 1128*7513SDarren.Reed@Sun.COM return (ESRCH); 11292958Sdr146992 } 11302958Sdr146992 1131*7513SDarren.Reed@Sun.COM free_family = B_FALSE; 1132*7513SDarren.Reed@Sun.COM 1133*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(&hei->hei_lock); 1134*7513SDarren.Reed@Sun.COM /* 1135*7513SDarren.Reed@Sun.COM * If there are any hooks still registered for this event or 1136*7513SDarren.Reed@Sun.COM * there are any notifiers registered, return an error indicating 1137*7513SDarren.Reed@Sun.COM * that the event is still busy. 1138*7513SDarren.Reed@Sun.COM */ 1139*7513SDarren.Reed@Sun.COM if (!TAILQ_EMPTY(&hei->hei_head) || !TAILQ_EMPTY(&hei->hei_nhead)) { 1140*7513SDarren.Reed@Sun.COM hei->hei_condemned = B_TRUE; 1141*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hei->hei_lock); 1142*7513SDarren.Reed@Sun.COM } else { 1143*7513SDarren.Reed@Sun.COM /* hei_condemned = B_FALSE is implied from creation */ 1144*7513SDarren.Reed@Sun.COM /* 1145*7513SDarren.Reed@Sun.COM * Even though we know the notify list is empty, we call 1146*7513SDarren.Reed@Sun.COM * hook_wait_destroy here to synchronise wait removing a 1147*7513SDarren.Reed@Sun.COM * hook from an event. 1148*7513SDarren.Reed@Sun.COM */ 1149*7513SDarren.Reed@Sun.COM hook_wait_destroy(&hei->hei_waiter); 11502958Sdr146992 1151*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hei->hei_lock); 1152*7513SDarren.Reed@Sun.COM 1153*7513SDarren.Reed@Sun.COM if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) && 1154*7513SDarren.Reed@Sun.COM TAILQ_EMPTY(&hfi->hfi_nhead)) 1155*7513SDarren.Reed@Sun.COM free_family = B_TRUE; 1156*7513SDarren.Reed@Sun.COM } 1157*7513SDarren.Reed@Sun.COM 1158*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 1159*7513SDarren.Reed@Sun.COM 1160*7513SDarren.Reed@Sun.COM hook_notify_run(&hfi->hfi_nhead, 1161*7513SDarren.Reed@Sun.COM hfi->hfi_family.hf_name, NULL, he->he_name, HN_UNREGISTER); 1162*7513SDarren.Reed@Sun.COM 1163*7513SDarren.Reed@Sun.COM hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE); 1164*7513SDarren.Reed@Sun.COM 1165*7513SDarren.Reed@Sun.COM if (!hei->hei_condemned) { 1166*7513SDarren.Reed@Sun.COM hook_event_free(hei, hfi); 1167*7513SDarren.Reed@Sun.COM if (free_family) 1168*7513SDarren.Reed@Sun.COM hook_family_free(hfi, hfi->hfi_stack); 1169*7513SDarren.Reed@Sun.COM } 11702958Sdr146992 11712958Sdr146992 return (0); 11722958Sdr146992 } 11732958Sdr146992 1174*7513SDarren.Reed@Sun.COM /* 1175*7513SDarren.Reed@Sun.COM * Function: hook_event_free 1176*7513SDarren.Reed@Sun.COM * Returns: None 1177*7513SDarren.Reed@Sun.COM * Parameters: hei(I) - internal event pointer 1178*7513SDarren.Reed@Sun.COM * 1179*7513SDarren.Reed@Sun.COM * Free alloc memory for event 1180*7513SDarren.Reed@Sun.COM */ 1181*7513SDarren.Reed@Sun.COM static void 1182*7513SDarren.Reed@Sun.COM hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi) 1183*7513SDarren.Reed@Sun.COM { 1184*7513SDarren.Reed@Sun.COM boolean_t free_family; 1185*7513SDarren.Reed@Sun.COM 1186*7513SDarren.Reed@Sun.COM ASSERT(hei != NULL); 1187*7513SDarren.Reed@Sun.COM 1188*7513SDarren.Reed@Sun.COM if (hfi != NULL) { 1189*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(&hfi->hfi_lock); 1190*7513SDarren.Reed@Sun.COM /* 1191*7513SDarren.Reed@Sun.COM * Remove the event from the hook family's list. 1192*7513SDarren.Reed@Sun.COM */ 1193*7513SDarren.Reed@Sun.COM SLIST_REMOVE(&hfi->hfi_head, hei, hook_event_int, hei_entry); 1194*7513SDarren.Reed@Sun.COM if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) && 1195*7513SDarren.Reed@Sun.COM TAILQ_EMPTY(&hfi->hfi_nhead)) { 1196*7513SDarren.Reed@Sun.COM free_family = B_TRUE; 1197*7513SDarren.Reed@Sun.COM } else { 1198*7513SDarren.Reed@Sun.COM free_family = B_FALSE; 1199*7513SDarren.Reed@Sun.COM } 1200*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 1201*7513SDarren.Reed@Sun.COM } 1202*7513SDarren.Reed@Sun.COM 1203*7513SDarren.Reed@Sun.COM if (hei->hei_kstatp != NULL) { 1204*7513SDarren.Reed@Sun.COM ASSERT(hfi != NULL); 1205*7513SDarren.Reed@Sun.COM 1206*7513SDarren.Reed@Sun.COM kstat_delete_netstack(hei->hei_kstatp, 1207*7513SDarren.Reed@Sun.COM hfi->hfi_stack->hks_netstackid); 1208*7513SDarren.Reed@Sun.COM hei->hei_kstatp = NULL; 1209*7513SDarren.Reed@Sun.COM } 1210*7513SDarren.Reed@Sun.COM 1211*7513SDarren.Reed@Sun.COM /* Free container */ 1212*7513SDarren.Reed@Sun.COM kmem_free(hei, sizeof (*hei)); 1213*7513SDarren.Reed@Sun.COM 1214*7513SDarren.Reed@Sun.COM if (free_family) 1215*7513SDarren.Reed@Sun.COM hook_family_free(hfi, hfi->hfi_stack); 1216*7513SDarren.Reed@Sun.COM } 12172958Sdr146992 12182958Sdr146992 /* 12192958Sdr146992 * Function: hook_event_checkdup 12202958Sdr146992 * Returns: internal event pointer - NULL = Not match 12212958Sdr146992 * Parameters: he(I) - event pointer 12222958Sdr146992 * 1223*7513SDarren.Reed@Sun.COM * Search all of the hook families to see if the event being passed in 1224*7513SDarren.Reed@Sun.COM * has already been associated with one. 12252958Sdr146992 */ 12262958Sdr146992 static hook_event_int_t * 12273448Sdh155122 hook_event_checkdup(hook_event_t *he, hook_stack_t *hks) 12282958Sdr146992 { 12292958Sdr146992 hook_family_int_t *hfi; 12302958Sdr146992 hook_event_int_t *hei; 12312958Sdr146992 12322958Sdr146992 ASSERT(he != NULL); 12332958Sdr146992 1234*7513SDarren.Reed@Sun.COM CVW_ENTER_READ(&hks->hks_lock); 12353448Sdh155122 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) { 12362958Sdr146992 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) { 1237*7513SDarren.Reed@Sun.COM if (hei->hei_event == he) { 1238*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hks->hks_lock); 12392958Sdr146992 return (hei); 1240*7513SDarren.Reed@Sun.COM } 12412958Sdr146992 } 12422958Sdr146992 } 1243*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hks->hks_lock); 12442958Sdr146992 12452958Sdr146992 return (NULL); 12462958Sdr146992 } 12472958Sdr146992 12482958Sdr146992 /* 12492958Sdr146992 * Function: hook_event_copy 12502958Sdr146992 * Returns: internal event pointer - NULL = Failed 12512958Sdr146992 * Parameters: src(I) - event pointer 12522958Sdr146992 * 12532958Sdr146992 * Allocate internal event block and duplicate incoming event 12542958Sdr146992 * No locks should be held across this function as it may sleep. 12552958Sdr146992 */ 12562958Sdr146992 static hook_event_int_t * 12572958Sdr146992 hook_event_copy(hook_event_t *src) 12582958Sdr146992 { 12592958Sdr146992 hook_event_int_t *new; 12602958Sdr146992 12612958Sdr146992 ASSERT(src != NULL); 12622958Sdr146992 ASSERT(src->he_name != NULL); 12632958Sdr146992 12642958Sdr146992 new = (hook_event_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP); 12652958Sdr146992 12662958Sdr146992 /* Copy body */ 12672958Sdr146992 TAILQ_INIT(&new->hei_head); 12682958Sdr146992 new->hei_event = src; 12692958Sdr146992 12702958Sdr146992 return (new); 12712958Sdr146992 } 12722958Sdr146992 12732958Sdr146992 /* 12742958Sdr146992 * Function: hook_event_find 12752958Sdr146992 * Returns: internal event pointer - NULL = Not match 12762958Sdr146992 * Parameters: hfi(I) - internal family pointer 12772958Sdr146992 * event(I) - event name string 12782958Sdr146992 * 12792958Sdr146992 * Search event list with event name 1280*7513SDarren.Reed@Sun.COM * A lock on hfi->hfi_lock must be held when called. 12812958Sdr146992 */ 12822958Sdr146992 static hook_event_int_t * 12832958Sdr146992 hook_event_find(hook_family_int_t *hfi, char *event) 12842958Sdr146992 { 12852958Sdr146992 hook_event_int_t *hei = NULL; 12862958Sdr146992 12872958Sdr146992 ASSERT(hfi != NULL); 12882958Sdr146992 ASSERT(event != NULL); 12892958Sdr146992 12902958Sdr146992 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) { 1291*7513SDarren.Reed@Sun.COM if ((strcmp(hei->hei_event->he_name, event) == 0) && 1292*7513SDarren.Reed@Sun.COM ((hei->hei_waiter.fw_flags & FWF_UNSAFE) == 0)) 12932958Sdr146992 break; 12942958Sdr146992 } 12952958Sdr146992 return (hei); 12962958Sdr146992 } 12972958Sdr146992 1298*7513SDarren.Reed@Sun.COM /* 1299*7513SDarren.Reed@Sun.COM * Function: hook_event_notify_register 1300*7513SDarren.Reed@Sun.COM * Returns: 0 = success, else failure 1301*7513SDarren.Reed@Sun.COM * Parameters: hfi(I) - hook family 1302*7513SDarren.Reed@Sun.COM * event(I) - name of the event 1303*7513SDarren.Reed@Sun.COM * callback(I) - function to be called 1304*7513SDarren.Reed@Sun.COM * arg(I) - arg to provide callback when it is called 1305*7513SDarren.Reed@Sun.COM * 1306*7513SDarren.Reed@Sun.COM * Adds a new callback to the event named by "event" (we must find it) 1307*7513SDarren.Reed@Sun.COM * that will be executed each time a new hook is added to the event. 1308*7513SDarren.Reed@Sun.COM * Of course, if the stack is being shut down, this call should fail. 1309*7513SDarren.Reed@Sun.COM */ 1310*7513SDarren.Reed@Sun.COM int 1311*7513SDarren.Reed@Sun.COM hook_event_notify_register(hook_family_int_t *hfi, char *event, 1312*7513SDarren.Reed@Sun.COM hook_notify_fn_t callback, void *arg) 1313*7513SDarren.Reed@Sun.COM { 1314*7513SDarren.Reed@Sun.COM hook_event_int_t *hei; 1315*7513SDarren.Reed@Sun.COM hook_stack_t *hks; 1316*7513SDarren.Reed@Sun.COM int error; 1317*7513SDarren.Reed@Sun.COM 1318*7513SDarren.Reed@Sun.COM hks = hfi->hfi_stack; 1319*7513SDarren.Reed@Sun.COM CVW_ENTER_READ(&hks->hks_lock); 1320*7513SDarren.Reed@Sun.COM if (hks->hks_shutdown != 0) { 1321*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hks->hks_lock); 1322*7513SDarren.Reed@Sun.COM return (ESHUTDOWN); 1323*7513SDarren.Reed@Sun.COM } 1324*7513SDarren.Reed@Sun.COM 1325*7513SDarren.Reed@Sun.COM CVW_ENTER_READ(&hfi->hfi_lock); 1326*7513SDarren.Reed@Sun.COM 1327*7513SDarren.Reed@Sun.COM if (hfi->hfi_condemned) { 1328*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hfi->hfi_lock); 1329*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hks->hks_lock); 1330*7513SDarren.Reed@Sun.COM return (ESHUTDOWN); 1331*7513SDarren.Reed@Sun.COM } 1332*7513SDarren.Reed@Sun.COM 1333*7513SDarren.Reed@Sun.COM hei = hook_event_find(hfi, event); 1334*7513SDarren.Reed@Sun.COM if (hei == NULL) { 1335*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hfi->hfi_lock); 1336*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hks->hks_lock); 1337*7513SDarren.Reed@Sun.COM return (ESRCH); 1338*7513SDarren.Reed@Sun.COM } 1339*7513SDarren.Reed@Sun.COM 1340*7513SDarren.Reed@Sun.COM /* 1341*7513SDarren.Reed@Sun.COM * Grabbing the read lock on hei_lock is only so that we can 1342*7513SDarren.Reed@Sun.COM * synchronise access to hei_condemned. 1343*7513SDarren.Reed@Sun.COM */ 1344*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(&hei->hei_lock); 1345*7513SDarren.Reed@Sun.COM if (hei->hei_condemned) { 1346*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hei->hei_lock); 1347*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hfi->hfi_lock); 1348*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hks->hks_lock); 1349*7513SDarren.Reed@Sun.COM return (ESHUTDOWN); 1350*7513SDarren.Reed@Sun.COM } 1351*7513SDarren.Reed@Sun.COM 1352*7513SDarren.Reed@Sun.COM error = hook_notify_register(&hei->hei_lock, &hei->hei_nhead, 1353*7513SDarren.Reed@Sun.COM callback, arg); 1354*7513SDarren.Reed@Sun.COM 1355*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hei->hei_lock); 1356*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hfi->hfi_lock); 1357*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hks->hks_lock); 1358*7513SDarren.Reed@Sun.COM 1359*7513SDarren.Reed@Sun.COM return (error); 1360*7513SDarren.Reed@Sun.COM } 13612958Sdr146992 13622958Sdr146992 /* 1363*7513SDarren.Reed@Sun.COM * Function: hook_event_notify_unregister 1364*7513SDarren.Reed@Sun.COM * Returns: 0 = success, else failure 1365*7513SDarren.Reed@Sun.COM * Parameters: hfi(I) - hook family 1366*7513SDarren.Reed@Sun.COM * event(I) - name of the event 1367*7513SDarren.Reed@Sun.COM * callback(I) - function to be called 1368*7513SDarren.Reed@Sun.COM * 1369*7513SDarren.Reed@Sun.COM * Remove the given callback from the named event's list of functions 1370*7513SDarren.Reed@Sun.COM * to call when a hook is added or removed. 1371*7513SDarren.Reed@Sun.COM */ 1372*7513SDarren.Reed@Sun.COM int 1373*7513SDarren.Reed@Sun.COM hook_event_notify_unregister(hook_family_int_t *hfi, char *event, 1374*7513SDarren.Reed@Sun.COM hook_notify_fn_t callback) 1375*7513SDarren.Reed@Sun.COM { 1376*7513SDarren.Reed@Sun.COM hook_event_int_t *hei; 1377*7513SDarren.Reed@Sun.COM boolean_t free_event; 1378*7513SDarren.Reed@Sun.COM int error; 1379*7513SDarren.Reed@Sun.COM 1380*7513SDarren.Reed@Sun.COM CVW_ENTER_READ(&hfi->hfi_lock); 1381*7513SDarren.Reed@Sun.COM 1382*7513SDarren.Reed@Sun.COM hei = hook_event_find(hfi, event); 1383*7513SDarren.Reed@Sun.COM if (hei == NULL) { 1384*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hfi->hfi_lock); 1385*7513SDarren.Reed@Sun.COM return (ESRCH); 1386*7513SDarren.Reed@Sun.COM } 1387*7513SDarren.Reed@Sun.COM 1388*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(&hei->hei_lock); 1389*7513SDarren.Reed@Sun.COM 1390*7513SDarren.Reed@Sun.COM error = hook_notify_unregister(&hei->hei_lock, &hei->hei_nhead, 1391*7513SDarren.Reed@Sun.COM callback); 1392*7513SDarren.Reed@Sun.COM 1393*7513SDarren.Reed@Sun.COM /* 1394*7513SDarren.Reed@Sun.COM * hei_condemned has been set if someone tried to remove the 1395*7513SDarren.Reed@Sun.COM * event but couldn't because there were still things attached to 1396*7513SDarren.Reed@Sun.COM * it. Now that we've done a successful remove, if it is now empty 1397*7513SDarren.Reed@Sun.COM * then by all rights we should be free'ing it too. Note that the 1398*7513SDarren.Reed@Sun.COM * expectation is that only the caller of hook_event_add will ever 1399*7513SDarren.Reed@Sun.COM * call hook_event_remove. 1400*7513SDarren.Reed@Sun.COM */ 1401*7513SDarren.Reed@Sun.COM if ((error == 0) && hei->hei_condemned && 1402*7513SDarren.Reed@Sun.COM TAILQ_EMPTY(&hei->hei_head) && TAILQ_EMPTY(&hei->hei_nhead)) { 1403*7513SDarren.Reed@Sun.COM free_event = B_TRUE; 1404*7513SDarren.Reed@Sun.COM } else { 1405*7513SDarren.Reed@Sun.COM free_event = B_FALSE; 1406*7513SDarren.Reed@Sun.COM } 1407*7513SDarren.Reed@Sun.COM 1408*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hei->hei_lock); 1409*7513SDarren.Reed@Sun.COM CVW_EXIT_READ(&hfi->hfi_lock); 1410*7513SDarren.Reed@Sun.COM 1411*7513SDarren.Reed@Sun.COM if (free_event) { 1412*7513SDarren.Reed@Sun.COM /* 1413*7513SDarren.Reed@Sun.COM * It is safe to pass in hfi here, without a lock, because 1414*7513SDarren.Reed@Sun.COM * our structure (hei) is still on one of its lists and thus 1415*7513SDarren.Reed@Sun.COM * it won't be able to disappear yet... 1416*7513SDarren.Reed@Sun.COM */ 1417*7513SDarren.Reed@Sun.COM hook_event_free(hei, hfi); 1418*7513SDarren.Reed@Sun.COM } 1419*7513SDarren.Reed@Sun.COM 1420*7513SDarren.Reed@Sun.COM return (error); 1421*7513SDarren.Reed@Sun.COM } 1422*7513SDarren.Reed@Sun.COM 1423*7513SDarren.Reed@Sun.COM /* 1424*7513SDarren.Reed@Sun.COM * Function: hook_event_notify_run 14252958Sdr146992 * Returns: None 1426*7513SDarren.Reed@Sun.COM * Parameters: nrun(I) - pointer to the list of callbacks to execute 1427*7513SDarren.Reed@Sun.COM * hfi(I) - hook stack pointer to execute callbacks for 1428*7513SDarren.Reed@Sun.COM * name(I) - name of a hook family 1429*7513SDarren.Reed@Sun.COM * cmd(I) - either HN_UNREGISTER or HN_REGISTER 14302958Sdr146992 * 1431*7513SDarren.Reed@Sun.COM * Execute all of the callbacks registered for this event. 14322958Sdr146992 */ 14332958Sdr146992 static void 1434*7513SDarren.Reed@Sun.COM hook_event_notify_run(hook_event_int_t *hei, hook_family_int_t *hfi, 1435*7513SDarren.Reed@Sun.COM char *event, char *name, hook_notify_cmd_t cmd) 14362958Sdr146992 { 14372958Sdr146992 1438*7513SDarren.Reed@Sun.COM hook_notify_run(&hei->hei_nhead, hfi->hfi_family.hf_name, 1439*7513SDarren.Reed@Sun.COM event, name, cmd); 14402958Sdr146992 } 14412958Sdr146992 14422958Sdr146992 /* 14432958Sdr146992 * Function: hook_register 14442958Sdr146992 * Returns: int- 0 = Succ, Else = Fail 14452958Sdr146992 * Parameters: hfi(I) - internal family pointer 14462958Sdr146992 * event(I) - event name string 14472958Sdr146992 * h(I) - hook pointer 14482958Sdr146992 * 1449*7513SDarren.Reed@Sun.COM * Add new hook to hook list on the specified family and event. 14502958Sdr146992 */ 14512958Sdr146992 int 14522958Sdr146992 hook_register(hook_family_int_t *hfi, char *event, hook_t *h) 14532958Sdr146992 { 14542958Sdr146992 hook_event_int_t *hei; 14552958Sdr146992 hook_int_t *hi, *new; 1456*7513SDarren.Reed@Sun.COM int error; 14572958Sdr146992 14582958Sdr146992 ASSERT(hfi != NULL); 14592958Sdr146992 ASSERT(event != NULL); 14602958Sdr146992 ASSERT(h != NULL); 1461*7513SDarren.Reed@Sun.COM 1462*7513SDarren.Reed@Sun.COM if (hfi->hfi_stack->hks_shutdown) 1463*7513SDarren.Reed@Sun.COM return (NULL); 14642958Sdr146992 14652958Sdr146992 /* Alloc hook_int_t and copy hook */ 14662958Sdr146992 new = hook_copy(h); 14672958Sdr146992 if (new == NULL) 14682958Sdr146992 return (ENOMEM); 14692958Sdr146992 14702958Sdr146992 /* 14712958Sdr146992 * Since hook add/remove only impact event, so it is unnecessary 14722958Sdr146992 * to hold global family write lock. Just get read lock here to 14732958Sdr146992 * ensure event will not be removed when doing hooks operation 14742958Sdr146992 */ 1475*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(&hfi->hfi_lock); 14762958Sdr146992 14772958Sdr146992 hei = hook_event_find(hfi, event); 14782958Sdr146992 if (hei == NULL) { 1479*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 1480*7513SDarren.Reed@Sun.COM hook_int_free(new, hfi->hfi_stack->hks_netstackid); 14812958Sdr146992 return (ENXIO); 14822958Sdr146992 } 14832958Sdr146992 14842958Sdr146992 CVW_ENTER_WRITE(&hei->hei_lock); 14852958Sdr146992 1486*7513SDarren.Reed@Sun.COM hi = hook_find(hei, h); 1487*7513SDarren.Reed@Sun.COM if (hi != NULL) { 1488*7513SDarren.Reed@Sun.COM error = EEXIST; 1489*7513SDarren.Reed@Sun.COM goto bad_add; 14902958Sdr146992 } 14912958Sdr146992 1492*7513SDarren.Reed@Sun.COM if (hook_wait_setflag(&hei->hei_waiter, FWF_WAIT_MASK, 1493*7513SDarren.Reed@Sun.COM FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) { 1494*7513SDarren.Reed@Sun.COM error = ENOENT; 1495*7513SDarren.Reed@Sun.COM bad_add: 14962958Sdr146992 CVW_EXIT_WRITE(&hei->hei_lock); 1497*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 1498*7513SDarren.Reed@Sun.COM hook_int_free(new, hfi->hfi_stack->hks_netstackid); 1499*7513SDarren.Reed@Sun.COM return (error); 15002958Sdr146992 } 15012958Sdr146992 15022958Sdr146992 /* Add to hook list head */ 1503*7513SDarren.Reed@Sun.COM error = hook_insert(&hei->hei_head, new); 1504*7513SDarren.Reed@Sun.COM if (error == 0) { 1505*7513SDarren.Reed@Sun.COM hei->hei_event->he_interested = B_TRUE; 1506*7513SDarren.Reed@Sun.COM hei->hei_kstats.hooks_added.value.ui64++; 1507*7513SDarren.Reed@Sun.COM 1508*7513SDarren.Reed@Sun.COM hook_init_kstats(hfi, hei, new); 1509*7513SDarren.Reed@Sun.COM } 15102958Sdr146992 15112958Sdr146992 CVW_EXIT_WRITE(&hei->hei_lock); 1512*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 1513*7513SDarren.Reed@Sun.COM 1514*7513SDarren.Reed@Sun.COM /* 1515*7513SDarren.Reed@Sun.COM * Note that the name string passed through to the notify callbacks 1516*7513SDarren.Reed@Sun.COM * is from the original hook being registered, not the copy being 1517*7513SDarren.Reed@Sun.COM * inserted. 1518*7513SDarren.Reed@Sun.COM */ 1519*7513SDarren.Reed@Sun.COM if (error == 0) { 1520*7513SDarren.Reed@Sun.COM hook_event_notify_run(hei, hfi, event, h->h_name, HN_REGISTER); 1521*7513SDarren.Reed@Sun.COM hook_wait_unsetflag(&hei->hei_waiter, FWF_ADD_ACTIVE); 1522*7513SDarren.Reed@Sun.COM } 1523*7513SDarren.Reed@Sun.COM 1524*7513SDarren.Reed@Sun.COM return (error); 1525*7513SDarren.Reed@Sun.COM } 1526*7513SDarren.Reed@Sun.COM 1527*7513SDarren.Reed@Sun.COM /* 1528*7513SDarren.Reed@Sun.COM * Function: hook_insert 1529*7513SDarren.Reed@Sun.COM * Returns: int- 0 = Succ, else = Fail 1530*7513SDarren.Reed@Sun.COM * Parameters: head(I) - pointer to hook list to insert hook onto 1531*7513SDarren.Reed@Sun.COM * new(I) - pointer to hook to be inserted 1532*7513SDarren.Reed@Sun.COM * 1533*7513SDarren.Reed@Sun.COM * Try to insert the hook onto the list of hooks according to the hints 1534*7513SDarren.Reed@Sun.COM * given in the hook to be inserted and those that already exist on the 1535*7513SDarren.Reed@Sun.COM * list. For now, the implementation permits only a single hook to be 1536*7513SDarren.Reed@Sun.COM * either first or last and names provided with before or after are only 1537*7513SDarren.Reed@Sun.COM * loosely coupled with the action. 1538*7513SDarren.Reed@Sun.COM */ 1539*7513SDarren.Reed@Sun.COM static int 1540*7513SDarren.Reed@Sun.COM hook_insert(hook_int_head_t *head, hook_int_t *new) 1541*7513SDarren.Reed@Sun.COM { 1542*7513SDarren.Reed@Sun.COM hook_int_t *before; 1543*7513SDarren.Reed@Sun.COM hook_int_t *hi; 1544*7513SDarren.Reed@Sun.COM hook_t *hih; 1545*7513SDarren.Reed@Sun.COM hook_t *h = &new->hi_hook; 1546*7513SDarren.Reed@Sun.COM 1547*7513SDarren.Reed@Sun.COM switch (new->hi_hook.h_hint) { 1548*7513SDarren.Reed@Sun.COM case HH_NONE : 1549*7513SDarren.Reed@Sun.COM before = NULL; 1550*7513SDarren.Reed@Sun.COM /* 1551*7513SDarren.Reed@Sun.COM * If there is no hint present (or not one that can be 1552*7513SDarren.Reed@Sun.COM * satisfied now) then try to at least respect the wishes 1553*7513SDarren.Reed@Sun.COM * of those that want to be last. If there are none wanting 1554*7513SDarren.Reed@Sun.COM * to be last then add the new hook to the tail of the 1555*7513SDarren.Reed@Sun.COM * list - this means we keep any wanting to be first 1556*7513SDarren.Reed@Sun.COM * happy without having to search for HH_FIRST. 1557*7513SDarren.Reed@Sun.COM */ 1558*7513SDarren.Reed@Sun.COM TAILQ_FOREACH(hi, head, hi_entry) { 1559*7513SDarren.Reed@Sun.COM hih = &hi->hi_hook; 1560*7513SDarren.Reed@Sun.COM if ((hih->h_hint == HH_AFTER) && 1561*7513SDarren.Reed@Sun.COM (strcmp(h->h_name, 1562*7513SDarren.Reed@Sun.COM (char *)hih->h_hintvalue) == 0)) { 1563*7513SDarren.Reed@Sun.COM TAILQ_INSERT_BEFORE(hi, new, hi_entry); 1564*7513SDarren.Reed@Sun.COM return (0); 1565*7513SDarren.Reed@Sun.COM } 1566*7513SDarren.Reed@Sun.COM if ((hih->h_hint == HH_BEFORE) && (before == NULL) && 1567*7513SDarren.Reed@Sun.COM (strcmp(h->h_name, 1568*7513SDarren.Reed@Sun.COM (char *)hih->h_hintvalue) == 0)) { 1569*7513SDarren.Reed@Sun.COM before = hi; 1570*7513SDarren.Reed@Sun.COM } 1571*7513SDarren.Reed@Sun.COM } 1572*7513SDarren.Reed@Sun.COM if (before != NULL) { 1573*7513SDarren.Reed@Sun.COM TAILQ_INSERT_AFTER(head, before, new, hi_entry); 1574*7513SDarren.Reed@Sun.COM return (0); 1575*7513SDarren.Reed@Sun.COM } 1576*7513SDarren.Reed@Sun.COM hook_insert_plain(head, new); 1577*7513SDarren.Reed@Sun.COM break; 1578*7513SDarren.Reed@Sun.COM 1579*7513SDarren.Reed@Sun.COM case HH_FIRST : 1580*7513SDarren.Reed@Sun.COM hi = TAILQ_FIRST(head); 1581*7513SDarren.Reed@Sun.COM if ((hi != NULL) && (hi->hi_hook.h_hint == HH_FIRST)) 1582*7513SDarren.Reed@Sun.COM return (EBUSY); 1583*7513SDarren.Reed@Sun.COM TAILQ_INSERT_HEAD(head, new, hi_entry); 1584*7513SDarren.Reed@Sun.COM break; 1585*7513SDarren.Reed@Sun.COM 1586*7513SDarren.Reed@Sun.COM case HH_LAST : 1587*7513SDarren.Reed@Sun.COM hi = TAILQ_LAST(head, hook_int_head); 1588*7513SDarren.Reed@Sun.COM if ((hi != NULL) && (hi->hi_hook.h_hint == HH_LAST)) 1589*7513SDarren.Reed@Sun.COM return (EBUSY); 1590*7513SDarren.Reed@Sun.COM TAILQ_INSERT_TAIL(head, new, hi_entry); 1591*7513SDarren.Reed@Sun.COM break; 1592*7513SDarren.Reed@Sun.COM 1593*7513SDarren.Reed@Sun.COM case HH_BEFORE : 1594*7513SDarren.Reed@Sun.COM hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue); 1595*7513SDarren.Reed@Sun.COM if (hi == NULL) 1596*7513SDarren.Reed@Sun.COM return (hook_insert_afterbefore(head, new)); 1597*7513SDarren.Reed@Sun.COM 1598*7513SDarren.Reed@Sun.COM if (hi->hi_hook.h_hint == HH_FIRST) 1599*7513SDarren.Reed@Sun.COM return (EBUSY); 1600*7513SDarren.Reed@Sun.COM 1601*7513SDarren.Reed@Sun.COM TAILQ_INSERT_BEFORE(hi, new, hi_entry); 1602*7513SDarren.Reed@Sun.COM break; 1603*7513SDarren.Reed@Sun.COM 1604*7513SDarren.Reed@Sun.COM case HH_AFTER : 1605*7513SDarren.Reed@Sun.COM hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue); 1606*7513SDarren.Reed@Sun.COM if (hi == NULL) 1607*7513SDarren.Reed@Sun.COM return (hook_insert_afterbefore(head, new)); 1608*7513SDarren.Reed@Sun.COM 1609*7513SDarren.Reed@Sun.COM if (hi->hi_hook.h_hint == HH_LAST) 1610*7513SDarren.Reed@Sun.COM return (EBUSY); 1611*7513SDarren.Reed@Sun.COM 1612*7513SDarren.Reed@Sun.COM TAILQ_INSERT_AFTER(head, hi, new, hi_entry); 1613*7513SDarren.Reed@Sun.COM break; 1614*7513SDarren.Reed@Sun.COM 1615*7513SDarren.Reed@Sun.COM default : 1616*7513SDarren.Reed@Sun.COM return (EINVAL); 1617*7513SDarren.Reed@Sun.COM } 1618*7513SDarren.Reed@Sun.COM 16192958Sdr146992 return (0); 16202958Sdr146992 } 16212958Sdr146992 1622*7513SDarren.Reed@Sun.COM /* 1623*7513SDarren.Reed@Sun.COM * Function: hook_insert_plain 1624*7513SDarren.Reed@Sun.COM * Returns: int- 0 = success, else = failure 1625*7513SDarren.Reed@Sun.COM * Parameters: head(I) - pointer to hook list to insert hook onto 1626*7513SDarren.Reed@Sun.COM * new(I) - pointer to hook to be inserted 1627*7513SDarren.Reed@Sun.COM * 1628*7513SDarren.Reed@Sun.COM * Insert a hook such that it respects the wishes of those that want to 1629*7513SDarren.Reed@Sun.COM * be last. If there are none wanting to be last then add the new hook 1630*7513SDarren.Reed@Sun.COM * to the tail of the list - this means we keep any wanting to be first 1631*7513SDarren.Reed@Sun.COM * happy without having to search for HH_FIRST. 1632*7513SDarren.Reed@Sun.COM */ 1633*7513SDarren.Reed@Sun.COM static void 1634*7513SDarren.Reed@Sun.COM hook_insert_plain(hook_int_head_t *head, hook_int_t *new) 1635*7513SDarren.Reed@Sun.COM { 1636*7513SDarren.Reed@Sun.COM hook_int_t *hi; 1637*7513SDarren.Reed@Sun.COM 1638*7513SDarren.Reed@Sun.COM hi = TAILQ_FIRST(head); 1639*7513SDarren.Reed@Sun.COM if (hi != NULL) { 1640*7513SDarren.Reed@Sun.COM if (hi->hi_hook.h_hint == HH_LAST) { 1641*7513SDarren.Reed@Sun.COM TAILQ_INSERT_BEFORE(hi, new, hi_entry); 1642*7513SDarren.Reed@Sun.COM } else { 1643*7513SDarren.Reed@Sun.COM TAILQ_INSERT_TAIL(head, new, hi_entry); 1644*7513SDarren.Reed@Sun.COM } 1645*7513SDarren.Reed@Sun.COM } else { 1646*7513SDarren.Reed@Sun.COM TAILQ_INSERT_TAIL(head, new, hi_entry); 1647*7513SDarren.Reed@Sun.COM } 1648*7513SDarren.Reed@Sun.COM } 1649*7513SDarren.Reed@Sun.COM 1650*7513SDarren.Reed@Sun.COM /* 1651*7513SDarren.Reed@Sun.COM * Function: hook_insert_afterbefore 1652*7513SDarren.Reed@Sun.COM * Returns: int- 0 = success, else = failure 1653*7513SDarren.Reed@Sun.COM * Parameters: head(I) - pointer to hook list to insert hook onto 1654*7513SDarren.Reed@Sun.COM * new(I) - pointer to hook to be inserted 1655*7513SDarren.Reed@Sun.COM * 1656*7513SDarren.Reed@Sun.COM * Simple insertion of a hook specifying a HH_BEFORE or HH_AFTER was not 1657*7513SDarren.Reed@Sun.COM * possible, so now we need to be more careful. The first pass is to go 1658*7513SDarren.Reed@Sun.COM * through the list and look for any other hooks that also specify the 1659*7513SDarren.Reed@Sun.COM * same hint name as the new one. The object of this exercise is to make 1660*7513SDarren.Reed@Sun.COM * sure that hooks with HH_BEFORE always appear on the list before those 1661*7513SDarren.Reed@Sun.COM * with HH_AFTER so that when said hook arrives, it can be placed in the 1662*7513SDarren.Reed@Sun.COM * middle of the BEFOREs and AFTERs. If this condition does not arise, 1663*7513SDarren.Reed@Sun.COM * just use hook_insert_plain() to try and insert the hook somewhere that 1664*7513SDarren.Reed@Sun.COM * is innocuous to existing efforts. 1665*7513SDarren.Reed@Sun.COM */ 1666*7513SDarren.Reed@Sun.COM static int 1667*7513SDarren.Reed@Sun.COM hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new) 1668*7513SDarren.Reed@Sun.COM { 1669*7513SDarren.Reed@Sun.COM hook_int_t *hi; 1670*7513SDarren.Reed@Sun.COM hook_t *nh; 1671*7513SDarren.Reed@Sun.COM hook_t *h; 1672*7513SDarren.Reed@Sun.COM 1673*7513SDarren.Reed@Sun.COM nh = &new->hi_hook; 1674*7513SDarren.Reed@Sun.COM ASSERT(new->hi_hook.h_hint != HH_NONE); 1675*7513SDarren.Reed@Sun.COM ASSERT(new->hi_hook.h_hint != HH_LAST); 1676*7513SDarren.Reed@Sun.COM ASSERT(new->hi_hook.h_hint != HH_FIRST); 1677*7513SDarren.Reed@Sun.COM 1678*7513SDarren.Reed@Sun.COM /* 1679*7513SDarren.Reed@Sun.COM * First, look through the list to see if there are any other 1680*7513SDarren.Reed@Sun.COM * before's or after's that have a matching hint name. 1681*7513SDarren.Reed@Sun.COM */ 1682*7513SDarren.Reed@Sun.COM TAILQ_FOREACH(hi, head, hi_entry) { 1683*7513SDarren.Reed@Sun.COM h = &hi->hi_hook; 1684*7513SDarren.Reed@Sun.COM switch (h->h_hint) { 1685*7513SDarren.Reed@Sun.COM case HH_FIRST : 1686*7513SDarren.Reed@Sun.COM case HH_LAST : 1687*7513SDarren.Reed@Sun.COM case HH_NONE : 1688*7513SDarren.Reed@Sun.COM break; 1689*7513SDarren.Reed@Sun.COM case HH_BEFORE : 1690*7513SDarren.Reed@Sun.COM if ((nh->h_hint == HH_BEFORE) && 1691*7513SDarren.Reed@Sun.COM (strcmp((char *)h->h_hintvalue, 1692*7513SDarren.Reed@Sun.COM (char *)nh->h_hintvalue) == 0)) { 1693*7513SDarren.Reed@Sun.COM TAILQ_INSERT_AFTER(head, hi, new, hi_entry); 1694*7513SDarren.Reed@Sun.COM return (0); 1695*7513SDarren.Reed@Sun.COM } 1696*7513SDarren.Reed@Sun.COM if ((nh->h_hint == HH_AFTER) && 1697*7513SDarren.Reed@Sun.COM (strcmp((char *)h->h_hintvalue, 1698*7513SDarren.Reed@Sun.COM (char *)nh->h_hintvalue) == 0)) { 1699*7513SDarren.Reed@Sun.COM TAILQ_INSERT_BEFORE(hi, new, hi_entry); 1700*7513SDarren.Reed@Sun.COM return (0); 1701*7513SDarren.Reed@Sun.COM } 1702*7513SDarren.Reed@Sun.COM break; 1703*7513SDarren.Reed@Sun.COM case HH_AFTER : 1704*7513SDarren.Reed@Sun.COM if ((nh->h_hint == HH_AFTER) && 1705*7513SDarren.Reed@Sun.COM (strcmp((char *)h->h_hintvalue, 1706*7513SDarren.Reed@Sun.COM (char *)nh->h_hintvalue) == 0)) { 1707*7513SDarren.Reed@Sun.COM TAILQ_INSERT_AFTER(head, hi, new, hi_entry); 1708*7513SDarren.Reed@Sun.COM return (0); 1709*7513SDarren.Reed@Sun.COM } 1710*7513SDarren.Reed@Sun.COM if ((nh->h_hint == HH_BEFORE) && 1711*7513SDarren.Reed@Sun.COM (strcmp((char *)h->h_hintvalue, 1712*7513SDarren.Reed@Sun.COM (char *)nh->h_hintvalue) == 0)) { 1713*7513SDarren.Reed@Sun.COM TAILQ_INSERT_BEFORE(hi, new, hi_entry); 1714*7513SDarren.Reed@Sun.COM return (0); 1715*7513SDarren.Reed@Sun.COM } 1716*7513SDarren.Reed@Sun.COM break; 1717*7513SDarren.Reed@Sun.COM } 1718*7513SDarren.Reed@Sun.COM } 1719*7513SDarren.Reed@Sun.COM 1720*7513SDarren.Reed@Sun.COM hook_insert_plain(head, new); 1721*7513SDarren.Reed@Sun.COM 1722*7513SDarren.Reed@Sun.COM return (0); 1723*7513SDarren.Reed@Sun.COM } 17242958Sdr146992 17252958Sdr146992 /* 17262958Sdr146992 * Function: hook_unregister 17272958Sdr146992 * Returns: int - 0 = Succ, Else = Fail 17282958Sdr146992 * Parameters: hfi(I) - internal family pointer 17292958Sdr146992 * event(I) - event name string 17302958Sdr146992 * h(I) - hook pointer 17312958Sdr146992 * 17322958Sdr146992 * Remove hook from hook list on specific family, event 17332958Sdr146992 */ 17342958Sdr146992 int 17352958Sdr146992 hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h) 17362958Sdr146992 { 17372958Sdr146992 hook_event_int_t *hei; 17382958Sdr146992 hook_int_t *hi; 1739*7513SDarren.Reed@Sun.COM boolean_t free_event; 17402958Sdr146992 17412958Sdr146992 ASSERT(hfi != NULL); 17422958Sdr146992 ASSERT(h != NULL); 17432958Sdr146992 1744*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(&hfi->hfi_lock); 17452958Sdr146992 17462958Sdr146992 hei = hook_event_find(hfi, event); 17472958Sdr146992 if (hei == NULL) { 1748*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 17492958Sdr146992 return (ENXIO); 17502958Sdr146992 } 17512958Sdr146992 17522958Sdr146992 /* Hold write lock for event */ 17532958Sdr146992 CVW_ENTER_WRITE(&hei->hei_lock); 17542958Sdr146992 17552958Sdr146992 hi = hook_find(hei, h); 17562958Sdr146992 if (hi == NULL) { 17572958Sdr146992 CVW_EXIT_WRITE(&hei->hei_lock); 1758*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 17592958Sdr146992 return (ENXIO); 17602958Sdr146992 } 17612958Sdr146992 1762*7513SDarren.Reed@Sun.COM if (hook_wait_setflag(&hei->hei_waiter, FWF_WAIT_MASK, 1763*7513SDarren.Reed@Sun.COM FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) { 1764*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hei->hei_lock); 1765*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 1766*7513SDarren.Reed@Sun.COM return (ENOENT); 1767*7513SDarren.Reed@Sun.COM } 1768*7513SDarren.Reed@Sun.COM 17692958Sdr146992 /* Remove from hook list */ 17702958Sdr146992 TAILQ_REMOVE(&hei->hei_head, hi, hi_entry); 1771*7513SDarren.Reed@Sun.COM 1772*7513SDarren.Reed@Sun.COM free_event = B_FALSE; 17732958Sdr146992 if (TAILQ_EMPTY(&hei->hei_head)) { 17742958Sdr146992 hei->hei_event->he_interested = B_FALSE; 1775*7513SDarren.Reed@Sun.COM /* 1776*7513SDarren.Reed@Sun.COM * If the delete pending flag has been set and there are 1777*7513SDarren.Reed@Sun.COM * no notifiers on the event (and we've removed the last 1778*7513SDarren.Reed@Sun.COM * hook) then we need to free this event after we're done. 1779*7513SDarren.Reed@Sun.COM */ 1780*7513SDarren.Reed@Sun.COM if (hei->hei_condemned && TAILQ_EMPTY(&hei->hei_nhead)) 1781*7513SDarren.Reed@Sun.COM free_event = B_TRUE; 17822958Sdr146992 } 1783*7513SDarren.Reed@Sun.COM hei->hei_kstats.hooks_removed.value.ui64++; 17842958Sdr146992 17852958Sdr146992 CVW_EXIT_WRITE(&hei->hei_lock); 1786*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(&hfi->hfi_lock); 1787*7513SDarren.Reed@Sun.COM /* 1788*7513SDarren.Reed@Sun.COM * While the FWF_DEL_ACTIVE flag is set, the hook_event_int_t 1789*7513SDarren.Reed@Sun.COM * will not be free'd and thus the hook_family_int_t wil not 1790*7513SDarren.Reed@Sun.COM * be free'd either. 1791*7513SDarren.Reed@Sun.COM */ 1792*7513SDarren.Reed@Sun.COM hook_event_notify_run(hei, hfi, event, h->h_name, HN_UNREGISTER); 1793*7513SDarren.Reed@Sun.COM hook_wait_unsetflag(&hei->hei_waiter, FWF_DEL_ACTIVE); 17942958Sdr146992 1795*7513SDarren.Reed@Sun.COM hook_int_free(hi, hfi->hfi_stack->hks_netstackid); 1796*7513SDarren.Reed@Sun.COM 1797*7513SDarren.Reed@Sun.COM if (free_event) 1798*7513SDarren.Reed@Sun.COM hook_event_free(hei, hfi); 1799*7513SDarren.Reed@Sun.COM 18002958Sdr146992 return (0); 18012958Sdr146992 } 18022958Sdr146992 1803*7513SDarren.Reed@Sun.COM /* 1804*7513SDarren.Reed@Sun.COM * Function: hook_find_byname 1805*7513SDarren.Reed@Sun.COM * Returns: internal hook pointer - NULL = Not match 1806*7513SDarren.Reed@Sun.COM * Parameters: hei(I) - internal event pointer 1807*7513SDarren.Reed@Sun.COM * name(I)- hook name 1808*7513SDarren.Reed@Sun.COM * 1809*7513SDarren.Reed@Sun.COM * Search an event's list of hooks to see if there is a hook present that 1810*7513SDarren.Reed@Sun.COM * has a matching name to the one being looked for. 1811*7513SDarren.Reed@Sun.COM */ 1812*7513SDarren.Reed@Sun.COM static hook_int_t * 1813*7513SDarren.Reed@Sun.COM hook_find_byname(hook_int_head_t *head, char *name) 1814*7513SDarren.Reed@Sun.COM { 1815*7513SDarren.Reed@Sun.COM hook_int_t *hi; 1816*7513SDarren.Reed@Sun.COM 1817*7513SDarren.Reed@Sun.COM TAILQ_FOREACH(hi, head, hi_entry) { 1818*7513SDarren.Reed@Sun.COM if (strcmp(hi->hi_hook.h_name, name) == 0) 1819*7513SDarren.Reed@Sun.COM return (hi); 1820*7513SDarren.Reed@Sun.COM } 1821*7513SDarren.Reed@Sun.COM 1822*7513SDarren.Reed@Sun.COM return (NULL); 1823*7513SDarren.Reed@Sun.COM } 18242958Sdr146992 18252958Sdr146992 /* 18262958Sdr146992 * Function: hook_find 18272958Sdr146992 * Returns: internal hook pointer - NULL = Not match 18282958Sdr146992 * Parameters: hei(I) - internal event pointer 18292958Sdr146992 * h(I) - hook pointer 18302958Sdr146992 * 1831*7513SDarren.Reed@Sun.COM * Search an event's list of hooks to see if there is already one that 1832*7513SDarren.Reed@Sun.COM * matches the hook being passed in. Currently the only criteria for a 1833*7513SDarren.Reed@Sun.COM * successful search here is for the names to be the same. 18342958Sdr146992 */ 18352958Sdr146992 static hook_int_t * 18362958Sdr146992 hook_find(hook_event_int_t *hei, hook_t *h) 18372958Sdr146992 { 18382958Sdr146992 18392958Sdr146992 ASSERT(hei != NULL); 18402958Sdr146992 ASSERT(h != NULL); 18412958Sdr146992 1842*7513SDarren.Reed@Sun.COM return (hook_find_byname(&hei->hei_head, h->h_name)); 18432958Sdr146992 } 18442958Sdr146992 18452958Sdr146992 /* 18462958Sdr146992 * Function: hook_copy 18472958Sdr146992 * Returns: internal hook pointer - NULL = Failed 18482958Sdr146992 * Parameters: src(I) - hook pointer 18492958Sdr146992 * 18502958Sdr146992 * Allocate internal hook block and duplicate incoming hook. 18512958Sdr146992 * No locks should be held across this function as it may sleep. 1852*7513SDarren.Reed@Sun.COM * Because hook_copy() is responsible for the creation of the internal 1853*7513SDarren.Reed@Sun.COM * hook structure that is used here, it takes on population the structure 1854*7513SDarren.Reed@Sun.COM * with the kstat information. Note that while the kstat bits are 1855*7513SDarren.Reed@Sun.COM * seeded here, their installation of the kstats is handled elsewhere. 18562958Sdr146992 */ 18572958Sdr146992 static hook_int_t * 18582958Sdr146992 hook_copy(hook_t *src) 18592958Sdr146992 { 18602958Sdr146992 hook_int_t *new; 18612958Sdr146992 hook_t *dst; 1862*7513SDarren.Reed@Sun.COM int len; 18632958Sdr146992 18642958Sdr146992 ASSERT(src != NULL); 18652958Sdr146992 ASSERT(src->h_name != NULL); 18662958Sdr146992 18672958Sdr146992 new = (hook_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP); 18682958Sdr146992 18692958Sdr146992 /* Copy body */ 18702958Sdr146992 dst = &new->hi_hook; 18712958Sdr146992 *dst = *src; 18722958Sdr146992 18732958Sdr146992 /* Copy name */ 1874*7513SDarren.Reed@Sun.COM len = strlen(src->h_name); 1875*7513SDarren.Reed@Sun.COM dst->h_name = (char *)kmem_alloc(len + 1, KM_SLEEP); 18762958Sdr146992 (void) strcpy(dst->h_name, src->h_name); 18772958Sdr146992 1878*7513SDarren.Reed@Sun.COM /* 1879*7513SDarren.Reed@Sun.COM * This is initialised in this manner to make it safer to use the 1880*7513SDarren.Reed@Sun.COM * same pointer in the kstats field. 1881*7513SDarren.Reed@Sun.COM */ 1882*7513SDarren.Reed@Sun.COM dst->h_hintvalue = (uintptr_t)""; 1883*7513SDarren.Reed@Sun.COM 1884*7513SDarren.Reed@Sun.COM if (dst->h_hint == HH_BEFORE || dst->h_hint == HH_AFTER) { 1885*7513SDarren.Reed@Sun.COM len = strlen((char *)src->h_hintvalue); 1886*7513SDarren.Reed@Sun.COM if (len > 0) { 1887*7513SDarren.Reed@Sun.COM dst->h_hintvalue = (uintptr_t)kmem_alloc(len + 1, 1888*7513SDarren.Reed@Sun.COM KM_SLEEP); 1889*7513SDarren.Reed@Sun.COM (void) strcpy((char *)dst->h_hintvalue, 1890*7513SDarren.Reed@Sun.COM (char *)src->h_hintvalue); 1891*7513SDarren.Reed@Sun.COM } 1892*7513SDarren.Reed@Sun.COM } 1893*7513SDarren.Reed@Sun.COM 18942958Sdr146992 return (new); 18952958Sdr146992 } 18962958Sdr146992 18972958Sdr146992 /* 1898*7513SDarren.Reed@Sun.COM * Function: hook_init_kstats 1899*7513SDarren.Reed@Sun.COM * Returns: None 1900*7513SDarren.Reed@Sun.COM * Parameters: hfi(I) - pointer to the family that owns the event. 1901*7513SDarren.Reed@Sun.COM * hei(I) - pointer to the event that owns this hook 1902*7513SDarren.Reed@Sun.COM * hi(I) - pointer to the hook for which we create kstats for 1903*7513SDarren.Reed@Sun.COM * 1904*7513SDarren.Reed@Sun.COM * Each hook that is registered with this framework has its own kstats 1905*7513SDarren.Reed@Sun.COM * set up so that we can provide an easy way in which to observe the 1906*7513SDarren.Reed@Sun.COM * look of hooks (using the kstat command.) The position is set to 0 1907*7513SDarren.Reed@Sun.COM * here but is recalculated after we know the insertion has been a 1908*7513SDarren.Reed@Sun.COM * success. 1909*7513SDarren.Reed@Sun.COM */ 1910*7513SDarren.Reed@Sun.COM static void 1911*7513SDarren.Reed@Sun.COM hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei, hook_int_t *hi) 1912*7513SDarren.Reed@Sun.COM { 1913*7513SDarren.Reed@Sun.COM hook_hook_kstat_t template = { 1914*7513SDarren.Reed@Sun.COM { "version", KSTAT_DATA_INT32 }, 1915*7513SDarren.Reed@Sun.COM { "flags", KSTAT_DATA_UINT32 }, 1916*7513SDarren.Reed@Sun.COM { "hint", KSTAT_DATA_INT32 }, 1917*7513SDarren.Reed@Sun.COM { "hint_value", KSTAT_DATA_UINT64 }, 1918*7513SDarren.Reed@Sun.COM { "position", KSTAT_DATA_INT32 }, 1919*7513SDarren.Reed@Sun.COM { "hook_hits", KSTAT_DATA_UINT64 } 1920*7513SDarren.Reed@Sun.COM }; 1921*7513SDarren.Reed@Sun.COM hook_stack_t *hks; 1922*7513SDarren.Reed@Sun.COM size_t kslen; 1923*7513SDarren.Reed@Sun.COM int position; 1924*7513SDarren.Reed@Sun.COM hook_int_t *h; 1925*7513SDarren.Reed@Sun.COM 1926*7513SDarren.Reed@Sun.COM kslen = strlen(hfi->hfi_family.hf_name) + 1927*7513SDarren.Reed@Sun.COM strlen(hei->hei_event->he_name) + 2; 1928*7513SDarren.Reed@Sun.COM 1929*7513SDarren.Reed@Sun.COM hi->hi_ksname = (char *)kmem_zalloc(kslen, KM_SLEEP); 1930*7513SDarren.Reed@Sun.COM (void) snprintf(hi->hi_ksname, kslen, "%s/%s", 1931*7513SDarren.Reed@Sun.COM hfi->hfi_family.hf_name, hei->hei_event->he_name); 1932*7513SDarren.Reed@Sun.COM 1933*7513SDarren.Reed@Sun.COM hks = hfi->hfi_stack; 1934*7513SDarren.Reed@Sun.COM hi->hi_kstatp = kstat_create_netstack(hi->hi_ksname, 0, 1935*7513SDarren.Reed@Sun.COM hi->hi_hook.h_name, "hook", KSTAT_TYPE_NAMED, 1936*7513SDarren.Reed@Sun.COM sizeof (hi->hi_kstats) / sizeof (kstat_named_t), 1937*7513SDarren.Reed@Sun.COM KSTAT_FLAG_VIRTUAL, hks->hks_netstackid); 1938*7513SDarren.Reed@Sun.COM 1939*7513SDarren.Reed@Sun.COM /* Initialise the kstats for the structure */ 1940*7513SDarren.Reed@Sun.COM bcopy(&template, &hi->hi_kstats, sizeof (template)); 1941*7513SDarren.Reed@Sun.COM hi->hi_kstats.hook_version.value.i32 = hi->hi_hook.h_version; 1942*7513SDarren.Reed@Sun.COM hi->hi_kstats.hook_flags.value.ui32 = hi->hi_hook.h_flags; 1943*7513SDarren.Reed@Sun.COM hi->hi_kstats.hook_hint.value.i32 = hi->hi_hook.h_hint; 1944*7513SDarren.Reed@Sun.COM hi->hi_kstats.hook_position.value.i32 = 0; 1945*7513SDarren.Reed@Sun.COM hi->hi_kstats.hook_hits.value.ui64 = 0; 1946*7513SDarren.Reed@Sun.COM 1947*7513SDarren.Reed@Sun.COM switch (hi->hi_hook.h_hint) { 1948*7513SDarren.Reed@Sun.COM case HH_BEFORE : 1949*7513SDarren.Reed@Sun.COM case HH_AFTER : 1950*7513SDarren.Reed@Sun.COM hi->hi_kstats.hook_hintvalue.data_type = KSTAT_DATA_STRING; 1951*7513SDarren.Reed@Sun.COM hi->hi_kstats.hook_hintvalue.value.ui64 = 1952*7513SDarren.Reed@Sun.COM hi->hi_hook.h_hintvalue; 1953*7513SDarren.Reed@Sun.COM break; 1954*7513SDarren.Reed@Sun.COM default : 1955*7513SDarren.Reed@Sun.COM break; 1956*7513SDarren.Reed@Sun.COM } 1957*7513SDarren.Reed@Sun.COM 1958*7513SDarren.Reed@Sun.COM if (hi->hi_kstatp != NULL) { 1959*7513SDarren.Reed@Sun.COM hi->hi_kstatp->ks_data = (void *)&hi->hi_kstats; 1960*7513SDarren.Reed@Sun.COM hi->hi_kstatp->ks_private = 1961*7513SDarren.Reed@Sun.COM (void *)(uintptr_t)hks->hks_netstackid; 1962*7513SDarren.Reed@Sun.COM 1963*7513SDarren.Reed@Sun.COM kstat_install(hi->hi_kstatp); 1964*7513SDarren.Reed@Sun.COM } 1965*7513SDarren.Reed@Sun.COM 1966*7513SDarren.Reed@Sun.COM position = 1; 1967*7513SDarren.Reed@Sun.COM TAILQ_FOREACH(h, &hei->hei_head, hi_entry) { 1968*7513SDarren.Reed@Sun.COM h->hi_kstats.hook_position.value.ui32 = position++; 1969*7513SDarren.Reed@Sun.COM } 1970*7513SDarren.Reed@Sun.COM } 1971*7513SDarren.Reed@Sun.COM 1972*7513SDarren.Reed@Sun.COM /* 1973*7513SDarren.Reed@Sun.COM * Function: hook_int_free 19742958Sdr146992 * Returns: None 19752958Sdr146992 * Parameters: hi(I) - internal hook pointer 19762958Sdr146992 * 19772958Sdr146992 * Free alloc memory for hook 19782958Sdr146992 */ 19792958Sdr146992 static void 1980*7513SDarren.Reed@Sun.COM hook_int_free(hook_int_t *hi, netstackid_t stackid) 19812958Sdr146992 { 1982*7513SDarren.Reed@Sun.COM int len; 1983*7513SDarren.Reed@Sun.COM 19842958Sdr146992 ASSERT(hi != NULL); 19852958Sdr146992 19862958Sdr146992 /* Free name space */ 19872958Sdr146992 if (hi->hi_hook.h_name != NULL) { 19882958Sdr146992 kmem_free(hi->hi_hook.h_name, strlen(hi->hi_hook.h_name) + 1); 19892958Sdr146992 } 1990*7513SDarren.Reed@Sun.COM if (hi->hi_ksname != NULL) { 1991*7513SDarren.Reed@Sun.COM kmem_free(hi->hi_ksname, strlen(hi->hi_ksname) + 1); 1992*7513SDarren.Reed@Sun.COM } 1993*7513SDarren.Reed@Sun.COM 1994*7513SDarren.Reed@Sun.COM /* Free the name used with the before/after hints. */ 1995*7513SDarren.Reed@Sun.COM switch (hi->hi_hook.h_hint) { 1996*7513SDarren.Reed@Sun.COM case HH_BEFORE : 1997*7513SDarren.Reed@Sun.COM case HH_AFTER : 1998*7513SDarren.Reed@Sun.COM len = strlen((char *)hi->hi_hook.h_hintvalue); 1999*7513SDarren.Reed@Sun.COM if (len > 0) 2000*7513SDarren.Reed@Sun.COM kmem_free((void *)hi->hi_hook.h_hintvalue, len + 1); 2001*7513SDarren.Reed@Sun.COM break; 2002*7513SDarren.Reed@Sun.COM default : 2003*7513SDarren.Reed@Sun.COM break; 2004*7513SDarren.Reed@Sun.COM } 2005*7513SDarren.Reed@Sun.COM 2006*7513SDarren.Reed@Sun.COM if (hi->hi_kstatp != NULL) 2007*7513SDarren.Reed@Sun.COM kstat_delete_netstack(hi->hi_kstatp, stackid); 20082958Sdr146992 20092958Sdr146992 /* Free container */ 20102958Sdr146992 kmem_free(hi, sizeof (*hi)); 20112958Sdr146992 } 2012*7513SDarren.Reed@Sun.COM 2013*7513SDarren.Reed@Sun.COM /* 2014*7513SDarren.Reed@Sun.COM * Function: hook_alloc 2015*7513SDarren.Reed@Sun.COM * Returns: hook_t * - pointer to new hook structure 2016*7513SDarren.Reed@Sun.COM * Parameters: version(I) - version number of the API when compiled 2017*7513SDarren.Reed@Sun.COM * 2018*7513SDarren.Reed@Sun.COM * This function serves as the interface for consumers to obtain a hook_t 2019*7513SDarren.Reed@Sun.COM * structure. At this point in time, there is only a single "version" of 2020*7513SDarren.Reed@Sun.COM * it, leading to a straight forward function. In a perfect world the 2021*7513SDarren.Reed@Sun.COM * h_vesion would be a protected data structure member, but C isn't that 2022*7513SDarren.Reed@Sun.COM * advanced... 2023*7513SDarren.Reed@Sun.COM */ 2024*7513SDarren.Reed@Sun.COM hook_t * 2025*7513SDarren.Reed@Sun.COM hook_alloc(const int h_version) 2026*7513SDarren.Reed@Sun.COM { 2027*7513SDarren.Reed@Sun.COM hook_t *h; 2028*7513SDarren.Reed@Sun.COM 2029*7513SDarren.Reed@Sun.COM h = kmem_zalloc(sizeof (hook_t), KM_SLEEP); 2030*7513SDarren.Reed@Sun.COM h->h_version = h_version; 2031*7513SDarren.Reed@Sun.COM return (h); 2032*7513SDarren.Reed@Sun.COM } 2033*7513SDarren.Reed@Sun.COM 2034*7513SDarren.Reed@Sun.COM /* 2035*7513SDarren.Reed@Sun.COM * Function: hook_free 2036*7513SDarren.Reed@Sun.COM * Returns: None 2037*7513SDarren.Reed@Sun.COM * Parameters: h(I) - external hook pointer 2038*7513SDarren.Reed@Sun.COM * 2039*7513SDarren.Reed@Sun.COM * This function only free's memory allocated with hook_alloc(), so that if 2040*7513SDarren.Reed@Sun.COM * (for example) kernel memory was allocated for h_name, this needs to be 2041*7513SDarren.Reed@Sun.COM * free'd before calling hook_free(). 2042*7513SDarren.Reed@Sun.COM */ 2043*7513SDarren.Reed@Sun.COM void 2044*7513SDarren.Reed@Sun.COM hook_free(hook_t *h) 2045*7513SDarren.Reed@Sun.COM { 2046*7513SDarren.Reed@Sun.COM kmem_free(h, sizeof (*h)); 2047*7513SDarren.Reed@Sun.COM } 2048*7513SDarren.Reed@Sun.COM 2049*7513SDarren.Reed@Sun.COM /* 2050*7513SDarren.Reed@Sun.COM * Function: hook_notify_register 2051*7513SDarren.Reed@Sun.COM * Returns: 0 = success, else failure 2052*7513SDarren.Reed@Sun.COM * Parameters: lock(I) - netstack identifier 2053*7513SDarren.Reed@Sun.COM * head(I) - top of the list of callbacks 2054*7513SDarren.Reed@Sun.COM * callback(I) - function to be called 2055*7513SDarren.Reed@Sun.COM * arg(I) - arg to pass back to the function 2056*7513SDarren.Reed@Sun.COM * 2057*7513SDarren.Reed@Sun.COM * This function implements the modification of the list of callbacks 2058*7513SDarren.Reed@Sun.COM * that are registered when someone wants to be advised of a change 2059*7513SDarren.Reed@Sun.COM * that has happened. 2060*7513SDarren.Reed@Sun.COM */ 2061*7513SDarren.Reed@Sun.COM static int 2062*7513SDarren.Reed@Sun.COM hook_notify_register(cvwaitlock_t *lock, hook_notify_head_t *head, 2063*7513SDarren.Reed@Sun.COM hook_notify_fn_t callback, void *arg) 2064*7513SDarren.Reed@Sun.COM { 2065*7513SDarren.Reed@Sun.COM hook_notify_t *hn; 2066*7513SDarren.Reed@Sun.COM 2067*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(lock); 2068*7513SDarren.Reed@Sun.COM 2069*7513SDarren.Reed@Sun.COM TAILQ_FOREACH(hn, head, hn_entry) { 2070*7513SDarren.Reed@Sun.COM if (hn->hn_func == callback) { 2071*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(lock); 2072*7513SDarren.Reed@Sun.COM return (EEXIST); 2073*7513SDarren.Reed@Sun.COM } 2074*7513SDarren.Reed@Sun.COM } 2075*7513SDarren.Reed@Sun.COM 2076*7513SDarren.Reed@Sun.COM hn = (hook_notify_t *)kmem_alloc(sizeof (*hn), KM_SLEEP); 2077*7513SDarren.Reed@Sun.COM hn->hn_func = callback; 2078*7513SDarren.Reed@Sun.COM hn->hn_arg = arg; 2079*7513SDarren.Reed@Sun.COM TAILQ_INSERT_TAIL(head, hn, hn_entry); 2080*7513SDarren.Reed@Sun.COM 2081*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(lock); 2082*7513SDarren.Reed@Sun.COM 2083*7513SDarren.Reed@Sun.COM return (0); 2084*7513SDarren.Reed@Sun.COM } 2085*7513SDarren.Reed@Sun.COM 2086*7513SDarren.Reed@Sun.COM /* 2087*7513SDarren.Reed@Sun.COM * Function: hook_stack_notify_register 2088*7513SDarren.Reed@Sun.COM * Returns: 0 = success, else failure 2089*7513SDarren.Reed@Sun.COM * Parameters: stackid(I) - netstack identifier 2090*7513SDarren.Reed@Sun.COM * callback(I) - function to be called 2091*7513SDarren.Reed@Sun.COM * 2092*7513SDarren.Reed@Sun.COM */ 2093*7513SDarren.Reed@Sun.COM static int 2094*7513SDarren.Reed@Sun.COM hook_notify_unregister(cvwaitlock_t *lock, hook_notify_head_t *head, 2095*7513SDarren.Reed@Sun.COM hook_notify_fn_t callback) 2096*7513SDarren.Reed@Sun.COM { 2097*7513SDarren.Reed@Sun.COM hook_notify_t *hn; 2098*7513SDarren.Reed@Sun.COM 2099*7513SDarren.Reed@Sun.COM CVW_ENTER_WRITE(lock); 2100*7513SDarren.Reed@Sun.COM 2101*7513SDarren.Reed@Sun.COM TAILQ_FOREACH(hn, head, hn_entry) { 2102*7513SDarren.Reed@Sun.COM if (hn->hn_func == callback) 2103*7513SDarren.Reed@Sun.COM break; 2104*7513SDarren.Reed@Sun.COM } 2105*7513SDarren.Reed@Sun.COM if (hn == NULL) { 2106*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(lock); 2107*7513SDarren.Reed@Sun.COM return (ESRCH); 2108*7513SDarren.Reed@Sun.COM } 2109*7513SDarren.Reed@Sun.COM 2110*7513SDarren.Reed@Sun.COM TAILQ_REMOVE(head, hn, hn_entry); 2111*7513SDarren.Reed@Sun.COM 2112*7513SDarren.Reed@Sun.COM CVW_EXIT_WRITE(lock); 2113*7513SDarren.Reed@Sun.COM 2114*7513SDarren.Reed@Sun.COM kmem_free(hn, sizeof (*hn)); 2115*7513SDarren.Reed@Sun.COM 2116*7513SDarren.Reed@Sun.COM return (0); 2117*7513SDarren.Reed@Sun.COM } 2118*7513SDarren.Reed@Sun.COM 2119*7513SDarren.Reed@Sun.COM /* 2120*7513SDarren.Reed@Sun.COM * Function: hook_notify_run 2121*7513SDarren.Reed@Sun.COM * Returns: None 2122*7513SDarren.Reed@Sun.COM * Parameters: head(I) - top of the list of callbacks 2123*7513SDarren.Reed@Sun.COM * family(I) - name of the hook family that owns the event 2124*7513SDarren.Reed@Sun.COM * event(I) - name of the event being changed 2125*7513SDarren.Reed@Sun.COM * name(I) - name of the object causing change 2126*7513SDarren.Reed@Sun.COM * cmd(I) - either HN_UNREGISTER or HN_REGISTER 2127*7513SDarren.Reed@Sun.COM * 2128*7513SDarren.Reed@Sun.COM * This function walks through the list of registered callbacks and 2129*7513SDarren.Reed@Sun.COM * executes each one, passing back the arg supplied when registered 2130*7513SDarren.Reed@Sun.COM * and the name of the family (that owns the event), event (the thing 2131*7513SDarren.Reed@Sun.COM * to which we're making a change) and finally a name that describes 2132*7513SDarren.Reed@Sun.COM * what is being added or removed, as indicated by cmd. 2133*7513SDarren.Reed@Sun.COM * 2134*7513SDarren.Reed@Sun.COM * This function does not acquire or release any lock as it is required 2135*7513SDarren.Reed@Sun.COM * that code calling it do so before hand. The use of hook_notify_head_t 2136*7513SDarren.Reed@Sun.COM * is protected by the use of flagwait_t in the structures that own this 2137*7513SDarren.Reed@Sun.COM * list and with the use of the FWF_ADD/DEL_ACTIVE flags. 2138*7513SDarren.Reed@Sun.COM */ 2139*7513SDarren.Reed@Sun.COM static void 2140*7513SDarren.Reed@Sun.COM hook_notify_run(hook_notify_head_t *head, char *family, char *event, 2141*7513SDarren.Reed@Sun.COM char *name, hook_notify_cmd_t cmd) 2142*7513SDarren.Reed@Sun.COM { 2143*7513SDarren.Reed@Sun.COM hook_notify_t *hn; 2144*7513SDarren.Reed@Sun.COM 2145*7513SDarren.Reed@Sun.COM TAILQ_FOREACH(hn, head, hn_entry) { 2146*7513SDarren.Reed@Sun.COM (*hn->hn_func)(cmd, hn->hn_arg, family, event, name); 2147*7513SDarren.Reed@Sun.COM } 2148*7513SDarren.Reed@Sun.COM } 2149