xref: /illumos-gate/usr/src/uts/common/ipp/ippconf.c (revision 4e93fb0f6383eaac21897dcdae56b87118131e4d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/param.h>
30 #include <sys/modctl.h>
31 #include <sys/sysmacros.h>
32 #include <sys/kmem.h>
33 #include <sys/cmn_err.h>
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/spl.h>
37 #include <sys/time.h>
38 #include <sys/varargs.h>
39 #include <ipp/ipp.h>
40 #include <ipp/ipp_impl.h>
41 #include <ipp/ipgpc/ipgpc.h>
42 
43 /*
44  * Debug switch.
45  */
46 
47 #if	defined(DEBUG)
48 #define	IPP_DBG
49 #endif
50 
51 /*
52  * Globals
53  */
54 
55 /*
56  * ipp_action_count is not static because it is imported by inet/ipp_common.h
57  */
58 uint32_t		ipp_action_count = 0;
59 
60 static kmem_cache_t	*ipp_mod_cache = NULL;
61 static uint32_t		ipp_mod_count = 0;
62 static uint32_t		ipp_max_mod = IPP_NMOD;
63 static ipp_mod_t	**ipp_mod_byid;
64 static krwlock_t	ipp_mod_byid_lock[1];
65 
66 static ipp_mod_id_t	ipp_next_mid = IPP_MOD_RESERVED + 1;
67 static ipp_mod_id_t	ipp_mid_limit;
68 
69 static ipp_ref_t	*ipp_mod_byname[IPP_NBUCKET];
70 static krwlock_t	ipp_mod_byname_lock[1];
71 
72 static kmem_cache_t	*ipp_action_cache = NULL;
73 static uint32_t		ipp_max_action = IPP_NACTION;
74 static ipp_action_t	**ipp_action_byid;
75 static krwlock_t	ipp_action_byid_lock[1];
76 
77 static ipp_action_id_t	ipp_next_aid = IPP_ACTION_RESERVED + 1;
78 static ipp_action_id_t	ipp_aid_limit;
79 
80 static ipp_ref_t	*ipp_action_byname[IPP_NBUCKET];
81 static krwlock_t	ipp_action_byname_lock[1];
82 static ipp_ref_t	*ipp_action_noname;
83 
84 static kmem_cache_t	*ipp_packet_cache = NULL;
85 static uint_t		ipp_packet_classes = IPP_NCLASS;
86 static uint_t		ipp_packet_logging = 0;
87 static uint_t		ipp_packet_log_entries = IPP_NLOG;
88 
89 /*
90  * Prototypes
91  */
92 
93 void			ipp_init(void);
94 
95 int			ipp_list_mods(ipp_mod_id_t **, int *);
96 
97 ipp_mod_id_t		ipp_mod_lookup(const char *);
98 int			ipp_mod_name(ipp_mod_id_t, char **);
99 int			ipp_mod_register(const char *, ipp_ops_t *);
100 int			ipp_mod_unregister(ipp_mod_id_t);
101 int			ipp_mod_list_actions(ipp_mod_id_t, ipp_action_id_t **,
102     int *);
103 
104 ipp_action_id_t		ipp_action_lookup(const char *);
105 int			ipp_action_name(ipp_action_id_t, char **);
106 int			ipp_action_mod(ipp_action_id_t, ipp_mod_id_t *);
107 int			ipp_action_create(ipp_mod_id_t, const char *,
108     nvlist_t **, ipp_flags_t, ipp_action_id_t *);
109 int			ipp_action_modify(ipp_action_id_t, nvlist_t **,
110     ipp_flags_t);
111 int			ipp_action_destroy(ipp_action_id_t, ipp_flags_t);
112 int			ipp_action_info(ipp_action_id_t, int (*)(nvlist_t *,
113     void *), void *, ipp_flags_t);
114 void			ipp_action_set_ptr(ipp_action_id_t, void *);
115 void			*ipp_action_get_ptr(ipp_action_id_t);
116 int			ipp_action_ref(ipp_action_id_t,	ipp_action_id_t,
117     ipp_flags_t);
118 int			ipp_action_unref(ipp_action_id_t, ipp_action_id_t,
119     ipp_flags_t);
120 
121 int			ipp_packet_alloc(ipp_packet_t **, const char *,
122     ipp_action_id_t);
123 void			ipp_packet_free(ipp_packet_t *);
124 int			ipp_packet_add_class(ipp_packet_t *, const char *,
125     ipp_action_id_t);
126 int			ipp_packet_process(ipp_packet_t **);
127 int			ipp_packet_next(ipp_packet_t *, ipp_action_id_t);
128 void			ipp_packet_set_data(ipp_packet_t *, mblk_t *);
129 mblk_t			*ipp_packet_get_data(ipp_packet_t *);
130 void			ipp_packet_set_private(ipp_packet_t *, void *,
131     void (*)(void *));
132 void			*ipp_packet_get_private(ipp_packet_t *);
133 
134 int			ipp_stat_create(ipp_action_id_t, const char *, int,
135     int (*)(ipp_stat_t *, void *, int), void *, ipp_stat_t **);
136 void			ipp_stat_install(ipp_stat_t *);
137 void			ipp_stat_destroy(ipp_stat_t *);
138 int			ipp_stat_named_init(ipp_stat_t *, const char *, uchar_t,
139     ipp_named_t	*);
140 int			ipp_stat_named_op(ipp_named_t *, void *, int);
141 
142 static int		ref_mod(ipp_action_t *, ipp_mod_t *);
143 static void		unref_mod(ipp_action_t *, ipp_mod_t *);
144 static int		is_mod_busy(ipp_mod_t *);
145 static int		get_mod_ref(ipp_mod_t *, ipp_action_id_t **, int *);
146 static int		get_mods(ipp_mod_id_t **bufp, int *);
147 static ipp_mod_id_t	find_mod(const char *);
148 static int		alloc_mod(const char *, ipp_mod_id_t *);
149 static void		free_mod(ipp_mod_t *);
150 static ipp_mod_t	*hold_mod(ipp_mod_id_t);
151 static void		rele_mod(ipp_mod_t *);
152 static ipp_mod_id_t	get_mid(void);
153 
154 static int		condemn_action(ipp_ref_t **, ipp_action_t *);
155 static int		destroy_action(ipp_action_t *, ipp_flags_t);
156 static int		ref_action(ipp_action_t *, ipp_action_t *);
157 static int		unref_action(ipp_action_t *, ipp_action_t *);
158 static int		is_action_refd(ipp_action_t *);
159 static ipp_action_id_t	find_action(const char *);
160 static int		alloc_action(const char *, ipp_action_id_t *);
161 static void		free_action(ipp_action_t *);
162 static ipp_action_t	*hold_action(ipp_action_id_t);
163 static void		rele_action(ipp_action_t *);
164 static ipp_action_id_t	get_aid(void);
165 
166 static int		alloc_packet(const char *, ipp_action_id_t,
167     ipp_packet_t **);
168 static int		realloc_packet(ipp_packet_t *);
169 static void		free_packet(ipp_packet_t *);
170 
171 static int		hash(const char *);
172 static int		update_stats(kstat_t *, int);
173 static void		init_mods(void);
174 static void		init_actions(void);
175 static void		init_packets(void);
176 static int		mod_constructor(void *, void *, int);
177 static void		mod_destructor(void *, void *);
178 static int		action_constructor(void *, void *, int);
179 static void		action_destructor(void *, void *);
180 static int		packet_constructor(void *, void *, int);
181 static void		packet_destructor(void *, void *);
182 
183 /*
184  * Debug message macros
185  */
186 
187 #ifdef	IPP_DBG
188 
189 #define	DBG_MOD		0x00000001ull
190 #define	DBG_ACTION	0x00000002ull
191 #define	DBG_PACKET	0x00000004ull
192 #define	DBG_STATS	0x00000008ull
193 #define	DBG_LIST	0x00000010ull
194 
195 static uint64_t		ipp_debug_flags =
196 /*
197  * DBG_PACKET |
198  * DBG_STATS |
199  * DBG_LIST |
200  * DBG_MOD |
201  * DBG_ACTION |
202  */
203 0;
204 
205 static kmutex_t	debug_mutex[1];
206 
207 /*PRINTFLIKE3*/
208 static void ipp_debug(uint64_t, const char *, char *, ...)
209 	__KPRINTFLIKE(3);
210 
211 #define	DBG0(_type, _fmt)		    			\
212 	ipp_debug((_type), __FN__, (_fmt));
213 
214 #define	DBG1(_type, _fmt, _a1) 					\
215 	ipp_debug((_type), __FN__, (_fmt), (_a1));
216 
217 #define	DBG2(_type, _fmt, _a1, _a2)				\
218 	ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2));
219 
220 #define	DBG3(_type, _fmt, _a1, _a2, _a3)			\
221 	ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2),	\
222 	    (_a3));
223 
224 #define	DBG4(_type, _fmt, _a1, _a2, _a3, _a4)			\
225 	ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2),	\
226 	    (_a3), (_a4));
227 
228 #define	DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5)		\
229 	ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2),	\
230 	    (_a3), (_a4), (_a5));
231 
232 #else	/* IPP_DBG */
233 
234 #define	DBG0(_type, _fmt)
235 #define	DBG1(_type, _fmt, _a1)
236 #define	DBG2(_type, _fmt, _a1, _a2)
237 #define	DBG3(_type, _fmt, _a1, _a2, _a3)
238 #define	DBG4(_type, _fmt, _a1, _a2, _a3, _a4)
239 #define	DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5)
240 
241 #endif	/* IPP_DBG */
242 
243 /*
244  * Lock macros
245  */
246 
247 #define	LOCK_MOD(_imp, _rw)						\
248 	rw_enter((_imp)->ippm_lock, (_rw))
249 #define	UNLOCK_MOD(_imp)						\
250 	rw_exit((_imp)->ippm_lock)
251 
252 #define	LOCK_ACTION(_ap, _rw)						\
253 	rw_enter((_ap)->ippa_lock, (_rw))
254 #define	UNLOCK_ACTION(_imp)						\
255 	rw_exit((_imp)->ippa_lock)
256 
257 #define	CONFIG_WRITE_START(_ap)						\
258 	CONFIG_LOCK_ENTER((_ap)->ippa_config_lock, CL_WRITE)
259 
260 #define	CONFIG_WRITE_END(_ap)						\
261 	CONFIG_LOCK_EXIT((_ap)->ippa_config_lock)
262 
263 #define	CONFIG_READ_START(_ap)						\
264 	CONFIG_LOCK_ENTER((_ap)->ippa_config_lock, CL_READ)
265 
266 #define	CONFIG_READ_END(_ap)						\
267 	CONFIG_LOCK_EXIT((_ap)->ippa_config_lock)
268 
269 /*
270  * Exported functions
271  */
272 
273 #define	__FN__	"ipp_init"
274 void
275 ipp_init(
276 	void)
277 {
278 #ifdef	IPP_DBG
279 	mutex_init(debug_mutex, NULL, MUTEX_ADAPTIVE,
280 	    (void *)ipltospl(LOCK_LEVEL));
281 #endif	/* IPP_DBG */
282 
283 	/*
284 	 * Initialize module and action structure caches and associated locks.
285 	 */
286 
287 	init_mods();
288 	init_actions();
289 	init_packets();
290 }
291 #undef	__FN__
292 
293 #define	__FN__	"ipp_list_mods"
294 int
295 ipp_list_mods(
296 	ipp_mod_id_t	**bufp,
297 	int		*neltp)
298 {
299 	ASSERT(bufp != NULL);
300 	ASSERT(neltp != NULL);
301 
302 	return (get_mods(bufp, neltp));
303 }
304 #undef	__FN__
305 
306 /*
307  * Module manipulation interface.
308  */
309 
310 #define	__FN__	"ipp_mod_lookup"
311 ipp_mod_id_t
312 ipp_mod_lookup(
313 	const char	*modname)
314 {
315 	ipp_mod_id_t	mid;
316 #define	FIRST_TIME	0
317 	int		try = FIRST_TIME;
318 
319 	/*
320 	 * Sanity check the module name.
321 	 */
322 
323 	if (modname == NULL || strlen(modname) > MAXNAMELEN - 1)
324 		return (IPP_MOD_INVAL);
325 
326 try_again:
327 	if ((mid = find_mod(modname)) == IPP_MOD_INVAL) {
328 
329 		/*
330 		 * Module not installed.
331 		 */
332 
333 		if (try++ == FIRST_TIME) {
334 
335 			/*
336 			 * This is the first attempt to find the module so
337 			 * try to 'demand load' it.
338 			 */
339 
340 			DBG1(DBG_MOD, "loading module '%s'\n", modname);
341 			(void) modload("ipp", (char *)modname);
342 			goto try_again;
343 		}
344 	}
345 
346 	return (mid);
347 
348 #undef	FIRST_TIME
349 }
350 #undef	__FN__
351 
352 #define	__FN__	"ipp_mod_name"
353 int
354 ipp_mod_name(
355 	ipp_mod_id_t	mid,
356 	char		**modnamep)
357 {
358 	ipp_mod_t	*imp;
359 	char		*modname;
360 	char		*buf;
361 
362 	ASSERT(modnamep != NULL);
363 
364 	/*
365 	 * Translate the module id into the module pointer.
366 	 */
367 
368 	if ((imp = hold_mod(mid)) == NULL)
369 		return (ENOENT);
370 
371 	LOCK_MOD(imp, RW_READER);
372 	modname = imp->ippm_name;
373 
374 	/*
375 	 * Allocate a buffer to pass back to the caller.
376 	 */
377 
378 	if ((buf = kmem_zalloc(strlen(modname) + 1, KM_NOSLEEP)) == NULL) {
379 		UNLOCK_MOD(imp);
380 		rele_mod(imp);
381 		return (ENOMEM);
382 	}
383 
384 	/*
385 	 * Copy the module name into the buffer.
386 	 */
387 
388 	(void) strcpy(buf, modname);
389 	UNLOCK_MOD(imp);
390 
391 	*modnamep = buf;
392 
393 	rele_mod(imp);
394 	return (0);
395 }
396 #undef	__FN__
397 
398 #define	__FN__	"ipp_mod_register"
399 int
400 ipp_mod_register(
401 	const char	*modname,
402 	ipp_ops_t	*ipp_ops)
403 {
404 	ipp_mod_id_t	mid;
405 	ipp_mod_t	*imp;
406 	int		rc;
407 
408 	ASSERT(ipp_ops != NULL);
409 
410 	/*
411 	 * Sanity check the module name.
412 	 */
413 
414 	if (modname == NULL || strlen(modname) > MAXNAMELEN - 1)
415 		return (EINVAL);
416 
417 	/*
418 	 * Allocate a module structure.
419 	 */
420 
421 	if ((rc = alloc_mod(modname, &mid)) != 0)
422 		return (rc);
423 
424 	imp = hold_mod(mid);
425 	ASSERT(imp != NULL);
426 
427 	/*
428 	 * Make module available for use.
429 	 */
430 
431 	LOCK_MOD(imp, RW_WRITER);
432 	DBG1(DBG_MOD, "registering module '%s'\n", imp->ippm_name);
433 	imp->ippm_ops = ipp_ops;
434 	imp->ippm_state = IPP_MODSTATE_AVAILABLE;
435 	UNLOCK_MOD(imp);
436 
437 	rele_mod(imp);
438 	return (0);
439 }
440 #undef	__FN__
441 
442 #define	__FN__	"ipp_mod_unregister"
443 int
444 ipp_mod_unregister(
445 	ipp_mod_id_t	mid)
446 {
447 	ipp_mod_t	*imp;
448 
449 	/*
450 	 * Translate the module id into the module pointer.
451 	 */
452 
453 	if ((imp = hold_mod(mid)) == NULL)
454 		return (ENOENT);
455 
456 	LOCK_MOD(imp, RW_WRITER);
457 	ASSERT(imp->ippm_state == IPP_MODSTATE_AVAILABLE);
458 
459 	/*
460 	 * Check to see if there are any actions that reference the module.
461 	 */
462 
463 	if (is_mod_busy(imp)) {
464 		UNLOCK_MOD(imp);
465 		rele_mod(imp);
466 		return (EBUSY);
467 	}
468 
469 	/*
470 	 * Prevent further use of the module.
471 	 */
472 
473 	DBG1(DBG_MOD, "unregistering module '%s'\n", imp->ippm_name);
474 	imp->ippm_state = IPP_MODSTATE_PROTO;
475 	imp->ippm_ops = NULL;
476 	UNLOCK_MOD(imp);
477 
478 	/*
479 	 * Free the module structure.
480 	 */
481 
482 	free_mod(imp);
483 	rele_mod(imp);
484 
485 	return (0);
486 }
487 #undef	__FN__
488 
489 #define	__FN__	"ipp_mod_list_actions"
490 int
491 ipp_mod_list_actions(
492 	ipp_mod_id_t	mid,
493 	ipp_action_id_t	**bufp,
494 	int		*neltp)
495 {
496 	ipp_mod_t	*imp;
497 	int		rc;
498 
499 	ASSERT(bufp != NULL);
500 	ASSERT(neltp != NULL);
501 
502 	/*
503 	 * Translate the module id into the module pointer.
504 	 */
505 
506 	if ((imp = hold_mod(mid)) == NULL)
507 		return (ENOENT);
508 
509 	/*
510 	 * Get the list of actions referencing the module.
511 	 */
512 
513 	LOCK_MOD(imp, RW_READER);
514 	rc = get_mod_ref(imp, bufp, neltp);
515 	UNLOCK_MOD(imp);
516 
517 	rele_mod(imp);
518 	return (rc);
519 }
520 #undef	__FN__
521 
522 /*
523  * Action manipulation interface.
524  */
525 
526 #define	__FN__	"ipp_action_lookup"
527 ipp_action_id_t
528 ipp_action_lookup(
529 	const char	*aname)
530 {
531 	if (aname == NULL)
532 		return (IPP_ACTION_INVAL);
533 
534 	/*
535 	 * Check for special case 'virtual action' names.
536 	 */
537 
538 	if (strcmp(aname, IPP_ANAME_CONT) == 0)
539 		return (IPP_ACTION_CONT);
540 	else if (strcmp(aname, IPP_ANAME_DEFER) == 0)
541 		return (IPP_ACTION_DEFER);
542 	else if (strcmp(aname, IPP_ANAME_DROP) == 0)
543 		return (IPP_ACTION_DROP);
544 
545 	/*
546 	 * Now check real actions.
547 	 */
548 
549 	return (find_action(aname));
550 }
551 #undef	__FN__
552 
553 #define	__FN__	"ipp_action_name"
554 int
555 ipp_action_name(
556 	ipp_action_id_t	aid,
557 	char		**anamep)
558 {
559 	ipp_action_t	*ap;
560 	char		*aname;
561 	char		*buf;
562 	int		rc;
563 
564 	ASSERT(anamep != NULL);
565 
566 	/*
567 	 * Check for special case 'virtual action' ids.
568 	 */
569 
570 	switch (aid) {
571 	case IPP_ACTION_CONT:
572 		ap = NULL;
573 		aname = IPP_ANAME_CONT;
574 		break;
575 	case IPP_ACTION_DEFER:
576 		ap = NULL;
577 		aname = IPP_ANAME_DEFER;
578 		break;
579 	case IPP_ACTION_DROP:
580 		ap = NULL;
581 		aname = IPP_ANAME_DROP;
582 		break;
583 	default:
584 
585 		/*
586 		 * Not a special case. Check for a real action.
587 		 */
588 
589 		if ((ap = hold_action(aid)) == NULL)
590 			return (ENOENT);
591 
592 		LOCK_ACTION(ap, RW_READER);
593 		aname = ap->ippa_name;
594 		break;
595 	}
596 
597 	/*
598 	 * Allocate a buffer to pass back to the caller.
599 	 */
600 
601 	if ((buf = kmem_zalloc(strlen(aname) + 1, KM_NOSLEEP)) == NULL) {
602 		rc = ENOMEM;
603 		goto done;
604 	}
605 
606 	/*
607 	 * Copy the action name into the buffer.
608 	 */
609 
610 	(void) strcpy(buf, aname);
611 	*anamep = buf;
612 	rc = 0;
613 done:
614 	/*
615 	 * Unlock the action if necessary (i.e. it wasn't a virtual action).
616 	 */
617 
618 	if (ap != NULL) {
619 		UNLOCK_ACTION(ap);
620 		rele_action(ap);
621 	}
622 
623 	return (rc);
624 }
625 #undef	__FN__
626 
627 #define	__FN__	"ipp_action_mod"
628 int
629 ipp_action_mod(
630 	ipp_action_id_t	aid,
631 	ipp_mod_id_t	*midp)
632 {
633 	ipp_action_t	*ap;
634 	ipp_mod_t	*imp;
635 
636 	ASSERT(midp != NULL);
637 
638 	/*
639 	 * Return an error for  'virtual action' ids.
640 	 */
641 
642 	switch (aid) {
643 	case IPP_ACTION_CONT:
644 	/*FALLTHRU*/
645 	case IPP_ACTION_DEFER:
646 	/*FALLTHRU*/
647 	case IPP_ACTION_DROP:
648 		return (EINVAL);
649 	default:
650 		break;
651 	}
652 
653 	/*
654 	 * This is a real action.
655 	 */
656 
657 	if ((ap = hold_action(aid)) == NULL)
658 		return (ENOENT);
659 
660 	/*
661 	 * Check that the action is not in prototype state.
662 	 */
663 
664 	LOCK_ACTION(ap, RW_READER);
665 	if (ap->ippa_state == IPP_ASTATE_PROTO) {
666 		UNLOCK_ACTION(ap);
667 		rele_action(ap);
668 		return (ENOENT);
669 	}
670 
671 	imp = ap->ippa_mod;
672 	ASSERT(imp != NULL);
673 	UNLOCK_ACTION(ap);
674 
675 	*midp = imp->ippm_id;
676 
677 	rele_action(ap);
678 	return (0);
679 }
680 #undef	__FN__
681 
682 #define	__FN__	"ipp_action_create"
683 int
684 ipp_action_create(
685 	ipp_mod_id_t	mid,
686 	const char	*aname,
687 	nvlist_t	**nvlpp,
688 	ipp_flags_t	flags,
689 	ipp_action_id_t	*aidp)
690 {
691 	ipp_ops_t	*ippo;
692 	ipp_mod_t	*imp;
693 	ipp_action_id_t	aid;
694 	ipp_action_t	*ap;
695 	int		rc;
696 
697 	ASSERT(nvlpp != NULL);
698 	ASSERT(*nvlpp != NULL);
699 
700 	/*
701 	 * Sanity check the action name (NULL means the framework chooses the
702 	 * name).
703 	 */
704 
705 	if (aname != NULL && strlen(aname) > MAXNAMELEN - 1)
706 		return (EINVAL);
707 
708 	/*
709 	 * Translate the module id into the module pointer.
710 	 */
711 
712 	if ((imp = hold_mod(mid)) == NULL)
713 		return (ENOENT);
714 
715 	/*
716 	 * Allocate an action.
717 	 */
718 
719 	if ((rc = alloc_action(aname, &aid)) != 0) {
720 		rele_mod(imp);
721 		return (rc);
722 	}
723 
724 	ap = hold_action(aid);
725 	ASSERT(ap != NULL);
726 
727 	/*
728 	 * Note that the action is in the process of creation/destruction.
729 	 */
730 
731 	LOCK_ACTION(ap, RW_WRITER);
732 	ap->ippa_state = IPP_ASTATE_CONFIG_PENDING;
733 
734 	/*
735 	 * Reference the module for which the action is being created.
736 	 */
737 
738 	LOCK_MOD(imp, RW_WRITER);
739 	if ((rc = ref_mod(ap, imp)) != 0) {
740 		UNLOCK_MOD(imp);
741 		ap->ippa_state = IPP_ASTATE_PROTO;
742 		UNLOCK_ACTION(ap);
743 
744 		free_action(ap);
745 		rele_action(ap);
746 		rele_mod(imp);
747 		return (rc);
748 	}
749 
750 	UNLOCK_ACTION(ap);
751 
752 	ippo = imp->ippm_ops;
753 	ASSERT(ippo != NULL);
754 	UNLOCK_MOD(imp);
755 
756 	/*
757 	 * Call into the module to create the action context.
758 	 */
759 
760 	CONFIG_WRITE_START(ap);
761 	DBG2(DBG_ACTION, "creating action '%s' in module '%s'\n",
762 	    ap->ippa_name, imp->ippm_name);
763 	if ((rc = ippo->ippo_action_create(ap->ippa_id, nvlpp, flags)) != 0) {
764 		LOCK_ACTION(ap, RW_WRITER);
765 		LOCK_MOD(imp, RW_WRITER);
766 		unref_mod(ap, imp);
767 		UNLOCK_MOD(imp);
768 		ap->ippa_state = IPP_ASTATE_PROTO;
769 		UNLOCK_ACTION(ap);
770 
771 		CONFIG_WRITE_END(ap);
772 
773 		free_action(ap);
774 		rele_action(ap);
775 		rele_mod(imp);
776 		return (rc);
777 	}
778 	CONFIG_WRITE_END(ap);
779 
780 	/*
781 	 * Make the action available for use.
782 	 */
783 
784 	LOCK_ACTION(ap, RW_WRITER);
785 	ap->ippa_state = IPP_ASTATE_AVAILABLE;
786 	if (aidp != NULL)
787 		*aidp = ap->ippa_id;
788 	UNLOCK_ACTION(ap);
789 
790 	rele_action(ap);
791 	rele_mod(imp);
792 	return (0);
793 }
794 #undef	__FN__
795 
796 #define	__FN__	"ipp_action_destroy"
797 int
798 ipp_action_destroy(
799 	ipp_action_id_t	aid,
800 	ipp_flags_t	flags)
801 {
802 	ipp_ref_t	*rp = NULL;
803 	ipp_ref_t	*tmp;
804 	ipp_action_t	*ap;
805 	int		rc;
806 
807 	/*
808 	 * Translate the action id into the action pointer.
809 	 */
810 
811 	if ((ap = hold_action(aid)) == NULL)
812 		return (ENOENT);
813 
814 	/*
815 	 * Set the condemned action list pointer and destroy the action.
816 	 */
817 
818 	ap->ippa_condemned = &rp;
819 	if ((rc = destroy_action(ap, flags)) == 0) {
820 
821 		/*
822 		 * Destroy any other actions condemned by the destruction of
823 		 * the first action.
824 		 */
825 
826 		for (tmp = rp; tmp != NULL; tmp = tmp->ippr_nextp) {
827 			ap = tmp->ippr_action;
828 			ap->ippa_condemned = &rp;
829 			(void) destroy_action(ap, flags);
830 		}
831 	} else {
832 
833 		/*
834 		 * Unreference any condemned actions since the destruction of
835 		 * the first action failed.
836 		 */
837 
838 		for (tmp = rp; tmp != NULL; tmp = tmp->ippr_nextp) {
839 			ap = tmp->ippr_action;
840 			rele_action(ap);
841 		}
842 	}
843 
844 	/*
845 	 * Clean up the condemned list.
846 	 */
847 
848 	while (rp != NULL) {
849 		tmp = rp;
850 		rp = rp->ippr_nextp;
851 		kmem_free(tmp, sizeof (ipp_ref_t));
852 	}
853 
854 	return (rc);
855 }
856 #undef	__FN__
857 
858 #define	__FN__	"ipp_action_modify"
859 int
860 ipp_action_modify(
861 	ipp_action_id_t	aid,
862 	nvlist_t	**nvlpp,
863 	ipp_flags_t	flags)
864 {
865 	ipp_action_t	*ap;
866 	ipp_ops_t	*ippo;
867 	ipp_mod_t	*imp;
868 	int		rc;
869 
870 	ASSERT(nvlpp != NULL);
871 	ASSERT(*nvlpp != NULL);
872 
873 	/*
874 	 * Translate the action id into the action pointer.
875 	 */
876 
877 	if ((ap = hold_action(aid)) == NULL)
878 		return (ENOENT);
879 
880 	/*
881 	 * Check that the action is either available for use or is in the
882 	 * process of creation/destruction.
883 	 *
884 	 * NOTE: It is up to the module to lock multiple configuration
885 	 *	 operations against each other if necessary.
886 	 */
887 
888 	LOCK_ACTION(ap, RW_READER);
889 	if (ap->ippa_state != IPP_ASTATE_AVAILABLE &&
890 	    ap->ippa_state != IPP_ASTATE_CONFIG_PENDING) {
891 		UNLOCK_ACTION(ap);
892 		rele_action(ap);
893 		return (EPROTO);
894 	}
895 
896 	imp = ap->ippa_mod;
897 	ASSERT(imp != NULL);
898 	UNLOCK_ACTION(ap);
899 
900 	ippo = imp->ippm_ops;
901 	ASSERT(ippo != NULL);
902 
903 	/*
904 	 * Call into the module to modify the action context.
905 	 */
906 
907 	DBG1(DBG_ACTION, "modifying action '%s'\n", ap->ippa_name);
908 	CONFIG_WRITE_START(ap);
909 	rc = ippo->ippo_action_modify(aid, nvlpp, flags);
910 	CONFIG_WRITE_END(ap);
911 
912 	rele_action(ap);
913 	return (rc);
914 }
915 #undef	__FN__
916 
917 #define	__FN__	"ipp_action_info"
918 int
919 ipp_action_info(
920 	ipp_action_id_t	aid,
921 	int		(*fn)(nvlist_t *, void *),
922 	void		*arg,
923 	ipp_flags_t    	flags)
924 {
925 	ipp_action_t	*ap;
926 	ipp_mod_t	*imp;
927 	ipp_ops_t	*ippo;
928 	int		rc;
929 
930 	/*
931 	 * Translate the action id into the action pointer.
932 	 */
933 
934 	if ((ap = hold_action(aid)) == NULL)
935 		return (ENOENT);
936 
937 	/*
938 	 * Check that the action is available for use. We don't want to
939 	 * read back parameters while the action is in the process of
940 	 * creation/destruction.
941 	 */
942 
943 	LOCK_ACTION(ap, RW_READER);
944 	if (ap->ippa_state != IPP_ASTATE_AVAILABLE) {
945 		UNLOCK_ACTION(ap);
946 		rele_action(ap);
947 		return (EPROTO);
948 	}
949 
950 	imp = ap->ippa_mod;
951 	ASSERT(imp != NULL);
952 	UNLOCK_ACTION(ap);
953 
954 	ippo = imp->ippm_ops;
955 	ASSERT(ippo != NULL);
956 
957 	/*
958 	 * Call into the module to get the action configuration information.
959 	 */
960 
961 	DBG1(DBG_ACTION,
962 	    "getting configuration information from action '%s'\n",
963 	    ap->ippa_name);
964 	CONFIG_READ_START(ap);
965 	if ((rc = ippo->ippo_action_info(aid, fn, arg, flags)) != 0) {
966 		CONFIG_READ_END(ap);
967 		rele_action(ap);
968 		return (rc);
969 	}
970 	CONFIG_READ_END(ap);
971 
972 	rele_action(ap);
973 	return (0);
974 }
975 #undef	__FN__
976 
977 #define	__FN__	"ipp_action_set_ptr"
978 void
979 ipp_action_set_ptr(
980 	ipp_action_id_t	aid,
981 	void		*ptr)
982 {
983 	ipp_action_t	*ap;
984 
985 	/*
986 	 * Translate the action id into the action pointer.
987 	 */
988 
989 	ap = hold_action(aid);
990 	ASSERT(ap != NULL);
991 
992 	/*
993 	 * Set the private data pointer.
994 	 */
995 
996 	ap->ippa_ptr = ptr;
997 	rele_action(ap);
998 }
999 #undef	__FN__
1000 
1001 #define	__FN__	"ipp_action_get_ptr"
1002 void *
1003 ipp_action_get_ptr(
1004 	ipp_action_id_t	aid)
1005 {
1006 	ipp_action_t	*ap;
1007 	void		*ptr;
1008 
1009 	/*
1010 	 * Translate the action id into the action pointer.
1011 	 */
1012 
1013 	ap = hold_action(aid);
1014 	ASSERT(ap != NULL);
1015 
1016 	/*
1017 	 * Return the private data pointer.
1018 	 */
1019 
1020 	ptr = ap->ippa_ptr;
1021 	rele_action(ap);
1022 
1023 	return (ptr);
1024 }
1025 #undef	__FN__
1026 
1027 #define	__FN__	"ipp_action_ref"
1028 /*ARGSUSED*/
1029 int
1030 ipp_action_ref(
1031 	ipp_action_id_t	aid,
1032 	ipp_action_id_t	ref_aid,
1033 	ipp_flags_t	flags)
1034 {
1035 	ipp_action_t	*ap;
1036 	ipp_action_t	*ref_ap;
1037 	int		rc;
1038 
1039 	/*
1040 	 * Actions are not allowed to reference themselves.
1041 	 */
1042 
1043 	if (aid == ref_aid)
1044 		return (EINVAL);
1045 
1046 	/*
1047 	 * Check for a special case 'virtual action' id.
1048 	 */
1049 
1050 	switch (ref_aid) {
1051 	case IPP_ACTION_CONT:
1052 	/*FALLTHRU*/
1053 	case IPP_ACTION_DEFER:
1054 	/*FALLTHRU*/
1055 	case IPP_ACTION_DROP:
1056 		return (0);
1057 	default:
1058 		break;
1059 	}
1060 
1061 	/*
1062 	 * Translate the action ids into action pointers.
1063 	 */
1064 
1065 	if ((ap = hold_action(aid)) == NULL)
1066 		return (ENOENT);
1067 
1068 	if ((ref_ap = hold_action(ref_aid)) == NULL) {
1069 		rele_action(ap);
1070 		return (ENOENT);
1071 	}
1072 
1073 	LOCK_ACTION(ap, RW_WRITER);
1074 	LOCK_ACTION(ref_ap, RW_WRITER);
1075 
1076 	if (ref_ap->ippa_state != IPP_ASTATE_AVAILABLE) {
1077 		UNLOCK_ACTION(ref_ap);
1078 		UNLOCK_ACTION(ap);
1079 
1080 		rele_action(ref_ap);
1081 		rele_action(ap);
1082 		return (EPROTO);
1083 	}
1084 
1085 	/*
1086 	 * Create references between the two actions.
1087 	 */
1088 
1089 	rc = ref_action(ap, ref_ap);
1090 	UNLOCK_ACTION(ref_ap);
1091 	UNLOCK_ACTION(ap);
1092 
1093 	rele_action(ref_ap);
1094 	rele_action(ap);
1095 	return (rc);
1096 }
1097 #undef	__FN__
1098 
1099 #define	__FN__	"ipp_action_unref"
1100 int
1101 ipp_action_unref(
1102 	ipp_action_id_t	aid,
1103 	ipp_action_id_t	ref_aid,
1104 	ipp_flags_t	flags)
1105 {
1106 	ipp_action_t	*ap;
1107 	ipp_action_t	*ref_ap;
1108 	int		ref_is_busy;
1109 	int		rc;
1110 
1111 	if (aid == ref_aid)
1112 		return (EINVAL);
1113 
1114 	/*
1115 	 * Check for a special case 'virtual action' id.
1116 	 */
1117 
1118 	switch (ref_aid) {
1119 	case IPP_ACTION_CONT:
1120 	/*FALLTHRU*/
1121 	case IPP_ACTION_DEFER:
1122 	/*FALLTHRU*/
1123 	case IPP_ACTION_DROP:
1124 		return (0);
1125 	default:
1126 		break;
1127 	}
1128 
1129 	/*
1130 	 * Translate the action ids into action pointers.
1131 	 */
1132 
1133 	if ((ap = hold_action(aid)) == NULL)
1134 		return (ENOENT);
1135 
1136 	if ((ref_ap = hold_action(ref_aid)) == NULL) {
1137 		rele_action(ap);
1138 		return (ENOENT);
1139 	}
1140 
1141 	LOCK_ACTION(ap, RW_WRITER);
1142 	LOCK_ACTION(ref_ap, RW_WRITER);
1143 
1144 	/*
1145 	 * Remove the reference between the actions.
1146 	 */
1147 
1148 	if ((rc = unref_action(ap, ref_ap)) != 0) {
1149 		UNLOCK_ACTION(ref_ap);
1150 		UNLOCK_ACTION(ap);
1151 		rele_action(ref_ap);
1152 		rele_action(ap);
1153 		return (rc);
1154 	}
1155 
1156 	ref_is_busy = is_action_refd(ref_ap);
1157 
1158 	UNLOCK_ACTION(ref_ap);
1159 	UNLOCK_ACTION(ap);
1160 
1161 	if (flags & IPP_DESTROY_REF) {
1162 		if (!ref_is_busy) {
1163 
1164 			/*
1165 			 * Condemn the action so that it will be destroyed.
1166 			 */
1167 
1168 			(void) condemn_action(ap->ippa_condemned, ref_ap);
1169 			return (0);
1170 		}
1171 	}
1172 
1173 	rele_action(ref_ap);
1174 	rele_action(ap);
1175 	return (0);
1176 }
1177 #undef	__FN__
1178 
1179 /*
1180  * Packet manipulation interface.
1181  */
1182 
1183 #define	__FN__	"ipp_packet_alloc"
1184 int
1185 ipp_packet_alloc(
1186 	ipp_packet_t	**ppp,
1187 	const char	*name,
1188 	ipp_action_id_t	aid)
1189 {
1190 	ipp_packet_t	*pp;
1191 	int		rc;
1192 
1193 	ASSERT(ppp != NULL);
1194 
1195 	/*
1196 	 * A name is required.
1197 	 */
1198 
1199 	if (name == NULL || strlen(name) > MAXNAMELEN - 1)
1200 		return (EINVAL);
1201 
1202 	/*
1203 	 * Allocate a packet structure from the cache.
1204 	 */
1205 
1206 	if ((rc = alloc_packet(name, aid, &pp)) != 0)
1207 		return (rc);
1208 
1209 	if (ipp_packet_logging != 0 && pp->ippp_log == NULL) {
1210 
1211 		/*
1212 		 * Logging is turned on but there's no log buffer. We need
1213 		 * to allocate one.
1214 		 */
1215 		if ((pp->ippp_log = kmem_alloc(
1216 		    ipp_packet_log_entries * sizeof (ipp_log_t),
1217 		    KM_NOSLEEP)) != NULL) {
1218 			pp->ippp_log_limit = ipp_packet_log_entries - 1;
1219 			pp->ippp_log_windex = 0;
1220 		}
1221 	} else if (ipp_packet_logging == 0 && pp->ippp_log != NULL) {
1222 
1223 		/*
1224 		 * A log buffer is present but logging has been turned off.
1225 		 * Free the buffer now,
1226 		 */
1227 
1228 		kmem_free(pp->ippp_log,
1229 		    (pp->ippp_log_limit + 1) * sizeof (ipp_log_t));
1230 		pp->ippp_log = NULL;
1231 		pp->ippp_log_limit = 0;
1232 		pp->ippp_log_windex = 0;
1233 	}
1234 
1235 	*ppp = pp;
1236 	return (0);
1237 }
1238 #undef	__FN__
1239 
1240 #define	__FN__	"ipp_packet_free"
1241 void
1242 ipp_packet_free(
1243 	ipp_packet_t	*pp)
1244 {
1245 
1246 	ASSERT(pp != NULL);
1247 
1248 	/*
1249 	 * If there is a private structure pointer set, call its free
1250 	 * function.
1251 	 */
1252 
1253 	if (pp->ippp_private) {
1254 		pp->ippp_private_free(pp->ippp_private);
1255 		pp->ippp_private = NULL;
1256 		pp->ippp_private_free = NULL;
1257 	}
1258 
1259 	/*
1260 	 * Free the packet structure back to the cache.
1261 	 */
1262 
1263 	free_packet(pp);
1264 }
1265 #undef	__FN__
1266 
1267 #define	__FN__	"ipp_packet_add_class"
1268 int
1269 ipp_packet_add_class(
1270 	ipp_packet_t	*pp,
1271 	const char	*name,
1272 	ipp_action_id_t	aid)
1273 {
1274 	ipp_class_t	*cp;
1275 	int		rc;
1276 
1277 	ASSERT(pp != NULL);
1278 
1279 	/*
1280 	 * A name is required.
1281 	 */
1282 
1283 	if (name == NULL || strlen(name) > MAXNAMELEN - 1)
1284 		return (EINVAL);
1285 
1286 	/*
1287 	 * Check if there is an available class structure.
1288 	 */
1289 
1290 	if (pp->ippp_class_windex == pp->ippp_class_limit) {
1291 
1292 		/*
1293 		 * No more structures. Re-allocate the array.
1294 		 */
1295 
1296 		if ((rc = realloc_packet(pp)) != 0)
1297 			return (rc);
1298 	}
1299 	ASSERT(pp->ippp_class_windex < pp->ippp_class_limit);
1300 
1301 	/*
1302 	 * Set up a new class structure.
1303 	 */
1304 
1305 	cp = &(pp->ippp_class_array[pp->ippp_class_windex++]);
1306 	(void) strcpy(cp->ippc_name, name);
1307 	cp->ippc_aid = aid;
1308 
1309 	return (0);
1310 }
1311 #undef	__FN__
1312 
1313 #define	__FN__	"ipp_packet_process"
1314 int
1315 ipp_packet_process(
1316 	ipp_packet_t	**ppp)
1317 {
1318 	ipp_packet_t	*pp;
1319 	ipp_action_id_t	aid;
1320 	ipp_class_t	*cp;
1321 	ipp_log_t	*lp;
1322 	ipp_action_t	*ap;
1323 	ipp_mod_t	*imp;
1324 	ipp_ops_t	*ippo;
1325 	int		rc;
1326 
1327 	ASSERT(ppp != NULL);
1328 	pp = *ppp;
1329 	ASSERT(pp != NULL);
1330 
1331 	/*
1332 	 * Walk the class list.
1333 	 */
1334 
1335 	while (pp->ippp_class_rindex < pp->ippp_class_windex) {
1336 		cp = &(pp->ippp_class_array[pp->ippp_class_rindex]);
1337 
1338 		/*
1339 		 * While there is a real action to invoke...
1340 		 */
1341 
1342 		aid = cp->ippc_aid;
1343 		while (aid != IPP_ACTION_CONT &&
1344 		    aid != IPP_ACTION_DEFER &&
1345 		    aid != IPP_ACTION_DROP) {
1346 
1347 			ASSERT(aid != IPP_ACTION_INVAL);
1348 
1349 			/*
1350 			 * Translate the action id to the action pointer.
1351 			 */
1352 
1353 			if ((ap = hold_action(aid)) == NULL) {
1354 				DBG1(DBG_PACKET,
1355 				    "action id '%d' not found\n", aid);
1356 				return (ENOENT);
1357 			}
1358 
1359 			/*
1360 			 * Check that the action is available for use...
1361 			 */
1362 			LOCK_ACTION(ap, RW_READER);
1363 			if (ap->ippa_state != IPP_ASTATE_AVAILABLE) {
1364 				UNLOCK_ACTION(ap);
1365 				rele_action(ap);
1366 				return (EPROTO);
1367 			}
1368 
1369 			/*
1370 			 * Increment the action's packet count to note that
1371 			 * it's being used.
1372 			 *
1373 			 * NOTE: We only have a read lock, so we need to use
1374 			 *	 atomic_add_32(). The read lock is still
1375 			 *	 important though as it is crucial to block
1376 			 *	 out a destroy operation between the action
1377 			 *	 state being checked and the packet count
1378 			 *	 being incremented.
1379 			 */
1380 
1381 			atomic_add_32(&(ap->ippa_packets), 1);
1382 
1383 			imp = ap->ippa_mod;
1384 			ASSERT(imp != NULL);
1385 			UNLOCK_ACTION(ap);
1386 
1387 			ippo = imp->ippm_ops;
1388 			ASSERT(ippo != NULL);
1389 
1390 			/*
1391 			 * If there's a log, grab the next entry and fill it
1392 			 * in.
1393 			 */
1394 
1395 			if (pp->ippp_log != NULL &&
1396 			    pp->ippp_log_windex <= pp->ippp_log_limit) {
1397 				lp = &(pp->ippp_log[pp->ippp_log_windex++]);
1398 				lp->ippl_aid = aid;
1399 				(void) strcpy(lp->ippl_name, cp->ippc_name);
1400 				gethrestime(&lp->ippl_begin);
1401 			} else {
1402 				lp = NULL;
1403 			}
1404 
1405 			/*
1406 			 * Invoke the action.
1407 			 */
1408 
1409 			rc = ippo->ippo_action_invoke(aid, pp);
1410 
1411 			/*
1412 			 * Also log the time that the action finished
1413 			 * processing.
1414 			 */
1415 
1416 			if (lp != NULL)
1417 				gethrestime(&lp->ippl_end);
1418 
1419 			/*
1420 			 * Decrement the packet count.
1421 			 */
1422 
1423 			atomic_add_32(&(ap->ippa_packets), -1);
1424 
1425 			/*
1426 			 * If the class' action id is the same now as it was
1427 			 * before then clearly no 'next action' has been set.
1428 			 * This is a protocol error.
1429 			 */
1430 
1431 			if (cp->ippc_aid == aid) {
1432 				DBG1(DBG_PACKET,
1433 				    "action '%s' did not set next action\n",
1434 				    ap->ippa_name);
1435 				rele_action(ap);
1436 				return (EPROTO);
1437 			}
1438 
1439 			/*
1440 			 * The action did not complete successfully. Terminate
1441 			 * packet processing.
1442 			 */
1443 
1444 			if (rc != 0) {
1445 				DBG2(DBG_PACKET,
1446 				    "action error '%d' from action '%s'\n",
1447 				    rc, ap->ippa_name);
1448 				rele_action(ap);
1449 				return (rc);
1450 			}
1451 
1452 			rele_action(ap);
1453 
1454 			/*
1455 			 * Look at the next action.
1456 			 */
1457 
1458 			aid = cp->ippc_aid;
1459 		}
1460 
1461 		/*
1462 		 * No more real actions to invoke, check for 'virtual' ones.
1463 		 */
1464 
1465 		/*
1466 		 * Packet deferred: module has held onto packet for processing
1467 		 * later.
1468 		 */
1469 
1470 		if (cp->ippc_aid == IPP_ACTION_DEFER) {
1471 			*ppp = NULL;
1472 			return (0);
1473 		}
1474 
1475 		/*
1476 		 * Packet dropped: free the packet and discontinue processing.
1477 		 */
1478 
1479 		if (cp->ippc_aid == IPP_ACTION_DROP) {
1480 			freemsg(pp->ippp_data);
1481 			ipp_packet_free(pp);
1482 			*ppp = NULL;
1483 			return (0);
1484 		}
1485 
1486 		/*
1487 		 * Must be 'continue processing': move onto the next class.
1488 		 */
1489 
1490 		ASSERT(cp->ippc_aid == IPP_ACTION_CONT);
1491 		pp->ippp_class_rindex++;
1492 	}
1493 
1494 	return (0);
1495 }
1496 #undef	__FN__
1497 
1498 #define	__FN__	"ipp_packet_next"
1499 int
1500 ipp_packet_next(
1501 	ipp_packet_t	*pp,
1502 	ipp_action_id_t	aid)
1503 {
1504 	ipp_action_t	*ap;
1505 	ipp_class_t	*cp;
1506 
1507 	ASSERT(pp != NULL);
1508 
1509 	cp = &(pp->ippp_class_array[pp->ippp_class_rindex]);
1510 	ASSERT(cp != NULL);
1511 
1512 	/*
1513 	 * Check for a special case 'virtual action' id.
1514 	 */
1515 
1516 	switch (aid) {
1517 	case IPP_ACTION_INVAL:
1518 		return (EINVAL);
1519 	case IPP_ACTION_DEFER:
1520 	/*FALLTHRU*/
1521 	case IPP_ACTION_CONT:
1522 	/*FALLTHRU*/
1523 	case IPP_ACTION_DROP:
1524 		break;
1525 	default:
1526 
1527 		/*
1528 		 * Not a virtual action so try to translate the action id
1529 		 * into the action pointer to confirm the actions existence.
1530 		 */
1531 
1532 		if ((ap = hold_action(aid)) == NULL) {
1533 			DBG0(DBG_PACKET, "invalid action\n");
1534 			return (ENOENT);
1535 		}
1536 		rele_action(ap);
1537 
1538 		break;
1539 	}
1540 
1541 	/*
1542 	 * Set the class' new action id.
1543 	 */
1544 
1545 	cp->ippc_aid = aid;
1546 
1547 	return (0);
1548 }
1549 #undef	__FN__
1550 
1551 #define	__FN__	"ipp_packet_set_data"
1552 void
1553 ipp_packet_set_data(
1554 	ipp_packet_t	*pp,
1555 	mblk_t		*data)
1556 {
1557 	ASSERT(pp != NULL);
1558 	pp->ippp_data = data;
1559 }
1560 #undef	__FN__
1561 
1562 #define	__FN__	"ipp_packet_get_data"
1563 mblk_t *
1564 ipp_packet_get_data(
1565 	ipp_packet_t	*pp)
1566 {
1567 	ASSERT(pp != NULL);
1568 	return (pp->ippp_data);
1569 }
1570 #undef	__FN__
1571 
1572 #define	__FN__	"ipp_packet_set_private"
1573 void
1574 ipp_packet_set_private(
1575 	ipp_packet_t	*pp,
1576 	void		*buf,
1577 	void		(*free_func)(void *))
1578 {
1579 	ASSERT(pp != NULL);
1580 	ASSERT(free_func != NULL);
1581 
1582 	pp->ippp_private = buf;
1583 	pp->ippp_private_free = free_func;
1584 }
1585 #undef	__FN__
1586 
1587 #define	__FN__	"ipp_packet_get_private"
1588 void *
1589 ipp_packet_get_private(
1590 	ipp_packet_t	*pp)
1591 {
1592 	ASSERT(pp != NULL);
1593 	return (pp->ippp_private);
1594 }
1595 #undef	__FN__
1596 
1597 /*
1598  * Statistics interface.
1599  */
1600 
1601 #define	__FN__	"ipp_stat_create"
1602 int
1603 ipp_stat_create(
1604 	ipp_action_id_t	aid,
1605 	const char	*name,
1606 	int		nstat,
1607 	int		(*update)(ipp_stat_t *, void *, int),
1608 	void		*arg,
1609 	ipp_stat_t	**spp)
1610 {
1611 	ipp_action_t	*ap;
1612 	ipp_mod_t	*imp;
1613 	ipp_stat_impl_t	*sip;
1614 	ipp_stat_t	*sp;
1615 	kstat_t		*ksp;
1616 	char		*class;
1617 	char		*modname;
1618 	int		instance;
1619 
1620 	ASSERT(spp != NULL);
1621 
1622 	/*
1623 	 * Sanity check the arguments.
1624 	 */
1625 
1626 	if (name == NULL || nstat <= 0 || update == NULL)
1627 		return (EINVAL);
1628 
1629 	/*
1630 	 * Translate the action id into the action pointer.
1631 	 */
1632 
1633 	if ((ap = hold_action(aid)) == NULL)
1634 		return (ENOENT);
1635 
1636 	/*
1637 	 * Grab relevant action and module information.
1638 	 */
1639 
1640 	LOCK_ACTION(ap, RW_READER);
1641 	class = ap->ippa_name;
1642 	instance = (int)ap->ippa_id;
1643 
1644 	imp = ap->ippa_mod;
1645 	ASSERT(imp != NULL);
1646 
1647 	LOCK_MOD(imp, RW_READER);
1648 	modname = imp->ippm_name;
1649 
1650 	/*
1651 	 * Allocate a stats info structure.
1652 	 */
1653 
1654 	if ((sip = kmem_alloc(sizeof (ipp_stat_impl_t), KM_NOSLEEP)) == NULL)
1655 		return (ENOMEM);
1656 
1657 	/*
1658 	 * Create a set of kstats.
1659 	 */
1660 
1661 	DBG2(DBG_STATS, "creating stat set '%s' for action '%s'\n",
1662 	    name, class);
1663 	if ((ksp = kstat_create(modname, instance, name, class,
1664 	    KSTAT_TYPE_NAMED, nstat, KSTAT_FLAG_WRITABLE)) == NULL) {
1665 		kmem_free(sip, sizeof (ipp_stat_impl_t));
1666 		UNLOCK_ACTION(ap);
1667 		UNLOCK_MOD(imp);
1668 		return (EINVAL);	/* Assume EINVAL was the cause */
1669 	}
1670 
1671 	UNLOCK_ACTION(ap);
1672 	UNLOCK_MOD(imp);
1673 
1674 	DBG1(DBG_STATS, "ks_data = %p\n", ksp->ks_data);
1675 
1676 	/*
1677 	 * Set up the kstats structure with a private data pointer and an
1678 	 * 'update' function.
1679 	 */
1680 
1681 	ksp->ks_update = update_stats;
1682 	ksp->ks_private = (void *)sip;
1683 
1684 	/*
1685 	 * Keep a reference to the kstats structure in our own stats info
1686 	 * structure.
1687 	 */
1688 
1689 	sip->ippsi_ksp = ksp;
1690 	sip->ippsi_data = ksp->ks_data;
1691 
1692 	/*
1693 	 * Fill in the rest of the stats info structure.
1694 	 */
1695 
1696 	(void) strcpy(sip->ippsi_name, name);
1697 	sip->ippsi_arg = arg;
1698 	sip->ippsi_update = update;
1699 	sip->ippsi_limit = nstat;
1700 	sip->ippsi_count = 0;
1701 	mutex_init(sip->ippsi_lock, NULL, MUTEX_ADAPTIVE,
1702 	    (void *)ipltospl(LOCK_LEVEL));
1703 
1704 	/*
1705 	 * Case the stats info structure to a semi-opaque structure that
1706 	 * we pass back to the caller.
1707 	 */
1708 
1709 	sp = (ipp_stat_t *)sip;
1710 	ASSERT(sp->ipps_data == sip->ippsi_data);
1711 	*spp = sp;
1712 
1713 	rele_action(ap);
1714 	return (0);
1715 }
1716 #undef __FN__
1717 
1718 #define	__FN__	"ipp_stat_install"
1719 void
1720 ipp_stat_install(
1721 	ipp_stat_t	*sp)
1722 {
1723 	ipp_stat_impl_t	*sip = (ipp_stat_impl_t *)sp;
1724 
1725 	ASSERT(sp != NULL);
1726 
1727 	/*
1728 	 * Install the set of kstats referenced by the stats info structure.
1729 	 */
1730 
1731 	DBG1(DBG_STATS, "installing stat set '%s'\n", sip->ippsi_name);
1732 	kstat_install(sip->ippsi_ksp);
1733 }
1734 #undef	__FN__
1735 
1736 #define	__FN__	"ipp_stat_destroy"
1737 void
1738 ipp_stat_destroy(
1739 	ipp_stat_t	*sp)
1740 {
1741 	ipp_stat_impl_t	*sip = (ipp_stat_impl_t *)sp;
1742 
1743 	ASSERT(sp != NULL);
1744 
1745 	/*
1746 	 * Destroy the set of kstats referenced by the stats info structure.
1747 	 */
1748 
1749 	DBG1(DBG_STATS, "destroying stat set '%s'\n", sip->ippsi_name);
1750 	kstat_delete(sip->ippsi_ksp);
1751 
1752 	/*
1753 	 * Destroy the stats info structure itself.
1754 	 */
1755 
1756 	mutex_destroy(sip->ippsi_lock);
1757 	kmem_free(sip, sizeof (ipp_stat_impl_t));
1758 }
1759 #undef	__FN__
1760 
1761 #define	__FN__	"ipp_stat_named_init"
1762 int
1763 ipp_stat_named_init(
1764 	ipp_stat_t	*sp,
1765 	const char	*name,
1766 	uchar_t		type,
1767 	ipp_named_t	*np)
1768 {
1769 	ipp_stat_impl_t	*sip = (ipp_stat_impl_t *)sp;
1770 	uchar_t		ktype;
1771 
1772 	ASSERT(sp != NULL);
1773 	ASSERT(np != NULL);
1774 
1775 	if (name == NULL)
1776 		return (EINVAL);
1777 
1778 	if ((type & IPP_STAT_TAG) == 0)
1779 		return (EINVAL);
1780 	ktype = type & ~IPP_STAT_TAG;
1781 
1782 	/*
1783 	 * Check we will not exceed the maximum number of a stats that was
1784 	 * indicated during set creation.
1785 	 */
1786 
1787 	mutex_enter(sip->ippsi_lock);
1788 	if (sip->ippsi_count >= sip->ippsi_limit) {
1789 		mutex_exit(sip->ippsi_lock);
1790 		return (ENOSPC);
1791 	}
1792 
1793 	/*
1794 	 * Bump the count.
1795 	 */
1796 
1797 	sip->ippsi_count++;
1798 
1799 	/*
1800 	 * Create a new named kstat.
1801 	 */
1802 
1803 	DBG3(DBG_STATS, "%s.%s: knp = %p\n", sip->ippsi_name, name, np);
1804 	kstat_named_init(np, name, ktype);
1805 	mutex_exit(sip->ippsi_lock);
1806 
1807 	return (0);
1808 }
1809 #undef	__FN__
1810 
1811 #define	__FN__	"ipp_stat_named_op"
1812 int
1813 ipp_stat_named_op(
1814 	ipp_named_t	*np,
1815 	void		*valp,
1816 	int		rw)
1817 {
1818 	kstat_named_t	*knp;
1819 	uchar_t		type;
1820 	int		rc = 0;
1821 
1822 	ASSERT(np != NULL);
1823 	ASSERT(valp != NULL);
1824 
1825 	knp = np;
1826 	type = knp->data_type | IPP_STAT_TAG;
1827 
1828 	/*
1829 	 * Copy data to or from the named kstat, depending on the specified
1830 	 * opcode.
1831 	 */
1832 
1833 	switch (rw) {
1834 	case IPP_STAT_WRITE:
1835 		switch (type) {
1836 		case IPP_STAT_INT32:
1837 			*(int32_t *)valp = knp->value.i32;
1838 			break;
1839 		case IPP_STAT_UINT32:
1840 			*(uint32_t *)valp = knp->value.ui32;
1841 			break;
1842 		case IPP_STAT_INT64:
1843 			*(int64_t *)valp = knp->value.i64;
1844 			break;
1845 		case IPP_STAT_UINT64:
1846 			*(uint64_t *)valp = knp->value.ui64;
1847 			break;
1848 		case IPP_STAT_STRING:
1849 			(void) strncpy(valp, knp->value.c, 16);
1850 			break;
1851 		default:
1852 			ASSERT(0);	/* should not reach here */
1853 			break;
1854 		}
1855 
1856 		break;
1857 	case IPP_STAT_READ:
1858 		switch (type) {
1859 		case IPP_STAT_INT32:
1860 			knp->value.i32 = *(int32_t *)valp;
1861 			break;
1862 		case IPP_STAT_UINT32:
1863 			knp->value.ui32 = *(uint32_t *)valp;
1864 			break;
1865 		case IPP_STAT_INT64:
1866 			knp->value.i64 = *(int64_t *)valp;
1867 			break;
1868 		case IPP_STAT_UINT64:
1869 			knp->value.ui64 = *(uint64_t *)valp;
1870 			break;
1871 		case IPP_STAT_STRING:
1872 			(void) strncpy(knp->value.c, valp, 16);
1873 			break;
1874 		default:
1875 			ASSERT(0);	/* should not reach here */
1876 			break;
1877 		}
1878 
1879 		break;
1880 	default:
1881 		rc = EINVAL;
1882 	}
1883 
1884 	return (rc);
1885 }
1886 #undef	__FN__
1887 
1888 /*
1889  * Local functions (for local people. There's nothing for you here!)
1890  */
1891 
1892 #define	__FN__	"ref_mod"
1893 static int
1894 ref_mod(
1895 	ipp_action_t	*ap,
1896 	ipp_mod_t	*imp)
1897 {
1898 	ipp_ref_t	**rpp;
1899 	ipp_ref_t	*rp;
1900 
1901 	ASSERT(rw_write_held(ap->ippa_lock));
1902 	ASSERT(rw_write_held(imp->ippm_lock));
1903 
1904 	/*
1905 	 * Add the new reference at the end of the module's list.
1906 	 */
1907 
1908 	rpp = &(imp->ippm_action);
1909 	while ((rp = *rpp) != NULL) {
1910 		ASSERT(rp->ippr_action != ap);
1911 		rpp = &(rp->ippr_nextp);
1912 	}
1913 
1914 	/*
1915 	 * Allocate a reference structure.
1916 	 */
1917 
1918 	if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL)
1919 		return (ENOMEM);
1920 
1921 	/*
1922 	 * Set the reference to the action and link it onto the module's list.
1923 	 */
1924 
1925 	rp->ippr_action = ap;
1926 	*rpp = rp;
1927 
1928 	/*
1929 	 * Keep a 'back pointer' from the action structure to the module
1930 	 * structure.
1931 	 */
1932 
1933 	ap->ippa_mod = imp;
1934 
1935 	return (0);
1936 }
1937 #undef	__FN__
1938 
1939 #define	__FN__	"unref_mod"
1940 static void
1941 unref_mod(
1942 	ipp_action_t	*ap,
1943 	ipp_mod_t	*imp)
1944 {
1945 	ipp_ref_t	**rpp;
1946 	ipp_ref_t	*rp;
1947 
1948 	ASSERT(rw_write_held(ap->ippa_lock));
1949 	ASSERT(rw_write_held(imp->ippm_lock));
1950 
1951 	/*
1952 	 * Scan the module's list for the reference to the action.
1953 	 */
1954 
1955 	rpp = &(imp->ippm_action);
1956 	while ((rp = *rpp) != NULL) {
1957 		if (rp->ippr_action == ap)
1958 			break;
1959 		rpp = &(rp->ippr_nextp);
1960 	}
1961 	ASSERT(rp != NULL);
1962 
1963 	/*
1964 	 * Unlink the reference structure and free it.
1965 	 */
1966 
1967 	*rpp = rp->ippr_nextp;
1968 	kmem_free(rp, sizeof (ipp_ref_t));
1969 
1970 	/*
1971 	 * NULL the 'back pointer'.
1972 	 */
1973 
1974 	ap->ippa_mod = NULL;
1975 }
1976 #undef	__FN__
1977 
1978 #define	__FN__	"is_mod_busy"
1979 static int
1980 is_mod_busy(
1981 	ipp_mod_t	*imp)
1982 {
1983 	/*
1984 	 * Return a value which is true (non-zero) iff the module refers
1985 	 * to no actions.
1986 	 */
1987 
1988 	return (imp->ippm_action != NULL);
1989 }
1990 #undef	__FN__
1991 
1992 #define	__FN__	"get_mod_ref"
1993 static int
1994 get_mod_ref(
1995 	ipp_mod_t	*imp,
1996 	ipp_action_id_t	**bufp,
1997 	int		*neltp)
1998 {
1999 	ipp_ref_t	*rp;
2000 	int		nelt;
2001 	ipp_action_t	*ap;
2002 	ipp_action_id_t	*buf;
2003 	int		length;
2004 
2005 	ASSERT(rw_lock_held(imp->ippm_lock));
2006 
2007 	/*
2008 	 * Count the number of actions referred to from the module structure.
2009 	 */
2010 
2011 	nelt = 0;
2012 	for (rp = imp->ippm_action; rp != NULL; rp = rp->ippr_nextp) {
2013 		nelt++;
2014 	}
2015 	DBG1(DBG_LIST, "%d actions found\n", nelt);
2016 
2017 	/*
2018 	 * If there are no actions referred to then there's nothing to do.
2019 	 */
2020 
2021 	if (nelt == 0) {
2022 		*bufp = NULL;
2023 		*neltp = 0;
2024 		return (0);
2025 	}
2026 
2027 	/*
2028 	 * Allocate a buffer to pass back to the caller.
2029 	 */
2030 
2031 	length = nelt * sizeof (ipp_action_id_t);
2032 	if ((buf = kmem_alloc(length, KM_NOSLEEP)) == NULL)
2033 		return (ENOMEM);
2034 
2035 	/*
2036 	 * Fill the buffer with an array of action ids.
2037 	 */
2038 
2039 	*bufp = buf;
2040 	*neltp = nelt;
2041 
2042 	for (rp = imp->ippm_action; rp != NULL; rp = rp->ippr_nextp) {
2043 		ap = rp->ippr_action;
2044 		*buf++ = ap->ippa_id;
2045 	}
2046 
2047 	ASSERT((uintptr_t)buf == (uintptr_t)*bufp + length);
2048 	return (0);
2049 }
2050 #undef	__FN__
2051 
2052 #define	__FN__	"get_mods"
2053 static int
2054 get_mods(
2055 	ipp_mod_id_t	**bufp,
2056 	int		*neltp)
2057 {
2058 	ipp_mod_id_t	*buf;
2059 	int		length;
2060 	ipp_mod_id_t	mid;
2061 	ipp_mod_t	*imp;
2062 
2063 
2064 	rw_enter(ipp_mod_byname_lock, RW_READER);
2065 
2066 	/*
2067 	 * If there are no modules registered then there's nothing to do.
2068 	 */
2069 
2070 	if (ipp_mod_count == 0) {
2071 		DBG0(DBG_LIST, "no modules registered\n");
2072 		*bufp = NULL;
2073 		*neltp = 0;
2074 		rw_exit(ipp_mod_byname_lock);
2075 		return (0);
2076 	}
2077 
2078 	/*
2079 	 * Allocate a buffer to pass back to the caller.
2080 	 */
2081 
2082 	DBG1(DBG_LIST, "%d modules registered\n", ipp_mod_count);
2083 	length = ipp_mod_count * sizeof (ipp_mod_id_t);
2084 	if ((buf = kmem_alloc(length, KM_NOSLEEP)) == NULL) {
2085 		rw_exit(ipp_mod_byname_lock);
2086 		return (ENOMEM);
2087 	}
2088 
2089 	rw_enter(ipp_mod_byid_lock, RW_READER);
2090 
2091 	/*
2092 	 * Search the array of all modules.
2093 	 */
2094 
2095 	*bufp = buf;
2096 	*neltp = ipp_mod_count;
2097 
2098 	for (mid = IPP_MOD_RESERVED + 1; mid <= ipp_mid_limit; mid++) {
2099 		if ((imp = ipp_mod_byid[mid]) == NULL)
2100 			continue;
2101 
2102 		/*
2103 		 * If the module has 'destruct pending' set then it means it
2104 		 * is either still in the cache (i.e not allocated) or in the
2105 		 * process of being set up by alloc_mod().
2106 		 */
2107 
2108 		LOCK_MOD(imp, RW_READER);
2109 		ASSERT(imp->ippm_id == mid);
2110 
2111 		if (imp->ippm_destruct_pending) {
2112 			UNLOCK_MOD(imp);
2113 			continue;
2114 		}
2115 		UNLOCK_MOD(imp);
2116 
2117 		*buf++ = mid;
2118 	}
2119 
2120 	rw_exit(ipp_mod_byid_lock);
2121 	rw_exit(ipp_mod_byname_lock);
2122 
2123 	ASSERT((uintptr_t)buf == (uintptr_t)*bufp + length);
2124 	return (0);
2125 }
2126 #undef	__FN__
2127 
2128 #define	__FN__	"find_mod"
2129 static ipp_mod_id_t
2130 find_mod(
2131 	const char	*modname)
2132 {
2133 	ipp_mod_id_t	mid;
2134 	ipp_mod_t	*imp;
2135 	ipp_ref_t	*rp;
2136 	int		hb;
2137 
2138 	ASSERT(modname != NULL);
2139 
2140 	rw_enter(ipp_mod_byname_lock, RW_READER);
2141 
2142 	/*
2143 	 * Quick return if no modules are registered.
2144 	 */
2145 
2146 	if (ipp_mod_count == 0) {
2147 		rw_exit(ipp_mod_byname_lock);
2148 		return (IPP_MOD_INVAL);
2149 	}
2150 
2151 	/*
2152 	 * Find the hash bucket where the module structure should be.
2153 	 */
2154 
2155 	hb = hash(modname);
2156 	rp = ipp_mod_byname[hb];
2157 
2158 	/*
2159 	 * Scan the bucket for a match.
2160 	 */
2161 
2162 	while (rp != NULL) {
2163 		imp = rp->ippr_mod;
2164 		if (strcmp(imp->ippm_name, modname) == 0)
2165 			break;
2166 		rp = rp->ippr_nextp;
2167 	}
2168 
2169 	if (rp == NULL) {
2170 		rw_exit(ipp_mod_byname_lock);
2171 		return (IPP_MOD_INVAL);
2172 	}
2173 
2174 	if (imp->ippm_state == IPP_MODSTATE_PROTO) {
2175 		rw_exit(ipp_mod_byname_lock);
2176 		return (IPP_MOD_INVAL);
2177 	}
2178 
2179 	mid = imp->ippm_id;
2180 	rw_exit(ipp_mod_byname_lock);
2181 
2182 	return (mid);
2183 }
2184 #undef __FN__
2185 
2186 #define	__FN__	"alloc_mod"
2187 static int
2188 alloc_mod(
2189 	const char	*modname,
2190 	ipp_mod_id_t	*midp)
2191 {
2192 	ipp_mod_t	*imp;
2193 	ipp_ref_t	**rpp;
2194 	ipp_ref_t	*rp;
2195 	int		hb;
2196 
2197 	ASSERT(modname != NULL);
2198 	ASSERT(midp != NULL);
2199 
2200 	rw_enter(ipp_mod_byname_lock, RW_WRITER);
2201 
2202 	/*
2203 	 * Find the right hash bucket for a module of the given name.
2204 	 */
2205 
2206 	hb = hash(modname);
2207 	rpp = &ipp_mod_byname[hb];
2208 
2209 	/*
2210 	 * Scan the bucket making sure the module isn't already
2211 	 * registered.
2212 	 */
2213 
2214 	while ((rp = *rpp) != NULL) {
2215 		imp = rp->ippr_mod;
2216 		if (strcmp(imp->ippm_name, modname) == 0) {
2217 			DBG1(DBG_MOD, "module '%s' already exists\n", modname);
2218 			rw_exit(ipp_mod_byname_lock);
2219 			return (EEXIST);
2220 		}
2221 		rpp = &(rp->ippr_nextp);
2222 	}
2223 
2224 	/*
2225 	 * Allocate a new reference structure and a new module structure.
2226 	 */
2227 
2228 	if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL) {
2229 		rw_exit(ipp_mod_byname_lock);
2230 		return (ENOMEM);
2231 	}
2232 
2233 	if ((imp = kmem_cache_alloc(ipp_mod_cache, KM_NOSLEEP)) == NULL) {
2234 		kmem_free(rp, sizeof (ipp_ref_t));
2235 		rw_exit(ipp_mod_byname_lock);
2236 		return (ENOMEM);
2237 	}
2238 
2239 	/*
2240 	 * Set up the name of the new structure.
2241 	 */
2242 
2243 	(void) strcpy(imp->ippm_name, modname);
2244 
2245 	/*
2246 	 * Make sure the 'destruct pending' flag is clear. This indicates
2247 	 * that the structure is no longer part of the cache.
2248 	 */
2249 
2250 	LOCK_MOD(imp, RW_WRITER);
2251 	imp->ippm_destruct_pending = B_FALSE;
2252 	UNLOCK_MOD(imp);
2253 
2254 	/*
2255 	 * Set the reference and link it into the hash bucket.
2256 	 */
2257 
2258 	rp->ippr_mod = imp;
2259 	*rpp = rp;
2260 
2261 	/*
2262 	 * Increment the module count.
2263 	 */
2264 
2265 	ipp_mod_count++;
2266 
2267 	*midp = imp->ippm_id;
2268 	rw_exit(ipp_mod_byname_lock);
2269 	return (0);
2270 }
2271 #undef	__FN__
2272 
2273 #define	__FN__	"free_mod"
2274 static void
2275 free_mod(
2276 	ipp_mod_t	*imp)
2277 {
2278 	ipp_ref_t	**rpp;
2279 	ipp_ref_t	*rp;
2280 	int		hb;
2281 
2282 	rw_enter(ipp_mod_byname_lock, RW_WRITER);
2283 
2284 	/*
2285 	 * Find the hash bucket where the module structure should be.
2286 	 */
2287 
2288 	hb = hash(imp->ippm_name);
2289 	rpp = &ipp_mod_byname[hb];
2290 
2291 	/*
2292 	 * Scan the bucket for a match.
2293 	 */
2294 
2295 	while ((rp = *rpp) != NULL) {
2296 		if (rp->ippr_mod == imp)
2297 			break;
2298 		rpp = &(rp->ippr_nextp);
2299 	}
2300 	ASSERT(rp != NULL);
2301 
2302 	/*
2303 	 * Unlink the reference structure and free it.
2304 	 */
2305 
2306 	*rpp = rp->ippr_nextp;
2307 	kmem_free(rp, sizeof (ipp_ref_t));
2308 
2309 	/*
2310 	 * Decrement the module count.
2311 	 */
2312 
2313 	ipp_mod_count--;
2314 
2315 	/*
2316 	 * Empty the name.
2317 	 */
2318 
2319 	*imp->ippm_name = '\0';
2320 
2321 	/*
2322 	 * If the hold count is zero then we can free the structure
2323 	 * immediately, otherwise we defer to rele_mod().
2324 	 */
2325 
2326 	LOCK_MOD(imp, RW_WRITER);
2327 	imp->ippm_destruct_pending = B_TRUE;
2328 	if (imp->ippm_hold_count == 0) {
2329 		UNLOCK_MOD(imp);
2330 		kmem_cache_free(ipp_mod_cache, imp);
2331 		rw_exit(ipp_mod_byname_lock);
2332 		return;
2333 	}
2334 	UNLOCK_MOD(imp);
2335 
2336 	rw_exit(ipp_mod_byname_lock);
2337 }
2338 #undef __FN__
2339 
2340 #define	__FN__	"hold_mod"
2341 static ipp_mod_t *
2342 hold_mod(
2343 	ipp_mod_id_t	mid)
2344 {
2345 	ipp_mod_t	*imp;
2346 
2347 	if (mid < 0)
2348 		return (NULL);
2349 
2350 	/*
2351 	 * Use the module id as an index into the array of all module
2352 	 * structures.
2353 	 */
2354 
2355 	rw_enter(ipp_mod_byid_lock, RW_READER);
2356 	if ((imp = ipp_mod_byid[mid]) == NULL) {
2357 		rw_exit(ipp_mod_byid_lock);
2358 		return (NULL);
2359 	}
2360 
2361 	ASSERT(imp->ippm_id == mid);
2362 
2363 	/*
2364 	 * If the modul has 'destruct pending' set then it means it is either
2365 	 * still in the cache (i.e not allocated) or in the process of
2366 	 * being set up by alloc_mod().
2367 	 */
2368 
2369 	LOCK_MOD(imp, RW_READER);
2370 	if (imp->ippm_destruct_pending) {
2371 		UNLOCK_MOD(imp);
2372 		rw_exit(ipp_mod_byid_lock);
2373 		return (NULL);
2374 	}
2375 	UNLOCK_MOD(imp);
2376 
2377 	/*
2378 	 * Increment the hold count to prevent the structure from being
2379 	 * freed.
2380 	 */
2381 
2382 	atomic_add_32(&(imp->ippm_hold_count), 1);
2383 	rw_exit(ipp_mod_byid_lock);
2384 
2385 	return (imp);
2386 }
2387 #undef	__FN__
2388 
2389 #define	__FN__	"rele_mod"
2390 static void
2391 rele_mod(
2392 	ipp_mod_t	*imp)
2393 {
2394 	/*
2395 	 * This call means we're done with the pointer so we can drop the
2396 	 * hold count.
2397 	 */
2398 
2399 	ASSERT(imp->ippm_hold_count != 0);
2400 	atomic_add_32(&(imp->ippm_hold_count), -1);
2401 
2402 	/*
2403 	 * If the structure has 'destruct pending' set then we tried to free
2404 	 * it but couldn't, so do it now.
2405 	 */
2406 
2407 	LOCK_MOD(imp, RW_READER);
2408 	if (imp->ippm_destruct_pending && imp->ippm_hold_count == 0) {
2409 		UNLOCK_MOD(imp);
2410 		kmem_cache_free(ipp_mod_cache, imp);
2411 		return;
2412 	}
2413 
2414 	UNLOCK_MOD(imp);
2415 }
2416 #undef	__FN__
2417 
2418 #define	__FN__	"get_mid"
2419 static ipp_mod_id_t
2420 get_mid(
2421 	void)
2422 {
2423 	int	index;
2424 	int	start;
2425 	int	limit;
2426 
2427 	ASSERT(rw_write_held(ipp_mod_byid_lock));
2428 
2429 	/*
2430 	 * Start searching after the last module id we allocated.
2431 	 */
2432 
2433 	start = (int)ipp_next_mid;
2434 	limit = (int)ipp_mid_limit;
2435 
2436 	/*
2437 	 * Look for a spare slot in the array.
2438 	 */
2439 
2440 	index = start;
2441 	while (ipp_mod_byid[index] != NULL) {
2442 		index++;
2443 		if (index > limit)
2444 			index = IPP_MOD_RESERVED + 1;
2445 		if (index == start)
2446 			return (IPP_MOD_INVAL);
2447 	}
2448 
2449 	/*
2450 	 * Note that we've just allocated a new module id so that we can
2451 	 * start our search there next time.
2452 	 */
2453 
2454 	index++;
2455 	if (index > limit) {
2456 		ipp_next_mid = IPP_MOD_RESERVED + 1;
2457 	} else
2458 		ipp_next_mid = (ipp_mod_id_t)index;
2459 
2460 	return ((ipp_mod_id_t)(--index));
2461 }
2462 #undef	__FN__
2463 
2464 #define	__FN__	"condemn_action"
2465 static int
2466 condemn_action(
2467 	ipp_ref_t	**rpp,
2468 	ipp_action_t	*ap)
2469 {
2470 	ipp_ref_t	*rp;
2471 
2472 	DBG1(DBG_ACTION, "condemning action '%s'\n", ap->ippa_name);
2473 
2474 	/*
2475 	 * Check to see if the action is already condemned.
2476 	 */
2477 
2478 	while ((rp = *rpp) != NULL) {
2479 		if (rp->ippr_action == ap)
2480 			break;
2481 		rpp = &(rp->ippr_nextp);
2482 	}
2483 
2484 	/*
2485 	 * Create a new entry for the action.
2486 	 */
2487 
2488 	if (rp == NULL) {
2489 		if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL)
2490 			return (ENOMEM);
2491 
2492 		rp->ippr_action = ap;
2493 		*rpp = rp;
2494 	}
2495 
2496 	return (0);
2497 }
2498 #undef	__FN__
2499 
2500 #define	__FN__	"destroy_action"
2501 static int
2502 destroy_action(
2503 	ipp_action_t	*ap,
2504 	ipp_flags_t	flags)
2505 {
2506 	ipp_ops_t	*ippo;
2507 	ipp_mod_t	*imp;
2508 #define	MAXWAIT		10
2509 	uint32_t	wait;
2510 	int		rc;
2511 
2512 	/*
2513 	 * Check that the action is available.
2514 	 */
2515 
2516 	LOCK_ACTION(ap, RW_WRITER);
2517 	if (ap->ippa_state != IPP_ASTATE_AVAILABLE) {
2518 		UNLOCK_ACTION(ap);
2519 		rele_action(ap);
2520 		return (EPROTO);
2521 	}
2522 
2523 	/*
2524 	 * Note that the action is in the process of creation/destruction.
2525 	 */
2526 
2527 	ap->ippa_state = IPP_ASTATE_CONFIG_PENDING;
2528 
2529 	/*
2530 	 * Wait for the in-transit packet count for this action to fall to
2531 	 * zero (checking at millisecond intervals).
2532 	 *
2533 	 * NOTE: no new packets will enter the action now that the
2534 	 *	 state has been changed.
2535 	 */
2536 
2537 	for (wait = 0; ap->ippa_packets > 0 && wait < (MAXWAIT * 1000000);
2538 	    wait += 1000) {
2539 
2540 		/*
2541 		 * NOTE: We can hang onto the lock because the packet count is
2542 		 *	 decremented without needing to take the lock.
2543 		 */
2544 
2545 		drv_usecwait(1000);
2546 	}
2547 
2548 	/*
2549 	 * The packet count did not fall to zero.
2550 	 */
2551 	if (ap->ippa_packets > 0) {
2552 		ap->ippa_state = IPP_ASTATE_AVAILABLE;
2553 		UNLOCK_ACTION(ap);
2554 		rele_action(ap);
2555 		return (EAGAIN);
2556 	}
2557 
2558 	/*
2559 	 * Check to see if any other action has a dependency on this one.
2560 	 */
2561 
2562 	if (is_action_refd(ap)) {
2563 		ap->ippa_state = IPP_ASTATE_AVAILABLE;
2564 		UNLOCK_ACTION(ap);
2565 		rele_action(ap);
2566 		return (EBUSY);
2567 	}
2568 
2569 	imp = ap->ippa_mod;
2570 	ASSERT(imp != NULL);
2571 	UNLOCK_ACTION(ap);
2572 
2573 	ippo = imp->ippm_ops;
2574 	ASSERT(ippo != NULL);
2575 
2576 	/*
2577 	 * Call into the module to destroy the action context.
2578 	 */
2579 
2580 	CONFIG_WRITE_START(ap);
2581 	DBG1(DBG_ACTION, "destroying action '%s'\n", ap->ippa_name);
2582 	if ((rc = ippo->ippo_action_destroy(ap->ippa_id, flags)) != 0) {
2583 		LOCK_ACTION(ap, RW_WRITER);
2584 		ap->ippa_state = IPP_ASTATE_AVAILABLE;
2585 		UNLOCK_ACTION(ap);
2586 
2587 		CONFIG_WRITE_END(ap);
2588 
2589 		rele_action(ap);
2590 		return (rc);
2591 	}
2592 	CONFIG_WRITE_END(ap);
2593 
2594 	LOCK_ACTION(ap, RW_WRITER);
2595 	LOCK_MOD(imp, RW_WRITER);
2596 	unref_mod(ap, imp);
2597 	UNLOCK_MOD(imp);
2598 	ap->ippa_state = IPP_ASTATE_PROTO;
2599 	UNLOCK_ACTION(ap);
2600 
2601 	/*
2602 	 * Free the action structure.
2603 	 */
2604 
2605 	ASSERT(ap->ippa_ref == NULL);
2606 	free_action(ap);
2607 	rele_action(ap);
2608 	return (0);
2609 #undef	MAXWAIT
2610 }
2611 #undef	__FN__
2612 
2613 #define	__FN__	"ref_action"
2614 static int
2615 ref_action(
2616 	ipp_action_t	*refby_ap,
2617 	ipp_action_t	*ref_ap)
2618 {
2619 	ipp_ref_t	**rpp;
2620 	ipp_ref_t	**save_rpp;
2621 	ipp_ref_t	*rp;
2622 
2623 	ASSERT(rw_write_held(refby_ap->ippa_lock));
2624 	ASSERT(rw_write_held(ref_ap->ippa_lock));
2625 
2626 	/*
2627 	 * We want to add the new reference at the end of the refering
2628 	 * action's list.
2629 	 */
2630 
2631 	rpp = &(refby_ap->ippa_ref);
2632 	while ((rp = *rpp) != NULL) {
2633 		if (rp->ippr_action == ref_ap)
2634 			break;
2635 		rpp = &(rp->ippr_nextp);
2636 	}
2637 
2638 	if ((rp = *rpp) != NULL) {
2639 
2640 		/*
2641 		 * There is an existing reference so increment its counter.
2642 		 */
2643 
2644 		rp->ippr_count++;
2645 
2646 		/*
2647 		 * Find the 'back pointer' and increment its counter too.
2648 		 */
2649 
2650 		rp = ref_ap->ippa_refby;
2651 		while (rp != NULL) {
2652 			if (rp->ippr_action == refby_ap)
2653 				break;
2654 			rp = rp->ippr_nextp;
2655 		}
2656 		ASSERT(rp != NULL);
2657 
2658 		rp->ippr_count++;
2659 	} else {
2660 
2661 		/*
2662 		 * Allocate, fill in and link a new reference structure.
2663 		 */
2664 
2665 		if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL)
2666 			return (ENOMEM);
2667 
2668 		rp->ippr_action = ref_ap;
2669 		rp->ippr_count = 1;
2670 		*rpp = rp;
2671 		save_rpp = rpp;
2672 
2673 		/*
2674 		 * We keep a 'back pointer' which we want to add at the end of
2675 		 * a list in the referred action's structure.
2676 		 */
2677 
2678 		rpp = &(ref_ap->ippa_refby);
2679 		while ((rp = *rpp) != NULL) {
2680 			ASSERT(rp->ippr_action != refby_ap);
2681 			rpp = &(rp->ippr_nextp);
2682 		}
2683 
2684 		/*
2685 		 * Allocate another reference structure and, if this fails,
2686 		 * remember to clean up the first reference structure we
2687 		 * allocated.
2688 		 */
2689 
2690 		if ((rp = kmem_zalloc(sizeof (ipp_ref_t),
2691 		    KM_NOSLEEP)) == NULL) {
2692 			rpp = save_rpp;
2693 			rp = *rpp;
2694 			*rpp = NULL;
2695 			kmem_free(rp, sizeof (ipp_ref_t));
2696 
2697 			return (ENOMEM);
2698 		}
2699 
2700 		/*
2701 		 * Fill in the reference structure with the 'back pointer' and
2702 		 * link it into the list.
2703 		 */
2704 
2705 		rp->ippr_action = refby_ap;
2706 		rp->ippr_count = 1;
2707 		*rpp = rp;
2708 	}
2709 
2710 	return (0);
2711 }
2712 #undef	__FN__
2713 
2714 #define	__FN__	"unref_action"
2715 static int
2716 unref_action(
2717 	ipp_action_t	*refby_ap,
2718 	ipp_action_t	*ref_ap)
2719 {
2720 	ipp_ref_t	**rpp;
2721 	ipp_ref_t	*rp;
2722 
2723 	ASSERT(rw_write_held(refby_ap->ippa_lock));
2724 	ASSERT(rw_write_held(ref_ap->ippa_lock));
2725 
2726 	/*
2727 	 * Scan for the reference in the referring action's list.
2728 	 */
2729 
2730 	rpp = &(refby_ap->ippa_ref);
2731 	while ((rp = *rpp) != NULL) {
2732 		if (rp->ippr_action == ref_ap)
2733 			break;
2734 		rpp = &(rp->ippr_nextp);
2735 	}
2736 
2737 	if (rp == NULL)
2738 		return (ENOENT);
2739 
2740 	if (rp->ippr_count > 1) {
2741 
2742 		/*
2743 		 * There are currently multiple references so decrement the
2744 		 * count.
2745 		 */
2746 
2747 		rp->ippr_count--;
2748 
2749 		/*
2750 		 * Find the 'back pointer' and decrement its counter too.
2751 		 */
2752 
2753 		rp = ref_ap->ippa_refby;
2754 		while (rp != NULL) {
2755 			if (rp->ippr_action == refby_ap)
2756 				break;
2757 			rp = rp->ippr_nextp;
2758 		}
2759 		ASSERT(rp != NULL);
2760 
2761 		rp->ippr_count--;
2762 	} else {
2763 
2764 		/*
2765 		 * There is currently only a single reference, so unlink and
2766 		 * free the reference structure.
2767 		 */
2768 
2769 		*rpp = rp->ippr_nextp;
2770 		kmem_free(rp, sizeof (ipp_ref_t));
2771 
2772 		/*
2773 		 * Scan for the 'back pointer' in the referred action's list.
2774 		 */
2775 
2776 		rpp = &(ref_ap->ippa_refby);
2777 		while ((rp = *rpp) != NULL) {
2778 			if (rp->ippr_action == refby_ap)
2779 				break;
2780 			rpp = &(rp->ippr_nextp);
2781 		}
2782 		ASSERT(rp != NULL);
2783 
2784 		/*
2785 		 * Unlink and free this reference structure too.
2786 		 */
2787 
2788 		*rpp = rp->ippr_nextp;
2789 		kmem_free(rp, sizeof (ipp_ref_t));
2790 	}
2791 
2792 	return (0);
2793 }
2794 #undef	__FN__
2795 
2796 #define	__FN__	"is_action_refd"
2797 static int
2798 is_action_refd(
2799 	ipp_action_t	*ap)
2800 {
2801 	/*
2802 	 * Return a value which is true (non-zero) iff the action is not
2803 	 * referred to by any other actions.
2804 	 */
2805 
2806 	return (ap->ippa_refby != NULL);
2807 }
2808 #undef	__FN__
2809 
2810 #define	__FN__	"find_action"
2811 static ipp_action_id_t
2812 find_action(
2813 	const char	*aname)
2814 {
2815 	ipp_action_id_t	aid;
2816 	ipp_action_t	*ap;
2817 	ipp_ref_t	*rp;
2818 	int		hb;
2819 
2820 	ASSERT(aname != NULL);
2821 
2822 	rw_enter(ipp_action_byname_lock, RW_READER);
2823 
2824 	/*
2825 	 * Quick return if there are no actions defined at all.
2826 	 */
2827 
2828 	if (ipp_action_count == 0) {
2829 		rw_exit(ipp_action_byname_lock);
2830 		return (IPP_ACTION_INVAL);
2831 	}
2832 
2833 	/*
2834 	 * Find the hash bucket where the action structure should be.
2835 	 */
2836 
2837 	hb = hash(aname);
2838 	rp = ipp_action_byname[hb];
2839 
2840 	/*
2841 	 * Scan the bucket looking for a match.
2842 	 */
2843 
2844 	while (rp != NULL) {
2845 		ap = rp->ippr_action;
2846 		if (strcmp(ap->ippa_name, aname) == 0)
2847 			break;
2848 		rp = rp->ippr_nextp;
2849 	}
2850 
2851 	if (rp == NULL) {
2852 		rw_exit(ipp_action_byname_lock);
2853 		return (IPP_ACTION_INVAL);
2854 	}
2855 
2856 	if (ap->ippa_state == IPP_ASTATE_PROTO) {
2857 		rw_exit(ipp_action_byname_lock);
2858 		return (IPP_ACTION_INVAL);
2859 	}
2860 
2861 	aid = ap->ippa_id;
2862 	rw_exit(ipp_action_byname_lock);
2863 
2864 	return (aid);
2865 }
2866 #undef __FN__
2867 
2868 #define	__FN__	"alloc_action"
2869 static int
2870 alloc_action(
2871 	const char	*aname,
2872 	ipp_action_id_t	*aidp)
2873 {
2874 	ipp_action_t	*ap;
2875 	ipp_ref_t	**rpp;
2876 	ipp_ref_t	*rp;
2877 	int		hb;
2878 
2879 	ASSERT(aidp != NULL);
2880 
2881 	rw_enter(ipp_action_byname_lock, RW_WRITER);
2882 
2883 	/*
2884 	 * Find the right hash bucket for an action of the given name.
2885 	 * (Nameless actions always go in a special bucket).
2886 	 */
2887 
2888 	if (aname != NULL) {
2889 		hb = hash(aname);
2890 		rpp = &ipp_action_byname[hb];
2891 	} else
2892 		rpp = &ipp_action_noname;
2893 
2894 	/*
2895 	 * Scan the bucket to make sure that an action with the given name
2896 	 * does not already exist.
2897 	 */
2898 
2899 	while ((rp = *rpp) != NULL) {
2900 		ap = rp->ippr_action;
2901 		if (aname != NULL && strcmp(ap->ippa_name, aname) == 0) {
2902 			DBG1(DBG_ACTION, "action '%s' already exists\n",
2903 			    aname);
2904 			rw_exit(ipp_action_byname_lock);
2905 			return (EEXIST);
2906 		}
2907 		rpp = &(rp->ippr_nextp);
2908 	}
2909 
2910 	/*
2911 	 * Allocate a new reference structure and a new action structure.
2912 	 */
2913 
2914 	if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL) {
2915 		rw_exit(ipp_action_byname_lock);
2916 		return (ENOMEM);
2917 	}
2918 
2919 	if ((ap = kmem_cache_alloc(ipp_action_cache, KM_NOSLEEP)) == NULL) {
2920 		kmem_free(rp, sizeof (ipp_ref_t));
2921 		rw_exit(ipp_action_byname_lock);
2922 		return (ENOMEM);
2923 	}
2924 
2925 	/*
2926 	 * Dream up a name if there isn't a real one and note that the action is
2927 	 * really nameless.
2928 	 */
2929 
2930 	if (aname == NULL) {
2931 		(void) sprintf(ap->ippa_name, "$%08X", ap->ippa_id);
2932 		ap->ippa_nameless = B_TRUE;
2933 	} else
2934 		(void) strcpy(ap->ippa_name, aname);
2935 
2936 	/*
2937 	 * Make sure the 'destruct pending' flag is clear. This indicates that
2938 	 * the structure is no longer part of the cache.
2939 	 */
2940 
2941 	LOCK_ACTION(ap, RW_WRITER);
2942 	ap->ippa_destruct_pending = B_FALSE;
2943 	UNLOCK_ACTION(ap);
2944 
2945 	/*
2946 	 * Fill in the reference structure and lint it onto the list.
2947 	 */
2948 
2949 	rp->ippr_action = ap;
2950 	*rpp = rp;
2951 
2952 	/*
2953 	 * Increment the action count.
2954 	 */
2955 
2956 	ipp_action_count++;
2957 
2958 	*aidp = ap->ippa_id;
2959 	rw_exit(ipp_action_byname_lock);
2960 	return (0);
2961 }
2962 #undef	__FN__
2963 
2964 #define	__FN__	"free_action"
2965 static void
2966 free_action(
2967 	ipp_action_t	*ap)
2968 {
2969 	ipp_ref_t	**rpp;
2970 	ipp_ref_t	*rp;
2971 	int		hb;
2972 
2973 	rw_enter(ipp_action_byname_lock, RW_WRITER);
2974 
2975 	/*
2976 	 * Find the hash bucket where the action structure should be.
2977 	 */
2978 
2979 	if (!ap->ippa_nameless) {
2980 		hb = hash(ap->ippa_name);
2981 		rpp = &ipp_action_byname[hb];
2982 	} else
2983 		rpp = &ipp_action_noname;
2984 
2985 	/*
2986 	 * Scan the bucket for a match.
2987 	 */
2988 
2989 	while ((rp = *rpp) != NULL) {
2990 		if (rp->ippr_action == ap)
2991 			break;
2992 		rpp = &(rp->ippr_nextp);
2993 	}
2994 	ASSERT(rp != NULL);
2995 
2996 	/*
2997 	 * Unlink and free the reference structure.
2998 	 */
2999 
3000 	*rpp = rp->ippr_nextp;
3001 	kmem_free(rp, sizeof (ipp_ref_t));
3002 
3003 	/*
3004 	 * Decrement the action count.
3005 	 */
3006 
3007 	ipp_action_count--;
3008 
3009 	/*
3010 	 * Empty the name.
3011 	 */
3012 
3013 	*ap->ippa_name = '\0';
3014 
3015 	/*
3016 	 * If the hold count is zero then we can free the structure
3017 	 * immediately, otherwise we defer to rele_action().
3018 	 */
3019 
3020 	LOCK_ACTION(ap, RW_WRITER);
3021 	ap->ippa_destruct_pending = B_TRUE;
3022 	if (ap->ippa_hold_count == 0) {
3023 		UNLOCK_ACTION(ap);
3024 		kmem_cache_free(ipp_action_cache, ap);
3025 		rw_exit(ipp_action_byname_lock);
3026 		return;
3027 	}
3028 	UNLOCK_ACTION(ap);
3029 
3030 	rw_exit(ipp_action_byname_lock);
3031 }
3032 #undef __FN__
3033 
3034 #define	__FN__	"hold_action"
3035 static ipp_action_t *
3036 hold_action(
3037 	ipp_action_id_t	aid)
3038 {
3039 	ipp_action_t	*ap;
3040 
3041 	if (aid < 0)
3042 		return (NULL);
3043 
3044 	/*
3045 	 * Use the action id as an index into the array of all action
3046 	 * structures.
3047 	 */
3048 
3049 	rw_enter(ipp_action_byid_lock, RW_READER);
3050 	if ((ap = ipp_action_byid[aid]) == NULL) {
3051 		rw_exit(ipp_action_byid_lock);
3052 		return (NULL);
3053 	}
3054 
3055 	/*
3056 	 * If the action has 'destruct pending' set then it means it is either
3057 	 * still in the cache (i.e not allocated) or in the process of
3058 	 * being set up by alloc_action().
3059 	 */
3060 
3061 	LOCK_ACTION(ap, RW_READER);
3062 	if (ap->ippa_destruct_pending) {
3063 		UNLOCK_ACTION(ap);
3064 		rw_exit(ipp_action_byid_lock);
3065 		return (NULL);
3066 	}
3067 	UNLOCK_ACTION(ap);
3068 
3069 	/*
3070 	 * Increment the hold count to prevent the structure from being
3071 	 * freed.
3072 	 */
3073 
3074 	atomic_add_32(&(ap->ippa_hold_count), 1);
3075 	rw_exit(ipp_action_byid_lock);
3076 
3077 	return (ap);
3078 }
3079 #undef	__FN__
3080 
3081 #define	__FN__	"rele_action"
3082 static void
3083 rele_action(
3084 	ipp_action_t	*ap)
3085 {
3086 	/*
3087 	 * This call means we're done with the pointer so we can drop the
3088 	 * hold count.
3089 	 */
3090 
3091 	ASSERT(ap->ippa_hold_count != 0);
3092 	atomic_add_32(&(ap->ippa_hold_count), -1);
3093 
3094 	/*
3095 	 * If the structure has 'destruct pending' set then we tried to free
3096 	 * it but couldn't, so do it now.
3097 	 */
3098 
3099 	LOCK_ACTION(ap, RW_READER);
3100 	if (ap->ippa_destruct_pending && ap->ippa_hold_count == 0) {
3101 		UNLOCK_ACTION(ap);
3102 		kmem_cache_free(ipp_action_cache, ap);
3103 		return;
3104 	}
3105 	UNLOCK_ACTION(ap);
3106 }
3107 #undef	__FN__
3108 
3109 #define	__FN__	"get_aid"
3110 static ipp_action_id_t
3111 get_aid(
3112 	void)
3113 {
3114 	int	index;
3115 	int	start;
3116 	int	limit;
3117 
3118 	ASSERT(rw_write_held(ipp_action_byid_lock));
3119 
3120 	/*
3121 	 * Start searching after the last action id that we allocated.
3122 	 */
3123 
3124 	start = (int)ipp_next_aid;
3125 	limit = (int)ipp_aid_limit;
3126 
3127 	/*
3128 	 * Look for a spare slot in the array.
3129 	 */
3130 
3131 	index = start;
3132 	while (ipp_action_byid[index] != NULL) {
3133 		index++;
3134 		if (index > limit)
3135 			index = IPP_ACTION_RESERVED + 1;
3136 		if (index == start)
3137 			return (IPP_ACTION_INVAL);
3138 	}
3139 
3140 	/*
3141 	 * Note that we've just allocated a new action id so that we can
3142 	 * start our search there next time.
3143 	 */
3144 
3145 	index++;
3146 	if (index > limit)
3147 		ipp_next_aid = IPP_ACTION_RESERVED + 1;
3148 	else
3149 		ipp_next_aid = (ipp_action_id_t)index;
3150 
3151 	return ((ipp_action_id_t)(--index));
3152 }
3153 #undef	__FN__
3154 
3155 #define	__FN__	"alloc_packet"
3156 static int
3157 alloc_packet(
3158 	const char	*name,
3159 	ipp_action_id_t	aid,
3160 	ipp_packet_t	**ppp)
3161 {
3162 	ipp_packet_t	*pp;
3163 	ipp_class_t	*cp;
3164 
3165 	if ((pp = kmem_cache_alloc(ipp_packet_cache, KM_NOSLEEP)) == NULL)
3166 		return (ENOMEM);
3167 
3168 	/*
3169 	 * Set the packet up with a single class.
3170 	 */
3171 
3172 	cp = &(pp->ippp_class_array[0]);
3173 	pp->ippp_class_windex = 1;
3174 
3175 	(void) strcpy(cp->ippc_name, name);
3176 	cp->ippc_aid = aid;
3177 
3178 	*ppp = pp;
3179 	return (0);
3180 }
3181 #undef	__FN__
3182 
3183 #define	__FN__	"realloc_packet"
3184 static int
3185 realloc_packet(
3186 	ipp_packet_t	*pp)
3187 {
3188 	uint_t		length;
3189 	ipp_class_t	*array;
3190 
3191 	length = (pp->ippp_class_limit + 1) << 1;
3192 	if ((array = kmem_alloc(length * sizeof (ipp_class_t),
3193 	    KM_NOSLEEP)) == NULL)
3194 		return (ENOMEM);
3195 
3196 	bcopy(pp->ippp_class_array, array,
3197 	    (length >> 1) * sizeof (ipp_class_t));
3198 
3199 	kmem_free(pp->ippp_class_array,
3200 	    (length >> 1) * sizeof (ipp_class_t));
3201 
3202 	pp->ippp_class_array = array;
3203 	pp->ippp_class_limit = length - 1;
3204 
3205 	return (0);
3206 }
3207 #undef	__FN__
3208 
3209 #define	__FN__	"free_packet"
3210 static void
3211 free_packet(
3212 	ipp_packet_t	*pp)
3213 {
3214 	pp->ippp_class_windex = 0;
3215 	pp->ippp_class_rindex = 0;
3216 
3217 	pp->ippp_data = NULL;
3218 	pp->ippp_private = NULL;
3219 
3220 	kmem_cache_free(ipp_packet_cache, pp);
3221 }
3222 #undef	__FN__
3223 
3224 #define	__FN__ 	"hash"
3225 static int
3226 hash(
3227 	const char	*name)
3228 {
3229 	int		val = 0;
3230 	char		*ptr;
3231 
3232 	/*
3233 	 * Make a hash value by XORing all the ascii codes in the text string.
3234 	 */
3235 
3236 	for (ptr = (char *)name; *ptr != NULL; ptr++) {
3237 		val ^= *ptr;
3238 	}
3239 
3240 	/*
3241 	 * Return the value modulo the number of hash buckets we allow.
3242 	 */
3243 
3244 	return (val % IPP_NBUCKET);
3245 }
3246 #undef	__FN__
3247 
3248 #define	__FN__	"update_stats"
3249 static int
3250 update_stats(
3251 	kstat_t		*ksp,
3252 	int		rw)
3253 {
3254 	ipp_stat_impl_t	*sip;
3255 
3256 	ASSERT(ksp->ks_private != NULL);
3257 	sip = (ipp_stat_impl_t *)ksp->ks_private;
3258 
3259 	/*
3260 	 * Call the update function passed to ipp_stat_create() for the given
3261 	 * set of kstats.
3262 	 */
3263 
3264 	return (sip->ippsi_update((ipp_stat_t *)sip, sip->ippsi_arg, rw));
3265 }
3266 #undef	__FN__
3267 
3268 #define	__FN__	"init_mods"
3269 static void
3270 init_mods(
3271 	void)
3272 {
3273 	/*
3274 	 * Initialise the array of all module structures and the module
3275 	 * structure kmem cache.
3276 	 */
3277 
3278 	rw_init(ipp_mod_byid_lock, NULL, RW_DEFAULT,
3279 	    (void *)ipltospl(LOCK_LEVEL));
3280 	ipp_mod_byid = kmem_zalloc(sizeof (ipp_mod_t *) * (ipp_max_mod + 1),
3281 	    KM_SLEEP);
3282 	ipp_mod_byid[ipp_max_mod] = (ipp_mod_t *)-1;
3283 	ipp_mid_limit = (ipp_mod_id_t)(ipp_max_mod - 1);
3284 
3285 	ipp_mod_cache = kmem_cache_create("ipp_mod", sizeof (ipp_mod_t),
3286 	    IPP_ALIGN, mod_constructor, mod_destructor, NULL, NULL, NULL, 0);
3287 	ASSERT(ipp_mod_cache != NULL);
3288 
3289 	/*
3290 	 * Initialize the 'module by name' hash bucket array.
3291 	 */
3292 
3293 	rw_init(ipp_mod_byname_lock, NULL, RW_DEFAULT,
3294 	    (void *)ipltospl(LOCK_LEVEL));
3295 	bzero(ipp_mod_byname, IPP_NBUCKET * sizeof (ipp_ref_t *));
3296 }
3297 #undef	__FN__
3298 
3299 #define	__FN__	"init_actions"
3300 static void
3301 init_actions(
3302 	void)
3303 {
3304 	/*
3305 	 * Initialise the array of all action structures and the action
3306 	 * structure cache.
3307 	 */
3308 
3309 	rw_init(ipp_action_byid_lock, NULL, RW_DEFAULT,
3310 	    (void *)ipltospl(LOCK_LEVEL));
3311 	ipp_action_byid = kmem_zalloc(sizeof (ipp_action_t *) *
3312 	    (ipp_max_action + 1), KM_SLEEP);
3313 	ipp_action_byid[ipp_max_action] = (ipp_action_t *)-1;
3314 	ipp_aid_limit = (ipp_action_id_t)(ipp_max_action - 1);
3315 
3316 	ipp_action_cache = kmem_cache_create("ipp_action",
3317 	    sizeof (ipp_action_t), IPP_ALIGN, action_constructor,
3318 	    action_destructor, NULL, NULL, NULL, 0);
3319 	ASSERT(ipp_action_cache != NULL);
3320 
3321 	/*
3322 	 * Initialize the 'action by name' hash bucket array (and the special
3323 	 * 'hash' bucket for nameless actions).
3324 	 */
3325 
3326 	rw_init(ipp_action_byname_lock, NULL, RW_DEFAULT,
3327 	    (void *)ipltospl(LOCK_LEVEL));
3328 	bzero(ipp_action_byname, IPP_NBUCKET * sizeof (ipp_ref_t *));
3329 	ipp_action_noname = NULL;
3330 }
3331 #undef	__FN__
3332 
3333 #define	__FN__	"init_packets"
3334 static void
3335 init_packets(
3336 	void)
3337 {
3338 	/*
3339 	 * Initialise the packet structure cache.
3340 	 */
3341 
3342 	ipp_packet_cache = kmem_cache_create("ipp_packet",
3343 	    sizeof (ipp_packet_t), IPP_ALIGN, packet_constructor,
3344 	    packet_destructor, NULL, NULL, NULL, 0);
3345 	ASSERT(ipp_packet_cache != NULL);
3346 }
3347 #undef	__FN__
3348 
3349 /*
3350  * Kmem cache constructor/destructor functions.
3351  */
3352 
3353 #define	__FN__	"mod_constructor"
3354 /*ARGSUSED*/
3355 static int
3356 mod_constructor(
3357 	void		*buf,
3358 	void		*cdrarg,
3359 	int		kmflags)
3360 {
3361 	ipp_mod_t	*imp;
3362 	ipp_mod_id_t	mid;
3363 
3364 	ASSERT(buf != NULL);
3365 	bzero(buf, sizeof (ipp_mod_t));
3366 	imp = (ipp_mod_t *)buf;
3367 
3368 	rw_enter(ipp_mod_byid_lock, RW_WRITER);
3369 
3370 	/*
3371 	 * Get a new module id.
3372 	 */
3373 
3374 	if ((mid = get_mid()) <= IPP_MOD_RESERVED) {
3375 		rw_exit(ipp_mod_byid_lock);
3376 		return (-1);
3377 	}
3378 
3379 	/*
3380 	 * Initialize the buffer as a module structure in PROTO form.
3381 	 */
3382 
3383 	imp->ippm_destruct_pending = B_TRUE;
3384 	imp->ippm_state = IPP_MODSTATE_PROTO;
3385 	rw_init(imp->ippm_lock, NULL, RW_DEFAULT,
3386 	    (void *)ipltospl(LOCK_LEVEL));
3387 
3388 	/*
3389 	 * Insert it into the array of all module structures.
3390 	 */
3391 
3392 	imp->ippm_id = mid;
3393 	ipp_mod_byid[mid] = imp;
3394 
3395 	rw_exit(ipp_mod_byid_lock);
3396 
3397 	return (0);
3398 }
3399 #undef	__FN__
3400 
3401 #define	__FN__	"mod_destructor"
3402 /*ARGSUSED*/
3403 static void
3404 mod_destructor(
3405 	void		*buf,
3406 	void		*cdrarg)
3407 {
3408 	ipp_mod_t	*imp;
3409 
3410 	ASSERT(buf != NULL);
3411 	imp = (ipp_mod_t *)buf;
3412 
3413 	ASSERT(imp->ippm_state == IPP_MODSTATE_PROTO);
3414 	ASSERT(imp->ippm_action == NULL);
3415 	ASSERT(*imp->ippm_name == '\0');
3416 	ASSERT(imp->ippm_destruct_pending);
3417 
3418 	rw_enter(ipp_mod_byid_lock, RW_WRITER);
3419 	ASSERT(imp->ippm_hold_count == 0);
3420 
3421 	/*
3422 	 * NULL the entry in the array of all module structures.
3423 	 */
3424 
3425 	ipp_mod_byid[imp->ippm_id] = NULL;
3426 
3427 	/*
3428 	 * Clean up any remnants of the module structure as the buffer is
3429 	 * about to disappear.
3430 	 */
3431 
3432 	rw_destroy(imp->ippm_lock);
3433 	rw_exit(ipp_mod_byid_lock);
3434 }
3435 #undef	__FN__
3436 
3437 #define	__FN__	"action_constructor"
3438 /*ARGSUSED*/
3439 static int
3440 action_constructor(
3441 	void		*buf,
3442 	void		*cdrarg,
3443 	int		kmflags)
3444 {
3445 	ipp_action_t	*ap;
3446 	ipp_action_id_t	aid;
3447 
3448 	ASSERT(buf != NULL);
3449 	bzero(buf, sizeof (ipp_action_t));
3450 	ap = (ipp_action_t *)buf;
3451 
3452 	rw_enter(ipp_action_byid_lock, RW_WRITER);
3453 
3454 	/*
3455 	 * Get a new action id.
3456 	 */
3457 
3458 	if ((aid = get_aid()) <= IPP_ACTION_RESERVED) {
3459 		rw_exit(ipp_action_byid_lock);
3460 		return (-1);
3461 	}
3462 
3463 	/*
3464 	 * Initialize the buffer as an action structure in PROTO form.
3465 	 */
3466 
3467 	ap->ippa_state = IPP_ASTATE_PROTO;
3468 	ap->ippa_destruct_pending = B_TRUE;
3469 	rw_init(ap->ippa_lock, NULL, RW_DEFAULT,
3470 	    (void *)ipltospl(LOCK_LEVEL));
3471 	CONFIG_LOCK_INIT(ap->ippa_config_lock);
3472 
3473 	/*
3474 	 * Insert it into the array of all action structures.
3475 	 */
3476 
3477 	ap->ippa_id = aid;
3478 	ipp_action_byid[aid] = ap;
3479 
3480 	rw_exit(ipp_action_byid_lock);
3481 	return (0);
3482 }
3483 #undef	__FN__
3484 
3485 #define	__FN__	"action_destructor"
3486 /*ARGSUSED*/
3487 static void
3488 action_destructor(
3489 	void		*buf,
3490 	void		*cdrarg)
3491 {
3492 	ipp_action_t	*ap;
3493 
3494 	ASSERT(buf != NULL);
3495 	ap = (ipp_action_t *)buf;
3496 
3497 	ASSERT(ap->ippa_state == IPP_ASTATE_PROTO);
3498 	ASSERT(ap->ippa_ref == NULL);
3499 	ASSERT(ap->ippa_refby == NULL);
3500 	ASSERT(ap->ippa_packets == 0);
3501 	ASSERT(*ap->ippa_name == '\0');
3502 	ASSERT(ap->ippa_destruct_pending);
3503 
3504 	rw_enter(ipp_action_byid_lock, RW_WRITER);
3505 	ASSERT(ap->ippa_hold_count == 0);
3506 
3507 	/*
3508 	 * NULL the entry in the array of all action structures.
3509 	 */
3510 
3511 	ipp_action_byid[ap->ippa_id] = NULL;
3512 
3513 	/*
3514 	 * Clean up any remnants of the action structure as the buffer is
3515 	 * about to disappear.
3516 	 */
3517 
3518 	CONFIG_LOCK_FINI(ap->ippa_config_lock);
3519 	rw_destroy(ap->ippa_lock);
3520 
3521 	rw_exit(ipp_action_byid_lock);
3522 }
3523 #undef	__FN__
3524 
3525 #define	__FN__	"packet_constructor"
3526 /*ARGSUSED*/
3527 static int
3528 packet_constructor(
3529 	void		*buf,
3530 	void		*cdrarg,
3531 	int		kmflags)
3532 {
3533 	ipp_packet_t	*pp;
3534 	ipp_class_t	*cp;
3535 
3536 	ASSERT(buf != NULL);
3537 	bzero(buf, sizeof (ipp_packet_t));
3538 	pp = (ipp_packet_t *)buf;
3539 
3540 	if ((cp = kmem_alloc(ipp_packet_classes * sizeof (ipp_class_t),
3541 	    KM_NOSLEEP)) == NULL)
3542 		return (ENOMEM);
3543 
3544 	pp->ippp_class_array = cp;
3545 	pp->ippp_class_windex = 0;
3546 	pp->ippp_class_rindex = 0;
3547 	pp->ippp_class_limit = ipp_packet_classes - 1;
3548 
3549 	return (0);
3550 }
3551 #undef	__FN__
3552 
3553 #define	__FN__	"packet_destructor"
3554 /*ARGSUSED*/
3555 static void
3556 packet_destructor(
3557 	void		*buf,
3558 	void		*cdrarg)
3559 {
3560 	ipp_packet_t	*pp;
3561 
3562 	ASSERT(buf != NULL);
3563 	pp = (ipp_packet_t *)buf;
3564 
3565 	ASSERT(pp->ippp_data == NULL);
3566 	ASSERT(pp->ippp_class_windex == 0);
3567 	ASSERT(pp->ippp_class_rindex == 0);
3568 	ASSERT(pp->ippp_private == NULL);
3569 	ASSERT(pp->ippp_private_free == NULL);
3570 
3571 	kmem_free(pp->ippp_class_array,
3572 	    (pp->ippp_class_limit + 1) * sizeof (ipp_class_t));
3573 
3574 	if (pp->ippp_log != NULL) {
3575 		kmem_free(pp->ippp_log,
3576 		    (pp->ippp_log_limit + 1) * sizeof (ipp_log_t));
3577 	}
3578 }
3579 #undef	__FN__
3580 
3581 /*
3582  * Debug message printout code.
3583  */
3584 
3585 #ifdef	IPP_DBG
3586 static void
3587 ipp_debug(
3588 	uint64_t	type,
3589 	const char	*fn,
3590 	char		*fmt,
3591 			...)
3592 {
3593 	char		buf[255];
3594 	va_list		adx;
3595 
3596 	if ((type & ipp_debug_flags) == 0)
3597 		return;
3598 
3599 	mutex_enter(debug_mutex);
3600 	va_start(adx, fmt);
3601 	(void) vsnprintf(buf, 255, fmt, adx);
3602 	va_end(adx);
3603 
3604 	printf("(%llx) %s: %s", (unsigned long long)curthread->t_did, fn,
3605 	    buf);
3606 	mutex_exit(debug_mutex);
3607 }
3608 #endif	/* IPP_DBG */
3609