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