Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / net / base / net_util_win.cc
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 "net/base/net_util_win.h"
26 #include "url/gurl.h"
27
28 namespace net {
29
30 namespace {
31
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;
39
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;
46   }
47   // TODO(mallinath) - Cellular?
48   return type;
49 }
50
51 }  // namespace
52
53 namespace internal {
54
55 base::LazyInstance<WlanApi>::Leaky lazy_wlanapi =
56   LAZY_INSTANCE_INITIALIZER;
57
58 WlanApi& WlanApi::GetInstance() {
59   return lazy_wlanapi.Get();
60 }
61
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;
70
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;
86 }
87
88 }  // namespace internal
89
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;
101   }
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;
109   }
110
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;
115
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;
121     }
122
123     if (adapter->OperStatus != IfOperStatusUp) {
124       continue;
125     }
126
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;
134     }
135
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);
161               }
162             }
163           }
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;
185             }
186           }
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));
195         }
196       }
197     }
198   }
199
200   if (ipv6_address.get()) {
201     networks->push_back(*(ipv6_address.get()));
202   }
203   return true;
204 }
205
206 WifiPHYLayerProtocol GetWifiPHYLayerProtocol() {
207   const internal::WlanApi& wlanapi = internal::WlanApi::GetInstance();
208   if (!wlanapi.initialized)
209     return WIFI_PHY_LAYER_PROTOCOL_NONE;
210
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;
217
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);
225
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;
233     }
234   }
235
236   if (info == NULL)
237     return WIFI_PHY_LAYER_PROTOCOL_NONE;
238
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);
250
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;
268   }
269 }
270
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;
280
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;
287
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);
295
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);
306       }
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);
315       }
316     }
317   }
318
319  private:
320   internal::WlanHandle client_;
321 };
322
323 scoped_ptr<ScopedWifiOptions> SetWifiOptions(int options) {
324   return scoped_ptr<ScopedWifiOptions>(new WifiOptionSetter(options));
325 }
326
327 }  // namespace net