2 * Copyright (c) 2002-2007, 2010, 2011, 2013 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * October 21, 2000 Allan Nathanson <ajn@apple.com>
33 #define KERNEL_PRIVATE
34 #include <sys/ioctl.h>
36 #include <sys/socket.h>
37 #include <net/ethernet.h>
39 #include <net/if_vlan_var.h>
40 #include <net/if_media.h>
41 #include <net/if_types.h>
42 #include <netinet/in.h>
43 #include <netinet/ip6.h> // for IPV6_MMTU
45 #include <SystemConfiguration/SystemConfiguration.h>
46 #include <SystemConfiguration/SCPrivate.h> // for SCLog()
47 #include "SCNetworkConfigurationInternal.h" // for __SCNetworkInterfaceCreatePrivate
48 #include <SystemConfiguration/SCValidation.h>
50 #include <IOKit/IOKitLib.h>
51 #include <IOKit/network/IONetworkInterface.h>
52 #include <IOKit/network/IONetworkController.h>
53 #include "dy_framework.h"
57 #pragma mark Capabilities
60 // the following table needs to keep the capabilitiy names and values
61 // between the <SystemConfiguration/SCSchemaDefinitionsPrivate.h> and
62 // <net/if.h> headers in sync.
64 const CFStringRef
*name
;
67 } capabilityMappings
[] = {
69 { &kSCPropNetEthernetCapabilityRXCSUM
, TRUE
, IFCAP_RXCSUM
}, // can offload checksum on RX
70 { &kSCPropNetEthernetCapabilityTXCSUM
, TRUE
, IFCAP_TXCSUM
}, // can offload checksum on TX
71 { &kSCPropNetEthernetCapabilityVLAN_MTU
, FALSE
, IFCAP_VLAN_MTU
}, // VLAN-compatible MTU
72 { &kSCPropNetEthernetCapabilityVLAN_HWTAGGING
, FALSE
, IFCAP_VLAN_HWTAGGING
}, // hardware VLAN tag support
73 { &kSCPropNetEthernetCapabilityJUMBO_MTU
, FALSE
, IFCAP_JUMBO_MTU
}, // 9000 byte MTU supported
74 { &kSCPropNetEthernetCapabilityTSO
, TRUE
, IFCAP_TSO
}, // can do TCP/TCP6 Segmentation Offload
75 { &kSCPropNetEthernetCapabilityTSO4
, FALSE
, IFCAP_TSO4
}, // can do TCP Segmentation Offload
76 { &kSCPropNetEthernetCapabilityTSO6
, FALSE
, IFCAP_TSO6
}, // can do TCP6 Segmentation Offload
77 { &kSCPropNetEthernetCapabilityLRO
, TRUE
, IFCAP_LRO
}, // can do Large Receive Offload
78 { &kSCPropNetEthernetCapabilityAV
, TRUE
, IFCAP_AV
}, // can do 802.1 AV Bridging
84 findCapability(CFStringRef capability
)
88 for (i
= 0; i
< sizeof(capabilityMappings
) / sizeof(capabilityMappings
[0]); i
++) {
89 if (CFEqual(capability
, *capabilityMappings
[i
].name
)) {
99 __getCapabilities(CFStringRef interfaceName
,
108 bzero((void *)&ifr
, sizeof(ifr
));
109 if (_SC_cfstring_to_cstring(interfaceName
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
) == NULL
) {
110 SCLog(TRUE
, LOG_ERR
, CFSTR("could not convert interface name"));
111 _SCErrorSet(kSCStatusInvalidArgument
);
115 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
118 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
122 if (ioctl(sock
, SIOCGIFCAP
, (caddr_t
)&ifr
) == -1) {
130 CFSTR("ioctl(SIOCGIFCAP) failed: %s"),
136 if (current
!= NULL
) *current
= ifr
.ifr_curcap
;
137 if (available
!= NULL
) *available
= ifr
.ifr_reqcap
;
146 if (current
!= NULL
) *current
= 0;
147 if (available
!= NULL
) *available
= 0;
154 __SCNetworkInterfaceCreateCapabilities(SCNetworkInterfaceRef interface
,
156 CFDictionaryRef capability_options
)
158 int cap_available
= 0;
159 int cap_current
= capability_base
;
161 CFStringRef interfaceName
;
163 if (!isA_SCNetworkInterface(interface
)) {
164 _SCErrorSet(kSCStatusInvalidArgument
);
168 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
169 if (interfaceName
== NULL
) {
170 _SCErrorSet(kSCStatusInvalidArgument
);
174 if (!__getCapabilities(interfaceName
,
175 (capability_base
== -1) ? &cap_current
: NULL
,
180 if (cap_available
== 0) {
184 if (capability_options
== NULL
) {
188 for (i
= 0; i
< sizeof(capabilityMappings
) / sizeof(capabilityMappings
[0]); i
++) {
192 if (((cap_available
& capabilityMappings
[i
].val
) != 0) &&
193 capabilityMappings
[i
].readwrite
&&
194 CFDictionaryGetValueIfPresent(capability_options
,
195 *capabilityMappings
[i
].name
,
198 CFNumberGetValue(val
, kCFNumberIntType
, &cap_val
)) {
201 cap_current
|= (cap_available
& capabilityMappings
[i
].val
);
203 cap_current
&= ~capabilityMappings
[i
].val
;
206 // don't process again
207 cap_available
&= ~capabilityMappings
[i
].val
;
218 SCNetworkInterfaceCopyCapability(SCNetworkInterfaceRef interface
,
219 CFStringRef capability
)
222 int cap_available
= 0;
225 CFStringRef interfaceName
;
226 CFTypeRef val
= NULL
;
228 if (!isA_SCNetworkInterface(interface
)) {
229 _SCErrorSet(kSCStatusInvalidArgument
);
233 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
234 if (interfaceName
== NULL
) {
235 _SCErrorSet(kSCStatusInvalidArgument
);
239 if (!__getCapabilities(interfaceName
, &cap_current
, &cap_available
)) {
243 if (capability
== NULL
) {
244 CFMutableDictionaryRef all
= NULL
;
246 // if ALL capabilities requested
247 for (i
= 0; i
< sizeof(capabilityMappings
) / sizeof(capabilityMappings
[0]); i
++) {
248 if ((cap_available
& capabilityMappings
[i
].val
) == capabilityMappings
[i
].val
) {
250 all
= CFDictionaryCreateMutable(NULL
,
252 &kCFTypeDictionaryKeyCallBacks
,
253 &kCFTypeDictionaryValueCallBacks
);
255 cap_val
= ((cap_current
& capabilityMappings
[i
].val
) == capabilityMappings
[i
].val
) ? 1 : 0;
256 val
= CFNumberCreate(NULL
, kCFNumberIntType
, &cap_val
);
257 CFDictionarySetValue(all
, *capabilityMappings
[i
].name
, val
);
259 cap_available
&= ~capabilityMappings
[i
].val
;
265 i
= findCapability(capability
);
266 if (i
== kCFNotFound
) {
267 // if unknown capability
268 _SCErrorSet(kSCStatusInvalidArgument
);
272 if ((cap_available
& capabilityMappings
[i
].val
) != capabilityMappings
[i
].val
) {
273 // if capability not available
274 _SCErrorSet(kSCStatusInvalidArgument
);
278 cap_val
= ((cap_current
& capabilityMappings
[i
].val
) == capabilityMappings
[i
].val
) ? 1 : 0;
279 val
= CFNumberCreate(NULL
, kCFNumberIntType
, &cap_val
);
287 SCNetworkInterfaceSetCapability(SCNetworkInterfaceRef interface
,
288 CFStringRef capability
,
291 int cap_available
= 0;
292 CFDictionaryRef configuration
;
294 CFStringRef interfaceName
;
295 CFMutableDictionaryRef newConfiguration
= NULL
;
298 if (!isA_SCNetworkInterface(interface
)) {
299 _SCErrorSet(kSCStatusInvalidArgument
);
303 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
304 if (interfaceName
== NULL
) {
305 // if no interface name
306 _SCErrorSet(kSCStatusInvalidArgument
);
310 i
= findCapability(capability
);
311 if (i
== kCFNotFound
) {
312 // if unknown capability
313 _SCErrorSet(kSCStatusInvalidArgument
);
317 if (!capabilityMappings
[i
].readwrite
) {
319 _SCErrorSet(kSCStatusInvalidArgument
);
323 if ((newValue
!= NULL
) && !isA_CFNumber(newValue
)) {
324 // all values must (for now) be CFNumber[0 or 1]'s
325 _SCErrorSet(kSCStatusInvalidArgument
);
329 if (!__getCapabilities(interfaceName
, NULL
, &cap_available
)) {
333 if ((cap_available
& capabilityMappings
[i
].val
) == 0) {
334 // if capability not available
335 _SCErrorSet(kSCStatusInvalidArgument
);
339 configuration
= SCNetworkInterfaceGetConfiguration(interface
);
340 if (configuration
== NULL
) {
341 newConfiguration
= CFDictionaryCreateMutable(NULL
,
343 &kCFTypeDictionaryKeyCallBacks
,
344 &kCFTypeDictionaryValueCallBacks
);
346 newConfiguration
= CFDictionaryCreateMutableCopy(NULL
, 0, configuration
);
347 CFDictionaryRemoveValue(newConfiguration
, kSCResvInactive
);
350 if ((newValue
!= NULL
)) {
351 CFDictionarySetValue(newConfiguration
, capability
, newValue
);
353 CFDictionaryRemoveValue(newConfiguration
, capability
);
354 if (CFDictionaryGetCount(newConfiguration
) == 0) {
355 CFRelease(newConfiguration
);
356 newConfiguration
= NULL
;
360 ok
= SCNetworkInterfaceSetConfiguration(interface
, newConfiguration
);
361 if (newConfiguration
!= NULL
) CFRelease(newConfiguration
);
368 #pragma mark Media Options
371 static const struct ifmedia_description ifm_subtype_shared_descriptions
[] =
372 IFM_SUBTYPE_SHARED_DESCRIPTIONS
;
374 static const struct ifmedia_description ifm_subtype_ethernet_descriptions
[] =
375 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS
;
377 static const struct ifmedia_description ifm_subtype_ieee80211_descriptions
[] =
378 IFM_SUBTYPE_IEEE80211_DESCRIPTIONS
;
380 static const struct ifmedia_description ifm_shared_option_descriptions
[] =
381 IFM_SHARED_OPTION_DESCRIPTIONS
;
383 static const struct ifmedia_description ifm_subtype_ethernet_option_descriptions
[] =
384 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS
;
386 static const struct ifmedia_description ifm_subtype_ieee80211_option_descriptions
[] =
387 IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS
;
391 __freeMediaList(struct ifmediareq
*ifm
)
393 if (ifm
->ifm_ulist
!= NULL
) CFAllocatorDeallocate(NULL
, ifm
->ifm_ulist
);
394 CFAllocatorDeallocate(NULL
, ifm
);
399 static struct ifmediareq
*
400 __copyMediaList(CFStringRef interfaceName
)
402 struct ifmediareq
*ifm
;
406 ifm
= (struct ifmediareq
*)CFAllocatorAllocate(NULL
, sizeof(struct ifmediareq
), 0);
407 bzero((void *)ifm
, sizeof(*ifm
));
409 if (_SC_cfstring_to_cstring(interfaceName
, ifm
->ifm_name
, sizeof(ifm
->ifm_name
), kCFStringEncodingASCII
) == NULL
) {
410 SCLog(TRUE
, LOG_ERR
, CFSTR("could not convert interface name"));
414 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
416 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
420 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)ifm
) == -1) {
421 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno));
425 if (ifm
->ifm_count
> 0) {
426 ifm
->ifm_ulist
= (int *)CFAllocatorAllocate(NULL
, ifm
->ifm_count
* sizeof(int), 0);
427 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)ifm
) == -1) {
428 SCLog(TRUE
, LOG_DEBUG
, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno
));
437 if (sock
!= -1) (void)close(sock
);
439 __freeMediaList(ifm
);
441 _SCErrorSet(kSCStatusFailed
);
447 static CFDictionaryRef
448 __createMediaDictionary(int media_options
, Boolean filter
)
450 CFMutableDictionaryRef dict
= NULL
;
452 const struct ifmedia_description
*option_descriptions
= NULL
;
453 CFMutableArrayRef options
= NULL
;
454 const struct ifmedia_description
*subtype_descriptions
= NULL
;
458 ((IFM_SUBTYPE(media_options
) == IFM_NONE
) ||
459 ((IFM_OPTIONS(media_options
) & IFM_LOOP
) != 0))) {
460 return NULL
; /* filter */
463 switch (IFM_TYPE(media_options
)) {
465 option_descriptions
= ifm_subtype_ethernet_option_descriptions
;
466 subtype_descriptions
= ifm_subtype_ethernet_descriptions
;
469 option_descriptions
= ifm_subtype_ieee80211_option_descriptions
;
470 subtype_descriptions
= ifm_subtype_ieee80211_descriptions
;
476 dict
= CFDictionaryCreateMutable(NULL
,
478 &kCFTypeDictionaryKeyCallBacks
,
479 &kCFTypeDictionaryValueCallBacks
);
484 for (i
= 0; !val
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) {
485 if (IFM_SUBTYPE(media_options
) == ifm_subtype_shared_descriptions
[i
].ifmt_word
) {
486 val
= CFStringCreateWithCString(NULL
,
487 ifm_subtype_shared_descriptions
[i
].ifmt_string
,
488 kCFStringEncodingASCII
);
493 if (subtype_descriptions
!= NULL
) {
494 for (i
= 0; !val
&& subtype_descriptions
[i
].ifmt_string
; i
++) {
495 if (IFM_SUBTYPE(media_options
) == subtype_descriptions
[i
].ifmt_word
) {
496 val
= CFStringCreateWithCString(NULL
,
497 subtype_descriptions
[i
].ifmt_string
,
498 kCFStringEncodingASCII
);
505 CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaSubType
, val
);
511 options
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
513 for (i
= 0; (IFM_OPTIONS(media_options
) != 0) && (ifm_shared_option_descriptions
[i
].ifmt_string
!= NULL
); i
++) {
514 if ((media_options
& ifm_shared_option_descriptions
[i
].ifmt_word
) != 0) {
515 val
= CFStringCreateWithCString(NULL
,
516 ifm_shared_option_descriptions
[i
].ifmt_string
,
517 kCFStringEncodingASCII
);
518 CFArrayAppendValue(options
, val
);
521 media_options
&= ~ifm_shared_option_descriptions
[i
].ifmt_word
;
525 if (option_descriptions
!= NULL
) {
526 for (i
= 0; (IFM_OPTIONS(media_options
) != 0) && (option_descriptions
[i
].ifmt_string
!= NULL
); i
++) {
527 if ((media_options
& option_descriptions
[i
].ifmt_word
) != 0) {
528 val
= CFStringCreateWithCString(NULL
,
529 option_descriptions
[i
].ifmt_string
,
530 kCFStringEncodingASCII
);
531 CFArrayAppendValue(options
, val
);
534 media_options
&= ~option_descriptions
[i
].ifmt_word
;
539 CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaOptions
, options
);
547 __SCNetworkInterfaceCreateMediaOptions(SCNetworkInterfaceRef interface
, CFDictionaryRef media_options
)
550 struct ifmediareq
*ifm
;
552 CFStringRef interfaceName
;
555 const struct ifmedia_description
*option_descriptions
= NULL
;
558 const struct ifmedia_description
*subtype_descriptions
= NULL
;
561 if (!isA_SCNetworkInterface(interface
)) {
562 _SCErrorSet(kSCStatusInvalidArgument
);
566 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
567 if (interfaceName
== NULL
) {
568 _SCErrorSet(kSCStatusInvalidArgument
);
574 ifm
= __copyMediaList(interfaceName
);
576 if (ifm
->ifm_count
> 0) {
577 ifm_new
= IFM_TYPE(ifm
->ifm_ulist
[0]);
579 __freeMediaList(ifm
);
583 // if we cannot determine the media type for the interface
587 switch (IFM_TYPE(ifm_new
)) {
589 option_descriptions
= ifm_subtype_ethernet_option_descriptions
;
590 subtype_descriptions
= ifm_subtype_ethernet_descriptions
;
593 option_descriptions
= ifm_subtype_ieee80211_option_descriptions
;
594 subtype_descriptions
= ifm_subtype_ieee80211_descriptions
;
600 val
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaSubType
);
601 if (!isA_CFString(val
)) {
605 str
= _SC_cfstring_to_cstring(val
, NULL
, 0, kCFStringEncodingASCII
);
611 for (i
= 0; !match
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) {
612 if (strcasecmp(str
, ifm_subtype_shared_descriptions
[i
].ifmt_string
) == 0) {
613 ifm_new
|= ifm_subtype_shared_descriptions
[i
].ifmt_word
;
619 if (subtype_descriptions
!= NULL
) {
620 for (i
= 0; !match
&& subtype_descriptions
[i
].ifmt_string
; i
++) {
621 if (strcasecmp(str
, subtype_descriptions
[i
].ifmt_string
) == 0) {
622 ifm_new
|= subtype_descriptions
[i
].ifmt_word
;
629 CFAllocatorDeallocate(NULL
, str
);
632 return -1; /* if no subtype */
637 options
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaOptions
);
638 if (!isA_CFArray(options
)) {
642 n
= CFArrayGetCount(options
);
643 for (i
= 0; i
< n
; i
++) {
646 val
= CFArrayGetValueAtIndex(options
, i
);
647 if (!isA_CFString(val
)) {
651 str
= _SC_cfstring_to_cstring(val
, NULL
, 0, kCFStringEncodingASCII
);
658 for (j
= 0; !match
&& ifm_shared_option_descriptions
[j
].ifmt_string
; j
++) {
659 if (strcasecmp(str
, ifm_shared_option_descriptions
[j
].ifmt_string
) == 0) {
660 ifm_new
|= ifm_shared_option_descriptions
[j
].ifmt_word
;
666 if (option_descriptions
!= NULL
) {
667 for (j
= 0; !match
&& option_descriptions
[j
].ifmt_string
; j
++) {
668 if (strcasecmp(str
, option_descriptions
[j
].ifmt_string
) == 0) {
669 ifm_new
|= option_descriptions
[j
].ifmt_word
;
676 CFAllocatorDeallocate(NULL
, str
);
679 return -1; /* if no option */
688 SCNetworkInterfaceCopyMediaOptions(SCNetworkInterfaceRef interface
,
689 CFDictionaryRef
*current
,
690 CFDictionaryRef
*active
,
691 CFArrayRef
*available
,
695 struct ifmediareq
*ifm
;
696 CFStringRef interfaceName
;
698 if (!isA_SCNetworkInterface(interface
)) {
699 _SCErrorSet(kSCStatusInvalidArgument
);
703 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
704 if (interfaceName
== NULL
) {
705 _SCErrorSet(kSCStatusInvalidArgument
);
709 ifm
= __copyMediaList(interfaceName
);
714 if (active
!= NULL
) *active
= NULL
;
715 if (current
!= NULL
) *current
= NULL
;
716 if (available
!= NULL
) {
717 CFMutableArrayRef media_options
;
719 media_options
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
720 for (i
= 0; i
< ifm
->ifm_count
; i
++) {
721 CFDictionaryRef options
;
723 options
= __createMediaDictionary(ifm
->ifm_ulist
[i
], filter
);
724 if (options
== NULL
) {
728 if ((active
!= NULL
) && (*active
== NULL
) && (ifm
->ifm_active
== ifm
->ifm_ulist
[i
])) {
729 *active
= CFRetain(options
);
732 if ((current
!= NULL
) && (*current
== NULL
) && (ifm
->ifm_current
== ifm
->ifm_ulist
[i
])) {
733 *current
= CFRetain(options
);
736 if (!CFArrayContainsValue(media_options
, CFRangeMake(0, CFArrayGetCount(media_options
)), options
)) {
737 CFArrayAppendValue(media_options
, options
);
742 *available
= (CFArrayRef
)media_options
;
745 if ((active
!= NULL
) && (*active
== NULL
)) {
746 *active
= __createMediaDictionary(ifm
->ifm_active
, FALSE
);
749 if ((current
!= NULL
) && (*current
== NULL
)) {
750 if ((active
!= NULL
) && (ifm
->ifm_active
== ifm
->ifm_current
)) {
751 if (*active
!= NULL
) *current
= CFRetain(*active
);
753 *current
= __createMediaDictionary(ifm
->ifm_current
, FALSE
);
757 __freeMediaList(ifm
);
763 SCNetworkInterfaceCopyMediaSubTypes(CFArrayRef available
)
767 CFMutableArrayRef subTypes
;
769 if (!isA_CFArray(available
)) {
770 _SCErrorSet(kSCStatusInvalidArgument
);
774 subTypes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
776 n
= CFArrayGetCount(available
);
777 for (i
= 0; i
< n
; i
++) {
778 CFDictionaryRef options
;
781 options
= CFArrayGetValueAtIndex(available
, i
);
782 if (!isA_CFDictionary(options
)) {
786 subType
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
787 if (!isA_CFString(subType
)) {
791 if (!CFArrayContainsValue(subTypes
, CFRangeMake(0, CFArrayGetCount(subTypes
)), subType
)) {
792 CFArrayAppendValue(subTypes
, subType
);
796 if (CFArrayGetCount(subTypes
) == 0) {
799 _SCErrorSet(kSCStatusOK
);
807 SCNetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef available
,
812 CFMutableArrayRef subTypeOptions
;
814 if (!isA_CFArray(available
)) {
815 _SCErrorSet(kSCStatusInvalidArgument
);
819 subTypeOptions
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
821 n
= CFArrayGetCount(available
);
822 for (i
= 0; i
< n
; i
++) {
823 CFDictionaryRef options
;
824 CFArrayRef mediaOptions
;
825 CFStringRef mediaSubType
;
827 options
= CFArrayGetValueAtIndex(available
, i
);
828 if (!isA_CFDictionary(options
)) {
832 mediaSubType
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
833 if (!isA_CFString(mediaSubType
) || !CFEqual(subType
, mediaSubType
)) {
837 mediaOptions
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaOptions
);
838 if (!isA_CFArray(mediaOptions
)) {
842 if (!CFArrayContainsValue(subTypeOptions
, CFRangeMake(0, CFArrayGetCount(subTypeOptions
)), mediaOptions
)) {
843 CFArrayAppendValue(subTypeOptions
, mediaOptions
);
847 if (CFArrayGetCount(subTypeOptions
) == 0) {
848 CFRelease(subTypeOptions
);
849 subTypeOptions
= NULL
;
850 _SCErrorSet(kSCStatusOK
);
853 return subTypeOptions
;
858 _SCNetworkInterfaceIsPhysicalEthernet(SCNetworkInterfaceRef interface
)
861 struct ifmediareq
*ifm
;
862 CFStringRef interfaceName
;
863 Boolean realEthernet
= FALSE
;
865 if (!isA_SCNetworkInterface(interface
)) {
866 _SCErrorSet(kSCStatusInvalidArgument
);
870 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
871 if (interfaceName
== NULL
) {
872 _SCErrorSet(kSCStatusInvalidArgument
);
876 ifm
= __copyMediaList(interfaceName
);
878 CFStringRef interfaceType
;
880 interfaceType
= SCNetworkInterfaceGetInterfaceType(interface
);
881 if (CFEqual(interfaceType
, kSCNetworkInterfaceTypeEthernet
) &&
882 !_SCNetworkInterfaceIsTethered(interface
) &&
883 !_SCNetworkInterfaceIsBluetoothPAN(interface
)) {
884 // if likely physical ethernet interface
889 _SCErrorSet(kSCStatusOK
);
890 if (IFM_TYPE(ifm
->ifm_current
) != IFM_ETHER
) {
893 if (ifm
->ifm_count
== 1
894 && IFM_SUBTYPE(ifm
->ifm_ulist
[0]) == IFM_AUTO
) {
895 /* only support autoselect, not really ethernet */
898 for (i
= 0; i
< ifm
->ifm_count
; i
++) {
899 if ((ifm
->ifm_ulist
[i
] & IFM_FDX
) != 0) {
905 __freeMediaList(ifm
);
906 return (realEthernet
);
910 __getMTULimits(char ifr_name
[IFNAMSIZ
],
915 io_iterator_t io_iter
= 0;
916 io_registry_entry_t io_interface
= 0;
917 io_registry_entry_t io_controller
= 0;
919 static mach_port_t masterPort
= MACH_PORT_NULL
;
920 CFMutableDictionaryRef matchingDict
;
922 /* look for a matching interface in the IORegistry */
924 if (masterPort
== MACH_PORT_NULL
) {
925 kr
= IOMasterPort(MACH_PORT_NULL
, &masterPort
);
926 if (kr
!= KERN_SUCCESS
) {
931 matchingDict
= IOBSDNameMatching(masterPort
, 0, ifr_name
);
933 /* Note: IOServiceGetMatchingServices consumes a reference on the 'matchingDict' */
934 kr
= IOServiceGetMatchingServices(masterPort
, matchingDict
, &io_iter
);
935 if ((kr
== KERN_SUCCESS
) && io_iter
) {
936 /* should only have a single match */
937 io_interface
= IOIteratorNext(io_iter
);
939 if (io_iter
) IOObjectRelease(io_iter
);
946 * found an interface, get the interface type
948 num
= IORegistryEntryCreateCFProperty(io_interface
, CFSTR(kIOInterfaceType
), NULL
, kNilOptions
);
950 if (isA_CFNumber(num
)) {
951 CFNumberGetValue(num
, kCFNumberIntType
, &ifType
);
957 * ...and the property we are REALLY interested is in the controller,
958 * which is the parent of the interface object.
960 (void)IORegistryEntryGetParentEntry(io_interface
, kIOServicePlane
, &io_controller
);
961 IOObjectRelease(io_interface
);
963 /* if no matching interface */
970 num
= IORegistryEntryCreateCFProperty(io_controller
, CFSTR(kIOMaxPacketSize
), NULL
, kNilOptions
);
972 if (isA_CFNumber(num
)) {
976 * Get the value and subtract the FCS bytes and Ethernet header
977 * sizes from the maximum frame size reported by the controller
978 * to get the MTU size. The 14 byte media header can be found
979 * in the registry, but not the size for the trailing FCS bytes.
981 CFNumberGetValue(num
, kCFNumberIntType
, &value
);
983 if (ifType
== IFT_ETHER
) {
984 value
-= (ETHER_HDR_LEN
+ ETHER_CRC_LEN
);
987 if (mtu_min
) *mtu_min
= IF_MINMTU
;
988 if (mtu_max
) *mtu_max
= value
;
993 IOObjectRelease(io_controller
);
1001 SCNetworkInterfaceCopyMTU(SCNetworkInterfaceRef interface
,
1007 CFStringRef interfaceName
;
1011 if (!isA_SCNetworkInterface(interface
)) {
1012 _SCErrorSet(kSCStatusInvalidArgument
);
1016 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
1017 if (interfaceName
== NULL
) {
1018 _SCErrorSet(kSCStatusInvalidArgument
);
1022 bzero((void *)&ifr
, sizeof(ifr
));
1023 if (_SC_cfstring_to_cstring(interfaceName
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
) == NULL
) {
1024 SCLog(TRUE
, LOG_ERR
, CFSTR("could not convert interface name"));
1025 _SCErrorSet(kSCStatusInvalidArgument
);
1029 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
1032 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
1036 if (ioctl(sock
, SIOCGIFMTU
, (caddr_t
)&ifr
) == -1) {
1038 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMTU) failed: %s"), strerror(errno));
1042 if (mtu_cur
) *mtu_cur
= ifr
.ifr_mtu
;
1043 if (mtu_min
) *mtu_min
= ifr
.ifr_mtu
;
1044 if (mtu_max
) *mtu_max
= ifr
.ifr_mtu
;
1046 /* get valid MTU range */
1048 if (mtu_min
!= NULL
|| mtu_max
!= NULL
) {
1049 if (ioctl(sock
, SIOCGIFDEVMTU
, (caddr_t
)&ifr
) == 0) {
1050 struct ifdevmtu
* devmtu_p
;
1052 devmtu_p
= &ifr
.ifr_devmtu
;
1053 if (mtu_min
!= NULL
) {
1054 *mtu_min
= (devmtu_p
->ifdm_min
> IF_MINMTU
)
1055 ? devmtu_p
->ifdm_min
: IF_MINMTU
;
1057 if (mtu_max
!= NULL
) {
1058 *mtu_max
= devmtu_p
->ifdm_max
;
1061 (void)__getMTULimits(ifr
.ifr_name
, mtu_min
, mtu_max
);
1064 if (mtu_min
!= NULL
) {
1065 #if IP_MSS > IPV6_MMTU
1066 if (*mtu_min
< IP_MSS
) {
1067 /* bump up the minimum MTU */
1068 *mtu_min
= IP_MSS
/*576*/;
1070 #else // IP_MSS > IPV6_MMTU
1071 if (*mtu_min
< IPV6_MMTU
) {
1072 /* bump up the minimum MTU */
1073 *mtu_min
= IPV6_MMTU
;
1075 #endif // IP_MSS > IPV6_MMTU
1077 if ((mtu_cur
!= NULL
) && (*mtu_min
> *mtu_cur
)) {
1078 /* min must be <= cur */
1079 *mtu_min
= *mtu_cur
;
1082 if ((mtu_max
!= NULL
) && (*mtu_min
> *mtu_max
)) {
1083 /* min must be <= max */
1084 *mtu_min
= *mtu_max
;
1099 SCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef interface
,
1100 CFStringRef subtype
,
1103 CFDictionaryRef configuration
;
1104 CFMutableDictionaryRef newConfiguration
= NULL
;
1107 if (!isA_SCNetworkInterface(interface
)) {
1108 _SCErrorSet(kSCStatusInvalidArgument
);
1112 configuration
= SCNetworkInterfaceGetConfiguration(interface
);
1113 if (configuration
== NULL
) {
1114 newConfiguration
= CFDictionaryCreateMutable(NULL
,
1116 &kCFTypeDictionaryKeyCallBacks
,
1117 &kCFTypeDictionaryValueCallBacks
);
1119 newConfiguration
= CFDictionaryCreateMutableCopy(NULL
, 0, configuration
);
1120 CFDictionaryRemoveValue(newConfiguration
, kSCResvInactive
);
1123 if (subtype
!= NULL
) {
1124 CFArrayRef available
= NULL
;
1125 CFArrayRef config_options
= options
;
1126 CFArrayRef subtypes
= NULL
;
1127 CFArrayRef subtype_options
= NULL
;
1129 if (options
== NULL
) {
1130 config_options
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
);
1133 if (!SCNetworkInterfaceCopyMediaOptions(interface
, NULL
, NULL
, &available
, FALSE
)) {
1134 SCLog(_sc_debug
, LOG_DEBUG
, CFSTR("media type / options not available"));
1138 if (available
== NULL
) {
1139 _SCErrorSet(kSCStatusInvalidArgument
);
1143 subtypes
= SCNetworkInterfaceCopyMediaSubTypes(available
);
1144 if ((subtypes
== NULL
) ||
1145 !CFArrayContainsValue(subtypes
,
1146 CFRangeMake(0, CFArrayGetCount(subtypes
)),
1148 SCLog(_sc_debug
, LOG_DEBUG
, CFSTR("media type not valid"));
1149 _SCErrorSet(kSCStatusInvalidArgument
);
1153 subtype_options
= SCNetworkInterfaceCopyMediaSubTypeOptions(available
, subtype
);
1154 if ((subtype_options
== NULL
) ||
1155 !CFArrayContainsValue(subtype_options
,
1156 CFRangeMake(0, CFArrayGetCount(subtype_options
)),
1158 SCLog(_sc_debug
, LOG_DEBUG
, CFSTR("media options not valid for \"%@\""), subtype
);
1159 _SCErrorSet(kSCStatusInvalidArgument
);
1163 CFDictionarySetValue(newConfiguration
, kSCPropNetEthernetMediaSubType
, subtype
);
1164 CFDictionarySetValue(newConfiguration
,
1165 kSCPropNetEthernetMediaOptions
,
1166 (options
!= NULL
) ? options
: config_options
);
1172 if (available
!= NULL
) CFRelease(available
);
1173 if (subtypes
!= NULL
) CFRelease(subtypes
);
1174 if (subtype_options
!= NULL
) CFRelease(subtype_options
);
1175 if (options
== NULL
) CFRelease(config_options
);
1176 } else if (options
== NULL
) {
1177 CFDictionaryRemoveValue(newConfiguration
, kSCPropNetEthernetMediaSubType
);
1178 CFDictionaryRemoveValue(newConfiguration
, kSCPropNetEthernetMediaOptions
);
1179 if (CFDictionaryGetCount(newConfiguration
) == 0) {
1180 CFRelease(newConfiguration
);
1181 newConfiguration
= NULL
;
1185 SCLog(_sc_debug
, LOG_DEBUG
, CFSTR("media type must be specified with options"));
1186 _SCErrorSet(kSCStatusInvalidArgument
);
1190 ok
= SCNetworkInterfaceSetConfiguration(interface
, newConfiguration
);
1193 if (newConfiguration
!= NULL
) CFRelease(newConfiguration
);
1199 SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface
,
1202 CFDictionaryRef configuration
;
1205 CFMutableDictionaryRef newConfiguration
= NULL
;
1208 if (!isA_SCNetworkInterface(interface
)) {
1209 _SCErrorSet(kSCStatusInvalidArgument
);
1213 if (!SCNetworkInterfaceCopyMTU(interface
, NULL
, &mtu_min
, &mtu_max
)) {
1214 SCLog(_sc_debug
, LOG_DEBUG
, CFSTR("MTU bounds not available"));
1218 configuration
= SCNetworkInterfaceGetConfiguration(interface
);
1219 if (configuration
== NULL
) {
1220 newConfiguration
= CFDictionaryCreateMutable(NULL
,
1222 &kCFTypeDictionaryKeyCallBacks
,
1223 &kCFTypeDictionaryValueCallBacks
);
1225 newConfiguration
= CFDictionaryCreateMutableCopy(NULL
, 0, configuration
);
1226 CFDictionaryRemoveValue(newConfiguration
, kSCResvInactive
);
1229 if ((mtu
>= mtu_min
) && (mtu
<= mtu_max
)) {
1232 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &mtu
);
1233 CFDictionarySetValue(newConfiguration
, kSCPropNetEthernetMTU
, num
);
1236 } else if (mtu
== 0) {
1237 CFDictionaryRemoveValue(newConfiguration
, kSCPropNetEthernetMTU
);
1238 if (CFDictionaryGetCount(newConfiguration
) == 0) {
1239 CFRelease(newConfiguration
);
1240 newConfiguration
= NULL
;
1244 SCLog(_sc_debug
, LOG_DEBUG
, CFSTR("MTU out of range"));
1245 _SCErrorSet(kSCStatusInvalidArgument
);
1249 ok
= SCNetworkInterfaceSetConfiguration(interface
, newConfiguration
);
1252 if (newConfiguration
!= NULL
) CFRelease(newConfiguration
);