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