PlzNavigate: Improvements to RFHM commit logic.
[chromium-blink-merge.git] / net / base / net_util_win.cc
blob0889917830123e2411be2e086d9821f8e68f53f1
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.
5 #include "net/base/net_util.h"
7 #include <iphlpapi.h>
8 #include <wlanapi.h>
10 #include <algorithm>
12 #include "base/files/file_path.h"
13 #include "base/lazy_instance.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/profiler/scoped_tracker.h"
16 #include "base/strings/string_piece.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/sys_string_conversions.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/threading/thread_restrictions.h"
21 #include "base/win/scoped_handle.h"
22 #include "base/win/windows_version.h"
23 #include "net/base/escape.h"
24 #include "net/base/ip_endpoint.h"
25 #include "net/base/net_errors.h"
26 #include "net/base/net_util_win.h"
27 #include "url/gurl.h"
29 namespace net {
31 namespace {
33 // Converts Windows defined types to NetworkInterfaceType.
34 NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(DWORD ifType) {
35 // Bail out for pre-Vista versions of Windows which are documented to give
36 // inaccurate results like returning Ethernet for WiFi.
37 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366058.aspx
38 if (base::win::GetVersion() < base::win::VERSION_VISTA)
39 return NetworkChangeNotifier::CONNECTION_UNKNOWN;
41 NetworkChangeNotifier::ConnectionType type =
42 NetworkChangeNotifier::CONNECTION_UNKNOWN;
43 if (ifType == IF_TYPE_ETHERNET_CSMACD) {
44 type = NetworkChangeNotifier::CONNECTION_ETHERNET;
45 } else if (ifType == IF_TYPE_IEEE80211) {
46 type = NetworkChangeNotifier::CONNECTION_WIFI;
48 // TODO(mallinath) - Cellular?
49 return type;
52 } // namespace
54 namespace internal {
56 base::LazyInstance<WlanApi>::Leaky lazy_wlanapi =
57 LAZY_INSTANCE_INITIALIZER;
59 WlanApi& WlanApi::GetInstance() {
60 return lazy_wlanapi.Get();
63 WlanApi::WlanApi() : initialized(false) {
64 // Use an absolute path to load the DLL to avoid DLL preloading attacks.
65 static const wchar_t* const kDLL = L"%WINDIR%\\system32\\wlanapi.dll";
66 wchar_t path[MAX_PATH] = {0};
67 ExpandEnvironmentStrings(kDLL, path, arraysize(path));
68 module = ::LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
69 if (!module)
70 return;
72 open_handle_func = reinterpret_cast<WlanOpenHandleFunc>(
73 ::GetProcAddress(module, "WlanOpenHandle"));
74 enum_interfaces_func = reinterpret_cast<WlanEnumInterfacesFunc>(
75 ::GetProcAddress(module, "WlanEnumInterfaces"));
76 query_interface_func = reinterpret_cast<WlanQueryInterfaceFunc>(
77 ::GetProcAddress(module, "WlanQueryInterface"));
78 set_interface_func = reinterpret_cast<WlanSetInterfaceFunc>(
79 ::GetProcAddress(module, "WlanSetInterface"));
80 free_memory_func = reinterpret_cast<WlanFreeMemoryFunc>(
81 ::GetProcAddress(module, "WlanFreeMemory"));
82 close_handle_func = reinterpret_cast<WlanCloseHandleFunc>(
83 ::GetProcAddress(module, "WlanCloseHandle"));
84 initialized = open_handle_func && enum_interfaces_func &&
85 query_interface_func && set_interface_func &&
86 free_memory_func && close_handle_func;
89 bool GetNetworkListImpl(NetworkInterfaceList* networks,
90 int policy,
91 bool is_xp,
92 const IP_ADAPTER_ADDRESSES* adapters) {
93 for (const IP_ADAPTER_ADDRESSES* adapter = adapters; adapter != NULL;
94 adapter = adapter->Next) {
95 // Ignore the loopback device.
96 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) {
97 continue;
100 if (adapter->OperStatus != IfOperStatusUp) {
101 continue;
104 // Ignore any HOST side vmware adapters with a description like:
105 // VMware Virtual Ethernet Adapter for VMnet1
106 // but don't ignore any GUEST side adapters with a description like:
107 // VMware Accelerated AMD PCNet Adapter #2
108 if ((policy & EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES) &&
109 strstr(adapter->AdapterName, "VMnet") != NULL) {
110 continue;
113 for (IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress;
114 address; address = address->Next) {
115 int family = address->Address.lpSockaddr->sa_family;
116 if (family == AF_INET || family == AF_INET6) {
117 IPEndPoint endpoint;
118 if (endpoint.FromSockAddr(address->Address.lpSockaddr,
119 address->Address.iSockaddrLength)) {
120 // XP has no OnLinkPrefixLength field.
121 size_t prefix_length = is_xp ? 0 : address->OnLinkPrefixLength;
122 if (is_xp) {
123 // Prior to Windows Vista the FirstPrefix pointed to the list with
124 // single prefix for each IP address assigned to the adapter.
125 // Order of FirstPrefix does not match order of FirstUnicastAddress,
126 // so we need to find corresponding prefix.
127 for (IP_ADAPTER_PREFIX* prefix = adapter->FirstPrefix; prefix;
128 prefix = prefix->Next) {
129 int prefix_family = prefix->Address.lpSockaddr->sa_family;
130 IPEndPoint network_endpoint;
131 if (prefix_family == family &&
132 network_endpoint.FromSockAddr(prefix->Address.lpSockaddr,
133 prefix->Address.iSockaddrLength) &&
134 IPNumberMatchesPrefix(endpoint.address(),
135 network_endpoint.address(),
136 prefix->PrefixLength)) {
137 prefix_length =
138 std::max<size_t>(prefix_length, prefix->PrefixLength);
143 // If the duplicate address detection (DAD) state is not changed to
144 // Preferred, skip this address.
145 if (address->DadState != IpDadStatePreferred) {
146 continue;
149 uint32 index =
150 (family == AF_INET) ? adapter->IfIndex : adapter->Ipv6IfIndex;
152 // From http://technet.microsoft.com/en-us/ff568768(v=vs.60).aspx, the
153 // way to identify a temporary IPv6 Address is to check if
154 // PrefixOrigin is equal to IpPrefixOriginRouterAdvertisement and
155 // SuffixOrigin equal to IpSuffixOriginRandom.
156 int ip_address_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
157 if (family == AF_INET6) {
158 if (address->PrefixOrigin == IpPrefixOriginRouterAdvertisement &&
159 address->SuffixOrigin == IpSuffixOriginRandom) {
160 ip_address_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
162 if (address->PreferredLifetime == 0) {
163 ip_address_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
166 networks->push_back(NetworkInterface(
167 adapter->AdapterName,
168 base::SysWideToNativeMB(adapter->FriendlyName), index,
169 GetNetworkInterfaceType(adapter->IfType), endpoint.address(),
170 prefix_length, ip_address_attributes));
175 return true;
178 } // namespace internal
180 bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
181 bool is_xp = base::win::GetVersion() < base::win::VERSION_VISTA;
182 ULONG len = 0;
183 ULONG flags = is_xp ? GAA_FLAG_INCLUDE_PREFIX : 0;
184 // GetAdaptersAddresses() may require IO operations.
185 base::ThreadRestrictions::AssertIOAllowed();
186 ULONG result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, NULL, &len);
187 if (result != ERROR_BUFFER_OVERFLOW) {
188 // There are 0 networks.
189 return true;
191 scoped_ptr<char[]> buf(new char[len]);
192 IP_ADAPTER_ADDRESSES* adapters =
193 reinterpret_cast<IP_ADAPTER_ADDRESSES*>(buf.get());
194 result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapters, &len);
195 if (result != NO_ERROR) {
196 LOG(ERROR) << "GetAdaptersAddresses failed: " << result;
197 return false;
200 return internal::GetNetworkListImpl(networks, policy, is_xp, adapters);
203 WifiPHYLayerProtocol GetWifiPHYLayerProtocol() {
204 const internal::WlanApi& wlanapi = internal::WlanApi::GetInstance();
205 if (!wlanapi.initialized)
206 return WIFI_PHY_LAYER_PROTOCOL_NONE;
208 internal::WlanHandle client;
209 DWORD cur_version = 0;
210 const DWORD kMaxClientVersion = 2;
212 // TODO(rtenneti): Remove ScopedTracker below once crbug.com/422516 is
213 // fixed.
214 tracked_objects::ScopedTracker tracking_profile(
215 FROM_HERE_WITH_EXPLICIT_FUNCTION("422516 OpenHandle()"));
216 DWORD result = wlanapi.OpenHandle(kMaxClientVersion, &cur_version, &client);
217 if (result != ERROR_SUCCESS)
218 return WIFI_PHY_LAYER_PROTOCOL_NONE;
221 WLAN_INTERFACE_INFO_LIST* interface_list_ptr = NULL;
222 DWORD result =
223 wlanapi.enum_interfaces_func(client.Get(), NULL, &interface_list_ptr);
224 if (result != ERROR_SUCCESS)
225 return WIFI_PHY_LAYER_PROTOCOL_NONE;
226 scoped_ptr<WLAN_INTERFACE_INFO_LIST, internal::WlanApiDeleter> interface_list(
227 interface_list_ptr);
229 // Assume at most one connected wifi interface.
230 WLAN_INTERFACE_INFO* info = NULL;
231 for (unsigned i = 0; i < interface_list->dwNumberOfItems; ++i) {
232 if (interface_list->InterfaceInfo[i].isState ==
233 wlan_interface_state_connected) {
234 info = &interface_list->InterfaceInfo[i];
235 break;
239 if (info == NULL)
240 return WIFI_PHY_LAYER_PROTOCOL_NONE;
242 WLAN_CONNECTION_ATTRIBUTES* conn_info_ptr;
243 DWORD conn_info_size = 0;
244 WLAN_OPCODE_VALUE_TYPE op_code;
245 result = wlanapi.query_interface_func(
246 client.Get(), &info->InterfaceGuid, wlan_intf_opcode_current_connection,
247 NULL, &conn_info_size, reinterpret_cast<VOID**>(&conn_info_ptr),
248 &op_code);
249 if (result != ERROR_SUCCESS)
250 return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
251 scoped_ptr<WLAN_CONNECTION_ATTRIBUTES, internal::WlanApiDeleter> conn_info(
252 conn_info_ptr);
254 switch (conn_info->wlanAssociationAttributes.dot11PhyType) {
255 case dot11_phy_type_fhss:
256 return WIFI_PHY_LAYER_PROTOCOL_ANCIENT;
257 case dot11_phy_type_dsss:
258 return WIFI_PHY_LAYER_PROTOCOL_B;
259 case dot11_phy_type_irbaseband:
260 return WIFI_PHY_LAYER_PROTOCOL_ANCIENT;
261 case dot11_phy_type_ofdm:
262 return WIFI_PHY_LAYER_PROTOCOL_A;
263 case dot11_phy_type_hrdsss:
264 return WIFI_PHY_LAYER_PROTOCOL_B;
265 case dot11_phy_type_erp:
266 return WIFI_PHY_LAYER_PROTOCOL_G;
267 case dot11_phy_type_ht:
268 return WIFI_PHY_LAYER_PROTOCOL_N;
269 default:
270 return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
274 // Note: There is no need to explicitly set the options back
275 // as the OS will automatically set them back when the WlanHandle
276 // is closed.
277 class WifiOptionSetter : public ScopedWifiOptions {
278 public:
279 WifiOptionSetter(int options) {
280 const internal::WlanApi& wlanapi = internal::WlanApi::GetInstance();
281 if (!wlanapi.initialized)
282 return;
284 DWORD cur_version = 0;
285 const DWORD kMaxClientVersion = 2;
286 DWORD result = wlanapi.OpenHandle(
287 kMaxClientVersion, &cur_version, &client_);
288 if (result != ERROR_SUCCESS)
289 return;
291 WLAN_INTERFACE_INFO_LIST* interface_list_ptr = NULL;
292 result = wlanapi.enum_interfaces_func(client_.Get(), NULL,
293 &interface_list_ptr);
294 if (result != ERROR_SUCCESS)
295 return;
296 scoped_ptr<WLAN_INTERFACE_INFO_LIST, internal::WlanApiDeleter>
297 interface_list(interface_list_ptr);
299 for (unsigned i = 0; i < interface_list->dwNumberOfItems; ++i) {
300 WLAN_INTERFACE_INFO* info = &interface_list->InterfaceInfo[i];
301 if (options & WIFI_OPTIONS_DISABLE_SCAN) {
302 BOOL data = false;
303 wlanapi.set_interface_func(client_.Get(),
304 &info->InterfaceGuid,
305 wlan_intf_opcode_background_scan_enabled,
306 sizeof(data),
307 &data,
308 NULL);
310 if (options & WIFI_OPTIONS_MEDIA_STREAMING_MODE) {
311 BOOL data = true;
312 wlanapi.set_interface_func(client_.Get(),
313 &info->InterfaceGuid,
314 wlan_intf_opcode_media_streaming_mode,
315 sizeof(data),
316 &data,
317 NULL);
322 private:
323 internal::WlanHandle client_;
326 scoped_ptr<ScopedWifiOptions> SetWifiOptions(int options) {
327 return scoped_ptr<ScopedWifiOptions>(new WifiOptionSetter(options));
330 std::string GetWifiSSID() {
331 NOTIMPLEMENTED();
332 return "";
335 } // namespace net