]> git.saurik.com Git - apple/configd.git/blob - Plugins/LinkConfiguration/linkconfig.c
configd-802.40.13.tar.gz
[apple/configd.git] / Plugins / LinkConfiguration / linkconfig.c
1 /*
2 * Copyright (c) 2002-2007, 2011, 2013, 2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * October 21, 2000 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
36 #include <sys/wait.h>
37 #include <net/if.h>
38 #include <net/if_media.h>
39
40 #include <SystemConfiguration/SystemConfiguration.h>
41 #include <SystemConfiguration/SCPrivate.h>
42 #include <SystemConfiguration/SCValidation.h>
43 #include <SystemConfiguration/SCDPlugin.h> // for _SCDPluginExecCommand
44
45 #include "SCNetworkConfigurationInternal.h"
46
47
48 static CFMutableDictionaryRef baseSettings = NULL;
49 static CFStringRef interfacesKey = NULL;
50 static SCDynamicStoreRef store = NULL;
51 static CFRunLoopSourceRef rls = NULL;
52 static CFMutableDictionaryRef wantSettings = NULL;
53
54
55 #pragma mark -
56 #pragma mark Capabilities
57
58
59 #define CAPABILITIES_KEY CFSTR("_CAPABILITIES_")
60
61
62 __private_extern__
63 Boolean
64 _SCNetworkInterfaceSetCapabilities(SCNetworkInterfaceRef interface,
65 CFDictionaryRef options)
66 {
67 CFDictionaryRef baseOptions;
68 int cap_base;
69 int cap_current;
70 int cap_requested;
71 CFStringRef interfaceName;
72
73 #ifdef SIOCSIFCAP
74 struct ifreq ifr;
75 int ret;
76 int sock;
77 #endif // SIOCSIFCAP
78
79 interfaceName = SCNetworkInterfaceGetBSDName(interface);
80 if (interfaceName == NULL) {
81 /* if no BSD interface name */
82 return FALSE;
83 }
84
85 cap_current = __SCNetworkInterfaceCreateCapabilities(interface, -1, NULL);
86 if (cap_current == -1) {
87 /* could not get current capabilities */
88 return FALSE;
89 }
90
91 // get base capabilities
92 cap_base = cap_current;
93 baseOptions = CFDictionaryGetValue(baseSettings, interfaceName);
94 if (baseOptions != NULL) {
95 CFNumberRef num;
96
97 num = CFDictionaryGetValue(baseOptions, CAPABILITIES_KEY);
98 if (num != NULL) {
99 CFNumberGetValue(num, kCFNumberIntType, &cap_base);
100 }
101 }
102
103 cap_requested = __SCNetworkInterfaceCreateCapabilities(interface, cap_base, options);
104
105 #ifdef SIOCSIFCAP
106 if (cap_requested == cap_current) {
107 /* if current setting is as requested */
108 return TRUE;
109 }
110
111 bzero((char *)&ifr, sizeof(ifr));
112 (void)_SC_cfstring_to_cstring(interfaceName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII);
113 ifr.ifr_curcap = cap_current;
114 ifr.ifr_reqcap = cap_requested;
115
116 sock = socket(AF_INET, SOCK_DGRAM, 0);
117 if (sock == -1) {
118 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno));
119 return FALSE;
120 }
121
122 ret = ioctl(sock, SIOCSIFCAP, (caddr_t)&ifr);
123 (void)close(sock);
124 if (ret == -1) {
125 SC_log(LOG_INFO, "ioctl(SIOCSIFCAP) failed: %s", strerror(errno));
126 return FALSE;
127 }
128 #endif // SIOCSIFCAP
129
130 return TRUE;
131 }
132
133
134 #pragma mark -
135 #pragma mark Media options
136
137
138 static CFDictionaryRef
139 __copyMediaOptions(CFDictionaryRef options)
140 {
141 CFMutableDictionaryRef requested = NULL;
142 CFTypeRef val;
143
144 if (!isA_CFDictionary(options)) {
145 return NULL;
146 }
147
148 val = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType);
149 if (isA_CFString(val)) {
150 requested = CFDictionaryCreateMutable(NULL,
151 0,
152 &kCFTypeDictionaryKeyCallBacks,
153 &kCFTypeDictionaryValueCallBacks);
154 CFDictionaryAddValue(requested, kSCPropNetEthernetMediaSubType, val);
155 } else {
156 /* if garbage */;
157 return NULL;
158 }
159
160 val = CFDictionaryGetValue(options, kSCPropNetEthernetMediaOptions);
161 if (isA_CFArray(val)) {
162 CFDictionaryAddValue(requested, kSCPropNetEthernetMediaOptions, val);
163 } else {
164 /* if garbage */;
165 CFRelease(requested);
166 return NULL;
167 }
168
169 return requested;
170 }
171
172
173 __private_extern__
174 Boolean
175 _SCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef interface,
176 CFDictionaryRef options)
177 {
178 CFArrayRef available = NULL;
179 CFDictionaryRef current = NULL;
180 struct ifmediareq ifm;
181 struct ifreq ifr;
182 CFStringRef interfaceName;
183 Boolean ok = FALSE;
184 int newOptions;
185 CFDictionaryRef requested;
186 int sock = -1;
187
188 if (!isA_SCNetworkInterface(interface)) {
189 _SCErrorSet(kSCStatusInvalidArgument);
190 return FALSE;
191 }
192
193 interfaceName = SCNetworkInterfaceGetBSDName(interface);
194 if (interfaceName == NULL) {
195 /* if no BSD interface name */
196 SC_log(LOG_INFO, "no BSD interface name for %@", interface);
197 _SCErrorSet(kSCStatusInvalidArgument);
198 return FALSE;
199 }
200
201 /* get current & available options */
202 if (!SCNetworkInterfaceCopyMediaOptions(interface, &current, NULL, &available, FALSE)) {
203 /* could not get current media options */
204 SC_log(LOG_INFO, "no media options for %@", interfaceName);
205 return FALSE;
206 }
207
208 /* extract just the dictionary key/value pairs of interest */
209 requested = __copyMediaOptions(options);
210 if (requested == NULL) {
211 CFDictionaryRef baseOptions;
212
213 /* get base options */
214 baseOptions = CFDictionaryGetValue(baseSettings, interfaceName);
215 requested = __copyMediaOptions(baseOptions);
216 }
217 if (requested == NULL) {
218 /* get base options */
219 requested = __copyMediaOptions(current);
220 }
221 if (requested == NULL) {
222 /* if no media options to set */
223 goto done;
224 }
225
226 if ((current != NULL) && CFEqual(current, requested)) {
227 /* if current settings are as requested */
228 ok = TRUE;
229 goto done;
230 }
231
232 if (!CFArrayContainsValue(available, CFRangeMake(0, CFArrayGetCount(available)), requested)) {
233 /* if requested settings not currently available */
234 SC_log(LOG_INFO, "requested media settings unavailable for %@", interfaceName);
235 goto done;
236 }
237
238 newOptions = __SCNetworkInterfaceCreateMediaOptions(interface, requested);
239 if (newOptions == -1) {
240 /* since we have just validated, this should never happen */
241 goto done;
242 }
243
244 sock = socket(AF_INET, SOCK_DGRAM, 0);
245 if (sock == -1) {
246 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno));
247 goto done;
248 }
249
250 bzero((char *)&ifm, sizeof(ifm));
251 (void)_SC_cfstring_to_cstring(interfaceName, ifm.ifm_name, sizeof(ifm.ifm_name), kCFStringEncodingASCII);
252
253 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifm) == -1) {
254 SC_log(LOG_NOTICE, "ioctl(SIOCGIFMEDIA) failed: %s", strerror(errno));
255 goto done;
256 }
257
258 bzero((char *)&ifr, sizeof(ifr));
259 bcopy(ifm.ifm_name, ifr.ifr_name, sizeof(ifr.ifr_name));
260 ifr.ifr_media = ifm.ifm_current & ~(IFM_NMASK|IFM_TMASK|IFM_OMASK|IFM_GMASK);
261 ifr.ifr_media |= newOptions;
262
263 SC_log(LOG_INFO, "old media settings: 0x%8.8x (0x%8.8x)", ifm.ifm_current, ifm.ifm_active);
264 SC_log(LOG_INFO, "new media settings: 0x%8.8x", ifr.ifr_media);
265
266 if (ioctl(sock, SIOCSIFMEDIA, (caddr_t)&ifr) == -1) {
267 SC_log(LOG_NOTICE, "%@: ioctl(SIOCSIFMEDIA) failed: %s", interfaceName, strerror(errno));
268 goto done;
269 }
270
271 ok = TRUE;
272
273 done :
274
275 if (available != NULL) CFRelease(available);
276 if (current != NULL) CFRelease(current);
277 if (requested != NULL) CFRelease(requested);
278 if (sock != -1) (void)close(sock);
279
280 return ok;
281 }
282
283
284 #pragma mark -
285 #pragma mark MTU
286
287
288 #ifndef USE_SIOCSIFMTU
289 static void
290 ifconfig_exit(pid_t pid, int status, struct rusage *rusage, void *context)
291 {
292 char *if_name = (char *)context;
293
294 if (WIFEXITED(status)) {
295 if (WEXITSTATUS(status) != 0) {
296 SC_log(LOG_NOTICE, "ifconfig %s failed, exit status = %d",
297 if_name,
298 WEXITSTATUS(status));
299 }
300 } else if (WIFSIGNALED(status)) {
301 SC_log(LOG_NOTICE, "ifconfig %s: terminated w/signal = %d",
302 if_name,
303 WTERMSIG(status));
304 } else {
305 SC_log(LOG_NOTICE, "ifconfig %s: exit status = %d",
306 if_name,
307 status);
308 }
309
310 CFAllocatorDeallocate(NULL, if_name);
311 return;
312 }
313 #endif /* !USE_SIOCSIFMTU */
314
315
316 __private_extern__
317 Boolean
318 _SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface,
319 CFDictionaryRef options)
320 {
321 CFStringRef interfaceName;
322 int mtu_cur = -1;
323 int mtu_max = -1;
324 int mtu_min = -1;
325 int requested;
326 CFNumberRef val;
327
328 interfaceName = SCNetworkInterfaceGetBSDName(interface);
329 if (interfaceName == NULL) {
330 /* if no BSD interface name */
331 return FALSE;
332 }
333
334 if (!SCNetworkInterfaceCopyMTU(interface, &mtu_cur, &mtu_min, &mtu_max)) {
335 /* could not get current MTU */
336 return FALSE;
337 }
338
339 val = NULL;
340 if (isA_CFDictionary(options)) {
341 val = CFDictionaryGetValue(options, kSCPropNetEthernetMTU);
342 val = isA_CFNumber(val);
343 }
344 if (val == NULL) {
345 CFDictionaryRef baseOptions;
346
347 /* get base MTU */
348 baseOptions = CFDictionaryGetValue(baseSettings, interfaceName);
349 if (baseOptions != NULL) {
350 val = CFDictionaryGetValue(baseOptions, kSCPropNetEthernetMTU);
351 }
352 }
353 if (val != NULL) {
354 CFNumberGetValue(val, kCFNumberIntType, &requested);
355 } else {
356 requested = mtu_cur;
357 }
358
359 if (requested == mtu_cur) {
360 /* if current setting is as requested */
361 return TRUE;
362 }
363
364 if (((mtu_min >= 0) && (requested < mtu_min)) ||
365 ((mtu_max >= 0) && (requested > mtu_max))) {
366 /* if requested MTU outside of the valid range */
367 return FALSE;
368 }
369
370 #ifdef USE_SIOCSIFMTU
371 {
372 struct ifreq ifr;
373 int ret;
374 int sock;
375
376 bzero((char *)&ifr, sizeof(ifr));
377 (void)_SC_cfstring_to_cstring(interfaceName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII);
378 ifr.ifr_mtu = requested;
379
380 sock = socket(AF_INET, SOCK_DGRAM, 0);
381 if (sock == -1) {
382 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno));
383 return FALSE;
384 }
385
386 ret = ioctl(sock, SIOCSIFMTU, (caddr_t)&ifr);
387 (void)close(sock);
388 if (ret == -1) {
389 SC_log(LOG_NOTICE, "ioctl(SIOCSIFMTU) failed: %s", strerror(errno));
390 return FALSE;
391 }
392 }
393 #else /* !USE_SIOCSIFMTU */
394 {
395 char *ifconfig_argv[] = { "ifconfig", NULL, "mtu", NULL, NULL };
396 pid_t pid;
397
398 ifconfig_argv[1] = _SC_cfstring_to_cstring(interfaceName, NULL, 0, kCFStringEncodingASCII);
399 (void)asprintf(&ifconfig_argv[3], "%d", requested);
400
401 pid = _SCDPluginExecCommand(ifconfig_exit, // callout,
402 ifconfig_argv[1], // context
403 0, // uid
404 0, // gid
405 "/sbin/ifconfig", // path
406 ifconfig_argv // argv
407 );
408
409 // CFAllocatorDeallocate(NULL, ifconfig_argv[1]); // released in ifconfig_exit()
410 free(ifconfig_argv[3]);
411
412 if (pid <= 0) {
413 return FALSE;
414 }
415 }
416 #endif /* !USE_SIOCSIFMTU */
417
418 return TRUE;
419 }
420
421
422 #pragma mark -
423 #pragma mark Update link configuration
424
425
426 /*
427 * Function: parse_component
428 * Purpose:
429 * Given a string 'key' and a string prefix 'prefix',
430 * return the next component in the slash '/' separated
431 * key.
432 *
433 * Examples:
434 * 1. key = "a/b/c" prefix = "a/"
435 * returns "b"
436 * 2. key = "a/b/c" prefix = "a/b/"
437 * returns "c"
438 */
439 static CF_RETURNS_RETAINED CFStringRef
440 parse_component(CFStringRef key, CFStringRef prefix)
441 {
442 CFMutableStringRef comp;
443 CFRange range;
444
445 if (CFStringHasPrefix(key, prefix) == FALSE) {
446 return NULL;
447 }
448 comp = CFStringCreateMutableCopy(NULL, 0, key);
449 CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix)));
450 range = CFStringFind(comp, CFSTR("/"), 0);
451 if (range.location == kCFNotFound) {
452 return comp;
453 }
454 range.length = CFStringGetLength(comp) - range.location;
455 CFStringDelete(comp, range);
456 return comp;
457 }
458
459
460 static void updateLink(CFStringRef interfaceName, CFDictionaryRef options);
461
462
463 static void
464 updateInterfaces(CFArrayRef newInterfaces)
465 {
466 CFIndex i;
467 CFIndex n_old;
468 CFIndex n_new;
469 static CFArrayRef oldInterfaces = NULL;
470
471 n_old = (oldInterfaces != NULL) ? CFArrayGetCount(oldInterfaces) : 0;
472 n_new = CFArrayGetCount(newInterfaces);
473
474 for (i = 0; i < n_new; i++) {
475 CFStringRef interfaceName;
476
477 interfaceName = CFArrayGetValueAtIndex(newInterfaces, i);
478
479 if ((n_old == 0) ||
480 !CFArrayContainsValue(oldInterfaces,
481 CFRangeMake(0, n_old),
482 interfaceName)) {
483 CFDictionaryRef options;
484
485 // if new interface
486 options = CFDictionaryGetValue(wantSettings, interfaceName);
487 updateLink(interfaceName, options);
488 }
489 }
490
491 if (oldInterfaces != NULL) CFRelease(oldInterfaces);
492 oldInterfaces = CFRetain(newInterfaces);
493 }
494
495
496 static void
497 updateLink(CFStringRef interfaceName, CFDictionaryRef options)
498 {
499 SCNetworkInterfaceRef interface;
500
501 /* retain requested configuration */
502 if (options != NULL) {
503 CFDictionarySetValue(wantSettings, interfaceName, options);
504 } else {
505 CFDictionaryRemoveValue(wantSettings, interfaceName);
506 }
507
508 /* apply requested configuration */
509 interface = _SCNetworkInterfaceCreateWithBSDName(NULL, interfaceName,
510 kIncludeAllVirtualInterfaces);
511 if (interface == NULL) {
512 return;
513 }
514
515 if (options != NULL) {
516 if (!CFDictionaryContainsKey(baseSettings, interfaceName)) {
517 int cur_cap = -1;
518 CFDictionaryRef cur_media = NULL;
519 CFMutableDictionaryRef new_media = NULL;
520 int cur_mtu = -1;
521
522 /* preserve current media options */
523 if (SCNetworkInterfaceCopyMediaOptions(interface, &cur_media, NULL, NULL, FALSE)) {
524 if (cur_media != NULL) {
525 new_media = CFDictionaryCreateMutableCopy(NULL, 0, cur_media);
526 CFRelease(cur_media);
527 }
528 }
529
530 /* preserve current MTU */
531 if (SCNetworkInterfaceCopyMTU(interface, &cur_mtu, NULL, NULL)) {
532 if (cur_mtu != -1) {
533 CFNumberRef num;
534
535 if (new_media == NULL) {
536 new_media = CFDictionaryCreateMutable(NULL,
537 0,
538 &kCFTypeDictionaryKeyCallBacks,
539 &kCFTypeDictionaryValueCallBacks);
540 }
541
542 num = CFNumberCreate(NULL, kCFNumberIntType, &cur_mtu);
543 CFDictionaryAddValue(new_media, kSCPropNetEthernetMTU, num);
544 CFRelease(num);
545 }
546 }
547
548 /* preserve capabilities */
549 cur_cap = __SCNetworkInterfaceCreateCapabilities(interface, -1, NULL);
550 if (cur_cap != -1) {
551 CFNumberRef num;
552
553 if (new_media == NULL) {
554 new_media = CFDictionaryCreateMutable(NULL,
555 0,
556 &kCFTypeDictionaryKeyCallBacks,
557 &kCFTypeDictionaryValueCallBacks);
558 }
559
560 num = CFNumberCreate(NULL, kCFNumberIntType, &cur_cap);
561 CFDictionaryAddValue(new_media, CAPABILITIES_KEY, num);
562 CFRelease(num);
563 }
564
565 if (new_media != NULL) {
566 CFDictionarySetValue(baseSettings, interfaceName, new_media);
567 CFRelease(new_media);
568 }
569 }
570
571 /* establish new settings */
572 (void)_SCNetworkInterfaceSetCapabilities(interface, options);
573 (void)_SCNetworkInterfaceSetMediaOptions(interface, options);
574 (void)_SCNetworkInterfaceSetMTU (interface, options);
575 } else {
576 /* no requested settings */
577 options = CFDictionaryGetValue(baseSettings, interfaceName);
578 if (options != NULL) {
579 /* restore original settings */
580 (void)_SCNetworkInterfaceSetCapabilities(interface, options);
581 (void)_SCNetworkInterfaceSetMediaOptions(interface, options);
582 (void)_SCNetworkInterfaceSetMTU (interface, options);
583 CFDictionaryRemoveValue(baseSettings, interfaceName);
584 }
585 }
586
587 CFRelease(interface);
588 return;
589 }
590
591
592 static void
593 linkConfigChangedCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *arg)
594 {
595 os_activity_t activity_id;
596 CFDictionaryRef changes;
597 CFIndex i;
598 CFIndex n;
599 static CFStringRef prefix = NULL;
600
601 activity_id = os_activity_start("processing link configuration changes",
602 OS_ACTIVITY_FLAG_DEFAULT);
603
604 if (prefix == NULL) {
605 prefix = SCDynamicStoreKeyCreate(NULL,
606 CFSTR("%@/%@/%@/"),
607 kSCDynamicStoreDomainSetup,
608 kSCCompNetwork,
609 kSCCompInterface);
610 }
611
612 changes = SCDynamicStoreCopyMultiple(store, changedKeys, NULL);
613
614 n = (changes != NULL) ? CFArrayGetCount(changedKeys) : 0;
615 for (i = 0; i < n; i++) {
616 CFStringRef key;
617 CFDictionaryRef info;
618
619 key = CFArrayGetValueAtIndex(changedKeys, i);
620 info = CFDictionaryGetValue(changes, key);
621
622 if (CFEqual(key, interfacesKey)) {
623 if (isA_CFDictionary(info) != NULL) {
624 CFArrayRef interfaces;
625
626 interfaces = CFDictionaryGetValue(info, kSCPropNetInterfaces);
627 if (isA_CFArray(interfaces)) {
628 updateInterfaces(interfaces);
629 }
630 }
631 } else {
632 CFStringRef interfaceName;
633
634 interfaceName = parse_component(key, prefix);
635 if (interfaceName != NULL) {
636 updateLink(interfaceName, info);
637 CFRelease(interfaceName);
638 }
639 }
640 }
641
642 if (changes != NULL) {
643 CFRelease(changes);
644 }
645
646 os_activity_end(activity_id);
647
648 return;
649 }
650
651
652 __private_extern__
653 void
654 load_LinkConfiguration(CFBundleRef bundle, Boolean bundleVerbose)
655 {
656 CFStringRef key;
657 CFMutableArrayRef keys = NULL;
658 Boolean ok;
659 CFMutableArrayRef patterns = NULL;
660
661 SC_log(LOG_DEBUG, "load() called");
662 SC_log(LOG_DEBUG, " bundle ID = %@", CFBundleGetIdentifier(bundle));
663
664 /* initialize a few globals */
665
666 baseSettings = CFDictionaryCreateMutable(NULL,
667 0,
668 &kCFTypeDictionaryKeyCallBacks,
669 &kCFTypeDictionaryValueCallBacks);
670 wantSettings = CFDictionaryCreateMutable(NULL,
671 0,
672 &kCFTypeDictionaryKeyCallBacks,
673 &kCFTypeDictionaryValueCallBacks);
674
675 /* open a "configd" store to allow cache updates */
676 store = SCDynamicStoreCreate(NULL,
677 CFSTR("Link Configuraton plug-in"),
678 linkConfigChangedCallback,
679 NULL);
680 if (store == NULL) {
681 SC_log(LOG_ERR, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError()));
682 goto error;
683 }
684
685 /* establish notification keys and patterns */
686 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
687 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
688
689 /* ...watch for a change in the list of network interfaces */
690 interfacesKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
691 kSCDynamicStoreDomainState);
692 CFArrayAppendValue(keys, interfacesKey);
693
694 /* ...watch for (per-interface) AirPort configuration changes */
695 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
696 kSCDynamicStoreDomainSetup,
697 kSCCompAnyRegex,
698 kSCEntNetAirPort);
699 CFArrayAppendValue(patterns, key);
700 CFRelease(key);
701
702 /* ...watch for (per-interface) Ethernet configuration changes */
703 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
704 kSCDynamicStoreDomainSetup,
705 kSCCompAnyRegex,
706 kSCEntNetEthernet);
707 CFArrayAppendValue(patterns, key);
708 CFRelease(key);
709
710 /* ...watch for (per-interface) FireWire configuration changes */
711 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
712 kSCDynamicStoreDomainSetup,
713 kSCCompAnyRegex,
714 kSCEntNetFireWire);
715 CFArrayAppendValue(patterns, key);
716 CFRelease(key);
717
718 /* register the keys/patterns */
719 ok = SCDynamicStoreSetNotificationKeys(store, keys, patterns);
720 CFRelease(keys);
721 CFRelease(patterns);
722 if (!ok) {
723 SC_log(LOG_NOTICE, "SCDynamicStoreSetNotificationKeys() failed: %s",
724 SCErrorString(SCError()));
725 goto error;
726 }
727
728 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
729 if (rls == NULL) {
730 SC_log(LOG_NOTICE, "SCDynamicStoreCreateRunLoopSource() failed: %s",
731 SCErrorString(SCError()));
732 goto error;
733 }
734
735 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
736 return;
737
738 error :
739
740 if (baseSettings != NULL) CFRelease(baseSettings);
741 if (wantSettings != NULL) CFRelease(wantSettings);
742 if (store != NULL) CFRelease(store);
743 return;
744 }
745
746
747 #ifdef MAIN
748
749
750 #pragma mark -
751 #pragma mark Standalone test code
752
753
754 int
755 main(int argc, char **argv)
756 {
757 SCPreferencesRef prefs;
758
759 _sc_log = FALSE;
760 _sc_verbose = (argc > 1) ? TRUE : FALSE;
761
762 prefs = SCPreferencesCreate(NULL, CFSTR("linkconfig"), NULL);
763 if (prefs != NULL) {
764 SCNetworkSetRef set;
765
766 set = SCNetworkSetCopyCurrent(prefs);
767 if (set != NULL) {
768 CFMutableSetRef seen;
769 CFArrayRef services;
770
771 services = SCNetworkSetCopyServices(set);
772 if (services != NULL) {
773 CFIndex i;
774 CFIndex n;
775
776 seen = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
777
778 n = CFArrayGetCount(services);
779 for (i = 0; i < n; i++) {
780 SCNetworkInterfaceRef interface;
781 SCNetworkServiceRef service;
782
783 service = CFArrayGetValueAtIndex(services, i);
784 interface = SCNetworkServiceGetInterface(service);
785 if ((interface != NULL) &&
786 !CFSetContainsValue(seen, interface)) {
787 CFDictionaryRef capabilities;
788
789 capabilities = SCNetworkInterfaceCopyCapability(interface, NULL);
790 if (capabilities != NULL) {
791 int cap_current;
792 int cap_requested;
793 CFDictionaryRef options;
794
795 options = SCNetworkInterfaceGetConfiguration(interface);
796 cap_current = __SCNetworkInterfaceCreateCapabilities(interface, -1, NULL);
797 cap_requested = __SCNetworkInterfaceCreateCapabilities(interface, cap_current, options);
798
799 SCPrint(TRUE, stdout,
800 CFSTR("%sinterface = %@, current = %p, requested = %p\n%@\n"),
801 (i == 0) ? "" : "\n",
802 SCNetworkInterfaceGetBSDName(interface),
803 (void *)(uintptr_t)cap_current,
804 (void *)(uintptr_t)cap_requested,
805 capabilities);
806 CFRelease(capabilities);
807 }
808
809 CFSetAddValue(seen, interface);
810 }
811 }
812
813 CFRelease(seen);
814 CFRelease(services);
815 }
816
817 CFRelease(set);
818 }
819
820 CFRelease(prefs);
821 }
822
823 load_LinkConfiguration(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
824 CFRunLoopRun();
825 /* not reached */
826 exit(0);
827 return 0;
828 }
829 #endif