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