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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/systm.h> 28 #include <sys/socket.h> 29 #include <netinet/in.h> 30 #include <sys/modctl.h> 31 #include <sys/sunddi.h> 32 #include <ipp/ipp.h> 33 #include <ipp/ipp_config.h> 34 #include <inet/common.h> 35 #include <ipp/dscpmk/dscpmk_impl.h> 36 37 #define D_SM_COMMENT "IPP dscpmk marker module" 38 39 /* DDI file for dscpmk ipp module */ 40 41 /* default dscp map - dscp unchanged */ 42 uint8_t default_dscp_map[DSCPMK_ARRAY_COUNT] = { 43 0, 1, 2, 3, 44 4, 5, 6, 7, 45 8, 9, 10, 11, 46 12, 13, 14, 15, 47 16, 17, 18, 19, 48 20, 21, 22, 23, 49 24, 25, 26, 27, 50 28, 29, 30, 31, 51 32, 33, 34, 35, 52 36, 37, 38, 39, 53 40, 41, 42, 43, 54 44, 45, 46, 47, 55 48, 49, 50, 51, 56 52, 53, 54, 55, 57 56, 57, 58, 59, 58 60, 61, 62, 63 59 }; 60 61 static int dscpmk_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t); 62 static int dscpmk_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t); 63 static int dscpmk_destroy_action(ipp_action_id_t, ipp_flags_t); 64 static int dscpmk_info(ipp_action_id_t, int (*)(nvlist_t *, void *), void *, 65 ipp_flags_t); 66 static int dscpmk_invoke_action(ipp_action_id_t, ipp_packet_t *); 67 68 /* Creating and updating summary stats */ 69 static int dscpmk_summ_statinit(ipp_action_id_t, dscpmk_data_t *); 70 static int dscpmk_update_stats(ipp_stat_t *, void *, int); 71 72 /* Creating and updating per-dscp stats */ 73 static int dscpmk_det_statinit(ipp_action_id_t, dscpmk_data_t *, int); 74 static int dscpmk_update_det_stats(ipp_stat_t *, void *, int); 75 76 /* Entry points for this IPP module */ 77 ipp_ops_t dscpmk_ops = { 78 IPPO_REV, 79 dscpmk_create_action, /* ippo_action_create */ 80 dscpmk_modify_action, /* ippo_action_modify */ 81 dscpmk_destroy_action, /* ippo_action_destroy */ 82 dscpmk_info, /* ippo_action_info */ 83 dscpmk_invoke_action /* ippo_action_invoke */ 84 }; 85 86 extern struct mod_ops mod_ippops; 87 88 /* 89 * Module linkage information for the kernel. 90 */ 91 static struct modlipp modlipp = { 92 &mod_ippops, 93 D_SM_COMMENT, 94 &dscpmk_ops 95 }; 96 97 static struct modlinkage modlinkage = { 98 MODREV_1, 99 { (void *)&modlipp, NULL } 100 }; 101 102 103 int 104 _init(void) 105 { 106 return (mod_install(&modlinkage)); 107 } 108 109 int 110 _fini(void) 111 { 112 return (mod_remove(&modlinkage)); 113 } 114 115 int 116 _info(struct modinfo *modinfop) 117 { 118 return (mod_info(&modlinkage, modinfop)); 119 } 120 121 static int 122 dscpmk_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags) 123 { 124 nvlist_t *nvlp; 125 dscpmk_data_t *dscpmk_data; 126 char *next_action; 127 int err, cnt; 128 int32_t *tbl; 129 uint_t nelem = DSCPMK_ARRAY_COUNT; 130 uint32_t bstats; 131 132 ASSERT((nvlpp != NULL) && (*nvlpp != NULL)); 133 134 nvlp = *nvlpp; 135 *nvlpp = NULL; /* nvlist should be NULL on return */ 136 137 if ((dscpmk_data = kmem_zalloc(DSCPMK_DATA_SZ, KM_NOSLEEP)) == NULL) { 138 nvlist_free(nvlp); 139 return (ENOMEM); 140 } 141 142 /* parse next action name */ 143 if ((err = nvlist_lookup_string(nvlp, DSCPMK_NEXT_ACTION_NAME, 144 &next_action)) != 0) { 145 nvlist_free(nvlp); 146 dscpmk0dbg(("dscpmk_create_action: invalid config, " \ 147 "next_action name missing\n")); 148 kmem_free(dscpmk_data, DSCPMK_DATA_SZ); 149 return (err); 150 } 151 152 if ((dscpmk_data->next_action = ipp_action_lookup(next_action)) 153 == IPP_ACTION_INVAL) { 154 nvlist_free(nvlp); 155 dscpmk0dbg(("dscpmk_create_action: next_action "\ 156 "invalid\n")); 157 kmem_free(dscpmk_data, DSCPMK_DATA_SZ); 158 return (EINVAL); 159 } 160 161 /* Fill in the default value */ 162 bcopy(default_dscp_map, dscpmk_data->dscp_map, 163 sizeof (default_dscp_map)); 164 /* 165 * parse dscp_map, if present. Note that the module gets 166 * the entire array with unchanged entries marked with -1. 167 */ 168 if ((err = nvlist_lookup_int32_array(nvlp, DSCPMK_DSCP_MAP, 169 &tbl, &nelem)) == 0) { 170 for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) { 171 if ((tbl[cnt] != DSCPMK_UNCHANGED_DSCP) && (tbl[cnt] != 172 dscpmk_data->dscp_map[cnt])) { 173 dscpmk_data->dscp_map[cnt] = tbl[cnt]; 174 } 175 } 176 } 177 178 179 /* parse summary_stats boolean */ 180 if ((err = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats)) 181 != 0) { 182 dscpmk_data->summary_stats = B_FALSE; 183 } else { 184 dscpmk_data->summary_stats = (bstats != 0) ? B_TRUE : B_FALSE; 185 /* If stats is needed, initialize the stats structure */ 186 if (dscpmk_data->summary_stats) { 187 if ((err = dscpmk_summ_statinit(aid, dscpmk_data)) 188 != 0) { 189 nvlist_free(nvlp); 190 kmem_free(dscpmk_data, DSCPMK_DATA_SZ); 191 return (err); 192 } 193 } 194 } 195 196 /* 197 * Initialize per-dscp stats; B_FALSE in present indicates a dscp 198 * with this value (count) is not present in the map. 199 */ 200 for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) { 201 dscpmk_data->dscp_stats[cnt].present = B_FALSE; 202 dscpmk_data->dscp_stats[cnt].npackets = 0; 203 } 204 205 /* parse detailed_stats boolean */ 206 if ((err = nvlist_lookup_uint32(nvlp, DSCPMK_DETAILED_STATS, &bstats)) 207 != 0) { 208 dscpmk_data->detailed_stats = B_FALSE; 209 } else { 210 dscpmk_data->detailed_stats = (bstats != 0) ? B_TRUE : B_FALSE; 211 /* If stats is needed, initialize the stats structure */ 212 if (dscpmk_data->detailed_stats) { 213 for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) { 214 int val = dscpmk_data->dscp_map[cnt]; 215 if (dscpmk_data->dscp_stats[val].present) { 216 continue; 217 } 218 dscpmk_data->dscp_stats[val].present = B_TRUE; 219 if ((err = dscpmk_det_statinit(aid, dscpmk_data, 220 val)) != 0) { 221 nvlist_free(nvlp); 222 kmem_free(dscpmk_data, DSCPMK_DATA_SZ); 223 return (err); 224 } 225 } 226 } 227 } 228 229 /* Free the nvlist */ 230 nvlist_free(nvlp); 231 232 /* set action chain reference */ 233 if ((err = ipp_action_ref(aid, dscpmk_data->next_action, flags)) != 0) { 234 dscpmk0dbg(("dscpmk_create_action: ipp_action_ref " \ 235 "returned with error %d\n", err)); 236 if (dscpmk_data->summary_stats) { 237 ipp_stat_destroy(dscpmk_data->stats); 238 } 239 if (dscpmk_data->detailed_stats) { 240 for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) { 241 if (dscpmk_data->dscp_stats[cnt].present) { 242 ipp_stat_destroy( 243 dscpmk_data->dscp_stats[cnt].stats); 244 } 245 } 246 } 247 kmem_free(dscpmk_data, DSCPMK_DATA_SZ); 248 return (err); 249 } 250 251 ipp_action_set_ptr(aid, (void *)dscpmk_data); 252 return (0); 253 } 254 255 static int 256 dscpmk_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags) 257 { 258 nvlist_t *nvlp; 259 int err = 0, cnt; 260 uint8_t config_type; 261 char *next_action_name; 262 uint32_t bstats; 263 uint_t nelem = DSCPMK_ARRAY_COUNT; 264 int32_t *tbl; 265 ipp_action_id_t next_action; 266 dscpmk_data_t *dscpmk_data; 267 268 ASSERT((nvlpp != NULL) && (*nvlpp != NULL)); 269 270 nvlp = *nvlpp; 271 *nvlpp = NULL; /* nvlist should be NULL when this returns */ 272 273 if ((err = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type)) 274 != 0) { 275 nvlist_free(nvlp); 276 dscpmk0dbg(("dscpmk_modify_action: invalid cfg. type\n")); 277 return (err); 278 } 279 280 if (config_type != IPP_SET) { 281 nvlist_free(nvlp); 282 dscpmk0dbg(("dscpmk_modify_action: invalid cfg. type " \ 283 "%d\n", config_type)); 284 return (EINVAL); 285 } 286 287 dscpmk_data = (dscpmk_data_t *)ipp_action_get_ptr(aid); 288 ASSERT(dscpmk_data != NULL); 289 290 /* parse next action name, if present */ 291 if ((err = nvlist_lookup_string(nvlp, DSCPMK_NEXT_ACTION_NAME, 292 &next_action_name)) == 0) { 293 /* lookup action name to get action id */ 294 if ((next_action = ipp_action_lookup(next_action_name)) 295 == IPP_ACTION_INVAL) { 296 nvlist_free(nvlp); 297 dscpmk0dbg(("dscpmk_modify_action: next_action "\ 298 "invalid\n")); 299 return (EINVAL); 300 } 301 /* reference new action */ 302 if ((err = ipp_action_ref(aid, next_action, flags)) != 0) { 303 nvlist_free(nvlp); 304 dscpmk0dbg(("dscpmk_modify_action: ipp_action_ref " \ 305 "returned with error %d\n", err)); 306 return (err); 307 } 308 /* unref old action */ 309 err = ipp_action_unref(aid, dscpmk_data->next_action, flags); 310 ASSERT(err == 0); 311 dscpmk_data->next_action = next_action; 312 } 313 314 /* 315 * parse dscp_map, if present. Note that the module gets 316 * the entire array with unchanged entries marked with -1. 317 * If this array is absent during modification, it means revert to 318 * the default table. 319 */ 320 if ((err = nvlist_lookup_int32_array(nvlp, DSCPMK_DSCP_MAP, 321 &tbl, &nelem)) == 0) { 322 for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) { 323 if ((tbl[cnt] != DSCPMK_UNCHANGED_DSCP) && (tbl[cnt] != 324 dscpmk_data->dscp_map[cnt])) { 325 dscpmk_data->dscp_map[cnt] = tbl[cnt]; 326 } 327 } 328 } else { 329 bcopy(default_dscp_map, dscpmk_data->dscp_map, 330 sizeof (default_dscp_map)); 331 } 332 333 /* parse summary_stats boolean, if present */ 334 if ((err = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats)) 335 == 0) { 336 boolean_t val = (bstats != 0) ? B_TRUE : B_FALSE; 337 /* Turning on stats */ 338 if (!dscpmk_data->summary_stats && val) { 339 if ((err = dscpmk_summ_statinit(aid, dscpmk_data)) 340 != 0) { 341 nvlist_free(nvlp); 342 return (err); 343 } 344 /* Turning off stats */ 345 } else if (!val && dscpmk_data->summary_stats) { 346 ipp_stat_destroy(dscpmk_data->stats); 347 348 } 349 dscpmk_data->summary_stats = val; 350 } 351 352 /* parse detailed_stats boolean */ 353 if ((err = nvlist_lookup_uint32(nvlp, DSCPMK_DETAILED_STATS, &bstats)) 354 == 0) { 355 boolean_t val = (bstats != 0) ? B_TRUE : B_FALSE; 356 if (dscpmk_data->detailed_stats && !val) { 357 for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) { 358 if (dscpmk_data->dscp_stats[cnt].present) { 359 dscpmk_data->dscp_stats[cnt].present = 360 B_FALSE; 361 ipp_stat_destroy(dscpmk_data-> 362 dscp_stats[cnt].stats); 363 } 364 } 365 } 366 dscpmk_data->detailed_stats = val; 367 } 368 369 /* The map might have changed */ 370 if (dscpmk_data->detailed_stats) { 371 for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) { 372 int val = dscpmk_data->dscp_map[cnt]; 373 if (!dscpmk_data->dscp_stats[val].present) { 374 dscpmk_data->dscp_stats[val].present = B_TRUE; 375 if ((err = dscpmk_det_statinit(aid, dscpmk_data, 376 val)) != 0) { 377 nvlist_free(nvlp); 378 return (err); 379 } 380 } 381 } 382 } 383 384 /* Free the nvlist */ 385 nvlist_free(nvlp); 386 return (0); 387 } 388 389 static int 390 dscpmk_destroy_action(ipp_action_id_t aid, ipp_flags_t flags) 391 { 392 dscpmk_data_t *dscpmk_data; 393 int err, cnt; 394 395 dscpmk_data = (dscpmk_data_t *)ipp_action_get_ptr(aid); 396 ASSERT(dscpmk_data != NULL); 397 398 /* Destroy stats, if gathered */ 399 if (dscpmk_data->summary_stats) { 400 ipp_stat_destroy(dscpmk_data->stats); 401 } 402 403 if (dscpmk_data->detailed_stats) { 404 for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) { 405 if (dscpmk_data->dscp_stats[cnt].present) { 406 ipp_stat_destroy(dscpmk_data->dscp_stats[cnt]. 407 stats); 408 } 409 } 410 } 411 412 /* unreference the action */ 413 err = ipp_action_unref(aid, dscpmk_data->next_action, flags); 414 ASSERT(err == 0); 415 416 kmem_free(dscpmk_data, DSCPMK_DATA_SZ); 417 return (0); 418 } 419 420 static int 421 dscpmk_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet) 422 { 423 dscpmk_data_t *dscpmk_data; 424 mblk_t *mp = NULL; 425 ip_priv_t *priv; 426 int err; 427 428 ASSERT(packet != NULL); 429 430 /* get mblk from ipp_packet structure */ 431 mp = ipp_packet_get_data(packet); 432 priv = (ip_priv_t *)ipp_packet_get_private(packet); 433 434 dscpmk_data = (dscpmk_data_t *)ipp_action_get_ptr(aid); 435 ASSERT(dscpmk_data != NULL); 436 437 /* dscpmk packet as configured */ 438 if ((err = dscpmk_process(&mp, dscpmk_data, priv->proc)) != 0) { 439 return (err); 440 } else { 441 /* return packet with next action set */ 442 return (ipp_packet_next(packet, dscpmk_data->next_action)); 443 } 444 } 445 446 static int 447 dscpmk_det_statinit(ipp_action_id_t aid, dscpmk_data_t *dscpmk_data, int val) 448 { 449 int err = 0; 450 dscpmk_dscp_stats_t *statp; 451 char stats_string[15]; 452 453 (void) sprintf(stats_string, "dscpmk_dscp0x%x", val); 454 455 /* install stats entry */ 456 if ((err = ipp_stat_create(aid, stats_string, DSCPMK_DSCP_STATS_COUNT, 457 dscpmk_update_det_stats, dscpmk_data, 458 &dscpmk_data->dscp_stats[val].stats)) != 0) { 459 dscpmk0dbg(("dscpmk_det_statinit: ipp_stat_create returned "\ 460 "with error %d\n", err)); 461 return (err); 462 } 463 464 statp = (dscpmk_dscp_stats_t *) 465 (dscpmk_data->dscp_stats[val].stats)->ipps_data; 466 ASSERT(statp != NULL); 467 468 if ((err = ipp_stat_named_init(dscpmk_data->dscp_stats[val].stats, 469 "dscp", IPP_STAT_UINT32, &statp->dscp)) != 0) { 470 dscpmk0dbg(("dscpmk_det_statinit: ipp_stat_named_init "\ 471 "returned with error %d\n", err)); 472 return (err); 473 } 474 475 if ((err = ipp_stat_named_init(dscpmk_data->dscp_stats[val].stats, 476 "npackets", IPP_STAT_UINT64, &statp->npackets)) != 0) { 477 dscpmk0dbg(("dscpmk_det_statinit: ipp_stat_named_init "\ 478 "returned with error %d\n", err)); 479 return (err); 480 } 481 482 ipp_stat_install(dscpmk_data->dscp_stats[val].stats); 483 return (0); 484 } 485 486 487 static int 488 dscpmk_summ_statinit(ipp_action_id_t aid, dscpmk_data_t *dscpmk_data) 489 { 490 int err = 0; 491 dscpmk_stat_t *statp; 492 493 /* install stats entry */ 494 if ((err = ipp_stat_create(aid, DSCPMK_STATS_STRING, DSCPMK_STATS_COUNT, 495 dscpmk_update_stats, dscpmk_data, &dscpmk_data->stats)) != 0) { 496 dscpmk0dbg(("dscpmk_create_action: ipp_stat_create returned " \ 497 "with error %d\n", err)); 498 return (err); 499 } 500 501 statp = (dscpmk_stat_t *)(dscpmk_data->stats)->ipps_data; 502 ASSERT(statp != NULL); 503 504 if ((err = ipp_stat_named_init(dscpmk_data->stats, "npackets", 505 IPP_STAT_UINT64, &statp->npackets)) != 0) { 506 dscpmk0dbg(("dscpmk_summ_statinit: ipp_stat_named_init " \ 507 "returned with error %d\n", err)); 508 return (err); 509 } 510 511 if ((err = ipp_stat_named_init(dscpmk_data->stats, "dscp_changed", 512 IPP_STAT_UINT64, &statp->dscp_changed)) != 0) { 513 dscpmk0dbg(("dscpmk_summ_statinit: ipp_stat_named_init " \ 514 "returned with error %d\n", err)); 515 return (err); 516 } 517 518 if ((err = ipp_stat_named_init(dscpmk_data->stats, "dscp_unchanged", 519 IPP_STAT_UINT64, &statp->dscp_unchanged)) != 0) { 520 dscpmk0dbg(("dscpmk_summ_statinit: ipp_stat_named_init " \ 521 "returned with error %d\n", err)); 522 return (err); 523 } 524 525 if ((err = ipp_stat_named_init(dscpmk_data->stats, "ipackets", 526 IPP_STAT_UINT64, &statp->ipackets)) != 0) { 527 dscpmk0dbg(("dscpmk_summ_statinit: ipp_stat_named_init " \ 528 "returned with error %d\n", err)); 529 return (err); 530 } 531 532 if ((err = ipp_stat_named_init(dscpmk_data->stats, "epackets", 533 IPP_STAT_UINT64, &statp->epackets)) != 0) { 534 dscpmk0dbg(("dscpmk_summ_statinit: ipp_stat_named_init " \ 535 "returned with error %d\n", err)); 536 return (err); 537 } 538 539 ipp_stat_install(dscpmk_data->stats); 540 return (0); 541 } 542 543 /* ARGSUSED */ 544 static int 545 dscpmk_update_det_stats(ipp_stat_t *sp, void *arg, int rw) 546 { 547 dscpmk_data_t *dscpmk_data = (dscpmk_data_t *)arg; 548 dscpmk_dscp_stats_t *statp; 549 uint32_t count; 550 551 for (count = 0; count < DSCPMK_ARRAY_COUNT; count++) { 552 if (!dscpmk_data->dscp_stats[count].present) 553 continue; 554 statp = (dscpmk_dscp_stats_t *) 555 (dscpmk_data->dscp_stats[count].stats)->ipps_data; 556 ASSERT(statp != NULL); 557 (void) ipp_stat_named_op(&statp->npackets, 558 &dscpmk_data->dscp_stats[count].npackets, rw); 559 (void) ipp_stat_named_op(&statp->dscp, &count, rw); 560 } 561 return (0); 562 } 563 564 static int 565 dscpmk_update_stats(ipp_stat_t *sp, void *arg, int rw) 566 { 567 dscpmk_data_t *dscpmk_data = (dscpmk_data_t *)arg; 568 dscpmk_stat_t *snames = (dscpmk_stat_t *)sp->ipps_data; 569 ASSERT(dscpmk_data != NULL); 570 ASSERT(snames != NULL); 571 572 (void) ipp_stat_named_op(&snames->npackets, &dscpmk_data->npackets, rw); 573 (void) ipp_stat_named_op(&snames->dscp_changed, &dscpmk_data->changed, 574 rw); 575 (void) ipp_stat_named_op(&snames->dscp_unchanged, 576 &dscpmk_data->unchanged, rw); 577 (void) ipp_stat_named_op(&snames->ipackets, &dscpmk_data->ipackets, rw); 578 (void) ipp_stat_named_op(&snames->epackets, &dscpmk_data->epackets, rw); 579 580 return (0); 581 } 582 583 /* ARGSUSED */ 584 static int 585 dscpmk_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg, 586 ipp_flags_t flags) 587 { 588 nvlist_t *nvlp; 589 dscpmk_data_t *dscpmk_data; 590 char *next_action; 591 int err, cnt; 592 int32_t dscp_map[DSCPMK_ARRAY_COUNT]; 593 594 ASSERT(fn != NULL); 595 596 dscpmk_data = (dscpmk_data_t *)ipp_action_get_ptr(aid); 597 ASSERT(dscpmk_data != NULL); 598 599 /* allocate nvlist to be passed back */ 600 if ((err = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_NOSLEEP)) != 0) { 601 dscpmk0dbg(("dscpmk_info: error allocating memory\n")); 602 return (err); 603 } 604 605 /* look up next action with the next action id */ 606 if ((err = ipp_action_name(dscpmk_data->next_action, 607 &next_action)) != 0) { 608 dscpmk0dbg(("dscpmk_info: next action not available\n")); 609 nvlist_free(nvlp); 610 return (err); 611 } 612 613 /* add next action name */ 614 if ((err = nvlist_add_string(nvlp, DSCPMK_NEXT_ACTION_NAME, 615 next_action)) != 0) { 616 dscpmk0dbg(("dscpmk_info: error adding next action\n")); 617 nvlist_free(nvlp); 618 kmem_free(next_action, (strlen(next_action) + 1)); 619 return (err); 620 } 621 622 /* free action name */ 623 kmem_free(next_action, (strlen(next_action) + 1)); 624 625 /* add config type */ 626 if ((err = nvlist_add_byte(nvlp, IPP_CONFIG_TYPE, IPP_SET)) != 0) { 627 dscpmk0dbg(("dscpmk_info: error adding config type\n")); 628 nvlist_free(nvlp); 629 return (err); 630 } 631 632 /* add dscp map */ 633 bcopy(dscpmk_data->dscp_map, dscp_map, sizeof (dscp_map)); 634 for (cnt = 0; cnt < DSCPMK_ARRAY_COUNT; cnt++) { 635 dscp_map[cnt] = dscpmk_data->dscp_map[cnt]; 636 } 637 if ((err = nvlist_add_int32_array(nvlp, DSCPMK_DSCP_MAP, 638 dscp_map, DSCPMK_ARRAY_COUNT)) != 0) { 639 dscpmk0dbg(("dscpmk_info: error adding dscp map\n")); 640 nvlist_free(nvlp); 641 return (err); 642 } 643 644 /* add summary stats boolean */ 645 if ((err = nvlist_add_uint32(nvlp, IPP_ACTION_STATS_ENABLE, 646 (dscpmk_data->summary_stats ? 1 : 0))) != 0) { 647 dscpmk0dbg(("dscpmk_info: error adding stats status\n")); 648 nvlist_free(nvlp); 649 return (err); 650 } 651 652 /* add detailed stats boolean */ 653 if ((err = nvlist_add_uint32(nvlp, DSCPMK_DETAILED_STATS, 654 (dscpmk_data->detailed_stats ? 1 : 0))) != 0) { 655 dscpmk0dbg(("dscpmk_info: error adding det stats status\n")); 656 nvlist_free(nvlp); 657 return (err); 658 } 659 660 /* call back with nvlist */ 661 err = fn(nvlp, arg); 662 663 nvlist_free(nvlp); 664 return (err); 665 }