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"
25 #include "net/base/net_util_win.h"
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?
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
);
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
;
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.
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
;
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
) {
123 if (adapter
->OperStatus
!= IfOperStatusUp
) {
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
) {
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
) {
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
;
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
);
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
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
),
180 GetNetworkInterfaceType(adapter
->IfType
),
183 IP_ADDRESS_ATTRIBUTE_NONE
));
188 NetworkInterface(adapter
->AdapterName
,
189 base::SysWideToNativeMB(adapter
->FriendlyName
),
191 GetNetworkInterfaceType(adapter
->IfType
),
194 IP_ADDRESS_ATTRIBUTE_NONE
));
200 if (ipv6_address
.get()) {
201 networks
->push_back(*(ipv6_address
.get()));
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(
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
];
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
),
246 if (result
!= ERROR_SUCCESS
)
247 return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN
;
248 scoped_ptr
<WLAN_CONNECTION_ATTRIBUTES
, internal::WlanApiDeleter
> conn_info(
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
;
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
274 class WifiOptionSetter
: public ScopedWifiOptions
{
276 WifiOptionSetter(int options
) {
277 const internal::WlanApi
& wlanapi
= internal::WlanApi::GetInstance();
278 if (!wlanapi
.initialized
)
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
)
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
)
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
) {
300 wlanapi
.set_interface_func(client_
.Get(),
301 &info
->InterfaceGuid
,
302 wlan_intf_opcode_background_scan_enabled
,
307 if (options
& WIFI_OPTIONS_MEDIA_STREAMING_MODE
) {
309 wlanapi
.set_interface_func(client_
.Get(),
310 &info
->InterfaceGuid
,
311 wlan_intf_opcode_media_streaming_mode
,
320 internal::WlanHandle client_
;
323 scoped_ptr
<ScopedWifiOptions
> SetWifiOptions(int options
) {
324 return scoped_ptr
<ScopedWifiOptions
>(new WifiOptionSetter(options
));