2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
27 * Modification History
29 * October 21, 2000 Allan Nathanson <ajn@apple.com>
35 #include <sys/ioctl.h>
36 #include <sys/socket.h>
37 #include <net/ethernet.h>
39 #include <net/if_media.h>
40 #include <net/if_types.h>
42 #include <SystemConfiguration/SystemConfiguration.h>
43 #include <SystemConfiguration/SCPrivate.h> // for SCLog()
44 #include <SystemConfiguration/SCValidation.h>
46 #include <IOKit/IOKitLib.h>
47 #include <IOKit/network/IONetworkInterface.h>
48 #include <IOKit/network/IONetworkController.h>
49 #include "dy_framework.h"
52 static const struct ifmedia_description ifm_subtype_shared_descriptions
[] =
53 IFM_SUBTYPE_SHARED_DESCRIPTIONS
;
55 static const struct ifmedia_description ifm_subtype_ethernet_descriptions
[] =
56 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS
;
58 static const struct ifmedia_description ifm_shared_option_descriptions
[] =
59 IFM_SHARED_OPTION_DESCRIPTIONS
;
61 static const struct ifmedia_description ifm_subtype_ethernet_option_descriptions
[] =
62 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS
;
65 static CFDictionaryRef
66 __createMediaDictionary(int media_options
, Boolean filter
)
68 CFMutableDictionaryRef dict
= NULL
;
70 CFMutableArrayRef options
= NULL
;
73 if (IFM_TYPE(media_options
) != IFM_ETHER
) {
77 if (filter
&& (IFM_SUBTYPE(media_options
) == IFM_NONE
)) {
78 return NULL
; /* filter */
81 dict
= CFDictionaryCreateMutable(NULL
,
83 &kCFTypeDictionaryKeyCallBacks
,
84 &kCFTypeDictionaryValueCallBacks
);
89 for (i
= 0; !val
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) {
90 if (IFM_SUBTYPE(media_options
) == ifm_subtype_shared_descriptions
[i
].ifmt_word
) {
91 val
= CFStringCreateWithCString(NULL
,
92 ifm_subtype_shared_descriptions
[i
].ifmt_string
,
93 kCFStringEncodingASCII
);
98 for (i
= 0; !val
&& ifm_subtype_ethernet_descriptions
[i
].ifmt_string
; i
++) {
99 if (IFM_SUBTYPE(media_options
) == ifm_subtype_ethernet_descriptions
[i
].ifmt_word
) {
100 val
= CFStringCreateWithCString(NULL
,
101 ifm_subtype_ethernet_descriptions
[i
].ifmt_string
,
102 kCFStringEncodingASCII
);
108 CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaSubType
, val
);
114 options
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
116 while (IFM_OPTIONS(media_options
) != 0) {
117 if (filter
&& (IFM_OPTIONS(media_options
) & IFM_LOOP
)) {
118 media_options
&= ~IFM_LOOP
; /* filter */
123 for (i
= 0; !val
&& ifm_shared_option_descriptions
[i
].ifmt_string
; i
++) {
124 if (IFM_OPTIONS(media_options
) & ifm_shared_option_descriptions
[i
].ifmt_word
) {
125 val
= CFStringCreateWithCString(NULL
,
126 ifm_shared_option_descriptions
[i
].ifmt_string
,
127 kCFStringEncodingASCII
);
128 media_options
&= ~ifm_shared_option_descriptions
[i
].ifmt_word
;
133 for (i
= 0; !val
&& ifm_subtype_ethernet_option_descriptions
[i
].ifmt_string
; i
++) {
134 if (IFM_OPTIONS(media_options
) & ifm_subtype_ethernet_option_descriptions
[i
].ifmt_word
) {
135 val
= CFStringCreateWithCString(NULL
,
136 ifm_subtype_ethernet_option_descriptions
[i
].ifmt_string
,
137 kCFStringEncodingASCII
);
138 media_options
&= ~ifm_shared_option_descriptions
[i
].ifmt_word
;
144 CFArrayAppendValue(options
, val
);
149 CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaOptions
, options
);
157 __createMediaOptions(CFDictionaryRef media_options
)
161 int ifm_new
= IFM_ETHER
;
169 val
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaSubType
);
170 if (!isA_CFString(val
)) {
174 str
= _SC_cfstring_to_cstring(val
, NULL
, 0, kCFStringEncodingASCII
);
180 for (i
= 0; !match
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) {
181 if (strcasecmp(str
, ifm_subtype_shared_descriptions
[i
].ifmt_string
) == 0) {
182 ifm_new
|= ifm_subtype_shared_descriptions
[i
].ifmt_word
;
188 for (i
= 0; !match
&& ifm_subtype_ethernet_descriptions
[i
].ifmt_string
; i
++) {
189 if (strcasecmp(str
, ifm_subtype_ethernet_descriptions
[i
].ifmt_string
) == 0) {
190 ifm_new
|= ifm_subtype_ethernet_descriptions
[i
].ifmt_word
;
196 CFAllocatorDeallocate(NULL
, str
);
199 return -1; /* if no subtype */
204 options
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaOptions
);
205 if (!isA_CFArray(options
)) {
209 n
= CFArrayGetCount(options
);
210 for (i
= 0; i
< n
; i
++) {
213 val
= CFArrayGetValueAtIndex(options
, i
);
214 if (!isA_CFString(val
)) {
218 str
= _SC_cfstring_to_cstring(val
, NULL
, 0, kCFStringEncodingASCII
);
225 for (j
= 0; !match
&& ifm_shared_option_descriptions
[j
].ifmt_string
; j
++) {
226 if (strcasecmp(str
, ifm_shared_option_descriptions
[j
].ifmt_string
) == 0) {
227 ifm_new
|= ifm_shared_option_descriptions
[j
].ifmt_word
;
233 for (j
= 0; !match
&& ifm_subtype_ethernet_option_descriptions
[j
].ifmt_string
; j
++) {
234 if (strcasecmp(str
, ifm_subtype_ethernet_option_descriptions
[j
].ifmt_string
) == 0) {
235 ifm_new
|= ifm_subtype_ethernet_option_descriptions
[j
].ifmt_word
;
241 CFAllocatorDeallocate(NULL
, str
);
244 return -1; /* if no option */
253 NetworkInterfaceCopyMediaOptions(CFStringRef interface
,
254 CFDictionaryRef
*current
,
255 CFDictionaryRef
*active
,
256 CFArrayRef
*available
,
260 struct ifmediareq ifm
;
261 int *media_list
= NULL
;
265 bzero((void *)&ifm
, sizeof(ifm
));
267 if (_SC_cfstring_to_cstring(interface
, ifm
.ifm_name
, sizeof(ifm
.ifm_name
), kCFStringEncodingASCII
) == NULL
) {
268 SCLog(TRUE
, LOG_ERR
, CFSTR("could not convert inteface name"));
272 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
274 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
278 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifm
) < 0) {
279 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno));
283 if (ifm
.ifm_count
> 0) {
284 media_list
= (int *)CFAllocatorAllocate(NULL
, ifm
.ifm_count
* sizeof(int), 0);
285 ifm
.ifm_ulist
= media_list
;
286 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifm
) < 0) {
287 SCLog(TRUE
, LOG_DEBUG
, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno
));
292 if (active
) *active
= NULL
;
293 if (current
) *current
= NULL
;
295 CFMutableArrayRef media_options
;
297 media_options
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
298 for (i
= 0; i
< ifm
.ifm_count
; i
++) {
299 CFDictionaryRef options
;
301 options
= __createMediaDictionary(media_list
[i
], filter
);
306 if (active
&& (*active
== NULL
) && (ifm
.ifm_active
== media_list
[i
])) {
307 *active
= CFRetain(options
);
310 if (current
&& (*current
== NULL
) && (ifm
.ifm_current
== media_list
[i
])) {
311 *current
= CFRetain(options
);
314 if (!CFArrayContainsValue(media_options
, CFRangeMake(0, CFArrayGetCount(media_options
)), options
)) {
315 CFArrayAppendValue(media_options
, options
);
320 *available
= (CFArrayRef
)media_options
;
323 if (active
&& (*active
== NULL
)) {
324 *active
= __createMediaDictionary(ifm
.ifm_active
, FALSE
);
327 if (current
&& (*current
== NULL
)) {
328 if (active
&& (ifm
.ifm_active
== ifm
.ifm_current
)) {
329 if (*active
) *current
= CFRetain(active
);
331 *current
= __createMediaDictionary(ifm
.ifm_current
, FALSE
);
339 if (sock
>= 0) (void)close(sock
);
340 if (media_list
) CFAllocatorDeallocate(NULL
, media_list
);
347 NetworkInterfaceCopyMediaSubTypes(CFArrayRef available
)
351 CFMutableArrayRef subTypes
;
353 if (!isA_CFArray(available
)) {
357 subTypes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
359 n
= CFArrayGetCount(available
);
360 for (i
= 0; i
< n
; i
++) {
361 CFDictionaryRef options
;
364 options
= CFArrayGetValueAtIndex(available
, i
);
365 if (!isA_CFDictionary(options
)) {
369 subType
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
370 if (!isA_CFString(subType
)) {
374 if (!CFArrayContainsValue(subTypes
, CFRangeMake(0, CFArrayGetCount(subTypes
)), subType
)) {
375 CFArrayAppendValue(subTypes
, subType
);
379 if (CFArrayGetCount(subTypes
) == 0) {
389 NetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef available
,
394 CFMutableArrayRef subTypeOptions
;
396 if (!isA_CFArray(available
)) {
400 subTypeOptions
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
402 n
= CFArrayGetCount(available
);
403 for (i
= 0; i
< n
; i
++) {
404 CFDictionaryRef options
;
405 CFArrayRef mediaOptions
;
406 CFStringRef mediaSubType
;
408 options
= CFArrayGetValueAtIndex(available
, i
);
409 if (!isA_CFDictionary(options
)) {
413 mediaSubType
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
414 if (!isA_CFString(mediaSubType
) || !CFEqual(subType
, mediaSubType
)) {
418 mediaOptions
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaOptions
);
419 if (!isA_CFArray(mediaOptions
)) {
423 if (!CFArrayContainsValue(subTypeOptions
, CFRangeMake(0, CFArrayGetCount(subTypeOptions
)), mediaOptions
)) {
424 CFArrayAppendValue(subTypeOptions
, mediaOptions
);
428 if (CFArrayGetCount(subTypeOptions
) == 0) {
429 CFRelease(subTypeOptions
);
430 subTypeOptions
= NULL
;
433 return subTypeOptions
;
438 NetworkInterfaceCopyMTU(CFStringRef interface
,
447 bzero((void *)&ifr
, sizeof(ifr
));
448 if (_SC_cfstring_to_cstring(interface
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
) == NULL
) {
449 SCLog(TRUE
, LOG_ERR
, CFSTR("could not convert inteface name"));
453 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
455 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
459 if (ioctl(sock
, SIOCGIFMTU
, (caddr_t
)&ifr
) < 0) {
460 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMTU) failed: %s"), strerror(errno));
464 if (mtu_cur
) *mtu_cur
= ifr
.ifr_mtu
;
466 /* get valid MTU range */
468 if (mtu_min
|| mtu_max
) {
470 io_iterator_t io_iter
= 0;
471 io_registry_entry_t io_interface
= 0;
472 io_registry_entry_t io_controller
= 0;
474 mach_port_t masterPort
= MACH_PORT_NULL
;
475 CFMutableDictionaryRef matchingDict
;
477 /* assume that we don't know */
479 if (mtu_min
) *mtu_min
= -1;
480 if (mtu_max
) *mtu_max
= -1;
482 /* look for a matching interface in the IORegistry */
484 matchingDict
= IOBSDNameMatching(masterPort
, 0, ifr
.ifr_name
);
486 /* Note: IOServiceGetMatchingServices consumes a reference on the 'matchingDict' */
487 kr
= IOServiceGetMatchingServices(masterPort
, matchingDict
, &io_iter
);
488 if ((kr
== KERN_SUCCESS
) && io_iter
) {
489 /* should only have a single match */
490 io_interface
= IOIteratorNext(io_iter
);
492 if (io_iter
) IOObjectRelease(io_iter
);
495 /* found an interface with the given BSD name, get its parent */
501 * get the interface type
503 num
= IORegistryEntryCreateCFProperty(io_interface
, CFSTR(kIOInterfaceType
), NULL
, kNilOptions
);
505 if (isA_CFNumber(num
)) {
506 CFNumberGetValue(num
, kCFNumberIntType
, &ifType
);
512 * ...and the property we are REALLY interested is in the controller,
513 * which is the parent of the interface object.
515 (void)IORegistryEntryGetParentEntry(io_interface
, kIOServicePlane
, &io_controller
);
517 IOObjectRelease(io_interface
);
523 num
= IORegistryEntryCreateCFProperty(io_controller
, CFSTR(kIOMaxPacketSize
), NULL
, kNilOptions
);
525 if (isA_CFNumber(num
)) {
529 * Get the value and subtract the FCS bytes and Ethernet header
530 * sizes from the maximum frame size reported by the controller
531 * to get the MTU size. The 14 byte media header can be found
532 * in the registry, but not the size for the trailing FCS bytes.
534 CFNumberGetValue(num
, kCFNumberIntType
, &value
);
536 if (ifType
== IFT_ETHER
) {
537 value
-= (ETHER_HDR_LEN
+ ETHER_CRC_LEN
);
540 if (mtu_min
) *mtu_min
= IF_MINMTU
;
541 if (mtu_max
) *mtu_max
= value
;
546 IOObjectRelease(io_controller
);
554 if (sock
>= 0) (void)close(sock
);