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