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