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 nvlist_free(nvlp);
1247 return (rc);
1248 }
1249
1250 /*
1251 * If the module passed back an nvlist, add this as
1252 * well.
1253 */
1254
1255 if (nvlp != NULL) {
1256 rc = ippctl_callback(nvlp, NULL);
1257 nvlist_free(nvlp);
1258 } else
1259 rc = 0;
1260
1261 return (rc);
1262 }
1263 #undef __FN__
1264
1265 #define __FN__ "ippctl_action_info"
1266 static int
ippctl_action_info(char * aname,ipp_flags_t flags)1267 ippctl_action_info(
1268 char *aname,
1269 ipp_flags_t flags)
1270 {
1271 ipp_action_id_t aid;
1272 int ipp_rc;
1273 int rc;
1274
1275 /*
1276 * Look up the action and call the information retrieval
1277 * entry point.
1278 *
1279 * NOTE: The callback function that is passed in packs and
1280 * stores each of the nvlists it is called with in the array
1281 * that will be passed back to libipp.
1282 */
1283
1284 aid = ipp_action_lookup(aname);
1285 FREE_TEXT(aname);
1286
1287 ipp_rc = ipp_action_info(aid, ippctl_callback, NULL, flags);
1288
1289 /*
1290 * Add an nvlist containing the kernel return code to the
1291 * set of nvlists to pass back to libipp.
1292 */
1293
1294 if ((rc = ippctl_set_rc(ipp_rc)) != 0)
1295 return (rc);
1296
1297 /*
1298 * There's no more information to pass back.
1299 */
1300
1301 return (0);
1302 }
1303 #undef __FN__
1304
1305 #define __FN__ "ippctl_action_mod"
1306 static int
ippctl_action_mod(char * aname)1307 ippctl_action_mod(
1308 char *aname)
1309 {
1310 ipp_mod_id_t mid;
1311 ipp_action_id_t aid;
1312 char *modname;
1313 nvlist_t *nvlp;
1314 int ipp_rc;
1315 int rc;
1316
1317 /*
1318 * Look up the action id and get the id of the module that
1319 * implements the action. If that succeeds then look up the
1320 * name of the module.
1321 */
1322
1323 aid = ipp_action_lookup(aname);
1324 FREE_TEXT(aname);
1325
1326 if ((ipp_rc = ipp_action_mod(aid, &mid)) == 0)
1327 ipp_rc = ipp_mod_name(mid, &modname);
1328
1329 /*
1330 * Add an nvlist containing the kernel return code to the
1331 * set of nvlists to pass back to libipp.
1332 */
1333
1334 if ((rc = ippctl_set_rc(ipp_rc)) != 0)
1335 return (rc);
1336
1337 /*
1338 * If everything succeeded add an nvlist containing the
1339 * module name to the set of nvlists to pass back to libipp.
1340 */
1341
1342 if (ipp_rc == 0) {
1343 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_SLEEP)) != 0)
1344 return (rc);
1345
1346 if ((rc = ippctl_attach_modname(nvlp, modname)) != 0) {
1347 nvlist_free(nvlp);
1348 return (rc);
1349 }
1350
1351 FREE_TEXT(modname);
1352
1353 rc = ippctl_callback(nvlp, NULL);
1354 nvlist_free(nvlp);
1355 } else
1356 rc = 0;
1357
1358 return (rc);
1359 }
1360 #undef __FN__
1361
1362 #define __FN__ "ippctl_list_mods"
1363 static int
ippctl_list_mods(void)1364 ippctl_list_mods(
1365 void)
1366 {
1367 nvlist_t *nvlp;
1368 int ipp_rc;
1369 int rc = 0;
1370 ipp_mod_id_t *mid_array;
1371 char **modname_array = NULL;
1372 int nelt;
1373 int length;
1374 int i;
1375
1376 /*
1377 * Get a list of all the module ids. If that succeeds,
1378 * translate the ids into names.
1379 *
1380 * NOTE: This translation may fail if a module is
1381 * unloaded during this operation. If this occurs, EAGAIN
1382 * will be passed back to libipp note that a transient
1383 * problem occured.
1384 */
1385
1386 if ((ipp_rc = ipp_list_mods(&mid_array, &nelt)) == 0) {
1387
1388 /*
1389 * It is possible that there are no modules
1390 * registered.
1391 */
1392
1393 if (nelt > 0) {
1394 length = nelt * sizeof (char *);
1395 modname_array = kmem_zalloc(length, KM_SLEEP);
1396
1397 for (i = 0; i < nelt; i++) {
1398 if (ipp_mod_name(mid_array[i],
1399 &modname_array[i]) != 0) {
1400 kmem_free(mid_array, nelt *
1401 sizeof (ipp_mod_id_t));
1402 FREE_TEXT_ARRAY(modname_array, nelt);
1403 ipp_rc = EAGAIN;
1404 goto done;
1405 }
1406 }
1407
1408 kmem_free(mid_array, nelt * sizeof (ipp_mod_id_t));
1409
1410 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME,
1411 KM_SLEEP)) != 0) {
1412 FREE_TEXT_ARRAY(modname_array, nelt);
1413 return (rc);
1414 }
1415
1416 if ((rc = ippctl_attach_modname_array(nvlp,
1417 modname_array, nelt)) != 0) {
1418 FREE_TEXT_ARRAY(modname_array, nelt);
1419 nvlist_free(nvlp);
1420 return (rc);
1421 }
1422
1423 FREE_TEXT_ARRAY(modname_array, nelt);
1424
1425 if ((rc = ippctl_callback(nvlp, NULL)) != 0) {
1426 nvlist_free(nvlp);
1427 return (rc);
1428 }
1429
1430 nvlist_free(nvlp);
1431 }
1432 }
1433
1434 done:
1435 /*
1436 * Add an nvlist containing the kernel return code to the
1437 * set of nvlists to pass back to libipp.
1438 */
1439
1440 if ((rc = ippctl_set_rc(ipp_rc)) != 0)
1441 return (rc);
1442
1443 return (0);
1444 }
1445 #undef __FN__
1446
1447 #define __FN__ "ippctl_mod_list_actions"
1448 static int
ippctl_mod_list_actions(char * modname)1449 ippctl_mod_list_actions(
1450 char *modname)
1451 {
1452 ipp_mod_id_t mid;
1453 nvlist_t *nvlp;
1454 int ipp_rc;
1455 int rc = 0;
1456 ipp_action_id_t *aid_array;
1457 char **aname_array = NULL;
1458 int nelt;
1459 int length;
1460 int i;
1461
1462 /*
1463 * Get the module id.
1464 */
1465
1466 mid = ipp_mod_lookup(modname);
1467 FREE_TEXT(modname);
1468
1469 /*
1470 * Get a list of all the action ids for the module. If that succeeds,
1471 * translate the ids into names.
1472 *
1473 * NOTE: This translation may fail if an action is
1474 * destroyed during this operation. If this occurs, EAGAIN
1475 * will be passed back to libipp note that a transient
1476 * problem occured.
1477 */
1478
1479 if ((ipp_rc = ipp_mod_list_actions(mid, &aid_array, &nelt)) == 0) {
1480
1481 /*
1482 * It is possible that there are no actions defined.
1483 * (This is unlikely though as the module would normally
1484 * be auto-unloaded fairly quickly)
1485 */
1486
1487 if (nelt > 0) {
1488 length = nelt * sizeof (char *);
1489 aname_array = kmem_zalloc(length, KM_SLEEP);
1490
1491 for (i = 0; i < nelt; i++) {
1492 if (ipp_action_name(aid_array[i],
1493 &aname_array[i]) != 0) {
1494 kmem_free(aid_array, nelt *
1495 sizeof (ipp_action_id_t));
1496 FREE_TEXT_ARRAY(aname_array, nelt);
1497 ipp_rc = EAGAIN;
1498 goto done;
1499 }
1500 }
1501
1502 kmem_free(aid_array, nelt * sizeof (ipp_action_id_t));
1503
1504 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME,
1505 KM_SLEEP)) != 0) {
1506 FREE_TEXT_ARRAY(aname_array, nelt);
1507 return (rc);
1508 }
1509
1510 if ((rc = ippctl_attach_aname_array(nvlp, aname_array,
1511 nelt)) != 0) {
1512 FREE_TEXT_ARRAY(aname_array, nelt);
1513 nvlist_free(nvlp);
1514 return (rc);
1515 }
1516
1517 FREE_TEXT_ARRAY(aname_array, nelt);
1518
1519 if ((rc = ippctl_callback(nvlp, NULL)) != 0) {
1520 nvlist_free(nvlp);
1521 return (rc);
1522 }
1523
1524 nvlist_free(nvlp);
1525 }
1526 }
1527
1528 done:
1529 /*
1530 * Add an nvlist containing the kernel return code to the
1531 * set of nvlists to pass back to libipp.
1532 */
1533
1534 if ((rc = ippctl_set_rc(ipp_rc)) != 0)
1535 return (rc);
1536
1537 return (0);
1538 }
1539 #undef __FN__
1540
1541 #define __FN__ "ippctl_data"
1542 static int
ippctl_data(char ** dbufp,size_t * dbuflenp,size_t * nextbuflenp)1543 ippctl_data(
1544 char **dbufp,
1545 size_t *dbuflenp,
1546 size_t *nextbuflenp)
1547 {
1548 int i;
1549
1550 DBG0(DBG_CBOPS, "called\n");
1551
1552 /*
1553 * Get the next data buffer from the array by looking at the
1554 * 'read index'. If this is the same as the 'write index' then
1555 * there's no more buffers in the array.
1556 */
1557
1558 i = ippctl_rindex;
1559 if (i == ippctl_windex)
1560 return (ENOENT);
1561
1562 /*
1563 * Extract the buffer details. It is a pre-packed nvlist.
1564 */
1565
1566 *dbufp = ippctl_array[i].buf;
1567 *dbuflenp = ippctl_array[i].buflen;
1568
1569 DBG2(DBG_CBOPS, "accessing nvlist[%d], length %lu\n", i, *dbuflenp);
1570 ASSERT(*dbufp != NULL);
1571
1572 /*
1573 * Advance the 'read index' and check if there's another buffer.
1574 * If there is then we need to pass back its length to libipp so that
1575 * another data ioctl will be issued.
1576 */
1577
1578 i++;
1579 if (i < ippctl_windex)
1580 *nextbuflenp = ippctl_array[i].buflen;
1581 else
1582 *nextbuflenp = 0;
1583
1584 ippctl_rindex = i;
1585 return (0);
1586 }
1587 #undef __FN__
1588
1589 #define __FN__ "ippctl_flush"
1590 static void
ippctl_flush(void)1591 ippctl_flush(
1592 void)
1593 {
1594 int i;
1595 char *buf;
1596 size_t buflen;
1597
1598 /*
1599 * Free any buffers left in the array.
1600 */
1601
1602 for (i = 0; i < ippctl_limit; i++) {
1603 if ((buflen = ippctl_array[i].buflen) > 0) {
1604 buf = ippctl_array[i].buf;
1605 ASSERT(buf != NULL);
1606 kmem_free(buf, buflen);
1607 }
1608 }
1609
1610 /*
1611 * NULL all the entries.
1612 */
1613
1614 bzero(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t));
1615
1616 /*
1617 * Reset the indexes.
1618 */
1619
1620 ippctl_rindex = 0;
1621 ippctl_windex = 1;
1622 }
1623 #undef __FN__
1624
1625 #define __FN__ "ippctl_add_nvlist"
1626 static int
ippctl_add_nvlist(nvlist_t * nvlp,int i)1627 ippctl_add_nvlist(
1628 nvlist_t *nvlp,
1629 int i)
1630 {
1631 char *buf;
1632 size_t buflen;
1633 int rc;
1634
1635 /*
1636 * NULL the buffer pointer so that a buffer is automatically
1637 * allocated for us.
1638 */
1639
1640 buf = NULL;
1641
1642 /*
1643 * Pack the nvlist and get back the buffer pointer and length.
1644 */
1645
1646 if ((rc = nvlist_pack(nvlp, &buf, &buflen, NV_ENCODE_NATIVE,
1647 KM_SLEEP)) != 0) {
1648 ippctl_array[i].buf = NULL;
1649 ippctl_array[i].buflen = 0;
1650 return (rc);
1651 }
1652
1653 DBG2(DBG_CBOPS, "added nvlist[%d]: length %lu\n", i, buflen);
1654
1655 /*
1656 * Store the pointer an length in the array at the given index.
1657 */
1658
1659 ippctl_array[i].buf = buf;
1660 ippctl_array[i].buflen = buflen;
1661
1662 return (0);
1663 }
1664 #undef __FN__
1665
1666 #define __FN__ "ippctl_callback"
1667 /*ARGSUSED*/
1668 static int
ippctl_callback(nvlist_t * nvlp,void * arg)1669 ippctl_callback(
1670 nvlist_t *nvlp,
1671 void *arg)
1672 {
1673 int i;
1674 int rc;
1675
1676 /*
1677 * Check the 'write index' to see if there's space in the array for
1678 * a new entry.
1679 */
1680
1681 i = ippctl_windex;
1682 ASSERT(i != 0);
1683
1684 /*
1685 * If there's no space, re-allocate the array (see comments in
1686 * ippctl_realloc() for details).
1687 */
1688
1689 if (i == ippctl_limit)
1690 ippctl_realloc();
1691
1692 /*
1693 * Add the nvlist to the array.
1694 */
1695
1696 if ((rc = ippctl_add_nvlist(nvlp, i)) == 0)
1697 ippctl_windex++;
1698
1699 return (rc);
1700 }
1701 #undef __FN__
1702
1703 #define __FN__ "ippctl_set_rc"
1704 static int
ippctl_set_rc(int val)1705 ippctl_set_rc(
1706 int val)
1707 {
1708 nvlist_t *nvlp;
1709 int rc;
1710
1711 /*
1712 * Create an nvlist to store the return code,
1713 */
1714
1715 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_SLEEP)) != 0)
1716 return (ENOMEM);
1717
1718 if ((rc = nvlist_add_int32(nvlp, IPPCTL_RC, val)) != 0) {
1719 nvlist_free(nvlp);
1720 return (rc);
1721 }
1722
1723 /*
1724 * Add it at the beginning of the array.
1725 */
1726
1727 rc = ippctl_add_nvlist(nvlp, 0);
1728
1729 nvlist_free(nvlp);
1730 return (rc);
1731 }
1732 #undef __FN__
1733
1734 #define __FN__ "ippctl_alloc"
1735 static void
ippctl_alloc(int limit)1736 ippctl_alloc(
1737 int limit)
1738 {
1739 /*
1740 * Allocate the data buffer array and initialize the indexes.
1741 */
1742
1743 ippctl_array = kmem_zalloc(limit * sizeof (ippctl_buf_t), KM_SLEEP);
1744 ippctl_limit = limit;
1745 ippctl_rindex = 0;
1746 ippctl_windex = 1;
1747 }
1748 #undef __FN__
1749
1750 #define __FN__ "ippctl_realloc"
1751 static void
ippctl_realloc(void)1752 ippctl_realloc(
1753 void)
1754 {
1755 ippctl_buf_t *array;
1756 int limit;
1757 int i;
1758
1759 /*
1760 * Allocate a new array twice the size of the old one.
1761 */
1762
1763 limit = ippctl_limit << 1;
1764 array = kmem_zalloc(limit * sizeof (ippctl_buf_t), KM_SLEEP);
1765
1766 /*
1767 * Copy across the information from the old array into the new one.
1768 */
1769
1770 for (i = 0; i < ippctl_limit; i++)
1771 array[i] = ippctl_array[i];
1772
1773 /*
1774 * Free the old array.
1775 */
1776
1777 kmem_free(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t));
1778
1779 ippctl_array = array;
1780 ippctl_limit = limit;
1781 }
1782 #undef __FN__
1783
1784 #define __FN__ "ippctl_free"
1785 static void
ippctl_free(void)1786 ippctl_free(
1787 void)
1788 {
1789 /*
1790 * Flush the array prior to freeing it to make sure no buffers are
1791 * leaked.
1792 */
1793
1794 ippctl_flush();
1795
1796 /*
1797 * Free the array.
1798 */
1799
1800 kmem_free(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t));
1801 ippctl_array = NULL;
1802 ippctl_limit = -1;
1803 ippctl_rindex = -1;
1804 ippctl_windex = -1;
1805 }
1806 #undef __FN__
1807
1808 #ifdef IPPCTL_DEBUG
1809 static void
ippctl_debug(uint64_t type,char * fn,char * fmt,...)1810 ippctl_debug(
1811 uint64_t type,
1812 char *fn,
1813 char *fmt,
1814 ...)
1815 {
1816 char buf[255];
1817 va_list adx;
1818
1819 if ((type & ippctl_debug_flags) == 0)
1820 return;
1821
1822 mutex_enter(debug_mutex);
1823 va_start(adx, fmt);
1824 (void) vsnprintf(buf, 255, fmt, adx);
1825 va_end(adx);
1826
1827 printf("%s: %s", fn, buf);
1828 mutex_exit(debug_mutex);
1829 }
1830 #endif /* IPPCTL_DBG */
1831