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