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