2 * Copyright (c) 2002-2007, 2010, 2011 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) {
124 SCLog(TRUE
, LOG_ERR
, CFSTR("ioctl(SIOCGIFCAP) failed: %s"), strerror(errno
));
128 if (current
!= NULL
) *current
= ifr
.ifr_curcap
;
129 if (available
!= NULL
) *available
= ifr
.ifr_reqcap
;
138 if (current
!= NULL
) *current
= 0;
139 if (available
!= NULL
) *available
= 0;
146 __SCNetworkInterfaceCreateCapabilities(SCNetworkInterfaceRef interface
,
148 CFDictionaryRef capability_options
)
150 int cap_available
= 0;
151 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 (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;
217 CFStringRef interfaceName
;
218 CFTypeRef val
= NULL
;
220 if (!isA_SCNetworkInterface(interface
)) {
221 _SCErrorSet(kSCStatusInvalidArgument
);
225 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
226 if (interfaceName
== NULL
) {
227 _SCErrorSet(kSCStatusInvalidArgument
);
231 if (!__getCapabilities(interfaceName
, &cap_current
, &cap_available
)) {
235 if (capability
== NULL
) {
236 CFMutableDictionaryRef all
= NULL
;
238 // if ALL capabilities requested
239 for (i
= 0; i
< sizeof(capabilityMappings
) / sizeof(capabilityMappings
[0]); i
++) {
240 if ((cap_available
& capabilityMappings
[i
].val
) == capabilityMappings
[i
].val
) {
242 all
= CFDictionaryCreateMutable(NULL
,
244 &kCFTypeDictionaryKeyCallBacks
,
245 &kCFTypeDictionaryValueCallBacks
);
247 cap_val
= ((cap_current
& capabilityMappings
[i
].val
) == capabilityMappings
[i
].val
) ? 1 : 0;
248 val
= CFNumberCreate(NULL
, kCFNumberIntType
, &cap_val
);
249 CFDictionarySetValue(all
, *capabilityMappings
[i
].name
, val
);
251 cap_available
&= ~capabilityMappings
[i
].val
;
257 i
= findCapability(capability
);
258 if (i
== kCFNotFound
) {
259 // if unknown capability
260 _SCErrorSet(kSCStatusInvalidArgument
);
264 if ((cap_available
& capabilityMappings
[i
].val
) != capabilityMappings
[i
].val
) {
265 // if capability not available
266 _SCErrorSet(kSCStatusInvalidArgument
);
270 cap_val
= ((cap_current
& capabilityMappings
[i
].val
) == capabilityMappings
[i
].val
) ? 1 : 0;
271 val
= CFNumberCreate(NULL
, kCFNumberIntType
, &cap_val
);
279 SCNetworkInterfaceSetCapability(SCNetworkInterfaceRef interface
,
280 CFStringRef capability
,
283 int cap_available
= 0;
284 CFDictionaryRef configuration
;
286 CFStringRef interfaceName
;
287 CFMutableDictionaryRef newConfiguration
= NULL
;
290 if (!isA_SCNetworkInterface(interface
)) {
291 _SCErrorSet(kSCStatusInvalidArgument
);
295 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
296 if (interfaceName
== NULL
) {
297 // if no interface name
298 _SCErrorSet(kSCStatusInvalidArgument
);
302 i
= findCapability(capability
);
303 if (i
== kCFNotFound
) {
304 // if unknown capability
305 _SCErrorSet(kSCStatusInvalidArgument
);
309 if (!capabilityMappings
[i
].readwrite
) {
311 _SCErrorSet(kSCStatusInvalidArgument
);
315 if ((newValue
!= NULL
) && !isA_CFNumber(newValue
)) {
316 // all values must (for now) be CFNumber[0 or 1]'s
317 _SCErrorSet(kSCStatusInvalidArgument
);
321 if (!__getCapabilities(interfaceName
, NULL
, &cap_available
)) {
325 if ((cap_available
& capabilityMappings
[i
].val
) == 0) {
326 // if capability not available
327 _SCErrorSet(kSCStatusInvalidArgument
);
331 configuration
= SCNetworkInterfaceGetConfiguration(interface
);
332 if (configuration
== NULL
) {
333 newConfiguration
= CFDictionaryCreateMutable(NULL
,
335 &kCFTypeDictionaryKeyCallBacks
,
336 &kCFTypeDictionaryValueCallBacks
);
338 newConfiguration
= CFDictionaryCreateMutableCopy(NULL
, 0, configuration
);
339 CFDictionaryRemoveValue(newConfiguration
, kSCResvInactive
);
342 if ((newValue
!= NULL
)) {
343 CFDictionarySetValue(newConfiguration
, capability
, newValue
);
345 CFDictionaryRemoveValue(newConfiguration
, capability
);
346 if (CFDictionaryGetCount(newConfiguration
) == 0) {
347 CFRelease(newConfiguration
);
348 newConfiguration
= NULL
;
352 ok
= SCNetworkInterfaceSetConfiguration(interface
, newConfiguration
);
353 if (newConfiguration
!= NULL
) CFRelease(newConfiguration
);
360 #pragma mark Media Options
363 static const struct ifmedia_description ifm_subtype_shared_descriptions
[] =
364 IFM_SUBTYPE_SHARED_DESCRIPTIONS
;
366 static const struct ifmedia_description ifm_subtype_ethernet_descriptions
[] =
367 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS
;
369 static const struct ifmedia_description ifm_subtype_ieee80211_descriptions
[] =
370 IFM_SUBTYPE_IEEE80211_DESCRIPTIONS
;
372 static const struct ifmedia_description ifm_shared_option_descriptions
[] =
373 IFM_SHARED_OPTION_DESCRIPTIONS
;
375 static const struct ifmedia_description ifm_subtype_ethernet_option_descriptions
[] =
376 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS
;
378 static const struct ifmedia_description ifm_subtype_ieee80211_option_descriptions
[] =
379 IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS
;
383 __freeMediaList(struct ifmediareq
*ifm
)
385 if (ifm
->ifm_ulist
!= NULL
) CFAllocatorDeallocate(NULL
, ifm
->ifm_ulist
);
386 CFAllocatorDeallocate(NULL
, ifm
);
391 static struct ifmediareq
*
392 __copyMediaList(CFStringRef interfaceName
)
394 struct ifmediareq
*ifm
;
398 ifm
= (struct ifmediareq
*)CFAllocatorAllocate(NULL
, sizeof(struct ifmediareq
), 0);
399 bzero((void *)ifm
, sizeof(*ifm
));
401 if (_SC_cfstring_to_cstring(interfaceName
, ifm
->ifm_name
, sizeof(ifm
->ifm_name
), kCFStringEncodingASCII
) == NULL
) {
402 SCLog(TRUE
, LOG_ERR
, CFSTR("could not convert interface name"));
406 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
408 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
412 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)ifm
) == -1) {
413 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno));
417 if (ifm
->ifm_count
> 0) {
418 ifm
->ifm_ulist
= (int *)CFAllocatorAllocate(NULL
, ifm
->ifm_count
* sizeof(int), 0);
419 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)ifm
) == -1) {
420 SCLog(TRUE
, LOG_DEBUG
, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno
));
429 if (sock
!= -1) (void)close(sock
);
431 __freeMediaList(ifm
);
433 _SCErrorSet(kSCStatusFailed
);
439 static CFDictionaryRef
440 __createMediaDictionary(int media_options
, Boolean filter
)
442 CFMutableDictionaryRef dict
= NULL
;
444 const struct ifmedia_description
*option_descriptions
= NULL
;
445 CFMutableArrayRef options
= NULL
;
446 const struct ifmedia_description
*subtype_descriptions
= NULL
;
450 ((IFM_SUBTYPE(media_options
) == IFM_NONE
) ||
451 ((IFM_OPTIONS(media_options
) & IFM_LOOP
) != 0))) {
452 return NULL
; /* filter */
455 switch (IFM_TYPE(media_options
)) {
457 option_descriptions
= ifm_subtype_ethernet_option_descriptions
;
458 subtype_descriptions
= ifm_subtype_ethernet_descriptions
;
461 option_descriptions
= ifm_subtype_ieee80211_option_descriptions
;
462 subtype_descriptions
= ifm_subtype_ieee80211_descriptions
;
468 dict
= CFDictionaryCreateMutable(NULL
,
470 &kCFTypeDictionaryKeyCallBacks
,
471 &kCFTypeDictionaryValueCallBacks
);
476 for (i
= 0; !val
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) {
477 if (IFM_SUBTYPE(media_options
) == ifm_subtype_shared_descriptions
[i
].ifmt_word
) {
478 val
= CFStringCreateWithCString(NULL
,
479 ifm_subtype_shared_descriptions
[i
].ifmt_string
,
480 kCFStringEncodingASCII
);
485 if (subtype_descriptions
!= NULL
) {
486 for (i
= 0; !val
&& subtype_descriptions
[i
].ifmt_string
; i
++) {
487 if (IFM_SUBTYPE(media_options
) == subtype_descriptions
[i
].ifmt_word
) {
488 val
= CFStringCreateWithCString(NULL
,
489 subtype_descriptions
[i
].ifmt_string
,
490 kCFStringEncodingASCII
);
497 CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaSubType
, val
);
503 options
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
505 for (i
= 0; (IFM_OPTIONS(media_options
) != 0) && (ifm_shared_option_descriptions
[i
].ifmt_string
!= NULL
); i
++) {
506 if ((media_options
& ifm_shared_option_descriptions
[i
].ifmt_word
) != 0) {
507 val
= CFStringCreateWithCString(NULL
,
508 ifm_shared_option_descriptions
[i
].ifmt_string
,
509 kCFStringEncodingASCII
);
510 CFArrayAppendValue(options
, val
);
513 media_options
&= ~ifm_shared_option_descriptions
[i
].ifmt_word
;
517 if (option_descriptions
!= NULL
) {
518 for (i
= 0; (IFM_OPTIONS(media_options
) != 0) && (option_descriptions
[i
].ifmt_string
!= NULL
); i
++) {
519 if ((media_options
& option_descriptions
[i
].ifmt_word
) != 0) {
520 val
= CFStringCreateWithCString(NULL
,
521 option_descriptions
[i
].ifmt_string
,
522 kCFStringEncodingASCII
);
523 CFArrayAppendValue(options
, val
);
526 media_options
&= ~option_descriptions
[i
].ifmt_word
;
531 CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaOptions
, options
);
539 __SCNetworkInterfaceCreateMediaOptions(SCNetworkInterfaceRef interface
, CFDictionaryRef media_options
)
542 struct ifmediareq
*ifm
;
544 CFStringRef interfaceName
;
547 const struct ifmedia_description
*option_descriptions
= NULL
;
550 const struct ifmedia_description
*subtype_descriptions
= NULL
;
553 if (!isA_SCNetworkInterface(interface
)) {
554 _SCErrorSet(kSCStatusInvalidArgument
);
558 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
559 if (interfaceName
== NULL
) {
560 _SCErrorSet(kSCStatusInvalidArgument
);
566 ifm
= __copyMediaList(interfaceName
);
568 if (ifm
->ifm_count
> 0) {
569 ifm_new
= IFM_TYPE(ifm
->ifm_ulist
[0]);
571 __freeMediaList(ifm
);
575 // if we cannot determine the media type for the interface
579 switch (IFM_TYPE(ifm_new
)) {
581 option_descriptions
= ifm_subtype_ethernet_option_descriptions
;
582 subtype_descriptions
= ifm_subtype_ethernet_descriptions
;
585 option_descriptions
= ifm_subtype_ieee80211_option_descriptions
;
586 subtype_descriptions
= ifm_subtype_ieee80211_descriptions
;
592 val
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaSubType
);
593 if (!isA_CFString(val
)) {
597 str
= _SC_cfstring_to_cstring(val
, NULL
, 0, kCFStringEncodingASCII
);
603 for (i
= 0; !match
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) {
604 if (strcasecmp(str
, ifm_subtype_shared_descriptions
[i
].ifmt_string
) == 0) {
605 ifm_new
|= ifm_subtype_shared_descriptions
[i
].ifmt_word
;
611 if (subtype_descriptions
!= NULL
) {
612 for (i
= 0; !match
&& subtype_descriptions
[i
].ifmt_string
; i
++) {
613 if (strcasecmp(str
, subtype_descriptions
[i
].ifmt_string
) == 0) {
614 ifm_new
|= subtype_descriptions
[i
].ifmt_word
;
621 CFAllocatorDeallocate(NULL
, str
);
624 return -1; /* if no subtype */
629 options
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaOptions
);
630 if (!isA_CFArray(options
)) {
634 n
= CFArrayGetCount(options
);
635 for (i
= 0; i
< n
; i
++) {
638 val
= CFArrayGetValueAtIndex(options
, i
);
639 if (!isA_CFString(val
)) {
643 str
= _SC_cfstring_to_cstring(val
, NULL
, 0, kCFStringEncodingASCII
);
650 for (j
= 0; !match
&& ifm_shared_option_descriptions
[j
].ifmt_string
; j
++) {
651 if (strcasecmp(str
, ifm_shared_option_descriptions
[j
].ifmt_string
) == 0) {
652 ifm_new
|= ifm_shared_option_descriptions
[j
].ifmt_word
;
658 if (option_descriptions
!= NULL
) {
659 for (j
= 0; !match
&& option_descriptions
[j
].ifmt_string
; j
++) {
660 if (strcasecmp(str
, option_descriptions
[j
].ifmt_string
) == 0) {
661 ifm_new
|= option_descriptions
[j
].ifmt_word
;
668 CFAllocatorDeallocate(NULL
, str
);
671 return -1; /* if no option */
680 SCNetworkInterfaceCopyMediaOptions(SCNetworkInterfaceRef interface
,
681 CFDictionaryRef
*current
,
682 CFDictionaryRef
*active
,
683 CFArrayRef
*available
,
687 struct ifmediareq
*ifm
;
688 CFStringRef interfaceName
;
690 if (!isA_SCNetworkInterface(interface
)) {
691 _SCErrorSet(kSCStatusInvalidArgument
);
695 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
696 if (interfaceName
== NULL
) {
697 _SCErrorSet(kSCStatusInvalidArgument
);
701 ifm
= __copyMediaList(interfaceName
);
706 if (active
!= NULL
) *active
= NULL
;
707 if (current
!= NULL
) *current
= NULL
;
708 if (available
!= NULL
) {
709 CFMutableArrayRef media_options
;
711 media_options
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
712 for (i
= 0; i
< ifm
->ifm_count
; i
++) {
713 CFDictionaryRef options
;
715 options
= __createMediaDictionary(ifm
->ifm_ulist
[i
], filter
);
716 if (options
== NULL
) {
720 if ((active
!= NULL
) && (*active
== NULL
) && (ifm
->ifm_active
== ifm
->ifm_ulist
[i
])) {
721 *active
= CFRetain(options
);
724 if ((current
!= NULL
) && (*current
== NULL
) && (ifm
->ifm_current
== ifm
->ifm_ulist
[i
])) {
725 *current
= CFRetain(options
);
728 if (!CFArrayContainsValue(media_options
, CFRangeMake(0, CFArrayGetCount(media_options
)), options
)) {
729 CFArrayAppendValue(media_options
, options
);
734 *available
= (CFArrayRef
)media_options
;
737 if ((active
!= NULL
) && (*active
== NULL
)) {
738 *active
= __createMediaDictionary(ifm
->ifm_active
, FALSE
);
741 if ((current
!= NULL
) && (*current
== NULL
)) {
742 if ((active
!= NULL
) && (ifm
->ifm_active
== ifm
->ifm_current
)) {
743 if (*active
!= NULL
) *current
= CFRetain(*active
);
745 *current
= __createMediaDictionary(ifm
->ifm_current
, FALSE
);
749 __freeMediaList(ifm
);
755 SCNetworkInterfaceCopyMediaSubTypes(CFArrayRef available
)
759 CFMutableArrayRef subTypes
;
761 if (!isA_CFArray(available
)) {
762 _SCErrorSet(kSCStatusInvalidArgument
);
766 subTypes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
768 n
= CFArrayGetCount(available
);
769 for (i
= 0; i
< n
; i
++) {
770 CFDictionaryRef options
;
773 options
= CFArrayGetValueAtIndex(available
, i
);
774 if (!isA_CFDictionary(options
)) {
778 subType
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
779 if (!isA_CFString(subType
)) {
783 if (!CFArrayContainsValue(subTypes
, CFRangeMake(0, CFArrayGetCount(subTypes
)), subType
)) {
784 CFArrayAppendValue(subTypes
, subType
);
788 if (CFArrayGetCount(subTypes
) == 0) {
791 _SCErrorSet(kSCStatusOK
);
799 SCNetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef available
,
804 CFMutableArrayRef subTypeOptions
;
806 if (!isA_CFArray(available
)) {
807 _SCErrorSet(kSCStatusInvalidArgument
);
811 subTypeOptions
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
813 n
= CFArrayGetCount(available
);
814 for (i
= 0; i
< n
; i
++) {
815 CFDictionaryRef options
;
816 CFArrayRef mediaOptions
;
817 CFStringRef mediaSubType
;
819 options
= CFArrayGetValueAtIndex(available
, i
);
820 if (!isA_CFDictionary(options
)) {
824 mediaSubType
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
825 if (!isA_CFString(mediaSubType
) || !CFEqual(subType
, mediaSubType
)) {
829 mediaOptions
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaOptions
);
830 if (!isA_CFArray(mediaOptions
)) {
834 if (!CFArrayContainsValue(subTypeOptions
, CFRangeMake(0, CFArrayGetCount(subTypeOptions
)), mediaOptions
)) {
835 CFArrayAppendValue(subTypeOptions
, mediaOptions
);
839 if (CFArrayGetCount(subTypeOptions
) == 0) {
840 CFRelease(subTypeOptions
);
841 subTypeOptions
= NULL
;
842 _SCErrorSet(kSCStatusOK
);
845 return subTypeOptions
;
850 _SCNetworkInterfaceIsPhysicalEthernet(SCNetworkInterfaceRef interface
)
853 struct ifmediareq
*ifm
;
854 CFStringRef interfaceName
;
855 Boolean realEthernet
= FALSE
;
857 if (!isA_SCNetworkInterface(interface
)) {
858 _SCErrorSet(kSCStatusInvalidArgument
);
862 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
863 if (interfaceName
== NULL
) {
864 _SCErrorSet(kSCStatusInvalidArgument
);
868 ifm
= __copyMediaList(interfaceName
);
872 _SCErrorSet(kSCStatusOK
);
873 if (IFM_TYPE(ifm
->ifm_current
) != IFM_ETHER
) {
876 if (ifm
->ifm_count
== 1
877 && IFM_SUBTYPE(ifm
->ifm_ulist
[0]) == IFM_AUTO
) {
878 /* only support autoselect, not really ethernet */
881 for (i
= 0; i
< ifm
->ifm_count
; i
++) {
882 if ((ifm
->ifm_ulist
[i
] & IFM_FDX
) != 0) {
888 __freeMediaList(ifm
);
889 return (realEthernet
);
893 __getMTULimits(char ifr_name
[IFNAMSIZ
],
898 io_iterator_t io_iter
= 0;
899 io_registry_entry_t io_interface
= 0;
900 io_registry_entry_t io_controller
= 0;
902 static mach_port_t masterPort
= MACH_PORT_NULL
;
903 CFMutableDictionaryRef matchingDict
;
905 /* look for a matching interface in the IORegistry */
907 if (masterPort
== MACH_PORT_NULL
) {
908 kr
= IOMasterPort(MACH_PORT_NULL
, &masterPort
);
909 if (kr
!= KERN_SUCCESS
) {
914 matchingDict
= IOBSDNameMatching(masterPort
, 0, ifr_name
);
916 /* Note: IOServiceGetMatchingServices consumes a reference on the 'matchingDict' */
917 kr
= IOServiceGetMatchingServices(masterPort
, matchingDict
, &io_iter
);
918 if ((kr
== KERN_SUCCESS
) && io_iter
) {
919 /* should only have a single match */
920 io_interface
= IOIteratorNext(io_iter
);
922 if (io_iter
) IOObjectRelease(io_iter
);
929 * found an interface, get the interface type
931 num
= IORegistryEntryCreateCFProperty(io_interface
, CFSTR(kIOInterfaceType
), NULL
, kNilOptions
);
933 if (isA_CFNumber(num
)) {
934 CFNumberGetValue(num
, kCFNumberIntType
, &ifType
);
940 * ...and the property we are REALLY interested is in the controller,
941 * which is the parent of the interface object.
943 (void)IORegistryEntryGetParentEntry(io_interface
, kIOServicePlane
, &io_controller
);
944 IOObjectRelease(io_interface
);
946 /* if no matching interface */
953 num
= IORegistryEntryCreateCFProperty(io_controller
, CFSTR(kIOMaxPacketSize
), NULL
, kNilOptions
);
955 if (isA_CFNumber(num
)) {
959 * Get the value and subtract the FCS bytes and Ethernet header
960 * sizes from the maximum frame size reported by the controller
961 * to get the MTU size. The 14 byte media header can be found
962 * in the registry, but not the size for the trailing FCS bytes.
964 CFNumberGetValue(num
, kCFNumberIntType
, &value
);
966 if (ifType
== IFT_ETHER
) {
967 value
-= (ETHER_HDR_LEN
+ ETHER_CRC_LEN
);
970 if (mtu_min
) *mtu_min
= IF_MINMTU
;
971 if (mtu_max
) *mtu_max
= value
;
976 IOObjectRelease(io_controller
);
984 SCNetworkInterfaceCopyMTU(SCNetworkInterfaceRef interface
,
990 CFStringRef interfaceName
;
994 if (!isA_SCNetworkInterface(interface
)) {
995 _SCErrorSet(kSCStatusInvalidArgument
);
999 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
1000 if (interfaceName
== NULL
) {
1001 _SCErrorSet(kSCStatusInvalidArgument
);
1005 bzero((void *)&ifr
, sizeof(ifr
));
1006 if (_SC_cfstring_to_cstring(interfaceName
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
) == NULL
) {
1007 SCLog(TRUE
, LOG_ERR
, CFSTR("could not convert interface name"));
1008 _SCErrorSet(kSCStatusInvalidArgument
);
1012 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
1015 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
1019 if (ioctl(sock
, SIOCGIFMTU
, (caddr_t
)&ifr
) == -1) {
1021 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMTU) failed: %s"), strerror(errno));
1025 if (mtu_cur
) *mtu_cur
= ifr
.ifr_mtu
;
1026 if (mtu_min
) *mtu_min
= ifr
.ifr_mtu
;
1027 if (mtu_max
) *mtu_max
= ifr
.ifr_mtu
;
1029 /* get valid MTU range */
1031 if (mtu_min
!= NULL
|| mtu_max
!= NULL
) {
1032 if (ioctl(sock
, SIOCGIFDEVMTU
, (caddr_t
)&ifr
) == 0) {
1033 struct ifdevmtu
* devmtu_p
;
1035 devmtu_p
= &ifr
.ifr_devmtu
;
1036 if (mtu_min
!= NULL
) {
1037 *mtu_min
= (devmtu_p
->ifdm_min
> IF_MINMTU
)
1038 ? devmtu_p
->ifdm_min
: IF_MINMTU
;
1040 if (mtu_max
!= NULL
) {
1041 *mtu_max
= devmtu_p
->ifdm_max
;
1044 (void)__getMTULimits(ifr
.ifr_name
, mtu_min
, mtu_max
);
1047 if (mtu_min
!= NULL
) {
1048 #if IP_MSS > IPV6_MMTU
1049 if (*mtu_min
< IP_MSS
) {
1050 /* bump up the minimum MTU */
1051 *mtu_min
= IP_MSS
/*576*/;
1053 #else // IP_MSS > IPV6_MMTU
1054 if (*mtu_min
< IPV6_MMTU
) {
1055 /* bump up the minimum MTU */
1056 *mtu_min
= IPV6_MMTU
;
1058 #endif // IP_MSS > IPV6_MMTU
1060 if ((mtu_cur
!= NULL
) && (*mtu_min
> *mtu_cur
)) {
1061 /* min must be <= cur */
1062 *mtu_min
= *mtu_cur
;
1065 if ((mtu_max
!= NULL
) && (*mtu_min
> *mtu_max
)) {
1066 /* min must be <= max */
1067 *mtu_min
= *mtu_max
;
1082 SCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef interface
,
1083 CFStringRef subtype
,
1086 CFDictionaryRef configuration
;
1087 CFMutableDictionaryRef newConfiguration
= NULL
;
1090 if (!isA_SCNetworkInterface(interface
)) {
1091 _SCErrorSet(kSCStatusInvalidArgument
);
1095 configuration
= SCNetworkInterfaceGetConfiguration(interface
);
1096 if (configuration
== NULL
) {
1097 newConfiguration
= CFDictionaryCreateMutable(NULL
,
1099 &kCFTypeDictionaryKeyCallBacks
,
1100 &kCFTypeDictionaryValueCallBacks
);
1102 newConfiguration
= CFDictionaryCreateMutableCopy(NULL
, 0, configuration
);
1103 CFDictionaryRemoveValue(newConfiguration
, kSCResvInactive
);
1106 if (subtype
!= NULL
) {
1107 CFArrayRef available
= NULL
;
1108 CFArrayRef config_options
= options
;
1109 CFArrayRef subtypes
= NULL
;
1110 CFArrayRef subtype_options
= NULL
;
1112 if (options
== NULL
) {
1113 config_options
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
);
1116 if (!SCNetworkInterfaceCopyMediaOptions(interface
, NULL
, NULL
, &available
, FALSE
)) {
1117 SCLog(_sc_debug
, LOG_DEBUG
, CFSTR("media type / options not available"));
1121 if (available
== NULL
) {
1122 _SCErrorSet(kSCStatusInvalidArgument
);
1126 subtypes
= SCNetworkInterfaceCopyMediaSubTypes(available
);
1127 if ((subtypes
== NULL
) ||
1128 !CFArrayContainsValue(subtypes
,
1129 CFRangeMake(0, CFArrayGetCount(subtypes
)),
1131 SCLog(_sc_debug
, LOG_DEBUG
, CFSTR("media type not valid"));
1132 _SCErrorSet(kSCStatusInvalidArgument
);
1136 subtype_options
= SCNetworkInterfaceCopyMediaSubTypeOptions(available
, subtype
);
1137 if ((subtype_options
== NULL
) ||
1138 !CFArrayContainsValue(subtype_options
,
1139 CFRangeMake(0, CFArrayGetCount(subtype_options
)),
1141 SCLog(_sc_debug
, LOG_DEBUG
, CFSTR("media options not valid for \"%@\""), subtype
);
1142 _SCErrorSet(kSCStatusInvalidArgument
);
1146 CFDictionarySetValue(newConfiguration
, kSCPropNetEthernetMediaSubType
, subtype
);
1147 CFDictionarySetValue(newConfiguration
,
1148 kSCPropNetEthernetMediaOptions
,
1149 (options
!= NULL
) ? options
: config_options
);
1155 if (available
!= NULL
) CFRelease(available
);
1156 if (subtypes
!= NULL
) CFRelease(subtypes
);
1157 if (subtype_options
!= NULL
) CFRelease(subtype_options
);
1158 if (options
== NULL
) CFRelease(config_options
);
1159 } else if (options
== NULL
) {
1160 CFDictionaryRemoveValue(newConfiguration
, kSCPropNetEthernetMediaSubType
);
1161 CFDictionaryRemoveValue(newConfiguration
, kSCPropNetEthernetMediaOptions
);
1162 if (CFDictionaryGetCount(newConfiguration
) == 0) {
1163 CFRelease(newConfiguration
);
1164 newConfiguration
= NULL
;
1168 SCLog(_sc_debug
, LOG_DEBUG
, CFSTR("media type must be specified with options"));
1169 _SCErrorSet(kSCStatusInvalidArgument
);
1173 ok
= SCNetworkInterfaceSetConfiguration(interface
, newConfiguration
);
1176 if (newConfiguration
!= NULL
) CFRelease(newConfiguration
);
1182 SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface
,
1185 CFDictionaryRef configuration
;
1188 CFMutableDictionaryRef newConfiguration
= NULL
;
1191 if (!isA_SCNetworkInterface(interface
)) {
1192 _SCErrorSet(kSCStatusInvalidArgument
);
1196 if (!SCNetworkInterfaceCopyMTU(interface
, NULL
, &mtu_min
, &mtu_max
)) {
1197 SCLog(_sc_debug
, LOG_DEBUG
, CFSTR("MTU bounds not available"));
1201 configuration
= SCNetworkInterfaceGetConfiguration(interface
);
1202 if (configuration
== NULL
) {
1203 newConfiguration
= CFDictionaryCreateMutable(NULL
,
1205 &kCFTypeDictionaryKeyCallBacks
,
1206 &kCFTypeDictionaryValueCallBacks
);
1208 newConfiguration
= CFDictionaryCreateMutableCopy(NULL
, 0, configuration
);
1209 CFDictionaryRemoveValue(newConfiguration
, kSCResvInactive
);
1212 if ((mtu
>= mtu_min
) && (mtu
<= mtu_max
)) {
1215 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &mtu
);
1216 CFDictionarySetValue(newConfiguration
, kSCPropNetEthernetMTU
, num
);
1219 } else if (mtu
== 0) {
1220 CFDictionaryRemoveValue(newConfiguration
, kSCPropNetEthernetMTU
);
1221 if (CFDictionaryGetCount(newConfiguration
) == 0) {
1222 CFRelease(newConfiguration
);
1223 newConfiguration
= NULL
;
1227 SCLog(_sc_debug
, LOG_DEBUG
, CFSTR("MTU out of range"));
1228 _SCErrorSet(kSCStatusInvalidArgument
);
1232 ok
= SCNetworkInterfaceSetConfiguration(interface
, newConfiguration
);
1235 if (newConfiguration
!= NULL
) CFRelease(newConfiguration
);
1241 // XXXXX Remove the following SPIs as soon as we have migrated all
1242 // XXXXX internal users
1245 /* DEPRECATED */ Boolean
1246 NetworkInterfaceCopyMediaOptions(CFStringRef interfaceName
,
1247 CFDictionaryRef
*current
,
1248 CFDictionaryRef
*active
,
1249 CFArrayRef
*available
,
1252 SCNetworkInterfacePrivateRef interfacePrivate
;
1255 interfacePrivate
= __SCNetworkInterfaceCreatePrivate(NULL
, NULL
, NULL
, NULL
, NULL
);
1256 if (interfacePrivate
== NULL
) {
1259 interfacePrivate
->entity_device
= CFRetain(interfaceName
);
1260 ok
= SCNetworkInterfaceCopyMediaOptions((SCNetworkInterfaceRef
)interfacePrivate
,
1265 CFRelease(interfacePrivate
);
1270 /* DEPRECATED */ CFArrayRef
1271 NetworkInterfaceCopyMediaSubTypes(CFArrayRef available
)
1273 return SCNetworkInterfaceCopyMediaSubTypes(available
);
1277 /* DEPRECATED */ CFArrayRef
1278 NetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef available
,
1279 CFStringRef subType
)
1281 return SCNetworkInterfaceCopyMediaSubTypeOptions(available
, subType
);
1285 /* DEPRECATED */ Boolean
1286 NetworkInterfaceCopyMTU(CFStringRef interfaceName
,
1291 SCNetworkInterfacePrivateRef interfacePrivate
;
1294 interfacePrivate
= __SCNetworkInterfaceCreatePrivate(NULL
, NULL
, NULL
, NULL
, NULL
);
1295 if (interfacePrivate
== NULL
) {
1298 interfacePrivate
->entity_device
= CFRetain(interfaceName
);
1299 ok
= SCNetworkInterfaceCopyMTU((SCNetworkInterfaceRef
)interfacePrivate
,
1303 CFRelease(interfacePrivate
);