]> git.saurik.com Git - apple/configd.git/blame - Plugins/LinkConfiguration/linkconfig.c
configd-395.10.tar.gz
[apple/configd.git] / Plugins / LinkConfiguration / linkconfig.c
CommitLineData
dbf6a266 1/*
6bb65964 2 * Copyright (c) 2002-2007, 2011 Apple Inc. All rights reserved.
dbf6a266
A
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>
dbf6a266
A
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
6bb65964
A
46#include "SCNetworkConfigurationInternal.h"
47
dbf6a266
A
48
49static CFMutableDictionaryRef baseSettings = NULL;
edebe297 50static CFStringRef interfacesKey = NULL;
dbf6a266
A
51static SCDynamicStoreRef store = NULL;
52static CFRunLoopSourceRef rls = NULL;
edebe297 53static CFMutableDictionaryRef wantSettings = NULL;
dbf6a266
A
54
55static Boolean _verbose = FALSE;
56
57
6bb65964
A
58#pragma mark -
59#pragma mark Capabilities
60
61
62#define CAPABILITIES_KEY CFSTR("_CAPABILITIES_")
63
64
65__private_extern__
66Boolean
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
d6c893b2
A
139
140
141static 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}
dbf6a266
A
174
175
176__private_extern__
177Boolean
edebe297
A
178_SCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef interface,
179 CFDictionaryRef options)
dbf6a266
A
180{
181 CFArrayRef available = NULL;
182 CFDictionaryRef current = NULL;
183 struct ifmediareq ifm;
184 struct ifreq ifr;
edebe297 185 CFStringRef interfaceName;
dbf6a266
A
186 Boolean ok = FALSE;
187 int newOptions;
d6c893b2 188 CFDictionaryRef requested;
dbf6a266 189 int sock = -1;
dbf6a266 190
6bb65964
A
191 if (!isA_SCNetworkInterface(interface)) {
192 _SCErrorSet(kSCStatusInvalidArgument);
193 return FALSE;
194 }
195
edebe297
A
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);
6bb65964 200 _SCErrorSet(kSCStatusInvalidArgument);
edebe297
A
201 return FALSE;
202 }
203
dbf6a266 204 /* get current & available options */
edebe297 205 if (!SCNetworkInterfaceCopyMediaOptions(interface, &current, NULL, &available, FALSE)) {
d6c893b2 206 /* could not get current media options */
edebe297 207 SCLog(_verbose, LOG_INFO, CFSTR("no media options for %@"), interfaceName);
dbf6a266
A
208 return FALSE;
209 }
210
211 /* extract just the dictionary key/value pairs of interest */
d6c893b2
A
212 requested = __copyMediaOptions(options);
213 if (requested == NULL) {
214 CFDictionaryRef baseOptions;
dbf6a266 215
d6c893b2 216 /* get base options */
edebe297 217 baseOptions = CFDictionaryGetValue(baseSettings, interfaceName);
d6c893b2 218 requested = __copyMediaOptions(baseOptions);
dbf6a266 219 }
d6c893b2
A
220 if (requested == NULL) {
221 /* get base options */
222 requested = __copyMediaOptions(current);
dbf6a266 223 }
d6c893b2
A
224 if (requested == NULL) {
225 /* if no media options to set */
dbf6a266
A
226 goto done;
227 }
228
d6c893b2 229 if ((current != NULL) && CFEqual(current, requested)) {
dbf6a266
A
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 */
edebe297 237 SCLog(_verbose, LOG_INFO, CFSTR("requested media settings unavailable for %@"), interfaceName);
dbf6a266
A
238 goto done;
239 }
240
6bb65964 241 newOptions = __SCNetworkInterfaceCreateMediaOptions(interface, requested);
dbf6a266
A
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);
edebe297 248 if (sock == -1) {
dbf6a266
A
249 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
250 goto done;
251 }
252
253 bzero((char *)&ifm, sizeof(ifm));
edebe297 254 (void)_SC_cfstring_to_cstring(interfaceName, ifm.ifm_name, sizeof(ifm.ifm_name), kCFStringEncodingASCII);
dbf6a266 255
edebe297 256 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifm) == -1) {
dbf6a266
A
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
edebe297
A
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);
dbf6a266 268
edebe297
A
269 if (ioctl(sock, SIOCSIFMEDIA, (caddr_t)&ifr) == -1) {
270 SCLog(TRUE, LOG_DEBUG, CFSTR("%@: ioctl(SIOCSIFMEDIA) failed: %s"), interfaceName, strerror(errno));
dbf6a266
A
271 goto done;
272 }
273
274 ok = TRUE;
275
276 done :
277
edebe297
A
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);
dbf6a266
A
282
283 return ok;
284}
285
286
6bb65964
A
287#pragma mark -
288#pragma mark MTU
289
290
dbf6a266
A
291#ifndef USE_SIOCSIFMTU
292static void
293ifconfig_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__
323Boolean
edebe297
A
324_SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface,
325 CFDictionaryRef options)
dbf6a266 326{
edebe297 327 CFStringRef interfaceName;
dbf6a266
A
328 int mtu_cur = -1;
329 int mtu_max = -1;
330 int mtu_min = -1;
331 int requested;
332 CFNumberRef val;
333
edebe297
A
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)) {
dbf6a266
A
341 /* could not get current MTU */
342 return FALSE;
343 }
344
d6c893b2
A
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 */
edebe297 354 baseOptions = CFDictionaryGetValue(baseSettings, interfaceName);
d6c893b2
A
355 if (baseOptions != NULL) {
356 val = CFDictionaryGetValue(baseOptions, kSCPropNetEthernetMTU);
dbf6a266 357 }
d6c893b2
A
358 }
359 if (val != NULL) {
360 CFNumberGetValue(val, kCFNumberIntType, &requested);
dbf6a266
A
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));
edebe297 383 (void)_SC_cfstring_to_cstring(interfaceName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII);
dbf6a266
A
384 ifr.ifr_mtu = requested;
385
386 sock = socket(AF_INET, SOCK_DGRAM, 0);
edebe297 387 if (sock == -1) {
dbf6a266
A
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
edebe297 404 ifconfig_argv[1] = _SC_cfstring_to_cstring(interfaceName, NULL, 0, kCFStringEncodingASCII);
dbf6a266
A
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
6bb65964
A
428#pragma mark -
429#pragma mark Update link configuration
430
431
dbf6a266
A
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 */
445static CFStringRef
446parse_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
edebe297
A
466static void updateLink(CFStringRef interfaceName, CFDictionaryRef options);
467
468
dbf6a266 469static void
edebe297 470updateInterfaces(CFArrayRef newInterfaces)
dbf6a266 471{
edebe297
A
472 CFIndex i;
473 CFIndex n_old;
474 CFIndex n_new;
475 static CFArrayRef oldInterfaces = NULL;
dbf6a266 476
edebe297
A
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 }
dbf6a266
A
495 }
496
edebe297
A
497 if (oldInterfaces != NULL) CFRelease(oldInterfaces);
498 oldInterfaces = CFRetain(newInterfaces);
499}
500
501
502static void
503updateLink(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;
dbf6a266
A
519 }
520
edebe297
A
521 if (options != NULL) {
522 if (!CFDictionaryContainsKey(baseSettings, interfaceName)) {
6bb65964 523 int cur_cap = -1;
dbf6a266
A
524 CFDictionaryRef cur_media = NULL;
525 CFMutableDictionaryRef new_media = NULL;
526 int cur_mtu = -1;
dbf6a266 527
d6c893b2 528 /* preserve current media options */
edebe297 529 if (SCNetworkInterfaceCopyMediaOptions(interface, &cur_media, NULL, NULL, FALSE)) {
d6c893b2
A
530 if (cur_media != NULL) {
531 new_media = CFDictionaryCreateMutableCopy(NULL, 0, cur_media);
532 CFRelease(cur_media);
533 }
dbf6a266
A
534 }
535
d6c893b2 536 /* preserve current MTU */
edebe297 537 if (SCNetworkInterfaceCopyMTU(interface, &cur_mtu, NULL, NULL)) {
d6c893b2
A
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 }
dbf6a266
A
552 }
553
6bb65964
A
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
d6c893b2 571 if (new_media != NULL) {
edebe297 572 CFDictionarySetValue(baseSettings, interfaceName, new_media);
d6c893b2 573 CFRelease(new_media);
dbf6a266 574 }
dbf6a266
A
575 }
576
577 /* establish new settings */
6bb65964 578 (void)_SCNetworkInterfaceSetCapabilities(interface, options);
edebe297
A
579 (void)_SCNetworkInterfaceSetMediaOptions(interface, options);
580 (void)_SCNetworkInterfaceSetMTU (interface, options);
dbf6a266
A
581 } else {
582 /* no requested settings */
edebe297
A
583 options = CFDictionaryGetValue(baseSettings, interfaceName);
584 if (options != NULL) {
dbf6a266 585 /* restore original settings */
6bb65964 586 (void)_SCNetworkInterfaceSetCapabilities(interface, options);
edebe297
A
587 (void)_SCNetworkInterfaceSetMediaOptions(interface, options);
588 (void)_SCNetworkInterfaceSetMTU (interface, options);
589 CFDictionaryRemoveValue(baseSettings, interfaceName);
dbf6a266
A
590 }
591 }
592
edebe297 593 CFRelease(interface);
dbf6a266
A
594 return;
595}
596
597
598static void
599linkConfigChangedCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *arg)
600{
edebe297 601 CFDictionaryRef changes;
dbf6a266
A
602 CFIndex i;
603 CFIndex n;
edebe297
A
604 static CFStringRef prefix = NULL;
605
606 if (prefix == NULL) {
607 prefix = SCDynamicStoreKeyCreate(NULL,
608 CFSTR("%@/%@/%@/"),
609 kSCDynamicStoreDomainSetup,
610 kSCCompNetwork,
611 kSCCompInterface);
612 }
dbf6a266 613
edebe297 614 changes = SCDynamicStoreCopyMultiple(store, changedKeys, NULL);
dbf6a266
A
615
616 n = CFArrayGetCount(changedKeys);
617 for (i = 0; i < n; i++) {
618 CFStringRef key;
edebe297 619 CFDictionaryRef info;
dbf6a266
A
620
621 key = CFArrayGetValueAtIndex(changedKeys, i);
edebe297
A
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 }
dbf6a266
A
640 }
641
edebe297 642 CFRelease(changes);
dbf6a266
A
643
644 return;
645}
646
647
648__private_extern__
649void
650load_LinkConfiguration(CFBundleRef bundle, Boolean bundleVerbose)
651{
652 CFStringRef key;
edebe297
A
653 CFMutableArrayRef keys = NULL;
654 Boolean ok;
dbf6a266
A
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);
edebe297
A
670 wantSettings = CFDictionaryCreateMutable(NULL,
671 0,
672 &kCFTypeDictionaryKeyCallBacks,
673 &kCFTypeDictionaryValueCallBacks);
dbf6a266
A
674
675 /* open a "configd" store to allow cache updates */
676 store = SCDynamicStoreCreate(NULL,
677 CFSTR("Link Configuraton plug-in"),
678 linkConfigChangedCallback,
679 NULL);
edebe297 680 if (store == NULL) {
dbf6a266
A
681 SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCreate() failed: %s"), SCErrorString(SCError()));
682 goto error;
683 }
684
685 /* establish notification keys and patterns */
edebe297 686 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
dbf6a266
A
687 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
688
edebe297
A
689 /* ...watch for a change in the list of network interfaces */
690 interfacesKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
691 kSCDynamicStoreDomainState);
692 CFArrayAppendValue(keys, interfacesKey);
693
d6c893b2
A
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
dbf6a266
A
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
d6c893b2
A
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
dbf6a266 718 /* register the keys/patterns */
edebe297
A
719 ok = SCDynamicStoreSetNotificationKeys(store, keys, patterns);
720 CFRelease(keys);
721 CFRelease(patterns);
722 if (!ok) {
dbf6a266
A
723 SCLog(TRUE, LOG_ERR,
724 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s"),
725 SCErrorString(SCError()));
726 goto error;
727 }
728
729 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
edebe297 730 if (rls == NULL) {
dbf6a266
A
731 SCLog(TRUE, LOG_ERR,
732 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s"),
733 SCErrorString(SCError()));
734 goto error;
735 }
736
737 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
dbf6a266
A
738 return;
739
740 error :
741
edebe297
A
742 if (baseSettings != NULL) CFRelease(baseSettings);
743 if (wantSettings != NULL) CFRelease(wantSettings);
744 if (store != NULL) CFRelease(store);
dbf6a266
A
745 return;
746}
747
748
749#ifdef MAIN
6bb65964
A
750
751
752#pragma mark -
753#pragma mark Standalone test code
754
755
dbf6a266
A
756int
757main(int argc, char **argv)
758{
6bb65964
A
759 SCPreferencesRef prefs;
760
dbf6a266
A
761 _sc_log = FALSE;
762 _sc_verbose = (argc > 1) ? TRUE : FALSE;
763
6bb65964
A
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
dbf6a266
A
825 load_LinkConfiguration(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
826 CFRunLoopRun();
827 /* not reached */
828 exit(0);
829 return 0;
830}
831#endif