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