]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/VLANConfiguration.c
configd-1061.141.1.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / VLANConfiguration.c
1 /*
2 * Copyright (c) 2003-2013, 2015-2018, 2020 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 = SCPreferencesCreateCompanion(prefs, INTERFACES_DEFAULT_CONFIG);
226 }
227
228 context.vlans = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
229 context.ni_prefs = ni_prefs;
230 context.prefs = prefs;
231
232 path = CFStringCreateWithFormat(NULL,
233 NULL,
234 CFSTR("/%@/%@"),
235 kSCPrefVirtualNetworkInterfaces,
236 kSCNetworkInterfaceTypeVLAN);
237 dict = SCPreferencesPathGetValue(prefs, path);
238 CFRelease(path);
239 if (isA_CFDictionary(dict)) {
240 my_CFDictionaryApplyFunction(dict, add_configured_interface, &context);
241 }
242
243 if (ni_prefs != NULL) {
244 CFRelease(ni_prefs);
245 }
246 return context.vlans;
247 }
248
249
250 static void
251 addAvailableInterfaces(CFMutableArrayRef available, CFArrayRef interfaces,
252 CFSetRef excluded)
253 {
254 CFIndex i;
255 CFIndex n;
256
257 n = CFArrayGetCount(interfaces);
258 for (i = 0; i < n; i++) {
259 SCNetworkInterfaceRef interface;
260 SCNetworkInterfacePrivateRef interfacePrivate;
261
262 interface = CFArrayGetValueAtIndex(interfaces, i);
263 interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
264
265 if ((excluded != NULL)
266 && CFSetContainsValue(excluded, interface)) {
267 // exclude this interface
268 continue;
269 }
270 if (interfacePrivate->supportsVLAN) {
271 // if this interface is available
272 CFArrayAppendValue(available, interface);
273 }
274 }
275
276 return;
277 }
278
279
280 CFArrayRef
281 SCVLANInterfaceCopyAvailablePhysicalInterfaces()
282 {
283 CFMutableArrayRef available;
284 #if !TARGET_OS_IPHONE
285 CFArrayRef bond_interfaces = NULL;
286 #endif // !TARGET_OS_IPHONE
287 CFArrayRef bridge_interfaces = NULL;
288 CFMutableSetRef excluded = NULL;
289 CFArrayRef interfaces;
290 SCPreferencesRef prefs;
291
292 available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
293
294 prefs = SCPreferencesCreate(NULL, CFSTR("SCVLANInterfaceCopyAvailablePhysicalInterfaces"), NULL);
295 if (prefs != NULL) {
296 #if !TARGET_OS_IPHONE
297 bond_interfaces = SCBondInterfaceCopyAll(prefs);
298 if (bond_interfaces != NULL) {
299 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
300 __SCBondInterfaceListCollectMembers(bond_interfaces, excluded);
301 }
302 #endif // !TARGET_OS_IPHONE
303
304 bridge_interfaces = SCBridgeInterfaceCopyAll(prefs);
305 if (bridge_interfaces != NULL) {
306 if (excluded == NULL) {
307 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
308 }
309 __SCBridgeInterfaceListCollectMembers(bridge_interfaces, excluded);
310 }
311
312 CFRelease(prefs);
313 }
314
315 // add real interfaces that aren't part of a bond or bridge
316 interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(FALSE);
317 if (interfaces != NULL) {
318 addAvailableInterfaces(available, interfaces, excluded);
319 CFRelease(interfaces);
320 }
321
322 #if !TARGET_OS_IPHONE
323 // add bond interfaces
324 if (bond_interfaces != NULL) {
325 addAvailableInterfaces(available, bond_interfaces, NULL);
326 CFRelease(bond_interfaces);
327 }
328 #endif // !TARGET_OS_IPHONE
329
330 // add bridge interfaces
331 if (bridge_interfaces != NULL) {
332 addAvailableInterfaces(available, bridge_interfaces, NULL);
333 CFRelease(bridge_interfaces);
334 }
335
336 if (excluded != NULL) {
337 CFRelease(excluded);
338 }
339
340 return available;
341 }
342
343
344 CFArrayRef
345 _SCVLANInterfaceCopyActive(void)
346 {
347 struct ifaddrs *ifap;
348 struct ifaddrs *ifp;
349 int s;
350 CFMutableArrayRef vlans = NULL;
351
352 if (getifaddrs(&ifap) == -1) {
353 SC_log(LOG_NOTICE, "getifaddrs() failed: %s", strerror(errno));
354 _SCErrorSet(kSCStatusFailed);
355 return NULL;
356 }
357
358 s = inet_dgram_socket();
359 if (s == -1) {
360 _SCErrorSet(errno);
361 goto done;
362 }
363
364 vlans = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
365
366 for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) {
367 struct if_data *if_data;
368 struct ifreq ifr;
369 SCVLANInterfaceRef vlan;
370 CFStringRef vlan_if;
371 SCNetworkInterfaceRef vlan_physical;
372 CFStringRef vlan_physical_if;
373 CFNumberRef vlan_tag;
374 char vlr_parent[IFNAMSIZ];
375 int vlr_tag;
376 struct vlanreq vreq;
377
378 if_data = (struct if_data *)ifp->ifa_data;
379 if (if_data == NULL
380 || ifp->ifa_addr->sa_family != AF_LINK
381 || if_data->ifi_type != IFT_L2VLAN) {
382 continue;
383 }
384
385 memset(&ifr, 0, sizeof(ifr));
386 memset(&vreq, 0, sizeof(vreq));
387 strlcpy(ifr.ifr_name, ifp->ifa_name, sizeof(ifr.ifr_name));
388 ifr.ifr_data = (caddr_t)&vreq;
389
390 if (ioctl(s, SIOCGIFVLAN, (caddr_t)&ifr) == -1) {
391 SC_log(LOG_NOTICE, "ioctl(SIOCGIFVLAN) failed: %s", strerror(errno));
392 CFRelease(vlans);
393 vlans = NULL;
394 _SCErrorSet(kSCStatusFailed);
395 goto done;
396 }
397
398 // create the VLAN interface
399 vlan_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
400 vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(NULL, vlan_if);
401 assert(vlan != NULL);
402 CFRelease(vlan_if);
403
404 // set the physical interface and tag
405 strlcpy(vlr_parent, vreq.vlr_parent, sizeof(vlr_parent));
406 vlan_physical_if = CFStringCreateWithCString(NULL, vlr_parent, kCFStringEncodingASCII);
407 vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if,
408 kIncludeBondInterfaces);
409 assert(vlan_physical != NULL);
410 CFRelease(vlan_physical_if);
411
412 vlr_tag = vreq.vlr_tag;
413 vlan_tag = CFNumberCreate(NULL, kCFNumberIntType, &vlr_tag);
414 assert(vlan_tag != NULL);
415
416 SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag);
417 CFRelease(vlan_physical);
418 CFRelease(vlan_tag);
419
420 // add VLAN
421 CFArrayAppendValue(vlans, vlan);
422 CFRelease(vlan);
423 }
424
425 done :
426
427 if (s != -1) {
428 (void) close(s);
429 }
430 freeifaddrs(ifap);
431 return vlans;
432 }
433
434
435 SCVLANInterfaceRef
436 SCVLANInterfaceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef physical, CFNumberRef tag)
437 {
438 CFAllocatorRef allocator;
439 CFIndex i;
440 SCNetworkInterfacePrivateRef interfacePrivate;
441 SCVLANInterfaceRef vlan;
442
443 if (prefs == NULL) {
444 _SCErrorSet(kSCStatusInvalidArgument);
445 return NULL;
446 }
447
448 if (!isA_SCNetworkInterface(physical)) {
449 _SCErrorSet(kSCStatusInvalidArgument);
450 return NULL;
451 }
452
453 interfacePrivate = (SCNetworkInterfacePrivateRef)physical;
454 if (!interfacePrivate->supportsVLAN) {
455 if (!__SCPreferencesUsingDefaultPrefs(prefs)) {
456 interfacePrivate->supportsVLAN = TRUE;
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)) {
635 interfacePrivate->supportsVLAN = TRUE;
636 } else {
637 _SCErrorSet(kSCStatusInvalidArgument);
638 return FALSE;
639 }
640 }
641
642 if (isA_CFNumber(tag)) {
643 int tag_val;
644
645 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
646 if ((tag_val < 1) || (tag_val > 4094)) {
647 _SCErrorSet(kSCStatusInvalidArgument);
648 return FALSE;
649 }
650 } else {
651 _SCErrorSet(kSCStatusInvalidArgument);
652 return FALSE;
653 }
654
655 interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
656 if (interfacePrivate->prefs != NULL) {
657 SCVLANInterfaceRef config_vlan;
658 CFDictionaryRef dict;
659 CFMutableDictionaryRef newDict;
660 CFStringRef path;
661
662 // make sure that physical interface and tag are not used
663 config_vlan = findVLANInterfaceAndTag(interfacePrivate->prefs, physical, tag);
664 if (config_vlan != NULL) {
665 if (!CFEqual(vlan, config_vlan)) {
666 CFRelease(config_vlan);
667 _SCErrorSet(kSCStatusKeyExists);
668 return FALSE;
669 }
670 CFRelease(config_vlan);
671 }
672
673 // set interface/tag in the stored preferences
674 path = CFStringCreateWithFormat(NULL,
675 NULL,
676 CFSTR("/%@/%@/%@"),
677 kSCPrefVirtualNetworkInterfaces,
678 kSCNetworkInterfaceTypeVLAN,
679 interfacePrivate->entity_device);
680 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
681 if (!isA_CFDictionary(dict)) {
682 // if the prefs are confused
683 CFRelease(path);
684 _SCErrorSet(kSCStatusFailed);
685 return FALSE;
686 }
687
688 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
689 CFDictionarySetValue(newDict,
690 kSCPropVirtualNetworkInterfacesVLANInterface,
691 SCNetworkInterfaceGetBSDName(physical));
692 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANTag, tag);
693 if (!CFEqual(dict, newDict)) {
694 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
695 }
696 CFRelease(newDict);
697 CFRelease(path);
698 }
699
700 if (ok) {
701 SCNetworkInterfacePrivateRef newInterface;
702 CFTypeRef save;
703
704 // set physical interface
705 newInterface = __SCNetworkInterfaceCreateCopy(NULL,
706 physical,
707 interfacePrivate->prefs,
708 interfacePrivate->serviceID);
709 save = interfacePrivate->vlan.interface;
710 interfacePrivate->vlan.interface = (SCNetworkInterfaceRef)newInterface;
711 if (save != NULL) CFRelease(save);
712
713 // set tag
714 save = interfacePrivate->vlan.tag;
715 interfacePrivate->vlan.tag = CFRetain(tag);
716 if (save != NULL) CFRelease(save);
717 }
718
719 return ok;
720 }
721
722
723 Boolean
724 SCVLANInterfaceSetLocalizedDisplayName(SCVLANInterfaceRef vlan, CFStringRef newName)
725 {
726 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
727 Boolean ok = TRUE;
728
729 if (!isA_SCVLANInterface(vlan)) {
730 _SCErrorSet(kSCStatusInvalidArgument);
731 return FALSE;
732 }
733
734 if ((newName != NULL) && !isA_CFString(newName)) {
735 _SCErrorSet(kSCStatusInvalidArgument);
736 return FALSE;
737 }
738
739 // set name in the stored preferences
740 if (interfacePrivate->prefs != NULL) {
741 CFDictionaryRef dict;
742 CFMutableDictionaryRef newDict;
743 CFStringRef path;
744
745 path = CFStringCreateWithFormat(NULL,
746 NULL,
747 CFSTR("/%@/%@/%@"),
748 kSCPrefVirtualNetworkInterfaces,
749 kSCNetworkInterfaceTypeVLAN,
750 interfacePrivate->entity_device);
751 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
752 if (!isA_CFDictionary(dict)) {
753 // if the prefs are confused
754 CFRelease(path);
755 _SCErrorSet(kSCStatusFailed);
756 return FALSE;
757 }
758
759 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
760 if (newName != NULL) {
761 CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName);
762 } else {
763 CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName);
764 }
765 if (!CFEqual(dict, newDict)) {
766 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
767 }
768 CFRelease(newDict);
769 CFRelease(path);
770 }
771
772 // set name in the SCVLANInterfaceRef
773 if (ok) {
774 if (interfacePrivate->localized_name != NULL) {
775 CFRelease(interfacePrivate->localized_name);
776 interfacePrivate->localized_name = NULL;
777 }
778 if (newName != NULL) {
779 interfacePrivate->localized_name = CFStringCreateCopy(NULL, newName);
780 }
781 }
782
783 return ok;
784 }
785
786
787 Boolean
788 SCVLANInterfaceSetOptions(SCVLANInterfaceRef vlan, CFDictionaryRef newOptions)
789 {
790 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)vlan;
791 Boolean ok = TRUE;
792
793 if (!isA_SCVLANInterface(vlan)) {
794 _SCErrorSet(kSCStatusInvalidArgument);
795 return FALSE;
796 }
797
798 if ((newOptions != NULL) && !isA_CFDictionary(newOptions)) {
799 _SCErrorSet(kSCStatusInvalidArgument);
800 return FALSE;
801 }
802
803 // set options in the stored preferences
804 if (interfacePrivate->prefs != NULL) {
805 CFDictionaryRef dict;
806 CFMutableDictionaryRef newDict;
807 CFStringRef path;
808
809 path = CFStringCreateWithFormat(NULL,
810 NULL,
811 CFSTR("/%@/%@/%@"),
812 kSCPrefVirtualNetworkInterfaces,
813 kSCNetworkInterfaceTypeVLAN,
814 interfacePrivate->entity_device);
815 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
816 if (!isA_CFDictionary(dict)) {
817 // if the prefs are confused
818 CFRelease(path);
819 _SCErrorSet(kSCStatusFailed);
820 return FALSE;
821 }
822
823 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
824 if (newOptions != NULL) {
825 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANOptions, newOptions);
826 } else {
827 CFDictionaryRemoveValue(newDict, kSCPropVirtualNetworkInterfacesVLANOptions);
828 }
829 if (!CFEqual(dict, newDict)) {
830 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
831 }
832 CFRelease(newDict);
833 CFRelease(path);
834 }
835
836 // set options in the SCVLANInterfaceRef
837 if (ok) {
838 if (interfacePrivate->vlan.options != NULL) {
839 CFRelease(interfacePrivate->vlan.options);
840 interfacePrivate->vlan.options = NULL;
841 }
842 if (newOptions != NULL) {
843 interfacePrivate->vlan.options = CFDictionaryCreateCopy(NULL, newOptions);
844 }
845 }
846
847 return ok;
848 }
849
850
851 #pragma mark -
852 #pragma mark SCVLANInterface management
853
854
855 static Boolean
856 __vlan_set(int s, CFStringRef interface_if, CFStringRef physical_if, CFNumberRef tag)
857 {
858 struct ifreq ifr;
859 int tag_val;
860 struct vlanreq vreq;
861
862 memset(&ifr, 0, sizeof(ifr));
863 memset(&vreq, 0, sizeof(vreq));
864
865 // interface
866 (void) _SC_cfstring_to_cstring(interface_if,
867 ifr.ifr_name,
868 sizeof(ifr.ifr_name),
869 kCFStringEncodingASCII);
870 ifr.ifr_data = (caddr_t)&vreq;
871
872 // physical interface
873 (void) _SC_cfstring_to_cstring(physical_if,
874 vreq.vlr_parent,
875 sizeof(vreq.vlr_parent),
876 kCFStringEncodingASCII);
877
878 // tag
879 CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
880 vreq.vlr_tag = tag_val;
881
882 // update physical interface and tag
883 if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) {
884 SC_log(LOG_NOTICE, "ioctl(SIOCSIFVLAN) failed: %s", strerror(errno));
885 _SCErrorSet(kSCStatusFailed);
886 return FALSE;
887 }
888
889 return TRUE;
890 }
891
892
893 static Boolean
894 __vlan_clear(int s, CFStringRef interface_if)
895 {
896 struct ifreq ifr;
897 struct vlanreq vreq;
898
899 memset(&ifr, 0, sizeof(ifr));
900 memset(&vreq, 0, sizeof(vreq));
901
902 // interface
903 (void) _SC_cfstring_to_cstring(interface_if,
904 ifr.ifr_name,
905 sizeof(ifr.ifr_name),
906 kCFStringEncodingASCII);
907 ifr.ifr_data = (caddr_t)&vreq;
908
909 // clear physical interface
910 memset(&vreq.vlr_parent, 0, sizeof(vreq.vlr_parent));
911
912 // clear tag
913 vreq.vlr_tag = 0;
914
915 // update physical interface and tag
916 if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) {
917 SC_log(LOG_NOTICE, "ioctl(SIOCSIFVLAN) failed: %s", strerror(errno));
918 _SCErrorSet(kSCStatusFailed);
919 return FALSE;
920 }
921
922 return TRUE;
923 }
924
925
926 Boolean
927 _SCVLANInterfaceUpdateConfiguration(SCPreferencesRef prefs)
928 {
929 CFArrayRef active = NULL;
930 CFArrayRef config = NULL;
931 CFMutableDictionaryRef devices = NULL;
932 CFIndex i;
933 CFIndex nActive;
934 CFIndex nConfig;
935 Boolean ok = TRUE;
936 int s = -1;
937
938 if (prefs == NULL) {
939 _SCErrorSet(kSCStatusInvalidArgument);
940 return FALSE;
941 }
942
943 /* configured VLANs */
944 config = SCVLANInterfaceCopyAll(prefs);
945 nConfig = (config != NULL) ? CFArrayGetCount(config) : 0;
946
947 /* physical interfaces */
948 devices = CFDictionaryCreateMutable(NULL,
949 0,
950 &kCFTypeDictionaryKeyCallBacks,
951 &kCFTypeDictionaryValueCallBacks);
952
953 /* active VLANs */
954 active = _SCVLANInterfaceCopyActive();
955 nActive = (active != NULL) ? CFArrayGetCount(active) : 0;
956
957 /* remove any no-longer-configured VLAN interfaces */
958 for (i = 0; i < nActive; i++) {
959 SCVLANInterfaceRef a_vlan;
960 CFStringRef a_vlan_if;
961 CFIndex j;
962 Boolean found = FALSE;
963
964 a_vlan = CFArrayGetValueAtIndex(active, i);
965 a_vlan_if = SCNetworkInterfaceGetBSDName(a_vlan);
966
967 for (j = 0; j < nConfig; j++) {
968 SCVLANInterfaceRef c_vlan;
969 CFStringRef c_vlan_if;
970
971 c_vlan = CFArrayGetValueAtIndex(config, j);
972 c_vlan_if = SCNetworkInterfaceGetBSDName(c_vlan);
973
974 if (CFEqual(a_vlan_if, c_vlan_if)) {
975 found = TRUE;
976 break;
977 }
978 }
979
980 if (!found) {
981 // remove VLAN interface
982 if (s == -1) {
983 s = inet_dgram_socket();
984 if (s == -1) {
985 _SCErrorSet(errno);
986 ok = FALSE;
987 goto done;
988 }
989 }
990 if (!__destroyInterface(s, a_vlan_if)) {
991 ok = FALSE;
992 _SCErrorSet(errno);
993 }
994 }
995 }
996
997 /* create (and update) configured VLAN interfaces */
998 for (i = 0; i < nConfig; i++) {
999 SCVLANInterfaceRef c_vlan;
1000 CFStringRef c_vlan_if;
1001 SCNetworkInterfaceRef c_vlan_physical;
1002 Boolean found = FALSE;
1003 CFIndex j;
1004 CFBooleanRef supported;
1005
1006 c_vlan = CFArrayGetValueAtIndex(config, i);
1007 c_vlan_if = SCNetworkInterfaceGetBSDName(c_vlan);
1008 c_vlan_physical = SCVLANInterfaceGetPhysicalInterface(c_vlan);
1009
1010 if (c_vlan_physical == NULL) {
1011 continue;
1012 }
1013 // determine if the physical interface supports VLANs
1014 supported = CFDictionaryGetValue(devices, c_vlan_physical);
1015 if (supported == NULL) {
1016 SCNetworkInterfacePrivateRef c_vlan_physicalPrivate = (SCNetworkInterfacePrivateRef)c_vlan_physical;
1017
1018 supported = c_vlan_physicalPrivate->supportsVLAN ? kCFBooleanTrue
1019 : kCFBooleanFalse;
1020 CFDictionaryAddValue(devices, c_vlan_physical, supported);
1021 }
1022
1023 for (j = 0; j < nActive; j++) {
1024 SCVLANInterfaceRef a_vlan;
1025 CFStringRef a_vlan_if;
1026
1027 a_vlan = CFArrayGetValueAtIndex(active, j);
1028 a_vlan_if = SCNetworkInterfaceGetBSDName(a_vlan);
1029
1030 if (CFEqual(c_vlan_if, a_vlan_if)) {
1031 if (!CFEqual(c_vlan, a_vlan)) {
1032 // update VLAN interface
1033 if (s == -1) {
1034 s = inet_dgram_socket();
1035 if (s == -1) {
1036 _SCErrorSet(errno);
1037 ok = FALSE;
1038 goto done;
1039 }
1040 }
1041
1042 if (!CFBooleanGetValue(supported)
1043 || !__vlan_clear(s, c_vlan_if)
1044 || !__vlan_set(s, c_vlan_if,
1045 SCNetworkInterfaceGetBSDName(c_vlan_physical),
1046 SCVLANInterfaceGetTag(c_vlan))) {
1047 // something went wrong, try to blow the VLAN away
1048 if (!CFBooleanGetValue(supported)) {
1049 _SCErrorSet(kSCStatusFailed);
1050 }
1051 (void)__destroyInterface(s, c_vlan_if);
1052 ok = FALSE;
1053 }
1054 }
1055
1056 found = TRUE;
1057 break;
1058 }
1059 }
1060
1061 if (!found && CFBooleanGetValue(supported)) {
1062 // if the physical interface supports VLANs, add new interface
1063 Boolean created;
1064
1065 if (s == -1) {
1066 s = inet_dgram_socket();
1067 if (s == -1) {
1068 _SCErrorSet(errno);
1069 ok = FALSE;
1070 goto done;
1071 }
1072 }
1073
1074 created = __createInterface(s, c_vlan_if);
1075 if (!created
1076 || !__vlan_set(s,
1077 c_vlan_if,
1078 SCNetworkInterfaceGetBSDName(c_vlan_physical),
1079 SCVLANInterfaceGetTag(c_vlan))) {
1080 if (created) {
1081 // something went wrong, try to blow the VLAN away
1082 (void)__destroyInterface(s, c_vlan_if);
1083 } else {
1084 _SCErrorSet(errno);
1085 }
1086 ok = FALSE;
1087 }
1088 }
1089
1090 }
1091
1092 done :
1093
1094 if (active) CFRelease(active);
1095 if (config) CFRelease(config);
1096 if (devices) CFRelease(devices);
1097 if (s != -1) (void) close(s);
1098
1099 return ok;
1100 }