]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/VLANConfiguration.c
configd-699.1.5.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / VLANConfiguration.c
1 /*
2 * Copyright (c) 2003-2013 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 "SCPreferencesInternal.h"
41 #include <SystemConfiguration/SCValidation.h>
42 #include <SystemConfiguration/SCPrivate.h>
43
44 #include <ifaddrs.h>
45 #include <pthread.h>
46 #include <unistd.h>
47 #include <sys/types.h>
48 #include <sys/ioctl.h>
49 #include <sys/socket.h>
50 #include <net/ethernet.h>
51 #define KERNEL_PRIVATE
52 #include <net/if.h>
53 #include <net/if_var.h>
54 #undef KERNEL_PRIVATE
55 #include <net/if_vlan_var.h>
56 #include <net/if_types.h>
57
58 /* ---------- VLAN support ---------- */
59
60 static int
61 inet_dgram_socket()
62 {
63 int s;
64
65 s = socket(AF_INET, SOCK_DGRAM, 0);
66 if (s == -1) {
67 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
68 }
69
70 return s;
71 }
72
73
74 typedef struct {
75 CFMutableArrayRef vlans;
76 SCPreferencesRef ni_prefs;
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 = NULL;
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 assert(vlan != NULL);
110
111 // set physical interface and tag
112 if (myContext->ni_prefs != NULL) {
113 vlan_physical = __SCNetworkInterfaceCreateWithNIPreferencesUsingBSDName(NULL, myContext->ni_prefs,
114 vlan_physical_if);
115 }
116 if (vlan_physical == NULL) {
117 vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if,
118 kIncludeBondInterfaces);
119 }
120 assert(vlan_physical != NULL);
121
122 // since we KNOW that the physical interface supported VLANs when
123 // it was first established it's OK to force that state here ...
124 // and this is needed for the case when the interface (e.g. a
125 // dongle) is not currently attached to the system
126 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan_physical;
127 interfacePrivate->supportsVLAN = TRUE;
128
129 // and now we associate the physical interface and tag
130 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag);
131 CFRelease(vlan_physical);
132
133 // set display name
134 vlan_name = CFDictionaryGetValue(vlan_info, kSCPropUserDefinedName);
135 if (isA_CFString(vlan_name)) {
136 SCVLANInterfaceSetLocalizedDisplayName(vlan, vlan_name);
137 }
138
139 // set options
140 vlan_options = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANOptions);
141 if (isA_CFDictionary(vlan_options)) {
142 SCVLANInterfaceSetOptions(vlan, vlan_options);
143 }
144
145 // estabish link to the stored configuration
146 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
147 interfacePrivate->prefs = CFRetain(myContext->prefs);
148
149 CFArrayAppendValue(myContext->vlans, vlan);
150 CFRelease(vlan);
151
152 return;
153 }
154
155
156 static SCVLANInterfaceRef
157 findVLANInterfaceAndTag(SCPreferencesRef prefs, SCNetworkInterfaceRef physical, CFNumberRef tag)
158 {
159 CFIndex i;
160 CFIndex n;
161 SCVLANInterfaceRef vlan = NULL;
162 CFArrayRef vlans;
163
164 vlans = SCVLANInterfaceCopyAll(prefs);
165
166 n = CFArrayGetCount(vlans);
167 for (i = 0; i < n; i++) {
168 SCVLANInterfaceRef config_vlan;
169 SCNetworkInterfaceRef config_physical;
170 CFNumberRef config_tag;
171
172 config_vlan = CFArrayGetValueAtIndex(vlans, i);
173 config_physical = SCVLANInterfaceGetPhysicalInterface(config_vlan);
174 config_tag = SCVLANInterfaceGetTag(config_vlan);
175
176 if ((config_physical != NULL) && (config_tag != NULL)) {
177 if (!CFEqual(physical, config_physical)) {
178 // if this VLAN has a different physical interface
179 continue;
180 }
181
182 if (!CFEqual(tag, config_tag)) {
183 // if this VLAN has a different tag
184 continue;
185 }
186
187 vlan = CFRetain(config_vlan);
188 break;
189 }
190 }
191 CFRelease(vlans);
192
193 return vlan;
194 }
195
196
197 #pragma mark -
198 #pragma mark SCVLANInterface APIs
199
200
201 static __inline__ void
202 my_CFDictionaryApplyFunction(CFDictionaryRef theDict,
203 CFDictionaryApplierFunction applier,
204 void *context)
205 {
206 CFAllocatorRef myAllocator;
207 CFDictionaryRef myDict;
208
209 myAllocator = CFGetAllocator(theDict);
210 myDict = CFDictionaryCreateCopy(myAllocator, theDict);
211 CFDictionaryApplyFunction(myDict, applier, context);
212 CFRelease(myDict);
213 return;
214 }
215
216
217 CFArrayRef
218 SCVLANInterfaceCopyAll(SCPreferencesRef prefs)
219 {
220 addContext context;
221 CFDictionaryRef dict;
222 SCPreferencesRef ni_prefs;
223 CFStringRef path;
224
225 if ((prefs == NULL) ||
226 (__SCPreferencesUsingDefaultPrefs(prefs) == TRUE)) {
227 ni_prefs = NULL;
228 }
229 else {
230 ni_prefs = __SCPreferencesCreateNIPrefsFromPrefs(prefs);
231 }
232 context.vlans = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
233 context.ni_prefs = ni_prefs;
234 context.prefs = prefs;
235
236 path = CFStringCreateWithFormat(NULL,
237 NULL,
238 CFSTR("/%@/%@"),
239 kSCPrefVirtualNetworkInterfaces,
240 kSCNetworkInterfaceTypeVLAN);
241 dict = SCPreferencesPathGetValue(prefs, path);
242 CFRelease(path);
243 if (isA_CFDictionary(dict)) {
244 my_CFDictionaryApplyFunction(dict, add_configured_interface, &context);
245 }
246 if (ni_prefs != NULL) {
247 CFRelease(ni_prefs);
248 }
249 return context.vlans;
250 }
251
252
253 static void
254 addAvailableInterfaces(CFMutableArrayRef available, CFArrayRef interfaces,
255 CFSetRef excluded)
256 {
257 CFIndex i;
258 CFIndex n;
259
260 n = CFArrayGetCount(interfaces);
261 for (i = 0; i < n; i++) {
262 SCNetworkInterfaceRef interface;
263 SCNetworkInterfacePrivateRef interfacePrivate;
264
265 interface = CFArrayGetValueAtIndex(interfaces, i);
266 interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
267
268 if ((excluded != NULL)
269 && CFSetContainsValue(excluded, interface)) {
270 // exclude this interface
271 continue;
272 }
273 if (interfacePrivate->supportsVLAN) {
274 // if this interface is available
275 CFArrayAppendValue(available, interface);
276 }
277 }
278
279 return;
280 }
281
282
283 CFArrayRef
284 SCVLANInterfaceCopyAvailablePhysicalInterfaces()
285 {
286 CFMutableArrayRef available;
287 CFArrayRef bond_interfaces = NULL;
288 CFArrayRef bridge_interfaces = NULL;
289 CFMutableSetRef excluded = NULL;
290 CFArrayRef interfaces;
291 SCPreferencesRef prefs;
292
293 available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
294
295 prefs = SCPreferencesCreate(NULL, CFSTR("SCVLANInterfaceCopyAvailablePhysicalInterfaces"), NULL);
296 if (prefs != NULL) {
297 #if !TARGET_OS_IPHONE
298 bond_interfaces = SCBondInterfaceCopyAll(prefs);
299 if (bond_interfaces != NULL) {
300 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
301 __SCBondInterfaceListCollectMembers(bond_interfaces, excluded);
302 }
303 #endif // !TARGET_OS_IPHONE
304
305 bridge_interfaces = SCBridgeInterfaceCopyAll(prefs);
306 if (bridge_interfaces != NULL) {
307 if (excluded == NULL) {
308 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
309 }
310 __SCBridgeInterfaceListCollectMembers(bridge_interfaces, excluded);
311 }
312
313 CFRelease(prefs);
314 }
315
316 // add real interfaces that aren't part of a bond or bridge
317 interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface();
318 if (interfaces != NULL) {
319 addAvailableInterfaces(available, interfaces, excluded);
320 CFRelease(interfaces);
321 }
322
323 // add bond interfaces
324 if (bond_interfaces != NULL) {
325 addAvailableInterfaces(available, bond_interfaces, NULL);
326 CFRelease(bond_interfaces);
327 }
328
329 // add bridge interfaces
330 if (bridge_interfaces != NULL) {
331 addAvailableInterfaces(available, bridge_interfaces, NULL);
332 CFRelease(bridge_interfaces);
333 }
334
335 if (excluded != NULL) {
336 CFRelease(excluded);
337 }
338
339 return available;
340 }
341
342
343 CFArrayRef
344 _SCVLANInterfaceCopyActive(void)
345 {
346 struct ifaddrs *ifap;
347 struct ifaddrs *ifp;
348 int s;
349 CFMutableArrayRef vlans = NULL;
350
351 if (getifaddrs(&ifap) == -1) {
352 SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno));
353 _SCErrorSet(kSCStatusFailed);
354 return NULL;
355 }
356
357 s = inet_dgram_socket();
358 if (s == -1) {
359 _SCErrorSet(errno);
360 goto done;
361 }
362
363 vlans = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
364
365 for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) {
366 struct if_data *if_data;
367 struct ifreq ifr;
368 SCVLANInterfaceRef vlan;
369 CFStringRef vlan_if;
370 SCNetworkInterfaceRef vlan_physical;
371 CFStringRef vlan_physical_if;
372 CFNumberRef vlan_tag;
373 char vlr_parent[IFNAMSIZ];
374 int vlr_tag;
375 struct vlanreq vreq;
376
377 if_data = (struct if_data *)ifp->ifa_data;
378 if (if_data == NULL
379 || ifp->ifa_addr->sa_family != AF_LINK
380 || if_data->ifi_type != IFT_L2VLAN) {
381 continue;
382 }
383
384 bzero(&ifr, sizeof(ifr));
385 bzero(&vreq, sizeof(vreq));
386 strlcpy(ifr.ifr_name, ifp->ifa_name, sizeof(ifr.ifr_name));
387 ifr.ifr_data = (caddr_t)&vreq;
388
389 if (ioctl(s, SIOCGIFVLAN, (caddr_t)&ifr) == -1) {
390 SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCGIFVLAN) failed: %s"), strerror(errno));
391 CFRelease(vlans);
392 vlans = NULL;
393 _SCErrorSet(kSCStatusFailed);
394 goto done;
395 }
396
397 // create the VLAN interface
398 vlan_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
399 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(NULL, vlan_if);
400 assert(vlan != NULL);
401 CFRelease(vlan_if);
402
403 // set the physical interface and tag
404 strlcpy(vlr_parent, vreq.vlr_parent, sizeof(vlr_parent));
405 vlan_physical_if = CFStringCreateWithCString(NULL, vlr_parent, kCFStringEncodingASCII);
406 vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if,
407 kIncludeBondInterfaces);
408 assert(vlan_physical != NULL);
409 CFRelease(vlan_physical_if);
410
411 vlr_tag = vreq.vlr_tag;
412 vlan_tag = CFNumberCreate(NULL, kCFNumberIntType, &vlr_tag);
413 assert(vlan_tag != NULL);
414
415 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag);
416 CFRelease(vlan_physical);
417 CFRelease(vlan_tag);
418
419 // add VLAN
420 CFArrayAppendValue(vlans, vlan);
421 CFRelease(vlan);
422 }
423
424 done :
425
426 if (s != -1) {
427 (void) close(s);
428 }
429 freeifaddrs(ifap);
430 return vlans;
431 }
432
433
434 SCVLANInterfaceRef
435 SCVLANInterfaceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef physical, CFNumberRef tag)
436 {
437 CFAllocatorRef allocator;
438 CFIndex i;
439 SCNetworkInterfacePrivateRef interfacePrivate;
440 SCVLANInterfaceRef vlan;
441
442 if (prefs == NULL) {
443 _SCErrorSet(kSCStatusInvalidArgument);
444 return NULL;
445 }
446
447 if (!isA_SCNetworkInterface(physical)) {
448 _SCErrorSet(kSCStatusInvalidArgument);
449 return NULL;
450 }
451
452 interfacePrivate = (SCNetworkInterfacePrivateRef)physical;
453 if (!interfacePrivate->supportsVLAN) {
454 if (__SCPreferencesUsingDefaultPrefs(prefs) == FALSE) {
455 interfacePrivate->supportsVLAN = TRUE;
456 }
457 else {
458 _SCErrorSet(kSCStatusInvalidArgument);
459 return NULL;
460 }
461 }
462
463 if (isA_CFNumber(tag)) {
464 int tag_val;
465
466 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
467 if ((tag_val < 1) || (tag_val > 4094)) {
468 _SCErrorSet(kSCStatusInvalidArgument);
469 return NULL;
470 }
471 } else {
472 _SCErrorSet(kSCStatusInvalidArgument);
473 return NULL;
474 }
475
476 // make sure that physical interface and tag are not used
477 vlan = findVLANInterfaceAndTag(prefs, physical, tag);
478 if (vlan != NULL) {
479 CFRelease(vlan);
480 _SCErrorSet(kSCStatusKeyExists);
481 return NULL;
482 }
483
484 allocator = CFGetAllocator(prefs);
485
486 // create a new VLAN using an unused interface name
487 for (i = 0; vlan == NULL; i++) {
488 CFDictionaryRef dict;
489 CFStringRef vlan_if;
490 Boolean ok;
491 CFStringRef path;
492
493 vlan_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("vlan%ld"), i);
494 path = CFStringCreateWithFormat(allocator,
495 NULL,
496 CFSTR("/%@/%@/%@"),
497 kSCPrefVirtualNetworkInterfaces,
498 kSCNetworkInterfaceTypeVLAN,
499 vlan_if);
500 dict = SCPreferencesPathGetValue(prefs, path);
501 if (dict != NULL) {
502 // if VLAN interface name not available
503 CFRelease(path);
504 CFRelease(vlan_if);
505 continue;
506 }
507
508 // add the VLAN to the stored preferences
509 dict = CFDictionaryCreate(allocator,
510 NULL, NULL, 0,
511 &kCFTypeDictionaryKeyCallBacks,
512 &kCFTypeDictionaryValueCallBacks);
513 ok = SCPreferencesPathSetValue(prefs, path, dict);
514 CFRelease(dict);
515 CFRelease(path);
516 if (!ok) {
517 // if the VLAN could not be saved
518 CFRelease(vlan_if);
519 _SCErrorSet(kSCStatusFailed);
520 break;
521 }
522
523 // create the SCVLANInterfaceRef
524 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(allocator, vlan_if);
525 CFRelease(vlan_if);
526
527 // estabish link to the stored configuration
528 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
529 interfacePrivate->prefs = CFRetain(prefs);
530
531 // set physical interface and tag
532 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, physical, tag);
533 }
534
535 return vlan;
536 }
537
538
539 Boolean
540 SCVLANInterfaceRemove(SCVLANInterfaceRef vlan)
541 {
542 CFStringRef vlan_if;
543 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
544 Boolean ok;
545 CFStringRef path;
546
547 if (!isA_SCVLANInterface(vlan)) {
548 _SCErrorSet(kSCStatusInvalidArgument);
549 return FALSE;
550 }
551
552 if (interfacePrivate->prefs == NULL) {
553 _SCErrorSet(kSCStatusInvalidArgument);
554 return FALSE;
555 }
556
557 vlan_if = SCNetworkInterfaceGetBSDName(vlan);
558 path = CFStringCreateWithFormat(NULL,
559 NULL,
560 CFSTR("/%@/%@/%@"),
561 kSCPrefVirtualNetworkInterfaces,
562 kSCNetworkInterfaceTypeVLAN,
563 vlan_if);
564 ok = SCPreferencesPathRemoveValue(interfacePrivate->prefs, path);
565 CFRelease(path);
566
567 return ok;
568 }
569
570
571 SCNetworkInterfaceRef
572 SCVLANInterfaceGetPhysicalInterface(SCVLANInterfaceRef vlan)
573 {
574 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
575
576 if (!isA_SCVLANInterface(vlan)) {
577 _SCErrorSet(kSCStatusInvalidArgument);
578 return NULL;
579 }
580
581 return interfacePrivate->vlan.interface;
582 }
583
584
585 CFNumberRef
586 SCVLANInterfaceGetTag(SCVLANInterfaceRef vlan)
587 {
588 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
589
590 if (!isA_SCVLANInterface(vlan)) {
591 _SCErrorSet(kSCStatusInvalidArgument);
592 return NULL;
593 }
594
595 return interfacePrivate->vlan.tag;
596 }
597
598
599 CFDictionaryRef
600 SCVLANInterfaceGetOptions(SCVLANInterfaceRef vlan)
601 {
602 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
603
604 if (!isA_SCVLANInterface(vlan)) {
605 _SCErrorSet(kSCStatusInvalidArgument);
606 return NULL;
607 }
608
609 return interfacePrivate->vlan.options;
610 }
611
612
613 Boolean
614 SCVLANInterfaceSetPhysicalInterfaceAndTag(SCVLANInterfaceRef vlan, SCNetworkInterfaceRef physical, CFNumberRef tag)
615 {
616 SCNetworkInterfacePrivateRef interfacePrivate;
617 Boolean ok = TRUE;
618 SCPreferencesRef prefs;
619
620 if (!isA_SCVLANInterface(vlan)) {
621 _SCErrorSet(kSCStatusInvalidArgument);
622 return FALSE;
623 }
624
625 if (!isA_SCNetworkInterface(physical)) {
626 _SCErrorSet(kSCStatusInvalidArgument);
627 return FALSE;
628 }
629
630 interfacePrivate = (SCNetworkInterfacePrivateRef)physical;
631 prefs = interfacePrivate->prefs;
632
633 if (!interfacePrivate->supportsVLAN) {
634 if (__SCPreferencesUsingDefaultPrefs(prefs) == FALSE) {
635 interfacePrivate->supportsVLAN = TRUE;
636 }
637 else {
638 _SCErrorSet(kSCStatusInvalidArgument);
639 return FALSE;
640 }
641 }
642
643 if (isA_CFNumber(tag)) {
644 int tag_val;
645
646 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
647 if ((tag_val < 1) || (tag_val > 4094)) {
648 _SCErrorSet(kSCStatusInvalidArgument);
649 return FALSE;
650 }
651 } else {
652 _SCErrorSet(kSCStatusInvalidArgument);
653 return FALSE;
654 }
655
656 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
657 if (interfacePrivate->prefs != NULL) {
658 SCVLANInterfaceRef config_vlan;
659 CFDictionaryRef dict;
660 CFMutableDictionaryRef newDict;
661 CFStringRef path;
662
663 // make sure that physical interface and tag are not used
664 config_vlan = findVLANInterfaceAndTag(interfacePrivate->prefs, physical, tag);
665 if (config_vlan != NULL) {
666 if (!CFEqual(vlan, config_vlan)) {
667 CFRelease(config_vlan);
668 _SCErrorSet(kSCStatusKeyExists);
669 return FALSE;
670 }
671 CFRelease(config_vlan);
672 }
673
674 // set interface/tag in the stored preferences
675 path = CFStringCreateWithFormat(NULL,
676 NULL,
677 CFSTR("/%@/%@/%@"),
678 kSCPrefVirtualNetworkInterfaces,
679 kSCNetworkInterfaceTypeVLAN,
680 interfacePrivate->entity_device);
681 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
682 if (!isA_CFDictionary(dict)) {
683 // if the prefs are confused
684 CFRelease(path);
685 _SCErrorSet(kSCStatusFailed);
686 return FALSE;
687 }
688
689 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
690 CFDictionarySetValue(newDict,
691 kSCPropVirtualNetworkInterfacesVLANInterface,
692 SCNetworkInterfaceGetBSDName(physical));
693 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANTag, tag);
694 if (!CFEqual(dict, newDict)) {
695 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
696 }
697 CFRelease(newDict);
698 CFRelease(path);
699 }
700
701 if (ok) {
702 SCNetworkInterfacePrivateRef newInterface;
703 CFTypeRef save;
704
705 // set physical interface
706 newInterface = __SCNetworkInterfaceCreateCopy(NULL,
707 physical,
708 interfacePrivate->prefs,
709 interfacePrivate->serviceID);
710 save = interfacePrivate->vlan.interface;
711 interfacePrivate->vlan.interface = (SCNetworkInterfaceRef)newInterface;
712 if (save != NULL) CFRelease(save);
713
714 // set tag
715 save = interfacePrivate->vlan.tag;
716 interfacePrivate->vlan.tag = CFRetain(tag);
717 if (save != NULL) CFRelease(save);
718 }
719
720 return ok;
721 }
722
723
724 Boolean
725 SCVLANInterfaceSetLocalizedDisplayName(SCVLANInterfaceRef vlan, CFStringRef newName)
726 {
727 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
728 Boolean ok = TRUE;
729
730 if (!isA_SCVLANInterface(vlan)) {
731 _SCErrorSet(kSCStatusInvalidArgument);
732 return FALSE;
733 }
734
735 if ((newName != NULL) && !isA_CFString(newName)) {
736 _SCErrorSet(kSCStatusInvalidArgument);
737 return FALSE;
738 }
739
740 // set name in the stored preferences
741 if (interfacePrivate->prefs != NULL) {
742 CFDictionaryRef dict;
743 CFMutableDictionaryRef newDict;
744 CFStringRef path;
745
746 path = CFStringCreateWithFormat(NULL,
747 NULL,
748 CFSTR("/%@/%@/%@"),
749 kSCPrefVirtualNetworkInterfaces,
750 kSCNetworkInterfaceTypeVLAN,
751 interfacePrivate->entity_device);
752 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
753 if (!isA_CFDictionary(dict)) {
754 // if the prefs are confused
755 CFRelease(path);
756 _SCErrorSet(kSCStatusFailed);
757 return FALSE;
758 }
759
760 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
761 if (newName != NULL) {
762 CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName);
763 } else {
764 CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName);
765 }
766 if (!CFEqual(dict, newDict)) {
767 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
768 }
769 CFRelease(newDict);
770 CFRelease(path);
771 }
772
773 // set name in the SCVLANInterfaceRef
774 if (ok) {
775 if (interfacePrivate->localized_name != NULL) {
776 CFRelease(interfacePrivate->localized_name);
777 interfacePrivate->localized_name = NULL;
778 }
779 if (newName != NULL) {
780 interfacePrivate->localized_name = CFStringCreateCopy(NULL, newName);
781 }
782 }
783
784 return ok;
785 }
786
787
788 Boolean
789 SCVLANInterfaceSetOptions(SCVLANInterfaceRef vlan, CFDictionaryRef newOptions)
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 ((newOptions != NULL) && !isA_CFDictionary(newOptions)) {
800 _SCErrorSet(kSCStatusInvalidArgument);
801 return FALSE;
802 }
803
804 // set options 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 (newOptions != NULL) {
826 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANOptions, newOptions);
827 } else {
828 CFDictionaryRemoveValue(newDict, kSCPropVirtualNetworkInterfacesVLANOptions);
829 }
830 if (!CFEqual(dict, newDict)) {
831 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
832 }
833 CFRelease(newDict);
834 CFRelease(path);
835 }
836
837 // set options in the SCVLANInterfaceRef
838 if (ok) {
839 if (interfacePrivate->vlan.options != NULL) {
840 CFRelease(interfacePrivate->vlan.options);
841 interfacePrivate->vlan.options = NULL;
842 }
843 if (newOptions != NULL) {
844 interfacePrivate->vlan.options = CFDictionaryCreateCopy(NULL, newOptions);
845 }
846 }
847
848 return ok;
849 }
850
851
852 #pragma mark -
853 #pragma mark SCVLANInterface management
854
855
856 static Boolean
857 __vlan_set(int s, CFStringRef interface_if, CFStringRef physical_if, CFNumberRef tag)
858 {
859 struct ifreq ifr;
860 int tag_val;
861 struct vlanreq vreq;
862
863 bzero(&ifr, sizeof(ifr));
864 bzero(&vreq, sizeof(vreq));
865
866 // interface
867 (void) _SC_cfstring_to_cstring(interface_if,
868 ifr.ifr_name,
869 sizeof(ifr.ifr_name),
870 kCFStringEncodingASCII);
871 ifr.ifr_data = (caddr_t)&vreq;
872
873 // physical interface
874 (void) _SC_cfstring_to_cstring(physical_if,
875 vreq.vlr_parent,
876 sizeof(vreq.vlr_parent),
877 kCFStringEncodingASCII);
878
879 // tag
880 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
881 vreq.vlr_tag = tag_val;
882
883 // update physical interface and tag
884 if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) {
885 SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno));
886 _SCErrorSet(kSCStatusFailed);
887 return FALSE;
888 }
889
890 return TRUE;
891 }
892
893
894 static Boolean
895 __vlan_clear(int s, CFStringRef interface_if)
896 {
897 struct ifreq ifr;
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 // clear physical interface
911 bzero(&vreq.vlr_parent, sizeof(vreq.vlr_parent));
912
913 // clear tag
914 vreq.vlr_tag = 0;
915
916 // update physical interface and tag
917 if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) {
918 SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno));
919 _SCErrorSet(kSCStatusFailed);
920 return FALSE;
921 }
922
923 return TRUE;
924 }
925
926
927 Boolean
928 _SCVLANInterfaceUpdateConfiguration(SCPreferencesRef prefs)
929 {
930 CFArrayRef active = NULL;
931 CFArrayRef config = NULL;
932 CFMutableDictionaryRef devices = NULL;
933 CFIndex i;
934 CFIndex nActive;
935 CFIndex nConfig;
936 Boolean ok = TRUE;
937 int s = -1;
938
939 if (prefs == NULL) {
940 _SCErrorSet(kSCStatusInvalidArgument);
941 return FALSE;
942 }
943
944 /* configured VLANs */
945 config = SCVLANInterfaceCopyAll(prefs);
946 nConfig = (config != NULL) ? CFArrayGetCount(config) : 0;
947
948 /* physical interfaces */
949 devices = CFDictionaryCreateMutable(NULL,
950 0,
951 &kCFTypeDictionaryKeyCallBacks,
952 &kCFTypeDictionaryValueCallBacks);
953
954 /* active VLANs */
955 active = _SCVLANInterfaceCopyActive();
956 nActive = (active != NULL) ? CFArrayGetCount(active) : 0;
957
958 /* remove any no-longer-configured VLAN interfaces */
959 for (i = 0; i < nActive; i++) {
960 SCVLANInterfaceRef a_vlan;
961 CFStringRef a_vlan_if;
962 CFIndex j;
963 Boolean found = FALSE;
964
965 a_vlan = CFArrayGetValueAtIndex(active, i);
966 a_vlan_if = SCNetworkInterfaceGetBSDName(a_vlan);
967
968 for (j = 0; j < nConfig; j++) {
969 SCVLANInterfaceRef c_vlan;
970 CFStringRef c_vlan_if;
971
972 c_vlan = CFArrayGetValueAtIndex(config, j);
973 c_vlan_if = SCNetworkInterfaceGetBSDName(c_vlan);
974
975 if (CFEqual(a_vlan_if, c_vlan_if)) {
976 found = TRUE;
977 break;
978 }
979 }
980
981 if (!found) {
982 // remove VLAN interface
983 if (s == -1) {
984 s = inet_dgram_socket();
985 if (s == -1) {
986 _SCErrorSet(errno);
987 ok = FALSE;
988 goto done;
989 }
990 }
991 if (!__destroyInterface(s, a_vlan_if)) {
992 ok = FALSE;
993 _SCErrorSet(errno);
994 }
995 }
996 }
997
998 /* create (and update) configured VLAN interfaces */
999 for (i = 0; i < nConfig; i++) {
1000 SCVLANInterfaceRef c_vlan;
1001 CFStringRef c_vlan_if;
1002 SCNetworkInterfaceRef c_vlan_physical;
1003 Boolean found = FALSE;
1004 CFIndex j;
1005 CFBooleanRef supported;
1006
1007 c_vlan = CFArrayGetValueAtIndex(config, i);
1008 c_vlan_if = SCNetworkInterfaceGetBSDName(c_vlan);
1009 c_vlan_physical = SCVLANInterfaceGetPhysicalInterface(c_vlan);
1010
1011 if (c_vlan_physical == NULL) {
1012 continue;
1013 }
1014 // determine if the physical interface supports VLANs
1015 supported = CFDictionaryGetValue(devices, c_vlan_physical);
1016 if (supported == NULL) {
1017 SCNetworkInterfacePrivateRef c_vlan_physicalPrivate = (SCNetworkInterfacePrivateRef)c_vlan_physical;
1018
1019 supported = c_vlan_physicalPrivate->supportsVLAN ? kCFBooleanTrue
1020 : kCFBooleanFalse;
1021 CFDictionaryAddValue(devices, c_vlan_physical, supported);
1022 }
1023
1024 for (j = 0; j < nActive; j++) {
1025 SCVLANInterfaceRef a_vlan;
1026 CFStringRef a_vlan_if;
1027
1028 a_vlan = CFArrayGetValueAtIndex(active, j);
1029 a_vlan_if = SCNetworkInterfaceGetBSDName(a_vlan);
1030
1031 if (CFEqual(c_vlan_if, a_vlan_if)) {
1032 if (!CFEqual(c_vlan, a_vlan)) {
1033 // update VLAN interface
1034 if (s == -1) {
1035 s = inet_dgram_socket();
1036 if (s == -1) {
1037 _SCErrorSet(errno);
1038 ok = FALSE;
1039 goto done;
1040 }
1041 }
1042
1043 if (!CFBooleanGetValue(supported)
1044 || !__vlan_clear(s, c_vlan_if)
1045 || !__vlan_set(s, c_vlan_if,
1046 SCNetworkInterfaceGetBSDName(c_vlan_physical),
1047 SCVLANInterfaceGetTag(c_vlan))) {
1048 // something went wrong, try to blow the VLAN away
1049 if (!CFBooleanGetValue(supported)) {
1050 _SCErrorSet(kSCStatusFailed);
1051 }
1052 (void)__destroyInterface(s, c_vlan_if);
1053 ok = FALSE;
1054 }
1055 }
1056
1057 found = TRUE;
1058 break;
1059 }
1060 }
1061
1062 if (!found && CFBooleanGetValue(supported)) {
1063 // if the physical interface supports VLANs, add new interface
1064 Boolean created;
1065
1066 if (s == -1) {
1067 s = inet_dgram_socket();
1068 if (s == -1) {
1069 _SCErrorSet(errno);
1070 ok = FALSE;
1071 goto done;
1072 }
1073 }
1074
1075 created = __createInterface(s, c_vlan_if);
1076 if (!created
1077 || !__vlan_set(s,
1078 c_vlan_if,
1079 SCNetworkInterfaceGetBSDName(c_vlan_physical),
1080 SCVLANInterfaceGetTag(c_vlan))) {
1081 if (created) {
1082 // something went wrong, try to blow the VLAN away
1083 (void)__destroyInterface(s, c_vlan_if);
1084 } else {
1085 _SCErrorSet(errno);
1086 }
1087 ok = FALSE;
1088 }
1089 }
1090
1091 }
1092
1093 done :
1094
1095 if (active) CFRelease(active);
1096 if (config) CFRelease(config);
1097 if (devices) CFRelease(devices);
1098 if (s != -1) (void) close(s);
1099
1100 return ok;
1101 }