1381a2a9aSdr146992 /* 2381a2a9aSdr146992 * CDDL HEADER START 3381a2a9aSdr146992 * 4381a2a9aSdr146992 * The contents of this file are subject to the terms of the 5381a2a9aSdr146992 * Common Development and Distribution License (the "License"). 6381a2a9aSdr146992 * You may not use this file except in compliance with the License. 7381a2a9aSdr146992 * 8381a2a9aSdr146992 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9381a2a9aSdr146992 * or http://www.opensolaris.org/os/licensing. 10381a2a9aSdr146992 * See the License for the specific language governing permissions 11381a2a9aSdr146992 * and limitations under the License. 12381a2a9aSdr146992 * 13381a2a9aSdr146992 * When distributing Covered Code, include this CDDL HEADER in each 14381a2a9aSdr146992 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15381a2a9aSdr146992 * If applicable, add the following below this CDDL HEADER, with the 16381a2a9aSdr146992 * fields enclosed by brackets "[]" replaced with your own identifying 17381a2a9aSdr146992 * information: Portions Copyright [yyyy] [name of copyright owner] 18381a2a9aSdr146992 * 19381a2a9aSdr146992 * CDDL HEADER END 20381a2a9aSdr146992 */ 21381a2a9aSdr146992 /* 22*7ddc9b1aSDarren Reed * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23381a2a9aSdr146992 * Use is subject to license terms. 24381a2a9aSdr146992 */ 25381a2a9aSdr146992 #include <sys/param.h> 26381a2a9aSdr146992 #include <sys/types.h> 27381a2a9aSdr146992 #include <sys/systm.h> 28381a2a9aSdr146992 #include <sys/errno.h> 29381a2a9aSdr146992 #include <sys/kmem.h> 30381a2a9aSdr146992 #include <sys/mutex.h> 31381a2a9aSdr146992 #include <sys/condvar.h> 32381a2a9aSdr146992 #include <sys/modctl.h> 33381a2a9aSdr146992 #include <sys/hook_impl.h> 34381a2a9aSdr146992 #include <sys/sdt.h> 35*7ddc9b1aSDarren Reed #include <sys/cmn_err.h> 36381a2a9aSdr146992 37381a2a9aSdr146992 /* 38381a2a9aSdr146992 * This file provides kernel hook framework. 39381a2a9aSdr146992 */ 40381a2a9aSdr146992 41381a2a9aSdr146992 static struct modldrv modlmisc = { 42381a2a9aSdr146992 &mod_miscops, /* drv_modops */ 43381a2a9aSdr146992 "Hooks Interface v1.0", /* drv_linkinfo */ 44381a2a9aSdr146992 }; 45381a2a9aSdr146992 46381a2a9aSdr146992 static struct modlinkage modlinkage = { 47381a2a9aSdr146992 MODREV_1, /* ml_rev */ 48381a2a9aSdr146992 &modlmisc, /* ml_linkage */ 49381a2a9aSdr146992 NULL 50381a2a9aSdr146992 }; 51381a2a9aSdr146992 52381a2a9aSdr146992 /* 53*7ddc9b1aSDarren Reed * How it works. 54*7ddc9b1aSDarren Reed * ============= 55*7ddc9b1aSDarren Reed * Use of the hook framework here is tied up with zones - when a new zone 56*7ddc9b1aSDarren Reed * is created, we create a new hook_stack_t and are open to business for 57*7ddc9b1aSDarren Reed * allowing new hook families and their events. 58*7ddc9b1aSDarren Reed * 59*7ddc9b1aSDarren Reed * A consumer of these hooks is expected to operate in this fashion: 60*7ddc9b1aSDarren Reed * 1) call hook_family_add() to create a new family of hooks. It is a 61*7ddc9b1aSDarren Reed * current requirement that this call must be made with the value 62*7ddc9b1aSDarren Reed * returned from hook_stack_init, by way of infrastructure elsewhere. 63*7ddc9b1aSDarren Reed * 2) add events to the registered family with calls to hook_event_add. 64*7ddc9b1aSDarren Reed * 65*7ddc9b1aSDarren Reed * At this point, the structures in place should be open to others to 66*7ddc9b1aSDarren Reed * add hooks to the event or add notifiers for when the contents of the 67*7ddc9b1aSDarren Reed * hook stack changes. 68*7ddc9b1aSDarren Reed * 69*7ddc9b1aSDarren Reed * The interesting stuff happens on teardown. 70*7ddc9b1aSDarren Reed * 71*7ddc9b1aSDarren Reed * It is a requirement that the provider of hook events work in the reverse 72*7ddc9b1aSDarren Reed * order to the above, so that the first step is: 73*7ddc9b1aSDarren Reed * 1) remove events from each hook family created earlier 74*7ddc9b1aSDarren Reed * 2) remove hook families from the hook stack. 75*7ddc9b1aSDarren Reed * 76*7ddc9b1aSDarren Reed * When doing teardown of both events and families, a check is made to see 77*7ddc9b1aSDarren Reed * if either structure is still "busy". If so then a boolean flag is set to 78*7ddc9b1aSDarren Reed * say that the structure is condemned. The presence of this flag being set 79*7ddc9b1aSDarren Reed * must be checked for in _add()/_register()/ functions and a failure returned 80*7ddc9b1aSDarren Reed * if it is set. It is ignored by the _find() functions because they're 81*7ddc9b1aSDarren Reed * used by _remove()/_unregister(). While setting the condemned flag when 82*7ddc9b1aSDarren Reed * trying to delete a structure would normally be keyed from the presence 83*7ddc9b1aSDarren Reed * of a reference count being greater than 1, in this implementation there 84*7ddc9b1aSDarren Reed * are no reference counts required: instead the presence of objects on 85*7ddc9b1aSDarren Reed * linked lists is taken to mean something is still "busy." 86*7ddc9b1aSDarren Reed * 87*7ddc9b1aSDarren Reed * ONLY the caller that adds the family and the events ever has a direct 88*7ddc9b1aSDarren Reed * reference to the internal structures and thus ONLY it should be doing 89*7ddc9b1aSDarren Reed * the removal of either the event or family. In practise, what this means 90*7ddc9b1aSDarren Reed * is that in ip_netinfo.c, we have calls to net_protocol_register(), followed 91*7ddc9b1aSDarren Reed * by net_event_register() (these interface to hook_family_add() and 92*7ddc9b1aSDarren Reed * hook_event_add(), respectively) that are made when we create an instance 93*7ddc9b1aSDarren Reed * of IP and when the IP instance is shutdown/destroyed, it calls 94*7ddc9b1aSDarren Reed * net_event_unregister() and net_protocol_unregister(), which in turn call 95*7ddc9b1aSDarren Reed * hook_event_remove() and hook_family_remove() respectively. Nobody else 96*7ddc9b1aSDarren Reed * is entitled to call the _unregister() functions. It is imperative that 97*7ddc9b1aSDarren Reed * there be only one _remove() call for every _add() call. 98*7ddc9b1aSDarren Reed * 99*7ddc9b1aSDarren Reed * It is possible that code which is interfacing with this hook framework 100*7ddc9b1aSDarren Reed * won't do all the cleaning up that it needs to at the right time. While 101*7ddc9b1aSDarren Reed * we can't prevent programmers from creating memory leaks, we can synchronise 102*7ddc9b1aSDarren Reed * when we clean up data structures to prevent code accessing free'd memory. 103*7ddc9b1aSDarren Reed * 104*7ddc9b1aSDarren Reed * A simple diagram showing the ownership is as follows: 105*7ddc9b1aSDarren Reed * 106*7ddc9b1aSDarren Reed * Owned +--------------+ 107*7ddc9b1aSDarren Reed * by | hook_stack_t | 108*7ddc9b1aSDarren Reed * the +--------------+ 109*7ddc9b1aSDarren Reed * Instance | 110*7ddc9b1aSDarren Reed * - - - - - - - -|- - - - - - - - - - - - - - - - - - 111*7ddc9b1aSDarren Reed * V 112*7ddc9b1aSDarren Reed * Owned +-------------------+ +-------------------+ 113*7ddc9b1aSDarren Reed * | hook_family_int_t |---->| hook_family_int_t | 114*7ddc9b1aSDarren Reed * by +-------------------+ +-------------------+ 115*7ddc9b1aSDarren Reed * | \+---------------+ \+---------------+ 116*7ddc9b1aSDarren Reed * network | | hook_family_t | | hook_family_t | 117*7ddc9b1aSDarren Reed * V +---------------+ +---------------+ 118*7ddc9b1aSDarren Reed * protocol +------------------+ +------------------+ 119*7ddc9b1aSDarren Reed * | hook_event_int_t |---->| hook_event_int_t | 120*7ddc9b1aSDarren Reed * (ipv4,ipv6) +------------------+ +------------------+ 121*7ddc9b1aSDarren Reed * | \+--------------+ \+--------------+ 122*7ddc9b1aSDarren Reed * | | hook_event_t | | hook_event_t | 123*7ddc9b1aSDarren Reed * | +--------------+ +--------------+ 124*7ddc9b1aSDarren Reed * - - - - - - - -|- - - - - - - - - - - - - - - - - - 125*7ddc9b1aSDarren Reed * V 126*7ddc9b1aSDarren Reed * Owned +------------+ 127*7ddc9b1aSDarren Reed * | hook_int_t | 128*7ddc9b1aSDarren Reed * by +------------+ 129*7ddc9b1aSDarren Reed * \+--------+ 130*7ddc9b1aSDarren Reed * the consumer | hook_t | 131*7ddc9b1aSDarren Reed * +--------+ 132*7ddc9b1aSDarren Reed * 133*7ddc9b1aSDarren Reed * The consumers, such as IPFilter, do not have any pointers or hold any 134*7ddc9b1aSDarren Reed * references to hook_int_t, hook_event_t or hook_event_int_t. By placing 135*7ddc9b1aSDarren Reed * a hook on an event through net_hook_register(), an implicit reference 136*7ddc9b1aSDarren Reed * to the hook_event_int_t is returned with a successful call. Additionally, 137*7ddc9b1aSDarren Reed * IPFilter does not see the hook_family_int_t or hook_family_t directly. 138*7ddc9b1aSDarren Reed * Rather it is returned a net_handle_t (from net_protocol_lookup()) that 139*7ddc9b1aSDarren Reed * contains a pointer to hook_family_int_t. The structure behind the 140*7ddc9b1aSDarren Reed * net_handle_t (struct net_data) *is* reference counted and managed 141*7ddc9b1aSDarren Reed * appropriately. 142*7ddc9b1aSDarren Reed * 143*7ddc9b1aSDarren Reed * A more detailed picture that describes how the family/event structures 144*7ddc9b1aSDarren Reed * are linked together can be found in <sys/hook_impl.h> 145*7ddc9b1aSDarren Reed */ 146*7ddc9b1aSDarren Reed 147*7ddc9b1aSDarren Reed /* 148*7ddc9b1aSDarren Reed * Locking 149*7ddc9b1aSDarren Reed * ======= 150*7ddc9b1aSDarren Reed * The use of CVW_* macros to do locking is driven by the need to allow 151*7ddc9b1aSDarren Reed * recursive locking with read locks when we're processing packets. This 152*7ddc9b1aSDarren Reed * is necessary because various netinfo functions need to hold read locks, 153*7ddc9b1aSDarren Reed * by design, as they can be called in or out of packet context. 154*7ddc9b1aSDarren Reed */ 155*7ddc9b1aSDarren Reed /* 156381a2a9aSdr146992 * Hook internal functions 157381a2a9aSdr146992 */ 158381a2a9aSdr146992 static hook_int_t *hook_copy(hook_t *src); 159f4b3ec61Sdh155122 static hook_event_int_t *hook_event_checkdup(hook_event_t *he, 160f4b3ec61Sdh155122 hook_stack_t *hks); 161381a2a9aSdr146992 static hook_event_int_t *hook_event_copy(hook_event_t *src); 162381a2a9aSdr146992 static hook_event_int_t *hook_event_find(hook_family_int_t *hfi, char *event); 163*7ddc9b1aSDarren Reed static void hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi); 164381a2a9aSdr146992 static hook_family_int_t *hook_family_copy(hook_family_t *src); 165f4b3ec61Sdh155122 static hook_family_int_t *hook_family_find(char *family, hook_stack_t *hks); 166*7ddc9b1aSDarren Reed static void hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks); 167381a2a9aSdr146992 static hook_int_t *hook_find(hook_event_int_t *hei, hook_t *h); 168*7ddc9b1aSDarren Reed static void hook_int_free(hook_int_t *hi, netstackid_t); 169381a2a9aSdr146992 static void hook_init(void); 170f4b3ec61Sdh155122 static void hook_fini(void); 171f4b3ec61Sdh155122 static void *hook_stack_init(netstackid_t stackid, netstack_t *ns); 172f4b3ec61Sdh155122 static void hook_stack_fini(netstackid_t stackid, void *arg); 173*7ddc9b1aSDarren Reed static void hook_stack_shutdown(netstackid_t stackid, void *arg); 174*7ddc9b1aSDarren Reed static int hook_insert(hook_int_head_t *head, hook_int_t *new); 175*7ddc9b1aSDarren Reed static void hook_insert_plain(hook_int_head_t *head, hook_int_t *new); 176*7ddc9b1aSDarren Reed static int hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new); 177*7ddc9b1aSDarren Reed static hook_int_t *hook_find_byname(hook_int_head_t *head, char *name); 178*7ddc9b1aSDarren Reed static void hook_event_init_kstats(hook_family_int_t *, hook_event_int_t *); 179*7ddc9b1aSDarren Reed static void hook_event_notify_run(hook_event_int_t *, hook_family_int_t *, 180*7ddc9b1aSDarren Reed char *event, char *name, hook_notify_cmd_t cmd); 181*7ddc9b1aSDarren Reed static void hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei, 182*7ddc9b1aSDarren Reed hook_int_t *hi); 183*7ddc9b1aSDarren Reed static int hook_notify_register(cvwaitlock_t *lock, hook_notify_head_t *head, 184*7ddc9b1aSDarren Reed hook_notify_fn_t callback, void *arg); 185*7ddc9b1aSDarren Reed static int hook_notify_unregister(cvwaitlock_t *lock, 186*7ddc9b1aSDarren Reed hook_notify_head_t *head, hook_notify_fn_t callback); 187*7ddc9b1aSDarren Reed static void hook_notify_run(hook_notify_head_t *head, char *family, 188*7ddc9b1aSDarren Reed char *event, char *name, hook_notify_cmd_t cmd); 189*7ddc9b1aSDarren Reed static void hook_stack_notify_run(hook_stack_t *hks, char *name, 190*7ddc9b1aSDarren Reed hook_notify_cmd_t cmd); 191*7ddc9b1aSDarren Reed static void hook_stack_remove(hook_stack_t *hks); 192*7ddc9b1aSDarren Reed 193*7ddc9b1aSDarren Reed /* 194*7ddc9b1aSDarren Reed * A list of the hook stacks is kept here because we need to enable 195*7ddc9b1aSDarren Reed * net_instance_notify_register() to be called during the creation 196*7ddc9b1aSDarren Reed * of a new instance. Previously hook_stack_get() would just use 197*7ddc9b1aSDarren Reed * the netstack functions for this work but they will return NULL 198*7ddc9b1aSDarren Reed * until the zone has been fully initialised. 199*7ddc9b1aSDarren Reed */ 200*7ddc9b1aSDarren Reed static hook_stack_head_t hook_stacks; 201*7ddc9b1aSDarren Reed static kmutex_t hook_stack_lock; 202381a2a9aSdr146992 203381a2a9aSdr146992 /* 204381a2a9aSdr146992 * Module entry points. 205381a2a9aSdr146992 */ 206381a2a9aSdr146992 int 207381a2a9aSdr146992 _init(void) 208381a2a9aSdr146992 { 209f4b3ec61Sdh155122 int error; 210f4b3ec61Sdh155122 211381a2a9aSdr146992 hook_init(); 212f4b3ec61Sdh155122 error = mod_install(&modlinkage); 213f4b3ec61Sdh155122 if (error != 0) 214f4b3ec61Sdh155122 hook_fini(); 215f4b3ec61Sdh155122 216f4b3ec61Sdh155122 return (error); 217381a2a9aSdr146992 } 218381a2a9aSdr146992 219381a2a9aSdr146992 int 220381a2a9aSdr146992 _fini(void) 221381a2a9aSdr146992 { 222f4b3ec61Sdh155122 int error; 223f4b3ec61Sdh155122 224f4b3ec61Sdh155122 error = mod_remove(&modlinkage); 225f4b3ec61Sdh155122 if (error == 0) 226f4b3ec61Sdh155122 hook_fini(); 227f4b3ec61Sdh155122 228f4b3ec61Sdh155122 return (error); 229381a2a9aSdr146992 } 230381a2a9aSdr146992 231381a2a9aSdr146992 int 232381a2a9aSdr146992 _info(struct modinfo *modinfop) 233381a2a9aSdr146992 { 234381a2a9aSdr146992 return (mod_info(&modlinkage, modinfop)); 235381a2a9aSdr146992 } 236381a2a9aSdr146992 237381a2a9aSdr146992 /* 238381a2a9aSdr146992 * Function: hook_init 239381a2a9aSdr146992 * Returns: None 240381a2a9aSdr146992 * Parameters: None 241381a2a9aSdr146992 * 242381a2a9aSdr146992 * Initialize hooks 243381a2a9aSdr146992 */ 244381a2a9aSdr146992 static void 245381a2a9aSdr146992 hook_init(void) 246381a2a9aSdr146992 { 247*7ddc9b1aSDarren Reed mutex_init(&hook_stack_lock, NULL, MUTEX_DRIVER, NULL); 248*7ddc9b1aSDarren Reed SLIST_INIT(&hook_stacks); 249*7ddc9b1aSDarren Reed 250f4b3ec61Sdh155122 /* 251f4b3ec61Sdh155122 * We want to be informed each time a stack is created or 252f4b3ec61Sdh155122 * destroyed in the kernel. 253f4b3ec61Sdh155122 */ 254*7ddc9b1aSDarren Reed netstack_register(NS_HOOK, hook_stack_init, hook_stack_shutdown, 255f4b3ec61Sdh155122 hook_stack_fini); 256381a2a9aSdr146992 } 257381a2a9aSdr146992 258f4b3ec61Sdh155122 /* 259f4b3ec61Sdh155122 * Function: hook_fini 260f4b3ec61Sdh155122 * Returns: None 261f4b3ec61Sdh155122 * Parameters: None 262f4b3ec61Sdh155122 * 263f4b3ec61Sdh155122 * Deinitialize hooks 264f4b3ec61Sdh155122 */ 265f4b3ec61Sdh155122 static void 266f4b3ec61Sdh155122 hook_fini(void) 267f4b3ec61Sdh155122 { 268f4b3ec61Sdh155122 netstack_unregister(NS_HOOK); 269*7ddc9b1aSDarren Reed 270*7ddc9b1aSDarren Reed mutex_destroy(&hook_stack_lock); 271*7ddc9b1aSDarren Reed ASSERT(SLIST_EMPTY(&hook_stacks)); 272*7ddc9b1aSDarren Reed } 273*7ddc9b1aSDarren Reed 274*7ddc9b1aSDarren Reed /* 275*7ddc9b1aSDarren Reed * Function: hook_wait_setflag 276*7ddc9b1aSDarren Reed * Returns: -1 = setting flag is disallowed, 0 = flag set and did 277*7ddc9b1aSDarren Reed * not have to wait (ie no lock droped), 1 = flag set but 278*7ddc9b1aSDarren Reed * it was necessary to drop locks to set it. 279*7ddc9b1aSDarren Reed * Parameters: waiter(I) - control data structure 280*7ddc9b1aSDarren Reed * busyset(I) - set of flags that we don't want set while 281*7ddc9b1aSDarren Reed * we are active. 282*7ddc9b1aSDarren Reed * wanted(I) - flag associated with newflag to indicate 283*7ddc9b1aSDarren Reed * what we want to do. 284*7ddc9b1aSDarren Reed * newflag(I) - the new ACTIVE flag we want to set that 285*7ddc9b1aSDarren Reed * indicates what we are doing. 286*7ddc9b1aSDarren Reed * 287*7ddc9b1aSDarren Reed * The set of functions hook_wait_* implement an API that builds on top of 288*7ddc9b1aSDarren Reed * the kcondvar_t to provide controlled execution through a critical region. 289*7ddc9b1aSDarren Reed * For each flag that indicates work is being done (FWF_*_ACTIVE) there is 290*7ddc9b1aSDarren Reed * also a flag that we set to indicate that we want to do it (FWF_*_WANTED). 291*7ddc9b1aSDarren Reed * The combination of flags is required as when this function exits to do 292*7ddc9b1aSDarren Reed * the task, the structure is then free for another caller to use and 293*7ddc9b1aSDarren Reed * to indicate that it wants to do work. The trump flags here are those 294*7ddc9b1aSDarren Reed * that indicate someone wants to destroy the structure that owns this 295*7ddc9b1aSDarren Reed * flagwait_t. In this case, we don't try to secure the ability to run 296*7ddc9b1aSDarren Reed * and return with an error. 297*7ddc9b1aSDarren Reed * 298*7ddc9b1aSDarren Reed * wanted - the FWF_*_WANTED flag that describes the action being requested 299*7ddc9b1aSDarren Reed * busyset- the set of FWF_* flags we don't want set when we run 300*7ddc9b1aSDarren Reed * newflag- the FWF_*_ACTIVE flag we will set to indicate we are busy 301*7ddc9b1aSDarren Reed */ 302*7ddc9b1aSDarren Reed int 303*7ddc9b1aSDarren Reed hook_wait_setflag(flagwait_t *waiter, uint32_t busyset, fwflag_t wanted, 304*7ddc9b1aSDarren Reed fwflag_t newflag) 305*7ddc9b1aSDarren Reed { 306*7ddc9b1aSDarren Reed int waited = 0; 307*7ddc9b1aSDarren Reed 308*7ddc9b1aSDarren Reed mutex_enter(&waiter->fw_lock); 309*7ddc9b1aSDarren Reed if (waiter->fw_flags & FWF_DESTROY) { 310*7ddc9b1aSDarren Reed mutex_exit(&waiter->fw_lock); 311*7ddc9b1aSDarren Reed return (-1); 312*7ddc9b1aSDarren Reed } 313*7ddc9b1aSDarren Reed while (waiter->fw_flags & busyset) { 314*7ddc9b1aSDarren Reed waiter->fw_flags |= wanted; 315*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(waiter->fw_owner); 316*7ddc9b1aSDarren Reed cv_wait(&waiter->fw_cv, &waiter->fw_lock); 317*7ddc9b1aSDarren Reed waited = 1; 318*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(waiter->fw_owner); 319*7ddc9b1aSDarren Reed if (waiter->fw_flags & FWF_DESTROY) { 320*7ddc9b1aSDarren Reed waiter->fw_flags &= ~wanted; 321*7ddc9b1aSDarren Reed mutex_exit(&waiter->fw_lock); 322*7ddc9b1aSDarren Reed return (-1); 323*7ddc9b1aSDarren Reed } 324*7ddc9b1aSDarren Reed waiter->fw_flags |= wanted; 325*7ddc9b1aSDarren Reed } 326*7ddc9b1aSDarren Reed waiter->fw_flags &= ~wanted; 327*7ddc9b1aSDarren Reed waiter->fw_flags |= newflag; 328*7ddc9b1aSDarren Reed mutex_exit(&waiter->fw_lock); 329*7ddc9b1aSDarren Reed return (waited); 330*7ddc9b1aSDarren Reed } 331*7ddc9b1aSDarren Reed 332*7ddc9b1aSDarren Reed /* 333*7ddc9b1aSDarren Reed * Function: hook_wait_unsetflag 334*7ddc9b1aSDarren Reed * Returns: None 335*7ddc9b1aSDarren Reed * Parameters: waiter(I) - control data structure 336*7ddc9b1aSDarren Reed * oldflag(I) - flag to reset 337*7ddc9b1aSDarren Reed * 338*7ddc9b1aSDarren Reed * Turn off the bit that we had set to run and let others know that 339*7ddc9b1aSDarren Reed * they should now check to see if they can run. 340*7ddc9b1aSDarren Reed */ 341*7ddc9b1aSDarren Reed void 342*7ddc9b1aSDarren Reed hook_wait_unsetflag(flagwait_t *waiter, uint32_t oldflag) 343*7ddc9b1aSDarren Reed { 344*7ddc9b1aSDarren Reed mutex_enter(&waiter->fw_lock); 345*7ddc9b1aSDarren Reed waiter->fw_flags &= ~oldflag; 346*7ddc9b1aSDarren Reed cv_signal(&waiter->fw_cv); 347*7ddc9b1aSDarren Reed mutex_exit(&waiter->fw_lock); 348*7ddc9b1aSDarren Reed } 349*7ddc9b1aSDarren Reed 350*7ddc9b1aSDarren Reed /* 351*7ddc9b1aSDarren Reed * Function: hook_wait_destroy 352*7ddc9b1aSDarren Reed * Returns: None 353*7ddc9b1aSDarren Reed * Parameters: waiter(I) - control data structure 354*7ddc9b1aSDarren Reed * 355*7ddc9b1aSDarren Reed * Since outer locking (on fw_owner) should ensure that only one function 356*7ddc9b1aSDarren Reed * at a time gets to call hook_wait_destroy() on a given object, there is 357*7ddc9b1aSDarren Reed * no need to guard against setting FWF_DESTROY_WANTED already being set. 358*7ddc9b1aSDarren Reed * It is, however, necessary to wait for all activity on the owning 359*7ddc9b1aSDarren Reed * structure to cease. 360*7ddc9b1aSDarren Reed */ 361*7ddc9b1aSDarren Reed void 362*7ddc9b1aSDarren Reed hook_wait_destroy(flagwait_t *waiter) 363*7ddc9b1aSDarren Reed { 364*7ddc9b1aSDarren Reed ASSERT((waiter->fw_flags & FWF_DESTROY_WANTED) == 0); 365*7ddc9b1aSDarren Reed waiter->fw_flags |= FWF_DESTROY_WANTED; 366*7ddc9b1aSDarren Reed while (!FWF_DESTROY_OK(waiter)) { 367*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(waiter->fw_owner); 368*7ddc9b1aSDarren Reed cv_wait(&waiter->fw_cv, &waiter->fw_lock); 369*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(waiter->fw_owner); 370*7ddc9b1aSDarren Reed } 371*7ddc9b1aSDarren Reed /* 372*7ddc9b1aSDarren Reed * There should now be nothing else using "waiter" or its 373*7ddc9b1aSDarren Reed * owner, so we can safely assign here without risk of wiiping 374*7ddc9b1aSDarren Reed * out someone's bit. 375*7ddc9b1aSDarren Reed */ 376*7ddc9b1aSDarren Reed waiter->fw_flags = FWF_DESTROY_ACTIVE; 377*7ddc9b1aSDarren Reed } 378*7ddc9b1aSDarren Reed 379*7ddc9b1aSDarren Reed /* 380*7ddc9b1aSDarren Reed * Function: hook_wait_init 381*7ddc9b1aSDarren Reed * Returns: None 382*7ddc9b1aSDarren Reed * Parameters: waiter(I) - control data structure 383*7ddc9b1aSDarren Reed * ownder(I) - pointer to lock that the owner of this 384*7ddc9b1aSDarren Reed * waiter uses 385*7ddc9b1aSDarren Reed * 386*7ddc9b1aSDarren Reed * "owner" gets passed in here so that when we need to call cv_wait, 387*7ddc9b1aSDarren Reed * for example in hook_wait_setflag(), we can drop the lock for the 388*7ddc9b1aSDarren Reed * next layer out, which is likely to be held in an exclusive manner. 389*7ddc9b1aSDarren Reed */ 390*7ddc9b1aSDarren Reed void 391*7ddc9b1aSDarren Reed hook_wait_init(flagwait_t *waiter, cvwaitlock_t *owner) 392*7ddc9b1aSDarren Reed { 393*7ddc9b1aSDarren Reed cv_init(&waiter->fw_cv, NULL, CV_DRIVER, NULL); 394*7ddc9b1aSDarren Reed mutex_init(&waiter->fw_lock, NULL, MUTEX_DRIVER, NULL); 395*7ddc9b1aSDarren Reed waiter->fw_flags = FWF_NONE; 396*7ddc9b1aSDarren Reed waiter->fw_owner = owner; 397f4b3ec61Sdh155122 } 398f4b3ec61Sdh155122 399f4b3ec61Sdh155122 /* 400f4b3ec61Sdh155122 * Initialize the hook stack instance. 401f4b3ec61Sdh155122 */ 402f4b3ec61Sdh155122 /*ARGSUSED*/ 403f4b3ec61Sdh155122 static void * 404f4b3ec61Sdh155122 hook_stack_init(netstackid_t stackid, netstack_t *ns) 405f4b3ec61Sdh155122 { 406f4b3ec61Sdh155122 hook_stack_t *hks; 407f4b3ec61Sdh155122 408f4b3ec61Sdh155122 #ifdef NS_DEBUG 409f4b3ec61Sdh155122 printf("hook_stack_init(stack %d)\n", stackid); 410f4b3ec61Sdh155122 #endif 411f4b3ec61Sdh155122 412f4b3ec61Sdh155122 hks = (hook_stack_t *)kmem_zalloc(sizeof (*hks), KM_SLEEP); 413*7ddc9b1aSDarren Reed hks->hks_netstack = ns; 414*7ddc9b1aSDarren Reed hks->hks_netstackid = stackid; 415f4b3ec61Sdh155122 416*7ddc9b1aSDarren Reed CVW_INIT(&hks->hks_lock); 417*7ddc9b1aSDarren Reed TAILQ_INIT(&hks->hks_nhead); 418f4b3ec61Sdh155122 SLIST_INIT(&hks->hks_familylist); 419f4b3ec61Sdh155122 420*7ddc9b1aSDarren Reed hook_wait_init(&hks->hks_waiter, &hks->hks_lock); 421*7ddc9b1aSDarren Reed 422*7ddc9b1aSDarren Reed mutex_enter(&hook_stack_lock); 423*7ddc9b1aSDarren Reed SLIST_INSERT_HEAD(&hook_stacks, hks, hks_entry); 424*7ddc9b1aSDarren Reed mutex_exit(&hook_stack_lock); 425*7ddc9b1aSDarren Reed 426f4b3ec61Sdh155122 return (hks); 427f4b3ec61Sdh155122 } 428f4b3ec61Sdh155122 429*7ddc9b1aSDarren Reed /*ARGSUSED*/ 430*7ddc9b1aSDarren Reed static void 431*7ddc9b1aSDarren Reed hook_stack_shutdown(netstackid_t stackid, void *arg) 432*7ddc9b1aSDarren Reed { 433*7ddc9b1aSDarren Reed hook_stack_t *hks = (hook_stack_t *)arg; 434*7ddc9b1aSDarren Reed 435*7ddc9b1aSDarren Reed mutex_enter(&hook_stack_lock); 436*7ddc9b1aSDarren Reed /* 437*7ddc9b1aSDarren Reed * Once this flag gets set to one, no more additions are allowed 438*7ddc9b1aSDarren Reed * to any of the structures that make up this stack. 439*7ddc9b1aSDarren Reed */ 440*7ddc9b1aSDarren Reed hks->hks_shutdown = 1; 441*7ddc9b1aSDarren Reed mutex_exit(&hook_stack_lock); 442*7ddc9b1aSDarren Reed } 443*7ddc9b1aSDarren Reed 444f4b3ec61Sdh155122 /* 445f4b3ec61Sdh155122 * Free the hook stack instance. 446f4b3ec61Sdh155122 */ 447f4b3ec61Sdh155122 /*ARGSUSED*/ 448f4b3ec61Sdh155122 static void 449f4b3ec61Sdh155122 hook_stack_fini(netstackid_t stackid, void *arg) 450f4b3ec61Sdh155122 { 451f4b3ec61Sdh155122 hook_stack_t *hks = (hook_stack_t *)arg; 452*7ddc9b1aSDarren Reed 453*7ddc9b1aSDarren Reed mutex_enter(&hook_stack_lock); 454*7ddc9b1aSDarren Reed hks->hks_shutdown = 2; 455*7ddc9b1aSDarren Reed hook_stack_remove(hks); 456*7ddc9b1aSDarren Reed mutex_exit(&hook_stack_lock); 457*7ddc9b1aSDarren Reed } 458*7ddc9b1aSDarren Reed 459*7ddc9b1aSDarren Reed /* 460*7ddc9b1aSDarren Reed * This function assumes that it is called with hook_stack_lock held. 461*7ddc9b1aSDarren Reed * It functions differently to hook_family/event_remove in that it does 462*7ddc9b1aSDarren Reed * the checks to see if it can be removed. This difference exists 463*7ddc9b1aSDarren Reed * because this structure has nothing higher up that depends on it. 464*7ddc9b1aSDarren Reed */ 465*7ddc9b1aSDarren Reed static void 466*7ddc9b1aSDarren Reed hook_stack_remove(hook_stack_t *hks) 467*7ddc9b1aSDarren Reed { 468*7ddc9b1aSDarren Reed 469*7ddc9b1aSDarren Reed ASSERT(mutex_owned(&hook_stack_lock)); 470*7ddc9b1aSDarren Reed 471*7ddc9b1aSDarren Reed /* 472*7ddc9b1aSDarren Reed * Is the structure still in use? 473*7ddc9b1aSDarren Reed */ 474*7ddc9b1aSDarren Reed if (!SLIST_EMPTY(&hks->hks_familylist) || 475*7ddc9b1aSDarren Reed !TAILQ_EMPTY(&hks->hks_nhead)) 476*7ddc9b1aSDarren Reed return; 477*7ddc9b1aSDarren Reed 478*7ddc9b1aSDarren Reed SLIST_REMOVE(&hook_stacks, hks, hook_stack, hks_entry); 479*7ddc9b1aSDarren Reed 480*7ddc9b1aSDarren Reed hook_wait_destroy(&hks->hks_waiter); 481*7ddc9b1aSDarren Reed CVW_DESTROY(&hks->hks_lock); 482f4b3ec61Sdh155122 kmem_free(hks, sizeof (*hks)); 483f4b3ec61Sdh155122 } 484381a2a9aSdr146992 485*7ddc9b1aSDarren Reed static hook_stack_t * 486*7ddc9b1aSDarren Reed hook_stack_get(netstackid_t stackid) 487*7ddc9b1aSDarren Reed { 488*7ddc9b1aSDarren Reed hook_stack_t *hks; 489*7ddc9b1aSDarren Reed 490*7ddc9b1aSDarren Reed SLIST_FOREACH(hks, &hook_stacks, hks_entry) { 491*7ddc9b1aSDarren Reed if (hks->hks_netstackid == stackid) 492*7ddc9b1aSDarren Reed break; 493*7ddc9b1aSDarren Reed } 494*7ddc9b1aSDarren Reed 495*7ddc9b1aSDarren Reed return (hks); 496*7ddc9b1aSDarren Reed } 497*7ddc9b1aSDarren Reed 498*7ddc9b1aSDarren Reed /* 499*7ddc9b1aSDarren Reed * Function: hook_stack_notify_register 500*7ddc9b1aSDarren Reed * Returns: 0 = success, else failure 501*7ddc9b1aSDarren Reed * Parameters: stackid(I) - netstack identifier 502*7ddc9b1aSDarren Reed * callback(I)- function to be called 503*7ddc9b1aSDarren Reed * arg(I) - arg to provide callback when it is called 504*7ddc9b1aSDarren Reed * 505*7ddc9b1aSDarren Reed * If we're not shutting down this instance, append a new function to the 506*7ddc9b1aSDarren Reed * list of those to call when a new family of hooks is added to this stack. 507*7ddc9b1aSDarren Reed */ 508*7ddc9b1aSDarren Reed int 509*7ddc9b1aSDarren Reed hook_stack_notify_register(netstackid_t stackid, hook_notify_fn_t callback, 510*7ddc9b1aSDarren Reed void *arg) 511*7ddc9b1aSDarren Reed { 512*7ddc9b1aSDarren Reed hook_stack_t *hks; 513*7ddc9b1aSDarren Reed int error; 514*7ddc9b1aSDarren Reed 515*7ddc9b1aSDarren Reed mutex_enter(&hook_stack_lock); 516*7ddc9b1aSDarren Reed hks = hook_stack_get(stackid); 517*7ddc9b1aSDarren Reed if (hks != NULL) { 518*7ddc9b1aSDarren Reed if (hks->hks_shutdown != 0) { 519*7ddc9b1aSDarren Reed error = ESHUTDOWN; 520*7ddc9b1aSDarren Reed } else { 521*7ddc9b1aSDarren Reed error = hook_notify_register(&hks->hks_lock, 522*7ddc9b1aSDarren Reed &hks->hks_nhead, callback, arg); 523*7ddc9b1aSDarren Reed } 524*7ddc9b1aSDarren Reed } else { 525*7ddc9b1aSDarren Reed error = ESRCH; 526*7ddc9b1aSDarren Reed } 527*7ddc9b1aSDarren Reed mutex_exit(&hook_stack_lock); 528*7ddc9b1aSDarren Reed 529*7ddc9b1aSDarren Reed return (error); 530*7ddc9b1aSDarren Reed } 531*7ddc9b1aSDarren Reed 532*7ddc9b1aSDarren Reed /* 533*7ddc9b1aSDarren Reed * Function: hook_stack_notify_unregister 534*7ddc9b1aSDarren Reed * Returns: 0 = success, else failure 535*7ddc9b1aSDarren Reed * Parameters: stackid(I) - netstack identifier 536*7ddc9b1aSDarren Reed * callback(I) - function to be called 537*7ddc9b1aSDarren Reed * 538*7ddc9b1aSDarren Reed * Attempt to remove a registered function from a hook stack's list of 539*7ddc9b1aSDarren Reed * callbacks to activiate when protocols are added/deleted. 540*7ddc9b1aSDarren Reed */ 541*7ddc9b1aSDarren Reed int 542*7ddc9b1aSDarren Reed hook_stack_notify_unregister(netstackid_t stackid, hook_notify_fn_t callback) 543*7ddc9b1aSDarren Reed { 544*7ddc9b1aSDarren Reed hook_stack_t *hks; 545*7ddc9b1aSDarren Reed int error; 546*7ddc9b1aSDarren Reed 547*7ddc9b1aSDarren Reed mutex_enter(&hook_stack_lock); 548*7ddc9b1aSDarren Reed hks = hook_stack_get(stackid); 549*7ddc9b1aSDarren Reed if (hks != NULL) { 550*7ddc9b1aSDarren Reed error = hook_notify_unregister(&hks->hks_lock, 551*7ddc9b1aSDarren Reed &hks->hks_nhead, callback); 552*7ddc9b1aSDarren Reed if ((error == 0) && (hks->hks_shutdown == 2)) 553*7ddc9b1aSDarren Reed hook_stack_remove(hks); 554*7ddc9b1aSDarren Reed } else { 555*7ddc9b1aSDarren Reed error = ESRCH; 556*7ddc9b1aSDarren Reed } 557*7ddc9b1aSDarren Reed mutex_exit(&hook_stack_lock); 558*7ddc9b1aSDarren Reed 559*7ddc9b1aSDarren Reed return (error); 560*7ddc9b1aSDarren Reed } 561*7ddc9b1aSDarren Reed 562*7ddc9b1aSDarren Reed /* 563*7ddc9b1aSDarren Reed * Function: hook_stack_notify_run 564*7ddc9b1aSDarren Reed * Returns: None 565*7ddc9b1aSDarren Reed * Parameters: hks(I) - hook stack pointer to execute callbacks for 566*7ddc9b1aSDarren Reed * name(I) - name of a hook family 567*7ddc9b1aSDarren Reed * cmd(I) - either HN_UNREGISTER or HN_REGISTER 568*7ddc9b1aSDarren Reed * 569*7ddc9b1aSDarren Reed * Run through the list of callbacks on the hook stack to be called when 570*7ddc9b1aSDarren Reed * a new hook family is added 571*7ddc9b1aSDarren Reed * 572*7ddc9b1aSDarren Reed * As hook_notify_run() expects 3 names, one for the family, one for the 573*7ddc9b1aSDarren Reed * event and one for the object being introduced and we really only have 574*7ddc9b1aSDarren Reed * one name (that of the new hook family), fake the hook stack's name by 575*7ddc9b1aSDarren Reed * converting the integer to a string and for the event just pass NULL. 576*7ddc9b1aSDarren Reed */ 577*7ddc9b1aSDarren Reed static void 578*7ddc9b1aSDarren Reed hook_stack_notify_run(hook_stack_t *hks, char *name, 579*7ddc9b1aSDarren Reed hook_notify_cmd_t cmd) 580*7ddc9b1aSDarren Reed { 581*7ddc9b1aSDarren Reed char buffer[16]; 582*7ddc9b1aSDarren Reed 583*7ddc9b1aSDarren Reed (void) snprintf(buffer, sizeof (buffer), "%u", hks->hks_netstackid); 584*7ddc9b1aSDarren Reed 585*7ddc9b1aSDarren Reed hook_notify_run(&hks->hks_nhead, buffer, NULL, name, cmd); 586*7ddc9b1aSDarren Reed } 587*7ddc9b1aSDarren Reed 588381a2a9aSdr146992 /* 589381a2a9aSdr146992 * Function: hook_run 590381a2a9aSdr146992 * Returns: int - return value according to callback func 591381a2a9aSdr146992 * Parameters: token(I) - event pointer 592381a2a9aSdr146992 * info(I) - message 593381a2a9aSdr146992 * 594381a2a9aSdr146992 * Run hooks for specific provider. The hooks registered are stepped through 595381a2a9aSdr146992 * until either the end of the list is reached or a hook function returns a 596381a2a9aSdr146992 * non-zero value. If a non-zero value is returned from a hook function, we 597381a2a9aSdr146992 * return that value back to our caller. By design, a hook function can be 598381a2a9aSdr146992 * called more than once, simultaneously. 599381a2a9aSdr146992 */ 600381a2a9aSdr146992 int 601*7ddc9b1aSDarren Reed hook_run(hook_family_int_t *hfi, hook_event_token_t token, hook_data_t info) 602381a2a9aSdr146992 { 603381a2a9aSdr146992 hook_event_int_t *hei; 604*7ddc9b1aSDarren Reed hook_int_t *hi; 605381a2a9aSdr146992 int rval = 0; 606381a2a9aSdr146992 607381a2a9aSdr146992 ASSERT(token != NULL); 608381a2a9aSdr146992 609381a2a9aSdr146992 hei = (hook_event_int_t *)token; 610381a2a9aSdr146992 DTRACE_PROBE2(hook__run__start, 611381a2a9aSdr146992 hook_event_token_t, token, 612381a2a9aSdr146992 hook_data_t, info); 613381a2a9aSdr146992 614*7ddc9b1aSDarren Reed /* 615*7ddc9b1aSDarren Reed * Hold global read lock to ensure event will not be deleted. 616*7ddc9b1aSDarren Reed * While it might be expected that we should also hold a read lock 617*7ddc9b1aSDarren Reed * on the event lock (hei_lock) to prevent the hook list from 618*7ddc9b1aSDarren Reed * changing while we're executing this function, both addition 619*7ddc9b1aSDarren Reed * to and removal from the hook list on the event is done with 620*7ddc9b1aSDarren Reed * a write lock held on hfi_lock. This is by design so that we 621*7ddc9b1aSDarren Reed * only need to get one of these locks to process a packet. 622*7ddc9b1aSDarren Reed * - locking is not a cheap thing to do for every packet. 623*7ddc9b1aSDarren Reed */ 624*7ddc9b1aSDarren Reed CVW_ENTER_READ(&hfi->hfi_lock); 625381a2a9aSdr146992 626381a2a9aSdr146992 TAILQ_FOREACH(hi, &hei->hei_head, hi_entry) { 627381a2a9aSdr146992 ASSERT(hi->hi_hook.h_func != NULL); 628381a2a9aSdr146992 DTRACE_PROBE3(hook__func__start, 629381a2a9aSdr146992 hook_event_token_t, token, 630381a2a9aSdr146992 hook_data_t, info, 631381a2a9aSdr146992 hook_int_t *, hi); 632*7ddc9b1aSDarren Reed rval = (*hi->hi_hook.h_func)(token, info, hi->hi_hook.h_arg); 633381a2a9aSdr146992 DTRACE_PROBE4(hook__func__end, 634381a2a9aSdr146992 hook_event_token_t, token, 635381a2a9aSdr146992 hook_data_t, info, 636381a2a9aSdr146992 hook_int_t *, hi, 637381a2a9aSdr146992 int, rval); 638*7ddc9b1aSDarren Reed hi->hi_kstats.hook_hits.value.ui64++; 639381a2a9aSdr146992 if (rval != 0) 640381a2a9aSdr146992 break; 641381a2a9aSdr146992 } 642381a2a9aSdr146992 643*7ddc9b1aSDarren Reed hei->hei_kstats.events.value.ui64++; 644*7ddc9b1aSDarren Reed 645*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hfi->hfi_lock); 646381a2a9aSdr146992 647381a2a9aSdr146992 DTRACE_PROBE3(hook__run__end, 648381a2a9aSdr146992 hook_event_token_t, token, 649381a2a9aSdr146992 hook_data_t, info, 650381a2a9aSdr146992 hook_int_t *, hi); 651381a2a9aSdr146992 652381a2a9aSdr146992 return (rval); 653381a2a9aSdr146992 } 654381a2a9aSdr146992 655381a2a9aSdr146992 /* 656381a2a9aSdr146992 * Function: hook_family_add 657381a2a9aSdr146992 * Returns: internal family pointer - NULL = Fail 658381a2a9aSdr146992 * Parameters: hf(I) - family pointer 659381a2a9aSdr146992 * 660381a2a9aSdr146992 * Add new family to family list 661381a2a9aSdr146992 */ 662381a2a9aSdr146992 hook_family_int_t * 663f4b3ec61Sdh155122 hook_family_add(hook_family_t *hf, hook_stack_t *hks) 664381a2a9aSdr146992 { 665381a2a9aSdr146992 hook_family_int_t *hfi, *new; 666381a2a9aSdr146992 667381a2a9aSdr146992 ASSERT(hf != NULL); 668381a2a9aSdr146992 ASSERT(hf->hf_name != NULL); 669381a2a9aSdr146992 670381a2a9aSdr146992 new = hook_family_copy(hf); 671381a2a9aSdr146992 if (new == NULL) 672381a2a9aSdr146992 return (NULL); 673381a2a9aSdr146992 674*7ddc9b1aSDarren Reed mutex_enter(&hook_stack_lock); 675*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(&hks->hks_lock); 676*7ddc9b1aSDarren Reed 677*7ddc9b1aSDarren Reed if (hks->hks_shutdown != 0) { 678*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hks->hks_lock); 679*7ddc9b1aSDarren Reed mutex_exit(&hook_stack_lock); 680*7ddc9b1aSDarren Reed hook_family_free(new, NULL); 681*7ddc9b1aSDarren Reed return (NULL); 682*7ddc9b1aSDarren Reed } 683381a2a9aSdr146992 684381a2a9aSdr146992 /* search family list */ 685f4b3ec61Sdh155122 hfi = hook_family_find(hf->hf_name, hks); 686381a2a9aSdr146992 if (hfi != NULL) { 687*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hks->hks_lock); 688*7ddc9b1aSDarren Reed mutex_exit(&hook_stack_lock); 689*7ddc9b1aSDarren Reed hook_family_free(new, NULL); 690381a2a9aSdr146992 return (NULL); 691381a2a9aSdr146992 } 692381a2a9aSdr146992 693*7ddc9b1aSDarren Reed if (hook_wait_setflag(&hks->hks_waiter, FWF_WAIT_MASK, 694*7ddc9b1aSDarren Reed FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) { 695*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hks->hks_lock); 696*7ddc9b1aSDarren Reed mutex_exit(&hook_stack_lock); 697*7ddc9b1aSDarren Reed hook_family_free(new, NULL); 698*7ddc9b1aSDarren Reed return (NULL); 699*7ddc9b1aSDarren Reed } 700*7ddc9b1aSDarren Reed 701*7ddc9b1aSDarren Reed CVW_INIT(&new->hfi_lock); 702*7ddc9b1aSDarren Reed SLIST_INIT(&new->hfi_head); 703*7ddc9b1aSDarren Reed TAILQ_INIT(&new->hfi_nhead); 704*7ddc9b1aSDarren Reed 705*7ddc9b1aSDarren Reed hook_wait_init(&new->hfi_waiter, &new->hfi_lock); 706*7ddc9b1aSDarren Reed 707*7ddc9b1aSDarren Reed new->hfi_stack = hks; 708381a2a9aSdr146992 709f4b3ec61Sdh155122 /* Add to family list head */ 710f4b3ec61Sdh155122 SLIST_INSERT_HEAD(&hks->hks_familylist, new, hfi_entry); 711f4b3ec61Sdh155122 712*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hks->hks_lock); 713*7ddc9b1aSDarren Reed mutex_exit(&hook_stack_lock); 714*7ddc9b1aSDarren Reed 715*7ddc9b1aSDarren Reed hook_stack_notify_run(hks, hf->hf_name, HN_REGISTER); 716*7ddc9b1aSDarren Reed 717*7ddc9b1aSDarren Reed hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE); 718*7ddc9b1aSDarren Reed 719381a2a9aSdr146992 return (new); 720381a2a9aSdr146992 } 721381a2a9aSdr146992 722381a2a9aSdr146992 /* 723381a2a9aSdr146992 * Function: hook_family_remove 724381a2a9aSdr146992 * Returns: int - 0 = Succ, Else = Fail 725381a2a9aSdr146992 * Parameters: hfi(I) - internal family pointer 726381a2a9aSdr146992 * 727*7ddc9b1aSDarren Reed * Remove family from family list. This function has been designed to be 728*7ddc9b1aSDarren Reed * called once and once only per hook_family_int_t. Thus when cleaning up 729*7ddc9b1aSDarren Reed * this structure as an orphan, callers should only call hook_family_free. 730381a2a9aSdr146992 */ 731381a2a9aSdr146992 int 732381a2a9aSdr146992 hook_family_remove(hook_family_int_t *hfi) 733381a2a9aSdr146992 { 734f4b3ec61Sdh155122 hook_stack_t *hks; 735381a2a9aSdr146992 736381a2a9aSdr146992 ASSERT(hfi != NULL); 737*7ddc9b1aSDarren Reed hks = hfi->hfi_stack; 738381a2a9aSdr146992 739*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(&hks->hks_lock); 740381a2a9aSdr146992 741*7ddc9b1aSDarren Reed if (hook_wait_setflag(&hks->hks_waiter, FWF_WAIT_MASK, 742*7ddc9b1aSDarren Reed FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) { 743*7ddc9b1aSDarren Reed /* 744*7ddc9b1aSDarren Reed * If we're trying to destroy the hook_stack_t... 745*7ddc9b1aSDarren Reed */ 746*7ddc9b1aSDarren Reed return (ENXIO); 747381a2a9aSdr146992 } 748381a2a9aSdr146992 749*7ddc9b1aSDarren Reed /* 750*7ddc9b1aSDarren Reed * Check if the family is in use by the presence of either events 751*7ddc9b1aSDarren Reed * or notify callbacks on the hook family. 752*7ddc9b1aSDarren Reed */ 753*7ddc9b1aSDarren Reed if (!SLIST_EMPTY(&hfi->hfi_head) || !TAILQ_EMPTY(&hfi->hfi_nhead)) { 754*7ddc9b1aSDarren Reed hfi->hfi_condemned = B_TRUE; 755*7ddc9b1aSDarren Reed } else { 756*7ddc9b1aSDarren Reed /* 757*7ddc9b1aSDarren Reed * Although hfi_condemned = B_FALSE is implied from creation, 758*7ddc9b1aSDarren Reed * putting a comment here inside the else upsets lint. 759*7ddc9b1aSDarren Reed */ 760*7ddc9b1aSDarren Reed hfi->hfi_condemned = B_FALSE; 761*7ddc9b1aSDarren Reed } 762381a2a9aSdr146992 763*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(&hfi->hfi_lock); 764*7ddc9b1aSDarren Reed hook_wait_destroy(&hfi->hfi_waiter); 765*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 766*7ddc9b1aSDarren Reed 767*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hks->hks_lock); 768*7ddc9b1aSDarren Reed 769*7ddc9b1aSDarren Reed hook_stack_notify_run(hks, hfi->hfi_family.hf_name, HN_UNREGISTER); 770*7ddc9b1aSDarren Reed 771*7ddc9b1aSDarren Reed hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE); 772*7ddc9b1aSDarren Reed 773*7ddc9b1aSDarren Reed /* 774*7ddc9b1aSDarren Reed * If we don't have to wait for anything else to disappear from this 775*7ddc9b1aSDarren Reed * structure then we can free it up. 776*7ddc9b1aSDarren Reed */ 777*7ddc9b1aSDarren Reed if (!hfi->hfi_condemned) 778*7ddc9b1aSDarren Reed hook_family_free(hfi, hks); 779381a2a9aSdr146992 780381a2a9aSdr146992 return (0); 781381a2a9aSdr146992 } 782381a2a9aSdr146992 783381a2a9aSdr146992 784381a2a9aSdr146992 /* 785*7ddc9b1aSDarren Reed * Function: hook_family_free 786*7ddc9b1aSDarren Reed * Returns: None 787*7ddc9b1aSDarren Reed * Parameters: hfi(I) - internal family pointer 788*7ddc9b1aSDarren Reed * 789*7ddc9b1aSDarren Reed * Free alloc memory for family 790*7ddc9b1aSDarren Reed */ 791*7ddc9b1aSDarren Reed static void 792*7ddc9b1aSDarren Reed hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks) 793*7ddc9b1aSDarren Reed { 794*7ddc9b1aSDarren Reed 795*7ddc9b1aSDarren Reed /* 796*7ddc9b1aSDarren Reed * This lock gives us possession of the hks pointer after the 797*7ddc9b1aSDarren Reed * SLIST_REMOVE, for which it is not needed, when hks_shutdown 798*7ddc9b1aSDarren Reed * is checked and hook_stack_remove called. 799*7ddc9b1aSDarren Reed */ 800*7ddc9b1aSDarren Reed mutex_enter(&hook_stack_lock); 801*7ddc9b1aSDarren Reed 802*7ddc9b1aSDarren Reed ASSERT(hfi != NULL); 803*7ddc9b1aSDarren Reed 804*7ddc9b1aSDarren Reed if (hks != NULL) { 805*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(&hks->hks_lock); 806*7ddc9b1aSDarren Reed /* Remove from family list */ 807*7ddc9b1aSDarren Reed SLIST_REMOVE(&hks->hks_familylist, hfi, hook_family_int, 808*7ddc9b1aSDarren Reed hfi_entry); 809*7ddc9b1aSDarren Reed 810*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hks->hks_lock); 811*7ddc9b1aSDarren Reed } 812*7ddc9b1aSDarren Reed 813*7ddc9b1aSDarren Reed /* Free name space */ 814*7ddc9b1aSDarren Reed if (hfi->hfi_family.hf_name != NULL) { 815*7ddc9b1aSDarren Reed kmem_free(hfi->hfi_family.hf_name, 816*7ddc9b1aSDarren Reed strlen(hfi->hfi_family.hf_name) + 1); 817*7ddc9b1aSDarren Reed } 818*7ddc9b1aSDarren Reed 819*7ddc9b1aSDarren Reed /* Free container */ 820*7ddc9b1aSDarren Reed kmem_free(hfi, sizeof (*hfi)); 821*7ddc9b1aSDarren Reed 822*7ddc9b1aSDarren Reed if (hks->hks_shutdown == 2) 823*7ddc9b1aSDarren Reed hook_stack_remove(hks); 824*7ddc9b1aSDarren Reed 825*7ddc9b1aSDarren Reed mutex_exit(&hook_stack_lock); 826*7ddc9b1aSDarren Reed } 827*7ddc9b1aSDarren Reed 828*7ddc9b1aSDarren Reed 829*7ddc9b1aSDarren Reed /* 830381a2a9aSdr146992 * Function: hook_family_copy 831381a2a9aSdr146992 * Returns: internal family pointer - NULL = Failed 832381a2a9aSdr146992 * Parameters: src(I) - family pointer 833381a2a9aSdr146992 * 834381a2a9aSdr146992 * Allocate internal family block and duplicate incoming family 835381a2a9aSdr146992 * No locks should be held across this function as it may sleep. 836381a2a9aSdr146992 */ 837381a2a9aSdr146992 static hook_family_int_t * 838381a2a9aSdr146992 hook_family_copy(hook_family_t *src) 839381a2a9aSdr146992 { 840381a2a9aSdr146992 hook_family_int_t *new; 841381a2a9aSdr146992 hook_family_t *dst; 842381a2a9aSdr146992 843381a2a9aSdr146992 ASSERT(src != NULL); 844381a2a9aSdr146992 ASSERT(src->hf_name != NULL); 845381a2a9aSdr146992 846381a2a9aSdr146992 new = (hook_family_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP); 847381a2a9aSdr146992 848381a2a9aSdr146992 /* Copy body */ 849381a2a9aSdr146992 dst = &new->hfi_family; 850381a2a9aSdr146992 *dst = *src; 851381a2a9aSdr146992 852*7ddc9b1aSDarren Reed SLIST_INIT(&new->hfi_head); 853*7ddc9b1aSDarren Reed TAILQ_INIT(&new->hfi_nhead); 854*7ddc9b1aSDarren Reed 855381a2a9aSdr146992 /* Copy name */ 856381a2a9aSdr146992 dst->hf_name = (char *)kmem_alloc(strlen(src->hf_name) + 1, KM_SLEEP); 857381a2a9aSdr146992 (void) strcpy(dst->hf_name, src->hf_name); 858381a2a9aSdr146992 859381a2a9aSdr146992 return (new); 860381a2a9aSdr146992 } 861381a2a9aSdr146992 862381a2a9aSdr146992 /* 863*7ddc9b1aSDarren Reed * Function: hook_family_find 864381a2a9aSdr146992 * Returns: internal family pointer - NULL = Not match 865381a2a9aSdr146992 * Parameters: family(I) - family name string 866381a2a9aSdr146992 * 867381a2a9aSdr146992 * Search family list with family name 868*7ddc9b1aSDarren Reed * A lock on hfi_lock must be held when called. 869381a2a9aSdr146992 */ 870381a2a9aSdr146992 static hook_family_int_t * 871f4b3ec61Sdh155122 hook_family_find(char *family, hook_stack_t *hks) 872381a2a9aSdr146992 { 873381a2a9aSdr146992 hook_family_int_t *hfi = NULL; 874381a2a9aSdr146992 875381a2a9aSdr146992 ASSERT(family != NULL); 876381a2a9aSdr146992 877f4b3ec61Sdh155122 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) { 878381a2a9aSdr146992 if (strcmp(hfi->hfi_family.hf_name, family) == 0) 879381a2a9aSdr146992 break; 880381a2a9aSdr146992 } 881381a2a9aSdr146992 return (hfi); 882381a2a9aSdr146992 } 883381a2a9aSdr146992 884*7ddc9b1aSDarren Reed /* 885*7ddc9b1aSDarren Reed * Function: hook_family_notify_register 886*7ddc9b1aSDarren Reed * Returns: 0 = success, else failure 887*7ddc9b1aSDarren Reed * Parameters: hfi(I) - hook family 888*7ddc9b1aSDarren Reed * callback(I) - function to be called 889*7ddc9b1aSDarren Reed * arg(I) - arg to provide callback when it is called 890*7ddc9b1aSDarren Reed * 891*7ddc9b1aSDarren Reed * So long as this hook stack isn't being shut down, register a new 892*7ddc9b1aSDarren Reed * callback to be activated each time a new event is added to this 893*7ddc9b1aSDarren Reed * family. 894*7ddc9b1aSDarren Reed * 895*7ddc9b1aSDarren Reed * To call this function we must have an active handle in use on the family, 896*7ddc9b1aSDarren Reed * so if we take this into account, then neither the hook_family_int_t nor 897*7ddc9b1aSDarren Reed * the hook_stack_t that owns it can disappear. We have to put some trust 898*7ddc9b1aSDarren Reed * in the callers to be properly synchronised... 899*7ddc9b1aSDarren Reed * 900*7ddc9b1aSDarren Reed * Holding hks_lock is required to provide synchronisation for hks_shutdown. 901*7ddc9b1aSDarren Reed */ 902*7ddc9b1aSDarren Reed int 903*7ddc9b1aSDarren Reed hook_family_notify_register(hook_family_int_t *hfi, 904*7ddc9b1aSDarren Reed hook_notify_fn_t callback, void *arg) 905*7ddc9b1aSDarren Reed { 906*7ddc9b1aSDarren Reed hook_stack_t *hks; 907*7ddc9b1aSDarren Reed int error; 908*7ddc9b1aSDarren Reed 909*7ddc9b1aSDarren Reed hks = hfi->hfi_stack; 910*7ddc9b1aSDarren Reed 911*7ddc9b1aSDarren Reed CVW_ENTER_READ(&hks->hks_lock); 912*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(&hfi->hfi_lock); 913*7ddc9b1aSDarren Reed 914*7ddc9b1aSDarren Reed if (hfi->hfi_stack->hks_shutdown != 0) { 915*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 916*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hks->hks_lock); 917*7ddc9b1aSDarren Reed return (ESHUTDOWN); 918*7ddc9b1aSDarren Reed } 919*7ddc9b1aSDarren Reed 920*7ddc9b1aSDarren Reed error = hook_notify_register(&hfi->hfi_lock, &hfi->hfi_nhead, 921*7ddc9b1aSDarren Reed callback, arg); 922*7ddc9b1aSDarren Reed 923*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 924*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hks->hks_lock); 925*7ddc9b1aSDarren Reed 926*7ddc9b1aSDarren Reed return (error); 927*7ddc9b1aSDarren Reed } 928381a2a9aSdr146992 929381a2a9aSdr146992 /* 930*7ddc9b1aSDarren Reed * Function: hook_family_notify_unregister 931*7ddc9b1aSDarren Reed * Returns: 0 = success, else failure 932*7ddc9b1aSDarren Reed * Parameters: hfi(I) - hook family 933*7ddc9b1aSDarren Reed * callback(I) - function to be called 934381a2a9aSdr146992 * 935*7ddc9b1aSDarren Reed * Remove a callback from the list of those executed when a new event is 936*7ddc9b1aSDarren Reed * added to a hook family. 937381a2a9aSdr146992 */ 938*7ddc9b1aSDarren Reed int 939*7ddc9b1aSDarren Reed hook_family_notify_unregister(hook_family_int_t *hfi, 940*7ddc9b1aSDarren Reed hook_notify_fn_t callback) 941381a2a9aSdr146992 { 942*7ddc9b1aSDarren Reed boolean_t free_family; 943*7ddc9b1aSDarren Reed int error; 944381a2a9aSdr146992 945*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(&hfi->hfi_lock); 946*7ddc9b1aSDarren Reed 947*7ddc9b1aSDarren Reed error = hook_notify_unregister(&hfi->hfi_lock, &hfi->hfi_nhead, 948*7ddc9b1aSDarren Reed callback); 949*7ddc9b1aSDarren Reed 950*7ddc9b1aSDarren Reed /* 951*7ddc9b1aSDarren Reed * If hook_family_remove has been called but the structure was still 952*7ddc9b1aSDarren Reed * "busy" ... but we might have just made it "unbusy"... 953*7ddc9b1aSDarren Reed */ 954*7ddc9b1aSDarren Reed if ((error == 0) && hfi->hfi_condemned && 955*7ddc9b1aSDarren Reed SLIST_EMPTY(&hfi->hfi_head) && TAILQ_EMPTY(&hfi->hfi_nhead)) { 956*7ddc9b1aSDarren Reed free_family = B_TRUE; 957*7ddc9b1aSDarren Reed } else { 958*7ddc9b1aSDarren Reed free_family = B_FALSE; 959381a2a9aSdr146992 } 960381a2a9aSdr146992 961*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 962381a2a9aSdr146992 963*7ddc9b1aSDarren Reed if (free_family) 964*7ddc9b1aSDarren Reed hook_family_free(hfi, hfi->hfi_stack); 965*7ddc9b1aSDarren Reed 966*7ddc9b1aSDarren Reed return (error); 967*7ddc9b1aSDarren Reed } 968381a2a9aSdr146992 969381a2a9aSdr146992 /* 970381a2a9aSdr146992 * Function: hook_event_add 971381a2a9aSdr146992 * Returns: internal event pointer - NULL = Fail 972381a2a9aSdr146992 * Parameters: hfi(I) - internal family pointer 973381a2a9aSdr146992 * he(I) - event pointer 974381a2a9aSdr146992 * 975381a2a9aSdr146992 * Add new event to event list on specific family. 976381a2a9aSdr146992 * This function can fail to return successfully if (1) it cannot allocate 977381a2a9aSdr146992 * enough memory for its own internal data structures, (2) the event has 978381a2a9aSdr146992 * already been registered (for any hook family.) 979381a2a9aSdr146992 */ 980381a2a9aSdr146992 hook_event_int_t * 981381a2a9aSdr146992 hook_event_add(hook_family_int_t *hfi, hook_event_t *he) 982381a2a9aSdr146992 { 983381a2a9aSdr146992 hook_event_int_t *hei, *new; 984*7ddc9b1aSDarren Reed hook_stack_t *hks; 985381a2a9aSdr146992 986381a2a9aSdr146992 ASSERT(hfi != NULL); 987381a2a9aSdr146992 ASSERT(he != NULL); 988381a2a9aSdr146992 ASSERT(he->he_name != NULL); 989381a2a9aSdr146992 990381a2a9aSdr146992 new = hook_event_copy(he); 991381a2a9aSdr146992 if (new == NULL) 992381a2a9aSdr146992 return (NULL); 993381a2a9aSdr146992 994*7ddc9b1aSDarren Reed hks = hfi->hfi_stack; 995*7ddc9b1aSDarren Reed CVW_ENTER_READ(&hks->hks_lock); 996*7ddc9b1aSDarren Reed 997*7ddc9b1aSDarren Reed hks = hfi->hfi_stack; 998*7ddc9b1aSDarren Reed if (hks->hks_shutdown != 0) { 999*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hks->hks_lock); 1000*7ddc9b1aSDarren Reed hook_event_free(new, NULL); 1001*7ddc9b1aSDarren Reed return (NULL); 1002*7ddc9b1aSDarren Reed } 1003381a2a9aSdr146992 1004381a2a9aSdr146992 /* Check whether this event pointer is already registered */ 1005f4b3ec61Sdh155122 hei = hook_event_checkdup(he, hks); 1006381a2a9aSdr146992 if (hei != NULL) { 1007*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hks->hks_lock); 1008*7ddc9b1aSDarren Reed hook_event_free(new, NULL); 1009381a2a9aSdr146992 return (NULL); 1010381a2a9aSdr146992 } 1011381a2a9aSdr146992 1012*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(&hfi->hfi_lock); 1013*7ddc9b1aSDarren Reed 1014*7ddc9b1aSDarren Reed if (hfi->hfi_condemned) { 1015*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 1016*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hks->hks_lock); 1017*7ddc9b1aSDarren Reed hook_event_free(new, NULL); 1018*7ddc9b1aSDarren Reed return (NULL); 1019*7ddc9b1aSDarren Reed } 1020*7ddc9b1aSDarren Reed 1021*7ddc9b1aSDarren Reed if (hook_wait_setflag(&hfi->hfi_waiter, FWF_WAIT_MASK, 1022*7ddc9b1aSDarren Reed FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) { 1023*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 1024*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hks->hks_lock); 1025*7ddc9b1aSDarren Reed hook_event_free(new, NULL); 1026*7ddc9b1aSDarren Reed return (NULL); 1027*7ddc9b1aSDarren Reed } 1028*7ddc9b1aSDarren Reed 1029*7ddc9b1aSDarren Reed TAILQ_INIT(&new->hei_nhead); 1030*7ddc9b1aSDarren Reed 1031*7ddc9b1aSDarren Reed hook_event_init_kstats(hfi, new); 1032*7ddc9b1aSDarren Reed hook_wait_init(&new->hei_waiter, &new->hei_lock); 1033*7ddc9b1aSDarren Reed 1034381a2a9aSdr146992 /* Add to event list head */ 1035381a2a9aSdr146992 SLIST_INSERT_HEAD(&hfi->hfi_head, new, hei_entry); 1036381a2a9aSdr146992 1037*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 1038*7ddc9b1aSDarren Reed 1039*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hks->hks_lock); 1040*7ddc9b1aSDarren Reed 1041*7ddc9b1aSDarren Reed hook_notify_run(&hfi->hfi_nhead, 1042*7ddc9b1aSDarren Reed hfi->hfi_family.hf_name, NULL, he->he_name, HN_REGISTER); 1043*7ddc9b1aSDarren Reed 1044*7ddc9b1aSDarren Reed hook_wait_unsetflag(&hfi->hfi_waiter, FWF_ADD_ACTIVE); 1045*7ddc9b1aSDarren Reed 1046381a2a9aSdr146992 return (new); 1047381a2a9aSdr146992 } 1048381a2a9aSdr146992 1049*7ddc9b1aSDarren Reed /* 1050*7ddc9b1aSDarren Reed * Function: hook_event_init_kstats 1051*7ddc9b1aSDarren Reed * Returns: None 1052*7ddc9b1aSDarren Reed * Parameters: hfi(I) - pointer to the family that owns this event. 1053*7ddc9b1aSDarren Reed * hei(I) - pointer to the hook event that needs some kstats. 1054*7ddc9b1aSDarren Reed * 1055*7ddc9b1aSDarren Reed * Create a set of kstats that relate to each event registered with 1056*7ddc9b1aSDarren Reed * the hook framework. A counter is kept for each time the event is 1057*7ddc9b1aSDarren Reed * activated and for each time a hook is added or removed. As the 1058*7ddc9b1aSDarren Reed * kstats just count the events as they happen, the total number of 1059*7ddc9b1aSDarren Reed * hooks registered must be obtained by subtractived removed from added. 1060*7ddc9b1aSDarren Reed */ 1061*7ddc9b1aSDarren Reed static void 1062*7ddc9b1aSDarren Reed hook_event_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei) 1063*7ddc9b1aSDarren Reed { 1064*7ddc9b1aSDarren Reed hook_event_kstat_t template = { 1065*7ddc9b1aSDarren Reed { "hooksAdded", KSTAT_DATA_UINT64 }, 1066*7ddc9b1aSDarren Reed { "hooksRemoved", KSTAT_DATA_UINT64 }, 1067*7ddc9b1aSDarren Reed { "events", KSTAT_DATA_UINT64 } 1068*7ddc9b1aSDarren Reed }; 1069*7ddc9b1aSDarren Reed hook_stack_t *hks; 1070*7ddc9b1aSDarren Reed 1071*7ddc9b1aSDarren Reed hks = hfi->hfi_stack; 1072*7ddc9b1aSDarren Reed hei->hei_kstatp = kstat_create_netstack(hfi->hfi_family.hf_name, 0, 1073*7ddc9b1aSDarren Reed hei->hei_event->he_name, "hook_event", KSTAT_TYPE_NAMED, 1074*7ddc9b1aSDarren Reed sizeof (hei->hei_kstats) / sizeof (kstat_named_t), 1075*7ddc9b1aSDarren Reed KSTAT_FLAG_VIRTUAL, hks->hks_netstackid); 1076*7ddc9b1aSDarren Reed 1077*7ddc9b1aSDarren Reed bcopy((char *)&template, &hei->hei_kstats, sizeof (template)); 1078*7ddc9b1aSDarren Reed 1079*7ddc9b1aSDarren Reed if (hei->hei_kstatp != NULL) { 1080*7ddc9b1aSDarren Reed hei->hei_kstatp->ks_data = (void *)&hei->hei_kstats; 1081*7ddc9b1aSDarren Reed hei->hei_kstatp->ks_private = 1082*7ddc9b1aSDarren Reed (void *)(uintptr_t)hks->hks_netstackid; 1083*7ddc9b1aSDarren Reed 1084*7ddc9b1aSDarren Reed kstat_install(hei->hei_kstatp); 1085*7ddc9b1aSDarren Reed } 1086*7ddc9b1aSDarren Reed } 1087381a2a9aSdr146992 1088381a2a9aSdr146992 /* 1089381a2a9aSdr146992 * Function: hook_event_remove 1090381a2a9aSdr146992 * Returns: int - 0 = Succ, Else = Fail 1091381a2a9aSdr146992 * Parameters: hfi(I) - internal family pointer 1092381a2a9aSdr146992 * he(I) - event pointer 1093381a2a9aSdr146992 * 1094381a2a9aSdr146992 * Remove event from event list on specific family 1095*7ddc9b1aSDarren Reed * 1096*7ddc9b1aSDarren Reed * This function assumes that the caller has received a pointer to a the 1097*7ddc9b1aSDarren Reed * hook_family_int_t via a call to net_protocol_lookup or net_protocol_unreg'. 1098*7ddc9b1aSDarren Reed * This the hook_family_int_t is guaranteed to be around for the life of this 1099*7ddc9b1aSDarren Reed * call, unless the caller has decided to call net_protocol_release or 1100*7ddc9b1aSDarren Reed * net_protocol_unregister before calling net_event_unregister - an error. 1101381a2a9aSdr146992 */ 1102381a2a9aSdr146992 int 1103381a2a9aSdr146992 hook_event_remove(hook_family_int_t *hfi, hook_event_t *he) 1104381a2a9aSdr146992 { 1105*7ddc9b1aSDarren Reed boolean_t free_family; 1106381a2a9aSdr146992 hook_event_int_t *hei; 1107381a2a9aSdr146992 1108381a2a9aSdr146992 ASSERT(hfi != NULL); 1109381a2a9aSdr146992 ASSERT(he != NULL); 1110381a2a9aSdr146992 1111*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(&hfi->hfi_lock); 1112381a2a9aSdr146992 1113*7ddc9b1aSDarren Reed /* 1114*7ddc9b1aSDarren Reed * Set the flag so that we can call hook_event_notify_run without 1115*7ddc9b1aSDarren Reed * holding any locks but at the same time prevent other changes to 1116*7ddc9b1aSDarren Reed * the event at the same time. 1117*7ddc9b1aSDarren Reed */ 1118*7ddc9b1aSDarren Reed if (hook_wait_setflag(&hfi->hfi_waiter, FWF_WAIT_MASK, 1119*7ddc9b1aSDarren Reed FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) { 1120*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 1121381a2a9aSdr146992 return (ENXIO); 1122381a2a9aSdr146992 } 1123381a2a9aSdr146992 1124*7ddc9b1aSDarren Reed hei = hook_event_find(hfi, he->he_name); 1125*7ddc9b1aSDarren Reed if (hei == NULL) { 1126*7ddc9b1aSDarren Reed hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE); 1127*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 1128*7ddc9b1aSDarren Reed return (ESRCH); 1129381a2a9aSdr146992 } 1130381a2a9aSdr146992 1131*7ddc9b1aSDarren Reed free_family = B_FALSE; 1132381a2a9aSdr146992 1133*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(&hei->hei_lock); 1134*7ddc9b1aSDarren Reed /* 1135*7ddc9b1aSDarren Reed * If there are any hooks still registered for this event or 1136*7ddc9b1aSDarren Reed * there are any notifiers registered, return an error indicating 1137*7ddc9b1aSDarren Reed * that the event is still busy. 1138*7ddc9b1aSDarren Reed */ 1139*7ddc9b1aSDarren Reed if (!TAILQ_EMPTY(&hei->hei_head) || !TAILQ_EMPTY(&hei->hei_nhead)) { 1140*7ddc9b1aSDarren Reed hei->hei_condemned = B_TRUE; 1141*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hei->hei_lock); 1142*7ddc9b1aSDarren Reed } else { 1143*7ddc9b1aSDarren Reed /* hei_condemned = B_FALSE is implied from creation */ 1144*7ddc9b1aSDarren Reed /* 1145*7ddc9b1aSDarren Reed * Even though we know the notify list is empty, we call 1146*7ddc9b1aSDarren Reed * hook_wait_destroy here to synchronise wait removing a 1147*7ddc9b1aSDarren Reed * hook from an event. 1148*7ddc9b1aSDarren Reed */ 1149*7ddc9b1aSDarren Reed hook_wait_destroy(&hei->hei_waiter); 1150*7ddc9b1aSDarren Reed 1151*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hei->hei_lock); 1152*7ddc9b1aSDarren Reed 1153*7ddc9b1aSDarren Reed if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) && 1154*7ddc9b1aSDarren Reed TAILQ_EMPTY(&hfi->hfi_nhead)) 1155*7ddc9b1aSDarren Reed free_family = B_TRUE; 1156*7ddc9b1aSDarren Reed } 1157*7ddc9b1aSDarren Reed 1158*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 1159*7ddc9b1aSDarren Reed 1160*7ddc9b1aSDarren Reed hook_notify_run(&hfi->hfi_nhead, 1161*7ddc9b1aSDarren Reed hfi->hfi_family.hf_name, NULL, he->he_name, HN_UNREGISTER); 1162*7ddc9b1aSDarren Reed 1163*7ddc9b1aSDarren Reed hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE); 1164*7ddc9b1aSDarren Reed 1165*7ddc9b1aSDarren Reed if (!hei->hei_condemned) { 1166*7ddc9b1aSDarren Reed hook_event_free(hei, hfi); 1167*7ddc9b1aSDarren Reed if (free_family) 1168*7ddc9b1aSDarren Reed hook_family_free(hfi, hfi->hfi_stack); 1169*7ddc9b1aSDarren Reed } 1170381a2a9aSdr146992 1171381a2a9aSdr146992 return (0); 1172381a2a9aSdr146992 } 1173381a2a9aSdr146992 1174*7ddc9b1aSDarren Reed /* 1175*7ddc9b1aSDarren Reed * Function: hook_event_free 1176*7ddc9b1aSDarren Reed * Returns: None 1177*7ddc9b1aSDarren Reed * Parameters: hei(I) - internal event pointer 1178*7ddc9b1aSDarren Reed * 1179*7ddc9b1aSDarren Reed * Free alloc memory for event 1180*7ddc9b1aSDarren Reed */ 1181*7ddc9b1aSDarren Reed static void 1182*7ddc9b1aSDarren Reed hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi) 1183*7ddc9b1aSDarren Reed { 1184*7ddc9b1aSDarren Reed boolean_t free_family; 1185*7ddc9b1aSDarren Reed 1186*7ddc9b1aSDarren Reed ASSERT(hei != NULL); 1187*7ddc9b1aSDarren Reed 1188*7ddc9b1aSDarren Reed if (hfi != NULL) { 1189*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(&hfi->hfi_lock); 1190*7ddc9b1aSDarren Reed /* 1191*7ddc9b1aSDarren Reed * Remove the event from the hook family's list. 1192*7ddc9b1aSDarren Reed */ 1193*7ddc9b1aSDarren Reed SLIST_REMOVE(&hfi->hfi_head, hei, hook_event_int, hei_entry); 1194*7ddc9b1aSDarren Reed if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) && 1195*7ddc9b1aSDarren Reed TAILQ_EMPTY(&hfi->hfi_nhead)) { 1196*7ddc9b1aSDarren Reed free_family = B_TRUE; 1197*7ddc9b1aSDarren Reed } else { 1198*7ddc9b1aSDarren Reed free_family = B_FALSE; 1199*7ddc9b1aSDarren Reed } 1200*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 1201*7ddc9b1aSDarren Reed } 1202*7ddc9b1aSDarren Reed 1203*7ddc9b1aSDarren Reed if (hei->hei_kstatp != NULL) { 1204*7ddc9b1aSDarren Reed ASSERT(hfi != NULL); 1205*7ddc9b1aSDarren Reed 1206*7ddc9b1aSDarren Reed kstat_delete_netstack(hei->hei_kstatp, 1207*7ddc9b1aSDarren Reed hfi->hfi_stack->hks_netstackid); 1208*7ddc9b1aSDarren Reed hei->hei_kstatp = NULL; 1209*7ddc9b1aSDarren Reed } 1210*7ddc9b1aSDarren Reed 1211*7ddc9b1aSDarren Reed /* Free container */ 1212*7ddc9b1aSDarren Reed kmem_free(hei, sizeof (*hei)); 1213*7ddc9b1aSDarren Reed 1214*7ddc9b1aSDarren Reed if (free_family) 1215*7ddc9b1aSDarren Reed hook_family_free(hfi, hfi->hfi_stack); 1216*7ddc9b1aSDarren Reed } 1217381a2a9aSdr146992 1218381a2a9aSdr146992 /* 1219381a2a9aSdr146992 * Function: hook_event_checkdup 1220381a2a9aSdr146992 * Returns: internal event pointer - NULL = Not match 1221381a2a9aSdr146992 * Parameters: he(I) - event pointer 1222381a2a9aSdr146992 * 1223*7ddc9b1aSDarren Reed * Search all of the hook families to see if the event being passed in 1224*7ddc9b1aSDarren Reed * has already been associated with one. 1225381a2a9aSdr146992 */ 1226381a2a9aSdr146992 static hook_event_int_t * 1227f4b3ec61Sdh155122 hook_event_checkdup(hook_event_t *he, hook_stack_t *hks) 1228381a2a9aSdr146992 { 1229381a2a9aSdr146992 hook_family_int_t *hfi; 1230381a2a9aSdr146992 hook_event_int_t *hei; 1231381a2a9aSdr146992 1232381a2a9aSdr146992 ASSERT(he != NULL); 1233381a2a9aSdr146992 1234*7ddc9b1aSDarren Reed CVW_ENTER_READ(&hks->hks_lock); 1235f4b3ec61Sdh155122 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) { 1236381a2a9aSdr146992 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) { 1237*7ddc9b1aSDarren Reed if (hei->hei_event == he) { 1238*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hks->hks_lock); 1239381a2a9aSdr146992 return (hei); 1240381a2a9aSdr146992 } 1241381a2a9aSdr146992 } 1242*7ddc9b1aSDarren Reed } 1243*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hks->hks_lock); 1244381a2a9aSdr146992 1245381a2a9aSdr146992 return (NULL); 1246381a2a9aSdr146992 } 1247381a2a9aSdr146992 1248381a2a9aSdr146992 /* 1249381a2a9aSdr146992 * Function: hook_event_copy 1250381a2a9aSdr146992 * Returns: internal event pointer - NULL = Failed 1251381a2a9aSdr146992 * Parameters: src(I) - event pointer 1252381a2a9aSdr146992 * 1253381a2a9aSdr146992 * Allocate internal event block and duplicate incoming event 1254381a2a9aSdr146992 * No locks should be held across this function as it may sleep. 1255381a2a9aSdr146992 */ 1256381a2a9aSdr146992 static hook_event_int_t * 1257381a2a9aSdr146992 hook_event_copy(hook_event_t *src) 1258381a2a9aSdr146992 { 1259381a2a9aSdr146992 hook_event_int_t *new; 1260381a2a9aSdr146992 1261381a2a9aSdr146992 ASSERT(src != NULL); 1262381a2a9aSdr146992 ASSERT(src->he_name != NULL); 1263381a2a9aSdr146992 1264381a2a9aSdr146992 new = (hook_event_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP); 1265381a2a9aSdr146992 1266381a2a9aSdr146992 /* Copy body */ 1267381a2a9aSdr146992 TAILQ_INIT(&new->hei_head); 1268381a2a9aSdr146992 new->hei_event = src; 1269381a2a9aSdr146992 1270381a2a9aSdr146992 return (new); 1271381a2a9aSdr146992 } 1272381a2a9aSdr146992 1273381a2a9aSdr146992 /* 1274381a2a9aSdr146992 * Function: hook_event_find 1275381a2a9aSdr146992 * Returns: internal event pointer - NULL = Not match 1276381a2a9aSdr146992 * Parameters: hfi(I) - internal family pointer 1277381a2a9aSdr146992 * event(I) - event name string 1278381a2a9aSdr146992 * 1279381a2a9aSdr146992 * Search event list with event name 1280*7ddc9b1aSDarren Reed * A lock on hfi->hfi_lock must be held when called. 1281381a2a9aSdr146992 */ 1282381a2a9aSdr146992 static hook_event_int_t * 1283381a2a9aSdr146992 hook_event_find(hook_family_int_t *hfi, char *event) 1284381a2a9aSdr146992 { 1285381a2a9aSdr146992 hook_event_int_t *hei = NULL; 1286381a2a9aSdr146992 1287381a2a9aSdr146992 ASSERT(hfi != NULL); 1288381a2a9aSdr146992 ASSERT(event != NULL); 1289381a2a9aSdr146992 1290381a2a9aSdr146992 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) { 1291*7ddc9b1aSDarren Reed if ((strcmp(hei->hei_event->he_name, event) == 0) && 1292*7ddc9b1aSDarren Reed ((hei->hei_waiter.fw_flags & FWF_UNSAFE) == 0)) 1293381a2a9aSdr146992 break; 1294381a2a9aSdr146992 } 1295381a2a9aSdr146992 return (hei); 1296381a2a9aSdr146992 } 1297381a2a9aSdr146992 1298381a2a9aSdr146992 /* 1299*7ddc9b1aSDarren Reed * Function: hook_event_notify_register 1300*7ddc9b1aSDarren Reed * Returns: 0 = success, else failure 1301*7ddc9b1aSDarren Reed * Parameters: hfi(I) - hook family 1302*7ddc9b1aSDarren Reed * event(I) - name of the event 1303*7ddc9b1aSDarren Reed * callback(I) - function to be called 1304*7ddc9b1aSDarren Reed * arg(I) - arg to provide callback when it is called 1305381a2a9aSdr146992 * 1306*7ddc9b1aSDarren Reed * Adds a new callback to the event named by "event" (we must find it) 1307*7ddc9b1aSDarren Reed * that will be executed each time a new hook is added to the event. 1308*7ddc9b1aSDarren Reed * Of course, if the stack is being shut down, this call should fail. 1309381a2a9aSdr146992 */ 1310*7ddc9b1aSDarren Reed int 1311*7ddc9b1aSDarren Reed hook_event_notify_register(hook_family_int_t *hfi, char *event, 1312*7ddc9b1aSDarren Reed hook_notify_fn_t callback, void *arg) 1313381a2a9aSdr146992 { 1314*7ddc9b1aSDarren Reed hook_event_int_t *hei; 1315*7ddc9b1aSDarren Reed hook_stack_t *hks; 1316*7ddc9b1aSDarren Reed int error; 1317381a2a9aSdr146992 1318*7ddc9b1aSDarren Reed hks = hfi->hfi_stack; 1319*7ddc9b1aSDarren Reed CVW_ENTER_READ(&hks->hks_lock); 1320*7ddc9b1aSDarren Reed if (hks->hks_shutdown != 0) { 1321*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hks->hks_lock); 1322*7ddc9b1aSDarren Reed return (ESHUTDOWN); 1323381a2a9aSdr146992 } 1324381a2a9aSdr146992 1325*7ddc9b1aSDarren Reed CVW_ENTER_READ(&hfi->hfi_lock); 1326*7ddc9b1aSDarren Reed 1327*7ddc9b1aSDarren Reed if (hfi->hfi_condemned) { 1328*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hfi->hfi_lock); 1329*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hks->hks_lock); 1330*7ddc9b1aSDarren Reed return (ESHUTDOWN); 1331*7ddc9b1aSDarren Reed } 1332*7ddc9b1aSDarren Reed 1333*7ddc9b1aSDarren Reed hei = hook_event_find(hfi, event); 1334*7ddc9b1aSDarren Reed if (hei == NULL) { 1335*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hfi->hfi_lock); 1336*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hks->hks_lock); 1337*7ddc9b1aSDarren Reed return (ESRCH); 1338*7ddc9b1aSDarren Reed } 1339*7ddc9b1aSDarren Reed 1340*7ddc9b1aSDarren Reed /* 1341*7ddc9b1aSDarren Reed * Grabbing the read lock on hei_lock is only so that we can 1342*7ddc9b1aSDarren Reed * synchronise access to hei_condemned. 1343*7ddc9b1aSDarren Reed */ 1344*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(&hei->hei_lock); 1345*7ddc9b1aSDarren Reed if (hei->hei_condemned) { 1346*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hei->hei_lock); 1347*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hfi->hfi_lock); 1348*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hks->hks_lock); 1349*7ddc9b1aSDarren Reed return (ESHUTDOWN); 1350*7ddc9b1aSDarren Reed } 1351*7ddc9b1aSDarren Reed 1352*7ddc9b1aSDarren Reed error = hook_notify_register(&hei->hei_lock, &hei->hei_nhead, 1353*7ddc9b1aSDarren Reed callback, arg); 1354*7ddc9b1aSDarren Reed 1355*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hei->hei_lock); 1356*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hfi->hfi_lock); 1357*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hks->hks_lock); 1358*7ddc9b1aSDarren Reed 1359*7ddc9b1aSDarren Reed return (error); 1360*7ddc9b1aSDarren Reed } 1361*7ddc9b1aSDarren Reed 1362*7ddc9b1aSDarren Reed /* 1363*7ddc9b1aSDarren Reed * Function: hook_event_notify_unregister 1364*7ddc9b1aSDarren Reed * Returns: 0 = success, else failure 1365*7ddc9b1aSDarren Reed * Parameters: hfi(I) - hook family 1366*7ddc9b1aSDarren Reed * event(I) - name of the event 1367*7ddc9b1aSDarren Reed * callback(I) - function to be called 1368*7ddc9b1aSDarren Reed * 1369*7ddc9b1aSDarren Reed * Remove the given callback from the named event's list of functions 1370*7ddc9b1aSDarren Reed * to call when a hook is added or removed. 1371*7ddc9b1aSDarren Reed */ 1372*7ddc9b1aSDarren Reed int 1373*7ddc9b1aSDarren Reed hook_event_notify_unregister(hook_family_int_t *hfi, char *event, 1374*7ddc9b1aSDarren Reed hook_notify_fn_t callback) 1375*7ddc9b1aSDarren Reed { 1376*7ddc9b1aSDarren Reed hook_event_int_t *hei; 1377*7ddc9b1aSDarren Reed boolean_t free_event; 1378*7ddc9b1aSDarren Reed int error; 1379*7ddc9b1aSDarren Reed 1380*7ddc9b1aSDarren Reed CVW_ENTER_READ(&hfi->hfi_lock); 1381*7ddc9b1aSDarren Reed 1382*7ddc9b1aSDarren Reed hei = hook_event_find(hfi, event); 1383*7ddc9b1aSDarren Reed if (hei == NULL) { 1384*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hfi->hfi_lock); 1385*7ddc9b1aSDarren Reed return (ESRCH); 1386*7ddc9b1aSDarren Reed } 1387*7ddc9b1aSDarren Reed 1388*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(&hei->hei_lock); 1389*7ddc9b1aSDarren Reed 1390*7ddc9b1aSDarren Reed error = hook_notify_unregister(&hei->hei_lock, &hei->hei_nhead, 1391*7ddc9b1aSDarren Reed callback); 1392*7ddc9b1aSDarren Reed 1393*7ddc9b1aSDarren Reed /* 1394*7ddc9b1aSDarren Reed * hei_condemned has been set if someone tried to remove the 1395*7ddc9b1aSDarren Reed * event but couldn't because there were still things attached to 1396*7ddc9b1aSDarren Reed * it. Now that we've done a successful remove, if it is now empty 1397*7ddc9b1aSDarren Reed * then by all rights we should be free'ing it too. Note that the 1398*7ddc9b1aSDarren Reed * expectation is that only the caller of hook_event_add will ever 1399*7ddc9b1aSDarren Reed * call hook_event_remove. 1400*7ddc9b1aSDarren Reed */ 1401*7ddc9b1aSDarren Reed if ((error == 0) && hei->hei_condemned && 1402*7ddc9b1aSDarren Reed TAILQ_EMPTY(&hei->hei_head) && TAILQ_EMPTY(&hei->hei_nhead)) { 1403*7ddc9b1aSDarren Reed free_event = B_TRUE; 1404*7ddc9b1aSDarren Reed } else { 1405*7ddc9b1aSDarren Reed free_event = B_FALSE; 1406*7ddc9b1aSDarren Reed } 1407*7ddc9b1aSDarren Reed 1408*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hei->hei_lock); 1409*7ddc9b1aSDarren Reed CVW_EXIT_READ(&hfi->hfi_lock); 1410*7ddc9b1aSDarren Reed 1411*7ddc9b1aSDarren Reed if (free_event) { 1412*7ddc9b1aSDarren Reed /* 1413*7ddc9b1aSDarren Reed * It is safe to pass in hfi here, without a lock, because 1414*7ddc9b1aSDarren Reed * our structure (hei) is still on one of its lists and thus 1415*7ddc9b1aSDarren Reed * it won't be able to disappear yet... 1416*7ddc9b1aSDarren Reed */ 1417*7ddc9b1aSDarren Reed hook_event_free(hei, hfi); 1418*7ddc9b1aSDarren Reed } 1419*7ddc9b1aSDarren Reed 1420*7ddc9b1aSDarren Reed return (error); 1421*7ddc9b1aSDarren Reed } 1422*7ddc9b1aSDarren Reed 1423*7ddc9b1aSDarren Reed /* 1424*7ddc9b1aSDarren Reed * Function: hook_event_notify_run 1425*7ddc9b1aSDarren Reed * Returns: None 1426*7ddc9b1aSDarren Reed * Parameters: nrun(I) - pointer to the list of callbacks to execute 1427*7ddc9b1aSDarren Reed * hfi(I) - hook stack pointer to execute callbacks for 1428*7ddc9b1aSDarren Reed * name(I) - name of a hook family 1429*7ddc9b1aSDarren Reed * cmd(I) - either HN_UNREGISTER or HN_REGISTER 1430*7ddc9b1aSDarren Reed * 1431*7ddc9b1aSDarren Reed * Execute all of the callbacks registered for this event. 1432*7ddc9b1aSDarren Reed */ 1433*7ddc9b1aSDarren Reed static void 1434*7ddc9b1aSDarren Reed hook_event_notify_run(hook_event_int_t *hei, hook_family_int_t *hfi, 1435*7ddc9b1aSDarren Reed char *event, char *name, hook_notify_cmd_t cmd) 1436*7ddc9b1aSDarren Reed { 1437*7ddc9b1aSDarren Reed 1438*7ddc9b1aSDarren Reed hook_notify_run(&hei->hei_nhead, hfi->hfi_family.hf_name, 1439*7ddc9b1aSDarren Reed event, name, cmd); 1440*7ddc9b1aSDarren Reed } 1441381a2a9aSdr146992 1442381a2a9aSdr146992 /* 1443381a2a9aSdr146992 * Function: hook_register 1444381a2a9aSdr146992 * Returns: int- 0 = Succ, Else = Fail 1445381a2a9aSdr146992 * Parameters: hfi(I) - internal family pointer 1446381a2a9aSdr146992 * event(I) - event name string 1447381a2a9aSdr146992 * h(I) - hook pointer 1448381a2a9aSdr146992 * 1449*7ddc9b1aSDarren Reed * Add new hook to hook list on the specified family and event. 1450381a2a9aSdr146992 */ 1451381a2a9aSdr146992 int 1452381a2a9aSdr146992 hook_register(hook_family_int_t *hfi, char *event, hook_t *h) 1453381a2a9aSdr146992 { 1454381a2a9aSdr146992 hook_event_int_t *hei; 1455381a2a9aSdr146992 hook_int_t *hi, *new; 1456*7ddc9b1aSDarren Reed int error; 1457381a2a9aSdr146992 1458381a2a9aSdr146992 ASSERT(hfi != NULL); 1459381a2a9aSdr146992 ASSERT(event != NULL); 1460381a2a9aSdr146992 ASSERT(h != NULL); 1461*7ddc9b1aSDarren Reed 1462*7ddc9b1aSDarren Reed if (hfi->hfi_stack->hks_shutdown) 1463*7ddc9b1aSDarren Reed return (NULL); 1464381a2a9aSdr146992 1465381a2a9aSdr146992 /* Alloc hook_int_t and copy hook */ 1466381a2a9aSdr146992 new = hook_copy(h); 1467381a2a9aSdr146992 if (new == NULL) 1468381a2a9aSdr146992 return (ENOMEM); 1469381a2a9aSdr146992 1470381a2a9aSdr146992 /* 1471381a2a9aSdr146992 * Since hook add/remove only impact event, so it is unnecessary 1472381a2a9aSdr146992 * to hold global family write lock. Just get read lock here to 1473381a2a9aSdr146992 * ensure event will not be removed when doing hooks operation 1474381a2a9aSdr146992 */ 1475*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(&hfi->hfi_lock); 1476381a2a9aSdr146992 1477381a2a9aSdr146992 hei = hook_event_find(hfi, event); 1478381a2a9aSdr146992 if (hei == NULL) { 1479*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 1480*7ddc9b1aSDarren Reed hook_int_free(new, hfi->hfi_stack->hks_netstackid); 1481381a2a9aSdr146992 return (ENXIO); 1482381a2a9aSdr146992 } 1483381a2a9aSdr146992 1484381a2a9aSdr146992 CVW_ENTER_WRITE(&hei->hei_lock); 1485381a2a9aSdr146992 1486381a2a9aSdr146992 hi = hook_find(hei, h); 1487381a2a9aSdr146992 if (hi != NULL) { 1488*7ddc9b1aSDarren Reed error = EEXIST; 1489*7ddc9b1aSDarren Reed goto bad_add; 1490*7ddc9b1aSDarren Reed } 1491*7ddc9b1aSDarren Reed 1492*7ddc9b1aSDarren Reed if (hook_wait_setflag(&hei->hei_waiter, FWF_WAIT_MASK, 1493*7ddc9b1aSDarren Reed FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) { 1494*7ddc9b1aSDarren Reed error = ENOENT; 1495*7ddc9b1aSDarren Reed bad_add: 1496381a2a9aSdr146992 CVW_EXIT_WRITE(&hei->hei_lock); 1497*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 1498*7ddc9b1aSDarren Reed hook_int_free(new, hfi->hfi_stack->hks_netstackid); 1499*7ddc9b1aSDarren Reed return (error); 1500381a2a9aSdr146992 } 1501381a2a9aSdr146992 1502381a2a9aSdr146992 /* Add to hook list head */ 1503*7ddc9b1aSDarren Reed error = hook_insert(&hei->hei_head, new); 1504*7ddc9b1aSDarren Reed if (error == 0) { 1505381a2a9aSdr146992 hei->hei_event->he_interested = B_TRUE; 1506*7ddc9b1aSDarren Reed hei->hei_kstats.hooks_added.value.ui64++; 1507*7ddc9b1aSDarren Reed 1508*7ddc9b1aSDarren Reed hook_init_kstats(hfi, hei, new); 1509*7ddc9b1aSDarren Reed } 1510381a2a9aSdr146992 1511381a2a9aSdr146992 CVW_EXIT_WRITE(&hei->hei_lock); 1512*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 1513*7ddc9b1aSDarren Reed 1514*7ddc9b1aSDarren Reed /* 1515*7ddc9b1aSDarren Reed * Note that the name string passed through to the notify callbacks 1516*7ddc9b1aSDarren Reed * is from the original hook being registered, not the copy being 1517*7ddc9b1aSDarren Reed * inserted. 1518*7ddc9b1aSDarren Reed */ 1519*7ddc9b1aSDarren Reed if (error == 0) { 1520*7ddc9b1aSDarren Reed hook_event_notify_run(hei, hfi, event, h->h_name, HN_REGISTER); 1521*7ddc9b1aSDarren Reed hook_wait_unsetflag(&hei->hei_waiter, FWF_ADD_ACTIVE); 1522*7ddc9b1aSDarren Reed } 1523*7ddc9b1aSDarren Reed 1524*7ddc9b1aSDarren Reed return (error); 1525*7ddc9b1aSDarren Reed } 1526*7ddc9b1aSDarren Reed 1527*7ddc9b1aSDarren Reed /* 1528*7ddc9b1aSDarren Reed * Function: hook_insert 1529*7ddc9b1aSDarren Reed * Returns: int- 0 = Succ, else = Fail 1530*7ddc9b1aSDarren Reed * Parameters: head(I) - pointer to hook list to insert hook onto 1531*7ddc9b1aSDarren Reed * new(I) - pointer to hook to be inserted 1532*7ddc9b1aSDarren Reed * 1533*7ddc9b1aSDarren Reed * Try to insert the hook onto the list of hooks according to the hints 1534*7ddc9b1aSDarren Reed * given in the hook to be inserted and those that already exist on the 1535*7ddc9b1aSDarren Reed * list. For now, the implementation permits only a single hook to be 1536*7ddc9b1aSDarren Reed * either first or last and names provided with before or after are only 1537*7ddc9b1aSDarren Reed * loosely coupled with the action. 1538*7ddc9b1aSDarren Reed */ 1539*7ddc9b1aSDarren Reed static int 1540*7ddc9b1aSDarren Reed hook_insert(hook_int_head_t *head, hook_int_t *new) 1541*7ddc9b1aSDarren Reed { 1542*7ddc9b1aSDarren Reed hook_int_t *before; 1543*7ddc9b1aSDarren Reed hook_int_t *hi; 1544*7ddc9b1aSDarren Reed hook_t *hih; 1545*7ddc9b1aSDarren Reed hook_t *h = &new->hi_hook; 1546*7ddc9b1aSDarren Reed 1547*7ddc9b1aSDarren Reed switch (new->hi_hook.h_hint) { 1548*7ddc9b1aSDarren Reed case HH_NONE : 1549*7ddc9b1aSDarren Reed before = NULL; 1550*7ddc9b1aSDarren Reed /* 1551*7ddc9b1aSDarren Reed * If there is no hint present (or not one that can be 1552*7ddc9b1aSDarren Reed * satisfied now) then try to at least respect the wishes 1553*7ddc9b1aSDarren Reed * of those that want to be last. If there are none wanting 1554*7ddc9b1aSDarren Reed * to be last then add the new hook to the tail of the 1555*7ddc9b1aSDarren Reed * list - this means we keep any wanting to be first 1556*7ddc9b1aSDarren Reed * happy without having to search for HH_FIRST. 1557*7ddc9b1aSDarren Reed */ 1558*7ddc9b1aSDarren Reed TAILQ_FOREACH(hi, head, hi_entry) { 1559*7ddc9b1aSDarren Reed hih = &hi->hi_hook; 1560*7ddc9b1aSDarren Reed if ((hih->h_hint == HH_AFTER) && 1561*7ddc9b1aSDarren Reed (strcmp(h->h_name, 1562*7ddc9b1aSDarren Reed (char *)hih->h_hintvalue) == 0)) { 1563*7ddc9b1aSDarren Reed TAILQ_INSERT_BEFORE(hi, new, hi_entry); 1564*7ddc9b1aSDarren Reed return (0); 1565*7ddc9b1aSDarren Reed } 1566*7ddc9b1aSDarren Reed if ((hih->h_hint == HH_BEFORE) && (before == NULL) && 1567*7ddc9b1aSDarren Reed (strcmp(h->h_name, 1568*7ddc9b1aSDarren Reed (char *)hih->h_hintvalue) == 0)) { 1569*7ddc9b1aSDarren Reed before = hi; 1570*7ddc9b1aSDarren Reed } 1571*7ddc9b1aSDarren Reed } 1572*7ddc9b1aSDarren Reed if (before != NULL) { 1573*7ddc9b1aSDarren Reed TAILQ_INSERT_AFTER(head, before, new, hi_entry); 1574*7ddc9b1aSDarren Reed return (0); 1575*7ddc9b1aSDarren Reed } 1576*7ddc9b1aSDarren Reed hook_insert_plain(head, new); 1577*7ddc9b1aSDarren Reed break; 1578*7ddc9b1aSDarren Reed 1579*7ddc9b1aSDarren Reed case HH_FIRST : 1580*7ddc9b1aSDarren Reed hi = TAILQ_FIRST(head); 1581*7ddc9b1aSDarren Reed if ((hi != NULL) && (hi->hi_hook.h_hint == HH_FIRST)) 1582*7ddc9b1aSDarren Reed return (EBUSY); 1583*7ddc9b1aSDarren Reed TAILQ_INSERT_HEAD(head, new, hi_entry); 1584*7ddc9b1aSDarren Reed break; 1585*7ddc9b1aSDarren Reed 1586*7ddc9b1aSDarren Reed case HH_LAST : 1587*7ddc9b1aSDarren Reed hi = TAILQ_LAST(head, hook_int_head); 1588*7ddc9b1aSDarren Reed if ((hi != NULL) && (hi->hi_hook.h_hint == HH_LAST)) 1589*7ddc9b1aSDarren Reed return (EBUSY); 1590*7ddc9b1aSDarren Reed TAILQ_INSERT_TAIL(head, new, hi_entry); 1591*7ddc9b1aSDarren Reed break; 1592*7ddc9b1aSDarren Reed 1593*7ddc9b1aSDarren Reed case HH_BEFORE : 1594*7ddc9b1aSDarren Reed hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue); 1595*7ddc9b1aSDarren Reed if (hi == NULL) 1596*7ddc9b1aSDarren Reed return (hook_insert_afterbefore(head, new)); 1597*7ddc9b1aSDarren Reed 1598*7ddc9b1aSDarren Reed if (hi->hi_hook.h_hint == HH_FIRST) 1599*7ddc9b1aSDarren Reed return (EBUSY); 1600*7ddc9b1aSDarren Reed 1601*7ddc9b1aSDarren Reed TAILQ_INSERT_BEFORE(hi, new, hi_entry); 1602*7ddc9b1aSDarren Reed break; 1603*7ddc9b1aSDarren Reed 1604*7ddc9b1aSDarren Reed case HH_AFTER : 1605*7ddc9b1aSDarren Reed hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue); 1606*7ddc9b1aSDarren Reed if (hi == NULL) 1607*7ddc9b1aSDarren Reed return (hook_insert_afterbefore(head, new)); 1608*7ddc9b1aSDarren Reed 1609*7ddc9b1aSDarren Reed if (hi->hi_hook.h_hint == HH_LAST) 1610*7ddc9b1aSDarren Reed return (EBUSY); 1611*7ddc9b1aSDarren Reed 1612*7ddc9b1aSDarren Reed TAILQ_INSERT_AFTER(head, hi, new, hi_entry); 1613*7ddc9b1aSDarren Reed break; 1614*7ddc9b1aSDarren Reed 1615*7ddc9b1aSDarren Reed default : 1616*7ddc9b1aSDarren Reed return (EINVAL); 1617*7ddc9b1aSDarren Reed } 1618*7ddc9b1aSDarren Reed 1619381a2a9aSdr146992 return (0); 1620381a2a9aSdr146992 } 1621381a2a9aSdr146992 1622*7ddc9b1aSDarren Reed /* 1623*7ddc9b1aSDarren Reed * Function: hook_insert_plain 1624*7ddc9b1aSDarren Reed * Returns: int- 0 = success, else = failure 1625*7ddc9b1aSDarren Reed * Parameters: head(I) - pointer to hook list to insert hook onto 1626*7ddc9b1aSDarren Reed * new(I) - pointer to hook to be inserted 1627*7ddc9b1aSDarren Reed * 1628*7ddc9b1aSDarren Reed * Insert a hook such that it respects the wishes of those that want to 1629*7ddc9b1aSDarren Reed * be last. If there are none wanting to be last then add the new hook 1630*7ddc9b1aSDarren Reed * to the tail of the list - this means we keep any wanting to be first 1631*7ddc9b1aSDarren Reed * happy without having to search for HH_FIRST. 1632*7ddc9b1aSDarren Reed */ 1633*7ddc9b1aSDarren Reed static void 1634*7ddc9b1aSDarren Reed hook_insert_plain(hook_int_head_t *head, hook_int_t *new) 1635*7ddc9b1aSDarren Reed { 1636*7ddc9b1aSDarren Reed hook_int_t *hi; 1637*7ddc9b1aSDarren Reed 1638*7ddc9b1aSDarren Reed hi = TAILQ_FIRST(head); 1639*7ddc9b1aSDarren Reed if (hi != NULL) { 1640*7ddc9b1aSDarren Reed if (hi->hi_hook.h_hint == HH_LAST) { 1641*7ddc9b1aSDarren Reed TAILQ_INSERT_BEFORE(hi, new, hi_entry); 1642*7ddc9b1aSDarren Reed } else { 1643*7ddc9b1aSDarren Reed TAILQ_INSERT_TAIL(head, new, hi_entry); 1644*7ddc9b1aSDarren Reed } 1645*7ddc9b1aSDarren Reed } else { 1646*7ddc9b1aSDarren Reed TAILQ_INSERT_TAIL(head, new, hi_entry); 1647*7ddc9b1aSDarren Reed } 1648*7ddc9b1aSDarren Reed } 1649*7ddc9b1aSDarren Reed 1650*7ddc9b1aSDarren Reed /* 1651*7ddc9b1aSDarren Reed * Function: hook_insert_afterbefore 1652*7ddc9b1aSDarren Reed * Returns: int- 0 = success, else = failure 1653*7ddc9b1aSDarren Reed * Parameters: head(I) - pointer to hook list to insert hook onto 1654*7ddc9b1aSDarren Reed * new(I) - pointer to hook to be inserted 1655*7ddc9b1aSDarren Reed * 1656*7ddc9b1aSDarren Reed * Simple insertion of a hook specifying a HH_BEFORE or HH_AFTER was not 1657*7ddc9b1aSDarren Reed * possible, so now we need to be more careful. The first pass is to go 1658*7ddc9b1aSDarren Reed * through the list and look for any other hooks that also specify the 1659*7ddc9b1aSDarren Reed * same hint name as the new one. The object of this exercise is to make 1660*7ddc9b1aSDarren Reed * sure that hooks with HH_BEFORE always appear on the list before those 1661*7ddc9b1aSDarren Reed * with HH_AFTER so that when said hook arrives, it can be placed in the 1662*7ddc9b1aSDarren Reed * middle of the BEFOREs and AFTERs. If this condition does not arise, 1663*7ddc9b1aSDarren Reed * just use hook_insert_plain() to try and insert the hook somewhere that 1664*7ddc9b1aSDarren Reed * is innocuous to existing efforts. 1665*7ddc9b1aSDarren Reed */ 1666*7ddc9b1aSDarren Reed static int 1667*7ddc9b1aSDarren Reed hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new) 1668*7ddc9b1aSDarren Reed { 1669*7ddc9b1aSDarren Reed hook_int_t *hi; 1670*7ddc9b1aSDarren Reed hook_t *nh; 1671*7ddc9b1aSDarren Reed hook_t *h; 1672*7ddc9b1aSDarren Reed 1673*7ddc9b1aSDarren Reed nh = &new->hi_hook; 1674*7ddc9b1aSDarren Reed ASSERT(new->hi_hook.h_hint != HH_NONE); 1675*7ddc9b1aSDarren Reed ASSERT(new->hi_hook.h_hint != HH_LAST); 1676*7ddc9b1aSDarren Reed ASSERT(new->hi_hook.h_hint != HH_FIRST); 1677*7ddc9b1aSDarren Reed 1678*7ddc9b1aSDarren Reed /* 1679*7ddc9b1aSDarren Reed * First, look through the list to see if there are any other 1680*7ddc9b1aSDarren Reed * before's or after's that have a matching hint name. 1681*7ddc9b1aSDarren Reed */ 1682*7ddc9b1aSDarren Reed TAILQ_FOREACH(hi, head, hi_entry) { 1683*7ddc9b1aSDarren Reed h = &hi->hi_hook; 1684*7ddc9b1aSDarren Reed switch (h->h_hint) { 1685*7ddc9b1aSDarren Reed case HH_FIRST : 1686*7ddc9b1aSDarren Reed case HH_LAST : 1687*7ddc9b1aSDarren Reed case HH_NONE : 1688*7ddc9b1aSDarren Reed break; 1689*7ddc9b1aSDarren Reed case HH_BEFORE : 1690*7ddc9b1aSDarren Reed if ((nh->h_hint == HH_BEFORE) && 1691*7ddc9b1aSDarren Reed (strcmp((char *)h->h_hintvalue, 1692*7ddc9b1aSDarren Reed (char *)nh->h_hintvalue) == 0)) { 1693*7ddc9b1aSDarren Reed TAILQ_INSERT_AFTER(head, hi, new, hi_entry); 1694*7ddc9b1aSDarren Reed return (0); 1695*7ddc9b1aSDarren Reed } 1696*7ddc9b1aSDarren Reed if ((nh->h_hint == HH_AFTER) && 1697*7ddc9b1aSDarren Reed (strcmp((char *)h->h_hintvalue, 1698*7ddc9b1aSDarren Reed (char *)nh->h_hintvalue) == 0)) { 1699*7ddc9b1aSDarren Reed TAILQ_INSERT_BEFORE(hi, new, hi_entry); 1700*7ddc9b1aSDarren Reed return (0); 1701*7ddc9b1aSDarren Reed } 1702*7ddc9b1aSDarren Reed break; 1703*7ddc9b1aSDarren Reed case HH_AFTER : 1704*7ddc9b1aSDarren Reed if ((nh->h_hint == HH_AFTER) && 1705*7ddc9b1aSDarren Reed (strcmp((char *)h->h_hintvalue, 1706*7ddc9b1aSDarren Reed (char *)nh->h_hintvalue) == 0)) { 1707*7ddc9b1aSDarren Reed TAILQ_INSERT_AFTER(head, hi, new, hi_entry); 1708*7ddc9b1aSDarren Reed return (0); 1709*7ddc9b1aSDarren Reed } 1710*7ddc9b1aSDarren Reed if ((nh->h_hint == HH_BEFORE) && 1711*7ddc9b1aSDarren Reed (strcmp((char *)h->h_hintvalue, 1712*7ddc9b1aSDarren Reed (char *)nh->h_hintvalue) == 0)) { 1713*7ddc9b1aSDarren Reed TAILQ_INSERT_BEFORE(hi, new, hi_entry); 1714*7ddc9b1aSDarren Reed return (0); 1715*7ddc9b1aSDarren Reed } 1716*7ddc9b1aSDarren Reed break; 1717*7ddc9b1aSDarren Reed } 1718*7ddc9b1aSDarren Reed } 1719*7ddc9b1aSDarren Reed 1720*7ddc9b1aSDarren Reed hook_insert_plain(head, new); 1721*7ddc9b1aSDarren Reed 1722*7ddc9b1aSDarren Reed return (0); 1723*7ddc9b1aSDarren Reed } 1724381a2a9aSdr146992 1725381a2a9aSdr146992 /* 1726381a2a9aSdr146992 * Function: hook_unregister 1727381a2a9aSdr146992 * Returns: int - 0 = Succ, Else = Fail 1728381a2a9aSdr146992 * Parameters: hfi(I) - internal family pointer 1729381a2a9aSdr146992 * event(I) - event name string 1730381a2a9aSdr146992 * h(I) - hook pointer 1731381a2a9aSdr146992 * 1732381a2a9aSdr146992 * Remove hook from hook list on specific family, event 1733381a2a9aSdr146992 */ 1734381a2a9aSdr146992 int 1735381a2a9aSdr146992 hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h) 1736381a2a9aSdr146992 { 1737381a2a9aSdr146992 hook_event_int_t *hei; 1738381a2a9aSdr146992 hook_int_t *hi; 1739*7ddc9b1aSDarren Reed boolean_t free_event; 1740381a2a9aSdr146992 1741381a2a9aSdr146992 ASSERT(hfi != NULL); 1742381a2a9aSdr146992 ASSERT(h != NULL); 1743381a2a9aSdr146992 1744*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(&hfi->hfi_lock); 1745381a2a9aSdr146992 1746381a2a9aSdr146992 hei = hook_event_find(hfi, event); 1747381a2a9aSdr146992 if (hei == NULL) { 1748*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 1749381a2a9aSdr146992 return (ENXIO); 1750381a2a9aSdr146992 } 1751381a2a9aSdr146992 1752381a2a9aSdr146992 /* Hold write lock for event */ 1753381a2a9aSdr146992 CVW_ENTER_WRITE(&hei->hei_lock); 1754381a2a9aSdr146992 1755381a2a9aSdr146992 hi = hook_find(hei, h); 1756381a2a9aSdr146992 if (hi == NULL) { 1757381a2a9aSdr146992 CVW_EXIT_WRITE(&hei->hei_lock); 1758*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 1759381a2a9aSdr146992 return (ENXIO); 1760381a2a9aSdr146992 } 1761381a2a9aSdr146992 1762*7ddc9b1aSDarren Reed if (hook_wait_setflag(&hei->hei_waiter, FWF_WAIT_MASK, 1763*7ddc9b1aSDarren Reed FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) { 1764*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hei->hei_lock); 1765*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 1766*7ddc9b1aSDarren Reed return (ENOENT); 1767*7ddc9b1aSDarren Reed } 1768*7ddc9b1aSDarren Reed 1769381a2a9aSdr146992 /* Remove from hook list */ 1770381a2a9aSdr146992 TAILQ_REMOVE(&hei->hei_head, hi, hi_entry); 1771*7ddc9b1aSDarren Reed 1772*7ddc9b1aSDarren Reed free_event = B_FALSE; 1773381a2a9aSdr146992 if (TAILQ_EMPTY(&hei->hei_head)) { 1774381a2a9aSdr146992 hei->hei_event->he_interested = B_FALSE; 1775*7ddc9b1aSDarren Reed /* 1776*7ddc9b1aSDarren Reed * If the delete pending flag has been set and there are 1777*7ddc9b1aSDarren Reed * no notifiers on the event (and we've removed the last 1778*7ddc9b1aSDarren Reed * hook) then we need to free this event after we're done. 1779*7ddc9b1aSDarren Reed */ 1780*7ddc9b1aSDarren Reed if (hei->hei_condemned && TAILQ_EMPTY(&hei->hei_nhead)) 1781*7ddc9b1aSDarren Reed free_event = B_TRUE; 1782381a2a9aSdr146992 } 1783*7ddc9b1aSDarren Reed hei->hei_kstats.hooks_removed.value.ui64++; 1784381a2a9aSdr146992 1785381a2a9aSdr146992 CVW_EXIT_WRITE(&hei->hei_lock); 1786*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(&hfi->hfi_lock); 1787*7ddc9b1aSDarren Reed /* 1788*7ddc9b1aSDarren Reed * While the FWF_DEL_ACTIVE flag is set, the hook_event_int_t 1789*7ddc9b1aSDarren Reed * will not be free'd and thus the hook_family_int_t wil not 1790*7ddc9b1aSDarren Reed * be free'd either. 1791*7ddc9b1aSDarren Reed */ 1792*7ddc9b1aSDarren Reed hook_event_notify_run(hei, hfi, event, h->h_name, HN_UNREGISTER); 1793*7ddc9b1aSDarren Reed hook_wait_unsetflag(&hei->hei_waiter, FWF_DEL_ACTIVE); 1794381a2a9aSdr146992 1795*7ddc9b1aSDarren Reed hook_int_free(hi, hfi->hfi_stack->hks_netstackid); 1796*7ddc9b1aSDarren Reed 1797*7ddc9b1aSDarren Reed if (free_event) 1798*7ddc9b1aSDarren Reed hook_event_free(hei, hfi); 1799*7ddc9b1aSDarren Reed 1800381a2a9aSdr146992 return (0); 1801381a2a9aSdr146992 } 1802381a2a9aSdr146992 1803*7ddc9b1aSDarren Reed /* 1804*7ddc9b1aSDarren Reed * Function: hook_find_byname 1805*7ddc9b1aSDarren Reed * Returns: internal hook pointer - NULL = Not match 1806*7ddc9b1aSDarren Reed * Parameters: hei(I) - internal event pointer 1807*7ddc9b1aSDarren Reed * name(I)- hook name 1808*7ddc9b1aSDarren Reed * 1809*7ddc9b1aSDarren Reed * Search an event's list of hooks to see if there is a hook present that 1810*7ddc9b1aSDarren Reed * has a matching name to the one being looked for. 1811*7ddc9b1aSDarren Reed */ 1812*7ddc9b1aSDarren Reed static hook_int_t * 1813*7ddc9b1aSDarren Reed hook_find_byname(hook_int_head_t *head, char *name) 1814*7ddc9b1aSDarren Reed { 1815*7ddc9b1aSDarren Reed hook_int_t *hi; 1816*7ddc9b1aSDarren Reed 1817*7ddc9b1aSDarren Reed TAILQ_FOREACH(hi, head, hi_entry) { 1818*7ddc9b1aSDarren Reed if (strcmp(hi->hi_hook.h_name, name) == 0) 1819*7ddc9b1aSDarren Reed return (hi); 1820*7ddc9b1aSDarren Reed } 1821*7ddc9b1aSDarren Reed 1822*7ddc9b1aSDarren Reed return (NULL); 1823*7ddc9b1aSDarren Reed } 1824381a2a9aSdr146992 1825381a2a9aSdr146992 /* 1826381a2a9aSdr146992 * Function: hook_find 1827381a2a9aSdr146992 * Returns: internal hook pointer - NULL = Not match 1828381a2a9aSdr146992 * Parameters: hei(I) - internal event pointer 1829381a2a9aSdr146992 * h(I) - hook pointer 1830381a2a9aSdr146992 * 1831*7ddc9b1aSDarren Reed * Search an event's list of hooks to see if there is already one that 1832*7ddc9b1aSDarren Reed * matches the hook being passed in. Currently the only criteria for a 1833*7ddc9b1aSDarren Reed * successful search here is for the names to be the same. 1834381a2a9aSdr146992 */ 1835381a2a9aSdr146992 static hook_int_t * 1836381a2a9aSdr146992 hook_find(hook_event_int_t *hei, hook_t *h) 1837381a2a9aSdr146992 { 1838381a2a9aSdr146992 1839381a2a9aSdr146992 ASSERT(hei != NULL); 1840381a2a9aSdr146992 ASSERT(h != NULL); 1841381a2a9aSdr146992 1842*7ddc9b1aSDarren Reed return (hook_find_byname(&hei->hei_head, h->h_name)); 1843381a2a9aSdr146992 } 1844381a2a9aSdr146992 1845381a2a9aSdr146992 /* 1846381a2a9aSdr146992 * Function: hook_copy 1847381a2a9aSdr146992 * Returns: internal hook pointer - NULL = Failed 1848381a2a9aSdr146992 * Parameters: src(I) - hook pointer 1849381a2a9aSdr146992 * 1850381a2a9aSdr146992 * Allocate internal hook block and duplicate incoming hook. 1851381a2a9aSdr146992 * No locks should be held across this function as it may sleep. 1852*7ddc9b1aSDarren Reed * Because hook_copy() is responsible for the creation of the internal 1853*7ddc9b1aSDarren Reed * hook structure that is used here, it takes on population the structure 1854*7ddc9b1aSDarren Reed * with the kstat information. Note that while the kstat bits are 1855*7ddc9b1aSDarren Reed * seeded here, their installation of the kstats is handled elsewhere. 1856381a2a9aSdr146992 */ 1857381a2a9aSdr146992 static hook_int_t * 1858381a2a9aSdr146992 hook_copy(hook_t *src) 1859381a2a9aSdr146992 { 1860381a2a9aSdr146992 hook_int_t *new; 1861381a2a9aSdr146992 hook_t *dst; 1862*7ddc9b1aSDarren Reed int len; 1863381a2a9aSdr146992 1864381a2a9aSdr146992 ASSERT(src != NULL); 1865381a2a9aSdr146992 ASSERT(src->h_name != NULL); 1866381a2a9aSdr146992 1867381a2a9aSdr146992 new = (hook_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP); 1868381a2a9aSdr146992 1869381a2a9aSdr146992 /* Copy body */ 1870381a2a9aSdr146992 dst = &new->hi_hook; 1871381a2a9aSdr146992 *dst = *src; 1872381a2a9aSdr146992 1873381a2a9aSdr146992 /* Copy name */ 1874*7ddc9b1aSDarren Reed len = strlen(src->h_name); 1875*7ddc9b1aSDarren Reed dst->h_name = (char *)kmem_alloc(len + 1, KM_SLEEP); 1876381a2a9aSdr146992 (void) strcpy(dst->h_name, src->h_name); 1877381a2a9aSdr146992 1878*7ddc9b1aSDarren Reed /* 1879*7ddc9b1aSDarren Reed * This is initialised in this manner to make it safer to use the 1880*7ddc9b1aSDarren Reed * same pointer in the kstats field. 1881*7ddc9b1aSDarren Reed */ 1882*7ddc9b1aSDarren Reed dst->h_hintvalue = (uintptr_t)""; 1883*7ddc9b1aSDarren Reed 1884*7ddc9b1aSDarren Reed if (dst->h_hint == HH_BEFORE || dst->h_hint == HH_AFTER) { 1885*7ddc9b1aSDarren Reed len = strlen((char *)src->h_hintvalue); 1886*7ddc9b1aSDarren Reed if (len > 0) { 1887*7ddc9b1aSDarren Reed dst->h_hintvalue = (uintptr_t)kmem_alloc(len + 1, 1888*7ddc9b1aSDarren Reed KM_SLEEP); 1889*7ddc9b1aSDarren Reed (void) strcpy((char *)dst->h_hintvalue, 1890*7ddc9b1aSDarren Reed (char *)src->h_hintvalue); 1891*7ddc9b1aSDarren Reed } 1892*7ddc9b1aSDarren Reed } 1893*7ddc9b1aSDarren Reed 1894381a2a9aSdr146992 return (new); 1895381a2a9aSdr146992 } 1896381a2a9aSdr146992 1897381a2a9aSdr146992 /* 1898*7ddc9b1aSDarren Reed * Function: hook_init_kstats 1899*7ddc9b1aSDarren Reed * Returns: None 1900*7ddc9b1aSDarren Reed * Parameters: hfi(I) - pointer to the family that owns the event. 1901*7ddc9b1aSDarren Reed * hei(I) - pointer to the event that owns this hook 1902*7ddc9b1aSDarren Reed * hi(I) - pointer to the hook for which we create kstats for 1903*7ddc9b1aSDarren Reed * 1904*7ddc9b1aSDarren Reed * Each hook that is registered with this framework has its own kstats 1905*7ddc9b1aSDarren Reed * set up so that we can provide an easy way in which to observe the 1906*7ddc9b1aSDarren Reed * look of hooks (using the kstat command.) The position is set to 0 1907*7ddc9b1aSDarren Reed * here but is recalculated after we know the insertion has been a 1908*7ddc9b1aSDarren Reed * success. 1909*7ddc9b1aSDarren Reed */ 1910*7ddc9b1aSDarren Reed static void 1911*7ddc9b1aSDarren Reed hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei, hook_int_t *hi) 1912*7ddc9b1aSDarren Reed { 1913*7ddc9b1aSDarren Reed hook_hook_kstat_t template = { 1914*7ddc9b1aSDarren Reed { "version", KSTAT_DATA_INT32 }, 1915*7ddc9b1aSDarren Reed { "flags", KSTAT_DATA_UINT32 }, 1916*7ddc9b1aSDarren Reed { "hint", KSTAT_DATA_INT32 }, 1917*7ddc9b1aSDarren Reed { "hint_value", KSTAT_DATA_UINT64 }, 1918*7ddc9b1aSDarren Reed { "position", KSTAT_DATA_INT32 }, 1919*7ddc9b1aSDarren Reed { "hook_hits", KSTAT_DATA_UINT64 } 1920*7ddc9b1aSDarren Reed }; 1921*7ddc9b1aSDarren Reed hook_stack_t *hks; 1922*7ddc9b1aSDarren Reed size_t kslen; 1923*7ddc9b1aSDarren Reed int position; 1924*7ddc9b1aSDarren Reed hook_int_t *h; 1925*7ddc9b1aSDarren Reed 1926*7ddc9b1aSDarren Reed kslen = strlen(hfi->hfi_family.hf_name) + 1927*7ddc9b1aSDarren Reed strlen(hei->hei_event->he_name) + 2; 1928*7ddc9b1aSDarren Reed 1929*7ddc9b1aSDarren Reed hi->hi_ksname = (char *)kmem_zalloc(kslen, KM_SLEEP); 1930*7ddc9b1aSDarren Reed (void) snprintf(hi->hi_ksname, kslen, "%s/%s", 1931*7ddc9b1aSDarren Reed hfi->hfi_family.hf_name, hei->hei_event->he_name); 1932*7ddc9b1aSDarren Reed 1933*7ddc9b1aSDarren Reed hks = hfi->hfi_stack; 1934*7ddc9b1aSDarren Reed hi->hi_kstatp = kstat_create_netstack(hi->hi_ksname, 0, 1935*7ddc9b1aSDarren Reed hi->hi_hook.h_name, "hook", KSTAT_TYPE_NAMED, 1936*7ddc9b1aSDarren Reed sizeof (hi->hi_kstats) / sizeof (kstat_named_t), 1937*7ddc9b1aSDarren Reed KSTAT_FLAG_VIRTUAL, hks->hks_netstackid); 1938*7ddc9b1aSDarren Reed 1939*7ddc9b1aSDarren Reed /* Initialise the kstats for the structure */ 1940*7ddc9b1aSDarren Reed bcopy(&template, &hi->hi_kstats, sizeof (template)); 1941*7ddc9b1aSDarren Reed hi->hi_kstats.hook_version.value.i32 = hi->hi_hook.h_version; 1942*7ddc9b1aSDarren Reed hi->hi_kstats.hook_flags.value.ui32 = hi->hi_hook.h_flags; 1943*7ddc9b1aSDarren Reed hi->hi_kstats.hook_hint.value.i32 = hi->hi_hook.h_hint; 1944*7ddc9b1aSDarren Reed hi->hi_kstats.hook_position.value.i32 = 0; 1945*7ddc9b1aSDarren Reed hi->hi_kstats.hook_hits.value.ui64 = 0; 1946*7ddc9b1aSDarren Reed 1947*7ddc9b1aSDarren Reed switch (hi->hi_hook.h_hint) { 1948*7ddc9b1aSDarren Reed case HH_BEFORE : 1949*7ddc9b1aSDarren Reed case HH_AFTER : 1950*7ddc9b1aSDarren Reed hi->hi_kstats.hook_hintvalue.data_type = KSTAT_DATA_STRING; 1951*7ddc9b1aSDarren Reed hi->hi_kstats.hook_hintvalue.value.ui64 = 1952*7ddc9b1aSDarren Reed hi->hi_hook.h_hintvalue; 1953*7ddc9b1aSDarren Reed break; 1954*7ddc9b1aSDarren Reed default : 1955*7ddc9b1aSDarren Reed break; 1956*7ddc9b1aSDarren Reed } 1957*7ddc9b1aSDarren Reed 1958*7ddc9b1aSDarren Reed if (hi->hi_kstatp != NULL) { 1959*7ddc9b1aSDarren Reed hi->hi_kstatp->ks_data = (void *)&hi->hi_kstats; 1960*7ddc9b1aSDarren Reed hi->hi_kstatp->ks_private = 1961*7ddc9b1aSDarren Reed (void *)(uintptr_t)hks->hks_netstackid; 1962*7ddc9b1aSDarren Reed 1963*7ddc9b1aSDarren Reed kstat_install(hi->hi_kstatp); 1964*7ddc9b1aSDarren Reed } 1965*7ddc9b1aSDarren Reed 1966*7ddc9b1aSDarren Reed position = 1; 1967*7ddc9b1aSDarren Reed TAILQ_FOREACH(h, &hei->hei_head, hi_entry) { 1968*7ddc9b1aSDarren Reed h->hi_kstats.hook_position.value.ui32 = position++; 1969*7ddc9b1aSDarren Reed } 1970*7ddc9b1aSDarren Reed } 1971*7ddc9b1aSDarren Reed 1972*7ddc9b1aSDarren Reed /* 1973*7ddc9b1aSDarren Reed * Function: hook_int_free 1974381a2a9aSdr146992 * Returns: None 1975381a2a9aSdr146992 * Parameters: hi(I) - internal hook pointer 1976381a2a9aSdr146992 * 1977381a2a9aSdr146992 * Free alloc memory for hook 1978381a2a9aSdr146992 */ 1979381a2a9aSdr146992 static void 1980*7ddc9b1aSDarren Reed hook_int_free(hook_int_t *hi, netstackid_t stackid) 1981381a2a9aSdr146992 { 1982*7ddc9b1aSDarren Reed int len; 1983*7ddc9b1aSDarren Reed 1984381a2a9aSdr146992 ASSERT(hi != NULL); 1985381a2a9aSdr146992 1986381a2a9aSdr146992 /* Free name space */ 1987381a2a9aSdr146992 if (hi->hi_hook.h_name != NULL) { 1988381a2a9aSdr146992 kmem_free(hi->hi_hook.h_name, strlen(hi->hi_hook.h_name) + 1); 1989381a2a9aSdr146992 } 1990*7ddc9b1aSDarren Reed if (hi->hi_ksname != NULL) { 1991*7ddc9b1aSDarren Reed kmem_free(hi->hi_ksname, strlen(hi->hi_ksname) + 1); 1992*7ddc9b1aSDarren Reed } 1993*7ddc9b1aSDarren Reed 1994*7ddc9b1aSDarren Reed /* Free the name used with the before/after hints. */ 1995*7ddc9b1aSDarren Reed switch (hi->hi_hook.h_hint) { 1996*7ddc9b1aSDarren Reed case HH_BEFORE : 1997*7ddc9b1aSDarren Reed case HH_AFTER : 1998*7ddc9b1aSDarren Reed len = strlen((char *)hi->hi_hook.h_hintvalue); 1999*7ddc9b1aSDarren Reed if (len > 0) 2000*7ddc9b1aSDarren Reed kmem_free((void *)hi->hi_hook.h_hintvalue, len + 1); 2001*7ddc9b1aSDarren Reed break; 2002*7ddc9b1aSDarren Reed default : 2003*7ddc9b1aSDarren Reed break; 2004*7ddc9b1aSDarren Reed } 2005*7ddc9b1aSDarren Reed 2006*7ddc9b1aSDarren Reed if (hi->hi_kstatp != NULL) 2007*7ddc9b1aSDarren Reed kstat_delete_netstack(hi->hi_kstatp, stackid); 2008381a2a9aSdr146992 2009381a2a9aSdr146992 /* Free container */ 2010381a2a9aSdr146992 kmem_free(hi, sizeof (*hi)); 2011381a2a9aSdr146992 } 2012*7ddc9b1aSDarren Reed 2013*7ddc9b1aSDarren Reed /* 2014*7ddc9b1aSDarren Reed * Function: hook_alloc 2015*7ddc9b1aSDarren Reed * Returns: hook_t * - pointer to new hook structure 2016*7ddc9b1aSDarren Reed * Parameters: version(I) - version number of the API when compiled 2017*7ddc9b1aSDarren Reed * 2018*7ddc9b1aSDarren Reed * This function serves as the interface for consumers to obtain a hook_t 2019*7ddc9b1aSDarren Reed * structure. At this point in time, there is only a single "version" of 2020*7ddc9b1aSDarren Reed * it, leading to a straight forward function. In a perfect world the 2021*7ddc9b1aSDarren Reed * h_vesion would be a protected data structure member, but C isn't that 2022*7ddc9b1aSDarren Reed * advanced... 2023*7ddc9b1aSDarren Reed */ 2024*7ddc9b1aSDarren Reed hook_t * 2025*7ddc9b1aSDarren Reed hook_alloc(const int h_version) 2026*7ddc9b1aSDarren Reed { 2027*7ddc9b1aSDarren Reed hook_t *h; 2028*7ddc9b1aSDarren Reed 2029*7ddc9b1aSDarren Reed h = kmem_zalloc(sizeof (hook_t), KM_SLEEP); 2030*7ddc9b1aSDarren Reed h->h_version = h_version; 2031*7ddc9b1aSDarren Reed return (h); 2032*7ddc9b1aSDarren Reed } 2033*7ddc9b1aSDarren Reed 2034*7ddc9b1aSDarren Reed /* 2035*7ddc9b1aSDarren Reed * Function: hook_free 2036*7ddc9b1aSDarren Reed * Returns: None 2037*7ddc9b1aSDarren Reed * Parameters: h(I) - external hook pointer 2038*7ddc9b1aSDarren Reed * 2039*7ddc9b1aSDarren Reed * This function only free's memory allocated with hook_alloc(), so that if 2040*7ddc9b1aSDarren Reed * (for example) kernel memory was allocated for h_name, this needs to be 2041*7ddc9b1aSDarren Reed * free'd before calling hook_free(). 2042*7ddc9b1aSDarren Reed */ 2043*7ddc9b1aSDarren Reed void 2044*7ddc9b1aSDarren Reed hook_free(hook_t *h) 2045*7ddc9b1aSDarren Reed { 2046*7ddc9b1aSDarren Reed kmem_free(h, sizeof (*h)); 2047*7ddc9b1aSDarren Reed } 2048*7ddc9b1aSDarren Reed 2049*7ddc9b1aSDarren Reed /* 2050*7ddc9b1aSDarren Reed * Function: hook_notify_register 2051*7ddc9b1aSDarren Reed * Returns: 0 = success, else failure 2052*7ddc9b1aSDarren Reed * Parameters: lock(I) - netstack identifier 2053*7ddc9b1aSDarren Reed * head(I) - top of the list of callbacks 2054*7ddc9b1aSDarren Reed * callback(I) - function to be called 2055*7ddc9b1aSDarren Reed * arg(I) - arg to pass back to the function 2056*7ddc9b1aSDarren Reed * 2057*7ddc9b1aSDarren Reed * This function implements the modification of the list of callbacks 2058*7ddc9b1aSDarren Reed * that are registered when someone wants to be advised of a change 2059*7ddc9b1aSDarren Reed * that has happened. 2060*7ddc9b1aSDarren Reed */ 2061*7ddc9b1aSDarren Reed static int 2062*7ddc9b1aSDarren Reed hook_notify_register(cvwaitlock_t *lock, hook_notify_head_t *head, 2063*7ddc9b1aSDarren Reed hook_notify_fn_t callback, void *arg) 2064*7ddc9b1aSDarren Reed { 2065*7ddc9b1aSDarren Reed hook_notify_t *hn; 2066*7ddc9b1aSDarren Reed 2067*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(lock); 2068*7ddc9b1aSDarren Reed 2069*7ddc9b1aSDarren Reed TAILQ_FOREACH(hn, head, hn_entry) { 2070*7ddc9b1aSDarren Reed if (hn->hn_func == callback) { 2071*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(lock); 2072*7ddc9b1aSDarren Reed return (EEXIST); 2073*7ddc9b1aSDarren Reed } 2074*7ddc9b1aSDarren Reed } 2075*7ddc9b1aSDarren Reed 2076*7ddc9b1aSDarren Reed hn = (hook_notify_t *)kmem_alloc(sizeof (*hn), KM_SLEEP); 2077*7ddc9b1aSDarren Reed hn->hn_func = callback; 2078*7ddc9b1aSDarren Reed hn->hn_arg = arg; 2079*7ddc9b1aSDarren Reed TAILQ_INSERT_TAIL(head, hn, hn_entry); 2080*7ddc9b1aSDarren Reed 2081*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(lock); 2082*7ddc9b1aSDarren Reed 2083*7ddc9b1aSDarren Reed return (0); 2084*7ddc9b1aSDarren Reed } 2085*7ddc9b1aSDarren Reed 2086*7ddc9b1aSDarren Reed /* 2087*7ddc9b1aSDarren Reed * Function: hook_stack_notify_register 2088*7ddc9b1aSDarren Reed * Returns: 0 = success, else failure 2089*7ddc9b1aSDarren Reed * Parameters: stackid(I) - netstack identifier 2090*7ddc9b1aSDarren Reed * callback(I) - function to be called 2091*7ddc9b1aSDarren Reed * 2092*7ddc9b1aSDarren Reed */ 2093*7ddc9b1aSDarren Reed static int 2094*7ddc9b1aSDarren Reed hook_notify_unregister(cvwaitlock_t *lock, hook_notify_head_t *head, 2095*7ddc9b1aSDarren Reed hook_notify_fn_t callback) 2096*7ddc9b1aSDarren Reed { 2097*7ddc9b1aSDarren Reed hook_notify_t *hn; 2098*7ddc9b1aSDarren Reed 2099*7ddc9b1aSDarren Reed CVW_ENTER_WRITE(lock); 2100*7ddc9b1aSDarren Reed 2101*7ddc9b1aSDarren Reed TAILQ_FOREACH(hn, head, hn_entry) { 2102*7ddc9b1aSDarren Reed if (hn->hn_func == callback) 2103*7ddc9b1aSDarren Reed break; 2104*7ddc9b1aSDarren Reed } 2105*7ddc9b1aSDarren Reed if (hn == NULL) { 2106*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(lock); 2107*7ddc9b1aSDarren Reed return (ESRCH); 2108*7ddc9b1aSDarren Reed } 2109*7ddc9b1aSDarren Reed 2110*7ddc9b1aSDarren Reed TAILQ_REMOVE(head, hn, hn_entry); 2111*7ddc9b1aSDarren Reed 2112*7ddc9b1aSDarren Reed CVW_EXIT_WRITE(lock); 2113*7ddc9b1aSDarren Reed 2114*7ddc9b1aSDarren Reed kmem_free(hn, sizeof (*hn)); 2115*7ddc9b1aSDarren Reed 2116*7ddc9b1aSDarren Reed return (0); 2117*7ddc9b1aSDarren Reed } 2118*7ddc9b1aSDarren Reed 2119*7ddc9b1aSDarren Reed /* 2120*7ddc9b1aSDarren Reed * Function: hook_notify_run 2121*7ddc9b1aSDarren Reed * Returns: None 2122*7ddc9b1aSDarren Reed * Parameters: head(I) - top of the list of callbacks 2123*7ddc9b1aSDarren Reed * family(I) - name of the hook family that owns the event 2124*7ddc9b1aSDarren Reed * event(I) - name of the event being changed 2125*7ddc9b1aSDarren Reed * name(I) - name of the object causing change 2126*7ddc9b1aSDarren Reed * cmd(I) - either HN_UNREGISTER or HN_REGISTER 2127*7ddc9b1aSDarren Reed * 2128*7ddc9b1aSDarren Reed * This function walks through the list of registered callbacks and 2129*7ddc9b1aSDarren Reed * executes each one, passing back the arg supplied when registered 2130*7ddc9b1aSDarren Reed * and the name of the family (that owns the event), event (the thing 2131*7ddc9b1aSDarren Reed * to which we're making a change) and finally a name that describes 2132*7ddc9b1aSDarren Reed * what is being added or removed, as indicated by cmd. 2133*7ddc9b1aSDarren Reed * 2134*7ddc9b1aSDarren Reed * This function does not acquire or release any lock as it is required 2135*7ddc9b1aSDarren Reed * that code calling it do so before hand. The use of hook_notify_head_t 2136*7ddc9b1aSDarren Reed * is protected by the use of flagwait_t in the structures that own this 2137*7ddc9b1aSDarren Reed * list and with the use of the FWF_ADD/DEL_ACTIVE flags. 2138*7ddc9b1aSDarren Reed */ 2139*7ddc9b1aSDarren Reed static void 2140*7ddc9b1aSDarren Reed hook_notify_run(hook_notify_head_t *head, char *family, char *event, 2141*7ddc9b1aSDarren Reed char *name, hook_notify_cmd_t cmd) 2142*7ddc9b1aSDarren Reed { 2143*7ddc9b1aSDarren Reed hook_notify_t *hn; 2144*7ddc9b1aSDarren Reed 2145*7ddc9b1aSDarren Reed TAILQ_FOREACH(hn, head, hn_entry) { 2146*7ddc9b1aSDarren Reed (*hn->hn_func)(cmd, hn->hn_arg, family, event, name); 2147*7ddc9b1aSDarren Reed } 2148*7ddc9b1aSDarren Reed } 2149