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