Chromecast Android buildfix: rework CommandLine initialization logic.
[chromium-blink-merge.git] / net / base / net_util_win.cc
blob7d146b91e511f2f3ba1c8f213ea90eb2652b3e4b
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/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 "net/base/net_util_win.h"
26 #include "url/gurl.h"
28 namespace net {
30 namespace {
32 // Converts Windows defined types to NetworkInterfaceType.
33 NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(DWORD ifType) {
34 // Bail out for pre-Vista versions of Windows which are documented to give
35 // inaccurate results like returning Ethernet for WiFi.
36 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366058.aspx
37 if (base::win::GetVersion() < base::win::VERSION_VISTA)
38 return NetworkChangeNotifier::CONNECTION_UNKNOWN;
40 NetworkChangeNotifier::ConnectionType type =
41 NetworkChangeNotifier::CONNECTION_UNKNOWN;
42 if (ifType == IF_TYPE_ETHERNET_CSMACD) {
43 type = NetworkChangeNotifier::CONNECTION_ETHERNET;
44 } else if (ifType == IF_TYPE_IEEE80211) {
45 type = NetworkChangeNotifier::CONNECTION_WIFI;
47 // TODO(mallinath) - Cellular?
48 return type;
51 } // namespace
53 namespace internal {
55 base::LazyInstance<WlanApi>::Leaky lazy_wlanapi =
56 LAZY_INSTANCE_INITIALIZER;
58 WlanApi& WlanApi::GetInstance() {
59 return lazy_wlanapi.Get();
62 WlanApi::WlanApi() : initialized(false) {
63 // Use an absolute path to load the DLL to avoid DLL preloading attacks.
64 static const wchar_t* const kDLL = L"%WINDIR%\\system32\\wlanapi.dll";
65 wchar_t path[MAX_PATH] = {0};
66 ExpandEnvironmentStrings(kDLL, path, arraysize(path));
67 module = ::LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
68 if (!module)
69 return;
71 open_handle_func = reinterpret_cast<WlanOpenHandleFunc>(
72 ::GetProcAddress(module, "WlanOpenHandle"));
73 enum_interfaces_func = reinterpret_cast<WlanEnumInterfacesFunc>(
74 ::GetProcAddress(module, "WlanEnumInterfaces"));
75 query_interface_func = reinterpret_cast<WlanQueryInterfaceFunc>(
76 ::GetProcAddress(module, "WlanQueryInterface"));
77 set_interface_func = reinterpret_cast<WlanSetInterfaceFunc>(
78 ::GetProcAddress(module, "WlanSetInterface"));
79 free_memory_func = reinterpret_cast<WlanFreeMemoryFunc>(
80 ::GetProcAddress(module, "WlanFreeMemory"));
81 close_handle_func = reinterpret_cast<WlanCloseHandleFunc>(
82 ::GetProcAddress(module, "WlanCloseHandle"));
83 initialized = open_handle_func && enum_interfaces_func &&
84 query_interface_func && set_interface_func &&
85 free_memory_func && close_handle_func;
88 } // namespace internal
90 bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
91 // GetAdaptersAddresses() may require IO operations.
92 base::ThreadRestrictions::AssertIOAllowed();
93 bool is_xp = base::win::GetVersion() < base::win::VERSION_VISTA;
94 ULONG len = 0;
95 ULONG flags = is_xp ? GAA_FLAG_INCLUDE_PREFIX : 0;
96 // First get number of networks.
97 ULONG result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, NULL, &len);
98 if (result != ERROR_BUFFER_OVERFLOW) {
99 // There are 0 networks.
100 return true;
102 scoped_ptr<char[]> buf(new char[len]);
103 IP_ADAPTER_ADDRESSES *adapters =
104 reinterpret_cast<IP_ADAPTER_ADDRESSES *>(buf.get());
105 result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapters, &len);
106 if (result != NO_ERROR) {
107 LOG(ERROR) << "GetAdaptersAddresses failed: " << result;
108 return false;
111 // These two variables are used below when this method is asked to pick a
112 // IPv6 address which has the shortest lifetime.
113 ULONG ipv6_valid_lifetime = 0;
114 scoped_ptr<NetworkInterface> ipv6_address;
116 for (IP_ADAPTER_ADDRESSES *adapter = adapters; adapter != NULL;
117 adapter = adapter->Next) {
118 // Ignore the loopback device.
119 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) {
120 continue;
123 if (adapter->OperStatus != IfOperStatusUp) {
124 continue;
127 // Ignore any HOST side vmware adapters with a description like:
128 // VMware Virtual Ethernet Adapter for VMnet1
129 // but don't ignore any GUEST side adapters with a description like:
130 // VMware Accelerated AMD PCNet Adapter #2
131 if (policy == EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES &&
132 strstr(adapter->AdapterName, "VMnet") != NULL) {
133 continue;
136 for (IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress;
137 address; address = address->Next) {
138 int family = address->Address.lpSockaddr->sa_family;
139 if (family == AF_INET || family == AF_INET6) {
140 IPEndPoint endpoint;
141 if (endpoint.FromSockAddr(address->Address.lpSockaddr,
142 address->Address.iSockaddrLength)) {
143 // XP has no OnLinkPrefixLength field.
144 size_t net_prefix = is_xp ? 0 : address->OnLinkPrefixLength;
145 if (is_xp) {
146 // Prior to Windows Vista the FirstPrefix pointed to the list with
147 // single prefix for each IP address assigned to the adapter.
148 // Order of FirstPrefix does not match order of FirstUnicastAddress,
149 // so we need to find corresponding prefix.
150 for (IP_ADAPTER_PREFIX* prefix = adapter->FirstPrefix; prefix;
151 prefix = prefix->Next) {
152 int prefix_family = prefix->Address.lpSockaddr->sa_family;
153 IPEndPoint network_endpoint;
154 if (prefix_family == family &&
155 network_endpoint.FromSockAddr(prefix->Address.lpSockaddr,
156 prefix->Address.iSockaddrLength) &&
157 IPNumberMatchesPrefix(endpoint.address(),
158 network_endpoint.address(),
159 prefix->PrefixLength)) {
160 net_prefix = std::max<size_t>(net_prefix, prefix->PrefixLength);
164 uint32 index =
165 (family == AF_INET) ? adapter->IfIndex : adapter->Ipv6IfIndex;
166 // Pick one IPv6 address with least valid lifetime.
167 // The reason we are checking |ValidLifeftime| as there is no other
168 // way identifying the interface type. Usually (and most likely) temp
169 // IPv6 will have a shorter ValidLifetime value then the permanent
170 // interface.
171 if (family == AF_INET6 &&
172 (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE)) {
173 if (ipv6_valid_lifetime == 0 ||
174 ipv6_valid_lifetime > address->ValidLifetime) {
175 ipv6_valid_lifetime = address->ValidLifetime;
176 ipv6_address.reset(new NetworkInterface(
177 adapter->AdapterName,
178 base::SysWideToNativeMB(adapter->FriendlyName),
179 index,
180 GetNetworkInterfaceType(adapter->IfType),
181 endpoint.address(),
182 net_prefix,
183 IP_ADDRESS_ATTRIBUTE_NONE));
184 continue;
187 networks->push_back(
188 NetworkInterface(adapter->AdapterName,
189 base::SysWideToNativeMB(adapter->FriendlyName),
190 index,
191 GetNetworkInterfaceType(adapter->IfType),
192 endpoint.address(),
193 net_prefix,
194 IP_ADDRESS_ATTRIBUTE_NONE));
200 if (ipv6_address.get()) {
201 networks->push_back(*(ipv6_address.get()));
203 return true;
206 WifiPHYLayerProtocol GetWifiPHYLayerProtocol() {
207 const internal::WlanApi& wlanapi = internal::WlanApi::GetInstance();
208 if (!wlanapi.initialized)
209 return WIFI_PHY_LAYER_PROTOCOL_NONE;
211 internal::WlanHandle client;
212 DWORD cur_version = 0;
213 const DWORD kMaxClientVersion = 2;
214 DWORD result = wlanapi.OpenHandle(kMaxClientVersion, &cur_version, &client);
215 if (result != ERROR_SUCCESS)
216 return WIFI_PHY_LAYER_PROTOCOL_NONE;
218 WLAN_INTERFACE_INFO_LIST* interface_list_ptr = NULL;
219 result = wlanapi.enum_interfaces_func(client.Get(), NULL,
220 &interface_list_ptr);
221 if (result != ERROR_SUCCESS)
222 return WIFI_PHY_LAYER_PROTOCOL_NONE;
223 scoped_ptr<WLAN_INTERFACE_INFO_LIST, internal::WlanApiDeleter> interface_list(
224 interface_list_ptr);
226 // Assume at most one connected wifi interface.
227 WLAN_INTERFACE_INFO* info = NULL;
228 for (unsigned i = 0; i < interface_list->dwNumberOfItems; ++i) {
229 if (interface_list->InterfaceInfo[i].isState ==
230 wlan_interface_state_connected) {
231 info = &interface_list->InterfaceInfo[i];
232 break;
236 if (info == NULL)
237 return WIFI_PHY_LAYER_PROTOCOL_NONE;
239 WLAN_CONNECTION_ATTRIBUTES* conn_info_ptr;
240 DWORD conn_info_size = 0;
241 WLAN_OPCODE_VALUE_TYPE op_code;
242 result = wlanapi.query_interface_func(
243 client.Get(), &info->InterfaceGuid, wlan_intf_opcode_current_connection,
244 NULL, &conn_info_size, reinterpret_cast<VOID**>(&conn_info_ptr),
245 &op_code);
246 if (result != ERROR_SUCCESS)
247 return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
248 scoped_ptr<WLAN_CONNECTION_ATTRIBUTES, internal::WlanApiDeleter> conn_info(
249 conn_info_ptr);
251 switch (conn_info->wlanAssociationAttributes.dot11PhyType) {
252 case dot11_phy_type_fhss:
253 return WIFI_PHY_LAYER_PROTOCOL_ANCIENT;
254 case dot11_phy_type_dsss:
255 return WIFI_PHY_LAYER_PROTOCOL_B;
256 case dot11_phy_type_irbaseband:
257 return WIFI_PHY_LAYER_PROTOCOL_ANCIENT;
258 case dot11_phy_type_ofdm:
259 return WIFI_PHY_LAYER_PROTOCOL_A;
260 case dot11_phy_type_hrdsss:
261 return WIFI_PHY_LAYER_PROTOCOL_B;
262 case dot11_phy_type_erp:
263 return WIFI_PHY_LAYER_PROTOCOL_G;
264 case dot11_phy_type_ht:
265 return WIFI_PHY_LAYER_PROTOCOL_N;
266 default:
267 return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
271 // Note: There is no need to explicitly set the options back
272 // as the OS will automatically set them back when the WlanHandle
273 // is closed.
274 class WifiOptionSetter : public ScopedWifiOptions {
275 public:
276 WifiOptionSetter(int options) {
277 const internal::WlanApi& wlanapi = internal::WlanApi::GetInstance();
278 if (!wlanapi.initialized)
279 return;
281 DWORD cur_version = 0;
282 const DWORD kMaxClientVersion = 2;
283 DWORD result = wlanapi.OpenHandle(
284 kMaxClientVersion, &cur_version, &client_);
285 if (result != ERROR_SUCCESS)
286 return;
288 WLAN_INTERFACE_INFO_LIST* interface_list_ptr = NULL;
289 result = wlanapi.enum_interfaces_func(client_.Get(), NULL,
290 &interface_list_ptr);
291 if (result != ERROR_SUCCESS)
292 return;
293 scoped_ptr<WLAN_INTERFACE_INFO_LIST, internal::WlanApiDeleter>
294 interface_list(interface_list_ptr);
296 for (unsigned i = 0; i < interface_list->dwNumberOfItems; ++i) {
297 WLAN_INTERFACE_INFO* info = &interface_list->InterfaceInfo[i];
298 if (options & WIFI_OPTIONS_DISABLE_SCAN) {
299 BOOL data = false;
300 wlanapi.set_interface_func(client_.Get(),
301 &info->InterfaceGuid,
302 wlan_intf_opcode_background_scan_enabled,
303 sizeof(data),
304 &data,
305 NULL);
307 if (options & WIFI_OPTIONS_MEDIA_STREAMING_MODE) {
308 BOOL data = true;
309 wlanapi.set_interface_func(client_.Get(),
310 &info->InterfaceGuid,
311 wlan_intf_opcode_media_streaming_mode,
312 sizeof(data),
313 &data,
314 NULL);
319 private:
320 internal::WlanHandle client_;
323 scoped_ptr<ScopedWifiOptions> SetWifiOptions(int options) {
324 return scoped_ptr<ScopedWifiOptions>(new WifiOptionSetter(options));
327 } // namespace net