VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/solaris/VBoxUSBMon-solaris.c@ 56927

Last change on this file since 56927 was 56293, checked in by vboxsync, 10 years ago

HostDrivers: Updated (C) year.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.8 KB
Line 
1/* $Id: VBoxUSBMon-solaris.c 56293 2015-06-09 14:23:56Z vboxsync $ */
2/** @file
3 * VirtualBox USB Monitor Driver, Solaris Hosts.
4 */
5
6/*
7 * Copyright (C) 2008-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#define LOG_GROUP LOG_GROUP_USB_DRV
31#include "VBoxUSBFilterMgr.h"
32#include <VBox/usblib-solaris.h>
33#include <VBox/version.h>
34#include <VBox/log.h>
35#include <VBox/cdefs.h>
36#include <VBox/types.h>
37#include <VBox/version.h>
38#include <iprt/assert.h>
39#include <iprt/string.h>
40#include <iprt/initterm.h>
41#include <iprt/process.h>
42#include <iprt/mem.h>
43#include <iprt/semaphore.h>
44#include <iprt/path.h>
45
46#define USBDRV_MAJOR_VER 2
47#define USBDRV_MINOR_VER 0
48#include <sys/usb/usba.h>
49#include <sys/conf.h>
50#include <sys/modctl.h>
51#include <sys/mutex.h>
52#include <sys/stat.h>
53#include <sys/ddi.h>
54#include <sys/sunddi.h>
55#include <sys/sunndi.h>
56#include <sys/open.h>
57#include <sys/cmn_err.h>
58
59
60/*******************************************************************************
61* Defined Constants And Macros *
62*******************************************************************************/
63/** The module name. */
64#define DEVICE_NAME "vboxusbmon"
65/** The module description as seen in 'modinfo'. */
66#define DEVICE_DESC_DRV "VirtualBox USBMon"
67
68/*******************************************************************************
69* Internal Functions *
70*******************************************************************************/
71static int VBoxUSBMonSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred);
72static int VBoxUSBMonSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred);
73static int VBoxUSBMonSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred);
74static int VBoxUSBMonSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred);
75static int VBoxUSBMonSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal);
76static int VBoxUSBMonSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
77static int VBoxUSBMonSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
78static int VBoxUSBMonSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
79
80/*******************************************************************************
81* Structures and Typedefs *
82*******************************************************************************/
83/**
84 * cb_ops: for drivers that support char/block entry points
85 */
86static struct cb_ops g_VBoxUSBMonSolarisCbOps =
87{
88 VBoxUSBMonSolarisOpen,
89 VBoxUSBMonSolarisClose,
90 nodev, /* b strategy */
91 nodev, /* b dump */
92 nodev, /* b print */
93 VBoxUSBMonSolarisRead,
94 VBoxUSBMonSolarisWrite,
95 VBoxUSBMonSolarisIOCtl,
96 nodev, /* c devmap */
97 nodev, /* c mmap */
98 nodev, /* c segmap */
99 nochpoll, /* c poll */
100 ddi_prop_op, /* property ops */
101 NULL, /* streamtab */
102 D_NEW | D_MP, /* compat. flag */
103 CB_REV /* revision */
104};
105
106/**
107 * dev_ops: for driver device operations
108 */
109static struct dev_ops g_VBoxUSBMonSolarisDevOps =
110{
111 DEVO_REV, /* driver build revision */
112 0, /* ref count */
113 VBoxUSBMonSolarisGetInfo,
114 nulldev, /* identify */
115 nulldev, /* probe */
116 VBoxUSBMonSolarisAttach,
117 VBoxUSBMonSolarisDetach,
118 nodev, /* reset */
119 &g_VBoxUSBMonSolarisCbOps,
120 (struct bus_ops *)0,
121 nodev, /* power */
122 ddi_quiesce_not_needed
123};
124
125/**
126 * modldrv: export driver specifics to the kernel
127 */
128static struct modldrv g_VBoxUSBMonSolarisModule =
129{
130 &mod_driverops, /* extern from kernel */
131 DEVICE_DESC_DRV " " VBOX_VERSION_STRING "r" RT_XSTR(VBOX_SVN_REV),
132 &g_VBoxUSBMonSolarisDevOps
133};
134
135/**
136 * modlinkage: export install/remove/info to the kernel
137 */
138static struct modlinkage g_VBoxUSBMonSolarisModLinkage =
139{
140 MODREV_1,
141 &g_VBoxUSBMonSolarisModule,
142 NULL,
143};
144
145/**
146 * Client driver info.
147 */
148typedef struct vboxusbmon_client_t
149{
150 dev_info_t *pDip; /* Client device info. pointer */
151 VBOXUSB_CLIENT_INFO Info; /* Client registration data. */
152 struct vboxusbmon_client_t *pNext; /* Pointer to next client */
153} vboxusbmon_client_t;
154
155/**
156 * Device state info.
157 */
158typedef struct
159{
160 RTPROCESS Process; /* The process (id) of the session */
161} vboxusbmon_state_t;
162
163
164/*******************************************************************************
165* Global Variables *
166*******************************************************************************/
167/** Global Device handle we only support one instance. */
168static dev_info_t *g_pDip = NULL;
169/** Global Mutex. */
170static kmutex_t g_VBoxUSBMonSolarisMtx;
171/** Number of userland clients that have kept us open. */
172static uint64_t g_cVBoxUSBMonSolarisClient = 0;
173/** Global list of client drivers registered with us. */
174vboxusbmon_client_t *g_pVBoxUSBMonSolarisClients = NULL;
175/** Opaque pointer to list of soft states. */
176static void *g_pVBoxUSBMonSolarisState;
177
178/*******************************************************************************
179* Internal Functions *
180*******************************************************************************/
181static int vboxUSBMonSolarisProcessIOCtl(int iFunction, void *pvState, void *pvData, size_t cbData, size_t *pcbReturnedData);
182static int vboxUSBMonSolarisResetDevice(char *pszDevicePath, bool fReattach);
183
184
185/*******************************************************************************
186* Monitor Global Hooks *
187*******************************************************************************/
188static int vboxUSBMonSolarisClientInfo(vboxusbmon_state_t *pState, PVBOXUSB_CLIENT_INFO pClientInfo);
189int VBoxUSBMonSolarisRegisterClient(dev_info_t *pClientDip, PVBOXUSB_CLIENT_INFO pClientInfo);
190int VBoxUSBMonSolarisUnregisterClient(dev_info_t *pClientDip);
191int VBoxUSBMonSolarisElectDriver(usb_dev_descr_t *pDevDesc, usb_dev_str_t *pDevStrings, char *pszDevicePath, int Bus, int Port,
192 char **ppszDrv, void *pvReserved);
193
194
195/**
196 * Kernel entry points
197 */
198int _init(void)
199{
200 int rc;
201
202 LogFunc((DEVICE_NAME ":_init\n"));
203
204 g_pDip = NULL;
205
206 /*
207 * Prevent module autounloading.
208 */
209 modctl_t *pModCtl = mod_getctl(&g_VBoxUSBMonSolarisModLinkage);
210 if (pModCtl)
211 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
212 else
213 LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
214
215 /*
216 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
217 */
218 rc = RTR0Init(0);
219 if (RT_SUCCESS(rc))
220 {
221 /*
222 * Initialize global mutex.
223 */
224 mutex_init(&g_VBoxUSBMonSolarisMtx, NULL, MUTEX_DRIVER, NULL);
225 rc = VBoxUSBFilterInit();
226 if (RT_SUCCESS(rc))
227 {
228 rc = ddi_soft_state_init(&g_pVBoxUSBMonSolarisState, sizeof(vboxusbmon_state_t), 1);
229 if (!rc)
230 {
231 rc = mod_install(&g_VBoxUSBMonSolarisModLinkage);
232 if (!rc)
233 return rc;
234
235 LogRel((DEVICE_NAME ":mod_install failed! rc=%d\n", rc));
236 ddi_soft_state_fini(&g_pVBoxUSBMonSolarisState);
237 }
238 else
239 LogRel((DEVICE_NAME ":ddi_soft_state_init failed! rc=%d\n", rc));
240 }
241 else
242 LogRel((DEVICE_NAME ":VBoxUSBFilterInit failed! rc=%d\n", rc));
243
244 mutex_destroy(&g_VBoxUSBMonSolarisMtx);
245 RTR0Term();
246 }
247 else
248 LogRel((DEVICE_NAME ":RTR0Init failed! rc=%d\n", rc));
249
250 return -1;
251}
252
253
254int _fini(void)
255{
256 int rc;
257
258 LogFunc((DEVICE_NAME ":_fini\n"));
259
260 rc = mod_remove(&g_VBoxUSBMonSolarisModLinkage);
261 if (!rc)
262 {
263 ddi_soft_state_fini(&g_pVBoxUSBMonSolarisState);
264 VBoxUSBFilterTerm();
265 mutex_destroy(&g_VBoxUSBMonSolarisMtx);
266
267 RTR0Term();
268 }
269 return rc;
270}
271
272
273int _info(struct modinfo *pModInfo)
274{
275 LogFunc((DEVICE_NAME ":_info\n"));
276
277 return mod_info(&g_VBoxUSBMonSolarisModLinkage, pModInfo);
278}
279
280
281/**
282 * Attach entry point, to attach a device to the system or resume it.
283 *
284 * @param pDip The module structure instance.
285 * @param enmCmd Attach type (ddi_attach_cmd_t)
286 *
287 * @returns corresponding solaris error code.
288 */
289static int VBoxUSBMonSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
290{
291 LogFunc((DEVICE_NAME ":VBoxUSBMonSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd));
292 switch (enmCmd)
293 {
294 case DDI_ATTACH:
295 {
296 if (RT_UNLIKELY(g_pDip))
297 {
298 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisAttach global instance already initialized.\n"));
299 return DDI_FAILURE;
300 }
301
302 g_pDip = pDip;
303 int instance = ddi_get_instance(pDip);
304 int rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, 0,
305 "none", "none", 0660);
306 if (rc == DDI_SUCCESS)
307 {
308 ddi_report_dev(pDip);
309 return rc;
310 }
311 else
312 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisAttach ddi_create_minor_node failed! rc=%d\n", rc));
313 return DDI_FAILURE;
314 }
315
316 case DDI_RESUME:
317 {
318 /* We don't have to bother about power management. */
319 return DDI_SUCCESS;
320 }
321
322 default:
323 return DDI_FAILURE;
324 }
325}
326
327
328/**
329 * Detach entry point, to detach a device to the system or suspend it.
330 *
331 * @param pDip The module structure instance.
332 * @param enmCmd Attach type (ddi_attach_cmd_t)
333 *
334 * @returns corresponding solaris error code.
335 */
336static int VBoxUSBMonSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
337{
338 LogFunc((DEVICE_NAME ":VBoxUSBMonSolarisDetach\n"));
339
340 switch (enmCmd)
341 {
342 case DDI_DETACH:
343 {
344 /*
345 * Free all registered clients' info.
346 */
347 mutex_enter(&g_VBoxUSBMonSolarisMtx);
348 vboxusbmon_client_t *pCur = g_pVBoxUSBMonSolarisClients;
349 while (pCur)
350 {
351 vboxusbmon_client_t *pNext = pCur->pNext;
352 RTMemFree(pCur);
353 pCur = pNext;
354 }
355 mutex_exit(&g_VBoxUSBMonSolarisMtx);
356
357 ddi_remove_minor_node(pDip, NULL);
358 g_pDip = NULL;
359 return DDI_SUCCESS;
360 }
361
362 case DDI_SUSPEND:
363 {
364 /* We don't have to bother about power management. */
365 return DDI_SUCCESS;
366 }
367
368 default:
369 return DDI_FAILURE;
370 }
371}
372
373
374/**
375 * Info entry point, called by solaris kernel for obtaining driver info.
376 *
377 * @param pDip The module structure instance (do not use).
378 * @param enmCmd Information request type.
379 * @param pvArg Type specific argument.
380 * @param ppvResult Where to store the requested info.
381 *
382 * @returns corresponding solaris error code.
383 */
384static int VBoxUSBMonSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppvResult)
385{
386 int rc = DDI_SUCCESS;
387
388 LogFunc((DEVICE_NAME ":VBoxUSBMonSolarisGetInfo\n"));
389
390 switch (enmCmd)
391 {
392 case DDI_INFO_DEVT2DEVINFO:
393 *ppvResult = (void *)g_pDip;
394 break;
395
396 case DDI_INFO_DEVT2INSTANCE:
397 *ppvResult = (void *)(uintptr_t)ddi_get_instance(g_pDip);
398 break;
399
400 default:
401 rc = DDI_FAILURE;
402 break;
403 }
404 return rc;
405}
406
407
408static int VBoxUSBMonSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
409{
410 vboxusbmon_state_t *pState = NULL;
411 unsigned iOpenInstance;
412
413 LogFunc((DEVICE_NAME ":VBoxUSBMonSolarisOpen\n"));
414
415 /*
416 * Verify we are being opened as a character device.
417 */
418 if (fType != OTYP_CHR)
419 return EINVAL;
420
421 /*
422 * Verify that we're called after attach.
423 */
424 if (!g_pDip)
425 {
426 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisOpen invalid state for opening.\n"));
427 return ENXIO;
428 }
429
430 mutex_enter(&g_VBoxUSBMonSolarisMtx);
431 if (!g_cVBoxUSBMonSolarisClient)
432 {
433 mutex_exit(&g_VBoxUSBMonSolarisMtx);
434 int rc = usb_register_dev_driver(g_pDip, VBoxUSBMonSolarisElectDriver);
435 if (RT_UNLIKELY(rc != DDI_SUCCESS))
436 {
437 LogRel((DEVICE_NAME ":Failed to register driver election callback with USBA rc=%d\n", rc));
438 return EINVAL;
439 }
440 Log((DEVICE_NAME ":Successfully registered election callback with USBA\n"));
441 mutex_enter(&g_VBoxUSBMonSolarisMtx);
442 }
443 g_cVBoxUSBMonSolarisClient++;
444 mutex_exit(&g_VBoxUSBMonSolarisMtx);
445
446 for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++)
447 {
448 if ( !ddi_get_soft_state(g_pVBoxUSBMonSolarisState, iOpenInstance) /* faster */
449 && ddi_soft_state_zalloc(g_pVBoxUSBMonSolarisState, iOpenInstance) == DDI_SUCCESS)
450 {
451 pState = ddi_get_soft_state(g_pVBoxUSBMonSolarisState, iOpenInstance);
452 break;
453 }
454 }
455 if (!pState)
456 {
457 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisOpen: too many open instances."));
458 mutex_enter(&g_VBoxUSBMonSolarisMtx);
459 g_cVBoxUSBMonSolarisClient--;
460 mutex_exit(&g_VBoxUSBMonSolarisMtx);
461 return ENXIO;
462 }
463
464 pState->Process = RTProcSelf();
465 *pDev = makedevice(getmajor(*pDev), iOpenInstance);
466
467 NOREF(fFlag);
468 NOREF(pCred);
469
470 return 0;
471}
472
473
474static int VBoxUSBMonSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred)
475{
476 vboxusbmon_state_t *pState = NULL;
477
478 LogFunc((DEVICE_NAME ":VBoxUSBMonSolarisClose\n"));
479
480 pState = ddi_get_soft_state(g_pVBoxUSBMonSolarisState, getminor(Dev));
481 if (!pState)
482 {
483 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisClose: failed to get pState.\n"));
484 return EFAULT;
485 }
486
487 mutex_enter(&g_VBoxUSBMonSolarisMtx);
488 g_cVBoxUSBMonSolarisClient--;
489 if (!g_cVBoxUSBMonSolarisClient)
490 {
491 if (RT_LIKELY(g_pDip))
492 {
493 mutex_exit(&g_VBoxUSBMonSolarisMtx);
494 usb_unregister_dev_driver(g_pDip);
495 Log((DEVICE_NAME ":Successfully deregistered driver election callback\n"));
496 }
497 else
498 {
499 mutex_exit(&g_VBoxUSBMonSolarisMtx);
500 LogRel((DEVICE_NAME ":Extreme error! Missing device info during close.\n"));
501 }
502 }
503 else
504 mutex_exit(&g_VBoxUSBMonSolarisMtx);
505
506 /*
507 * Remove all filters for this client process.
508 */
509 VBoxUSBFilterRemoveOwner(pState->Process);
510
511 ddi_soft_state_free(g_pVBoxUSBMonSolarisState, getminor(Dev));
512 pState = NULL;
513
514 NOREF(fFlag);
515 NOREF(fType);
516 NOREF(pCred);
517
518 return 0;
519}
520
521
522static int VBoxUSBMonSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
523{
524 LogFunc((DEVICE_NAME ":VBoxUSBMonSolarisRead\n"));
525 return 0;
526}
527
528
529static int VBoxUSBMonSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
530{
531 LogFunc((DEVICE_NAME ":VBoxUSBMonSolarisWrite\n"));
532 return 0;
533}
534
535
536/** @def IOCPARM_LEN
537 * Gets the length from the ioctl number.
538 * This is normally defined by sys/ioccom.h on BSD systems...
539 */
540#ifndef IOCPARM_LEN
541# define IOCPARM_LEN(Code) (((Code) >> 16) & IOCPARM_MASK)
542#endif
543
544static int VBoxUSBMonSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal)
545{
546 LogFunc((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl Dev=%d Cmd=%d pArg=%p Mode=%d\n", Dev, Cmd, pArg));
547
548 /*
549 * Get the session from the soft state item.
550 */
551 vboxusbmon_state_t *pState = ddi_get_soft_state(g_pVBoxUSBMonSolarisState, getminor(Dev));
552 if (!pState)
553 {
554 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: no state data for %d\n", getminor(Dev)));
555 return EINVAL;
556 }
557
558 /*
559 * Read the request wrapper. Though We don't really need wrapper struct. now
560 * it's room for the future as Solaris isn't generous regarding the size.
561 */
562 VBOXUSBREQ ReqWrap;
563 if (IOCPARM_LEN(Cmd) != sizeof(ReqWrap))
564 {
565 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: bad request %#x size=%d expected=%d\n", Cmd, IOCPARM_LEN(Cmd), sizeof(ReqWrap)));
566 return ENOTTY;
567 }
568
569 int rc = ddi_copyin((void *)pArg, &ReqWrap, sizeof(ReqWrap), Mode);
570 if (RT_UNLIKELY(rc))
571 {
572 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: ddi_copyin failed to read header pArg=%p Cmd=%d. rc=%d.\n", pArg, Cmd, rc));
573 return EINVAL;
574 }
575
576 if (ReqWrap.u32Magic != VBOXUSBMON_MAGIC)
577 {
578 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: bad magic %#x; pArg=%p Cmd=%d.\n", ReqWrap.u32Magic, pArg, Cmd));
579 return EINVAL;
580 }
581 if (RT_UNLIKELY( ReqWrap.cbData == 0
582 || ReqWrap.cbData > _1M*16))
583 {
584 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: bad size %#x; pArg=%p Cmd=%d.\n", ReqWrap.cbData, pArg, Cmd));
585 return EINVAL;
586 }
587
588 /*
589 * Read the request.
590 */
591 void *pvBuf = RTMemTmpAlloc(ReqWrap.cbData);
592 if (RT_UNLIKELY(!pvBuf))
593 {
594 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: RTMemTmpAlloc failed to alloc %d bytes.\n", ReqWrap.cbData));
595 return ENOMEM;
596 }
597
598 rc = ddi_copyin((void *)(uintptr_t)ReqWrap.pvDataR3, pvBuf, ReqWrap.cbData, Mode);
599 if (RT_UNLIKELY(rc))
600 {
601 RTMemTmpFree(pvBuf);
602 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: ddi_copyin failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc));
603 return EFAULT;
604 }
605 if (RT_UNLIKELY( ReqWrap.cbData != 0
606 && !VALID_PTR(pvBuf)))
607 {
608 RTMemTmpFree(pvBuf);
609 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: pvBuf invalid pointer %p\n", pvBuf));
610 return EINVAL;
611 }
612 Log((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: pid=%d.\n", (int)RTProcSelf()));
613
614 /*
615 * Process the IOCtl.
616 */
617 size_t cbDataReturned = 0;
618 rc = vboxUSBMonSolarisProcessIOCtl(Cmd, pState, pvBuf, ReqWrap.cbData, &cbDataReturned);
619 ReqWrap.rc = rc;
620 rc = 0;
621
622 if (RT_UNLIKELY(cbDataReturned > ReqWrap.cbData))
623 {
624 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: too much output data %d expected %d\n", cbDataReturned, ReqWrap.cbData));
625 cbDataReturned = ReqWrap.cbData;
626 }
627
628 ReqWrap.cbData = cbDataReturned;
629
630 /*
631 * Copy the request back to user space.
632 */
633 rc = ddi_copyout(&ReqWrap, (void *)pArg, sizeof(ReqWrap), Mode);
634 if (RT_LIKELY(!rc))
635 {
636 /*
637 * Copy the payload (if any) back to user space.
638 */
639 if (cbDataReturned > 0)
640 {
641 rc = ddi_copyout(pvBuf, (void *)(uintptr_t)ReqWrap.pvDataR3, cbDataReturned, Mode);
642 if (RT_UNLIKELY(rc))
643 {
644 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: ddi_copyout failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc));
645 rc = EFAULT;
646 }
647 }
648 }
649 else
650 {
651 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: ddi_copyout(1) failed pArg=%p Cmd=%d\n", pArg, Cmd));
652 rc = EFAULT;
653 }
654
655 *pVal = rc;
656 RTMemTmpFree(pvBuf);
657 return rc;
658}
659
660
661/**
662 * IOCtl processor for user to kernel and kernel to kernel communication.
663 *
664 * @returns VBox status code.
665 *
666 * @param iFunction The requested function.
667 * @param pvState Opaque pointer to driver state used for getting ring-3 process (Id).
668 * @param pvData The input/output data buffer. Can be NULL depending on the function.
669 * @param cbData The max size of the data buffer.
670 * @param pcbDataReturned Where to store the amount of returned data. Can be NULL.
671 */
672static int vboxUSBMonSolarisProcessIOCtl(int iFunction, void *pvState, void *pvData, size_t cbData, size_t *pcbReturnedData)
673{
674 LogFunc((DEVICE_NAME ":solarisUSBProcessIOCtl iFunction=%d pvBuf=%p cbBuf=%zu\n", iFunction, pvData, cbData));
675
676 AssertPtrReturn(pvState, VERR_INVALID_POINTER);
677 vboxusbmon_state_t *pState = (vboxusbmon_state_t *)pvState;
678 int rc;
679
680#define CHECKRET_MIN_SIZE(mnemonic, cbMin) \
681 do { \
682 if (cbData < (cbMin)) \
683 { \
684 LogRel(("vboxUSBSolarisProcessIOCtl: " mnemonic ": cbData=%#zx (%zu) min is %#zx (%zu)\n", \
685 cbData, cbData, (size_t)(cbMin), (size_t)(cbMin))); \
686 return VERR_BUFFER_OVERFLOW; \
687 } \
688 if ((cbMin) != 0 && !VALID_PTR(pvData)) \
689 { \
690 LogRel(("vboxUSBSolarisProcessIOCtl: " mnemonic ": Invalid pointer %p\n", pvData)); \
691 return VERR_INVALID_POINTER; \
692 } \
693 } while (0)
694
695 switch (iFunction)
696 {
697 case VBOXUSBMON_IOCTL_ADD_FILTER:
698 {
699 CHECKRET_MIN_SIZE("ADD_FILTER", sizeof(VBOXUSBREQ_ADD_FILTER));
700
701 VBOXUSBREQ_ADD_FILTER *pReq = (VBOXUSBREQ_ADD_FILTER *)pvData;
702 PUSBFILTER pFilter = (PUSBFILTER)&pReq->Filter;
703
704 Log(("vboxUSBMonSolarisProcessIOCtl: idVendor=%#x idProduct=%#x bcdDevice=%#x bDeviceClass=%#x bDeviceSubClass=%#x bDeviceProtocol=%#x bBus=%#x bPort=%#x\n",
705 USBFilterGetNum(pFilter, USBFILTERIDX_VENDOR_ID),
706 USBFilterGetNum(pFilter, USBFILTERIDX_PRODUCT_ID),
707 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_REV),
708 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_CLASS),
709 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_SUB_CLASS),
710 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_PROTOCOL),
711 USBFilterGetNum(pFilter, USBFILTERIDX_BUS),
712 USBFilterGetNum(pFilter, USBFILTERIDX_PORT)));
713 Log(("vboxUSBMonSolarisProcessIOCtl: Manufacturer=%s Product=%s Serial=%s\n",
714 USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
715 USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) : "<null>",
716 USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
717
718 rc = USBFilterSetMustBePresent(pFilter, USBFILTERIDX_BUS, false /* fMustBePresent */); AssertRC(rc);
719
720 rc = VBoxUSBFilterAdd(pFilter, pState->Process, &pReq->uId);
721 *pcbReturnedData = cbData;
722 Log((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: ADD_FILTER (Process:%d) returned %d\n", pState->Process, rc));
723 break;
724 }
725
726 case VBOXUSBMON_IOCTL_REMOVE_FILTER:
727 {
728 CHECKRET_MIN_SIZE("REMOVE_FILTER", sizeof(VBOXUSBREQ_REMOVE_FILTER));
729
730 VBOXUSBREQ_REMOVE_FILTER *pReq = (VBOXUSBREQ_REMOVE_FILTER *)pvData;
731 rc = VBoxUSBFilterRemove(pState->Process, (uintptr_t)pReq->uId);
732 *pcbReturnedData = 0;
733 Log((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: REMOVE_FILTER (Process:%d) returned %d\n", pState->Process, rc));
734 break;
735 }
736
737 case VBOXUSBMON_IOCTL_RESET_DEVICE:
738 {
739 CHECKRET_MIN_SIZE("RESET_DEVICE", sizeof(VBOXUSBREQ_RESET_DEVICE));
740
741 VBOXUSBREQ_RESET_DEVICE *pReq = (VBOXUSBREQ_RESET_DEVICE *)pvData;
742 rc = vboxUSBMonSolarisResetDevice(pReq->szDevicePath, pReq->fReattach);
743 *pcbReturnedData = 0;
744 Log((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: RESET_DEVICE (Process:%d) returned %d\n", pState->Process, rc));
745 break;
746 }
747
748 case VBOXUSBMON_IOCTL_CLIENT_INFO:
749 {
750 CHECKRET_MIN_SIZE("CLIENT_INFO", sizeof(VBOXUSBREQ_CLIENT_INFO));
751
752 VBOXUSBREQ_CLIENT_INFO *pReq = (VBOXUSBREQ_CLIENT_INFO *)pvData;
753 rc = vboxUSBMonSolarisClientInfo(pState, pReq);
754 *pcbReturnedData = cbData;
755 Log((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: CLIENT_INFO (Process:%d) returned %d\n", pState->Process, rc));
756 break;
757 }
758
759 case VBOXUSBMON_IOCTL_GET_VERSION:
760 {
761 CHECKRET_MIN_SIZE("GET_VERSION", sizeof(VBOXUSBREQ_GET_VERSION));
762
763 PVBOXUSBREQ_GET_VERSION pGetVersionReq = (PVBOXUSBREQ_GET_VERSION)pvData;
764 pGetVersionReq->u32Major = VBOXUSBMON_VERSION_MAJOR;
765 pGetVersionReq->u32Minor = VBOXUSBMON_VERSION_MINOR;
766 *pcbReturnedData = sizeof(VBOXUSBREQ_GET_VERSION);
767 rc = VINF_SUCCESS;
768 Log((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: GET_VERSION returned %d\n", rc));
769 break;
770 }
771
772 default:
773 {
774 LogRel((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: Unknown request (Process:%d) %#x\n", pState->Process, iFunction));
775 *pcbReturnedData = 0;
776 rc = VERR_NOT_SUPPORTED;
777 break;
778 }
779 }
780 return rc;
781}
782
783
784static int vboxUSBMonSolarisResetDevice(char *pszDevicePath, bool fReattach)
785{
786 int rc = VERR_GENERAL_FAILURE;
787
788 LogFunc((DEVICE_NAME ":vboxUSBMonSolarisResetDevice pszDevicePath=%s fReattach=%d\n", pszDevicePath, fReattach));
789
790 /*
791 * Try grabbing the dev_info_t.
792 */
793 dev_info_t *pDeviceInfo = e_ddi_hold_devi_by_path(pszDevicePath, 0);
794 if (pDeviceInfo)
795 {
796 ddi_release_devi(pDeviceInfo);
797
798 /*
799 * Grab the root device node from the parent hub for resetting.
800 */
801 dev_info_t *pTmpDeviceInfo = NULL;
802 for (;;)
803 {
804 pTmpDeviceInfo = ddi_get_parent(pDeviceInfo);
805 if (!pTmpDeviceInfo)
806 {
807 LogRel((DEVICE_NAME ":vboxUSBMonSolarisResetDevice failed to get parent device info for %s\n", pszDevicePath));
808 return VERR_GENERAL_FAILURE;
809 }
810
811 if (ddi_prop_exists(DDI_DEV_T_ANY, pTmpDeviceInfo, DDI_PROP_DONTPASS, "usb-port-count")) /* parent hub */
812 break;
813
814 pDeviceInfo = pTmpDeviceInfo;
815 }
816
817 /*
818 * Try re-enumerating the device.
819 */
820 rc = usb_reset_device(pDeviceInfo, fReattach ? USB_RESET_LVL_REATTACH : USB_RESET_LVL_DEFAULT);
821 Log((DEVICE_NAME ":usb_reset_device for %s level=%s returned %d\n", pszDevicePath, fReattach ? "ReAttach" : "Default", rc));
822 switch (rc)
823 {
824 case USB_SUCCESS: rc = VINF_SUCCESS; break;
825 case USB_INVALID_PERM: rc = VERR_PERMISSION_DENIED; break;
826 case USB_INVALID_ARGS: rc = VERR_INVALID_PARAMETER; break;
827 case USB_BUSY: rc = VERR_RESOURCE_BUSY; break;
828 case USB_INVALID_CONTEXT: rc = VERR_INVALID_CONTEXT; break;
829 case USB_FAILURE: rc = VERR_GENERAL_FAILURE; break;
830
831 default: rc = VERR_UNRESOLVED_ERROR; break;
832 }
833 }
834 else
835 {
836 rc = VERR_INVALID_HANDLE;
837 LogRel((DEVICE_NAME ":vboxUSBMonSolarisResetDevice Cannot obtain device info for %s\n", pszDevicePath));
838 }
839
840 return rc;
841}
842
843
844/**
845 * Query client driver information. This also has a side-effect that it informs
846 * the client driver which upcoming VM process should be allowed to open it.
847 *
848 * @returns VBox status code.
849 * @param pState Pointer to the device state.
850 * @param pClientInfo Pointer to the client info. object.
851 */
852static int vboxUSBMonSolarisClientInfo(vboxusbmon_state_t *pState, PVBOXUSB_CLIENT_INFO pClientInfo)
853{
854 LogFunc((DEVICE_NAME ":vboxUSBMonSolarisClientInfo pState=%p pClientInfo=%p\n", pState, pClientInfo));
855
856 AssertPtrReturn(pState, VERR_INVALID_POINTER);
857 AssertPtrReturn(pClientInfo, VERR_INVALID_POINTER);
858
859 mutex_enter(&g_VBoxUSBMonSolarisMtx);
860 vboxusbmon_client_t *pCur = g_pVBoxUSBMonSolarisClients;
861 vboxusbmon_client_t *pPrev = NULL;
862 while (pCur)
863 {
864 if (strncmp(pClientInfo->szDeviceIdent, pCur->Info.szDeviceIdent, sizeof(pCur->Info.szDeviceIdent) - 1) == 0)
865 {
866 pClientInfo->Instance = pCur->Info.Instance;
867 RTStrPrintf(pClientInfo->szClientPath, sizeof(pClientInfo->szClientPath), "%s", pCur->Info.szClientPath);
868
869 /*
870 * Inform the client driver that this is the client process that is going to open it. We can predict the future!
871 */
872 int rc;
873 if (pCur->Info.pfnSetConsumerCredentials)
874 {
875 rc = pCur->Info.pfnSetConsumerCredentials(pState->Process, pCur->Info.Instance, NULL /* pvReserved */);
876 if (RT_FAILURE(rc))
877 LogRel((DEVICE_NAME ":vboxUSBMonSolarisClientInfo pfnSetConsumerCredentials failed. rc=%d\n", rc));
878 }
879 else
880 rc = VERR_INVALID_FUNCTION;
881
882 mutex_exit(&g_VBoxUSBMonSolarisMtx);
883
884 Log((DEVICE_NAME ":vboxUSBMonSolarisClientInfo found. %s rc=%d\n", pClientInfo->szDeviceIdent, rc));
885 return rc;
886 }
887 pPrev = pCur;
888 pCur = pCur->pNext;
889 }
890
891 mutex_exit(&g_VBoxUSBMonSolarisMtx);
892
893 LogRel((DEVICE_NAME ":vboxUSBMonSolarisClientInfo Failed to find client %s\n", pClientInfo->szDeviceIdent));
894 return VERR_NOT_FOUND;
895}
896
897
898/**
899 * Registers client driver.
900 *
901 * @returns VBox status code.
902 * @param pszDevicePath The device path of the client driver.
903 * @param Instance The client driver instance.
904 */
905int VBoxUSBMonSolarisRegisterClient(dev_info_t *pClientDip, PVBOXUSB_CLIENT_INFO pClientInfo)
906{
907 LogFunc((DEVICE_NAME ":VBoxUSBMonSolarisRegisterClient pClientDip=%p pClientInfo=%p\n", pClientDip, pClientInfo));
908 AssertPtrReturn(pClientInfo, VERR_INVALID_PARAMETER);
909
910 if (RT_LIKELY(g_pDip))
911 {
912 vboxusbmon_client_t *pClient = RTMemAllocZ(sizeof(vboxusbmon_client_t));
913 if (RT_LIKELY(pClient))
914 {
915 pClient->Info.Instance = pClientInfo->Instance;
916 strncpy(pClient->Info.szClientPath, pClientInfo->szClientPath, sizeof(pClient->Info.szClientPath));
917 strncpy(pClient->Info.szDeviceIdent, pClientInfo->szDeviceIdent, sizeof(pClient->Info.szDeviceIdent));
918 pClient->Info.pfnSetConsumerCredentials = pClientInfo->pfnSetConsumerCredentials;
919 pClient->pDip = pClientDip;
920
921 mutex_enter(&g_VBoxUSBMonSolarisMtx);
922 pClient->pNext = g_pVBoxUSBMonSolarisClients;
923 g_pVBoxUSBMonSolarisClients = pClient;
924 mutex_exit(&g_VBoxUSBMonSolarisMtx);
925
926 Log((DEVICE_NAME ":VBoxUSBMonSolarisRegisterClient registered. %d %s %s\n",
927 pClient->Info.Instance, pClient->Info.szClientPath, pClient->Info.szDeviceIdent));
928
929 return VINF_SUCCESS;
930 }
931 else
932 return VERR_NO_MEMORY;
933 }
934 else
935 return VERR_INVALID_STATE;
936}
937
938
939/**
940 * Deregisters client driver.
941 *
942 * @returns VBox status code.
943 * @param pszDevicePath The device path of the client driver.
944 * @param Instance The client driver instance.
945 */
946int VBoxUSBMonSolarisUnregisterClient(dev_info_t *pClientDip)
947{
948 LogFunc((DEVICE_NAME ":VBoxUSBMonSolarisUnregisterClient pClientDip=%p\n", pClientDip));
949 AssertReturn(pClientDip, VERR_INVALID_PARAMETER);
950
951 if (RT_LIKELY(g_pDip))
952 {
953 mutex_enter(&g_VBoxUSBMonSolarisMtx);
954
955 vboxusbmon_client_t *pCur = g_pVBoxUSBMonSolarisClients;
956 vboxusbmon_client_t *pPrev = NULL;
957 while (pCur)
958 {
959 if (pCur->pDip == pClientDip)
960 {
961 if (pPrev)
962 pPrev->pNext = pCur->pNext;
963 else
964 g_pVBoxUSBMonSolarisClients = pCur->pNext;
965
966 mutex_exit(&g_VBoxUSBMonSolarisMtx);
967
968 Log((DEVICE_NAME ":VBoxUSBMonSolarisUnregisterClient unregistered. %d %s %s\n",
969 pCur->Info.Instance, pCur->Info.szClientPath, pCur->Info.szDeviceIdent));
970 RTMemFree(pCur);
971 pCur = NULL;
972 return VINF_SUCCESS;
973 }
974 pPrev = pCur;
975 pCur = pCur->pNext;
976 }
977
978 mutex_exit(&g_VBoxUSBMonSolarisMtx);
979
980 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisUnregisterClient Failed to find registered client %p\n", pClientDip));
981 return VERR_NOT_FOUND;
982 }
983 else
984 return VERR_INVALID_STATE;
985}
986
987
988/**
989 * USBA driver election callback.
990 *
991 * @returns USB_SUCCESS if we want to capture the device, USB_FAILURE otherwise.
992 * @param pDevDesc The parsed device descriptor (does not include subconfigs).
993 * @param pDevStrings Device strings: Manufacturer, Product, Serial Number.
994 * @param pszDevicePath The physical path of the device being attached.
995 * @param Bus The Bus number on which the device is on.
996 * @param Port The Port number on the bus.
997 * @param ppszDrv The name of the driver we wish to capture the device with.
998 * @param pvReserved Reserved for future use.
999 */
1000int VBoxUSBMonSolarisElectDriver(usb_dev_descr_t *pDevDesc, usb_dev_str_t *pDevStrings, char *pszDevicePath, int Bus, int Port,
1001 char **ppszDrv, void *pvReserved)
1002{
1003 LogFunc((DEVICE_NAME ":VBoxUSBMonSolarisElectDriver pDevDesc=%p pDevStrings=%p pszDevicePath=%s Bus=%d Port=%d\n", pDevDesc,
1004 pDevStrings, pszDevicePath, Bus, Port));
1005
1006 AssertPtrReturn(pDevDesc, USB_FAILURE);
1007 AssertPtrReturn(pDevStrings, USB_FAILURE);
1008
1009 /*
1010 * Create a filter from the device being attached.
1011 */
1012 USBFILTER Filter;
1013 USBFilterInit(&Filter, USBFILTERTYPE_CAPTURE);
1014 USBFilterSetNumExact(&Filter, USBFILTERIDX_VENDOR_ID, pDevDesc->idVendor, true);
1015 USBFilterSetNumExact(&Filter, USBFILTERIDX_PRODUCT_ID, pDevDesc->idProduct, true);
1016 USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_REV, pDevDesc->bcdDevice, true);
1017 USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_CLASS, pDevDesc->bDeviceClass, true);
1018 USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_SUB_CLASS, pDevDesc->bDeviceSubClass, true);
1019 USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_PROTOCOL, pDevDesc->bDeviceProtocol, true);
1020 USBFilterSetNumExact(&Filter, USBFILTERIDX_BUS, 0x0 /* Bus */, true); /* Use 0x0 as userland initFilterFromDevice function in Main: see comment on "SetMustBePresent" below */
1021 USBFilterSetNumExact(&Filter, USBFILTERIDX_PORT, Port, true);
1022 USBFilterSetStringExact(&Filter, USBFILTERIDX_MANUFACTURER_STR, pDevStrings->usb_mfg ? pDevStrings->usb_mfg : "", true);
1023 USBFilterSetStringExact(&Filter, USBFILTERIDX_PRODUCT_STR, pDevStrings->usb_product ? pDevStrings->usb_product : "", true);
1024 USBFilterSetStringExact(&Filter, USBFILTERIDX_SERIAL_NUMBER_STR, pDevStrings->usb_serialno ? pDevStrings->usb_serialno : "", true);
1025
1026 /* This doesn't work like it should (USBFilterMatch fails on matching field (6) i.e. Bus despite this. Investigate later. */
1027 USBFilterSetMustBePresent(&Filter, USBFILTERIDX_BUS, false /* fMustBePresent */);
1028
1029 Log((DEVICE_NAME ":VBoxUSBMonSolarisElectDriver: idVendor=%#x idProduct=%#x bcdDevice=%#x bDeviceClass=%#x bDeviceSubClass=%#x bDeviceProtocol=%#x bBus=%#x bPort=%#x\n",
1030 USBFilterGetNum(&Filter, USBFILTERIDX_VENDOR_ID),
1031 USBFilterGetNum(&Filter, USBFILTERIDX_PRODUCT_ID),
1032 USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_REV),
1033 USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_CLASS),
1034 USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_SUB_CLASS),
1035 USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_PROTOCOL),
1036 USBFilterGetNum(&Filter, USBFILTERIDX_BUS),
1037 USBFilterGetNum(&Filter, USBFILTERIDX_PORT)));
1038 Log((DEVICE_NAME ":VBoxUSBMonSolarisElectDriver: Manufacturer=%s Product=%s Serial=%s\n",
1039 USBFilterGetString(&Filter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(&Filter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
1040 USBFilterGetString(&Filter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(&Filter, USBFILTERIDX_PRODUCT_STR) : "<null>",
1041 USBFilterGetString(&Filter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(&Filter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
1042
1043 /*
1044 * Run through user filters and try to see if it has a match.
1045 */
1046 uintptr_t uId = 0;
1047 RTPROCESS Owner = VBoxUSBFilterMatch(&Filter, &uId);
1048 USBFilterDelete(&Filter);
1049 if (Owner == NIL_RTPROCESS)
1050 {
1051 Log((DEVICE_NAME ":No matching filters, device %#x:%#x uninteresting.\n", pDevDesc->idVendor, pDevDesc->idProduct));
1052 return USB_FAILURE;
1053 }
1054
1055 *ppszDrv = ddi_strdup(VBOXUSB_DRIVER_NAME, KM_SLEEP);
1056 LogRel((DEVICE_NAME ": Capturing %s %#x:%#x:%s\n", pDevStrings->usb_product ? pDevStrings->usb_product : "<Unnamed USB device>",
1057 pDevDesc->idVendor, pDevDesc->idProduct, pszDevicePath));
1058 return USB_SUCCESS;
1059}
1060
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette