2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 * Modification History
26 * October 21, 2000 Allan Nathanson <ajn@apple.com>
32 #include <sys/ioctl.h>
33 #include <sys/socket.h>
34 #include <net/ethernet.h>
36 #include <net/if_media.h>
37 #include <net/if_types.h>
39 #include <SystemConfiguration/SystemConfiguration.h>
40 #include <SystemConfiguration/SCPrivate.h> // for SCLog()
41 #include <SystemConfiguration/SCValidation.h>
43 #include <IOKit/IOKitLib.h>
44 #include <IOKit/network/IONetworkInterface.h>
45 #include <IOKit/network/IONetworkController.h>
46 #include "dy_framework.h"
49 static struct ifmedia_description ifm_subtype_shared_descriptions
[] =
50 IFM_SUBTYPE_SHARED_DESCRIPTIONS
;
52 static struct ifmedia_description ifm_subtype_ethernet_descriptions
[] =
53 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS
;
55 static struct ifmedia_description ifm_shared_option_descriptions
[] =
56 IFM_SHARED_OPTION_DESCRIPTIONS
;
58 static struct ifmedia_description ifm_subtype_ethernet_option_descriptions
[] =
59 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS
;
63 cfstring_to_cstring(CFStringRef cfstr
, char *buf
, int bufLen
)
65 CFIndex len
= CFStringGetLength(cfstr
);
69 buf
= CFAllocatorAllocate(NULL
, bufLen
, 0);
76 (void)CFStringGetBytes(cfstr
,
78 kCFStringEncodingASCII
,
91 static CFDictionaryRef
92 __createMediaDictionary(int media_options
, Boolean filter
)
94 CFMutableDictionaryRef dict
= NULL
;
96 CFMutableArrayRef options
= NULL
;
99 if (IFM_TYPE(media_options
) != IFM_ETHER
) {
103 if (filter
&& (IFM_SUBTYPE(media_options
) == IFM_NONE
)) {
104 return NULL
; /* filter */
107 dict
= CFDictionaryCreateMutable(NULL
,
109 &kCFTypeDictionaryKeyCallBacks
,
110 &kCFTypeDictionaryValueCallBacks
);
115 for (i
=0; !val
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) {
116 if (IFM_SUBTYPE(media_options
) == ifm_subtype_shared_descriptions
[i
].ifmt_word
) {
117 val
= CFStringCreateWithCString(NULL
,
118 ifm_subtype_shared_descriptions
[i
].ifmt_string
,
119 kCFStringEncodingASCII
);
124 for (i
=0; !val
&& ifm_subtype_ethernet_descriptions
[i
].ifmt_string
; i
++) {
125 if (IFM_SUBTYPE(media_options
) == ifm_subtype_ethernet_descriptions
[i
].ifmt_word
) {
126 val
= CFStringCreateWithCString(NULL
,
127 ifm_subtype_ethernet_descriptions
[i
].ifmt_string
,
128 kCFStringEncodingASCII
);
134 CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaSubType
, val
);
140 options
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
142 while (IFM_OPTIONS(media_options
) != 0) {
143 if (filter
&& (IFM_OPTIONS(media_options
) & IFM_LOOP
)) {
144 media_options
&= ~IFM_LOOP
; /* filter */
149 for (i
=0; !val
&& ifm_shared_option_descriptions
[i
].ifmt_string
; i
++) {
150 if (IFM_OPTIONS(media_options
) & ifm_shared_option_descriptions
[i
].ifmt_word
) {
151 val
= CFStringCreateWithCString(NULL
,
152 ifm_shared_option_descriptions
[i
].ifmt_string
,
153 kCFStringEncodingASCII
);
154 media_options
&= ~ifm_shared_option_descriptions
[i
].ifmt_word
;
159 for (i
=0; !val
&& ifm_subtype_ethernet_option_descriptions
[i
].ifmt_string
; i
++) {
160 if (IFM_OPTIONS(media_options
) & ifm_subtype_ethernet_option_descriptions
[i
].ifmt_word
) {
161 val
= CFStringCreateWithCString(NULL
,
162 ifm_subtype_ethernet_option_descriptions
[i
].ifmt_string
,
163 kCFStringEncodingASCII
);
164 media_options
&= ~ifm_shared_option_descriptions
[i
].ifmt_word
;
170 CFArrayAppendValue(options
, val
);
175 CFDictionaryAddValue(dict
, kSCPropNetEthernetMediaOptions
, options
);
183 __createMediaOptions(CFDictionaryRef media_options
)
187 int ifm_new
= IFM_ETHER
;
194 val
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaSubType
);
195 if (!isA_CFString(val
)) {
199 str
= cfstring_to_cstring(val
, NULL
, 0);
205 for (i
=0; !match
&& ifm_subtype_shared_descriptions
[i
].ifmt_string
; i
++) {
206 if (strcasecmp(str
, ifm_subtype_shared_descriptions
[i
].ifmt_string
) == 0) {
207 ifm_new
|= ifm_subtype_shared_descriptions
[i
].ifmt_word
;
213 for (i
=0; !match
&& ifm_subtype_ethernet_descriptions
[i
].ifmt_string
; i
++) {
214 if (strcasecmp(str
, ifm_subtype_ethernet_descriptions
[i
].ifmt_string
) == 0) {
215 ifm_new
|= ifm_subtype_ethernet_descriptions
[i
].ifmt_word
;
221 CFAllocatorDeallocate(NULL
, str
);
224 return -1; /* if no subtype */
229 options
= CFDictionaryGetValue(media_options
, kSCPropNetEthernetMediaOptions
);
230 if (!isA_CFArray(options
)) {
234 for (i
=0; i
<CFArrayGetCount(options
); i
++) {
237 val
= CFArrayGetValueAtIndex(options
, i
);
238 if (!isA_CFString(val
)) {
242 str
= cfstring_to_cstring(val
, NULL
, 0);
249 for (j
=0; !match
&& ifm_shared_option_descriptions
[j
].ifmt_string
; j
++) {
250 if (strcasecmp(str
, ifm_shared_option_descriptions
[j
].ifmt_string
) == 0) {
251 ifm_new
|= ifm_shared_option_descriptions
[j
].ifmt_word
;
257 for (j
=0; !match
&& ifm_subtype_ethernet_option_descriptions
[j
].ifmt_string
; j
++) {
258 if (strcasecmp(str
, ifm_subtype_ethernet_option_descriptions
[j
].ifmt_string
) == 0) {
259 ifm_new
|= ifm_subtype_ethernet_option_descriptions
[j
].ifmt_word
;
265 CFAllocatorDeallocate(NULL
, str
);
268 return -1; /* if no option */
277 NetworkInterfaceCopyMediaOptions(CFStringRef interface
,
278 CFDictionaryRef
*current
,
279 CFDictionaryRef
*active
,
280 CFArrayRef
*available
,
284 struct ifmediareq ifm
;
285 int *media_list
= NULL
;
289 bzero((char *)&ifm
, sizeof(ifm
));
291 (void)cfstring_to_cstring(interface
, ifm
.ifm_name
, sizeof(ifm
.ifm_name
));
293 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
295 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
299 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifm
) < 0) {
300 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno));
304 if (ifm
.ifm_count
> 0) {
305 media_list
= (int *)CFAllocatorAllocate(NULL
, ifm
.ifm_count
* sizeof(int), 0);
306 ifm
.ifm_ulist
= media_list
;
307 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifm
) < 0) {
308 SCLog(TRUE
, LOG_DEBUG
, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno
));
313 if (active
) *active
= NULL
;
314 if (current
) *current
= NULL
;
316 CFMutableArrayRef media_options
;
318 media_options
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
319 for (i
=0; i
<ifm
.ifm_count
; i
++) {
320 CFDictionaryRef options
;
322 options
= __createMediaDictionary(media_list
[i
], filter
);
327 if (active
&& (*active
== NULL
) && (ifm
.ifm_active
== media_list
[i
])) {
328 *active
= CFRetain(options
);
331 if (current
&& (*current
== NULL
) && (ifm
.ifm_current
== media_list
[i
])) {
332 *current
= CFRetain(options
);
335 if (!CFArrayContainsValue(media_options
, CFRangeMake(0, CFArrayGetCount(media_options
)), options
)) {
336 CFArrayAppendValue(media_options
, options
);
341 *available
= (CFArrayRef
)media_options
;
344 if (active
&& (*active
== NULL
)) {
345 *active
= __createMediaDictionary(ifm
.ifm_active
, FALSE
);
348 if (current
&& (*current
== NULL
)) {
349 if (active
&& (ifm
.ifm_active
== ifm
.ifm_current
)) {
350 if (*active
) *current
= CFRetain(active
);
352 *current
= __createMediaDictionary(ifm
.ifm_current
, FALSE
);
360 if (sock
>= 0) (void)close(sock
);
361 if (media_list
) CFAllocatorDeallocate(NULL
, media_list
);
368 NetworkInterfaceCopyMediaSubTypes(CFArrayRef available
)
371 CFMutableArrayRef subTypes
;
373 if (!isA_CFArray(available
)) {
377 subTypes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
378 for (i
=0; i
<CFArrayGetCount(available
); i
++) {
379 CFDictionaryRef options
;
382 options
= CFArrayGetValueAtIndex(available
, i
);
383 if (!isA_CFDictionary(options
)) {
387 subType
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
388 if (!isA_CFString(subType
)) {
392 if (!CFArrayContainsValue(subTypes
, CFRangeMake(0, CFArrayGetCount(subTypes
)), subType
)) {
393 CFArrayAppendValue(subTypes
, subType
);
397 if (CFArrayGetCount(subTypes
) == 0) {
407 NetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef available
,
411 CFMutableArrayRef subTypeOptions
;
413 if (!isA_CFArray(available
)) {
417 subTypeOptions
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
418 for (i
=0; i
<CFArrayGetCount(available
); i
++) {
419 CFDictionaryRef options
;
420 CFArrayRef mediaOptions
;
421 CFStringRef mediaSubType
;
423 options
= CFArrayGetValueAtIndex(available
, i
);
424 if (!isA_CFDictionary(options
)) {
428 mediaSubType
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
429 if (!isA_CFString(mediaSubType
) || !CFEqual(subType
, mediaSubType
)) {
433 mediaOptions
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaOptions
);
434 if (!isA_CFArray(mediaOptions
)) {
438 if (!CFArrayContainsValue(subTypeOptions
, CFRangeMake(0, CFArrayGetCount(subTypeOptions
)), mediaOptions
)) {
439 CFArrayAppendValue(subTypeOptions
, mediaOptions
);
443 if (CFArrayGetCount(subTypeOptions
) == 0) {
444 CFRelease(subTypeOptions
);
445 subTypeOptions
= NULL
;
448 return subTypeOptions
;
453 NetworkInterfaceCopyMTU(CFStringRef interface
,
462 bzero((char *)&ifr
, sizeof(ifr
));
463 (void)cfstring_to_cstring(interface
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
));
465 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
467 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
471 if (ioctl(sock
, SIOCGIFMTU
, (caddr_t
)&ifr
) < 0) {
472 // SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMTU) failed: %s"), strerror(errno));
476 if (mtu_cur
) *mtu_cur
= ifr
.ifr_mtu
;
478 /* get valid MTU range */
480 if (mtu_min
|| mtu_max
) {
481 char ifName
[IFNAMSIZ
+1];
483 io_iterator_t io_iter
= 0;
484 io_registry_entry_t io_interface
= 0;
485 io_registry_entry_t io_controller
= 0;
487 mach_port_t masterPort
= MACH_PORT_NULL
;
488 CFMutableDictionaryRef matchingDict
;
490 /* assume that we don't know */
492 if (mtu_min
) *mtu_min
= -1;
493 if (mtu_max
) *mtu_max
= -1;
495 /* look for a matching interface in the IORegistry */
497 (void)cfstring_to_cstring(interface
, ifName
, sizeof(ifName
));
498 matchingDict
= IOBSDNameMatching(masterPort
, 0, ifName
);
500 /* Note: IOServiceGetMatchingServices consumes a reference on the 'matchingDict' */
501 kr
= IOServiceGetMatchingServices(masterPort
, matchingDict
, &io_iter
);
502 if ((kr
== KERN_SUCCESS
) && io_iter
) {
503 /* should only have a single match */
504 io_interface
= IOIteratorNext(io_iter
);
506 if (io_iter
) IOObjectRelease(io_iter
);
509 /* found an interface with the given BSD name, get its parent */
515 * get the interface type
517 num
= IORegistryEntryCreateCFProperty(io_interface
, CFSTR(kIOInterfaceType
), NULL
, kNilOptions
);
519 if (isA_CFNumber(num
)) {
520 CFNumberGetValue(num
, kCFNumberIntType
, &ifType
);
526 * ...and the property we are REALLY interested is in the controller,
527 * which is the parent of the interface object.
529 (void)IORegistryEntryGetParentEntry(io_interface
, kIOServicePlane
, &io_controller
);
531 IOObjectRelease(io_interface
);
537 num
= IORegistryEntryCreateCFProperty(io_controller
, CFSTR(kIOMaxPacketSize
), NULL
, kNilOptions
);
539 if (isA_CFNumber(num
)) {
543 * Get the value and subtract the FCS bytes and Ethernet header
544 * sizes from the maximum frame size reported by the controller
545 * to get the MTU size. The 14 byte media header can be found
546 * in the registry, but not the size for the trailing FCS bytes.
548 CFNumberGetValue(num
, kCFNumberIntType
, &value
);
550 if (ifType
== IFT_ETHER
) {
551 value
-= (ETHER_HDR_LEN
+ ETHER_CRC_LEN
);
554 if (mtu_min
) *mtu_min
= IF_MINMTU
;
555 if (mtu_max
) *mtu_max
= value
;
560 IOObjectRelease(io_controller
);
568 if (sock
>= 0) (void)close(sock
);