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
_init(void)105 _init(void)
106 {
107 return (mod_install(&modlinkage));
108 }
109
110 int
_fini(void)111 _fini(void)
112 {
113 return (mod_remove(&modlinkage));
114 }
115
116 int
_info(struct modinfo * modinfop)117 _info(struct modinfo *modinfop)
118 {
119 return (mod_info(&modlinkage, modinfop));
120 }
121
122 static int
dscpmk_create_action(ipp_action_id_t aid,nvlist_t ** nvlpp,ipp_flags_t flags)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
dscpmk_modify_action(ipp_action_id_t aid,nvlist_t ** nvlpp,ipp_flags_t flags)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
dscpmk_destroy_action(ipp_action_id_t aid,ipp_flags_t flags)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
dscpmk_invoke_action(ipp_action_id_t aid,ipp_packet_t * packet)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
dscpmk_det_statinit(ipp_action_id_t aid,dscpmk_data_t * dscpmk_data,int val)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
dscpmk_summ_statinit(ipp_action_id_t aid,dscpmk_data_t * dscpmk_data)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
dscpmk_update_det_stats(ipp_stat_t * sp,void * arg,int rw)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
dscpmk_update_stats(ipp_stat_t * sp,void * arg,int rw)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
dscpmk_info(ipp_action_id_t aid,int (* fn)(nvlist_t *,void *),void * arg,ipp_flags_t flags)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 }
667