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 /* 430 * Set the shutdown flag to indicate that we should stop accepting new 431 * register calls as we're now in the cleanup process. 432 */ 433 /*ARGSUSED*/ 434 static void 435 hook_stack_shutdown(netstackid_t stackid, void *arg) 436 { 437 hook_stack_t *hks = (hook_stack_t *)arg; 438 439 mutex_enter(&hook_stack_lock); 440 /* 441 * Once this flag gets set to one, no more additions are allowed 442 * to any of the structures that make up this stack. 443 */ 444 hks->hks_shutdown = 1; 445 mutex_exit(&hook_stack_lock); 446 } 447 448 /* 449 * Free the hook stack instance. 450 */ 451 /*ARGSUSED*/ 452 static void 453 hook_stack_fini(netstackid_t stackid, void *arg) 454 { 455 hook_stack_t *hks = (hook_stack_t *)arg; 456 457 mutex_enter(&hook_stack_lock); 458 hks->hks_shutdown = 2; 459 hook_stack_remove(hks); 460 mutex_exit(&hook_stack_lock); 461 } 462 463 /* 464 * This function assumes that it is called with hook_stack_lock held. 465 * It functions differently to hook_family/event_remove in that it does 466 * the checks to see if it can be removed. This difference exists 467 * because this structure has nothing higher up that depends on it. 468 */ 469 static void 470 hook_stack_remove(hook_stack_t *hks) 471 { 472 473 ASSERT(mutex_owned(&hook_stack_lock)); 474 475 /* 476 * Is the structure still in use? 477 */ 478 if (!SLIST_EMPTY(&hks->hks_familylist) || 479 !TAILQ_EMPTY(&hks->hks_nhead)) 480 return; 481 482 SLIST_REMOVE(&hook_stacks, hks, hook_stack, hks_entry); 483 484 hook_wait_destroy(&hks->hks_waiter); 485 CVW_DESTROY(&hks->hks_lock); 486 kmem_free(hks, sizeof (*hks)); 487 } 488 489 static hook_stack_t * 490 hook_stack_get(netstackid_t stackid) 491 { 492 hook_stack_t *hks; 493 494 SLIST_FOREACH(hks, &hook_stacks, hks_entry) { 495 if (hks->hks_netstackid == stackid) 496 break; 497 } 498 499 return (hks); 500 } 501 502 /* 503 * Function: hook_stack_notify_register 504 * Returns: 0 = success, else failure 505 * Parameters: stackid(I) - netstack identifier 506 * callback(I)- function to be called 507 * arg(I) - arg to provide callback when it is called 508 * 509 * If we're not shutting down this instance, append a new function to the 510 * list of those to call when a new family of hooks is added to this stack. 511 */ 512 int 513 hook_stack_notify_register(netstackid_t stackid, hook_notify_fn_t callback, 514 void *arg) 515 { 516 hook_stack_t *hks; 517 int error; 518 519 mutex_enter(&hook_stack_lock); 520 hks = hook_stack_get(stackid); 521 if (hks != NULL) { 522 if (hks->hks_shutdown != 0) { 523 error = ESHUTDOWN; 524 } else { 525 error = hook_notify_register(&hks->hks_lock, 526 &hks->hks_nhead, callback, arg); 527 } 528 } else { 529 error = ESRCH; 530 } 531 mutex_exit(&hook_stack_lock); 532 533 return (error); 534 } 535 536 /* 537 * Function: hook_stack_notify_unregister 538 * Returns: 0 = success, else failure 539 * Parameters: stackid(I) - netstack identifier 540 * callback(I) - function to be called 541 * 542 * Attempt to remove a registered function from a hook stack's list of 543 * callbacks to activiate when protocols are added/deleted. 544 */ 545 int 546 hook_stack_notify_unregister(netstackid_t stackid, hook_notify_fn_t callback) 547 { 548 hook_stack_t *hks; 549 int error; 550 551 mutex_enter(&hook_stack_lock); 552 hks = hook_stack_get(stackid); 553 if (hks != NULL) { 554 error = hook_notify_unregister(&hks->hks_lock, 555 &hks->hks_nhead, callback); 556 if ((error == 0) && (hks->hks_shutdown == 2)) 557 hook_stack_remove(hks); 558 } else { 559 error = ESRCH; 560 } 561 mutex_exit(&hook_stack_lock); 562 563 return (error); 564 } 565 566 /* 567 * Function: hook_stack_notify_run 568 * Returns: None 569 * Parameters: hks(I) - hook stack pointer to execute callbacks for 570 * name(I) - name of a hook family 571 * cmd(I) - either HN_UNREGISTER or HN_REGISTER 572 * 573 * Run through the list of callbacks on the hook stack to be called when 574 * a new hook family is added 575 * 576 * As hook_notify_run() expects 3 names, one for the family, one for the 577 * event and one for the object being introduced and we really only have 578 * one name (that of the new hook family), fake the hook stack's name by 579 * converting the integer to a string and for the event just pass NULL. 580 */ 581 static void 582 hook_stack_notify_run(hook_stack_t *hks, char *name, 583 hook_notify_cmd_t cmd) 584 { 585 char buffer[16]; 586 587 (void) snprintf(buffer, sizeof (buffer), "%u", hks->hks_netstackid); 588 589 hook_notify_run(&hks->hks_nhead, buffer, NULL, name, cmd); 590 } 591 592 /* 593 * Function: hook_run 594 * Returns: int - return value according to callback func 595 * Parameters: token(I) - event pointer 596 * info(I) - message 597 * 598 * Run hooks for specific provider. The hooks registered are stepped through 599 * until either the end of the list is reached or a hook function returns a 600 * non-zero value. If a non-zero value is returned from a hook function, we 601 * return that value back to our caller. By design, a hook function can be 602 * called more than once, simultaneously. 603 */ 604 int 605 hook_run(hook_family_int_t *hfi, hook_event_token_t token, hook_data_t info) 606 { 607 hook_event_int_t *hei; 608 hook_int_t *hi; 609 int rval = 0; 610 611 ASSERT(token != NULL); 612 613 hei = (hook_event_int_t *)token; 614 DTRACE_PROBE2(hook__run__start, 615 hook_event_token_t, token, 616 hook_data_t, info); 617 618 /* 619 * Hold global read lock to ensure event will not be deleted. 620 * While it might be expected that we should also hold a read lock 621 * on the event lock (hei_lock) to prevent the hook list from 622 * changing while we're executing this function, both addition 623 * to and removal from the hook list on the event is done with 624 * a write lock held on hfi_lock. This is by design so that we 625 * only need to get one of these locks to process a packet. 626 * - locking is not a cheap thing to do for every packet. 627 */ 628 CVW_ENTER_READ(&hfi->hfi_lock); 629 630 TAILQ_FOREACH(hi, &hei->hei_head, hi_entry) { 631 ASSERT(hi->hi_hook.h_func != NULL); 632 DTRACE_PROBE3(hook__func__start, 633 hook_event_token_t, token, 634 hook_data_t, info, 635 hook_int_t *, hi); 636 rval = (*hi->hi_hook.h_func)(token, info, hi->hi_hook.h_arg); 637 DTRACE_PROBE4(hook__func__end, 638 hook_event_token_t, token, 639 hook_data_t, info, 640 hook_int_t *, hi, 641 int, rval); 642 hi->hi_kstats.hook_hits.value.ui64++; 643 if (rval != 0) 644 break; 645 } 646 647 hei->hei_kstats.events.value.ui64++; 648 649 CVW_EXIT_READ(&hfi->hfi_lock); 650 651 DTRACE_PROBE3(hook__run__end, 652 hook_event_token_t, token, 653 hook_data_t, info, 654 hook_int_t *, hi); 655 656 return (rval); 657 } 658 659 /* 660 * Function: hook_family_add 661 * Returns: internal family pointer - NULL = Fail 662 * Parameters: hf(I) - family pointer 663 * 664 * Add new family to family list 665 */ 666 hook_family_int_t * 667 hook_family_add(hook_family_t *hf, hook_stack_t *hks) 668 { 669 hook_family_int_t *hfi, *new; 670 671 ASSERT(hf != NULL); 672 ASSERT(hf->hf_name != NULL); 673 674 new = hook_family_copy(hf); 675 if (new == NULL) 676 return (NULL); 677 678 mutex_enter(&hook_stack_lock); 679 CVW_ENTER_WRITE(&hks->hks_lock); 680 681 if (hks->hks_shutdown != 0) { 682 CVW_EXIT_WRITE(&hks->hks_lock); 683 mutex_exit(&hook_stack_lock); 684 hook_family_free(new, NULL); 685 return (NULL); 686 } 687 688 /* search family list */ 689 hfi = hook_family_find(hf->hf_name, hks); 690 if (hfi != NULL) { 691 CVW_EXIT_WRITE(&hks->hks_lock); 692 mutex_exit(&hook_stack_lock); 693 hook_family_free(new, NULL); 694 return (NULL); 695 } 696 697 if (hook_wait_setflag(&hks->hks_waiter, FWF_WAIT_MASK, 698 FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) { 699 CVW_EXIT_WRITE(&hks->hks_lock); 700 mutex_exit(&hook_stack_lock); 701 hook_family_free(new, NULL); 702 return (NULL); 703 } 704 705 CVW_INIT(&new->hfi_lock); 706 SLIST_INIT(&new->hfi_head); 707 TAILQ_INIT(&new->hfi_nhead); 708 709 hook_wait_init(&new->hfi_waiter, &new->hfi_lock); 710 711 new->hfi_stack = hks; 712 713 /* Add to family list head */ 714 SLIST_INSERT_HEAD(&hks->hks_familylist, new, hfi_entry); 715 716 CVW_EXIT_WRITE(&hks->hks_lock); 717 mutex_exit(&hook_stack_lock); 718 719 hook_stack_notify_run(hks, hf->hf_name, HN_REGISTER); 720 721 hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE); 722 723 return (new); 724 } 725 726 /* 727 * Function: hook_family_remove 728 * Returns: int - 0 = Succ, Else = Fail 729 * Parameters: hfi(I) - internal family pointer 730 * 731 * Remove family from family list. This function has been designed to be 732 * called once and once only per hook_family_int_t. Thus when cleaning up 733 * this structure as an orphan, callers should only call hook_family_free. 734 */ 735 int 736 hook_family_remove(hook_family_int_t *hfi) 737 { 738 hook_stack_t *hks; 739 boolean_t notifydone; 740 741 ASSERT(hfi != NULL); 742 hks = hfi->hfi_stack; 743 744 CVW_ENTER_WRITE(&hks->hks_lock); 745 746 if (hook_wait_setflag(&hks->hks_waiter, FWF_WAIT_MASK, 747 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) { 748 /* 749 * If we're trying to destroy the hook_stack_t... 750 */ 751 CVW_EXIT_WRITE(&hks->hks_lock); 752 return (ENXIO); 753 } 754 755 /* 756 * Check if the family is in use by the presence of either events 757 * or notify callbacks on the hook family. 758 */ 759 if (!SLIST_EMPTY(&hfi->hfi_head) || !TAILQ_EMPTY(&hfi->hfi_nhead)) { 760 hfi->hfi_condemned = B_TRUE; 761 } else { 762 /* 763 * Although hfi_condemned = B_FALSE is implied from creation, 764 * putting a comment here inside the else upsets lint. 765 */ 766 hfi->hfi_condemned = B_FALSE; 767 } 768 769 CVW_ENTER_WRITE(&hfi->hfi_lock); 770 hook_wait_destroy(&hfi->hfi_waiter); 771 notifydone = hfi->hfi_shutdown; 772 hfi->hfi_shutdown = B_TRUE; 773 CVW_EXIT_WRITE(&hfi->hfi_lock); 774 775 CVW_EXIT_WRITE(&hks->hks_lock); 776 777 if (!notifydone) 778 hook_stack_notify_run(hks, hfi->hfi_family.hf_name, 779 HN_UNREGISTER); 780 781 hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE); 782 783 /* 784 * If we don't have to wait for anything else to disappear from this 785 * structure then we can free it up. 786 */ 787 if (!hfi->hfi_condemned) 788 hook_family_free(hfi, hks); 789 790 return (0); 791 } 792 793 794 /* 795 * Function: hook_family_free 796 * Returns: None 797 * Parameters: hfi(I) - internal family pointer 798 * 799 * Free alloc memory for family 800 */ 801 static void 802 hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks) 803 { 804 805 /* 806 * This lock gives us possession of the hks pointer after the 807 * SLIST_REMOVE, for which it is not needed, when hks_shutdown 808 * is checked and hook_stack_remove called. 809 */ 810 mutex_enter(&hook_stack_lock); 811 812 ASSERT(hfi != NULL); 813 814 if (hks != NULL) { 815 CVW_ENTER_WRITE(&hks->hks_lock); 816 /* Remove from family list */ 817 SLIST_REMOVE(&hks->hks_familylist, hfi, hook_family_int, 818 hfi_entry); 819 820 CVW_EXIT_WRITE(&hks->hks_lock); 821 } 822 823 /* Free name space */ 824 if (hfi->hfi_family.hf_name != NULL) { 825 kmem_free(hfi->hfi_family.hf_name, 826 strlen(hfi->hfi_family.hf_name) + 1); 827 } 828 829 /* Free container */ 830 kmem_free(hfi, sizeof (*hfi)); 831 832 if (hks->hks_shutdown == 2) 833 hook_stack_remove(hks); 834 835 mutex_exit(&hook_stack_lock); 836 } 837 838 /* 839 * Function: hook_family_shutdown 840 * Returns: int - 0 = Succ, Else = Fail 841 * Parameters: hfi(I) - internal family pointer 842 * 843 * As an alternative to removing a family, we may desire to just generate 844 * a series of callbacks to indicate that we will be going away in the 845 * future. The hfi_condemned flag isn't set because we aren't trying to 846 * remove the structure. 847 */ 848 int 849 hook_family_shutdown(hook_family_int_t *hfi) 850 { 851 hook_stack_t *hks; 852 boolean_t notifydone; 853 854 ASSERT(hfi != NULL); 855 hks = hfi->hfi_stack; 856 857 CVW_ENTER_WRITE(&hks->hks_lock); 858 859 if (hook_wait_setflag(&hks->hks_waiter, FWF_WAIT_MASK, 860 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) { 861 /* 862 * If we're trying to destroy the hook_stack_t... 863 */ 864 CVW_EXIT_WRITE(&hks->hks_lock); 865 return (ENXIO); 866 } 867 868 CVW_ENTER_WRITE(&hfi->hfi_lock); 869 notifydone = hfi->hfi_shutdown; 870 hfi->hfi_shutdown = B_TRUE; 871 CVW_EXIT_WRITE(&hfi->hfi_lock); 872 CVW_EXIT_WRITE(&hks->hks_lock); 873 874 if (!notifydone) 875 hook_stack_notify_run(hks, hfi->hfi_family.hf_name, 876 HN_UNREGISTER); 877 878 hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE); 879 880 return (0); 881 } 882 883 /* 884 * Function: hook_family_copy 885 * Returns: internal family pointer - NULL = Failed 886 * Parameters: src(I) - family pointer 887 * 888 * Allocate internal family block and duplicate incoming family 889 * No locks should be held across this function as it may sleep. 890 */ 891 static hook_family_int_t * 892 hook_family_copy(hook_family_t *src) 893 { 894 hook_family_int_t *new; 895 hook_family_t *dst; 896 897 ASSERT(src != NULL); 898 ASSERT(src->hf_name != NULL); 899 900 new = (hook_family_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP); 901 902 /* Copy body */ 903 dst = &new->hfi_family; 904 *dst = *src; 905 906 SLIST_INIT(&new->hfi_head); 907 TAILQ_INIT(&new->hfi_nhead); 908 909 /* Copy name */ 910 dst->hf_name = (char *)kmem_alloc(strlen(src->hf_name) + 1, KM_SLEEP); 911 (void) strcpy(dst->hf_name, src->hf_name); 912 913 return (new); 914 } 915 916 /* 917 * Function: hook_family_find 918 * Returns: internal family pointer - NULL = Not match 919 * Parameters: family(I) - family name string 920 * 921 * Search family list with family name 922 * A lock on hfi_lock must be held when called. 923 */ 924 static hook_family_int_t * 925 hook_family_find(char *family, hook_stack_t *hks) 926 { 927 hook_family_int_t *hfi = NULL; 928 929 ASSERT(family != NULL); 930 931 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) { 932 if (strcmp(hfi->hfi_family.hf_name, family) == 0) 933 break; 934 } 935 return (hfi); 936 } 937 938 /* 939 * Function: hook_family_notify_register 940 * Returns: 0 = success, else failure 941 * Parameters: hfi(I) - hook family 942 * callback(I) - function to be called 943 * arg(I) - arg to provide callback when it is called 944 * 945 * So long as this hook stack isn't being shut down, register a new 946 * callback to be activated each time a new event is added to this 947 * family. 948 * 949 * To call this function we must have an active handle in use on the family, 950 * so if we take this into account, then neither the hook_family_int_t nor 951 * the hook_stack_t that owns it can disappear. We have to put some trust 952 * in the callers to be properly synchronised... 953 * 954 * Holding hks_lock is required to provide synchronisation for hks_shutdown. 955 */ 956 int 957 hook_family_notify_register(hook_family_int_t *hfi, 958 hook_notify_fn_t callback, void *arg) 959 { 960 hook_stack_t *hks; 961 int error; 962 963 hks = hfi->hfi_stack; 964 965 CVW_ENTER_READ(&hks->hks_lock); 966 CVW_ENTER_WRITE(&hfi->hfi_lock); 967 968 if ((hfi->hfi_stack->hks_shutdown != 0) || 969 hfi->hfi_condemned || hfi->hfi_shutdown) { 970 CVW_EXIT_WRITE(&hfi->hfi_lock); 971 CVW_EXIT_READ(&hks->hks_lock); 972 return (ESHUTDOWN); 973 } 974 975 error = hook_notify_register(&hfi->hfi_lock, &hfi->hfi_nhead, 976 callback, arg); 977 978 CVW_EXIT_WRITE(&hfi->hfi_lock); 979 CVW_EXIT_READ(&hks->hks_lock); 980 981 return (error); 982 } 983 984 /* 985 * Function: hook_family_notify_unregister 986 * Returns: 0 = success, else failure 987 * Parameters: hfi(I) - hook family 988 * callback(I) - function to be called 989 * 990 * Remove a callback from the list of those executed when a new event is 991 * added to a hook family. 992 */ 993 int 994 hook_family_notify_unregister(hook_family_int_t *hfi, 995 hook_notify_fn_t callback) 996 { 997 boolean_t free_family; 998 int error; 999 1000 CVW_ENTER_WRITE(&hfi->hfi_lock); 1001 1002 error = hook_notify_unregister(&hfi->hfi_lock, &hfi->hfi_nhead, 1003 callback); 1004 1005 /* 1006 * If hook_family_remove has been called but the structure was still 1007 * "busy" ... but we might have just made it "unbusy"... 1008 */ 1009 if ((error == 0) && hfi->hfi_condemned && 1010 SLIST_EMPTY(&hfi->hfi_head) && TAILQ_EMPTY(&hfi->hfi_nhead)) { 1011 free_family = B_TRUE; 1012 } else { 1013 free_family = B_FALSE; 1014 } 1015 1016 CVW_EXIT_WRITE(&hfi->hfi_lock); 1017 1018 if (free_family) 1019 hook_family_free(hfi, hfi->hfi_stack); 1020 1021 return (error); 1022 } 1023 1024 /* 1025 * Function: hook_event_add 1026 * Returns: internal event pointer - NULL = Fail 1027 * Parameters: hfi(I) - internal family pointer 1028 * he(I) - event pointer 1029 * 1030 * Add new event to event list on specific family. 1031 * This function can fail to return successfully if (1) it cannot allocate 1032 * enough memory for its own internal data structures, (2) the event has 1033 * already been registered (for any hook family.) 1034 */ 1035 hook_event_int_t * 1036 hook_event_add(hook_family_int_t *hfi, hook_event_t *he) 1037 { 1038 hook_event_int_t *hei, *new; 1039 hook_stack_t *hks; 1040 1041 ASSERT(hfi != NULL); 1042 ASSERT(he != NULL); 1043 ASSERT(he->he_name != NULL); 1044 1045 new = hook_event_copy(he); 1046 if (new == NULL) 1047 return (NULL); 1048 1049 hks = hfi->hfi_stack; 1050 CVW_ENTER_READ(&hks->hks_lock); 1051 1052 hks = hfi->hfi_stack; 1053 if (hks->hks_shutdown != 0) { 1054 CVW_EXIT_READ(&hks->hks_lock); 1055 hook_event_free(new, NULL); 1056 return (NULL); 1057 } 1058 1059 /* Check whether this event pointer is already registered */ 1060 hei = hook_event_checkdup(he, hks); 1061 if (hei != NULL) { 1062 CVW_EXIT_READ(&hks->hks_lock); 1063 hook_event_free(new, NULL); 1064 return (NULL); 1065 } 1066 1067 CVW_ENTER_WRITE(&hfi->hfi_lock); 1068 1069 if (hfi->hfi_condemned || hfi->hfi_shutdown) { 1070 CVW_EXIT_WRITE(&hfi->hfi_lock); 1071 CVW_EXIT_READ(&hks->hks_lock); 1072 hook_event_free(new, NULL); 1073 return (NULL); 1074 } 1075 1076 if (hook_wait_setflag(&hfi->hfi_waiter, FWF_WAIT_MASK, 1077 FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) { 1078 CVW_EXIT_WRITE(&hfi->hfi_lock); 1079 CVW_EXIT_READ(&hks->hks_lock); 1080 hook_event_free(new, NULL); 1081 return (NULL); 1082 } 1083 1084 TAILQ_INIT(&new->hei_nhead); 1085 1086 hook_event_init_kstats(hfi, new); 1087 hook_wait_init(&new->hei_waiter, &new->hei_lock); 1088 1089 /* Add to event list head */ 1090 SLIST_INSERT_HEAD(&hfi->hfi_head, new, hei_entry); 1091 1092 CVW_EXIT_WRITE(&hfi->hfi_lock); 1093 1094 CVW_EXIT_READ(&hks->hks_lock); 1095 1096 hook_notify_run(&hfi->hfi_nhead, 1097 hfi->hfi_family.hf_name, NULL, he->he_name, HN_REGISTER); 1098 1099 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_ADD_ACTIVE); 1100 1101 return (new); 1102 } 1103 1104 /* 1105 * Function: hook_event_init_kstats 1106 * Returns: None 1107 * Parameters: hfi(I) - pointer to the family that owns this event. 1108 * hei(I) - pointer to the hook event that needs some kstats. 1109 * 1110 * Create a set of kstats that relate to each event registered with 1111 * the hook framework. A counter is kept for each time the event is 1112 * activated and for each time a hook is added or removed. As the 1113 * kstats just count the events as they happen, the total number of 1114 * hooks registered must be obtained by subtractived removed from added. 1115 */ 1116 static void 1117 hook_event_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei) 1118 { 1119 hook_event_kstat_t template = { 1120 { "hooksAdded", KSTAT_DATA_UINT64 }, 1121 { "hooksRemoved", KSTAT_DATA_UINT64 }, 1122 { "events", KSTAT_DATA_UINT64 } 1123 }; 1124 hook_stack_t *hks; 1125 1126 hks = hfi->hfi_stack; 1127 hei->hei_kstatp = kstat_create_netstack(hfi->hfi_family.hf_name, 0, 1128 hei->hei_event->he_name, "hook_event", KSTAT_TYPE_NAMED, 1129 sizeof (hei->hei_kstats) / sizeof (kstat_named_t), 1130 KSTAT_FLAG_VIRTUAL, hks->hks_netstackid); 1131 1132 bcopy((char *)&template, &hei->hei_kstats, sizeof (template)); 1133 1134 if (hei->hei_kstatp != NULL) { 1135 hei->hei_kstatp->ks_data = (void *)&hei->hei_kstats; 1136 hei->hei_kstatp->ks_private = 1137 (void *)(uintptr_t)hks->hks_netstackid; 1138 1139 kstat_install(hei->hei_kstatp); 1140 } 1141 } 1142 1143 /* 1144 * Function: hook_event_remove 1145 * Returns: int - 0 = Succ, Else = Fail 1146 * Parameters: hfi(I) - internal family pointer 1147 * he(I) - event pointer 1148 * 1149 * Remove event from event list on specific family 1150 * 1151 * This function assumes that the caller has received a pointer to a the 1152 * hook_family_int_t via a call to net_protocol_lookup or net_protocol_unreg'. 1153 * This the hook_family_int_t is guaranteed to be around for the life of this 1154 * call, unless the caller has decided to call net_protocol_release or 1155 * net_protocol_unregister before calling net_event_unregister - an error. 1156 */ 1157 int 1158 hook_event_remove(hook_family_int_t *hfi, hook_event_t *he) 1159 { 1160 boolean_t free_family; 1161 hook_event_int_t *hei; 1162 boolean_t notifydone; 1163 1164 ASSERT(hfi != NULL); 1165 ASSERT(he != NULL); 1166 1167 CVW_ENTER_WRITE(&hfi->hfi_lock); 1168 1169 /* 1170 * Set the flag so that we can call hook_event_notify_run without 1171 * holding any locks but at the same time prevent other changes to 1172 * the event at the same time. 1173 */ 1174 if (hook_wait_setflag(&hfi->hfi_waiter, FWF_WAIT_MASK, 1175 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) { 1176 CVW_EXIT_WRITE(&hfi->hfi_lock); 1177 return (ENXIO); 1178 } 1179 1180 hei = hook_event_find(hfi, he->he_name); 1181 if (hei == NULL) { 1182 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE); 1183 CVW_EXIT_WRITE(&hfi->hfi_lock); 1184 return (ESRCH); 1185 } 1186 1187 free_family = B_FALSE; 1188 1189 CVW_ENTER_WRITE(&hei->hei_lock); 1190 /* 1191 * The hei_shutdown flag is used to indicate whether or not we have 1192 * done a shutdown and thus already walked through the notify list. 1193 */ 1194 notifydone = hei->hei_shutdown; 1195 hei->hei_shutdown = B_TRUE; 1196 /* 1197 * If there are any hooks still registered for this event or 1198 * there are any notifiers registered, return an error indicating 1199 * that the event is still busy. 1200 */ 1201 if (!TAILQ_EMPTY(&hei->hei_head) || !TAILQ_EMPTY(&hei->hei_nhead)) { 1202 hei->hei_condemned = B_TRUE; 1203 CVW_EXIT_WRITE(&hei->hei_lock); 1204 } else { 1205 /* hei_condemned = B_FALSE is implied from creation */ 1206 /* 1207 * Even though we know the notify list is empty, we call 1208 * hook_wait_destroy here to synchronise wait removing a 1209 * hook from an event. 1210 */ 1211 hook_wait_destroy(&hei->hei_waiter); 1212 1213 CVW_EXIT_WRITE(&hei->hei_lock); 1214 1215 if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) && 1216 TAILQ_EMPTY(&hfi->hfi_nhead)) 1217 free_family = B_TRUE; 1218 } 1219 1220 CVW_EXIT_WRITE(&hfi->hfi_lock); 1221 1222 if (!notifydone) 1223 hook_notify_run(&hfi->hfi_nhead, 1224 hfi->hfi_family.hf_name, NULL, he->he_name, HN_UNREGISTER); 1225 1226 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE); 1227 1228 if (!hei->hei_condemned) { 1229 hook_event_free(hei, hfi); 1230 if (free_family) 1231 hook_family_free(hfi, hfi->hfi_stack); 1232 } 1233 1234 return (0); 1235 } 1236 1237 /* 1238 * Function: hook_event_shutdown 1239 * Returns: int - 0 = Succ, Else = Fail 1240 * Parameters: hfi(I) - internal family pointer 1241 * he(I) - event pointer 1242 * 1243 * As with hook_family_shutdown, we want to generate the notify callbacks 1244 * as if the event was being removed but not actually do the remove. 1245 */ 1246 int 1247 hook_event_shutdown(hook_family_int_t *hfi, hook_event_t *he) 1248 { 1249 hook_event_int_t *hei; 1250 boolean_t notifydone; 1251 1252 ASSERT(hfi != NULL); 1253 ASSERT(he != NULL); 1254 1255 CVW_ENTER_WRITE(&hfi->hfi_lock); 1256 1257 /* 1258 * Set the flag so that we can call hook_event_notify_run without 1259 * holding any locks but at the same time prevent other changes to 1260 * the event at the same time. 1261 */ 1262 if (hook_wait_setflag(&hfi->hfi_waiter, FWF_WAIT_MASK, 1263 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) { 1264 CVW_EXIT_WRITE(&hfi->hfi_lock); 1265 return (ENXIO); 1266 } 1267 1268 hei = hook_event_find(hfi, he->he_name); 1269 if (hei == NULL) { 1270 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE); 1271 CVW_EXIT_WRITE(&hfi->hfi_lock); 1272 return (ESRCH); 1273 } 1274 1275 CVW_ENTER_WRITE(&hei->hei_lock); 1276 notifydone = hei->hei_shutdown; 1277 hei->hei_shutdown = B_TRUE; 1278 CVW_EXIT_WRITE(&hei->hei_lock); 1279 1280 CVW_EXIT_WRITE(&hfi->hfi_lock); 1281 1282 if (!notifydone) 1283 hook_notify_run(&hfi->hfi_nhead, 1284 hfi->hfi_family.hf_name, NULL, he->he_name, HN_UNREGISTER); 1285 1286 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE); 1287 1288 return (0); 1289 } 1290 1291 /* 1292 * Function: hook_event_free 1293 * Returns: None 1294 * Parameters: hei(I) - internal event pointer 1295 * 1296 * Free alloc memory for event 1297 */ 1298 static void 1299 hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi) 1300 { 1301 boolean_t free_family; 1302 1303 ASSERT(hei != NULL); 1304 1305 if (hfi != NULL) { 1306 CVW_ENTER_WRITE(&hfi->hfi_lock); 1307 /* 1308 * Remove the event from the hook family's list. 1309 */ 1310 SLIST_REMOVE(&hfi->hfi_head, hei, hook_event_int, hei_entry); 1311 if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) && 1312 TAILQ_EMPTY(&hfi->hfi_nhead)) { 1313 free_family = B_TRUE; 1314 } else { 1315 free_family = B_FALSE; 1316 } 1317 CVW_EXIT_WRITE(&hfi->hfi_lock); 1318 } 1319 1320 if (hei->hei_kstatp != NULL) { 1321 ASSERT(hfi != NULL); 1322 1323 kstat_delete_netstack(hei->hei_kstatp, 1324 hfi->hfi_stack->hks_netstackid); 1325 hei->hei_kstatp = NULL; 1326 } 1327 1328 /* Free container */ 1329 kmem_free(hei, sizeof (*hei)); 1330 1331 if (free_family) 1332 hook_family_free(hfi, hfi->hfi_stack); 1333 } 1334 1335 /* 1336 * Function: hook_event_checkdup 1337 * Returns: internal event pointer - NULL = Not match 1338 * Parameters: he(I) - event pointer 1339 * 1340 * Search all of the hook families to see if the event being passed in 1341 * has already been associated with one. 1342 */ 1343 static hook_event_int_t * 1344 hook_event_checkdup(hook_event_t *he, hook_stack_t *hks) 1345 { 1346 hook_family_int_t *hfi; 1347 hook_event_int_t *hei; 1348 1349 ASSERT(he != NULL); 1350 1351 CVW_ENTER_READ(&hks->hks_lock); 1352 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) { 1353 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) { 1354 if (hei->hei_event == he) { 1355 CVW_EXIT_READ(&hks->hks_lock); 1356 return (hei); 1357 } 1358 } 1359 } 1360 CVW_EXIT_READ(&hks->hks_lock); 1361 1362 return (NULL); 1363 } 1364 1365 /* 1366 * Function: hook_event_copy 1367 * Returns: internal event pointer - NULL = Failed 1368 * Parameters: src(I) - event pointer 1369 * 1370 * Allocate internal event block and duplicate incoming event 1371 * No locks should be held across this function as it may sleep. 1372 */ 1373 static hook_event_int_t * 1374 hook_event_copy(hook_event_t *src) 1375 { 1376 hook_event_int_t *new; 1377 1378 ASSERT(src != NULL); 1379 ASSERT(src->he_name != NULL); 1380 1381 new = (hook_event_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP); 1382 1383 /* Copy body */ 1384 TAILQ_INIT(&new->hei_head); 1385 new->hei_event = src; 1386 1387 return (new); 1388 } 1389 1390 /* 1391 * Function: hook_event_find 1392 * Returns: internal event pointer - NULL = Not match 1393 * Parameters: hfi(I) - internal family pointer 1394 * event(I) - event name string 1395 * 1396 * Search event list with event name 1397 * A lock on hfi->hfi_lock must be held when called. 1398 */ 1399 static hook_event_int_t * 1400 hook_event_find(hook_family_int_t *hfi, char *event) 1401 { 1402 hook_event_int_t *hei = NULL; 1403 1404 ASSERT(hfi != NULL); 1405 ASSERT(event != NULL); 1406 1407 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) { 1408 if ((strcmp(hei->hei_event->he_name, event) == 0) && 1409 ((hei->hei_waiter.fw_flags & FWF_UNSAFE) == 0)) 1410 break; 1411 } 1412 return (hei); 1413 } 1414 1415 /* 1416 * Function: hook_event_notify_register 1417 * Returns: 0 = success, else failure 1418 * Parameters: hfi(I) - hook family 1419 * event(I) - name of the event 1420 * callback(I) - function to be called 1421 * arg(I) - arg to provide callback when it is called 1422 * 1423 * Adds a new callback to the event named by "event" (we must find it) 1424 * that will be executed each time a new hook is added to the event. 1425 * Of course, if the stack is being shut down, this call should fail. 1426 */ 1427 int 1428 hook_event_notify_register(hook_family_int_t *hfi, char *event, 1429 hook_notify_fn_t callback, void *arg) 1430 { 1431 hook_event_int_t *hei; 1432 hook_stack_t *hks; 1433 int error; 1434 1435 hks = hfi->hfi_stack; 1436 CVW_ENTER_READ(&hks->hks_lock); 1437 if (hks->hks_shutdown != 0) { 1438 CVW_EXIT_READ(&hks->hks_lock); 1439 return (ESHUTDOWN); 1440 } 1441 1442 CVW_ENTER_READ(&hfi->hfi_lock); 1443 1444 if (hfi->hfi_condemned || hfi->hfi_shutdown) { 1445 CVW_EXIT_READ(&hfi->hfi_lock); 1446 CVW_EXIT_READ(&hks->hks_lock); 1447 return (ESHUTDOWN); 1448 } 1449 1450 hei = hook_event_find(hfi, event); 1451 if (hei == NULL) { 1452 CVW_EXIT_READ(&hfi->hfi_lock); 1453 CVW_EXIT_READ(&hks->hks_lock); 1454 return (ESRCH); 1455 } 1456 1457 /* 1458 * Grabbing the read lock on hei_lock is only so that we can 1459 * synchronise access to hei_condemned. 1460 */ 1461 CVW_ENTER_WRITE(&hei->hei_lock); 1462 if (hei->hei_condemned || hei->hei_shutdown) { 1463 CVW_EXIT_WRITE(&hei->hei_lock); 1464 CVW_EXIT_READ(&hfi->hfi_lock); 1465 CVW_EXIT_READ(&hks->hks_lock); 1466 return (ESHUTDOWN); 1467 } 1468 1469 error = hook_notify_register(&hei->hei_lock, &hei->hei_nhead, 1470 callback, arg); 1471 1472 CVW_EXIT_WRITE(&hei->hei_lock); 1473 CVW_EXIT_READ(&hfi->hfi_lock); 1474 CVW_EXIT_READ(&hks->hks_lock); 1475 1476 return (error); 1477 } 1478 1479 /* 1480 * Function: hook_event_notify_unregister 1481 * Returns: 0 = success, else failure 1482 * Parameters: hfi(I) - hook family 1483 * event(I) - name of the event 1484 * callback(I) - function to be called 1485 * 1486 * Remove the given callback from the named event's list of functions 1487 * to call when a hook is added or removed. 1488 */ 1489 int 1490 hook_event_notify_unregister(hook_family_int_t *hfi, char *event, 1491 hook_notify_fn_t callback) 1492 { 1493 hook_event_int_t *hei; 1494 boolean_t free_event; 1495 int error; 1496 1497 CVW_ENTER_READ(&hfi->hfi_lock); 1498 1499 hei = hook_event_find(hfi, event); 1500 if (hei == NULL) { 1501 CVW_EXIT_READ(&hfi->hfi_lock); 1502 return (ESRCH); 1503 } 1504 1505 CVW_ENTER_WRITE(&hei->hei_lock); 1506 1507 error = hook_notify_unregister(&hei->hei_lock, &hei->hei_nhead, 1508 callback); 1509 1510 /* 1511 * hei_condemned has been set if someone tried to remove the 1512 * event but couldn't because there were still things attached to 1513 * it. Now that we've done a successful remove, if it is now empty 1514 * then by all rights we should be free'ing it too. Note that the 1515 * expectation is that only the caller of hook_event_add will ever 1516 * call hook_event_remove. 1517 */ 1518 if ((error == 0) && hei->hei_condemned && 1519 TAILQ_EMPTY(&hei->hei_head) && TAILQ_EMPTY(&hei->hei_nhead)) { 1520 free_event = B_TRUE; 1521 } else { 1522 free_event = B_FALSE; 1523 } 1524 1525 CVW_EXIT_WRITE(&hei->hei_lock); 1526 CVW_EXIT_READ(&hfi->hfi_lock); 1527 1528 if (free_event) { 1529 /* 1530 * It is safe to pass in hfi here, without a lock, because 1531 * our structure (hei) is still on one of its lists and thus 1532 * it won't be able to disappear yet... 1533 */ 1534 hook_event_free(hei, hfi); 1535 } 1536 1537 return (error); 1538 } 1539 1540 /* 1541 * Function: hook_event_notify_run 1542 * Returns: None 1543 * Parameters: nrun(I) - pointer to the list of callbacks to execute 1544 * hfi(I) - hook stack pointer to execute callbacks for 1545 * name(I) - name of a hook family 1546 * cmd(I) - either HN_UNREGISTER or HN_REGISTER 1547 * 1548 * Execute all of the callbacks registered for this event. 1549 */ 1550 static void 1551 hook_event_notify_run(hook_event_int_t *hei, hook_family_int_t *hfi, 1552 char *event, char *name, hook_notify_cmd_t cmd) 1553 { 1554 1555 hook_notify_run(&hei->hei_nhead, hfi->hfi_family.hf_name, 1556 event, name, cmd); 1557 } 1558 1559 /* 1560 * Function: hook_register 1561 * Returns: int- 0 = Succ, Else = Fail 1562 * Parameters: hfi(I) - internal family pointer 1563 * event(I) - event name string 1564 * h(I) - hook pointer 1565 * 1566 * Add new hook to hook list on the specified family and event. 1567 */ 1568 int 1569 hook_register(hook_family_int_t *hfi, char *event, hook_t *h) 1570 { 1571 hook_event_int_t *hei; 1572 hook_int_t *hi, *new; 1573 int error; 1574 1575 ASSERT(hfi != NULL); 1576 ASSERT(event != NULL); 1577 ASSERT(h != NULL); 1578 1579 if (hfi->hfi_stack->hks_shutdown) 1580 return (NULL); 1581 1582 /* Alloc hook_int_t and copy hook */ 1583 new = hook_copy(h); 1584 if (new == NULL) 1585 return (ENOMEM); 1586 1587 /* 1588 * Since hook add/remove only impact event, so it is unnecessary 1589 * to hold global family write lock. Just get read lock here to 1590 * ensure event will not be removed when doing hooks operation 1591 */ 1592 CVW_ENTER_WRITE(&hfi->hfi_lock); 1593 1594 hei = hook_event_find(hfi, event); 1595 if (hei == NULL) { 1596 CVW_EXIT_WRITE(&hfi->hfi_lock); 1597 hook_int_free(new, hfi->hfi_stack->hks_netstackid); 1598 return (ENXIO); 1599 } 1600 1601 CVW_ENTER_WRITE(&hei->hei_lock); 1602 1603 /* 1604 * If we've run either the remove() or shutdown(), do not allow any 1605 * more hooks to be added to this event. 1606 */ 1607 if (hei->hei_shutdown) { 1608 error = ESHUTDOWN; 1609 goto bad_add; 1610 } 1611 1612 hi = hook_find(hei, h); 1613 if (hi != NULL) { 1614 error = EEXIST; 1615 goto bad_add; 1616 } 1617 1618 if (hook_wait_setflag(&hei->hei_waiter, FWF_WAIT_MASK, 1619 FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) { 1620 error = ENOENT; 1621 bad_add: 1622 CVW_EXIT_WRITE(&hei->hei_lock); 1623 CVW_EXIT_WRITE(&hfi->hfi_lock); 1624 hook_int_free(new, hfi->hfi_stack->hks_netstackid); 1625 return (error); 1626 } 1627 1628 /* Add to hook list head */ 1629 error = hook_insert(&hei->hei_head, new); 1630 if (error == 0) { 1631 hei->hei_event->he_interested = B_TRUE; 1632 hei->hei_kstats.hooks_added.value.ui64++; 1633 1634 hook_init_kstats(hfi, hei, new); 1635 } 1636 1637 CVW_EXIT_WRITE(&hei->hei_lock); 1638 CVW_EXIT_WRITE(&hfi->hfi_lock); 1639 1640 /* 1641 * Note that the name string passed through to the notify callbacks 1642 * is from the original hook being registered, not the copy being 1643 * inserted. 1644 */ 1645 if (error == 0) { 1646 hook_event_notify_run(hei, hfi, event, h->h_name, HN_REGISTER); 1647 hook_wait_unsetflag(&hei->hei_waiter, FWF_ADD_ACTIVE); 1648 } 1649 1650 return (error); 1651 } 1652 1653 /* 1654 * Function: hook_insert 1655 * Returns: int- 0 = Succ, else = Fail 1656 * Parameters: head(I) - pointer to hook list to insert hook onto 1657 * new(I) - pointer to hook to be inserted 1658 * 1659 * Try to insert the hook onto the list of hooks according to the hints 1660 * given in the hook to be inserted and those that already exist on the 1661 * list. For now, the implementation permits only a single hook to be 1662 * either first or last and names provided with before or after are only 1663 * loosely coupled with the action. 1664 */ 1665 static int 1666 hook_insert(hook_int_head_t *head, hook_int_t *new) 1667 { 1668 hook_int_t *before; 1669 hook_int_t *hi; 1670 hook_t *hih; 1671 hook_t *h = &new->hi_hook; 1672 1673 switch (new->hi_hook.h_hint) { 1674 case HH_NONE : 1675 before = NULL; 1676 /* 1677 * If there is no hint present (or not one that can be 1678 * satisfied now) then try to at least respect the wishes 1679 * of those that want to be last. If there are none wanting 1680 * to be last then add the new hook to the tail of the 1681 * list - this means we keep any wanting to be first 1682 * happy without having to search for HH_FIRST. 1683 */ 1684 TAILQ_FOREACH(hi, head, hi_entry) { 1685 hih = &hi->hi_hook; 1686 if ((hih->h_hint == HH_AFTER) && 1687 (strcmp(h->h_name, 1688 (char *)hih->h_hintvalue) == 0)) { 1689 TAILQ_INSERT_BEFORE(hi, new, hi_entry); 1690 return (0); 1691 } 1692 if ((hih->h_hint == HH_BEFORE) && (before == NULL) && 1693 (strcmp(h->h_name, 1694 (char *)hih->h_hintvalue) == 0)) { 1695 before = hi; 1696 } 1697 } 1698 if (before != NULL) { 1699 TAILQ_INSERT_AFTER(head, before, new, hi_entry); 1700 return (0); 1701 } 1702 hook_insert_plain(head, new); 1703 break; 1704 1705 case HH_FIRST : 1706 hi = TAILQ_FIRST(head); 1707 if ((hi != NULL) && (hi->hi_hook.h_hint == HH_FIRST)) 1708 return (EBUSY); 1709 TAILQ_INSERT_HEAD(head, new, hi_entry); 1710 break; 1711 1712 case HH_LAST : 1713 hi = TAILQ_LAST(head, hook_int_head); 1714 if ((hi != NULL) && (hi->hi_hook.h_hint == HH_LAST)) 1715 return (EBUSY); 1716 TAILQ_INSERT_TAIL(head, new, hi_entry); 1717 break; 1718 1719 case HH_BEFORE : 1720 hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue); 1721 if (hi == NULL) 1722 return (hook_insert_afterbefore(head, new)); 1723 1724 if (hi->hi_hook.h_hint == HH_FIRST) 1725 return (EBUSY); 1726 1727 TAILQ_INSERT_BEFORE(hi, new, hi_entry); 1728 break; 1729 1730 case HH_AFTER : 1731 hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue); 1732 if (hi == NULL) 1733 return (hook_insert_afterbefore(head, new)); 1734 1735 if (hi->hi_hook.h_hint == HH_LAST) 1736 return (EBUSY); 1737 1738 TAILQ_INSERT_AFTER(head, hi, new, hi_entry); 1739 break; 1740 1741 default : 1742 return (EINVAL); 1743 } 1744 1745 return (0); 1746 } 1747 1748 /* 1749 * Function: hook_insert_plain 1750 * Returns: int- 0 = success, else = failure 1751 * Parameters: head(I) - pointer to hook list to insert hook onto 1752 * new(I) - pointer to hook to be inserted 1753 * 1754 * Insert a hook such that it respects the wishes of those that want to 1755 * be last. If there are none wanting to be last then add the new hook 1756 * to the tail of the list - this means we keep any wanting to be first 1757 * happy without having to search for HH_FIRST. 1758 */ 1759 static void 1760 hook_insert_plain(hook_int_head_t *head, hook_int_t *new) 1761 { 1762 hook_int_t *hi; 1763 1764 hi = TAILQ_FIRST(head); 1765 if (hi != NULL) { 1766 if (hi->hi_hook.h_hint == HH_LAST) { 1767 TAILQ_INSERT_BEFORE(hi, new, hi_entry); 1768 } else { 1769 TAILQ_INSERT_TAIL(head, new, hi_entry); 1770 } 1771 } else { 1772 TAILQ_INSERT_TAIL(head, new, hi_entry); 1773 } 1774 } 1775 1776 /* 1777 * Function: hook_insert_afterbefore 1778 * Returns: int- 0 = success, else = failure 1779 * Parameters: head(I) - pointer to hook list to insert hook onto 1780 * new(I) - pointer to hook to be inserted 1781 * 1782 * Simple insertion of a hook specifying a HH_BEFORE or HH_AFTER was not 1783 * possible, so now we need to be more careful. The first pass is to go 1784 * through the list and look for any other hooks that also specify the 1785 * same hint name as the new one. The object of this exercise is to make 1786 * sure that hooks with HH_BEFORE always appear on the list before those 1787 * with HH_AFTER so that when said hook arrives, it can be placed in the 1788 * middle of the BEFOREs and AFTERs. If this condition does not arise, 1789 * just use hook_insert_plain() to try and insert the hook somewhere that 1790 * is innocuous to existing efforts. 1791 */ 1792 static int 1793 hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new) 1794 { 1795 hook_int_t *hi; 1796 hook_t *nh; 1797 hook_t *h; 1798 1799 nh = &new->hi_hook; 1800 ASSERT(new->hi_hook.h_hint != HH_NONE); 1801 ASSERT(new->hi_hook.h_hint != HH_LAST); 1802 ASSERT(new->hi_hook.h_hint != HH_FIRST); 1803 1804 /* 1805 * First, look through the list to see if there are any other 1806 * before's or after's that have a matching hint name. 1807 */ 1808 TAILQ_FOREACH(hi, head, hi_entry) { 1809 h = &hi->hi_hook; 1810 switch (h->h_hint) { 1811 case HH_FIRST : 1812 case HH_LAST : 1813 case HH_NONE : 1814 break; 1815 case HH_BEFORE : 1816 if ((nh->h_hint == HH_BEFORE) && 1817 (strcmp((char *)h->h_hintvalue, 1818 (char *)nh->h_hintvalue) == 0)) { 1819 TAILQ_INSERT_AFTER(head, hi, new, hi_entry); 1820 return (0); 1821 } 1822 if ((nh->h_hint == HH_AFTER) && 1823 (strcmp((char *)h->h_hintvalue, 1824 (char *)nh->h_hintvalue) == 0)) { 1825 TAILQ_INSERT_BEFORE(hi, new, hi_entry); 1826 return (0); 1827 } 1828 break; 1829 case HH_AFTER : 1830 if ((nh->h_hint == HH_AFTER) && 1831 (strcmp((char *)h->h_hintvalue, 1832 (char *)nh->h_hintvalue) == 0)) { 1833 TAILQ_INSERT_AFTER(head, hi, new, hi_entry); 1834 return (0); 1835 } 1836 if ((nh->h_hint == HH_BEFORE) && 1837 (strcmp((char *)h->h_hintvalue, 1838 (char *)nh->h_hintvalue) == 0)) { 1839 TAILQ_INSERT_BEFORE(hi, new, hi_entry); 1840 return (0); 1841 } 1842 break; 1843 } 1844 } 1845 1846 hook_insert_plain(head, new); 1847 1848 return (0); 1849 } 1850 1851 /* 1852 * Function: hook_unregister 1853 * Returns: int - 0 = Succ, Else = Fail 1854 * Parameters: hfi(I) - internal family pointer 1855 * event(I) - event name string 1856 * h(I) - hook pointer 1857 * 1858 * Remove hook from hook list on specific family, event 1859 */ 1860 int 1861 hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h) 1862 { 1863 hook_event_int_t *hei; 1864 hook_int_t *hi; 1865 boolean_t free_event; 1866 1867 ASSERT(hfi != NULL); 1868 ASSERT(h != NULL); 1869 1870 CVW_ENTER_WRITE(&hfi->hfi_lock); 1871 1872 hei = hook_event_find(hfi, event); 1873 if (hei == NULL) { 1874 CVW_EXIT_WRITE(&hfi->hfi_lock); 1875 return (ENXIO); 1876 } 1877 1878 /* Hold write lock for event */ 1879 CVW_ENTER_WRITE(&hei->hei_lock); 1880 1881 hi = hook_find(hei, h); 1882 if (hi == NULL) { 1883 CVW_EXIT_WRITE(&hei->hei_lock); 1884 CVW_EXIT_WRITE(&hfi->hfi_lock); 1885 return (ENXIO); 1886 } 1887 1888 if (hook_wait_setflag(&hei->hei_waiter, FWF_WAIT_MASK, 1889 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) { 1890 CVW_EXIT_WRITE(&hei->hei_lock); 1891 CVW_EXIT_WRITE(&hfi->hfi_lock); 1892 return (ENOENT); 1893 } 1894 1895 /* Remove from hook list */ 1896 TAILQ_REMOVE(&hei->hei_head, hi, hi_entry); 1897 1898 free_event = B_FALSE; 1899 if (TAILQ_EMPTY(&hei->hei_head)) { 1900 hei->hei_event->he_interested = B_FALSE; 1901 /* 1902 * If the delete pending flag has been set and there are 1903 * no notifiers on the event (and we've removed the last 1904 * hook) then we need to free this event after we're done. 1905 */ 1906 if (hei->hei_condemned && TAILQ_EMPTY(&hei->hei_nhead)) 1907 free_event = B_TRUE; 1908 } 1909 hei->hei_kstats.hooks_removed.value.ui64++; 1910 1911 CVW_EXIT_WRITE(&hei->hei_lock); 1912 CVW_EXIT_WRITE(&hfi->hfi_lock); 1913 /* 1914 * While the FWF_DEL_ACTIVE flag is set, the hook_event_int_t 1915 * will not be free'd and thus the hook_family_int_t wil not 1916 * be free'd either. 1917 */ 1918 hook_event_notify_run(hei, hfi, event, h->h_name, HN_UNREGISTER); 1919 hook_wait_unsetflag(&hei->hei_waiter, FWF_DEL_ACTIVE); 1920 1921 hook_int_free(hi, hfi->hfi_stack->hks_netstackid); 1922 1923 if (free_event) 1924 hook_event_free(hei, hfi); 1925 1926 return (0); 1927 } 1928 1929 /* 1930 * Function: hook_find_byname 1931 * Returns: internal hook pointer - NULL = Not match 1932 * Parameters: hei(I) - internal event pointer 1933 * name(I)- hook name 1934 * 1935 * Search an event's list of hooks to see if there is a hook present that 1936 * has a matching name to the one being looked for. 1937 */ 1938 static hook_int_t * 1939 hook_find_byname(hook_int_head_t *head, char *name) 1940 { 1941 hook_int_t *hi; 1942 1943 TAILQ_FOREACH(hi, head, hi_entry) { 1944 if (strcmp(hi->hi_hook.h_name, name) == 0) 1945 return (hi); 1946 } 1947 1948 return (NULL); 1949 } 1950 1951 /* 1952 * Function: hook_find 1953 * Returns: internal hook pointer - NULL = Not match 1954 * Parameters: hei(I) - internal event pointer 1955 * h(I) - hook pointer 1956 * 1957 * Search an event's list of hooks to see if there is already one that 1958 * matches the hook being passed in. Currently the only criteria for a 1959 * successful search here is for the names to be the same. 1960 */ 1961 static hook_int_t * 1962 hook_find(hook_event_int_t *hei, hook_t *h) 1963 { 1964 1965 ASSERT(hei != NULL); 1966 ASSERT(h != NULL); 1967 1968 return (hook_find_byname(&hei->hei_head, h->h_name)); 1969 } 1970 1971 /* 1972 * Function: hook_copy 1973 * Returns: internal hook pointer - NULL = Failed 1974 * Parameters: src(I) - hook pointer 1975 * 1976 * Allocate internal hook block and duplicate incoming hook. 1977 * No locks should be held across this function as it may sleep. 1978 * Because hook_copy() is responsible for the creation of the internal 1979 * hook structure that is used here, it takes on population the structure 1980 * with the kstat information. Note that while the kstat bits are 1981 * seeded here, their installation of the kstats is handled elsewhere. 1982 */ 1983 static hook_int_t * 1984 hook_copy(hook_t *src) 1985 { 1986 hook_int_t *new; 1987 hook_t *dst; 1988 int len; 1989 1990 ASSERT(src != NULL); 1991 ASSERT(src->h_name != NULL); 1992 1993 new = (hook_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP); 1994 1995 /* Copy body */ 1996 dst = &new->hi_hook; 1997 *dst = *src; 1998 1999 /* Copy name */ 2000 len = strlen(src->h_name); 2001 dst->h_name = (char *)kmem_alloc(len + 1, KM_SLEEP); 2002 (void) strcpy(dst->h_name, src->h_name); 2003 2004 /* 2005 * This is initialised in this manner to make it safer to use the 2006 * same pointer in the kstats field. 2007 */ 2008 dst->h_hintvalue = (uintptr_t)""; 2009 2010 if (dst->h_hint == HH_BEFORE || dst->h_hint == HH_AFTER) { 2011 len = strlen((char *)src->h_hintvalue); 2012 if (len > 0) { 2013 dst->h_hintvalue = (uintptr_t)kmem_alloc(len + 1, 2014 KM_SLEEP); 2015 (void) strcpy((char *)dst->h_hintvalue, 2016 (char *)src->h_hintvalue); 2017 } 2018 } 2019 2020 return (new); 2021 } 2022 2023 /* 2024 * Function: hook_init_kstats 2025 * Returns: None 2026 * Parameters: hfi(I) - pointer to the family that owns the event. 2027 * hei(I) - pointer to the event that owns this hook 2028 * hi(I) - pointer to the hook for which we create kstats for 2029 * 2030 * Each hook that is registered with this framework has its own kstats 2031 * set up so that we can provide an easy way in which to observe the 2032 * look of hooks (using the kstat command.) The position is set to 0 2033 * here but is recalculated after we know the insertion has been a 2034 * success. 2035 */ 2036 static void 2037 hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei, hook_int_t *hi) 2038 { 2039 hook_hook_kstat_t template = { 2040 { "version", KSTAT_DATA_INT32 }, 2041 { "flags", KSTAT_DATA_UINT32 }, 2042 { "hint", KSTAT_DATA_INT32 }, 2043 { "hint_value", KSTAT_DATA_UINT64 }, 2044 { "position", KSTAT_DATA_INT32 }, 2045 { "hook_hits", KSTAT_DATA_UINT64 } 2046 }; 2047 hook_stack_t *hks; 2048 size_t kslen; 2049 int position; 2050 hook_int_t *h; 2051 2052 kslen = strlen(hfi->hfi_family.hf_name) + 2053 strlen(hei->hei_event->he_name) + 2; 2054 2055 hi->hi_ksname = (char *)kmem_zalloc(kslen, KM_SLEEP); 2056 (void) snprintf(hi->hi_ksname, kslen, "%s/%s", 2057 hfi->hfi_family.hf_name, hei->hei_event->he_name); 2058 2059 hks = hfi->hfi_stack; 2060 hi->hi_kstatp = kstat_create_netstack(hi->hi_ksname, 0, 2061 hi->hi_hook.h_name, "hook", KSTAT_TYPE_NAMED, 2062 sizeof (hi->hi_kstats) / sizeof (kstat_named_t), 2063 KSTAT_FLAG_VIRTUAL, hks->hks_netstackid); 2064 2065 /* Initialise the kstats for the structure */ 2066 bcopy(&template, &hi->hi_kstats, sizeof (template)); 2067 hi->hi_kstats.hook_version.value.i32 = hi->hi_hook.h_version; 2068 hi->hi_kstats.hook_flags.value.ui32 = hi->hi_hook.h_flags; 2069 hi->hi_kstats.hook_hint.value.i32 = hi->hi_hook.h_hint; 2070 hi->hi_kstats.hook_position.value.i32 = 0; 2071 hi->hi_kstats.hook_hits.value.ui64 = 0; 2072 2073 switch (hi->hi_hook.h_hint) { 2074 case HH_BEFORE : 2075 case HH_AFTER : 2076 hi->hi_kstats.hook_hintvalue.data_type = KSTAT_DATA_STRING; 2077 hi->hi_kstats.hook_hintvalue.value.ui64 = 2078 hi->hi_hook.h_hintvalue; 2079 break; 2080 default : 2081 break; 2082 } 2083 2084 if (hi->hi_kstatp != NULL) { 2085 hi->hi_kstatp->ks_data = (void *)&hi->hi_kstats; 2086 hi->hi_kstatp->ks_private = 2087 (void *)(uintptr_t)hks->hks_netstackid; 2088 2089 kstat_install(hi->hi_kstatp); 2090 } 2091 2092 position = 1; 2093 TAILQ_FOREACH(h, &hei->hei_head, hi_entry) { 2094 h->hi_kstats.hook_position.value.ui32 = position++; 2095 } 2096 } 2097 2098 /* 2099 * Function: hook_int_free 2100 * Returns: None 2101 * Parameters: hi(I) - internal hook pointer 2102 * 2103 * Free alloc memory for hook 2104 */ 2105 static void 2106 hook_int_free(hook_int_t *hi, netstackid_t stackid) 2107 { 2108 int len; 2109 2110 ASSERT(hi != NULL); 2111 2112 /* Free name space */ 2113 if (hi->hi_hook.h_name != NULL) { 2114 kmem_free(hi->hi_hook.h_name, strlen(hi->hi_hook.h_name) + 1); 2115 } 2116 if (hi->hi_ksname != NULL) { 2117 kmem_free(hi->hi_ksname, strlen(hi->hi_ksname) + 1); 2118 } 2119 2120 /* Free the name used with the before/after hints. */ 2121 switch (hi->hi_hook.h_hint) { 2122 case HH_BEFORE : 2123 case HH_AFTER : 2124 len = strlen((char *)hi->hi_hook.h_hintvalue); 2125 if (len > 0) 2126 kmem_free((void *)hi->hi_hook.h_hintvalue, len + 1); 2127 break; 2128 default : 2129 break; 2130 } 2131 2132 if (hi->hi_kstatp != NULL) 2133 kstat_delete_netstack(hi->hi_kstatp, stackid); 2134 2135 /* Free container */ 2136 kmem_free(hi, sizeof (*hi)); 2137 } 2138 2139 /* 2140 * Function: hook_alloc 2141 * Returns: hook_t * - pointer to new hook structure 2142 * Parameters: version(I) - version number of the API when compiled 2143 * 2144 * This function serves as the interface for consumers to obtain a hook_t 2145 * structure. At this point in time, there is only a single "version" of 2146 * it, leading to a straight forward function. In a perfect world the 2147 * h_vesion would be a protected data structure member, but C isn't that 2148 * advanced... 2149 */ 2150 hook_t * 2151 hook_alloc(const int h_version) 2152 { 2153 hook_t *h; 2154 2155 h = kmem_zalloc(sizeof (hook_t), KM_SLEEP); 2156 h->h_version = h_version; 2157 return (h); 2158 } 2159 2160 /* 2161 * Function: hook_free 2162 * Returns: None 2163 * Parameters: h(I) - external hook pointer 2164 * 2165 * This function only free's memory allocated with hook_alloc(), so that if 2166 * (for example) kernel memory was allocated for h_name, this needs to be 2167 * free'd before calling hook_free(). 2168 */ 2169 void 2170 hook_free(hook_t *h) 2171 { 2172 kmem_free(h, sizeof (*h)); 2173 } 2174 2175 /* 2176 * Function: hook_notify_register 2177 * Returns: 0 = success, else failure 2178 * Parameters: lock(I) - netstack identifier 2179 * head(I) - top of the list of callbacks 2180 * callback(I) - function to be called 2181 * arg(I) - arg to pass back to the function 2182 * 2183 * This function implements the modification of the list of callbacks 2184 * that are registered when someone wants to be advised of a change 2185 * that has happened. 2186 */ 2187 static int 2188 hook_notify_register(cvwaitlock_t *lock, hook_notify_head_t *head, 2189 hook_notify_fn_t callback, void *arg) 2190 { 2191 hook_notify_t *hn; 2192 2193 CVW_ENTER_WRITE(lock); 2194 2195 TAILQ_FOREACH(hn, head, hn_entry) { 2196 if (hn->hn_func == callback) { 2197 CVW_EXIT_WRITE(lock); 2198 return (EEXIST); 2199 } 2200 } 2201 2202 hn = (hook_notify_t *)kmem_alloc(sizeof (*hn), KM_SLEEP); 2203 hn->hn_func = callback; 2204 hn->hn_arg = arg; 2205 TAILQ_INSERT_TAIL(head, hn, hn_entry); 2206 2207 CVW_EXIT_WRITE(lock); 2208 2209 return (0); 2210 } 2211 2212 /* 2213 * Function: hook_stack_notify_register 2214 * Returns: 0 = success, else failure 2215 * Parameters: stackid(I) - netstack identifier 2216 * callback(I) - function to be called 2217 * 2218 */ 2219 static int 2220 hook_notify_unregister(cvwaitlock_t *lock, hook_notify_head_t *head, 2221 hook_notify_fn_t callback) 2222 { 2223 hook_notify_t *hn; 2224 2225 CVW_ENTER_WRITE(lock); 2226 2227 TAILQ_FOREACH(hn, head, hn_entry) { 2228 if (hn->hn_func == callback) 2229 break; 2230 } 2231 if (hn == NULL) { 2232 CVW_EXIT_WRITE(lock); 2233 return (ESRCH); 2234 } 2235 2236 TAILQ_REMOVE(head, hn, hn_entry); 2237 2238 CVW_EXIT_WRITE(lock); 2239 2240 kmem_free(hn, sizeof (*hn)); 2241 2242 return (0); 2243 } 2244 2245 /* 2246 * Function: hook_notify_run 2247 * Returns: None 2248 * Parameters: head(I) - top of the list of callbacks 2249 * family(I) - name of the hook family that owns the event 2250 * event(I) - name of the event being changed 2251 * name(I) - name of the object causing change 2252 * cmd(I) - either HN_UNREGISTER or HN_REGISTER 2253 * 2254 * This function walks through the list of registered callbacks and 2255 * executes each one, passing back the arg supplied when registered 2256 * and the name of the family (that owns the event), event (the thing 2257 * to which we're making a change) and finally a name that describes 2258 * what is being added or removed, as indicated by cmd. 2259 * 2260 * This function does not acquire or release any lock as it is required 2261 * that code calling it do so before hand. The use of hook_notify_head_t 2262 * is protected by the use of flagwait_t in the structures that own this 2263 * list and with the use of the FWF_ADD/DEL_ACTIVE flags. 2264 */ 2265 static void 2266 hook_notify_run(hook_notify_head_t *head, char *family, char *event, 2267 char *name, hook_notify_cmd_t cmd) 2268 { 2269 hook_notify_t *hn; 2270 2271 TAILQ_FOREACH(hn, head, hn_entry) { 2272 (*hn->hn_func)(cmd, hn->hn_arg, family, event, name); 2273 } 2274 } 2275