VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/darwin/iokit.cpp@ 58170

Last change on this file since 58170 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 70.7 KB
Line 
1/* $Id: iokit.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * Main - Darwin IOKit Routines.
4 *
5 * Because IOKit makes use of COM like interfaces, it does not mix very
6 * well with COM/XPCOM and must therefore be isolated from it using a
7 * simpler C interface.
8 */
9
10/*
11 * Copyright (C) 2006-2014 Oracle Corporation
12 *
13 * This file is part of VirtualBox Open Source Edition (OSE), as
14 * available from http://www.virtualbox.org. This file is free software;
15 * you can redistribute it and/or modify it under the terms of the GNU
16 * General Public License (GPL) as published by the Free Software
17 * Foundation, in version 2 as it comes in the "COPYING" file of the
18 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20 */
21
22
23/*********************************************************************************************************************************
24* Header Files *
25*********************************************************************************************************************************/
26#define LOG_GROUP LOG_GROUP_MAIN
27#ifdef STANDALONE_TESTCASE
28# define VBOX_WITH_USB
29#endif
30
31#include <mach/mach.h>
32#include <Carbon/Carbon.h>
33#include <IOKit/IOKitLib.h>
34#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
35#include <IOKit/scsi/SCSITaskLib.h>
36#include <SystemConfiguration/SystemConfiguration.h>
37#include <mach/mach_error.h>
38#ifdef VBOX_WITH_USB
39# include <IOKit/usb/IOUSBLib.h>
40# include <IOKit/IOCFPlugIn.h>
41# include <IOKit/storage/IOMedia.h>
42#endif
43
44#include <VBox/log.h>
45#include <VBox/err.h>
46#include <iprt/mem.h>
47#include <iprt/string.h>
48#include <iprt/process.h>
49#include <iprt/assert.h>
50#include <iprt/thread.h>
51#include <iprt/uuid.h>
52#ifdef STANDALONE_TESTCASE
53# include <iprt/initterm.h>
54# include <iprt/stream.h>
55#endif
56
57#include "iokit.h"
58
59/* A small hack... */
60#ifdef STANDALONE_TESTCASE
61# define DarwinFreeUSBDeviceFromIOKit(a) do { } while (0)
62#endif
63
64
65/*********************************************************************************************************************************
66* Defined Constants And Macros *
67*********************************************************************************************************************************/
68/** An attempt at catching reference leaks. */
69#define MY_CHECK_CREFS(cRefs) do { AssertMsg(cRefs < 25, ("%ld\n", cRefs)); NOREF(cRefs); } while (0)
70
71/** Contains the pid of the current client. If 0, the kernel is the current client. */
72#define VBOXUSB_CLIENT_KEY "VBoxUSB-Client"
73/** Contains the pid of the filter owner (i.e. the VBoxSVC pid). */
74#define VBOXUSB_OWNER_KEY "VBoxUSB-Owner"
75/** The VBoxUSBDevice class name. */
76#define VBOXUSBDEVICE_CLASS_NAME "org_virtualbox_VBoxUSBDevice"
77
78
79/*********************************************************************************************************************************
80* Global Variables *
81*********************************************************************************************************************************/
82/** The IO Master Port. */
83static mach_port_t g_MasterPort = NULL;
84
85
86/**
87 * Lazily opens the master port.
88 *
89 * @returns true if the port is open, false on failure (very unlikely).
90 */
91static bool darwinOpenMasterPort(void)
92{
93 if (!g_MasterPort)
94 {
95 kern_return_t krc = IOMasterPort(MACH_PORT_NULL, &g_MasterPort);
96 AssertReturn(krc == KERN_SUCCESS, false);
97 }
98 return true;
99}
100
101
102/**
103 * Checks whether the value exists.
104 *
105 * @returns true / false accordingly.
106 * @param DictRef The dictionary.
107 * @param KeyStrRef The key name.
108 */
109static bool darwinDictIsPresent(CFDictionaryRef DictRef, CFStringRef KeyStrRef)
110{
111 return !!CFDictionaryGetValue(DictRef, KeyStrRef);
112}
113
114
115/**
116 * Gets a boolean value.
117 *
118 * @returns Success indicator (true/false).
119 * @param DictRef The dictionary.
120 * @param KeyStrRef The key name.
121 * @param pf Where to store the key value.
122 */
123static bool darwinDictGetBool(CFDictionaryRef DictRef, CFStringRef KeyStrRef, bool *pf)
124{
125 CFTypeRef BoolRef = CFDictionaryGetValue(DictRef, KeyStrRef);
126 if ( BoolRef
127 && CFGetTypeID(BoolRef) == CFBooleanGetTypeID())
128 {
129 *pf = CFBooleanGetValue((CFBooleanRef)BoolRef);
130 return true;
131 }
132 *pf = false;
133 return false;
134}
135
136
137/**
138 * Gets an unsigned 8-bit integer value.
139 *
140 * @returns Success indicator (true/false).
141 * @param DictRef The dictionary.
142 * @param KeyStrRef The key name.
143 * @param pu8 Where to store the key value.
144 */
145static bool darwinDictGetU8(CFDictionaryRef DictRef, CFStringRef KeyStrRef, uint8_t *pu8)
146{
147 CFTypeRef ValRef = CFDictionaryGetValue(DictRef, KeyStrRef);
148 if (ValRef)
149 {
150 if (CFNumberGetValue((CFNumberRef)ValRef, kCFNumberSInt8Type, pu8))
151 return true;
152 }
153 *pu8 = 0;
154 return false;
155}
156
157
158/**
159 * Gets an unsigned 16-bit integer value.
160 *
161 * @returns Success indicator (true/false).
162 * @param DictRef The dictionary.
163 * @param KeyStrRef The key name.
164 * @param pu16 Where to store the key value.
165 */
166static bool darwinDictGetU16(CFDictionaryRef DictRef, CFStringRef KeyStrRef, uint16_t *pu16)
167{
168 CFTypeRef ValRef = CFDictionaryGetValue(DictRef, KeyStrRef);
169 if (ValRef)
170 {
171 if (CFNumberGetValue((CFNumberRef)ValRef, kCFNumberSInt16Type, pu16))
172 return true;
173 }
174 *pu16 = 0;
175 return false;
176}
177
178
179/**
180 * Gets an unsigned 32-bit integer value.
181 *
182 * @returns Success indicator (true/false).
183 * @param DictRef The dictionary.
184 * @param KeyStrRef The key name.
185 * @param pu32 Where to store the key value.
186 */
187static bool darwinDictGetU32(CFDictionaryRef DictRef, CFStringRef KeyStrRef, uint32_t *pu32)
188{
189 CFTypeRef ValRef = CFDictionaryGetValue(DictRef, KeyStrRef);
190 if (ValRef)
191 {
192 if (CFNumberGetValue((CFNumberRef)ValRef, kCFNumberSInt32Type, pu32))
193 return true;
194 }
195 *pu32 = 0;
196 return false;
197}
198
199
200/**
201 * Gets an unsigned 64-bit integer value.
202 *
203 * @returns Success indicator (true/false).
204 * @param DictRef The dictionary.
205 * @param KeyStrRef The key name.
206 * @param pu64 Where to store the key value.
207 */
208static bool darwinDictGetU64(CFDictionaryRef DictRef, CFStringRef KeyStrRef, uint64_t *pu64)
209{
210 CFTypeRef ValRef = CFDictionaryGetValue(DictRef, KeyStrRef);
211 if (ValRef)
212 {
213 if (CFNumberGetValue((CFNumberRef)ValRef, kCFNumberSInt64Type, pu64))
214 return true;
215 }
216 *pu64 = 0;
217 return false;
218}
219
220
221/**
222 * Gets a RTPROCESS value.
223 *
224 * @returns Success indicator (true/false).
225 * @param DictRef The dictionary.
226 * @param KeyStrRef The key name.
227 * @param pProcess Where to store the key value.
228 */
229static bool darwinDictGetProcess(CFMutableDictionaryRef DictRef, CFStringRef KeyStrRef, PRTPROCESS pProcess)
230{
231 switch (sizeof(*pProcess))
232 {
233 case sizeof(uint16_t): return darwinDictGetU16(DictRef, KeyStrRef, (uint16_t *)pProcess);
234 case sizeof(uint32_t): return darwinDictGetU32(DictRef, KeyStrRef, (uint32_t *)pProcess);
235 case sizeof(uint64_t): return darwinDictGetU64(DictRef, KeyStrRef, (uint64_t *)pProcess);
236 default:
237 AssertMsgFailedReturn(("%d\n", sizeof(*pProcess)), false);
238 }
239}
240
241
242/**
243 * Gets string value, converted to UTF-8 and put in user buffer.
244 *
245 * @returns Success indicator (true/false).
246 * @param DictRef The dictionary.
247 * @param KeyStrRef The key name.
248 * @param psz The string buffer. On failure this will be an empty string ("").
249 * @param cch The size of the buffer.
250 */
251static bool darwinDictGetString(CFDictionaryRef DictRef, CFStringRef KeyStrRef, char *psz, size_t cch)
252{
253 CFTypeRef ValRef = CFDictionaryGetValue(DictRef, KeyStrRef);
254 if (ValRef)
255 {
256 if (CFStringGetCString((CFStringRef)ValRef, psz, cch, kCFStringEncodingUTF8))
257 return true;
258 }
259 Assert(cch > 0);
260 *psz = '\0';
261 return false;
262}
263
264
265/**
266 * Gets string value, converted to UTF-8 and put in a IPRT string buffer.
267 *
268 * @returns Success indicator (true/false).
269 * @param DictRef The dictionary.
270 * @param KeyStrRef The key name.
271 * @param ppsz Where to store the key value. Free with RTStrFree. Set to NULL on failure.
272 */
273static bool darwinDictDupString(CFDictionaryRef DictRef, CFStringRef KeyStrRef, char **ppsz)
274{
275 char szBuf[512];
276 if (darwinDictGetString(DictRef, KeyStrRef, szBuf, sizeof(szBuf)))
277 {
278 *ppsz = RTStrDup(szBuf);
279 if (*ppsz)
280 return true;
281 }
282 *ppsz = NULL;
283 return false;
284}
285
286
287/**
288 * Gets a byte string (data) of a specific size.
289 *
290 * @returns Success indicator (true/false).
291 * @param DictRef The dictionary.
292 * @param KeyStrRef The key name.
293 * @param pvBuf The buffer to store the bytes in.
294 * @param cbBuf The size of the buffer. This must exactly match the data size.
295 */
296static bool darwinDictGetData(CFDictionaryRef DictRef, CFStringRef KeyStrRef, void *pvBuf, size_t cbBuf)
297{
298 CFTypeRef ValRef = CFDictionaryGetValue(DictRef, KeyStrRef);
299 if (ValRef)
300 {
301 CFIndex cbActual = CFDataGetLength((CFDataRef)ValRef);
302 if (cbActual >= 0 && cbBuf == (size_t)cbActual)
303 {
304 CFDataGetBytes((CFDataRef)ValRef, CFRangeMake(0, cbBuf), (uint8_t *)pvBuf);
305 return true;
306 }
307 }
308 memset(pvBuf, '\0', cbBuf);
309 return false;
310}
311
312
313#if 1 && !defined(STANDALONE_TESTCASE) /* dumping disabled */
314# define DARWIN_IOKIT_LOG(a) Log(a)
315# define DARWIN_IOKIT_LOG_FLUSH() do {} while (0)
316# define DARWIN_IOKIT_DUMP_OBJ(o) do {} while (0)
317#else
318# if defined(STANDALONE_TESTCASE)
319# include <iprt/stream.h>
320# define DARWIN_IOKIT_LOG(a) RTPrintf a
321# define DARWIN_IOKIT_LOG_FLUSH() RTStrmFlush(g_pStdOut)
322# else
323# define DARWIN_IOKIT_LOG(a) RTLogPrintf a
324# define DARWIN_IOKIT_LOG_FLUSH() RTLogFlush(NULL)
325# endif
326# define DARWIN_IOKIT_DUMP_OBJ(o) darwinDumpObj(o)
327
328/**
329 * Callback for dumping a dictionary key.
330 *
331 * @param pvKey The key name.
332 * @param pvValue The key value
333 * @param pvUser The recursion depth.
334 */
335static void darwinDumpDictCallback(const void *pvKey, const void *pvValue, void *pvUser)
336{
337 /* display the key name. */
338 char *pszKey = (char *)RTMemTmpAlloc(1024);
339 if (!CFStringGetCString((CFStringRef)pvKey, pszKey, 1024, kCFStringEncodingUTF8))
340 strcpy(pszKey, "CFStringGetCString failure");
341 DARWIN_IOKIT_LOG(("%+*s%s", (int)(uintptr_t)pvUser, "", pszKey));
342 RTMemTmpFree(pszKey);
343
344 /* display the value type */
345 CFTypeID Type = CFGetTypeID(pvValue);
346 DARWIN_IOKIT_LOG((" [%d-", Type));
347
348 /* display the value */
349 if (Type == CFDictionaryGetTypeID())
350 {
351 DARWIN_IOKIT_LOG(("dictionary] =\n"
352 "%-*s{\n", (int)(uintptr_t)pvUser, ""));
353 CFDictionaryApplyFunction((CFDictionaryRef)pvValue, darwinDumpDictCallback, (void *)((uintptr_t)pvUser + 4));
354 DARWIN_IOKIT_LOG(("%-*s}\n", (int)(uintptr_t)pvUser, ""));
355 }
356 else if (Type == CFBooleanGetTypeID())
357 DARWIN_IOKIT_LOG(("bool] = %s\n", CFBooleanGetValue((CFBooleanRef)pvValue) ? "true" : "false"));
358 else if (Type == CFNumberGetTypeID())
359 {
360 union
361 {
362 SInt8 s8;
363 SInt16 s16;
364 SInt32 s32;
365 SInt64 s64;
366 Float32 rf32;
367 Float64 rd64;
368 char ch;
369 short s;
370 int i;
371 long l;
372 long long ll;
373 float rf;
374 double rd;
375 CFIndex iCF;
376 } u;
377 RT_ZERO(u);
378 CFNumberType NumType = CFNumberGetType((CFNumberRef)pvValue);
379 if (CFNumberGetValue((CFNumberRef)pvValue, NumType, &u))
380 {
381 switch (CFNumberGetType((CFNumberRef)pvValue))
382 {
383 case kCFNumberSInt8Type: DARWIN_IOKIT_LOG(("SInt8] = %RI8 (%#RX8)\n", NumType, u.s8, u.s8)); break;
384 case kCFNumberSInt16Type: DARWIN_IOKIT_LOG(("SInt16] = %RI16 (%#RX16)\n", NumType, u.s16, u.s16)); break;
385 case kCFNumberSInt32Type: DARWIN_IOKIT_LOG(("SInt32] = %RI32 (%#RX32)\n", NumType, u.s32, u.s32)); break;
386 case kCFNumberSInt64Type: DARWIN_IOKIT_LOG(("SInt64] = %RI64 (%#RX64)\n", NumType, u.s64, u.s64)); break;
387 case kCFNumberFloat32Type: DARWIN_IOKIT_LOG(("float32] = %#lx\n", NumType, u.l)); break;
388 case kCFNumberFloat64Type: DARWIN_IOKIT_LOG(("float64] = %#llx\n", NumType, u.ll)); break;
389 case kCFNumberFloatType: DARWIN_IOKIT_LOG(("float] = %#lx\n", NumType, u.l)); break;
390 case kCFNumberDoubleType: DARWIN_IOKIT_LOG(("double] = %#llx\n", NumType, u.ll)); break;
391 case kCFNumberCharType: DARWIN_IOKIT_LOG(("char] = %hhd (%hhx)\n", NumType, u.ch, u.ch)); break;
392 case kCFNumberShortType: DARWIN_IOKIT_LOG(("short] = %hd (%hx)\n", NumType, u.s, u.s)); break;
393 case kCFNumberIntType: DARWIN_IOKIT_LOG(("int] = %d (%#x)\n", NumType, u.i, u.i)); break;
394 case kCFNumberLongType: DARWIN_IOKIT_LOG(("long] = %ld (%#lx)\n", NumType, u.l, u.l)); break;
395 case kCFNumberLongLongType: DARWIN_IOKIT_LOG(("long long] = %lld (%#llx)\n", NumType, u.ll, u.ll)); break;
396 case kCFNumberCFIndexType: DARWIN_IOKIT_LOG(("CFIndex] = %lld (%#llx)\n", NumType, (long long)u.iCF, (long long)u.iCF)); break;
397 break;
398 default: DARWIN_IOKIT_LOG(("%d?] = %lld (%llx)\n", NumType, u.ll, u.ll)); break;
399 }
400 }
401 else
402 DARWIN_IOKIT_LOG(("number] = CFNumberGetValue failed\n"));
403 }
404 else if (Type == CFBooleanGetTypeID())
405 DARWIN_IOKIT_LOG(("boolean] = %RTbool\n", CFBooleanGetValue((CFBooleanRef)pvValue)));
406 else if (Type == CFStringGetTypeID())
407 {
408 DARWIN_IOKIT_LOG(("string] = "));
409 char *pszValue = (char *)RTMemTmpAlloc(16*_1K);
410 if (!CFStringGetCString((CFStringRef)pvValue, pszValue, 16*_1K, kCFStringEncodingUTF8))
411 strcpy(pszValue, "CFStringGetCString failure");
412 DARWIN_IOKIT_LOG(("\"%s\"\n", pszValue));
413 RTMemTmpFree(pszValue);
414 }
415 else if (Type == CFDataGetTypeID())
416 {
417 CFIndex cb = CFDataGetLength((CFDataRef)pvValue);
418 DARWIN_IOKIT_LOG(("%zu bytes] =", (size_t)cb));
419 void *pvData = RTMemTmpAlloc(cb + 8);
420 CFDataGetBytes((CFDataRef)pvValue, CFRangeMake(0, cb), (uint8_t *)pvData);
421 if (!cb)
422 DARWIN_IOKIT_LOG((" \n"));
423 else if (cb <= 32)
424 DARWIN_IOKIT_LOG((" %.*Rhxs\n", cb, pvData));
425 else
426 DARWIN_IOKIT_LOG(("\n%.*Rhxd\n", cb, pvData));
427 RTMemTmpFree(pvData);
428 }
429 else
430 DARWIN_IOKIT_LOG(("??] = %p\n", pvValue));
431}
432
433
434/**
435 * Dumps a dictionary to the log.
436 *
437 * @param DictRef The dictionary to dump.
438 */
439static void darwinDumpDict(CFDictionaryRef DictRef, unsigned cIndents)
440{
441 CFDictionaryApplyFunction(DictRef, darwinDumpDictCallback, (void *)(uintptr_t)cIndents);
442 DARWIN_IOKIT_LOG_FLUSH();
443}
444
445
446/**
447 * Dumps an I/O kit registry object and all it children.
448 * @param Object The object to dump.
449 * @param cIndents The number of indents to use.
450 */
451static void darwinDumpObjInt(io_object_t Object, unsigned cIndents)
452{
453 static io_string_t s_szPath;
454 kern_return_t krc = IORegistryEntryGetPath(Object, kIOServicePlane, s_szPath);
455 if (krc != KERN_SUCCESS)
456 strcpy(s_szPath, "IORegistryEntryGetPath failed");
457 DARWIN_IOKIT_LOG(("Dumping %p - %s:\n", (const void *)Object, s_szPath));
458
459 CFMutableDictionaryRef PropsRef = 0;
460 krc = IORegistryEntryCreateCFProperties(Object, &PropsRef, kCFAllocatorDefault, kNilOptions);
461 if (krc == KERN_SUCCESS)
462 {
463 darwinDumpDict(PropsRef, cIndents + 4);
464 CFRelease(PropsRef);
465 }
466
467 /*
468 * Children.
469 */
470 io_iterator_t Children;
471 krc = IORegistryEntryGetChildIterator(Object, kIOServicePlane, &Children);
472 if (krc == KERN_SUCCESS)
473 {
474 io_object_t Child;
475 while ((Child = IOIteratorNext(Children)))
476 {
477 darwinDumpObjInt(Child, cIndents + 4);
478 IOObjectRelease(Child);
479 }
480 IOObjectRelease(Children);
481 }
482 else
483 DARWIN_IOKIT_LOG(("IORegistryEntryGetChildIterator -> %#x\n", krc));
484}
485
486/**
487 * Dumps an I/O kit registry object and all it children.
488 * @param Object The object to dump.
489 */
490static void darwinDumpObj(io_object_t Object)
491{
492 darwinDumpObjInt(Object, 0);
493}
494
495#endif /* helpers for dumping registry dictionaries */
496
497
498#ifdef VBOX_WITH_USB
499
500/**
501 * Notification data created by DarwinSubscribeUSBNotifications, used by
502 * the callbacks and finally freed by DarwinUnsubscribeUSBNotifications.
503 */
504typedef struct DARWINUSBNOTIFY
505{
506 /** The notification port.
507 * It's shared between the notification callbacks. */
508 IONotificationPortRef NotifyPort;
509 /** The run loop source for NotifyPort. */
510 CFRunLoopSourceRef NotifyRLSrc;
511 /** The attach notification iterator. */
512 io_iterator_t AttachIterator;
513 /** The 2nd attach notification iterator. */
514 io_iterator_t AttachIterator2;
515 /** The detach notification iterator. */
516 io_iterator_t DetachIterator;
517} DARWINUSBNOTIFY, *PDARWINUSBNOTIFY;
518
519
520/**
521 * Run thru an iterator.
522 *
523 * The docs says this is necessary to start getting notifications,
524 * so this function is called in the callbacks and right after
525 * registering the notification.
526 *
527 * @param pIterator The iterator reference.
528 */
529static void darwinDrainIterator(io_iterator_t pIterator)
530{
531 io_object_t Object;
532 while ((Object = IOIteratorNext(pIterator)))
533 {
534 DARWIN_IOKIT_DUMP_OBJ(Object);
535 IOObjectRelease(Object);
536 }
537}
538
539
540/**
541 * Callback for the 1st attach notification.
542 *
543 * @param pvNotify Our data.
544 * @param NotifyIterator The notification iterator.
545 */
546static void darwinUSBAttachNotification1(void *pvNotify, io_iterator_t NotifyIterator)
547{
548 DARWIN_IOKIT_LOG(("USB Attach Notification1\n"));
549 NOREF(pvNotify); //PDARWINUSBNOTIFY pNotify = (PDARWINUSBNOTIFY)pvNotify;
550 darwinDrainIterator(NotifyIterator);
551}
552
553
554/**
555 * Callback for the 2nd attach notification.
556 *
557 * @param pvNotify Our data.
558 * @param NotifyIterator The notification iterator.
559 */
560static void darwinUSBAttachNotification2(void *pvNotify, io_iterator_t NotifyIterator)
561{
562 DARWIN_IOKIT_LOG(("USB Attach Notification2\n"));
563 NOREF(pvNotify); //PDARWINUSBNOTIFY pNotify = (PDARWINUSBNOTIFY)pvNotify;
564 darwinDrainIterator(NotifyIterator);
565}
566
567
568/**
569 * Callback for the detach notifications.
570 *
571 * @param pvNotify Our data.
572 * @param NotifyIterator The notification iterator.
573 */
574static void darwinUSBDetachNotification(void *pvNotify, io_iterator_t NotifyIterator)
575{
576 DARWIN_IOKIT_LOG(("USB Detach Notification\n"));
577 NOREF(pvNotify); //PDARWINUSBNOTIFY pNotify = (PDARWINUSBNOTIFY)pvNotify;
578 darwinDrainIterator(NotifyIterator);
579}
580
581
582/**
583 * Subscribes the run loop to USB notification events relevant to
584 * device attach/detach.
585 *
586 * The source mode for these events is defined as VBOX_IOKIT_MODE_STRING
587 * so that the caller can listen to events from this mode only and
588 * re-evalutate the list of attached devices whenever an event arrives.
589 *
590 * @returns opaque for passing to the unsubscribe function. If NULL
591 * something unexpectedly failed during subscription.
592 */
593void *DarwinSubscribeUSBNotifications(void)
594{
595 AssertReturn(darwinOpenMasterPort(), NULL);
596
597 PDARWINUSBNOTIFY pNotify = (PDARWINUSBNOTIFY)RTMemAllocZ(sizeof(*pNotify));
598 AssertReturn(pNotify, NULL);
599
600 /*
601 * Create the notification port, bake it into a runloop source which we
602 * then add to our run loop.
603 */
604 pNotify->NotifyPort = IONotificationPortCreate(g_MasterPort);
605 Assert(pNotify->NotifyPort);
606 if (pNotify->NotifyPort)
607 {
608 pNotify->NotifyRLSrc = IONotificationPortGetRunLoopSource(pNotify->NotifyPort);
609 Assert(pNotify->NotifyRLSrc);
610 if (pNotify->NotifyRLSrc)
611 {
612 CFRunLoopRef RunLoopRef = CFRunLoopGetCurrent();
613 CFRetain(RunLoopRef); /* Workaround for crash when cleaning up the TLS / runloop((sub)mode). See @bugref{2807}. */
614 CFRunLoopAddSource(RunLoopRef, pNotify->NotifyRLSrc, CFSTR(VBOX_IOKIT_MODE_STRING));
615
616 /*
617 * Create the notification callbacks.
618 */
619 kern_return_t rc = IOServiceAddMatchingNotification(pNotify->NotifyPort,
620 kIOPublishNotification,
621 IOServiceMatching(kIOUSBDeviceClassName),
622 darwinUSBAttachNotification1,
623 pNotify,
624 &pNotify->AttachIterator);
625 if (rc == KERN_SUCCESS)
626 {
627 darwinDrainIterator(pNotify->AttachIterator);
628 rc = IOServiceAddMatchingNotification(pNotify->NotifyPort,
629 kIOMatchedNotification,
630 IOServiceMatching(kIOUSBDeviceClassName),
631 darwinUSBAttachNotification2,
632 pNotify,
633 &pNotify->AttachIterator2);
634 if (rc == KERN_SUCCESS)
635 {
636 darwinDrainIterator(pNotify->AttachIterator2);
637 rc = IOServiceAddMatchingNotification(pNotify->NotifyPort,
638 kIOTerminatedNotification,
639 IOServiceMatching(kIOUSBDeviceClassName),
640 darwinUSBDetachNotification,
641 pNotify,
642 &pNotify->DetachIterator);
643 {
644 darwinDrainIterator(pNotify->DetachIterator);
645 return pNotify;
646 }
647 IOObjectRelease(pNotify->AttachIterator2);
648 }
649 IOObjectRelease(pNotify->AttachIterator);
650 }
651 CFRunLoopRemoveSource(RunLoopRef, pNotify->NotifyRLSrc, CFSTR(VBOX_IOKIT_MODE_STRING));
652 }
653 IONotificationPortDestroy(pNotify->NotifyPort);
654 }
655
656 RTMemFree(pNotify);
657 return NULL;
658}
659
660
661/**
662 * Unsubscribe the run loop from USB notification subscribed to
663 * by DarwinSubscribeUSBNotifications.
664 *
665 * @param pvOpaque The return value from DarwinSubscribeUSBNotifications.
666 */
667void DarwinUnsubscribeUSBNotifications(void *pvOpaque)
668{
669 PDARWINUSBNOTIFY pNotify = (PDARWINUSBNOTIFY)pvOpaque;
670 if (!pNotify)
671 return;
672
673 IOObjectRelease(pNotify->AttachIterator);
674 pNotify->AttachIterator = NULL;
675 IOObjectRelease(pNotify->AttachIterator2);
676 pNotify->AttachIterator2 = NULL;
677 IOObjectRelease(pNotify->DetachIterator);
678 pNotify->DetachIterator = NULL;
679
680 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), pNotify->NotifyRLSrc, CFSTR(VBOX_IOKIT_MODE_STRING));
681 IONotificationPortDestroy(pNotify->NotifyPort);
682 pNotify->NotifyRLSrc = NULL;
683 pNotify->NotifyPort = NULL;
684
685 RTMemFree(pNotify);
686}
687
688
689/**
690 * Descends recursively into a IORegistry tree locating the first object of a given class.
691 *
692 * The search is performed depth first.
693 *
694 * @returns Object reference if found, NULL if not.
695 * @param Object The current tree root.
696 * @param pszClass The name of the class we're looking for.
697 * @param pszNameBuf A scratch buffer for query the class name in to avoid
698 * wasting 128 bytes on an io_name_t object for every recursion.
699 */
700static io_object_t darwinFindObjectByClass(io_object_t Object, const char *pszClass, io_name_t pszNameBuf)
701{
702 io_iterator_t Children;
703 kern_return_t krc = IORegistryEntryGetChildIterator(Object, kIOServicePlane, &Children);
704 if (krc != KERN_SUCCESS)
705 return NULL;
706 io_object_t Child;
707 while ((Child = IOIteratorNext(Children)))
708 {
709 krc = IOObjectGetClass(Child, pszNameBuf);
710 if ( krc == KERN_SUCCESS
711 && !strcmp(pszNameBuf, pszClass))
712 break;
713
714 io_object_t GrandChild = darwinFindObjectByClass(Child, pszClass, pszNameBuf);
715 IOObjectRelease(Child);
716 if (GrandChild)
717 {
718 Child = GrandChild;
719 break;
720 }
721 }
722 IOObjectRelease(Children);
723 return Child;
724}
725
726
727/**
728 * Descends recursively into IOUSBMassStorageClass tree to check whether
729 * the MSD is mounted or not.
730 *
731 * The current heuristic is to look for the IOMedia class.
732 *
733 * @returns true if mounted, false if not.
734 * @param MSDObj The IOUSBMassStorageClass object.
735 * @param pszNameBuf A scratch buffer for query the class name in to avoid
736 * wasting 128 bytes on an io_name_t object for every recursion.
737 */
738static bool darwinIsMassStorageInterfaceInUse(io_object_t MSDObj, io_name_t pszNameBuf)
739{
740 io_object_t MediaObj = darwinFindObjectByClass(MSDObj, kIOMediaClass, pszNameBuf);
741 if (MediaObj)
742 {
743 CFMutableDictionaryRef pProperties;
744 kern_return_t krc;
745 bool fInUse = true;
746
747 krc = IORegistryEntryCreateCFProperties(MediaObj, &pProperties, kCFAllocatorDefault, kNilOptions);
748 if (krc == KERN_SUCCESS)
749 {
750 CFBooleanRef pBoolValue = (CFBooleanRef)CFDictionaryGetValue(pProperties, CFSTR(kIOMediaOpenKey));
751 if (pBoolValue)
752 fInUse = CFBooleanGetValue(pBoolValue);
753
754 CFRelease(pProperties);
755 }
756
757 /* more checks? */
758 IOObjectRelease(MediaObj);
759 return fInUse;
760 }
761
762 return false;
763}
764
765
766/**
767 * Worker function for DarwinGetUSBDevices() that tries to figure out
768 * what state the device is in and set enmState.
769 *
770 * This is mostly a matter of distinguishing between devices that nobody
771 * uses, devices that can be seized and devices that cannot be grabbed.
772 *
773 * @param pCur The USB device data.
774 * @param USBDevice The USB device object.
775 * @param PropsRef The USB device properties.
776 */
777static void darwinDeterminUSBDeviceState(PUSBDEVICE pCur, io_object_t USBDevice, CFMutableDictionaryRef /* PropsRef */)
778{
779 /*
780 * Iterate the interfaces (among the children of the IOUSBDevice object).
781 */
782 io_iterator_t Interfaces;
783 kern_return_t krc = IORegistryEntryGetChildIterator(USBDevice, kIOServicePlane, &Interfaces);
784 if (krc != KERN_SUCCESS)
785 return;
786
787 bool fHaveOwner = false;
788 RTPROCESS Owner = NIL_RTPROCESS;
789 bool fHaveClient = false;
790 RTPROCESS Client = NIL_RTPROCESS;
791 bool fUserClientOnly = true;
792 bool fConfigured = false;
793 bool fInUse = false;
794 bool fSeizable = true;
795 io_object_t Interface;
796 while ((Interface = IOIteratorNext(Interfaces)))
797 {
798 io_name_t szName;
799 krc = IOObjectGetClass(Interface, szName);
800 if ( krc == KERN_SUCCESS
801 && !strcmp(szName, "IOUSBInterface"))
802 {
803 fConfigured = true;
804
805 /*
806 * Iterate the interface children looking for stuff other than
807 * IOUSBUserClientInit objects.
808 */
809 io_iterator_t Children1;
810 krc = IORegistryEntryGetChildIterator(Interface, kIOServicePlane, &Children1);
811 if (krc == KERN_SUCCESS)
812 {
813 io_object_t Child1;
814 while ((Child1 = IOIteratorNext(Children1)))
815 {
816 krc = IOObjectGetClass(Child1, szName);
817 if ( krc == KERN_SUCCESS
818 && strcmp(szName, "IOUSBUserClientInit"))
819 {
820 fUserClientOnly = false;
821
822 if (!strcmp(szName, "IOUSBMassStorageClass"))
823 {
824 /* Only permit capturing MSDs that aren't mounted, at least
825 until the GUI starts poping up warnings about data loss
826 and such when capturing a busy device. */
827 fSeizable = false;
828 fInUse |= darwinIsMassStorageInterfaceInUse(Child1, szName);
829 }
830 else if (!strcmp(szName, "IOUSBHIDDriver")
831 || !strcmp(szName, "AppleHIDMouse")
832 /** @todo more? */)
833 {
834 /* For now, just assume that all HID devices are inaccessible
835 because of the greedy HID service. */
836 fSeizable = false;
837 fInUse = true;
838 }
839 else
840 fInUse = true;
841 }
842 IOObjectRelease(Child1);
843 }
844 IOObjectRelease(Children1);
845 }
846 }
847 /*
848 * Not an interface, could it be VBoxUSBDevice?
849 * If it is, get the owner and client properties.
850 */
851 else if ( krc == KERN_SUCCESS
852 && !strcmp(szName, VBOXUSBDEVICE_CLASS_NAME))
853 {
854 CFMutableDictionaryRef PropsRef = 0;
855 krc = IORegistryEntryCreateCFProperties(Interface, &PropsRef, kCFAllocatorDefault, kNilOptions);
856 if (krc == KERN_SUCCESS)
857 {
858 fHaveOwner = darwinDictGetProcess(PropsRef, CFSTR(VBOXUSB_OWNER_KEY), &Owner);
859 fHaveClient = darwinDictGetProcess(PropsRef, CFSTR(VBOXUSB_CLIENT_KEY), &Client);
860 CFRelease(PropsRef);
861 }
862 }
863
864 IOObjectRelease(Interface);
865 }
866 IOObjectRelease(Interfaces);
867
868 /*
869 * Calc the status.
870 */
871 if (fHaveOwner)
872 {
873 if (Owner == RTProcSelf())
874 pCur->enmState = !fHaveClient || Client == NIL_RTPROCESS || !Client
875 ? USBDEVICESTATE_HELD_BY_PROXY
876 : USBDEVICESTATE_USED_BY_GUEST;
877 else
878 pCur->enmState = USBDEVICESTATE_USED_BY_HOST;
879 }
880 else if (fUserClientOnly)
881 /** @todo how to detect other user client?!? - Look for IOUSBUserClient! */
882 pCur->enmState = !fConfigured
883 ? USBDEVICESTATE_UNUSED
884 : USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
885 else if (!fInUse)
886 pCur->enmState = USBDEVICESTATE_UNUSED;
887 else
888 pCur->enmState = fSeizable
889 ? USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
890 : USBDEVICESTATE_USED_BY_HOST;
891}
892
893
894/**
895 * Enumerate the USB devices returning a FIFO of them.
896 *
897 * @returns Pointer to the head.
898 * USBProxyService::freeDevice is expected to free each of the list elements.
899 */
900PUSBDEVICE DarwinGetUSBDevices(void)
901{
902 AssertReturn(darwinOpenMasterPort(), NULL);
903 //DARWIN_IOKIT_LOG(("DarwinGetUSBDevices\n"));
904
905 /*
906 * Create a matching dictionary for searching for USB Devices in the IOKit.
907 */
908 CFMutableDictionaryRef RefMatchingDict = IOServiceMatching(kIOUSBDeviceClassName);
909 AssertReturn(RefMatchingDict, NULL);
910
911 /*
912 * Perform the search and get a collection of USB Device back.
913 */
914 io_iterator_t USBDevices = NULL;
915 IOReturn rc = IOServiceGetMatchingServices(g_MasterPort, RefMatchingDict, &USBDevices);
916 AssertMsgReturn(rc == kIOReturnSuccess, ("rc=%d\n", rc), NULL);
917 RefMatchingDict = NULL; /* the reference is consumed by IOServiceGetMatchingServices. */
918
919 /*
920 * Enumerate the USB Devices.
921 */
922 PUSBDEVICE pHead = NULL;
923 PUSBDEVICE pTail = NULL;
924 unsigned i = 0;
925 io_object_t USBDevice;
926 while ((USBDevice = IOIteratorNext(USBDevices)) != 0)
927 {
928 DARWIN_IOKIT_DUMP_OBJ(USBDevice);
929
930 /*
931 * Query the device properties from the registry.
932 *
933 * We could alternatively use the device and such, but that will be
934 * slower and we would have to resort to the registry for the three
935 * string anyway.
936 */
937 CFMutableDictionaryRef PropsRef = 0;
938 kern_return_t krc = IORegistryEntryCreateCFProperties(USBDevice, &PropsRef, kCFAllocatorDefault, kNilOptions);
939 if (krc == KERN_SUCCESS)
940 {
941 bool fOk = false;
942 PUSBDEVICE pCur = (PUSBDEVICE)RTMemAllocZ(sizeof(*pCur));
943 do /* loop for breaking out of on failure. */
944 {
945 AssertBreak(pCur);
946
947 /*
948 * Mandatory
949 */
950 pCur->bcdUSB = 0; /* we've no idea. */
951 pCur->enmState = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE; /* just a default, we'll try harder in a bit. */
952
953 /* Skip hubs. On 10.11 beta 3, the root hub simulations does not have a USBDeviceClass property, so
954 simply ignore failures to retrieve it. */
955 if (!darwinDictGetU8(PropsRef, CFSTR(kUSBDeviceClass), &pCur->bDeviceClass))
956 {
957#ifdef VBOX_STRICT
958 char szTmp[80];
959 Assert( darwinDictGetString(PropsRef, CFSTR("IOClassNameOverride"), szTmp, sizeof(szTmp))
960 && strcmp(szTmp, "IOUSBRootHubDevice") == 0);
961#endif
962 break;
963 }
964 if (pCur->bDeviceClass == 0x09 /* hub, find a define! */)
965 break;
966 AssertBreak(darwinDictGetU8(PropsRef, CFSTR(kUSBDeviceSubClass), &pCur->bDeviceSubClass));
967 AssertBreak(darwinDictGetU8(PropsRef, CFSTR(kUSBDeviceProtocol), &pCur->bDeviceProtocol));
968 AssertBreak(darwinDictGetU16(PropsRef, CFSTR(kUSBVendorID), &pCur->idVendor));
969 AssertBreak(darwinDictGetU16(PropsRef, CFSTR(kUSBProductID), &pCur->idProduct));
970 AssertBreak(darwinDictGetU16(PropsRef, CFSTR(kUSBDeviceReleaseNumber), &pCur->bcdDevice));
971 uint32_t u32LocationId;
972 AssertBreak(darwinDictGetU32(PropsRef, CFSTR(kUSBDevicePropertyLocationID), &u32LocationId));
973 uint64_t u64SessionId;
974 AssertBreak(darwinDictGetU64(PropsRef, CFSTR("sessionID"), &u64SessionId));
975 char szAddress[64];
976 RTStrPrintf(szAddress, sizeof(szAddress), "p=0x%04RX16;v=0x%04RX16;s=0x%016RX64;l=0x%08RX32",
977 pCur->idProduct, pCur->idVendor, u64SessionId, u32LocationId);
978 pCur->pszAddress = RTStrDup(szAddress);
979 AssertBreak(pCur->pszAddress);
980 pCur->bBus = u32LocationId >> 24;
981 darwinDictGetU8(PropsRef, CFSTR("PortNum"), &pCur->bPort); /* Not present in 10.11 beta 3, so ignore failure. (Is set to zero.) */
982 uint8_t bSpeed;
983 AssertBreak(darwinDictGetU8(PropsRef, CFSTR(kUSBDevicePropertySpeed), &bSpeed));
984 Assert(bSpeed <= 3);
985 pCur->enmSpeed = bSpeed == 3 ? USBDEVICESPEED_SUPER
986 : bSpeed == 2 ? USBDEVICESPEED_HIGH
987 : bSpeed == 1 ? USBDEVICESPEED_FULL
988 : bSpeed == 0 ? USBDEVICESPEED_LOW
989 : USBDEVICESPEED_UNKNOWN;
990
991 /*
992 * Optional.
993 * There are some nameless device in the iMac, apply names to them.
994 */
995 darwinDictDupString(PropsRef, CFSTR("USB Vendor Name"), (char **)&pCur->pszManufacturer);
996 if ( !pCur->pszManufacturer
997 && pCur->idVendor == kIOUSBVendorIDAppleComputer)
998 pCur->pszManufacturer = RTStrDup("Apple Computer, Inc.");
999 darwinDictDupString(PropsRef, CFSTR("USB Product Name"), (char **)&pCur->pszProduct);
1000 if ( !pCur->pszProduct
1001 && pCur->bDeviceClass == 224 /* Wireless */
1002 && pCur->bDeviceSubClass == 1 /* Radio Frequency */
1003 && pCur->bDeviceProtocol == 1 /* Bluetooth */)
1004 pCur->pszProduct = RTStrDup("Bluetooth");
1005 darwinDictDupString(PropsRef, CFSTR("USB Serial Number"), (char **)&pCur->pszSerialNumber);
1006
1007#if 0 /* leave the remainder as zero for now. */
1008 /*
1009 * Create a plugin interface for the service and query its USB Device interface.
1010 */
1011 SInt32 Score = 0;
1012 IOCFPlugInInterface **ppPlugInInterface = NULL;
1013 rc = IOCreatePlugInInterfaceForService(USBDevice, kIOUSBDeviceUserClientTypeID,
1014 kIOCFPlugInInterfaceID, &ppPlugInInterface, &Score);
1015 if (rc == kIOReturnSuccess)
1016 {
1017 IOUSBDeviceInterface245 **ppUSBDevI = NULL;
1018 HRESULT hrc = (*ppPlugInInterface)->QueryInterface(ppPlugInInterface,
1019 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID245),
1020 (LPVOID *)&ppUSBDevI);
1021 rc = IODestroyPlugInInterface(ppPlugInInterface); Assert(rc == kIOReturnSuccess);
1022 ppPlugInInterface = NULL;
1023 if (hrc == S_OK)
1024 {
1025 /** @todo enumerate configurations and interfaces if we actually need them. */
1026 //IOReturn (*GetNumberOfConfigurations)(void *self, UInt8 *numConfig);
1027 //IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc);
1028 //IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter);
1029 }
1030 long cReft = (*ppUSBDeviceInterface)->Release(ppUSBDeviceInterface); MY_CHECK_CREFS(cRefs);
1031 }
1032#endif
1033 /*
1034 * Try determine the state.
1035 */
1036 darwinDeterminUSBDeviceState(pCur, USBDevice, PropsRef);
1037
1038 /*
1039 * We're good. Link the device.
1040 */
1041 pCur->pPrev = pTail;
1042 if (pTail)
1043 pTail = pTail->pNext = pCur;
1044 else
1045 pTail = pHead = pCur;
1046 fOk = true;
1047 } while (0);
1048
1049 /* cleanup on failure / skipped device. */
1050 if (!fOk && pCur)
1051 DarwinFreeUSBDeviceFromIOKit(pCur);
1052
1053 CFRelease(PropsRef);
1054 }
1055 else
1056 AssertMsgFailed(("krc=%#x\n", krc));
1057
1058 IOObjectRelease(USBDevice);
1059 i++;
1060 }
1061
1062 IOObjectRelease(USBDevices);
1063 //DARWIN_IOKIT_LOG_FLUSH();
1064
1065 /*
1066 * Some post processing. There are a couple of things we have to
1067 * make 100% sure about, and that is that the (Apple) keyboard
1068 * and mouse most likely to be in use by the user aren't available
1069 * for capturing. If there is no Apple mouse or keyboard we'll
1070 * take the first one from another vendor.
1071 */
1072 /* As it turns out, the HID service will take all keyboards and mice
1073 and we're not currently able to seize them. */
1074 PUSBDEVICE pMouse = NULL;
1075 PUSBDEVICE pKeyboard = NULL;
1076 for (PUSBDEVICE pCur = pHead; pCur; pCur = pCur->pNext)
1077 if (pCur->idVendor == kIOUSBVendorIDAppleComputer)
1078 {
1079 /*
1080 * This test is a bit rough, should check device class/protocol but
1081 * we don't have interface info yet so that might be a bit tricky.
1082 */
1083 if ( ( !pKeyboard
1084 || pKeyboard->idVendor != kIOUSBVendorIDAppleComputer)
1085 && pCur->pszProduct
1086 && strstr(pCur->pszProduct, " Keyboard"))
1087 pKeyboard = pCur;
1088 else if ( ( !pMouse
1089 || pMouse->idVendor != kIOUSBVendorIDAppleComputer)
1090 && pCur->pszProduct
1091 && strstr(pCur->pszProduct, " Mouse")
1092 )
1093 pMouse = pCur;
1094 }
1095 else if (!pKeyboard || !pMouse)
1096 {
1097 if ( pCur->bDeviceClass == 3 /* HID */
1098 && pCur->bDeviceProtocol == 1 /* Keyboard */)
1099 pKeyboard = pCur;
1100 else if ( pCur->bDeviceClass == 3 /* HID */
1101 && pCur->bDeviceProtocol == 2 /* Mouse */)
1102 pMouse = pCur;
1103 /** @todo examin interfaces */
1104 }
1105
1106 if (pKeyboard)
1107 pKeyboard->enmState = USBDEVICESTATE_USED_BY_HOST;
1108 if (pMouse)
1109 pMouse->enmState = USBDEVICESTATE_USED_BY_HOST;
1110
1111 return pHead;
1112}
1113
1114
1115/**
1116 * Triggers re-enumeration of a device.
1117 *
1118 * @returns VBox status code.
1119 * @param pCur The USBDEVICE structure for the device.
1120 */
1121int DarwinReEnumerateUSBDevice(PCUSBDEVICE pCur)
1122{
1123 int vrc;
1124 const char *pszAddress = pCur->pszAddress;
1125 AssertPtrReturn(pszAddress, VERR_INVALID_POINTER);
1126 AssertReturn(darwinOpenMasterPort(), VERR_GENERAL_FAILURE);
1127
1128 /*
1129 * This code is a short version of the Open method in USBProxyDevice-darwin.cpp stuff.
1130 * Fixes made to this code probably applies there too!
1131 */
1132
1133 CFMutableDictionaryRef RefMatchingDict = IOServiceMatching(kIOUSBDeviceClassName);
1134 AssertReturn(RefMatchingDict, NULL);
1135
1136 uint64_t u64SessionId = 0;
1137 uint32_t u32LocationId = 0;
1138 const char *psz = pszAddress;
1139 do
1140 {
1141 const char chValue = *psz;
1142 AssertReleaseReturn(psz[1] == '=', VERR_INTERNAL_ERROR);
1143 uint64_t u64Value;
1144 int rc = RTStrToUInt64Ex(psz + 2, (char **)&psz, 0, &u64Value);
1145 AssertReleaseRCReturn(rc, rc);
1146 AssertReleaseReturn(!*psz || *psz == ';', rc);
1147 switch (chValue)
1148 {
1149 case 'l':
1150 u32LocationId = (uint32_t)u64Value;
1151 break;
1152 case 's':
1153 u64SessionId = u64Value;
1154 break;
1155 case 'p':
1156 case 'v':
1157 {
1158#if 0 /* Guess what, this doesn't 'ing work either! */
1159 SInt32 i32 = (int16_t)u64Value;
1160 CFNumberRef Num = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i32);
1161 AssertBreak(Num);
1162 CFDictionarySetValue(RefMatchingDict, chValue == 'p' ? CFSTR(kUSBProductID) : CFSTR(kUSBVendorID), Num);
1163 CFRelease(Num);
1164#endif
1165 break;
1166 }
1167 default:
1168 AssertReleaseMsgFailedReturn(("chValue=%#x\n", chValue), VERR_INTERNAL_ERROR);
1169 }
1170 if (*psz == ';')
1171 psz++;
1172 } while (*psz);
1173
1174 io_iterator_t USBDevices = NULL;
1175 IOReturn irc = IOServiceGetMatchingServices(g_MasterPort, RefMatchingDict, &USBDevices);
1176 AssertMsgReturn(irc == kIOReturnSuccess, ("irc=%#x\n", irc), NULL);
1177 RefMatchingDict = NULL; /* the reference is consumed by IOServiceGetMatchingServices. */
1178
1179 unsigned cMatches = 0;
1180 io_object_t USBDevice;
1181 while ((USBDevice = IOIteratorNext(USBDevices)))
1182 {
1183 cMatches++;
1184 CFMutableDictionaryRef PropsRef = 0;
1185 kern_return_t krc = IORegistryEntryCreateCFProperties(USBDevice, &PropsRef, kCFAllocatorDefault, kNilOptions);
1186 if (krc == KERN_SUCCESS)
1187 {
1188 uint64_t u64CurSessionId;
1189 uint32_t u32CurLocationId;
1190 if ( ( !u64SessionId
1191 || ( darwinDictGetU64(PropsRef, CFSTR("sessionID"), &u64CurSessionId)
1192 && u64CurSessionId == u64SessionId))
1193 && ( !u32LocationId
1194 || ( darwinDictGetU32(PropsRef, CFSTR(kUSBDevicePropertyLocationID), &u32CurLocationId)
1195 && u32CurLocationId == u32LocationId))
1196 )
1197 {
1198 CFRelease(PropsRef);
1199 break;
1200 }
1201 CFRelease(PropsRef);
1202 }
1203 IOObjectRelease(USBDevice);
1204 }
1205 IOObjectRelease(USBDevices);
1206 USBDevices = NULL;
1207 if (!USBDevice)
1208 {
1209 LogRel(("USB: Device '%s' not found (%d pid+vid matches)\n", pszAddress, cMatches));
1210 IOObjectRelease(USBDevices);
1211 return VERR_VUSB_DEVICE_NAME_NOT_FOUND;
1212 }
1213
1214 /*
1215 * Create a plugin interface for the device and query its IOUSBDeviceInterface.
1216 */
1217 SInt32 Score = 0;
1218 IOCFPlugInInterface **ppPlugInInterface = NULL;
1219 irc = IOCreatePlugInInterfaceForService(USBDevice, kIOUSBDeviceUserClientTypeID,
1220 kIOCFPlugInInterfaceID, &ppPlugInInterface, &Score);
1221 if (irc == kIOReturnSuccess)
1222 {
1223 IOUSBDeviceInterface245 **ppDevI = NULL;
1224 HRESULT hrc = (*ppPlugInInterface)->QueryInterface(ppPlugInInterface,
1225 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID245),
1226 (LPVOID *)&ppDevI);
1227 irc = IODestroyPlugInInterface(ppPlugInInterface); Assert(irc == kIOReturnSuccess);
1228 ppPlugInInterface = NULL;
1229 if (hrc == S_OK)
1230 {
1231 /*
1232 * Try open the device for exclusive access.
1233 */
1234 irc = (*ppDevI)->USBDeviceOpenSeize(ppDevI);
1235 if (irc == kIOReturnExclusiveAccess)
1236 {
1237 RTThreadSleep(20);
1238 irc = (*ppDevI)->USBDeviceOpenSeize(ppDevI);
1239 }
1240 if (irc == kIOReturnSuccess)
1241 {
1242 /*
1243 * Re-enumerate the device and bail out.
1244 */
1245 irc = (*ppDevI)->USBDeviceReEnumerate(ppDevI, 0);
1246 if (irc == kIOReturnSuccess)
1247 vrc = VINF_SUCCESS;
1248 else
1249 {
1250 LogRel(("USB: Failed to open device '%s', plug-in creation failed with irc=%#x.\n", pszAddress, irc));
1251 vrc = RTErrConvertFromDarwinIO(irc);
1252 }
1253
1254 (*ppDevI)->USBDeviceClose(ppDevI);
1255 }
1256 else if (irc == kIOReturnExclusiveAccess)
1257 {
1258 LogRel(("USB: Device '%s' is being used by another process\n", pszAddress));
1259 vrc = VERR_SHARING_VIOLATION;
1260 }
1261 else
1262 {
1263 LogRel(("USB: Failed to open device '%s', irc=%#x.\n", pszAddress, irc));
1264 vrc = VERR_OPEN_FAILED;
1265 }
1266 }
1267 else
1268 {
1269 LogRel(("USB: Failed to create plugin interface for device '%s', hrc=%#x.\n", pszAddress, hrc));
1270 vrc = VERR_OPEN_FAILED;
1271 }
1272
1273 (*ppDevI)->Release(ppDevI);
1274 }
1275 else
1276 {
1277 LogRel(("USB: Failed to open device '%s', plug-in creation failed with irc=%#x.\n", pszAddress, irc));
1278 vrc = RTErrConvertFromDarwinIO(irc);
1279 }
1280
1281 return vrc;
1282}
1283
1284#endif /* VBOX_WITH_USB */
1285
1286
1287/**
1288 * Enumerate the CD, DVD and BlueRay drives returning a FIFO of device name strings.
1289 *
1290 * @returns Pointer to the head.
1291 * The caller is responsible for calling RTMemFree() on each of the nodes.
1292 */
1293PDARWINDVD DarwinGetDVDDrives(void)
1294{
1295 AssertReturn(darwinOpenMasterPort(), NULL);
1296
1297 /*
1298 * Create a matching dictionary for searching for CD, DVD and BlueRay services in the IOKit.
1299 *
1300 * The idea is to find all the devices which are of class IOCDBlockStorageDevice.
1301 * CD devices are represented by IOCDBlockStorageDevice class itself, while DVD and BlueRay ones
1302 * have it as a parent class.
1303 */
1304 CFMutableDictionaryRef RefMatchingDict = IOServiceMatching("IOCDBlockStorageDevice");
1305 AssertReturn(RefMatchingDict, NULL);
1306
1307 /*
1308 * Perform the search and get a collection of DVD services.
1309 */
1310 io_iterator_t DVDServices = NULL;
1311 IOReturn rc = IOServiceGetMatchingServices(g_MasterPort, RefMatchingDict, &DVDServices);
1312 AssertMsgReturn(rc == kIOReturnSuccess, ("rc=%d\n", rc), NULL);
1313 RefMatchingDict = NULL; /* the reference is consumed by IOServiceGetMatchingServices. */
1314
1315 /*
1316 * Enumerate the matching services.
1317 * (This enumeration must be identical to the one performed in DrvHostBase.cpp.)
1318 */
1319 PDARWINDVD pHead = NULL;
1320 PDARWINDVD pTail = NULL;
1321 unsigned i = 0;
1322 io_object_t DVDService;
1323 while ((DVDService = IOIteratorNext(DVDServices)) != 0)
1324 {
1325 DARWIN_IOKIT_DUMP_OBJ(DVDService);
1326
1327 /*
1328 * Get the properties we use to identify the DVD drive.
1329 *
1330 * While there is a (weird 12 byte) GUID, it isn't persistent
1331 * across boots. So, we have to use a combination of the
1332 * vendor name and product name properties with an optional
1333 * sequence number for identification.
1334 */
1335 CFMutableDictionaryRef PropsRef = 0;
1336 kern_return_t krc = IORegistryEntryCreateCFProperties(DVDService, &PropsRef, kCFAllocatorDefault, kNilOptions);
1337 if (krc == KERN_SUCCESS)
1338 {
1339 /* Get the Device Characteristics dictionary. */
1340 CFDictionaryRef DevCharRef = (CFDictionaryRef)CFDictionaryGetValue(PropsRef, CFSTR(kIOPropertyDeviceCharacteristicsKey));
1341 if (DevCharRef)
1342 {
1343 /* The vendor name. */
1344 char szVendor[128];
1345 char *pszVendor = &szVendor[0];
1346 CFTypeRef ValueRef = CFDictionaryGetValue(DevCharRef, CFSTR(kIOPropertyVendorNameKey));
1347 if ( ValueRef
1348 && CFGetTypeID(ValueRef) == CFStringGetTypeID()
1349 && CFStringGetCString((CFStringRef)ValueRef, szVendor, sizeof(szVendor), kCFStringEncodingUTF8))
1350 pszVendor = RTStrStrip(szVendor);
1351 else
1352 *pszVendor = '\0';
1353
1354 /* The product name. */
1355 char szProduct[128];
1356 char *pszProduct = &szProduct[0];
1357 ValueRef = CFDictionaryGetValue(DevCharRef, CFSTR(kIOPropertyProductNameKey));
1358 if ( ValueRef
1359 && CFGetTypeID(ValueRef) == CFStringGetTypeID()
1360 && CFStringGetCString((CFStringRef)ValueRef, szProduct, sizeof(szProduct), kCFStringEncodingUTF8))
1361 pszProduct = RTStrStrip(szProduct);
1362 else
1363 *pszProduct = '\0';
1364
1365 /* Construct the name and check for duplicates. */
1366 char szName[256 + 32];
1367 if (*pszVendor || *pszProduct)
1368 {
1369 if (*pszVendor && *pszProduct)
1370 RTStrPrintf(szName, sizeof(szName), "%s %s", pszVendor, pszProduct);
1371 else
1372 strcpy(szName, *pszVendor ? pszVendor : pszProduct);
1373
1374 for (PDARWINDVD pCur = pHead; pCur; pCur = pCur->pNext)
1375 {
1376 if (!strcmp(szName, pCur->szName))
1377 {
1378 if (*pszVendor && *pszProduct)
1379 RTStrPrintf(szName, sizeof(szName), "%s %s (#%u)", pszVendor, pszProduct, i);
1380 else
1381 RTStrPrintf(szName, sizeof(szName), "%s (#%u)", *pszVendor ? pszVendor : pszProduct, i);
1382 break;
1383 }
1384 }
1385 }
1386 else
1387 RTStrPrintf(szName, sizeof(szName), "(#%u)", i);
1388
1389 /* Create the device. */
1390 size_t cbName = strlen(szName) + 1;
1391 PDARWINDVD pNew = (PDARWINDVD)RTMemAlloc(RT_OFFSETOF(DARWINDVD, szName[cbName]));
1392 if (pNew)
1393 {
1394 pNew->pNext = NULL;
1395 memcpy(pNew->szName, szName, cbName);
1396 if (pTail)
1397 pTail = pTail->pNext = pNew;
1398 else
1399 pTail = pHead = pNew;
1400 }
1401 }
1402 CFRelease(PropsRef);
1403 }
1404 else
1405 AssertMsgFailed(("krc=%#x\n", krc));
1406
1407 IOObjectRelease(DVDService);
1408 i++;
1409 }
1410
1411 IOObjectRelease(DVDServices);
1412
1413 return pHead;
1414}
1415
1416
1417/**
1418 * Enumerate the ethernet capable network devices returning a FIFO of them.
1419 *
1420 * @returns Pointer to the head.
1421 */
1422PDARWINETHERNIC DarwinGetEthernetControllers(void)
1423{
1424 AssertReturn(darwinOpenMasterPort(), NULL);
1425
1426 /*
1427 * Create a matching dictionary for searching for ethernet controller
1428 * services in the IOKit.
1429 *
1430 * For some really stupid reason I don't get all the controllers if I look for
1431 * objects that are instances of IOEthernetController or its descendants (only
1432 * get the AirPort on my mac pro). But fortunately using IOEthernetInterface
1433 * seems to work. Weird s**t!
1434 */
1435 //CFMutableDictionaryRef RefMatchingDict = IOServiceMatching("IOEthernetController"); - this doesn't work :-(
1436 CFMutableDictionaryRef RefMatchingDict = IOServiceMatching("IOEthernetInterface");
1437 AssertReturn(RefMatchingDict, NULL);
1438
1439 /*
1440 * Perform the search and get a collection of ethernet controller services.
1441 */
1442 io_iterator_t EtherIfServices = NULL;
1443 IOReturn rc = IOServiceGetMatchingServices(g_MasterPort, RefMatchingDict, &EtherIfServices);
1444 AssertMsgReturn(rc == kIOReturnSuccess, ("rc=%d\n", rc), NULL);
1445 RefMatchingDict = NULL; /* the reference is consumed by IOServiceGetMatchingServices. */
1446
1447 /*
1448 * Get a copy of the current network interfaces from the system configuration service.
1449 * We'll use this for looking up the proper interface names.
1450 */
1451 CFArrayRef IfsRef = SCNetworkInterfaceCopyAll();
1452 CFIndex cIfs = IfsRef ? CFArrayGetCount(IfsRef) : 0;
1453
1454 /*
1455 * Get the current preferences and make a copy of the network services so we
1456 * can look up the right interface names. The IfsRef is just for fallback.
1457 */
1458 CFArrayRef ServicesRef = NULL;
1459 CFIndex cServices = 0;
1460 SCPreferencesRef PrefsRef = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("org.virtualbox.VBoxSVC"), NULL);
1461 if (PrefsRef)
1462 {
1463 SCNetworkSetRef SetRef = SCNetworkSetCopyCurrent(PrefsRef);
1464 CFRelease(PrefsRef);
1465 if (SetRef)
1466 {
1467 ServicesRef = SCNetworkSetCopyServices(SetRef);
1468 CFRelease(SetRef);
1469 cServices = ServicesRef ? CFArrayGetCount(ServicesRef) : 0;
1470 }
1471 }
1472
1473 /*
1474 * Enumerate the ethernet controller services.
1475 */
1476 PDARWINETHERNIC pHead = NULL;
1477 PDARWINETHERNIC pTail = NULL;
1478 io_object_t EtherIfService;
1479 while ((EtherIfService = IOIteratorNext(EtherIfServices)) != 0)
1480 {
1481 /*
1482 * Dig up the parent, meaning the IOEthernetController.
1483 */
1484 io_object_t EtherNICService;
1485 kern_return_t krc = IORegistryEntryGetParentEntry(EtherIfService, kIOServicePlane, &EtherNICService);
1486 /*krc = IORegistryEntryGetChildEntry(EtherNICService, kIOServicePlane, &EtherIfService); */
1487 if (krc == KERN_SUCCESS)
1488 {
1489 DARWIN_IOKIT_DUMP_OBJ(EtherNICService);
1490 /*
1491 * Get the properties we use to identify and name the Ethernet NIC.
1492 * We need the both the IOEthernetController and it's IONetworkInterface child.
1493 */
1494 CFMutableDictionaryRef PropsRef = 0;
1495 krc = IORegistryEntryCreateCFProperties(EtherNICService, &PropsRef, kCFAllocatorDefault, kNilOptions);
1496 if (krc == KERN_SUCCESS)
1497 {
1498 CFMutableDictionaryRef IfPropsRef = 0;
1499 krc = IORegistryEntryCreateCFProperties(EtherIfService, &IfPropsRef, kCFAllocatorDefault, kNilOptions);
1500 if (krc == KERN_SUCCESS)
1501 {
1502 /*
1503 * Gather the required data.
1504 * We'll create a UUID from the MAC address and the BSD name.
1505 */
1506 char szTmp[256];
1507 do
1508 {
1509 /* Check if airport (a bit heuristical - it's com.apple.driver.AirPortBrcm43xx here). */
1510 darwinDictGetString(PropsRef, CFSTR("CFBundleIdentifier"), szTmp, sizeof(szTmp));
1511 bool fWireless;
1512 bool fAirPort = fWireless = strstr(szTmp, ".AirPort") != NULL;
1513
1514 /* Check if it's USB. */
1515 darwinDictGetString(PropsRef, CFSTR("IOProviderClass"), szTmp, sizeof(szTmp));
1516 bool fUSB = strstr(szTmp, "USB") != NULL;
1517
1518
1519 /* Is it builtin? */
1520 bool fBuiltin;
1521 darwinDictGetBool(IfPropsRef, CFSTR("IOBuiltin"), &fBuiltin);
1522
1523 /* Is it the primary interface */
1524 bool fPrimaryIf;
1525 darwinDictGetBool(IfPropsRef, CFSTR("IOPrimaryInterface"), &fPrimaryIf);
1526
1527 /* Get the MAC address. */
1528 RTMAC Mac;
1529 AssertBreak(darwinDictGetData(PropsRef, CFSTR("IOMACAddress"), &Mac, sizeof(Mac)));
1530
1531 /* The BSD Name from the interface dictionary. */
1532 char szBSDName[RT_SIZEOFMEMB(DARWINETHERNIC, szBSDName)];
1533 AssertBreak(darwinDictGetString(IfPropsRef, CFSTR("BSD Name"), szBSDName, sizeof(szBSDName)));
1534
1535 /* Check if it's really wireless. */
1536 if ( darwinDictIsPresent(IfPropsRef, CFSTR("IO80211CountryCode"))
1537 || darwinDictIsPresent(IfPropsRef, CFSTR("IO80211DriverVersion"))
1538 || darwinDictIsPresent(IfPropsRef, CFSTR("IO80211HardwareVersion"))
1539 || darwinDictIsPresent(IfPropsRef, CFSTR("IO80211Locale")))
1540 fWireless = true;
1541 else
1542 fAirPort = fWireless = false;
1543
1544 /** @todo IOPacketFilters / IONetworkFilterGroup? */
1545 /*
1546 * Create the interface name.
1547 *
1548 * Note! The ConsoleImpl2.cpp code ASSUMES things about the name. It is also
1549 * stored in the VM config files. (really bright idea)
1550 */
1551 strcpy(szTmp, szBSDName);
1552 char *psz = strchr(szTmp, '\0');
1553 *psz++ = ':';
1554 *psz++ = ' ';
1555 size_t cchLeft = sizeof(szTmp) - (psz - &szTmp[0]) - (sizeof(" (Wireless)") - 1);
1556 bool fFound = false;
1557 CFIndex i;
1558
1559 /* look it up among the current services */
1560 for (i = 0; i < cServices; i++)
1561 {
1562 SCNetworkServiceRef ServiceRef = (SCNetworkServiceRef)CFArrayGetValueAtIndex(ServicesRef, i);
1563 SCNetworkInterfaceRef IfRef = SCNetworkServiceGetInterface(ServiceRef);
1564 if (IfRef)
1565 {
1566 CFStringRef BSDNameRef = SCNetworkInterfaceGetBSDName(IfRef);
1567 if ( BSDNameRef
1568 && CFStringGetCString(BSDNameRef, psz, cchLeft, kCFStringEncodingUTF8)
1569 && !strcmp(psz, szBSDName))
1570 {
1571 CFStringRef ServiceNameRef = SCNetworkServiceGetName(ServiceRef);
1572 if ( ServiceNameRef
1573 && CFStringGetCString(ServiceNameRef, psz, cchLeft, kCFStringEncodingUTF8))
1574 {
1575 fFound = true;
1576 break;
1577 }
1578 }
1579 }
1580 }
1581 /* Look it up in the interface list. */
1582 if (!fFound)
1583 for (i = 0; i < cIfs; i++)
1584 {
1585 SCNetworkInterfaceRef IfRef = (SCNetworkInterfaceRef)CFArrayGetValueAtIndex(IfsRef, i);
1586 CFStringRef BSDNameRef = SCNetworkInterfaceGetBSDName(IfRef);
1587 if ( BSDNameRef
1588 && CFStringGetCString(BSDNameRef, psz, cchLeft, kCFStringEncodingUTF8)
1589 && !strcmp(psz, szBSDName))
1590 {
1591 CFStringRef DisplayNameRef = SCNetworkInterfaceGetLocalizedDisplayName(IfRef);
1592 if ( DisplayNameRef
1593 && CFStringGetCString(DisplayNameRef, psz, cchLeft, kCFStringEncodingUTF8))
1594 {
1595 fFound = true;
1596 break;
1597 }
1598 }
1599 }
1600 /* Generate a half plausible name if we for some silly reason didn't find the interface. */
1601 if (!fFound)
1602 RTStrPrintf(szTmp, sizeof(szTmp), "%s: %s%s(?)",
1603 szBSDName,
1604 fUSB ? "USB " : "",
1605 fWireless ? fAirPort ? "AirPort " : "Wireless" : "Ethernet");
1606 /* If we did find it and it's wireless but without "AirPort" or "Wireless", fix it */
1607 else if ( fWireless
1608 && !strstr(psz, "AirPort")
1609 && !strstr(psz, "Wireless"))
1610 strcat(szTmp, fAirPort ? " (AirPort)" : " (Wireless)");
1611
1612 /*
1613 * Create the list entry.
1614 */
1615 DARWIN_IOKIT_LOG(("Found: if=%s mac=%.6Rhxs fWireless=%RTbool fAirPort=%RTbool fBuiltin=%RTbool fPrimaryIf=%RTbool fUSB=%RTbool\n",
1616 szBSDName, &Mac, fWireless, fAirPort, fBuiltin, fPrimaryIf, fUSB));
1617
1618 size_t cchName = strlen(szTmp);
1619 PDARWINETHERNIC pNew = (PDARWINETHERNIC)RTMemAlloc(RT_OFFSETOF(DARWINETHERNIC, szName[cchName + 1]));
1620 if (pNew)
1621 {
1622 strncpy(pNew->szBSDName, szBSDName, sizeof(pNew->szBSDName)); /* the '\0' padding is intentional! */
1623
1624 RTUuidClear(&pNew->Uuid);
1625 memcpy(&pNew->Uuid, pNew->szBSDName, RT_MIN(sizeof(pNew->szBSDName), sizeof(pNew->Uuid)));
1626 pNew->Uuid.Gen.u8ClockSeqHiAndReserved = (pNew->Uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
1627 pNew->Uuid.Gen.u16TimeHiAndVersion = (pNew->Uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
1628 pNew->Uuid.Gen.au8Node[0] = Mac.au8[0];
1629 pNew->Uuid.Gen.au8Node[1] = Mac.au8[1];
1630 pNew->Uuid.Gen.au8Node[2] = Mac.au8[2];
1631 pNew->Uuid.Gen.au8Node[3] = Mac.au8[3];
1632 pNew->Uuid.Gen.au8Node[4] = Mac.au8[4];
1633 pNew->Uuid.Gen.au8Node[5] = Mac.au8[5];
1634
1635 pNew->Mac = Mac;
1636 pNew->fWireless = fWireless;
1637 pNew->fAirPort = fAirPort;
1638 pNew->fBuiltin = fBuiltin;
1639 pNew->fUSB = fUSB;
1640 pNew->fPrimaryIf = fPrimaryIf;
1641 memcpy(pNew->szName, szTmp, cchName + 1);
1642
1643 /*
1644 * Link it into the list, keep the list sorted by fPrimaryIf and the BSD name.
1645 */
1646 if (pTail)
1647 {
1648 PDARWINETHERNIC pPrev = pTail;
1649 if (strcmp(pNew->szBSDName, pPrev->szBSDName) < 0)
1650 {
1651 pPrev = NULL;
1652 for (PDARWINETHERNIC pCur = pHead; pCur; pPrev = pCur, pCur = pCur->pNext)
1653 if ( (int)pNew->fPrimaryIf - (int)pCur->fPrimaryIf > 0
1654 || ( (int)pNew->fPrimaryIf - (int)pCur->fPrimaryIf == 0
1655 && strcmp(pNew->szBSDName, pCur->szBSDName) >= 0))
1656 break;
1657 }
1658 if (pPrev)
1659 {
1660 /* tail or in list. */
1661 pNew->pNext = pPrev->pNext;
1662 pPrev->pNext = pNew;
1663 if (pPrev == pTail)
1664 pTail = pNew;
1665 }
1666 else
1667 {
1668 /* head */
1669 pNew->pNext = pHead;
1670 pHead = pNew;
1671 }
1672 }
1673 else
1674 {
1675 /* empty list */
1676 pNew->pNext = NULL;
1677 pTail = pHead = pNew;
1678 }
1679 }
1680 } while (0);
1681
1682 CFRelease(IfPropsRef);
1683 }
1684 CFRelease(PropsRef);
1685 }
1686 IOObjectRelease(EtherNICService);
1687 }
1688 else
1689 AssertMsgFailed(("krc=%#x\n", krc));
1690 IOObjectRelease(EtherIfService);
1691 }
1692
1693 IOObjectRelease(EtherIfServices);
1694 if (ServicesRef)
1695 CFRelease(ServicesRef);
1696 if (IfsRef)
1697 CFRelease(IfsRef);
1698 return pHead;
1699}
1700
1701#ifdef STANDALONE_TESTCASE
1702/**
1703 * This file can optionally be compiled into a testcase, this is the main function.
1704 * To build:
1705 * g++ -I ../../../../include -D IN_RING3 iokit.cpp ../../../../out/darwin.x86/debug/lib/RuntimeR3.a ../../../../out/darwin.x86/debug/lib/SUPR3.a ../../../../out/darwin.x86/debug/lib/RuntimeR3.a ../../../../out/darwin.x86/debug/lib/VBox-kStuff.a ../../../../out/darwin.x86/debug/lib/RuntimeR3.a -framework CoreFoundation -framework IOKit -framework SystemConfiguration -liconv -D STANDALONE_TESTCASE -o iokit -g && ./iokit
1706 */
1707int main(int argc, char **argv)
1708{
1709 RTR3InitExe(argc, &argv, 0);
1710
1711 if (1)
1712 {
1713 /*
1714 * Network preferences.
1715 */
1716 RTPrintf("Preferences: Network Services\n");
1717 SCPreferencesRef PrefsRef = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("org.virtualbox.VBoxSVC"), NULL);
1718 if (PrefsRef)
1719 {
1720 CFDictionaryRef NetworkServiceRef = (CFDictionaryRef)SCPreferencesGetValue(PrefsRef, kSCPrefNetworkServices);
1721 darwinDumpDict(NetworkServiceRef, 4);
1722 CFRelease(PrefsRef);
1723 }
1724 }
1725
1726 if (1)
1727 {
1728 /*
1729 * Network services interfaces in the current config.
1730 */
1731 RTPrintf("Preferences: Network Service Interfaces\n");
1732 SCPreferencesRef PrefsRef = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("org.virtualbox.VBoxSVC"), NULL);
1733 if (PrefsRef)
1734 {
1735 SCNetworkSetRef SetRef = SCNetworkSetCopyCurrent(PrefsRef);
1736 if (SetRef)
1737 {
1738 CFArrayRef ServicesRef = SCNetworkSetCopyServices(SetRef);
1739 CFIndex cServices = CFArrayGetCount(ServicesRef);
1740 for (CFIndex i = 0; i < cServices; i++)
1741 {
1742 SCNetworkServiceRef ServiceRef = (SCNetworkServiceRef)CFArrayGetValueAtIndex(ServicesRef, i);
1743 char szServiceName[128] = {0};
1744 CFStringGetCString(SCNetworkServiceGetName(ServiceRef), szServiceName, sizeof(szServiceName), kCFStringEncodingUTF8);
1745
1746 SCNetworkInterfaceRef IfRef = SCNetworkServiceGetInterface(ServiceRef);
1747 char szBSDName[16] = {0};
1748 if (SCNetworkInterfaceGetBSDName(IfRef))
1749 CFStringGetCString(SCNetworkInterfaceGetBSDName(IfRef), szBSDName, sizeof(szBSDName), kCFStringEncodingUTF8);
1750 char szDisplayName[128] = {0};
1751 if (SCNetworkInterfaceGetLocalizedDisplayName(IfRef))
1752 CFStringGetCString(SCNetworkInterfaceGetLocalizedDisplayName(IfRef), szDisplayName, sizeof(szDisplayName), kCFStringEncodingUTF8);
1753
1754 RTPrintf(" #%u ServiceName=\"%s\" IfBSDName=\"%s\" IfDisplayName=\"%s\"\n",
1755 i, szServiceName, szBSDName, szDisplayName);
1756 }
1757
1758 CFRelease(ServicesRef);
1759 CFRelease(SetRef);
1760 }
1761
1762 CFRelease(PrefsRef);
1763 }
1764 }
1765
1766 if (1)
1767 {
1768 /*
1769 * Network interfaces.
1770 */
1771 RTPrintf("Preferences: Network Interfaces\n");
1772 CFArrayRef IfsRef = SCNetworkInterfaceCopyAll();
1773 if (IfsRef)
1774 {
1775 CFIndex cIfs = CFArrayGetCount(IfsRef);
1776 for (CFIndex i = 0; i < cIfs; i++)
1777 {
1778 SCNetworkInterfaceRef IfRef = (SCNetworkInterfaceRef)CFArrayGetValueAtIndex(IfsRef, i);
1779 char szBSDName[16] = {0};
1780 if (SCNetworkInterfaceGetBSDName(IfRef))
1781 CFStringGetCString(SCNetworkInterfaceGetBSDName(IfRef), szBSDName, sizeof(szBSDName), kCFStringEncodingUTF8);
1782 char szDisplayName[128] = {0};
1783 if (SCNetworkInterfaceGetLocalizedDisplayName(IfRef))
1784 CFStringGetCString(SCNetworkInterfaceGetLocalizedDisplayName(IfRef), szDisplayName, sizeof(szDisplayName), kCFStringEncodingUTF8);
1785 RTPrintf(" #%u BSDName=\"%s\" DisplayName=\"%s\"\n",
1786 i, szBSDName, szDisplayName);
1787 }
1788
1789 CFRelease(IfsRef);
1790 }
1791 }
1792
1793 if (1)
1794 {
1795 /*
1796 * Get and display the ethernet controllers.
1797 */
1798 RTPrintf("Ethernet controllers:\n");
1799 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
1800 for (PDARWINETHERNIC pCur = pEtherNICs; pCur; pCur = pCur->pNext)
1801 {
1802 RTPrintf("%s\n", pCur->szName);
1803 RTPrintf(" szBSDName=%s\n", pCur->szBSDName);
1804 RTPrintf(" UUID=%RTuuid\n", &pCur->Uuid);
1805 RTPrintf(" Mac=%.6Rhxs\n", &pCur->Mac);
1806 RTPrintf(" fWireless=%RTbool\n", pCur->fWireless);
1807 RTPrintf(" fAirPort=%RTbool\n", pCur->fAirPort);
1808 RTPrintf(" fBuiltin=%RTbool\n", pCur->fBuiltin);
1809 RTPrintf(" fUSB=%RTbool\n", pCur->fUSB);
1810 RTPrintf(" fPrimaryIf=%RTbool\n", pCur->fPrimaryIf);
1811 }
1812 }
1813
1814
1815 return 0;
1816}
1817#endif
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