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