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