]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/VLANConfiguration.c
configd-395.6.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 bond_interfaces = SCBondInterfaceCopyAll(prefs);
382 if (bond_interfaces != NULL) {
383 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
384 __SCBondInterfaceListCollectMembers(bond_interfaces, excluded);
385 }
386
387 bridge_interfaces = SCBridgeInterfaceCopyAll(prefs);
388 if (bridge_interfaces != NULL) {
389 if (excluded == NULL) {
390 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
391 }
392 __SCBridgeInterfaceListCollectMembers(bridge_interfaces, excluded);
393 }
394
395 CFRelease(prefs);
396 }
397
398 // add real interfaces that aren't part of a bond or bridge
399 interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface();
400 if (interfaces != NULL) {
401 addAvailableInterfaces(available, interfaces, excluded);
402 CFRelease(interfaces);
403 }
404
405 // add bond interfaces
406 if (bond_interfaces != NULL) {
407 addAvailableInterfaces(available, bond_interfaces, NULL);
408 CFRelease(bond_interfaces);
409 }
410
411 // add bridge interfaces
412 if (bridge_interfaces != NULL) {
413 addAvailableInterfaces(available, bridge_interfaces, NULL);
414 CFRelease(bridge_interfaces);
415 }
416
417 if (excluded != NULL) {
418 CFRelease(excluded);
419 }
420
421 return available;
422 }
423
424
425 CFArrayRef
426 _SCVLANInterfaceCopyActive(void)
427 {
428 struct ifaddrs *ifap;
429 struct ifaddrs *ifp;
430 int s;
431 CFMutableArrayRef vlans = NULL;
432
433 if (getifaddrs(&ifap) == -1) {
434 SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno));
435 _SCErrorSet(kSCStatusFailed);
436 return NULL;
437 }
438
439 s = inet_dgram_socket();
440 if (s == -1) {
441 _SCErrorSet(errno);
442 goto done;
443 }
444
445 vlans = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
446
447 for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) {
448 struct if_data *if_data;
449 struct ifreq ifr;
450 SCVLANInterfaceRef vlan;
451 CFStringRef vlan_if;
452 SCNetworkInterfaceRef vlan_physical;
453 CFStringRef vlan_physical_if;
454 CFNumberRef vlan_tag;
455 char vlr_parent[IFNAMSIZ];
456 int vlr_tag;
457 struct vlanreq vreq;
458
459 if_data = (struct if_data *)ifp->ifa_data;
460 if (if_data == NULL
461 || ifp->ifa_addr->sa_family != AF_LINK
462 || if_data->ifi_type != IFT_L2VLAN) {
463 continue;
464 }
465
466 bzero(&ifr, sizeof(ifr));
467 bzero(&vreq, sizeof(vreq));
468 strlcpy(ifr.ifr_name, ifp->ifa_name, sizeof(ifr.ifr_name));
469 ifr.ifr_data = (caddr_t)&vreq;
470
471 if (ioctl(s, SIOCGIFVLAN, (caddr_t)&ifr) == -1) {
472 SCLog(TRUE, LOG_ERR, CFSTR("ioctl() failed: %s"), strerror(errno));
473 CFRelease(vlans);
474 vlans = NULL;
475 _SCErrorSet(kSCStatusFailed);
476 goto done;
477 }
478
479 // create the VLAN interface
480 vlan_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
481 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(NULL, vlan_if);
482 CFRelease(vlan_if);
483
484 // set the physical interface and tag
485 strlcpy(vlr_parent, vreq.vlr_parent, sizeof(vlr_parent));
486 vlan_physical_if = CFStringCreateWithCString(NULL, vlr_parent, kCFStringEncodingASCII);
487 vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if,
488 kIncludeBondInterfaces);
489 CFRelease(vlan_physical_if);
490
491 vlr_tag = vreq.vlr_tag;
492 vlan_tag = CFNumberCreate(NULL, kCFNumberIntType, &vlr_tag);
493
494 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag);
495 CFRelease(vlan_physical);
496 CFRelease(vlan_tag);
497
498 // add VLAN
499 CFArrayAppendValue(vlans, vlan);
500 CFRelease(vlan);
501 }
502
503 done :
504
505 (void) close(s);
506 freeifaddrs(ifap);
507 return vlans;
508 }
509
510
511 SCVLANInterfaceRef
512 SCVLANInterfaceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef physical, CFNumberRef tag)
513 {
514 CFAllocatorRef allocator;
515 CFIndex i;
516 SCNetworkInterfacePrivateRef interfacePrivate;
517 SCVLANInterfaceRef vlan;
518
519 if (prefs == NULL) {
520 _SCErrorSet(kSCStatusInvalidArgument);
521 return NULL;
522 }
523
524 if (!isA_SCNetworkInterface(physical)) {
525 _SCErrorSet(kSCStatusInvalidArgument);
526 return NULL;
527 }
528
529 interfacePrivate = (SCNetworkInterfacePrivateRef)physical;
530 if (!interfacePrivate->supportsVLAN) {
531 _SCErrorSet(kSCStatusInvalidArgument);
532 return NULL;
533 }
534
535 if (isA_CFNumber(tag)) {
536 int tag_val;
537
538 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
539 if ((tag_val < 1) || (tag_val > 4094)) {
540 _SCErrorSet(kSCStatusInvalidArgument);
541 return NULL;
542 }
543 } else {
544 _SCErrorSet(kSCStatusInvalidArgument);
545 return NULL;
546 }
547
548 // make sure that physical interface and tag are not used
549 vlan = findVLANInterfaceAndTag(prefs, physical, tag);
550 if (vlan != NULL) {
551 CFRelease(vlan);
552 _SCErrorSet(kSCStatusKeyExists);
553 return NULL;
554 }
555
556 allocator = CFGetAllocator(prefs);
557
558 // create a new VLAN using an unused interface name
559 for (i = 0; vlan == NULL; i++) {
560 CFDictionaryRef dict;
561 CFStringRef vlan_if;
562 Boolean ok;
563 CFStringRef path;
564
565 vlan_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("vlan%d"), i);
566 path = CFStringCreateWithFormat(allocator,
567 NULL,
568 CFSTR("/%@/%@/%@"),
569 kSCPrefVirtualNetworkInterfaces,
570 kSCNetworkInterfaceTypeVLAN,
571 vlan_if);
572 dict = SCPreferencesPathGetValue(prefs, path);
573 if (dict != NULL) {
574 // if VLAN interface name not available
575 CFRelease(path);
576 CFRelease(vlan_if);
577 continue;
578 }
579
580 // add the VLAN to the stored preferences
581 dict = CFDictionaryCreate(allocator,
582 NULL, NULL, 0,
583 &kCFTypeDictionaryKeyCallBacks,
584 &kCFTypeDictionaryValueCallBacks);
585 ok = SCPreferencesPathSetValue(prefs, path, dict);
586 CFRelease(dict);
587 CFRelease(path);
588 if (!ok) {
589 // if the VLAN could not be saved
590 CFRelease(vlan_if);
591 _SCErrorSet(kSCStatusFailed);
592 break;
593 }
594
595 // create the SCVLANInterfaceRef
596 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(allocator, vlan_if);
597 CFRelease(vlan_if);
598
599 // estabish link to the stored configuration
600 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
601 interfacePrivate->prefs = CFRetain(prefs);
602
603 // set physical interface and tag
604 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, physical, tag);
605 }
606
607 return vlan;
608 }
609
610
611 Boolean
612 SCVLANInterfaceRemove(SCVLANInterfaceRef vlan)
613 {
614 CFStringRef vlan_if;
615 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
616 Boolean ok;
617 CFStringRef path;
618
619 if (!isA_SCVLANInterface(vlan)) {
620 _SCErrorSet(kSCStatusInvalidArgument);
621 return FALSE;
622 }
623
624 if (interfacePrivate->prefs == NULL) {
625 _SCErrorSet(kSCStatusInvalidArgument);
626 return FALSE;
627 }
628
629 vlan_if = SCNetworkInterfaceGetBSDName(vlan);
630 path = CFStringCreateWithFormat(NULL,
631 NULL,
632 CFSTR("/%@/%@/%@"),
633 kSCPrefVirtualNetworkInterfaces,
634 kSCNetworkInterfaceTypeVLAN,
635 vlan_if);
636 ok = SCPreferencesPathRemoveValue(interfacePrivate->prefs, path);
637 CFRelease(path);
638
639 return ok;
640 }
641
642
643 SCNetworkInterfaceRef
644 SCVLANInterfaceGetPhysicalInterface(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.interface;
654 }
655
656
657 CFNumberRef
658 SCVLANInterfaceGetTag(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.tag;
668 }
669
670
671 CFDictionaryRef
672 SCVLANInterfaceGetOptions(SCVLANInterfaceRef vlan)
673 {
674 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
675
676 if (!isA_SCVLANInterface(vlan)) {
677 _SCErrorSet(kSCStatusInvalidArgument);
678 return NULL;
679 }
680
681 return interfacePrivate->vlan.options;
682 }
683
684
685 Boolean
686 SCVLANInterfaceSetPhysicalInterfaceAndTag(SCVLANInterfaceRef vlan, SCNetworkInterfaceRef physical, CFNumberRef tag)
687 {
688 SCNetworkInterfacePrivateRef interfacePrivate;
689 Boolean ok = TRUE;
690
691 if (!isA_SCVLANInterface(vlan)) {
692 _SCErrorSet(kSCStatusInvalidArgument);
693 return FALSE;
694 }
695
696 if (!isA_SCNetworkInterface(physical)) {
697 _SCErrorSet(kSCStatusInvalidArgument);
698 return FALSE;
699 }
700
701 interfacePrivate = (SCNetworkInterfacePrivateRef)physical;
702 if (!interfacePrivate->supportsVLAN) {
703 _SCErrorSet(kSCStatusInvalidArgument);
704 return FALSE;
705 }
706
707 if (isA_CFNumber(tag)) {
708 int tag_val;
709
710 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
711 if ((tag_val < 1) || (tag_val > 4094)) {
712 _SCErrorSet(kSCStatusInvalidArgument);
713 return FALSE;
714 }
715 } else {
716 _SCErrorSet(kSCStatusInvalidArgument);
717 return FALSE;
718 }
719
720 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
721 if (interfacePrivate->prefs != NULL) {
722 SCVLANInterfaceRef config_vlan;
723 CFDictionaryRef dict;
724 CFMutableDictionaryRef newDict;
725 CFStringRef path;
726
727 // make sure that physical interface and tag are not used
728 config_vlan = findVLANInterfaceAndTag(interfacePrivate->prefs, physical, tag);
729 if (config_vlan != NULL) {
730 if (!CFEqual(vlan, config_vlan)) {
731 CFRelease(config_vlan);
732 _SCErrorSet(kSCStatusKeyExists);
733 return FALSE;
734 }
735 CFRelease(config_vlan);
736 }
737
738 // set interface/tag in the stored preferences
739 path = CFStringCreateWithFormat(NULL,
740 NULL,
741 CFSTR("/%@/%@/%@"),
742 kSCPrefVirtualNetworkInterfaces,
743 kSCNetworkInterfaceTypeVLAN,
744 interfacePrivate->entity_device);
745 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
746 if (!isA_CFDictionary(dict)) {
747 // if the prefs are confused
748 CFRelease(path);
749 _SCErrorSet(kSCStatusFailed);
750 return FALSE;
751 }
752
753 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
754 CFDictionarySetValue(newDict,
755 kSCPropVirtualNetworkInterfacesVLANInterface,
756 SCNetworkInterfaceGetBSDName(physical));
757 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANTag, tag);
758 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
759 CFRelease(newDict);
760 CFRelease(path);
761 }
762
763 if (ok) {
764 SCNetworkInterfacePrivateRef newInterface;
765 CFTypeRef save;
766
767 // set physical interface
768 newInterface = __SCNetworkInterfaceCreateCopy(NULL,
769 physical,
770 interfacePrivate->prefs,
771 interfacePrivate->serviceID);
772 save = interfacePrivate->vlan.interface;
773 interfacePrivate->vlan.interface = (SCNetworkInterfaceRef)newInterface;
774 if (save != NULL) CFRelease(save);
775
776 // set tag
777 save = interfacePrivate->vlan.tag;
778 interfacePrivate->vlan.tag = CFRetain(tag);
779 if (save != NULL) CFRelease(save);
780 }
781
782 return ok;
783 }
784
785
786 Boolean
787 SCVLANInterfaceSetLocalizedDisplayName(SCVLANInterfaceRef vlan, CFStringRef newName)
788 {
789 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
790 Boolean ok = TRUE;
791
792 if (!isA_SCVLANInterface(vlan)) {
793 _SCErrorSet(kSCStatusInvalidArgument);
794 return FALSE;
795 }
796
797 if ((newName != NULL) && !isA_CFString(newName)) {
798 _SCErrorSet(kSCStatusInvalidArgument);
799 return FALSE;
800 }
801
802 // set name in the stored preferences
803 if (interfacePrivate->prefs != NULL) {
804 CFDictionaryRef dict;
805 CFMutableDictionaryRef newDict;
806 CFStringRef path;
807
808 path = CFStringCreateWithFormat(NULL,
809 NULL,
810 CFSTR("/%@/%@/%@"),
811 kSCPrefVirtualNetworkInterfaces,
812 kSCNetworkInterfaceTypeVLAN,
813 interfacePrivate->entity_device);
814 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
815 if (!isA_CFDictionary(dict)) {
816 // if the prefs are confused
817 CFRelease(path);
818 _SCErrorSet(kSCStatusFailed);
819 return FALSE;
820 }
821
822 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
823 if (newName != NULL) {
824 CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName);
825 } else {
826 CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName);
827 }
828 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
829 CFRelease(newDict);
830 CFRelease(path);
831 }
832
833 // set name in the SCVLANInterfaceRef
834 if (ok) {
835 if (interfacePrivate->localized_name != NULL) {
836 CFRelease(interfacePrivate->localized_name);
837 interfacePrivate->localized_name = NULL;
838 }
839 if (newName != NULL) {
840 interfacePrivate->localized_name = CFStringCreateCopy(NULL, newName);
841 }
842 }
843
844 return ok;
845 }
846
847
848 Boolean
849 SCVLANInterfaceSetOptions(SCVLANInterfaceRef vlan, CFDictionaryRef newOptions)
850 {
851 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
852 Boolean ok = TRUE;
853
854 if (!isA_SCVLANInterface(vlan)) {
855 _SCErrorSet(kSCStatusInvalidArgument);
856 return FALSE;
857 }
858
859 if ((newOptions != NULL) && !isA_CFDictionary(newOptions)) {
860 _SCErrorSet(kSCStatusInvalidArgument);
861 return FALSE;
862 }
863
864 // set options in the stored preferences
865 if (interfacePrivate->prefs != NULL) {
866 CFDictionaryRef dict;
867 CFMutableDictionaryRef newDict;
868 CFStringRef path;
869
870 path = CFStringCreateWithFormat(NULL,
871 NULL,
872 CFSTR("/%@/%@/%@"),
873 kSCPrefVirtualNetworkInterfaces,
874 kSCNetworkInterfaceTypeVLAN,
875 interfacePrivate->entity_device);
876 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
877 if (!isA_CFDictionary(dict)) {
878 // if the prefs are confused
879 CFRelease(path);
880 _SCErrorSet(kSCStatusFailed);
881 return FALSE;
882 }
883
884 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
885 if (newOptions != NULL) {
886 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANOptions, newOptions);
887 } else {
888 CFDictionaryRemoveValue(newDict, kSCPropVirtualNetworkInterfacesVLANOptions);
889 }
890 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
891 CFRelease(newDict);
892 CFRelease(path);
893 }
894
895 // set options in the SCVLANInterfaceRef
896 if (ok) {
897 if (interfacePrivate->vlan.options != NULL) {
898 CFRelease(interfacePrivate->vlan.options);
899 interfacePrivate->vlan.options = NULL;
900 }
901 if (newOptions != NULL) {
902 interfacePrivate->vlan.options = CFDictionaryCreateCopy(NULL, newOptions);
903 }
904 }
905
906 return ok;
907 }
908
909
910 #pragma mark -
911 #pragma mark SCVLANInterface management
912
913
914 static Boolean
915 __vlan_set(int s, CFStringRef interface_if, CFStringRef physical_if, CFNumberRef tag)
916 {
917 struct ifreq ifr;
918 int tag_val;
919 struct vlanreq vreq;
920
921 bzero(&ifr, sizeof(ifr));
922 bzero(&vreq, sizeof(vreq));
923
924 // interface
925 (void) _SC_cfstring_to_cstring(interface_if,
926 ifr.ifr_name,
927 sizeof(ifr.ifr_name),
928 kCFStringEncodingASCII);
929 ifr.ifr_data = (caddr_t)&vreq;
930
931 // physical interface
932 (void) _SC_cfstring_to_cstring(physical_if,
933 vreq.vlr_parent,
934 sizeof(vreq.vlr_parent),
935 kCFStringEncodingASCII);
936
937 // tag
938 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
939 vreq.vlr_tag = tag_val;
940
941 // update physical interface and tag
942 if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) {
943 SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno));
944 _SCErrorSet(kSCStatusFailed);
945 return FALSE;
946 }
947
948 return TRUE;
949 }
950
951
952 static Boolean
953 __vlan_clear(int s, CFStringRef interface_if)
954 {
955 struct ifreq ifr;
956 struct vlanreq vreq;
957
958 bzero(&ifr, sizeof(ifr));
959 bzero(&vreq, sizeof(vreq));
960
961 // interface
962 (void) _SC_cfstring_to_cstring(interface_if,
963 ifr.ifr_name,
964 sizeof(ifr.ifr_name),
965 kCFStringEncodingASCII);
966 ifr.ifr_data = (caddr_t)&vreq;
967
968 // clear physical interface
969 bzero(&vreq.vlr_parent, sizeof(vreq.vlr_parent));
970
971 // clear tag
972 vreq.vlr_tag = 0;
973
974 // update physical interface and tag
975 if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) {
976 SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno));
977 _SCErrorSet(kSCStatusFailed);
978 return FALSE;
979 }
980
981 return TRUE;
982 }
983
984
985 Boolean
986 _SCVLANInterfaceUpdateConfiguration(SCPreferencesRef prefs)
987 {
988 CFArrayRef active = NULL;
989 CFArrayRef config = NULL;
990 CFMutableDictionaryRef devices = NULL;
991 CFIndex i;
992 CFIndex nActive;
993 CFIndex nConfig;
994 Boolean ok = TRUE;
995 int s = -1;
996
997 if (prefs == NULL) {
998 _SCErrorSet(kSCStatusInvalidArgument);
999 return FALSE;
1000 }
1001
1002 /* configured VLANs */
1003 config = SCVLANInterfaceCopyAll(prefs);
1004 nConfig = (config != NULL) ? CFArrayGetCount(config) : 0;
1005
1006 /* physical interfaces */
1007 devices = CFDictionaryCreateMutable(NULL,
1008 0,
1009 &kCFTypeDictionaryKeyCallBacks,
1010 &kCFTypeDictionaryValueCallBacks);
1011
1012 /* active VLANs */
1013 active = _SCVLANInterfaceCopyActive();
1014 nActive = (active != NULL) ? CFArrayGetCount(active) : 0;
1015
1016 /* remove any no-longer-configured VLAN interfaces */
1017 for (i = 0; i < nActive; i++) {
1018 SCVLANInterfaceRef a_vlan;
1019 CFStringRef a_vlan_if;
1020 CFIndex j;
1021 Boolean found = FALSE;
1022
1023 a_vlan = CFArrayGetValueAtIndex(active, i);
1024 a_vlan_if = SCNetworkInterfaceGetBSDName(a_vlan);
1025
1026 for (j = 0; j < nConfig; j++) {
1027 SCVLANInterfaceRef c_vlan;
1028 CFStringRef c_vlan_if;
1029
1030 c_vlan = CFArrayGetValueAtIndex(config, j);
1031 c_vlan_if = SCNetworkInterfaceGetBSDName(c_vlan);
1032
1033 if (CFEqual(a_vlan_if, c_vlan_if)) {
1034 found = TRUE;
1035 break;
1036 }
1037 }
1038
1039 if (!found) {
1040 // remove VLAN interface
1041 if (s == -1) {
1042 s = inet_dgram_socket();
1043 if (s == -1) {
1044 _SCErrorSet(errno);
1045 ok = FALSE;
1046 goto done;
1047 }
1048 }
1049 if (!__destroyInterface(s, a_vlan_if)) {
1050 ok = FALSE;
1051 _SCErrorSet(errno);
1052 }
1053 }
1054 }
1055
1056 /* create (and update) configured VLAN interfaces */
1057 for (i = 0; i < nConfig; i++) {
1058 SCVLANInterfaceRef c_vlan;
1059 CFStringRef c_vlan_if;
1060 SCNetworkInterfaceRef c_vlan_physical;
1061 Boolean found = FALSE;
1062 CFIndex j;
1063 CFBooleanRef supported;
1064
1065 c_vlan = CFArrayGetValueAtIndex(config, i);
1066 c_vlan_if = SCNetworkInterfaceGetBSDName(c_vlan);
1067 c_vlan_physical = SCVLANInterfaceGetPhysicalInterface(c_vlan);
1068
1069 if (c_vlan_physical == NULL) {
1070 continue;
1071 }
1072 // determine if the physical interface supports VLANs
1073 supported = CFDictionaryGetValue(devices, c_vlan_physical);
1074 if (supported == NULL) {
1075 SCNetworkInterfacePrivateRef c_vlan_physicalPrivate = (SCNetworkInterfacePrivateRef)c_vlan_physical;
1076
1077 supported = c_vlan_physicalPrivate->supportsVLAN ? kCFBooleanTrue
1078 : kCFBooleanFalse;
1079 CFDictionaryAddValue(devices, c_vlan_physical, supported);
1080 }
1081
1082 for (j = 0; j < nActive; j++) {
1083 SCVLANInterfaceRef a_vlan;
1084 CFStringRef a_vlan_if;
1085
1086 a_vlan = CFArrayGetValueAtIndex(active, j);
1087 a_vlan_if = SCNetworkInterfaceGetBSDName(a_vlan);
1088
1089 if (CFEqual(c_vlan_if, a_vlan_if)) {
1090 if (!CFEqual(c_vlan, a_vlan)) {
1091 // update VLAN interface
1092 if (s == -1) {
1093 s = inet_dgram_socket();
1094 if (s == -1) {
1095 _SCErrorSet(errno);
1096 ok = FALSE;
1097 goto done;
1098 }
1099 }
1100
1101 if (!CFBooleanGetValue(supported)
1102 || !__vlan_clear(s, c_vlan_if)
1103 || !__vlan_set(s, c_vlan_if,
1104 SCNetworkInterfaceGetBSDName(c_vlan_physical),
1105 SCVLANInterfaceGetTag(c_vlan))) {
1106 // something went wrong, try to blow the VLAN away
1107 if (!CFBooleanGetValue(supported)) {
1108 _SCErrorSet(kSCStatusFailed);
1109 }
1110 (void)__destroyInterface(s, c_vlan_if);
1111 ok = FALSE;
1112 }
1113 }
1114
1115 found = TRUE;
1116 break;
1117 }
1118 }
1119
1120 if (!found && CFBooleanGetValue(supported)) {
1121 // if the physical interface supports VLANs, add new interface
1122 Boolean created;
1123
1124 if (s == -1) {
1125 s = inet_dgram_socket();
1126 if (s == -1) {
1127 _SCErrorSet(errno);
1128 ok = FALSE;
1129 goto done;
1130 }
1131 }
1132
1133 created = __createInterface(s, c_vlan_if);
1134 if (!created
1135 || !__vlan_set(s,
1136 c_vlan_if,
1137 SCNetworkInterfaceGetBSDName(c_vlan_physical),
1138 SCVLANInterfaceGetTag(c_vlan))) {
1139 if (created) {
1140 // something went wrong, try to blow the VLAN away
1141 (void)__destroyInterface(s, c_vlan_if);
1142 } else {
1143 _SCErrorSet(errno);
1144 }
1145 ok = FALSE;
1146 }
1147 }
1148
1149 }
1150
1151 done :
1152
1153 if (active) CFRelease(active);
1154 if (config) CFRelease(config);
1155 if (devices) CFRelease(devices);
1156 if (s != -1) (void) close(s);
1157
1158 return ok;
1159 }