1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "wificond/client_interface_impl.h"
18
19 #include <vector>
20
21 #include <android-base/logging.h>
22 #include <utils/Timers.h>
23
24 #include "wificond/client_interface_binder.h"
25 #include "wificond/logging_utils.h"
26 #include "wificond/net/mlme_event.h"
27 #include "wificond/net/netlink_utils.h"
28 #include "wificond/scanning/scan_result.h"
29 #include "wificond/scanning/scan_utils.h"
30 #include "wificond/scanning/scanner_impl.h"
31
32 using android::net::wifi::nl80211::IClientInterface;
33 using android::net::wifi::nl80211::ISendMgmtFrameEvent;
34 using android::net::wifi::nl80211::NativeScanResult;
35 using android::sp;
36 using android::wifi_system::InterfaceTool;
37
38 using std::endl;
39 using std::string;
40 using std::unique_ptr;
41 using std::vector;
42
43 using namespace std::placeholders;
44
45 namespace android {
46 namespace wificond {
47
MlmeEventHandlerImpl(ClientInterfaceImpl * client_interface)48 MlmeEventHandlerImpl::MlmeEventHandlerImpl(ClientInterfaceImpl* client_interface)
49 : client_interface_(client_interface) {
50 }
51
~MlmeEventHandlerImpl()52 MlmeEventHandlerImpl::~MlmeEventHandlerImpl() {
53 }
54
OnConnect(unique_ptr<MlmeConnectEvent> event)55 void MlmeEventHandlerImpl::OnConnect(unique_ptr<MlmeConnectEvent> event) {
56 if (!event->IsTimeout() && event->GetStatusCode() == 0) {
57 client_interface_->is_associated_ = true;
58 client_interface_->RefreshAssociateFreq();
59 client_interface_->bssid_ = event->GetBSSID();
60 } else {
61 if (event->IsTimeout()) {
62 LOG(INFO) << "Connect timeout";
63 }
64 client_interface_->is_associated_ = false;
65 client_interface_->bssid_.fill(0);
66 }
67 }
68
OnRoam(unique_ptr<MlmeRoamEvent> event)69 void MlmeEventHandlerImpl::OnRoam(unique_ptr<MlmeRoamEvent> event) {
70 client_interface_->is_associated_ = true;
71 client_interface_->RefreshAssociateFreq();
72 client_interface_->bssid_ = event->GetBSSID();
73 }
74
OnAssociate(unique_ptr<MlmeAssociateEvent> event)75 void MlmeEventHandlerImpl::OnAssociate(unique_ptr<MlmeAssociateEvent> event) {
76 if (!event->IsTimeout() && event->GetStatusCode() == 0) {
77 client_interface_->is_associated_ = true;
78 client_interface_->RefreshAssociateFreq();
79 client_interface_->bssid_ = event->GetBSSID();
80 } else {
81 if (event->IsTimeout()) {
82 LOG(INFO) << "Associate timeout";
83 }
84 client_interface_->is_associated_ = false;
85 client_interface_->bssid_.fill(0);
86 }
87 }
88
OnDisconnect(unique_ptr<MlmeDisconnectEvent> event)89 void MlmeEventHandlerImpl::OnDisconnect(unique_ptr<MlmeDisconnectEvent> event) {
90 client_interface_->is_associated_ = false;
91 client_interface_->bssid_.fill(0);
92 }
93
OnDisassociate(unique_ptr<MlmeDisassociateEvent> event)94 void MlmeEventHandlerImpl::OnDisassociate(unique_ptr<MlmeDisassociateEvent> event) {
95 client_interface_->is_associated_ = false;
96 client_interface_->bssid_.fill(0);
97 }
98
99
ClientInterfaceImpl(uint32_t wiphy_index,const std::string & interface_name,uint32_t interface_index,const std::array<uint8_t,ETH_ALEN> & interface_mac_addr,InterfaceTool * if_tool,NetlinkUtils * netlink_utils,ScanUtils * scan_utils)100 ClientInterfaceImpl::ClientInterfaceImpl(
101 uint32_t wiphy_index,
102 const std::string& interface_name,
103 uint32_t interface_index,
104 const std::array<uint8_t, ETH_ALEN>& interface_mac_addr,
105 InterfaceTool* if_tool,
106 NetlinkUtils* netlink_utils,
107 ScanUtils* scan_utils)
108 : wiphy_index_(wiphy_index),
109 interface_name_(interface_name),
110 interface_index_(interface_index),
111 interface_mac_addr_(interface_mac_addr),
112 if_tool_(if_tool),
113 netlink_utils_(netlink_utils),
114 scan_utils_(scan_utils),
115 mlme_event_handler_(new MlmeEventHandlerImpl(this)),
116 binder_(new ClientInterfaceBinder(this)),
117 is_associated_(false),
118 frame_tx_in_progress_(false),
119 frame_tx_status_cookie_(0),
120 on_frame_tx_status_event_handler_([](bool was_acked) {}) {
121 netlink_utils_->SubscribeMlmeEvent(
122 interface_index_,
123 mlme_event_handler_.get());
124
125 netlink_utils_->SubscribeFrameTxStatusEvent(
126 interface_index,
__anon6049e0590202(uint64_t cookie, bool was_acked) 127 [this](uint64_t cookie, bool was_acked) {
128 if (frame_tx_in_progress_ && frame_tx_status_cookie_ == cookie) {
129 on_frame_tx_status_event_handler_(was_acked);
130 frame_tx_in_progress_ = false;
131 frame_tx_status_cookie_ = 0;
132 on_frame_tx_status_event_handler_ = [](bool was_acked) {};
133 }
134 });
135
136 netlink_utils_->SubscribeChannelSwitchEvent(interface_index_,
137 std::bind(&ClientInterfaceImpl::OnChannelSwitchEvent, this, _1));
138
139 if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
140 &band_info_,
141 &scan_capabilities_,
142 &wiphy_features_)) {
143 LOG(ERROR) << "Failed to get wiphy info from kernel";
144 }
145 LOG(INFO) << "create scanner for interface with index: "
146 << (int)interface_index_;
147 scanner_ = new ScannerImpl(interface_index_,
148 scan_capabilities_,
149 wiphy_features_,
150 this,
151 scan_utils_);
152 // Need to set the interface up (especially in scan mode since wpa_supplicant
153 // is not started)
154 if_tool_->SetUpState(interface_name_.c_str(), true);
155 }
156
~ClientInterfaceImpl()157 ClientInterfaceImpl::~ClientInterfaceImpl() {
158 binder_->NotifyImplDead();
159 scanner_->Invalidate();
160 netlink_utils_->UnsubscribeFrameTxStatusEvent(interface_index_);
161 netlink_utils_->UnsubscribeMlmeEvent(interface_index_);
162 netlink_utils_->UnsubscribeChannelSwitchEvent(interface_index_);
163 if_tool_->SetUpState(interface_name_.c_str(), false);
164 }
165
GetBinder() const166 sp<android::net::wifi::nl80211::IClientInterface> ClientInterfaceImpl::GetBinder() const {
167 return binder_;
168 }
169
Dump(std::stringstream * ss) const170 void ClientInterfaceImpl::Dump(std::stringstream* ss) const {
171 *ss << "------- Dump of client interface with index: "
172 << interface_index_ << " and name: " << interface_name_
173 << "-------" << endl;
174 *ss << "Max number of ssids for single shot scan: "
175 << static_cast<int>(scan_capabilities_.max_num_scan_ssids) << endl;
176 *ss << "Max number of ssids for scheduled scan: "
177 << static_cast<int>(scan_capabilities_.max_num_sched_scan_ssids) << endl;
178 *ss << "Max number of match sets for scheduled scan: "
179 << static_cast<int>(scan_capabilities_.max_match_sets) << endl;
180 *ss << "Maximum number of scan plans: "
181 << scan_capabilities_.max_num_scan_plans << endl;
182 *ss << "Max scan plan interval in seconds: "
183 << scan_capabilities_.max_scan_plan_interval << endl;
184 *ss << "Max scan plan iterations: "
185 << scan_capabilities_.max_scan_plan_iterations << endl;
186 *ss << "Device supports random MAC for single shot scan: "
187 << wiphy_features_.supports_random_mac_oneshot_scan << endl;
188 *ss << "Device supports low span single shot scan: "
189 << wiphy_features_.supports_low_span_oneshot_scan << endl;
190 *ss << "Device supports low power single shot scan: "
191 << wiphy_features_.supports_low_power_oneshot_scan << endl;
192 *ss << "Device supports high accuracy single shot scan: "
193 << wiphy_features_.supports_high_accuracy_oneshot_scan << endl;
194 *ss << "Device supports random MAC for scheduled scan: "
195 << wiphy_features_.supports_random_mac_sched_scan << endl;
196 *ss << "Device supports sending management frames at specified MCS rate: "
197 << wiphy_features_.supports_tx_mgmt_frame_mcs << endl;
198 *ss << "------- Dump End -------" << endl;
199 }
200
GetPacketCounters(vector<int32_t> * out_packet_counters)201 bool ClientInterfaceImpl::GetPacketCounters(vector<int32_t>* out_packet_counters) {
202 StationInfo station_info;
203 if (!netlink_utils_->GetStationInfo(interface_index_,
204 bssid_,
205 &station_info)) {
206 return false;
207 }
208 out_packet_counters->push_back(station_info.station_tx_packets);
209 out_packet_counters->push_back(station_info.station_tx_failed);
210
211 return true;
212 }
213
SignalPoll(vector<int32_t> * out_signal_poll_results)214 bool ClientInterfaceImpl::SignalPoll(vector<int32_t>* out_signal_poll_results) {
215 if (!IsAssociated()) {
216 LOG(INFO) << "Fail RSSI polling because wifi is not associated.";
217 return false;
218 }
219
220 StationInfo station_info;
221 if (!netlink_utils_->GetStationInfo(interface_index_,
222 bssid_,
223 &station_info)) {
224 return false;
225 }
226 out_signal_poll_results->push_back(
227 static_cast<int32_t>(station_info.current_rssi));
228 // Convert from 100kbit/s to Mbps.
229 out_signal_poll_results->push_back(
230 static_cast<int32_t>(station_info.station_tx_bitrate/10));
231 // Association frequency.
232 out_signal_poll_results->push_back(
233 static_cast<int32_t>(associate_freq_));
234 // Convert from 100kbit/s to Mbps.
235 out_signal_poll_results->push_back(
236 static_cast<int32_t>(station_info.station_rx_bitrate/10));
237
238 return true;
239 }
240
GetMacAddress()241 const std::array<uint8_t, ETH_ALEN>& ClientInterfaceImpl::GetMacAddress() {
242 return interface_mac_addr_;
243 }
244
UpdateBandInfo()245 void ClientInterfaceImpl::UpdateBandInfo() {
246 LOG(INFO) << "UpdateBandInfo";
247 if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
248 &band_info_,
249 &scan_capabilities_,
250 &wiphy_features_)) {
251 LOG(ERROR) << "Failed to get wiphy info from kernel";
252 }
253 }
254
GetBandInfo() const255 const BandInfo& ClientInterfaceImpl::GetBandInfo() const {
256 return band_info_;
257 }
258
RefreshAssociateFreq()259 bool ClientInterfaceImpl::RefreshAssociateFreq() {
260 // wpa_supplicant fetches associate frequency using the latest scan result.
261 // We should follow the same method here before we find a better solution.
262 std::vector<NativeScanResult> scan_results;
263 if (!scan_utils_->GetScanResult(interface_index_, &scan_results)) {
264 return false;
265 }
266 for (auto& scan_result : scan_results) {
267 if (scan_result.associated) {
268 associate_freq_ = scan_result.frequency;
269 }
270 }
271 return false;
272 }
273
OnChannelSwitchEvent(uint32_t frequency)274 bool ClientInterfaceImpl::OnChannelSwitchEvent(uint32_t frequency) {
275 if(!frequency) {
276 LOG(ERROR) << "Frequency value is null";
277 return false;
278 }
279 LOG(INFO) << "New channel on frequency: " << frequency;
280 associate_freq_ = frequency;
281 return true;
282 }
283
IsAssociated() const284 bool ClientInterfaceImpl::IsAssociated() const {
285 return is_associated_;
286 }
287
SendMgmtFrame(const vector<uint8_t> & frame,const sp<ISendMgmtFrameEvent> & callback,int32_t mcs)288 void ClientInterfaceImpl::SendMgmtFrame(const vector<uint8_t>& frame,
289 const sp<ISendMgmtFrameEvent>& callback, int32_t mcs) {
290 if (mcs >= 0 && !wiphy_features_.supports_tx_mgmt_frame_mcs) {
291 callback->OnFailure(
292 ISendMgmtFrameEvent::SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED);
293 return;
294 }
295
296 uint64_t cookie;
297 if (!netlink_utils_->SendMgmtFrame(interface_index_, frame, mcs, &cookie)) {
298 callback->OnFailure(ISendMgmtFrameEvent::SEND_MGMT_FRAME_ERROR_UNKNOWN);
299 return;
300 }
301
302 frame_tx_in_progress_ = true;
303 frame_tx_status_cookie_ = cookie;
304 nsecs_t start_time_ns = systemTime(SYSTEM_TIME_MONOTONIC);
305 on_frame_tx_status_event_handler_ =
306 [callback, start_time_ns](bool was_acked) {
307 if (was_acked) {
308 nsecs_t end_time_ns = systemTime(SYSTEM_TIME_MONOTONIC);
309 int32_t elapsed_time_ms = static_cast<int32_t>(
310 nanoseconds_to_milliseconds(end_time_ns - start_time_ns));
311 callback->OnAck(elapsed_time_ms);
312 } else {
313 callback->OnFailure(
314 ISendMgmtFrameEvent::SEND_MGMT_FRAME_ERROR_NO_ACK);
315 }
316 };
317 }
318
319 } // namespace wificond
320 } // namespace android
321