Upstream version 7.36.149.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 "url/gurl.h"
26
27 namespace net {
28
29 namespace {
30
31 struct 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.
87 NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(DWORD ifType) {
88   NetworkChangeNotifier::ConnectionType type =
89       NetworkChangeNotifier::CONNECTION_UNKNOWN;
90   if (ifType == IF_TYPE_ETHERNET_CSMACD) {
91     type = NetworkChangeNotifier::CONNECTION_ETHERNET;
92   } else if (ifType == IF_TYPE_IEEE80211) {
93     type = NetworkChangeNotifier::CONNECTION_WIFI;
94   }
95   // TODO(mallinath) - Cellular?
96   return type;
97 }
98
99 }  // namespace
100
101 bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
102   // GetAdaptersAddresses() may require IO operations.
103   base::ThreadRestrictions::AssertIOAllowed();
104   bool is_xp = base::win::GetVersion() < base::win::VERSION_VISTA;
105   ULONG len = 0;
106   ULONG flags = is_xp ? GAA_FLAG_INCLUDE_PREFIX : 0;
107   // First get number of networks.
108   ULONG result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, NULL, &len);
109   if (result != ERROR_BUFFER_OVERFLOW) {
110     // There are 0 networks.
111     return true;
112   }
113   scoped_ptr<char[]> buf(new char[len]);
114   IP_ADAPTER_ADDRESSES *adapters =
115       reinterpret_cast<IP_ADAPTER_ADDRESSES *>(buf.get());
116   result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapters, &len);
117   if (result != NO_ERROR) {
118     LOG(ERROR) << "GetAdaptersAddresses failed: " << result;
119     return false;
120   }
121
122   // These two variables are used below when this method is asked to pick a
123   // IPv6 address which has the shortest lifetime.
124   ULONG ipv6_valid_lifetime = 0;
125   scoped_ptr<NetworkInterface> ipv6_address;
126
127   for (IP_ADAPTER_ADDRESSES *adapter = adapters; adapter != NULL;
128        adapter = adapter->Next) {
129     // Ignore the loopback device.
130     if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) {
131       continue;
132     }
133
134     if (adapter->OperStatus != IfOperStatusUp) {
135       continue;
136     }
137
138     // Ignore any HOST side vmware adapters with a description like:
139     // VMware Virtual Ethernet Adapter for VMnet1
140     // but don't ignore any GUEST side adapters with a description like:
141     // VMware Accelerated AMD PCNet Adapter #2
142     if (policy == EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES &&
143         strstr(adapter->AdapterName, "VMnet") != NULL) {
144       continue;
145     }
146
147     for (IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress;
148          address; address = address->Next) {
149       int family = address->Address.lpSockaddr->sa_family;
150       if (family == AF_INET || family == AF_INET6) {
151         IPEndPoint endpoint;
152         if (endpoint.FromSockAddr(address->Address.lpSockaddr,
153                                   address->Address.iSockaddrLength)) {
154           // XP has no OnLinkPrefixLength field.
155           size_t net_prefix = is_xp ? 0 : address->OnLinkPrefixLength;
156           if (is_xp) {
157             // Prior to Windows Vista the FirstPrefix pointed to the list with
158             // single prefix for each IP address assigned to the adapter.
159             // Order of FirstPrefix does not match order of FirstUnicastAddress,
160             // so we need to find corresponding prefix.
161             for (IP_ADAPTER_PREFIX* prefix = adapter->FirstPrefix; prefix;
162                  prefix = prefix->Next) {
163               int prefix_family = prefix->Address.lpSockaddr->sa_family;
164               IPEndPoint network_endpoint;
165               if (prefix_family == family &&
166                   network_endpoint.FromSockAddr(prefix->Address.lpSockaddr,
167                       prefix->Address.iSockaddrLength) &&
168                   IPNumberMatchesPrefix(endpoint.address(),
169                                         network_endpoint.address(),
170                                         prefix->PrefixLength)) {
171                 net_prefix = std::max<size_t>(net_prefix, prefix->PrefixLength);
172               }
173             }
174           }
175           uint32 index =
176               (family == AF_INET) ? adapter->IfIndex : adapter->Ipv6IfIndex;
177           // Pick one IPv6 address with least valid lifetime.
178           // The reason we are checking |ValidLifeftime| as there is no other
179           // way identifying the interface type. Usually (and most likely) temp
180           // IPv6 will have a shorter ValidLifetime value then the permanent
181           // interface.
182           if (family == AF_INET6 &&
183               (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE)) {
184             if (ipv6_valid_lifetime == 0 ||
185                 ipv6_valid_lifetime > address->ValidLifetime) {
186               ipv6_valid_lifetime = address->ValidLifetime;
187               ipv6_address.reset(new NetworkInterface(adapter->AdapterName,
188                                  base::SysWideToNativeMB(adapter->FriendlyName),
189                                  index,
190                                  GetNetworkInterfaceType(adapter->IfType),
191                                  endpoint.address(),
192                                  net_prefix));
193               continue;
194             }
195           }
196           networks->push_back(
197               NetworkInterface(adapter->AdapterName,
198                                base::SysWideToNativeMB(adapter->FriendlyName),
199                                index, GetNetworkInterfaceType(adapter->IfType),
200                                endpoint.address(), net_prefix));
201         }
202       }
203     }
204   }
205
206   if (ipv6_address.get()) {
207     networks->push_back(*(ipv6_address.get()));
208   }
209   return true;
210 }
211
212 WifiPHYLayerProtocol GetWifiPHYLayerProtocol() {
213   static base::LazyInstance<WlanApi>::Leaky lazy_wlanapi =
214       LAZY_INSTANCE_INITIALIZER;
215
216   struct WlanApiHandleTraits {
217     typedef HANDLE Handle;
218
219     static bool CloseHandle(HANDLE handle) {
220       return lazy_wlanapi.Get().close_handle_func(handle, NULL) ==
221           ERROR_SUCCESS;
222     }
223     static bool IsHandleValid(HANDLE handle) {
224       return base::win::HandleTraits::IsHandleValid(handle);
225     }
226     static HANDLE NullHandle() {
227       return base::win::HandleTraits::NullHandle();
228     }
229   };
230
231   typedef base::win::GenericScopedHandle<
232       WlanApiHandleTraits,
233       base::win::DummyVerifierTraits> WlanHandle;
234
235   struct WlanApiDeleter {
236     inline void operator()(void* ptr) const {
237       lazy_wlanapi.Get().free_memory_func(ptr);
238     }
239   };
240
241   const WlanApi& wlanapi = lazy_wlanapi.Get();
242   if (!wlanapi.initialized)
243     return WIFI_PHY_LAYER_PROTOCOL_NONE;
244
245   WlanHandle client;
246   DWORD cur_version = 0;
247   const DWORD kMaxClientVersion = 2;
248   DWORD result = wlanapi.OpenHandle(kMaxClientVersion, &cur_version, &client);
249   if (result != ERROR_SUCCESS)
250     return WIFI_PHY_LAYER_PROTOCOL_NONE;
251
252   WLAN_INTERFACE_INFO_LIST* interface_list_ptr = NULL;
253   result = wlanapi.enum_interfaces_func(client, NULL, &interface_list_ptr);
254   if (result != ERROR_SUCCESS)
255     return WIFI_PHY_LAYER_PROTOCOL_NONE;
256   scoped_ptr<WLAN_INTERFACE_INFO_LIST, WlanApiDeleter> interface_list(
257       interface_list_ptr);
258
259   // Assume at most one connected wifi interface.
260   WLAN_INTERFACE_INFO* info = NULL;
261   for (unsigned i = 0; i < interface_list->dwNumberOfItems; ++i) {
262     if (interface_list->InterfaceInfo[i].isState ==
263         wlan_interface_state_connected) {
264       info = &interface_list->InterfaceInfo[i];
265       break;
266     }
267   }
268
269   if (info == NULL)
270     return WIFI_PHY_LAYER_PROTOCOL_NONE;
271
272   WLAN_CONNECTION_ATTRIBUTES* conn_info_ptr;
273   DWORD conn_info_size = 0;
274   WLAN_OPCODE_VALUE_TYPE op_code;
275   result = wlanapi.query_interface_func(
276       client, &info->InterfaceGuid, wlan_intf_opcode_current_connection, NULL,
277       &conn_info_size, reinterpret_cast<VOID**>(&conn_info_ptr), &op_code);
278   if (result != ERROR_SUCCESS)
279     return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
280   scoped_ptr<WLAN_CONNECTION_ATTRIBUTES, WlanApiDeleter> conn_info(
281       conn_info_ptr);
282
283   switch (conn_info->wlanAssociationAttributes.dot11PhyType) {
284     case dot11_phy_type_fhss:
285       return WIFI_PHY_LAYER_PROTOCOL_ANCIENT;
286     case dot11_phy_type_dsss:
287       return WIFI_PHY_LAYER_PROTOCOL_B;
288     case dot11_phy_type_irbaseband:
289       return WIFI_PHY_LAYER_PROTOCOL_ANCIENT;
290     case dot11_phy_type_ofdm:
291       return WIFI_PHY_LAYER_PROTOCOL_A;
292     case dot11_phy_type_hrdsss:
293       return WIFI_PHY_LAYER_PROTOCOL_B;
294     case dot11_phy_type_erp:
295       return WIFI_PHY_LAYER_PROTOCOL_G;
296     case dot11_phy_type_ht:
297       return WIFI_PHY_LAYER_PROTOCOL_N;
298     default:
299       return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
300   }
301 }
302
303 }  // namespace net