1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "net/base/net_util.h" 6 7#include <iphlpapi.h> 8#include <wlanapi.h> 9 10#include <algorithm> 11 12#include "base/files/file_path.h" 13#include "base/lazy_instance.h" 14#include "base/memory/scoped_ptr.h" 15#include "base/strings/string_piece.h" 16#include "base/strings/string_util.h" 17#include "base/strings/sys_string_conversions.h" 18#include "base/strings/utf_string_conversions.h" 19#include "base/threading/thread_restrictions.h" 20#include "base/win/scoped_handle.h" 21#include "base/win/windows_version.h" 22#include "net/base/escape.h" 23#include "net/base/ip_endpoint.h" 24#include "net/base/net_errors.h" 25#include "url/gurl.h" 26 27namespace net { 28 29namespace { 30 31struct WlanApi { 32 typedef DWORD (WINAPI *WlanOpenHandleFunc)( 33 DWORD, VOID*, DWORD*, HANDLE*); 34 typedef DWORD (WINAPI *WlanEnumInterfacesFunc)( 35 HANDLE, VOID*, WLAN_INTERFACE_INFO_LIST**); 36 typedef DWORD (WINAPI *WlanQueryInterfaceFunc)( 37 HANDLE, const GUID*, WLAN_INTF_OPCODE, VOID*, DWORD*, VOID**, 38 WLAN_OPCODE_VALUE_TYPE*); 39 typedef VOID (WINAPI *WlanFreeMemoryFunc)(VOID*); 40 typedef DWORD (WINAPI *WlanCloseHandleFunc)(HANDLE, VOID*); 41 42 WlanApi() : initialized(false) { 43 // Use an absolute path to load the DLL to avoid DLL preloading attacks. 44 static const wchar_t* const kDLL = L"%WINDIR%\\system32\\wlanapi.dll"; 45 wchar_t path[MAX_PATH] = {0}; 46 ExpandEnvironmentStrings(kDLL, path, arraysize(path)); 47 module = ::LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); 48 if (!module) 49 return; 50 51 open_handle_func = reinterpret_cast<WlanOpenHandleFunc>( 52 ::GetProcAddress(module, "WlanOpenHandle")); 53 enum_interfaces_func = reinterpret_cast<WlanEnumInterfacesFunc>( 54 ::GetProcAddress(module, "WlanEnumInterfaces")); 55 query_interface_func = reinterpret_cast<WlanQueryInterfaceFunc>( 56 ::GetProcAddress(module, "WlanQueryInterface")); 57 free_memory_func = reinterpret_cast<WlanFreeMemoryFunc>( 58 ::GetProcAddress(module, "WlanFreeMemory")); 59 close_handle_func = reinterpret_cast<WlanCloseHandleFunc>( 60 ::GetProcAddress(module, "WlanCloseHandle")); 61 initialized = open_handle_func && enum_interfaces_func && 62 query_interface_func && free_memory_func && 63 close_handle_func; 64 } 65 66 template <typename T> 67 DWORD OpenHandle(DWORD client_version, DWORD* cur_version, T* handle) const { 68 HANDLE temp_handle; 69 DWORD result = open_handle_func(client_version, NULL, cur_version, 70 &temp_handle); 71 if (result != ERROR_SUCCESS) 72 return result; 73 handle->Set(temp_handle); 74 return ERROR_SUCCESS; 75 } 76 77 HMODULE module; 78 WlanOpenHandleFunc open_handle_func; 79 WlanEnumInterfacesFunc enum_interfaces_func; 80 WlanQueryInterfaceFunc query_interface_func; 81 WlanFreeMemoryFunc free_memory_func; 82 WlanCloseHandleFunc close_handle_func; 83 bool initialized; 84}; 85 86// Converts Windows defined types to NetworkInterfaceType. 87NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(DWORD ifType) { 88 // Bail out for pre-Vista versions of Windows which are documented to give 89 // inaccurate results like returning Ethernet for WiFi. 90 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366058.aspx 91 if (base::win::GetVersion() < base::win::VERSION_VISTA) 92 return NetworkChangeNotifier::CONNECTION_UNKNOWN; 93 94 NetworkChangeNotifier::ConnectionType type = 95 NetworkChangeNotifier::CONNECTION_UNKNOWN; 96 if (ifType == IF_TYPE_ETHERNET_CSMACD) { 97 type = NetworkChangeNotifier::CONNECTION_ETHERNET; 98 } else if (ifType == IF_TYPE_IEEE80211) { 99 type = NetworkChangeNotifier::CONNECTION_WIFI; 100 } 101 // TODO(mallinath) - Cellular? 102 return type; 103} 104 105} // namespace 106 107bool GetNetworkList(NetworkInterfaceList* networks, int policy) { 108 // GetAdaptersAddresses() may require IO operations. 109 base::ThreadRestrictions::AssertIOAllowed(); 110 bool is_xp = base::win::GetVersion() < base::win::VERSION_VISTA; 111 ULONG len = 0; 112 ULONG flags = is_xp ? GAA_FLAG_INCLUDE_PREFIX : 0; 113 // First get number of networks. 114 ULONG result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, NULL, &len); 115 if (result != ERROR_BUFFER_OVERFLOW) { 116 // There are 0 networks. 117 return true; 118 } 119 scoped_ptr<char[]> buf(new char[len]); 120 IP_ADAPTER_ADDRESSES *adapters = 121 reinterpret_cast<IP_ADAPTER_ADDRESSES *>(buf.get()); 122 result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapters, &len); 123 if (result != NO_ERROR) { 124 LOG(ERROR) << "GetAdaptersAddresses failed: " << result; 125 return false; 126 } 127 128 // These two variables are used below when this method is asked to pick a 129 // IPv6 address which has the shortest lifetime. 130 ULONG ipv6_valid_lifetime = 0; 131 scoped_ptr<NetworkInterface> ipv6_address; 132 133 for (IP_ADAPTER_ADDRESSES *adapter = adapters; adapter != NULL; 134 adapter = adapter->Next) { 135 // Ignore the loopback device. 136 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) { 137 continue; 138 } 139 140 if (adapter->OperStatus != IfOperStatusUp) { 141 continue; 142 } 143 144 // Ignore any HOST side vmware adapters with a description like: 145 // VMware Virtual Ethernet Adapter for VMnet1 146 // but don't ignore any GUEST side adapters with a description like: 147 // VMware Accelerated AMD PCNet Adapter #2 148 if (policy == EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES && 149 strstr(adapter->AdapterName, "VMnet") != NULL) { 150 continue; 151 } 152 153 for (IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress; 154 address; address = address->Next) { 155 int family = address->Address.lpSockaddr->sa_family; 156 if (family == AF_INET || family == AF_INET6) { 157 IPEndPoint endpoint; 158 if (endpoint.FromSockAddr(address->Address.lpSockaddr, 159 address->Address.iSockaddrLength)) { 160 // XP has no OnLinkPrefixLength field. 161 size_t net_prefix = is_xp ? 0 : address->OnLinkPrefixLength; 162 if (is_xp) { 163 // Prior to Windows Vista the FirstPrefix pointed to the list with 164 // single prefix for each IP address assigned to the adapter. 165 // Order of FirstPrefix does not match order of FirstUnicastAddress, 166 // so we need to find corresponding prefix. 167 for (IP_ADAPTER_PREFIX* prefix = adapter->FirstPrefix; prefix; 168 prefix = prefix->Next) { 169 int prefix_family = prefix->Address.lpSockaddr->sa_family; 170 IPEndPoint network_endpoint; 171 if (prefix_family == family && 172 network_endpoint.FromSockAddr(prefix->Address.lpSockaddr, 173 prefix->Address.iSockaddrLength) && 174 IPNumberMatchesPrefix(endpoint.address(), 175 network_endpoint.address(), 176 prefix->PrefixLength)) { 177 net_prefix = std::max<size_t>(net_prefix, prefix->PrefixLength); 178 } 179 } 180 } 181 uint32 index = 182 (family == AF_INET) ? adapter->IfIndex : adapter->Ipv6IfIndex; 183 // Pick one IPv6 address with least valid lifetime. 184 // The reason we are checking |ValidLifeftime| as there is no other 185 // way identifying the interface type. Usually (and most likely) temp 186 // IPv6 will have a shorter ValidLifetime value then the permanent 187 // interface. 188 if (family == AF_INET6 && 189 (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE)) { 190 if (ipv6_valid_lifetime == 0 || 191 ipv6_valid_lifetime > address->ValidLifetime) { 192 ipv6_valid_lifetime = address->ValidLifetime; 193 ipv6_address.reset(new NetworkInterface(adapter->AdapterName, 194 base::SysWideToNativeMB(adapter->FriendlyName), 195 index, 196 GetNetworkInterfaceType(adapter->IfType), 197 endpoint.address(), 198 net_prefix)); 199 continue; 200 } 201 } 202 networks->push_back( 203 NetworkInterface(adapter->AdapterName, 204 base::SysWideToNativeMB(adapter->FriendlyName), 205 index, GetNetworkInterfaceType(adapter->IfType), 206 endpoint.address(), net_prefix)); 207 } 208 } 209 } 210 } 211 212 if (ipv6_address.get()) { 213 networks->push_back(*(ipv6_address.get())); 214 } 215 return true; 216} 217 218WifiPHYLayerProtocol GetWifiPHYLayerProtocol() { 219 static base::LazyInstance<WlanApi>::Leaky lazy_wlanapi = 220 LAZY_INSTANCE_INITIALIZER; 221 222 struct WlanApiHandleTraits { 223 typedef HANDLE Handle; 224 225 static bool CloseHandle(HANDLE handle) { 226 return lazy_wlanapi.Get().close_handle_func(handle, NULL) == 227 ERROR_SUCCESS; 228 } 229 static bool IsHandleValid(HANDLE handle) { 230 return base::win::HandleTraits::IsHandleValid(handle); 231 } 232 static HANDLE NullHandle() { 233 return base::win::HandleTraits::NullHandle(); 234 } 235 }; 236 237 typedef base::win::GenericScopedHandle< 238 WlanApiHandleTraits, 239 base::win::DummyVerifierTraits> WlanHandle; 240 241 struct WlanApiDeleter { 242 inline void operator()(void* ptr) const { 243 lazy_wlanapi.Get().free_memory_func(ptr); 244 } 245 }; 246 247 const WlanApi& wlanapi = lazy_wlanapi.Get(); 248 if (!wlanapi.initialized) 249 return WIFI_PHY_LAYER_PROTOCOL_NONE; 250 251 WlanHandle client; 252 DWORD cur_version = 0; 253 const DWORD kMaxClientVersion = 2; 254 DWORD result = wlanapi.OpenHandle(kMaxClientVersion, &cur_version, &client); 255 if (result != ERROR_SUCCESS) 256 return WIFI_PHY_LAYER_PROTOCOL_NONE; 257 258 WLAN_INTERFACE_INFO_LIST* interface_list_ptr = NULL; 259 result = wlanapi.enum_interfaces_func(client, NULL, &interface_list_ptr); 260 if (result != ERROR_SUCCESS) 261 return WIFI_PHY_LAYER_PROTOCOL_NONE; 262 scoped_ptr<WLAN_INTERFACE_INFO_LIST, WlanApiDeleter> interface_list( 263 interface_list_ptr); 264 265 // Assume at most one connected wifi interface. 266 WLAN_INTERFACE_INFO* info = NULL; 267 for (unsigned i = 0; i < interface_list->dwNumberOfItems; ++i) { 268 if (interface_list->InterfaceInfo[i].isState == 269 wlan_interface_state_connected) { 270 info = &interface_list->InterfaceInfo[i]; 271 break; 272 } 273 } 274 275 if (info == NULL) 276 return WIFI_PHY_LAYER_PROTOCOL_NONE; 277 278 WLAN_CONNECTION_ATTRIBUTES* conn_info_ptr; 279 DWORD conn_info_size = 0; 280 WLAN_OPCODE_VALUE_TYPE op_code; 281 result = wlanapi.query_interface_func( 282 client, &info->InterfaceGuid, wlan_intf_opcode_current_connection, NULL, 283 &conn_info_size, reinterpret_cast<VOID**>(&conn_info_ptr), &op_code); 284 if (result != ERROR_SUCCESS) 285 return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN; 286 scoped_ptr<WLAN_CONNECTION_ATTRIBUTES, WlanApiDeleter> conn_info( 287 conn_info_ptr); 288 289 switch (conn_info->wlanAssociationAttributes.dot11PhyType) { 290 case dot11_phy_type_fhss: 291 return WIFI_PHY_LAYER_PROTOCOL_ANCIENT; 292 case dot11_phy_type_dsss: 293 return WIFI_PHY_LAYER_PROTOCOL_B; 294 case dot11_phy_type_irbaseband: 295 return WIFI_PHY_LAYER_PROTOCOL_ANCIENT; 296 case dot11_phy_type_ofdm: 297 return WIFI_PHY_LAYER_PROTOCOL_A; 298 case dot11_phy_type_hrdsss: 299 return WIFI_PHY_LAYER_PROTOCOL_B; 300 case dot11_phy_type_erp: 301 return WIFI_PHY_LAYER_PROTOCOL_G; 302 case dot11_phy_type_ht: 303 return WIFI_PHY_LAYER_PROTOCOL_N; 304 default: 305 return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN; 306 } 307} 308 309} // namespace net 310