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::IClientInterface;
33 using android::net::wifi::ISendMgmtFrameEvent;
34 using com::android::server::wifi::wificond::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 namespace android {
44 namespace wificond {
45 
MlmeEventHandlerImpl(ClientInterfaceImpl * client_interface)46 MlmeEventHandlerImpl::MlmeEventHandlerImpl(ClientInterfaceImpl* client_interface)
47     : client_interface_(client_interface) {
48 }
49 
~MlmeEventHandlerImpl()50 MlmeEventHandlerImpl::~MlmeEventHandlerImpl() {
51 }
52 
OnConnect(unique_ptr<MlmeConnectEvent> event)53 void MlmeEventHandlerImpl::OnConnect(unique_ptr<MlmeConnectEvent> event) {
54   if (!event->IsTimeout() && event->GetStatusCode() == 0) {
55     client_interface_->is_associated_ = true;
56     client_interface_->RefreshAssociateFreq();
57     client_interface_->bssid_ = event->GetBSSID();
58   } else {
59     if (event->IsTimeout()) {
60       LOG(INFO) << "Connect timeout";
61     }
62     client_interface_->is_associated_ = false;
63     client_interface_->bssid_.fill(0);
64   }
65 }
66 
OnRoam(unique_ptr<MlmeRoamEvent> event)67 void MlmeEventHandlerImpl::OnRoam(unique_ptr<MlmeRoamEvent> event) {
68   client_interface_->is_associated_ = true;
69   client_interface_->RefreshAssociateFreq();
70   client_interface_->bssid_ = event->GetBSSID();
71 }
72 
OnAssociate(unique_ptr<MlmeAssociateEvent> event)73 void MlmeEventHandlerImpl::OnAssociate(unique_ptr<MlmeAssociateEvent> event) {
74   if (!event->IsTimeout() && event->GetStatusCode() == 0) {
75     client_interface_->is_associated_ = true;
76     client_interface_->RefreshAssociateFreq();
77     client_interface_->bssid_ = event->GetBSSID();
78   } else {
79     if (event->IsTimeout()) {
80       LOG(INFO) << "Associate timeout";
81     }
82     client_interface_->is_associated_ = false;
83     client_interface_->bssid_.fill(0);
84   }
85 }
86 
OnDisconnect(unique_ptr<MlmeDisconnectEvent> event)87 void MlmeEventHandlerImpl::OnDisconnect(unique_ptr<MlmeDisconnectEvent> event) {
88   client_interface_->is_associated_ = false;
89   client_interface_->bssid_.fill(0);
90 }
91 
OnDisassociate(unique_ptr<MlmeDisassociateEvent> event)92 void MlmeEventHandlerImpl::OnDisassociate(unique_ptr<MlmeDisassociateEvent> event) {
93   client_interface_->is_associated_ = false;
94   client_interface_->bssid_.fill(0);
95 }
96 
97 
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)98 ClientInterfaceImpl::ClientInterfaceImpl(
99     uint32_t wiphy_index,
100     const std::string& interface_name,
101     uint32_t interface_index,
102     const std::array<uint8_t, ETH_ALEN>& interface_mac_addr,
103     InterfaceTool* if_tool,
104     NetlinkUtils* netlink_utils,
105     ScanUtils* scan_utils)
106     : wiphy_index_(wiphy_index),
107       interface_name_(interface_name),
108       interface_index_(interface_index),
109       interface_mac_addr_(interface_mac_addr),
110       if_tool_(if_tool),
111       netlink_utils_(netlink_utils),
112       scan_utils_(scan_utils),
113       mlme_event_handler_(new MlmeEventHandlerImpl(this)),
114       binder_(new ClientInterfaceBinder(this)),
115       is_associated_(false),
116       frame_tx_in_progress_(false),
117       frame_tx_status_cookie_(0),
118       on_frame_tx_status_event_handler_([](bool was_acked) {}) {
119   netlink_utils_->SubscribeMlmeEvent(
120       interface_index_,
121       mlme_event_handler_.get());
122 
123   netlink_utils_->SubscribeFrameTxStatusEvent(
124       interface_index,
__anonb3c3c0140202(uint64_t cookie, bool was_acked) 125       [this](uint64_t cookie, bool was_acked) {
126         if (frame_tx_in_progress_ && frame_tx_status_cookie_ == cookie) {
127           on_frame_tx_status_event_handler_(was_acked);
128           frame_tx_in_progress_ = false;
129           frame_tx_status_cookie_ = 0;
130           on_frame_tx_status_event_handler_ = [](bool was_acked) {};
131         }
132       });
133 
134   if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
135                                &band_info_,
136                                &scan_capabilities_,
137                                &wiphy_features_)) {
138     LOG(ERROR) << "Failed to get wiphy info from kernel";
139   }
140   LOG(INFO) << "create scanner for interface with index: "
141             << (int)interface_index_;
142   scanner_ = new ScannerImpl(interface_index_,
143                              scan_capabilities_,
144                              wiphy_features_,
145                              this,
146                              scan_utils_);
147   // Need to set the interface up (especially in scan mode since wpa_supplicant
148   // is not started)
149   if_tool_->SetUpState(interface_name_.c_str(), true);
150 }
151 
~ClientInterfaceImpl()152 ClientInterfaceImpl::~ClientInterfaceImpl() {
153   binder_->NotifyImplDead();
154   scanner_->Invalidate();
155   netlink_utils_->UnsubscribeFrameTxStatusEvent(interface_index_);
156   netlink_utils_->UnsubscribeMlmeEvent(interface_index_);
157   if_tool_->SetUpState(interface_name_.c_str(), false);
158 }
159 
GetBinder() const160 sp<android::net::wifi::IClientInterface> ClientInterfaceImpl::GetBinder() const {
161   return binder_;
162 }
163 
Dump(std::stringstream * ss) const164 void ClientInterfaceImpl::Dump(std::stringstream* ss) const {
165   *ss << "------- Dump of client interface with index: "
166       << interface_index_ << " and name: " << interface_name_
167       << "-------" << endl;
168   *ss << "Max number of ssids for single shot scan: "
169       << static_cast<int>(scan_capabilities_.max_num_scan_ssids) << endl;
170   *ss << "Max number of ssids for scheduled scan: "
171       << static_cast<int>(scan_capabilities_.max_num_sched_scan_ssids) << endl;
172   *ss << "Max number of match sets for scheduled scan: "
173       << static_cast<int>(scan_capabilities_.max_match_sets) << endl;
174   *ss << "Maximum number of scan plans: "
175       << scan_capabilities_.max_num_scan_plans << endl;
176   *ss << "Max scan plan interval in seconds: "
177       << scan_capabilities_.max_scan_plan_interval << endl;
178   *ss << "Max scan plan iterations: "
179       << scan_capabilities_.max_scan_plan_iterations << endl;
180   *ss << "Device supports random MAC for single shot scan: "
181       << wiphy_features_.supports_random_mac_oneshot_scan << endl;
182   *ss << "Device supports low span single shot scan: "
183       << wiphy_features_.supports_low_span_oneshot_scan << endl;
184   *ss << "Device supports low power single shot scan: "
185       << wiphy_features_.supports_low_power_oneshot_scan << endl;
186   *ss << "Device supports high accuracy single shot scan: "
187       << wiphy_features_.supports_high_accuracy_oneshot_scan << endl;
188   *ss << "Device supports random MAC for scheduled scan: "
189       << wiphy_features_.supports_random_mac_sched_scan << endl;
190   *ss << "Device supports sending management frames at specified MCS rate: "
191       << wiphy_features_.supports_tx_mgmt_frame_mcs << endl;
192   *ss << "------- Dump End -------" << endl;
193 }
194 
GetPacketCounters(vector<int32_t> * out_packet_counters)195 bool ClientInterfaceImpl::GetPacketCounters(vector<int32_t>* out_packet_counters) {
196   StationInfo station_info;
197   if (!netlink_utils_->GetStationInfo(interface_index_,
198                                       bssid_,
199                                       &station_info)) {
200     return false;
201   }
202   out_packet_counters->push_back(station_info.station_tx_packets);
203   out_packet_counters->push_back(station_info.station_tx_failed);
204 
205   return true;
206 }
207 
SignalPoll(vector<int32_t> * out_signal_poll_results)208 bool ClientInterfaceImpl::SignalPoll(vector<int32_t>* out_signal_poll_results) {
209   if (!IsAssociated()) {
210     LOG(INFO) << "Fail RSSI polling because wifi is not associated.";
211     return false;
212   }
213 
214   StationInfo station_info;
215   if (!netlink_utils_->GetStationInfo(interface_index_,
216                                       bssid_,
217                                       &station_info)) {
218     return false;
219   }
220   out_signal_poll_results->push_back(
221       static_cast<int32_t>(station_info.current_rssi));
222   // Convert from 100kbit/s to Mbps.
223   out_signal_poll_results->push_back(
224       static_cast<int32_t>(station_info.station_tx_bitrate/10));
225   // Association frequency.
226   out_signal_poll_results->push_back(
227       static_cast<int32_t>(associate_freq_));
228   // Convert from 100kbit/s to Mbps.
229   out_signal_poll_results->push_back(
230       static_cast<int32_t>(station_info.station_rx_bitrate/10));
231 
232   return true;
233 }
234 
GetMacAddress()235 const std::array<uint8_t, ETH_ALEN>& ClientInterfaceImpl::GetMacAddress() {
236   return interface_mac_addr_;
237 }
238 
SetMacAddress(const std::array<uint8_t,ETH_ALEN> & mac)239 bool ClientInterfaceImpl::SetMacAddress(const std::array<uint8_t, ETH_ALEN>& mac) {
240   if (!if_tool_->SetWifiUpState(false)) {
241     LOG(ERROR) << "SetWifiUpState(false) failed.";
242     return false;
243   }
244   if (!if_tool_->SetMacAddress(interface_name_.c_str(), mac)) {
245     LOG(ERROR) << "SetMacAddress(" << interface_name_ << ", "
246                << LoggingUtils::GetMacString(mac) << ") failed.";
247     return false;
248   }
249   if (!if_tool_->SetWifiUpState(true)) {
250     LOG(ERROR) << "SetWifiUpState(true) failed.";
251     return false;
252   }
253   LOG(DEBUG) << "Successfully SetMacAddress.";
254   return true;
255 }
256 
RefreshAssociateFreq()257 bool ClientInterfaceImpl::RefreshAssociateFreq() {
258   // wpa_supplicant fetches associate frequency using the latest scan result.
259   // We should follow the same method here before we find a better solution.
260   std::vector<NativeScanResult> scan_results;
261   if (!scan_utils_->GetScanResult(interface_index_, &scan_results)) {
262     return false;
263   }
264   for (auto& scan_result : scan_results) {
265     if (scan_result.associated) {
266       associate_freq_ = scan_result.frequency;
267     }
268   }
269   return false;
270 }
271 
IsAssociated() const272 bool ClientInterfaceImpl::IsAssociated() const {
273   return is_associated_;
274 }
275 
SendMgmtFrame(const vector<uint8_t> & frame,const sp<ISendMgmtFrameEvent> & callback,int32_t mcs)276 void ClientInterfaceImpl::SendMgmtFrame(const vector<uint8_t>& frame,
277     const sp<ISendMgmtFrameEvent>& callback, int32_t mcs) {
278   if (mcs >= 0 && !wiphy_features_.supports_tx_mgmt_frame_mcs) {
279     callback->OnFailure(
280         ISendMgmtFrameEvent::SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED);
281     return;
282   }
283 
284   uint64_t cookie;
285   if (!netlink_utils_->SendMgmtFrame(interface_index_, frame, mcs, &cookie)) {
286     callback->OnFailure(ISendMgmtFrameEvent::SEND_MGMT_FRAME_ERROR_UNKNOWN);
287     return;
288   }
289 
290   frame_tx_in_progress_ = true;
291   frame_tx_status_cookie_ = cookie;
292   nsecs_t start_time_ns = systemTime(SYSTEM_TIME_MONOTONIC);
293   on_frame_tx_status_event_handler_ =
294       [callback, start_time_ns](bool was_acked) {
295         if (was_acked) {
296           nsecs_t end_time_ns = systemTime(SYSTEM_TIME_MONOTONIC);
297           int32_t elapsed_time_ms = static_cast<int32_t>(
298               nanoseconds_to_milliseconds(end_time_ns - start_time_ns));
299           callback->OnAck(elapsed_time_ms);
300         } else {
301           callback->OnFailure(
302               ISendMgmtFrameEvent::SEND_MGMT_FRAME_ERROR_NO_ACK);
303         }
304       };
305 }
306 
307 }  // namespace wificond
308 }  // namespace android
309