VirtualBox

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

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

HostDrivers: Doxygen fixes

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

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