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