2 * Copyright (c) 2002-2005 Apple Computer, 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>
43 #include <SystemConfiguration/SystemConfiguration.h>
44 #include <SystemConfiguration/SCPrivate.h> // for SCLog()
45 #include <SystemConfiguration/SCValidation.h>
47 #include <IOKit/IOKitLib.h>
48 #include <IOKit/network/IONetworkInterface.h>
49 #include <IOKit/network/IONetworkController.h>
50 #include "dy_framework.h"
53 static const struct ifmedia_description ifm_subtype_shared_descriptions
[] =
54 IFM_SUBTYPE_SHARED_DESCRIPTIONS
;
56 static const struct ifmedia_description ifm_subtype_ethernet_descriptions
[] =
57 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS
;
59 static const struct ifmedia_description ifm_subtype_ieee80211_descriptions
[] =
60 IFM_SUBTYPE_IEEE80211_DESCRIPTIONS
;
62 static const struct ifmedia_description ifm_shared_option_descriptions
[] =
63 IFM_SHARED_OPTION_DESCRIPTIONS
;
65 static const struct ifmedia_description ifm_subtype_ethernet_option_descriptions
[] =
66 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS
;
68 static const struct ifmedia_description ifm_subtype_ieee80211_option_descriptions
[] =
69 IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS
;
73 __freeMediaList(struct ifmediareq
*ifm
)
75 if (ifm
->ifm_ulist
!= NULL
) CFAllocatorDeallocate(NULL
, ifm
->ifm_ulist
);
76 CFAllocatorDeallocate(NULL
, ifm
);
81 static struct ifmediareq
*
82 __copyMediaList(CFStringRef interface
)
84 struct ifmediareq
*ifm
;
88 ifm
= (struct ifmediareq
*)CFAllocatorAllocate(NULL
, sizeof(struct ifmediareq
), 0);
89 bzero((void *)ifm
, sizeof(*ifm
));
91 if (_SC_cfstring_to_cstring(interface
, ifm
->ifm_name
, sizeof(ifm
->ifm_name
), kCFStringEncodingASCII
) == NULL
) {
92 SCLog(TRUE
, LOG_ERR
, CFSTR("could not convert inteface name"));
96 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
98 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
102 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)ifm
) == -1) {
103 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno));
107 if (ifm
->ifm_count
> 0) {
108 ifm
->ifm_ulist
= (int *)CFAllocatorAllocate(NULL
, ifm
->ifm_count
* sizeof(int), 0);
109 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)ifm
) == -1) {
110 SCLog(TRUE
, LOG_DEBUG
, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno
));
119 if (sock
!= -1) (void)close(sock
);
121 __freeMediaList(ifm
);
128 static CFDictionaryRef
129 __createMediaDictionary(int media_options
, Boolean filter
)
131 CFMutableDictionaryRef dict
= NULL
;
133 const struct ifmedia_description
*option_descriptions
= NULL
;
134 CFMutableArrayRef options
= NULL
;
135 const struct ifmedia_description
*subtype_descriptions
= NULL
;
138 switch (IFM_TYPE(media_options
)) {
140 option_descriptions
= ifm_subtype_ethernet_option_descriptions
;
141 subtype_descriptions
= ifm_subtype_ethernet_descriptions
;
144 option_descriptions
= ifm_subtype_ieee80211_option_descriptions
;
145 subtype_descriptions
= ifm_subtype_ieee80211_descriptions
;
151 if (filter
&& (IFM_SUBTYPE(media_options
) == IFM_NONE
)) {
152 return NULL
; /* filter */
155 dict
= CFDictionaryCreateMutable(NULL
,
157 &kCFTypeDictionaryKeyCallBacks
,
158 &kCFTypeDictionaryValueCallBacks
);
163 for (i
= 0; !val
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) {
164 if (IFM_SUBTYPE(media_options
) == ifm_subtype_shared_descriptions
[i
].ifmt_word
) {
165 val
= CFStringCreateWithCString(NULL
,
166 ifm_subtype_shared_descriptions
[i
].ifmt_string
,
167 kCFStringEncodingASCII
);
172 if (subtype_descriptions
!= NULL
) {
173 for (i
= 0; !val
&& subtype_descriptions
[i
].ifmt_string
; i
++) {
174 if (IFM_SUBTYPE(media_options
) == subtype_descriptions
[i
].ifmt_word
) {
175 val
= CFStringCreateWithCString(NULL
,
176 subtype_descriptions
[i
].ifmt_string
,
177 kCFStringEncodingASCII
);
184 CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaSubType
, val
);
190 options
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
192 while (IFM_OPTIONS(media_options
) != 0) {
193 if (filter
&& (IFM_OPTIONS(media_options
) & IFM_LOOP
)) {
194 media_options
&= ~IFM_LOOP
; /* filter */
199 for (i
= 0; !val
&& ifm_shared_option_descriptions
[i
].ifmt_string
; i
++) {
200 if (IFM_OPTIONS(media_options
) & ifm_shared_option_descriptions
[i
].ifmt_word
) {
201 val
= CFStringCreateWithCString(NULL
,
202 ifm_shared_option_descriptions
[i
].ifmt_string
,
203 kCFStringEncodingASCII
);
204 media_options
&= ~ifm_shared_option_descriptions
[i
].ifmt_word
;
209 if (option_descriptions
!= NULL
) {
210 for (i
= 0; !val
&& option_descriptions
[i
].ifmt_string
; i
++) {
211 if (IFM_OPTIONS(media_options
) & option_descriptions
[i
].ifmt_word
) {
212 val
= CFStringCreateWithCString(NULL
,
213 option_descriptions
[i
].ifmt_string
,
214 kCFStringEncodingASCII
);
215 media_options
&= ~option_descriptions
[i
].ifmt_word
;
222 CFArrayAppendValue(options
, val
);
227 CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaOptions
, options
);
235 __createMediaOptions(CFStringRef interface
, CFDictionaryRef media_options
)
238 struct ifmediareq
*ifm
;
242 const struct ifmedia_description
*option_descriptions
= NULL
;
245 const struct ifmedia_description
*subtype_descriptions
= NULL
;
250 ifm
= __copyMediaList(interface
);
252 if (ifm
->ifm_count
> 0) {
253 ifm_new
= IFM_TYPE(ifm
->ifm_ulist
[0]);
255 __freeMediaList(ifm
);
259 // if we cannot determine the media type for the interface
263 switch (IFM_TYPE(ifm_new
)) {
265 option_descriptions
= ifm_subtype_ethernet_option_descriptions
;
266 subtype_descriptions
= ifm_subtype_ethernet_descriptions
;
269 option_descriptions
= ifm_subtype_ieee80211_option_descriptions
;
270 subtype_descriptions
= ifm_subtype_ieee80211_descriptions
;
276 val
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaSubType
);
277 if (!isA_CFString(val
)) {
281 str
= _SC_cfstring_to_cstring(val
, NULL
, 0, kCFStringEncodingASCII
);
287 for (i
= 0; !match
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) {
288 if (strcasecmp(str
, ifm_subtype_shared_descriptions
[i
].ifmt_string
) == 0) {
289 ifm_new
|= ifm_subtype_shared_descriptions
[i
].ifmt_word
;
295 if (subtype_descriptions
!= NULL
) {
296 for (i
= 0; !match
&& subtype_descriptions
[i
].ifmt_string
; i
++) {
297 if (strcasecmp(str
, subtype_descriptions
[i
].ifmt_string
) == 0) {
298 ifm_new
|= subtype_descriptions
[i
].ifmt_word
;
305 CFAllocatorDeallocate(NULL
, str
);
308 return -1; /* if no subtype */
313 options
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaOptions
);
314 if (!isA_CFArray(options
)) {
318 n
= CFArrayGetCount(options
);
319 for (i
= 0; i
< n
; i
++) {
322 val
= CFArrayGetValueAtIndex(options
, i
);
323 if (!isA_CFString(val
)) {
327 str
= _SC_cfstring_to_cstring(val
, NULL
, 0, kCFStringEncodingASCII
);
334 for (j
= 0; !match
&& ifm_shared_option_descriptions
[j
].ifmt_string
; j
++) {
335 if (strcasecmp(str
, ifm_shared_option_descriptions
[j
].ifmt_string
) == 0) {
336 ifm_new
|= ifm_shared_option_descriptions
[j
].ifmt_word
;
342 if (option_descriptions
!= NULL
) {
343 for (j
= 0; !match
&& option_descriptions
[j
].ifmt_string
; j
++) {
344 if (strcasecmp(str
, option_descriptions
[j
].ifmt_string
) == 0) {
345 ifm_new
|= option_descriptions
[j
].ifmt_word
;
352 CFAllocatorDeallocate(NULL
, str
);
355 return -1; /* if no option */
364 NetworkInterfaceCopyMediaOptions(CFStringRef interface
,
365 CFDictionaryRef
*current
,
366 CFDictionaryRef
*active
,
367 CFArrayRef
*available
,
371 struct ifmediareq
*ifm
;
373 ifm
= __copyMediaList(interface
);
378 if (active
) *active
= NULL
;
379 if (current
) *current
= NULL
;
381 CFMutableArrayRef media_options
;
383 media_options
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
384 for (i
= 0; i
< ifm
->ifm_count
; i
++) {
385 CFDictionaryRef options
;
387 options
= __createMediaDictionary(ifm
->ifm_ulist
[i
], filter
);
392 if (active
&& (*active
== NULL
) && (ifm
->ifm_active
== ifm
->ifm_ulist
[i
])) {
393 *active
= CFRetain(options
);
396 if (current
&& (*current
== NULL
) && (ifm
->ifm_current
== ifm
->ifm_ulist
[i
])) {
397 *current
= CFRetain(options
);
400 if (!CFArrayContainsValue(media_options
, CFRangeMake(0, CFArrayGetCount(media_options
)), options
)) {
401 CFArrayAppendValue(media_options
, options
);
406 *available
= (CFArrayRef
)media_options
;
409 if (active
&& (*active
== NULL
)) {
410 *active
= __createMediaDictionary(ifm
->ifm_active
, FALSE
);
413 if (current
&& (*current
== NULL
)) {
414 if (active
&& (ifm
->ifm_active
== ifm
->ifm_current
)) {
415 if (*active
) *current
= CFRetain(active
);
417 *current
= __createMediaDictionary(ifm
->ifm_current
, FALSE
);
421 __freeMediaList(ifm
);
427 NetworkInterfaceCopyMediaSubTypes(CFArrayRef available
)
431 CFMutableArrayRef subTypes
;
433 if (!isA_CFArray(available
)) {
437 subTypes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
439 n
= CFArrayGetCount(available
);
440 for (i
= 0; i
< n
; i
++) {
441 CFDictionaryRef options
;
444 options
= CFArrayGetValueAtIndex(available
, i
);
445 if (!isA_CFDictionary(options
)) {
449 subType
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
450 if (!isA_CFString(subType
)) {
454 if (!CFArrayContainsValue(subTypes
, CFRangeMake(0, CFArrayGetCount(subTypes
)), subType
)) {
455 CFArrayAppendValue(subTypes
, subType
);
459 if (CFArrayGetCount(subTypes
) == 0) {
469 NetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef available
,
474 CFMutableArrayRef subTypeOptions
;
476 if (!isA_CFArray(available
)) {
480 subTypeOptions
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
482 n
= CFArrayGetCount(available
);
483 for (i
= 0; i
< n
; i
++) {
484 CFDictionaryRef options
;
485 CFArrayRef mediaOptions
;
486 CFStringRef mediaSubType
;
488 options
= CFArrayGetValueAtIndex(available
, i
);
489 if (!isA_CFDictionary(options
)) {
493 mediaSubType
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
494 if (!isA_CFString(mediaSubType
) || !CFEqual(subType
, mediaSubType
)) {
498 mediaOptions
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaOptions
);
499 if (!isA_CFArray(mediaOptions
)) {
503 if (!CFArrayContainsValue(subTypeOptions
, CFRangeMake(0, CFArrayGetCount(subTypeOptions
)), mediaOptions
)) {
504 CFArrayAppendValue(subTypeOptions
, mediaOptions
);
508 if (CFArrayGetCount(subTypeOptions
) == 0) {
509 CFRelease(subTypeOptions
);
510 subTypeOptions
= NULL
;
513 return subTypeOptions
;
518 __getMTULimits(char ifr_name
[IFNAMSIZ
],
523 io_iterator_t io_iter
= 0;
524 io_registry_entry_t io_interface
= 0;
525 io_registry_entry_t io_controller
= 0;
527 static mach_port_t masterPort
= MACH_PORT_NULL
;
528 CFMutableDictionaryRef matchingDict
;
530 /* look for a matching interface in the IORegistry */
532 if (masterPort
== MACH_PORT_NULL
) {
533 kr
= IOMasterPort(MACH_PORT_NULL
, &masterPort
);
534 if (kr
!= KERN_SUCCESS
) {
539 matchingDict
= IOBSDNameMatching(masterPort
, 0, ifr_name
);
541 /* Note: IOServiceGetMatchingServices consumes a reference on the 'matchingDict' */
542 kr
= IOServiceGetMatchingServices(masterPort
, matchingDict
, &io_iter
);
543 if ((kr
== KERN_SUCCESS
) && io_iter
) {
544 /* should only have a single match */
545 io_interface
= IOIteratorNext(io_iter
);
547 if (io_iter
) IOObjectRelease(io_iter
);
554 * found an interface, get the interface type
556 num
= IORegistryEntryCreateCFProperty(io_interface
, CFSTR(kIOInterfaceType
), NULL
, kNilOptions
);
558 if (isA_CFNumber(num
)) {
559 CFNumberGetValue(num
, kCFNumberIntType
, &ifType
);
565 * ...and the property we are REALLY interested is in the controller,
566 * which is the parent of the interface object.
568 (void)IORegistryEntryGetParentEntry(io_interface
, kIOServicePlane
, &io_controller
);
569 IOObjectRelease(io_interface
);
571 /* if no matching interface */
578 num
= IORegistryEntryCreateCFProperty(io_controller
, CFSTR(kIOMaxPacketSize
), NULL
, kNilOptions
);
580 if (isA_CFNumber(num
)) {
584 * Get the value and subtract the FCS bytes and Ethernet header
585 * sizes from the maximum frame size reported by the controller
586 * to get the MTU size. The 14 byte media header can be found
587 * in the registry, but not the size for the trailing FCS bytes.
589 CFNumberGetValue(num
, kCFNumberIntType
, &value
);
591 if (ifType
== IFT_ETHER
) {
592 value
-= (ETHER_HDR_LEN
+ ETHER_CRC_LEN
);
595 if (mtu_min
) *mtu_min
= IF_MINMTU
;
596 if (mtu_max
) *mtu_max
= value
;
601 IOObjectRelease(io_controller
);
609 NetworkInterfaceCopyMTU(CFStringRef interface
,
618 bzero((void *)&ifr
, sizeof(ifr
));
619 if (_SC_cfstring_to_cstring(interface
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
) == NULL
) {
620 SCLog(TRUE
, LOG_ERR
, CFSTR("could not convert interface name"));
624 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
626 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
630 if (ioctl(sock
, SIOCGIFMTU
, (caddr_t
)&ifr
) < 0) {
631 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMTU) failed: %s"), strerror(errno));
635 if (mtu_cur
) *mtu_cur
= ifr
.ifr_mtu
;
636 if (mtu_min
) *mtu_min
= ifr
.ifr_mtu
;
637 if (mtu_max
) *mtu_max
= ifr
.ifr_mtu
;
639 /* get valid MTU range */
641 if (mtu_min
!= NULL
|| mtu_max
!= NULL
) {
642 if (ioctl(sock
, SIOCGIFDEVMTU
, (caddr_t
)&ifr
) == 0) {
643 struct ifdevmtu
* devmtu_p
;
645 devmtu_p
= &ifr
.ifr_devmtu
;
646 if (mtu_min
!= NULL
) {
647 *mtu_min
= (devmtu_p
->ifdm_min
> IF_MINMTU
)
648 ? devmtu_p
->ifdm_min
: IF_MINMTU
;
650 if (mtu_max
!= NULL
) {
651 *mtu_max
= devmtu_p
->ifdm_max
;
655 (void)__getMTULimits(ifr
.ifr_name
, mtu_min
, mtu_max
);
663 if (sock
>= 0) (void)close(sock
);