VirtualBox

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

Last change on this file since 41700 was 41700, checked in by vboxsync, 13 years ago

Solaris: license header update for kernel bits.

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