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,
__anonfc78103b0202(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
GetBandInfo() const245 const BandInfo& ClientInterfaceImpl::GetBandInfo() const {
246 return band_info_;
247 }
248
RefreshAssociateFreq()249 bool ClientInterfaceImpl::RefreshAssociateFreq() {
250 // wpa_supplicant fetches associate frequency using the latest scan result.
251 // We should follow the same method here before we find a better solution.
252 std::vector<NativeScanResult> scan_results;
253 if (!scan_utils_->GetScanResult(interface_index_, &scan_results)) {
254 return false;
255 }
256 for (auto& scan_result : scan_results) {
257 if (scan_result.associated) {
258 associate_freq_ = scan_result.frequency;
259 }
260 }
261 return false;
262 }
263
OnChannelSwitchEvent(uint32_t frequency)264 bool ClientInterfaceImpl::OnChannelSwitchEvent(uint32_t frequency) {
265 if(!frequency) {
266 LOG(ERROR) << "Frequency value is null";
267 return false;
268 }
269 LOG(INFO) << "New channel on frequency: " << frequency;
270 associate_freq_ = frequency;
271 return true;
272 }
273
IsAssociated() const274 bool ClientInterfaceImpl::IsAssociated() const {
275 return is_associated_;
276 }
277
SendMgmtFrame(const vector<uint8_t> & frame,const sp<ISendMgmtFrameEvent> & callback,int32_t mcs)278 void ClientInterfaceImpl::SendMgmtFrame(const vector<uint8_t>& frame,
279 const sp<ISendMgmtFrameEvent>& callback, int32_t mcs) {
280 if (mcs >= 0 && !wiphy_features_.supports_tx_mgmt_frame_mcs) {
281 callback->OnFailure(
282 ISendMgmtFrameEvent::SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED);
283 return;
284 }
285
286 uint64_t cookie;
287 if (!netlink_utils_->SendMgmtFrame(interface_index_, frame, mcs, &cookie)) {
288 callback->OnFailure(ISendMgmtFrameEvent::SEND_MGMT_FRAME_ERROR_UNKNOWN);
289 return;
290 }
291
292 frame_tx_in_progress_ = true;
293 frame_tx_status_cookie_ = cookie;
294 nsecs_t start_time_ns = systemTime(SYSTEM_TIME_MONOTONIC);
295 on_frame_tx_status_event_handler_ =
296 [callback, start_time_ns](bool was_acked) {
297 if (was_acked) {
298 nsecs_t end_time_ns = systemTime(SYSTEM_TIME_MONOTONIC);
299 int32_t elapsed_time_ms = static_cast<int32_t>(
300 nanoseconds_to_milliseconds(end_time_ns - start_time_ns));
301 callback->OnAck(elapsed_time_ms);
302 } else {
303 callback->OnFailure(
304 ISendMgmtFrameEvent::SEND_MGMT_FRAME_ERROR_NO_ACK);
305 }
306 };
307 }
308
309 } // namespace wificond
310 } // namespace android
311