]>
Commit | Line | Data |
---|---|---|
dbf6a266 | 1 | /* |
78403150 | 2 | * Copyright (c) 2001-2014 Apple Inc. All rights reserved. |
dbf6a266 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
78403150 | 5 | * |
dbf6a266 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
78403150 | 12 | * |
dbf6a266 A |
13 | * The Original Code and all software distributed under the License are |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
78403150 | 20 | * |
dbf6a266 A |
21 | * @APPLE_LICENSE_HEADER_END@ |
22 | */ | |
23 | ||
24 | /* | |
25 | * Modification History | |
26 | * | |
af243a0d A |
27 | * May 20, 2006 Joe Liu <joe.liu@apple.com> |
28 | * Allan Nathanson <ajn@apple.com> | |
29 | * - register interface by entryID (and not path) | |
30 | * | |
edebe297 A |
31 | * November 6, 2006 Allan Nathanson <ajn@apple.com> |
32 | * Dan Markarian <markarian@apple.com> | |
33 | * Dieter Siegmund <dieter@apple.com> | |
34 | * - updated code to name interfaces quicker (without need for | |
35 | * calling IOKitWaitQuiet). | |
36 | * | |
dbf6a266 A |
37 | * October 3, 2003 Allan Nathanson <ajn@apple.com> |
38 | * - sort new interfaces by IOKit path (rather than MAC address) to | |
39 | * help facilitate a more predictable interface-->name mapping for | |
40 | * like hardware configurations. | |
41 | * | |
42 | * June 23, 2001 Allan Nathanson <ajn@apple.com> | |
43 | * - update to public SystemConfiguration.framework APIs | |
44 | * | |
45 | * January 23, 2001 Dieter Siegmund <dieter@apple.com> | |
46 | * - initial revision | |
47 | */ | |
48 | ||
49 | /* | |
50 | * ifnamer.c | |
51 | * - module that receives IOKit Network Interface messages | |
52 | * and names any interface that currently does not have a name | |
53 | * - uses Interface Type and MACAddress as the unique identifying | |
54 | * keys; any interface that doesn't contain both of these properties | |
55 | * is ignored and not processed | |
56 | * - stores the Interface Type, MACAddress, and Unit in permanent storage | |
57 | * to give persistent interface names | |
58 | */ | |
59 | ||
60 | #include <ctype.h> | |
61 | #include <stdlib.h> | |
62 | #include <stdio.h> | |
63 | #include <unistd.h> | |
64 | #include <fcntl.h> | |
d0784775 | 65 | #include <sys/ioctl.h> |
dbf6a266 | 66 | #include <sys/stat.h> |
6bb65964 | 67 | #include <sys/sysctl.h> |
dbf6a266 A |
68 | #include <sys/param.h> |
69 | #include <mach/mach.h> | |
edebe297 | 70 | #include <net/ethernet.h> |
dbf6a266 | 71 | #include <net/if_types.h> |
17d3ee29 A |
72 | #include <pthread.h> |
73 | #include <vproc.h> | |
74 | ||
75 | #include <CommonCrypto/CommonDigest.h> | |
dbf6a266 A |
76 | |
77 | #include <CoreFoundation/CoreFoundation.h> | |
78 | ||
79 | #include <SystemConfiguration/SystemConfiguration.h> | |
80 | #include <SystemConfiguration/SCDPlugin.h> | |
81 | #include <SystemConfiguration/SCPrivate.h> // for SCLog(), SCPrint() | |
82 | #include <SystemConfiguration/SCValidation.h> | |
83 | ||
dbf6a266 | 84 | #include <IOKit/IOKitLib.h> |
d0784775 | 85 | #include <IOKit/IOKitLibPrivate.h> |
dbf6a266 | 86 | #include <IOKit/IOBSD.h> |
edebe297 | 87 | #include <IOKit/IOMessage.h> |
dbf6a266 A |
88 | #include <IOKit/network/IONetworkController.h> |
89 | #include <IOKit/network/IONetworkInterface.h> | |
af243a0d | 90 | #include <IOKit/network/IONetworkStack.h> |
d0784775 | 91 | #include <IOKit/usb/USB.h> |
dbf6a266 | 92 | |
af243a0d A |
93 | #ifdef kIONetworkStackUserCommandKey |
94 | #define USE_REGISTRY_ENTRY_ID | |
95 | #endif | |
96 | ||
97 | #ifndef USE_REGISTRY_ENTRY_ID | |
6bb65964 | 98 | // from <IOKit/network/IONetworkStack.h> |
af243a0d | 99 | #define kIONetworkStackUserCommandKey "IONetworkStackUserCommand" |
6bb65964 A |
100 | enum { |
101 | kRegisterInterfaceWithFixedUnit = 0, | |
102 | kRegisterInterface, | |
103 | kRegisterAllInterfaces | |
104 | }; | |
af243a0d | 105 | #endif // !USE_REGISTRY_ENTRY_ID |
edebe297 | 106 | |
d0784775 | 107 | #define kSCNetworkInterfaceInfo "SCNetworkInterfaceInfo" |
edebe297 A |
108 | #define kSCNetworkInterfaceType "SCNetworkInterfaceType" |
109 | #define kSCNetworkInterfaceActive "Active" | |
dbf6a266 A |
110 | |
111 | #define MY_PLUGIN_NAME "InterfaceNamer" | |
edebe297 | 112 | #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME) |
dbf6a266 | 113 | |
6bb65964 A |
114 | #define WAIT_STACK_TIMEOUT_KEY "WaitStackTimeout" |
115 | #define WAIT_STACK_TIMEOUT_DEFAULT 300.0 | |
116 | ||
edebe297 A |
117 | #define WAIT_QUIET_TIMEOUT_KEY "WaitQuietTimeout" |
118 | #define WAIT_QUIET_TIMEOUT_DEFAULT 60.0 | |
dbf6a266 | 119 | |
edebe297 A |
120 | /* |
121 | * S_connect | |
122 | * "IONetworkStack" connect object used to "name" an interface. | |
123 | */ | |
124 | static io_connect_t S_connect = MACH_PORT_NULL; | |
dbf6a266 | 125 | |
edebe297 A |
126 | /* |
127 | * S_dblist | |
128 | * An array of CFDictionary's representing the interfaces | |
129 | * that have been identified and [need to be] named. | |
130 | */ | |
131 | static CFMutableArrayRef S_dblist = NULL; | |
dbf6a266 | 132 | |
edebe297 A |
133 | /* |
134 | * S_debug | |
135 | * A boolean that enables additional logging. | |
136 | */ | |
137 | static boolean_t S_debug = FALSE; | |
138 | ||
139 | /* | |
140 | * S_iflist | |
141 | * An array of SCNetworkInterface's representing the | |
142 | * interfaces that have been identified. | |
143 | */ | |
144 | static CFMutableArrayRef S_iflist = NULL; | |
145 | ||
146 | /* | |
147 | * S_iter | |
148 | * IOServiceAddMatchingNotification object used to watch for | |
149 | * new network interfaces. | |
150 | */ | |
151 | static io_iterator_t S_iter = MACH_PORT_NULL; | |
152 | ||
153 | /* | |
154 | * S_notify | |
155 | * notification object for receiving IOKit notifications of | |
156 | * new devices or state changes. | |
157 | */ | |
158 | static IONotificationPortRef S_notify = NULL; | |
159 | ||
160 | /* S_prev_active_list | |
161 | * An array of CFDictionary's representing the previously | |
162 | * named interfaces. | |
163 | */ | |
164 | static CFMutableArrayRef S_prev_active_list = NULL; | |
165 | ||
166 | /* | |
167 | * S_quiet | |
168 | * IOServiceAddInterestNotification object used to watch for | |
169 | * IOKit matching to quiesce. | |
170 | */ | |
171 | static io_object_t S_quiet = MACH_PORT_NULL; | |
172 | ||
173 | /* | |
174 | * S_stack | |
175 | * IOServiceAddMatchingNotification object used to watch for | |
176 | * the availability of the "IONetworkStack" object. | |
177 | */ | |
178 | static io_iterator_t S_stack = MACH_PORT_NULL; | |
dbf6a266 | 179 | |
edebe297 A |
180 | /* |
181 | * S_state | |
182 | * A dictionary containing Information about each network | |
183 | * interface. For now, the key is the BSD name and the | |
184 | * value is a CFNumber noting how long (in milliseconds) | |
185 | * it took for the interface to be recognized/named. | |
186 | */ | |
187 | static CFMutableDictionaryRef S_state = NULL; | |
188 | ||
189 | /* | |
190 | * S_timer | |
191 | * CFRunLoopTimer tracking how long we are willing to wait | |
192 | * for IOKit matching to quiesce (IOKitWaitQuiet). | |
6bb65964 A |
193 | * |
194 | * S_stack_timeout | |
195 | * time to wait for the IONetworkStack object to appear before timeout | |
196 | * | |
197 | * S_quiet_timeout | |
198 | * time to wait for the IOKit to quiesce (after the IONetworkStack is | |
199 | * has appeared. | |
edebe297 A |
200 | */ |
201 | static CFRunLoopTimerRef S_timer = NULL; | |
6bb65964 A |
202 | static double S_stack_timeout = WAIT_STACK_TIMEOUT_DEFAULT; |
203 | static double S_quiet_timeout = WAIT_QUIET_TIMEOUT_DEFAULT; | |
204 | ||
17d3ee29 A |
205 | #if !TARGET_OS_EMBEDDED |
206 | /* | |
207 | * S_vproc_transaction | |
208 | * The vproc transaction used to keep launchd from sending us | |
209 | * a SIGKILL before we've had a chance to set the platform UUID | |
210 | */ | |
211 | vproc_transaction_t S_vproc_transaction = NULL; | |
212 | #endif // !TARGET_OS_EMBEDDED | |
edebe297 A |
213 | |
214 | /* | |
215 | * Virtual network interface configuration | |
6bb65964 A |
216 | * S_prefs : SCPreferences to configuration |
217 | * S_bonds : most recently actived Bond configuration | |
218 | * S_bridges : most recently actived Bridge configuration | |
219 | * S_vlans : most recently actived VLAN configuration | |
edebe297 A |
220 | */ |
221 | static SCPreferencesRef S_prefs = NULL; | |
222 | static CFArrayRef S_bonds = NULL; | |
6bb65964 | 223 | static CFArrayRef S_bridges = NULL; |
edebe297 A |
224 | static CFArrayRef S_vlans = NULL; |
225 | ||
226 | static void | |
227 | addTimestamp(CFMutableDictionaryRef dict, CFStringRef key) | |
dbf6a266 | 228 | { |
edebe297 A |
229 | CFAbsoluteTime now; |
230 | CFNumberRef val; | |
231 | ||
232 | now = CFAbsoluteTimeGetCurrent(); | |
233 | val = CFNumberCreate(NULL, kCFNumberDoubleType, &now); | |
234 | CFDictionaryAddValue(dict, key, val); | |
235 | CFRelease(val); | |
236 | return; | |
dbf6a266 A |
237 | } |
238 | ||
6bb65964 | 239 | #define INTERFACES CFSTR("Interfaces") |
6bb65964 A |
240 | #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist") |
241 | ||
dbf6a266 A |
242 | static CFComparisonResult |
243 | if_unit_compare(const void *val1, const void *val2, void *context) | |
244 | { | |
245 | CFComparisonResult res; | |
246 | CFNumberRef type1; | |
247 | CFNumberRef type2; | |
248 | CFNumberRef unit1; | |
249 | CFNumberRef unit2; | |
250 | ||
251 | type1 = CFDictionaryGetValue((CFDictionaryRef)val1, | |
252 | CFSTR(kIOInterfaceType)); | |
253 | type2 = CFDictionaryGetValue((CFDictionaryRef)val2, | |
254 | CFSTR(kIOInterfaceType)); | |
255 | res = CFNumberCompare(type1, type2, NULL); | |
256 | if (res != kCFCompareEqualTo) { | |
257 | return (res); | |
258 | } | |
259 | unit1 = CFDictionaryGetValue((CFDictionaryRef)val1, | |
260 | CFSTR(kIOInterfaceUnit)); | |
261 | unit2 = CFDictionaryGetValue((CFDictionaryRef)val2, | |
262 | CFSTR(kIOInterfaceUnit)); | |
263 | return (CFNumberCompare(unit1, unit2, NULL)); | |
264 | } | |
265 | ||
6bb65964 A |
266 | static void |
267 | reportIssue(const char *signature, CFStringRef issue) | |
dbf6a266 | 268 | { |
78403150 | 269 | asl_object_t m; |
dbf6a266 | 270 | |
6bb65964 A |
271 | m = asl_new(ASL_TYPE_MSG); |
272 | asl_set(m, "com.apple.message.domain", "com.apple.SystemConfiguration." MY_PLUGIN_NAME); | |
273 | asl_set(m, "com.apple.message.signature", signature); | |
274 | asl_set(m, "com.apple.message.result", "failure"); | |
275 | SCLOG(NULL, m, ~ASL_LEVEL_ERR, CFSTR("%s\n%@"), signature, issue); | |
78403150 | 276 | asl_release(m); |
dbf6a266 | 277 | |
6bb65964 | 278 | return; |
dbf6a266 A |
279 | } |
280 | ||
edebe297 A |
281 | static void |
282 | writeInterfaceList(CFArrayRef if_list) | |
283 | { | |
284 | CFArrayRef cur_list; | |
6bb65964 A |
285 | CFStringRef new_model; |
286 | CFStringRef old_model; | |
edebe297 A |
287 | SCPreferencesRef prefs; |
288 | ||
289 | if (isA_CFArray(if_list) == NULL) { | |
290 | return; | |
291 | } | |
292 | ||
293 | prefs = SCPreferencesCreate(NULL, MY_PLUGIN_ID, NETWORK_INTERFACES_PREFS); | |
294 | if (prefs == NULL) { | |
295 | SCLog(TRUE, LOG_ERR, | |
296 | CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate failed, %s"), | |
297 | SCErrorString(SCError())); | |
298 | return; | |
299 | } | |
300 | ||
301 | cur_list = SCPreferencesGetValue(prefs, INTERFACES); | |
302 | if (_SC_CFEqual(cur_list, if_list)) { | |
303 | goto done; | |
304 | } | |
305 | ||
6bb65964 | 306 | old_model = SCPreferencesGetValue(prefs, MODEL); |
78403150 | 307 | new_model = _SC_hw_model(FALSE); |
af243a0d A |
308 | if ((new_model != NULL) && !_SC_CFEqual(old_model, new_model)) { |
309 | // if new hardware | |
310 | if ((old_model != NULL) && (cur_list != NULL)) { | |
311 | CFStringRef history; | |
312 | CFStringRef issue; | |
6bb65964 | 313 | |
af243a0d A |
314 | // if interface list was created on other hardware |
315 | history = CFStringCreateWithFormat(NULL, NULL, | |
316 | CFSTR("%@:%@"), | |
317 | INTERFACES, | |
318 | old_model); | |
319 | SCPreferencesSetValue(prefs, history, cur_list); | |
320 | CFRelease(history); | |
321 | ||
322 | SCLog(TRUE, LOG_ERR, | |
323 | CFSTR(MY_PLUGIN_NAME ": Hardware model changed\n" | |
324 | MY_PLUGIN_NAME ": created on \"%@\"\n" | |
325 | MY_PLUGIN_NAME ": now on \"%@\""), | |
326 | old_model, | |
327 | new_model); | |
328 | ||
329 | issue = CFStringCreateWithFormat(NULL, NULL, | |
330 | CFSTR("%@ --> %@"), | |
331 | old_model, | |
332 | new_model); | |
333 | reportIssue("Hardware model changed", issue); | |
334 | CFRelease(issue); | |
335 | } | |
6bb65964 | 336 | |
af243a0d A |
337 | if (!SCPreferencesSetValue(prefs, MODEL, new_model)) { |
338 | SCLog(TRUE, LOG_ERR, | |
339 | CFSTR(MY_PLUGIN_NAME ": SCPreferencesSetValue failed, %s"), | |
340 | SCErrorString(SCError())); | |
341 | goto done; | |
342 | } | |
6bb65964 A |
343 | } |
344 | ||
edebe297 A |
345 | if (!SCPreferencesSetValue(prefs, INTERFACES, if_list)) { |
346 | SCLog(TRUE, LOG_ERR, | |
347 | CFSTR(MY_PLUGIN_NAME ": SCPreferencesSetValue failed, %s"), | |
348 | SCErrorString(SCError())); | |
349 | goto done; | |
350 | } | |
351 | ||
352 | if (!SCPreferencesCommitChanges(prefs)) { | |
353 | SCLog((SCError() != EROFS), LOG_ERR, | |
354 | CFSTR(MY_PLUGIN_NAME ": SCPreferencesCommitChanges failed, %s"), | |
355 | SCErrorString(SCError())); | |
356 | goto done; | |
357 | } | |
358 | ||
359 | done: | |
360 | ||
361 | CFRelease(prefs); | |
362 | return; | |
363 | } | |
364 | ||
17d3ee29 | 365 | static CF_RETURNS_RETAINED CFMutableArrayRef |
dbf6a266 A |
366 | readInterfaceList() |
367 | { | |
edebe297 | 368 | CFArrayRef if_list; |
6bb65964 A |
369 | CFStringRef old_model; |
370 | CFMutableArrayRef plist = NULL; | |
371 | SCPreferencesRef prefs = NULL; | |
dbf6a266 | 372 | |
edebe297 | 373 | prefs = SCPreferencesCreate(NULL, MY_PLUGIN_ID, NETWORK_INTERFACES_PREFS); |
dbf6a266 | 374 | if (!prefs) { |
edebe297 | 375 | SCLog(TRUE, LOG_ERR, |
dbf6a266 A |
376 | CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate failed, %s"), |
377 | SCErrorString(SCError())); | |
378 | return (NULL); | |
379 | } | |
380 | ||
edebe297 | 381 | if_list = SCPreferencesGetValue(prefs, INTERFACES); |
6bb65964 A |
382 | if_list = isA_CFArray(if_list); |
383 | ||
384 | old_model = SCPreferencesGetValue(prefs, MODEL); | |
385 | if (old_model != NULL) { | |
386 | CFStringRef new_model; | |
387 | ||
78403150 | 388 | new_model = _SC_hw_model(FALSE); |
6bb65964 A |
389 | if (!_SC_CFEqual(old_model, new_model)) { |
390 | // if interface list was created on other hardware | |
edebe297 | 391 | if_list = NULL; |
dbf6a266 | 392 | } |
dbf6a266 A |
393 | } |
394 | ||
edebe297 A |
395 | if (if_list != NULL) { |
396 | CFIndex i; | |
397 | CFIndex n = CFArrayGetCount(if_list); | |
398 | ||
399 | plist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |
400 | for (i = 0; i < n; i++) { | |
401 | CFDictionaryRef dict; | |
402 | ||
403 | dict = CFArrayGetValueAtIndex(if_list, i); | |
404 | if (isA_CFDictionary(dict) && | |
405 | CFDictionaryContainsKey(dict, CFSTR(kIOInterfaceType)) && | |
406 | CFDictionaryContainsKey(dict, CFSTR(kIOInterfaceUnit)) && | |
407 | CFDictionaryContainsKey(dict, CFSTR(kIOMACAddress))) { | |
408 | CFArrayAppendValue(plist, dict); | |
409 | } | |
410 | } | |
411 | } | |
6bb65964 A |
412 | |
413 | if (prefs != NULL) { | |
dbf6a266 A |
414 | CFRelease(prefs); |
415 | } | |
416 | return (plist); | |
417 | } | |
418 | ||
17d3ee29 | 419 | static CF_RETURNS_RETAINED CFMutableArrayRef |
edebe297 | 420 | previouslyActiveInterfaces() |
dbf6a266 | 421 | { |
edebe297 A |
422 | CFMutableArrayRef active; |
423 | CFIndex i; | |
424 | CFIndex n; | |
dbf6a266 | 425 | |
edebe297 A |
426 | if (S_dblist == NULL) { |
427 | return NULL; | |
dbf6a266 A |
428 | } |
429 | ||
edebe297 | 430 | active = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); |
dbf6a266 | 431 | |
edebe297 A |
432 | n = CFArrayGetCount(S_dblist); |
433 | for (i = 0; i < n; i++) { | |
434 | CFDictionaryRef if_dict; | |
435 | ||
436 | if_dict = CFArrayGetValueAtIndex(S_dblist, i); | |
437 | if (CFDictionaryContainsKey(if_dict, CFSTR(kSCNetworkInterfaceActive))) { | |
438 | CFMutableDictionaryRef new_dict; | |
439 | ||
440 | new_dict = CFDictionaryCreateMutableCopy(NULL, 0, if_dict); | |
441 | CFDictionaryRemoveValue(new_dict, CFSTR(kSCNetworkInterfaceActive)); | |
442 | CFArraySetValueAtIndex(S_dblist, i, new_dict); | |
443 | CFArrayAppendValue(active, new_dict); | |
444 | CFRelease(new_dict); | |
445 | } | |
dbf6a266 A |
446 | } |
447 | ||
edebe297 A |
448 | return active; |
449 | } | |
450 | ||
451 | static void | |
452 | updateStore(void) | |
453 | { | |
454 | CFStringRef key; | |
dbf6a266 | 455 | |
edebe297 A |
456 | key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@" MY_PLUGIN_NAME), |
457 | kSCDynamicStoreDomainPlugin); | |
17d3ee29 | 458 | (void)SCDynamicStoreSetValue(NULL, key, S_state); |
edebe297 | 459 | CFRelease(key); |
dbf6a266 | 460 | |
dbf6a266 A |
461 | return; |
462 | } | |
463 | ||
17d3ee29 | 464 | #if !TARGET_OS_IPHONE |
dbf6a266 | 465 | static void |
6bb65964 | 466 | updateBondInterfaceConfiguration(SCPreferencesRef prefs) |
dbf6a266 | 467 | { |
edebe297 | 468 | CFArrayRef interfaces; |
dbf6a266 | 469 | |
6bb65964 A |
470 | interfaces = SCBondInterfaceCopyAll(prefs); |
471 | if ((interfaces != NULL) && (CFArrayGetCount(interfaces) == 0)) { | |
472 | CFRelease(interfaces); | |
473 | interfaces = NULL; | |
474 | } | |
475 | ||
476 | if (_SC_CFEqual(S_bonds, interfaces)) { | |
477 | // if no change | |
478 | if (interfaces != NULL) CFRelease(interfaces); | |
dbf6a266 A |
479 | return; |
480 | } | |
481 | ||
6bb65964 A |
482 | if (S_bonds != NULL) CFRelease(S_bonds); |
483 | S_bonds = interfaces; | |
484 | ||
485 | if (!_SCBondInterfaceUpdateConfiguration(prefs)) { | |
486 | SCLog(TRUE, LOG_ERR, | |
487 | CFSTR(MY_PLUGIN_NAME ": _SCBondInterfaceUpdateConfiguration failed, %s"), | |
488 | SCErrorString(SCError())); | |
edebe297 A |
489 | } |
490 | ||
6bb65964 A |
491 | return; |
492 | } | |
17d3ee29 | 493 | #endif // !TARGET_OS_IPHONE |
edebe297 | 494 | |
6bb65964 A |
495 | static void |
496 | updateBridgeInterfaceConfiguration(SCPreferencesRef prefs) | |
497 | { | |
498 | CFArrayRef interfaces; | |
499 | ||
500 | interfaces = SCBridgeInterfaceCopyAll(prefs); | |
501 | if ((interfaces != NULL) && (CFArrayGetCount(interfaces) == 0)) { | |
502 | CFRelease(interfaces); | |
503 | interfaces = NULL; | |
edebe297 | 504 | } |
6bb65964 A |
505 | |
506 | if (_SC_CFEqual(S_bridges, interfaces)) { | |
edebe297 | 507 | // if no change |
6bb65964 A |
508 | if (interfaces != NULL) CFRelease(interfaces); |
509 | return; | |
edebe297 | 510 | } |
edebe297 | 511 | |
6bb65964 A |
512 | if (S_bridges != NULL) CFRelease(S_bridges); |
513 | S_bridges = interfaces; | |
514 | ||
515 | if (!_SCBridgeInterfaceUpdateConfiguration(prefs)) { | |
edebe297 | 516 | SCLog(TRUE, LOG_ERR, |
6bb65964 | 517 | CFSTR(MY_PLUGIN_NAME ": _SCBridgeInterfaceUpdateConfiguration failed, %s"), |
dbf6a266 | 518 | SCErrorString(SCError())); |
edebe297 A |
519 | } |
520 | ||
6bb65964 A |
521 | return; |
522 | } | |
edebe297 | 523 | |
6bb65964 A |
524 | static void |
525 | updateVLANInterfaceConfiguration(SCPreferencesRef prefs) | |
526 | { | |
527 | CFArrayRef interfaces; | |
edebe297 A |
528 | |
529 | interfaces = SCVLANInterfaceCopyAll(prefs); | |
6bb65964 A |
530 | if ((interfaces != NULL) && (CFArrayGetCount(interfaces) == 0)) { |
531 | CFRelease(interfaces); | |
532 | interfaces = NULL; | |
dbf6a266 | 533 | } |
6bb65964 A |
534 | |
535 | if (_SC_CFEqual(S_vlans, interfaces)) { | |
edebe297 | 536 | // if no change |
6bb65964 A |
537 | if (interfaces != NULL) CFRelease(interfaces); |
538 | return; | |
edebe297 | 539 | } |
6bb65964 | 540 | |
edebe297 A |
541 | if (S_vlans != NULL) CFRelease(S_vlans); |
542 | S_vlans = interfaces; | |
dbf6a266 | 543 | |
edebe297 A |
544 | if (!_SCVLANInterfaceUpdateConfiguration(prefs)) { |
545 | SCLog(TRUE, LOG_ERR, | |
546 | CFSTR(MY_PLUGIN_NAME ": _SCVLANInterfaceUpdateConfiguration failed, %s"), | |
547 | SCErrorString(SCError())); | |
548 | } | |
dbf6a266 | 549 | |
6bb65964 A |
550 | return; |
551 | } | |
edebe297 | 552 | |
6bb65964 A |
553 | static void |
554 | updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs, | |
555 | SCPreferencesNotification notificationType, | |
556 | void *info) | |
557 | { | |
558 | if ((notificationType & kSCPreferencesNotificationApply) != kSCPreferencesNotificationApply) { | |
559 | return; | |
560 | } | |
edebe297 | 561 | |
6bb65964 A |
562 | if (prefs == NULL) { |
563 | // if a new interface has been "named" | |
564 | prefs = S_prefs; | |
565 | if (S_bonds != NULL) { | |
566 | CFRelease(S_bonds); | |
567 | S_bonds = NULL; | |
568 | } | |
569 | if (S_bridges != NULL) { | |
570 | CFRelease(S_bridges); | |
571 | S_bridges = NULL; | |
572 | } | |
573 | if (S_vlans != NULL) { | |
574 | CFRelease(S_vlans); | |
575 | S_vlans = NULL; | |
576 | } | |
577 | } | |
578 | ||
17d3ee29 | 579 | #if !TARGET_OS_IPHONE |
6bb65964 | 580 | updateBondInterfaceConfiguration (prefs); |
17d3ee29 | 581 | #endif // !TARGET_OS_IPHONE |
6bb65964 A |
582 | updateBridgeInterfaceConfiguration(prefs); |
583 | updateVLANInterfaceConfiguration (prefs); | |
584 | ||
585 | // we are finished with current prefs, wait for changes | |
edebe297 | 586 | SCPreferencesSynchronize(prefs); |
dbf6a266 A |
587 | return; |
588 | } | |
589 | ||
5e9ce69e A |
590 | #if !TARGET_OS_EMBEDDED |
591 | ||
78403150 A |
592 | #define BT_PAN_NAME "Bluetooth PAN" |
593 | #define BT_PAN_MAC BT_PAN_NAME " (MAC)" | |
5e9ce69e A |
594 | |
595 | static void | |
596 | updateBTPANInformation(const void *value, void *context) | |
78403150 A |
597 | { |
598 | CFDataRef addr; | |
599 | CFDictionaryRef dict = (CFDictionaryRef)value; | |
600 | CFStringRef if_name; | |
601 | CFDictionaryRef info; | |
602 | CFStringRef name; | |
5e9ce69e A |
603 | |
604 | if_name = CFDictionaryGetValue(dict, CFSTR(kIOBSDNameKey)); | |
605 | if (!isA_CFString(if_name)) { | |
606 | // if no BSD name | |
607 | return; | |
608 | } | |
609 | ||
610 | info = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceInfo)); | |
611 | if (!isA_CFDictionary(info)) { | |
612 | // if no SCNetworkInterface info | |
613 | return; | |
614 | } | |
615 | ||
616 | name = CFDictionaryGetValue(info, kSCPropUserDefinedName); | |
617 | if (!isA_CFString(name) || !CFEqual(name, CFSTR(BT_PAN_NAME))) { | |
618 | // if not BT-PAN interface | |
619 | return; | |
620 | } | |
621 | ||
622 | CFDictionaryAddValue(S_state, CFSTR("_" BT_PAN_NAME "_"), if_name); | |
78403150 A |
623 | |
624 | addr = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress)); | |
625 | if (isA_CFData(addr)) { | |
626 | CFDictionaryAddValue(S_state, CFSTR("_" BT_PAN_MAC "_"), addr); | |
627 | } | |
628 | ||
5e9ce69e A |
629 | return; |
630 | } | |
631 | #endif // !TARGET_OS_EMBEDDED | |
632 | ||
edebe297 A |
633 | static CFDictionaryRef |
634 | createInterfaceDict(SCNetworkInterfaceRef interface) | |
dbf6a266 | 635 | { |
edebe297 A |
636 | CFMutableDictionaryRef new_if; |
637 | CFTypeRef val; | |
dbf6a266 | 638 | |
edebe297 A |
639 | new_if = CFDictionaryCreateMutable(NULL, |
640 | 0, | |
641 | &kCFTypeDictionaryKeyCallBacks, | |
642 | &kCFTypeDictionaryValueCallBacks); | |
643 | ||
d0784775 A |
644 | val = _SCNetworkInterfaceCopyInterfaceInfo(interface); |
645 | if (val != NULL) { | |
646 | CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceInfo), val); | |
647 | CFRelease(val); | |
648 | } | |
649 | ||
edebe297 A |
650 | val = _SCNetworkInterfaceGetIOPath(interface); |
651 | if (val != NULL) { | |
652 | CFDictionarySetValue(new_if, CFSTR(kIOPathMatchKey), val); | |
dbf6a266 A |
653 | } |
654 | ||
5e9ce69e A |
655 | val = _SCNetworkInterfaceGetIOInterfaceNamePrefix(interface); |
656 | if (val != NULL) { | |
657 | CFDictionarySetValue(new_if, CFSTR(kIOInterfaceNamePrefix), val); | |
658 | } | |
659 | ||
edebe297 A |
660 | val = _SCNetworkInterfaceGetIOInterfaceType(interface); |
661 | if (val != NULL) { | |
662 | CFDictionarySetValue(new_if, CFSTR(kIOInterfaceType), val); | |
dbf6a266 A |
663 | } |
664 | ||
edebe297 A |
665 | val = _SCNetworkInterfaceGetIOInterfaceUnit(interface); |
666 | if (val != NULL) { | |
667 | CFDictionarySetValue(new_if, CFSTR(kIOInterfaceUnit), val); | |
668 | } | |
dbf6a266 | 669 | |
edebe297 A |
670 | val = _SCNetworkInterfaceGetHardwareAddress(interface); |
671 | if (val != NULL) { | |
672 | CFDictionarySetValue(new_if, CFSTR(kIOMACAddress), val); | |
673 | } | |
674 | ||
675 | val = SCNetworkInterfaceGetBSDName(interface); | |
676 | if (val != NULL) { | |
677 | CFDictionarySetValue(new_if, CFSTR(kIOBSDNameKey), val); | |
678 | } | |
679 | ||
680 | val = SCNetworkInterfaceGetInterfaceType(interface); | |
681 | if (val != NULL) { | |
682 | CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceType), val); | |
683 | } | |
dbf6a266 | 684 | |
edebe297 A |
685 | CFDictionarySetValue(new_if, |
686 | CFSTR(kIOBuiltin), | |
687 | _SCNetworkInterfaceIsBuiltin(interface) ? kCFBooleanTrue : kCFBooleanFalse); | |
688 | ||
689 | CFDictionarySetValue(new_if, CFSTR(kSCNetworkInterfaceActive), kCFBooleanTrue); | |
690 | ||
691 | return new_if; | |
692 | } | |
dbf6a266 A |
693 | |
694 | static CFDictionaryRef | |
edebe297 | 695 | lookupInterfaceByAddress(CFArrayRef db_list, SCNetworkInterfaceRef interface, CFIndex * where) |
dbf6a266 A |
696 | { |
697 | CFDataRef addr; | |
698 | CFIndex i; | |
699 | CFIndex n; | |
700 | CFNumberRef type; | |
701 | ||
edebe297 | 702 | if (db_list == NULL) { |
dbf6a266 A |
703 | return (NULL); |
704 | } | |
edebe297 A |
705 | type = _SCNetworkInterfaceGetIOInterfaceType(interface); |
706 | addr = _SCNetworkInterfaceGetHardwareAddress(interface); | |
dbf6a266 A |
707 | if (type == NULL || addr == NULL) { |
708 | return (NULL); | |
709 | } | |
710 | ||
edebe297 | 711 | n = CFArrayGetCount(db_list); |
dbf6a266 | 712 | for (i = 0; i < n; i++) { |
dbf6a266 | 713 | CFDataRef a; |
edebe297 | 714 | CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i); |
dbf6a266 A |
715 | CFNumberRef t; |
716 | ||
dbf6a266 | 717 | t = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType)); |
edebe297 A |
718 | a = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress)); |
719 | if (t == NULL || a == NULL) | |
dbf6a266 A |
720 | continue; |
721 | ||
edebe297 | 722 | if (CFEqual(type, t) && CFEqual(addr, a)) { |
dbf6a266 A |
723 | if (where) { |
724 | *where = i; | |
725 | } | |
726 | return (dict); | |
727 | } | |
728 | } | |
729 | return (NULL); | |
730 | } | |
731 | ||
732 | static CFDictionaryRef | |
edebe297 | 733 | lookupInterfaceByUnit(CFArrayRef db_list, SCNetworkInterfaceRef interface, CFIndex * where) |
dbf6a266 A |
734 | { |
735 | CFIndex i; | |
736 | CFIndex n; | |
737 | CFNumberRef type; | |
738 | CFNumberRef unit; | |
739 | ||
edebe297 | 740 | if (db_list == NULL) { |
dbf6a266 A |
741 | return (NULL); |
742 | } | |
edebe297 A |
743 | type = _SCNetworkInterfaceGetIOInterfaceType(interface); |
744 | unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface); | |
dbf6a266 A |
745 | if (type == NULL || unit == NULL) { |
746 | return (NULL); | |
747 | } | |
748 | ||
edebe297 | 749 | n = CFArrayGetCount(db_list); |
dbf6a266 | 750 | for (i = 0; i < n; i++) { |
edebe297 | 751 | CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i); |
dbf6a266 A |
752 | CFNumberRef t; |
753 | CFNumberRef u; | |
754 | ||
755 | t = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType)); | |
756 | u = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit)); | |
757 | if (t == NULL || u == NULL) { | |
758 | continue; | |
759 | } | |
760 | ||
edebe297 | 761 | if (CFEqual(type, t) && CFEqual(unit, u)) { |
dbf6a266 A |
762 | if (where) |
763 | *where = i; | |
764 | return (dict); | |
765 | } | |
766 | } | |
767 | return (NULL); | |
768 | } | |
769 | ||
d0784775 A |
770 | typedef struct { |
771 | CFDictionaryRef match_info; | |
772 | CFStringRef match_type; | |
773 | CFBooleanRef match_builtin; | |
774 | CFMutableArrayRef matches; | |
775 | } matchContext, *matchContextRef; | |
776 | ||
17d3ee29 | 777 | static CF_RETURNS_RETAINED CFDictionaryRef |
d0784775 | 778 | thinInterfaceInfo(CFDictionaryRef info) |
dbf6a266 | 779 | { |
d0784775 A |
780 | CFNumberRef num; |
781 | int vid; | |
782 | ||
783 | if (CFDictionaryGetValueIfPresent(info, CFSTR(kUSBVendorID), (const void **)&num) | |
784 | && isA_CFNumber(num) | |
785 | && CFNumberGetValue(num, kCFNumberIntType, &vid) | |
786 | && (vid == kIOUSBVendorIDAppleComputer)) { | |
787 | CFMutableDictionaryRef thin; | |
788 | ||
789 | // if this is an Apple USB device than we trust that | |
790 | // the non-localized name will be correct. | |
791 | thin = CFDictionaryCreateMutableCopy(NULL, 0, info); | |
792 | CFDictionaryRemoveValue(thin, CFSTR(kUSBProductString)); | |
793 | CFDictionaryRemoveValue(thin, CFSTR(kUSBVendorID)); | |
794 | CFDictionaryRemoveValue(thin, CFSTR(kUSBProductID)); | |
795 | return thin; | |
796 | } | |
dbf6a266 | 797 | |
d0784775 A |
798 | return CFRetain(info); |
799 | } | |
800 | ||
801 | static Boolean | |
802 | matchInterfaceInfo(CFDictionaryRef known_info, CFDictionaryRef match_info) | |
803 | { | |
804 | Boolean match; | |
805 | ||
806 | match = _SC_CFEqual(known_info, match_info); | |
807 | if (!match && | |
808 | isA_CFDictionary(known_info) && | |
809 | isA_CFDictionary(match_info)) { | |
810 | ||
811 | // if not an exact match, try thinning | |
812 | known_info = thinInterfaceInfo(known_info); | |
813 | match_info = thinInterfaceInfo(match_info); | |
814 | match = _SC_CFEqual(known_info, match_info); | |
5e9ce69e A |
815 | if (known_info != NULL) CFRelease(known_info); |
816 | if (match_info != NULL) CFRelease(match_info); | |
dbf6a266 | 817 | } |
d0784775 A |
818 | |
819 | return match; | |
820 | } | |
821 | ||
822 | static void | |
823 | matchKnown(const void *value, void *context) | |
824 | { | |
825 | CFDictionaryRef known_dict = (CFDictionaryRef)value; | |
826 | matchContextRef match_context = (matchContextRef)context; | |
827 | ||
828 | // match interface type | |
829 | { | |
830 | CFStringRef known_type; | |
831 | ||
832 | known_type = CFDictionaryGetValue(known_dict, CFSTR(kSCNetworkInterfaceType)); | |
833 | if (!_SC_CFEqual(known_type, match_context->match_type)) { | |
834 | return; | |
835 | } | |
836 | } | |
837 | ||
838 | // match SCNetworkInterfaceInfo | |
839 | { | |
840 | CFDictionaryRef known_info; | |
841 | ||
842 | known_info = CFDictionaryGetValue(known_dict, CFSTR(kSCNetworkInterfaceInfo)); | |
843 | if (!matchInterfaceInfo(known_info, match_context->match_info)) { | |
844 | return; | |
845 | } | |
846 | } | |
847 | ||
848 | // if requested, match [non-]builtin | |
849 | if (match_context->match_builtin != NULL) { | |
850 | CFBooleanRef known_builtin; | |
851 | ||
852 | known_builtin = CFDictionaryGetValue(known_dict, CFSTR(kIOBuiltin)); | |
853 | if (!isA_CFBoolean(known_builtin)) { | |
854 | known_builtin = kCFBooleanFalse; | |
855 | } | |
856 | if (!_SC_CFEqual(known_builtin, match_context->match_builtin)) { | |
857 | return; | |
858 | } | |
859 | } | |
860 | ||
861 | // if we have a match | |
862 | if (match_context->matches == NULL) { | |
863 | match_context->matches = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |
864 | } | |
865 | CFArrayAppendValue(match_context->matches, known_dict); | |
866 | ||
867 | return; | |
868 | } | |
869 | ||
870 | static void | |
871 | matchUnnamed(const void *value, void *context) | |
872 | { | |
873 | SCNetworkInterfaceRef known_if = (SCNetworkInterfaceRef)value; | |
874 | matchContextRef match_context = (matchContextRef)context; | |
875 | ||
876 | if (match_context->matches == NULL) { | |
877 | return; | |
878 | } | |
879 | ||
880 | // match interface type | |
881 | { | |
882 | CFStringRef known_type; | |
883 | ||
884 | known_type = SCNetworkInterfaceGetInterfaceType(known_if); | |
885 | if (!_SC_CFEqual(known_type, match_context->match_type)) { | |
886 | return; | |
887 | } | |
888 | } | |
889 | ||
890 | // match SCNetworkInterfaceInfo | |
891 | { | |
892 | CFDictionaryRef known_info; | |
893 | Boolean match; | |
894 | ||
895 | known_info = _SCNetworkInterfaceCopyInterfaceInfo(known_if); | |
896 | match = matchInterfaceInfo(known_info, match_context->match_info); | |
897 | if (known_info != NULL) CFRelease(known_info); | |
898 | if (!match) { | |
899 | return; | |
900 | } | |
901 | } | |
902 | ||
903 | // if requested, match [non-]builtin | |
904 | if (match_context->match_builtin != NULL) { | |
905 | CFBooleanRef known_builtin; | |
906 | ||
907 | known_builtin = _SCNetworkInterfaceIsBuiltin(known_if) ? kCFBooleanTrue | |
908 | : kCFBooleanFalse; | |
909 | if (!_SC_CFEqual(known_builtin, match_context->match_builtin)) { | |
910 | return; | |
911 | } | |
912 | } | |
913 | ||
914 | // if we have a match | |
915 | CFRelease(match_context->matches); | |
916 | match_context->matches = NULL; | |
917 | ||
918 | return; | |
919 | } | |
920 | ||
5e9ce69e A |
921 | static Boolean |
922 | interfaceExists(CFStringRef prefix, CFNumberRef unit) | |
923 | { | |
924 | Boolean found = FALSE; | |
925 | CFDictionaryRef match_dict; | |
926 | CFStringRef match_keys[2]; | |
927 | CFTypeRef match_vals[2]; | |
928 | CFDictionaryRef matching; | |
929 | ||
930 | ||
931 | ||
932 | io_registry_entry_t entry = MACH_PORT_NULL; | |
933 | io_iterator_t iterator = MACH_PORT_NULL; | |
934 | kern_return_t kr; | |
935 | mach_port_t masterPort = MACH_PORT_NULL; | |
936 | ||
937 | kr = IOMasterPort(bootstrap_port, &masterPort); | |
938 | if (kr != KERN_SUCCESS) { | |
939 | SCLog(TRUE, LOG_ERR, | |
940 | CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"), | |
941 | kr); | |
942 | goto error; | |
943 | } | |
944 | ||
945 | // look for kIONetworkInterface with matching prefix and unit | |
946 | match_keys[0] = CFSTR(kIOInterfaceNamePrefix); | |
947 | match_vals[0] = prefix; | |
948 | match_keys[1] = CFSTR(kIOInterfaceUnit); | |
949 | match_vals[1] = unit; | |
950 | match_dict = CFDictionaryCreate(NULL, | |
951 | (const void **)match_keys, | |
952 | (const void **)match_vals, | |
953 | 2, | |
954 | &kCFTypeDictionaryKeyCallBacks, | |
955 | &kCFTypeDictionaryValueCallBacks); | |
956 | ||
957 | match_keys[0] = CFSTR(kIOProviderClassKey); | |
958 | match_vals[0] = CFSTR(kIONetworkInterfaceClass); | |
959 | match_keys[1] = CFSTR(kIOPropertyMatchKey); | |
960 | match_vals[1] = match_dict; | |
961 | matching = CFDictionaryCreate(NULL, | |
962 | (const void **)match_keys, | |
963 | (const void **)match_vals, | |
964 | sizeof(match_keys)/sizeof(match_keys[0]), | |
965 | &kCFTypeDictionaryKeyCallBacks, | |
966 | &kCFTypeDictionaryValueCallBacks); | |
967 | CFRelease(match_dict); | |
968 | ||
969 | // note: the "matching" dictionary will be consumed by the following | |
970 | kr = IOServiceGetMatchingServices(masterPort, matching, &iterator); | |
971 | if ((kr != kIOReturnSuccess) || (iterator == MACH_PORT_NULL)) { | |
972 | // if no interface | |
973 | goto error; | |
974 | } | |
975 | ||
976 | entry = IOIteratorNext(iterator); | |
977 | if (entry == MACH_PORT_NULL) { | |
978 | // if no interface | |
979 | goto error; | |
980 | } | |
981 | ||
982 | found = TRUE; | |
983 | ||
984 | error: | |
985 | if (masterPort != MACH_PORT_NULL) { | |
986 | mach_port_deallocate(mach_task_self(), masterPort); | |
987 | } | |
988 | if (entry != MACH_PORT_NULL) { | |
989 | IOObjectRelease(entry); | |
990 | } | |
991 | if (iterator != MACH_PORT_NULL) { | |
992 | IOObjectRelease(iterator); | |
993 | } | |
994 | ||
995 | return (found); | |
996 | } | |
997 | ||
d0784775 A |
998 | /* |
999 | * lookupMatchingInterface | |
1000 | * | |
1001 | * Looks at the interfaces that have already been [or need to be] named with | |
1002 | * the goal of allowing a system using a single network interface/adaptor of | |
1003 | * a given type (vendor, model, ...) to not care about the specific adaptor | |
1004 | * that is used (i.e. swapping dongle's is OK). Once a system has had more | |
1005 | * than one interface/adaptor connected at the same time than we assume that | |
1006 | * the network configuration is being setup for multi-homing that should be | |
1007 | * maintained. | |
1008 | * | |
1009 | * If no matches are found or if more than one match is found, return NULL. | |
1010 | * If a single match is found, return the match. | |
1011 | */ | |
1012 | static CFDictionaryRef | |
1013 | lookupMatchingInterface(SCNetworkInterfaceRef interface, | |
1014 | CFArrayRef db_list, // already named | |
1015 | CFArrayRef if_list, // to be named | |
1016 | CFIndex if_list_index, | |
1017 | CFBooleanRef builtin) | |
1018 | { | |
1019 | CFStringRef if_type; | |
1020 | CFDictionaryRef match = NULL; | |
1021 | matchContext match_context; | |
1022 | ||
1023 | if_type = SCNetworkInterfaceGetInterfaceType(interface); | |
1024 | if (if_type == NULL) { | |
1025 | return NULL; | |
1026 | } | |
1027 | ||
1028 | match_context.match_type = if_type; | |
1029 | match_context.match_info = _SCNetworkInterfaceCopyInterfaceInfo(interface); | |
1030 | match_context.match_builtin = builtin; | |
1031 | match_context.matches = NULL; | |
1032 | ||
5e9ce69e A |
1033 | // check for matches to interfaces that have already been named |
1034 | // ... and append each match that we find to match_context.matches | |
d0784775 A |
1035 | if (db_list != NULL) { |
1036 | CFArrayApplyFunction(db_list, | |
1037 | CFRangeMake(0, CFArrayGetCount(db_list)), | |
1038 | matchKnown, | |
1039 | &match_context); | |
1040 | } | |
1041 | ||
5e9ce69e A |
1042 | // check for matches to interfaces that will be named |
1043 | // ... and CFRelease match_context.matches if we find another network | |
d0784775 A |
1044 | // interface of the same type that also needs to be named |
1045 | if (if_list != NULL) { | |
1046 | CFIndex if_list_count; | |
1047 | ||
1048 | if_list_count = CFArrayGetCount(if_list); | |
1049 | if (if_list_index < if_list_count) { | |
1050 | CFArrayApplyFunction(if_list, | |
1051 | CFRangeMake(if_list_index, if_list_count - if_list_index), | |
1052 | matchUnnamed, | |
1053 | &match_context); | |
1054 | } | |
1055 | } | |
1056 | ||
1057 | // check if we have a single match | |
1058 | if (match_context.matches != NULL) { | |
1059 | if (CFArrayGetCount(match_context.matches) == 1) { | |
1060 | match = CFArrayGetValueAtIndex(match_context.matches, 0); | |
1061 | } | |
1062 | CFRelease(match_context.matches); | |
1063 | } | |
1064 | ||
1065 | if (match != NULL) { | |
1066 | Boolean active = TRUE; | |
1067 | CFStringRef name; | |
1068 | ||
1069 | name = CFDictionaryGetValue(match, CFSTR(kIOBSDNameKey)); | |
1070 | if (isA_CFString(name)) { | |
5e9ce69e A |
1071 | CFStringRef prefix; |
1072 | CFNumberRef unit; | |
d0784775 | 1073 | |
5e9ce69e A |
1074 | prefix = CFDictionaryGetValue(match, CFSTR(kIOInterfaceNamePrefix)); |
1075 | unit = CFDictionaryGetValue(match, CFSTR(kIOInterfaceUnit)); | |
1076 | if (isA_CFString(prefix) && isA_CFNumber(unit)) { | |
1077 | if (!interfaceExists(prefix, unit)) { | |
d0784775 A |
1078 | active = FALSE; |
1079 | } | |
a40a14f8 | 1080 | } |
dbf6a266 | 1081 | } |
d0784775 A |
1082 | |
1083 | if (active) { | |
1084 | match = NULL; | |
1085 | } | |
dbf6a266 | 1086 | } |
d0784775 A |
1087 | |
1088 | if (match_context.match_info != NULL) CFRelease(match_context.match_info); | |
1089 | return match; | |
dbf6a266 A |
1090 | } |
1091 | ||
1092 | static void | |
edebe297 | 1093 | insertInterface(CFMutableArrayRef db_list, SCNetworkInterfaceRef interface) |
dbf6a266 A |
1094 | { |
1095 | CFIndex i; | |
edebe297 A |
1096 | CFDictionaryRef if_dict; |
1097 | CFStringRef if_name; | |
dbf6a266 A |
1098 | CFNumberRef if_type; |
1099 | CFNumberRef if_unit; | |
edebe297 | 1100 | CFIndex n = CFArrayGetCount(db_list); |
dbf6a266 A |
1101 | CFComparisonResult res; |
1102 | ||
edebe297 A |
1103 | if_name = SCNetworkInterfaceGetBSDName(interface); |
1104 | if (if_name != NULL) { | |
1105 | addTimestamp(S_state, if_name); | |
1106 | } | |
1107 | ||
1108 | if_dict = createInterfaceDict(interface); | |
1109 | if_type = _SCNetworkInterfaceGetIOInterfaceType(interface); | |
1110 | if_unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface); | |
1111 | if ((if_type == NULL) || (if_unit == NULL)) { | |
1112 | CFRelease(if_dict); | |
1113 | return; | |
1114 | } | |
1115 | ||
dbf6a266 | 1116 | for (i = 0; i < n; i++) { |
edebe297 A |
1117 | CFNumberRef db_type; |
1118 | CFNumberRef db_unit; | |
1119 | CFDictionaryRef dict = CFArrayGetValueAtIndex(db_list, i); | |
dbf6a266 | 1120 | |
edebe297 A |
1121 | db_type = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType)); |
1122 | db_unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit)); | |
1123 | res = CFNumberCompare(if_type, db_type, NULL); | |
dbf6a266 A |
1124 | if (res == kCFCompareLessThan |
1125 | || (res == kCFCompareEqualTo | |
edebe297 | 1126 | && (CFNumberCompare(if_unit, db_unit, NULL) |
dbf6a266 | 1127 | == kCFCompareLessThan))) { |
edebe297 A |
1128 | CFArrayInsertValueAtIndex(db_list, i, if_dict); |
1129 | CFRelease(if_dict); | |
dbf6a266 A |
1130 | return; |
1131 | } | |
1132 | } | |
edebe297 | 1133 | |
dbf6a266 | 1134 | CFArrayAppendValue(S_dblist, if_dict); |
5e9ce69e A |
1135 | |
1136 | #if !TARGET_OS_EMBEDDED | |
1137 | updateBTPANInformation(if_dict, NULL); | |
1138 | #endif // !TARGET_OS_EMBEDDED | |
1139 | ||
edebe297 | 1140 | CFRelease(if_dict); |
dbf6a266 A |
1141 | return; |
1142 | } | |
1143 | ||
1144 | static void | |
edebe297 | 1145 | replaceInterface(SCNetworkInterfaceRef interface) |
dbf6a266 | 1146 | { |
6bb65964 A |
1147 | int n = 0; |
1148 | CFIndex where; | |
dbf6a266 A |
1149 | |
1150 | if (S_dblist == NULL) { | |
1151 | S_dblist = CFArrayCreateMutable(NULL, 0, | |
1152 | &kCFTypeArrayCallBacks); | |
1153 | } | |
edebe297 | 1154 | // remove any dict that has our type/addr |
6bb65964 | 1155 | while (lookupInterfaceByAddress(S_dblist, interface, &where) != NULL) { |
dbf6a266 | 1156 | CFArrayRemoveValueAtIndex(S_dblist, where); |
6bb65964 | 1157 | n++; |
dbf6a266 | 1158 | } |
edebe297 | 1159 | // remove any dict that has the same type/unit |
6bb65964 | 1160 | while (lookupInterfaceByUnit(S_dblist, interface, &where) != NULL) { |
dbf6a266 | 1161 | CFArrayRemoveValueAtIndex(S_dblist, where); |
6bb65964 | 1162 | n++; |
dbf6a266 | 1163 | } |
edebe297 | 1164 | insertInterface(S_dblist, interface); |
6bb65964 A |
1165 | |
1166 | if (n > 1) { | |
1167 | CFStringRef issue; | |
1168 | ||
1169 | issue = CFStringCreateWithFormat(NULL, NULL, | |
1170 | CFSTR("n = %d, %@"), | |
1171 | n, | |
1172 | interface); | |
1173 | reportIssue("Multiple interfaces updated", issue); | |
1174 | CFRelease(issue); | |
1175 | } | |
1176 | ||
dbf6a266 A |
1177 | return; |
1178 | } | |
1179 | ||
1180 | static CFNumberRef | |
1181 | getHighestUnitForType(CFNumberRef if_type) | |
1182 | { | |
1183 | int i; | |
1184 | CFIndex n; | |
edebe297 | 1185 | CFNumberRef ret_unit = NULL; |
dbf6a266 | 1186 | |
edebe297 | 1187 | if (S_dblist == NULL) { |
dbf6a266 | 1188 | return (NULL); |
edebe297 | 1189 | } |
dbf6a266 A |
1190 | |
1191 | n = CFArrayGetCount(S_dblist); | |
1192 | for (i = 0; i < n; i++) { | |
1193 | CFDictionaryRef dict = CFArrayGetValueAtIndex(S_dblist, i); | |
1194 | CFNumberRef type; | |
dbf6a266 A |
1195 | |
1196 | type = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceType)); | |
1197 | if (CFEqual(type, if_type)) { | |
edebe297 A |
1198 | CFNumberRef unit; |
1199 | ||
dbf6a266 A |
1200 | unit = CFDictionaryGetValue(dict, CFSTR(kIOInterfaceUnit)); |
1201 | if (ret_unit == NULL | |
1202 | || (CFNumberCompare(unit, ret_unit, NULL) | |
1203 | == kCFCompareGreaterThan)) { | |
1204 | ret_unit = unit; | |
1205 | } | |
1206 | } | |
1207 | } | |
edebe297 | 1208 | |
dbf6a266 A |
1209 | return (ret_unit); |
1210 | } | |
1211 | ||
17d3ee29 A |
1212 | /* |
1213 | * Function: ensureInterfaceHasUnit | |
1214 | * Purpose: | |
1215 | * Ensure that the SCNetworkInterfaceRef has a unit number. If it doesn't, | |
1216 | * release the interface and return NULL. | |
1217 | */ | |
1218 | static SCNetworkInterfaceRef | |
1219 | ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if) | |
1220 | { | |
1221 | if (net_if != NULL | |
1222 | && _SCNetworkInterfaceGetIOInterfaceUnit(net_if) == NULL) { | |
1223 | CFRelease(net_if); | |
1224 | net_if = NULL; | |
1225 | } | |
1226 | return (net_if); | |
1227 | } | |
1228 | ||
af243a0d A |
1229 | #ifdef USE_REGISTRY_ENTRY_ID |
1230 | static kern_return_t | |
1231 | registerInterfaceWithIORegistryEntryID(io_connect_t connect, | |
1232 | uint64_t entryID, | |
1233 | CFNumberRef unit, | |
1234 | const int command) | |
1235 | { | |
1236 | CFDataRef data; | |
1237 | CFMutableDictionaryRef dict; | |
1238 | kern_return_t kr; | |
1239 | CFNumberRef num; | |
1240 | ||
1241 | dict = CFDictionaryCreateMutable(NULL, 0, | |
1242 | &kCFTypeDictionaryKeyCallBacks, | |
1243 | &kCFTypeDictionaryValueCallBacks); | |
1244 | num = CFNumberCreate(NULL, kCFNumberIntType, &command); | |
1245 | CFDictionarySetValue(dict, CFSTR(kIONetworkStackUserCommandKey), num); | |
1246 | CFRelease(num); | |
1247 | data = CFDataCreate(NULL, (void *) &entryID, sizeof(entryID)); | |
1248 | CFDictionarySetValue(dict, CFSTR(kIORegistryEntryIDKey), data); | |
1249 | CFRelease(data); | |
1250 | CFDictionarySetValue(dict, CFSTR(kIOInterfaceUnit), unit); | |
1251 | kr = IOConnectSetCFProperties(connect, dict); | |
1252 | CFRelease(dict); | |
1253 | return kr; | |
1254 | } | |
1255 | ||
1256 | static SCNetworkInterfaceRef | |
17d3ee29 | 1257 | copyInterfaceForIORegistryEntryID(uint64_t entryID) |
af243a0d A |
1258 | { |
1259 | io_registry_entry_t entry = MACH_PORT_NULL; | |
1260 | SCNetworkInterfaceRef interface = NULL; | |
1261 | io_iterator_t iterator = MACH_PORT_NULL; | |
1262 | kern_return_t kr; | |
1263 | mach_port_t masterPort = MACH_PORT_NULL; | |
1264 | ||
1265 | kr = IOMasterPort(bootstrap_port, &masterPort); | |
1266 | if (kr != KERN_SUCCESS) { | |
1267 | SCLog(TRUE, LOG_ERR, | |
1268 | CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"), | |
1269 | kr); | |
1270 | goto error; | |
1271 | } | |
1272 | ||
1273 | kr = IOServiceGetMatchingServices(masterPort, | |
1274 | IORegistryEntryIDMatching(entryID), | |
1275 | &iterator); | |
1276 | if ((kr != KERN_SUCCESS) || (iterator == MACH_PORT_NULL)) { | |
1277 | SCLog(TRUE, LOG_ERR, | |
1278 | CFSTR(MY_PLUGIN_NAME ": IOServiceGetMatchingServices(0x%llx) returned 0x%x/%d"), | |
1279 | entryID, | |
1280 | kr, | |
1281 | iterator); | |
1282 | goto error; | |
1283 | } | |
1284 | ||
1285 | entry = IOIteratorNext(iterator); | |
1286 | if (entry == MACH_PORT_NULL) { | |
1287 | SCLog(TRUE, LOG_ERR, | |
1288 | CFSTR(MY_PLUGIN_NAME ": IORegistryEntryIDMatching(0x%llx) failed"), | |
1289 | entryID); | |
1290 | goto error; | |
1291 | } | |
1292 | ||
1293 | interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry); | |
1294 | ||
1295 | error: | |
1296 | if (masterPort != MACH_PORT_NULL) { | |
1297 | mach_port_deallocate(mach_task_self(), masterPort); | |
1298 | } | |
1299 | if (entry != MACH_PORT_NULL) { | |
1300 | IOObjectRelease(entry); | |
1301 | } | |
1302 | if (iterator != MACH_PORT_NULL) { | |
1303 | IOObjectRelease(iterator); | |
1304 | } | |
1305 | return (interface); | |
af243a0d | 1306 | } |
17d3ee29 A |
1307 | |
1308 | static SCNetworkInterfaceRef | |
1309 | copyNamedInterfaceForIORegistryEntryID(uint64_t entryID) | |
1310 | { | |
1311 | SCNetworkInterfaceRef net_if; | |
1312 | ||
1313 | net_if = copyInterfaceForIORegistryEntryID(entryID); | |
1314 | return (ensureInterfaceHasUnit(net_if)); | |
1315 | } | |
1316 | ||
af243a0d | 1317 | #else // USE_REGISTRY_ENTRY_ID |
edebe297 A |
1318 | /* |
1319 | * Function: registerInterface | |
1320 | * Purpose: | |
1321 | * Register a single interface with the given service path to the | |
1322 | * data link layer (BSD), using the specified unit number. | |
1323 | */ | |
dbf6a266 | 1324 | static kern_return_t |
af243a0d A |
1325 | registerInterfaceWithIOServicePath(io_connect_t connect, |
1326 | CFStringRef path, | |
1327 | CFNumberRef unit, | |
1328 | const int command) | |
dbf6a266 A |
1329 | { |
1330 | CFMutableDictionaryRef dict; | |
edebe297 A |
1331 | kern_return_t kr; |
1332 | CFNumberRef num; | |
dbf6a266 A |
1333 | |
1334 | dict = CFDictionaryCreateMutable(NULL, 0, | |
1335 | &kCFTypeDictionaryKeyCallBacks, | |
1336 | &kCFTypeDictionaryValueCallBacks); | |
edebe297 | 1337 | num = CFNumberCreate(NULL, kCFNumberIntType, &command); |
af243a0d | 1338 | CFDictionarySetValue(dict, CFSTR(kIONetworkStackUserCommandKey), num); |
edebe297 A |
1339 | CFRelease(num); |
1340 | CFDictionarySetValue(dict, CFSTR(kIOPathMatchKey), path); | |
1341 | CFDictionarySetValue(dict, CFSTR(kIOInterfaceUnit), unit); | |
1342 | kr = IOConnectSetCFProperties(connect, dict); | |
1343 | CFRelease(dict); | |
dbf6a266 A |
1344 | return kr; |
1345 | } | |
1346 | ||
edebe297 | 1347 | static SCNetworkInterfaceRef |
17d3ee29 | 1348 | copyInterfaceForIOKitPath(CFStringRef if_path) |
dbf6a266 | 1349 | { |
edebe297 A |
1350 | io_registry_entry_t entry = MACH_PORT_NULL; |
1351 | SCNetworkInterfaceRef interface = NULL; | |
dbf6a266 | 1352 | kern_return_t kr; |
edebe297 | 1353 | mach_port_t masterPort = MACH_PORT_NULL; |
dbf6a266 A |
1354 | io_string_t path; |
1355 | ||
1356 | kr = IOMasterPort(bootstrap_port, &masterPort); | |
1357 | if (kr != KERN_SUCCESS) { | |
edebe297 | 1358 | SCLog(TRUE, LOG_ERR, |
6bb65964 | 1359 | CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"), |
dbf6a266 A |
1360 | kr); |
1361 | goto error; | |
1362 | } | |
1363 | _SC_cfstring_to_cstring(if_path, path, sizeof(path), kCFStringEncodingASCII); | |
1364 | entry = IORegistryEntryFromPath(masterPort, path); | |
1365 | if (entry == MACH_PORT_NULL) { | |
edebe297 | 1366 | SCLog(TRUE, LOG_ERR, |
dbf6a266 A |
1367 | CFSTR(MY_PLUGIN_NAME ": IORegistryEntryFromPath(%@) failed"), |
1368 | if_path); | |
1369 | goto error; | |
1370 | } | |
edebe297 A |
1371 | |
1372 | interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(entry); | |
dbf6a266 A |
1373 | |
1374 | error: | |
1375 | if (masterPort != MACH_PORT_NULL) { | |
1376 | mach_port_deallocate(mach_task_self(), masterPort); | |
1377 | } | |
1378 | if (entry != MACH_PORT_NULL) { | |
1379 | IOObjectRelease(entry); | |
1380 | } | |
edebe297 | 1381 | return (interface); |
dbf6a266 A |
1382 | |
1383 | } | |
17d3ee29 A |
1384 | |
1385 | static SCNetworkInterfaceRef | |
1386 | copyNamedInterfaceForIOKitPath(CFStringRef if_path) | |
1387 | { | |
1388 | SCNetworkInterfaceRef net_if; | |
1389 | ||
1390 | net_if = copyInterfaceForIOKitPath(if_path); | |
1391 | return (ensureInterfaceHasUnit(net_if)); | |
1392 | } | |
1393 | ||
af243a0d | 1394 | #endif // USE_REGISTRY_ENTRY_ID |
dbf6a266 A |
1395 | |
1396 | static void | |
edebe297 | 1397 | displayInterface(SCNetworkInterfaceRef interface) |
dbf6a266 | 1398 | { |
edebe297 | 1399 | CFStringRef addr; |
dbf6a266 A |
1400 | CFStringRef name; |
1401 | CFNumberRef type; | |
1402 | CFNumberRef unit; | |
1403 | ||
edebe297 A |
1404 | name = SCNetworkInterfaceGetBSDName(interface); |
1405 | unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface); | |
1406 | type = _SCNetworkInterfaceGetIOInterfaceType(interface); | |
1407 | addr = SCNetworkInterfaceGetHardwareAddressString(interface); | |
1408 | ||
1409 | SCLog(TRUE, LOG_INFO, | |
1410 | CFSTR(MY_PLUGIN_NAME ": %s%@%sType: %@, %s%@%sMAC address: %@"), | |
1411 | (name != NULL) ? "BSD Name: " : "", | |
1412 | (name != NULL) ? name : CFSTR(""), | |
1413 | (name != NULL) ? ", " : "", | |
1414 | type, | |
1415 | (unit != NULL) ? "Unit: " : "", | |
1416 | (unit != NULL) ? (CFTypeRef)unit : (CFTypeRef)CFSTR(""), | |
1417 | (unit != NULL) ? ", " : "", | |
1418 | addr); | |
dbf6a266 A |
1419 | } |
1420 | ||
5e9ce69e A |
1421 | static Boolean |
1422 | builtinAvailable(SCNetworkInterfaceRef interface, // new interface | |
1423 | CFNumberRef if_unit) // desired unit | |
1424 | { | |
1425 | CFIndex i; | |
1426 | CFNumberRef if_type = _SCNetworkInterfaceGetIOInterfaceType(interface); | |
1427 | CFIndex n; | |
1428 | ||
1429 | n = (S_dblist != NULL) ? CFArrayGetCount(S_dblist) : 0; | |
1430 | for (i = 0; i < n; i++) { | |
1431 | CFStringRef if_path; | |
1432 | CFDictionaryRef known_dict = CFArrayGetValueAtIndex(S_dblist, i); | |
1433 | CFStringRef known_path; | |
1434 | CFNumberRef known_type; | |
1435 | CFNumberRef known_unit; | |
1436 | ||
1437 | known_type = CFDictionaryGetValue(known_dict, CFSTR(kIOInterfaceType)); | |
1438 | if (!_SC_CFEqual(if_type, known_type)) { | |
1439 | continue; // if not the same interface type | |
1440 | } | |
1441 | ||
1442 | known_unit = CFDictionaryGetValue(known_dict, CFSTR(kIOInterfaceUnit)); | |
1443 | if (!_SC_CFEqual(if_unit, known_unit)) { | |
1444 | continue; // if not the same interface unit | |
1445 | } | |
1446 | ||
1447 | if_path = _SCNetworkInterfaceGetIOPath(interface); | |
1448 | known_path = CFDictionaryGetValue(known_dict, CFSTR(kIOPathMatchKey)); | |
1449 | if (!_SC_CFEqual(if_path, known_path)) { | |
1450 | // if different IORegistry path | |
1451 | return FALSE; | |
1452 | } | |
1453 | ||
1454 | // if same type, same unit, same path | |
1455 | return TRUE; | |
1456 | } | |
1457 | ||
1458 | // if interface type/unit not found | |
1459 | return TRUE; | |
1460 | } | |
1461 | ||
edebe297 A |
1462 | static int |
1463 | builtinCount(CFArrayRef if_list, CFIndex last, CFNumberRef if_type) | |
dbf6a266 | 1464 | { |
edebe297 A |
1465 | CFIndex i; |
1466 | int n = 0; | |
dbf6a266 | 1467 | |
edebe297 A |
1468 | for (i = 0; i < last; i++) { |
1469 | SCNetworkInterfaceRef builtin_if; | |
1470 | CFNumberRef builtin_type; | |
1471 | ||
1472 | builtin_if = CFArrayGetValueAtIndex(if_list, i); | |
1473 | builtin_type = _SCNetworkInterfaceGetIOInterfaceType(builtin_if); | |
1474 | if (CFEqual(if_type, builtin_type)) { | |
1475 | if (_SCNetworkInterfaceIsBuiltin(builtin_if)) { | |
1476 | n++; // if built-in interface | |
1477 | } | |
1478 | } | |
1479 | } | |
1480 | ||
1481 | return n; | |
dbf6a266 A |
1482 | } |
1483 | ||
edebe297 A |
1484 | static __inline__ boolean_t |
1485 | isQuiet(void) | |
dbf6a266 | 1486 | { |
edebe297 | 1487 | return (S_quiet == MACH_PORT_NULL); |
dbf6a266 A |
1488 | } |
1489 | ||
1490 | static void | |
edebe297 | 1491 | nameInterfaces(CFMutableArrayRef if_list) |
dbf6a266 A |
1492 | { |
1493 | CFIndex i; | |
edebe297 | 1494 | CFIndex n = CFArrayGetCount(if_list); |
dbf6a266 A |
1495 | |
1496 | for (i = 0; i < n; i++) { | |
af243a0d | 1497 | uint64_t entryID; |
edebe297 | 1498 | SCNetworkInterfaceRef interface; |
17d3ee29 | 1499 | SCNetworkInterfaceRef new_interface; |
edebe297 | 1500 | CFStringRef path; |
af243a0d | 1501 | CFStringRef str; |
edebe297 A |
1502 | CFNumberRef type; |
1503 | CFNumberRef unit; | |
1504 | CFIndex where; | |
1505 | ||
1506 | interface = CFArrayGetValueAtIndex(if_list, i); | |
1507 | path = _SCNetworkInterfaceGetIOPath(interface); | |
1508 | type = _SCNetworkInterfaceGetIOInterfaceType(interface); | |
1509 | unit = _SCNetworkInterfaceGetIOInterfaceUnit(interface); | |
af243a0d | 1510 | entryID = _SCNetworkInterfaceGetIORegistryEntryID(interface); |
edebe297 A |
1511 | |
1512 | if (unit != NULL) { | |
dbf6a266 | 1513 | if (S_debug) { |
edebe297 A |
1514 | CFStringRef if_name; |
1515 | ||
1516 | if_name = SCNetworkInterfaceGetBSDName(interface); | |
1517 | if ((if_name == NULL) || !CFDictionaryContainsKey(S_state, if_name)) { | |
1518 | SCLog(TRUE, LOG_INFO, | |
1519 | CFSTR(MY_PLUGIN_NAME ": Interface already has a unit number")); | |
1520 | displayInterface(interface); | |
1521 | } | |
dbf6a266 | 1522 | } |
edebe297 A |
1523 | |
1524 | // update the list of interfaces that were previously named | |
1525 | if ((S_prev_active_list != NULL) | |
1526 | && lookupInterfaceByAddress(S_prev_active_list, interface, &where) != NULL) { | |
1527 | CFArrayRemoveValueAtIndex(S_prev_active_list, where); | |
dbf6a266 | 1528 | } |
17d3ee29 A |
1529 | |
1530 | replaceInterface(interface); | |
edebe297 A |
1531 | } else { |
1532 | CFDictionaryRef dbdict; | |
d0784775 | 1533 | boolean_t is_builtin; |
edebe297 | 1534 | kern_return_t kr; |
af243a0d | 1535 | int retries = 0; |
edebe297 A |
1536 | |
1537 | dbdict = lookupInterfaceByAddress(S_dblist, interface, NULL); | |
dbf6a266 | 1538 | if (dbdict != NULL) { |
edebe297 | 1539 | unit = CFDictionaryGetValue(dbdict, CFSTR(kIOInterfaceUnit)); |
dbf6a266 | 1540 | CFRetain(unit); |
edebe297 A |
1541 | |
1542 | SCLog(S_debug, LOG_INFO, | |
1543 | CFSTR(MY_PLUGIN_NAME ": Interface assigned unit %@ (from database)"), | |
1544 | unit); | |
d0784775 | 1545 | } |
edebe297 | 1546 | |
d0784775 A |
1547 | if ((dbdict == NULL) && !isQuiet()) { |
1548 | // if new interface, wait until quiet before naming | |
1549 | addTimestamp(S_state, path); | |
1550 | continue; | |
1551 | } | |
edebe297 | 1552 | |
d0784775 A |
1553 | is_builtin = _SCNetworkInterfaceIsBuiltin(interface); |
1554 | ||
1555 | if (dbdict == NULL) { | |
1556 | dbdict = lookupMatchingInterface(interface, | |
1557 | S_dblist, | |
1558 | if_list, | |
1559 | i + 1, | |
1560 | is_builtin ? kCFBooleanTrue : kCFBooleanFalse); | |
1561 | if (dbdict != NULL) { | |
1562 | unit = CFDictionaryGetValue(dbdict, CFSTR(kIOInterfaceUnit)); | |
1563 | CFRetain(unit); | |
1564 | ||
1565 | SCLog(S_debug, LOG_INFO, | |
1566 | CFSTR(MY_PLUGIN_NAME ": Interface assigned unit %@ (updating database)"), | |
1567 | unit); | |
dbf6a266 | 1568 | } |
edebe297 A |
1569 | } |
1570 | ||
1571 | if ((dbdict != NULL) && (S_prev_active_list != NULL)) { | |
1572 | // update the list of interfaces that were previously named | |
1573 | where = CFArrayGetFirstIndexOfValue(S_prev_active_list, | |
1574 | CFRangeMake(0, CFArrayGetCount(S_prev_active_list)), | |
1575 | dbdict); | |
1576 | if (where != kCFNotFound) { | |
1577 | CFArrayRemoveValueAtIndex(S_prev_active_list, where); | |
1578 | } | |
1579 | } | |
1580 | ||
1581 | if (dbdict == NULL) { | |
edebe297 A |
1582 | int next_unit = 0; |
1583 | ||
edebe297 | 1584 | if (is_builtin) { |
5e9ce69e | 1585 | // built-in interface, try to use the reserved slots |
edebe297 | 1586 | next_unit = builtinCount(if_list, i, type); |
5e9ce69e A |
1587 | |
1588 | // But, before claiming a reserved slot we check to see if the | |
1589 | // slot had previously been used. If so, and if the slot had been | |
1590 | // assigned to the same type of interface, then we will perform a | |
1591 | // replacement (e.g. assume that this was a board swap). But, if | |
1592 | // the new interface is a different type then we assume that the | |
1593 | // built-in configuration has changed and allocate a new unit from | |
1594 | // the non-reserved slots. | |
1595 | ||
1596 | unit = CFNumberCreate(NULL, kCFNumberIntType, &next_unit); | |
1597 | if (!builtinAvailable(interface, unit)) { | |
1598 | // if [built-in] unit not available | |
1599 | SCLog(S_debug, LOG_INFO, | |
1600 | CFSTR(MY_PLUGIN_NAME ": Interface not assigned [built-in] unit %@"), | |
1601 | unit); | |
1602 | CFRelease(unit); | |
1603 | unit = NULL; | |
1604 | } | |
1605 | } | |
1606 | ||
1607 | if (unit == NULL) { | |
1608 | // not built-in (or built-in unit not available), allocate from | |
1609 | // the non-reserved slots | |
edebe297 A |
1610 | next_unit = builtinCount(if_list, n, type); |
1611 | ||
dbf6a266 | 1612 | unit = getHighestUnitForType(type); |
edebe297 | 1613 | if (unit != NULL) { |
dbf6a266 A |
1614 | int high_unit; |
1615 | ||
edebe297 | 1616 | CFNumberGetValue(unit, kCFNumberIntType, &high_unit); |
dbf6a266 A |
1617 | if (high_unit >= next_unit) { |
1618 | next_unit = high_unit + 1; | |
1619 | } | |
1620 | } | |
5e9ce69e A |
1621 | |
1622 | unit = CFNumberCreate(NULL, kCFNumberIntType, &next_unit); | |
dbf6a266 | 1623 | } |
edebe297 A |
1624 | |
1625 | SCLog(S_debug, LOG_INFO, | |
1626 | CFSTR(MY_PLUGIN_NAME ": Interface assigned unit %@ (%s)"), | |
1627 | unit, | |
1628 | is_builtin ? "built-in" : "next available"); | |
dbf6a266 | 1629 | } |
edebe297 | 1630 | |
af243a0d A |
1631 | retry : |
1632 | ||
1633 | #ifdef USE_REGISTRY_ENTRY_ID | |
1634 | kr = registerInterfaceWithIORegistryEntryID(S_connect, | |
1635 | entryID, | |
1636 | unit, | |
1637 | (dbdict == NULL) ? kIONetworkStackRegisterInterfaceWithLowestUnit | |
1638 | : kIONetworkStackRegisterInterfaceWithUnit); | |
17d3ee29 | 1639 | new_interface = copyNamedInterfaceForIORegistryEntryID(entryID); |
af243a0d A |
1640 | #else // USE_REGISTRY_ENTRY_ID |
1641 | kr = registerInterfaceWithIOServicePath(S_connect, | |
1642 | path, | |
1643 | unit, | |
1644 | (dbdict == NULL) ? kRegisterInterface | |
1645 | : kRegisterInterfaceWithFixedUnit); | |
17d3ee29 | 1646 | new_interface = copyNamedInterfaceForIOKitPath(path); |
af243a0d | 1647 | #endif // USE_REGISTRY_ENTRY_ID |
17d3ee29 | 1648 | if (new_interface == NULL) { |
6bb65964 A |
1649 | const char *signature; |
1650 | ||
1651 | signature = (dbdict == NULL) ? "failed to name new interface" | |
1652 | : "failed to name known interface"; | |
1653 | ||
edebe297 | 1654 | SCLog(TRUE, LOG_ERR, |
6bb65964 | 1655 | CFSTR(MY_PLUGIN_NAME ": %s, kr=0x%x\n" |
d0784775 | 1656 | MY_PLUGIN_NAME ": path = %@\n" |
af243a0d | 1657 | MY_PLUGIN_NAME ": id = 0x%llx\n" |
d0784775 | 1658 | MY_PLUGIN_NAME ": unit = %@"), |
6bb65964 | 1659 | signature, |
d0784775 A |
1660 | kr, |
1661 | path, | |
af243a0d | 1662 | entryID, |
d0784775 | 1663 | unit); |
6bb65964 | 1664 | |
dbf6a266 | 1665 | if (S_debug) { |
edebe297 | 1666 | displayInterface(interface); |
dbf6a266 | 1667 | } |
6bb65964 A |
1668 | |
1669 | // report issue w/MessageTracer | |
af243a0d A |
1670 | str = CFStringCreateWithFormat(NULL, NULL, |
1671 | CFSTR("kr=0x%x, path=%@, unit=%@"), | |
1672 | kr, | |
1673 | path, | |
1674 | unit); | |
1675 | reportIssue(signature, str); | |
1676 | CFRelease(str); | |
1677 | ||
1678 | if ((dbdict != NULL) && (retries++ < 5)) { | |
1679 | usleep(50 * 1000); // sleep 50ms between attempts | |
1680 | goto retry; | |
1681 | } | |
17d3ee29 A |
1682 | } |
1683 | else { | |
1684 | CFNumberRef new_unit; | |
dbf6a266 | 1685 | |
af243a0d A |
1686 | if (retries > 0) { |
1687 | SCLog(TRUE, LOG_ERR, | |
1688 | CFSTR(MY_PLUGIN_NAME ": %s interface named after %d %s\n" | |
1689 | MY_PLUGIN_NAME ": path = %@\n" | |
1690 | MY_PLUGIN_NAME ": unit = %@"), | |
1691 | (dbdict == NULL) ? "New" : "Known", | |
1692 | retries, | |
1693 | (retries == 1) ? "try" : "tries", | |
1694 | path, | |
1695 | unit); | |
1696 | ||
1697 | #ifdef SHOW_NAMING_FAILURE | |
1698 | str = CFStringCreateWithFormat(NULL, | |
1699 | NULL, | |
1700 | CFSTR("\"%s\" interface named after %d %s, unit = %@"), | |
1701 | (dbdict == NULL) ? "New" : "Known", | |
1702 | retries, | |
1703 | (retries == 1) ? "try" : "tries", | |
1704 | unit); | |
1705 | CFUserNotificationDisplayNotice(0, | |
1706 | kCFUserNotificationStopAlertLevel, | |
1707 | NULL, | |
1708 | NULL, | |
1709 | NULL, | |
1710 | str, | |
1711 | CFSTR("Please report repeated failures."), | |
1712 | NULL); | |
1713 | CFRelease(str); | |
1714 | #endif // SHOW_NAMING_FAILURE | |
1715 | } | |
1716 | ||
17d3ee29 A |
1717 | new_unit = _SCNetworkInterfaceGetIOInterfaceUnit(new_interface); |
1718 | if (CFEqual(unit, new_unit) == FALSE) { | |
1719 | SCLog(S_debug, LOG_INFO, | |
1720 | CFSTR(MY_PLUGIN_NAME | |
1721 | ": interface type %@ assigned " | |
1722 | "unit %@ instead of %@"), | |
1723 | type, new_unit, unit); | |
1724 | } | |
1725 | if (S_debug) { | |
1726 | displayInterface(new_interface); | |
1727 | } | |
edebe297 | 1728 | |
17d3ee29 A |
1729 | // update if_list (with the interface name & unit) |
1730 | CFArraySetValueAtIndex(if_list, i, new_interface); | |
1731 | CFRelease(new_interface); | |
1732 | interface = new_interface; // if_list holds the reference | |
d0784775 | 1733 | |
17d3ee29 A |
1734 | if (is_builtin && (S_prev_active_list != NULL)) { |
1735 | CFIndex where; | |
d0784775 | 1736 | |
17d3ee29 A |
1737 | // update the list of [built-in] interfaces that were previously named |
1738 | if (lookupInterfaceByUnit(S_prev_active_list, interface, &where) != NULL) { | |
1739 | SCLog(S_debug, LOG_INFO, | |
1740 | CFSTR(MY_PLUGIN_NAME ": and updated database (new address)")); | |
1741 | CFArrayRemoveValueAtIndex(S_prev_active_list, where); | |
d0784775 | 1742 | } |
dbf6a266 | 1743 | } |
17d3ee29 | 1744 | replaceInterface(interface); |
dbf6a266 A |
1745 | } |
1746 | CFRelease(unit); | |
1747 | } | |
1748 | } | |
dbf6a266 A |
1749 | return; |
1750 | } | |
1751 | ||
5e9ce69e A |
1752 | #if !TARGET_OS_IPHONE |
1753 | static void | |
1754 | updateNetworkConfiguration(CFArrayRef if_list) | |
1755 | { | |
1756 | Boolean do_commit = FALSE; | |
1757 | CFIndex i; | |
1758 | CFIndex n; | |
1759 | SCPreferencesRef prefs = NULL; | |
1760 | SCNetworkSetRef set = NULL; | |
1761 | ||
78403150 | 1762 | prefs = SCPreferencesCreate(NULL, CFSTR("InterfaceNamer:updateNetworkConfiguration"), NULL); |
5e9ce69e A |
1763 | |
1764 | set = SCNetworkSetCopyCurrent(prefs); | |
1765 | if (set == NULL) { | |
1766 | SCLog(TRUE, LOG_ERR, CFSTR(MY_PLUGIN_NAME ": No current set")); | |
1767 | goto done; | |
1768 | } | |
1769 | ||
1770 | n = CFArrayGetCount(if_list); | |
1771 | for (i = 0; i < n; i++) { | |
1772 | SCNetworkInterfaceRef interface; | |
1773 | ||
1774 | interface = CFArrayGetValueAtIndex(if_list, i); | |
1775 | if (SCNetworkSetEstablishDefaultInterfaceConfiguration(set, interface)) { | |
1776 | SCLog(TRUE, LOG_INFO, | |
78403150 | 1777 | CFSTR(MY_PLUGIN_NAME ": adding default configuration for %@"), |
5e9ce69e A |
1778 | SCNetworkInterfaceGetBSDName(interface)); |
1779 | do_commit = TRUE; | |
1780 | } | |
1781 | } | |
1782 | ||
1783 | if (do_commit) { | |
1784 | Boolean ok; | |
1785 | ||
1786 | ok = SCPreferencesCommitChanges(prefs); | |
1787 | if (!ok) { | |
1788 | SCLog(TRUE, LOG_INFO, | |
1789 | CFSTR(MY_PLUGIN_NAME ": updateNetworkConfiguration: SCPreferencesCommitChanges() failed: %s"), | |
1790 | SCErrorString(SCError())); | |
1791 | goto done; | |
1792 | } | |
1793 | ||
1794 | ok = SCPreferencesApplyChanges(prefs); | |
1795 | if (!ok) { | |
1796 | SCLog(TRUE, LOG_INFO, | |
1797 | CFSTR(MY_PLUGIN_NAME ": updateNetworkConfiguration: SCPreferencesApplyChanges() failed: %s"), | |
1798 | SCErrorString(SCError())); | |
1799 | goto done; | |
1800 | } | |
1801 | } | |
1802 | ||
1803 | done : | |
1804 | ||
1805 | if (set != NULL) { | |
1806 | CFRelease(set); | |
1807 | set = NULL; | |
1808 | } | |
1809 | ||
1810 | if (prefs != NULL) { | |
1811 | CFRelease(prefs); | |
1812 | prefs = NULL; | |
1813 | } | |
1814 | ||
1815 | return; | |
1816 | } | |
1817 | #endif // !TARGET_OS_IPHONE | |
1818 | ||
dbf6a266 | 1819 | static void |
edebe297 | 1820 | updateInterfaces() |
dbf6a266 | 1821 | { |
edebe297 A |
1822 | if (S_connect == MACH_PORT_NULL) { |
1823 | // if we don't have the "IONetworkStack" connect object | |
1824 | return; | |
1825 | } | |
dbf6a266 | 1826 | |
edebe297 A |
1827 | if (S_iflist != NULL) { |
1828 | CFIndex n; | |
dbf6a266 | 1829 | |
edebe297 A |
1830 | n = CFArrayGetCount(S_iflist); |
1831 | if (n > 1) { | |
1832 | CFArraySortValues(S_iflist, CFRangeMake(0, n), _SCNetworkInterfaceCompare, NULL); | |
1833 | } | |
1834 | nameInterfaces(S_iflist); | |
1835 | } | |
1836 | ||
1837 | if (isQuiet()) { | |
1838 | /* | |
1839 | * The registry [matching] has quiesced so let's | |
1840 | * - save the DB with the interfaces that have been named | |
1841 | * - update the VLAN/BOND configuration | |
1842 | * - tell everyone that we've finished (at least for now) | |
1843 | * - log those interfaces which are no longer present | |
1844 | * in the HW config (or have yet to show up). | |
1845 | */ | |
1846 | writeInterfaceList(S_dblist); | |
1847 | updateVirtualNetworkInterfaceConfiguration(NULL, kSCPreferencesNotificationApply, NULL); | |
5e9ce69e A |
1848 | |
1849 | #if !TARGET_OS_IPHONE | |
1850 | if (access("/usr/libexec/UserEventAgent", X_OK) == -1 | |
1851 | && errno == ENOENT) { | |
1852 | /* | |
1853 | * We are most likely booted into the Recovery OS with no "SCMonitor" | |
1854 | * UserEventAgent plugin running so let's make sure we update the | |
1855 | * network configuration for new interfaces. | |
1856 | */ | |
1857 | updateNetworkConfiguration(S_iflist); | |
1858 | } | |
1859 | #endif // !TARGET_OS_IPHONE | |
1860 | ||
edebe297 A |
1861 | updateStore(); |
1862 | ||
1863 | if (S_iflist != NULL) { | |
1864 | CFRelease(S_iflist); | |
1865 | S_iflist = NULL; | |
1866 | } | |
1867 | ||
1868 | if (S_prev_active_list != NULL) { | |
1869 | if (S_debug) { | |
1870 | CFIndex i; | |
1871 | CFIndex n; | |
dbf6a266 | 1872 | |
edebe297 | 1873 | n = CFArrayGetCount(S_prev_active_list); |
d0784775 A |
1874 | if (n > 0) { |
1875 | SCLog(TRUE, LOG_INFO, | |
1876 | CFSTR(MY_PLUGIN_NAME ": Interface%s not [yet] active"), | |
1877 | (n > 1) ? "s" : ""); | |
1878 | } | |
edebe297 A |
1879 | for (i = 0; i < n; i++) { |
1880 | CFDictionaryRef if_dict; | |
1881 | CFStringRef name; | |
1882 | CFNumberRef type; | |
1883 | CFNumberRef unit; | |
1884 | ||
1885 | if_dict = CFArrayGetValueAtIndex(S_prev_active_list, i); | |
1886 | name = CFDictionaryGetValue(if_dict, CFSTR(kIOBSDNameKey)); | |
1887 | type = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceType)); | |
1888 | unit = CFDictionaryGetValue(if_dict, CFSTR(kIOInterfaceUnit)); | |
1889 | SCLog(TRUE, LOG_INFO, | |
1890 | CFSTR(MY_PLUGIN_NAME ": %s%@%sType: %@, Unit: %@"), | |
1891 | (name != NULL) ? "BSD Name: " : "", | |
1892 | (name != NULL) ? name : CFSTR(""), | |
1893 | (name != NULL) ? ", " : "", | |
1894 | type, | |
1895 | unit); | |
1896 | } | |
dbf6a266 | 1897 | } |
edebe297 A |
1898 | CFRelease(S_prev_active_list); |
1899 | S_prev_active_list = NULL; | |
dbf6a266 | 1900 | } |
edebe297 A |
1901 | } else { |
1902 | if ((S_prev_active_list != NULL) && (CFArrayGetCount(S_prev_active_list) == 0)) { | |
1903 | /* | |
1904 | * if we've named all of the interfaces that | |
1905 | * were used during the previous boot. | |
1906 | */ | |
1907 | addTimestamp(S_state, CFSTR("*RELEASE*")); | |
1908 | SCLog(S_debug, LOG_INFO, | |
1909 | CFSTR(MY_PLUGIN_NAME ": last boot interfaces have been named")); | |
1910 | updateStore(); | |
1911 | CFRelease(S_prev_active_list); | |
1912 | S_prev_active_list = NULL; | |
1913 | } | |
1914 | } | |
1915 | ||
1916 | return; | |
1917 | } | |
1918 | ||
17d3ee29 | 1919 | #if !TARGET_OS_EMBEDDED |
edebe297 A |
1920 | static CFComparisonResult |
1921 | compareMacAddress(const void *val1, const void *val2, void *context) | |
1922 | { | |
1923 | CFDataRef mac1 = (CFDataRef)val1; | |
1924 | CFDataRef mac2 = (CFDataRef)val2; | |
1925 | CFIndex n1; | |
1926 | CFIndex n2; | |
1927 | CFComparisonResult res; | |
1928 | ||
1929 | n1 = CFDataGetLength(mac1); | |
1930 | n2 = CFDataGetLength(mac2); | |
1931 | if (n1 < n2) { | |
1932 | res = kCFCompareLessThan; | |
1933 | } else if (n2 > n1) { | |
1934 | res = kCFCompareGreaterThan; | |
1935 | } else { | |
1936 | res = bcmp(CFDataGetBytePtr(mac1), CFDataGetBytePtr(mac2), n1); | |
1937 | } | |
1938 | ||
1939 | return res; | |
1940 | } | |
1941 | ||
17d3ee29 A |
1942 | static CFStringRef |
1943 | copyEthernetUUID() | |
edebe297 A |
1944 | { |
1945 | CFDataRef addr; | |
1946 | CFMutableArrayRef addrs = NULL; | |
17d3ee29 | 1947 | CFStringRef guid = NULL; |
edebe297 A |
1948 | CFIndex i; |
1949 | CFIndex n; | |
edebe297 A |
1950 | |
1951 | addrs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |
1952 | n = (S_dblist != NULL) ? CFArrayGetCount(S_dblist) : 0; | |
1953 | for (i = 0; i < n; i++) { | |
1954 | CFBooleanRef builtin; | |
1955 | CFDictionaryRef dict; | |
1956 | CFStringRef type; | |
1957 | ||
1958 | dict = CFArrayGetValueAtIndex(S_dblist, i); | |
1959 | type = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceType)); | |
1960 | if (!isA_CFString(type) || !CFEqual(type, kSCNetworkInterfaceTypeEthernet)) { | |
1961 | continue; | |
1962 | } | |
1963 | builtin = CFDictionaryGetValue(dict, CFSTR(kIOBuiltin)); | |
1964 | if (!isA_CFBoolean(builtin) || !CFBooleanGetValue(builtin)) { | |
1965 | continue; | |
1966 | } | |
1967 | addr = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress)); | |
1968 | if (!isA_CFData(addr) || (CFDataGetLength(addr) != ETHER_ADDR_LEN)) { | |
1969 | continue; | |
1970 | } | |
1971 | CFArrayAppendValue(addrs, addr); | |
1972 | } | |
1973 | ||
1974 | if (CFArrayGetCount(addrs) == 0) { | |
1975 | // if no ethernet interfaces, look for wireless | |
1976 | for (i = 0; i < n; i++) { | |
1977 | CFDictionaryRef dict; | |
1978 | CFStringRef type; | |
1979 | ||
1980 | dict = CFArrayGetValueAtIndex(S_dblist, i); | |
1981 | type = CFDictionaryGetValue(dict, CFSTR(kSCNetworkInterfaceType)); | |
1982 | if (!isA_CFString(type) || !CFEqual(type, kSCNetworkInterfaceTypeIEEE80211)) { | |
1983 | continue; | |
1984 | } | |
1985 | addr = CFDictionaryGetValue(dict, CFSTR(kIOMACAddress)); | |
1986 | if (!isA_CFData(addr) || (CFDataGetLength(addr) != ETHER_ADDR_LEN)) { | |
1987 | continue; | |
1988 | } | |
1989 | CFArrayAppendValue(addrs, addr); | |
1990 | } | |
1991 | } | |
1992 | ||
1993 | n = CFArrayGetCount(addrs); | |
1994 | switch (n) { | |
1995 | case 0 : | |
17d3ee29 | 1996 | // if no network interfaces |
edebe297 A |
1997 | break; |
1998 | default : | |
1999 | // sort by MAC address | |
2000 | CFArraySortValues(addrs, CFRangeMake(0, n), compareMacAddress, NULL); | |
2001 | ||
2002 | // fall through | |
2003 | case 1 : { | |
2004 | CFUUIDBytes bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, | |
2005 | 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
edebe297 A |
2006 | CFUUIDRef uuid; |
2007 | ||
2008 | // set GUID | |
2009 | addr = CFArrayGetValueAtIndex(addrs, 0); | |
2010 | bcopy(CFDataGetBytePtr(addr), | |
2011 | (void *)&bytes + sizeof(bytes) - ETHER_ADDR_LEN, | |
2012 | ETHER_ADDR_LEN); | |
2013 | uuid = CFUUIDCreateFromUUIDBytes(NULL, bytes); | |
2014 | guid = CFUUIDCreateString(NULL, uuid); | |
2015 | CFRelease(uuid); | |
2016 | ||
2017 | SCLog(TRUE, LOG_INFO, | |
17d3ee29 | 2018 | CFSTR(MY_PLUGIN_NAME ": setting platform UUID [MAC] = %@"), |
edebe297 | 2019 | guid); |
edebe297 A |
2020 | break; |
2021 | } | |
dbf6a266 | 2022 | } |
edebe297 | 2023 | |
17d3ee29 A |
2024 | if (addrs != NULL) CFRelease(addrs); |
2025 | return guid; | |
2026 | } | |
2027 | ||
2028 | #ifndef kIOPlatformUUIDKey | |
2029 | #define kIOPlatformUUIDKey "IOPlatformUUID" | |
2030 | #endif | |
2031 | static void | |
2032 | updatePlatformUUID() | |
2033 | { | |
2034 | CFStringRef guid = NULL; | |
2035 | kern_return_t kr; | |
2036 | io_registry_entry_t platform; | |
2037 | ||
2038 | platform = IORegistryEntryFromPath(kIOMasterPortDefault, kIODeviceTreePlane ":/"); | |
2039 | if (platform == MACH_PORT_NULL) { | |
2040 | goto done; | |
2041 | } | |
2042 | ||
2043 | guid = IORegistryEntryCreateCFProperty(platform, CFSTR(kIOPlatformUUIDKey), NULL, 0); | |
2044 | if (guid != NULL) { | |
2045 | // if GUID already defined | |
2046 | goto done; | |
2047 | } | |
2048 | ||
2049 | guid = copyEthernetUUID(); | |
2050 | if (guid == NULL) { | |
2051 | CFUUIDRef uuid; | |
2052 | ||
2053 | uuid = CFUUIDCreate(NULL); | |
2054 | guid = CFUUIDCreateString(NULL, uuid); | |
2055 | CFRelease(uuid); | |
2056 | ||
2057 | SCLog(TRUE, LOG_INFO, | |
2058 | CFSTR(MY_PLUGIN_NAME ": setting platform UUID [random] = %@"), | |
2059 | guid); | |
2060 | } | |
2061 | ||
2062 | if (getenv("DO_NOT_SET_PLATFORM_UUID") == NULL) { | |
2063 | kr = IORegistryEntrySetCFProperty(platform, CFSTR(kIOPlatformUUIDKey), guid); | |
2064 | if (kr != KERN_SUCCESS) { | |
2065 | SCLog(TRUE, LOG_ERR, | |
2066 | CFSTR(MY_PLUGIN_NAME ": IORegistryEntrySetCFProperty(platform UUID) failed, kr=0x%x"), | |
2067 | kr); | |
2068 | } | |
2069 | } | |
2070 | ||
2071 | addTimestamp(S_state, CFSTR("*PLATFORM-UUID*")); | |
2072 | updateStore(); | |
2073 | ||
edebe297 A |
2074 | done : |
2075 | ||
17d3ee29 A |
2076 | if (S_vproc_transaction != NULL) { |
2077 | vproc_transaction_end(NULL, S_vproc_transaction); | |
2078 | S_vproc_transaction = NULL; | |
2079 | } | |
2080 | ||
edebe297 A |
2081 | if (platform != MACH_PORT_NULL) IOObjectRelease(platform); |
2082 | if (guid != NULL) CFRelease(guid); | |
dbf6a266 A |
2083 | return; |
2084 | } | |
17d3ee29 | 2085 | #endif // !TARGET_OS_EMBEDDED |
dbf6a266 | 2086 | |
edebe297 A |
2087 | static void |
2088 | interfaceArrivalCallback(void *refcon, io_iterator_t iter) | |
2089 | { | |
2090 | io_object_t obj; | |
dbf6a266 | 2091 | |
edebe297 A |
2092 | while ((obj = IOIteratorNext(iter)) != MACH_PORT_NULL) { |
2093 | SCNetworkInterfaceRef interface; | |
2094 | ||
2095 | interface = _SCNetworkInterfaceCreateWithIONetworkInterfaceObject(obj); | |
2096 | if (interface != NULL) { | |
2097 | if (S_iflist == NULL) { | |
2098 | S_iflist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |
2099 | } | |
2100 | CFArrayAppendValue(S_iflist, interface); | |
2101 | CFRelease(interface); | |
2102 | } | |
2103 | IOObjectRelease(obj); | |
2104 | } | |
2105 | ||
2106 | updateInterfaces(); | |
2107 | return; | |
2108 | } | |
2109 | ||
2110 | /* | |
2111 | * Function: stackCallback | |
2112 | * Purpose: | |
2113 | * Get a reference to the single IONetworkStack object instance in | |
2114 | * the kernel. Naming requests must be sent to this object, which is | |
2115 | * attached as a client to all network interface objects in the system. | |
2116 | * Note: | |
2117 | * Call IOObjectRelease on the returned object. | |
2118 | */ | |
2119 | static void | |
2120 | stackCallback(void *refcon, io_iterator_t iter) | |
dbf6a266 A |
2121 | { |
2122 | kern_return_t kr; | |
edebe297 | 2123 | io_object_t stack; |
dbf6a266 | 2124 | |
edebe297 A |
2125 | stack = IOIteratorNext(iter); |
2126 | if (stack == MACH_PORT_NULL) { | |
2127 | goto error; | |
dbf6a266 A |
2128 | } |
2129 | ||
edebe297 | 2130 | kr = IOServiceOpen(stack, mach_task_self(), 0, &S_connect); |
dbf6a266 | 2131 | if (kr != KERN_SUCCESS) { |
edebe297 A |
2132 | SCLog(TRUE, LOG_ERR, |
2133 | CFSTR(MY_PLUGIN_NAME ": IOServiceOpen returned 0x%x"), | |
dbf6a266 A |
2134 | kr); |
2135 | goto error; | |
2136 | } | |
2137 | ||
edebe297 A |
2138 | addTimestamp(S_state, CFSTR("*STACK*")); |
2139 | SCLog(S_debug, LOG_INFO, | |
2140 | CFSTR(MY_PLUGIN_NAME ": IONetworkStack found")); | |
dbf6a266 | 2141 | |
edebe297 A |
2142 | if (S_stack != MACH_PORT_NULL) { |
2143 | IOObjectRelease(S_stack); | |
2144 | S_stack = MACH_PORT_NULL; | |
2145 | } | |
2146 | ||
6bb65964 A |
2147 | if ((S_timer != NULL) && CFRunLoopTimerIsValid(S_timer)) { |
2148 | // With the IONetworkStack object now available we can | |
2149 | // reset (shorten?) the time we are willing to wait for | |
2150 | // IOKit to quiesce. | |
2151 | CFRunLoopTimerSetNextFireDate(S_timer, | |
2152 | CFAbsoluteTimeGetCurrent() + S_quiet_timeout); | |
2153 | } | |
2154 | ||
edebe297 A |
2155 | updateInterfaces(); |
2156 | ||
2157 | error: | |
2158 | if (stack != MACH_PORT_NULL) { | |
2159 | IOObjectRelease(stack); | |
2160 | } | |
2161 | ||
2162 | return; | |
2163 | } | |
2164 | ||
2165 | static void | |
2166 | quietCallback(void *refcon, | |
2167 | io_service_t service, | |
2168 | natural_t messageType, | |
2169 | void *messageArgument) | |
2170 | { | |
2171 | if (messageArgument != NULL) { | |
2172 | // if not yet quiet | |
2173 | return; | |
2174 | } | |
2175 | ||
2176 | if (messageType == kIOMessageServiceBusyStateChange) { | |
2177 | addTimestamp(S_state, CFSTR("*QUIET*")); | |
2178 | SCLog(S_debug, LOG_INFO, | |
2179 | CFSTR(MY_PLUGIN_NAME ": IOKit quiet")); | |
2180 | } | |
2181 | ||
2182 | if (S_connect == MACH_PORT_NULL) { | |
2183 | SCLog(TRUE, LOG_ERR, | |
dbf6a266 | 2184 | CFSTR(MY_PLUGIN_NAME ": No network stack object")); |
edebe297 | 2185 | return; |
dbf6a266 | 2186 | } |
edebe297 A |
2187 | |
2188 | if (S_quiet != MACH_PORT_NULL) { | |
2189 | IOObjectRelease(S_quiet); | |
2190 | S_quiet = MACH_PORT_NULL; | |
2191 | } | |
2192 | ||
2193 | if (S_timer != NULL) { | |
2194 | CFRunLoopTimerInvalidate(S_timer); | |
2195 | CFRelease(S_timer); | |
2196 | S_timer = NULL; | |
2197 | } | |
2198 | ||
2199 | // grab (and name) any additional interfaces. | |
2200 | interfaceArrivalCallback((void *)S_notify, S_iter); | |
2201 | ||
17d3ee29 | 2202 | #if !TARGET_OS_EMBEDDED |
edebe297 | 2203 | updatePlatformUUID(); |
17d3ee29 | 2204 | #endif // !TARGET_OS_EMBEDDED |
edebe297 A |
2205 | |
2206 | return; | |
2207 | } | |
2208 | ||
2209 | static void | |
6bb65964 | 2210 | iterateRegistryBusy(io_iterator_t iterator, CFArrayRef nodes, CFMutableStringRef snapshot, int *count) |
edebe297 A |
2211 | { |
2212 | kern_return_t kr = kIOReturnSuccess;; | |
2213 | io_object_t obj; | |
2214 | ||
2215 | while ((kr == kIOReturnSuccess) && | |
2216 | ((obj = IOIteratorNext(iterator)) != MACH_PORT_NULL)) { | |
6bb65964 A |
2217 | uint64_t accumulated_busy_time; |
2218 | uint32_t busy_state; | |
edebe297 A |
2219 | io_name_t location; |
2220 | io_name_t name; | |
2221 | CFMutableArrayRef newNodes; | |
6bb65964 | 2222 | uint64_t state; |
edebe297 A |
2223 | CFMutableStringRef str = NULL; |
2224 | ||
2225 | if (nodes == NULL) { | |
2226 | newNodes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |
2227 | } else { | |
2228 | newNodes = CFArrayCreateMutableCopy(NULL, 0, nodes); | |
2229 | } | |
5e9ce69e | 2230 | assert(newNodes != NULL); |
edebe297 A |
2231 | |
2232 | kr = IORegistryEntryGetName(obj, name); | |
2233 | if (kr != kIOReturnSuccess) { | |
2234 | SCLog(TRUE, LOG_ERR, | |
6bb65964 | 2235 | CFSTR(MY_PLUGIN_NAME ": captureBusy IORegistryEntryGetName returned 0x%x"), |
edebe297 A |
2236 | kr); |
2237 | goto next; | |
2238 | } | |
2239 | ||
2240 | str = CFStringCreateMutable(NULL, 0); | |
2241 | CFStringAppendCString(str, name, kCFStringEncodingUTF8); | |
2242 | ||
2243 | kr = IORegistryEntryGetLocationInPlane(obj, kIOServicePlane, location); | |
2244 | switch (kr) { | |
2245 | case kIOReturnSuccess : | |
2246 | CFStringAppendCString(str, "@", kCFStringEncodingUTF8); | |
2247 | CFStringAppendCString(str, location, kCFStringEncodingUTF8); | |
2248 | break; | |
2249 | case kIOReturnNotFound : | |
2250 | break; | |
2251 | default : | |
2252 | SCLog(TRUE, LOG_ERR, | |
6bb65964 | 2253 | CFSTR(MY_PLUGIN_NAME ": captureBusy IORegistryEntryGetLocationInPlane returned 0x%x"), |
edebe297 | 2254 | kr); |
a40a14f8 | 2255 | CFRelease(str); |
edebe297 | 2256 | goto next; |
edebe297 A |
2257 | } |
2258 | ||
2259 | CFArrayAppendValue(newNodes, str); | |
2260 | CFRelease(str); | |
2261 | ||
6bb65964 | 2262 | kr = IOServiceGetBusyStateAndTime(obj, &state, &busy_state, &accumulated_busy_time); |
edebe297 A |
2263 | if (kr != kIOReturnSuccess) { |
2264 | SCLog(TRUE, LOG_ERR, | |
6bb65964 | 2265 | CFSTR(MY_PLUGIN_NAME ": captureBusy IOServiceGetBusyStateAndTime returned 0x%x"), |
edebe297 A |
2266 | kr); |
2267 | goto next; | |
2268 | } | |
2269 | ||
6bb65964 A |
2270 | #ifdef TEST_SNAPSHOT |
2271 | // report all nodes | |
2272 | busy_state = 1; | |
2273 | #endif // TEST_SNAPSHOT | |
2274 | ||
2275 | if (busy_state != 0) { | |
edebe297 A |
2276 | CFStringRef path; |
2277 | ||
2278 | if ((*count)++ == 0) { | |
6bb65964 | 2279 | CFStringAppend(snapshot, CFSTR("Busy services :")); |
edebe297 A |
2280 | } |
2281 | ||
2282 | path = CFStringCreateByCombiningStrings(NULL, newNodes, CFSTR("/")); | |
6bb65964 A |
2283 | CFStringAppendFormat(snapshot, NULL, |
2284 | CFSTR("\n %@ [%s%s%s%d, %lld ms]"), | |
2285 | path, | |
2286 | (state & kIOServiceRegisteredState) ? "" : "!registered, ", | |
2287 | (state & kIOServiceMatchedState) ? "" : "!matched, ", | |
2288 | (state & kIOServiceInactiveState) ? "inactive, " : "", | |
17d3ee29 | 2289 | busy_state, |
6bb65964 | 2290 | accumulated_busy_time / kMillisecondScale); |
edebe297 A |
2291 | CFRelease(path); |
2292 | } | |
2293 | ||
2294 | kr = IORegistryIteratorEnterEntry(iterator); | |
2295 | if (kr != kIOReturnSuccess) { | |
2296 | SCLog(TRUE, LOG_ERR, | |
6bb65964 | 2297 | CFSTR(MY_PLUGIN_NAME ": captureBusy IORegistryIteratorEnterEntry returned 0x%x"), |
edebe297 A |
2298 | kr); |
2299 | goto next; | |
2300 | } | |
2301 | ||
6bb65964 | 2302 | iterateRegistryBusy(iterator, newNodes, snapshot, count); |
edebe297 A |
2303 | |
2304 | kr = IORegistryIteratorExitEntry(iterator); | |
2305 | if (kr != kIOReturnSuccess) { | |
2306 | SCLog(TRUE, LOG_ERR, | |
6bb65964 | 2307 | CFSTR(MY_PLUGIN_NAME ": captureBusy IORegistryIteratorExitEntry returned 0x%x"), |
edebe297 A |
2308 | kr); |
2309 | } | |
2310 | ||
2311 | next : | |
2312 | ||
2313 | CFRelease(newNodes); | |
2314 | IOObjectRelease(obj); | |
2315 | } | |
2316 | ||
2317 | return; | |
2318 | } | |
2319 | ||
17d3ee29 | 2320 | static CF_RETURNS_RETAINED CFStringRef |
6bb65964 | 2321 | captureBusy() |
edebe297 A |
2322 | { |
2323 | int count = 0; | |
2324 | io_iterator_t iterator = MACH_PORT_NULL; | |
2325 | kern_return_t kr; | |
6bb65964 A |
2326 | CFMutableStringRef snapshot; |
2327 | ||
2328 | snapshot = CFStringCreateMutable(NULL, 0); | |
edebe297 A |
2329 | |
2330 | kr = IORegistryCreateIterator(kIOMasterPortDefault, | |
2331 | kIOServicePlane, | |
2332 | 0, | |
2333 | &iterator); | |
2334 | if (kr != kIOReturnSuccess) { | |
2335 | SCLog(TRUE, LOG_ERR, | |
6bb65964 | 2336 | CFSTR(MY_PLUGIN_NAME ": captureBusy IORegistryCreateIterator returned 0x%x"), |
edebe297 | 2337 | kr); |
6bb65964 A |
2338 | return snapshot; |
2339 | } | |
2340 | ||
2341 | iterateRegistryBusy(iterator, NULL, snapshot, &count); | |
2342 | if (count == 0) { | |
2343 | CFStringAppend(snapshot, CFSTR("w/no busy services")); | |
edebe297 A |
2344 | } |
2345 | ||
edebe297 | 2346 | IOObjectRelease(iterator); |
6bb65964 | 2347 | return snapshot; |
edebe297 A |
2348 | } |
2349 | ||
2350 | static void | |
2351 | timerCallback(CFRunLoopTimerRef timer, void *info) | |
2352 | { | |
6bb65964 A |
2353 | CFStringRef snapshot; |
2354 | ||
2355 | // We've been waiting for IOKit to quiesce and it just | |
2356 | // hasn't happenned. Time to just move on! | |
edebe297 | 2357 | addTimestamp(S_state, CFSTR("*TIMEOUT*")); |
6bb65964 A |
2358 | |
2359 | // log busy nodes | |
2360 | snapshot = captureBusy(); | |
edebe297 | 2361 | SCLog(TRUE, LOG_ERR, |
6bb65964 A |
2362 | CFSTR(MY_PLUGIN_NAME ": timed out waiting for IOKit to quiesce\n%@"), |
2363 | snapshot); | |
2364 | reportIssue("timed out waiting for IOKit to quiesce", snapshot); | |
2365 | CFRelease(snapshot); | |
edebe297 | 2366 | |
edebe297 A |
2367 | quietCallback((void *)S_notify, MACH_PORT_NULL, 0, NULL); |
2368 | return; | |
2369 | } | |
2370 | ||
2371 | static Boolean | |
2372 | setup_IOKit(CFBundleRef bundle) | |
2373 | { | |
2374 | uint32_t busy; | |
edebe297 A |
2375 | kern_return_t kr; |
2376 | mach_port_t masterPort = MACH_PORT_NULL; | |
2377 | Boolean ok = FALSE; | |
2378 | io_object_t root = MACH_PORT_NULL; | |
edebe297 A |
2379 | |
2380 | // read DB of previously named network interfaces | |
2381 | S_dblist = readInterfaceList(); | |
2382 | if (S_dblist != NULL) { | |
2383 | CFIndex n; | |
2384 | ||
2385 | n = CFArrayGetCount(S_dblist); | |
2386 | if (n > 1) { | |
2387 | CFArraySortValues(S_dblist, CFRangeMake(0, n), if_unit_compare, NULL); | |
2388 | } | |
dbf6a266 A |
2389 | } |
2390 | ||
edebe297 A |
2391 | // get interfaces that were named during the last boot |
2392 | S_prev_active_list = previouslyActiveInterfaces(); | |
2393 | ||
2394 | // track how long we've waited to see each interface. | |
2395 | S_state = CFDictionaryCreateMutable(NULL, | |
2396 | 0, | |
2397 | &kCFTypeDictionaryKeyCallBacks, | |
2398 | &kCFTypeDictionaryValueCallBacks); | |
2399 | addTimestamp(S_state, CFSTR("*START*")); | |
2400 | ||
dbf6a266 A |
2401 | // Creates and returns a notification object for receiving IOKit |
2402 | // notifications of new devices or state changes. | |
edebe297 A |
2403 | kr = IOMasterPort(bootstrap_port, &masterPort); |
2404 | if (kr != KERN_SUCCESS) { | |
2405 | SCLog(TRUE, LOG_ERR, | |
2406 | CFSTR(MY_PLUGIN_NAME ": IOMasterPort returned 0x%x"), | |
2407 | kr); | |
2408 | goto done; | |
2409 | } | |
dbf6a266 A |
2410 | |
2411 | S_notify = IONotificationPortCreate(masterPort); | |
2412 | if (S_notify == NULL) { | |
edebe297 | 2413 | SCLog(TRUE, LOG_ERR, |
dbf6a266 | 2414 | CFSTR(MY_PLUGIN_NAME ": IONotificationPortCreate failed")); |
edebe297 A |
2415 | goto done; |
2416 | } | |
2417 | ||
2418 | // watch IOKit matching activity | |
2419 | root = IORegistryEntryFromPath(masterPort, kIOServicePlane ":/"); | |
2420 | if (root == MACH_PORT_NULL) { | |
2421 | SCLog(TRUE, LOG_ERR, | |
2422 | CFSTR(MY_PLUGIN_NAME ": IORegistryEntryFromPath failed")); | |
2423 | goto done; | |
2424 | } | |
2425 | ||
2426 | kr = IOServiceAddInterestNotification(S_notify, | |
2427 | root, | |
2428 | kIOBusyInterest, | |
2429 | &quietCallback, | |
2430 | (void *)S_notify, // refCon | |
2431 | &S_quiet); // notification | |
2432 | if (kr != KERN_SUCCESS) { | |
2433 | SCLog(TRUE, LOG_ERR, | |
2434 | CFSTR(MY_PLUGIN_NAME ": IOServiceAddInterestNotification returned 0x%x"), | |
2435 | kr); | |
2436 | goto done; | |
2437 | } | |
2438 | ||
2439 | kr = IOServiceGetBusyState(root, &busy); | |
2440 | if (kr != KERN_SUCCESS) { | |
2441 | SCLog(TRUE, LOG_ERR, | |
2442 | CFSTR(MY_PLUGIN_NAME ": IOServiceGetBusyState returned 0x%x"), | |
2443 | kr); | |
2444 | goto done; | |
dbf6a266 | 2445 | } |
edebe297 A |
2446 | |
2447 | // add a timer so we don't wait forever for IOKit to quiesce | |
edebe297 | 2448 | S_timer = CFRunLoopTimerCreate(NULL, |
6bb65964 | 2449 | CFAbsoluteTimeGetCurrent() + S_stack_timeout, |
edebe297 A |
2450 | 0, |
2451 | 0, | |
2452 | 0, | |
2453 | timerCallback, | |
2454 | NULL); | |
2455 | if (S_timer == NULL) { | |
2456 | SCLog(TRUE, LOG_ERR, | |
2457 | CFSTR(MY_PLUGIN_NAME ": CFRunLoopTimerCreate failed")); | |
2458 | goto done; | |
2459 | } | |
2460 | ||
2461 | CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer, kCFRunLoopDefaultMode); | |
2462 | ||
2463 | // watch for the introduction of the IONetworkStack | |
2464 | kr = IOServiceAddMatchingNotification(S_notify, | |
2465 | kIOFirstMatchNotification, | |
2466 | IOServiceMatching("IONetworkStack"), | |
2467 | &stackCallback, | |
2468 | (void *)S_notify, // refCon | |
2469 | &S_stack); // notification | |
2470 | if (kr != KERN_SUCCESS) { | |
2471 | SCLog(TRUE, LOG_ERR, | |
2472 | CFSTR(MY_PLUGIN_NAME ": IOServiceAddMatchingNotification returned 0x%x"), | |
2473 | kr); | |
2474 | goto done; | |
2475 | } | |
2476 | ||
2477 | // check and see if the stack is already available and arm the | |
2478 | // notification for its introduction. | |
2479 | stackCallback((void *)S_notify, S_stack); | |
2480 | ||
2481 | // watch for the introduction of new network interfaces | |
dbf6a266 A |
2482 | kr = IOServiceAddMatchingNotification(S_notify, |
2483 | kIOFirstMatchNotification, | |
2484 | IOServiceMatching("IONetworkInterface"), | |
2485 | &interfaceArrivalCallback, | |
edebe297 A |
2486 | (void *)S_notify, // refCon |
2487 | &S_iter); // notification | |
dbf6a266 | 2488 | if (kr != KERN_SUCCESS) { |
edebe297 A |
2489 | SCLog(TRUE, LOG_ERR, |
2490 | CFSTR(MY_PLUGIN_NAME ": IOServiceAddMatchingNotification returned 0x%x"), | |
dbf6a266 | 2491 | kr); |
edebe297 | 2492 | goto done; |
dbf6a266 A |
2493 | } |
2494 | ||
edebe297 | 2495 | // Get the current list of matches and arm the notification for |
dbf6a266 | 2496 | // future interface arrivals. |
edebe297 | 2497 | interfaceArrivalCallback((void *)S_notify, S_iter); |
dbf6a266 | 2498 | |
edebe297 A |
2499 | // Check if IOKit has already quiesced. |
2500 | quietCallback((void *)S_notify, | |
2501 | MACH_PORT_NULL, | |
2502 | kIOMessageServiceBusyStateChange, | |
a40a14f8 | 2503 | (void *)(uintptr_t)busy); |
dbf6a266 A |
2504 | |
2505 | CFRunLoopAddSource(CFRunLoopGetCurrent(), | |
2506 | IONotificationPortGetRunLoopSource(S_notify), | |
2507 | kCFRunLoopDefaultMode); | |
edebe297 A |
2508 | |
2509 | #ifdef WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET | |
2510 | /* | |
2511 | * Start the wheels turning until we've named all of | |
2512 | * the interfaces that were used during the previous | |
2513 | * boot, until IOKit [matching] has quiesced, or | |
2514 | * until we've waited long enough. | |
2515 | */ | |
2516 | CFRunLoopAddTimer(CFRunLoopGetCurrent(), S_timer, MY_PLUGIN_ID); | |
2517 | CFRunLoopAddSource(CFRunLoopGetCurrent(), | |
2518 | IONotificationPortGetRunLoopSource(S_notify), | |
2519 | MY_PLUGIN_ID); | |
2520 | while (S_prev_active_list != NULL) { | |
2521 | int rlStatus; | |
2522 | ||
2523 | rlStatus = CFRunLoopRunInMode(MY_PLUGIN_ID, 1.0e10, TRUE); | |
2524 | } | |
2525 | #endif /* WAIT_PREVIOUS_BOOT_INTERFACES_OR_QUIET */ | |
2526 | ||
5e9ce69e A |
2527 | #if !TARGET_OS_EMBEDDED |
2528 | if (S_dblist != NULL) { | |
2529 | // apply special handling for the BT-PAN interface (if present) | |
2530 | CFArrayApplyFunction(S_dblist, | |
2531 | CFRangeMake(0, CFArrayGetCount(S_dblist)), | |
2532 | updateBTPANInformation, | |
2533 | NULL); | |
2534 | } | |
2535 | #endif // !TARGET_OS_EMBEDDED | |
2536 | ||
edebe297 A |
2537 | ok = TRUE; |
2538 | ||
2539 | done: | |
2540 | if (root != MACH_PORT_NULL) { | |
2541 | IOObjectRelease(root); | |
dbf6a266 A |
2542 | } |
2543 | if (masterPort != MACH_PORT_NULL) { | |
2544 | mach_port_deallocate(mach_task_self(), masterPort); | |
2545 | } | |
edebe297 A |
2546 | |
2547 | return ok; | |
2548 | } | |
2549 | ||
2550 | static Boolean | |
2551 | setup_Virtual(CFBundleRef bundle) | |
2552 | { | |
2553 | // open a SCPreferences session | |
2554 | S_prefs = SCPreferencesCreate(NULL, CFSTR(MY_PLUGIN_NAME), NULL); | |
2555 | if (S_prefs == NULL) { | |
2556 | SCLog(TRUE, LOG_ERR, | |
2557 | CFSTR(MY_PLUGIN_NAME ": SCPreferencesCreate() failed: %s"), | |
2558 | SCErrorString(SCError())); | |
2559 | return FALSE; | |
dbf6a266 | 2560 | } |
edebe297 A |
2561 | |
2562 | // register for change notifications. | |
2563 | if (!SCPreferencesSetCallback(S_prefs, updateVirtualNetworkInterfaceConfiguration, NULL)) { | |
2564 | SCLog(TRUE, LOG_ERR, | |
2565 | CFSTR(MY_PLUGIN_NAME ": SCPreferencesSetCallBack() failed: %s"), | |
2566 | SCErrorString(SCError())); | |
2567 | CFRelease(S_prefs); | |
2568 | return FALSE; | |
2569 | } | |
2570 | ||
2571 | // schedule | |
2572 | if (!SCPreferencesScheduleWithRunLoop(S_prefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) { | |
a40a14f8 A |
2573 | if (SCError() != kSCStatusNoStoreServer) { |
2574 | SCLog(TRUE, LOG_ERR, | |
2575 | CFSTR(MY_PLUGIN_NAME ": SCPreferencesScheduleWithRunLoop() failed: %s"), | |
2576 | SCErrorString(SCError())); | |
2577 | CFRelease(S_prefs); | |
2578 | return FALSE; | |
2579 | } | |
edebe297 A |
2580 | } |
2581 | ||
2582 | return TRUE; | |
2583 | } | |
2584 | ||
6bb65964 A |
2585 | static void * |
2586 | exec_InterfaceNamer(void *arg) | |
edebe297 | 2587 | { |
6bb65964 A |
2588 | CFBundleRef bundle = (CFBundleRef)arg; |
2589 | CFDictionaryRef dict; | |
2590 | ||
6bb65964 | 2591 | pthread_setname_np(MY_PLUGIN_NAME " thread"); |
6bb65964 A |
2592 | |
2593 | dict = CFBundleGetInfoDictionary(bundle); | |
2594 | if (isA_CFDictionary(dict)) { | |
2595 | CFNumberRef num; | |
2596 | ||
2597 | num = CFDictionaryGetValue(dict, CFSTR(WAIT_STACK_TIMEOUT_KEY)); | |
2598 | if (num != NULL) { | |
2599 | if (!isA_CFNumber(num) || | |
2600 | !CFNumberGetValue(num, kCFNumberDoubleType, &S_stack_timeout) || | |
2601 | (S_stack_timeout <= 0.0)) { | |
2602 | SCLog(TRUE, LOG_ERR, | |
2603 | CFSTR(MY_PLUGIN_NAME ": " WAIT_STACK_TIMEOUT_KEY " value error")); | |
2604 | S_stack_timeout = WAIT_STACK_TIMEOUT_DEFAULT; | |
2605 | } | |
2606 | } | |
2607 | ||
2608 | num = CFDictionaryGetValue(dict, CFSTR(WAIT_QUIET_TIMEOUT_KEY)); | |
2609 | if (num != NULL) { | |
2610 | if (!isA_CFNumber(num) || | |
2611 | !CFNumberGetValue(num, kCFNumberDoubleType, &S_quiet_timeout) || | |
2612 | (S_quiet_timeout <= 0.0)) { | |
2613 | SCLog(TRUE, LOG_ERR, | |
2614 | CFSTR(MY_PLUGIN_NAME ": " WAIT_QUIET_TIMEOUT_KEY " value error")); | |
2615 | S_quiet_timeout = WAIT_QUIET_TIMEOUT_DEFAULT; | |
2616 | } | |
2617 | } | |
edebe297 A |
2618 | } |
2619 | ||
2620 | // setup virtual network interface monitoring | |
2621 | if (!setup_Virtual(bundle)) { | |
2622 | goto error; | |
2623 | } | |
2624 | ||
2625 | // setup [IOKit] network interface monitoring | |
2626 | if (!setup_IOKit(bundle)) { | |
2627 | goto error; | |
dbf6a266 | 2628 | } |
edebe297 | 2629 | |
17d3ee29 A |
2630 | #if !TARGET_OS_EMBEDDED |
2631 | // keep launchd from SIGKILL'ing us until after the platform-uuid has | |
2632 | // been updated | |
2633 | S_vproc_transaction = vproc_transaction_begin(NULL); | |
2634 | #endif // !TARGET_OS_EMBEDDED | |
2635 | ||
6bb65964 | 2636 | goto done; |
edebe297 A |
2637 | |
2638 | error : | |
dbf6a266 A |
2639 | if (S_connect != MACH_PORT_NULL) { |
2640 | IOServiceClose(S_connect); | |
2641 | S_connect = MACH_PORT_NULL; | |
2642 | } | |
edebe297 A |
2643 | if (S_dblist != NULL) { |
2644 | CFRelease(S_dblist); | |
2645 | S_dblist = NULL; | |
2646 | } | |
dbf6a266 A |
2647 | if (S_iter != MACH_PORT_NULL) { |
2648 | IOObjectRelease(S_iter); | |
2649 | S_iter = MACH_PORT_NULL; | |
2650 | } | |
2651 | if (S_notify != MACH_PORT_NULL) { | |
2652 | IONotificationPortDestroy(S_notify); | |
2653 | } | |
edebe297 A |
2654 | if (S_quiet != MACH_PORT_NULL) { |
2655 | IOObjectRelease(S_quiet); | |
2656 | S_quiet = MACH_PORT_NULL; | |
2657 | } | |
2658 | if (S_stack != MACH_PORT_NULL) { | |
2659 | IOObjectRelease(S_stack); | |
2660 | S_stack = MACH_PORT_NULL; | |
2661 | } | |
2662 | if (S_state != NULL) { | |
2663 | CFRelease(S_state); | |
2664 | S_state = NULL; | |
2665 | } | |
2666 | if (S_timer != NULL) { | |
2667 | CFRunLoopTimerInvalidate(S_timer); | |
2668 | CFRelease(S_timer); | |
2669 | S_timer = NULL; | |
2670 | } | |
2671 | ||
6bb65964 | 2672 | done : |
6bb65964 A |
2673 | CFRelease(bundle); |
2674 | CFRunLoopRun(); | |
6bb65964 A |
2675 | |
2676 | return NULL; | |
2677 | } | |
2678 | ||
2679 | __private_extern__ | |
2680 | void | |
2681 | load_InterfaceNamer(CFBundleRef bundle, Boolean bundleVerbose) | |
2682 | { | |
17d3ee29 A |
2683 | pthread_attr_t tattr; |
2684 | pthread_t tid; | |
2685 | ||
6bb65964 A |
2686 | if (bundleVerbose) { |
2687 | S_debug = TRUE; | |
2688 | } | |
2689 | ||
17d3ee29 | 2690 | CFRetain(bundle); // released in exec_InterfaceNamer |
6bb65964 | 2691 | |
17d3ee29 A |
2692 | pthread_attr_init(&tattr); |
2693 | pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM); | |
2694 | pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); | |
2695 | // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack | |
2696 | pthread_create(&tid, &tattr, exec_InterfaceNamer, bundle); | |
2697 | pthread_attr_destroy(&tattr); | |
6bb65964 | 2698 | |
dbf6a266 A |
2699 | return; |
2700 | } | |
2701 | ||
2702 | //------------------------------------------------------------------------ | |
2703 | // Main function. | |
2704 | #ifdef MAIN | |
2705 | int | |
2706 | main(int argc, char ** argv) | |
2707 | { | |
17d3ee29 A |
2708 | CFBundleRef bundle; |
2709 | ||
edebe297 A |
2710 | _sc_log = FALSE; |
2711 | _sc_verbose = (argc > 1) ? TRUE : FALSE; | |
2712 | ||
17d3ee29 A |
2713 | S_debug = _sc_verbose; |
2714 | ||
2715 | bundle = CFBundleGetMainBundle(); | |
2716 | CFRetain(bundle); // released in exec_InterfaceNamer | |
2717 | ||
2718 | (void)exec_InterfaceNamer(); | |
2719 | ||
dbf6a266 A |
2720 | /* not reached */ |
2721 | exit(0); | |
2722 | return 0; | |
2723 | } | |
2724 | #endif /* MAIN */ | |
edebe297 A |
2725 | |
2726 | #ifdef TEST_PLATFORM_UUID | |
2727 | int | |
2728 | main(int argc, char ** argv) | |
2729 | { | |
17d3ee29 | 2730 | CFStringRef guid; |
edebe297 A |
2731 | CFArrayRef interfaces; |
2732 | ||
2733 | _sc_log = FALSE; | |
2734 | _sc_verbose = (argc > 1) ? TRUE : FALSE; | |
2735 | ||
2736 | S_dblist = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |
2737 | interfaces = SCNetworkInterfaceCopyAll(); | |
2738 | if (interfaces != NULL) { | |
2739 | CFIndex i; | |
2740 | CFIndex n; | |
2741 | ||
2742 | n = CFArrayGetCount(interfaces); | |
2743 | for (i = 0; i < n; i++) { | |
2744 | CFDictionaryRef dict; | |
2745 | SCNetworkInterfaceRef interface; | |
2746 | ||
2747 | interface = CFArrayGetValueAtIndex(interfaces, i); | |
2748 | dict = createInterfaceDict(interface); | |
2749 | CFArrayAppendValue(S_dblist, dict); | |
2750 | CFRelease(dict); | |
2751 | } | |
2752 | CFRelease(interfaces); | |
2753 | } | |
17d3ee29 A |
2754 | |
2755 | guid = copyEthernetUUID(); | |
2756 | SCPrint(TRUE, stdout, CFSTR("copyEthernetUUID() = %@\n"), (guid != NULL) ? guid : CFSTR("NULL")); | |
2757 | if (guid != NULL) CFRelease(guid); | |
2758 | ||
edebe297 A |
2759 | updatePlatformUUID(); |
2760 | CFRelease(S_dblist); | |
2761 | exit(0); | |
2762 | return 0; | |
2763 | } | |
2764 | #endif /* TEST_PLATFORM_UUID */ | |
6bb65964 A |
2765 | |
2766 | #ifdef TEST_SNAPSHOT | |
2767 | int | |
2768 | main(int argc, char ** argv) | |
2769 | { | |
2770 | CFStringRef snapshot; | |
2771 | ||
2772 | _sc_log = FALSE; | |
2773 | _sc_verbose = (argc > 1) ? TRUE : FALSE; | |
2774 | ||
2775 | snapshot = captureBusy(); | |
2776 | SCPrint(TRUE, stdout, CFSTR("%@\n"), snapshot); | |
2777 | CFRelease(snapshot); | |
2778 | ||
2779 | exit(0); | |
2780 | return 0; | |
2781 | } | |
2782 | #endif /* TEST_SNAPSHOT */ | |
2783 |