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
27 /*
28 * IP Policy Framework config driver
29 */
30
31 #include <sys/types.h>
32 #include <sys/cmn_err.h>
33 #include <sys/kmem.h>
34 #include <sys/errno.h>
35 #include <sys/cpuvar.h>
36 #include <sys/open.h>
37 #include <sys/stat.h>
38 #include <sys/conf.h>
39 #include <sys/ddi.h>
40 #include <sys/sunddi.h>
41 #include <sys/modctl.h>
42 #include <sys/stream.h>
43 #include <ipp/ipp.h>
44 #include <ipp/ippctl.h>
45 #include <sys/nvpair.h>
46 #include <sys/policy.h>
47
48 /*
49 * Debug switch.
50 */
51
52 #if defined(DEBUG)
53 #define IPPCTL_DEBUG
54 #endif
55
56 /*
57 * Debug macros.
58 */
59
60 #ifdef IPPCTL_DEBUG
61
62 #define DBG_MODLINK 0x00000001ull
63 #define DBG_DEVOPS 0x00000002ull
64 #define DBG_CBOPS 0x00000004ull
65
66 static uint64_t ippctl_debug_flags =
67 /*
68 * DBG_MODLINK |
69 * DBG_DEVOPS |
70 * DBG_CBOPS |
71 */
72 0;
73
74 static kmutex_t debug_mutex[1];
75
76 /*PRINTFLIKE3*/
77 static void ippctl_debug(uint64_t, char *, char *, ...)
78 __PRINTFLIKE(3);
79
80 #define DBG0(_type, _fmt) \
81 ippctl_debug((_type), __FN__, (_fmt));
82
83 #define DBG1(_type, _fmt, _a1) \
84 ippctl_debug((_type), __FN__, (_fmt), (_a1));
85
86 #define DBG2(_type, _fmt, _a1, _a2) \
87 ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2));
88
89 #define DBG3(_type, _fmt, _a1, _a2, _a3) \
90 ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2), \
91 (_a3));
92
93 #define DBG4(_type, _fmt, _a1, _a2, _a3, _a4) \
94 ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2), \
95 (_a3), (_a4));
96
97 #define DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5) \
98 ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2), \
99 (_a3), (_a4), (_a5));
100
101 #else /* IPPCTL_DBG */
102
103 #define DBG0(_type, _fmt)
104 #define DBG1(_type, _fmt, _a1)
105 #define DBG2(_type, _fmt, _a1, _a2)
106 #define DBG3(_type, _fmt, _a1, _a2, _a3)
107 #define DBG4(_type, _fmt, _a1, _a2, _a3, _a4)
108 #define DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5)
109
110 #endif /* IPPCTL_DBG */
111
112 /*
113 * cb_ops
114 */
115
116 static int ippctl_open(dev_t *, int, int, cred_t *);
117 static int ippctl_close(dev_t, int, int, cred_t *);
118 static int ippctl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
119
120 static struct cb_ops ippctl_cb_ops = {
121 ippctl_open, /* cb_open */
122 ippctl_close, /* cb_close */
123 nodev, /* cb_strategy */
124 nodev, /* cb_print */
125 nodev, /* cb_dump */
126 nodev, /* cb_read */
127 nodev, /* cb_write */
128 ippctl_ioctl, /* cb_ioctl */
129 nodev, /* cb_devmap */
130 nodev, /* cb_mmap */
131 nodev, /* cb_segmap */
132 nochpoll, /* cb_chpoll */
133 ddi_prop_op, /* cb_prop_op */
134 0, /* cb_str */
135 D_NEW | D_MP, /* cb_flag */
136 CB_REV, /* cb_rev */
137 nodev, /* cb_aread */
138 nodev /* cb_awrite */
139 };
140
141 /*
142 * dev_ops
143 */
144
145 static int ippctl_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
146 static int ippctl_attach(dev_info_t *, ddi_attach_cmd_t);
147 static int ippctl_detach(dev_info_t *, ddi_detach_cmd_t);
148
149 static struct dev_ops ippctl_dev_ops = {
150 DEVO_REV, /* devo_rev, */
151 0, /* devo_refcnt */
152 ippctl_info, /* devo_getinfo */
153 nulldev, /* devo_identify */
154 nulldev, /* devo_probe */
155 ippctl_attach, /* devo_attach */
156 ippctl_detach, /* devo_detach */
157 nodev, /* devo_reset */
158 &ippctl_cb_ops, /* devo_cb_ops */
159 (struct bus_ops *)0, /* devo_bus_ops */
160 NULL, /* devo_power */
161 ddi_quiesce_not_needed, /* devo_quiesce */
162 };
163
164 static struct modldrv modldrv = {
165 &mod_driverops,
166 "IP Policy Configuration Driver",
167 &ippctl_dev_ops,
168 };
169
170 static struct modlinkage modlinkage = {
171 MODREV_1,
172 &modldrv,
173 NULL
174 };
175
176 /*
177 * Local definitions, types and prototypes.
178 */
179
180 #define MAXUBUFLEN (1 << 16)
181
182 #define FREE_TEXT(_string) \
183 kmem_free((_string), strlen(_string) + 1)
184
185 #define FREE_TEXT_ARRAY(_array, _nelt) \
186 { \
187 int j; \
188 \
189 for (j = 0; j < (_nelt); j++) \
190 if ((_array)[j] != NULL) \
191 FREE_TEXT((_array)[j]); \
192 kmem_free((_array), (_nelt) * sizeof (char *)); \
193 }
194
195 typedef struct ippctl_buf ippctl_buf_t;
196
197 struct ippctl_buf {
198 char *buf;
199 size_t buflen;
200 };
201
202 static int ippctl_copyin(caddr_t, int, char **, size_t *);
203 static int ippctl_copyout(caddr_t, int, char *, size_t);
204 static int ippctl_extract_op(nvlist_t *, uint8_t *);
205 static int ippctl_extract_aname(nvlist_t *, char **);
206 static int ippctl_extract_modname(nvlist_t *, char **);
207 static int ippctl_attach_modname(nvlist_t *nvlp, char *val);
208 static int ippctl_attach_modname_array(nvlist_t *nvlp, char **val, int);
209 static int ippctl_attach_aname_array(nvlist_t *nvlp, char **val, int);
210 static int ippctl_extract_flags(nvlist_t *, ipp_flags_t *);
211 static int ippctl_cmd(char *, size_t, size_t *);
212 static int ippctl_action_create(char *, char *, nvlist_t *, ipp_flags_t);
213 static int ippctl_action_destroy(char *, ipp_flags_t);
214 static int ippctl_action_modify(char *, nvlist_t *, ipp_flags_t);
215 static int ippctl_action_info(char *, ipp_flags_t);
216 static int ippctl_action_mod(char *);
217 static int ippctl_list_mods(void);
218 static int ippctl_mod_list_actions(char *);
219 static int ippctl_data(char **, size_t *, size_t *);
220 static void ippctl_flush(void);
221 static int ippctl_add_nvlist(nvlist_t *, int);
222 static int ippctl_callback(nvlist_t *, void *);
223 static int ippctl_set_rc(int);
224 static void ippctl_alloc(int);
225 static void ippctl_realloc(void);
226 static void ippctl_free(void);
227
228 /*
229 * Global data
230 */
231
232 static dev_info_t *ippctl_dip = NULL;
233 static kmutex_t ippctl_lock;
234 static boolean_t ippctl_busy;
235 static ippctl_buf_t *ippctl_array = NULL;
236 static int ippctl_limit = -1;
237 static int ippctl_rindex = -1;
238 static int ippctl_windex = -1;
239
240 /*
241 * Module linkage functions
242 */
243
244 #define __FN__ "_init"
245 int
_init(void)246 _init(
247 void)
248 {
249 int rc;
250
251 if ((rc = mod_install(&modlinkage)) != 0) {
252 DBG0(DBG_MODLINK, "mod_install failed\n");
253 return (rc);
254 }
255
256 return (rc);
257 }
258 #undef __FN__
259
260 #define __FN__ "_fini"
261 int
_fini(void)262 _fini(
263 void)
264 {
265 int rc;
266
267 if ((rc = mod_remove(&modlinkage)) == 0) {
268 return (rc);
269 }
270
271 DBG0(DBG_MODLINK, "mod_remove failed\n");
272 return (rc);
273 }
274 #undef __FN__
275
276 #define __FN__ "_info"
277 int
_info(struct modinfo * modinfop)278 _info(
279 struct modinfo *modinfop)
280 {
281 DBG0(DBG_MODLINK, "calling mod_info\n");
282 return (mod_info(&modlinkage, modinfop));
283 }
284 #undef __FN__
285
286 /*
287 * Driver interface functions (dev_ops and cb_ops)
288 */
289
290 #define __FN__ "ippctl_info"
291 /*ARGSUSED*/
292 static int
ippctl_info(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)293 ippctl_info(
294 dev_info_t *dip,
295 ddi_info_cmd_t cmd,
296 void *arg,
297 void **result)
298 {
299 int rc = DDI_FAILURE;
300
301 switch (cmd) {
302 case DDI_INFO_DEVT2INSTANCE:
303 *result = (void *)0; /* Single instance driver */
304 rc = DDI_SUCCESS;
305 break;
306 case DDI_INFO_DEVT2DEVINFO:
307 *result = (void *)ippctl_dip;
308 rc = DDI_SUCCESS;
309 break;
310 default:
311 break;
312 }
313
314 return (rc);
315 }
316 #undef __FN__
317
318 #define __FN__ "ippctl_attach"
319 static int
ippctl_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)320 ippctl_attach(
321 dev_info_t *dip,
322 ddi_attach_cmd_t cmd)
323 {
324 switch (cmd) {
325 case DDI_ATTACH:
326 break;
327 case DDI_PM_RESUME:
328 /*FALLTHRU*/
329 case DDI_RESUME:
330 /*FALLTHRU*/
331 default:
332 return (DDI_FAILURE);
333 }
334
335 DBG0(DBG_DEVOPS, "DDI_ATTACH\n");
336
337 /*
338 * This is strictly a single instance driver.
339 */
340
341 if (ippctl_dip != NULL)
342 return (DDI_FAILURE);
343
344 /*
345 * Create minor node.
346 */
347
348 if (ddi_create_minor_node(dip, "ctl", S_IFCHR, 0,
349 DDI_PSEUDO, 0) != DDI_SUCCESS)
350 return (DDI_FAILURE);
351
352 /*
353 * No need for per-instance structure, just store vital data in
354 * globals.
355 */
356
357 ippctl_dip = dip;
358 mutex_init(&ippctl_lock, NULL, MUTEX_DRIVER, NULL);
359 ippctl_busy = B_FALSE;
360
361 return (DDI_SUCCESS);
362 }
363 #undef __FN__
364
365 #define __FN__ "ippctl_detach"
366 /*ARGSUSED*/
367 static int
ippctl_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)368 ippctl_detach(
369 dev_info_t *dip,
370 ddi_detach_cmd_t cmd)
371 {
372 switch (cmd) {
373 case DDI_DETACH:
374 break;
375 case DDI_PM_SUSPEND:
376 /*FALLTHRU*/
377 case DDI_SUSPEND:
378 /*FALLTHRU*/
379 default:
380 return (DDI_FAILURE);
381 }
382
383 DBG0(DBG_DEVOPS, "DDI_DETACH\n");
384
385 ASSERT(dip == ippctl_dip);
386
387 ddi_remove_minor_node(dip, NULL);
388 mutex_destroy(&ippctl_lock);
389 ippctl_dip = NULL;
390
391 return (DDI_SUCCESS);
392 }
393 #undef __FN__
394
395 #define __FN__ "ippctl_open"
396 /*ARGSUSED*/
397 static int
ippctl_open(dev_t * devp,int flag,int otyp,cred_t * credp)398 ippctl_open(
399 dev_t *devp,
400 int flag,
401 int otyp,
402 cred_t *credp)
403 {
404 minor_t minor = getminor(*devp);
405 #define LIMIT 4
406
407 DBG0(DBG_CBOPS, "open\n");
408
409 /*
410 * Only allow privileged users to open our device.
411 */
412
413 if (secpolicy_net_config(credp, B_FALSE) != 0) {
414 DBG0(DBG_CBOPS, "not privileged user\n");
415 return (EPERM);
416 }
417
418 /*
419 * Sanity check other arguments.
420 */
421
422 if (minor != 0) {
423 DBG0(DBG_CBOPS, "bad minor\n");
424 return (ENXIO);
425 }
426
427 if (otyp != OTYP_CHR) {
428 DBG0(DBG_CBOPS, "bad device type\n");
429 return (EINVAL);
430 }
431
432 /*
433 * This is also a single dev_t driver.
434 */
435
436 mutex_enter(&ippctl_lock);
437 if (ippctl_busy) {
438 mutex_exit(&ippctl_lock);
439 return (EBUSY);
440 }
441 ippctl_busy = B_TRUE;
442 mutex_exit(&ippctl_lock);
443
444 /*
445 * Allocate data buffer array (starting with length LIMIT, defined
446 * at the start of this function).
447 */
448
449 ippctl_alloc(LIMIT);
450
451 DBG0(DBG_CBOPS, "success\n");
452
453 return (0);
454
455 #undef LIMIT
456 }
457 #undef __FN__
458
459 #define __FN__ "ippctl_close"
460 /*ARGSUSED*/
461 static int
ippctl_close(dev_t dev,int flag,int otyp,cred_t * credp)462 ippctl_close(
463 dev_t dev,
464 int flag,
465 int otyp,
466 cred_t *credp)
467 {
468 minor_t minor = getminor(dev);
469
470 DBG0(DBG_CBOPS, "close\n");
471
472 ASSERT(minor == 0);
473
474 /*
475 * Free the data buffer array.
476 */
477
478 ippctl_free();
479
480 mutex_enter(&ippctl_lock);
481 ippctl_busy = B_FALSE;
482 mutex_exit(&ippctl_lock);
483
484 DBG0(DBG_CBOPS, "success\n");
485
486 return (0);
487 }
488 #undef __FN__
489
490 #define __FN__ "ippctl_ioctl"
491 static int
ippctl_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)492 ippctl_ioctl(
493 dev_t dev,
494 int cmd,
495 intptr_t arg,
496 int mode,
497 cred_t *credp,
498 int *rvalp)
499 {
500 minor_t minor = getminor(dev);
501 char *cbuf;
502 char *dbuf;
503 size_t cbuflen;
504 size_t dbuflen;
505 size_t nextbuflen;
506 int rc;
507
508 /*
509 * Paranoia check.
510 */
511
512 if (secpolicy_net_config(credp, B_FALSE) != 0) {
513 DBG0(DBG_CBOPS, "not privileged user\n");
514 return (EPERM);
515 }
516
517 if (minor != 0) {
518 DBG0(DBG_CBOPS, "bad minor\n");
519 return (ENXIO);
520 }
521
522 switch (cmd) {
523 case IPPCTL_CMD:
524 DBG0(DBG_CBOPS, "command\n");
525
526 /*
527 * Copy in the command buffer from user space.
528 */
529
530 if ((rc = ippctl_copyin((caddr_t)arg, mode, &cbuf,
531 &cbuflen)) != 0)
532 break;
533
534 /*
535 * Execute the command.
536 */
537
538 rc = ippctl_cmd(cbuf, cbuflen, &nextbuflen);
539
540 /*
541 * Pass back the length of the first data buffer.
542 */
543
544 DBG1(DBG_CBOPS, "nextbuflen = %lu\n", nextbuflen);
545 *rvalp = nextbuflen;
546
547 /*
548 * Free the kernel copy of the command buffer.
549 */
550
551 kmem_free(cbuf, cbuflen);
552 break;
553
554 case IPPCTL_DATA:
555 DBG0(DBG_CBOPS, "data\n");
556
557 /*
558 * Grab the next data buffer from the array of pending
559 * buffers.
560 */
561
562 if ((rc = ippctl_data(&dbuf, &dbuflen, &nextbuflen)) != 0)
563 break;
564
565 /*
566 * Copy it out to user space.
567 */
568
569 rc = ippctl_copyout((caddr_t)arg, mode, dbuf, dbuflen);
570
571 /*
572 * Pass back the length of the next data buffer.
573 */
574
575 DBG1(DBG_CBOPS, "nextbuflen = %lu\n", nextbuflen);
576 *rvalp = nextbuflen;
577 break;
578
579 default:
580 DBG0(DBG_CBOPS, "unrecognized ioctl\n");
581 rc = EINVAL;
582 break;
583 }
584
585 DBG1(DBG_CBOPS, "rc = %d\n", rc);
586 return (rc);
587 }
588 #undef __FN__
589
590 /*
591 * Local functions
592 */
593
594 #define __FN__ "ippctl_copyin"
595 static int
ippctl_copyin(caddr_t arg,int mode,char ** kbufp,size_t * kbuflenp)596 ippctl_copyin(
597 caddr_t arg,
598 int mode,
599 char **kbufp,
600 size_t *kbuflenp)
601 {
602 ippctl_ioctl_t iioc;
603 caddr_t ubuf;
604 char *kbuf;
605 size_t ubuflen;
606
607 DBG0(DBG_CBOPS, "copying in ioctl structure\n");
608
609 /*
610 * Copy in the ioctl structure from user-space, converting from 32-bit
611 * as necessary.
612 */
613
614 #ifdef _MULTI_DATAMODEL
615 switch (ddi_model_convert_from(mode & FMODELS)) {
616 case DDI_MODEL_ILP32:
617 {
618 ippctl_ioctl32_t iioc32;
619
620 DBG0(DBG_CBOPS, "converting from 32-bit\n");
621
622 if (ddi_copyin(arg, (caddr_t)&iioc32,
623 sizeof (ippctl_ioctl32_t), mode) != 0)
624 return (EFAULT);
625
626 ubuf = (caddr_t)(uintptr_t)iioc32.ii32_buf;
627 ubuflen = (size_t)iioc32.ii32_buflen;
628 }
629 break;
630 case DDI_MODEL_NONE:
631 if (ddi_copyin(arg, (caddr_t)&iioc, sizeof (ippctl_ioctl_t),
632 mode) != 0)
633 return (EFAULT);
634
635 ubuf = iioc.ii_buf;
636 ubuflen = iioc.ii_buflen;
637 break;
638 default:
639 return (EFAULT);
640 }
641 #else /* _MULTI_DATAMODEL */
642 if (ddi_copyin(arg, (caddr_t)&iioc, sizeof (ippctl_ioctl_t),
643 mode) != 0)
644 return (EFAULT);
645
646 ubuf = iioc.ii_buf;
647 ubuflen = iioc.ii_buflen;
648 #endif /* _MULTI_DATAMODEL */
649
650 DBG1(DBG_CBOPS, "ubuf = 0x%p\n", (void *)ubuf);
651 DBG1(DBG_CBOPS, "ubuflen = %lu\n", ubuflen);
652
653 /*
654 * Sanity check the command buffer information.
655 */
656
657 if (ubuflen == 0 || ubuf == NULL)
658 return (EINVAL);
659 if (ubuflen > MAXUBUFLEN)
660 return (E2BIG);
661
662 /*
663 * Allocate some memory for the command buffer and copy it in.
664 */
665
666 kbuf = kmem_zalloc(ubuflen, KM_SLEEP);
667 DBG0(DBG_CBOPS, "copying in nvlist\n");
668 if (ddi_copyin(ubuf, (caddr_t)kbuf, ubuflen, mode) != 0) {
669 kmem_free(kbuf, ubuflen);
670 return (EFAULT);
671 }
672
673 *kbufp = kbuf;
674 *kbuflenp = ubuflen;
675 return (0);
676 }
677 #undef __FN__
678
679 #define __FN__ "ippctl_copyout"
680 static int
ippctl_copyout(caddr_t arg,int mode,char * kbuf,size_t kbuflen)681 ippctl_copyout(
682 caddr_t arg,
683 int mode,
684 char *kbuf,
685 size_t kbuflen)
686 {
687 ippctl_ioctl_t iioc;
688 caddr_t ubuf;
689 int ubuflen;
690
691 DBG0(DBG_CBOPS, "copying out ioctl structure\n");
692
693 /*
694 * Copy in the ioctl structure from user-space, converting from 32-bit
695 * as necessary.
696 */
697
698 #ifdef _MULTI_DATAMODEL
699 switch (ddi_model_convert_from(mode & FMODELS)) {
700 case DDI_MODEL_ILP32:
701 {
702 ippctl_ioctl32_t iioc32;
703
704 if (ddi_copyin(arg, (caddr_t)&iioc32,
705 sizeof (ippctl_ioctl32_t), mode) != 0)
706 return (EFAULT);
707
708 ubuf = (caddr_t)(uintptr_t)iioc32.ii32_buf;
709 ubuflen = iioc32.ii32_buflen;
710 }
711 break;
712 case DDI_MODEL_NONE:
713 if (ddi_copyin(arg, (caddr_t)&iioc, sizeof (ippctl_ioctl_t),
714 mode) != 0)
715 return (EFAULT);
716
717 ubuf = iioc.ii_buf;
718 ubuflen = iioc.ii_buflen;
719 break;
720 default:
721 return (EFAULT);
722 }
723 #else /* _MULTI_DATAMODEL */
724 if (ddi_copyin(arg, (caddr_t)&iioc, sizeof (ippctl_ioctl_t),
725 mode) != 0)
726 return (EFAULT);
727
728 ubuf = iioc.ii_buf;
729 ubuflen = iioc.ii_buflen;
730 #endif /* _MULTI_DATAMODEL */
731
732 DBG1(DBG_CBOPS, "ubuf = 0x%p\n", (void *)ubuf);
733 DBG1(DBG_CBOPS, "ubuflen = %d\n", ubuflen);
734
735 /*
736 * Sanity check the data buffer details.
737 */
738
739 if (ubuflen == 0 || ubuf == NULL)
740 return (EINVAL);
741
742 if (ubuflen < kbuflen)
743 return (ENOSPC);
744 if (ubuflen > MAXUBUFLEN)
745 return (E2BIG);
746
747 /*
748 * Copy out the data buffer to user space.
749 */
750
751 DBG0(DBG_CBOPS, "copying out nvlist\n");
752 if (ddi_copyout((caddr_t)kbuf, ubuf, kbuflen, mode) != 0)
753 return (EFAULT);
754
755 return (0);
756 }
757 #undef __FN__
758
759 #define __FN__ "ippctl_extract_op"
760 static int
ippctl_extract_op(nvlist_t * nvlp,uint8_t * valp)761 ippctl_extract_op(
762 nvlist_t *nvlp,
763 uint8_t *valp)
764 {
765 int rc;
766
767 /*
768 * Look-up and remove the opcode passed from libipp from the
769 * nvlist.
770 */
771
772 if ((rc = nvlist_lookup_byte(nvlp, IPPCTL_OP, valp)) != 0)
773 return (rc);
774
775 (void) nvlist_remove_all(nvlp, IPPCTL_OP);
776 return (0);
777 }
778 #undef __FN__
779
780 #define __FN__ "ippctl_extract_aname"
781 static int
ippctl_extract_aname(nvlist_t * nvlp,char ** valp)782 ippctl_extract_aname(
783 nvlist_t *nvlp,
784 char **valp)
785 {
786 int rc;
787 char *ptr;
788
789 /*
790 * Look-up and remove the action name passed from libipp from the
791 * nvlist.
792 */
793
794 if ((rc = nvlist_lookup_string(nvlp, IPPCTL_ANAME, &ptr)) != 0)
795 return (rc);
796
797 *valp = kmem_alloc(strlen(ptr) + 1, KM_SLEEP);
798 (void) strcpy(*valp, ptr);
799 (void) nvlist_remove_all(nvlp, IPPCTL_ANAME);
800 return (0);
801 }
802 #undef __FN__
803
804 #define __FN__ "ippctl_extract_modname"
805 static int
ippctl_extract_modname(nvlist_t * nvlp,char ** valp)806 ippctl_extract_modname(
807 nvlist_t *nvlp,
808 char **valp)
809 {
810 int rc;
811 char *ptr;
812
813 /*
814 * Look-up and remove the module name passed from libipp from the
815 * nvlist.
816 */
817
818 if ((rc = nvlist_lookup_string(nvlp, IPPCTL_MODNAME, &ptr)) != 0)
819 return (rc);
820
821 *valp = kmem_alloc(strlen(ptr) + 1, KM_SLEEP);
822 (void) strcpy(*valp, ptr);
823 (void) nvlist_remove_all(nvlp, IPPCTL_MODNAME);
824 return (0);
825 }
826 #undef __FN__
827
828 #define __FN__ "ippctl_attach_modname"
829 static int
ippctl_attach_modname(nvlist_t * nvlp,char * modname)830 ippctl_attach_modname(
831 nvlist_t *nvlp,
832 char *modname)
833 {
834 /*
835 * Add a module name to an nvlist for passing back to user
836 * space.
837 */
838
839 return (nvlist_add_string(nvlp, IPPCTL_MODNAME, modname));
840 }
841 #undef __FN__
842
843 #define __FN__ "ippctl_attach_modname_array"
844 static int
ippctl_attach_modname_array(nvlist_t * nvlp,char ** modname_array,int nelt)845 ippctl_attach_modname_array(
846 nvlist_t *nvlp,
847 char **modname_array,
848 int nelt)
849 {
850 /*
851 * Add a module name array to an nvlist for passing back to user
852 * space.
853 */
854
855 return (nvlist_add_string_array(nvlp, IPPCTL_MODNAME_ARRAY,
856 modname_array, nelt));
857 }
858 #undef __FN__
859
860 #define __FN__ "ippctl_attach_aname_array"
861 static int
ippctl_attach_aname_array(nvlist_t * nvlp,char ** aname_array,int nelt)862 ippctl_attach_aname_array(
863 nvlist_t *nvlp,
864 char **aname_array,
865 int nelt)
866 {
867 /*
868 * Add an action name array to an nvlist for passing back to user
869 * space.
870 */
871
872 return (nvlist_add_string_array(nvlp, IPPCTL_ANAME_ARRAY,
873 aname_array, nelt));
874 }
875 #undef __FN__
876
877 #define __FN__ "ippctl_extract_flags"
878 static int
ippctl_extract_flags(nvlist_t * nvlp,ipp_flags_t * valp)879 ippctl_extract_flags(
880 nvlist_t *nvlp,
881 ipp_flags_t *valp)
882 {
883 int rc;
884
885 /*
886 * Look-up and remove the flags passed from libipp from the
887 * nvlist.
888 */
889
890 if ((rc = nvlist_lookup_uint32(nvlp, IPPCTL_FLAGS,
891 (uint32_t *)valp)) != 0)
892 return (rc);
893
894 (void) nvlist_remove_all(nvlp, IPPCTL_FLAGS);
895 return (0);
896 }
897 #undef __FN__
898
899 #define __FN__ "ippctl_cmd"
900 static int
ippctl_cmd(char * cbuf,size_t cbuflen,size_t * nextbuflenp)901 ippctl_cmd(
902 char *cbuf,
903 size_t cbuflen,
904 size_t *nextbuflenp)
905 {
906 nvlist_t *nvlp = NULL;
907 int rc;
908 char *aname = NULL;
909 char *modname = NULL;
910 ipp_flags_t flags;
911 uint8_t op;
912
913 /*
914 * Start a new command cycle by flushing any previous data buffers.
915 */
916
917 ippctl_flush();
918 *nextbuflenp = 0;
919
920 /*
921 * Unpack the nvlist from the command buffer.
922 */
923
924 if ((rc = nvlist_unpack(cbuf, cbuflen, &nvlp, KM_SLEEP)) != 0)
925 return (rc);
926
927 /*
928 * Extract the opcode to find out what we should do.
929 */
930
931 if ((rc = ippctl_extract_op(nvlp, &op)) != 0) {
932 nvlist_free(nvlp);
933 return (rc);
934 }
935
936 switch (op) {
937 case IPPCTL_OP_ACTION_CREATE:
938 /*
939 * Create a new action.
940 */
941
942 DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_CREATE\n");
943
944 /*
945 * Extract the module name, action name and flags from the
946 * nvlist.
947 */
948
949 if ((rc = ippctl_extract_modname(nvlp, &modname)) != 0) {
950 nvlist_free(nvlp);
951 return (rc);
952 }
953
954 if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) {
955 FREE_TEXT(modname);
956 nvlist_free(nvlp);
957 return (rc);
958 }
959
960 if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) {
961 FREE_TEXT(aname);
962 FREE_TEXT(modname);
963 nvlist_free(nvlp);
964 return (rc);
965 }
966
967
968 rc = ippctl_action_create(modname, aname, nvlp, flags);
969 break;
970
971 case IPPCTL_OP_ACTION_MODIFY:
972
973 /*
974 * Modify an existing action.
975 */
976
977 DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_MODIFY\n");
978
979 /*
980 * Extract the action name and flags from the nvlist.
981 */
982
983 if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) {
984 nvlist_free(nvlp);
985 return (rc);
986 }
987
988 if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) {
989 FREE_TEXT(aname);
990 nvlist_free(nvlp);
991 return (rc);
992 }
993
994 rc = ippctl_action_modify(aname, nvlp, flags);
995 break;
996
997 case IPPCTL_OP_ACTION_DESTROY:
998
999 /*
1000 * Destroy an action.
1001 */
1002
1003 DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_DESTROY\n");
1004
1005 /*
1006 * Extract the action name and flags from the nvlist.
1007 */
1008
1009 if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) {
1010 nvlist_free(nvlp);
1011 return (rc);
1012 }
1013
1014 if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) {
1015 FREE_TEXT(aname);
1016 nvlist_free(nvlp);
1017 return (rc);
1018 }
1019
1020 nvlist_free(nvlp);
1021 rc = ippctl_action_destroy(aname, flags);
1022 break;
1023
1024 case IPPCTL_OP_ACTION_INFO:
1025
1026 /*
1027 * Retrive the configuration of an action.
1028 */
1029
1030 DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_INFO\n");
1031
1032 /*
1033 * Extract the action name and flags from the nvlist.
1034 */
1035
1036 if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) {
1037 nvlist_free(nvlp);
1038 return (rc);
1039 }
1040
1041 if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) {
1042 nvlist_free(nvlp);
1043 FREE_TEXT(aname);
1044 return (rc);
1045 }
1046
1047 nvlist_free(nvlp);
1048 rc = ippctl_action_info(aname, flags);
1049 break;
1050
1051 case IPPCTL_OP_ACTION_MOD:
1052
1053 /*
1054 * Find the module that implements a given action.
1055 */
1056
1057 DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_MOD\n");
1058
1059 /*
1060 * Extract the action name from the nvlist.
1061 */
1062
1063 if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) {
1064 nvlist_free(nvlp);
1065 return (rc);
1066 }
1067
1068 nvlist_free(nvlp);
1069 rc = ippctl_action_mod(aname);
1070 break;
1071
1072 case IPPCTL_OP_LIST_MODS:
1073
1074 /*
1075 * List all the modules.
1076 */
1077
1078 DBG0(DBG_CBOPS, "op = IPPCTL_OP_LIST_MODS\n");
1079
1080 nvlist_free(nvlp);
1081 rc = ippctl_list_mods();
1082 break;
1083
1084 case IPPCTL_OP_MOD_LIST_ACTIONS:
1085
1086 /*
1087 * List all the actions for a given module.
1088 */
1089
1090 DBG0(DBG_CBOPS, "op = IPPCTL_OP_LIST_MODS\n");
1091
1092 if ((rc = ippctl_extract_modname(nvlp, &modname)) != 0) {
1093 nvlist_free(nvlp);
1094 return (rc);
1095 }
1096
1097 nvlist_free(nvlp);
1098 rc = ippctl_mod_list_actions(modname);
1099 break;
1100
1101 default:
1102
1103 /*
1104 * Unrecognized opcode.
1105 */
1106
1107 nvlist_free(nvlp);
1108 rc = EINVAL;
1109 break;
1110 }
1111
1112 /*
1113 * The length of buffer that we need to notify back to libipp with
1114 * the command ioctl's return is the length of the first data buffer
1115 * in the array. We only expact to pass back data buffers if the
1116 * operation succeeds (NOTE: this does not mean the kernel call has
1117 * to succeed, merely that we successfully issued it and processed
1118 * the results).
1119 */
1120
1121 if (rc == 0)
1122 *nextbuflenp = ippctl_array[0].buflen;
1123
1124 return (rc);
1125 }
1126 #undef __FN__
1127
1128 #define __FN__ "ippctl_action_create"
1129 static int
ippctl_action_create(char * modname,char * aname,nvlist_t * nvlp,ipp_flags_t flags)1130 ippctl_action_create(
1131 char *modname,
1132 char *aname,
1133 nvlist_t *nvlp,
1134 ipp_flags_t flags)
1135 {
1136 int ipp_rc;
1137 int rc;
1138 ipp_mod_id_t mid;
1139 ipp_action_id_t aid;
1140
1141 /*
1142 * Look up the module id from the name and create the new
1143 * action.
1144 */
1145
1146 mid = ipp_mod_lookup(modname);
1147 FREE_TEXT(modname);
1148
1149 ipp_rc = ipp_action_create(mid, aname, &nvlp, flags, &aid);
1150 FREE_TEXT(aname);
1151
1152 /*
1153 * Add an nvlist containing the kernel return code to the
1154 * set of nvlists to pass back to libipp.
1155 */
1156
1157 if ((rc = ippctl_set_rc(ipp_rc)) != 0) {
1158 if (nvlp != NULL) {
1159 nvlist_free(nvlp);
1160 if (ipp_action_destroy(aid, 0) != 0) {
1161 cmn_err(CE_PANIC,
1162 "ippctl: unrecoverable error (aid = %d)",
1163 aid);
1164 /*NOTREACHED*/
1165 }
1166 }
1167 return (rc);
1168 }
1169
1170 /*
1171 * If the module passed back an nvlist, add this as
1172 * well.
1173 */
1174
1175 if (nvlp != NULL) {
1176 rc = ippctl_callback(nvlp, NULL);
1177 nvlist_free(nvlp);
1178 } else
1179 rc = 0;
1180
1181 return (rc);
1182 }
1183 #undef __FN__
1184
1185 #define __FN__ "ippctl_action_destroy"
1186 static int
ippctl_action_destroy(char * aname,ipp_flags_t flags)1187 ippctl_action_destroy(
1188 char *aname,
1189 ipp_flags_t flags)
1190 {
1191 ipp_action_id_t aid;
1192 int ipp_rc;
1193 int rc;
1194
1195 /*
1196 * Look up the action id and destroy the action.
1197 */
1198
1199 aid = ipp_action_lookup(aname);
1200 FREE_TEXT(aname);
1201
1202 ipp_rc = ipp_action_destroy(aid, flags);
1203
1204 /*
1205 * Add an nvlist containing the kernel return code to the
1206 * set of nvlists to pass back to libipp.
1207 */
1208
1209 if ((rc = ippctl_set_rc(ipp_rc)) != 0)
1210 return (rc);
1211
1212 /*
1213 * There's no more information to pass back.
1214 */
1215
1216 return (0);
1217 }
1218 #undef __FN__
1219
1220 #define __FN__ "ippctl_action_modify"
1221 static int
ippctl_action_modify(char * aname,nvlist_t * nvlp,ipp_flags_t flags)1222 ippctl_action_modify(
1223 char *aname,
1224 nvlist_t *nvlp,
1225 ipp_flags_t flags)
1226 {
1227 ipp_action_id_t aid;
1228 int ipp_rc;
1229 int rc;
1230
1231 /*
1232 * Look up the action id and modify the action.
1233 */
1234
1235 aid = ipp_action_lookup(aname);
1236 FREE_TEXT(aname);
1237
1238 ipp_rc = ipp_action_modify(aid, &nvlp, flags);
1239
1240 /*
1241 * Add an nvlist containing the kernel return code to the
1242 * set of nvlists to pass back to libipp.
1243 */
1244
1245 if ((rc = ippctl_set_rc(ipp_rc)) != 0) {
1246 if (nvlp != NULL)
1247 nvlist_free(nvlp);
1248 return (rc);
1249 }
1250
1251 /*
1252 * If the module passed back an nvlist, add this as
1253 * well.
1254 */
1255
1256 if (nvlp != NULL) {
1257 rc = ippctl_callback(nvlp, NULL);
1258 nvlist_free(nvlp);
1259 } else
1260 rc = 0;
1261
1262 return (rc);
1263 }
1264 #undef __FN__
1265
1266 #define __FN__ "ippctl_action_info"
1267 static int
ippctl_action_info(char * aname,ipp_flags_t flags)1268 ippctl_action_info(
1269 char *aname,
1270 ipp_flags_t flags)
1271 {
1272 ipp_action_id_t aid;
1273 int ipp_rc;
1274 int rc;
1275
1276 /*
1277 * Look up the action and call the information retrieval
1278 * entry point.
1279 *
1280 * NOTE: The callback function that is passed in packs and
1281 * stores each of the nvlists it is called with in the array
1282 * that will be passed back to libipp.
1283 */
1284
1285 aid = ipp_action_lookup(aname);
1286 FREE_TEXT(aname);
1287
1288 ipp_rc = ipp_action_info(aid, ippctl_callback, NULL, flags);
1289
1290 /*
1291 * Add an nvlist containing the kernel return code to the
1292 * set of nvlists to pass back to libipp.
1293 */
1294
1295 if ((rc = ippctl_set_rc(ipp_rc)) != 0)
1296 return (rc);
1297
1298 /*
1299 * There's no more information to pass back.
1300 */
1301
1302 return (0);
1303 }
1304 #undef __FN__
1305
1306 #define __FN__ "ippctl_action_mod"
1307 static int
ippctl_action_mod(char * aname)1308 ippctl_action_mod(
1309 char *aname)
1310 {
1311 ipp_mod_id_t mid;
1312 ipp_action_id_t aid;
1313 char *modname;
1314 nvlist_t *nvlp;
1315 int ipp_rc;
1316 int rc;
1317
1318 /*
1319 * Look up the action id and get the id of the module that
1320 * implements the action. If that succeeds then look up the
1321 * name of the module.
1322 */
1323
1324 aid = ipp_action_lookup(aname);
1325 FREE_TEXT(aname);
1326
1327 if ((ipp_rc = ipp_action_mod(aid, &mid)) == 0)
1328 ipp_rc = ipp_mod_name(mid, &modname);
1329
1330 /*
1331 * Add an nvlist containing the kernel return code to the
1332 * set of nvlists to pass back to libipp.
1333 */
1334
1335 if ((rc = ippctl_set_rc(ipp_rc)) != 0)
1336 return (rc);
1337
1338 /*
1339 * If everything succeeded add an nvlist containing the
1340 * module name to the set of nvlists to pass back to libipp.
1341 */
1342
1343 if (ipp_rc == 0) {
1344 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_SLEEP)) != 0)
1345 return (rc);
1346
1347 if ((rc = ippctl_attach_modname(nvlp, modname)) != 0) {
1348 nvlist_free(nvlp);
1349 return (rc);
1350 }
1351
1352 FREE_TEXT(modname);
1353
1354 rc = ippctl_callback(nvlp, NULL);
1355 nvlist_free(nvlp);
1356 } else
1357 rc = 0;
1358
1359 return (rc);
1360 }
1361 #undef __FN__
1362
1363 #define __FN__ "ippctl_list_mods"
1364 static int
ippctl_list_mods(void)1365 ippctl_list_mods(
1366 void)
1367 {
1368 nvlist_t *nvlp;
1369 int ipp_rc;
1370 int rc = 0;
1371 ipp_mod_id_t *mid_array;
1372 char **modname_array = NULL;
1373 int nelt;
1374 int length;
1375 int i;
1376
1377 /*
1378 * Get a list of all the module ids. If that succeeds,
1379 * translate the ids into names.
1380 *
1381 * NOTE: This translation may fail if a module is
1382 * unloaded during this operation. If this occurs, EAGAIN
1383 * will be passed back to libipp note that a transient
1384 * problem occured.
1385 */
1386
1387 if ((ipp_rc = ipp_list_mods(&mid_array, &nelt)) == 0) {
1388
1389 /*
1390 * It is possible that there are no modules
1391 * registered.
1392 */
1393
1394 if (nelt > 0) {
1395 length = nelt * sizeof (char *);
1396 modname_array = kmem_zalloc(length, KM_SLEEP);
1397
1398 for (i = 0; i < nelt; i++) {
1399 if (ipp_mod_name(mid_array[i],
1400 &modname_array[i]) != 0) {
1401 kmem_free(mid_array, nelt *
1402 sizeof (ipp_mod_id_t));
1403 FREE_TEXT_ARRAY(modname_array, nelt);
1404 ipp_rc = EAGAIN;
1405 goto done;
1406 }
1407 }
1408
1409 kmem_free(mid_array, nelt * sizeof (ipp_mod_id_t));
1410
1411 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME,
1412 KM_SLEEP)) != 0) {
1413 FREE_TEXT_ARRAY(modname_array, nelt);
1414 return (rc);
1415 }
1416
1417 if ((rc = ippctl_attach_modname_array(nvlp,
1418 modname_array, nelt)) != 0) {
1419 FREE_TEXT_ARRAY(modname_array, nelt);
1420 nvlist_free(nvlp);
1421 return (rc);
1422 }
1423
1424 FREE_TEXT_ARRAY(modname_array, nelt);
1425
1426 if ((rc = ippctl_callback(nvlp, NULL)) != 0) {
1427 nvlist_free(nvlp);
1428 return (rc);
1429 }
1430
1431 nvlist_free(nvlp);
1432 }
1433 }
1434
1435 done:
1436 /*
1437 * Add an nvlist containing the kernel return code to the
1438 * set of nvlists to pass back to libipp.
1439 */
1440
1441 if ((rc = ippctl_set_rc(ipp_rc)) != 0)
1442 return (rc);
1443
1444 return (0);
1445 }
1446 #undef __FN__
1447
1448 #define __FN__ "ippctl_mod_list_actions"
1449 static int
ippctl_mod_list_actions(char * modname)1450 ippctl_mod_list_actions(
1451 char *modname)
1452 {
1453 ipp_mod_id_t mid;
1454 nvlist_t *nvlp;
1455 int ipp_rc;
1456 int rc = 0;
1457 ipp_action_id_t *aid_array;
1458 char **aname_array = NULL;
1459 int nelt;
1460 int length;
1461 int i;
1462
1463 /*
1464 * Get the module id.
1465 */
1466
1467 mid = ipp_mod_lookup(modname);
1468 FREE_TEXT(modname);
1469
1470 /*
1471 * Get a list of all the action ids for the module. If that succeeds,
1472 * translate the ids into names.
1473 *
1474 * NOTE: This translation may fail if an action is
1475 * destroyed during this operation. If this occurs, EAGAIN
1476 * will be passed back to libipp note that a transient
1477 * problem occured.
1478 */
1479
1480 if ((ipp_rc = ipp_mod_list_actions(mid, &aid_array, &nelt)) == 0) {
1481
1482 /*
1483 * It is possible that there are no actions defined.
1484 * (This is unlikely though as the module would normally
1485 * be auto-unloaded fairly quickly)
1486 */
1487
1488 if (nelt > 0) {
1489 length = nelt * sizeof (char *);
1490 aname_array = kmem_zalloc(length, KM_SLEEP);
1491
1492 for (i = 0; i < nelt; i++) {
1493 if (ipp_action_name(aid_array[i],
1494 &aname_array[i]) != 0) {
1495 kmem_free(aid_array, nelt *
1496 sizeof (ipp_action_id_t));
1497 FREE_TEXT_ARRAY(aname_array, nelt);
1498 ipp_rc = EAGAIN;
1499 goto done;
1500 }
1501 }
1502
1503 kmem_free(aid_array, nelt * sizeof (ipp_action_id_t));
1504
1505 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME,
1506 KM_SLEEP)) != 0) {
1507 FREE_TEXT_ARRAY(aname_array, nelt);
1508 return (rc);
1509 }
1510
1511 if ((rc = ippctl_attach_aname_array(nvlp, aname_array,
1512 nelt)) != 0) {
1513 FREE_TEXT_ARRAY(aname_array, nelt);
1514 nvlist_free(nvlp);
1515 return (rc);
1516 }
1517
1518 FREE_TEXT_ARRAY(aname_array, nelt);
1519
1520 if ((rc = ippctl_callback(nvlp, NULL)) != 0) {
1521 nvlist_free(nvlp);
1522 return (rc);
1523 }
1524
1525 nvlist_free(nvlp);
1526 }
1527 }
1528
1529 done:
1530 /*
1531 * Add an nvlist containing the kernel return code to the
1532 * set of nvlists to pass back to libipp.
1533 */
1534
1535 if ((rc = ippctl_set_rc(ipp_rc)) != 0)
1536 return (rc);
1537
1538 return (0);
1539 }
1540 #undef __FN__
1541
1542 #define __FN__ "ippctl_data"
1543 static int
ippctl_data(char ** dbufp,size_t * dbuflenp,size_t * nextbuflenp)1544 ippctl_data(
1545 char **dbufp,
1546 size_t *dbuflenp,
1547 size_t *nextbuflenp)
1548 {
1549 int i;
1550
1551 DBG0(DBG_CBOPS, "called\n");
1552
1553 /*
1554 * Get the next data buffer from the array by looking at the
1555 * 'read index'. If this is the same as the 'write index' then
1556 * there's no more buffers in the array.
1557 */
1558
1559 i = ippctl_rindex;
1560 if (i == ippctl_windex)
1561 return (ENOENT);
1562
1563 /*
1564 * Extract the buffer details. It is a pre-packed nvlist.
1565 */
1566
1567 *dbufp = ippctl_array[i].buf;
1568 *dbuflenp = ippctl_array[i].buflen;
1569
1570 DBG2(DBG_CBOPS, "accessing nvlist[%d], length %lu\n", i, *dbuflenp);
1571 ASSERT(*dbufp != NULL);
1572
1573 /*
1574 * Advance the 'read index' and check if there's another buffer.
1575 * If there is then we need to pass back its length to libipp so that
1576 * another data ioctl will be issued.
1577 */
1578
1579 i++;
1580 if (i < ippctl_windex)
1581 *nextbuflenp = ippctl_array[i].buflen;
1582 else
1583 *nextbuflenp = 0;
1584
1585 ippctl_rindex = i;
1586 return (0);
1587 }
1588 #undef __FN__
1589
1590 #define __FN__ "ippctl_flush"
1591 static void
ippctl_flush(void)1592 ippctl_flush(
1593 void)
1594 {
1595 int i;
1596 char *buf;
1597 size_t buflen;
1598
1599 /*
1600 * Free any buffers left in the array.
1601 */
1602
1603 for (i = 0; i < ippctl_limit; i++) {
1604 if ((buflen = ippctl_array[i].buflen) > 0) {
1605 buf = ippctl_array[i].buf;
1606 ASSERT(buf != NULL);
1607 kmem_free(buf, buflen);
1608 }
1609 }
1610
1611 /*
1612 * NULL all the entries.
1613 */
1614
1615 bzero(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t));
1616
1617 /*
1618 * Reset the indexes.
1619 */
1620
1621 ippctl_rindex = 0;
1622 ippctl_windex = 1;
1623 }
1624 #undef __FN__
1625
1626 #define __FN__ "ippctl_add_nvlist"
1627 static int
ippctl_add_nvlist(nvlist_t * nvlp,int i)1628 ippctl_add_nvlist(
1629 nvlist_t *nvlp,
1630 int i)
1631 {
1632 char *buf;
1633 size_t buflen;
1634 int rc;
1635
1636 /*
1637 * NULL the buffer pointer so that a buffer is automatically
1638 * allocated for us.
1639 */
1640
1641 buf = NULL;
1642
1643 /*
1644 * Pack the nvlist and get back the buffer pointer and length.
1645 */
1646
1647 if ((rc = nvlist_pack(nvlp, &buf, &buflen, NV_ENCODE_NATIVE,
1648 KM_SLEEP)) != 0) {
1649 ippctl_array[i].buf = NULL;
1650 ippctl_array[i].buflen = 0;
1651 return (rc);
1652 }
1653
1654 DBG2(DBG_CBOPS, "added nvlist[%d]: length %lu\n", i, buflen);
1655
1656 /*
1657 * Store the pointer an length in the array at the given index.
1658 */
1659
1660 ippctl_array[i].buf = buf;
1661 ippctl_array[i].buflen = buflen;
1662
1663 return (0);
1664 }
1665 #undef __FN__
1666
1667 #define __FN__ "ippctl_callback"
1668 /*ARGSUSED*/
1669 static int
ippctl_callback(nvlist_t * nvlp,void * arg)1670 ippctl_callback(
1671 nvlist_t *nvlp,
1672 void *arg)
1673 {
1674 int i;
1675 int rc;
1676
1677 /*
1678 * Check the 'write index' to see if there's space in the array for
1679 * a new entry.
1680 */
1681
1682 i = ippctl_windex;
1683 ASSERT(i != 0);
1684
1685 /*
1686 * If there's no space, re-allocate the array (see comments in
1687 * ippctl_realloc() for details).
1688 */
1689
1690 if (i == ippctl_limit)
1691 ippctl_realloc();
1692
1693 /*
1694 * Add the nvlist to the array.
1695 */
1696
1697 if ((rc = ippctl_add_nvlist(nvlp, i)) == 0)
1698 ippctl_windex++;
1699
1700 return (rc);
1701 }
1702 #undef __FN__
1703
1704 #define __FN__ "ippctl_set_rc"
1705 static int
ippctl_set_rc(int val)1706 ippctl_set_rc(
1707 int val)
1708 {
1709 nvlist_t *nvlp;
1710 int rc;
1711
1712 /*
1713 * Create an nvlist to store the return code,
1714 */
1715
1716 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_SLEEP)) != 0)
1717 return (ENOMEM);
1718
1719 if ((rc = nvlist_add_int32(nvlp, IPPCTL_RC, val)) != 0) {
1720 nvlist_free(nvlp);
1721 return (rc);
1722 }
1723
1724 /*
1725 * Add it at the beginning of the array.
1726 */
1727
1728 rc = ippctl_add_nvlist(nvlp, 0);
1729
1730 nvlist_free(nvlp);
1731 return (rc);
1732 }
1733 #undef __FN__
1734
1735 #define __FN__ "ippctl_alloc"
1736 static void
ippctl_alloc(int limit)1737 ippctl_alloc(
1738 int limit)
1739 {
1740 /*
1741 * Allocate the data buffer array and initialize the indexes.
1742 */
1743
1744 ippctl_array = kmem_zalloc(limit * sizeof (ippctl_buf_t), KM_SLEEP);
1745 ippctl_limit = limit;
1746 ippctl_rindex = 0;
1747 ippctl_windex = 1;
1748 }
1749 #undef __FN__
1750
1751 #define __FN__ "ippctl_realloc"
1752 static void
ippctl_realloc(void)1753 ippctl_realloc(
1754 void)
1755 {
1756 ippctl_buf_t *array;
1757 int limit;
1758 int i;
1759
1760 /*
1761 * Allocate a new array twice the size of the old one.
1762 */
1763
1764 limit = ippctl_limit << 1;
1765 array = kmem_zalloc(limit * sizeof (ippctl_buf_t), KM_SLEEP);
1766
1767 /*
1768 * Copy across the information from the old array into the new one.
1769 */
1770
1771 for (i = 0; i < ippctl_limit; i++)
1772 array[i] = ippctl_array[i];
1773
1774 /*
1775 * Free the old array.
1776 */
1777
1778 kmem_free(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t));
1779
1780 ippctl_array = array;
1781 ippctl_limit = limit;
1782 }
1783 #undef __FN__
1784
1785 #define __FN__ "ippctl_free"
1786 static void
ippctl_free(void)1787 ippctl_free(
1788 void)
1789 {
1790 /*
1791 * Flush the array prior to freeing it to make sure no buffers are
1792 * leaked.
1793 */
1794
1795 ippctl_flush();
1796
1797 /*
1798 * Free the array.
1799 */
1800
1801 kmem_free(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t));
1802 ippctl_array = NULL;
1803 ippctl_limit = -1;
1804 ippctl_rindex = -1;
1805 ippctl_windex = -1;
1806 }
1807 #undef __FN__
1808
1809 #ifdef IPPCTL_DEBUG
1810 static void
ippctl_debug(uint64_t type,char * fn,char * fmt,...)1811 ippctl_debug(
1812 uint64_t type,
1813 char *fn,
1814 char *fmt,
1815 ...)
1816 {
1817 char buf[255];
1818 va_list adx;
1819
1820 if ((type & ippctl_debug_flags) == 0)
1821 return;
1822
1823 mutex_enter(debug_mutex);
1824 va_start(adx, fmt);
1825 (void) vsnprintf(buf, 255, fmt, adx);
1826 va_end(adx);
1827
1828 printf("%s: %s", fn, buf);
1829 mutex_exit(debug_mutex);
1830 }
1831 #endif /* IPPCTL_DBG */
1832