]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/VLANConfiguration.c
70728920960e088532f178848bc247aa99cbb620
[apple/configd.git] / SystemConfiguration.fproj / VLANConfiguration.c
1 /*
2 * Copyright (c) 2003 Apple Computer, 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 14, 2003 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <CoreFoundation/CFRuntime.h>
34
35 #include <SystemConfiguration/SystemConfiguration.h>
36 #include <SystemConfiguration/SCValidation.h>
37 #include <SystemConfiguration/SCPrivate.h>
38
39 #include <ifaddrs.h>
40 #include <pthread.h>
41 #include <sys/types.h>
42 #define KERNEL_PRIVATE
43 #include <sys/ioctl.h>
44 #undef KERNEL_PRIVATE
45 #include <sys/socket.h>
46 #include <sys/sysctl.h>
47 #include <net/ethernet.h>
48 #define KERNEL_PRIVATE 1
49 #include <net/if.h>
50 #include <net/if_var.h>
51 #undef KERNEL_PRIVATE
52 #include <net/if_vlan_var.h>
53 #include <net/if_types.h>
54 #include <net/route.h>
55
56 #include <SystemConfiguration/VLANConfiguration.h>
57 #include <SystemConfiguration/VLANConfigurationPrivate.h>
58
59 /* ---------- VLAN support ---------- */
60
61 static int
62 inet_dgram_socket()
63 {
64 int s;
65
66 s = socket(AF_INET, SOCK_DGRAM, 0);
67 if (s == -1) {
68 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
69 _SCErrorSet(kSCStatusFailed);
70 }
71
72 return s;
73 }
74
75
76 static Boolean
77 _VLAN_create(int s, CFStringRef interface)
78 {
79 #ifdef SIOCIFCREATE
80 struct ifreq ifr;
81
82 bzero(&ifr, sizeof(ifr));
83 (void) _SC_cfstring_to_cstring(interface,
84 ifr.ifr_name,
85 sizeof(ifr.ifr_name),
86 kCFStringEncodingASCII);
87
88 if (ioctl(s, SIOCIFCREATE, &ifr) == -1) {
89 SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCIFCREATE) failed: %s"), strerror(errno));
90 _SCErrorSet(kSCStatusFailed);
91 return FALSE;
92 }
93
94 return TRUE;
95 #else /* SIOCIFCREATE */
96 return FALSE;
97 #endif /* SIOCIFCREATE */
98 }
99
100
101 static Boolean
102 _VLAN_destroy(int s, CFStringRef interface)
103 {
104 #ifdef SIOCIFDESTROY
105 struct ifreq ifr;
106
107 bzero(&ifr, sizeof(ifr));
108 (void) _SC_cfstring_to_cstring(interface,
109 ifr.ifr_name,
110 sizeof(ifr.ifr_name),
111 kCFStringEncodingASCII);
112
113 if (ioctl(s, SIOCIFDESTROY, &ifr) == -1) {
114 SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCIFDESTROY) failed: %s"), strerror(errno));
115 _SCErrorSet(kSCStatusFailed);
116 return FALSE;
117 }
118
119 return TRUE;
120 #else /* SIOCIFDESTROY */
121 return FALSE;
122 #endif /* SIOCIFDESTROY */
123 }
124
125
126 static Boolean
127 _VLANDevice_set(int s, CFStringRef interface, CFStringRef device, CFNumberRef tag)
128 {
129 #ifdef SIOCSETVLAN
130 struct ifreq ifr;
131 int tag_val;
132 struct vlanreq vreq;
133
134 bzero(&ifr, sizeof(ifr));
135 bzero(&vreq, sizeof(vreq));
136
137 // interface
138 (void) _SC_cfstring_to_cstring(interface,
139 ifr.ifr_name,
140 sizeof(ifr.ifr_name),
141 kCFStringEncodingASCII);
142 ifr.ifr_data = (caddr_t)&vreq;
143
144 // parent device
145 (void) _SC_cfstring_to_cstring(device,
146 vreq.vlr_parent,
147 sizeof(vreq.vlr_parent),
148 kCFStringEncodingASCII);
149
150 // tag
151 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
152 vreq.vlr_tag = tag_val;
153
154 // update parent device and tag
155 if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1) {
156 SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCSETVLAN) failed: %s"), strerror(errno));
157 _SCErrorSet(kSCStatusFailed);
158 return FALSE;
159 }
160
161 return TRUE;
162 #else /* SIOCSETVLAN */
163 return FALSE;
164 #endif /* SIOCSETVLAN */
165 }
166
167
168 static Boolean
169 _VLANDevice_unset(int s, CFStringRef interface)
170 {
171 #ifdef SIOCSETVLAN
172 struct ifreq ifr;
173 struct vlanreq vreq;
174
175 bzero(&ifr, sizeof(ifr));
176 bzero(&vreq, sizeof(vreq));
177
178 // interface
179 (void) _SC_cfstring_to_cstring(interface,
180 ifr.ifr_name,
181 sizeof(ifr.ifr_name),
182 kCFStringEncodingASCII);
183 ifr.ifr_data = (caddr_t)&vreq;
184
185 // clear parent device
186 bzero(&vreq.vlr_parent, sizeof(vreq.vlr_parent));
187
188 // clear tag
189 vreq.vlr_tag = 0;
190
191 // update parent device and tag
192 if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1) {
193 SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCSETVLAN) failed: %s"), strerror(errno));
194 _SCErrorSet(kSCStatusFailed);
195 return FALSE;
196 }
197
198 return TRUE;
199 #else /* SIOCSETVLAN */
200 return FALSE;
201 #endif /* SIOCSETVLAN */
202 }
203
204
205 /* ---------- VLAN "device" ---------- */
206
207 Boolean
208 IsVLANSupported(CFStringRef device)
209 {
210 char * buf = NULL;
211 size_t buf_len = 0;
212 struct if_msghdr * ifm;
213 char * if_name = NULL;
214 unsigned int if_index;
215 Boolean isVlan = FALSE;
216 int mib[6];
217
218 /* get the interface index */
219
220 if_name = _SC_cfstring_to_cstring(device, NULL, NULL, kCFStringEncodingASCII);
221 if (if_name == NULL) {
222 return FALSE; // if conversion error
223 }
224 if_index = if_nametoindex(if_name);
225 if (if_index == 0) {
226 goto done; // if unknown interface
227 }
228
229 /* get information for the specified device */
230
231 mib[0] = CTL_NET;
232 mib[1] = PF_ROUTE;
233 mib[2] = 0;
234 mib[3] = AF_LINK;
235 mib[4] = NET_RT_IFLIST;
236 mib[5] = if_index; /* ask for exactly one interface */
237
238 if (sysctl(mib, 6, NULL, &buf_len, NULL, 0) < 0) {
239 SCLog(TRUE, LOG_ERR, CFSTR("sysctl() size failed: %s"), strerror(errno));
240 goto done;
241 }
242 buf = CFAllocatorAllocate(NULL, buf_len, 0);
243 if (sysctl(mib, 6, buf, &buf_len, NULL, 0) < 0) {
244 SCLog(TRUE, LOG_ERR, CFSTR("sysctl() failed: %s"), strerror(errno));
245 goto done;
246 }
247
248 /* check the link type and hwassist flags */
249
250 ifm = (struct if_msghdr *)buf;
251 switch (ifm->ifm_type) {
252 case RTM_IFINFO : {
253 #if defined(IF_HWASSIST_VLAN_TAGGING) && defined(IF_HWASSIST_VLAN_MTU)
254 struct if_data *if_data = &ifm->ifm_data;
255
256 if (if_data->ifi_hwassist & (IF_HWASSIST_VLAN_TAGGING | IF_HWASSIST_VLAN_MTU)) {
257 isVlan = TRUE;
258 }
259 #endif
260 break;
261 }
262 }
263
264 done :
265
266 if (if_name != NULL) CFAllocatorDeallocate(NULL, if_name);
267 if (buf != NULL) CFAllocatorDeallocate(NULL, buf);
268
269 return isVlan;
270 }
271
272 /* ---------- VLANInterface ---------- */
273
274 typedef struct {
275
276 /* base CFType information */
277 CFRuntimeBase cfBase;
278
279 /* vlan interface configuration */
280 CFStringRef ifname; // e.g. vlan0, vlan1, ...
281 CFStringRef device; // e.g. en0, en1, ...
282 CFNumberRef tag; // e.g. 1 <= tag <= 4094
283 CFDictionaryRef options; // e.g. UserDefinedName
284
285 } VLANInterfacePrivate, * VLANInterfacePrivateRef;
286
287
288 static CFStringRef __VLANInterfaceCopyDescription (CFTypeRef cf);
289 static void __VLANInterfaceDeallocate (CFTypeRef cf);
290 static Boolean __VLANInterfaceEqual (CFTypeRef cf1, CFTypeRef cf2);
291
292
293 static const CFRuntimeClass __VLANInterfaceClass = {
294 0, // version
295 "VLANInterface", // className
296 NULL, // init
297 NULL, // copy
298 __VLANInterfaceDeallocate, // dealloc
299 __VLANInterfaceEqual, // equal
300 NULL, // hash
301 NULL, // copyFormattingDesc
302 __VLANInterfaceCopyDescription // copyDebugDesc
303 };
304
305
306 static CFTypeID __kVLANInterfaceTypeID = _kCFRuntimeNotATypeID;
307
308
309 static pthread_once_t vlanInterface_init = PTHREAD_ONCE_INIT;
310
311
312 static CFStringRef
313 __VLANInterfaceCopyDescription(CFTypeRef cf)
314 {
315 CFAllocatorRef allocator = CFGetAllocator(cf);
316 CFMutableStringRef result;
317 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)cf;
318
319 result = CFStringCreateMutable(allocator, 0);
320 CFStringAppendFormat(result, NULL, CFSTR("<VLANInterface %p [%p]> {"), cf, allocator);
321 CFStringAppendFormat(result, NULL, CFSTR(" if = %@"), vlanPrivate->ifname);
322 CFStringAppendFormat(result, NULL, CFSTR(", device = %@"), vlanPrivate->device);
323 CFStringAppendFormat(result, NULL, CFSTR(", tag = %@"), vlanPrivate->tag);
324 if (vlanPrivate->options != NULL) {
325 CFStringAppendFormat(result, NULL, CFSTR(", options = %@"), vlanPrivate->options);
326 }
327 CFStringAppendFormat(result, NULL, CFSTR(" }"));
328
329 return result;
330 }
331
332
333 static void
334 __VLANInterfaceDeallocate(CFTypeRef cf)
335 {
336 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)cf;
337
338 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__VLANInterfaceDeallocate:"));
339
340 /* release resources */
341
342 CFRelease(vlanPrivate->ifname);
343 CFRelease(vlanPrivate->device);
344 CFRelease(vlanPrivate->tag);
345 if (vlanPrivate->options) CFRelease(vlanPrivate->options);
346
347 return;
348 }
349
350
351 static Boolean
352 __VLANInterfaceEquiv(CFTypeRef cf1, CFTypeRef cf2)
353 {
354 VLANInterfacePrivateRef vlan1 = (VLANInterfacePrivateRef)cf1;
355 VLANInterfacePrivateRef vlan2 = (VLANInterfacePrivateRef)cf2;
356
357 if (vlan1 == vlan2)
358 return TRUE;
359
360 if (!CFEqual(vlan1->ifname, vlan2->ifname))
361 return FALSE; // if not the same interface
362
363 if (!CFEqual(vlan1->device, vlan2->device))
364 return FALSE; // if not the same device
365
366 if (!CFEqual(vlan1->tag, vlan2->tag))
367 return FALSE; // if not the same tag
368
369 return TRUE;
370 }
371
372
373 static Boolean
374 __VLANInterfaceEqual(CFTypeRef cf1, CFTypeRef cf2)
375 {
376 VLANInterfacePrivateRef vlan1 = (VLANInterfacePrivateRef)cf1;
377 VLANInterfacePrivateRef vlan2 = (VLANInterfacePrivateRef)cf2;
378
379 if (!__VLANInterfaceEquiv(vlan1, vlan2))
380 return FALSE; // if not the same VLAN interface/device/tag
381
382 if (vlan1->options != vlan2->options) {
383 // if the options may differ
384 if ((vlan1->options != NULL) && (vlan2->options != NULL)) {
385 // if both VLANs have options
386 if (!CFEqual(vlan1->options, vlan2->options)) {
387 // if the options are not equal
388 return FALSE;
389 }
390 } else {
391 // if only one VLAN has options
392 return FALSE;
393 }
394 }
395
396 return TRUE;
397 }
398
399
400 static void
401 __VLANInterfaceInitialize(void)
402 {
403 __kVLANInterfaceTypeID = _CFRuntimeRegisterClass(&__VLANInterfaceClass);
404 return;
405 }
406
407
408 static __inline__ CFTypeRef
409 isA_VLANInterface(CFTypeRef obj)
410 {
411 return (isA_CFType(obj, VLANInterfaceGetTypeID()));
412 }
413
414
415 CFTypeID
416 VLANInterfaceGetTypeID(void)
417 {
418 pthread_once(&vlanInterface_init, __VLANInterfaceInitialize); /* initialize runtime */
419 return __kVLANInterfaceTypeID;
420 }
421
422
423 static VLANInterfaceRef
424 __VLANInterfaceCreatePrivate(CFAllocatorRef allocator,
425 CFStringRef ifname,
426 CFStringRef device,
427 CFNumberRef tag,
428 CFDictionaryRef options)
429 {
430 VLANInterfacePrivateRef vlanPrivate;
431 uint32_t size;
432
433 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__VLANInterfaceCreatePrivate:"));
434
435 /* initialize runtime */
436 pthread_once(&vlanInterface_init, __VLANInterfaceInitialize);
437
438 /* allocate vlan */
439 size = sizeof(VLANInterfacePrivate) - sizeof(CFRuntimeBase);
440 vlanPrivate = (VLANInterfacePrivateRef)_CFRuntimeCreateInstance(allocator,
441 __kVLANInterfaceTypeID,
442 size,
443 NULL);
444 if (!vlanPrivate) {
445 return NULL;
446 }
447
448 /* establish the vlan */
449
450 vlanPrivate->ifname = CFStringCreateCopy(allocator, ifname);
451 vlanPrivate->device = CFStringCreateCopy(allocator, device);
452 vlanPrivate->tag = CFRetain(tag);
453 if (options != NULL) {
454 vlanPrivate->options = CFDictionaryCreateCopy(allocator, options);
455 } else {
456 vlanPrivate->options = NULL;
457 }
458
459 return (VLANInterfaceRef)vlanPrivate;
460 }
461
462
463 CFStringRef
464 VLANInterfaceGetInterface(VLANInterfaceRef vlan)
465 {
466 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
467 CFStringRef vlan_if = NULL;
468
469 if (isA_VLANInterface(vlan)) {
470 vlan_if = vlanPrivate->ifname;
471 }
472
473 return vlan_if;
474 }
475
476
477 CFStringRef
478 VLANInterfaceGetDevice(VLANInterfaceRef vlan)
479 {
480 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
481 CFStringRef vlan_device = NULL;
482
483 if (isA_VLANInterface(vlan)) {
484 vlan_device = vlanPrivate->device;
485 }
486
487 return vlan_device;
488 }
489
490
491 static void
492 VLANInterfaceSetDevice(VLANInterfaceRef vlan, CFStringRef newDevice)
493 {
494 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
495
496 if (isA_VLANInterface(vlan)) {
497 CFAllocatorRef allocator = CFGetAllocator(vlan);
498
499 CFRelease(vlanPrivate->device);
500 vlanPrivate->device = CFStringCreateCopy(allocator, newDevice);
501 }
502
503 return;
504 }
505
506
507 CFNumberRef
508 VLANInterfaceGetTag(VLANInterfaceRef vlan)
509 {
510 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
511 CFNumberRef vlan_tag = NULL;
512
513 if (isA_VLANInterface(vlan)) {
514 vlan_tag = vlanPrivate->tag;
515 }
516
517 return vlan_tag;
518 }
519
520
521 static void
522 VLANInterfaceSetTag(VLANInterfaceRef vlan, CFNumberRef newTag)
523 {
524 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
525
526 if (isA_VLANInterface(vlan)) {
527 CFRelease(vlanPrivate->tag);
528 vlanPrivate->tag = CFRetain(newTag);
529 }
530
531 return;
532 }
533
534
535 CFDictionaryRef
536 VLANInterfaceGetOptions(VLANInterfaceRef vlan)
537 {
538 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
539 CFDictionaryRef vlan_options = NULL;
540
541 if (isA_VLANInterface(vlan)) {
542 vlan_options = vlanPrivate->options;
543 }
544
545 return vlan_options;
546 }
547
548
549 static void
550 VLANInterfaceSetOptions(VLANInterfaceRef vlan, CFDictionaryRef newOptions)
551 {
552 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
553
554 if (isA_VLANInterface(vlan)) {
555 CFAllocatorRef allocator = CFGetAllocator(vlan);
556
557 if (vlanPrivate->options) CFRelease(vlanPrivate->options);
558 if (newOptions != NULL) {
559 vlanPrivate->options = CFDictionaryCreateCopy(allocator, newOptions);
560 } else {
561 vlanPrivate->options = NULL;
562 }
563 }
564
565 return;
566 }
567
568
569 /* ---------- VLANPreferences ---------- */
570
571 #define VLAN_PREFERENCES_VLANS CFSTR("VLANs")
572
573 #define __kVLANInterface_interface CFSTR("interface") // e.g. vlan0, vlan1, ...
574 #define __kVLANInterface_device CFSTR("device") // e.g. en0, en1, ...
575 #define __kVLANInterface_tag CFSTR("tag") // e.g. 1 <= tag <= 4094
576 #define __kVLANInterface_options CFSTR("options") // e.g. UserDefinedName
577
578 typedef struct {
579
580 /* base CFType information */
581 CFRuntimeBase cfBase;
582
583 /* lock */
584 pthread_mutex_t lock;
585
586 /* underlying preferences */
587 SCPreferencesRef prefs;
588
589 /* base VLANs (before any commits) */
590 CFArrayRef vlBase;
591
592 } VLANPreferencesPrivate, * VLANPreferencesPrivateRef;
593
594
595 static CFStringRef __VLANPreferencesCopyDescription (CFTypeRef cf);
596 static void __VLANPreferencesDeallocate (CFTypeRef cf);
597
598
599 static const CFRuntimeClass __VLANPreferencesClass = {
600 0, // version
601 "VLANPreferences", // className
602 NULL, // init
603 NULL, // copy
604 __VLANPreferencesDeallocate, // dealloc
605 NULL, // equal
606 NULL, // hash
607 NULL, // copyFormattingDesc
608 __VLANPreferencesCopyDescription // copyDebugDesc
609 };
610
611
612 static CFTypeID __kVLANPreferencesTypeID = _kCFRuntimeNotATypeID;
613
614
615 static pthread_once_t vlanPreferences_init = PTHREAD_ONCE_INIT;
616
617
618 static CFStringRef
619 __VLANPreferencesCopyDescription(CFTypeRef cf)
620 {
621 CFAllocatorRef allocator = CFGetAllocator(cf);
622 CFIndex i;
623 CFArrayRef keys;
624 CFIndex n;
625 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)cf;
626 CFMutableStringRef result;
627
628 result = CFStringCreateMutable(allocator, 0);
629 CFStringAppendFormat(result, NULL, CFSTR("<VLANPreferences %p [%p]> {"), cf, allocator);
630
631 keys = SCPreferencesCopyKeyList(prefsPrivate->prefs);
632 n = CFArrayGetCount(keys);
633 for (i = 0; i < n; i++) {
634 CFStringRef key;
635 CFPropertyListRef val;
636
637 key = CFArrayGetValueAtIndex(keys, i);
638 val = SCPreferencesGetValue(prefsPrivate->prefs, key);
639
640 CFStringAppendFormat(result, NULL, CFSTR("%@ : %@"), key, val);
641 }
642 CFRelease(keys);
643
644 CFStringAppendFormat(result, NULL, CFSTR(" }"));
645
646 return result;
647 }
648
649
650 #define N_QUICK 8
651
652
653 static void
654 __VLANPreferencesDeallocate(CFTypeRef cf)
655 {
656 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)cf;
657
658 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__VLANPreferencesDeallocate:"));
659
660 /* release resources */
661
662 pthread_mutex_destroy(&prefsPrivate->lock);
663
664 if (prefsPrivate->prefs) CFRelease(prefsPrivate->prefs);
665 if (prefsPrivate->vlBase) CFRelease(prefsPrivate->vlBase);
666
667 return;
668 }
669
670
671 static void
672 __VLANPreferencesInitialize(void)
673 {
674 __kVLANPreferencesTypeID = _CFRuntimeRegisterClass(&__VLANPreferencesClass);
675 return;
676 }
677
678
679 static __inline__ CFTypeRef
680 isA_VLANPreferences(CFTypeRef obj)
681 {
682 return (isA_CFType(obj, VLANPreferencesGetTypeID()));
683 }
684
685
686 CFArrayRef
687 _VLANPreferencesCopyActiveInterfaces()
688 {
689 CFArrayCallBacks callbacks;
690 struct ifaddrs *ifap;
691 struct ifaddrs *ifp;
692 int s;
693 CFMutableArrayRef vlans = NULL;
694
695 if (getifaddrs(&ifap) == -1) {
696 SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno));
697 _SCErrorSet(kSCStatusFailed);
698 return NULL;
699 }
700
701 s = inet_dgram_socket();
702 if (s == -1) {
703 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
704 _SCErrorSet(kSCStatusFailed);
705 goto done;
706 }
707
708 callbacks = kCFTypeArrayCallBacks;
709 callbacks.equal = __VLANInterfaceEquiv;
710 vlans = CFArrayCreateMutable(NULL, 0, &callbacks);
711
712 for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) {
713 switch (ifp->ifa_addr->sa_family) {
714 case AF_LINK : {
715 CFStringRef device;
716 struct if_data *if_data;
717 struct ifreq ifr;
718 CFNumberRef tag;
719 VLANInterfaceRef vlan;
720 CFStringRef vlan_if;
721 char vlr_parent[IFNAMSIZ+1];
722 int vlr_tag;
723 struct vlanreq vreq;
724
725 if_data = (struct if_data *)ifp->ifa_data;
726 if (if_data == NULL) {
727 break; // if no interface data
728 }
729
730 if (if_data->ifi_type != IFT_L2VLAN) {
731 break; // if not VLAN
732 }
733
734 bzero(&ifr, sizeof(ifr));
735 bzero(&vreq, sizeof(vreq));
736 strncpy(ifr.ifr_name, ifp->ifa_name, sizeof(ifr.ifr_name));
737 ifr.ifr_data = (caddr_t)&vreq;
738
739 if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1) {
740 SCLog(TRUE, LOG_ERR, CFSTR("ioctl() failed: %s"), strerror(errno));
741 _SCErrorSet(kSCStatusFailed);
742 CFRelease(vlans);
743 goto done;
744 }
745 vlr_tag = vreq.vlr_tag;
746 strlcpy(vlr_parent, vreq.vlr_parent, sizeof(vlr_parent));
747
748 vlan_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
749 device = CFStringCreateWithCString(NULL, vlr_parent, kCFStringEncodingASCII);
750 tag = CFNumberCreate(NULL, kCFNumberIntType, &vlr_tag);
751 vlan = __VLANInterfaceCreatePrivate(NULL, vlan_if, device, tag, NULL);
752 CFArrayAppendValue(vlans, vlan);
753 CFRelease(vlan_if);
754 CFRelease(device);
755 CFRelease(tag);
756 CFRelease(vlan);
757 break;
758 }
759
760 default :
761 break;
762 }
763 }
764
765 done :
766
767 (void) close(s);
768 freeifaddrs(ifap);
769 return vlans;
770 }
771
772
773 static CFIndex
774 findVLAN(CFArrayRef vlans, CFStringRef device, CFNumberRef tag)
775 {
776 CFIndex found = kCFNotFound;
777 CFIndex i;
778 CFIndex n;
779
780 n = isA_CFArray(vlans) ? CFArrayGetCount(vlans) : 0;
781 for (i = 0; i < n; i++) {
782 CFDictionaryRef vlan_dict;
783 CFStringRef vlan_device;
784 CFStringRef vlan_if;
785 CFNumberRef vlan_tag;
786
787 vlan_dict = CFArrayGetValueAtIndex(vlans, i);
788 if (!isA_CFDictionary(vlan_dict)) {
789 continue; // if the prefs are confused
790 }
791
792 vlan_if = CFDictionaryGetValue(vlan_dict, __kVLANInterface_interface);
793 if (!isA_CFString(vlan_if)) {
794 continue; // if the prefs are confused
795 }
796
797 vlan_device = CFDictionaryGetValue(vlan_dict, __kVLANInterface_device);
798 if (isA_CFString(vlan_device)) {
799 if (!CFEqual(device, vlan_device)) {
800 continue; // if not a match
801 }
802 }
803
804 vlan_tag = CFDictionaryGetValue(vlan_dict, __kVLANInterface_tag);
805 if (isA_CFNumber(vlan_tag)) {
806 if (!CFEqual(tag, vlan_tag)) {
807 continue; // if not a match
808 }
809 }
810
811 // if we have found a match
812 found = i;
813 break;
814 }
815
816 return found;
817 }
818
819
820 static void
821 setConfigurationChanged(VLANPreferencesRef prefs)
822 {
823 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
824
825 /*
826 * to facilitate device configuration we will take
827 * a snapshot of the VLAN preferences before any
828 * changes are made. Then, when the changes are
829 * applied we can compare what we had to what we
830 * want and configured the system accordingly.
831 */
832 if (prefsPrivate->vlBase == NULL) {
833 prefsPrivate->vlBase = VLANPreferencesCopyInterfaces(prefs);
834 }
835
836 return;
837 }
838
839
840 CFTypeID
841 VLANPreferencesGetTypeID(void)
842 {
843 pthread_once(&vlanPreferences_init, __VLANPreferencesInitialize); /* initialize runtime */
844 return __kVLANPreferencesTypeID;
845 }
846
847
848 VLANPreferencesRef
849 VLANPreferencesCreate(CFAllocatorRef allocator)
850 {
851 CFBundleRef bundle;
852 CFStringRef bundleID = NULL;
853 CFStringRef name = CFSTR("VLANConfiguration");
854 VLANPreferencesPrivateRef prefsPrivate;
855 uint32_t size;
856
857 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__VLANPreferencesCreate:"));
858
859 /* initialize runtime */
860 pthread_once(&vlanPreferences_init, __VLANPreferencesInitialize);
861
862 /* allocate preferences */
863 size = sizeof(VLANPreferencesPrivate) - sizeof(CFRuntimeBase);
864 prefsPrivate = (VLANPreferencesPrivateRef)_CFRuntimeCreateInstance(allocator,
865 __kVLANPreferencesTypeID,
866 size,
867 NULL);
868 if (!prefsPrivate) {
869 return NULL;
870 }
871
872 /* establish the prefs */
873
874 pthread_mutex_init(&prefsPrivate->lock, NULL);
875
876 bundle = CFBundleGetMainBundle();
877 if (bundle) {
878 bundleID = CFBundleGetIdentifier(bundle);
879 if (bundleID) {
880 CFRetain(bundleID);
881 } else {
882 CFURLRef url;
883
884 url = CFBundleCopyExecutableURL(bundle);
885 if (url) {
886 bundleID = CFURLCopyPath(url);
887 CFRelease(url);
888 }
889 }
890 }
891
892 if (bundleID) {
893 CFStringRef fullName;
894
895 if (CFEqual(bundleID, CFSTR("/"))) {
896 CFRelease(bundleID);
897 bundleID = CFStringCreateWithFormat(allocator, NULL, CFSTR("(%d)"), getpid());
898 }
899
900 fullName = CFStringCreateWithFormat(allocator, NULL, CFSTR("%@:%@"), bundleID, name);
901 name = fullName;
902 CFRelease(bundleID);
903 } else {
904 CFRetain(name);
905 }
906
907 prefsPrivate->prefs = SCPreferencesCreate(allocator, name, VLAN_PREFERENCES_ID);
908 CFRelease(name);
909
910 prefsPrivate->vlBase = NULL;
911
912 return (VLANPreferencesRef)prefsPrivate;
913 }
914
915
916 CFArrayRef
917 VLANPreferencesCopyInterfaces(VLANPreferencesRef prefs)
918 {
919 CFAllocatorRef allocator;
920 CFArrayCallBacks callbacks;
921 CFIndex i;
922 CFIndex n;
923 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
924 CFMutableArrayRef result;
925 CFArrayRef vlans;
926
927 if (!isA_VLANPreferences(prefs)) {
928 _SCErrorSet(kSCStatusInvalidArgument);
929 return NULL;
930 }
931
932 allocator = CFGetAllocator(prefs);
933 callbacks = kCFTypeArrayCallBacks;
934 callbacks.equal = __VLANInterfaceEquiv;
935 result = CFArrayCreateMutable(allocator, 0, &callbacks);
936
937 vlans = SCPreferencesGetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS);
938 n = isA_CFArray(vlans) ? CFArrayGetCount(vlans) : 0;
939 for (i = 0; i < n; i++) {
940 CFDictionaryRef vlan_dict;
941 CFStringRef device;
942 CFDictionaryRef options;
943 CFNumberRef tag;
944 VLANInterfaceRef vlan;
945 CFStringRef vlan_if;
946
947 vlan_dict = CFArrayGetValueAtIndex(vlans, i);
948 if (!isA_CFDictionary(vlan_dict)) {
949 continue; // if the prefs are confused
950 }
951
952 vlan_if = CFDictionaryGetValue(vlan_dict, __kVLANInterface_interface);
953 if (!isA_CFString(vlan_if)) {
954 continue; // if the prefs are confused
955 }
956
957
958 device = CFDictionaryGetValue(vlan_dict, __kVLANInterface_device);
959 if (!isA_CFString(device)) {
960 continue; // if the prefs are confused
961 }
962
963 tag = CFDictionaryGetValue(vlan_dict, __kVLANInterface_tag);
964 if (!isA_CFNumber(tag)) {
965 continue; // if the prefs are confused
966 }
967
968 options = CFDictionaryGetValue(vlan_dict, __kVLANInterface_options);
969 if ((options != NULL) && !isA_CFDictionary(options)) {
970 continue; // if the prefs are confused
971 }
972
973 vlan = __VLANInterfaceCreatePrivate(allocator, vlan_if, device, tag, options);
974 CFArrayAppendValue(result, vlan);
975 CFRelease(vlan);
976 }
977
978 return result;
979 }
980
981
982 VLANInterfaceRef
983 VLANPreferencesAddInterface(VLANPreferencesRef prefs,
984 CFStringRef device,
985 CFNumberRef tag,
986 CFDictionaryRef options)
987 {
988 CFArrayRef active_vlans;
989 CFAllocatorRef allocator;
990 CFArrayRef config_vlans;
991 CFIndex dup_if;
992 CFIndex i;
993 CFIndex nActive;
994 CFIndex nConfig;
995 VLANInterfaceRef newVlan = NULL;
996 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
997
998 if (!isA_VLANPreferences(prefs)) {
999 _SCErrorSet(kSCStatusInvalidArgument);
1000 return NULL;
1001 }
1002
1003 if (!isA_CFString(device)) {
1004 _SCErrorSet(kSCStatusInvalidArgument);
1005 return NULL;
1006 }
1007
1008 if (isA_CFNumber(tag)) {
1009 int tag_val;
1010
1011 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
1012 if ((tag_val < 1) || (tag_val > 4094)) {
1013 _SCErrorSet(kSCStatusInvalidArgument);
1014 return NULL;
1015 }
1016 } else {
1017 _SCErrorSet(kSCStatusInvalidArgument);
1018 return NULL;
1019 }
1020
1021 if ((options != NULL) && !isA_CFDictionary(options)) {
1022 _SCErrorSet(kSCStatusInvalidArgument);
1023 return NULL;
1024 }
1025
1026 pthread_mutex_lock(&prefsPrivate->lock);
1027
1028 /* get "configured" VLANs (and check to ensure we are not creating a duplicate) */
1029 config_vlans = SCPreferencesGetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS);
1030 nConfig = isA_CFArray(config_vlans) ? CFArrayGetCount(config_vlans) : 0;
1031
1032 dup_if = findVLAN(config_vlans, device, tag);
1033 if (dup_if != kCFNotFound) {
1034 // sorry, you can't add a vlan using the same device/tag */
1035 _SCErrorSet(kSCStatusKeyExists);
1036 goto done;
1037 }
1038
1039 /* get "active" VLANs */
1040 active_vlans = _VLANPreferencesCopyActiveInterfaces();
1041 nActive = isA_CFArray(active_vlans) ? CFArrayGetCount(active_vlans) : 0;
1042
1043 /* create a new vlan using an unused interface name */
1044 allocator = CFGetAllocator(prefs);
1045
1046 for (i = 0; newVlan == NULL; i++) {
1047 CFIndex j;
1048 CFMutableDictionaryRef newDict;
1049 CFMutableArrayRef newVlans;
1050 CFStringRef vlan_if;
1051
1052 vlan_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("vlan%d"), i);
1053
1054 for (j = 0; j < nActive; j++) {
1055 CFStringRef active_if;
1056 VLANInterfaceRef active_vlan;
1057
1058 active_vlan = CFArrayGetValueAtIndex(active_vlans, j);
1059 active_if = VLANInterfaceGetInterface(active_vlan);
1060
1061 if (CFEqual(vlan_if, active_if)) {
1062 goto next_if; // if VLAN interface name not available
1063 }
1064 }
1065
1066 for (j = 0; j < nConfig; j++) {
1067 CFDictionaryRef config;
1068 CFStringRef config_if;
1069
1070 config = CFArrayGetValueAtIndex(config_vlans, j);
1071 if (!isA_CFDictionary(config)) {
1072 continue; // if the prefs are confused
1073 }
1074
1075 config_if = CFDictionaryGetValue(config, __kVLANInterface_interface);
1076 if (!isA_CFString(config_if)) {
1077 continue; // if the prefs are confused
1078 }
1079
1080 if (CFEqual(vlan_if, config_if)) {
1081 goto next_if; // if VLAN interface name not available
1082 }
1083 }
1084
1085 /* create the vlan */
1086
1087 newDict = CFDictionaryCreateMutable(allocator,
1088 0,
1089 &kCFTypeDictionaryKeyCallBacks,
1090 &kCFTypeDictionaryValueCallBacks);
1091 CFDictionaryAddValue(newDict, __kVLANInterface_interface, vlan_if);
1092 CFDictionaryAddValue(newDict, __kVLANInterface_device, device);
1093 CFDictionaryAddValue(newDict, __kVLANInterface_tag, tag);
1094 if (options != NULL) {
1095 CFDictionaryAddValue(newDict, __kVLANInterface_options, options);
1096 }
1097
1098 /* create the accessor handle to be returned */
1099
1100 newVlan = __VLANInterfaceCreatePrivate(allocator, vlan_if, device, tag, options);
1101
1102 /* save in the prefs */
1103
1104 if (nConfig == 0) {
1105 newVlans = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
1106 } else {
1107 newVlans = CFArrayCreateMutableCopy(allocator, 0, config_vlans);
1108 }
1109 CFArrayAppendValue(newVlans, newDict);
1110 CFRelease(newDict);
1111
1112 (void) SCPreferencesSetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS, newVlans);
1113 CFRelease(newVlans);
1114
1115 /* yes, we've change the configuration */
1116 setConfigurationChanged(prefs);
1117
1118 next_if :
1119 CFRelease(vlan_if);
1120 }
1121
1122 CFRelease(active_vlans);
1123
1124 done :
1125
1126 pthread_mutex_unlock(&prefsPrivate->lock);
1127
1128 return (VLANInterfaceRef) newVlan;
1129 }
1130
1131
1132 Boolean
1133 VLANPreferencesUpdateInterface(VLANPreferencesRef prefs,
1134 VLANInterfaceRef vlan,
1135 CFStringRef newDevice,
1136 CFNumberRef newTag,
1137 CFDictionaryRef newOptions)
1138 {
1139 CFAllocatorRef allocator;
1140 CFIndex cur_if;
1141 CFIndex dup_if;
1142 CFMutableDictionaryRef newDict;
1143 CFMutableArrayRef newVlans;
1144 Boolean ok = FALSE;
1145 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
1146 CFArrayRef vlans;
1147 CFStringRef vlan_if;
1148
1149 if (!isA_VLANPreferences(prefs)) {
1150 _SCErrorSet(kSCStatusInvalidArgument);
1151 return FALSE;
1152 }
1153
1154 if (!isA_VLANInterface(vlan)) {
1155 _SCErrorSet(kSCStatusInvalidArgument);
1156 return FALSE;
1157 }
1158
1159 if ((newDevice != NULL) && !isA_CFString(newDevice)) {
1160 _SCErrorSet(kSCStatusInvalidArgument);
1161 return FALSE;
1162 }
1163
1164 if (newTag != NULL) {
1165 if (isA_CFNumber(newTag)) {
1166 int tag_val;
1167
1168 CFNumberGetValue(newTag, kCFNumberIntType, &tag_val);
1169 if ((tag_val < 1) || (tag_val > 4094)) {
1170 _SCErrorSet(kSCStatusInvalidArgument);
1171 return FALSE;
1172 }
1173 } else {
1174 _SCErrorSet(kSCStatusInvalidArgument);
1175 return FALSE;
1176 }
1177 }
1178
1179 if ((newOptions != NULL)
1180 && !isA_CFDictionary(newOptions) && (newOptions != (CFDictionaryRef)kCFNull)) {
1181 _SCErrorSet(kSCStatusInvalidArgument);
1182 return FALSE;
1183 }
1184
1185 pthread_mutex_lock(&prefsPrivate->lock);
1186
1187 vlan_if = VLANInterfaceGetInterface(vlan);
1188
1189 vlans = SCPreferencesGetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS);
1190 if (!isA_CFArray(vlans)) {
1191 goto done; // if the prefs are confused
1192 }
1193
1194 cur_if = findVLAN(vlans,
1195 VLANInterfaceGetDevice(vlan),
1196 VLANInterfaceGetTag (vlan));
1197 if (cur_if == kCFNotFound) {
1198 _SCErrorSet(kSCStatusNoKey);
1199 goto done;
1200 }
1201
1202 dup_if = findVLAN(vlans,
1203 newDevice != NULL ? newDevice : VLANInterfaceGetDevice(vlan),
1204 newTag != NULL ? newTag : VLANInterfaceGetTag (vlan));
1205 if (dup_if != kCFNotFound) {
1206 // if the same device/tag has already been defined
1207 if (cur_if != dup_if) {
1208 /*
1209 * sorry, you can't update another vlan that is using
1210 * the same device/tag
1211 */
1212 _SCErrorSet(kSCStatusKeyExists);
1213 goto done;
1214 }
1215 }
1216
1217 /* update the vlan */
1218
1219 if (newDevice != NULL) {
1220 VLANInterfaceSetDevice(vlan, newDevice);
1221 } else {
1222 newDevice = VLANInterfaceGetDevice(vlan);
1223 }
1224
1225 if (newTag != NULL) {
1226 VLANInterfaceSetTag(vlan, newTag);
1227 } else {
1228 newTag = VLANInterfaceGetTag(vlan);
1229 }
1230
1231 if (newOptions != NULL) {
1232 if (newOptions != (CFDictionaryRef)kCFNull) {
1233 VLANInterfaceSetOptions(vlan, newOptions);
1234 } else {
1235 VLANInterfaceSetOptions(vlan, NULL);
1236 newOptions = NULL;
1237 }
1238 } else {
1239 newOptions = VLANInterfaceGetOptions(vlan);
1240 }
1241
1242 /* update the prefs */
1243
1244 allocator = CFGetAllocator(prefs);
1245 newDict = CFDictionaryCreateMutable(allocator,
1246 0,
1247 &kCFTypeDictionaryKeyCallBacks,
1248 &kCFTypeDictionaryValueCallBacks);
1249 CFDictionaryAddValue(newDict, __kVLANInterface_interface, vlan_if);
1250 CFDictionaryAddValue(newDict, __kVLANInterface_device, newDevice);
1251 CFDictionaryAddValue(newDict, __kVLANInterface_tag, newTag);
1252 if (newOptions != NULL) {
1253 CFDictionaryAddValue(newDict, __kVLANInterface_options, newOptions);
1254 }
1255
1256 /* update the prefs */
1257
1258 newVlans = CFArrayCreateMutableCopy(allocator, 0, vlans);
1259 CFArrayRemoveValueAtIndex(newVlans, cur_if);
1260 CFArrayAppendValue(newVlans, newDict);
1261 CFRelease(newDict);
1262
1263 (void) SCPreferencesSetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS, newVlans);
1264 CFRelease(newVlans);
1265
1266 /* yes, we've change the configuration */
1267 setConfigurationChanged(prefs);
1268
1269 ok = TRUE;
1270
1271 done :
1272
1273 pthread_mutex_unlock(&prefsPrivate->lock);
1274
1275 return ok;
1276 }
1277
1278
1279 Boolean
1280 VLANPreferencesRemoveInterface(VLANPreferencesRef prefs,
1281 VLANInterfaceRef vlan)
1282 {
1283 CFAllocatorRef allocator;
1284 CFIndex cur_if;
1285 CFMutableArrayRef newVlans;
1286 Boolean ok = FALSE;
1287 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
1288 CFArrayRef vlans;
1289
1290 if (!isA_VLANPreferences(prefs)) {
1291 _SCErrorSet(kSCStatusInvalidArgument);
1292 return FALSE;
1293 }
1294
1295 if (!isA_VLANInterface(vlan)) {
1296 _SCErrorSet(kSCStatusInvalidArgument);
1297 return FALSE;
1298 }
1299
1300 pthread_mutex_lock(&prefsPrivate->lock);
1301
1302 vlans = SCPreferencesGetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS);
1303 if (!isA_CFArray(vlans)) {
1304 _SCErrorSet(kSCStatusNoKey);
1305 goto done; // if the prefs are confused
1306 }
1307
1308 cur_if = findVLAN(vlans,
1309 VLANInterfaceGetDevice(vlan),
1310 VLANInterfaceGetTag (vlan));
1311 if (cur_if == kCFNotFound) {
1312 _SCErrorSet(kSCStatusNoKey);
1313 goto done;
1314 }
1315
1316 /* remove the vlan */
1317
1318 allocator = CFGetAllocator(prefs);
1319 newVlans = CFArrayCreateMutableCopy(allocator, 0, vlans);
1320 CFArrayRemoveValueAtIndex(newVlans, cur_if);
1321
1322 (void) SCPreferencesSetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS, newVlans);
1323 CFRelease(newVlans);
1324
1325 /* yes, we've change the configuration */
1326 setConfigurationChanged(prefs);
1327
1328 ok = TRUE;
1329
1330 done :
1331
1332 pthread_mutex_unlock(&prefsPrivate->lock);
1333
1334 return ok;
1335 }
1336
1337
1338 Boolean
1339 VLANPreferencesCommitChanges(VLANPreferencesRef prefs)
1340 {
1341 Boolean ok = FALSE;
1342 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
1343
1344 if (!isA_VLANPreferences(prefs)) {
1345 _SCErrorSet(kSCStatusInvalidArgument);
1346 return FALSE;
1347 }
1348
1349 ok = SCPreferencesCommitChanges(prefsPrivate->prefs);
1350 if (!ok) {
1351 return ok;
1352 }
1353
1354 if (prefsPrivate->vlBase != NULL) {
1355 CFRelease(prefsPrivate->vlBase);
1356 prefsPrivate->vlBase = NULL;
1357 }
1358
1359 return TRUE;
1360 }
1361
1362
1363 Boolean
1364 _VLANPreferencesUpdateConfiguration(VLANPreferencesRef prefs)
1365 {
1366 CFArrayRef active = NULL;
1367 CFArrayRef config = NULL;
1368 CFMutableDictionaryRef devices = NULL;
1369 CFIndex i;
1370 CFIndex nActive;
1371 CFIndex nConfig;
1372 Boolean ok = FALSE;
1373 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
1374 int s = -1;
1375
1376 if (!isA_VLANPreferences(prefs)) {
1377 _SCErrorSet(kSCStatusInvalidArgument);
1378 return FALSE;
1379 }
1380
1381 /* configured VLANs */
1382 if (prefsPrivate->vlBase != NULL) {
1383 /*
1384 * updated VLAN preferences have not been committed
1385 * so we ignore any in-progress changes and apply the
1386 * saved preferences.
1387 */
1388 config = CFRetain(prefsPrivate->vlBase);
1389 } else {
1390 /*
1391 * apply the saved preferences
1392 */
1393 config = VLANPreferencesCopyInterfaces(prefs);
1394 }
1395 nConfig = CFArrayGetCount(config);
1396
1397 /* [parent] devices */
1398 devices = CFDictionaryCreateMutable(NULL,
1399 0,
1400 &kCFTypeDictionaryKeyCallBacks,
1401 &kCFTypeDictionaryValueCallBacks);
1402
1403 /* active VLANs */
1404 active = _VLANPreferencesCopyActiveInterfaces();
1405 nActive = CFArrayGetCount(active);
1406
1407 /* remove any no-longer-configured VLAN interfaces */
1408 for (i = 0; i < nActive; i++) {
1409 VLANInterfaceRef a_vlan;
1410 CFStringRef a_vlan_if;
1411 CFIndex j;
1412 Boolean found = FALSE;
1413
1414 a_vlan = CFArrayGetValueAtIndex(active, i);
1415 a_vlan_if = VLANInterfaceGetInterface(a_vlan);
1416
1417 for (j = 0; j < nConfig; j++) {
1418 VLANInterfaceRef c_vlan;
1419 CFStringRef c_vlan_if;
1420
1421 c_vlan = CFArrayGetValueAtIndex(config, j);
1422 c_vlan_if = VLANInterfaceGetInterface(c_vlan);
1423
1424 if (CFEqual(a_vlan_if, c_vlan_if)) {
1425 found = TRUE;
1426 break;
1427 }
1428 }
1429
1430 if (!found) {
1431 // remove VLAN interface
1432 if (s == -1) {
1433 s = inet_dgram_socket();
1434 }
1435
1436 ok = _VLAN_destroy(s, a_vlan_if);
1437 if (!ok) {
1438 goto done;
1439 }
1440 }
1441 }
1442
1443 /* create (and update) configured VLAN interfaces */
1444 for (i = 0; i < nConfig; i++) {
1445 VLANInterfaceRef c_vlan;
1446 CFStringRef c_vlan_device;
1447 CFStringRef c_vlan_if;
1448 Boolean found = FALSE;
1449 CFIndex j;
1450 CFBooleanRef supported;
1451
1452 c_vlan = CFArrayGetValueAtIndex(config, i);
1453 c_vlan_device = VLANInterfaceGetDevice(c_vlan);
1454 c_vlan_if = VLANInterfaceGetInterface(c_vlan);
1455
1456 // determine if the [parent] device supports VLANs
1457 supported = CFDictionaryGetValue(devices, c_vlan_device);
1458 if (supported == NULL) {
1459 supported = IsVLANSupported(c_vlan_device) ? kCFBooleanTrue
1460 : kCFBooleanFalse;
1461 CFDictionaryAddValue(devices, c_vlan_device, supported);
1462 }
1463
1464 for (j = 0; j < nActive; j++) {
1465 VLANInterfaceRef a_vlan;
1466 CFStringRef a_vlan_if;
1467
1468 a_vlan = CFArrayGetValueAtIndex(active, j);
1469 a_vlan_if = VLANInterfaceGetInterface(a_vlan);
1470
1471 if (CFEqual(c_vlan_if, a_vlan_if)) {
1472 if (!__VLANInterfaceEquiv(c_vlan, a_vlan)) {
1473 // update VLAN interface;
1474 if (s == -1) {
1475 s = inet_dgram_socket();
1476 }
1477
1478 if (CFBooleanGetValue(supported)) {
1479 // if the new [parent] device supports VLANs
1480 ok = _VLANDevice_unset(s, c_vlan_if);
1481 if (!ok) {
1482 goto done;
1483 }
1484
1485 ok = _VLANDevice_set(s,
1486 c_vlan_if,
1487 c_vlan_device,
1488 VLANInterfaceGetTag(c_vlan));
1489 if (!ok) {
1490 goto done;
1491 }
1492 } else {
1493 // if the new [parent] device does not support VLANs
1494 ok = _VLAN_destroy(s, c_vlan_if);
1495 if (!ok) {
1496 goto done;
1497 }
1498 }
1499 }
1500
1501 found = TRUE;
1502 break;
1503 }
1504 }
1505
1506 if (!found && CFBooleanGetValue(supported)) {
1507 // if the [parent] device supports VLANs, add new interface
1508 if (s == -1) {
1509 s = inet_dgram_socket();
1510 }
1511
1512 ok = _VLAN_create(s, c_vlan_if);
1513 if (!ok) {
1514 goto done;
1515 }
1516
1517 ok = _VLANDevice_set(s,
1518 c_vlan_if,
1519 c_vlan_device,
1520 VLANInterfaceGetTag(c_vlan));
1521 if (!ok) {
1522 goto done;
1523 }
1524 }
1525
1526 }
1527
1528 ok = TRUE;
1529
1530 done :
1531
1532 if (active) CFRelease(active);
1533 if (config) CFRelease(config);
1534 if (devices) CFRelease(devices);
1535 if (s != -1) (void) close(s);
1536
1537 return ok;
1538 }
1539
1540
1541 Boolean
1542 VLANPreferencesApplyChanges(VLANPreferencesRef prefs)
1543 {
1544 Boolean ok = FALSE;
1545 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
1546
1547 if (!isA_VLANPreferences(prefs)) {
1548 _SCErrorSet(kSCStatusInvalidArgument);
1549 return FALSE;
1550 }
1551
1552 pthread_mutex_lock(&prefsPrivate->lock);
1553
1554 /* apply the preferences */
1555 ok = SCPreferencesApplyChanges(prefsPrivate->prefs);
1556 if (!ok) {
1557 goto done;
1558 }
1559
1560 /* apply the VLAN configuration */
1561 ok = _VLANPreferencesUpdateConfiguration(prefs);
1562 if (!ok) {
1563 goto done;
1564 }
1565
1566 ok = TRUE;
1567
1568 done :
1569
1570 pthread_mutex_unlock(&prefsPrivate->lock);
1571
1572 return ok;
1573 }