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