2 * Copyright (c) 2002-2007, 2010, 2011, 2013, 2015-2017 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 "SCNetworkConfigurationInternal.h" // for __SCNetworkInterfaceCreatePrivate
47 #include <IOKit/IOKitLib.h>
48 #include <IOKit/network/IONetworkInterface.h>
49 #include <IOKit/network/IONetworkController.h>
50 #include "dy_framework.h"
54 #pragma mark Capabilities
57 // the following table needs to keep the capabilitiy names and values
58 // between the <SystemConfiguration/SCSchemaDefinitionsPrivate.h> and
59 // <net/if.h> headers in sync.
61 const CFStringRef
*name
;
64 } capabilityMappings
[] = {
66 { &kSCPropNetEthernetCapabilityRXCSUM
, TRUE
, IFCAP_RXCSUM
}, // can offload checksum on RX
67 { &kSCPropNetEthernetCapabilityTXCSUM
, TRUE
, IFCAP_TXCSUM
}, // can offload checksum on TX
68 { &kSCPropNetEthernetCapabilityVLAN_MTU
, FALSE
, IFCAP_VLAN_MTU
}, // VLAN-compatible MTU
69 { &kSCPropNetEthernetCapabilityVLAN_HWTAGGING
, FALSE
, IFCAP_VLAN_HWTAGGING
}, // hardware VLAN tag support
70 { &kSCPropNetEthernetCapabilityJUMBO_MTU
, FALSE
, IFCAP_JUMBO_MTU
}, // 9000 byte MTU supported
71 { &kSCPropNetEthernetCapabilityTSO
, TRUE
, IFCAP_TSO
}, // can do TCP/TCP6 Segmentation Offload
72 { &kSCPropNetEthernetCapabilityTSO4
, FALSE
, IFCAP_TSO4
}, // can do TCP Segmentation Offload
73 { &kSCPropNetEthernetCapabilityTSO6
, FALSE
, IFCAP_TSO6
}, // can do TCP6 Segmentation Offload
74 { &kSCPropNetEthernetCapabilityLRO
, TRUE
, IFCAP_LRO
}, // can do Large Receive Offload
75 { &kSCPropNetEthernetCapabilityAV
, TRUE
, IFCAP_AV
}, // can do 802.1 AV Bridging
81 findCapability(CFStringRef capability
)
83 for (size_t i
= 0; i
< sizeof(capabilityMappings
) / sizeof(capabilityMappings
[0]); i
++) {
84 if (CFEqual(capability
, *capabilityMappings
[i
].name
)) {
94 __getCapabilities(CFStringRef interfaceName
,
103 bzero((void *)&ifr
, sizeof(ifr
));
104 if (_SC_cfstring_to_cstring(interfaceName
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
) == NULL
) {
105 SC_log(LOG_NOTICE
, "could not convert interface name");
106 _SCErrorSet(kSCStatusInvalidArgument
);
110 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
113 SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
));
117 if (ioctl(sock
, SIOCGIFCAP
, (caddr_t
)&ifr
) == -1) {
124 SC_log(LOG_NOTICE
, "ioctl(SIOCGIFCAP) failed: %s", strerror(errno
));
129 if (current
!= NULL
) *current
= ifr
.ifr_curcap
;
130 if (available
!= NULL
) *available
= ifr
.ifr_reqcap
;
139 if (current
!= NULL
) *current
= 0;
140 if (available
!= NULL
) *available
= 0;
147 __SCNetworkInterfaceCreateCapabilities(SCNetworkInterfaceRef interface
,
149 CFDictionaryRef capability_options
)
151 int cap_available
= 0;
152 int cap_current
= capability_base
;
153 CFStringRef interfaceName
;
155 if (!isA_SCNetworkInterface(interface
)) {
156 _SCErrorSet(kSCStatusInvalidArgument
);
160 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
161 if (interfaceName
== NULL
) {
162 _SCErrorSet(kSCStatusInvalidArgument
);
166 if (!__getCapabilities(interfaceName
,
167 (capability_base
== -1) ? &cap_current
: NULL
,
172 if (cap_available
== 0) {
176 if (capability_options
== NULL
) {
180 for (size_t i
= 0; i
< sizeof(capabilityMappings
) / sizeof(capabilityMappings
[0]); i
++) {
184 if (((cap_available
& capabilityMappings
[i
].val
) != 0) &&
185 capabilityMappings
[i
].readwrite
&&
186 CFDictionaryGetValueIfPresent(capability_options
,
187 *capabilityMappings
[i
].name
,
190 CFNumberGetValue(val
, kCFNumberIntType
, &cap_val
)) {
193 cap_current
|= (cap_available
& capabilityMappings
[i
].val
);
195 cap_current
&= ~capabilityMappings
[i
].val
;
198 // don't process again
199 cap_available
&= ~capabilityMappings
[i
].val
;
210 SCNetworkInterfaceCopyCapability(SCNetworkInterfaceRef interface
,
211 CFStringRef capability
)
214 int cap_available
= 0;
216 CFStringRef interfaceName
;
217 CFTypeRef val
= NULL
;
219 if (!isA_SCNetworkInterface(interface
)) {
220 _SCErrorSet(kSCStatusInvalidArgument
);
224 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
225 if (interfaceName
== NULL
) {
226 _SCErrorSet(kSCStatusInvalidArgument
);
230 if (!__getCapabilities(interfaceName
, &cap_current
, &cap_available
)) {
234 if (capability
== NULL
) {
235 CFMutableDictionaryRef all
= NULL
;
237 // if ALL capabilities requested
238 for (size_t i
= 0; i
< sizeof(capabilityMappings
) / sizeof(capabilityMappings
[0]); i
++) {
239 if ((cap_available
& capabilityMappings
[i
].val
) == capabilityMappings
[i
].val
) {
241 all
= CFDictionaryCreateMutable(NULL
,
243 &kCFTypeDictionaryKeyCallBacks
,
244 &kCFTypeDictionaryValueCallBacks
);
246 cap_val
= ((cap_current
& capabilityMappings
[i
].val
) == capabilityMappings
[i
].val
) ? 1 : 0;
247 val
= CFNumberCreate(NULL
, kCFNumberIntType
, &cap_val
);
248 CFDictionarySetValue(all
, *capabilityMappings
[i
].name
, val
);
250 cap_available
&= ~capabilityMappings
[i
].val
;
258 i
= findCapability(capability
);
259 if (i
== kCFNotFound
) {
260 // if unknown capability
261 _SCErrorSet(kSCStatusInvalidArgument
);
265 if ((cap_available
& capabilityMappings
[i
].val
) != capabilityMappings
[i
].val
) {
266 // if capability not available
267 _SCErrorSet(kSCStatusInvalidArgument
);
271 cap_val
= ((cap_current
& capabilityMappings
[i
].val
) == capabilityMappings
[i
].val
) ? 1 : 0;
272 val
= CFNumberCreate(NULL
, kCFNumberIntType
, &cap_val
);
280 SCNetworkInterfaceSetCapability(SCNetworkInterfaceRef interface
,
281 CFStringRef capability
,
284 int cap_available
= 0;
285 CFDictionaryRef configuration
;
287 CFStringRef interfaceName
;
288 CFMutableDictionaryRef newConfiguration
= NULL
;
291 if (!isA_SCNetworkInterface(interface
)) {
292 _SCErrorSet(kSCStatusInvalidArgument
);
296 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
297 if (interfaceName
== NULL
) {
298 // if no interface name
299 _SCErrorSet(kSCStatusInvalidArgument
);
303 i
= findCapability(capability
);
304 if (i
== kCFNotFound
) {
305 // if unknown capability
306 _SCErrorSet(kSCStatusInvalidArgument
);
310 if (!capabilityMappings
[i
].readwrite
) {
312 _SCErrorSet(kSCStatusInvalidArgument
);
316 if ((newValue
!= NULL
) && !isA_CFNumber(newValue
)) {
317 // all values must (for now) be CFNumber[0 or 1]'s
318 _SCErrorSet(kSCStatusInvalidArgument
);
322 if (!__getCapabilities(interfaceName
, NULL
, &cap_available
)) {
326 if ((cap_available
& capabilityMappings
[i
].val
) == 0) {
327 // if capability not available
328 _SCErrorSet(kSCStatusInvalidArgument
);
332 configuration
= SCNetworkInterfaceGetConfiguration(interface
);
333 if (configuration
== NULL
) {
334 newConfiguration
= CFDictionaryCreateMutable(NULL
,
336 &kCFTypeDictionaryKeyCallBacks
,
337 &kCFTypeDictionaryValueCallBacks
);
339 newConfiguration
= CFDictionaryCreateMutableCopy(NULL
, 0, configuration
);
340 CFDictionaryRemoveValue(newConfiguration
, kSCResvInactive
);
343 if ((newValue
!= NULL
)) {
344 CFDictionarySetValue(newConfiguration
, capability
, newValue
);
346 CFDictionaryRemoveValue(newConfiguration
, capability
);
347 if (CFDictionaryGetCount(newConfiguration
) == 0) {
348 CFRelease(newConfiguration
);
349 newConfiguration
= NULL
;
353 ok
= SCNetworkInterfaceSetConfiguration(interface
, newConfiguration
);
354 if (newConfiguration
!= NULL
) CFRelease(newConfiguration
);
361 #pragma mark Media Options
364 static const struct ifmedia_description ifm_subtype_shared_descriptions
[] =
365 IFM_SUBTYPE_SHARED_DESCRIPTIONS
;
367 static const struct ifmedia_description ifm_subtype_ethernet_descriptions
[] =
368 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS
;
370 static const struct ifmedia_description ifm_subtype_ieee80211_descriptions
[] =
371 IFM_SUBTYPE_IEEE80211_DESCRIPTIONS
;
373 static const struct ifmedia_description ifm_shared_option_descriptions
[] =
374 IFM_SHARED_OPTION_DESCRIPTIONS
;
376 static const struct ifmedia_description ifm_subtype_ethernet_option_descriptions
[] =
377 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS
;
379 static const struct ifmedia_description ifm_subtype_ieee80211_option_descriptions
[] =
380 IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS
;
384 __freeMediaList(struct ifmediareq
*ifm
)
386 if (ifm
->ifm_ulist
!= NULL
) CFAllocatorDeallocate(NULL
, ifm
->ifm_ulist
);
387 CFAllocatorDeallocate(NULL
, ifm
);
392 static struct ifmediareq
*
393 __copyMediaList(CFStringRef interfaceName
)
395 struct ifmediareq
*ifm
;
399 ifm
= (struct ifmediareq
*)CFAllocatorAllocate(NULL
, sizeof(struct ifmediareq
), 0);
400 bzero((void *)ifm
, sizeof(*ifm
));
402 if (_SC_cfstring_to_cstring(interfaceName
, ifm
->ifm_name
, sizeof(ifm
->ifm_name
), kCFStringEncodingASCII
) == NULL
) {
403 SC_log(LOG_NOTICE
, "could not convert interface name");
407 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
409 SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
));
413 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)ifm
) == -1) {
414 // SC_log(LOG_NOTICE, "ioctl(SIOCGIFMEDIA) failed: %s", strerror(errno));
418 if (ifm
->ifm_count
> 0) {
419 ifm
->ifm_ulist
= (int *)CFAllocatorAllocate(NULL
, ifm
->ifm_count
* sizeof(int), 0);
420 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)ifm
) == -1) {
421 SC_log(LOG_NOTICE
, "ioctl(SIOCGIFMEDIA) failed: %s", strerror(errno
));
430 if (sock
!= -1) (void)close(sock
);
432 __freeMediaList(ifm
);
434 _SCErrorSet(kSCStatusFailed
);
440 static CFDictionaryRef
441 __createMediaDictionary(int media_options
, Boolean filter
)
443 CFMutableDictionaryRef dict
= NULL
;
445 const struct ifmedia_description
*option_descriptions
= NULL
;
446 CFMutableArrayRef options
= NULL
;
447 const struct ifmedia_description
*subtype_descriptions
= NULL
;
451 ((IFM_SUBTYPE(media_options
) == IFM_NONE
) ||
452 ((IFM_OPTIONS(media_options
) & IFM_LOOP
) != 0))) {
453 return NULL
; /* filter */
456 switch (IFM_TYPE(media_options
)) {
458 option_descriptions
= ifm_subtype_ethernet_option_descriptions
;
459 subtype_descriptions
= ifm_subtype_ethernet_descriptions
;
462 option_descriptions
= ifm_subtype_ieee80211_option_descriptions
;
463 subtype_descriptions
= ifm_subtype_ieee80211_descriptions
;
469 dict
= CFDictionaryCreateMutable(NULL
,
471 &kCFTypeDictionaryKeyCallBacks
,
472 &kCFTypeDictionaryValueCallBacks
);
477 for (i
= 0; !val
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) {
478 if (IFM_SUBTYPE(media_options
) == ifm_subtype_shared_descriptions
[i
].ifmt_word
) {
479 val
= CFStringCreateWithCString(NULL
,
480 ifm_subtype_shared_descriptions
[i
].ifmt_string
,
481 kCFStringEncodingASCII
);
486 if (subtype_descriptions
!= NULL
) {
487 for (i
= 0; !val
&& subtype_descriptions
[i
].ifmt_string
; i
++) {
488 if (IFM_SUBTYPE(media_options
) == subtype_descriptions
[i
].ifmt_word
) {
489 val
= CFStringCreateWithCString(NULL
,
490 subtype_descriptions
[i
].ifmt_string
,
491 kCFStringEncodingASCII
);
498 CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaSubType
, val
);
504 options
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
506 for (i
= 0; (IFM_OPTIONS(media_options
) != 0) && (ifm_shared_option_descriptions
[i
].ifmt_string
!= NULL
); i
++) {
507 if ((media_options
& ifm_shared_option_descriptions
[i
].ifmt_word
) != 0) {
508 val
= CFStringCreateWithCString(NULL
,
509 ifm_shared_option_descriptions
[i
].ifmt_string
,
510 kCFStringEncodingASCII
);
511 CFArrayAppendValue(options
, val
);
514 media_options
&= ~ifm_shared_option_descriptions
[i
].ifmt_word
;
518 if (option_descriptions
!= NULL
) {
519 for (i
= 0; (IFM_OPTIONS(media_options
) != 0) && (option_descriptions
[i
].ifmt_string
!= NULL
); i
++) {
520 if ((media_options
& option_descriptions
[i
].ifmt_word
) != 0) {
521 val
= CFStringCreateWithCString(NULL
,
522 option_descriptions
[i
].ifmt_string
,
523 kCFStringEncodingASCII
);
524 CFArrayAppendValue(options
, val
);
527 media_options
&= ~option_descriptions
[i
].ifmt_word
;
532 CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaOptions
, options
);
540 __SCNetworkInterfaceCreateMediaOptions(SCNetworkInterfaceRef interface
, CFDictionaryRef media_options
)
543 struct ifmediareq
*ifm
;
545 CFStringRef interfaceName
;
548 const struct ifmedia_description
*option_descriptions
= NULL
;
551 const struct ifmedia_description
*subtype_descriptions
= NULL
;
554 if (!isA_SCNetworkInterface(interface
)) {
555 _SCErrorSet(kSCStatusInvalidArgument
);
559 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
560 if (interfaceName
== NULL
) {
561 _SCErrorSet(kSCStatusInvalidArgument
);
567 ifm
= __copyMediaList(interfaceName
);
569 if (ifm
->ifm_count
> 0) {
570 ifm_new
= IFM_TYPE(ifm
->ifm_ulist
[0]);
572 __freeMediaList(ifm
);
576 // if we cannot determine the media type for the interface
580 switch (IFM_TYPE(ifm_new
)) {
582 option_descriptions
= ifm_subtype_ethernet_option_descriptions
;
583 subtype_descriptions
= ifm_subtype_ethernet_descriptions
;
586 option_descriptions
= ifm_subtype_ieee80211_option_descriptions
;
587 subtype_descriptions
= ifm_subtype_ieee80211_descriptions
;
593 val
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaSubType
);
594 if (!isA_CFString(val
)) {
598 str
= _SC_cfstring_to_cstring(val
, NULL
, 0, kCFStringEncodingASCII
);
604 for (i
= 0; !match
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) {
605 if (strcasecmp(str
, ifm_subtype_shared_descriptions
[i
].ifmt_string
) == 0) {
606 ifm_new
|= ifm_subtype_shared_descriptions
[i
].ifmt_word
;
612 if (subtype_descriptions
!= NULL
) {
613 for (i
= 0; !match
&& subtype_descriptions
[i
].ifmt_string
; i
++) {
614 if (strcasecmp(str
, subtype_descriptions
[i
].ifmt_string
) == 0) {
615 ifm_new
|= subtype_descriptions
[i
].ifmt_word
;
622 CFAllocatorDeallocate(NULL
, str
);
625 return -1; /* if no subtype */
630 options
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaOptions
);
631 if (!isA_CFArray(options
)) {
635 n
= CFArrayGetCount(options
);
636 for (i
= 0; i
< n
; i
++) {
639 val
= CFArrayGetValueAtIndex(options
, i
);
640 if (!isA_CFString(val
)) {
644 str
= _SC_cfstring_to_cstring(val
, NULL
, 0, kCFStringEncodingASCII
);
651 for (j
= 0; !match
&& ifm_shared_option_descriptions
[j
].ifmt_string
; j
++) {
652 if (strcasecmp(str
, ifm_shared_option_descriptions
[j
].ifmt_string
) == 0) {
653 ifm_new
|= ifm_shared_option_descriptions
[j
].ifmt_word
;
659 if (option_descriptions
!= NULL
) {
660 for (j
= 0; !match
&& option_descriptions
[j
].ifmt_string
; j
++) {
661 if (strcasecmp(str
, option_descriptions
[j
].ifmt_string
) == 0) {
662 ifm_new
|= option_descriptions
[j
].ifmt_word
;
669 CFAllocatorDeallocate(NULL
, str
);
672 return -1; /* if no option */
681 SCNetworkInterfaceCopyMediaOptions(SCNetworkInterfaceRef interface
,
682 CFDictionaryRef
*current
,
683 CFDictionaryRef
*active
,
684 CFArrayRef
*available
,
688 struct ifmediareq
*ifm
;
689 CFStringRef interfaceName
;
691 if (!isA_SCNetworkInterface(interface
)) {
692 _SCErrorSet(kSCStatusInvalidArgument
);
696 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
697 if (interfaceName
== NULL
) {
698 _SCErrorSet(kSCStatusInvalidArgument
);
702 ifm
= __copyMediaList(interfaceName
);
707 if (active
!= NULL
) *active
= NULL
;
708 if (current
!= NULL
) *current
= NULL
;
709 if (available
!= NULL
) {
710 CFMutableArrayRef media_options
;
712 media_options
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
713 for (i
= 0; i
< ifm
->ifm_count
; i
++) {
714 CFDictionaryRef options
;
716 options
= __createMediaDictionary(ifm
->ifm_ulist
[i
], filter
);
717 if (options
== NULL
) {
721 if ((active
!= NULL
) && (*active
== NULL
) && (ifm
->ifm_active
== ifm
->ifm_ulist
[i
])) {
722 *active
= CFRetain(options
);
725 if ((current
!= NULL
) && (*current
== NULL
) && (ifm
->ifm_current
== ifm
->ifm_ulist
[i
])) {
726 *current
= CFRetain(options
);
729 if (!CFArrayContainsValue(media_options
, CFRangeMake(0, CFArrayGetCount(media_options
)), options
)) {
730 CFArrayAppendValue(media_options
, options
);
735 *available
= (CFArrayRef
)media_options
;
738 if ((active
!= NULL
) && (*active
== NULL
)) {
739 *active
= __createMediaDictionary(ifm
->ifm_active
, FALSE
);
742 if ((current
!= NULL
) && (*current
== NULL
)) {
743 if ((active
!= NULL
) && (ifm
->ifm_active
== ifm
->ifm_current
)) {
744 if (*active
!= NULL
) *current
= CFRetain(*active
);
746 *current
= __createMediaDictionary(ifm
->ifm_current
, FALSE
);
750 __freeMediaList(ifm
);
756 SCNetworkInterfaceCopyMediaSubTypes(CFArrayRef available
)
760 CFMutableArrayRef subTypes
;
762 if (!isA_CFArray(available
)) {
763 _SCErrorSet(kSCStatusInvalidArgument
);
767 subTypes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
769 n
= CFArrayGetCount(available
);
770 for (i
= 0; i
< n
; i
++) {
771 CFDictionaryRef options
;
774 options
= CFArrayGetValueAtIndex(available
, i
);
775 if (!isA_CFDictionary(options
)) {
779 subType
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
780 if (!isA_CFString(subType
)) {
784 if (!CFArrayContainsValue(subTypes
, CFRangeMake(0, CFArrayGetCount(subTypes
)), subType
)) {
785 CFArrayAppendValue(subTypes
, subType
);
789 if (CFArrayGetCount(subTypes
) == 0) {
792 _SCErrorSet(kSCStatusOK
);
800 SCNetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef available
,
805 CFMutableArrayRef subTypeOptions
;
807 if (!isA_CFArray(available
)) {
808 _SCErrorSet(kSCStatusInvalidArgument
);
812 subTypeOptions
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
814 n
= CFArrayGetCount(available
);
815 for (i
= 0; i
< n
; i
++) {
816 CFDictionaryRef options
;
817 CFArrayRef mediaOptions
;
818 CFStringRef mediaSubType
;
820 options
= CFArrayGetValueAtIndex(available
, i
);
821 if (!isA_CFDictionary(options
)) {
825 mediaSubType
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
826 if (!isA_CFString(mediaSubType
) || !CFEqual(subType
, mediaSubType
)) {
830 mediaOptions
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaOptions
);
831 if (!isA_CFArray(mediaOptions
)) {
835 if (!CFArrayContainsValue(subTypeOptions
, CFRangeMake(0, CFArrayGetCount(subTypeOptions
)), mediaOptions
)) {
836 CFArrayAppendValue(subTypeOptions
, mediaOptions
);
840 if (CFArrayGetCount(subTypeOptions
) == 0) {
841 CFRelease(subTypeOptions
);
842 subTypeOptions
= NULL
;
843 _SCErrorSet(kSCStatusOK
);
846 return subTypeOptions
;
851 _SCNetworkInterfaceIsPhysicalEthernet(SCNetworkInterfaceRef interface
)
854 struct ifmediareq
*ifm
;
855 CFStringRef interfaceName
;
856 Boolean realEthernet
= FALSE
;
858 if (!isA_SCNetworkInterface(interface
)) {
859 _SCErrorSet(kSCStatusInvalidArgument
);
863 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
864 if (interfaceName
== NULL
) {
865 _SCErrorSet(kSCStatusInvalidArgument
);
869 ifm
= __copyMediaList(interfaceName
);
871 CFStringRef interfaceType
;
873 interfaceType
= SCNetworkInterfaceGetInterfaceType(interface
);
874 if (CFEqual(interfaceType
, kSCNetworkInterfaceTypeEthernet
) &&
875 !_SCNetworkInterfaceIsTethered(interface
) &&
876 !_SCNetworkInterfaceIsBluetoothPAN(interface
)) {
877 // if likely physical ethernet interface
882 _SCErrorSet(kSCStatusOK
);
883 if (IFM_TYPE(ifm
->ifm_current
) != IFM_ETHER
) {
886 if (ifm
->ifm_count
== 1
887 && IFM_SUBTYPE(ifm
->ifm_ulist
[0]) == IFM_AUTO
) {
888 /* only support autoselect, not really ethernet */
891 for (i
= 0; i
< ifm
->ifm_count
; i
++) {
892 if ((ifm
->ifm_ulist
[i
] & IFM_FDX
) != 0) {
898 __freeMediaList(ifm
);
899 return (realEthernet
);
903 __getIOMTULimits(char ifr_name
[IFNAMSIZ
],
908 io_iterator_t io_iter
= 0;
909 io_registry_entry_t io_interface
= 0;
910 io_registry_entry_t io_controller
= 0;
912 static mach_port_t masterPort
= MACH_PORT_NULL
;
913 CFMutableDictionaryRef matchingDict
;
915 /* look for a matching interface in the IORegistry */
917 if (masterPort
== MACH_PORT_NULL
) {
918 kr
= IOMasterPort(MACH_PORT_NULL
, &masterPort
);
919 if (kr
!= KERN_SUCCESS
) {
924 matchingDict
= IOBSDNameMatching(masterPort
, 0, ifr_name
);
926 /* Note: IOServiceGetMatchingServices consumes a reference on the 'matchingDict' */
927 kr
= IOServiceGetMatchingServices(masterPort
, matchingDict
, &io_iter
);
928 if ((kr
== KERN_SUCCESS
) && io_iter
) {
929 /* should only have a single match */
930 io_interface
= IOIteratorNext(io_iter
);
932 if (io_iter
) IOObjectRelease(io_iter
);
939 * found an interface, get the interface type
941 num
= IORegistryEntryCreateCFProperty(io_interface
, CFSTR(kIOInterfaceType
), NULL
, kNilOptions
);
943 if (isA_CFNumber(num
)) {
944 CFNumberGetValue(num
, kCFNumberIntType
, &ifType
);
950 * ...and the property we are REALLY interested is in the controller,
951 * which is the parent of the interface object.
953 (void)IORegistryEntryGetParentEntry(io_interface
, kIOServicePlane
, &io_controller
);
954 IOObjectRelease(io_interface
);
956 /* if no matching interface */
963 num
= IORegistryEntryCreateCFProperty(io_controller
, CFSTR(kIOMaxPacketSize
), NULL
, kNilOptions
);
965 if (isA_CFNumber(num
)) {
969 * Get the value and subtract the FCS bytes and Ethernet header
970 * sizes from the maximum frame size reported by the controller
971 * to get the MTU size. The 14 byte media header can be found
972 * in the registry, but not the size for the trailing FCS bytes.
974 CFNumberGetValue(num
, kCFNumberIntType
, &value
);
976 if (ifType
== IFT_ETHER
) {
977 value
-= (ETHER_HDR_LEN
+ ETHER_CRC_LEN
);
980 if (mtu_min
) *mtu_min
= IF_MINMTU
;
981 if (mtu_max
) *mtu_max
= value
;
986 IOObjectRelease(io_controller
);
994 SCNetworkInterfaceCopyMTU(SCNetworkInterfaceRef interface
,
1000 CFStringRef interfaceName
;
1004 if (!isA_SCNetworkInterface(interface
)) {
1005 _SCErrorSet(kSCStatusInvalidArgument
);
1009 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
1010 if (interfaceName
== NULL
) {
1011 _SCErrorSet(kSCStatusInvalidArgument
);
1015 bzero((void *)&ifr
, sizeof(ifr
));
1016 if (_SC_cfstring_to_cstring(interfaceName
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
) == NULL
) {
1017 SC_log(LOG_NOTICE
, "could not convert interface name");
1018 _SCErrorSet(kSCStatusInvalidArgument
);
1022 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
1025 SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
));
1029 if (ioctl(sock
, SIOCGIFMTU
, (caddr_t
)&ifr
) == -1) {
1031 // SC_log(LOG_NOTICE, "ioctl(SIOCGIFMTU) failed: %s", strerror(errno));
1035 if (mtu_cur
) *mtu_cur
= ifr
.ifr_mtu
;
1036 if (mtu_min
) *mtu_min
= ifr
.ifr_mtu
;
1037 if (mtu_max
) *mtu_max
= ifr
.ifr_mtu
;
1039 /* get valid MTU range */
1041 if (mtu_min
!= NULL
|| mtu_max
!= NULL
) {
1042 if (ioctl(sock
, SIOCGIFDEVMTU
, (caddr_t
)&ifr
) == 0) {
1043 struct ifdevmtu
* devmtu_p
;
1045 devmtu_p
= &ifr
.ifr_devmtu
;
1046 if (mtu_min
!= NULL
) {
1047 *mtu_min
= (devmtu_p
->ifdm_min
> IF_MINMTU
)
1048 ? devmtu_p
->ifdm_min
: IF_MINMTU
;
1050 if (mtu_max
!= NULL
) {
1051 *mtu_max
= devmtu_p
->ifdm_max
;
1054 ok
= __getIOMTULimits(ifr
.ifr_name
, mtu_min
, mtu_max
);
1056 CFStringRef interfaceType
;
1058 interfaceType
= SCNetworkInterfaceGetInterfaceType(interface
);
1059 if (CFEqual(interfaceType
, kSCNetworkInterfaceTypeBridge
)) {
1064 members
= SCBridgeInterfaceGetMemberInterfaces(interface
);
1065 n
= (members
!= NULL
) ? CFArrayGetCount(members
) : 0;
1067 if (mtu_min
) *mtu_min
= IF_MINMTU
;
1068 if (mtu_max
) *mtu_max
= IF_MAXMTU
;
1070 for (i
= 0; i
< n
; i
++) {
1071 SCNetworkInterfaceRef member
;
1075 member
= CFArrayGetValueAtIndex(members
, i
);
1076 ok
= SCNetworkInterfaceCopyMTU(member
, NULL
, &member_mtu_min
, &member_mtu_max
);
1078 if ((mtu_min
!= NULL
) && (*mtu_min
< member_mtu_min
)) {
1079 *mtu_min
= member_mtu_min
; // min MTU needs to be higher
1081 if ((mtu_max
!= NULL
) && (*mtu_max
> member_mtu_max
)) {
1082 *mtu_max
= member_mtu_max
; // max MTU needs to be lower
1090 if (mtu_min
!= NULL
) {
1091 #if IP_MSS > IPV6_MMTU
1092 if (*mtu_min
< IP_MSS
) {
1093 /* bump up the minimum MTU */
1094 *mtu_min
= IP_MSS
/*576*/;
1096 #else // IP_MSS > IPV6_MMTU
1097 if (*mtu_min
< IPV6_MMTU
) {
1098 /* bump up the minimum MTU */
1099 *mtu_min
= IPV6_MMTU
;
1101 #endif // IP_MSS > IPV6_MMTU
1103 if ((mtu_cur
!= NULL
) && (*mtu_min
> *mtu_cur
)) {
1104 /* min must be <= cur */
1105 *mtu_min
= *mtu_cur
;
1108 if ((mtu_max
!= NULL
) && (*mtu_min
> *mtu_max
)) {
1109 /* min must be <= max */
1110 *mtu_min
= *mtu_max
;
1125 SCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef interface
,
1126 CFStringRef subtype
,
1129 CFDictionaryRef configuration
;
1130 CFMutableDictionaryRef newConfiguration
= NULL
;
1133 if (!isA_SCNetworkInterface(interface
)) {
1134 _SCErrorSet(kSCStatusInvalidArgument
);
1138 configuration
= SCNetworkInterfaceGetConfiguration(interface
);
1139 if (configuration
== NULL
) {
1140 newConfiguration
= CFDictionaryCreateMutable(NULL
,
1142 &kCFTypeDictionaryKeyCallBacks
,
1143 &kCFTypeDictionaryValueCallBacks
);
1145 newConfiguration
= CFDictionaryCreateMutableCopy(NULL
, 0, configuration
);
1146 CFDictionaryRemoveValue(newConfiguration
, kSCResvInactive
);
1149 if (subtype
!= NULL
) {
1150 CFArrayRef available
= NULL
;
1151 CFArrayRef config_options
= options
;
1152 CFArrayRef subtypes
= NULL
;
1153 CFArrayRef subtype_options
= NULL
;
1155 if (options
== NULL
) {
1156 config_options
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
);
1159 if (!SCNetworkInterfaceCopyMediaOptions(interface
, NULL
, NULL
, &available
, FALSE
)) {
1160 SC_log(LOG_INFO
, "media type / options not available");
1164 if (available
== NULL
) {
1165 _SCErrorSet(kSCStatusInvalidArgument
);
1169 subtypes
= SCNetworkInterfaceCopyMediaSubTypes(available
);
1170 if ((subtypes
== NULL
) ||
1171 !CFArrayContainsValue(subtypes
,
1172 CFRangeMake(0, CFArrayGetCount(subtypes
)),
1174 SC_log(LOG_INFO
, "media type not valid");
1175 _SCErrorSet(kSCStatusInvalidArgument
);
1179 subtype_options
= SCNetworkInterfaceCopyMediaSubTypeOptions(available
, subtype
);
1180 if ((subtype_options
== NULL
) ||
1181 !CFArrayContainsValue(subtype_options
,
1182 CFRangeMake(0, CFArrayGetCount(subtype_options
)),
1184 SC_log(LOG_INFO
, "media options not valid for \"%@\"", subtype
);
1185 _SCErrorSet(kSCStatusInvalidArgument
);
1189 CFDictionarySetValue(newConfiguration
, kSCPropNetEthernetMediaSubType
, subtype
);
1190 CFDictionarySetValue(newConfiguration
,
1191 kSCPropNetEthernetMediaOptions
,
1192 (options
!= NULL
) ? options
: config_options
);
1198 if (available
!= NULL
) CFRelease(available
);
1199 if (subtypes
!= NULL
) CFRelease(subtypes
);
1200 if (subtype_options
!= NULL
) CFRelease(subtype_options
);
1201 if (options
== NULL
) CFRelease(config_options
);
1202 } else if (options
== NULL
) {
1203 CFDictionaryRemoveValue(newConfiguration
, kSCPropNetEthernetMediaSubType
);
1204 CFDictionaryRemoveValue(newConfiguration
, kSCPropNetEthernetMediaOptions
);
1205 if (CFDictionaryGetCount(newConfiguration
) == 0) {
1206 CFRelease(newConfiguration
);
1207 newConfiguration
= NULL
;
1211 SC_log(LOG_INFO
, "media type must be specified with options");
1212 _SCErrorSet(kSCStatusInvalidArgument
);
1216 ok
= SCNetworkInterfaceSetConfiguration(interface
, newConfiguration
);
1219 if (newConfiguration
!= NULL
) CFRelease(newConfiguration
);
1225 SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface
,
1228 CFDictionaryRef configuration
;
1231 CFMutableDictionaryRef newConfiguration
= NULL
;
1234 if (!isA_SCNetworkInterface(interface
)) {
1235 _SCErrorSet(kSCStatusInvalidArgument
);
1239 if (!SCNetworkInterfaceCopyMTU(interface
, NULL
, &mtu_min
, &mtu_max
)) {
1240 SC_log(LOG_INFO
, "MTU bounds not available");
1244 configuration
= SCNetworkInterfaceGetConfiguration(interface
);
1245 if (configuration
== NULL
) {
1246 newConfiguration
= CFDictionaryCreateMutable(NULL
,
1248 &kCFTypeDictionaryKeyCallBacks
,
1249 &kCFTypeDictionaryValueCallBacks
);
1251 newConfiguration
= CFDictionaryCreateMutableCopy(NULL
, 0, configuration
);
1252 CFDictionaryRemoveValue(newConfiguration
, kSCResvInactive
);
1255 if ((mtu
>= mtu_min
) && (mtu
<= mtu_max
)) {
1258 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &mtu
);
1259 CFDictionarySetValue(newConfiguration
, kSCPropNetEthernetMTU
, num
);
1262 } else if (mtu
== 0) {
1263 CFDictionaryRemoveValue(newConfiguration
, kSCPropNetEthernetMTU
);
1264 if (CFDictionaryGetCount(newConfiguration
) == 0) {
1265 CFRelease(newConfiguration
);
1266 newConfiguration
= NULL
;
1270 SC_log(LOG_INFO
, "MTU out of range");
1271 _SCErrorSet(kSCStatusInvalidArgument
);
1275 ok
= SCNetworkInterfaceSetConfiguration(interface
, newConfiguration
);
1278 if (newConfiguration
!= NULL
) CFRelease(newConfiguration
);