1/* 2 * Copyright (c) 2005-2007 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * BLGetIOServiceForPreferredNetworkInterface.c 25 * bless 26 * 27 * Created by Shantonu Sen on 11/14/05. 28 * Copyright 2005-2007 Apple Inc. All Rights Reserved. 29 * 30 */ 31 32#import <mach/mach_error.h> 33 34#import <IOKit/IOKitLib.h> 35#import <IOKit/IOKitKeys.h> 36#import <IOKit/network/IONetworkInterface.h> 37#import <IOKit/network/IONetworkController.h> 38#import <IOKit/network/IONetworkMedium.h> 39#import <IOKit/IOBSD.h> 40 41#include <CoreFoundation/CoreFoundation.h> 42 43#include <sys/socket.h> 44#include <net/if.h> 45 46#include "bless.h" 47#include "bless_private.h" 48 49extern bool isInterfaceLinkUp(BLContextPtr context, 50 io_service_t serv); 51 52static io_service_t getLinkUpInterface(BLContextPtr context, 53 io_iterator_t iterator); 54 55/* Algorithm: 56 1) Search for IONetworkInterface that are built-in and have 57 an active link 58 2) Rank those according to order seen, or IOPrimaryInterface 59*/ 60int BLGetPreferredNetworkInterface(BLContextPtr context, 61 char *ifname) 62{ 63 64 io_service_t interface = IO_OBJECT_NULL; 65 kern_return_t kret; 66 CFMutableDictionaryRef matchingDict = NULL, propDict = NULL; 67 io_iterator_t iterator = IO_OBJECT_NULL; 68 69 ifname[0] = '\0'; 70 71 matchingDict = IOServiceMatching(kIONetworkInterfaceClass); 72 propDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 73 &kCFTypeDictionaryKeyCallBacks, 74 &kCFTypeDictionaryValueCallBacks); 75 76 CFDictionaryAddValue(propDict, CFSTR(kIOBuiltin), kCFBooleanTrue); 77 CFDictionaryAddValue(propDict, CFSTR(kIOPrimaryInterface), kCFBooleanTrue); 78 CFDictionaryAddValue(matchingDict, CFSTR(kIOPropertyMatchKey), propDict); 79 CFRelease(propDict); 80 81 kret = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, 82 &iterator); 83 if(kret) { 84 contextprintf(context, kBLLogLevelError, "Could not get interface iterator\n"); 85 return 1; 86 } 87 88 interface = getLinkUpInterface(context, iterator); 89 IOObjectRelease(iterator); 90 91 if(interface == IO_OBJECT_NULL) { 92 93 matchingDict = IOServiceMatching(kIONetworkInterfaceClass); 94 propDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 95 &kCFTypeDictionaryKeyCallBacks, 96 &kCFTypeDictionaryValueCallBacks); 97 98 CFDictionaryAddValue(propDict, CFSTR(kIOBuiltin), kCFBooleanTrue); 99 CFDictionaryAddValue(matchingDict, CFSTR(kIOPropertyMatchKey), propDict); 100 CFRelease(propDict); 101 102 kret = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, 103 &iterator); 104 if(kret) { 105 contextprintf(context, kBLLogLevelError, "Could not get interface iterator\n"); 106 return 1; 107 } 108 109 interface = getLinkUpInterface(context, iterator); 110 IOObjectRelease(iterator); 111 } 112 113 if(interface == IO_OBJECT_NULL) { 114 115 matchingDict = IOServiceMatching(kIONetworkInterfaceClass); 116 propDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 117 &kCFTypeDictionaryKeyCallBacks, 118 &kCFTypeDictionaryValueCallBacks); 119 120 CFDictionaryAddValue(matchingDict, CFSTR(kIOPropertyMatchKey), propDict); 121 CFRelease(propDict); 122 123 kret = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, 124 &iterator); 125 if(kret) { 126 contextprintf(context, kBLLogLevelError, "Could not get interface iterator\n"); 127 return 1; 128 } 129 130 interface = getLinkUpInterface(context, iterator); 131 IOObjectRelease(iterator); 132 } 133 134 if(interface != IO_OBJECT_NULL) { 135 CFStringRef name; 136 137 name = IORegistryEntryCreateCFProperty(interface, CFSTR(kIOBSDNameKey), 138 kCFAllocatorDefault, 139 0); 140 141 if(name == NULL || CFGetTypeID(name) != CFStringGetTypeID()) { 142 if(name) CFRelease(name); 143 IOObjectRelease(interface); 144 145 contextprintf(context, kBLLogLevelError, "Preferred interface does not have a BSD name\n"); 146 return 2; 147 } 148 149 if(!CFStringGetCString(name, ifname, IF_NAMESIZE, kCFStringEncodingUTF8)) { 150 CFRelease(name); 151 IOObjectRelease(interface); 152 153 contextprintf(context, kBLLogLevelError, "Could not get BSD name\n"); 154 return 3; 155 } 156 157 CFRelease(name); 158 IOObjectRelease(interface); 159 160 contextprintf(context, kBLLogLevelVerbose, "Found primary interface: %s\n", ifname); 161 162 return 0; 163 } 164 165 return 2; 166} 167 168static io_service_t getLinkUpInterface(BLContextPtr context, 169 io_iterator_t iterator) 170{ 171 io_service_t serv; 172 kern_return_t kret; 173 174 if(!IOIteratorIsValid(iterator)) 175 IOIteratorReset(iterator); 176 177 while((serv = IOIteratorNext(iterator))) { 178 io_string_t path; 179 bool hasLink; 180 181 hasLink = isInterfaceLinkUp(context, serv); 182 183 kret = IORegistryEntryGetPath(serv, kIOServicePlane, path); 184 if(kret) { 185 strlcpy(path, "<unknown>", sizeof path); 186 } 187 188 contextprintf(context, kBLLogLevelVerbose, "Interface at %s %s an active link\n", 189 path, 190 hasLink ? "has" : "does not have"); 191 192 if(hasLink) { 193 return serv; 194 } else { 195 IOObjectRelease(serv); 196 } 197 } 198 199 return IO_OBJECT_NULL; 200} 201 202