]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/BondConfiguration.c
configd-802.20.7.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / BondConfiguration.c
1 /*
2 * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * November 28, 2005 Allan Nathanson <ajn@apple.com>
28 * - public API
29 *
30 * July 22, 2004 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34
35 #include <CoreFoundation/CoreFoundation.h>
36 #include <CoreFoundation/CFRuntime.h>
37
38 #include <SystemConfiguration/SystemConfiguration.h>
39 #include "SCNetworkConfigurationInternal.h"
40 #include "SCPreferencesInternal.h"
41 #include <SystemConfiguration/SCValidation.h>
42 #include <SystemConfiguration/SCPrivate.h>
43
44 #include <ifaddrs.h>
45 #include <pthread.h>
46 #include <unistd.h>
47 #include <sys/types.h>
48 #include <sys/ioctl.h>
49 #include <sys/socket.h>
50 #include <sys/sysctl.h>
51 #include <net/ethernet.h>
52 #define KERNEL_PRIVATE
53 #include <net/if.h>
54 #include <net/if_var.h>
55 #undef KERNEL_PRIVATE
56 #include <net/if_bond_var.h>
57 #include <net/if_types.h>
58 #include <net/if_media.h>
59 #include <net/route.h>
60
61 /* ---------- Bond support ---------- */
62
63 static int
64 inet_dgram_socket()
65 {
66 int s;
67
68 s = socket(AF_INET, SOCK_DGRAM, 0);
69 if (s == -1) {
70 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno));
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) == -1) {
86 return (-1);
87 }
88 if (ifmr.ifm_count != 0) {
89 *status = ifmr.ifm_status;
90 *active = ifmr.ifm_active;
91 }
92 return (0);
93 }
94
95 static struct if_bond_status_req *
96 if_bond_status_req_copy(int s, const char * ifname)
97 {
98 void * buf = NULL;
99 struct if_bond_req ibr;
100 struct if_bond_status_req * ibsr_p;
101 struct ifreq ifr;
102
103 bzero(&ifr, sizeof(ifr));
104 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
105 bzero((char *)&ibr, sizeof(ibr));
106 ibr.ibr_op = IF_BOND_OP_GET_STATUS;
107 ibsr_p = &ibr.ibr_ibru.ibru_status;
108 ibsr_p->ibsr_version = IF_BOND_STATUS_REQ_VERSION;
109 ifr.ifr_data = (caddr_t)&ibr;
110
111 /* how many of them are there? */
112 if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) == -1) {
113 goto failed;
114 }
115 buf = malloc(sizeof(struct if_bond_status) * ibsr_p->ibsr_total + sizeof(*ibsr_p));
116 if (buf == NULL) {
117 goto failed;
118 }
119 if (ibsr_p->ibsr_total == 0) {
120 goto done;
121 }
122 ibsr_p->ibsr_count = ibsr_p->ibsr_total;
123 ibsr_p->ibsr_buffer = buf + sizeof(*ibsr_p);
124
125 /* get the list */
126 if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) == -1) {
127 goto failed;
128 }
129 done:
130 (*(struct if_bond_status_req *)buf) = *ibsr_p;
131 return ((struct if_bond_status_req *)buf);
132
133 failed:
134 if (buf != NULL) {
135 free(buf);
136 }
137 return (NULL);
138 }
139
140
141 static void
142 add_interface(CFMutableArrayRef *interfaces, CFStringRef if_name, SCPreferencesRef ni_prefs)
143 {
144 SCNetworkInterfaceRef interface = NULL;
145
146 if (*interfaces == NULL) {
147 *interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
148 }
149 if (ni_prefs != NULL) {
150 interface = __SCNetworkInterfaceCreateWithNIPreferencesUsingBSDName(NULL, ni_prefs, if_name);
151 }
152 if (interface == NULL) {
153 interface = _SCNetworkInterfaceCreateWithBSDName(NULL, if_name,
154 kIncludeNoVirtualInterfaces);
155 }
156
157 if (interface != NULL) {
158 CFArrayAppendValue(*interfaces, interface);
159 CFRelease(interface);
160 }
161 }
162
163
164 static Boolean
165 _SCBondInterfaceSetMode(SCBondInterfaceRef bond, CFNumberRef mode);
166
167
168 typedef struct {
169 CFMutableArrayRef bonds;
170 SCPreferencesRef ni_prefs;
171 SCPreferencesRef prefs;
172 } addContext, *addContextRef;
173
174
175 static void
176 add_configured_interface(const void *key, const void *value, void *context)
177 {
178 SCBondInterfaceRef bond;
179 CFStringRef bond_if = (CFStringRef)key;
180 CFDictionaryRef bond_info = (CFDictionaryRef)value;
181 CFDictionaryRef bond_options;
182 CFIndex i;
183 CFArrayRef interfaces;
184 SCNetworkInterfacePrivateRef interfacePrivate;
185 CFMutableArrayRef members = NULL;
186 CFNumberRef mode;
187 addContextRef myContext = (addContextRef)context;
188 CFStringRef name;
189 CFIndex n;
190
191 // create the bond interface
192 bond = (SCBondInterfaceRef)_SCBondInterfaceCreatePrivate(NULL, bond_if);
193
194 // add member interfaces
195 interfaces = CFDictionaryGetValue(bond_info, kSCPropVirtualNetworkInterfacesBondInterfaces);
196 n = isA_CFArray(interfaces) ? CFArrayGetCount(interfaces) : 0;
197 for (i = 0; i < n; i++) {
198 CFStringRef member;
199
200 member = CFArrayGetValueAtIndex(interfaces, i);
201 if (isA_CFString(member)) {
202 add_interface(&members, member, myContext->ni_prefs);
203 }
204 }
205 if (members != NULL) {
206 __SCBondInterfaceSetMemberInterfaces(bond, members);
207 CFRelease(members);
208 }
209
210 // set display name
211 name = CFDictionaryGetValue(bond_info, kSCPropUserDefinedName);
212 if (isA_CFString(name)) {
213 SCBondInterfaceSetLocalizedDisplayName(bond, name);
214 }
215
216 // set options
217 bond_options = CFDictionaryGetValue(bond_info, kSCPropVirtualNetworkInterfacesBondOptions);
218 if (isA_CFDictionary(bond_options)) {
219 SCBondInterfaceSetOptions(bond, bond_options);
220 }
221
222 // set the mode
223 mode = CFDictionaryGetValue(bond_info, kSCPropVirtualNetworkInterfacesBondMode);
224 _SCBondInterfaceSetMode(bond, isA_CFNumber(mode));
225
226 // estabish link to the stored configuration
227 interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
228 interfacePrivate->prefs = CFRetain(myContext->prefs);
229
230 CFArrayAppendValue(myContext->bonds, bond);
231 CFRelease(bond);
232
233 return;
234 }
235
236
237
238 #pragma mark -
239 #pragma mark SCBondInterface APIs
240
241
242 static __inline__ void
243 my_CFDictionaryApplyFunction(CFDictionaryRef theDict,
244 CFDictionaryApplierFunction applier,
245 void *context)
246 {
247 CFAllocatorRef myAllocator;
248 CFDictionaryRef myDict;
249
250 myAllocator = CFGetAllocator(theDict);
251 myDict = CFDictionaryCreateCopy(myAllocator, theDict);
252 CFDictionaryApplyFunction(myDict, applier, context);
253 CFRelease(myDict);
254 return;
255 }
256
257
258 CFArrayRef
259 SCBondInterfaceCopyAll(SCPreferencesRef prefs)
260 {
261 addContext context;
262 CFDictionaryRef dict;
263 SCPreferencesRef ni_prefs;
264 CFStringRef path;
265
266 if ((prefs == NULL) ||
267 (__SCPreferencesUsingDefaultPrefs(prefs) == TRUE)) {
268 ni_prefs = NULL;
269 }
270 else {
271 ni_prefs = __SCPreferencesCreateNIPrefsFromPrefs(prefs);
272 }
273
274 context.bonds = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
275 context.prefs = prefs;
276 context.ni_prefs = ni_prefs;
277
278 path = CFStringCreateWithFormat(NULL,
279 NULL,
280 CFSTR("/%@/%@"),
281 kSCPrefVirtualNetworkInterfaces,
282 kSCNetworkInterfaceTypeBond);
283 dict = SCPreferencesPathGetValue(prefs, path);
284 CFRelease(path);
285 if (isA_CFDictionary(dict)) {
286 my_CFDictionaryApplyFunction(dict, add_configured_interface, &context);
287 }
288
289 if (ni_prefs != NULL) {
290 CFRelease(ni_prefs);
291 }
292 return context.bonds;
293 }
294
295
296 __private_extern__ void
297 __SCBondInterfaceListCollectMembers(CFArrayRef interfaces, CFMutableSetRef set)
298 {
299 CFIndex i;
300 CFIndex n;
301
302 n = CFArrayGetCount(interfaces);
303 for (i = 0; i < n; i++) {
304 SCBondInterfaceRef bondInterface;
305 CFArrayRef members;
306
307 bondInterface = CFArrayGetValueAtIndex(interfaces, i);
308 members = SCBondInterfaceGetMemberInterfaces(bondInterface);
309 if (members != NULL) {
310 CFIndex j;
311 CFIndex n_members;
312
313 // exclude the member interfaces of this bond
314 n_members = CFArrayGetCount(members);
315 for (j = 0; j < n_members; j++) {
316 SCNetworkInterfaceRef member;
317
318 member = CFArrayGetValueAtIndex(members, j);
319 CFSetAddValue(set, member);
320 }
321 }
322
323 }
324 return;
325 }
326
327
328 CFArrayRef /* of SCNetworkInterfaceRef's */
329 SCBondInterfaceCopyAvailableMemberInterfaces(SCPreferencesRef prefs)
330 {
331 CFMutableArrayRef available;
332 CFMutableSetRef excluded;
333 CFArrayRef interfaces;
334
335 available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
336 excluded = CFSetCreateMutable (NULL, 0, &kCFTypeSetCallBacks);
337
338 // exclude Bond [member] interfaces
339 interfaces = SCBondInterfaceCopyAll(prefs);
340 if (interfaces != NULL) {
341 __SCBondInterfaceListCollectMembers(interfaces, excluded);
342 CFRelease(interfaces);
343 }
344
345 // exclude Bridge [member] interfaces
346 interfaces = SCBridgeInterfaceCopyAll(prefs);
347 if (interfaces != NULL) {
348 __SCBridgeInterfaceListCollectMembers(interfaces, excluded);
349 CFRelease(interfaces);
350 }
351
352 // exclude VLAN [physical] interfaces
353 interfaces = SCVLANInterfaceCopyAll(prefs);
354 if (interfaces != NULL) {
355 CFIndex i;
356 CFIndex n;
357
358 n = CFArrayGetCount(interfaces);
359 for (i = 0; i < n; i++) {
360 SCVLANInterfaceRef vlanInterface;
361 SCNetworkInterfaceRef physical;
362
363 // exclude the physical interface of this VLAN
364 vlanInterface = CFArrayGetValueAtIndex(interfaces, i);
365 physical = SCVLANInterfaceGetPhysicalInterface(vlanInterface);
366 CFSetAddValue(excluded, physical);
367 }
368 CFRelease(interfaces);
369 }
370
371 // identify available interfaces
372 interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface();
373 if (interfaces != NULL) {
374 CFIndex i;
375 CFIndex n;
376
377 n = CFArrayGetCount(interfaces);
378 for (i = 0; i < n; i++) {
379 SCNetworkInterfaceRef interface;
380 SCNetworkInterfacePrivateRef interfacePrivate;
381
382 interface = CFArrayGetValueAtIndex(interfaces, i);
383 interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
384
385 if (!interfacePrivate->supportsBond) {
386 // if this interface is not available
387 continue;
388 }
389
390 if (CFSetContainsValue(excluded, interface)) {
391 // if excluded
392 continue;
393 }
394
395 CFArrayAppendValue(available, interface);
396 }
397 CFRelease(interfaces);
398 }
399
400 CFRelease(excluded);
401
402 return available;
403 }
404
405
406 CFArrayRef
407 _SCBondInterfaceCopyActive(void)
408 {
409 struct ifaddrs *ifap;
410 struct ifaddrs *ifp;
411 int s;
412 CFMutableArrayRef bonds = NULL;
413
414 if (getifaddrs(&ifap) == -1) {
415 _SCErrorSet(errno);
416 SC_log(LOG_NOTICE, "getifaddrs() failed: %s", strerror(errno));
417 return NULL;
418 }
419
420 s = inet_dgram_socket();
421 if (s == -1) {
422 _SCErrorSet(errno);
423 goto done;
424 }
425
426 bonds = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
427
428 for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) {
429 SCBondInterfaceRef bond;
430 CFStringRef bond_if;
431 struct if_bond_status_req *ibsr_p;
432 struct if_data *if_data;
433 int int_val;
434 CFNumberRef mode;
435 CFMutableArrayRef members = NULL;
436
437 if_data = (struct if_data *)ifp->ifa_data;
438 if (if_data == NULL
439 || ifp->ifa_addr->sa_family != AF_LINK
440 || if_data->ifi_type != IFT_IEEE8023ADLAG) {
441 continue;
442 }
443
444 ibsr_p = if_bond_status_req_copy(s, ifp->ifa_name);
445 if (ibsr_p == NULL) {
446 if (errno == EBUSY) {
447 continue;
448 }
449 _SCErrorSet(errno);
450 SC_log(LOG_NOTICE, "if_bond_status_req_copy(%s) failed: %s",
451 ifp->ifa_name,
452 strerror(errno));
453 CFRelease(bonds);
454 bonds = NULL;
455 goto done;
456 }
457
458 // create the bond interface
459 bond_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
460 bond = (SCBondInterfaceRef)_SCBondInterfaceCreatePrivate(NULL, bond_if);
461 CFRelease(bond_if);
462
463 // set the mode
464 int_val = ibsr_p->ibsr_mode;
465 mode = CFNumberCreate(NULL, kCFNumberIntType, &int_val);
466 assert(mode != NULL);
467 _SCBondInterfaceSetMode(bond, mode);
468 CFRelease(mode);
469
470 // add member interfaces
471 if (ibsr_p->ibsr_total > 0) {
472 int i;
473 struct if_bond_status * ibs_p;
474
475 // iterate over each member interface
476 ibs_p = (struct if_bond_status *)ibsr_p->ibsr_buffer;
477 for (i = 0; i < ibsr_p->ibsr_total; i++) {
478 CFStringRef member;
479
480 member = CFStringCreateWithCString(NULL, ibs_p[i].ibs_if_name, kCFStringEncodingASCII);
481 add_interface(&members, member, NULL);
482 CFRelease(member);
483 }
484 }
485 free(ibsr_p);
486
487 if (members != NULL) {
488 __SCBondInterfaceSetMemberInterfaces(bond, members);
489 CFRelease(members);
490 }
491
492 // add bond
493 CFArrayAppendValue(bonds, bond);
494 CFRelease(bond);
495 }
496
497 done :
498
499 if (s != -1) {
500 (void) close(s);
501 }
502 freeifaddrs(ifap);
503 return bonds;
504 }
505
506
507 SCBondInterfaceRef
508 SCBondInterfaceCreate(SCPreferencesRef prefs)
509 {
510 CFAllocatorRef allocator;
511 SCBondInterfaceRef bond = NULL;
512 CFIndex i;
513
514 if (prefs == NULL) {
515 _SCErrorSet(kSCStatusInvalidArgument);
516 return NULL;
517 }
518
519 allocator = CFGetAllocator(prefs);
520
521 // create a new bond using an unused interface name
522 for (i = 0; bond == NULL; i++) {
523 CFDictionaryRef dict;
524 CFStringRef bond_if;
525 SCNetworkInterfacePrivateRef interfacePrivate;
526 CFMutableDictionaryRef newDict;
527 CFArrayRef newInterfaces;
528 Boolean ok;
529 CFStringRef path;
530
531 bond_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("bond%ld"), i);
532 path = CFStringCreateWithFormat(allocator,
533 NULL,
534 CFSTR("/%@/%@/%@"),
535 kSCPrefVirtualNetworkInterfaces,
536 kSCNetworkInterfaceTypeBond,
537 bond_if);
538 dict = SCPreferencesPathGetValue(prefs, path);
539 if (dict != NULL) {
540 // if bond interface name not available
541 CFRelease(path);
542 CFRelease(bond_if);
543 continue;
544 }
545
546 // add the bond to the stored preferences
547 newDict = CFDictionaryCreateMutable(allocator,
548 0,
549 &kCFTypeDictionaryKeyCallBacks,
550 &kCFTypeDictionaryValueCallBacks);
551 newInterfaces = CFArrayCreate(allocator, NULL, 0, &kCFTypeArrayCallBacks);
552 CFDictionaryAddValue(newDict, kSCPropVirtualNetworkInterfacesBondInterfaces, newInterfaces);
553 CFRelease(newInterfaces);
554 ok = SCPreferencesPathSetValue(prefs, path, newDict);
555 CFRelease(newDict);
556 CFRelease(path);
557 if (!ok) {
558 // if the bond could not be saved
559 CFRelease(bond_if);
560 break;
561 }
562
563 // create the SCBondInterfaceRef
564 bond = (SCBondInterfaceRef)_SCBondInterfaceCreatePrivate(allocator, bond_if);
565 CFRelease(bond_if);
566
567 // estabish link to the stored configuration
568 interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
569 interfacePrivate->prefs = CFRetain(prefs);
570 }
571
572 return bond;
573 }
574
575
576 Boolean
577 SCBondInterfaceRemove(SCBondInterfaceRef bond)
578 {
579 CFStringRef bond_if;
580 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
581 Boolean ok;
582 CFStringRef path;
583
584 if (!isA_SCBondInterface(bond)) {
585 _SCErrorSet(kSCStatusInvalidArgument);
586 return FALSE;
587 }
588
589 if (interfacePrivate->prefs == NULL) {
590 _SCErrorSet(kSCStatusInvalidArgument);
591 return FALSE;
592 }
593
594 bond_if = SCNetworkInterfaceGetBSDName(bond);
595 path = CFStringCreateWithFormat(NULL,
596 NULL,
597 CFSTR("/%@/%@/%@"),
598 kSCPrefVirtualNetworkInterfaces,
599 kSCNetworkInterfaceTypeBond,
600 bond_if);
601 ok = SCPreferencesPathRemoveValue(interfacePrivate->prefs, path);
602 CFRelease(path);
603
604 return ok;
605 }
606
607
608 CFArrayRef
609 SCBondInterfaceGetMemberInterfaces(SCBondInterfaceRef bond)
610 {
611 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
612
613 if (!isA_SCBondInterface(bond)) {
614 _SCErrorSet(kSCStatusInvalidArgument);
615 return NULL;
616 }
617
618 return interfacePrivate->bond.interfaces;
619 }
620
621
622 CFDictionaryRef
623 SCBondInterfaceGetOptions(SCBondInterfaceRef bond)
624 {
625 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
626
627 if (!isA_SCBondInterface(bond)) {
628 _SCErrorSet(kSCStatusInvalidArgument);
629 return NULL;
630 }
631
632 return interfacePrivate->bond.options;
633 }
634
635
636 __private_extern__
637 Boolean
638 __SCBondInterfaceSetMemberInterfaces(SCBondInterfaceRef bond, CFArrayRef members)
639 {
640 CFIndex i;
641 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
642 CFIndex n;
643 CFMutableArrayRef newMembers;
644 Boolean ok = TRUE;
645
646 n = (members != NULL) ? CFArrayGetCount(members) : 0;
647
648 // set member interfaces in the stored preferences
649 if (interfacePrivate->prefs != NULL) {
650 CFDictionaryRef dict;
651 CFMutableDictionaryRef newDict;
652 CFStringRef path;
653
654 path = CFStringCreateWithFormat(NULL,
655 NULL,
656 CFSTR("/%@/%@/%@"),
657 kSCPrefVirtualNetworkInterfaces,
658 kSCNetworkInterfaceTypeBond,
659 interfacePrivate->entity_device);
660 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
661 if (!isA_CFDictionary(dict)) {
662 // if the prefs are confused
663 CFRelease(path);
664 _SCErrorSet(kSCStatusFailed);
665 return FALSE;
666 }
667
668 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
669 for (i = 0; i < n; i++) {
670 SCNetworkInterfaceRef interface;
671 CFStringRef memberName;
672
673 interface = CFArrayGetValueAtIndex(members, i);
674 memberName = SCNetworkInterfaceGetBSDName(interface);
675 CFArrayAppendValue(newMembers, memberName);
676 }
677
678 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
679 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBondInterfaces, newMembers);
680 CFRelease(newMembers);
681 if (!CFEqual(dict, newDict)) {
682 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
683 }
684 CFRelease(newDict);
685 CFRelease(path);
686 }
687
688 if (ok) {
689 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
690 for (i = 0; i < n; i++) {
691 SCNetworkInterfaceRef member;
692 SCNetworkInterfacePrivateRef newMember;
693
694 member = CFArrayGetValueAtIndex(members, i);
695 newMember = __SCNetworkInterfaceCreateCopy(NULL,
696 member,
697 interfacePrivate->prefs,
698 interfacePrivate->serviceID);
699 CFArrayAppendValue(newMembers, newMember);
700 CFRelease(newMember);
701 }
702 CFRelease(interfacePrivate->bond.interfaces);
703 interfacePrivate->bond.interfaces = newMembers;
704 }
705
706 return ok;
707 }
708
709
710 Boolean
711 SCBondInterfaceSetMemberInterfaces(SCBondInterfaceRef bond, CFArrayRef members)
712 {
713 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
714 Boolean ok;
715 int sc_status = kSCStatusOK;
716
717 if (!isA_SCBondInterface(bond)) {
718 _SCErrorSet(kSCStatusInvalidArgument);
719 return FALSE;
720 }
721
722 if ((members != NULL) && !isA_CFArray(members)) {
723 _SCErrorSet(kSCStatusInvalidArgument);
724 return FALSE;
725 }
726
727 if (interfacePrivate->prefs != NULL) {
728 CFArrayRef available;
729 CFArrayRef current;
730 CFIndex i;
731 CFIndex n_available;
732 CFIndex n_current;
733 CFIndex n_members;
734 CFArrayRef services = NULL;
735
736 current = SCBondInterfaceGetMemberInterfaces(bond);
737 n_current = (current != NULL) ? CFArrayGetCount(current) : 0;
738
739 available = SCBondInterfaceCopyAvailableMemberInterfaces(interfacePrivate->prefs);
740 n_available = (available != NULL) ? CFArrayGetCount(available) : 0;
741
742 n_members = (members != NULL) ? CFArrayGetCount(members) : 0;
743 for (i = 0; i < n_members; i++) {
744 SCNetworkInterfaceRef member;
745
746 member = CFArrayGetValueAtIndex(members, i);
747
748 if ((current != NULL) &&
749 CFArrayContainsValue(current, CFRangeMake(0, n_current), member)) {
750 // current members are allowed
751 continue;
752 }
753
754 if ((available != NULL) &&
755 CFArrayContainsValue(available, CFRangeMake(0, n_available), member)) {
756 // available members are allowed but cannot be associated
757 // with any other network services.
758
759 if (services == NULL) {
760 services = __SCNetworkServiceCopyAllEnabled(interfacePrivate->prefs);
761 }
762 if ((services != NULL) &&
763 __SCNetworkServiceExistsForInterface(services, member)) {
764 sc_status = kSCStatusKeyExists;
765 break;
766 }
767
768 // if available
769 continue;
770 }
771
772 // if member not allowed
773 sc_status = kSCStatusInvalidArgument;
774 break;
775 }
776
777 if (available != NULL) CFRelease(available);
778 if (services != NULL) CFRelease(services);
779 }
780
781 if (sc_status != kSCStatusOK) {
782 _SCErrorSet(sc_status);
783 return FALSE;
784 }
785
786 ok = __SCBondInterfaceSetMemberInterfaces(bond, members);
787 return ok;
788 }
789
790
791 Boolean
792 SCBondInterfaceSetLocalizedDisplayName(SCBondInterfaceRef bond, CFStringRef newName)
793 {
794 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
795 Boolean ok = TRUE;
796
797 if (!isA_SCBondInterface(bond)) {
798 _SCErrorSet(kSCStatusInvalidArgument);
799 return FALSE;
800 }
801
802 if ((newName != NULL) && !isA_CFString(newName)) {
803 _SCErrorSet(kSCStatusInvalidArgument);
804 return FALSE;
805 }
806
807 // set name in the stored preferences
808 if (interfacePrivate->prefs != NULL) {
809 CFDictionaryRef dict;
810 CFMutableDictionaryRef newDict;
811 CFStringRef path;
812
813 path = CFStringCreateWithFormat(NULL,
814 NULL,
815 CFSTR("/%@/%@/%@"),
816 kSCPrefVirtualNetworkInterfaces,
817 kSCNetworkInterfaceTypeBond,
818 interfacePrivate->entity_device);
819 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
820 if (!isA_CFDictionary(dict)) {
821 // if the prefs are confused
822 CFRelease(path);
823 _SCErrorSet(kSCStatusFailed);
824 return FALSE;
825 }
826
827 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
828 if (newName != NULL) {
829 CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName);
830 } else {
831 CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName);
832 }
833 if (!CFEqual(dict, newDict)) {
834 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
835 }
836 CFRelease(newDict);
837 CFRelease(path);
838 }
839
840 // set name in the SCBondInterfaceRef
841 if (ok) {
842 if (interfacePrivate->localized_name != NULL) {
843 CFRelease(interfacePrivate->localized_name);
844 interfacePrivate->localized_name = NULL;
845 }
846 if (newName != NULL) {
847 interfacePrivate->localized_name = CFStringCreateCopy(NULL, newName);
848 }
849 }
850
851 return ok;
852 }
853
854
855 Boolean
856 SCBondInterfaceSetOptions(SCBondInterfaceRef bond, CFDictionaryRef newOptions)
857 {
858 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
859 Boolean ok = TRUE;
860
861 if (!isA_SCBondInterface(bond)) {
862 _SCErrorSet(kSCStatusInvalidArgument);
863 return FALSE;
864 }
865
866 if ((newOptions != NULL) && !isA_CFDictionary(newOptions)) {
867 _SCErrorSet(kSCStatusInvalidArgument);
868 return FALSE;
869 }
870
871 // set options in the stored preferences
872 if (interfacePrivate->prefs != NULL) {
873 CFDictionaryRef dict;
874 CFMutableDictionaryRef newDict;
875 CFStringRef path;
876
877 path = CFStringCreateWithFormat(NULL,
878 NULL,
879 CFSTR("/%@/%@/%@"),
880 kSCPrefVirtualNetworkInterfaces,
881 kSCNetworkInterfaceTypeBond,
882 interfacePrivate->entity_device);
883 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
884 if (!isA_CFDictionary(dict)) {
885 // if the prefs are confused
886 CFRelease(path);
887 _SCErrorSet(kSCStatusFailed);
888 return FALSE;
889 }
890
891 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
892 if (newOptions != NULL) {
893 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBondOptions, newOptions);
894 } else {
895 CFDictionaryRemoveValue(newDict, kSCPropVirtualNetworkInterfacesBondOptions);
896 }
897 if (!CFEqual(dict, newDict)) {
898 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
899 }
900 CFRelease(newDict);
901 CFRelease(path);
902 }
903
904 // set options in the SCBondInterfaceRef
905 if (ok) {
906 if (interfacePrivate->bond.options != NULL) {
907 CFRelease(interfacePrivate->bond.options);
908 interfacePrivate->bond.options = NULL;
909 }
910 if (newOptions != NULL) {
911 interfacePrivate->bond.options = CFDictionaryCreateCopy(NULL, newOptions);
912 }
913 }
914
915 return ok;
916 }
917
918
919 static Boolean
920 _SCBondInterfaceSetMode(SCBondInterfaceRef bond, CFNumberRef mode)
921 {
922 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
923 Boolean needs_release = FALSE;
924 Boolean ok = TRUE;
925
926 assert(bond != NULL);
927
928 if (mode == NULL) {
929 int mode_num = IF_BOND_MODE_LACP;
930
931 mode = CFNumberCreate(NULL, kCFNumberIntType, &mode_num);
932 needs_release = TRUE;
933 }
934
935 // set mode in the stored preferences
936 if (interfacePrivate->prefs != NULL) {
937 CFDictionaryRef dict;
938 CFMutableDictionaryRef newDict;
939 CFStringRef path;
940
941 path = CFStringCreateWithFormat(NULL,
942 NULL,
943 CFSTR("/%@/%@/%@"),
944 kSCPrefVirtualNetworkInterfaces,
945 kSCNetworkInterfaceTypeBond,
946 interfacePrivate->entity_device);
947 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
948 if (!isA_CFDictionary(dict)) {
949 // if the prefs are confused
950 CFRelease(path);
951 _SCErrorSet(kSCStatusFailed);
952 ok = FALSE;
953 goto done;
954 }
955 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
956 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBondMode, mode);
957 if (!CFEqual(dict, newDict)) {
958 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
959 }
960 CFRelease(newDict);
961 CFRelease(path);
962 }
963
964 if (ok) {
965 CFRetain(mode);
966 if (interfacePrivate->bond.mode != NULL) {
967 CFRelease(interfacePrivate->bond.mode);
968 }
969 interfacePrivate->bond.mode = mode;
970 }
971
972 done :
973
974 if (needs_release) CFRelease(mode);
975 return ok;
976 }
977
978 Boolean
979 SCBondInterfaceSetMode(SCBondInterfaceRef bond, CFNumberRef mode)
980 {
981 int mode_num;
982
983 if (!isA_SCBondInterface(bond) || !isA_CFNumber(mode)) {
984 _SCErrorSet(kSCStatusInvalidArgument);
985 return FALSE;
986 }
987
988 if (CFNumberGetValue(mode, kCFNumberIntType, &mode_num) == FALSE) {
989 _SCErrorSet(kSCStatusInvalidArgument);
990 return FALSE;
991 }
992
993 switch (mode_num) {
994 case IF_BOND_MODE_LACP:
995 case IF_BOND_MODE_STATIC:
996 break;
997 default:
998 _SCErrorSet(kSCStatusInvalidArgument);
999 return FALSE;
1000 }
1001
1002 return (_SCBondInterfaceSetMode(bond, mode));
1003 }
1004
1005 CFNumberRef
1006 SCBondInterfaceGetMode(SCBondInterfaceRef bond)
1007 {
1008 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
1009
1010 if (!isA_SCBondInterface(bond)) {
1011 _SCErrorSet(kSCStatusInvalidArgument);
1012 return NULL;
1013 }
1014 return (interfacePrivate->bond.mode);
1015 }
1016
1017
1018 #pragma mark -
1019 #pragma mark SCBondStatus APIs
1020
1021
1022 typedef struct {
1023
1024 // base CFType information
1025 CFRuntimeBase cfBase;
1026
1027 // bond status
1028 SCBondInterfaceRef bond;
1029 CFDictionaryRef status_bond;
1030
1031 // member interfaces and status
1032 CFArrayRef interfaces; // of SCNetworkInterfaceRef's
1033 CFDictionaryRef status_interfaces; // key = interface, val = interface status)
1034
1035 } SCBondStatusPrivate, * SCBondStatusPrivateRef;
1036
1037
1038 const CFStringRef kSCBondStatusDeviceAggregationStatus = CFSTR("AggregationStatus");
1039 const CFStringRef kSCBondStatusDeviceCollecting = CFSTR("Collecting");
1040 const CFStringRef kSCBondStatusDeviceDistributing = CFSTR("Distributing");
1041
1042
1043 static CFStringRef __SCBondStatusCopyDescription (CFTypeRef cf);
1044 static void __SCBondStatusDeallocate (CFTypeRef cf);
1045 static Boolean __SCBondStatusEqual (CFTypeRef cf1, CFTypeRef cf2);
1046
1047
1048 static const CFRuntimeClass __SCBondStatusClass = {
1049 0, // version
1050 "BondStatus", // className
1051 NULL, // init
1052 NULL, // copy
1053 __SCBondStatusDeallocate, // dealloc
1054 __SCBondStatusEqual, // equal
1055 NULL, // hash
1056 NULL, // copyFormattingDesc
1057 __SCBondStatusCopyDescription // copyDebugDesc
1058 };
1059
1060
1061 static CFTypeID __kSCBondStatusTypeID = _kCFRuntimeNotATypeID;
1062
1063
1064 static pthread_once_t bondStatus_init = PTHREAD_ONCE_INIT;
1065
1066
1067 static CFStringRef
1068 __SCBondStatusCopyDescription(CFTypeRef cf)
1069 {
1070 CFAllocatorRef allocator = CFGetAllocator(cf);
1071 CFMutableStringRef result;
1072 SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)cf;
1073
1074 result = CFStringCreateMutable(allocator, 0);
1075 CFStringAppendFormat(result, NULL, CFSTR("<SCBondStatus %p [%p]> {"), cf, allocator);
1076 CFStringAppendFormat(result, NULL, CFSTR(" bond = %@"), statusPrivate->bond);
1077 CFStringAppendFormat(result, NULL, CFSTR(", interface = %@"), statusPrivate->status_bond);
1078 CFStringAppendFormat(result, NULL, CFSTR(", members = %@"), statusPrivate->status_interfaces);
1079 CFStringAppendFormat(result, NULL, CFSTR(" }"));
1080
1081 return result;
1082 }
1083
1084
1085 static void
1086 __SCBondStatusDeallocate(CFTypeRef cf)
1087 {
1088 SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)cf;
1089
1090 /* release resources */
1091
1092 CFRelease(statusPrivate->bond);
1093 CFRelease(statusPrivate->status_bond);
1094 if (statusPrivate->interfaces != NULL) CFRelease(statusPrivate->interfaces);
1095 CFRelease(statusPrivate->status_interfaces);
1096 return;
1097 }
1098
1099
1100 static Boolean
1101 __SCBondStatusEqual(CFTypeRef cf1, CFTypeRef cf2)
1102 {
1103 SCBondStatusPrivateRef status1 = (SCBondStatusPrivateRef)cf1;
1104 SCBondStatusPrivateRef status2 = (SCBondStatusPrivateRef)cf2;
1105
1106 if (status1 == status2)
1107 return TRUE;
1108
1109 if (!CFEqual(status1->bond, status2->bond))
1110 return FALSE; // if not the same bond
1111
1112 if (!CFEqual(status1->status_bond, status2->status_bond))
1113 return FALSE; // if not the same interface status
1114
1115 if (!CFEqual(status1->status_interfaces, status2->status_interfaces))
1116 return FALSE; // if not the same status of the member interfaces
1117
1118 return TRUE;
1119 }
1120
1121
1122 static void
1123 __SCBondStatusInitialize(void)
1124 {
1125 __kSCBondStatusTypeID = _CFRuntimeRegisterClass(&__SCBondStatusClass);
1126 return;
1127 }
1128
1129
1130 static SCBondStatusRef
1131 __SCBondStatusCreatePrivate(CFAllocatorRef allocator,
1132 SCBondInterfaceRef bond,
1133 CFDictionaryRef status_bond,
1134 CFDictionaryRef status_interfaces)
1135 {
1136 SCBondStatusPrivateRef statusPrivate;
1137 uint32_t size;
1138
1139 /* initialize runtime */
1140 pthread_once(&bondStatus_init, __SCBondStatusInitialize);
1141
1142 /* allocate bond */
1143 size = sizeof(SCBondStatusPrivate) - sizeof(CFRuntimeBase);
1144 statusPrivate = (SCBondStatusPrivateRef)_CFRuntimeCreateInstance(allocator,
1145 __kSCBondStatusTypeID,
1146 size,
1147 NULL);
1148 if (statusPrivate == NULL) {
1149 return NULL;
1150 }
1151
1152 /* establish the bond status */
1153
1154 statusPrivate->bond = CFRetain(bond);
1155 statusPrivate->status_bond = CFDictionaryCreateCopy(NULL, status_bond);
1156
1157 statusPrivate->interfaces = NULL;
1158 statusPrivate->status_interfaces = CFDictionaryCreateCopy(NULL, status_interfaces);
1159
1160 return (SCBondStatusRef)statusPrivate;
1161 }
1162
1163
1164 static __inline__ CFTypeRef
1165 isA_SCBondStatus(CFTypeRef obj)
1166 {
1167 return (isA_CFType(obj, SCBondStatusGetTypeID()));
1168 }
1169
1170
1171 CFTypeID
1172 SCBondStatusGetTypeID()
1173 {
1174 pthread_once(&bondStatus_init, __SCBondStatusInitialize); /* initialize runtime */
1175 return __kSCBondStatusTypeID;
1176 }
1177
1178
1179 #define N_QUICK 16
1180
1181
1182 CFArrayRef /* of SCNetworkInterfaceRef's */
1183 SCBondStatusGetMemberInterfaces(SCBondStatusRef bondStatus)
1184 {
1185 SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)bondStatus;
1186
1187 if (!isA_SCBondStatus(bondStatus)) {
1188 return NULL;
1189 }
1190
1191 if (statusPrivate->interfaces == NULL) {
1192 const void * keys_q[N_QUICK];
1193 const void ** keys = keys_q;
1194 CFIndex n;
1195
1196 n = CFDictionaryGetCount(statusPrivate->status_interfaces);
1197 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
1198 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
1199 }
1200 CFDictionaryGetKeysAndValues(statusPrivate->status_interfaces, keys, NULL);
1201 statusPrivate->interfaces = CFArrayCreate(NULL, keys, n, &kCFTypeArrayCallBacks);
1202 if (keys != keys_q) {
1203 CFAllocatorDeallocate(NULL, keys);
1204 }
1205 }
1206
1207 return statusPrivate->interfaces;
1208 }
1209
1210
1211 CFDictionaryRef
1212 SCBondStatusGetInterfaceStatus(SCBondStatusRef bondStatus, SCNetworkInterfaceRef interface)
1213 {
1214 CFDictionaryRef status = NULL;
1215 SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)bondStatus;
1216
1217 if (!isA_SCBondStatus(bondStatus)) {
1218 return NULL;
1219 }
1220
1221 if (interface == NULL) {
1222 // return status of the bond
1223 status = statusPrivate->status_bond;
1224 } else {
1225 // return status of the member interface
1226 status = CFDictionaryGetValue(statusPrivate->status_interfaces, interface);
1227 }
1228
1229 return status;
1230 }
1231
1232
1233 SCBondStatusRef
1234 SCBondInterfaceCopyStatus(SCBondInterfaceRef bond)
1235 {
1236 int bond_if_active;
1237 int bond_if_status;
1238 CFIndex i;
1239 struct if_bond_status_req *ibsr_p = NULL;
1240 char if_name[IFNAMSIZ];
1241 CFIndex n;
1242 CFNumberRef num;
1243 int s;
1244 struct if_bond_status *scan_p;
1245 SCBondStatusRef status = NULL;
1246 CFMutableDictionaryRef status_bond;
1247 CFMutableDictionaryRef status_interfaces;
1248
1249 if (!isA_SCBondInterface(bond)) {
1250 _SCErrorSet(kSCStatusInvalidArgument);
1251 return NULL;
1252 }
1253
1254 s = inet_dgram_socket();
1255 if (s == -1) {
1256 _SCErrorSet(errno);
1257 goto done;
1258 }
1259
1260 _SC_cfstring_to_cstring(SCNetworkInterfaceGetBSDName(bond),
1261 if_name,
1262 sizeof(if_name),
1263 kCFStringEncodingASCII);
1264 if (siocgifmedia(s, if_name, &bond_if_status, &bond_if_active) == -1) {
1265 _SCErrorSet(errno);
1266 switch (errno) {
1267 case EBUSY :
1268 case ENXIO :
1269 break;
1270 default :
1271 SC_log(LOG_NOTICE, "siocgifmedia(%s) failed: %s",
1272 if_name,
1273 strerror(errno));
1274 }
1275 goto done;
1276 }
1277 ibsr_p = if_bond_status_req_copy(s, if_name);
1278 if (ibsr_p == NULL) {
1279 _SCErrorSet(errno);
1280 goto done;
1281 }
1282
1283 status_bond = CFDictionaryCreateMutable(NULL,
1284 0,
1285 &kCFTypeDictionaryKeyCallBacks,
1286 &kCFTypeDictionaryValueCallBacks);
1287
1288 status_interfaces = CFDictionaryCreateMutable(NULL,
1289 0,
1290 &kCFTypeDictionaryKeyCallBacks,
1291 &kCFTypeDictionaryValueCallBacks);
1292 n = ibsr_p->ibsr_total;
1293 for (i = 0, scan_p = (struct if_bond_status *)ibsr_p->ibsr_buffer; i < n; i++, scan_p++) {
1294 int collecting = 0;
1295 int distributing = 0;
1296 SCNetworkInterfaceRef interface;
1297 CFStringRef interface_name;
1298 struct if_bond_partner_state * ps;
1299 CFMutableDictionaryRef status_interface;
1300 int status_val;
1301
1302 ps = &scan_p->ibs_partner_state;
1303
1304 if (lacp_actor_partner_state_in_sync(scan_p->ibs_state)) {
1305 /* we're in-sync */
1306 status_val = kSCBondStatusOK;
1307 if (lacp_actor_partner_state_in_sync(ps->ibps_state)) {
1308 /* partner is also in-sync */
1309 if (lacp_actor_partner_state_collecting(scan_p->ibs_state)
1310 && lacp_actor_partner_state_distributing(ps->ibps_state)) {
1311 /* we're able to collect (receive) frames */
1312 collecting = 1;
1313 }
1314 if (lacp_actor_partner_state_distributing(scan_p->ibs_state)
1315 && lacp_actor_partner_state_collecting(ps->ibps_state)) {
1316 /* we're able to distribute (transmit) frames */
1317 distributing = 1;
1318 }
1319 }
1320 } else {
1321 int active = 0;
1322 int status = 0;
1323 static lacp_system zeroes = { {0, 0, 0, 0, 0, 0}};
1324
1325 if (siocgifmedia(s, scan_p->ibs_if_name, &status, &active) == -1) {
1326 switch (errno) {
1327 case EBUSY :
1328 case ENXIO :
1329 break;
1330 default :
1331 SC_log(LOG_NOTICE, "siocgifmedia(%s) failed: %s",
1332 if_name,
1333 strerror(errno));
1334 break;
1335 }
1336 }
1337 if (((status & IFM_AVALID) == 0) ||
1338 ((status & IFM_ACTIVE) == 0) ||
1339 ((active & IFM_FDX ) == 0)) {
1340 /* link down or not full-duplex */
1341 status_val = kSCBondStatusLinkInvalid;
1342 } else if ((ps->ibps_system_priority == 0) &&
1343 (bcmp(&zeroes, &ps->ibps_system, sizeof(zeroes)) == 0)) {
1344 /* no one on the other end of the link */
1345 status_val = kSCBondStatusNoPartner;
1346 } else if (active != bond_if_active) {
1347 /* the link speed was different */
1348 status_val = kSCBondStatusLinkInvalid;
1349 } else {
1350 /* partner is not in the active group */
1351 status_val = kSCBondStatusNotInActiveGroup;
1352 }
1353 }
1354
1355 // interface
1356 strlcpy(if_name, scan_p->ibs_if_name, sizeof(if_name));
1357 interface_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII);
1358 interface = _SCNetworkInterfaceCreateWithBSDName(NULL, interface_name,
1359 kIncludeNoVirtualInterfaces);
1360 CFRelease(interface_name);
1361
1362 // interface status
1363 status_interface = CFDictionaryCreateMutable(NULL,
1364 0,
1365 &kCFTypeDictionaryKeyCallBacks,
1366 &kCFTypeDictionaryValueCallBacks);
1367 num = CFNumberCreate(NULL, kCFNumberIntType, &status_val);
1368 CFDictionarySetValue(status_interface, kSCBondStatusDeviceAggregationStatus, num);
1369 CFRelease(num);
1370 num = CFNumberCreate(NULL, kCFNumberIntType, &collecting);
1371 CFDictionarySetValue(status_interface, kSCBondStatusDeviceCollecting, num);
1372 CFRelease(num);
1373 num = CFNumberCreate(NULL, kCFNumberIntType, &distributing);
1374 CFDictionarySetValue(status_interface, kSCBondStatusDeviceDistributing, num);
1375 CFRelease(num);
1376
1377 CFDictionarySetValue(status_interfaces, interface, status_interface);
1378 CFRelease(interface);
1379 CFRelease(status_interface);
1380 }
1381
1382 status = __SCBondStatusCreatePrivate(NULL, bond, status_bond, status_interfaces);
1383 CFRelease(status_bond);
1384 CFRelease(status_interfaces);
1385
1386 done:
1387
1388 if (s != -1) {
1389 close(s);
1390 }
1391 if (ibsr_p != NULL) {
1392 free(ibsr_p);
1393 }
1394 return (SCBondStatusRef)status;
1395 }
1396
1397
1398 #pragma mark -
1399 #pragma mark SCBondInterface management
1400
1401
1402 static Boolean
1403 __bond_set_mode(int s, CFStringRef bond_if, CFNumberRef mode)
1404 {
1405 struct if_bond_req breq;
1406 struct ifreq ifr;
1407 int mode_num;
1408
1409 mode_num = IF_BOND_MODE_LACP;
1410 if (mode != NULL) {
1411 CFNumberGetValue(mode, kCFNumberIntType, &mode_num);
1412 }
1413
1414 // bond interface
1415 bzero(&ifr, sizeof(ifr));
1416 (void) _SC_cfstring_to_cstring(bond_if,
1417 ifr.ifr_name,
1418 sizeof(ifr.ifr_name),
1419 kCFStringEncodingASCII);
1420 ifr.ifr_data = (caddr_t)&breq;
1421 bzero(&breq, sizeof(breq));
1422 breq.ibr_op = IF_BOND_OP_SET_MODE;
1423 breq.ibr_ibru.ibru_int_val = mode_num;
1424 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) {
1425 _SCErrorSet(errno);
1426 SC_log(LOG_ERR, "could not set mode to %@ on bond \"%@\": %s",
1427 mode,
1428 bond_if,
1429 strerror(errno));
1430 return FALSE;
1431 }
1432
1433 return TRUE;
1434 }
1435
1436 static Boolean
1437 __bond_add_interface(int s, CFStringRef bond_if, CFStringRef interface_if)
1438 {
1439 struct if_bond_req breq;
1440 struct ifreq ifr;
1441
1442 // bond interface
1443 bzero(&ifr, sizeof(ifr));
1444 (void) _SC_cfstring_to_cstring(bond_if,
1445 ifr.ifr_name,
1446 sizeof(ifr.ifr_name),
1447 kCFStringEncodingASCII);
1448 ifr.ifr_data = (caddr_t)&breq;
1449
1450 // new bond member
1451 bzero(&breq, sizeof(breq));
1452 breq.ibr_op = IF_BOND_OP_ADD_INTERFACE;
1453 (void) _SC_cfstring_to_cstring(interface_if,
1454 breq.ibr_ibru.ibru_if_name,
1455 sizeof(breq.ibr_ibru.ibru_if_name),
1456 kCFStringEncodingASCII);
1457
1458 // add new bond member
1459 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) {
1460 _SCErrorSet(errno);
1461 SC_log(LOG_ERR, "could not add interface \"%@\" to bond \"%@\": %s",
1462 interface_if,
1463 bond_if,
1464 strerror(errno));
1465 return FALSE;
1466 }
1467
1468 return TRUE;
1469 }
1470
1471
1472 static Boolean
1473 __bond_remove_interface(int s, CFStringRef bond_if, CFStringRef interface_if)
1474 {
1475 struct if_bond_req breq;
1476 struct ifreq ifr;
1477
1478 // bond interface
1479 bzero(&ifr, sizeof(ifr));
1480 (void) _SC_cfstring_to_cstring(bond_if,
1481 ifr.ifr_name,
1482 sizeof(ifr.ifr_name),
1483 kCFStringEncodingASCII);
1484 ifr.ifr_data = (caddr_t)&breq;
1485
1486 // bond member to remove
1487 bzero(&breq, sizeof(breq));
1488 breq.ibr_op = IF_BOND_OP_REMOVE_INTERFACE;
1489 (void) _SC_cfstring_to_cstring(interface_if,
1490 breq.ibr_ibru.ibru_if_name,
1491 sizeof(breq.ibr_ibru.ibru_if_name),
1492 kCFStringEncodingASCII);
1493
1494 // remove bond member
1495 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) {
1496 _SCErrorSet(errno);
1497 SC_log(LOG_ERR, "could not remove interface \"%@\" from bond \"%@\": %s",
1498 interface_if,
1499 bond_if,
1500 strerror(errno));
1501 return FALSE;
1502 }
1503
1504 return TRUE;
1505 }
1506
1507
1508 Boolean
1509 _SCBondInterfaceUpdateConfiguration(SCPreferencesRef prefs)
1510 {
1511 CFArrayRef active = NULL;
1512 CFArrayRef config = NULL;
1513 CFIndex i;
1514 CFIndex nActive;
1515 CFIndex nConfig;
1516 Boolean ok = TRUE;
1517 int s = -1;
1518
1519 if (prefs == NULL) {
1520 _SCErrorSet(kSCStatusInvalidArgument);
1521 return FALSE;
1522 }
1523
1524 /* configured Bonds */
1525 config = SCBondInterfaceCopyAll(prefs);
1526 nConfig = (config != NULL) ? CFArrayGetCount(config) : 0;
1527
1528 /* active Bonds */
1529 active = _SCBondInterfaceCopyActive();
1530 nActive = (active != NULL) ? CFArrayGetCount(active) : 0;
1531
1532 /*
1533 * remove any no-longer-configured bond interfaces and
1534 * any devices associated with a bond that are no longer
1535 * associated with a bond.
1536 */
1537 for (i = 0; i < nActive; i++) {
1538 SCBondInterfaceRef a_bond;
1539 CFStringRef a_bond_if;
1540 CFIndex j;
1541 Boolean found = FALSE;
1542
1543 a_bond = CFArrayGetValueAtIndex(active, i);
1544 a_bond_if = SCNetworkInterfaceGetBSDName(a_bond);
1545
1546 for (j = 0; j < nConfig; j++) {
1547 SCBondInterfaceRef c_bond;
1548 CFStringRef c_bond_if;
1549
1550 c_bond = CFArrayGetValueAtIndex(config, j);
1551 c_bond_if = SCNetworkInterfaceGetBSDName(c_bond);
1552
1553 if (CFEqual(a_bond_if, c_bond_if)) {
1554 CFIndex a;
1555 CFArrayRef a_bond_interfaces;
1556 CFIndex a_count;
1557 CFArrayRef c_bond_interfaces;
1558 CFIndex c_count;
1559
1560 c_bond_interfaces = SCBondInterfaceGetMemberInterfaces(c_bond);
1561 c_count = (c_bond_interfaces != NULL) ? CFArrayGetCount(c_bond_interfaces) : 0;
1562
1563 a_bond_interfaces = SCBondInterfaceGetMemberInterfaces(a_bond);
1564 a_count = (a_bond_interfaces != NULL) ? CFArrayGetCount(a_bond_interfaces) : 0;
1565
1566 for (a = 0; a < a_count; a++) {
1567 SCNetworkInterfaceRef a_interface;
1568 CFStringRef a_interface_if;
1569
1570 a_interface = CFArrayGetValueAtIndex(a_bond_interfaces, a);
1571 if ((c_count == 0) ||
1572 !CFArrayContainsValue(c_bond_interfaces,
1573 CFRangeMake(0, c_count),
1574 a_interface)) {
1575 /*
1576 * if this device is no longer part
1577 * of the bond.
1578 */
1579 if (s == -1) {
1580 s = inet_dgram_socket();
1581 if (s == -1) {
1582 _SCErrorSet(errno);
1583 ok = FALSE;
1584 goto done;
1585 }
1586 }
1587
1588 a_interface_if = SCNetworkInterfaceGetBSDName(a_interface);
1589 if (!__bond_remove_interface(s, a_bond_if, a_interface_if)) {
1590 ok = FALSE;
1591 }
1592 }
1593 }
1594
1595 found = TRUE;
1596 break;
1597 }
1598 }
1599
1600 if (!found) {
1601 /*
1602 * if this interface is no longer configured
1603 */
1604 if (s == -1) {
1605 s = inet_dgram_socket();
1606 if (s == -1) {
1607 _SCErrorSet(errno);
1608 ok = FALSE;
1609 goto done;
1610 }
1611 }
1612
1613 if (!__destroyInterface(s, a_bond_if)) {
1614 _SCErrorSet(errno);
1615 ok = FALSE;
1616 }
1617 }
1618 }
1619
1620 /*
1621 * add any newly-configured bond interfaces and add any
1622 * devices that should now be associated with the bond.
1623 */
1624 for (i = 0; i < nConfig; i++) {
1625 CFNumberRef c_bond_mode;
1626 SCBondInterfaceRef c_bond;
1627 CFArrayRef c_bond_interfaces;
1628 CFStringRef c_bond_if;
1629 CFIndex c_count;
1630 Boolean found = FALSE;
1631 CFIndex j;
1632
1633 c_bond = CFArrayGetValueAtIndex(config, i);
1634 c_bond_if = SCNetworkInterfaceGetBSDName(c_bond);
1635 c_bond_interfaces = SCBondInterfaceGetMemberInterfaces(c_bond);
1636 c_bond_mode = SCBondInterfaceGetMode(c_bond);
1637 c_count = (c_bond_interfaces != NULL) ? CFArrayGetCount(c_bond_interfaces) : 0;
1638
1639 for (j = 0; j < nActive; j++) {
1640 SCBondInterfaceRef a_bond;
1641 CFArrayRef a_bond_interfaces;
1642 CFNumberRef a_bond_mode;
1643 CFStringRef a_bond_if;
1644 CFIndex a_count;
1645
1646 a_bond = CFArrayGetValueAtIndex(active, j);
1647 a_bond_if = SCNetworkInterfaceGetBSDName(a_bond);
1648 a_bond_interfaces = SCBondInterfaceGetMemberInterfaces(a_bond);
1649 a_bond_mode = SCBondInterfaceGetMode(a_bond);
1650 a_count = (a_bond_interfaces != NULL) ? CFArrayGetCount(a_bond_interfaces) : 0;
1651
1652 if (CFEqual(c_bond_if, a_bond_if)) {
1653 CFIndex c;
1654 Boolean if_list_change = FALSE;
1655 Boolean mode_change = FALSE;
1656
1657 found = TRUE;
1658
1659 if (!_SC_CFEqual(a_bond_mode, c_bond_mode)) {
1660 mode_change = TRUE;
1661 }
1662
1663 if (!_SC_CFEqual(c_bond_interfaces, a_bond_interfaces)) {
1664 if_list_change = TRUE;
1665 }
1666 if (!mode_change && !if_list_change) {
1667 break; // if no change
1668 }
1669 if (s == -1) {
1670 s = inet_dgram_socket();
1671 if (s == -1) {
1672 _SCErrorSet(errno);
1673 ok = FALSE;
1674 goto done;
1675 }
1676 }
1677 if (mode_change) {
1678 __bond_set_mode(s, a_bond_if, c_bond_mode);
1679 }
1680 if (!if_list_change) {
1681 break; // no if list changes
1682 }
1683
1684 /*
1685 * ensure that the first device of the bond matches, if
1686 * not then we remove all current devices and add them
1687 * back in the preferred order.
1688 */
1689 if ((c_count > 0) &&
1690 (a_count > 0) &&
1691 !CFEqual(CFArrayGetValueAtIndex(c_bond_interfaces, 0),
1692 CFArrayGetValueAtIndex(a_bond_interfaces, 0))) {
1693 CFIndex a;
1694
1695 for (a = 0; a < a_count; a++) {
1696 SCNetworkInterfaceRef a_interface;
1697 CFStringRef a_interface_if;
1698
1699 a_interface = CFArrayGetValueAtIndex(a_bond_interfaces, a);
1700 if (!CFArrayContainsValue(c_bond_interfaces,
1701 CFRangeMake(0, c_count),
1702 a_interface)) {
1703 continue; // if already removed
1704 }
1705
1706 a_interface_if = SCNetworkInterfaceGetBSDName(a_interface);
1707 if (!__bond_remove_interface(s, a_bond_if, a_interface_if)) {
1708 ok = FALSE;
1709 }
1710 }
1711
1712 a_count = 0; // all active devices have been removed
1713 }
1714
1715 /*
1716 * add any devices which are not currently associated
1717 * with the bond interface.
1718 */
1719 for (c = 0; c < c_count; c++) {
1720 SCNetworkInterfaceRef c_interface;
1721 SCNetworkInterfacePrivateRef c_interfacePrivate;
1722 CFStringRef c_interface_if;
1723
1724 c_interface = CFArrayGetValueAtIndex(c_bond_interfaces, c);
1725 if ((a_count == 0) ||
1726 !CFArrayContainsValue(a_bond_interfaces,
1727 CFRangeMake(0, a_count),
1728 c_interface)) {
1729 /*
1730 * check if this member interface can be added to a bond.
1731 */
1732 c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface;
1733 if (!c_interfacePrivate->supportsBond) {
1734 // if member not supported
1735 continue;
1736 }
1737
1738 /*
1739 * if this member interface is not currently part of the bond.
1740 */
1741 c_interface_if = SCNetworkInterfaceGetBSDName(c_interface);
1742 if (!__bond_add_interface(s, c_bond_if, c_interface_if)) {
1743 // if member could not be added
1744 ok = FALSE;
1745 }
1746 }
1747 }
1748
1749 break;
1750 }
1751 }
1752
1753 if (!found) {
1754 CFIndex c;
1755
1756 if (s == -1) {
1757 s = inet_dgram_socket();
1758 if (s == -1) {
1759 _SCErrorSet(errno);
1760 ok = FALSE;
1761 goto done;
1762 }
1763 }
1764
1765 /*
1766 * establish the new bond interface.
1767 */
1768 if (!__createInterface(s, c_bond_if)) {
1769 _SCErrorSet(errno);
1770 ok = FALSE;
1771 continue;
1772 }
1773
1774 /* set the mode */
1775 __bond_set_mode(s, c_bond_if, c_bond_mode);
1776
1777 /*
1778 * add the member interfaces
1779 */
1780 for (c = 0; c < c_count; c++) {
1781 SCNetworkInterfaceRef c_interface;
1782 SCNetworkInterfacePrivateRef c_interfacePrivate;
1783 CFStringRef c_interface_if;
1784
1785 c_interface = CFArrayGetValueAtIndex(c_bond_interfaces, c);
1786 c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface;
1787 if (!c_interfacePrivate->supportsBond) {
1788 // if member not supported
1789 continue;
1790 }
1791
1792 c_interface_if = SCNetworkInterfaceGetBSDName(c_interface);
1793 if (!__bond_add_interface(s, c_bond_if, c_interface_if)) {
1794 // if member could not be added
1795 ok = FALSE;
1796 }
1797 }
1798 }
1799
1800 }
1801
1802 done :
1803
1804 if (active != NULL) CFRelease(active);
1805 if (config != NULL) CFRelease(config);
1806 if (s != -1) (void) close(s);
1807
1808 return ok;
1809 }