VirtualBox

source: vbox/trunk/src/VBox/Main/darwin/iokit.cpp@ 16560

Last change on this file since 16560 was 16401, checked in by vboxsync, 15 years ago

iokit.cpp: antoher scsi-commands.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use