]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/VLANConfiguration.c
configd-204.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / VLANConfiguration.c
1 /*
2 * Copyright (c) 2003-2007 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 * November 14, 2003 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 <net/ethernet.h>
50 #define KERNEL_PRIVATE
51 #include <net/if.h>
52 #include <net/if_var.h>
53 #undef KERNEL_PRIVATE
54 #include <net/if_vlan_var.h>
55 #include <net/if_types.h>
56
57 #include <SystemConfiguration/VLANConfiguration.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 }
70
71 return s;
72 }
73
74
75 typedef struct {
76 CFMutableArrayRef vlans;
77 SCPreferencesRef prefs;
78 } addContext, *addContextRef;
79
80
81 static void
82 add_configured_interface(const void *key, const void *value, void *context)
83 {
84 SCNetworkInterfacePrivateRef interfacePrivate;
85 addContextRef myContext = (addContextRef)context;
86 SCVLANInterfaceRef vlan;
87 CFStringRef vlan_if = (CFStringRef)key;
88 CFDictionaryRef vlan_info = (CFDictionaryRef)value;
89 CFStringRef vlan_name;
90 CFDictionaryRef vlan_options;
91 SCNetworkInterfaceRef vlan_physical;
92 CFStringRef vlan_physical_if;
93 CFNumberRef vlan_tag;
94
95 vlan_physical_if = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANInterface);
96 if (!isA_CFString(vlan_physical_if)) {
97 // if prefs are confused
98 return;
99 }
100
101 vlan_tag = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANTag);
102 if (!isA_CFNumber(vlan_tag)) {
103 // if prefs are confused
104 return;
105 }
106
107 // create the VLAN interface
108 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(NULL, vlan_if);
109
110 // set physical interface and tag
111 vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if,
112 kIncludeBondInterfaces);
113 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag);
114 CFRelease(vlan_physical);
115
116 // set display name
117 vlan_name = CFDictionaryGetValue(vlan_info, kSCPropUserDefinedName);
118 if (isA_CFString(vlan_name)) {
119 SCVLANInterfaceSetLocalizedDisplayName(vlan, vlan_name);
120 }
121
122 // set options
123 vlan_options = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANOptions);
124 if (isA_CFDictionary(vlan_options)) {
125 SCVLANInterfaceSetOptions(vlan, vlan_options);
126 }
127
128 // estabish link to the stored configuration
129 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
130 interfacePrivate->prefs = CFRetain(myContext->prefs);
131
132 CFArrayAppendValue(myContext->vlans, vlan);
133 CFRelease(vlan);
134
135 return;
136 }
137
138
139 static void
140 add_legacy_configuration(addContextRef myContext)
141 {
142 CFIndex i;
143 CFIndex n;
144 SCPreferencesRef prefs;
145 CFArrayRef vlans;
146
147 #define VLAN_PREFERENCES_ID CFSTR("VirtualNetworkInterfaces.plist")
148 #define VLAN_PREFERENCES_VLANS CFSTR("VLANs")
149 #define __kVLANInterface_interface CFSTR("interface") // e.g. vlan0, vlan1, ...
150 #define __kVLANInterface_device CFSTR("device") // e.g. en0, en1, ...
151 #define __kVLANInterface_tag CFSTR("tag") // e.g. 1 <= tag <= 4094
152 #define __kVLANInterface_options CFSTR("options") // e.g. UserDefinedName
153
154 prefs = SCPreferencesCreate(NULL, CFSTR("SCVLANInterfaceCopyAll"), VLAN_PREFERENCES_ID);
155 if (prefs == NULL) {
156 return;
157 }
158
159 vlans = SCPreferencesGetValue(prefs, VLAN_PREFERENCES_VLANS);
160 if ((vlans != NULL) && !isA_CFArray(vlans)) {
161 CFRelease(prefs); // if the prefs are confused
162 return;
163 }
164
165 n = (vlans != NULL) ? CFArrayGetCount(vlans) : 0;
166 for (i = 0; i < n; i++) {
167 CFDictionaryRef dict;
168 SCNetworkInterfacePrivateRef interfacePrivate;
169 Boolean ok;
170 CFDictionaryRef options;
171 CFStringRef path;
172 SCVLANInterfaceRef vlan;
173 CFStringRef vlan_if;
174 CFDictionaryRef vlan_dict;
175 SCNetworkInterfaceRef vlan_physical;
176 CFStringRef vlan_physical_if;
177 CFNumberRef vlan_tag;
178
179 vlan_dict = CFArrayGetValueAtIndex(vlans, i);
180 if (!isA_CFDictionary(vlan_dict)) {
181 continue; // if the prefs are confused
182 }
183
184 vlan_if = CFDictionaryGetValue(vlan_dict, __kVLANInterface_interface);
185 if (!isA_CFString(vlan_if)) {
186 continue; // if the prefs are confused
187 }
188
189 vlan_physical_if = CFDictionaryGetValue(vlan_dict, __kVLANInterface_device);
190 if (!isA_CFString(vlan_physical_if)) {
191 continue; // if the prefs are confused
192 }
193
194 vlan_tag = CFDictionaryGetValue(vlan_dict, __kVLANInterface_tag);
195 if (!isA_CFNumber(vlan_tag)) {
196 continue; // if the prefs are confused
197 }
198
199 // check if this VLAN interface has already been allocated
200 path = CFStringCreateWithFormat(NULL,
201 NULL,
202 CFSTR("/%@/%@/%@"),
203 kSCPrefVirtualNetworkInterfaces,
204 kSCNetworkInterfaceTypeVLAN,
205 vlan_if);
206 dict = SCPreferencesPathGetValue(myContext->prefs, path);
207 if (dict != NULL) {
208 // if VLAN interface name not available
209 CFRelease(path);
210 continue;
211 }
212
213 // add a placeholder for the VLAN in the stored preferences
214 dict = CFDictionaryCreate(NULL,
215 NULL, NULL, 0,
216 &kCFTypeDictionaryKeyCallBacks,
217 &kCFTypeDictionaryValueCallBacks);
218 ok = SCPreferencesPathSetValue(myContext->prefs, path, dict);
219 CFRelease(dict);
220 CFRelease(path);
221 if (!ok) {
222 // if the VLAN could not be saved
223 continue;
224 }
225
226 // create the VLAN interface
227 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(NULL, vlan_if);
228
229 // estabish link to the stored configuration
230 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
231 interfacePrivate->prefs = CFRetain(myContext->prefs);
232
233 // set the interface and tag (which updates the stored preferences)
234 vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if,
235 kIncludeBondInterfaces);
236 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag);
237 CFRelease(vlan_physical);
238
239 // set display name (which updates the stored preferences)
240 options = CFDictionaryGetValue(vlan_dict, __kVLANInterface_options);
241 if (isA_CFDictionary(options)) {
242 CFStringRef vlan_name;
243
244 vlan_name = CFDictionaryGetValue(options, CFSTR("VLAN Name"));
245 if (isA_CFString(vlan_name)) {
246 SCVLANInterfaceSetLocalizedDisplayName(vlan, vlan_name);
247 }
248 }
249
250 CFArrayAppendValue(myContext->vlans, vlan);
251 CFRelease(vlan);
252 }
253
254 CFRelease(prefs);
255 return;
256 }
257
258
259 static SCVLANInterfaceRef
260 findVLANInterfaceAndTag(SCPreferencesRef prefs, SCNetworkInterfaceRef physical, CFNumberRef tag)
261 {
262 CFIndex i;
263 CFIndex n;
264 SCVLANInterfaceRef vlan = NULL;
265 CFArrayRef vlans;
266
267 vlans = SCVLANInterfaceCopyAll(prefs);
268
269 n = CFArrayGetCount(vlans);
270 for (i = 0; i < n; i++) {
271 SCVLANInterfaceRef config_vlan;
272 SCNetworkInterfaceRef config_physical;
273 CFNumberRef config_tag;
274
275 config_vlan = CFArrayGetValueAtIndex(vlans, i);
276 config_physical = SCVLANInterfaceGetPhysicalInterface(config_vlan);
277 config_tag = SCVLANInterfaceGetTag(config_vlan);
278
279 if ((config_physical != NULL) && (config_tag != NULL)) {
280 if (!CFEqual(physical, config_physical)) {
281 // if this VLAN has a different physical interface
282 continue;
283 }
284
285 if (!CFEqual(tag, config_tag)) {
286 // if this VLAN has a different tag
287 continue;
288 }
289
290 vlan = CFRetain(config_vlan);
291 break;
292 }
293 }
294 CFRelease(vlans);
295
296 return vlan;
297 }
298
299
300 #pragma mark -
301 #pragma mark SCVLANInterface APIs
302
303
304 CFArrayRef
305 SCVLANInterfaceCopyAll(SCPreferencesRef prefs)
306 {
307 addContext context;
308 CFDictionaryRef dict;
309 CFStringRef path;
310
311 context.vlans = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
312 context.prefs = prefs;
313
314 path = CFStringCreateWithFormat(NULL,
315 NULL,
316 CFSTR("/%@/%@"),
317 kSCPrefVirtualNetworkInterfaces,
318 kSCNetworkInterfaceTypeVLAN);
319 dict = SCPreferencesPathGetValue(prefs, path);
320 if (isA_CFDictionary(dict)) {
321 CFDictionaryApplyFunction(dict, add_configured_interface, &context);
322 } else {
323 // no VLAN configuration, upgrade from legacy configuration
324 dict = CFDictionaryCreate(NULL,
325 NULL, NULL, 0,
326 &kCFTypeDictionaryKeyCallBacks,
327 &kCFTypeDictionaryValueCallBacks);
328 (void) SCPreferencesPathSetValue(prefs, path, dict);
329 CFRelease(dict);
330
331 add_legacy_configuration(&context);
332 }
333 CFRelease(path);
334
335 return context.vlans;
336 }
337
338
339 static void
340 addAvailableInterfaces(CFMutableArrayRef available, CFArrayRef interfaces,
341 CFSetRef exclude)
342 {
343 CFIndex i;
344 CFIndex n;
345
346 n = CFArrayGetCount(interfaces);
347 for (i = 0; i < n; i++) {
348 SCNetworkInterfaceRef interface;
349 SCNetworkInterfacePrivateRef interfacePrivate;
350
351 interface = CFArrayGetValueAtIndex(interfaces, i);
352 interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
353
354 if (exclude != NULL
355 && CFSetContainsValue(exclude, interface)) {
356 // exclude this interface
357 continue;
358 }
359 if (interfacePrivate->supportsVLAN) {
360 // if this interface is available
361 CFArrayAppendValue(available, interface);
362 }
363 }
364
365 return;
366 }
367
368
369 CFArrayRef
370 SCVLANInterfaceCopyAvailablePhysicalInterfaces()
371 {
372 CFMutableArrayRef available;
373 CFArrayRef bond_interfaces = NULL;
374 CFMutableSetRef exclude = NULL;
375 CFArrayRef interfaces;
376 SCPreferencesRef prefs;
377
378 available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
379
380 prefs = SCPreferencesCreate(NULL, CFSTR("SCVLANInterfaceCopyAvailablePhysicalInterfaces"), NULL);
381 if (prefs != NULL) {
382 bond_interfaces = SCBondInterfaceCopyAll(prefs);
383 CFRelease(prefs);
384 if (bond_interfaces != NULL) {
385 exclude = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
386 __SCBondInterfaceListCopyMembers(bond_interfaces, exclude);
387 }
388 }
389
390 // add real interfaces that aren't part of a bond
391 interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface();
392 if (interfaces != NULL) {
393 addAvailableInterfaces(available, interfaces, exclude);
394 CFRelease(interfaces);
395 }
396
397 // add bond interfaces
398 if (bond_interfaces != NULL) {
399 addAvailableInterfaces(available, bond_interfaces, NULL);
400 CFRelease(bond_interfaces);
401 }
402 if (exclude != NULL) {
403 CFRelease(exclude);
404 }
405
406 return available;
407 }
408
409
410 CFArrayRef
411 _SCVLANInterfaceCopyActive(void)
412 {
413 struct ifaddrs *ifap;
414 struct ifaddrs *ifp;
415 int s;
416 CFMutableArrayRef vlans = NULL;
417
418 if (getifaddrs(&ifap) == -1) {
419 SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno));
420 _SCErrorSet(kSCStatusFailed);
421 return NULL;
422 }
423
424 s = inet_dgram_socket();
425 if (s == -1) {
426 _SCErrorSet(errno);
427 goto done;
428 }
429
430 vlans = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
431
432 for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) {
433 struct if_data *if_data;
434 struct ifreq ifr;
435 SCVLANInterfaceRef vlan;
436 CFStringRef vlan_if;
437 SCNetworkInterfaceRef vlan_physical;
438 CFStringRef vlan_physical_if;
439 CFNumberRef vlan_tag;
440 char vlr_parent[IFNAMSIZ + 1];
441 int vlr_tag;
442 struct vlanreq vreq;
443
444 if_data = (struct if_data *)ifp->ifa_data;
445 if (if_data == NULL
446 || ifp->ifa_addr->sa_family != AF_LINK
447 || if_data->ifi_type != IFT_L2VLAN) {
448 continue;
449 }
450
451 bzero(&ifr, sizeof(ifr));
452 bzero(&vreq, sizeof(vreq));
453 strncpy(ifr.ifr_name, ifp->ifa_name, sizeof(ifr.ifr_name));
454 ifr.ifr_data = (caddr_t)&vreq;
455
456 if (ioctl(s, SIOCGIFVLAN, (caddr_t)&ifr) == -1) {
457 SCLog(TRUE, LOG_ERR, CFSTR("ioctl() failed: %s"), strerror(errno));
458 CFRelease(vlans);
459 vlans = NULL;
460 _SCErrorSet(kSCStatusFailed);
461 goto done;
462 }
463
464 // create the VLAN interface
465 vlan_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
466 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(NULL, vlan_if);
467 CFRelease(vlan_if);
468
469 // set the physical interface and tag
470 bzero(&vlr_parent, sizeof(vlr_parent));
471 bcopy(vreq.vlr_parent, vlr_parent, IFNAMSIZ);
472 vlan_physical_if = CFStringCreateWithCString(NULL, vlr_parent, kCFStringEncodingASCII);
473 vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if,
474 kIncludeBondInterfaces);
475 CFRelease(vlan_physical_if);
476
477 vlr_tag = vreq.vlr_tag;
478 vlan_tag = CFNumberCreate(NULL, kCFNumberIntType, &vlr_tag);
479
480 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag);
481 CFRelease(vlan_physical);
482 CFRelease(vlan_tag);
483
484 // add VLAN
485 CFArrayAppendValue(vlans, vlan);
486 CFRelease(vlan);
487 }
488
489 done :
490
491 (void) close(s);
492 freeifaddrs(ifap);
493 return vlans;
494 }
495
496
497 SCVLANInterfaceRef
498 SCVLANInterfaceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef physical, CFNumberRef tag)
499 {
500 CFAllocatorRef allocator;
501 CFIndex i;
502 SCNetworkInterfacePrivateRef interfacePrivate;
503 SCVLANInterfaceRef vlan;
504
505 if (prefs == NULL) {
506 _SCErrorSet(kSCStatusInvalidArgument);
507 return NULL;
508 }
509
510 if (!isA_SCNetworkInterface(physical)) {
511 _SCErrorSet(kSCStatusInvalidArgument);
512 return NULL;
513 }
514
515 interfacePrivate = (SCNetworkInterfacePrivateRef)physical;
516 if (!interfacePrivate->supportsVLAN) {
517 _SCErrorSet(kSCStatusInvalidArgument);
518 return NULL;
519 }
520
521 if (isA_CFNumber(tag)) {
522 int tag_val;
523
524 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
525 if ((tag_val < 1) || (tag_val > 4094)) {
526 _SCErrorSet(kSCStatusInvalidArgument);
527 return NULL;
528 }
529 } else {
530 _SCErrorSet(kSCStatusInvalidArgument);
531 return NULL;
532 }
533
534 // make sure that physical interface and tag are not used
535 vlan = findVLANInterfaceAndTag(prefs, physical, tag);
536 if (vlan != NULL) {
537 CFRelease(vlan);
538 _SCErrorSet(kSCStatusKeyExists);
539 return NULL;
540 }
541
542 allocator = CFGetAllocator(prefs);
543
544 // create a new VLAN using an unused interface name
545 for (i = 0; vlan == NULL; i++) {
546 CFDictionaryRef dict;
547 CFStringRef vlan_if;
548 Boolean ok;
549 CFStringRef path;
550
551 vlan_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("vlan%d"), i);
552 path = CFStringCreateWithFormat(allocator,
553 NULL,
554 CFSTR("/%@/%@/%@"),
555 kSCPrefVirtualNetworkInterfaces,
556 kSCNetworkInterfaceTypeVLAN,
557 vlan_if);
558 dict = SCPreferencesPathGetValue(prefs, path);
559 if (dict != NULL) {
560 // if VLAN interface name not available
561 CFRelease(path);
562 CFRelease(vlan_if);
563 continue;
564 }
565
566 // add the VLAN to the stored preferences
567 dict = CFDictionaryCreate(allocator,
568 NULL, NULL, 0,
569 &kCFTypeDictionaryKeyCallBacks,
570 &kCFTypeDictionaryValueCallBacks);
571 ok = SCPreferencesPathSetValue(prefs, path, dict);
572 CFRelease(dict);
573 CFRelease(path);
574 if (!ok) {
575 // if the VLAN could not be saved
576 CFRelease(vlan_if);
577 _SCErrorSet(kSCStatusFailed);
578 break;
579 }
580
581 // create the SCVLANInterfaceRef
582 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(allocator, vlan_if);
583 CFRelease(vlan_if);
584
585 // estabish link to the stored configuration
586 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
587 interfacePrivate->prefs = CFRetain(prefs);
588
589 // set physical interface and tag
590 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, physical, tag);
591 }
592
593 return vlan;
594 }
595
596
597 Boolean
598 SCVLANInterfaceRemove(SCVLANInterfaceRef vlan)
599 {
600 CFStringRef vlan_if;
601 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
602 Boolean ok;
603 CFStringRef path;
604
605 if (!isA_SCVLANInterface(vlan)) {
606 _SCErrorSet(kSCStatusInvalidArgument);
607 return FALSE;
608 }
609
610 if (interfacePrivate->prefs == NULL) {
611 _SCErrorSet(kSCStatusInvalidArgument);
612 return FALSE;
613 }
614
615 vlan_if = SCNetworkInterfaceGetBSDName(vlan);
616 path = CFStringCreateWithFormat(NULL,
617 NULL,
618 CFSTR("/%@/%@/%@"),
619 kSCPrefVirtualNetworkInterfaces,
620 kSCNetworkInterfaceTypeVLAN,
621 vlan_if);
622 ok = SCPreferencesPathRemoveValue(interfacePrivate->prefs, path);
623 CFRelease(path);
624
625 return ok;
626 }
627
628
629 SCNetworkInterfaceRef
630 SCVLANInterfaceGetPhysicalInterface(SCVLANInterfaceRef vlan)
631 {
632 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
633
634 if (!isA_SCVLANInterface(vlan)) {
635 _SCErrorSet(kSCStatusInvalidArgument);
636 return NULL;
637 }
638
639 return interfacePrivate->vlan.interface;
640 }
641
642
643 CFNumberRef
644 SCVLANInterfaceGetTag(SCVLANInterfaceRef vlan)
645 {
646 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
647
648 if (!isA_SCVLANInterface(vlan)) {
649 _SCErrorSet(kSCStatusInvalidArgument);
650 return NULL;
651 }
652
653 return interfacePrivate->vlan.tag;
654 }
655
656
657 CFDictionaryRef
658 SCVLANInterfaceGetOptions(SCVLANInterfaceRef vlan)
659 {
660 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
661
662 if (!isA_SCVLANInterface(vlan)) {
663 _SCErrorSet(kSCStatusInvalidArgument);
664 return NULL;
665 }
666
667 return interfacePrivate->vlan.options;
668 }
669
670
671 Boolean
672 SCVLANInterfaceSetPhysicalInterfaceAndTag(SCVLANInterfaceRef vlan, SCNetworkInterfaceRef physical, CFNumberRef tag)
673 {
674 SCNetworkInterfacePrivateRef interfacePrivate;
675 Boolean ok = TRUE;
676
677 if (!isA_SCVLANInterface(vlan)) {
678 _SCErrorSet(kSCStatusInvalidArgument);
679 return FALSE;
680 }
681
682 if (!isA_SCNetworkInterface(physical)) {
683 _SCErrorSet(kSCStatusInvalidArgument);
684 return FALSE;
685 }
686
687 interfacePrivate = (SCNetworkInterfacePrivateRef)physical;
688 if (!interfacePrivate->supportsVLAN) {
689 _SCErrorSet(kSCStatusInvalidArgument);
690 return FALSE;
691 }
692
693 if (isA_CFNumber(tag)) {
694 int tag_val;
695
696 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
697 if ((tag_val < 1) || (tag_val > 4094)) {
698 _SCErrorSet(kSCStatusInvalidArgument);
699 return FALSE;
700 }
701 } else {
702 _SCErrorSet(kSCStatusInvalidArgument);
703 return FALSE;
704 }
705
706 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
707 if (interfacePrivate->prefs != NULL) {
708 SCVLANInterfaceRef config_vlan;
709 CFDictionaryRef dict;
710 CFMutableDictionaryRef newDict;
711 CFStringRef path;
712
713 // make sure that physical interface and tag are not used
714 config_vlan = findVLANInterfaceAndTag(interfacePrivate->prefs, physical, tag);
715 if (config_vlan != NULL) {
716 if (!CFEqual(vlan, config_vlan)) {
717 CFRelease(config_vlan);
718 _SCErrorSet(kSCStatusKeyExists);
719 return FALSE;
720 }
721 CFRelease(config_vlan);
722 }
723
724 // set interface/tag in the stored preferences
725 path = CFStringCreateWithFormat(NULL,
726 NULL,
727 CFSTR("/%@/%@/%@"),
728 kSCPrefVirtualNetworkInterfaces,
729 kSCNetworkInterfaceTypeVLAN,
730 interfacePrivate->entity_device);
731 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
732 if (!isA_CFDictionary(dict)) {
733 // if the prefs are confused
734 CFRelease(path);
735 _SCErrorSet(kSCStatusFailed);
736 return FALSE;
737 }
738
739 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
740 CFDictionarySetValue(newDict,
741 kSCPropVirtualNetworkInterfacesVLANInterface,
742 SCNetworkInterfaceGetBSDName(physical));
743 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANTag, tag);
744 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
745 CFRelease(newDict);
746 CFRelease(path);
747 }
748
749 if (ok) {
750 // set physical interface
751 if (interfacePrivate->vlan.interface != NULL)
752 CFRelease(interfacePrivate->vlan.interface);
753 interfacePrivate->vlan.interface = CFRetain(physical);
754
755 // set tag
756 if (interfacePrivate->vlan.tag != NULL)
757 CFRelease(interfacePrivate->vlan.tag);
758 interfacePrivate->vlan.tag = CFRetain(tag);
759 }
760
761 return ok;
762 }
763
764
765 Boolean
766 SCVLANInterfaceSetLocalizedDisplayName(SCVLANInterfaceRef vlan, CFStringRef newName)
767 {
768 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
769 Boolean ok = TRUE;
770
771 if (!isA_SCVLANInterface(vlan)) {
772 _SCErrorSet(kSCStatusInvalidArgument);
773 return FALSE;
774 }
775
776 if ((newName != NULL) && !isA_CFString(newName)) {
777 _SCErrorSet(kSCStatusInvalidArgument);
778 return FALSE;
779 }
780
781 // set name in the stored preferences
782 if (interfacePrivate->prefs != NULL) {
783 CFDictionaryRef dict;
784 CFMutableDictionaryRef newDict;
785 CFStringRef path;
786
787 path = CFStringCreateWithFormat(NULL,
788 NULL,
789 CFSTR("/%@/%@/%@"),
790 kSCPrefVirtualNetworkInterfaces,
791 kSCNetworkInterfaceTypeVLAN,
792 interfacePrivate->entity_device);
793 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
794 if (!isA_CFDictionary(dict)) {
795 // if the prefs are confused
796 CFRelease(path);
797 _SCErrorSet(kSCStatusFailed);
798 return FALSE;
799 }
800
801 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
802 if (newName != NULL) {
803 CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName);
804 } else {
805 CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName);
806 }
807 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
808 CFRelease(newDict);
809 CFRelease(path);
810 }
811
812 // set name in the SCVLANInterfaceRef
813 if (ok) {
814 if (interfacePrivate->localized_name != NULL) {
815 CFRelease(interfacePrivate->localized_name);
816 interfacePrivate->localized_name = NULL;
817 }
818 if (newName != NULL) {
819 interfacePrivate->localized_name = CFStringCreateCopy(NULL, newName);
820 }
821 }
822
823 return ok;
824 }
825
826
827 Boolean
828 SCVLANInterfaceSetOptions(SCVLANInterfaceRef vlan, CFDictionaryRef newOptions)
829 {
830 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
831 Boolean ok = TRUE;
832
833 if (!isA_SCVLANInterface(vlan)) {
834 _SCErrorSet(kSCStatusInvalidArgument);
835 return FALSE;
836 }
837
838 if ((newOptions != NULL) && !isA_CFDictionary(newOptions)) {
839 _SCErrorSet(kSCStatusInvalidArgument);
840 return FALSE;
841 }
842
843 // set options in the stored preferences
844 if (interfacePrivate->prefs != NULL) {
845 CFDictionaryRef dict;
846 CFMutableDictionaryRef newDict;
847 CFStringRef path;
848
849 path = CFStringCreateWithFormat(NULL,
850 NULL,
851 CFSTR("/%@/%@/%@"),
852 kSCPrefVirtualNetworkInterfaces,
853 kSCNetworkInterfaceTypeVLAN,
854 interfacePrivate->entity_device);
855 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
856 if (!isA_CFDictionary(dict)) {
857 // if the prefs are confused
858 CFRelease(path);
859 _SCErrorSet(kSCStatusFailed);
860 return FALSE;
861 }
862
863 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
864 if (newOptions != NULL) {
865 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANOptions, newOptions);
866 } else {
867 CFDictionaryRemoveValue(newDict, kSCPropVirtualNetworkInterfacesVLANOptions);
868 }
869 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
870 CFRelease(newDict);
871 CFRelease(path);
872 }
873
874 // set options in the SCVLANInterfaceRef
875 if (ok) {
876 if (interfacePrivate->vlan.options != NULL) {
877 CFRelease(interfacePrivate->vlan.options);
878 interfacePrivate->vlan.options = NULL;
879 }
880 if (newOptions != NULL) {
881 interfacePrivate->vlan.options = CFDictionaryCreateCopy(NULL, newOptions);
882 }
883 }
884
885 return ok;
886 }
887
888
889 #pragma mark -
890 #pragma mark SCVLANInterface management
891
892
893 static Boolean
894 __vlan_set(int s, CFStringRef interface_if, CFStringRef physical_if, CFNumberRef tag)
895 {
896 struct ifreq ifr;
897 int tag_val;
898 struct vlanreq vreq;
899
900 bzero(&ifr, sizeof(ifr));
901 bzero(&vreq, sizeof(vreq));
902
903 // interface
904 (void) _SC_cfstring_to_cstring(interface_if,
905 ifr.ifr_name,
906 sizeof(ifr.ifr_name),
907 kCFStringEncodingASCII);
908 ifr.ifr_data = (caddr_t)&vreq;
909
910 // physical interface
911 (void) _SC_cfstring_to_cstring(physical_if,
912 vreq.vlr_parent,
913 sizeof(vreq.vlr_parent),
914 kCFStringEncodingASCII);
915
916 // tag
917 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
918 vreq.vlr_tag = tag_val;
919
920 // update physical interface and tag
921 if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) {
922 SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno));
923 _SCErrorSet(kSCStatusFailed);
924 return FALSE;
925 }
926
927 return TRUE;
928 }
929
930
931 static Boolean
932 __vlan_clear(int s, CFStringRef interface_if)
933 {
934 struct ifreq ifr;
935 struct vlanreq vreq;
936
937 bzero(&ifr, sizeof(ifr));
938 bzero(&vreq, sizeof(vreq));
939
940 // interface
941 (void) _SC_cfstring_to_cstring(interface_if,
942 ifr.ifr_name,
943 sizeof(ifr.ifr_name),
944 kCFStringEncodingASCII);
945 ifr.ifr_data = (caddr_t)&vreq;
946
947 // clear physical interface
948 bzero(&vreq.vlr_parent, sizeof(vreq.vlr_parent));
949
950 // clear tag
951 vreq.vlr_tag = 0;
952
953 // update physical interface and tag
954 if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) {
955 SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno));
956 _SCErrorSet(kSCStatusFailed);
957 return FALSE;
958 }
959
960 return TRUE;
961 }
962
963
964 Boolean
965 _SCVLANInterfaceUpdateConfiguration(SCPreferencesRef prefs)
966 {
967 CFArrayRef active = NULL;
968 CFArrayRef config = NULL;
969 CFMutableDictionaryRef devices = NULL;
970 CFIndex i;
971 CFIndex nActive;
972 CFIndex nConfig;
973 Boolean ok = TRUE;
974 int s = -1;
975
976 if (prefs == NULL) {
977 _SCErrorSet(kSCStatusInvalidArgument);
978 return FALSE;
979 }
980
981 /* configured VLANs */
982 config = SCVLANInterfaceCopyAll(prefs);
983 nConfig = CFArrayGetCount(config);
984
985 /* physical interfaces */
986 devices = CFDictionaryCreateMutable(NULL,
987 0,
988 &kCFTypeDictionaryKeyCallBacks,
989 &kCFTypeDictionaryValueCallBacks);
990
991 /* active VLANs */
992 active = _SCVLANInterfaceCopyActive();
993 nActive = CFArrayGetCount(active);
994
995 /* remove any no-longer-configured VLAN interfaces */
996 for (i = 0; i < nActive; i++) {
997 SCVLANInterfaceRef a_vlan;
998 CFStringRef a_vlan_if;
999 CFIndex j;
1000 Boolean found = FALSE;
1001
1002 a_vlan = CFArrayGetValueAtIndex(active, i);
1003 a_vlan_if = SCNetworkInterfaceGetBSDName(a_vlan);
1004
1005 for (j = 0; j < nConfig; j++) {
1006 SCVLANInterfaceRef c_vlan;
1007 CFStringRef c_vlan_if;
1008
1009 c_vlan = CFArrayGetValueAtIndex(config, j);
1010 c_vlan_if = SCNetworkInterfaceGetBSDName(c_vlan);
1011
1012 if (CFEqual(a_vlan_if, c_vlan_if)) {
1013 found = TRUE;
1014 break;
1015 }
1016 }
1017
1018 if (!found) {
1019 // remove VLAN interface
1020 if (s == -1) {
1021 s = inet_dgram_socket();
1022 if (s == -1) {
1023 _SCErrorSet(errno);
1024 ok = FALSE;
1025 goto done;
1026 }
1027 }
1028 if (!__destroyInterface(s, a_vlan_if)) {
1029 ok = FALSE;
1030 _SCErrorSet(errno);
1031 }
1032 }
1033 }
1034
1035 /* create (and update) configured VLAN interfaces */
1036 for (i = 0; i < nConfig; i++) {
1037 SCVLANInterfaceRef c_vlan;
1038 CFStringRef c_vlan_if;
1039 SCNetworkInterfaceRef c_vlan_physical;
1040 Boolean found = FALSE;
1041 CFIndex j;
1042 CFBooleanRef supported;
1043
1044 c_vlan = CFArrayGetValueAtIndex(config, i);
1045 c_vlan_if = SCNetworkInterfaceGetBSDName(c_vlan);
1046 c_vlan_physical = SCVLANInterfaceGetPhysicalInterface(c_vlan);
1047
1048 if (c_vlan_physical == NULL) {
1049 continue;
1050 }
1051 // determine if the physical interface supports VLANs
1052 supported = CFDictionaryGetValue(devices, c_vlan_physical);
1053 if (supported == NULL) {
1054 SCNetworkInterfacePrivateRef c_vlan_physicalPrivate = (SCNetworkInterfacePrivateRef)c_vlan_physical;
1055
1056 supported = c_vlan_physicalPrivate->supportsVLAN ? kCFBooleanTrue
1057 : kCFBooleanFalse;
1058 CFDictionaryAddValue(devices, c_vlan_physical, supported);
1059 }
1060
1061 for (j = 0; j < nActive; j++) {
1062 SCVLANInterfaceRef a_vlan;
1063 CFStringRef a_vlan_if;
1064
1065 a_vlan = CFArrayGetValueAtIndex(active, j);
1066 a_vlan_if = SCNetworkInterfaceGetBSDName(a_vlan);
1067
1068 if (CFEqual(c_vlan_if, a_vlan_if)) {
1069 if (!CFEqual(c_vlan, a_vlan)) {
1070 // update VLAN interface
1071 if (s == -1) {
1072 s = inet_dgram_socket();
1073 if (s == -1) {
1074 _SCErrorSet(errno);
1075 ok = FALSE;
1076 goto done;
1077 }
1078 }
1079
1080 if (!CFBooleanGetValue(supported)
1081 || !__vlan_clear(s, c_vlan_if)
1082 || !__vlan_set(s, c_vlan_if,
1083 SCNetworkInterfaceGetBSDName(c_vlan_physical),
1084 SCVLANInterfaceGetTag(c_vlan))) {
1085 // something went wrong, try to blow the VLAN away
1086 if (!CFBooleanGetValue(supported)) {
1087 _SCErrorSet(kSCStatusFailed);
1088 }
1089 (void)__destroyInterface(s, c_vlan_if);
1090 ok = FALSE;
1091 }
1092 }
1093
1094 found = TRUE;
1095 break;
1096 }
1097 }
1098
1099 if (!found && CFBooleanGetValue(supported)) {
1100 // if the physical interface supports VLANs, add new interface
1101 Boolean created;
1102
1103 if (s == -1) {
1104 s = inet_dgram_socket();
1105 if (s == -1) {
1106 _SCErrorSet(errno);
1107 ok = FALSE;
1108 goto done;
1109 }
1110 }
1111
1112 created = __createInterface(s, c_vlan_if);
1113 if (!created
1114 || !__vlan_set(s,
1115 c_vlan_if,
1116 SCNetworkInterfaceGetBSDName(c_vlan_physical),
1117 SCVLANInterfaceGetTag(c_vlan))) {
1118 if (created) {
1119 // something went wrong, try to blow the VLAN away
1120 (void)__destroyInterface(s, c_vlan_if);
1121 } else {
1122 _SCErrorSet(errno);
1123 }
1124 ok = FALSE;
1125 }
1126 }
1127
1128 }
1129
1130 done :
1131
1132 if (active) CFRelease(active);
1133 if (config) CFRelease(config);
1134 if (devices) CFRelease(devices);
1135 if (s != -1) (void) close(s);
1136
1137 return ok;
1138 }
1139
1140
1141 #pragma mark -
1142 #pragma mark Deprecated SPIs (remove when no longer referenced)
1143
1144
1145 /* ---------- VLAN "device" ---------- */
1146
1147 Boolean
1148 IsVLANSupported(CFStringRef device)
1149 {
1150 return __SCNetworkInterfaceSupportsVLAN(device);
1151 }
1152
1153 /* ---------- VLANInterface ---------- */
1154
1155 typedef struct {
1156
1157 /* base CFType information */
1158 CFRuntimeBase cfBase;
1159
1160 /* vlan interface configuration */
1161 CFStringRef ifname; // e.g. vlan0, vlan1, ...
1162 CFStringRef device; // e.g. en0, en1, ...
1163 CFNumberRef tag; // e.g. 1 <= tag <= 4094
1164 CFDictionaryRef options; // e.g. UserDefinedName
1165
1166 } VLANInterfacePrivate, * VLANInterfacePrivateRef;
1167
1168
1169 static CFStringRef __VLANInterfaceCopyDescription (CFTypeRef cf);
1170 static void __VLANInterfaceDeallocate (CFTypeRef cf);
1171 static Boolean __VLANInterfaceEqual (CFTypeRef cf1, CFTypeRef cf2);
1172
1173
1174 static const CFRuntimeClass __VLANInterfaceClass = {
1175 0, // version
1176 "VLANInterface", // className
1177 NULL, // init
1178 NULL, // copy
1179 __VLANInterfaceDeallocate, // dealloc
1180 __VLANInterfaceEqual, // equal
1181 NULL, // hash
1182 NULL, // copyFormattingDesc
1183 __VLANInterfaceCopyDescription // copyDebugDesc
1184 };
1185
1186
1187 static CFTypeID __kVLANInterfaceTypeID = _kCFRuntimeNotATypeID;
1188
1189
1190 static pthread_once_t vlanInterface_init = PTHREAD_ONCE_INIT;
1191
1192
1193 static CFStringRef
1194 __VLANInterfaceCopyDescription(CFTypeRef cf)
1195 {
1196 CFAllocatorRef allocator = CFGetAllocator(cf);
1197 CFMutableStringRef result;
1198 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)cf;
1199
1200 result = CFStringCreateMutable(allocator, 0);
1201 CFStringAppendFormat(result, NULL, CFSTR("<VLANInterface %p [%p]> {"), cf, allocator);
1202 CFStringAppendFormat(result, NULL, CFSTR("if = %@"), vlanPrivate->ifname);
1203 CFStringAppendFormat(result, NULL, CFSTR(", device = %@"), vlanPrivate->device);
1204 CFStringAppendFormat(result, NULL, CFSTR(", tag = %@"), vlanPrivate->tag);
1205 if (vlanPrivate->options != NULL) {
1206 CFStringAppendFormat(result, NULL, CFSTR(", options = %@"), vlanPrivate->options);
1207 }
1208 CFStringAppendFormat(result, NULL, CFSTR("}"));
1209
1210 return result;
1211 }
1212
1213
1214 static void
1215 __VLANInterfaceDeallocate(CFTypeRef cf)
1216 {
1217 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)cf;
1218
1219 /* release resources */
1220
1221 CFRelease(vlanPrivate->ifname);
1222 CFRelease(vlanPrivate->device);
1223 CFRelease(vlanPrivate->tag);
1224 if (vlanPrivate->options) CFRelease(vlanPrivate->options);
1225
1226 return;
1227 }
1228
1229
1230 static Boolean
1231 __VLANInterfaceEquiv(CFTypeRef cf1, CFTypeRef cf2)
1232 {
1233 VLANInterfacePrivateRef vlan1 = (VLANInterfacePrivateRef)cf1;
1234 VLANInterfacePrivateRef vlan2 = (VLANInterfacePrivateRef)cf2;
1235
1236 if (vlan1 == vlan2)
1237 return TRUE;
1238
1239 if (!CFEqual(vlan1->ifname, vlan2->ifname))
1240 return FALSE; // if not the same interface
1241
1242 if (!CFEqual(vlan1->device, vlan2->device))
1243 return FALSE; // if not the same device
1244
1245 if (!CFEqual(vlan1->tag, vlan2->tag))
1246 return FALSE; // if not the same tag
1247
1248 return TRUE;
1249 }
1250
1251
1252 static Boolean
1253 __VLANInterfaceEqual(CFTypeRef cf1, CFTypeRef cf2)
1254 {
1255 VLANInterfacePrivateRef vlan1 = (VLANInterfacePrivateRef)cf1;
1256 VLANInterfacePrivateRef vlan2 = (VLANInterfacePrivateRef)cf2;
1257
1258 if (!__VLANInterfaceEquiv(vlan1, vlan2))
1259 return FALSE; // if not the same VLAN interface/device/tag
1260
1261 if (vlan1->options != vlan2->options) {
1262 // if the options may differ
1263 if ((vlan1->options != NULL) && (vlan2->options != NULL)) {
1264 // if both VLANs have options
1265 if (!CFEqual(vlan1->options, vlan2->options)) {
1266 // if the options are not equal
1267 return FALSE;
1268 }
1269 } else {
1270 // if only one VLAN has options
1271 return FALSE;
1272 }
1273 }
1274
1275 return TRUE;
1276 }
1277
1278
1279 static void
1280 __VLANInterfaceInitialize(void)
1281 {
1282 __kVLANInterfaceTypeID = _CFRuntimeRegisterClass(&__VLANInterfaceClass);
1283 return;
1284 }
1285
1286
1287 static __inline__ CFTypeRef
1288 isA_VLANInterface(CFTypeRef obj)
1289 {
1290 return (isA_CFType(obj, VLANInterfaceGetTypeID()));
1291 }
1292
1293
1294 CFTypeID
1295 VLANInterfaceGetTypeID(void)
1296 {
1297 pthread_once(&vlanInterface_init, __VLANInterfaceInitialize); /* initialize runtime */
1298 return __kVLANInterfaceTypeID;
1299 }
1300
1301
1302 static VLANInterfaceRef
1303 __VLANInterfaceCreatePrivate(CFAllocatorRef allocator,
1304 CFStringRef ifname,
1305 CFStringRef device,
1306 CFNumberRef tag,
1307 CFDictionaryRef options)
1308 {
1309 VLANInterfacePrivateRef vlanPrivate;
1310 uint32_t size;
1311
1312 /* initialize runtime */
1313 pthread_once(&vlanInterface_init, __VLANInterfaceInitialize);
1314
1315 /* allocate vlan */
1316 size = sizeof(VLANInterfacePrivate) - sizeof(CFRuntimeBase);
1317 vlanPrivate = (VLANInterfacePrivateRef)_CFRuntimeCreateInstance(allocator,
1318 __kVLANInterfaceTypeID,
1319 size,
1320 NULL);
1321 if (!vlanPrivate) {
1322 return NULL;
1323 }
1324
1325 /* establish the vlan */
1326
1327 vlanPrivate->ifname = CFStringCreateCopy(allocator, ifname);
1328 vlanPrivate->device = CFStringCreateCopy(allocator, device);
1329 vlanPrivate->tag = CFRetain(tag);
1330 if (options != NULL) {
1331 vlanPrivate->options = CFDictionaryCreateCopy(allocator, options);
1332 } else {
1333 vlanPrivate->options = NULL;
1334 }
1335
1336 return (VLANInterfaceRef)vlanPrivate;
1337 }
1338
1339
1340 CFStringRef
1341 VLANInterfaceGetInterface(VLANInterfaceRef vlan)
1342 {
1343 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
1344 CFStringRef vlan_if = NULL;
1345
1346 if (isA_VLANInterface(vlan)) {
1347 vlan_if = vlanPrivate->ifname;
1348 }
1349
1350 return vlan_if;
1351 }
1352
1353
1354 CFStringRef
1355 VLANInterfaceGetDevice(VLANInterfaceRef vlan)
1356 {
1357 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
1358 CFStringRef vlan_device = NULL;
1359
1360 if (isA_VLANInterface(vlan)) {
1361 vlan_device = vlanPrivate->device;
1362 }
1363
1364 return vlan_device;
1365 }
1366
1367
1368 static void
1369 VLANInterfaceSetDevice(VLANInterfaceRef vlan, CFStringRef newDevice)
1370 {
1371 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
1372
1373 if (isA_VLANInterface(vlan)) {
1374 CFAllocatorRef allocator = CFGetAllocator(vlan);
1375
1376 CFRelease(vlanPrivate->device);
1377 vlanPrivate->device = CFStringCreateCopy(allocator, newDevice);
1378 }
1379
1380 return;
1381 }
1382
1383
1384 CFNumberRef
1385 VLANInterfaceGetTag(VLANInterfaceRef vlan)
1386 {
1387 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
1388 CFNumberRef vlan_tag = NULL;
1389
1390 if (isA_VLANInterface(vlan)) {
1391 vlan_tag = vlanPrivate->tag;
1392 }
1393
1394 return vlan_tag;
1395 }
1396
1397
1398 static void
1399 VLANInterfaceSetTag(VLANInterfaceRef vlan, CFNumberRef newTag)
1400 {
1401 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
1402
1403 if (isA_VLANInterface(vlan)) {
1404 CFRelease(vlanPrivate->tag);
1405 vlanPrivate->tag = CFRetain(newTag);
1406 }
1407
1408 return;
1409 }
1410
1411
1412 CFDictionaryRef
1413 VLANInterfaceGetOptions(VLANInterfaceRef vlan)
1414 {
1415 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
1416 CFDictionaryRef vlan_options = NULL;
1417
1418 if (isA_VLANInterface(vlan)) {
1419 vlan_options = vlanPrivate->options;
1420 }
1421
1422 return vlan_options;
1423 }
1424
1425
1426 static void
1427 VLANInterfaceSetOptions(VLANInterfaceRef vlan, CFDictionaryRef newOptions)
1428 {
1429 VLANInterfacePrivateRef vlanPrivate = (VLANInterfacePrivateRef)vlan;
1430
1431 if (isA_VLANInterface(vlan)) {
1432 CFAllocatorRef allocator = CFGetAllocator(vlan);
1433
1434 if (vlanPrivate->options) CFRelease(vlanPrivate->options);
1435 if (newOptions != NULL) {
1436 vlanPrivate->options = CFDictionaryCreateCopy(allocator, newOptions);
1437 } else {
1438 vlanPrivate->options = NULL;
1439 }
1440 }
1441
1442 return;
1443 }
1444
1445
1446 /* ---------- VLANPreferences ---------- */
1447
1448 typedef struct {
1449
1450 /* base CFType information */
1451 CFRuntimeBase cfBase;
1452
1453 /* lock */
1454 pthread_mutex_t lock;
1455
1456 /* underlying preferences */
1457 SCPreferencesRef prefs;
1458
1459 /* base VLANs (before any commits) */
1460 CFArrayRef vlBase;
1461
1462 } VLANPreferencesPrivate, * VLANPreferencesPrivateRef;
1463
1464
1465 static CFStringRef __VLANPreferencesCopyDescription (CFTypeRef cf);
1466 static void __VLANPreferencesDeallocate (CFTypeRef cf);
1467
1468
1469 static const CFRuntimeClass __VLANPreferencesClass = {
1470 0, // version
1471 "VLANPreferences", // className
1472 NULL, // init
1473 NULL, // copy
1474 __VLANPreferencesDeallocate, // dealloc
1475 NULL, // equal
1476 NULL, // hash
1477 NULL, // copyFormattingDesc
1478 __VLANPreferencesCopyDescription // copyDebugDesc
1479 };
1480
1481
1482 static CFTypeID __kVLANPreferencesTypeID = _kCFRuntimeNotATypeID;
1483
1484
1485 static pthread_once_t vlanPreferences_init = PTHREAD_ONCE_INIT;
1486
1487
1488 static CFStringRef
1489 __VLANPreferencesCopyDescription(CFTypeRef cf)
1490 {
1491 CFAllocatorRef allocator = CFGetAllocator(cf);
1492 CFIndex i;
1493 CFArrayRef keys;
1494 CFIndex n;
1495 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)cf;
1496 CFMutableStringRef result;
1497
1498 result = CFStringCreateMutable(allocator, 0);
1499 CFStringAppendFormat(result, NULL, CFSTR("<VLANPreferences %p [%p]> {"), cf, allocator);
1500
1501 keys = SCPreferencesCopyKeyList(prefsPrivate->prefs);
1502 n = CFArrayGetCount(keys);
1503 for (i = 0; i < n; i++) {
1504 CFStringRef key;
1505 CFPropertyListRef val;
1506
1507 key = CFArrayGetValueAtIndex(keys, i);
1508 val = SCPreferencesGetValue(prefsPrivate->prefs, key);
1509
1510 CFStringAppendFormat(result, NULL, CFSTR("%@ : %@"), key, val);
1511 }
1512 CFRelease(keys);
1513
1514 CFStringAppendFormat(result, NULL, CFSTR(" }"));
1515
1516 return result;
1517 }
1518
1519
1520 #define N_QUICK 8
1521
1522
1523 static void
1524 __VLANPreferencesDeallocate(CFTypeRef cf)
1525 {
1526 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)cf;
1527
1528 /* release resources */
1529
1530 pthread_mutex_destroy(&prefsPrivate->lock);
1531
1532 if (prefsPrivate->prefs) CFRelease(prefsPrivate->prefs);
1533 if (prefsPrivate->vlBase) CFRelease(prefsPrivate->vlBase);
1534
1535 return;
1536 }
1537
1538
1539 static void
1540 __VLANPreferencesInitialize(void)
1541 {
1542 __kVLANPreferencesTypeID = _CFRuntimeRegisterClass(&__VLANPreferencesClass);
1543 return;
1544 }
1545
1546
1547 static __inline__ CFTypeRef
1548 isA_VLANPreferences(CFTypeRef obj)
1549 {
1550 return (isA_CFType(obj, VLANPreferencesGetTypeID()));
1551 }
1552
1553
1554 CFArrayRef
1555 _VLANPreferencesCopyActiveInterfaces()
1556 {
1557 CFArrayCallBacks callbacks;
1558 struct ifaddrs *ifap;
1559 struct ifaddrs *ifp;
1560 int s;
1561 CFMutableArrayRef vlans = NULL;
1562
1563 if (getifaddrs(&ifap) == -1) {
1564 SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno));
1565 _SCErrorSet(kSCStatusFailed);
1566 return NULL;
1567 }
1568
1569 s = inet_dgram_socket();
1570 if (s == -1) {
1571 _SCErrorSet(errno);
1572 goto done;
1573 }
1574
1575 callbacks = kCFTypeArrayCallBacks;
1576 callbacks.equal = __VLANInterfaceEquiv;
1577 vlans = CFArrayCreateMutable(NULL, 0, &callbacks);
1578
1579 for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) {
1580 switch (ifp->ifa_addr->sa_family) {
1581 case AF_LINK : {
1582 CFStringRef device;
1583 struct if_data *if_data;
1584 struct ifreq ifr;
1585 CFNumberRef tag;
1586 VLANInterfaceRef vlan;
1587 CFStringRef vlan_if;
1588 char vlr_parent[IFNAMSIZ + 1];
1589 int vlr_tag;
1590 struct vlanreq vreq;
1591
1592 if_data = (struct if_data *)ifp->ifa_data;
1593 if (if_data == NULL) {
1594 break; // if no interface data
1595 }
1596
1597 if (if_data->ifi_type != IFT_L2VLAN) {
1598 break; // if not VLAN
1599 }
1600
1601 bzero(&ifr, sizeof(ifr));
1602 bzero(&vreq, sizeof(vreq));
1603 strncpy(ifr.ifr_name, ifp->ifa_name, sizeof(ifr.ifr_name));
1604 ifr.ifr_data = (caddr_t)&vreq;
1605
1606 if (ioctl(s, SIOCGIFVLAN, (caddr_t)&ifr) == -1) {
1607 SCLog(TRUE, LOG_ERR, CFSTR("ioctl() failed: %s"), strerror(errno));
1608 CFRelease(vlans);
1609 vlans = NULL;
1610 _SCErrorSet(kSCStatusFailed);
1611 goto done;
1612 }
1613 vlr_tag = vreq.vlr_tag;
1614 bzero(&vlr_parent, sizeof(vlr_parent));
1615 bcopy(vreq.vlr_parent, vlr_parent, IFNAMSIZ);
1616
1617 vlan_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
1618 device = CFStringCreateWithCString(NULL, vlr_parent, kCFStringEncodingASCII);
1619 tag = CFNumberCreate(NULL, kCFNumberIntType, &vlr_tag);
1620 vlan = __VLANInterfaceCreatePrivate(NULL, vlan_if, device, tag, NULL);
1621 CFArrayAppendValue(vlans, vlan);
1622 CFRelease(vlan_if);
1623 CFRelease(device);
1624 CFRelease(tag);
1625 CFRelease(vlan);
1626 break;
1627 }
1628
1629 default :
1630 break;
1631 }
1632 }
1633
1634 done :
1635
1636 (void) close(s);
1637 freeifaddrs(ifap);
1638 return vlans;
1639 }
1640
1641
1642 static CFIndex
1643 findVLAN(CFArrayRef vlans, CFStringRef device, CFNumberRef tag)
1644 {
1645 CFIndex found = kCFNotFound;
1646 CFIndex i;
1647 CFIndex n;
1648
1649 n = isA_CFArray(vlans) ? CFArrayGetCount(vlans) : 0;
1650 for (i = 0; i < n; i++) {
1651 CFDictionaryRef vlan_dict;
1652 CFStringRef vlan_device;
1653 CFStringRef vlan_if;
1654 CFNumberRef vlan_tag;
1655
1656 vlan_dict = CFArrayGetValueAtIndex(vlans, i);
1657 if (!isA_CFDictionary(vlan_dict)) {
1658 continue; // if the prefs are confused
1659 }
1660
1661 vlan_if = CFDictionaryGetValue(vlan_dict, __kVLANInterface_interface);
1662 if (!isA_CFString(vlan_if)) {
1663 continue; // if the prefs are confused
1664 }
1665
1666 vlan_device = CFDictionaryGetValue(vlan_dict, __kVLANInterface_device);
1667 if (isA_CFString(vlan_device)) {
1668 if (!CFEqual(device, vlan_device)) {
1669 continue; // if not a match
1670 }
1671 }
1672
1673 vlan_tag = CFDictionaryGetValue(vlan_dict, __kVLANInterface_tag);
1674 if (isA_CFNumber(vlan_tag)) {
1675 if (!CFEqual(tag, vlan_tag)) {
1676 continue; // if not a match
1677 }
1678 }
1679
1680 // if we have found a match
1681 found = i;
1682 break;
1683 }
1684
1685 return found;
1686 }
1687
1688
1689 static void
1690 setConfigurationChanged(VLANPreferencesRef prefs)
1691 {
1692 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
1693
1694 /*
1695 * to facilitate device configuration we will take
1696 * a snapshot of the VLAN preferences before any
1697 * changes are made. Then, when the changes are
1698 * applied we can compare what we had to what we
1699 * want and configured the system accordingly.
1700 */
1701 if (prefsPrivate->vlBase == NULL) {
1702 prefsPrivate->vlBase = VLANPreferencesCopyInterfaces(prefs);
1703 }
1704
1705 return;
1706 }
1707
1708
1709 CFTypeID
1710 VLANPreferencesGetTypeID(void)
1711 {
1712 pthread_once(&vlanPreferences_init, __VLANPreferencesInitialize); /* initialize runtime */
1713 return __kVLANPreferencesTypeID;
1714 }
1715
1716
1717 VLANPreferencesRef
1718 VLANPreferencesCreate(CFAllocatorRef allocator)
1719 {
1720 CFBundleRef bundle;
1721 CFStringRef bundleID = NULL;
1722 CFStringRef name = CFSTR("VLANConfiguration");
1723 VLANPreferencesPrivateRef prefsPrivate;
1724 uint32_t size;
1725
1726 /* initialize runtime */
1727 pthread_once(&vlanPreferences_init, __VLANPreferencesInitialize);
1728
1729 /* allocate preferences */
1730 size = sizeof(VLANPreferencesPrivate) - sizeof(CFRuntimeBase);
1731 prefsPrivate = (VLANPreferencesPrivateRef)_CFRuntimeCreateInstance(allocator,
1732 __kVLANPreferencesTypeID,
1733 size,
1734 NULL);
1735 if (prefsPrivate == NULL) {
1736 return NULL;
1737 }
1738
1739 /* establish the prefs */
1740
1741 pthread_mutex_init(&prefsPrivate->lock, NULL);
1742
1743 bundle = CFBundleGetMainBundle();
1744 if (bundle) {
1745 bundleID = CFBundleGetIdentifier(bundle);
1746 if (bundleID) {
1747 CFRetain(bundleID);
1748 } else {
1749 CFURLRef url;
1750
1751 url = CFBundleCopyExecutableURL(bundle);
1752 if (url) {
1753 bundleID = CFURLCopyPath(url);
1754 CFRelease(url);
1755 }
1756 }
1757 }
1758
1759 if (bundleID) {
1760 CFStringRef fullName;
1761
1762 if (CFEqual(bundleID, CFSTR("/"))) {
1763 CFRelease(bundleID);
1764 bundleID = CFStringCreateWithFormat(allocator, NULL, CFSTR("(%d)"), getpid());
1765 }
1766
1767 fullName = CFStringCreateWithFormat(allocator, NULL, CFSTR("%@:%@"), bundleID, name);
1768 name = fullName;
1769 CFRelease(bundleID);
1770 } else {
1771 CFRetain(name);
1772 }
1773
1774 prefsPrivate->prefs = SCPreferencesCreate(allocator, name, VLAN_PREFERENCES_ID);
1775 CFRelease(name);
1776
1777 prefsPrivate->vlBase = NULL;
1778
1779 return (VLANPreferencesRef)prefsPrivate;
1780 }
1781
1782
1783 CFArrayRef
1784 VLANPreferencesCopyInterfaces(VLANPreferencesRef prefs)
1785 {
1786 CFAllocatorRef allocator;
1787 CFArrayCallBacks callbacks;
1788 CFIndex i;
1789 CFIndex n;
1790 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
1791 CFMutableArrayRef result;
1792 CFArrayRef vlans;
1793
1794 if (!isA_VLANPreferences(prefs)) {
1795 _SCErrorSet(kSCStatusInvalidArgument);
1796 return NULL;
1797 }
1798
1799 allocator = CFGetAllocator(prefs);
1800 callbacks = kCFTypeArrayCallBacks;
1801 callbacks.equal = __VLANInterfaceEquiv;
1802 result = CFArrayCreateMutable(allocator, 0, &callbacks);
1803
1804 vlans = SCPreferencesGetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS);
1805 n = isA_CFArray(vlans) ? CFArrayGetCount(vlans) : 0;
1806 for (i = 0; i < n; i++) {
1807 CFDictionaryRef vlan_dict;
1808 CFStringRef device;
1809 CFDictionaryRef options;
1810 CFNumberRef tag;
1811 VLANInterfaceRef vlan;
1812 CFStringRef vlan_if;
1813
1814 vlan_dict = CFArrayGetValueAtIndex(vlans, i);
1815 if (!isA_CFDictionary(vlan_dict)) {
1816 continue; // if the prefs are confused
1817 }
1818
1819 vlan_if = CFDictionaryGetValue(vlan_dict, __kVLANInterface_interface);
1820 if (!isA_CFString(vlan_if)) {
1821 continue; // if the prefs are confused
1822 }
1823
1824
1825 device = CFDictionaryGetValue(vlan_dict, __kVLANInterface_device);
1826 if (!isA_CFString(device)) {
1827 continue; // if the prefs are confused
1828 }
1829
1830 tag = CFDictionaryGetValue(vlan_dict, __kVLANInterface_tag);
1831 if (!isA_CFNumber(tag)) {
1832 continue; // if the prefs are confused
1833 }
1834
1835 options = CFDictionaryGetValue(vlan_dict, __kVLANInterface_options);
1836 if ((options != NULL) && !isA_CFDictionary(options)) {
1837 continue; // if the prefs are confused
1838 }
1839
1840 vlan = __VLANInterfaceCreatePrivate(allocator, vlan_if, device, tag, options);
1841 CFArrayAppendValue(result, vlan);
1842 CFRelease(vlan);
1843 }
1844
1845 return result;
1846 }
1847
1848
1849 VLANInterfaceRef
1850 VLANPreferencesAddInterface(VLANPreferencesRef prefs,
1851 CFStringRef device,
1852 CFNumberRef tag,
1853 CFDictionaryRef options)
1854 {
1855 CFArrayRef active_vlans;
1856 CFAllocatorRef allocator;
1857 CFArrayRef config_vlans;
1858 CFIndex dup_if;
1859 CFIndex i;
1860 CFIndex nActive;
1861 CFIndex nConfig;
1862 VLANInterfaceRef newVlan = NULL;
1863 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
1864
1865 if (!isA_VLANPreferences(prefs)) {
1866 _SCErrorSet(kSCStatusInvalidArgument);
1867 return NULL;
1868 }
1869
1870 if (!isA_CFString(device)) {
1871 _SCErrorSet(kSCStatusInvalidArgument);
1872 return NULL;
1873 }
1874
1875 if (isA_CFNumber(tag)) {
1876 int tag_val;
1877
1878 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
1879 if ((tag_val < 1) || (tag_val > 4094)) {
1880 _SCErrorSet(kSCStatusInvalidArgument);
1881 return NULL;
1882 }
1883 } else {
1884 _SCErrorSet(kSCStatusInvalidArgument);
1885 return NULL;
1886 }
1887
1888 if ((options != NULL) && !isA_CFDictionary(options)) {
1889 _SCErrorSet(kSCStatusInvalidArgument);
1890 return NULL;
1891 }
1892
1893 pthread_mutex_lock(&prefsPrivate->lock);
1894
1895 /* get "configured" VLANs (and check to ensure we are not creating a duplicate) */
1896 config_vlans = SCPreferencesGetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS);
1897 nConfig = isA_CFArray(config_vlans) ? CFArrayGetCount(config_vlans) : 0;
1898
1899 dup_if = findVLAN(config_vlans, device, tag);
1900 if (dup_if != kCFNotFound) {
1901 // sorry, you can't add a vlan using the same device/tag */
1902 _SCErrorSet(kSCStatusKeyExists);
1903 goto done;
1904 }
1905
1906 /* get "active" VLANs */
1907 active_vlans = _VLANPreferencesCopyActiveInterfaces();
1908 nActive = isA_CFArray(active_vlans) ? CFArrayGetCount(active_vlans) : 0;
1909
1910 /* create a new vlan using an unused interface name */
1911 allocator = CFGetAllocator(prefs);
1912
1913 for (i = 0; newVlan == NULL; i++) {
1914 CFIndex j;
1915 CFMutableDictionaryRef newDict;
1916 CFMutableArrayRef newVlans;
1917 CFStringRef vlan_if;
1918
1919 vlan_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("vlan%d"), i);
1920
1921 for (j = 0; j < nActive; j++) {
1922 CFStringRef active_if;
1923 VLANInterfaceRef active_vlan;
1924
1925 active_vlan = CFArrayGetValueAtIndex(active_vlans, j);
1926 active_if = VLANInterfaceGetInterface(active_vlan);
1927
1928 if (CFEqual(vlan_if, active_if)) {
1929 goto next_if; // if VLAN interface name not available
1930 }
1931 }
1932
1933 for (j = 0; j < nConfig; j++) {
1934 CFDictionaryRef config;
1935 CFStringRef config_if;
1936
1937 config = CFArrayGetValueAtIndex(config_vlans, j);
1938 if (!isA_CFDictionary(config)) {
1939 continue; // if the prefs are confused
1940 }
1941
1942 config_if = CFDictionaryGetValue(config, __kVLANInterface_interface);
1943 if (!isA_CFString(config_if)) {
1944 continue; // if the prefs are confused
1945 }
1946
1947 if (CFEqual(vlan_if, config_if)) {
1948 goto next_if; // if VLAN interface name not available
1949 }
1950 }
1951
1952 /* create the vlan */
1953
1954 newDict = CFDictionaryCreateMutable(allocator,
1955 0,
1956 &kCFTypeDictionaryKeyCallBacks,
1957 &kCFTypeDictionaryValueCallBacks);
1958 CFDictionaryAddValue(newDict, __kVLANInterface_interface, vlan_if);
1959 CFDictionaryAddValue(newDict, __kVLANInterface_device, device);
1960 CFDictionaryAddValue(newDict, __kVLANInterface_tag, tag);
1961 if (options != NULL) {
1962 CFDictionaryAddValue(newDict, __kVLANInterface_options, options);
1963 }
1964
1965 /* create the accessor handle to be returned */
1966
1967 newVlan = __VLANInterfaceCreatePrivate(allocator, vlan_if, device, tag, options);
1968
1969 /* yes, we're going to be changing the configuration */
1970 setConfigurationChanged(prefs);
1971
1972 /* save in the prefs */
1973
1974 if (nConfig == 0) {
1975 newVlans = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
1976 } else {
1977 newVlans = CFArrayCreateMutableCopy(allocator, 0, config_vlans);
1978 }
1979 CFArrayAppendValue(newVlans, newDict);
1980 CFRelease(newDict);
1981
1982 (void) SCPreferencesSetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS, newVlans);
1983 CFRelease(newVlans);
1984
1985 next_if :
1986 CFRelease(vlan_if);
1987 }
1988
1989 CFRelease(active_vlans);
1990
1991 done :
1992
1993 pthread_mutex_unlock(&prefsPrivate->lock);
1994
1995 return (VLANInterfaceRef) newVlan;
1996 }
1997
1998
1999 Boolean
2000 VLANPreferencesUpdateInterface(VLANPreferencesRef prefs,
2001 VLANInterfaceRef vlan,
2002 CFStringRef newDevice,
2003 CFNumberRef newTag,
2004 CFDictionaryRef newOptions)
2005 {
2006 CFAllocatorRef allocator;
2007 CFIndex cur_if;
2008 CFIndex dup_if;
2009 CFMutableDictionaryRef newDict;
2010 CFMutableArrayRef newVlans;
2011 Boolean ok = FALSE;
2012 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
2013 CFArrayRef vlans;
2014 CFStringRef vlan_if;
2015
2016 if (!isA_VLANPreferences(prefs)) {
2017 _SCErrorSet(kSCStatusInvalidArgument);
2018 return FALSE;
2019 }
2020
2021 if (!isA_VLANInterface(vlan)) {
2022 _SCErrorSet(kSCStatusInvalidArgument);
2023 return FALSE;
2024 }
2025
2026 if ((newDevice != NULL) && !isA_CFString(newDevice)) {
2027 _SCErrorSet(kSCStatusInvalidArgument);
2028 return FALSE;
2029 }
2030
2031 if (newTag != NULL) {
2032 if (isA_CFNumber(newTag)) {
2033 int tag_val;
2034
2035 CFNumberGetValue(newTag, kCFNumberIntType, &tag_val);
2036 if ((tag_val < 1) || (tag_val > 4094)) {
2037 _SCErrorSet(kSCStatusInvalidArgument);
2038 return FALSE;
2039 }
2040 } else {
2041 _SCErrorSet(kSCStatusInvalidArgument);
2042 return FALSE;
2043 }
2044 }
2045
2046 if ((newOptions != NULL)
2047 && !isA_CFDictionary(newOptions) && (newOptions != (CFDictionaryRef)kCFNull)) {
2048 _SCErrorSet(kSCStatusInvalidArgument);
2049 return FALSE;
2050 }
2051
2052 pthread_mutex_lock(&prefsPrivate->lock);
2053
2054 vlan_if = VLANInterfaceGetInterface(vlan);
2055
2056 vlans = SCPreferencesGetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS);
2057 if (!isA_CFArray(vlans)) {
2058 goto done; // if the prefs are confused
2059 }
2060
2061 cur_if = findVLAN(vlans,
2062 VLANInterfaceGetDevice(vlan),
2063 VLANInterfaceGetTag (vlan));
2064 if (cur_if == kCFNotFound) {
2065 _SCErrorSet(kSCStatusNoKey);
2066 goto done;
2067 }
2068
2069 dup_if = findVLAN(vlans,
2070 newDevice != NULL ? newDevice : VLANInterfaceGetDevice(vlan),
2071 newTag != NULL ? newTag : VLANInterfaceGetTag (vlan));
2072 if (dup_if != kCFNotFound) {
2073 // if the same device/tag has already been defined
2074 if (cur_if != dup_if) {
2075 /*
2076 * sorry, you can't update another vlan that is using
2077 * the same device/tag
2078 */
2079 _SCErrorSet(kSCStatusKeyExists);
2080 goto done;
2081 }
2082 }
2083
2084 /* update the vlan */
2085
2086 if (newDevice != NULL) {
2087 VLANInterfaceSetDevice(vlan, newDevice);
2088 } else {
2089 newDevice = VLANInterfaceGetDevice(vlan);
2090 }
2091
2092 if (newTag != NULL) {
2093 VLANInterfaceSetTag(vlan, newTag);
2094 } else {
2095 newTag = VLANInterfaceGetTag(vlan);
2096 }
2097
2098 if (newOptions != NULL) {
2099 if (newOptions != (CFDictionaryRef)kCFNull) {
2100 VLANInterfaceSetOptions(vlan, newOptions);
2101 } else {
2102 VLANInterfaceSetOptions(vlan, NULL);
2103 newOptions = NULL;
2104 }
2105 } else {
2106 newOptions = VLANInterfaceGetOptions(vlan);
2107 }
2108
2109 /* update the prefs */
2110
2111 allocator = CFGetAllocator(prefs);
2112 newDict = CFDictionaryCreateMutable(allocator,
2113 0,
2114 &kCFTypeDictionaryKeyCallBacks,
2115 &kCFTypeDictionaryValueCallBacks);
2116 CFDictionaryAddValue(newDict, __kVLANInterface_interface, vlan_if);
2117 CFDictionaryAddValue(newDict, __kVLANInterface_device, newDevice);
2118 CFDictionaryAddValue(newDict, __kVLANInterface_tag, newTag);
2119 if (newOptions != NULL) {
2120 CFDictionaryAddValue(newDict, __kVLANInterface_options, newOptions);
2121 }
2122
2123 /* yes, we're going to be changing the configuration */
2124 setConfigurationChanged(prefs);
2125
2126 /* update the prefs */
2127
2128 newVlans = CFArrayCreateMutableCopy(allocator, 0, vlans);
2129 CFArraySetValueAtIndex(newVlans, cur_if, newDict);
2130 CFRelease(newDict);
2131
2132 (void) SCPreferencesSetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS, newVlans);
2133 CFRelease(newVlans);
2134
2135 ok = TRUE;
2136
2137 done :
2138
2139 pthread_mutex_unlock(&prefsPrivate->lock);
2140
2141 return ok;
2142 }
2143
2144
2145 Boolean
2146 VLANPreferencesRemoveInterface(VLANPreferencesRef prefs,
2147 VLANInterfaceRef vlan)
2148 {
2149 CFAllocatorRef allocator;
2150 CFIndex cur_if;
2151 CFMutableArrayRef newVlans;
2152 Boolean ok = FALSE;
2153 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
2154 CFArrayRef vlans;
2155
2156 if (!isA_VLANPreferences(prefs)) {
2157 _SCErrorSet(kSCStatusInvalidArgument);
2158 return FALSE;
2159 }
2160
2161 if (!isA_VLANInterface(vlan)) {
2162 _SCErrorSet(kSCStatusInvalidArgument);
2163 return FALSE;
2164 }
2165
2166 pthread_mutex_lock(&prefsPrivate->lock);
2167
2168 vlans = SCPreferencesGetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS);
2169 if (!isA_CFArray(vlans)) {
2170 _SCErrorSet(kSCStatusNoKey);
2171 goto done; // if the prefs are confused
2172 }
2173
2174 cur_if = findVLAN(vlans,
2175 VLANInterfaceGetDevice(vlan),
2176 VLANInterfaceGetTag (vlan));
2177 if (cur_if == kCFNotFound) {
2178 _SCErrorSet(kSCStatusNoKey);
2179 goto done;
2180 }
2181
2182 /* yes, we're going to be changing the configuration */
2183 setConfigurationChanged(prefs);
2184
2185 /* remove the vlan */
2186
2187 allocator = CFGetAllocator(prefs);
2188 newVlans = CFArrayCreateMutableCopy(allocator, 0, vlans);
2189 CFArrayRemoveValueAtIndex(newVlans, cur_if);
2190
2191 (void) SCPreferencesSetValue(prefsPrivate->prefs, VLAN_PREFERENCES_VLANS, newVlans);
2192 CFRelease(newVlans);
2193
2194 ok = TRUE;
2195
2196 done :
2197
2198 pthread_mutex_unlock(&prefsPrivate->lock);
2199
2200 return ok;
2201 }
2202
2203
2204 Boolean
2205 VLANPreferencesCommitChanges(VLANPreferencesRef prefs)
2206 {
2207 Boolean ok = FALSE;
2208 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
2209
2210 if (!isA_VLANPreferences(prefs)) {
2211 _SCErrorSet(kSCStatusInvalidArgument);
2212 return FALSE;
2213 }
2214
2215 ok = SCPreferencesCommitChanges(prefsPrivate->prefs);
2216 if (!ok) {
2217 return ok;
2218 }
2219
2220 if (prefsPrivate->vlBase != NULL) {
2221 CFRelease(prefsPrivate->vlBase);
2222 prefsPrivate->vlBase = NULL;
2223 }
2224
2225 return TRUE;
2226 }
2227
2228
2229 Boolean
2230 _VLANPreferencesUpdateConfiguration(VLANPreferencesRef prefs)
2231 {
2232 return TRUE;
2233 }
2234
2235
2236 Boolean
2237 VLANPreferencesApplyChanges(VLANPreferencesRef prefs)
2238 {
2239 SCPreferencesRef defaultPrefs;
2240 Boolean ok = FALSE;
2241 VLANPreferencesPrivateRef prefsPrivate = (VLANPreferencesPrivateRef)prefs;
2242
2243 if (!isA_VLANPreferences(prefs)) {
2244 _SCErrorSet(kSCStatusInvalidArgument);
2245 return FALSE;
2246 }
2247
2248 pthread_mutex_lock(&prefsPrivate->lock);
2249
2250 /* apply the preferences */
2251 ok = SCPreferencesApplyChanges(prefsPrivate->prefs);
2252 if (!ok) {
2253 goto done;
2254 }
2255
2256 /* apply the VLAN configuration */
2257 defaultPrefs = SCPreferencesCreate(NULL, CFSTR("VLANPreferencesApplyChanges"), NULL);
2258 {
2259 /*
2260 * Note: In an ideal world, we'd simply call SCPreferencesApplyChanges()
2261 * Unfortunately, it's possible that the caller (e.g NetworkCfgTool)
2262 * is holding the lock on the default prefs and since "Apply" attempts
2263 * to grab the lock we could end up in a deadlock situation.
2264 */
2265 #include "SCPreferencesInternal.h"
2266 SCPreferencesPrivateRef defaultPrefsPrivate;
2267
2268 defaultPrefsPrivate = (SCPreferencesPrivateRef)defaultPrefs;
2269
2270 pthread_mutex_lock(&defaultPrefsPrivate->lock);
2271 if (defaultPrefsPrivate->session == NULL) {
2272 __SCPreferencesAddSession(defaultPrefs);
2273 }
2274 pthread_mutex_unlock(&defaultPrefsPrivate->lock);
2275
2276 ok = SCDynamicStoreNotifyValue(defaultPrefsPrivate->session, defaultPrefsPrivate->sessionKeyApply);
2277 }
2278 CFRelease(defaultPrefs);
2279 if (!ok) {
2280 goto done;
2281 }
2282
2283 done :
2284
2285 pthread_mutex_unlock(&prefsPrivate->lock);
2286
2287 return ok;
2288 }