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