VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 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.6 KB
Line 
1/* $Id: VBoxUSBMon-solaris.c 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VirtualBox USB Monitor Driver, Solaris Hosts.
4 */
5
6/*
7 * Copyright (C) 2008-2022 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 rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, 0 /* instance */, DDI_PSEUDO, 0 /* flags */,
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 {
404 *ppvResult = (void *)g_pDip;
405 if (!*ppvResult)
406 rc = DDI_FAILURE;
407 break;
408 }
409
410 case DDI_INFO_DEVT2INSTANCE:
411 {
412 /* There can only be a single-instance of this driver and thus its instance number is 0. */
413 *ppvResult = (void *)0;
414 break;
415 }
416
417 default:
418 rc = DDI_FAILURE;
419 break;
420 }
421 return rc;
422}
423
424
425static int VBoxUSBMonSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
426{
427 vboxusbmon_state_t *pState = NULL;
428 unsigned iOpenInstance;
429
430 LogFunc((DEVICE_NAME ": VBoxUSBMonSolarisOpen\n"));
431
432 /*
433 * Verify we are being opened as a character device.
434 */
435 if (fType != OTYP_CHR)
436 return EINVAL;
437
438 /*
439 * Verify that we're called after attach.
440 */
441 if (!g_pDip)
442 {
443 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisOpen: Invalid state for opening\n"));
444 return ENXIO;
445 }
446
447 for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++)
448 {
449 if ( !ddi_get_soft_state(g_pVBoxUSBMonSolarisState, iOpenInstance) /* faster */
450 && ddi_soft_state_zalloc(g_pVBoxUSBMonSolarisState, iOpenInstance) == DDI_SUCCESS)
451 {
452 pState = ddi_get_soft_state(g_pVBoxUSBMonSolarisState, iOpenInstance);
453 break;
454 }
455 }
456 if (!pState)
457 {
458 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisOpen: Too many open instances"));
459 return ENXIO;
460 }
461
462 pState->Process = RTProcSelf();
463 *pDev = makedevice(getmajor(*pDev), iOpenInstance);
464
465 NOREF(fFlag);
466 NOREF(pCred);
467
468 return 0;
469}
470
471
472static int VBoxUSBMonSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred)
473{
474 vboxusbmon_state_t *pState = NULL;
475 LogFunc((DEVICE_NAME ": VBoxUSBMonSolarisClose\n"));
476
477 pState = ddi_get_soft_state(g_pVBoxUSBMonSolarisState, getminor(Dev));
478 if (!pState)
479 {
480 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisClose: Failed to get state\n"));
481 return EFAULT;
482 }
483
484 /*
485 * Remove all filters for this client process.
486 */
487 VBoxUSBFilterRemoveOwner(pState->Process);
488
489 ddi_soft_state_free(g_pVBoxUSBMonSolarisState, getminor(Dev));
490 pState = NULL;
491
492 NOREF(fFlag);
493 NOREF(fType);
494 NOREF(pCred);
495
496 return 0;
497}
498
499
500static int VBoxUSBMonSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
501{
502 LogFunc((DEVICE_NAME ": VBoxUSBMonSolarisRead\n"));
503 return 0;
504}
505
506
507static int VBoxUSBMonSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
508{
509 LogFunc((DEVICE_NAME ": VBoxUSBMonSolarisWrite\n"));
510 return 0;
511}
512
513
514/** @def IOCPARM_LEN
515 * Gets the length from the ioctl number.
516 * This is normally defined by sys/ioccom.h on BSD systems...
517 */
518#ifndef IOCPARM_LEN
519# define IOCPARM_LEN(Code) (((Code) >> 16) & IOCPARM_MASK)
520#endif
521
522static int VBoxUSBMonSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal)
523{
524 LogFunc((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: Dev=%d Cmd=%d pArg=%p Mode=%d\n", Dev, Cmd, pArg));
525
526 /*
527 * Get the session from the soft state item.
528 */
529 vboxusbmon_state_t *pState = ddi_get_soft_state(g_pVBoxUSBMonSolarisState, getminor(Dev));
530 if (!pState)
531 {
532 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: No state data for minor instance %d\n", getminor(Dev)));
533 return EINVAL;
534 }
535
536 /*
537 * Read the request wrapper. Though We don't really need wrapper struct. now
538 * it's room for the future as Solaris isn't generous regarding the size.
539 */
540 VBOXUSBREQ ReqWrap;
541 if (IOCPARM_LEN(Cmd) != sizeof(ReqWrap))
542 {
543 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: bad request %#x size=%d expected=%d\n", Cmd, IOCPARM_LEN(Cmd),
544 sizeof(ReqWrap)));
545 return ENOTTY;
546 }
547
548 int rc = ddi_copyin((void *)pArg, &ReqWrap, sizeof(ReqWrap), Mode);
549 if (RT_UNLIKELY(rc))
550 {
551 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: ddi_copyin failed to read header pArg=%p Cmd=%d. rc=%d\n", pArg, Cmd, rc));
552 return EINVAL;
553 }
554
555 if (ReqWrap.u32Magic != VBOXUSBMON_MAGIC)
556 {
557 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: Bad magic %#x; pArg=%p Cmd=%d\n", ReqWrap.u32Magic, pArg, Cmd));
558 return EINVAL;
559 }
560 if (RT_UNLIKELY( ReqWrap.cbData == 0
561 || ReqWrap.cbData > _1M*16))
562 {
563 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: Bad size %#x; pArg=%p Cmd=%d\n", ReqWrap.cbData, pArg, Cmd));
564 return EINVAL;
565 }
566
567 /*
568 * Read the request.
569 */
570 void *pvBuf = RTMemTmpAlloc(ReqWrap.cbData);
571 if (RT_UNLIKELY(!pvBuf))
572 {
573 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: RTMemTmpAlloc failed to alloc %d bytes\n", ReqWrap.cbData));
574 return ENOMEM;
575 }
576
577 rc = ddi_copyin((void *)(uintptr_t)ReqWrap.pvDataR3, pvBuf, ReqWrap.cbData, Mode);
578 if (RT_UNLIKELY(rc))
579 {
580 RTMemTmpFree(pvBuf);
581 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: ddi_copyin failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd,
582 rc));
583 return EFAULT;
584 }
585 if (RT_UNLIKELY( ReqWrap.cbData != 0
586 && !RT_VALID_PTR(pvBuf)))
587 {
588 RTMemTmpFree(pvBuf);
589 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: pvBuf Invalid pointer %p\n", pvBuf));
590 return EINVAL;
591 }
592 Log((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: pid=%d\n", (int)RTProcSelf()));
593
594 /*
595 * Process the IOCtl.
596 */
597 size_t cbDataReturned = 0;
598 rc = vboxUSBMonSolarisProcessIOCtl(Cmd, pState, pvBuf, ReqWrap.cbData, &cbDataReturned);
599 ReqWrap.rc = rc;
600 rc = 0;
601
602 if (RT_UNLIKELY(cbDataReturned > ReqWrap.cbData))
603 {
604 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: Too much output data %d expected %d\n", cbDataReturned, ReqWrap.cbData));
605 cbDataReturned = ReqWrap.cbData;
606 }
607
608 ReqWrap.cbData = cbDataReturned;
609
610 /*
611 * Copy the request back to user space.
612 */
613 rc = ddi_copyout(&ReqWrap, (void *)pArg, sizeof(ReqWrap), Mode);
614 if (RT_LIKELY(!rc))
615 {
616 /*
617 * Copy the payload (if any) back to user space.
618 */
619 if (cbDataReturned > 0)
620 {
621 rc = ddi_copyout(pvBuf, (void *)(uintptr_t)ReqWrap.pvDataR3, cbDataReturned, Mode);
622 if (RT_UNLIKELY(rc))
623 {
624 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: ddi_copyout failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf,
625 pArg, Cmd, rc));
626 rc = EFAULT;
627 }
628 }
629 }
630 else
631 {
632 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: ddi_copyout(1) failed pArg=%p Cmd=%d\n", pArg, Cmd));
633 rc = EFAULT;
634 }
635
636 *pVal = rc;
637 RTMemTmpFree(pvBuf);
638 return rc;
639}
640
641
642/**
643 * IOCtl processor for user to kernel and kernel to kernel communication.
644 *
645 * @returns VBox status code.
646 *
647 * @param iFunction The requested function.
648 * @param pvState Opaque pointer to driver state used for getting
649 * ring-3 process (Id).
650 * @param pvData The input/output data buffer. Can be NULL
651 * depending on the function.
652 * @param cbData The max size of the data buffer.
653 * @param pcbReturnedData Where to store the amount of returned data. Can
654 * be NULL.
655 */
656static int vboxUSBMonSolarisProcessIOCtl(int iFunction, void *pvState, void *pvData, size_t cbData, size_t *pcbReturnedData)
657{
658 LogFunc((DEVICE_NAME ": vboxUSBMonSolarisProcessIOCtl: iFunction=%d pvBuf=%p cbBuf=%zu\n", iFunction, pvData, cbData));
659
660 AssertPtrReturn(pvState, VERR_INVALID_POINTER);
661 vboxusbmon_state_t *pState = (vboxusbmon_state_t *)pvState;
662 int rc;
663
664#define CHECKRET_MIN_SIZE(mnemonic, cbMin) \
665 do { \
666 if (RT_UNLIKELY(cbData < (cbMin))) \
667 { \
668 LogRel(("vboxUSBSolarisProcessIOCtl: " mnemonic ": cbData=%#zx (%zu) min is %#zx (%zu)\n", \
669 cbData, cbData, (size_t)(cbMin), (size_t)(cbMin))); \
670 return VERR_BUFFER_OVERFLOW; \
671 } \
672 if (RT_UNLIKELY((cbMin) != 0 && !RT_VALID_PTR(pvData))) \
673 { \
674 LogRel(("vboxUSBSolarisProcessIOCtl: " mnemonic ": Invalid pointer %p\n", pvData)); \
675 return VERR_INVALID_POINTER; \
676 } \
677 } while (0)
678
679 switch (iFunction)
680 {
681 case VBOXUSBMON_IOCTL_ADD_FILTER:
682 {
683 CHECKRET_MIN_SIZE("ADD_FILTER", sizeof(VBOXUSBREQ_ADD_FILTER));
684
685 VBOXUSBREQ_ADD_FILTER *pReq = (VBOXUSBREQ_ADD_FILTER *)pvData;
686 PUSBFILTER pFilter = (PUSBFILTER)&pReq->Filter;
687
688 Log(("vboxUSBMonSolarisProcessIOCtl: idVendor=%#x idProduct=%#x bcdDevice=%#x bDeviceClass=%#x "
689 "bDeviceSubClass=%#x bDeviceProtocol=%#x bBus=%#x bPort=%#x\n",
690 USBFilterGetNum(pFilter, USBFILTERIDX_VENDOR_ID),
691 USBFilterGetNum(pFilter, USBFILTERIDX_PRODUCT_ID),
692 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_REV),
693 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_CLASS),
694 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_SUB_CLASS),
695 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_PROTOCOL),
696 USBFilterGetNum(pFilter, USBFILTERIDX_BUS),
697 USBFilterGetNum(pFilter, USBFILTERIDX_PORT)));
698 Log(("vboxUSBMonSolarisProcessIOCtl: Manufacturer=%s Product=%s Serial=%s\n",
699 USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
700 USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) : "<null>",
701 USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
702
703 rc = USBFilterSetMustBePresent(pFilter, USBFILTERIDX_BUS, false /* fMustBePresent */); AssertRC(rc);
704
705 rc = VBoxUSBFilterAdd(pFilter, pState->Process, &pReq->uId);
706 *pcbReturnedData = cbData;
707 Log((DEVICE_NAME ": vboxUSBMonSolarisProcessIOCtl: ADD_FILTER (Process:%d) returned %d\n", pState->Process, rc));
708 break;
709 }
710
711 case VBOXUSBMON_IOCTL_REMOVE_FILTER:
712 {
713 CHECKRET_MIN_SIZE("REMOVE_FILTER", sizeof(VBOXUSBREQ_REMOVE_FILTER));
714
715 VBOXUSBREQ_REMOVE_FILTER *pReq = (VBOXUSBREQ_REMOVE_FILTER *)pvData;
716 rc = VBoxUSBFilterRemove(pState->Process, (uintptr_t)pReq->uId);
717 *pcbReturnedData = 0;
718 Log((DEVICE_NAME ": vboxUSBMonSolarisProcessIOCtl: REMOVE_FILTER (Process:%d) returned %d\n", pState->Process, rc));
719 break;
720 }
721
722 case VBOXUSBMON_IOCTL_RESET_DEVICE:
723 {
724 CHECKRET_MIN_SIZE("RESET_DEVICE", sizeof(VBOXUSBREQ_RESET_DEVICE));
725
726 VBOXUSBREQ_RESET_DEVICE *pReq = (VBOXUSBREQ_RESET_DEVICE *)pvData;
727 rc = vboxUSBMonSolarisResetDevice(pReq->szDevicePath, pReq->fReattach);
728 *pcbReturnedData = 0;
729 Log((DEVICE_NAME ": vboxUSBMonSolarisProcessIOCtl: RESET_DEVICE (Process:%d) returned %d\n", pState->Process, rc));
730 break;
731 }
732
733 case VBOXUSBMON_IOCTL_CLIENT_INFO:
734 {
735 CHECKRET_MIN_SIZE("CLIENT_INFO", sizeof(VBOXUSBREQ_CLIENT_INFO));
736
737 VBOXUSBREQ_CLIENT_INFO *pReq = (VBOXUSBREQ_CLIENT_INFO *)pvData;
738 rc = vboxUSBMonSolarisClientInfo(pState, pReq);
739 *pcbReturnedData = cbData;
740 Log((DEVICE_NAME ": vboxUSBMonSolarisProcessIOCtl: CLIENT_INFO (Process:%d) returned %d\n", pState->Process, rc));
741 break;
742 }
743
744 case VBOXUSBMON_IOCTL_GET_VERSION:
745 {
746 CHECKRET_MIN_SIZE("GET_VERSION", sizeof(VBOXUSBREQ_GET_VERSION));
747
748 PVBOXUSBREQ_GET_VERSION pGetVersionReq = (PVBOXUSBREQ_GET_VERSION)pvData;
749 pGetVersionReq->u32Major = VBOXUSBMON_VERSION_MAJOR;
750 pGetVersionReq->u32Minor = VBOXUSBMON_VERSION_MINOR;
751 *pcbReturnedData = sizeof(VBOXUSBREQ_GET_VERSION);
752 rc = VINF_SUCCESS;
753 Log((DEVICE_NAME ": vboxUSBMonSolarisProcessIOCtl: GET_VERSION returned %d\n", rc));
754 break;
755 }
756
757 default:
758 {
759 LogRel((DEVICE_NAME ": vboxUSBMonSolarisProcessIOCtl: Unknown request (Process:%d) %#x\n", pState->Process,
760 iFunction));
761 *pcbReturnedData = 0;
762 rc = VERR_NOT_SUPPORTED;
763 break;
764 }
765 }
766 return rc;
767}
768
769
770static int vboxUSBMonSolarisResetDevice(char *pszDevicePath, bool fReattach)
771{
772 int rc = VERR_GENERAL_FAILURE;
773
774 LogFunc((DEVICE_NAME ": vboxUSBMonSolarisResetDevice: pszDevicePath=%s fReattach=%d\n", pszDevicePath, fReattach));
775
776 /*
777 * Try grabbing the dev_info_t.
778 */
779 dev_info_t *pDeviceInfo = e_ddi_hold_devi_by_path(pszDevicePath, 0);
780 if (pDeviceInfo)
781 {
782 ddi_release_devi(pDeviceInfo);
783
784 /*
785 * Grab the root device node from the parent hub for resetting.
786 */
787 dev_info_t *pTmpDeviceInfo = NULL;
788 for (;;)
789 {
790 pTmpDeviceInfo = ddi_get_parent(pDeviceInfo);
791 if (!pTmpDeviceInfo)
792 {
793 LogRel((DEVICE_NAME ":vboxUSBMonSolarisResetDevice: Failed to get parent device info for %s\n", pszDevicePath));
794 return VERR_GENERAL_FAILURE;
795 }
796
797 if (ddi_prop_exists(DDI_DEV_T_ANY, pTmpDeviceInfo, DDI_PROP_DONTPASS, "usb-port-count")) /* parent hub */
798 break;
799
800 pDeviceInfo = pTmpDeviceInfo;
801 }
802
803 /*
804 * Try re-enumerating the device.
805 */
806 rc = usb_reset_device(pDeviceInfo, fReattach ? USB_RESET_LVL_REATTACH : USB_RESET_LVL_DEFAULT);
807 Log((DEVICE_NAME ": vboxUSBMonSolarisResetDevice: usb_reset_device for %s level=%s rc=%d\n", pszDevicePath,
808 fReattach ? "ReAttach" : "Default", rc));
809
810 switch (rc)
811 {
812 case USB_SUCCESS: rc = VINF_SUCCESS; break;
813 case USB_INVALID_PERM: rc = VERR_PERMISSION_DENIED; break;
814 case USB_INVALID_ARGS: rc = VERR_INVALID_PARAMETER; break;
815 case USB_BUSY: rc = VERR_RESOURCE_BUSY; break;
816 case USB_INVALID_CONTEXT: rc = VERR_INVALID_CONTEXT; break;
817 case USB_FAILURE: rc = VERR_GENERAL_FAILURE; break;
818
819 default: rc = VERR_UNRESOLVED_ERROR; break;
820 }
821 }
822 else
823 {
824 rc = VERR_INVALID_HANDLE;
825 LogRel((DEVICE_NAME ": vboxUSBMonSolarisResetDevice: Cannot obtain device info for %s\n", pszDevicePath));
826 }
827
828 return rc;
829}
830
831
832/**
833 * Query client driver information. This also has a side-effect that it informs
834 * the client driver which upcoming VM process should be allowed to open it.
835 *
836 * @returns VBox status code.
837 * @param pState Pointer to the device state.
838 * @param pClientInfo Pointer to the client info. object.
839 */
840static int vboxUSBMonSolarisClientInfo(vboxusbmon_state_t *pState, PVBOXUSB_CLIENT_INFO pClientInfo)
841{
842 LogFunc((DEVICE_NAME ": vboxUSBMonSolarisClientInfo: pState=%p pClientInfo=%p\n", pState, pClientInfo));
843
844 AssertPtrReturn(pState, VERR_INVALID_POINTER);
845 AssertPtrReturn(pClientInfo, VERR_INVALID_POINTER);
846
847 mutex_enter(&g_VBoxUSBMonSolarisMtx);
848 vboxusbmon_client_t *pCur = g_pVBoxUSBMonSolarisClients;
849 vboxusbmon_client_t *pPrev = NULL;
850 while (pCur)
851 {
852 if (strncmp(pClientInfo->szDeviceIdent, pCur->Info.szDeviceIdent, sizeof(pCur->Info.szDeviceIdent) - 1) == 0)
853 {
854 pClientInfo->Instance = pCur->Info.Instance;
855 RTStrPrintf(pClientInfo->szClientPath, sizeof(pClientInfo->szClientPath), "%s", pCur->Info.szClientPath);
856
857 /*
858 * Inform the client driver that this is the client process that is going to open it. We can predict the future!
859 */
860 int rc;
861 if (pCur->Info.pfnSetConsumerCredentials)
862 {
863 rc = pCur->Info.pfnSetConsumerCredentials(pState->Process, pCur->Info.Instance, NULL /* pvReserved */);
864 if (RT_FAILURE(rc))
865 LogRel((DEVICE_NAME ": vboxUSBMonSolarisClientInfo: pfnSetConsumerCredentials failed! rc=%d\n", rc));
866 }
867 else
868 rc = VERR_INVALID_FUNCTION;
869
870 mutex_exit(&g_VBoxUSBMonSolarisMtx);
871
872 Log((DEVICE_NAME ": vboxUSBMonSolarisClientInfo: Found %s, rc=%d\n", pClientInfo->szDeviceIdent, rc));
873 return rc;
874 }
875 pPrev = pCur;
876 pCur = pCur->pNext;
877 }
878
879 mutex_exit(&g_VBoxUSBMonSolarisMtx);
880
881 LogRel((DEVICE_NAME ": vboxUSBMonSolarisClientInfo: Failed to find client %s\n", pClientInfo->szDeviceIdent));
882 return VERR_NOT_FOUND;
883}
884
885
886/**
887 * Registers client driver.
888 *
889 * @returns VBox status code.
890 */
891int VBoxUSBMonSolarisRegisterClient(dev_info_t *pClientDip, PVBOXUSB_CLIENT_INFO pClientInfo)
892{
893 LogFunc((DEVICE_NAME ": VBoxUSBMonSolarisRegisterClient: pClientDip=%p pClientInfo=%p\n", pClientDip, pClientInfo));
894 AssertPtrReturn(pClientInfo, VERR_INVALID_PARAMETER);
895
896 if (RT_LIKELY(g_pDip))
897 {
898 vboxusbmon_client_t *pClient = RTMemAllocZ(sizeof(vboxusbmon_client_t));
899 if (RT_LIKELY(pClient))
900 {
901 pClient->Info.Instance = pClientInfo->Instance;
902 strncpy(pClient->Info.szClientPath, pClientInfo->szClientPath, sizeof(pClient->Info.szClientPath));
903 strncpy(pClient->Info.szDeviceIdent, pClientInfo->szDeviceIdent, sizeof(pClient->Info.szDeviceIdent));
904 pClient->Info.pfnSetConsumerCredentials = pClientInfo->pfnSetConsumerCredentials;
905 pClient->pDip = pClientDip;
906
907 mutex_enter(&g_VBoxUSBMonSolarisMtx);
908 pClient->pNext = g_pVBoxUSBMonSolarisClients;
909 g_pVBoxUSBMonSolarisClients = pClient;
910 mutex_exit(&g_VBoxUSBMonSolarisMtx);
911
912 Log((DEVICE_NAME ": Client registered (ClientPath=%s Ident=%s)\n", pClient->Info.szClientPath,
913 pClient->Info.szDeviceIdent));
914 return VINF_SUCCESS;
915 }
916 return VERR_NO_MEMORY;
917 }
918 return VERR_INVALID_STATE;
919}
920
921
922/**
923 * Deregisters client driver.
924 *
925 * @returns VBox status code.
926 */
927int VBoxUSBMonSolarisUnregisterClient(dev_info_t *pClientDip)
928{
929 LogFunc((DEVICE_NAME ": VBoxUSBMonSolarisUnregisterClient: pClientDip=%p\n", pClientDip));
930 AssertReturn(pClientDip, VERR_INVALID_PARAMETER);
931
932 if (RT_LIKELY(g_pDip))
933 {
934 mutex_enter(&g_VBoxUSBMonSolarisMtx);
935
936 vboxusbmon_client_t *pCur = g_pVBoxUSBMonSolarisClients;
937 vboxusbmon_client_t *pPrev = NULL;
938 while (pCur)
939 {
940 if (pCur->pDip == pClientDip)
941 {
942 if (pPrev)
943 pPrev->pNext = pCur->pNext;
944 else
945 g_pVBoxUSBMonSolarisClients = pCur->pNext;
946
947 mutex_exit(&g_VBoxUSBMonSolarisMtx);
948
949 Log((DEVICE_NAME ": Client unregistered (ClientPath=%s Ident=%s)\n", pCur->Info.szClientPath,
950 pCur->Info.szDeviceIdent));
951 RTMemFree(pCur);
952 return VINF_SUCCESS;
953 }
954 pPrev = pCur;
955 pCur = pCur->pNext;
956 }
957
958 mutex_exit(&g_VBoxUSBMonSolarisMtx);
959
960 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisUnregisterClient: Failed to find registered client %p\n", pClientDip));
961 return VERR_NOT_FOUND;
962 }
963 return VERR_INVALID_STATE;
964}
965
966
967/**
968 * USBA driver election callback.
969 *
970 * @returns USB_SUCCESS if we want to capture the device, USB_FAILURE otherwise.
971 * @param pDevDesc The parsed device descriptor (does not include subconfigs).
972 * @param pDevStrings Device strings: Manufacturer, Product, Serial Number.
973 * @param pszDevicePath The physical path of the device being attached.
974 * @param Bus The Bus number on which the device is on.
975 * @param Port The Port number on the bus.
976 * @param ppszDrv The name of the driver we wish to capture the device with.
977 * @param pvReserved Reserved for future use.
978 */
979int VBoxUSBMonSolarisElectDriver(usb_dev_descr_t *pDevDesc, usb_dev_str_t *pDevStrings, char *pszDevicePath, int Bus, int Port,
980 char **ppszDrv, void *pvReserved)
981{
982 LogFunc((DEVICE_NAME ": VBoxUSBMonSolarisElectDriver: pDevDesc=%p pDevStrings=%p pszDevicePath=%s Bus=%d Port=%d\n", pDevDesc,
983 pDevStrings, pszDevicePath, Bus, Port));
984
985 AssertPtrReturn(pDevDesc, USB_FAILURE);
986 AssertPtrReturn(pDevStrings, USB_FAILURE);
987
988 /*
989 * Create a filter from the device being attached.
990 */
991 USBFILTER Filter;
992 USBFilterInit(&Filter, USBFILTERTYPE_CAPTURE);
993 USBFilterSetNumExact(&Filter, USBFILTERIDX_VENDOR_ID, pDevDesc->idVendor, true);
994 USBFilterSetNumExact(&Filter, USBFILTERIDX_PRODUCT_ID, pDevDesc->idProduct, true);
995 USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_REV, pDevDesc->bcdDevice, true);
996 USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_CLASS, pDevDesc->bDeviceClass, true);
997 USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_SUB_CLASS, pDevDesc->bDeviceSubClass, true);
998 USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_PROTOCOL, pDevDesc->bDeviceProtocol, true);
999 USBFilterSetNumExact(&Filter, USBFILTERIDX_BUS, 0x0 /* Bus */, true); /* Use 0x0 as userland initFilterFromDevice function in Main: see comment on "SetMustBePresent" below */
1000 USBFilterSetNumExact(&Filter, USBFILTERIDX_PORT, Port, true);
1001 USBFilterSetStringExact(&Filter, USBFILTERIDX_MANUFACTURER_STR, pDevStrings->usb_mfg ? pDevStrings->usb_mfg : "",
1002 true /*fMustBePresent*/, true /*fPurge*/);
1003 USBFilterSetStringExact(&Filter, USBFILTERIDX_PRODUCT_STR, pDevStrings->usb_product ? pDevStrings->usb_product : "",
1004 true /*fMustBePresent*/, true /*fPurge*/);
1005 USBFilterSetStringExact(&Filter, USBFILTERIDX_SERIAL_NUMBER_STR, pDevStrings->usb_serialno ? pDevStrings->usb_serialno : "",
1006 true /*fMustBePresent*/, true /*fPurge*/);
1007
1008 /* This doesn't work like it should (USBFilterMatch fails on matching field (6) i.e. Bus despite this. Investigate later. */
1009 USBFilterSetMustBePresent(&Filter, USBFILTERIDX_BUS, false /* fMustBePresent */);
1010
1011 Log((DEVICE_NAME ": VBoxUSBMonSolarisElectDriver: idVendor=%#x idProduct=%#x bcdDevice=%#x bDeviceClass=%#x "
1012 "bDeviceSubClass=%#x bDeviceProtocol=%#x bBus=%#x bPort=%#x\n",
1013 USBFilterGetNum(&Filter, USBFILTERIDX_VENDOR_ID),
1014 USBFilterGetNum(&Filter, USBFILTERIDX_PRODUCT_ID),
1015 USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_REV),
1016 USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_CLASS),
1017 USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_SUB_CLASS),
1018 USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_PROTOCOL),
1019 USBFilterGetNum(&Filter, USBFILTERIDX_BUS),
1020 USBFilterGetNum(&Filter, USBFILTERIDX_PORT)));
1021 Log((DEVICE_NAME ": VBoxUSBMonSolarisElectDriver: Manufacturer=%s Product=%s Serial=%s\n",
1022 USBFilterGetString(&Filter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(&Filter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
1023 USBFilterGetString(&Filter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(&Filter, USBFILTERIDX_PRODUCT_STR) : "<null>",
1024 USBFilterGetString(&Filter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(&Filter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
1025
1026 /*
1027 * Run through user filters and try to see if it has a match.
1028 */
1029 uintptr_t uId = 0;
1030 RTPROCESS Owner = VBoxUSBFilterMatch(&Filter, &uId);
1031 USBFilterDelete(&Filter);
1032 if (Owner == NIL_RTPROCESS)
1033 {
1034 Log((DEVICE_NAME ": VBoxUSBMonSolarisElectDriver: No matching filters, device %#x:%#x uninteresting\n",
1035 pDevDesc->idVendor, pDevDesc->idProduct));
1036 return USB_FAILURE;
1037 }
1038
1039 *ppszDrv = ddi_strdup(VBOXUSB_DRIVER_NAME, KM_SLEEP);
1040#if 0
1041 LogRel((DEVICE_NAME ": Capturing %s %s %#x:%#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#else
1046 /* Until IPRT R0 logging is fixed. See @bugref{6657#c7} */
1047 cmn_err(CE_CONT, "Capturing %s %s 0x%x:0x%x:%s Bus=%d Port=%d\n",
1048 pDevStrings->usb_mfg ? pDevStrings->usb_mfg : "<Unknown Manufacturer>",
1049 pDevStrings->usb_product ? pDevStrings->usb_product : "<Unnamed USB device>",
1050 pDevDesc->idVendor, pDevDesc->idProduct, pszDevicePath, Bus, Port);
1051#endif
1052 return USB_SUCCESS;
1053}
1054
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