VirtualBox

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

Last change on this file since 68033 was 62490, checked in by vboxsync, 8 years ago

(C) 2016

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