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