]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/VLANConfiguration.c
configd-453.19.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / VLANConfiguration.c
1 /*
2 * Copyright (c) 2003-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * November 28, 2005 Allan Nathanson <ajn@apple.com>
28 * - public API
29 *
30 * 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 /* ---------- VLAN support ---------- */
58
59 static int
60 inet_dgram_socket()
61 {
62 int s;
63
64 s = socket(AF_INET, SOCK_DGRAM, 0);
65 if (s == -1) {
66 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
67 }
68
69 return s;
70 }
71
72
73 typedef struct {
74 CFMutableArrayRef vlans;
75 SCPreferencesRef prefs;
76 } addContext, *addContextRef;
77
78
79 static void
80 add_configured_interface(const void *key, const void *value, void *context)
81 {
82 SCNetworkInterfacePrivateRef interfacePrivate;
83 addContextRef myContext = (addContextRef)context;
84 SCVLANInterfaceRef vlan;
85 CFStringRef vlan_if = (CFStringRef)key;
86 CFDictionaryRef vlan_info = (CFDictionaryRef)value;
87 CFStringRef vlan_name;
88 CFDictionaryRef vlan_options;
89 SCNetworkInterfaceRef vlan_physical;
90 CFStringRef vlan_physical_if;
91 CFNumberRef vlan_tag;
92
93 vlan_physical_if = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANInterface);
94 if (!isA_CFString(vlan_physical_if)) {
95 // if prefs are confused
96 return;
97 }
98
99 vlan_tag = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANTag);
100 if (!isA_CFNumber(vlan_tag)) {
101 // if prefs are confused
102 return;
103 }
104
105 // create the VLAN interface
106 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(NULL, vlan_if);
107
108 // set physical interface and tag
109 vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if,
110 kIncludeBondInterfaces);
111 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag);
112 CFRelease(vlan_physical);
113
114 // set display name
115 vlan_name = CFDictionaryGetValue(vlan_info, kSCPropUserDefinedName);
116 if (isA_CFString(vlan_name)) {
117 SCVLANInterfaceSetLocalizedDisplayName(vlan, vlan_name);
118 }
119
120 // set options
121 vlan_options = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANOptions);
122 if (isA_CFDictionary(vlan_options)) {
123 SCVLANInterfaceSetOptions(vlan, vlan_options);
124 }
125
126 // estabish link to the stored configuration
127 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
128 interfacePrivate->prefs = CFRetain(myContext->prefs);
129
130 CFArrayAppendValue(myContext->vlans, vlan);
131 CFRelease(vlan);
132
133 return;
134 }
135
136
137 static void
138 add_legacy_configuration(addContextRef myContext)
139 {
140 CFIndex i;
141 CFIndex n;
142 SCPreferencesRef prefs;
143 CFArrayRef vlans;
144
145 #define VLAN_PREFERENCES_ID CFSTR("VirtualNetworkInterfaces.plist")
146 #define VLAN_PREFERENCES_VLANS CFSTR("VLANs")
147 #define __kVLANInterface_interface CFSTR("interface") // e.g. vlan0, vlan1, ...
148 #define __kVLANInterface_device CFSTR("device") // e.g. en0, en1, ...
149 #define __kVLANInterface_tag CFSTR("tag") // e.g. 1 <= tag <= 4094
150 #define __kVLANInterface_options CFSTR("options") // e.g. UserDefinedName
151
152 prefs = SCPreferencesCreate(NULL, CFSTR("SCVLANInterfaceCopyAll"), VLAN_PREFERENCES_ID);
153 if (prefs == NULL) {
154 return;
155 }
156
157 vlans = SCPreferencesGetValue(prefs, VLAN_PREFERENCES_VLANS);
158 if ((vlans != NULL) && !isA_CFArray(vlans)) {
159 CFRelease(prefs); // if the prefs are confused
160 return;
161 }
162
163 n = (vlans != NULL) ? CFArrayGetCount(vlans) : 0;
164 for (i = 0; i < n; i++) {
165 CFDictionaryRef dict;
166 SCNetworkInterfacePrivateRef interfacePrivate;
167 Boolean ok;
168 CFDictionaryRef options;
169 CFStringRef path;
170 SCVLANInterfaceRef vlan;
171 CFStringRef vlan_if;
172 CFDictionaryRef vlan_dict;
173 SCNetworkInterfaceRef vlan_physical;
174 CFStringRef vlan_physical_if;
175 CFNumberRef vlan_tag;
176
177 vlan_dict = CFArrayGetValueAtIndex(vlans, i);
178 if (!isA_CFDictionary(vlan_dict)) {
179 continue; // if the prefs are confused
180 }
181
182 vlan_if = CFDictionaryGetValue(vlan_dict, __kVLANInterface_interface);
183 if (!isA_CFString(vlan_if)) {
184 continue; // if the prefs are confused
185 }
186
187 vlan_physical_if = CFDictionaryGetValue(vlan_dict, __kVLANInterface_device);
188 if (!isA_CFString(vlan_physical_if)) {
189 continue; // if the prefs are confused
190 }
191
192 vlan_tag = CFDictionaryGetValue(vlan_dict, __kVLANInterface_tag);
193 if (!isA_CFNumber(vlan_tag)) {
194 continue; // if the prefs are confused
195 }
196
197 // check if this VLAN interface has already been allocated
198 path = CFStringCreateWithFormat(NULL,
199 NULL,
200 CFSTR("/%@/%@/%@"),
201 kSCPrefVirtualNetworkInterfaces,
202 kSCNetworkInterfaceTypeVLAN,
203 vlan_if);
204 dict = SCPreferencesPathGetValue(myContext->prefs, path);
205 if (dict != NULL) {
206 // if VLAN interface name not available
207 CFRelease(path);
208 continue;
209 }
210
211 // add a placeholder for the VLAN in the stored preferences
212 dict = CFDictionaryCreate(NULL,
213 NULL, NULL, 0,
214 &kCFTypeDictionaryKeyCallBacks,
215 &kCFTypeDictionaryValueCallBacks);
216 ok = SCPreferencesPathSetValue(myContext->prefs, path, dict);
217 CFRelease(dict);
218 CFRelease(path);
219 if (!ok) {
220 // if the VLAN could not be saved
221 continue;
222 }
223
224 // create the VLAN interface
225 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(NULL, vlan_if);
226
227 // estabish link to the stored configuration
228 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
229 interfacePrivate->prefs = CFRetain(myContext->prefs);
230
231 // set the interface and tag (which updates the stored preferences)
232 vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if,
233 kIncludeBondInterfaces);
234 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag);
235 CFRelease(vlan_physical);
236
237 // set display name (which updates the stored preferences)
238 options = CFDictionaryGetValue(vlan_dict, __kVLANInterface_options);
239 if (isA_CFDictionary(options)) {
240 CFStringRef vlan_name;
241
242 vlan_name = CFDictionaryGetValue(options, CFSTR("VLAN Name"));
243 if (isA_CFString(vlan_name)) {
244 SCVLANInterfaceSetLocalizedDisplayName(vlan, vlan_name);
245 }
246 }
247
248 CFArrayAppendValue(myContext->vlans, vlan);
249 CFRelease(vlan);
250 }
251
252 CFRelease(prefs);
253 return;
254 }
255
256
257 static SCVLANInterfaceRef
258 findVLANInterfaceAndTag(SCPreferencesRef prefs, SCNetworkInterfaceRef physical, CFNumberRef tag)
259 {
260 CFIndex i;
261 CFIndex n;
262 SCVLANInterfaceRef vlan = NULL;
263 CFArrayRef vlans;
264
265 vlans = SCVLANInterfaceCopyAll(prefs);
266
267 n = CFArrayGetCount(vlans);
268 for (i = 0; i < n; i++) {
269 SCVLANInterfaceRef config_vlan;
270 SCNetworkInterfaceRef config_physical;
271 CFNumberRef config_tag;
272
273 config_vlan = CFArrayGetValueAtIndex(vlans, i);
274 config_physical = SCVLANInterfaceGetPhysicalInterface(config_vlan);
275 config_tag = SCVLANInterfaceGetTag(config_vlan);
276
277 if ((config_physical != NULL) && (config_tag != NULL)) {
278 if (!CFEqual(physical, config_physical)) {
279 // if this VLAN has a different physical interface
280 continue;
281 }
282
283 if (!CFEqual(tag, config_tag)) {
284 // if this VLAN has a different tag
285 continue;
286 }
287
288 vlan = CFRetain(config_vlan);
289 break;
290 }
291 }
292 CFRelease(vlans);
293
294 return vlan;
295 }
296
297
298 #pragma mark -
299 #pragma mark SCVLANInterface APIs
300
301
302 CFArrayRef
303 SCVLANInterfaceCopyAll(SCPreferencesRef prefs)
304 {
305 addContext context;
306 CFDictionaryRef dict;
307 CFStringRef path;
308
309 context.vlans = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
310 context.prefs = prefs;
311
312 path = CFStringCreateWithFormat(NULL,
313 NULL,
314 CFSTR("/%@/%@"),
315 kSCPrefVirtualNetworkInterfaces,
316 kSCNetworkInterfaceTypeVLAN);
317 dict = SCPreferencesPathGetValue(prefs, path);
318 if (isA_CFDictionary(dict)) {
319 CFDictionaryApplyFunction(dict, add_configured_interface, &context);
320 } else {
321 // no VLAN configuration, upgrade from legacy configuration
322 dict = CFDictionaryCreate(NULL,
323 NULL, NULL, 0,
324 &kCFTypeDictionaryKeyCallBacks,
325 &kCFTypeDictionaryValueCallBacks);
326 (void) SCPreferencesPathSetValue(prefs, path, dict);
327 CFRelease(dict);
328
329 add_legacy_configuration(&context);
330 }
331 CFRelease(path);
332
333 return context.vlans;
334 }
335
336
337 static void
338 addAvailableInterfaces(CFMutableArrayRef available, CFArrayRef interfaces,
339 CFSetRef excluded)
340 {
341 CFIndex i;
342 CFIndex n;
343
344 n = CFArrayGetCount(interfaces);
345 for (i = 0; i < n; i++) {
346 SCNetworkInterfaceRef interface;
347 SCNetworkInterfacePrivateRef interfacePrivate;
348
349 interface = CFArrayGetValueAtIndex(interfaces, i);
350 interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
351
352 if ((excluded != NULL)
353 && CFSetContainsValue(excluded, interface)) {
354 // exclude this interface
355 continue;
356 }
357 if (interfacePrivate->supportsVLAN) {
358 // if this interface is available
359 CFArrayAppendValue(available, interface);
360 }
361 }
362
363 return;
364 }
365
366
367 CFArrayRef
368 SCVLANInterfaceCopyAvailablePhysicalInterfaces()
369 {
370 CFMutableArrayRef available;
371 CFArrayRef bond_interfaces = NULL;
372 CFArrayRef bridge_interfaces = NULL;
373 CFMutableSetRef excluded = NULL;
374 CFArrayRef interfaces;
375 SCPreferencesRef prefs;
376
377 available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
378
379 prefs = SCPreferencesCreate(NULL, CFSTR("SCVLANInterfaceCopyAvailablePhysicalInterfaces"), NULL);
380 if (prefs != NULL) {
381 #if !TARGET_OS_IPHONE
382 bond_interfaces = SCBondInterfaceCopyAll(prefs);
383 if (bond_interfaces != NULL) {
384 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
385 __SCBondInterfaceListCollectMembers(bond_interfaces, excluded);
386 }
387 #endif // !TARGET_OS_IPHONE
388
389 bridge_interfaces = SCBridgeInterfaceCopyAll(prefs);
390 if (bridge_interfaces != NULL) {
391 if (excluded == NULL) {
392 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
393 }
394 __SCBridgeInterfaceListCollectMembers(bridge_interfaces, excluded);
395 }
396
397 CFRelease(prefs);
398 }
399
400 // add real interfaces that aren't part of a bond or bridge
401 interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface();
402 if (interfaces != NULL) {
403 addAvailableInterfaces(available, interfaces, excluded);
404 CFRelease(interfaces);
405 }
406
407 // add bond interfaces
408 if (bond_interfaces != NULL) {
409 addAvailableInterfaces(available, bond_interfaces, NULL);
410 CFRelease(bond_interfaces);
411 }
412
413 // add bridge interfaces
414 if (bridge_interfaces != NULL) {
415 addAvailableInterfaces(available, bridge_interfaces, NULL);
416 CFRelease(bridge_interfaces);
417 }
418
419 if (excluded != NULL) {
420 CFRelease(excluded);
421 }
422
423 return available;
424 }
425
426
427 CFArrayRef
428 _SCVLANInterfaceCopyActive(void)
429 {
430 struct ifaddrs *ifap;
431 struct ifaddrs *ifp;
432 int s;
433 CFMutableArrayRef vlans = NULL;
434
435 if (getifaddrs(&ifap) == -1) {
436 SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno));
437 _SCErrorSet(kSCStatusFailed);
438 return NULL;
439 }
440
441 s = inet_dgram_socket();
442 if (s == -1) {
443 _SCErrorSet(errno);
444 goto done;
445 }
446
447 vlans = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
448
449 for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) {
450 struct if_data *if_data;
451 struct ifreq ifr;
452 SCVLANInterfaceRef vlan;
453 CFStringRef vlan_if;
454 SCNetworkInterfaceRef vlan_physical;
455 CFStringRef vlan_physical_if;
456 CFNumberRef vlan_tag;
457 char vlr_parent[IFNAMSIZ];
458 int vlr_tag;
459 struct vlanreq vreq;
460
461 if_data = (struct if_data *)ifp->ifa_data;
462 if (if_data == NULL
463 || ifp->ifa_addr->sa_family != AF_LINK
464 || if_data->ifi_type != IFT_L2VLAN) {
465 continue;
466 }
467
468 bzero(&ifr, sizeof(ifr));
469 bzero(&vreq, sizeof(vreq));
470 strlcpy(ifr.ifr_name, ifp->ifa_name, sizeof(ifr.ifr_name));
471 ifr.ifr_data = (caddr_t)&vreq;
472
473 if (ioctl(s, SIOCGIFVLAN, (caddr_t)&ifr) == -1) {
474 SCLog(TRUE, LOG_ERR, CFSTR("ioctl() failed: %s"), strerror(errno));
475 CFRelease(vlans);
476 vlans = NULL;
477 _SCErrorSet(kSCStatusFailed);
478 goto done;
479 }
480
481 // create the VLAN interface
482 vlan_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
483 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(NULL, vlan_if);
484 CFRelease(vlan_if);
485
486 // set the physical interface and tag
487 strlcpy(vlr_parent, vreq.vlr_parent, sizeof(vlr_parent));
488 vlan_physical_if = CFStringCreateWithCString(NULL, vlr_parent, kCFStringEncodingASCII);
489 vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if,
490 kIncludeBondInterfaces);
491 CFRelease(vlan_physical_if);
492
493 vlr_tag = vreq.vlr_tag;
494 vlan_tag = CFNumberCreate(NULL, kCFNumberIntType, &vlr_tag);
495
496 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag);
497 CFRelease(vlan_physical);
498 CFRelease(vlan_tag);
499
500 // add VLAN
501 CFArrayAppendValue(vlans, vlan);
502 CFRelease(vlan);
503 }
504
505 done :
506
507 (void) close(s);
508 freeifaddrs(ifap);
509 return vlans;
510 }
511
512
513 SCVLANInterfaceRef
514 SCVLANInterfaceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef physical, CFNumberRef tag)
515 {
516 CFAllocatorRef allocator;
517 CFIndex i;
518 SCNetworkInterfacePrivateRef interfacePrivate;
519 SCVLANInterfaceRef vlan;
520
521 if (prefs == NULL) {
522 _SCErrorSet(kSCStatusInvalidArgument);
523 return NULL;
524 }
525
526 if (!isA_SCNetworkInterface(physical)) {
527 _SCErrorSet(kSCStatusInvalidArgument);
528 return NULL;
529 }
530
531 interfacePrivate = (SCNetworkInterfacePrivateRef)physical;
532 if (!interfacePrivate->supportsVLAN) {
533 _SCErrorSet(kSCStatusInvalidArgument);
534 return NULL;
535 }
536
537 if (isA_CFNumber(tag)) {
538 int tag_val;
539
540 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
541 if ((tag_val < 1) || (tag_val > 4094)) {
542 _SCErrorSet(kSCStatusInvalidArgument);
543 return NULL;
544 }
545 } else {
546 _SCErrorSet(kSCStatusInvalidArgument);
547 return NULL;
548 }
549
550 // make sure that physical interface and tag are not used
551 vlan = findVLANInterfaceAndTag(prefs, physical, tag);
552 if (vlan != NULL) {
553 CFRelease(vlan);
554 _SCErrorSet(kSCStatusKeyExists);
555 return NULL;
556 }
557
558 allocator = CFGetAllocator(prefs);
559
560 // create a new VLAN using an unused interface name
561 for (i = 0; vlan == NULL; i++) {
562 CFDictionaryRef dict;
563 CFStringRef vlan_if;
564 Boolean ok;
565 CFStringRef path;
566
567 vlan_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("vlan%d"), i);
568 path = CFStringCreateWithFormat(allocator,
569 NULL,
570 CFSTR("/%@/%@/%@"),
571 kSCPrefVirtualNetworkInterfaces,
572 kSCNetworkInterfaceTypeVLAN,
573 vlan_if);
574 dict = SCPreferencesPathGetValue(prefs, path);
575 if (dict != NULL) {
576 // if VLAN interface name not available
577 CFRelease(path);
578 CFRelease(vlan_if);
579 continue;
580 }
581
582 // add the VLAN to the stored preferences
583 dict = CFDictionaryCreate(allocator,
584 NULL, NULL, 0,
585 &kCFTypeDictionaryKeyCallBacks,
586 &kCFTypeDictionaryValueCallBacks);
587 ok = SCPreferencesPathSetValue(prefs, path, dict);
588 CFRelease(dict);
589 CFRelease(path);
590 if (!ok) {
591 // if the VLAN could not be saved
592 CFRelease(vlan_if);
593 _SCErrorSet(kSCStatusFailed);
594 break;
595 }
596
597 // create the SCVLANInterfaceRef
598 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(allocator, vlan_if);
599 CFRelease(vlan_if);
600
601 // estabish link to the stored configuration
602 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
603 interfacePrivate->prefs = CFRetain(prefs);
604
605 // set physical interface and tag
606 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, physical, tag);
607 }
608
609 return vlan;
610 }
611
612
613 Boolean
614 SCVLANInterfaceRemove(SCVLANInterfaceRef vlan)
615 {
616 CFStringRef vlan_if;
617 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
618 Boolean ok;
619 CFStringRef path;
620
621 if (!isA_SCVLANInterface(vlan)) {
622 _SCErrorSet(kSCStatusInvalidArgument);
623 return FALSE;
624 }
625
626 if (interfacePrivate->prefs == NULL) {
627 _SCErrorSet(kSCStatusInvalidArgument);
628 return FALSE;
629 }
630
631 vlan_if = SCNetworkInterfaceGetBSDName(vlan);
632 path = CFStringCreateWithFormat(NULL,
633 NULL,
634 CFSTR("/%@/%@/%@"),
635 kSCPrefVirtualNetworkInterfaces,
636 kSCNetworkInterfaceTypeVLAN,
637 vlan_if);
638 ok = SCPreferencesPathRemoveValue(interfacePrivate->prefs, path);
639 CFRelease(path);
640
641 return ok;
642 }
643
644
645 SCNetworkInterfaceRef
646 SCVLANInterfaceGetPhysicalInterface(SCVLANInterfaceRef vlan)
647 {
648 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
649
650 if (!isA_SCVLANInterface(vlan)) {
651 _SCErrorSet(kSCStatusInvalidArgument);
652 return NULL;
653 }
654
655 return interfacePrivate->vlan.interface;
656 }
657
658
659 CFNumberRef
660 SCVLANInterfaceGetTag(SCVLANInterfaceRef vlan)
661 {
662 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
663
664 if (!isA_SCVLANInterface(vlan)) {
665 _SCErrorSet(kSCStatusInvalidArgument);
666 return NULL;
667 }
668
669 return interfacePrivate->vlan.tag;
670 }
671
672
673 CFDictionaryRef
674 SCVLANInterfaceGetOptions(SCVLANInterfaceRef vlan)
675 {
676 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
677
678 if (!isA_SCVLANInterface(vlan)) {
679 _SCErrorSet(kSCStatusInvalidArgument);
680 return NULL;
681 }
682
683 return interfacePrivate->vlan.options;
684 }
685
686
687 Boolean
688 SCVLANInterfaceSetPhysicalInterfaceAndTag(SCVLANInterfaceRef vlan, SCNetworkInterfaceRef physical, CFNumberRef tag)
689 {
690 SCNetworkInterfacePrivateRef interfacePrivate;
691 Boolean ok = TRUE;
692
693 if (!isA_SCVLANInterface(vlan)) {
694 _SCErrorSet(kSCStatusInvalidArgument);
695 return FALSE;
696 }
697
698 if (!isA_SCNetworkInterface(physical)) {
699 _SCErrorSet(kSCStatusInvalidArgument);
700 return FALSE;
701 }
702
703 interfacePrivate = (SCNetworkInterfacePrivateRef)physical;
704 if (!interfacePrivate->supportsVLAN) {
705 _SCErrorSet(kSCStatusInvalidArgument);
706 return FALSE;
707 }
708
709 if (isA_CFNumber(tag)) {
710 int tag_val;
711
712 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
713 if ((tag_val < 1) || (tag_val > 4094)) {
714 _SCErrorSet(kSCStatusInvalidArgument);
715 return FALSE;
716 }
717 } else {
718 _SCErrorSet(kSCStatusInvalidArgument);
719 return FALSE;
720 }
721
722 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
723 if (interfacePrivate->prefs != NULL) {
724 SCVLANInterfaceRef config_vlan;
725 CFDictionaryRef dict;
726 CFMutableDictionaryRef newDict;
727 CFStringRef path;
728
729 // make sure that physical interface and tag are not used
730 config_vlan = findVLANInterfaceAndTag(interfacePrivate->prefs, physical, tag);
731 if (config_vlan != NULL) {
732 if (!CFEqual(vlan, config_vlan)) {
733 CFRelease(config_vlan);
734 _SCErrorSet(kSCStatusKeyExists);
735 return FALSE;
736 }
737 CFRelease(config_vlan);
738 }
739
740 // set interface/tag in the stored preferences
741 path = CFStringCreateWithFormat(NULL,
742 NULL,
743 CFSTR("/%@/%@/%@"),
744 kSCPrefVirtualNetworkInterfaces,
745 kSCNetworkInterfaceTypeVLAN,
746 interfacePrivate->entity_device);
747 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
748 if (!isA_CFDictionary(dict)) {
749 // if the prefs are confused
750 CFRelease(path);
751 _SCErrorSet(kSCStatusFailed);
752 return FALSE;
753 }
754
755 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
756 CFDictionarySetValue(newDict,
757 kSCPropVirtualNetworkInterfacesVLANInterface,
758 SCNetworkInterfaceGetBSDName(physical));
759 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANTag, tag);
760 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
761 CFRelease(newDict);
762 CFRelease(path);
763 }
764
765 if (ok) {
766 SCNetworkInterfacePrivateRef newInterface;
767 CFTypeRef save;
768
769 // set physical interface
770 newInterface = __SCNetworkInterfaceCreateCopy(NULL,
771 physical,
772 interfacePrivate->prefs,
773 interfacePrivate->serviceID);
774 save = interfacePrivate->vlan.interface;
775 interfacePrivate->vlan.interface = (SCNetworkInterfaceRef)newInterface;
776 if (save != NULL) CFRelease(save);
777
778 // set tag
779 save = interfacePrivate->vlan.tag;
780 interfacePrivate->vlan.tag = CFRetain(tag);
781 if (save != NULL) CFRelease(save);
782 }
783
784 return ok;
785 }
786
787
788 Boolean
789 SCVLANInterfaceSetLocalizedDisplayName(SCVLANInterfaceRef vlan, CFStringRef newName)
790 {
791 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
792 Boolean ok = TRUE;
793
794 if (!isA_SCVLANInterface(vlan)) {
795 _SCErrorSet(kSCStatusInvalidArgument);
796 return FALSE;
797 }
798
799 if ((newName != NULL) && !isA_CFString(newName)) {
800 _SCErrorSet(kSCStatusInvalidArgument);
801 return FALSE;
802 }
803
804 // set name in the stored preferences
805 if (interfacePrivate->prefs != NULL) {
806 CFDictionaryRef dict;
807 CFMutableDictionaryRef newDict;
808 CFStringRef path;
809
810 path = CFStringCreateWithFormat(NULL,
811 NULL,
812 CFSTR("/%@/%@/%@"),
813 kSCPrefVirtualNetworkInterfaces,
814 kSCNetworkInterfaceTypeVLAN,
815 interfacePrivate->entity_device);
816 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
817 if (!isA_CFDictionary(dict)) {
818 // if the prefs are confused
819 CFRelease(path);
820 _SCErrorSet(kSCStatusFailed);
821 return FALSE;
822 }
823
824 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
825 if (newName != NULL) {
826 CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName);
827 } else {
828 CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName);
829 }
830 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
831 CFRelease(newDict);
832 CFRelease(path);
833 }
834
835 // set name in the SCVLANInterfaceRef
836 if (ok) {
837 if (interfacePrivate->localized_name != NULL) {
838 CFRelease(interfacePrivate->localized_name);
839 interfacePrivate->localized_name = NULL;
840 }
841 if (newName != NULL) {
842 interfacePrivate->localized_name = CFStringCreateCopy(NULL, newName);
843 }
844 }
845
846 return ok;
847 }
848
849
850 Boolean
851 SCVLANInterfaceSetOptions(SCVLANInterfaceRef vlan, CFDictionaryRef newOptions)
852 {
853 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
854 Boolean ok = TRUE;
855
856 if (!isA_SCVLANInterface(vlan)) {
857 _SCErrorSet(kSCStatusInvalidArgument);
858 return FALSE;
859 }
860
861 if ((newOptions != NULL) && !isA_CFDictionary(newOptions)) {
862 _SCErrorSet(kSCStatusInvalidArgument);
863 return FALSE;
864 }
865
866 // set options in the stored preferences
867 if (interfacePrivate->prefs != NULL) {
868 CFDictionaryRef dict;
869 CFMutableDictionaryRef newDict;
870 CFStringRef path;
871
872 path = CFStringCreateWithFormat(NULL,
873 NULL,
874 CFSTR("/%@/%@/%@"),
875 kSCPrefVirtualNetworkInterfaces,
876 kSCNetworkInterfaceTypeVLAN,
877 interfacePrivate->entity_device);
878 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
879 if (!isA_CFDictionary(dict)) {
880 // if the prefs are confused
881 CFRelease(path);
882 _SCErrorSet(kSCStatusFailed);
883 return FALSE;
884 }
885
886 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
887 if (newOptions != NULL) {
888 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANOptions, newOptions);
889 } else {
890 CFDictionaryRemoveValue(newDict, kSCPropVirtualNetworkInterfacesVLANOptions);
891 }
892 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
893 CFRelease(newDict);
894 CFRelease(path);
895 }
896
897 // set options in the SCVLANInterfaceRef
898 if (ok) {
899 if (interfacePrivate->vlan.options != NULL) {
900 CFRelease(interfacePrivate->vlan.options);
901 interfacePrivate->vlan.options = NULL;
902 }
903 if (newOptions != NULL) {
904 interfacePrivate->vlan.options = CFDictionaryCreateCopy(NULL, newOptions);
905 }
906 }
907
908 return ok;
909 }
910
911
912 #pragma mark -
913 #pragma mark SCVLANInterface management
914
915
916 static Boolean
917 __vlan_set(int s, CFStringRef interface_if, CFStringRef physical_if, CFNumberRef tag)
918 {
919 struct ifreq ifr;
920 int tag_val;
921 struct vlanreq vreq;
922
923 bzero(&ifr, sizeof(ifr));
924 bzero(&vreq, sizeof(vreq));
925
926 // interface
927 (void) _SC_cfstring_to_cstring(interface_if,
928 ifr.ifr_name,
929 sizeof(ifr.ifr_name),
930 kCFStringEncodingASCII);
931 ifr.ifr_data = (caddr_t)&vreq;
932
933 // physical interface
934 (void) _SC_cfstring_to_cstring(physical_if,
935 vreq.vlr_parent,
936 sizeof(vreq.vlr_parent),
937 kCFStringEncodingASCII);
938
939 // tag
940 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
941 vreq.vlr_tag = tag_val;
942
943 // update physical interface and tag
944 if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) {
945 SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno));
946 _SCErrorSet(kSCStatusFailed);
947 return FALSE;
948 }
949
950 return TRUE;
951 }
952
953
954 static Boolean
955 __vlan_clear(int s, CFStringRef interface_if)
956 {
957 struct ifreq ifr;
958 struct vlanreq vreq;
959
960 bzero(&ifr, sizeof(ifr));
961 bzero(&vreq, sizeof(vreq));
962
963 // interface
964 (void) _SC_cfstring_to_cstring(interface_if,
965 ifr.ifr_name,
966 sizeof(ifr.ifr_name),
967 kCFStringEncodingASCII);
968 ifr.ifr_data = (caddr_t)&vreq;
969
970 // clear physical interface
971 bzero(&vreq.vlr_parent, sizeof(vreq.vlr_parent));
972
973 // clear tag
974 vreq.vlr_tag = 0;
975
976 // update physical interface and tag
977 if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) {
978 SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno));
979 _SCErrorSet(kSCStatusFailed);
980 return FALSE;
981 }
982
983 return TRUE;
984 }
985
986
987 Boolean
988 _SCVLANInterfaceUpdateConfiguration(SCPreferencesRef prefs)
989 {
990 CFArrayRef active = NULL;
991 CFArrayRef config = NULL;
992 CFMutableDictionaryRef devices = NULL;
993 CFIndex i;
994 CFIndex nActive;
995 CFIndex nConfig;
996 Boolean ok = TRUE;
997 int s = -1;
998
999 if (prefs == NULL) {
1000 _SCErrorSet(kSCStatusInvalidArgument);
1001 return FALSE;
1002 }
1003
1004 /* configured VLANs */
1005 config = SCVLANInterfaceCopyAll(prefs);
1006 nConfig = (config != NULL) ? CFArrayGetCount(config) : 0;
1007
1008 /* physical interfaces */
1009 devices = CFDictionaryCreateMutable(NULL,
1010 0,
1011 &kCFTypeDictionaryKeyCallBacks,
1012 &kCFTypeDictionaryValueCallBacks);
1013
1014 /* active VLANs */
1015 active = _SCVLANInterfaceCopyActive();
1016 nActive = (active != NULL) ? CFArrayGetCount(active) : 0;
1017
1018 /* remove any no-longer-configured VLAN interfaces */
1019 for (i = 0; i < nActive; i++) {
1020 SCVLANInterfaceRef a_vlan;
1021 CFStringRef a_vlan_if;
1022 CFIndex j;
1023 Boolean found = FALSE;
1024
1025 a_vlan = CFArrayGetValueAtIndex(active, i);
1026 a_vlan_if = SCNetworkInterfaceGetBSDName(a_vlan);
1027
1028 for (j = 0; j < nConfig; j++) {
1029 SCVLANInterfaceRef c_vlan;
1030 CFStringRef c_vlan_if;
1031
1032 c_vlan = CFArrayGetValueAtIndex(config, j);
1033 c_vlan_if = SCNetworkInterfaceGetBSDName(c_vlan);
1034
1035 if (CFEqual(a_vlan_if, c_vlan_if)) {
1036 found = TRUE;
1037 break;
1038 }
1039 }
1040
1041 if (!found) {
1042 // remove VLAN interface
1043 if (s == -1) {
1044 s = inet_dgram_socket();
1045 if (s == -1) {
1046 _SCErrorSet(errno);
1047 ok = FALSE;
1048 goto done;
1049 }
1050 }
1051 if (!__destroyInterface(s, a_vlan_if)) {
1052 ok = FALSE;
1053 _SCErrorSet(errno);
1054 }
1055 }
1056 }
1057
1058 /* create (and update) configured VLAN interfaces */
1059 for (i = 0; i < nConfig; i++) {
1060 SCVLANInterfaceRef c_vlan;
1061 CFStringRef c_vlan_if;
1062 SCNetworkInterfaceRef c_vlan_physical;
1063 Boolean found = FALSE;
1064 CFIndex j;
1065 CFBooleanRef supported;
1066
1067 c_vlan = CFArrayGetValueAtIndex(config, i);
1068 c_vlan_if = SCNetworkInterfaceGetBSDName(c_vlan);
1069 c_vlan_physical = SCVLANInterfaceGetPhysicalInterface(c_vlan);
1070
1071 if (c_vlan_physical == NULL) {
1072 continue;
1073 }
1074 // determine if the physical interface supports VLANs
1075 supported = CFDictionaryGetValue(devices, c_vlan_physical);
1076 if (supported == NULL) {
1077 SCNetworkInterfacePrivateRef c_vlan_physicalPrivate = (SCNetworkInterfacePrivateRef)c_vlan_physical;
1078
1079 supported = c_vlan_physicalPrivate->supportsVLAN ? kCFBooleanTrue
1080 : kCFBooleanFalse;
1081 CFDictionaryAddValue(devices, c_vlan_physical, supported);
1082 }
1083
1084 for (j = 0; j < nActive; j++) {
1085 SCVLANInterfaceRef a_vlan;
1086 CFStringRef a_vlan_if;
1087
1088 a_vlan = CFArrayGetValueAtIndex(active, j);
1089 a_vlan_if = SCNetworkInterfaceGetBSDName(a_vlan);
1090
1091 if (CFEqual(c_vlan_if, a_vlan_if)) {
1092 if (!CFEqual(c_vlan, a_vlan)) {
1093 // update VLAN interface
1094 if (s == -1) {
1095 s = inet_dgram_socket();
1096 if (s == -1) {
1097 _SCErrorSet(errno);
1098 ok = FALSE;
1099 goto done;
1100 }
1101 }
1102
1103 if (!CFBooleanGetValue(supported)
1104 || !__vlan_clear(s, c_vlan_if)
1105 || !__vlan_set(s, c_vlan_if,
1106 SCNetworkInterfaceGetBSDName(c_vlan_physical),
1107 SCVLANInterfaceGetTag(c_vlan))) {
1108 // something went wrong, try to blow the VLAN away
1109 if (!CFBooleanGetValue(supported)) {
1110 _SCErrorSet(kSCStatusFailed);
1111 }
1112 (void)__destroyInterface(s, c_vlan_if);
1113 ok = FALSE;
1114 }
1115 }
1116
1117 found = TRUE;
1118 break;
1119 }
1120 }
1121
1122 if (!found && CFBooleanGetValue(supported)) {
1123 // if the physical interface supports VLANs, add new interface
1124 Boolean created;
1125
1126 if (s == -1) {
1127 s = inet_dgram_socket();
1128 if (s == -1) {
1129 _SCErrorSet(errno);
1130 ok = FALSE;
1131 goto done;
1132 }
1133 }
1134
1135 created = __createInterface(s, c_vlan_if);
1136 if (!created
1137 || !__vlan_set(s,
1138 c_vlan_if,
1139 SCNetworkInterfaceGetBSDName(c_vlan_physical),
1140 SCVLANInterfaceGetTag(c_vlan))) {
1141 if (created) {
1142 // something went wrong, try to blow the VLAN away
1143 (void)__destroyInterface(s, c_vlan_if);
1144 } else {
1145 _SCErrorSet(errno);
1146 }
1147 ok = FALSE;
1148 }
1149 }
1150
1151 }
1152
1153 done :
1154
1155 if (active) CFRelease(active);
1156 if (config) CFRelease(config);
1157 if (devices) CFRelease(devices);
1158 if (s != -1) (void) close(s);
1159
1160 return ok;
1161 }