2 * Copyright (c) 2002-2007, 2010, 2011, 2013, 2015 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 SC_log(LOG_NOTICE
, "could not convert interface name");
111 _SCErrorSet(kSCStatusInvalidArgument
);
115 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
118 SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
));
122 if (ioctl(sock
, SIOCGIFCAP
, (caddr_t
)&ifr
) == -1) {
129 SC_log(LOG_NOTICE
, "ioctl(SIOCGIFCAP) failed: %s", strerror(errno
));
134 if (current
!= NULL
) *current
= ifr
.ifr_curcap
;
135 if (available
!= NULL
) *available
= ifr
.ifr_reqcap
;
144 if (current
!= NULL
) *current
= 0;
145 if (available
!= NULL
) *available
= 0;
152 __SCNetworkInterfaceCreateCapabilities(SCNetworkInterfaceRef interface
,
154 CFDictionaryRef capability_options
)
156 int cap_available
= 0;
157 int cap_current
= capability_base
;
159 CFStringRef interfaceName
;
161 if (!isA_SCNetworkInterface(interface
)) {
162 _SCErrorSet(kSCStatusInvalidArgument
);
166 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
167 if (interfaceName
== NULL
) {
168 _SCErrorSet(kSCStatusInvalidArgument
);
172 if (!__getCapabilities(interfaceName
,
173 (capability_base
== -1) ? &cap_current
: NULL
,
178 if (cap_available
== 0) {
182 if (capability_options
== NULL
) {
186 for (i
= 0; i
< sizeof(capabilityMappings
) / sizeof(capabilityMappings
[0]); i
++) {
190 if (((cap_available
& capabilityMappings
[i
].val
) != 0) &&
191 capabilityMappings
[i
].readwrite
&&
192 CFDictionaryGetValueIfPresent(capability_options
,
193 *capabilityMappings
[i
].name
,
196 CFNumberGetValue(val
, kCFNumberIntType
, &cap_val
)) {
199 cap_current
|= (cap_available
& capabilityMappings
[i
].val
);
201 cap_current
&= ~capabilityMappings
[i
].val
;
204 // don't process again
205 cap_available
&= ~capabilityMappings
[i
].val
;
216 SCNetworkInterfaceCopyCapability(SCNetworkInterfaceRef interface
,
217 CFStringRef capability
)
220 int cap_available
= 0;
223 CFStringRef interfaceName
;
224 CFTypeRef val
= NULL
;
226 if (!isA_SCNetworkInterface(interface
)) {
227 _SCErrorSet(kSCStatusInvalidArgument
);
231 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
232 if (interfaceName
== NULL
) {
233 _SCErrorSet(kSCStatusInvalidArgument
);
237 if (!__getCapabilities(interfaceName
, &cap_current
, &cap_available
)) {
241 if (capability
== NULL
) {
242 CFMutableDictionaryRef all
= NULL
;
244 // if ALL capabilities requested
245 for (i
= 0; i
< sizeof(capabilityMappings
) / sizeof(capabilityMappings
[0]); i
++) {
246 if ((cap_available
& capabilityMappings
[i
].val
) == capabilityMappings
[i
].val
) {
248 all
= CFDictionaryCreateMutable(NULL
,
250 &kCFTypeDictionaryKeyCallBacks
,
251 &kCFTypeDictionaryValueCallBacks
);
253 cap_val
= ((cap_current
& capabilityMappings
[i
].val
) == capabilityMappings
[i
].val
) ? 1 : 0;
254 val
= CFNumberCreate(NULL
, kCFNumberIntType
, &cap_val
);
255 CFDictionarySetValue(all
, *capabilityMappings
[i
].name
, val
);
257 cap_available
&= ~capabilityMappings
[i
].val
;
263 i
= findCapability(capability
);
264 if (i
== kCFNotFound
) {
265 // if unknown capability
266 _SCErrorSet(kSCStatusInvalidArgument
);
270 if ((cap_available
& capabilityMappings
[i
].val
) != capabilityMappings
[i
].val
) {
271 // if capability not available
272 _SCErrorSet(kSCStatusInvalidArgument
);
276 cap_val
= ((cap_current
& capabilityMappings
[i
].val
) == capabilityMappings
[i
].val
) ? 1 : 0;
277 val
= CFNumberCreate(NULL
, kCFNumberIntType
, &cap_val
);
285 SCNetworkInterfaceSetCapability(SCNetworkInterfaceRef interface
,
286 CFStringRef capability
,
289 int cap_available
= 0;
290 CFDictionaryRef configuration
;
292 CFStringRef interfaceName
;
293 CFMutableDictionaryRef newConfiguration
= NULL
;
296 if (!isA_SCNetworkInterface(interface
)) {
297 _SCErrorSet(kSCStatusInvalidArgument
);
301 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
302 if (interfaceName
== NULL
) {
303 // if no interface name
304 _SCErrorSet(kSCStatusInvalidArgument
);
308 i
= findCapability(capability
);
309 if (i
== kCFNotFound
) {
310 // if unknown capability
311 _SCErrorSet(kSCStatusInvalidArgument
);
315 if (!capabilityMappings
[i
].readwrite
) {
317 _SCErrorSet(kSCStatusInvalidArgument
);
321 if ((newValue
!= NULL
) && !isA_CFNumber(newValue
)) {
322 // all values must (for now) be CFNumber[0 or 1]'s
323 _SCErrorSet(kSCStatusInvalidArgument
);
327 if (!__getCapabilities(interfaceName
, NULL
, &cap_available
)) {
331 if ((cap_available
& capabilityMappings
[i
].val
) == 0) {
332 // if capability not available
333 _SCErrorSet(kSCStatusInvalidArgument
);
337 configuration
= SCNetworkInterfaceGetConfiguration(interface
);
338 if (configuration
== NULL
) {
339 newConfiguration
= CFDictionaryCreateMutable(NULL
,
341 &kCFTypeDictionaryKeyCallBacks
,
342 &kCFTypeDictionaryValueCallBacks
);
344 newConfiguration
= CFDictionaryCreateMutableCopy(NULL
, 0, configuration
);
345 CFDictionaryRemoveValue(newConfiguration
, kSCResvInactive
);
348 if ((newValue
!= NULL
)) {
349 CFDictionarySetValue(newConfiguration
, capability
, newValue
);
351 CFDictionaryRemoveValue(newConfiguration
, capability
);
352 if (CFDictionaryGetCount(newConfiguration
) == 0) {
353 CFRelease(newConfiguration
);
354 newConfiguration
= NULL
;
358 ok
= SCNetworkInterfaceSetConfiguration(interface
, newConfiguration
);
359 if (newConfiguration
!= NULL
) CFRelease(newConfiguration
);
366 #pragma mark Media Options
369 static const struct ifmedia_description ifm_subtype_shared_descriptions
[] =
370 IFM_SUBTYPE_SHARED_DESCRIPTIONS
;
372 static const struct ifmedia_description ifm_subtype_ethernet_descriptions
[] =
373 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS
;
375 static const struct ifmedia_description ifm_subtype_ieee80211_descriptions
[] =
376 IFM_SUBTYPE_IEEE80211_DESCRIPTIONS
;
378 static const struct ifmedia_description ifm_shared_option_descriptions
[] =
379 IFM_SHARED_OPTION_DESCRIPTIONS
;
381 static const struct ifmedia_description ifm_subtype_ethernet_option_descriptions
[] =
382 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS
;
384 static const struct ifmedia_description ifm_subtype_ieee80211_option_descriptions
[] =
385 IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS
;
389 __freeMediaList(struct ifmediareq
*ifm
)
391 if (ifm
->ifm_ulist
!= NULL
) CFAllocatorDeallocate(NULL
, ifm
->ifm_ulist
);
392 CFAllocatorDeallocate(NULL
, ifm
);
397 static struct ifmediareq
*
398 __copyMediaList(CFStringRef interfaceName
)
400 struct ifmediareq
*ifm
;
404 ifm
= (struct ifmediareq
*)CFAllocatorAllocate(NULL
, sizeof(struct ifmediareq
), 0);
405 bzero((void *)ifm
, sizeof(*ifm
));
407 if (_SC_cfstring_to_cstring(interfaceName
, ifm
->ifm_name
, sizeof(ifm
->ifm_name
), kCFStringEncodingASCII
) == NULL
) {
408 SC_log(LOG_NOTICE
, "could not convert interface name");
412 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
414 SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
));
418 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)ifm
) == -1) {
419 // SC_log(LOG_NOTICE, "ioctl(SIOCGIFMEDIA) failed: %s", strerror(errno));
423 if (ifm
->ifm_count
> 0) {
424 ifm
->ifm_ulist
= (int *)CFAllocatorAllocate(NULL
, ifm
->ifm_count
* sizeof(int), 0);
425 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)ifm
) == -1) {
426 SC_log(LOG_NOTICE
, "ioctl(SIOCGIFMEDIA) failed: %s", strerror(errno
));
435 if (sock
!= -1) (void)close(sock
);
437 __freeMediaList(ifm
);
439 _SCErrorSet(kSCStatusFailed
);
445 static CFDictionaryRef
446 __createMediaDictionary(int media_options
, Boolean filter
)
448 CFMutableDictionaryRef dict
= NULL
;
450 const struct ifmedia_description
*option_descriptions
= NULL
;
451 CFMutableArrayRef options
= NULL
;
452 const struct ifmedia_description
*subtype_descriptions
= NULL
;
456 ((IFM_SUBTYPE(media_options
) == IFM_NONE
) ||
457 ((IFM_OPTIONS(media_options
) & IFM_LOOP
) != 0))) {
458 return NULL
; /* filter */
461 switch (IFM_TYPE(media_options
)) {
463 option_descriptions
= ifm_subtype_ethernet_option_descriptions
;
464 subtype_descriptions
= ifm_subtype_ethernet_descriptions
;
467 option_descriptions
= ifm_subtype_ieee80211_option_descriptions
;
468 subtype_descriptions
= ifm_subtype_ieee80211_descriptions
;
474 dict
= CFDictionaryCreateMutable(NULL
,
476 &kCFTypeDictionaryKeyCallBacks
,
477 &kCFTypeDictionaryValueCallBacks
);
482 for (i
= 0; !val
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) {
483 if (IFM_SUBTYPE(media_options
) == ifm_subtype_shared_descriptions
[i
].ifmt_word
) {
484 val
= CFStringCreateWithCString(NULL
,
485 ifm_subtype_shared_descriptions
[i
].ifmt_string
,
486 kCFStringEncodingASCII
);
491 if (subtype_descriptions
!= NULL
) {
492 for (i
= 0; !val
&& subtype_descriptions
[i
].ifmt_string
; i
++) {
493 if (IFM_SUBTYPE(media_options
) == subtype_descriptions
[i
].ifmt_word
) {
494 val
= CFStringCreateWithCString(NULL
,
495 subtype_descriptions
[i
].ifmt_string
,
496 kCFStringEncodingASCII
);
503 CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaSubType
, val
);
509 options
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
511 for (i
= 0; (IFM_OPTIONS(media_options
) != 0) && (ifm_shared_option_descriptions
[i
].ifmt_string
!= NULL
); i
++) {
512 if ((media_options
& ifm_shared_option_descriptions
[i
].ifmt_word
) != 0) {
513 val
= CFStringCreateWithCString(NULL
,
514 ifm_shared_option_descriptions
[i
].ifmt_string
,
515 kCFStringEncodingASCII
);
516 CFArrayAppendValue(options
, val
);
519 media_options
&= ~ifm_shared_option_descriptions
[i
].ifmt_word
;
523 if (option_descriptions
!= NULL
) {
524 for (i
= 0; (IFM_OPTIONS(media_options
) != 0) && (option_descriptions
[i
].ifmt_string
!= NULL
); i
++) {
525 if ((media_options
& option_descriptions
[i
].ifmt_word
) != 0) {
526 val
= CFStringCreateWithCString(NULL
,
527 option_descriptions
[i
].ifmt_string
,
528 kCFStringEncodingASCII
);
529 CFArrayAppendValue(options
, val
);
532 media_options
&= ~option_descriptions
[i
].ifmt_word
;
537 CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaOptions
, options
);
545 __SCNetworkInterfaceCreateMediaOptions(SCNetworkInterfaceRef interface
, CFDictionaryRef media_options
)
548 struct ifmediareq
*ifm
;
550 CFStringRef interfaceName
;
553 const struct ifmedia_description
*option_descriptions
= NULL
;
556 const struct ifmedia_description
*subtype_descriptions
= NULL
;
559 if (!isA_SCNetworkInterface(interface
)) {
560 _SCErrorSet(kSCStatusInvalidArgument
);
564 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
565 if (interfaceName
== NULL
) {
566 _SCErrorSet(kSCStatusInvalidArgument
);
572 ifm
= __copyMediaList(interfaceName
);
574 if (ifm
->ifm_count
> 0) {
575 ifm_new
= IFM_TYPE(ifm
->ifm_ulist
[0]);
577 __freeMediaList(ifm
);
581 // if we cannot determine the media type for the interface
585 switch (IFM_TYPE(ifm_new
)) {
587 option_descriptions
= ifm_subtype_ethernet_option_descriptions
;
588 subtype_descriptions
= ifm_subtype_ethernet_descriptions
;
591 option_descriptions
= ifm_subtype_ieee80211_option_descriptions
;
592 subtype_descriptions
= ifm_subtype_ieee80211_descriptions
;
598 val
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaSubType
);
599 if (!isA_CFString(val
)) {
603 str
= _SC_cfstring_to_cstring(val
, NULL
, 0, kCFStringEncodingASCII
);
609 for (i
= 0; !match
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) {
610 if (strcasecmp(str
, ifm_subtype_shared_descriptions
[i
].ifmt_string
) == 0) {
611 ifm_new
|= ifm_subtype_shared_descriptions
[i
].ifmt_word
;
617 if (subtype_descriptions
!= NULL
) {
618 for (i
= 0; !match
&& subtype_descriptions
[i
].ifmt_string
; i
++) {
619 if (strcasecmp(str
, subtype_descriptions
[i
].ifmt_string
) == 0) {
620 ifm_new
|= subtype_descriptions
[i
].ifmt_word
;
627 CFAllocatorDeallocate(NULL
, str
);
630 return -1; /* if no subtype */
635 options
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaOptions
);
636 if (!isA_CFArray(options
)) {
640 n
= CFArrayGetCount(options
);
641 for (i
= 0; i
< n
; i
++) {
644 val
= CFArrayGetValueAtIndex(options
, i
);
645 if (!isA_CFString(val
)) {
649 str
= _SC_cfstring_to_cstring(val
, NULL
, 0, kCFStringEncodingASCII
);
656 for (j
= 0; !match
&& ifm_shared_option_descriptions
[j
].ifmt_string
; j
++) {
657 if (strcasecmp(str
, ifm_shared_option_descriptions
[j
].ifmt_string
) == 0) {
658 ifm_new
|= ifm_shared_option_descriptions
[j
].ifmt_word
;
664 if (option_descriptions
!= NULL
) {
665 for (j
= 0; !match
&& option_descriptions
[j
].ifmt_string
; j
++) {
666 if (strcasecmp(str
, option_descriptions
[j
].ifmt_string
) == 0) {
667 ifm_new
|= option_descriptions
[j
].ifmt_word
;
674 CFAllocatorDeallocate(NULL
, str
);
677 return -1; /* if no option */
686 SCNetworkInterfaceCopyMediaOptions(SCNetworkInterfaceRef interface
,
687 CFDictionaryRef
*current
,
688 CFDictionaryRef
*active
,
689 CFArrayRef
*available
,
693 struct ifmediareq
*ifm
;
694 CFStringRef interfaceName
;
696 if (!isA_SCNetworkInterface(interface
)) {
697 _SCErrorSet(kSCStatusInvalidArgument
);
701 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
702 if (interfaceName
== NULL
) {
703 _SCErrorSet(kSCStatusInvalidArgument
);
707 ifm
= __copyMediaList(interfaceName
);
712 if (active
!= NULL
) *active
= NULL
;
713 if (current
!= NULL
) *current
= NULL
;
714 if (available
!= NULL
) {
715 CFMutableArrayRef media_options
;
717 media_options
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
718 for (i
= 0; i
< ifm
->ifm_count
; i
++) {
719 CFDictionaryRef options
;
721 options
= __createMediaDictionary(ifm
->ifm_ulist
[i
], filter
);
722 if (options
== NULL
) {
726 if ((active
!= NULL
) && (*active
== NULL
) && (ifm
->ifm_active
== ifm
->ifm_ulist
[i
])) {
727 *active
= CFRetain(options
);
730 if ((current
!= NULL
) && (*current
== NULL
) && (ifm
->ifm_current
== ifm
->ifm_ulist
[i
])) {
731 *current
= CFRetain(options
);
734 if (!CFArrayContainsValue(media_options
, CFRangeMake(0, CFArrayGetCount(media_options
)), options
)) {
735 CFArrayAppendValue(media_options
, options
);
740 *available
= (CFArrayRef
)media_options
;
743 if ((active
!= NULL
) && (*active
== NULL
)) {
744 *active
= __createMediaDictionary(ifm
->ifm_active
, FALSE
);
747 if ((current
!= NULL
) && (*current
== NULL
)) {
748 if ((active
!= NULL
) && (ifm
->ifm_active
== ifm
->ifm_current
)) {
749 if (*active
!= NULL
) *current
= CFRetain(*active
);
751 *current
= __createMediaDictionary(ifm
->ifm_current
, FALSE
);
755 __freeMediaList(ifm
);
761 SCNetworkInterfaceCopyMediaSubTypes(CFArrayRef available
)
765 CFMutableArrayRef subTypes
;
767 if (!isA_CFArray(available
)) {
768 _SCErrorSet(kSCStatusInvalidArgument
);
772 subTypes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
774 n
= CFArrayGetCount(available
);
775 for (i
= 0; i
< n
; i
++) {
776 CFDictionaryRef options
;
779 options
= CFArrayGetValueAtIndex(available
, i
);
780 if (!isA_CFDictionary(options
)) {
784 subType
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
785 if (!isA_CFString(subType
)) {
789 if (!CFArrayContainsValue(subTypes
, CFRangeMake(0, CFArrayGetCount(subTypes
)), subType
)) {
790 CFArrayAppendValue(subTypes
, subType
);
794 if (CFArrayGetCount(subTypes
) == 0) {
797 _SCErrorSet(kSCStatusOK
);
805 SCNetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef available
,
810 CFMutableArrayRef subTypeOptions
;
812 if (!isA_CFArray(available
)) {
813 _SCErrorSet(kSCStatusInvalidArgument
);
817 subTypeOptions
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
819 n
= CFArrayGetCount(available
);
820 for (i
= 0; i
< n
; i
++) {
821 CFDictionaryRef options
;
822 CFArrayRef mediaOptions
;
823 CFStringRef mediaSubType
;
825 options
= CFArrayGetValueAtIndex(available
, i
);
826 if (!isA_CFDictionary(options
)) {
830 mediaSubType
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
831 if (!isA_CFString(mediaSubType
) || !CFEqual(subType
, mediaSubType
)) {
835 mediaOptions
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaOptions
);
836 if (!isA_CFArray(mediaOptions
)) {
840 if (!CFArrayContainsValue(subTypeOptions
, CFRangeMake(0, CFArrayGetCount(subTypeOptions
)), mediaOptions
)) {
841 CFArrayAppendValue(subTypeOptions
, mediaOptions
);
845 if (CFArrayGetCount(subTypeOptions
) == 0) {
846 CFRelease(subTypeOptions
);
847 subTypeOptions
= NULL
;
848 _SCErrorSet(kSCStatusOK
);
851 return subTypeOptions
;
856 _SCNetworkInterfaceIsPhysicalEthernet(SCNetworkInterfaceRef interface
)
859 struct ifmediareq
*ifm
;
860 CFStringRef interfaceName
;
861 Boolean realEthernet
= FALSE
;
863 if (!isA_SCNetworkInterface(interface
)) {
864 _SCErrorSet(kSCStatusInvalidArgument
);
868 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
869 if (interfaceName
== NULL
) {
870 _SCErrorSet(kSCStatusInvalidArgument
);
874 ifm
= __copyMediaList(interfaceName
);
876 CFStringRef interfaceType
;
878 interfaceType
= SCNetworkInterfaceGetInterfaceType(interface
);
879 if (CFEqual(interfaceType
, kSCNetworkInterfaceTypeEthernet
) &&
880 !_SCNetworkInterfaceIsTethered(interface
) &&
881 !_SCNetworkInterfaceIsBluetoothPAN(interface
)) {
882 // if likely physical ethernet interface
887 _SCErrorSet(kSCStatusOK
);
888 if (IFM_TYPE(ifm
->ifm_current
) != IFM_ETHER
) {
891 if (ifm
->ifm_count
== 1
892 && IFM_SUBTYPE(ifm
->ifm_ulist
[0]) == IFM_AUTO
) {
893 /* only support autoselect, not really ethernet */
896 for (i
= 0; i
< ifm
->ifm_count
; i
++) {
897 if ((ifm
->ifm_ulist
[i
] & IFM_FDX
) != 0) {
903 __freeMediaList(ifm
);
904 return (realEthernet
);
908 __getMTULimits(char ifr_name
[IFNAMSIZ
],
913 io_iterator_t io_iter
= 0;
914 io_registry_entry_t io_interface
= 0;
915 io_registry_entry_t io_controller
= 0;
917 static mach_port_t masterPort
= MACH_PORT_NULL
;
918 CFMutableDictionaryRef matchingDict
;
920 /* look for a matching interface in the IORegistry */
922 if (masterPort
== MACH_PORT_NULL
) {
923 kr
= IOMasterPort(MACH_PORT_NULL
, &masterPort
);
924 if (kr
!= KERN_SUCCESS
) {
929 matchingDict
= IOBSDNameMatching(masterPort
, 0, ifr_name
);
931 /* Note: IOServiceGetMatchingServices consumes a reference on the 'matchingDict' */
932 kr
= IOServiceGetMatchingServices(masterPort
, matchingDict
, &io_iter
);
933 if ((kr
== KERN_SUCCESS
) && io_iter
) {
934 /* should only have a single match */
935 io_interface
= IOIteratorNext(io_iter
);
937 if (io_iter
) IOObjectRelease(io_iter
);
944 * found an interface, get the interface type
946 num
= IORegistryEntryCreateCFProperty(io_interface
, CFSTR(kIOInterfaceType
), NULL
, kNilOptions
);
948 if (isA_CFNumber(num
)) {
949 CFNumberGetValue(num
, kCFNumberIntType
, &ifType
);
955 * ...and the property we are REALLY interested is in the controller,
956 * which is the parent of the interface object.
958 (void)IORegistryEntryGetParentEntry(io_interface
, kIOServicePlane
, &io_controller
);
959 IOObjectRelease(io_interface
);
961 /* if no matching interface */
968 num
= IORegistryEntryCreateCFProperty(io_controller
, CFSTR(kIOMaxPacketSize
), NULL
, kNilOptions
);
970 if (isA_CFNumber(num
)) {
974 * Get the value and subtract the FCS bytes and Ethernet header
975 * sizes from the maximum frame size reported by the controller
976 * to get the MTU size. The 14 byte media header can be found
977 * in the registry, but not the size for the trailing FCS bytes.
979 CFNumberGetValue(num
, kCFNumberIntType
, &value
);
981 if (ifType
== IFT_ETHER
) {
982 value
-= (ETHER_HDR_LEN
+ ETHER_CRC_LEN
);
985 if (mtu_min
) *mtu_min
= IF_MINMTU
;
986 if (mtu_max
) *mtu_max
= value
;
991 IOObjectRelease(io_controller
);
999 SCNetworkInterfaceCopyMTU(SCNetworkInterfaceRef interface
,
1005 CFStringRef interfaceName
;
1009 if (!isA_SCNetworkInterface(interface
)) {
1010 _SCErrorSet(kSCStatusInvalidArgument
);
1014 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
1015 if (interfaceName
== NULL
) {
1016 _SCErrorSet(kSCStatusInvalidArgument
);
1020 bzero((void *)&ifr
, sizeof(ifr
));
1021 if (_SC_cfstring_to_cstring(interfaceName
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
) == NULL
) {
1022 SC_log(LOG_NOTICE
, "could not convert interface name");
1023 _SCErrorSet(kSCStatusInvalidArgument
);
1027 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
1030 SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
));
1034 if (ioctl(sock
, SIOCGIFMTU
, (caddr_t
)&ifr
) == -1) {
1036 // SC_log(LOG_NOTICE, "ioctl(SIOCGIFMTU) failed: %s", strerror(errno));
1040 if (mtu_cur
) *mtu_cur
= ifr
.ifr_mtu
;
1041 if (mtu_min
) *mtu_min
= ifr
.ifr_mtu
;
1042 if (mtu_max
) *mtu_max
= ifr
.ifr_mtu
;
1044 /* get valid MTU range */
1046 if (mtu_min
!= NULL
|| mtu_max
!= NULL
) {
1047 if (ioctl(sock
, SIOCGIFDEVMTU
, (caddr_t
)&ifr
) == 0) {
1048 struct ifdevmtu
* devmtu_p
;
1050 devmtu_p
= &ifr
.ifr_devmtu
;
1051 if (mtu_min
!= NULL
) {
1052 *mtu_min
= (devmtu_p
->ifdm_min
> IF_MINMTU
)
1053 ? devmtu_p
->ifdm_min
: IF_MINMTU
;
1055 if (mtu_max
!= NULL
) {
1056 *mtu_max
= devmtu_p
->ifdm_max
;
1059 (void)__getMTULimits(ifr
.ifr_name
, mtu_min
, mtu_max
);
1062 if (mtu_min
!= NULL
) {
1063 #if IP_MSS > IPV6_MMTU
1064 if (*mtu_min
< IP_MSS
) {
1065 /* bump up the minimum MTU */
1066 *mtu_min
= IP_MSS
/*576*/;
1068 #else // IP_MSS > IPV6_MMTU
1069 if (*mtu_min
< IPV6_MMTU
) {
1070 /* bump up the minimum MTU */
1071 *mtu_min
= IPV6_MMTU
;
1073 #endif // IP_MSS > IPV6_MMTU
1075 if ((mtu_cur
!= NULL
) && (*mtu_min
> *mtu_cur
)) {
1076 /* min must be <= cur */
1077 *mtu_min
= *mtu_cur
;
1080 if ((mtu_max
!= NULL
) && (*mtu_min
> *mtu_max
)) {
1081 /* min must be <= max */
1082 *mtu_min
= *mtu_max
;
1097 SCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef interface
,
1098 CFStringRef subtype
,
1101 CFDictionaryRef configuration
;
1102 CFMutableDictionaryRef newConfiguration
= NULL
;
1105 if (!isA_SCNetworkInterface(interface
)) {
1106 _SCErrorSet(kSCStatusInvalidArgument
);
1110 configuration
= SCNetworkInterfaceGetConfiguration(interface
);
1111 if (configuration
== NULL
) {
1112 newConfiguration
= CFDictionaryCreateMutable(NULL
,
1114 &kCFTypeDictionaryKeyCallBacks
,
1115 &kCFTypeDictionaryValueCallBacks
);
1117 newConfiguration
= CFDictionaryCreateMutableCopy(NULL
, 0, configuration
);
1118 CFDictionaryRemoveValue(newConfiguration
, kSCResvInactive
);
1121 if (subtype
!= NULL
) {
1122 CFArrayRef available
= NULL
;
1123 CFArrayRef config_options
= options
;
1124 CFArrayRef subtypes
= NULL
;
1125 CFArrayRef subtype_options
= NULL
;
1127 if (options
== NULL
) {
1128 config_options
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
);
1131 if (!SCNetworkInterfaceCopyMediaOptions(interface
, NULL
, NULL
, &available
, FALSE
)) {
1132 SC_log(LOG_INFO
, "media type / options not available");
1136 if (available
== NULL
) {
1137 _SCErrorSet(kSCStatusInvalidArgument
);
1141 subtypes
= SCNetworkInterfaceCopyMediaSubTypes(available
);
1142 if ((subtypes
== NULL
) ||
1143 !CFArrayContainsValue(subtypes
,
1144 CFRangeMake(0, CFArrayGetCount(subtypes
)),
1146 SC_log(LOG_INFO
, "media type not valid");
1147 _SCErrorSet(kSCStatusInvalidArgument
);
1151 subtype_options
= SCNetworkInterfaceCopyMediaSubTypeOptions(available
, subtype
);
1152 if ((subtype_options
== NULL
) ||
1153 !CFArrayContainsValue(subtype_options
,
1154 CFRangeMake(0, CFArrayGetCount(subtype_options
)),
1156 SC_log(LOG_INFO
, "media options not valid for \"%@\"", subtype
);
1157 _SCErrorSet(kSCStatusInvalidArgument
);
1161 CFDictionarySetValue(newConfiguration
, kSCPropNetEthernetMediaSubType
, subtype
);
1162 CFDictionarySetValue(newConfiguration
,
1163 kSCPropNetEthernetMediaOptions
,
1164 (options
!= NULL
) ? options
: config_options
);
1170 if (available
!= NULL
) CFRelease(available
);
1171 if (subtypes
!= NULL
) CFRelease(subtypes
);
1172 if (subtype_options
!= NULL
) CFRelease(subtype_options
);
1173 if (options
== NULL
) CFRelease(config_options
);
1174 } else if (options
== NULL
) {
1175 CFDictionaryRemoveValue(newConfiguration
, kSCPropNetEthernetMediaSubType
);
1176 CFDictionaryRemoveValue(newConfiguration
, kSCPropNetEthernetMediaOptions
);
1177 if (CFDictionaryGetCount(newConfiguration
) == 0) {
1178 CFRelease(newConfiguration
);
1179 newConfiguration
= NULL
;
1183 SC_log(LOG_INFO
, "media type must be specified with options");
1184 _SCErrorSet(kSCStatusInvalidArgument
);
1188 ok
= SCNetworkInterfaceSetConfiguration(interface
, newConfiguration
);
1191 if (newConfiguration
!= NULL
) CFRelease(newConfiguration
);
1197 SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface
,
1200 CFDictionaryRef configuration
;
1203 CFMutableDictionaryRef newConfiguration
= NULL
;
1206 if (!isA_SCNetworkInterface(interface
)) {
1207 _SCErrorSet(kSCStatusInvalidArgument
);
1211 if (!SCNetworkInterfaceCopyMTU(interface
, NULL
, &mtu_min
, &mtu_max
)) {
1212 SC_log(LOG_INFO
, "MTU bounds not available");
1216 configuration
= SCNetworkInterfaceGetConfiguration(interface
);
1217 if (configuration
== NULL
) {
1218 newConfiguration
= CFDictionaryCreateMutable(NULL
,
1220 &kCFTypeDictionaryKeyCallBacks
,
1221 &kCFTypeDictionaryValueCallBacks
);
1223 newConfiguration
= CFDictionaryCreateMutableCopy(NULL
, 0, configuration
);
1224 CFDictionaryRemoveValue(newConfiguration
, kSCResvInactive
);
1227 if ((mtu
>= mtu_min
) && (mtu
<= mtu_max
)) {
1230 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &mtu
);
1231 CFDictionarySetValue(newConfiguration
, kSCPropNetEthernetMTU
, num
);
1234 } else if (mtu
== 0) {
1235 CFDictionaryRemoveValue(newConfiguration
, kSCPropNetEthernetMTU
);
1236 if (CFDictionaryGetCount(newConfiguration
) == 0) {
1237 CFRelease(newConfiguration
);
1238 newConfiguration
= NULL
;
1242 SC_log(LOG_INFO
, "MTU out of range");
1243 _SCErrorSet(kSCStatusInvalidArgument
);
1247 ok
= SCNetworkInterfaceSetConfiguration(interface
, newConfiguration
);
1250 if (newConfiguration
!= NULL
) CFRelease(newConfiguration
);