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