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