Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / ipp / ippctl.c
blob8d0a93605fffc118ac74c6a001350efab5643535
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * IP Policy Framework config driver
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>
49 * Debug switch.
52 #if defined(DEBUG)
53 #define IPPCTL_DEBUG
54 #endif
57 * Debug macros.
60 #ifdef IPPCTL_DEBUG
62 #define DBG_MODLINK 0x00000001ull
63 #define DBG_DEVOPS 0x00000002ull
64 #define DBG_CBOPS 0x00000004ull
66 static uint64_t ippctl_debug_flags =
68 * DBG_MODLINK |
69 * DBG_DEVOPS |
70 * DBG_CBOPS |
74 static kmutex_t debug_mutex[1];
76 /*PRINTFLIKE3*/
77 static void ippctl_debug(uint64_t, char *, char *, ...)
78 __PRINTFLIKE(3);
80 #define DBG0(_type, _fmt) \
81 ippctl_debug((_type), __FN__, (_fmt));
83 #define DBG1(_type, _fmt, _a1) \
84 ippctl_debug((_type), __FN__, (_fmt), (_a1));
86 #define DBG2(_type, _fmt, _a1, _a2) \
87 ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2));
89 #define DBG3(_type, _fmt, _a1, _a2, _a3) \
90 ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2), \
91 (_a3));
93 #define DBG4(_type, _fmt, _a1, _a2, _a3, _a4) \
94 ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2), \
95 (_a3), (_a4));
97 #define DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5) \
98 ippctl_debug((_type), __FN__, (_fmt), (_a1), (_a2), \
99 (_a3), (_a4), (_a5));
101 #else /* IPPCTL_DBG */
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)
110 #endif /* IPPCTL_DBG */
113 * cb_ops
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 *);
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 */
142 * dev_ops
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);
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 NULL, /* devo_bus_ops */
160 NULL, /* devo_power */
161 ddi_quiesce_not_needed, /* devo_quiesce */
164 static struct modldrv modldrv = {
165 &mod_driverops,
166 "IP Policy Configuration Driver",
167 &ippctl_dev_ops,
170 static struct modlinkage modlinkage = {
171 MODREV_1,
172 &modldrv,
173 NULL
177 * Local definitions, types and prototypes.
180 #define MAXUBUFLEN (1 << 16)
182 #define FREE_TEXT(_string) \
183 kmem_free((_string), strlen(_string) + 1)
185 #define FREE_TEXT_ARRAY(_array, _nelt) \
187 int j; \
189 for (j = 0; j < (_nelt); j++) \
190 if ((_array)[j] != NULL) \
191 FREE_TEXT((_array)[j]); \
192 kmem_free((_array), (_nelt) * sizeof (char *)); \
195 typedef struct ippctl_buf ippctl_buf_t;
197 struct ippctl_buf {
198 char *buf;
199 size_t buflen;
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);
229 * Global data
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;
241 * Module linkage functions
244 #define __FN__ "_init"
246 _init(
247 void)
249 int rc;
251 if ((rc = mod_install(&modlinkage)) != 0) {
252 DBG0(DBG_MODLINK, "mod_install failed\n");
253 return (rc);
256 return (rc);
258 #undef __FN__
260 #define __FN__ "_fini"
262 _fini(
263 void)
265 int rc;
267 if ((rc = mod_remove(&modlinkage)) == 0) {
268 return (rc);
271 DBG0(DBG_MODLINK, "mod_remove failed\n");
272 return (rc);
274 #undef __FN__
276 #define __FN__ "_info"
278 _info(
279 struct modinfo *modinfop)
281 DBG0(DBG_MODLINK, "calling mod_info\n");
282 return (mod_info(&modlinkage, modinfop));
284 #undef __FN__
287 * Driver interface functions (dev_ops and cb_ops)
290 #define __FN__ "ippctl_info"
291 /*ARGSUSED*/
292 static int
293 ippctl_info(
294 dev_info_t *dip,
295 ddi_info_cmd_t cmd,
296 void *arg,
297 void **result)
299 int rc = DDI_FAILURE;
301 switch (cmd) {
302 case DDI_INFO_DEVT2INSTANCE:
303 *result = NULL; /* 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;
314 return (rc);
316 #undef __FN__
318 #define __FN__ "ippctl_attach"
319 static int
320 ippctl_attach(
321 dev_info_t *dip,
322 ddi_attach_cmd_t cmd)
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);
335 DBG0(DBG_DEVOPS, "DDI_ATTACH\n");
338 * This is strictly a single instance driver.
341 if (ippctl_dip != NULL)
342 return (DDI_FAILURE);
345 * Create minor node.
348 if (ddi_create_minor_node(dip, "ctl", S_IFCHR, 0,
349 DDI_PSEUDO, 0) != DDI_SUCCESS)
350 return (DDI_FAILURE);
353 * No need for per-instance structure, just store vital data in
354 * globals.
357 ippctl_dip = dip;
358 mutex_init(&ippctl_lock, NULL, MUTEX_DRIVER, NULL);
359 ippctl_busy = B_FALSE;
361 return (DDI_SUCCESS);
363 #undef __FN__
365 #define __FN__ "ippctl_detach"
366 /*ARGSUSED*/
367 static int
368 ippctl_detach(
369 dev_info_t *dip,
370 ddi_detach_cmd_t cmd)
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);
383 DBG0(DBG_DEVOPS, "DDI_DETACH\n");
385 ASSERT(dip == ippctl_dip);
387 ddi_remove_minor_node(dip, NULL);
388 mutex_destroy(&ippctl_lock);
389 ippctl_dip = NULL;
391 return (DDI_SUCCESS);
393 #undef __FN__
395 #define __FN__ "ippctl_open"
396 /*ARGSUSED*/
397 static int
398 ippctl_open(
399 dev_t *devp,
400 int flag,
401 int otyp,
402 cred_t *credp)
404 minor_t minor = getminor(*devp);
405 #define LIMIT 4
407 DBG0(DBG_CBOPS, "open\n");
410 * Only allow privileged users to open our device.
413 if (secpolicy_net_config(credp, B_FALSE) != 0) {
414 DBG0(DBG_CBOPS, "not privileged user\n");
415 return (EPERM);
419 * Sanity check other arguments.
422 if (minor != 0) {
423 DBG0(DBG_CBOPS, "bad minor\n");
424 return (ENXIO);
427 if (otyp != OTYP_CHR) {
428 DBG0(DBG_CBOPS, "bad device type\n");
429 return (EINVAL);
433 * This is also a single dev_t driver.
436 mutex_enter(&ippctl_lock);
437 if (ippctl_busy) {
438 mutex_exit(&ippctl_lock);
439 return (EBUSY);
441 ippctl_busy = B_TRUE;
442 mutex_exit(&ippctl_lock);
445 * Allocate data buffer array (starting with length LIMIT, defined
446 * at the start of this function).
449 ippctl_alloc(LIMIT);
451 DBG0(DBG_CBOPS, "success\n");
453 return (0);
455 #undef LIMIT
457 #undef __FN__
459 #define __FN__ "ippctl_close"
460 /*ARGSUSED*/
461 static int
462 ippctl_close(
463 dev_t dev,
464 int flag,
465 int otyp,
466 cred_t *credp)
468 minor_t minor = getminor(dev);
470 DBG0(DBG_CBOPS, "close\n");
472 ASSERT(minor == 0);
475 * Free the data buffer array.
478 ippctl_free();
480 mutex_enter(&ippctl_lock);
481 ippctl_busy = B_FALSE;
482 mutex_exit(&ippctl_lock);
484 DBG0(DBG_CBOPS, "success\n");
486 return (0);
488 #undef __FN__
490 #define __FN__ "ippctl_ioctl"
491 static int
492 ippctl_ioctl(
493 dev_t dev,
494 int cmd,
495 intptr_t arg,
496 int mode,
497 cred_t *credp,
498 int *rvalp)
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;
509 * Paranoia check.
512 if (secpolicy_net_config(credp, B_FALSE) != 0) {
513 DBG0(DBG_CBOPS, "not privileged user\n");
514 return (EPERM);
517 if (minor != 0) {
518 DBG0(DBG_CBOPS, "bad minor\n");
519 return (ENXIO);
522 switch (cmd) {
523 case IPPCTL_CMD:
524 DBG0(DBG_CBOPS, "command\n");
527 * Copy in the command buffer from user space.
530 if ((rc = ippctl_copyin((caddr_t)arg, mode, &cbuf,
531 &cbuflen)) != 0)
532 break;
535 * Execute the command.
538 rc = ippctl_cmd(cbuf, cbuflen, &nextbuflen);
541 * Pass back the length of the first data buffer.
544 DBG1(DBG_CBOPS, "nextbuflen = %lu\n", nextbuflen);
545 *rvalp = nextbuflen;
548 * Free the kernel copy of the command buffer.
551 kmem_free(cbuf, cbuflen);
552 break;
554 case IPPCTL_DATA:
555 DBG0(DBG_CBOPS, "data\n");
558 * Grab the next data buffer from the array of pending
559 * buffers.
562 if ((rc = ippctl_data(&dbuf, &dbuflen, &nextbuflen)) != 0)
563 break;
566 * Copy it out to user space.
569 rc = ippctl_copyout((caddr_t)arg, mode, dbuf, dbuflen);
572 * Pass back the length of the next data buffer.
575 DBG1(DBG_CBOPS, "nextbuflen = %lu\n", nextbuflen);
576 *rvalp = nextbuflen;
577 break;
579 default:
580 DBG0(DBG_CBOPS, "unrecognized ioctl\n");
581 rc = EINVAL;
582 break;
585 DBG1(DBG_CBOPS, "rc = %d\n", rc);
586 return (rc);
588 #undef __FN__
591 * Local functions
594 #define __FN__ "ippctl_copyin"
595 static int
596 ippctl_copyin(
597 caddr_t arg,
598 int mode,
599 char **kbufp,
600 size_t *kbuflenp)
602 ippctl_ioctl_t iioc;
603 caddr_t ubuf;
604 char *kbuf;
605 size_t ubuflen;
607 DBG0(DBG_CBOPS, "copying in ioctl structure\n");
610 * Copy in the ioctl structure from user-space, converting from 32-bit
611 * as necessary.
614 #ifdef _MULTI_DATAMODEL
615 switch (ddi_model_convert_from(mode & FMODELS)) {
616 case DDI_MODEL_ILP32:
618 ippctl_ioctl32_t iioc32;
620 DBG0(DBG_CBOPS, "converting from 32-bit\n");
622 if (ddi_copyin(arg, (caddr_t)&iioc32,
623 sizeof (ippctl_ioctl32_t), mode) != 0)
624 return (EFAULT);
626 ubuf = (caddr_t)(uintptr_t)iioc32.ii32_buf;
627 ubuflen = (size_t)iioc32.ii32_buflen;
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);
635 ubuf = iioc.ii_buf;
636 ubuflen = iioc.ii_buflen;
637 break;
638 default:
639 return (EFAULT);
641 #else /* _MULTI_DATAMODEL */
642 if (ddi_copyin(arg, (caddr_t)&iioc, sizeof (ippctl_ioctl_t),
643 mode) != 0)
644 return (EFAULT);
646 ubuf = iioc.ii_buf;
647 ubuflen = iioc.ii_buflen;
648 #endif /* _MULTI_DATAMODEL */
650 DBG1(DBG_CBOPS, "ubuf = 0x%p\n", (void *)ubuf);
651 DBG1(DBG_CBOPS, "ubuflen = %lu\n", ubuflen);
654 * Sanity check the command buffer information.
657 if (ubuflen == 0 || ubuf == NULL)
658 return (EINVAL);
659 if (ubuflen > MAXUBUFLEN)
660 return (E2BIG);
663 * Allocate some memory for the command buffer and copy it in.
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);
673 *kbufp = kbuf;
674 *kbuflenp = ubuflen;
675 return (0);
677 #undef __FN__
679 #define __FN__ "ippctl_copyout"
680 static int
681 ippctl_copyout(
682 caddr_t arg,
683 int mode,
684 char *kbuf,
685 size_t kbuflen)
687 ippctl_ioctl_t iioc;
688 caddr_t ubuf;
689 int ubuflen;
691 DBG0(DBG_CBOPS, "copying out ioctl structure\n");
694 * Copy in the ioctl structure from user-space, converting from 32-bit
695 * as necessary.
698 #ifdef _MULTI_DATAMODEL
699 switch (ddi_model_convert_from(mode & FMODELS)) {
700 case DDI_MODEL_ILP32:
702 ippctl_ioctl32_t iioc32;
704 if (ddi_copyin(arg, (caddr_t)&iioc32,
705 sizeof (ippctl_ioctl32_t), mode) != 0)
706 return (EFAULT);
708 ubuf = (caddr_t)(uintptr_t)iioc32.ii32_buf;
709 ubuflen = iioc32.ii32_buflen;
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);
717 ubuf = iioc.ii_buf;
718 ubuflen = iioc.ii_buflen;
719 break;
720 default:
721 return (EFAULT);
723 #else /* _MULTI_DATAMODEL */
724 if (ddi_copyin(arg, (caddr_t)&iioc, sizeof (ippctl_ioctl_t),
725 mode) != 0)
726 return (EFAULT);
728 ubuf = iioc.ii_buf;
729 ubuflen = iioc.ii_buflen;
730 #endif /* _MULTI_DATAMODEL */
732 DBG1(DBG_CBOPS, "ubuf = 0x%p\n", (void *)ubuf);
733 DBG1(DBG_CBOPS, "ubuflen = %d\n", ubuflen);
736 * Sanity check the data buffer details.
739 if (ubuflen == 0 || ubuf == NULL)
740 return (EINVAL);
742 if (ubuflen < kbuflen)
743 return (ENOSPC);
744 if (ubuflen > MAXUBUFLEN)
745 return (E2BIG);
748 * Copy out the data buffer to user space.
751 DBG0(DBG_CBOPS, "copying out nvlist\n");
752 if (ddi_copyout((caddr_t)kbuf, ubuf, kbuflen, mode) != 0)
753 return (EFAULT);
755 return (0);
757 #undef __FN__
759 #define __FN__ "ippctl_extract_op"
760 static int
761 ippctl_extract_op(
762 nvlist_t *nvlp,
763 uint8_t *valp)
765 int rc;
768 * Look-up and remove the opcode passed from libipp from the
769 * nvlist.
772 if ((rc = nvlist_lookup_byte(nvlp, IPPCTL_OP, valp)) != 0)
773 return (rc);
775 (void) nvlist_remove_all(nvlp, IPPCTL_OP);
776 return (0);
778 #undef __FN__
780 #define __FN__ "ippctl_extract_aname"
781 static int
782 ippctl_extract_aname(
783 nvlist_t *nvlp,
784 char **valp)
786 int rc;
787 char *ptr;
790 * Look-up and remove the action name passed from libipp from the
791 * nvlist.
794 if ((rc = nvlist_lookup_string(nvlp, IPPCTL_ANAME, &ptr)) != 0)
795 return (rc);
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);
802 #undef __FN__
804 #define __FN__ "ippctl_extract_modname"
805 static int
806 ippctl_extract_modname(
807 nvlist_t *nvlp,
808 char **valp)
810 int rc;
811 char *ptr;
814 * Look-up and remove the module name passed from libipp from the
815 * nvlist.
818 if ((rc = nvlist_lookup_string(nvlp, IPPCTL_MODNAME, &ptr)) != 0)
819 return (rc);
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);
826 #undef __FN__
828 #define __FN__ "ippctl_attach_modname"
829 static int
830 ippctl_attach_modname(
831 nvlist_t *nvlp,
832 char *modname)
835 * Add a module name to an nvlist for passing back to user
836 * space.
839 return (nvlist_add_string(nvlp, IPPCTL_MODNAME, modname));
841 #undef __FN__
843 #define __FN__ "ippctl_attach_modname_array"
844 static int
845 ippctl_attach_modname_array(
846 nvlist_t *nvlp,
847 char **modname_array,
848 int nelt)
851 * Add a module name array to an nvlist for passing back to user
852 * space.
855 return (nvlist_add_string_array(nvlp, IPPCTL_MODNAME_ARRAY,
856 modname_array, nelt));
858 #undef __FN__
860 #define __FN__ "ippctl_attach_aname_array"
861 static int
862 ippctl_attach_aname_array(
863 nvlist_t *nvlp,
864 char **aname_array,
865 int nelt)
868 * Add an action name array to an nvlist for passing back to user
869 * space.
872 return (nvlist_add_string_array(nvlp, IPPCTL_ANAME_ARRAY,
873 aname_array, nelt));
875 #undef __FN__
877 #define __FN__ "ippctl_extract_flags"
878 static int
879 ippctl_extract_flags(
880 nvlist_t *nvlp,
881 ipp_flags_t *valp)
883 int rc;
886 * Look-up and remove the flags passed from libipp from the
887 * nvlist.
890 if ((rc = nvlist_lookup_uint32(nvlp, IPPCTL_FLAGS,
891 (uint32_t *)valp)) != 0)
892 return (rc);
894 (void) nvlist_remove_all(nvlp, IPPCTL_FLAGS);
895 return (0);
897 #undef __FN__
899 #define __FN__ "ippctl_cmd"
900 static int
901 ippctl_cmd(
902 char *cbuf,
903 size_t cbuflen,
904 size_t *nextbuflenp)
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;
914 * Start a new command cycle by flushing any previous data buffers.
917 ippctl_flush();
918 *nextbuflenp = 0;
921 * Unpack the nvlist from the command buffer.
924 if ((rc = nvlist_unpack(cbuf, cbuflen, &nvlp, KM_SLEEP)) != 0)
925 return (rc);
928 * Extract the opcode to find out what we should do.
931 if ((rc = ippctl_extract_op(nvlp, &op)) != 0) {
932 nvlist_free(nvlp);
933 return (rc);
936 switch (op) {
937 case IPPCTL_OP_ACTION_CREATE:
939 * Create a new action.
942 DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_CREATE\n");
945 * Extract the module name, action name and flags from the
946 * nvlist.
949 if ((rc = ippctl_extract_modname(nvlp, &modname)) != 0) {
950 nvlist_free(nvlp);
951 return (rc);
954 if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) {
955 FREE_TEXT(modname);
956 nvlist_free(nvlp);
957 return (rc);
960 if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) {
961 FREE_TEXT(aname);
962 FREE_TEXT(modname);
963 nvlist_free(nvlp);
964 return (rc);
968 rc = ippctl_action_create(modname, aname, nvlp, flags);
969 break;
971 case IPPCTL_OP_ACTION_MODIFY:
974 * Modify an existing action.
977 DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_MODIFY\n");
980 * Extract the action name and flags from the nvlist.
983 if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) {
984 nvlist_free(nvlp);
985 return (rc);
988 if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) {
989 FREE_TEXT(aname);
990 nvlist_free(nvlp);
991 return (rc);
994 rc = ippctl_action_modify(aname, nvlp, flags);
995 break;
997 case IPPCTL_OP_ACTION_DESTROY:
1000 * Destroy an action.
1003 DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_DESTROY\n");
1006 * Extract the action name and flags from the nvlist.
1009 if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) {
1010 nvlist_free(nvlp);
1011 return (rc);
1014 if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) {
1015 FREE_TEXT(aname);
1016 nvlist_free(nvlp);
1017 return (rc);
1020 nvlist_free(nvlp);
1021 rc = ippctl_action_destroy(aname, flags);
1022 break;
1024 case IPPCTL_OP_ACTION_INFO:
1027 * Retrive the configuration of an action.
1030 DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_INFO\n");
1033 * Extract the action name and flags from the nvlist.
1036 if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) {
1037 nvlist_free(nvlp);
1038 return (rc);
1041 if ((rc = ippctl_extract_flags(nvlp, &flags)) != 0) {
1042 nvlist_free(nvlp);
1043 FREE_TEXT(aname);
1044 return (rc);
1047 nvlist_free(nvlp);
1048 rc = ippctl_action_info(aname, flags);
1049 break;
1051 case IPPCTL_OP_ACTION_MOD:
1054 * Find the module that implements a given action.
1057 DBG0(DBG_CBOPS, "op = IPPCTL_OP_ACTION_MOD\n");
1060 * Extract the action name from the nvlist.
1063 if ((rc = ippctl_extract_aname(nvlp, &aname)) != 0) {
1064 nvlist_free(nvlp);
1065 return (rc);
1068 nvlist_free(nvlp);
1069 rc = ippctl_action_mod(aname);
1070 break;
1072 case IPPCTL_OP_LIST_MODS:
1075 * List all the modules.
1078 DBG0(DBG_CBOPS, "op = IPPCTL_OP_LIST_MODS\n");
1080 nvlist_free(nvlp);
1081 rc = ippctl_list_mods();
1082 break;
1084 case IPPCTL_OP_MOD_LIST_ACTIONS:
1087 * List all the actions for a given module.
1090 DBG0(DBG_CBOPS, "op = IPPCTL_OP_LIST_MODS\n");
1092 if ((rc = ippctl_extract_modname(nvlp, &modname)) != 0) {
1093 nvlist_free(nvlp);
1094 return (rc);
1097 nvlist_free(nvlp);
1098 rc = ippctl_mod_list_actions(modname);
1099 break;
1101 default:
1104 * Unrecognized opcode.
1107 nvlist_free(nvlp);
1108 rc = EINVAL;
1109 break;
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).
1121 if (rc == 0)
1122 *nextbuflenp = ippctl_array[0].buflen;
1124 return (rc);
1126 #undef __FN__
1128 #define __FN__ "ippctl_action_create"
1129 static int
1130 ippctl_action_create(
1131 char *modname,
1132 char *aname,
1133 nvlist_t *nvlp,
1134 ipp_flags_t flags)
1136 int ipp_rc;
1137 int rc;
1138 ipp_mod_id_t mid;
1139 ipp_action_id_t aid;
1142 * Look up the module id from the name and create the new
1143 * action.
1146 mid = ipp_mod_lookup(modname);
1147 FREE_TEXT(modname);
1149 ipp_rc = ipp_action_create(mid, aname, &nvlp, flags, &aid);
1150 FREE_TEXT(aname);
1153 * Add an nvlist containing the kernel return code to the
1154 * set of nvlists to pass back to libipp.
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*/
1167 return (rc);
1171 * If the module passed back an nvlist, add this as
1172 * well.
1175 if (nvlp != NULL) {
1176 rc = ippctl_callback(nvlp, NULL);
1177 nvlist_free(nvlp);
1178 } else
1179 rc = 0;
1181 return (rc);
1183 #undef __FN__
1185 #define __FN__ "ippctl_action_destroy"
1186 static int
1187 ippctl_action_destroy(
1188 char *aname,
1189 ipp_flags_t flags)
1191 ipp_action_id_t aid;
1192 int ipp_rc;
1193 int rc;
1196 * Look up the action id and destroy the action.
1199 aid = ipp_action_lookup(aname);
1200 FREE_TEXT(aname);
1202 ipp_rc = ipp_action_destroy(aid, flags);
1205 * Add an nvlist containing the kernel return code to the
1206 * set of nvlists to pass back to libipp.
1209 if ((rc = ippctl_set_rc(ipp_rc)) != 0)
1210 return (rc);
1213 * There's no more information to pass back.
1216 return (0);
1218 #undef __FN__
1220 #define __FN__ "ippctl_action_modify"
1221 static int
1222 ippctl_action_modify(
1223 char *aname,
1224 nvlist_t *nvlp,
1225 ipp_flags_t flags)
1227 ipp_action_id_t aid;
1228 int ipp_rc;
1229 int rc;
1232 * Look up the action id and modify the action.
1235 aid = ipp_action_lookup(aname);
1236 FREE_TEXT(aname);
1238 ipp_rc = ipp_action_modify(aid, &nvlp, flags);
1241 * Add an nvlist containing the kernel return code to the
1242 * set of nvlists to pass back to libipp.
1245 if ((rc = ippctl_set_rc(ipp_rc)) != 0) {
1246 nvlist_free(nvlp);
1247 return (rc);
1251 * If the module passed back an nvlist, add this as
1252 * well.
1255 if (nvlp != NULL) {
1256 rc = ippctl_callback(nvlp, NULL);
1257 nvlist_free(nvlp);
1258 } else
1259 rc = 0;
1261 return (rc);
1263 #undef __FN__
1265 #define __FN__ "ippctl_action_info"
1266 static int
1267 ippctl_action_info(
1268 char *aname,
1269 ipp_flags_t flags)
1271 ipp_action_id_t aid;
1272 int ipp_rc;
1273 int rc;
1276 * Look up the action and call the information retrieval
1277 * entry point.
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.
1284 aid = ipp_action_lookup(aname);
1285 FREE_TEXT(aname);
1287 ipp_rc = ipp_action_info(aid, ippctl_callback, NULL, flags);
1290 * Add an nvlist containing the kernel return code to the
1291 * set of nvlists to pass back to libipp.
1294 if ((rc = ippctl_set_rc(ipp_rc)) != 0)
1295 return (rc);
1298 * There's no more information to pass back.
1301 return (0);
1303 #undef __FN__
1305 #define __FN__ "ippctl_action_mod"
1306 static int
1307 ippctl_action_mod(
1308 char *aname)
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;
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.
1323 aid = ipp_action_lookup(aname);
1324 FREE_TEXT(aname);
1326 if ((ipp_rc = ipp_action_mod(aid, &mid)) == 0)
1327 ipp_rc = ipp_mod_name(mid, &modname);
1330 * Add an nvlist containing the kernel return code to the
1331 * set of nvlists to pass back to libipp.
1334 if ((rc = ippctl_set_rc(ipp_rc)) != 0)
1335 return (rc);
1338 * If everything succeeded add an nvlist containing the
1339 * module name to the set of nvlists to pass back to libipp.
1342 if (ipp_rc == 0) {
1343 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_SLEEP)) != 0)
1344 return (rc);
1346 if ((rc = ippctl_attach_modname(nvlp, modname)) != 0) {
1347 nvlist_free(nvlp);
1348 return (rc);
1351 FREE_TEXT(modname);
1353 rc = ippctl_callback(nvlp, NULL);
1354 nvlist_free(nvlp);
1355 } else
1356 rc = 0;
1358 return (rc);
1360 #undef __FN__
1362 #define __FN__ "ippctl_list_mods"
1363 static int
1364 ippctl_list_mods(
1365 void)
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;
1377 * Get a list of all the module ids. If that succeeds,
1378 * translate the ids into names.
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.
1386 if ((ipp_rc = ipp_list_mods(&mid_array, &nelt)) == 0) {
1389 * It is possible that there are no modules
1390 * registered.
1393 if (nelt > 0) {
1394 length = nelt * sizeof (char *);
1395 modname_array = kmem_zalloc(length, KM_SLEEP);
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;
1408 kmem_free(mid_array, nelt * sizeof (ipp_mod_id_t));
1410 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME,
1411 KM_SLEEP)) != 0) {
1412 FREE_TEXT_ARRAY(modname_array, nelt);
1413 return (rc);
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);
1423 FREE_TEXT_ARRAY(modname_array, nelt);
1425 if ((rc = ippctl_callback(nvlp, NULL)) != 0) {
1426 nvlist_free(nvlp);
1427 return (rc);
1430 nvlist_free(nvlp);
1434 done:
1436 * Add an nvlist containing the kernel return code to the
1437 * set of nvlists to pass back to libipp.
1440 if ((rc = ippctl_set_rc(ipp_rc)) != 0)
1441 return (rc);
1443 return (0);
1445 #undef __FN__
1447 #define __FN__ "ippctl_mod_list_actions"
1448 static int
1449 ippctl_mod_list_actions(
1450 char *modname)
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;
1463 * Get the module id.
1466 mid = ipp_mod_lookup(modname);
1467 FREE_TEXT(modname);
1470 * Get a list of all the action ids for the module. If that succeeds,
1471 * translate the ids into names.
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.
1479 if ((ipp_rc = ipp_mod_list_actions(mid, &aid_array, &nelt)) == 0) {
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)
1487 if (nelt > 0) {
1488 length = nelt * sizeof (char *);
1489 aname_array = kmem_zalloc(length, KM_SLEEP);
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;
1502 kmem_free(aid_array, nelt * sizeof (ipp_action_id_t));
1504 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME,
1505 KM_SLEEP)) != 0) {
1506 FREE_TEXT_ARRAY(aname_array, nelt);
1507 return (rc);
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);
1517 FREE_TEXT_ARRAY(aname_array, nelt);
1519 if ((rc = ippctl_callback(nvlp, NULL)) != 0) {
1520 nvlist_free(nvlp);
1521 return (rc);
1524 nvlist_free(nvlp);
1528 done:
1530 * Add an nvlist containing the kernel return code to the
1531 * set of nvlists to pass back to libipp.
1534 if ((rc = ippctl_set_rc(ipp_rc)) != 0)
1535 return (rc);
1537 return (0);
1539 #undef __FN__
1541 #define __FN__ "ippctl_data"
1542 static int
1543 ippctl_data(
1544 char **dbufp,
1545 size_t *dbuflenp,
1546 size_t *nextbuflenp)
1548 int i;
1550 DBG0(DBG_CBOPS, "called\n");
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.
1558 i = ippctl_rindex;
1559 if (i == ippctl_windex)
1560 return (ENOENT);
1563 * Extract the buffer details. It is a pre-packed nvlist.
1566 *dbufp = ippctl_array[i].buf;
1567 *dbuflenp = ippctl_array[i].buflen;
1569 DBG2(DBG_CBOPS, "accessing nvlist[%d], length %lu\n", i, *dbuflenp);
1570 ASSERT(*dbufp != NULL);
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.
1578 i++;
1579 if (i < ippctl_windex)
1580 *nextbuflenp = ippctl_array[i].buflen;
1581 else
1582 *nextbuflenp = 0;
1584 ippctl_rindex = i;
1585 return (0);
1587 #undef __FN__
1589 #define __FN__ "ippctl_flush"
1590 static void
1591 ippctl_flush(
1592 void)
1594 int i;
1595 char *buf;
1596 size_t buflen;
1599 * Free any buffers left in the array.
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);
1611 * NULL all the entries.
1614 bzero(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t));
1617 * Reset the indexes.
1620 ippctl_rindex = 0;
1621 ippctl_windex = 1;
1623 #undef __FN__
1625 #define __FN__ "ippctl_add_nvlist"
1626 static int
1627 ippctl_add_nvlist(
1628 nvlist_t *nvlp,
1629 int i)
1631 char *buf;
1632 size_t buflen;
1633 int rc;
1636 * NULL the buffer pointer so that a buffer is automatically
1637 * allocated for us.
1640 buf = NULL;
1643 * Pack the nvlist and get back the buffer pointer and length.
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);
1653 DBG2(DBG_CBOPS, "added nvlist[%d]: length %lu\n", i, buflen);
1656 * Store the pointer an length in the array at the given index.
1659 ippctl_array[i].buf = buf;
1660 ippctl_array[i].buflen = buflen;
1662 return (0);
1664 #undef __FN__
1666 #define __FN__ "ippctl_callback"
1667 /*ARGSUSED*/
1668 static int
1669 ippctl_callback(
1670 nvlist_t *nvlp,
1671 void *arg)
1673 int i;
1674 int rc;
1677 * Check the 'write index' to see if there's space in the array for
1678 * a new entry.
1681 i = ippctl_windex;
1682 ASSERT(i != 0);
1685 * If there's no space, re-allocate the array (see comments in
1686 * ippctl_realloc() for details).
1689 if (i == ippctl_limit)
1690 ippctl_realloc();
1693 * Add the nvlist to the array.
1696 if ((rc = ippctl_add_nvlist(nvlp, i)) == 0)
1697 ippctl_windex++;
1699 return (rc);
1701 #undef __FN__
1703 #define __FN__ "ippctl_set_rc"
1704 static int
1705 ippctl_set_rc(
1706 int val)
1708 nvlist_t *nvlp;
1709 int rc;
1712 * Create an nvlist to store the return code,
1715 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_SLEEP)) != 0)
1716 return (ENOMEM);
1718 if ((rc = nvlist_add_int32(nvlp, IPPCTL_RC, val)) != 0) {
1719 nvlist_free(nvlp);
1720 return (rc);
1724 * Add it at the beginning of the array.
1727 rc = ippctl_add_nvlist(nvlp, 0);
1729 nvlist_free(nvlp);
1730 return (rc);
1732 #undef __FN__
1734 #define __FN__ "ippctl_alloc"
1735 static void
1736 ippctl_alloc(
1737 int limit)
1740 * Allocate the data buffer array and initialize the indexes.
1743 ippctl_array = kmem_zalloc(limit * sizeof (ippctl_buf_t), KM_SLEEP);
1744 ippctl_limit = limit;
1745 ippctl_rindex = 0;
1746 ippctl_windex = 1;
1748 #undef __FN__
1750 #define __FN__ "ippctl_realloc"
1751 static void
1752 ippctl_realloc(
1753 void)
1755 ippctl_buf_t *array;
1756 int limit;
1757 int i;
1760 * Allocate a new array twice the size of the old one.
1763 limit = ippctl_limit << 1;
1764 array = kmem_zalloc(limit * sizeof (ippctl_buf_t), KM_SLEEP);
1767 * Copy across the information from the old array into the new one.
1770 for (i = 0; i < ippctl_limit; i++)
1771 array[i] = ippctl_array[i];
1774 * Free the old array.
1777 kmem_free(ippctl_array, ippctl_limit * sizeof (ippctl_buf_t));
1779 ippctl_array = array;
1780 ippctl_limit = limit;
1782 #undef __FN__
1784 #define __FN__ "ippctl_free"
1785 static void
1786 ippctl_free(
1787 void)
1790 * Flush the array prior to freeing it to make sure no buffers are
1791 * leaked.
1794 ippctl_flush();
1797 * Free the array.
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;
1806 #undef __FN__
1808 #ifdef IPPCTL_DEBUG
1809 static void
1810 ippctl_debug(
1811 uint64_t type,
1812 char *fn,
1813 char *fmt,
1814 ...)
1816 char buf[255];
1817 va_list adx;
1819 if ((type & ippctl_debug_flags) == 0)
1820 return;
1822 mutex_enter(debug_mutex);
1823 va_start(adx, fmt);
1824 (void) vsnprintf(buf, 255, fmt, adx);
1825 va_end(adx);
1827 printf("%s: %s", fn, buf);
1828 mutex_exit(debug_mutex);
1830 #endif /* IPPCTL_DBG */