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