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