]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/BondConfiguration.c
configd-130.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / BondConfiguration.c
1 /*
2 * Copyright (c) 2004 Apple Computer, 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 * July 22, 2004 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <CoreFoundation/CFRuntime.h>
34
35 #include <SystemConfiguration/SystemConfiguration.h>
36 #include <SystemConfiguration/SCNetworkConfigurationInternal.h>
37 #include <SystemConfiguration/SCValidation.h>
38 #include <SystemConfiguration/SCPrivate.h>
39
40 #include <SystemConfiguration/BondConfiguration.h>
41 #include <SystemConfiguration/BondConfigurationPrivate.h>
42
43 #include <ifaddrs.h>
44 #include <pthread.h>
45 #include <unistd.h>
46 #include <sys/types.h>
47 #include <sys/ioctl.h>
48 #include <sys/socket.h>
49 #include <sys/sysctl.h>
50 #include <net/ethernet.h>
51 #define KERNEL_PRIVATE
52 #include <net/if.h>
53 #include <net/if_var.h>
54 #undef KERNEL_PRIVATE
55 #include <net/if_bond_var.h>
56 #include <net/if_types.h>
57 #include <net/if_media.h>
58 #include <net/route.h>
59
60 /* ---------- Bond support ---------- */
61
62 static int
63 inet_dgram_socket()
64 {
65 int s;
66
67 s = socket(AF_INET, SOCK_DGRAM, 0);
68 if (s == -1) {
69 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
70 _SCErrorSet(kSCStatusFailed);
71 }
72
73 return s;
74 }
75
76 static int
77 siocgifmedia(int s, const char * ifname, int * status, int * active)
78 {
79 struct ifmediareq ifmr;
80
81 *status = 0;
82 *active = 0;
83 bzero(&ifmr, sizeof(ifmr));
84 strncpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
85 if (ioctl(s, SIOCGIFMEDIA, &ifmr) < 0) {
86 SCLog(TRUE, LOG_ERR, CFSTR("SIOCGIFMEDIA(%s) failed, %s\n"),
87 ifname, strerror(errno));
88 return (-1);
89 }
90 if (ifmr.ifm_count != 0) {
91 *status = ifmr.ifm_status;
92 *active = ifmr.ifm_active;
93 }
94 return (0);
95 }
96
97 static struct if_bond_status_req *
98 if_bond_status_req_copy(int s, const char * ifname)
99 {
100 void * buf = NULL;
101 struct if_bond_req ibr;
102 struct if_bond_status_req * ibsr_p;
103 struct ifreq ifr;
104
105 bzero(&ifr, sizeof(ifr));
106 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
107 bzero((char *)&ibr, sizeof(ibr));
108 ibr.ibr_op = IF_BOND_OP_GET_STATUS;
109 ibsr_p = &ibr.ibr_ibru.ibru_status;
110 ibsr_p->ibsr_version = IF_BOND_STATUS_REQ_VERSION;
111 ifr.ifr_data = (caddr_t)&ibr;
112
113 /* how many of them are there? */
114 if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) < 0) {
115 SCLog(TRUE, LOG_ERR, CFSTR("SIOCGIFBOND(%s) failed: %s"),
116 ifname, strerror(errno));
117 goto failed;
118 }
119 buf = malloc(sizeof(struct if_bond_status) * ibsr_p->ibsr_total + sizeof(*ibsr_p));
120 if (buf == NULL) {
121 goto failed;
122 }
123 if (ibsr_p->ibsr_total == 0) {
124 goto done;
125 }
126 ibsr_p->ibsr_count = ibsr_p->ibsr_total;
127 ibsr_p->ibsr_buffer = buf + sizeof(*ibsr_p);
128
129 /* get the list */
130 if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) < 0) {
131 SCLog(TRUE, LOG_ERR, CFSTR("SIOCGIFBOND(%s) failed: %s"),
132 ifname, strerror(errno));
133 goto failed;
134 }
135 done:
136 (*(struct if_bond_status_req *)buf) = *ibsr_p;
137 return ((struct if_bond_status_req *)buf);
138
139 failed:
140 if (buf != NULL) {
141 free(buf);
142 }
143 return (NULL);
144 }
145
146 static Boolean
147 _Bond_addDevice(int s, CFStringRef interface, CFStringRef device)
148 {
149 struct if_bond_req breq;
150 struct ifreq ifr;
151
152 // bond interface
153 bzero(&ifr, sizeof(ifr));
154 (void) _SC_cfstring_to_cstring(interface,
155 ifr.ifr_name,
156 sizeof(ifr.ifr_name),
157 kCFStringEncodingASCII);
158 ifr.ifr_data = (caddr_t)&breq;
159
160 // new bond member
161 bzero(&breq, sizeof(breq));
162 breq.ibr_op = IF_BOND_OP_ADD_INTERFACE;
163 (void) _SC_cfstring_to_cstring(device,
164 breq.ibr_ibru.ibru_if_name,
165 sizeof(breq.ibr_ibru.ibru_if_name),
166 kCFStringEncodingASCII);
167
168 // add new bond member
169 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) {
170 SCLog(TRUE, LOG_ERR,
171 CFSTR("could not add interface \"%@\" to bond \"%@\": %s"),
172 device,
173 interface,
174 strerror(errno));
175 _SCErrorSet(kSCStatusFailed);
176 return FALSE;
177 }
178
179 // mark the added interface "up"
180 if (!__markInterfaceUp(s, device)) {
181 _SCErrorSet(kSCStatusFailed);
182 return FALSE;
183 }
184
185 return TRUE;
186 }
187
188
189 static Boolean
190 _Bond_removeDevice(int s, CFStringRef interface, CFStringRef device)
191 {
192 struct if_bond_req breq;
193 struct ifreq ifr;
194
195 // bond interface
196 bzero(&ifr, sizeof(ifr));
197 (void) _SC_cfstring_to_cstring(interface,
198 ifr.ifr_name,
199 sizeof(ifr.ifr_name),
200 kCFStringEncodingASCII);
201 ifr.ifr_data = (caddr_t)&breq;
202
203 // bond member to remove
204 bzero(&breq, sizeof(breq));
205 breq.ibr_op = IF_BOND_OP_REMOVE_INTERFACE;
206 (void) _SC_cfstring_to_cstring(device,
207 breq.ibr_ibru.ibru_if_name,
208 sizeof(breq.ibr_ibru.ibru_if_name),
209 kCFStringEncodingASCII);
210
211 // remove bond member
212 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) {
213 SCLog(TRUE, LOG_ERR,
214 CFSTR("could not remove interface \"%@\" from bond \"%@\": %s"),
215 device,
216 interface,
217 strerror(errno));
218 _SCErrorSet(kSCStatusFailed);
219 return FALSE;
220 }
221
222 return TRUE;
223 }
224
225
226 /* ---------- Bond "device" ---------- */
227
228 Boolean
229 IsBondSupported(CFStringRef device)
230 {
231 CFMutableDictionaryRef entity;
232 SCNetworkInterfaceRef interface;
233 Boolean isBond = FALSE;
234
235 entity = CFDictionaryCreateMutable(NULL,
236 0,
237 &kCFTypeDictionaryKeyCallBacks,
238 &kCFTypeDictionaryValueCallBacks);
239 CFDictionarySetValue(entity, kSCPropNetInterfaceType, kSCValNetInterfaceTypeEthernet);
240 CFDictionarySetValue(entity, kSCPropNetInterfaceDeviceName, device);
241 interface = __SCNetworkInterfaceCreateWithEntity(NULL, entity, NULL);
242 CFRelease(entity);
243
244 if (interface != NULL) {
245 SCNetworkInterfacePrivateRef interfacePrivate;
246
247 interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
248 if (interfacePrivate->path != NULL) {
249 isBond = interfacePrivate->supportsBond;
250 }
251 CFRelease(interface);
252 }
253
254 return isBond;
255 }
256
257 /* ---------- BondInterface ---------- */
258
259 typedef struct {
260
261 /* base CFType information */
262 CFRuntimeBase cfBase;
263
264 /* bond interface configuration */
265 CFStringRef ifname; // e.g. bond0, bond1, ...
266 CFArrayRef devices; // e.g. en0, en1, ...
267 CFDictionaryRef options; // e.g. UserDefinedName
268
269 } BondInterfacePrivate, * BondInterfacePrivateRef;
270
271
272 static CFStringRef __BondInterfaceCopyDescription (CFTypeRef cf);
273 static void __BondInterfaceDeallocate (CFTypeRef cf);
274 static Boolean __BondInterfaceEqual (CFTypeRef cf1, CFTypeRef cf2);
275
276
277 static const CFRuntimeClass __BondInterfaceClass = {
278 0, // version
279 "BondInterface", // className
280 NULL, // init
281 NULL, // copy
282 __BondInterfaceDeallocate, // dealloc
283 __BondInterfaceEqual, // equal
284 NULL, // hash
285 NULL, // copyFormattingDesc
286 __BondInterfaceCopyDescription // copyDebugDesc
287 };
288
289
290 static CFTypeID __kBondInterfaceTypeID = _kCFRuntimeNotATypeID;
291
292
293 static pthread_once_t bondInterface_init = PTHREAD_ONCE_INIT;
294
295
296 static CFStringRef
297 __BondInterfaceCopyDescription(CFTypeRef cf)
298 {
299 CFAllocatorRef allocator = CFGetAllocator(cf);
300 CFMutableStringRef result;
301 BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)cf;
302
303 result = CFStringCreateMutable(allocator, 0);
304 CFStringAppendFormat(result, NULL, CFSTR("<BondInterface %p [%p]> {"), cf, allocator);
305 CFStringAppendFormat(result, NULL, CFSTR(" if = %@"), bondPrivate->ifname);
306 if (bondPrivate->devices != NULL) {
307 CFIndex i;
308 CFIndex n;
309
310 CFStringAppendFormat(result, NULL, CFSTR(", devices ="));
311
312 n = CFArrayGetCount(bondPrivate->devices);
313 for (i = 0; i < n; i++) {
314 CFStringAppendFormat(result,
315 NULL,
316 CFSTR(" %@"),
317 CFArrayGetValueAtIndex(bondPrivate->devices, i));
318 }
319 }
320 if (bondPrivate->options != NULL) {
321 CFStringAppendFormat(result, NULL, CFSTR(", options = %@"), bondPrivate->options);
322 }
323 CFStringAppendFormat(result, NULL, CFSTR(" }"));
324
325 return result;
326 }
327
328
329 static void
330 __BondInterfaceDeallocate(CFTypeRef cf)
331 {
332 BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)cf;
333
334 /* release resources */
335
336 CFRelease(bondPrivate->ifname);
337 if (bondPrivate->devices) CFRelease(bondPrivate->devices);
338 if (bondPrivate->options) CFRelease(bondPrivate->options);
339
340 return;
341 }
342
343
344 static Boolean
345 __BondInterfaceEquiv(CFTypeRef cf1, CFTypeRef cf2)
346 {
347 BondInterfacePrivateRef bond1 = (BondInterfacePrivateRef)cf1;
348 BondInterfacePrivateRef bond2 = (BondInterfacePrivateRef)cf2;
349
350 if (bond1 == bond2)
351 return TRUE;
352
353 if (!CFEqual(bond1->ifname, bond2->ifname))
354 return FALSE; // if not the same interface
355
356 if (!CFEqual(bond1->devices, bond2->devices))
357 return FALSE; // if not the same device
358
359 return TRUE;
360 }
361
362
363 static Boolean
364 __BondInterfaceEqual(CFTypeRef cf1, CFTypeRef cf2)
365 {
366 BondInterfacePrivateRef bond1 = (BondInterfacePrivateRef)cf1;
367 BondInterfacePrivateRef bond2 = (BondInterfacePrivateRef)cf2;
368
369 if (!__BondInterfaceEquiv(bond1, bond2))
370 return FALSE; // if not the same Bond interface/devices
371
372 if (bond1->options != bond2->options) {
373 // if the options may differ
374 if ((bond1->options != NULL) && (bond2->options != NULL)) {
375 // if both Bonds have options
376 if (!CFEqual(bond1->options, bond2->options)) {
377 // if the options are not equal
378 return FALSE;
379 }
380 } else {
381 // if only one Bond has options
382 return FALSE;
383 }
384 }
385
386 return TRUE;
387 }
388
389
390 static void
391 __BondInterfaceInitialize(void)
392 {
393 __kBondInterfaceTypeID = _CFRuntimeRegisterClass(&__BondInterfaceClass);
394 return;
395 }
396
397
398 static __inline__ CFTypeRef
399 isA_BondInterface(CFTypeRef obj)
400 {
401 return (isA_CFType(obj, BondInterfaceGetTypeID()));
402 }
403
404
405 CFTypeID
406 BondInterfaceGetTypeID(void)
407 {
408 pthread_once(&bondInterface_init, __BondInterfaceInitialize); /* initialize runtime */
409 return __kBondInterfaceTypeID;
410 }
411
412
413 static BondInterfaceRef
414 __BondInterfaceCreatePrivate(CFAllocatorRef allocator,
415 CFStringRef ifname)
416 {
417 BondInterfacePrivateRef bondPrivate;
418 uint32_t size;
419
420 /* initialize runtime */
421 pthread_once(&bondInterface_init, __BondInterfaceInitialize);
422
423 /* allocate bond */
424 size = sizeof(BondInterfacePrivate) - sizeof(CFRuntimeBase);
425 bondPrivate = (BondInterfacePrivateRef)_CFRuntimeCreateInstance(allocator,
426 __kBondInterfaceTypeID,
427 size,
428 NULL);
429 if (bondPrivate == NULL) {
430 return NULL;
431 }
432
433 /* establish the bond */
434
435 bondPrivate->ifname = CFStringCreateCopy(allocator, ifname);
436 bondPrivate->devices = NULL;
437 bondPrivate->options = NULL;
438
439 return (BondInterfaceRef)bondPrivate;
440 }
441
442
443 CFStringRef
444 BondInterfaceGetInterface(BondInterfaceRef bond)
445 {
446 BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)bond;
447 CFStringRef bond_if = NULL;
448
449 if (isA_BondInterface(bond)) {
450 bond_if = bondPrivate->ifname;
451 }
452
453 return bond_if;
454 }
455
456
457 CFArrayRef
458 BondInterfaceGetDevices(BondInterfaceRef bond)
459 {
460 BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)bond;
461 CFArrayRef bond_devices = NULL;
462
463 if (isA_BondInterface(bond)) {
464 bond_devices = bondPrivate->devices;
465 }
466
467 return bond_devices;
468 }
469
470
471 CFDictionaryRef
472 BondInterfaceGetOptions(BondInterfaceRef bond)
473 {
474 BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)bond;
475 CFDictionaryRef bond_options = NULL;
476
477 if (isA_BondInterface(bond)) {
478 bond_options = bondPrivate->options;
479 }
480
481 return bond_options;
482 }
483
484
485 static void
486 BondInterfaceSetDevices(BondInterfaceRef bond, CFArrayRef newDevices)
487 {
488 BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)bond;
489
490 if (isA_BondInterface(bond)) {
491 CFAllocatorRef allocator = CFGetAllocator(bond);
492
493 if (bondPrivate->devices != NULL) CFRelease(bondPrivate->devices);
494 if ((newDevices != NULL) && (CFArrayGetCount(newDevices) > 0)) {
495 bondPrivate->devices = CFArrayCreateCopy(allocator, newDevices);
496 } else {
497 bondPrivate->devices = NULL;
498 }
499 }
500
501 return;
502 }
503
504
505 static void
506 BondInterfaceSetOptions(BondInterfaceRef bond, CFDictionaryRef newOptions)
507 {
508 BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)bond;
509
510 if (isA_BondInterface(bond)) {
511 CFAllocatorRef allocator = CFGetAllocator(bond);
512
513 if (bondPrivate->options) CFRelease(bondPrivate->options);
514 if (newOptions != NULL) {
515 bondPrivate->options = CFDictionaryCreateCopy(allocator, newOptions);
516 } else {
517 bondPrivate->options = NULL;
518 }
519 }
520
521 return;
522 }
523
524
525 /* ---------- BondPreferences ---------- */
526
527 #define BOND_PREFERENCES_BONDS CFSTR("Bonds")
528
529 #define __kBondInterface_interface CFSTR("interface") // e.g. bond0, bond1, ...
530 #define __kBondInterface_devices CFSTR("devices") // e.g. en0, en1, ...
531 #define __kBondInterface_options CFSTR("options") // e.g. UserDefinedName
532
533 typedef struct {
534
535 /* base CFType information */
536 CFRuntimeBase cfBase;
537
538 /* lock */
539 pthread_mutex_t lock;
540
541 /* underlying preferences */
542 SCPreferencesRef prefs;
543
544 /* base Bonds (before any commits) */
545 CFArrayRef bBase;
546
547 } BondPreferencesPrivate, * BondPreferencesPrivateRef;
548
549
550 static CFStringRef __BondPreferencesCopyDescription (CFTypeRef cf);
551 static void __BondPreferencesDeallocate (CFTypeRef cf);
552
553
554 static const CFRuntimeClass __BondPreferencesClass = {
555 0, // version
556 "BondPreferences", // className
557 NULL, // init
558 NULL, // copy
559 __BondPreferencesDeallocate, // dealloc
560 NULL, // equal
561 NULL, // hash
562 NULL, // copyFormattingDesc
563 __BondPreferencesCopyDescription // copyDebugDesc
564 };
565
566
567 static CFTypeID __kBondPreferencesTypeID = _kCFRuntimeNotATypeID;
568
569
570 static pthread_once_t bondPreferences_init = PTHREAD_ONCE_INIT;
571
572
573 static CFStringRef
574 __BondPreferencesCopyDescription(CFTypeRef cf)
575 {
576 CFAllocatorRef allocator = CFGetAllocator(cf);
577 CFIndex i;
578 CFArrayRef keys;
579 CFIndex n;
580 BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)cf;
581 CFMutableStringRef result;
582
583 result = CFStringCreateMutable(allocator, 0);
584 CFStringAppendFormat(result, NULL, CFSTR("<BondPreferences %p [%p]> {"), cf, allocator);
585
586 keys = SCPreferencesCopyKeyList(prefsPrivate->prefs);
587 n = CFArrayGetCount(keys);
588 for (i = 0; i < n; i++) {
589 CFStringRef key;
590 CFPropertyListRef val;
591
592 key = CFArrayGetValueAtIndex(keys, i);
593 val = SCPreferencesGetValue(prefsPrivate->prefs, key);
594
595 CFStringAppendFormat(result, NULL, CFSTR("%@ : %@"), key, val);
596 }
597 CFRelease(keys);
598
599 CFStringAppendFormat(result, NULL, CFSTR(" }"));
600
601 return result;
602 }
603
604
605 static void
606 __BondPreferencesDeallocate(CFTypeRef cf)
607 {
608 BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)cf;
609
610 /* release resources */
611
612 pthread_mutex_destroy(&prefsPrivate->lock);
613
614 if (prefsPrivate->prefs) CFRelease(prefsPrivate->prefs);
615 if (prefsPrivate->bBase) CFRelease(prefsPrivate->bBase);
616
617 return;
618 }
619
620
621 static void
622 __BondPreferencesInitialize(void)
623 {
624 __kBondPreferencesTypeID = _CFRuntimeRegisterClass(&__BondPreferencesClass);
625 return;
626 }
627
628
629 static __inline__ CFTypeRef
630 isA_BondPreferences(CFTypeRef obj)
631 {
632 return (isA_CFType(obj, BondPreferencesGetTypeID()));
633 }
634
635
636 CFArrayRef
637 _BondPreferencesCopyActiveInterfaces()
638 {
639 CFArrayCallBacks callbacks;
640 struct ifaddrs *ifap;
641 struct ifaddrs *ifp;
642 int s;
643 CFMutableArrayRef bonds = NULL;
644
645 if (getifaddrs(&ifap) == -1) {
646 SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno));
647 _SCErrorSet(kSCStatusFailed);
648 return NULL;
649 }
650
651 s = inet_dgram_socket();
652 if (s == -1) {
653 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
654 _SCErrorSet(kSCStatusFailed);
655 goto done;
656 }
657
658 callbacks = kCFTypeArrayCallBacks;
659 callbacks.equal = __BondInterfaceEquiv;
660 bonds = CFArrayCreateMutable(NULL, 0, &callbacks);
661
662 for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) {
663 BondInterfaceRef bond;
664 CFStringRef bond_if;
665 CFMutableArrayRef devices = NULL;
666 struct if_bond_status_req *ibsr_p;
667 struct if_data *if_data;
668
669 if_data = (struct if_data *)ifp->ifa_data;
670 if (if_data == NULL
671 || ifp->ifa_addr->sa_family != AF_LINK
672 || if_data->ifi_type != IFT_IEEE8023ADLAG) {
673 continue;
674 }
675 ibsr_p = if_bond_status_req_copy(s, ifp->ifa_name);
676 if (ibsr_p == NULL) {
677 SCLog(TRUE, LOG_ERR, CFSTR("if_bond_status_req_copy(%s) failed: %s"),
678 ifp->ifa_name, strerror(errno));
679 _SCErrorSet(kSCStatusFailed);
680 CFRelease(bonds);
681 goto done;
682 }
683 if (ibsr_p->ibsr_total > 0) {
684 int i;
685 struct if_bond_status * ibs_p;
686 devices = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
687
688 // iterate over each member device
689 ibs_p = (struct if_bond_status *)ibsr_p->ibsr_buffer;
690 for (i = 0; i < ibsr_p->ibsr_total; i++) {
691 CFStringRef device;
692 char if_name[IFNAMSIZ+1];
693
694 strlcpy(if_name, ibs_p[i].ibs_if_name, sizeof(if_name));
695 device = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII);
696 CFArrayAppendValue(devices, device);
697 CFRelease(device);
698 }
699 }
700 free(ibsr_p);
701 bond_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
702 bond = __BondInterfaceCreatePrivate(NULL, bond_if);
703 CFRelease(bond_if);
704
705 if (devices != NULL) {
706 BondInterfaceSetDevices(bond, devices);
707 CFRelease(devices);
708 }
709 CFArrayAppendValue(bonds, bond);
710 CFRelease(bond);
711 }
712
713 done :
714
715 (void) close(s);
716 freeifaddrs(ifap);
717 return bonds;
718 }
719
720
721 static CFIndex
722 findBond(CFArrayRef bonds, CFStringRef interface)
723 {
724 CFIndex found = kCFNotFound;
725 CFIndex i;
726 CFIndex n;
727
728 n = isA_CFArray(bonds) ? CFArrayGetCount(bonds) : 0;
729 for (i = 0; i < n; i++) {
730 CFDictionaryRef bond_dict;
731 CFStringRef bond_if;
732
733 bond_dict = CFArrayGetValueAtIndex(bonds, i);
734 if (!isA_CFDictionary(bond_dict)) {
735 break; // if the prefs are confused
736 }
737
738 bond_if = CFDictionaryGetValue(bond_dict, __kBondInterface_interface);
739 if (!isA_CFString(bond_if)) {
740 break; // if the prefs are confused
741 }
742
743 if (!CFEqual(bond_if, interface)) {
744 continue; // if not a match
745 }
746
747 // if we have found a match
748 found = i;
749 break;
750 }
751
752 return found;
753 }
754
755
756 static void
757 setConfigurationChanged(BondPreferencesRef prefs)
758 {
759 BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
760
761 /*
762 * to facilitate device configuration we will take
763 * a snapshot of the Bond preferences before any
764 * changes are made. Then, when the changes are
765 * applied we can compare what we had to what we
766 * want and configured the system accordingly.
767 */
768 if (prefsPrivate->bBase == NULL) {
769 prefsPrivate->bBase = BondPreferencesCopyInterfaces(prefs);
770 }
771
772 return;
773 }
774
775
776 CFTypeID
777 BondPreferencesGetTypeID(void)
778 {
779 pthread_once(&bondPreferences_init, __BondPreferencesInitialize); /* initialize runtime */
780 return __kBondPreferencesTypeID;
781 }
782
783
784 BondPreferencesRef
785 BondPreferencesCreate(CFAllocatorRef allocator)
786 {
787 CFBundleRef bundle;
788 CFStringRef bundleID = NULL;
789 CFStringRef name = CFSTR("BondConfiguration");
790 BondPreferencesPrivateRef prefsPrivate;
791 uint32_t size;
792
793 /* initialize runtime */
794 pthread_once(&bondPreferences_init, __BondPreferencesInitialize);
795
796 /* allocate preferences */
797 size = sizeof(BondPreferencesPrivate) - sizeof(CFRuntimeBase);
798 prefsPrivate = (BondPreferencesPrivateRef)_CFRuntimeCreateInstance(allocator,
799 __kBondPreferencesTypeID,
800 size,
801 NULL);
802 if (prefsPrivate == NULL) {
803 return NULL;
804 }
805
806 /* establish the prefs */
807
808 pthread_mutex_init(&prefsPrivate->lock, NULL);
809
810 bundle = CFBundleGetMainBundle();
811 if (bundle) {
812 bundleID = CFBundleGetIdentifier(bundle);
813 if (bundleID) {
814 CFRetain(bundleID);
815 } else {
816 CFURLRef url;
817
818 url = CFBundleCopyExecutableURL(bundle);
819 if (url) {
820 bundleID = CFURLCopyPath(url);
821 CFRelease(url);
822 }
823 }
824 }
825
826 if (bundleID) {
827 CFStringRef fullName;
828
829 if (CFEqual(bundleID, CFSTR("/"))) {
830 CFRelease(bundleID);
831 bundleID = CFStringCreateWithFormat(allocator, NULL, CFSTR("(%d)"), getpid());
832 }
833
834 fullName = CFStringCreateWithFormat(allocator, NULL, CFSTR("%@:%@"), bundleID, name);
835 name = fullName;
836 CFRelease(bundleID);
837 } else {
838 CFRetain(name);
839 }
840
841 prefsPrivate->prefs = SCPreferencesCreate(allocator, name, BOND_PREFERENCES_ID);
842 CFRelease(name);
843
844 prefsPrivate->bBase = NULL;
845
846 return (BondPreferencesRef)prefsPrivate;
847 }
848
849
850 CFArrayRef
851 BondPreferencesCopyInterfaces(BondPreferencesRef prefs)
852 {
853 CFAllocatorRef allocator;
854 CFArrayCallBacks callbacks;
855 CFIndex i;
856 CFIndex n;
857 BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
858 CFMutableArrayRef result;
859 CFArrayRef bonds;
860
861 if (!isA_BondPreferences(prefs)) {
862 _SCErrorSet(kSCStatusInvalidArgument);
863 return NULL;
864 }
865
866 allocator = CFGetAllocator(prefs);
867 callbacks = kCFTypeArrayCallBacks;
868 callbacks.equal = __BondInterfaceEquiv;
869 result = CFArrayCreateMutable(allocator, 0, &callbacks);
870
871 bonds = SCPreferencesGetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS);
872 if ((bonds != NULL) && !isA_CFArray(bonds)) {
873 goto error; // if the prefs are confused
874 }
875
876 n = (bonds != NULL) ? CFArrayGetCount(bonds) : 0;
877 for (i = 0; i < n; i++) {
878 BondInterfaceRef bond;
879 CFDictionaryRef bond_dict;
880 CFStringRef bond_if;
881 CFArrayRef devices;
882 CFDictionaryRef options;
883
884 bond_dict = CFArrayGetValueAtIndex(bonds, i);
885 if (!isA_CFDictionary(bond_dict)) {
886 goto error; // if the prefs are confused
887 }
888
889 bond_if = CFDictionaryGetValue(bond_dict, __kBondInterface_interface);
890 if (!isA_CFString(bond_if)) {
891 goto error; // if the prefs are confused
892 }
893
894
895 devices = CFDictionaryGetValue(bond_dict, __kBondInterface_devices);
896 if ((devices != NULL) && !isA_CFArray(devices)) {
897 goto error; // if the prefs are confused
898 }
899
900 options = CFDictionaryGetValue(bond_dict, __kBondInterface_options);
901 if ((options != NULL) && !isA_CFDictionary(options)) {
902 goto error; // if the prefs are confused
903 }
904
905 bond = __BondInterfaceCreatePrivate(allocator, bond_if);
906 BondInterfaceSetDevices(bond, devices);
907 BondInterfaceSetOptions(bond, options);
908 CFArrayAppendValue(result, bond);
909 CFRelease(bond);
910 }
911
912 return result;
913
914 error :
915
916 _SCErrorSet(kSCStatusFailed);
917 CFRelease(result);
918 return NULL;
919 }
920
921
922 BondInterfaceRef
923 BondPreferencesCreateInterface(BondPreferencesRef prefs)
924 {
925 CFArrayRef active_bonds = NULL;
926 CFAllocatorRef allocator;
927 CFArrayRef config_bonds;
928 CFIndex i;
929 CFIndex nActive;
930 CFIndex nConfig;
931 BondInterfaceRef newBond = NULL;
932 BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
933
934 if (!isA_BondPreferences(prefs)) {
935 _SCErrorSet(kSCStatusInvalidArgument);
936 return NULL;
937 }
938
939 pthread_mutex_lock(&prefsPrivate->lock);
940
941 /* get "configured" Bonds (and check to ensure the device is available) */
942 config_bonds = SCPreferencesGetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS);
943 if ((config_bonds != NULL) && !isA_CFArray(config_bonds)) {
944 // if the prefs are confused
945 _SCErrorSet(kSCStatusFailed);
946 goto done;
947 }
948
949 nConfig = (config_bonds != NULL) ? CFArrayGetCount(config_bonds) : 0;
950
951 /* get "active" Bonds */
952 active_bonds = _BondPreferencesCopyActiveInterfaces();
953 nActive = isA_CFArray(active_bonds) ? CFArrayGetCount(active_bonds) : 0;
954
955 /* create a new bond using an unused interface name */
956 allocator = CFGetAllocator(prefs);
957
958 for (i = 0; newBond == NULL; i++) {
959 CFIndex j;
960 CFMutableDictionaryRef newDict;
961 CFMutableArrayRef newBonds;
962 CFStringRef bond_if;
963
964 bond_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("bond%d"), i);
965
966 for (j = 0; j < nActive; j++) {
967 CFStringRef active_if;
968 BondInterfaceRef active_bond;
969
970 active_bond = CFArrayGetValueAtIndex(active_bonds, j);
971 active_if = BondInterfaceGetInterface(active_bond);
972
973 if (CFEqual(bond_if, active_if)) {
974 goto next_if; // if bond interface name not available
975 }
976 }
977
978 for (j = 0; j < nConfig; j++) {
979 CFDictionaryRef config;
980 CFStringRef config_if;
981
982 config = CFArrayGetValueAtIndex(config_bonds, j);
983 if (!isA_CFDictionary(config)) {
984 // if the prefs are confused
985 _SCErrorSet(kSCStatusFailed);
986 CFRelease(bond_if);
987 goto done;
988 }
989
990 config_if = CFDictionaryGetValue(config, __kBondInterface_interface);
991 if (!isA_CFString(config_if)) {
992 // if the prefs are confused
993 _SCErrorSet(kSCStatusFailed);
994 CFRelease(bond_if);
995 goto done;
996 }
997
998 if (CFEqual(bond_if, config_if)) {
999 goto next_if; // if bond interface name not available
1000 }
1001 }
1002
1003 /* create the bond */
1004
1005 newDict = CFDictionaryCreateMutable(allocator,
1006 0,
1007 &kCFTypeDictionaryKeyCallBacks,
1008 &kCFTypeDictionaryValueCallBacks);
1009 CFDictionaryAddValue(newDict, __kBondInterface_interface, bond_if);
1010
1011 /* create the accessor handle to be returned */
1012
1013 newBond = __BondInterfaceCreatePrivate(allocator, bond_if);
1014
1015 /* save in the prefs */
1016
1017 if (nConfig > 0) {
1018 newBonds = CFArrayCreateMutableCopy(allocator, 0, config_bonds);
1019 } else {
1020 newBonds = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
1021 }
1022 CFArrayAppendValue(newBonds, newDict);
1023 CFRelease(newDict);
1024
1025 /* yes, we're going to be changing the configuration */
1026 setConfigurationChanged(prefs);
1027
1028 (void) SCPreferencesSetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS, newBonds);
1029 CFRelease(newBonds);
1030
1031 next_if :
1032 CFRelease(bond_if);
1033 }
1034
1035 done :
1036
1037 if (active_bonds != NULL) CFRelease(active_bonds);
1038
1039 pthread_mutex_unlock(&prefsPrivate->lock);
1040
1041 return (BondInterfaceRef) newBond;
1042 }
1043
1044
1045 static Boolean
1046 _BondPreferencesUpdate(BondPreferencesRef prefs, BondInterfaceRef bond)
1047 {
1048 CFAllocatorRef allocator;
1049 CFIndex bond_index;
1050 CFArrayRef devices;
1051 CFStringRef interface;
1052 CFMutableDictionaryRef newDict;
1053 CFMutableArrayRef newBonds;
1054 CFDictionaryRef options;
1055 BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
1056 CFArrayRef bonds;
1057
1058 bonds = SCPreferencesGetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS);
1059 if ((bonds != NULL) && !isA_CFArray(bonds)) {
1060 // if the prefs are confused
1061 _SCErrorSet(kSCStatusFailed);
1062 return FALSE;
1063 }
1064
1065 interface = BondInterfaceGetInterface(bond);
1066 bond_index = findBond(bonds, interface);
1067 if (bond_index == kCFNotFound) {
1068 _SCErrorSet(kSCStatusNoKey);
1069 return FALSE;
1070 }
1071
1072 /* create the bond dictionary */
1073
1074 allocator = CFGetAllocator(prefs);
1075 newDict = CFDictionaryCreateMutable(allocator,
1076 0,
1077 &kCFTypeDictionaryKeyCallBacks,
1078 &kCFTypeDictionaryValueCallBacks);
1079 CFDictionaryAddValue(newDict, __kBondInterface_interface, interface);
1080
1081 devices = BondInterfaceGetDevices(bond);
1082 if (devices != NULL) {
1083 CFDictionaryAddValue(newDict, __kBondInterface_devices, devices);
1084 }
1085
1086 options = BondInterfaceGetOptions(bond);
1087 if (options != NULL) {
1088 CFDictionaryAddValue(newDict, __kBondInterface_options, options);
1089 }
1090
1091 /* yes, we're going to be changing the configuration */
1092 setConfigurationChanged(prefs);
1093
1094 /* update the prefs */
1095
1096 newBonds = CFArrayCreateMutableCopy(allocator, 0, bonds);
1097 CFArraySetValueAtIndex(newBonds, bond_index, newDict);
1098 CFRelease(newDict);
1099 (void) SCPreferencesSetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS, newBonds);
1100 CFRelease(newBonds);
1101
1102 return TRUE;
1103 }
1104
1105
1106 Boolean
1107 BondPreferencesAddDevice(BondPreferencesRef prefs,
1108 BondInterfaceRef bond,
1109 CFStringRef device)
1110 {
1111 CFArrayRef config_bonds;
1112 CFIndex i;
1113 CFIndex nConfig;
1114 Boolean ok = TRUE;
1115 BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
1116
1117 if (!isA_BondPreferences(prefs)) {
1118 _SCErrorSet(kSCStatusInvalidArgument);
1119 return FALSE;
1120 }
1121
1122 if (!isA_BondInterface(bond)) {
1123 _SCErrorSet(kSCStatusInvalidArgument);
1124 return FALSE;
1125 }
1126
1127 if (!isA_CFString(device)) {
1128 _SCErrorSet(kSCStatusInvalidArgument);
1129 return FALSE;
1130 }
1131
1132 if (!IsBondSupported(device)) {
1133 _SCErrorSet(kSCStatusInvalidArgument);
1134 return FALSE;
1135 }
1136
1137 pthread_mutex_lock(&prefsPrivate->lock);
1138
1139 /* get "configured" bonds */
1140 config_bonds = SCPreferencesGetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS);
1141 if ((config_bonds != NULL) && !isA_CFArray(config_bonds)) {
1142 _SCErrorSet(kSCStatusFailed);
1143 ok = FALSE;
1144 goto done;
1145 }
1146
1147 nConfig = (config_bonds != NULL) ? CFArrayGetCount(config_bonds) : 0;
1148
1149 /* check to ensure the requested device is available */
1150 for (i = 0; ok && (i < nConfig); i++) {
1151 CFDictionaryRef config_bond;
1152 CFArrayRef devices;
1153
1154 config_bond = CFArrayGetValueAtIndex(config_bonds, i);
1155 if (!isA_CFDictionary(config_bond)) {
1156 ok = FALSE; // if the prefs are confused
1157 break;
1158 }
1159
1160 devices = CFDictionaryGetValue(config_bond, __kBondInterface_devices);
1161 if ((devices != NULL) && !isA_CFArray(devices)) {
1162 ok = FALSE; // if the prefs are confused
1163 break;
1164 }
1165
1166 if (devices == NULL) {
1167 continue; // if no devices
1168 }
1169
1170 ok = !CFArrayContainsValue(devices,
1171 CFRangeMake(0, CFArrayGetCount(devices)),
1172 device);
1173 }
1174
1175 if (ok) {
1176 CFArrayRef devices;
1177 CFMutableArrayRef newDevices;
1178
1179 devices = BondInterfaceGetDevices(bond);
1180 if (devices != NULL) {
1181 devices = CFArrayCreateCopy(NULL, devices);
1182 newDevices = CFArrayCreateMutableCopy(NULL, 0, devices);
1183 } else {
1184 newDevices = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1185 }
1186 CFArrayAppendValue(newDevices, device);
1187 BondInterfaceSetDevices(bond, newDevices);
1188 CFRelease(newDevices);
1189
1190 ok = _BondPreferencesUpdate(prefs, bond);
1191 if (!ok) {
1192 BondInterfaceSetDevices(bond, devices);
1193 }
1194
1195 if (devices != NULL) {
1196 CFRelease(devices);
1197 }
1198 } else {
1199 _SCErrorSet(kSCStatusKeyExists);
1200 }
1201
1202 done :
1203
1204 pthread_mutex_unlock(&prefsPrivate->lock);
1205
1206 return ok;
1207 }
1208
1209
1210 Boolean
1211 BondPreferencesRemoveDevice(BondPreferencesRef prefs,
1212 BondInterfaceRef bond,
1213 CFStringRef device)
1214 {
1215 CFIndex bond_index;
1216 CFArrayRef devices;
1217 Boolean ok = FALSE;
1218 BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
1219
1220 if (!isA_BondPreferences(prefs)) {
1221 _SCErrorSet(kSCStatusInvalidArgument);
1222 return FALSE;
1223 }
1224
1225 if (!isA_BondInterface(bond)) {
1226 _SCErrorSet(kSCStatusInvalidArgument);
1227 return FALSE;
1228 }
1229
1230 if (!isA_CFString(device)) {
1231 _SCErrorSet(kSCStatusInvalidArgument);
1232 return FALSE;
1233 }
1234
1235 pthread_mutex_lock(&prefsPrivate->lock);
1236
1237 devices = BondInterfaceGetDevices(bond);
1238 if (devices != NULL) {
1239 bond_index = CFArrayGetFirstIndexOfValue(devices,
1240 CFRangeMake(0, CFArrayGetCount(devices)),
1241 device);
1242 if (bond_index != kCFNotFound) {
1243 CFMutableArrayRef newDevices;
1244
1245 devices = CFArrayCreateCopy(NULL, devices);
1246 newDevices = CFArrayCreateMutableCopy(NULL, 0, devices);
1247 CFArrayRemoveValueAtIndex(newDevices, bond_index);
1248 BondInterfaceSetDevices(bond, newDevices);
1249 CFRelease(newDevices);
1250
1251 ok = _BondPreferencesUpdate(prefs, bond);
1252 if (!ok) {
1253 BondInterfaceSetDevices(bond, devices);
1254 }
1255
1256 CFRelease(devices);
1257 } else {
1258 _SCErrorSet(kSCStatusNoKey);
1259 }
1260 }
1261
1262 pthread_mutex_unlock(&prefsPrivate->lock);
1263
1264 return ok;
1265 }
1266
1267
1268 Boolean
1269 BondPreferencesSetOptions(BondPreferencesRef prefs, BondInterfaceRef bond, CFDictionaryRef newOptions)
1270 {
1271 Boolean ok = FALSE;
1272 CFDictionaryRef options;
1273 BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
1274
1275 if (!isA_BondPreferences(prefs)) {
1276 _SCErrorSet(kSCStatusInvalidArgument);
1277 return FALSE;
1278 }
1279
1280 if (!isA_BondInterface(bond)) {
1281 _SCErrorSet(kSCStatusInvalidArgument);
1282 return FALSE;
1283 }
1284
1285 pthread_mutex_lock(&prefsPrivate->lock);
1286
1287 options = BondInterfaceGetOptions(bond);
1288 if (options != NULL) {
1289 options = CFDictionaryCreateCopy(NULL, options);
1290 }
1291
1292 BondInterfaceSetOptions(bond, newOptions);
1293 ok = _BondPreferencesUpdate(prefs, bond);
1294 if (!ok) {
1295 BondInterfaceSetOptions(bond, options);
1296 }
1297
1298 if (options != NULL) {
1299 CFRelease(options);
1300 }
1301
1302 pthread_mutex_unlock(&prefsPrivate->lock);
1303
1304 return ok;
1305 }
1306
1307
1308 Boolean
1309 BondPreferencesRemoveInterface(BondPreferencesRef prefs,
1310 BondInterfaceRef bond)
1311 {
1312 CFIndex bond_index;
1313 Boolean ok = FALSE;
1314 BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
1315 CFArrayRef bonds;
1316
1317 if (!isA_BondPreferences(prefs)) {
1318 _SCErrorSet(kSCStatusInvalidArgument);
1319 return FALSE;
1320 }
1321
1322 if (!isA_BondInterface(bond)) {
1323 _SCErrorSet(kSCStatusInvalidArgument);
1324 return FALSE;
1325 }
1326
1327 pthread_mutex_lock(&prefsPrivate->lock);
1328
1329 bonds = SCPreferencesGetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS);
1330 if (!isA_CFArray(bonds)) {
1331 // if the prefs are confused
1332 _SCErrorSet(kSCStatusFailed);
1333 goto done;
1334 }
1335
1336 bond_index = findBond(bonds, BondInterfaceGetInterface(bond));
1337 if (bond_index == kCFNotFound) {
1338 _SCErrorSet(kSCStatusNoKey);
1339 goto done;
1340 }
1341
1342 /* yes, we're going to be changing the configuration */
1343 setConfigurationChanged(prefs);
1344
1345 /* remove the bond */
1346
1347 if (CFArrayGetCount(bonds) > 1) {
1348 CFAllocatorRef allocator;
1349 CFMutableArrayRef newBonds;
1350
1351 allocator = CFGetAllocator(prefs);
1352 newBonds = CFArrayCreateMutableCopy(allocator, 0, bonds);
1353 CFArrayRemoveValueAtIndex(newBonds, bond_index);
1354 (void) SCPreferencesSetValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS, newBonds);
1355 CFRelease(newBonds);
1356 } else {
1357 (void) SCPreferencesRemoveValue(prefsPrivate->prefs, BOND_PREFERENCES_BONDS);
1358 }
1359
1360 ok = TRUE;
1361
1362 done :
1363
1364 pthread_mutex_unlock(&prefsPrivate->lock);
1365
1366 return ok;
1367 }
1368
1369
1370 Boolean
1371 BondPreferencesCommitChanges(BondPreferencesRef prefs)
1372 {
1373 Boolean ok = FALSE;
1374 BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
1375
1376 if (!isA_BondPreferences(prefs)) {
1377 _SCErrorSet(kSCStatusInvalidArgument);
1378 return FALSE;
1379 }
1380
1381 ok = SCPreferencesCommitChanges(prefsPrivate->prefs);
1382 if (!ok) {
1383 return ok;
1384 }
1385
1386 if (prefsPrivate->bBase != NULL) {
1387 CFRelease(prefsPrivate->bBase);
1388 prefsPrivate->bBase = NULL;
1389 }
1390
1391 return TRUE;
1392 }
1393
1394
1395 Boolean
1396 _BondPreferencesUpdateConfiguration(BondPreferencesRef prefs)
1397 {
1398 CFArrayRef active = NULL;
1399 CFArrayRef config = NULL;
1400 CFIndex i;
1401 CFIndex nActive;
1402 CFIndex nConfig;
1403 Boolean ok = FALSE;
1404 BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
1405 int s = -1;
1406
1407 if (!isA_BondPreferences(prefs)) {
1408 _SCErrorSet(kSCStatusInvalidArgument);
1409 return FALSE;
1410 }
1411
1412 /* configured Bonds */
1413 if (prefsPrivate->bBase != NULL) {
1414 /*
1415 * updated Bond preferences have not been committed
1416 * so we ignore any in-progress changes and apply the
1417 * saved preferences.
1418 */
1419 config = CFRetain(prefsPrivate->bBase);
1420 } else {
1421 /*
1422 * apply the saved preferences
1423 */
1424 config = BondPreferencesCopyInterfaces(prefs);
1425 }
1426 nConfig = CFArrayGetCount(config);
1427
1428 /* active Bonds */
1429 active = _BondPreferencesCopyActiveInterfaces();
1430 nActive = CFArrayGetCount(active);
1431
1432 /*
1433 * remove any no-longer-configured bond interfaces and
1434 * any devices associated with a bond that are no longer
1435 * associated with a bond.
1436 */
1437 for (i = 0; i < nActive; i++) {
1438 BondInterfaceRef a_bond;
1439 CFStringRef a_bond_if;
1440 CFIndex j;
1441 Boolean found = FALSE;
1442
1443 a_bond = CFArrayGetValueAtIndex(active, i);
1444 a_bond_if = BondInterfaceGetInterface(a_bond);
1445
1446 for (j = 0; j < nConfig; j++) {
1447 BondInterfaceRef c_bond;
1448 CFStringRef c_bond_if;
1449
1450 c_bond = CFArrayGetValueAtIndex(config, j);
1451 c_bond_if = BondInterfaceGetInterface(c_bond);
1452
1453 if (CFEqual(a_bond_if, c_bond_if)) {
1454 CFIndex a;
1455 CFIndex a_count;
1456 CFArrayRef a_bond_devices;
1457 CFIndex c_count;
1458 CFArrayRef c_bond_devices;
1459
1460 c_bond_devices = BondInterfaceGetDevices(c_bond);
1461 c_count = (c_bond_devices != NULL) ? CFArrayGetCount(c_bond_devices) : 0;
1462
1463 a_bond_devices = BondInterfaceGetDevices(a_bond);
1464 a_count = (a_bond_devices != NULL) ? CFArrayGetCount(a_bond_devices) : 0;
1465
1466 for (a = 0; a < a_count; a++) {
1467 CFStringRef a_device;
1468
1469 a_device = CFArrayGetValueAtIndex(a_bond_devices, a);
1470 if ((c_count == 0) ||
1471 !CFArrayContainsValue(c_bond_devices,
1472 CFRangeMake(0, c_count),
1473 a_device)) {
1474 /*
1475 * if this device is no longer part
1476 * of the bond.
1477 */
1478 if (s == -1) {
1479 s = inet_dgram_socket();
1480 }
1481
1482 ok = _Bond_removeDevice(s, a_bond_if, a_device);
1483 if (!ok) {
1484 goto done;
1485 }
1486 }
1487 }
1488
1489 found = TRUE;
1490 break;
1491 }
1492 }
1493
1494 if (!found) {
1495 /*
1496 * if this interface is no longer configured
1497 */
1498 if (s == -1) {
1499 s = inet_dgram_socket();
1500 }
1501
1502 ok = __destroyInterface(s, a_bond_if);
1503 if (!ok) {
1504 _SCErrorSet(kSCStatusFailed);
1505 goto done;
1506 }
1507 }
1508 }
1509
1510 /*
1511 * add any newly-configured bond interfaces and add any
1512 * devices that should now be associated with the bond.
1513 */
1514 for (i = 0; i < nConfig; i++) {
1515 BondInterfaceRef c_bond;
1516 CFArrayRef c_bond_devices;
1517 CFStringRef c_bond_if;
1518 CFIndex c_count;
1519 Boolean found = FALSE;
1520 CFIndex j;
1521
1522 c_bond = CFArrayGetValueAtIndex(config, i);
1523 c_bond_if = BondInterfaceGetInterface(c_bond);
1524 c_bond_devices = BondInterfaceGetDevices(c_bond);
1525 c_count = (c_bond_devices != NULL) ? CFArrayGetCount(c_bond_devices) : 0;
1526
1527 for (j = 0; j < nActive; j++) {
1528 BondInterfaceRef a_bond;
1529 CFArrayRef a_bond_devices;
1530 CFStringRef a_bond_if;
1531 CFIndex a_count;
1532
1533 a_bond = CFArrayGetValueAtIndex(active, j);
1534 a_bond_if = BondInterfaceGetInterface(a_bond);
1535 a_bond_devices = BondInterfaceGetDevices(a_bond);
1536 a_count = (a_bond_devices != NULL) ? CFArrayGetCount(a_bond_devices) : 0;
1537
1538 if (CFEqual(c_bond_if, a_bond_if)) {
1539 CFIndex c;
1540
1541 found = TRUE;
1542
1543 if ((c_bond_devices == NULL) &&
1544 (a_bond_devices == NULL)) {
1545 break; // if no change
1546 }
1547
1548 if ((c_bond_devices != NULL) &&
1549 (a_bond_devices != NULL) &&
1550 CFEqual(c_bond_devices, a_bond_devices)) {
1551 break; // if no change
1552 }
1553
1554 if (s == -1) {
1555 s = inet_dgram_socket();
1556 }
1557
1558 /*
1559 * ensure that the first device of the bond matches, if
1560 * not then we remove all current devices and add them
1561 * back in the preferred order.
1562 */
1563 if ((c_count > 0) &&
1564 (a_count > 0) &&
1565 !CFEqual(CFArrayGetValueAtIndex(c_bond_devices, 0),
1566 CFArrayGetValueAtIndex(a_bond_devices, 0))) {
1567 CFIndex a;
1568
1569 for (a = 0; a < a_count; a++) {
1570 CFStringRef a_device;
1571
1572 a_device = CFArrayGetValueAtIndex(a_bond_devices, a);
1573
1574 if (!CFArrayContainsValue(c_bond_devices,
1575 CFRangeMake(0, c_count),
1576 a_device)) {
1577 continue; // if already removed
1578 }
1579
1580 ok = _Bond_removeDevice(s, a_bond_if, a_device);
1581 if (!ok) {
1582 goto done;
1583 }
1584 }
1585
1586 a_count = 0; // all active devices have been removed
1587 }
1588
1589 /*
1590 * add any devices which are not currently associated
1591 * with the bond interface.
1592 */
1593 for (c = 0; c < c_count; c++) {
1594 CFStringRef c_device;
1595
1596 c_device = CFArrayGetValueAtIndex(c_bond_devices, c);
1597 if ((a_count == 0) ||
1598 !CFArrayContainsValue(a_bond_devices,
1599 CFRangeMake(0, a_count),
1600 c_device)) {
1601 /*
1602 * check if this device can be added to
1603 * a bond.
1604 */
1605 if (!IsBondSupported(c_device)) {
1606 // if not supported
1607 continue;
1608 }
1609
1610 /*
1611 * if this device is not currently part
1612 * of the bond.
1613 */
1614
1615 ok = _Bond_addDevice(s, c_bond_if, c_device);
1616 if (!ok) {
1617 goto done;
1618 }
1619 }
1620 }
1621
1622 break;
1623 }
1624 }
1625
1626 if (!found) {
1627 CFIndex c;
1628
1629 if (s == -1) {
1630 s = inet_dgram_socket();
1631 }
1632
1633 /*
1634 * establish the new bond interface.
1635 */
1636 ok = __createInterface(s, c_bond_if);
1637 if (!ok) {
1638 _SCErrorSet(kSCStatusFailed);
1639 goto done;
1640 }
1641
1642 /*
1643 * add any devices which are not currently associated
1644 * with the bond interface.
1645 */
1646 for (c = 0; c < c_count; c++) {
1647 CFStringRef c_device;
1648
1649 c_device = CFArrayGetValueAtIndex(c_bond_devices, c);
1650
1651 if (!IsBondSupported(c_device)) {
1652 // if not supported
1653 continue;
1654 }
1655
1656 ok = _Bond_addDevice(s, c_bond_if, c_device);
1657 if (!ok) {
1658 goto done;
1659 }
1660 }
1661 }
1662
1663 }
1664
1665 ok = TRUE;
1666
1667 done :
1668
1669 if (active != NULL) CFRelease(active);
1670 if (config != NULL) CFRelease(config);
1671 if (s != -1) (void) close(s);
1672
1673 return ok;
1674 }
1675
1676
1677 Boolean
1678 BondPreferencesApplyChanges(BondPreferencesRef prefs)
1679 {
1680 Boolean ok = FALSE;
1681 BondPreferencesPrivateRef prefsPrivate = (BondPreferencesPrivateRef)prefs;
1682
1683 if (!isA_BondPreferences(prefs)) {
1684 _SCErrorSet(kSCStatusInvalidArgument);
1685 return FALSE;
1686 }
1687
1688 pthread_mutex_lock(&prefsPrivate->lock);
1689
1690 /* apply the preferences */
1691 ok = SCPreferencesApplyChanges(prefsPrivate->prefs);
1692 if (!ok) {
1693 goto done;
1694 }
1695
1696 /* apply the Bond configuration */
1697 ok = _BondPreferencesUpdateConfiguration(prefs);
1698 if (!ok) {
1699 goto done;
1700 }
1701
1702 done :
1703
1704 pthread_mutex_unlock(&prefsPrivate->lock);
1705
1706 return ok;
1707 }
1708
1709
1710 /* ---------- BondStatus ---------- */
1711
1712 typedef struct {
1713
1714 /* base CFType information */
1715 CFRuntimeBase cfBase;
1716
1717 /* bond interface */
1718 BondInterfaceRef bond;
1719
1720 /* bond status */
1721 CFDictionaryRef status_interface; // interface status
1722 CFArrayRef devices; // per-device status
1723 CFDictionaryRef status_devices;
1724
1725 } BondStatusPrivate, * BondStatusPrivateRef;
1726
1727
1728 const CFStringRef kSCBondStatusDeviceAggregationStatus = CFSTR("AggregationStatus");
1729 const CFStringRef kSCBondStatusDeviceCollecting = CFSTR("Collecting");
1730 const CFStringRef kSCBondStatusDeviceDistributing = CFSTR("Distributing");
1731
1732
1733 static CFStringRef __BondStatusCopyDescription (CFTypeRef cf);
1734 static void __BondStatusDeallocate (CFTypeRef cf);
1735 static Boolean __BondStatusEqual (CFTypeRef cf1, CFTypeRef cf2);
1736
1737
1738 static const CFRuntimeClass __BondStatusClass = {
1739 0, // version
1740 "BondStatus", // className
1741 NULL, // init
1742 NULL, // copy
1743 __BondStatusDeallocate, // dealloc
1744 __BondStatusEqual, // equal
1745 NULL, // hash
1746 NULL, // copyFormattingDesc
1747 __BondStatusCopyDescription // copyDebugDesc
1748 };
1749
1750
1751 static CFTypeID __kBondStatusTypeID = _kCFRuntimeNotATypeID;
1752
1753
1754 static pthread_once_t bondStatus_init = PTHREAD_ONCE_INIT;
1755
1756
1757 static CFStringRef
1758 __BondStatusCopyDescription(CFTypeRef cf)
1759 {
1760 CFAllocatorRef allocator = CFGetAllocator(cf);
1761 CFMutableStringRef result;
1762 BondStatusPrivateRef statusPrivate = (BondStatusPrivateRef)cf;
1763
1764 result = CFStringCreateMutable(allocator, 0);
1765 CFStringAppendFormat(result, NULL, CFSTR("<BondStatus %p [%p]> {"), cf, allocator);
1766 CFStringAppendFormat(result, NULL, CFSTR(" bond = %@"), statusPrivate->bond);
1767 CFStringAppendFormat(result, NULL, CFSTR(" interface = %@"), statusPrivate->status_interface);
1768 CFStringAppendFormat(result, NULL, CFSTR(" devices = %@"), statusPrivate->status_devices);
1769 CFStringAppendFormat(result, NULL, CFSTR(" }"));
1770
1771 return result;
1772 }
1773
1774
1775 static void
1776 __BondStatusDeallocate(CFTypeRef cf)
1777 {
1778 BondStatusPrivateRef statusPrivate = (BondStatusPrivateRef)cf;
1779
1780 /* release resources */
1781
1782 CFRelease(statusPrivate->bond);
1783 CFRelease(statusPrivate->status_interface);
1784 if (statusPrivate->devices != NULL) CFRelease(statusPrivate->devices);
1785 CFRelease(statusPrivate->status_devices);
1786 return;
1787 }
1788
1789
1790 static Boolean
1791 __BondStatusEqual(CFTypeRef cf1, CFTypeRef cf2)
1792 {
1793 BondStatusPrivateRef status1 = (BondStatusPrivateRef)cf1;
1794 BondStatusPrivateRef status2 = (BondStatusPrivateRef)cf2;
1795
1796 if (status1 == status2)
1797 return TRUE;
1798
1799 if (!CFEqual(status1->bond, status2->bond))
1800 return FALSE; // if not the same bond
1801
1802 if (!CFEqual(status1->status_interface, status2->status_interface))
1803 return FALSE; // if not the same interface status
1804
1805 if (!CFEqual(status1->status_devices, status2->status_devices))
1806 return FALSE; // if not the same device status
1807
1808 return TRUE;
1809 }
1810
1811
1812 static void
1813 __BondStatusInitialize(void)
1814 {
1815 __kBondStatusTypeID = _CFRuntimeRegisterClass(&__BondStatusClass);
1816 return;
1817 }
1818
1819
1820 static __inline__ CFTypeRef
1821 isA_BondStatus(CFTypeRef obj)
1822 {
1823 return (isA_CFType(obj, BondStatusGetTypeID()));
1824 }
1825
1826
1827 CFTypeID
1828 BondStatusGetTypeID(void)
1829 {
1830 pthread_once(&bondStatus_init, __BondStatusInitialize); /* initialize runtime */
1831 return __kBondStatusTypeID;
1832 }
1833
1834
1835 static BondStatusRef
1836 __BondStatusCreatePrivate(CFAllocatorRef allocator,
1837 BondInterfaceRef bond,
1838 CFDictionaryRef status_interface,
1839 CFDictionaryRef status_devices)
1840 {
1841 BondStatusPrivateRef statusPrivate;
1842 uint32_t size;
1843
1844 /* initialize runtime */
1845 pthread_once(&bondStatus_init, __BondStatusInitialize);
1846
1847 /* allocate bond */
1848 size = sizeof(BondStatusPrivate) - sizeof(CFRuntimeBase);
1849 statusPrivate = (BondStatusPrivateRef)_CFRuntimeCreateInstance(allocator,
1850 __kBondStatusTypeID,
1851 size,
1852 NULL);
1853 if (statusPrivate == NULL) {
1854 return NULL;
1855 }
1856
1857 /* establish the bond status */
1858
1859 statusPrivate->bond = CFRetain(bond);
1860 statusPrivate->status_interface = CFDictionaryCreateCopy(allocator, status_interface);
1861 statusPrivate->devices = NULL;
1862 statusPrivate->status_devices = CFDictionaryCreateCopy(allocator, status_devices);
1863
1864 return (BondStatusRef)statusPrivate;
1865 }
1866
1867
1868 BondStatusRef
1869 BondInterfaceCopyStatus(BondInterfaceRef bond)
1870 {
1871 BondInterfacePrivateRef bondPrivate = (BondInterfacePrivateRef)bond;
1872 int bond_if_active;
1873 int bond_if_status;
1874 char bond_ifname[IFNAMSIZ + 1];
1875 CFIndex i;
1876 struct if_bond_status_req *ibsr_p = NULL;
1877 CFIndex n;
1878 CFNumberRef num;
1879 int s;
1880 struct if_bond_status * scan_p;
1881 BondStatusRef status = NULL;
1882 CFMutableDictionaryRef status_devices;
1883 CFMutableDictionaryRef status_interface;
1884
1885 if (!isA_BondInterface(bond)) {
1886 return NULL;
1887 }
1888
1889 s = inet_dgram_socket();
1890 if (s < 0) {
1891 goto done;
1892 }
1893 _SC_cfstring_to_cstring(bondPrivate->ifname, bond_ifname,
1894 sizeof(bond_ifname), kCFStringEncodingASCII);
1895 (void)siocgifmedia(s, bond_ifname, &bond_if_status, &bond_if_active);
1896 ibsr_p = if_bond_status_req_copy(s, bond_ifname);
1897 if (ibsr_p == NULL) {
1898 goto done;
1899 }
1900 status_interface = CFDictionaryCreateMutable(NULL,
1901 0,
1902 &kCFTypeDictionaryKeyCallBacks,
1903 &kCFTypeDictionaryValueCallBacks);
1904
1905 status_devices = CFDictionaryCreateMutable(NULL,
1906 0,
1907 &kCFTypeDictionaryKeyCallBacks,
1908 &kCFTypeDictionaryValueCallBacks);
1909 n = ibsr_p->ibsr_total;
1910 for (i = 0, scan_p = (struct if_bond_status *)ibsr_p->ibsr_buffer; i < n; i++, scan_p++) {
1911 CFStringRef bond_if;
1912 int collecting = 0;
1913 int distributing = 0;
1914 struct if_bond_partner_state * ps;
1915 CFMutableDictionaryRef status_device;
1916 int status_val;
1917
1918 ps = &scan_p->ibs_partner_state;
1919
1920 status_device = CFDictionaryCreateMutable(NULL,
1921 0,
1922 &kCFTypeDictionaryKeyCallBacks,
1923 &kCFTypeDictionaryValueCallBacks);
1924 if (lacp_actor_partner_state_in_sync(scan_p->ibs_state)) {
1925 /* we're in-sync */
1926 status_val = kSCBondStatusOK;
1927 if (lacp_actor_partner_state_in_sync(ps->ibps_state)) {
1928 /* partner is also in-sync */
1929 if (lacp_actor_partner_state_collecting(scan_p->ibs_state)
1930 && lacp_actor_partner_state_distributing(ps->ibps_state)) {
1931 /* we're able to collect (receive) frames */
1932 collecting = 1;
1933 }
1934 if (lacp_actor_partner_state_distributing(scan_p->ibs_state)
1935 && lacp_actor_partner_state_collecting(ps->ibps_state)) {
1936 /* we're able to distribute (transmit) frames */
1937 distributing = 1;
1938 }
1939 }
1940 }
1941 else {
1942 int active = 0;
1943 int status = 0;
1944 lacp_system zeroes = {{0,0,0,0,0,0}};
1945
1946 (void)siocgifmedia(s, scan_p->ibs_if_name, &status, &active);
1947 if ((status & IFM_AVALID) == 0 || (status & IFM_ACTIVE) == 0
1948 || (active & IFM_FDX) == 0) {
1949 /* link down or not full-duplex */
1950 status_val = kSCBondStatusLinkInvalid;
1951 }
1952 else if (ps->ibps_system_priority == 0
1953 && bcmp(&zeroes, &ps->ibps_system, sizeof(zeroes)) == 0) {
1954 /* no one on the other end of the link */
1955 status_val = kSCBondStatusNoPartner;
1956 }
1957 else if (active != bond_if_active) {
1958 /* the link speed was different */
1959 status_val = kSCBondStatusLinkInvalid;
1960 }
1961 else {
1962 /* partner is not in the active group */
1963 status_val = kSCBondStatusNotInActiveGroup;
1964 }
1965 }
1966 num = CFNumberCreate(NULL, kCFNumberIntType, &status_val);
1967 CFDictionarySetValue(status_device, kSCBondStatusDeviceAggregationStatus, num);
1968 CFRelease(num);
1969 num = CFNumberCreate(NULL, kCFNumberIntType, &collecting);
1970 CFDictionarySetValue(status_device, kSCBondStatusDeviceCollecting, num);
1971 CFRelease(num);
1972 num = CFNumberCreate(NULL, kCFNumberIntType, &distributing);
1973 CFDictionarySetValue(status_device, kSCBondStatusDeviceDistributing, num);
1974 CFRelease(num);
1975 bond_if = CFArrayGetValueAtIndex(bondPrivate->devices, i);
1976 CFDictionarySetValue(status_devices, bond_if, status_device);
1977 CFRelease(status_device);
1978 }
1979
1980 status = __BondStatusCreatePrivate(NULL, bond, status_interface, status_devices);
1981
1982 CFRelease(status_interface);
1983 CFRelease(status_devices);
1984 done:
1985 if (s >= 0) {
1986 close(s);
1987 }
1988 if (ibsr_p != NULL) {
1989 free(ibsr_p);
1990 }
1991 return status;
1992 }
1993
1994
1995 #define N_QUICK 16
1996
1997
1998 CFArrayRef
1999 BondStatusGetDevices(BondStatusRef bondStatus)
2000 {
2001 BondStatusPrivateRef statusPrivate = (BondStatusPrivateRef)bondStatus;
2002
2003 if (!isA_BondStatus(bondStatus)) {
2004 return NULL;
2005 }
2006
2007 if (statusPrivate->devices == NULL) {
2008 const void * keys_q[N_QUICK];
2009 const void ** keys = keys_q;
2010 CFIndex n;
2011
2012 n = CFDictionaryGetCount(statusPrivate->status_devices);
2013 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
2014 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
2015 }
2016 CFDictionaryGetKeysAndValues(statusPrivate->status_devices, keys, NULL);
2017 statusPrivate->devices = CFArrayCreate(NULL, keys, n, &kCFTypeArrayCallBacks);
2018 if (keys != keys_q) {
2019 CFAllocatorDeallocate(NULL, keys);
2020 }
2021 }
2022
2023 return statusPrivate->devices;
2024 }
2025
2026
2027 CFDictionaryRef
2028 BondStatusGetInterfaceStatus(BondStatusRef bondStatus)
2029 {
2030 BondStatusPrivateRef statusPrivate = (BondStatusPrivateRef)bondStatus;
2031
2032 if (!isA_BondStatus(bondStatus)) {
2033 return NULL;
2034 }
2035
2036 return statusPrivate->status_interface;
2037 }
2038
2039
2040 CFDictionaryRef
2041 BondStatusGetDeviceStatus(BondStatusRef bondStatus, CFStringRef device)
2042 {
2043 BondStatusPrivateRef statusPrivate = (BondStatusPrivateRef)bondStatus;
2044
2045 if (!isA_BondStatus(bondStatus)) {
2046 return NULL;
2047 }
2048
2049 return CFDictionaryGetValue(statusPrivate->status_devices, device);
2050 }