]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/BondConfiguration.c
configd-699.1.5.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / BondConfiguration.c
1 /*
2 * Copyright (c) 2004-2014 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 SCLog(TRUE, LOG_ERR, CFSTR("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 SCLog(TRUE, LOG_ERR, CFSTR("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 SCLog(TRUE, LOG_ERR,
451 CFSTR("if_bond_status_req_copy(%s) failed: %s"),
452 ifp->ifa_name,
453 strerror(errno));
454 CFRelease(bonds);
455 bonds = NULL;
456 goto done;
457 }
458
459 // create the bond interface
460 bond_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
461 bond = (SCBondInterfaceRef)_SCBondInterfaceCreatePrivate(NULL, bond_if);
462 CFRelease(bond_if);
463
464 // set the mode
465 int_val = ibsr_p->ibsr_mode;
466 mode = CFNumberCreate(NULL, kCFNumberIntType, &int_val);
467 assert(mode != NULL);
468 _SCBondInterfaceSetMode(bond, mode);
469 CFRelease(mode);
470
471 // add member interfaces
472 if (ibsr_p->ibsr_total > 0) {
473 int i;
474 struct if_bond_status * ibs_p;
475
476 // iterate over each member interface
477 ibs_p = (struct if_bond_status *)ibsr_p->ibsr_buffer;
478 for (i = 0; i < ibsr_p->ibsr_total; i++) {
479 CFStringRef member;
480
481 member = CFStringCreateWithCString(NULL, ibs_p[i].ibs_if_name, kCFStringEncodingASCII);
482 add_interface(&members, member, NULL);
483 CFRelease(member);
484 }
485 }
486 free(ibsr_p);
487
488 if (members != NULL) {
489 __SCBondInterfaceSetMemberInterfaces(bond, members);
490 CFRelease(members);
491 }
492
493 // add bond
494 CFArrayAppendValue(bonds, bond);
495 CFRelease(bond);
496 }
497
498 done :
499
500 if (s != -1) {
501 (void) close(s);
502 }
503 freeifaddrs(ifap);
504 return bonds;
505 }
506
507
508 SCBondInterfaceRef
509 SCBondInterfaceCreate(SCPreferencesRef prefs)
510 {
511 CFAllocatorRef allocator;
512 SCBondInterfaceRef bond = NULL;
513 CFIndex i;
514
515 if (prefs == NULL) {
516 _SCErrorSet(kSCStatusInvalidArgument);
517 return NULL;
518 }
519
520 allocator = CFGetAllocator(prefs);
521
522 // create a new bond using an unused interface name
523 for (i = 0; bond == NULL; i++) {
524 CFDictionaryRef dict;
525 CFStringRef bond_if;
526 SCNetworkInterfacePrivateRef interfacePrivate;
527 CFMutableDictionaryRef newDict;
528 CFArrayRef newInterfaces;
529 Boolean ok;
530 CFStringRef path;
531
532 bond_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("bond%ld"), i);
533 path = CFStringCreateWithFormat(allocator,
534 NULL,
535 CFSTR("/%@/%@/%@"),
536 kSCPrefVirtualNetworkInterfaces,
537 kSCNetworkInterfaceTypeBond,
538 bond_if);
539 dict = SCPreferencesPathGetValue(prefs, path);
540 if (dict != NULL) {
541 // if bond interface name not available
542 CFRelease(path);
543 CFRelease(bond_if);
544 continue;
545 }
546
547 // add the bond to the stored preferences
548 newDict = CFDictionaryCreateMutable(allocator,
549 0,
550 &kCFTypeDictionaryKeyCallBacks,
551 &kCFTypeDictionaryValueCallBacks);
552 newInterfaces = CFArrayCreate(allocator, NULL, 0, &kCFTypeArrayCallBacks);
553 CFDictionaryAddValue(newDict, kSCPropVirtualNetworkInterfacesBondInterfaces, newInterfaces);
554 CFRelease(newInterfaces);
555 ok = SCPreferencesPathSetValue(prefs, path, newDict);
556 CFRelease(newDict);
557 CFRelease(path);
558 if (!ok) {
559 // if the bond could not be saved
560 CFRelease(bond_if);
561 break;
562 }
563
564 // create the SCBondInterfaceRef
565 bond = (SCBondInterfaceRef)_SCBondInterfaceCreatePrivate(allocator, bond_if);
566 CFRelease(bond_if);
567
568 // estabish link to the stored configuration
569 interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
570 interfacePrivate->prefs = CFRetain(prefs);
571 }
572
573 return bond;
574 }
575
576
577 Boolean
578 SCBondInterfaceRemove(SCBondInterfaceRef bond)
579 {
580 CFStringRef bond_if;
581 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
582 Boolean ok;
583 CFStringRef path;
584
585 if (!isA_SCBondInterface(bond)) {
586 _SCErrorSet(kSCStatusInvalidArgument);
587 return FALSE;
588 }
589
590 if (interfacePrivate->prefs == NULL) {
591 _SCErrorSet(kSCStatusInvalidArgument);
592 return FALSE;
593 }
594
595 bond_if = SCNetworkInterfaceGetBSDName(bond);
596 path = CFStringCreateWithFormat(NULL,
597 NULL,
598 CFSTR("/%@/%@/%@"),
599 kSCPrefVirtualNetworkInterfaces,
600 kSCNetworkInterfaceTypeBond,
601 bond_if);
602 ok = SCPreferencesPathRemoveValue(interfacePrivate->prefs, path);
603 CFRelease(path);
604
605 return ok;
606 }
607
608
609 CFArrayRef
610 SCBondInterfaceGetMemberInterfaces(SCBondInterfaceRef bond)
611 {
612 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
613
614 if (!isA_SCBondInterface(bond)) {
615 _SCErrorSet(kSCStatusInvalidArgument);
616 return NULL;
617 }
618
619 return interfacePrivate->bond.interfaces;
620 }
621
622
623 CFDictionaryRef
624 SCBondInterfaceGetOptions(SCBondInterfaceRef bond)
625 {
626 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
627
628 if (!isA_SCBondInterface(bond)) {
629 _SCErrorSet(kSCStatusInvalidArgument);
630 return NULL;
631 }
632
633 return interfacePrivate->bond.options;
634 }
635
636
637 __private_extern__
638 Boolean
639 __SCBondInterfaceSetMemberInterfaces(SCBondInterfaceRef bond, CFArrayRef members)
640 {
641 CFIndex i;
642 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
643 CFIndex n;
644 CFMutableArrayRef newMembers;
645 Boolean ok = TRUE;
646
647 n = (members != NULL) ? CFArrayGetCount(members) : 0;
648
649 // set member interfaces in the stored preferences
650 if (interfacePrivate->prefs != NULL) {
651 CFDictionaryRef dict;
652 CFMutableDictionaryRef newDict;
653 CFStringRef path;
654
655 path = CFStringCreateWithFormat(NULL,
656 NULL,
657 CFSTR("/%@/%@/%@"),
658 kSCPrefVirtualNetworkInterfaces,
659 kSCNetworkInterfaceTypeBond,
660 interfacePrivate->entity_device);
661 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
662 if (!isA_CFDictionary(dict)) {
663 // if the prefs are confused
664 CFRelease(path);
665 _SCErrorSet(kSCStatusFailed);
666 return FALSE;
667 }
668
669 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
670 for (i = 0; i < n; i++) {
671 SCNetworkInterfaceRef interface;
672 CFStringRef memberName;
673
674 interface = CFArrayGetValueAtIndex(members, i);
675 memberName = SCNetworkInterfaceGetBSDName(interface);
676 CFArrayAppendValue(newMembers, memberName);
677 }
678
679 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
680 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBondInterfaces, newMembers);
681 CFRelease(newMembers);
682 if (!CFEqual(dict, newDict)) {
683 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
684 }
685 CFRelease(newDict);
686 CFRelease(path);
687 }
688
689 if (ok) {
690 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
691 for (i = 0; i < n; i++) {
692 SCNetworkInterfaceRef member;
693 SCNetworkInterfacePrivateRef newMember;
694
695 member = CFArrayGetValueAtIndex(members, i);
696 newMember = __SCNetworkInterfaceCreateCopy(NULL,
697 member,
698 interfacePrivate->prefs,
699 interfacePrivate->serviceID);
700 CFArrayAppendValue(newMembers, newMember);
701 CFRelease(newMember);
702 }
703 CFRelease(interfacePrivate->bond.interfaces);
704 interfacePrivate->bond.interfaces = newMembers;
705 }
706
707 return ok;
708 }
709
710
711 Boolean
712 SCBondInterfaceSetMemberInterfaces(SCBondInterfaceRef bond, CFArrayRef members)
713 {
714 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
715 Boolean ok;
716 int sc_status = kSCStatusOK;
717
718 if (!isA_SCBondInterface(bond)) {
719 _SCErrorSet(kSCStatusInvalidArgument);
720 return FALSE;
721 }
722
723 if ((members != NULL) && !isA_CFArray(members)) {
724 _SCErrorSet(kSCStatusInvalidArgument);
725 return FALSE;
726 }
727
728 if (interfacePrivate->prefs != NULL) {
729 CFArrayRef available;
730 CFArrayRef current;
731 CFIndex i;
732 CFIndex n_available;
733 CFIndex n_current;
734 CFIndex n_members;
735 CFArrayRef services = NULL;
736
737 current = SCBondInterfaceGetMemberInterfaces(bond);
738 n_current = (current != NULL) ? CFArrayGetCount(current) : 0;
739
740 available = SCBondInterfaceCopyAvailableMemberInterfaces(interfacePrivate->prefs);
741 n_available = (available != NULL) ? CFArrayGetCount(available) : 0;
742
743 n_members = (members != NULL) ? CFArrayGetCount(members) : 0;
744 for (i = 0; i < n_members; i++) {
745 SCNetworkInterfaceRef member;
746
747 member = CFArrayGetValueAtIndex(members, i);
748
749 if ((current != NULL) &&
750 CFArrayContainsValue(current, CFRangeMake(0, n_current), member)) {
751 // current members are allowed
752 continue;
753 }
754
755 if ((available != NULL) &&
756 CFArrayContainsValue(available, CFRangeMake(0, n_available), member)) {
757 // available members are allowed but cannot be associated
758 // with any other network services.
759
760 if (services == NULL) {
761 services = __SCNetworkServiceCopyAllEnabled(interfacePrivate->prefs);
762 }
763 if ((services != NULL) &&
764 __SCNetworkServiceExistsForInterface(services, member)) {
765 sc_status = kSCStatusKeyExists;
766 break;
767 }
768
769 // if available
770 continue;
771 }
772
773 // if member not allowed
774 sc_status = kSCStatusInvalidArgument;
775 break;
776 }
777
778 if (available != NULL) CFRelease(available);
779 if (services != NULL) CFRelease(services);
780 }
781
782 if (sc_status != kSCStatusOK) {
783 _SCErrorSet(sc_status);
784 return FALSE;
785 }
786
787 ok = __SCBondInterfaceSetMemberInterfaces(bond, members);
788 return ok;
789 }
790
791
792 Boolean
793 SCBondInterfaceSetLocalizedDisplayName(SCBondInterfaceRef bond, CFStringRef newName)
794 {
795 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
796 Boolean ok = TRUE;
797
798 if (!isA_SCBondInterface(bond)) {
799 _SCErrorSet(kSCStatusInvalidArgument);
800 return FALSE;
801 }
802
803 if ((newName != NULL) && !isA_CFString(newName)) {
804 _SCErrorSet(kSCStatusInvalidArgument);
805 return FALSE;
806 }
807
808 // set name in the stored preferences
809 if (interfacePrivate->prefs != NULL) {
810 CFDictionaryRef dict;
811 CFMutableDictionaryRef newDict;
812 CFStringRef path;
813
814 path = CFStringCreateWithFormat(NULL,
815 NULL,
816 CFSTR("/%@/%@/%@"),
817 kSCPrefVirtualNetworkInterfaces,
818 kSCNetworkInterfaceTypeBond,
819 interfacePrivate->entity_device);
820 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
821 if (!isA_CFDictionary(dict)) {
822 // if the prefs are confused
823 CFRelease(path);
824 _SCErrorSet(kSCStatusFailed);
825 return FALSE;
826 }
827
828 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
829 if (newName != NULL) {
830 CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName);
831 } else {
832 CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName);
833 }
834 if (!CFEqual(dict, newDict)) {
835 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
836 }
837 CFRelease(newDict);
838 CFRelease(path);
839 }
840
841 // set name in the SCBondInterfaceRef
842 if (ok) {
843 if (interfacePrivate->localized_name != NULL) {
844 CFRelease(interfacePrivate->localized_name);
845 interfacePrivate->localized_name = NULL;
846 }
847 if (newName != NULL) {
848 interfacePrivate->localized_name = CFStringCreateCopy(NULL, newName);
849 }
850 }
851
852 return ok;
853 }
854
855
856 Boolean
857 SCBondInterfaceSetOptions(SCBondInterfaceRef bond, CFDictionaryRef newOptions)
858 {
859 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
860 Boolean ok = TRUE;
861
862 if (!isA_SCBondInterface(bond)) {
863 _SCErrorSet(kSCStatusInvalidArgument);
864 return FALSE;
865 }
866
867 if ((newOptions != NULL) && !isA_CFDictionary(newOptions)) {
868 _SCErrorSet(kSCStatusInvalidArgument);
869 return FALSE;
870 }
871
872 // set options in the stored preferences
873 if (interfacePrivate->prefs != NULL) {
874 CFDictionaryRef dict;
875 CFMutableDictionaryRef newDict;
876 CFStringRef path;
877
878 path = CFStringCreateWithFormat(NULL,
879 NULL,
880 CFSTR("/%@/%@/%@"),
881 kSCPrefVirtualNetworkInterfaces,
882 kSCNetworkInterfaceTypeBond,
883 interfacePrivate->entity_device);
884 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
885 if (!isA_CFDictionary(dict)) {
886 // if the prefs are confused
887 CFRelease(path);
888 _SCErrorSet(kSCStatusFailed);
889 return FALSE;
890 }
891
892 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
893 if (newOptions != NULL) {
894 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBondOptions, newOptions);
895 } else {
896 CFDictionaryRemoveValue(newDict, kSCPropVirtualNetworkInterfacesBondOptions);
897 }
898 if (!CFEqual(dict, newDict)) {
899 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
900 }
901 CFRelease(newDict);
902 CFRelease(path);
903 }
904
905 // set options in the SCBondInterfaceRef
906 if (ok) {
907 if (interfacePrivate->bond.options != NULL) {
908 CFRelease(interfacePrivate->bond.options);
909 interfacePrivate->bond.options = NULL;
910 }
911 if (newOptions != NULL) {
912 interfacePrivate->bond.options = CFDictionaryCreateCopy(NULL, newOptions);
913 }
914 }
915
916 return ok;
917 }
918
919
920 static Boolean
921 _SCBondInterfaceSetMode(SCBondInterfaceRef bond, CFNumberRef mode)
922 {
923 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
924 Boolean needs_release = FALSE;
925 Boolean ok = TRUE;
926
927 assert(bond != NULL);
928
929 if (mode == NULL) {
930 int mode_num = IF_BOND_MODE_LACP;
931
932 mode = CFNumberCreate(NULL, kCFNumberIntType, &mode_num);
933 needs_release = TRUE;
934 }
935
936 // set mode in the stored preferences
937 if (interfacePrivate->prefs != NULL) {
938 CFDictionaryRef dict;
939 CFMutableDictionaryRef newDict;
940 CFStringRef path;
941
942 path = CFStringCreateWithFormat(NULL,
943 NULL,
944 CFSTR("/%@/%@/%@"),
945 kSCPrefVirtualNetworkInterfaces,
946 kSCNetworkInterfaceTypeBond,
947 interfacePrivate->entity_device);
948 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
949 if (!isA_CFDictionary(dict)) {
950 // if the prefs are confused
951 CFRelease(path);
952 _SCErrorSet(kSCStatusFailed);
953 ok = FALSE;
954 goto done;
955 }
956 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
957 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBondMode, mode);
958 if (!CFEqual(dict, newDict)) {
959 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
960 }
961 CFRelease(newDict);
962 CFRelease(path);
963 }
964
965 if (ok) {
966 CFRetain(mode);
967 if (interfacePrivate->bond.mode != NULL) {
968 CFRelease(interfacePrivate->bond.mode);
969 }
970 interfacePrivate->bond.mode = mode;
971 }
972
973 done :
974
975 if (needs_release) CFRelease(mode);
976 return ok;
977 }
978
979 Boolean
980 SCBondInterfaceSetMode(SCBondInterfaceRef bond, CFNumberRef mode)
981 {
982 int mode_num;
983
984 if (!isA_SCBondInterface(bond) || !isA_CFNumber(mode)) {
985 _SCErrorSet(kSCStatusInvalidArgument);
986 return FALSE;
987 }
988
989 if (CFNumberGetValue(mode, kCFNumberIntType, &mode_num) == FALSE) {
990 _SCErrorSet(kSCStatusInvalidArgument);
991 return FALSE;
992 }
993
994 switch (mode_num) {
995 case IF_BOND_MODE_LACP:
996 case IF_BOND_MODE_STATIC:
997 break;
998 default:
999 _SCErrorSet(kSCStatusInvalidArgument);
1000 return FALSE;
1001 }
1002
1003 return (_SCBondInterfaceSetMode(bond, mode));
1004 }
1005
1006 CFNumberRef
1007 SCBondInterfaceGetMode(SCBondInterfaceRef bond)
1008 {
1009 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bond;
1010
1011 if (!isA_SCBondInterface(bond)) {
1012 _SCErrorSet(kSCStatusInvalidArgument);
1013 return NULL;
1014 }
1015 return (interfacePrivate->bond.mode);
1016 }
1017
1018
1019 #pragma mark -
1020 #pragma mark SCBondStatus APIs
1021
1022
1023 typedef struct {
1024
1025 // base CFType information
1026 CFRuntimeBase cfBase;
1027
1028 // bond status
1029 SCBondInterfaceRef bond;
1030 CFDictionaryRef status_bond;
1031
1032 // member interfaces and status
1033 CFArrayRef interfaces; // of SCNetworkInterfaceRef's
1034 CFDictionaryRef status_interfaces; // key = interface, val = interface status)
1035
1036 } SCBondStatusPrivate, * SCBondStatusPrivateRef;
1037
1038
1039 const CFStringRef kSCBondStatusDeviceAggregationStatus = CFSTR("AggregationStatus");
1040 const CFStringRef kSCBondStatusDeviceCollecting = CFSTR("Collecting");
1041 const CFStringRef kSCBondStatusDeviceDistributing = CFSTR("Distributing");
1042
1043
1044 static CFStringRef __SCBondStatusCopyDescription (CFTypeRef cf);
1045 static void __SCBondStatusDeallocate (CFTypeRef cf);
1046 static Boolean __SCBondStatusEqual (CFTypeRef cf1, CFTypeRef cf2);
1047
1048
1049 static const CFRuntimeClass __SCBondStatusClass = {
1050 0, // version
1051 "BondStatus", // className
1052 NULL, // init
1053 NULL, // copy
1054 __SCBondStatusDeallocate, // dealloc
1055 __SCBondStatusEqual, // equal
1056 NULL, // hash
1057 NULL, // copyFormattingDesc
1058 __SCBondStatusCopyDescription // copyDebugDesc
1059 };
1060
1061
1062 static CFTypeID __kSCBondStatusTypeID = _kCFRuntimeNotATypeID;
1063
1064
1065 static pthread_once_t bondStatus_init = PTHREAD_ONCE_INIT;
1066
1067
1068 static CFStringRef
1069 __SCBondStatusCopyDescription(CFTypeRef cf)
1070 {
1071 CFAllocatorRef allocator = CFGetAllocator(cf);
1072 CFMutableStringRef result;
1073 SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)cf;
1074
1075 result = CFStringCreateMutable(allocator, 0);
1076 CFStringAppendFormat(result, NULL, CFSTR("<SCBondStatus %p [%p]> {"), cf, allocator);
1077 CFStringAppendFormat(result, NULL, CFSTR(" bond = %@"), statusPrivate->bond);
1078 CFStringAppendFormat(result, NULL, CFSTR(", interface = %@"), statusPrivate->status_bond);
1079 CFStringAppendFormat(result, NULL, CFSTR(", members = %@"), statusPrivate->status_interfaces);
1080 CFStringAppendFormat(result, NULL, CFSTR(" }"));
1081
1082 return result;
1083 }
1084
1085
1086 static void
1087 __SCBondStatusDeallocate(CFTypeRef cf)
1088 {
1089 SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)cf;
1090
1091 /* release resources */
1092
1093 CFRelease(statusPrivate->bond);
1094 CFRelease(statusPrivate->status_bond);
1095 if (statusPrivate->interfaces != NULL) CFRelease(statusPrivate->interfaces);
1096 CFRelease(statusPrivate->status_interfaces);
1097 return;
1098 }
1099
1100
1101 static Boolean
1102 __SCBondStatusEqual(CFTypeRef cf1, CFTypeRef cf2)
1103 {
1104 SCBondStatusPrivateRef status1 = (SCBondStatusPrivateRef)cf1;
1105 SCBondStatusPrivateRef status2 = (SCBondStatusPrivateRef)cf2;
1106
1107 if (status1 == status2)
1108 return TRUE;
1109
1110 if (!CFEqual(status1->bond, status2->bond))
1111 return FALSE; // if not the same bond
1112
1113 if (!CFEqual(status1->status_bond, status2->status_bond))
1114 return FALSE; // if not the same interface status
1115
1116 if (!CFEqual(status1->status_interfaces, status2->status_interfaces))
1117 return FALSE; // if not the same status of the member interfaces
1118
1119 return TRUE;
1120 }
1121
1122
1123 static void
1124 __SCBondStatusInitialize(void)
1125 {
1126 __kSCBondStatusTypeID = _CFRuntimeRegisterClass(&__SCBondStatusClass);
1127 return;
1128 }
1129
1130
1131 static SCBondStatusRef
1132 __SCBondStatusCreatePrivate(CFAllocatorRef allocator,
1133 SCBondInterfaceRef bond,
1134 CFDictionaryRef status_bond,
1135 CFDictionaryRef status_interfaces)
1136 {
1137 SCBondStatusPrivateRef statusPrivate;
1138 uint32_t size;
1139
1140 /* initialize runtime */
1141 pthread_once(&bondStatus_init, __SCBondStatusInitialize);
1142
1143 /* allocate bond */
1144 size = sizeof(SCBondStatusPrivate) - sizeof(CFRuntimeBase);
1145 statusPrivate = (SCBondStatusPrivateRef)_CFRuntimeCreateInstance(allocator,
1146 __kSCBondStatusTypeID,
1147 size,
1148 NULL);
1149 if (statusPrivate == NULL) {
1150 return NULL;
1151 }
1152
1153 /* establish the bond status */
1154
1155 statusPrivate->bond = CFRetain(bond);
1156 statusPrivate->status_bond = CFDictionaryCreateCopy(NULL, status_bond);
1157
1158 statusPrivate->interfaces = NULL;
1159 statusPrivate->status_interfaces = CFDictionaryCreateCopy(NULL, status_interfaces);
1160
1161 return (SCBondStatusRef)statusPrivate;
1162 }
1163
1164
1165 static __inline__ CFTypeRef
1166 isA_SCBondStatus(CFTypeRef obj)
1167 {
1168 return (isA_CFType(obj, SCBondStatusGetTypeID()));
1169 }
1170
1171
1172 CFTypeID
1173 SCBondStatusGetTypeID()
1174 {
1175 pthread_once(&bondStatus_init, __SCBondStatusInitialize); /* initialize runtime */
1176 return __kSCBondStatusTypeID;
1177 }
1178
1179
1180 #define N_QUICK 16
1181
1182
1183 CFArrayRef /* of SCNetworkInterfaceRef's */
1184 SCBondStatusGetMemberInterfaces(SCBondStatusRef bondStatus)
1185 {
1186 SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)bondStatus;
1187
1188 if (!isA_SCBondStatus(bondStatus)) {
1189 return NULL;
1190 }
1191
1192 if (statusPrivate->interfaces == NULL) {
1193 const void * keys_q[N_QUICK];
1194 const void ** keys = keys_q;
1195 CFIndex n;
1196
1197 n = CFDictionaryGetCount(statusPrivate->status_interfaces);
1198 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
1199 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
1200 }
1201 CFDictionaryGetKeysAndValues(statusPrivate->status_interfaces, keys, NULL);
1202 statusPrivate->interfaces = CFArrayCreate(NULL, keys, n, &kCFTypeArrayCallBacks);
1203 if (keys != keys_q) {
1204 CFAllocatorDeallocate(NULL, keys);
1205 }
1206 }
1207
1208 return statusPrivate->interfaces;
1209 }
1210
1211
1212 CFDictionaryRef
1213 SCBondStatusGetInterfaceStatus(SCBondStatusRef bondStatus, SCNetworkInterfaceRef interface)
1214 {
1215 CFDictionaryRef status = NULL;
1216 SCBondStatusPrivateRef statusPrivate = (SCBondStatusPrivateRef)bondStatus;
1217
1218 if (!isA_SCBondStatus(bondStatus)) {
1219 return NULL;
1220 }
1221
1222 if (interface == NULL) {
1223 // return status of the bond
1224 status = statusPrivate->status_bond;
1225 } else {
1226 // return status of the member interface
1227 status = CFDictionaryGetValue(statusPrivate->status_interfaces, interface);
1228 }
1229
1230 return status;
1231 }
1232
1233
1234 SCBondStatusRef
1235 SCBondInterfaceCopyStatus(SCBondInterfaceRef bond)
1236 {
1237 int bond_if_active;
1238 int bond_if_status;
1239 CFIndex i;
1240 struct if_bond_status_req *ibsr_p = NULL;
1241 char if_name[IFNAMSIZ];
1242 CFIndex n;
1243 CFNumberRef num;
1244 int s;
1245 struct if_bond_status *scan_p;
1246 SCBondStatusRef status = NULL;
1247 CFMutableDictionaryRef status_bond;
1248 CFMutableDictionaryRef status_interfaces;
1249
1250 if (!isA_SCBondInterface(bond)) {
1251 _SCErrorSet(kSCStatusInvalidArgument);
1252 return NULL;
1253 }
1254
1255 s = inet_dgram_socket();
1256 if (s == -1) {
1257 _SCErrorSet(errno);
1258 goto done;
1259 }
1260
1261 _SC_cfstring_to_cstring(SCNetworkInterfaceGetBSDName(bond),
1262 if_name,
1263 sizeof(if_name),
1264 kCFStringEncodingASCII);
1265 if (siocgifmedia(s, if_name, &bond_if_status, &bond_if_active) == -1) {
1266 _SCErrorSet(errno);
1267 switch (errno) {
1268 case EBUSY :
1269 case ENXIO :
1270 break;
1271 default :
1272 SCLog(TRUE, LOG_ERR,
1273 CFSTR("siocgifmedia(%s) failed: %s"),
1274 if_name,
1275 strerror(errno));
1276 }
1277 goto done;
1278 }
1279 ibsr_p = if_bond_status_req_copy(s, if_name);
1280 if (ibsr_p == NULL) {
1281 _SCErrorSet(errno);
1282 goto done;
1283 }
1284
1285 status_bond = CFDictionaryCreateMutable(NULL,
1286 0,
1287 &kCFTypeDictionaryKeyCallBacks,
1288 &kCFTypeDictionaryValueCallBacks);
1289
1290 status_interfaces = CFDictionaryCreateMutable(NULL,
1291 0,
1292 &kCFTypeDictionaryKeyCallBacks,
1293 &kCFTypeDictionaryValueCallBacks);
1294 n = ibsr_p->ibsr_total;
1295 for (i = 0, scan_p = (struct if_bond_status *)ibsr_p->ibsr_buffer; i < n; i++, scan_p++) {
1296 int collecting = 0;
1297 int distributing = 0;
1298 SCNetworkInterfaceRef interface;
1299 CFStringRef interface_name;
1300 struct if_bond_partner_state * ps;
1301 CFMutableDictionaryRef status_interface;
1302 int status_val;
1303
1304 ps = &scan_p->ibs_partner_state;
1305
1306 if (lacp_actor_partner_state_in_sync(scan_p->ibs_state)) {
1307 /* we're in-sync */
1308 status_val = kSCBondStatusOK;
1309 if (lacp_actor_partner_state_in_sync(ps->ibps_state)) {
1310 /* partner is also in-sync */
1311 if (lacp_actor_partner_state_collecting(scan_p->ibs_state)
1312 && lacp_actor_partner_state_distributing(ps->ibps_state)) {
1313 /* we're able to collect (receive) frames */
1314 collecting = 1;
1315 }
1316 if (lacp_actor_partner_state_distributing(scan_p->ibs_state)
1317 && lacp_actor_partner_state_collecting(ps->ibps_state)) {
1318 /* we're able to distribute (transmit) frames */
1319 distributing = 1;
1320 }
1321 }
1322 } else {
1323 int active = 0;
1324 int status = 0;
1325 static lacp_system zeroes = { {0, 0, 0, 0, 0, 0}};
1326
1327 if (siocgifmedia(s, scan_p->ibs_if_name, &status, &active) == -1) {
1328 switch (errno) {
1329 case EBUSY :
1330 case ENXIO :
1331 break;
1332 default :
1333 SCLog(TRUE, LOG_ERR,
1334 CFSTR("siocgifmedia(%s) failed: %s"),
1335 if_name,
1336 strerror(errno));
1337 break;
1338 }
1339 }
1340 if (((status & IFM_AVALID) == 0) ||
1341 ((status & IFM_ACTIVE) == 0) ||
1342 ((active & IFM_FDX ) == 0)) {
1343 /* link down or not full-duplex */
1344 status_val = kSCBondStatusLinkInvalid;
1345 } else if ((ps->ibps_system_priority == 0) &&
1346 (bcmp(&zeroes, &ps->ibps_system, sizeof(zeroes)) == 0)) {
1347 /* no one on the other end of the link */
1348 status_val = kSCBondStatusNoPartner;
1349 } else if (active != bond_if_active) {
1350 /* the link speed was different */
1351 status_val = kSCBondStatusLinkInvalid;
1352 } else {
1353 /* partner is not in the active group */
1354 status_val = kSCBondStatusNotInActiveGroup;
1355 }
1356 }
1357
1358 // interface
1359 strlcpy(if_name, scan_p->ibs_if_name, sizeof(if_name));
1360 interface_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII);
1361 interface = _SCNetworkInterfaceCreateWithBSDName(NULL, interface_name,
1362 kIncludeNoVirtualInterfaces);
1363 CFRelease(interface_name);
1364
1365 // interface status
1366 status_interface = CFDictionaryCreateMutable(NULL,
1367 0,
1368 &kCFTypeDictionaryKeyCallBacks,
1369 &kCFTypeDictionaryValueCallBacks);
1370 num = CFNumberCreate(NULL, kCFNumberIntType, &status_val);
1371 CFDictionarySetValue(status_interface, kSCBondStatusDeviceAggregationStatus, num);
1372 CFRelease(num);
1373 num = CFNumberCreate(NULL, kCFNumberIntType, &collecting);
1374 CFDictionarySetValue(status_interface, kSCBondStatusDeviceCollecting, num);
1375 CFRelease(num);
1376 num = CFNumberCreate(NULL, kCFNumberIntType, &distributing);
1377 CFDictionarySetValue(status_interface, kSCBondStatusDeviceDistributing, num);
1378 CFRelease(num);
1379
1380 CFDictionarySetValue(status_interfaces, interface, status_interface);
1381 CFRelease(interface);
1382 CFRelease(status_interface);
1383 }
1384
1385 status = __SCBondStatusCreatePrivate(NULL, bond, status_bond, status_interfaces);
1386 CFRelease(status_bond);
1387 CFRelease(status_interfaces);
1388
1389 done:
1390
1391 if (s != -1) {
1392 close(s);
1393 }
1394 if (ibsr_p != NULL) {
1395 free(ibsr_p);
1396 }
1397 return (SCBondStatusRef)status;
1398 }
1399
1400
1401 #pragma mark -
1402 #pragma mark SCBondInterface management
1403
1404
1405 static Boolean
1406 __bond_set_mode(int s, CFStringRef bond_if, CFNumberRef mode)
1407 {
1408 struct if_bond_req breq;
1409 struct ifreq ifr;
1410 int mode_num;
1411
1412 mode_num = IF_BOND_MODE_LACP;
1413 if (mode != NULL) {
1414 CFNumberGetValue(mode, kCFNumberIntType, &mode_num);
1415 }
1416
1417 // bond interface
1418 bzero(&ifr, sizeof(ifr));
1419 (void) _SC_cfstring_to_cstring(bond_if,
1420 ifr.ifr_name,
1421 sizeof(ifr.ifr_name),
1422 kCFStringEncodingASCII);
1423 ifr.ifr_data = (caddr_t)&breq;
1424 bzero(&breq, sizeof(breq));
1425 breq.ibr_op = IF_BOND_OP_SET_MODE;
1426 breq.ibr_ibru.ibru_int_val = mode_num;
1427 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) {
1428 _SCErrorSet(errno);
1429 SCLog(TRUE, LOG_ERR,
1430 CFSTR("could not set mode to %@ on bond \"%@\": %s"),
1431 mode,
1432 bond_if,
1433 strerror(errno));
1434 return FALSE;
1435 }
1436
1437 return TRUE;
1438 }
1439
1440 static Boolean
1441 __bond_add_interface(int s, CFStringRef bond_if, CFStringRef interface_if)
1442 {
1443 struct if_bond_req breq;
1444 struct ifreq ifr;
1445
1446 // bond interface
1447 bzero(&ifr, sizeof(ifr));
1448 (void) _SC_cfstring_to_cstring(bond_if,
1449 ifr.ifr_name,
1450 sizeof(ifr.ifr_name),
1451 kCFStringEncodingASCII);
1452 ifr.ifr_data = (caddr_t)&breq;
1453
1454 // new bond member
1455 bzero(&breq, sizeof(breq));
1456 breq.ibr_op = IF_BOND_OP_ADD_INTERFACE;
1457 (void) _SC_cfstring_to_cstring(interface_if,
1458 breq.ibr_ibru.ibru_if_name,
1459 sizeof(breq.ibr_ibru.ibru_if_name),
1460 kCFStringEncodingASCII);
1461
1462 // add new bond member
1463 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) {
1464 _SCErrorSet(errno);
1465 SCLog(TRUE, LOG_ERR,
1466 CFSTR("could not add interface \"%@\" to bond \"%@\": %s"),
1467 interface_if,
1468 bond_if,
1469 strerror(errno));
1470 return FALSE;
1471 }
1472
1473 return TRUE;
1474 }
1475
1476
1477 static Boolean
1478 __bond_remove_interface(int s, CFStringRef bond_if, CFStringRef interface_if)
1479 {
1480 struct if_bond_req breq;
1481 struct ifreq ifr;
1482
1483 // bond interface
1484 bzero(&ifr, sizeof(ifr));
1485 (void) _SC_cfstring_to_cstring(bond_if,
1486 ifr.ifr_name,
1487 sizeof(ifr.ifr_name),
1488 kCFStringEncodingASCII);
1489 ifr.ifr_data = (caddr_t)&breq;
1490
1491 // bond member to remove
1492 bzero(&breq, sizeof(breq));
1493 breq.ibr_op = IF_BOND_OP_REMOVE_INTERFACE;
1494 (void) _SC_cfstring_to_cstring(interface_if,
1495 breq.ibr_ibru.ibru_if_name,
1496 sizeof(breq.ibr_ibru.ibru_if_name),
1497 kCFStringEncodingASCII);
1498
1499 // remove bond member
1500 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) {
1501 _SCErrorSet(errno);
1502 SCLog(TRUE, LOG_ERR,
1503 CFSTR("could not remove interface \"%@\" from bond \"%@\": %s"),
1504 interface_if,
1505 bond_if,
1506 strerror(errno));
1507 return FALSE;
1508 }
1509
1510 return TRUE;
1511 }
1512
1513
1514 Boolean
1515 _SCBondInterfaceUpdateConfiguration(SCPreferencesRef prefs)
1516 {
1517 CFArrayRef active = NULL;
1518 CFArrayRef config = NULL;
1519 CFIndex i;
1520 CFIndex nActive;
1521 CFIndex nConfig;
1522 Boolean ok = TRUE;
1523 int s = -1;
1524
1525 if (prefs == NULL) {
1526 _SCErrorSet(kSCStatusInvalidArgument);
1527 return FALSE;
1528 }
1529
1530 /* configured Bonds */
1531 config = SCBondInterfaceCopyAll(prefs);
1532 nConfig = (config != NULL) ? CFArrayGetCount(config) : 0;
1533
1534 /* active Bonds */
1535 active = _SCBondInterfaceCopyActive();
1536 nActive = (active != NULL) ? CFArrayGetCount(active) : 0;
1537
1538 /*
1539 * remove any no-longer-configured bond interfaces and
1540 * any devices associated with a bond that are no longer
1541 * associated with a bond.
1542 */
1543 for (i = 0; i < nActive; i++) {
1544 SCBondInterfaceRef a_bond;
1545 CFStringRef a_bond_if;
1546 CFIndex j;
1547 Boolean found = FALSE;
1548
1549 a_bond = CFArrayGetValueAtIndex(active, i);
1550 a_bond_if = SCNetworkInterfaceGetBSDName(a_bond);
1551
1552 for (j = 0; j < nConfig; j++) {
1553 SCBondInterfaceRef c_bond;
1554 CFStringRef c_bond_if;
1555
1556 c_bond = CFArrayGetValueAtIndex(config, j);
1557 c_bond_if = SCNetworkInterfaceGetBSDName(c_bond);
1558
1559 if (CFEqual(a_bond_if, c_bond_if)) {
1560 CFIndex a;
1561 CFArrayRef a_bond_interfaces;
1562 CFIndex a_count;
1563 CFArrayRef c_bond_interfaces;
1564 CFIndex c_count;
1565
1566 c_bond_interfaces = SCBondInterfaceGetMemberInterfaces(c_bond);
1567 c_count = (c_bond_interfaces != NULL) ? CFArrayGetCount(c_bond_interfaces) : 0;
1568
1569 a_bond_interfaces = SCBondInterfaceGetMemberInterfaces(a_bond);
1570 a_count = (a_bond_interfaces != NULL) ? CFArrayGetCount(a_bond_interfaces) : 0;
1571
1572 for (a = 0; a < a_count; a++) {
1573 SCNetworkInterfaceRef a_interface;
1574 CFStringRef a_interface_if;
1575
1576 a_interface = CFArrayGetValueAtIndex(a_bond_interfaces, a);
1577 if ((c_count == 0) ||
1578 !CFArrayContainsValue(c_bond_interfaces,
1579 CFRangeMake(0, c_count),
1580 a_interface)) {
1581 /*
1582 * if this device is no longer part
1583 * of the bond.
1584 */
1585 if (s == -1) {
1586 s = inet_dgram_socket();
1587 if (s == -1) {
1588 _SCErrorSet(errno);
1589 ok = FALSE;
1590 goto done;
1591 }
1592 }
1593
1594 a_interface_if = SCNetworkInterfaceGetBSDName(a_interface);
1595 if (!__bond_remove_interface(s, a_bond_if, a_interface_if)) {
1596 ok = FALSE;
1597 }
1598 }
1599 }
1600
1601 found = TRUE;
1602 break;
1603 }
1604 }
1605
1606 if (!found) {
1607 /*
1608 * if this interface is no longer configured
1609 */
1610 if (s == -1) {
1611 s = inet_dgram_socket();
1612 if (s == -1) {
1613 _SCErrorSet(errno);
1614 ok = FALSE;
1615 goto done;
1616 }
1617 }
1618
1619 if (!__destroyInterface(s, a_bond_if)) {
1620 _SCErrorSet(errno);
1621 ok = FALSE;
1622 }
1623 }
1624 }
1625
1626 /*
1627 * add any newly-configured bond interfaces and add any
1628 * devices that should now be associated with the bond.
1629 */
1630 for (i = 0; i < nConfig; i++) {
1631 CFNumberRef c_bond_mode;
1632 SCBondInterfaceRef c_bond;
1633 CFArrayRef c_bond_interfaces;
1634 CFStringRef c_bond_if;
1635 CFIndex c_count;
1636 Boolean found = FALSE;
1637 CFIndex j;
1638
1639 c_bond = CFArrayGetValueAtIndex(config, i);
1640 c_bond_if = SCNetworkInterfaceGetBSDName(c_bond);
1641 c_bond_interfaces = SCBondInterfaceGetMemberInterfaces(c_bond);
1642 c_bond_mode = SCBondInterfaceGetMode(c_bond);
1643 c_count = (c_bond_interfaces != NULL) ? CFArrayGetCount(c_bond_interfaces) : 0;
1644
1645 for (j = 0; j < nActive; j++) {
1646 SCBondInterfaceRef a_bond;
1647 CFArrayRef a_bond_interfaces;
1648 CFNumberRef a_bond_mode;
1649 CFStringRef a_bond_if;
1650 CFIndex a_count;
1651
1652 a_bond = CFArrayGetValueAtIndex(active, j);
1653 a_bond_if = SCNetworkInterfaceGetBSDName(a_bond);
1654 a_bond_interfaces = SCBondInterfaceGetMemberInterfaces(a_bond);
1655 a_bond_mode = SCBondInterfaceGetMode(a_bond);
1656 a_count = (a_bond_interfaces != NULL) ? CFArrayGetCount(a_bond_interfaces) : 0;
1657
1658 if (CFEqual(c_bond_if, a_bond_if)) {
1659 CFIndex c;
1660 Boolean if_list_change = FALSE;
1661 Boolean mode_change = FALSE;
1662
1663 found = TRUE;
1664
1665 if (!_SC_CFEqual(a_bond_mode, c_bond_mode)) {
1666 mode_change = TRUE;
1667 }
1668
1669 if (!_SC_CFEqual(c_bond_interfaces, a_bond_interfaces)) {
1670 if_list_change = TRUE;
1671 }
1672 if (!mode_change && !if_list_change) {
1673 break; // if no change
1674 }
1675 if (s == -1) {
1676 s = inet_dgram_socket();
1677 if (s == -1) {
1678 _SCErrorSet(errno);
1679 ok = FALSE;
1680 goto done;
1681 }
1682 }
1683 if (mode_change) {
1684 __bond_set_mode(s, a_bond_if, c_bond_mode);
1685 }
1686 if (!if_list_change) {
1687 break; // no if list changes
1688 }
1689
1690 /*
1691 * ensure that the first device of the bond matches, if
1692 * not then we remove all current devices and add them
1693 * back in the preferred order.
1694 */
1695 if ((c_count > 0) &&
1696 (a_count > 0) &&
1697 !CFEqual(CFArrayGetValueAtIndex(c_bond_interfaces, 0),
1698 CFArrayGetValueAtIndex(a_bond_interfaces, 0))) {
1699 CFIndex a;
1700
1701 for (a = 0; a < a_count; a++) {
1702 SCNetworkInterfaceRef a_interface;
1703 CFStringRef a_interface_if;
1704
1705 a_interface = CFArrayGetValueAtIndex(a_bond_interfaces, a);
1706 if (!CFArrayContainsValue(c_bond_interfaces,
1707 CFRangeMake(0, c_count),
1708 a_interface)) {
1709 continue; // if already removed
1710 }
1711
1712 a_interface_if = SCNetworkInterfaceGetBSDName(a_interface);
1713 if (!__bond_remove_interface(s, a_bond_if, a_interface_if)) {
1714 ok = FALSE;
1715 }
1716 }
1717
1718 a_count = 0; // all active devices have been removed
1719 }
1720
1721 /*
1722 * add any devices which are not currently associated
1723 * with the bond interface.
1724 */
1725 for (c = 0; c < c_count; c++) {
1726 SCNetworkInterfaceRef c_interface;
1727 SCNetworkInterfacePrivateRef c_interfacePrivate;
1728 CFStringRef c_interface_if;
1729
1730 c_interface = CFArrayGetValueAtIndex(c_bond_interfaces, c);
1731 if ((a_count == 0) ||
1732 !CFArrayContainsValue(a_bond_interfaces,
1733 CFRangeMake(0, a_count),
1734 c_interface)) {
1735 /*
1736 * check if this member interface can be added to a bond.
1737 */
1738 c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface;
1739 if (!c_interfacePrivate->supportsBond) {
1740 // if member not supported
1741 continue;
1742 }
1743
1744 /*
1745 * if this member interface is not currently part of the bond.
1746 */
1747 c_interface_if = SCNetworkInterfaceGetBSDName(c_interface);
1748 if (!__bond_add_interface(s, c_bond_if, c_interface_if)) {
1749 // if member could not be added
1750 ok = FALSE;
1751 }
1752 }
1753 }
1754
1755 break;
1756 }
1757 }
1758
1759 if (!found) {
1760 CFIndex c;
1761
1762 if (s == -1) {
1763 s = inet_dgram_socket();
1764 if (s == -1) {
1765 _SCErrorSet(errno);
1766 ok = FALSE;
1767 goto done;
1768 }
1769 }
1770
1771 /*
1772 * establish the new bond interface.
1773 */
1774 if (!__createInterface(s, c_bond_if)) {
1775 _SCErrorSet(errno);
1776 ok = FALSE;
1777 continue;
1778 }
1779
1780 /* set the mode */
1781 __bond_set_mode(s, c_bond_if, c_bond_mode);
1782
1783 /*
1784 * add the member interfaces
1785 */
1786 for (c = 0; c < c_count; c++) {
1787 SCNetworkInterfaceRef c_interface;
1788 SCNetworkInterfacePrivateRef c_interfacePrivate;
1789 CFStringRef c_interface_if;
1790
1791 c_interface = CFArrayGetValueAtIndex(c_bond_interfaces, c);
1792 c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface;
1793 if (!c_interfacePrivate->supportsBond) {
1794 // if member not supported
1795 continue;
1796 }
1797
1798 c_interface_if = SCNetworkInterfaceGetBSDName(c_interface);
1799 if (!__bond_add_interface(s, c_bond_if, c_interface_if)) {
1800 // if member could not be added
1801 ok = FALSE;
1802 }
1803 }
1804 }
1805
1806 }
1807
1808 done :
1809
1810 if (active != NULL) CFRelease(active);
1811 if (config != NULL) CFRelease(config);
1812 if (s != -1) (void) close(s);
1813
1814 return ok;
1815 }