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