VirtualBox

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

Last change on this file since 48955 was 48955, checked in by vboxsync, 11 years ago

Main: Whitespace (including tabs!) and svn:keywords cleanups by scm.

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