VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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