]> git.saurik.com Git - apple/configd.git/blame - Plugins/LinkConfiguration/linkconfig.c
configd-1109.101.1.tar.gz
[apple/configd.git] / Plugins / LinkConfiguration / linkconfig.c
CommitLineData
dbf6a266 1/*
59647b27 2 * Copyright (c) 2002-2007, 2011, 2013, 2015-2020 Apple Inc. All rights reserved.
dbf6a266
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
9de8ab86 5 *
dbf6a266
A
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.
9de8ab86 12 *
dbf6a266
A
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.
9de8ab86 20 *
dbf6a266
A
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
afb19109 40#define SC_LOG_HANDLE __log_LinkConfiguration
1ef45fa4 41#define SC_LOG_HANDLE_TYPE static
942cecd7 42#include "SCNetworkConfigurationInternal.h"
dbf6a266
A
43#include <SystemConfiguration/SCDPlugin.h> // for _SCDPluginExecCommand
44
6bb65964 45
942cecd7
A
46static CFMutableDictionaryRef baseSettings = NULL;
47static CFStringRef interfacesKey = NULL;
48static SCDynamicStoreRef store = NULL;
49static CFRunLoopSourceRef rls = NULL;
50static CFMutableDictionaryRef wantSettings = NULL;
51
52
53#pragma mark -
54#pragma mark Logging
55
56
57static os_log_t
f715d946 58__log_LinkConfiguration(void)
942cecd7
A
59{
60 static os_log_t log = NULL;
61
62 if (log == NULL) {
63 log = os_log_create("com.apple.SystemConfiguration", "LinkConfiguration");
64 }
dbf6a266 65
942cecd7
A
66 return log;
67}
dbf6a266 68
dbf6a266 69
6bb65964
A
70#pragma mark -
71#pragma mark Capabilities
72
73
74#define CAPABILITIES_KEY CFSTR("_CAPABILITIES_")
75
76
77__private_extern__
78Boolean
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
afb19109 126 memset((char *)&ifr, 0, sizeof(ifr));
6bb65964
A
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) {
9de8ab86 133 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno));
6bb65964
A
134 return FALSE;
135 }
136
137 ret = ioctl(sock, SIOCSIFCAP, (caddr_t)&ifr);
138 (void)close(sock);
139 if (ret == -1) {
1ef45fa4 140 SC_log(LOG_ERR, "%@: ioctl(SIOCSIFCAP) failed: %s", interfaceName, strerror(errno));
6bb65964
A
141 return FALSE;
142 }
143#endif // SIOCSIFCAP
144
145 return TRUE;
146}
147
148
149#pragma mark -
150#pragma mark Media options
d6c893b2
A
151
152
153static 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}
dbf6a266
A
186
187
188__private_extern__
189Boolean
edebe297
A
190_SCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef interface,
191 CFDictionaryRef options)
dbf6a266
A
192{
193 CFArrayRef available = NULL;
194 CFDictionaryRef current = NULL;
195 struct ifmediareq ifm;
196 struct ifreq ifr;
edebe297 197 CFStringRef interfaceName;
dbf6a266
A
198 Boolean ok = FALSE;
199 int newOptions;
d6c893b2 200 CFDictionaryRef requested;
dbf6a266 201 int sock = -1;
dbf6a266 202
6bb65964
A
203 if (!isA_SCNetworkInterface(interface)) {
204 _SCErrorSet(kSCStatusInvalidArgument);
205 return FALSE;
206 }
207
edebe297
A
208 interfaceName = SCNetworkInterfaceGetBSDName(interface);
209 if (interfaceName == NULL) {
210 /* if no BSD interface name */
9de8ab86 211 SC_log(LOG_INFO, "no BSD interface name for %@", interface);
6bb65964 212 _SCErrorSet(kSCStatusInvalidArgument);
edebe297
A
213 return FALSE;
214 }
215
dbf6a266 216 /* get current & available options */
edebe297 217 if (!SCNetworkInterfaceCopyMediaOptions(interface, &current, NULL, &available, FALSE)) {
d6c893b2 218 /* could not get current media options */
9de8ab86 219 SC_log(LOG_INFO, "no media options for %@", interfaceName);
dbf6a266
A
220 return FALSE;
221 }
222
223 /* extract just the dictionary key/value pairs of interest */
d6c893b2
A
224 requested = __copyMediaOptions(options);
225 if (requested == NULL) {
226 CFDictionaryRef baseOptions;
dbf6a266 227
d6c893b2 228 /* get base options */
edebe297 229 baseOptions = CFDictionaryGetValue(baseSettings, interfaceName);
d6c893b2 230 requested = __copyMediaOptions(baseOptions);
dbf6a266 231 }
d6c893b2
A
232 if (requested == NULL) {
233 /* get base options */
234 requested = __copyMediaOptions(current);
dbf6a266 235 }
d6c893b2
A
236 if (requested == NULL) {
237 /* if no media options to set */
dbf6a266
A
238 goto done;
239 }
240
d6c893b2 241 if ((current != NULL) && CFEqual(current, requested)) {
dbf6a266
A
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 */
9de8ab86 249 SC_log(LOG_INFO, "requested media settings unavailable for %@", interfaceName);
dbf6a266
A
250 goto done;
251 }
252
6bb65964 253 newOptions = __SCNetworkInterfaceCreateMediaOptions(interface, requested);
dbf6a266
A
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);
edebe297 260 if (sock == -1) {
9de8ab86 261 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno));
dbf6a266
A
262 goto done;
263 }
264
afb19109 265 memset((char *)&ifm, 0, sizeof(ifm));
edebe297 266 (void)_SC_cfstring_to_cstring(interfaceName, ifm.ifm_name, sizeof(ifm.ifm_name), kCFStringEncodingASCII);
dbf6a266 267
965d9e25
A
268 if (ioctl(sock, SIOCGIFXMEDIA, (caddr_t)&ifm) == -1) {
269 SC_log(LOG_ERR, "%@: ioctl(SIOCGIFXMEDIA) failed: %s", interfaceName, strerror(errno));
dbf6a266
A
270 goto done;
271 }
272
afb19109
A
273 memset((char *)&ifr, 0, sizeof(ifr));
274 memcpy(ifr.ifr_name, ifm.ifm_name, sizeof(ifr.ifr_name));
dbf6a266
A
275 ifr.ifr_media = ifm.ifm_current & ~(IFM_NMASK|IFM_TMASK|IFM_OMASK|IFM_GMASK);
276 ifr.ifr_media |= newOptions;
277
9de8ab86
A
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);
dbf6a266 280
edebe297 281 if (ioctl(sock, SIOCSIFMEDIA, (caddr_t)&ifr) == -1) {
1ef45fa4 282 SC_log(LOG_ERR, "%@: ioctl(SIOCSIFMEDIA) failed: %s", interfaceName, strerror(errno));
dbf6a266
A
283 goto done;
284 }
285
286 ok = TRUE;
287
288 done :
289
edebe297
A
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);
dbf6a266
A
294
295 return ok;
296}
297
298
6bb65964
A
299#pragma mark -
300#pragma mark MTU
301
302
dbf6a266
A
303#ifndef USE_SIOCSIFMTU
304static void
305ifconfig_exit(pid_t pid, int status, struct rusage *rusage, void *context)
306{
1ef45fa4
A
307#pragma unused(pid)
308#pragma unused(rusage)
dbf6a266
A
309 char *if_name = (char *)context;
310
311 if (WIFEXITED(status)) {
312 if (WEXITSTATUS(status) != 0) {
9de8ab86
A
313 SC_log(LOG_NOTICE, "ifconfig %s failed, exit status = %d",
314 if_name,
315 WEXITSTATUS(status));
dbf6a266
A
316 }
317 } else if (WIFSIGNALED(status)) {
9de8ab86
A
318 SC_log(LOG_NOTICE, "ifconfig %s: terminated w/signal = %d",
319 if_name,
320 WTERMSIG(status));
dbf6a266 321 } else {
9de8ab86
A
322 SC_log(LOG_NOTICE, "ifconfig %s: exit status = %d",
323 if_name,
324 status);
dbf6a266
A
325 }
326
327 CFAllocatorDeallocate(NULL, if_name);
328 return;
329}
330#endif /* !USE_SIOCSIFMTU */
331
332
333__private_extern__
334Boolean
edebe297
A
335_SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface,
336 CFDictionaryRef options)
dbf6a266 337{
942cecd7
A
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;
dbf6a266 349
edebe297
A
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)) {
dbf6a266
A
357 /* could not get current MTU */
358 return FALSE;
359 }
360
d6c893b2
A
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 */
edebe297 370 baseOptions = CFDictionaryGetValue(baseSettings, interfaceName);
d6c893b2
A
371 if (baseOptions != NULL) {
372 val = CFDictionaryGetValue(baseOptions, kSCPropNetEthernetMTU);
dbf6a266 373 }
d6c893b2
A
374 }
375 if (val != NULL) {
376 CFNumberGetValue(val, kCFNumberIntType, &requested);
dbf6a266
A
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
942cecd7
A
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
dbf6a266
A
423#ifdef USE_SIOCSIFMTU
424{
425 struct ifreq ifr;
426 int ret;
427 int sock;
428
afb19109 429 memset((char *)&ifr, 0, sizeof(ifr));
edebe297 430 (void)_SC_cfstring_to_cstring(interfaceName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII);
dbf6a266
A
431 ifr.ifr_mtu = requested;
432
433 sock = socket(AF_INET, SOCK_DGRAM, 0);
edebe297 434 if (sock == -1) {
9de8ab86 435 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno));
942cecd7
A
436 ok = FALSE;
437 goto done;
dbf6a266
A
438 }
439
440 ret = ioctl(sock, SIOCSIFMTU, (caddr_t)&ifr);
441 (void)close(sock);
442 if (ret == -1) {
1ef45fa4 443 SC_log(LOG_ERR, "%@: ioctl(SIOCSIFMTU) failed: %s", interfaceName, strerror(errno));
942cecd7
A
444 ok = FALSE;
445 goto done;
dbf6a266
A
446 }
447}
448#else /* !USE_SIOCSIFMTU */
449{
450 char *ifconfig_argv[] = { "ifconfig", NULL, "mtu", NULL, NULL };
451 pid_t pid;
452
edebe297 453 ifconfig_argv[1] = _SC_cfstring_to_cstring(interfaceName, NULL, 0, kCFStringEncodingASCII);
dbf6a266
A
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) {
942cecd7
A
468 ok = FALSE;
469 goto done;
dbf6a266
A
470 }
471}
472#endif /* !USE_SIOCSIFMTU */
473
942cecd7
A
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;
dbf6a266
A
488}
489
490
6bb65964
A
491#pragma mark -
492#pragma mark Update link configuration
493
494
dbf6a266
A
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 */
17d3ee29 508static CF_RETURNS_RETAINED CFStringRef
dbf6a266
A
509parse_component(CFStringRef key, CFStringRef prefix)
510{
511 CFMutableStringRef comp;
512 CFRange range;
513
942cecd7 514 if (!CFStringHasPrefix(key, prefix)) {
dbf6a266
A
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
edebe297
A
529static void updateLink(CFStringRef interfaceName, CFDictionaryRef options);
530
531
dbf6a266 532static void
edebe297 533updateInterfaces(CFArrayRef newInterfaces)
dbf6a266 534{
edebe297
A
535 CFIndex i;
536 CFIndex n_old;
537 CFIndex n_new;
538 static CFArrayRef oldInterfaces = NULL;
dbf6a266 539
edebe297
A
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 }
dbf6a266
A
558 }
559
edebe297
A
560 if (oldInterfaces != NULL) CFRelease(oldInterfaces);
561 oldInterfaces = CFRetain(newInterfaces);
562}
563
564
565static void
566updateLink(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;
dbf6a266
A
582 }
583
edebe297
A
584 if (options != NULL) {
585 if (!CFDictionaryContainsKey(baseSettings, interfaceName)) {
6bb65964 586 int cur_cap = -1;
dbf6a266
A
587 CFDictionaryRef cur_media = NULL;
588 CFMutableDictionaryRef new_media = NULL;
589 int cur_mtu = -1;
dbf6a266 590
d6c893b2 591 /* preserve current media options */
edebe297 592 if (SCNetworkInterfaceCopyMediaOptions(interface, &cur_media, NULL, NULL, FALSE)) {
d6c893b2
A
593 if (cur_media != NULL) {
594 new_media = CFDictionaryCreateMutableCopy(NULL, 0, cur_media);
595 CFRelease(cur_media);
596 }
dbf6a266
A
597 }
598
d6c893b2 599 /* preserve current MTU */
edebe297 600 if (SCNetworkInterfaceCopyMTU(interface, &cur_mtu, NULL, NULL)) {
d6c893b2
A
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 }
dbf6a266
A
615 }
616
6bb65964
A
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
d6c893b2 634 if (new_media != NULL) {
edebe297 635 CFDictionarySetValue(baseSettings, interfaceName, new_media);
d6c893b2 636 CFRelease(new_media);
dbf6a266 637 }
dbf6a266
A
638 }
639
640 /* establish new settings */
6bb65964 641 (void)_SCNetworkInterfaceSetCapabilities(interface, options);
edebe297
A
642 (void)_SCNetworkInterfaceSetMediaOptions(interface, options);
643 (void)_SCNetworkInterfaceSetMTU (interface, options);
dbf6a266
A
644 } else {
645 /* no requested settings */
edebe297
A
646 options = CFDictionaryGetValue(baseSettings, interfaceName);
647 if (options != NULL) {
dbf6a266 648 /* restore original settings */
6bb65964 649 (void)_SCNetworkInterfaceSetCapabilities(interface, options);
edebe297
A
650 (void)_SCNetworkInterfaceSetMediaOptions(interface, options);
651 (void)_SCNetworkInterfaceSetMTU (interface, options);
652 CFDictionaryRemoveValue(baseSettings, interfaceName);
dbf6a266
A
653 }
654 }
655
edebe297 656 CFRelease(interface);
dbf6a266
A
657 return;
658}
659
660
661static void
662linkConfigChangedCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *arg)
663{
1ef45fa4 664#pragma unused(arg)
edebe297 665 CFDictionaryRef changes;
dbf6a266
A
666 CFIndex i;
667 CFIndex n;
edebe297
A
668 static CFStringRef prefix = NULL;
669
670 if (prefix == NULL) {
671 prefix = SCDynamicStoreKeyCreate(NULL,
672 CFSTR("%@/%@/%@/"),
673 kSCDynamicStoreDomainSetup,
674 kSCCompNetwork,
675 kSCCompInterface);
676 }
dbf6a266 677
edebe297 678 changes = SCDynamicStoreCopyMultiple(store, changedKeys, NULL);
dbf6a266 679
9de8ab86 680 n = (changes != NULL) ? CFArrayGetCount(changedKeys) : 0;
dbf6a266
A
681 for (i = 0; i < n; i++) {
682 CFStringRef key;
edebe297 683 CFDictionaryRef info;
dbf6a266
A
684
685 key = CFArrayGetValueAtIndex(changedKeys, i);
edebe297
A
686 info = CFDictionaryGetValue(changes, key);
687
688 if (CFEqual(key, interfacesKey)) {
9de8ab86
A
689 if (isA_CFDictionary(info) != NULL) {
690 CFArrayRef interfaces;
edebe297 691
9de8ab86
A
692 interfaces = CFDictionaryGetValue(info, kSCPropNetInterfaces);
693 if (isA_CFArray(interfaces)) {
694 updateInterfaces(interfaces);
695 }
edebe297
A
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 }
dbf6a266
A
706 }
707
9de8ab86
A
708 if (changes != NULL) {
709 CFRelease(changes);
710 }
711
dbf6a266
A
712 return;
713}
714
715
716__private_extern__
717void
718load_LinkConfiguration(CFBundleRef bundle, Boolean bundleVerbose)
719{
1ef45fa4 720#pragma unused(bundleVerbose)
dbf6a266 721 CFStringRef key;
edebe297
A
722 CFMutableArrayRef keys = NULL;
723 Boolean ok;
dbf6a266
A
724 CFMutableArrayRef patterns = NULL;
725
9de8ab86
A
726 SC_log(LOG_DEBUG, "load() called");
727 SC_log(LOG_DEBUG, " bundle ID = %@", CFBundleGetIdentifier(bundle));
dbf6a266
A
728
729 /* initialize a few globals */
730
731 baseSettings = CFDictionaryCreateMutable(NULL,
732 0,
733 &kCFTypeDictionaryKeyCallBacks,
734 &kCFTypeDictionaryValueCallBacks);
edebe297
A
735 wantSettings = CFDictionaryCreateMutable(NULL,
736 0,
737 &kCFTypeDictionaryKeyCallBacks,
738 &kCFTypeDictionaryValueCallBacks);
dbf6a266
A
739
740 /* open a "configd" store to allow cache updates */
741 store = SCDynamicStoreCreate(NULL,
742 CFSTR("Link Configuraton plug-in"),
743 linkConfigChangedCallback,
744 NULL);
edebe297 745 if (store == NULL) {
9de8ab86 746 SC_log(LOG_ERR, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError()));
dbf6a266
A
747 goto error;
748 }
749
750 /* establish notification keys and patterns */
edebe297 751 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
dbf6a266
A
752 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
753
edebe297
A
754 /* ...watch for a change in the list of network interfaces */
755 interfacesKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
756 kSCDynamicStoreDomainState);
757 CFArrayAppendValue(keys, interfacesKey);
758
d6c893b2
A
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
dbf6a266
A
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
f715d946 775#if TARGET_OS_OSX
d6c893b2
A
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);
f715d946 783#endif // TARGET_OS_OSX
d6c893b2 784
dbf6a266 785 /* register the keys/patterns */
edebe297
A
786 ok = SCDynamicStoreSetNotificationKeys(store, keys, patterns);
787 CFRelease(keys);
788 CFRelease(patterns);
789 if (!ok) {
9de8ab86
A
790 SC_log(LOG_NOTICE, "SCDynamicStoreSetNotificationKeys() failed: %s",
791 SCErrorString(SCError()));
dbf6a266
A
792 goto error;
793 }
794
795 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
edebe297 796 if (rls == NULL) {
9de8ab86
A
797 SC_log(LOG_NOTICE, "SCDynamicStoreCreateRunLoopSource() failed: %s",
798 SCErrorString(SCError()));
dbf6a266
A
799 goto error;
800 }
801
802 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
dbf6a266
A
803 return;
804
805 error :
806
edebe297
A
807 if (baseSettings != NULL) CFRelease(baseSettings);
808 if (wantSettings != NULL) CFRelease(wantSettings);
809 if (store != NULL) CFRelease(store);
dbf6a266
A
810 return;
811}
812
813
814#ifdef MAIN
6bb65964
A
815
816
817#pragma mark -
818#pragma mark Standalone test code
819
820
dbf6a266
A
821int
822main(int argc, char **argv)
823{
6bb65964
A
824 SCPreferencesRef prefs;
825
59647b27 826 _sc_log = kSCLogDestinationFile;
dbf6a266
A
827 _sc_verbose = (argc > 1) ? TRUE : FALSE;
828
6bb65964
A
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) &&
5e9ce69e 853 !CFSetContainsValue(seen, interface)) {
6bb65964
A
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
dbf6a266
A
890 load_LinkConfiguration(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
891 CFRunLoopRun();
892 /* not reached */
893 exit(0);
894 return 0;
895}
896#endif