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