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