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