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"
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"
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
*);
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
);
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
&&
67 DWORD
OpenHandle(DWORD client_version
, DWORD
* cur_version
, T
* handle
) const {
69 DWORD result
= open_handle_func(client_version
, NULL
, cur_version
,
71 if (result
!= ERROR_SUCCESS
)
73 handle
->Set(temp_handle
);
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
;
86 // Converts Windows defined types to NetworkInterfaceType.
87 NetworkChangeNotifier::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
;
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
;
101 // TODO(mallinath) - Cellular?
107 bool 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
;
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.
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
;
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
;
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
) {
140 if (adapter
->OperStatus
!= IfOperStatusUp
) {
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
) {
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
) {
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
;
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
);
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
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
),
196 GetNetworkInterfaceType(adapter
->IfType
),
203 NetworkInterface(adapter
->AdapterName
,
204 base::SysWideToNativeMB(adapter
->FriendlyName
),
205 index
, GetNetworkInterfaceType(adapter
->IfType
),
206 endpoint
.address(), net_prefix
));
212 if (ipv6_address
.get()) {
213 networks
->push_back(*(ipv6_address
.get()));
218 WifiPHYLayerProtocol
GetWifiPHYLayerProtocol() {
219 static base::LazyInstance
<WlanApi
>::Leaky lazy_wlanapi
=
220 LAZY_INSTANCE_INITIALIZER
;
222 struct WlanApiHandleTraits
{
223 typedef HANDLE Handle
;
225 static bool CloseHandle(HANDLE handle
) {
226 return lazy_wlanapi
.Get().close_handle_func(handle
, NULL
) ==
229 static bool IsHandleValid(HANDLE handle
) {
230 return base::win::HandleTraits::IsHandleValid(handle
);
232 static HANDLE
NullHandle() {
233 return base::win::HandleTraits::NullHandle();
237 typedef base::win::GenericScopedHandle
<
239 base::win::DummyVerifierTraits
> WlanHandle
;
241 struct WlanApiDeleter
{
242 inline void operator()(void* ptr
) const {
243 lazy_wlanapi
.Get().free_memory_func(ptr
);
247 const WlanApi
& wlanapi
= lazy_wlanapi
.Get();
248 if (!wlanapi
.initialized
)
249 return WIFI_PHY_LAYER_PROTOCOL_NONE
;
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
;
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(
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
];
276 return WIFI_PHY_LAYER_PROTOCOL_NONE
;
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(
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
;
305 return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN
;