VirtualBox

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

Last change on this file since 79812 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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