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 */