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