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 }