blob: cb4d9d45cda9dedd013080e9436956172264fc0f [file] [log] [blame]
Roshan Piusaabe5752016-09-29 09:03:59 -07001/*
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 <array>
18
Roshan Piusaabe5752016-09-29 09:03:59 -070019#include <android-base/logging.h>
20#include <cutils/properties.h>
Roshan Pius908a69a2016-10-03 13:33:23 -070021#include <wifi_system/interface_tool.h>
Roshan Piusaabe5752016-09-29 09:03:59 -070022
Roshan Pius955542e2016-10-28 09:42:44 -070023#include "wifi_legacy_hal.h"
24
25namespace android {
26namespace hardware {
27namespace wifi {
28namespace V1_0 {
29namespace implementation {
30namespace legacy_hal {
Roshan Pius76ff3022016-10-28 10:33:34 -070031// Constants ported over from the legacy HAL calling code
32// (com_android_server_wifi_WifiNative.cpp). This will all be thrown
33// away when this shim layer is replaced by the real vendor
34// implementation.
Roshan Pius511cc492016-10-28 09:54:26 -070035static constexpr uint32_t kMaxVersionStringLength = 256;
Roshan Pius76ff3022016-10-28 10:33:34 -070036static constexpr uint32_t kMaxCachedGscanResults = 64;
37static constexpr uint32_t kMaxGscanFrequenciesForBand = 64;
Roshan Pius511cc492016-10-28 09:54:26 -070038
Roshan Piusaabe5752016-09-29 09:03:59 -070039// Legacy HAL functions accept "C" style function pointers, so use global
40// functions to pass to the legacy HAL function and store the corresponding
41// std::function methods to be invoked.
42// Callback to be invoked once |stop| is complete.
43std::function<void(wifi_handle handle)> on_stop_complete_internal_callback;
44void onStopComplete(wifi_handle handle) {
45 if (on_stop_complete_internal_callback) {
46 on_stop_complete_internal_callback(handle);
47 }
48}
Roshan Piuscdb77f32016-10-03 14:09:57 -070049
50// Callback to be invoked for driver dump.
51std::function<void(char*, int)> on_driver_memory_dump_internal_callback;
52void onDriverMemoryDump(char* buffer, int buffer_size) {
53 if (on_driver_memory_dump_internal_callback) {
54 on_driver_memory_dump_internal_callback(buffer, buffer_size);
55 }
56}
57
58// Callback to be invoked for firmware dump.
59std::function<void(char*, int)> on_firmware_memory_dump_internal_callback;
60void onFirmwareMemoryDump(char* buffer, int buffer_size) {
61 if (on_firmware_memory_dump_internal_callback) {
62 on_firmware_memory_dump_internal_callback(buffer, buffer_size);
63 }
64}
Roshan Pius76ff3022016-10-28 10:33:34 -070065
66// Callback to be invoked for Gscan events.
67std::function<void(wifi_request_id, wifi_scan_event)>
68 on_gscan_event_internal_callback;
69void onGscanEvent(wifi_request_id id, wifi_scan_event event) {
70 if (on_gscan_event_internal_callback) {
71 on_gscan_event_internal_callback(id, event);
72 }
73}
74
75// Callback to be invoked for Gscan full results.
76std::function<void(wifi_request_id, wifi_scan_result*, uint32_t)>
77 on_gscan_full_result_internal_callback;
78void onGscanFullResult(wifi_request_id id,
79 wifi_scan_result* result,
80 uint32_t buckets_scanned) {
81 if (on_gscan_full_result_internal_callback) {
82 on_gscan_full_result_internal_callback(id, result, buckets_scanned);
83 }
84}
85
Roshan Pius955542e2016-10-28 09:42:44 -070086// End of the free-standing "C" style callbacks.
Roshan Piusaabe5752016-09-29 09:03:59 -070087
Roshan Piusaabe5752016-09-29 09:03:59 -070088WifiLegacyHal::WifiLegacyHal()
89 : global_handle_(nullptr),
90 wlan_interface_handle_(nullptr),
Roshan Pius908a69a2016-10-03 13:33:23 -070091 awaiting_event_loop_termination_(false) {}
Roshan Piusaabe5752016-09-29 09:03:59 -070092
93wifi_error WifiLegacyHal::start() {
94 // Ensure that we're starting in a good state.
95 CHECK(!global_handle_ && !wlan_interface_handle_ &&
96 !awaiting_event_loop_termination_);
97
Roshan Pius908a69a2016-10-03 13:33:23 -070098 android::wifi_system::InterfaceTool if_tool;
Roshan Pius955542e2016-10-28 09:42:44 -070099 // TODO: Add back the HAL Tool if we need to. All we need from the HAL tool
100 // for now is this function call which we can directly call.
101 wifi_error status = init_wifi_vendor_hal_func_table(&global_func_table_);
102 if (status != WIFI_SUCCESS) {
Roshan Pius908a69a2016-10-03 13:33:23 -0700103 LOG(ERROR) << "Failed to initialize legacy hal function table";
104 return WIFI_ERROR_UNKNOWN;
105 }
106 if (!if_tool.SetWifiUpState(true)) {
107 LOG(ERROR) << "Failed to set WiFi interface up";
108 return WIFI_ERROR_UNKNOWN;
109 }
110
Roshan Piusaabe5752016-09-29 09:03:59 -0700111 LOG(INFO) << "Starting legacy HAL";
Roshan Pius955542e2016-10-28 09:42:44 -0700112 status = global_func_table_.wifi_initialize(&global_handle_);
Roshan Piusaabe5752016-09-29 09:03:59 -0700113 if (status != WIFI_SUCCESS || !global_handle_) {
114 LOG(ERROR) << "Failed to retrieve global handle";
115 return status;
116 }
117 event_loop_thread_ = std::thread(&WifiLegacyHal::runEventLoop, this);
118 status = retrieveWlanInterfaceHandle();
119 if (status != WIFI_SUCCESS || !wlan_interface_handle_) {
120 LOG(ERROR) << "Failed to retrieve wlan interface handle";
121 return status;
122 }
123 LOG(VERBOSE) << "Legacy HAL start complete";
124 return WIFI_SUCCESS;
125}
126
127wifi_error WifiLegacyHal::stop(
128 const std::function<void()>& on_stop_complete_user_callback) {
129 LOG(INFO) << "Stopping legacy HAL";
130 on_stop_complete_internal_callback = [&](wifi_handle handle) {
131 CHECK_EQ(global_handle_, handle) << "Handle mismatch";
132 on_stop_complete_user_callback();
Roshan Pius511cc492016-10-28 09:54:26 -0700133 // Invalidate all the internal pointers now that the HAL is
134 // stopped.
135 invalidate();
Roshan Piusaabe5752016-09-29 09:03:59 -0700136 };
137 awaiting_event_loop_termination_ = true;
138 global_func_table_.wifi_cleanup(global_handle_, onStopComplete);
139 LOG(VERBOSE) << "Legacy HAL stop initiated";
140 return WIFI_SUCCESS;
141}
142
Roshan Piusab5c4712016-10-06 14:37:15 -0700143std::string WifiLegacyHal::getApIfaceName() {
144 // Fake name. This interface does not exist in legacy HAL
145 // API's.
146 return "ap0";
147}
148
149std::string WifiLegacyHal::getNanIfaceName() {
150 // Fake name. This interface does not exist in legacy HAL
151 // API's.
152 return "nan0";
153}
154
155std::string WifiLegacyHal::getP2pIfaceName() {
156 std::array<char, PROPERTY_VALUE_MAX> buffer;
157 property_get("wifi.direct.interface", buffer.data(), "p2p0");
158 return buffer.data();
159}
160
161std::string WifiLegacyHal::getStaIfaceName() {
162 std::array<char, PROPERTY_VALUE_MAX> buffer;
163 property_get("wifi.interface", buffer.data(), "wlan0");
164 return buffer.data();
165}
166
167std::pair<wifi_error, std::string> WifiLegacyHal::getDriverVersion() {
Roshan Pius4b26c832016-10-03 12:49:58 -0700168 std::array<char, kMaxVersionStringLength> buffer;
169 buffer.fill(0);
170 wifi_error status = global_func_table_.wifi_get_driver_version(
171 wlan_interface_handle_, buffer.data(), buffer.size());
Roshan Pius0a47c182016-10-28 10:23:00 -0700172 return {status, buffer.data()};
Roshan Pius4b26c832016-10-03 12:49:58 -0700173}
174
Roshan Piusab5c4712016-10-06 14:37:15 -0700175std::pair<wifi_error, std::string> WifiLegacyHal::getFirmwareVersion() {
Roshan Pius4b26c832016-10-03 12:49:58 -0700176 std::array<char, kMaxVersionStringLength> buffer;
177 buffer.fill(0);
178 wifi_error status = global_func_table_.wifi_get_firmware_version(
179 wlan_interface_handle_, buffer.data(), buffer.size());
Roshan Pius0a47c182016-10-28 10:23:00 -0700180 return {status, buffer.data()};
Roshan Pius4b26c832016-10-03 12:49:58 -0700181}
182
Roshan Pius3c868522016-10-27 12:43:49 -0700183std::pair<wifi_error, std::vector<uint8_t>>
Roshan Piusab5c4712016-10-06 14:37:15 -0700184WifiLegacyHal::requestDriverMemoryDump() {
Roshan Pius3c868522016-10-27 12:43:49 -0700185 std::vector<uint8_t> driver_dump;
Roshan Piuscdb77f32016-10-03 14:09:57 -0700186 on_driver_memory_dump_internal_callback = [&driver_dump](char* buffer,
187 int buffer_size) {
Roshan Pius3c868522016-10-27 12:43:49 -0700188 driver_dump.insert(driver_dump.end(),
189 reinterpret_cast<uint8_t*>(buffer),
190 reinterpret_cast<uint8_t*>(buffer) + buffer_size);
Roshan Piuscdb77f32016-10-03 14:09:57 -0700191 };
192 wifi_error status = global_func_table_.wifi_get_driver_memory_dump(
193 wlan_interface_handle_, {onDriverMemoryDump});
194 on_driver_memory_dump_internal_callback = nullptr;
Roshan Pius0a47c182016-10-28 10:23:00 -0700195 return {status, std::move(driver_dump)};
Roshan Piuscdb77f32016-10-03 14:09:57 -0700196}
197
Roshan Pius3c868522016-10-27 12:43:49 -0700198std::pair<wifi_error, std::vector<uint8_t>>
Roshan Piusab5c4712016-10-06 14:37:15 -0700199WifiLegacyHal::requestFirmwareMemoryDump() {
Roshan Pius3c868522016-10-27 12:43:49 -0700200 std::vector<uint8_t> firmware_dump;
Roshan Piuscdb77f32016-10-03 14:09:57 -0700201 on_firmware_memory_dump_internal_callback = [&firmware_dump](
202 char* buffer, int buffer_size) {
Roshan Pius3c868522016-10-27 12:43:49 -0700203 firmware_dump.insert(firmware_dump.end(),
204 reinterpret_cast<uint8_t*>(buffer),
205 reinterpret_cast<uint8_t*>(buffer) + buffer_size);
Roshan Piuscdb77f32016-10-03 14:09:57 -0700206 };
207 wifi_error status = global_func_table_.wifi_get_firmware_memory_dump(
208 wlan_interface_handle_, {onFirmwareMemoryDump});
209 on_firmware_memory_dump_internal_callback = nullptr;
Roshan Pius0a47c182016-10-28 10:23:00 -0700210 return {status, std::move(firmware_dump)};
211}
212
213std::pair<wifi_error, uint32_t> WifiLegacyHal::getSupportedFeatureSet() {
214 feature_set set;
215 static_assert(sizeof(set) == sizeof(uint32_t),
216 "Some features can not be represented in output");
217 wifi_error status = global_func_table_.wifi_get_supported_feature_set(
218 wlan_interface_handle_, &set);
219 return {status, static_cast<uint32_t>(set)};
220}
221
222std::pair<wifi_error, PacketFilterCapabilities>
223WifiLegacyHal::getPacketFilterCapabilities() {
224 PacketFilterCapabilities caps;
225 wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
226 wlan_interface_handle_, &caps.version, &caps.max_len);
227 return {status, caps};
228}
229
230wifi_error WifiLegacyHal::setPacketFilter(const std::vector<uint8_t>& program) {
231 return global_func_table_.wifi_set_packet_filter(
232 wlan_interface_handle_, program.data(), program.size());
Roshan Piuscdb77f32016-10-03 14:09:57 -0700233}
234
Roshan Pius76ff3022016-10-28 10:33:34 -0700235std::pair<wifi_error, wifi_gscan_capabilities>
236WifiLegacyHal::getGscanCapabilities() {
237 wifi_gscan_capabilities caps;
238 wifi_error status = global_func_table_.wifi_get_gscan_capabilities(
239 wlan_interface_handle_, &caps);
240 return {status, caps};
241}
242
243wifi_error WifiLegacyHal::startGscan(
244 wifi_request_id id,
245 const wifi_scan_cmd_params& params,
246 const std::function<void(wifi_request_id)>& on_failure_user_callback,
247 const on_gscan_results_callback& on_results_user_callback,
248 const on_gscan_full_result_callback& on_full_result_user_callback) {
249 // If there is already an ongoing background scan, reject new scan requests.
250 if (on_gscan_event_internal_callback ||
251 on_gscan_full_result_internal_callback) {
252 return WIFI_ERROR_NOT_AVAILABLE;
253 }
254
255 // This callback will be used to either trigger |on_results_user_callback| or
256 // |on_failure_user_callback|.
257 on_gscan_event_internal_callback =
258 [on_failure_user_callback, on_results_user_callback, this](
259 wifi_request_id id, wifi_scan_event event) {
260 switch (event) {
261 case WIFI_SCAN_RESULTS_AVAILABLE:
262 case WIFI_SCAN_THRESHOLD_NUM_SCANS:
263 case WIFI_SCAN_THRESHOLD_PERCENT: {
264 wifi_error status;
265 std::vector<wifi_cached_scan_results> cached_scan_results;
266 std::tie(status, cached_scan_results) = getGscanCachedResults();
267 if (status == WIFI_SUCCESS) {
268 on_results_user_callback(id, cached_scan_results);
269 return;
270 }
271 }
272 // Fall through if failed. Failure to retrieve cached scan results
273 // should trigger a background scan failure.
274 case WIFI_SCAN_FAILED:
275 on_failure_user_callback(id);
276 on_gscan_event_internal_callback = nullptr;
277 on_gscan_full_result_internal_callback = nullptr;
278 return;
279 }
280 LOG(FATAL) << "Unexpected gscan event received: " << event;
281 };
282
283 on_gscan_full_result_internal_callback = [on_full_result_user_callback](
284 wifi_request_id id, wifi_scan_result* result, uint32_t buckets_scanned) {
285 if (result) {
286 on_full_result_user_callback(id, result, buckets_scanned);
287 }
288 };
289
290 wifi_scan_result_handler handler = {onGscanFullResult, onGscanEvent};
291 wifi_error status = global_func_table_.wifi_start_gscan(
292 id, wlan_interface_handle_, params, handler);
293 if (status != WIFI_SUCCESS) {
294 on_gscan_event_internal_callback = nullptr;
295 on_gscan_full_result_internal_callback = nullptr;
296 }
297 return status;
298}
299
300wifi_error WifiLegacyHal::stopGscan(wifi_request_id id) {
301 // If there is no an ongoing background scan, reject stop requests.
302 // TODO(b/32337212): This needs to be handled by the HIDL object because we
303 // need to return the NOT_STARTED error code.
304 if (!on_gscan_event_internal_callback &&
305 !on_gscan_full_result_internal_callback) {
306 return WIFI_ERROR_NOT_AVAILABLE;
307 }
308 wifi_error status =
309 global_func_table_.wifi_stop_gscan(id, wlan_interface_handle_);
310 // If the request Id is wrong, don't stop the ongoing background scan. Any
311 // other error should be treated as the end of background scan.
312 if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
313 on_gscan_event_internal_callback = nullptr;
314 on_gscan_full_result_internal_callback = nullptr;
315 }
316 return status;
317}
318
319std::pair<wifi_error, std::vector<uint32_t>>
320WifiLegacyHal::getValidFrequenciesForGscan(wifi_band band) {
321 static_assert(sizeof(uint32_t) >= sizeof(wifi_channel),
322 "Wifi Channel cannot be represented in output");
323 std::vector<uint32_t> freqs;
324 freqs.resize(kMaxGscanFrequenciesForBand);
325 int32_t num_freqs = 0;
326 wifi_error status = global_func_table_.wifi_get_valid_channels(
327 wlan_interface_handle_,
328 band,
329 freqs.size(),
330 reinterpret_cast<wifi_channel*>(freqs.data()),
331 &num_freqs);
332 CHECK(num_freqs >= 0 &&
333 static_cast<uint32_t>(num_freqs) <= kMaxGscanFrequenciesForBand);
334 freqs.resize(num_freqs);
335 return {status, std::move(freqs)};
336}
337
Roshan Piusaabe5752016-09-29 09:03:59 -0700338wifi_error WifiLegacyHal::retrieveWlanInterfaceHandle() {
Roshan Piusab5c4712016-10-06 14:37:15 -0700339 const std::string& ifname_to_find = getStaIfaceName();
Roshan Piusaabe5752016-09-29 09:03:59 -0700340 wifi_interface_handle* iface_handles = nullptr;
341 int num_iface_handles = 0;
342 wifi_error status = global_func_table_.wifi_get_ifaces(
343 global_handle_, &num_iface_handles, &iface_handles);
344 if (status != WIFI_SUCCESS) {
Roshan Pius511cc492016-10-28 09:54:26 -0700345 LOG(ERROR) << "Failed to enumerate interface handles";
Roshan Piusaabe5752016-09-29 09:03:59 -0700346 return status;
347 }
348 for (int i = 0; i < num_iface_handles; ++i) {
349 std::array<char, IFNAMSIZ> current_ifname;
350 current_ifname.fill(0);
351 status = global_func_table_.wifi_get_iface_name(
352 iface_handles[i], current_ifname.data(), current_ifname.size());
353 if (status != WIFI_SUCCESS) {
Roshan Pius511cc492016-10-28 09:54:26 -0700354 LOG(WARNING) << "Failed to get interface handle name";
Roshan Piusaabe5752016-09-29 09:03:59 -0700355 continue;
356 }
357 if (ifname_to_find == current_ifname.data()) {
358 wlan_interface_handle_ = iface_handles[i];
359 return WIFI_SUCCESS;
360 }
361 }
362 return WIFI_ERROR_UNKNOWN;
363}
364
365void WifiLegacyHal::runEventLoop() {
366 LOG(VERBOSE) << "Starting legacy HAL event loop";
367 global_func_table_.wifi_event_loop(global_handle_);
368 if (!awaiting_event_loop_termination_) {
369 LOG(FATAL) << "Legacy HAL event loop terminated, but HAL was not stopping";
370 }
371 LOG(VERBOSE) << "Legacy HAL event loop terminated";
372 awaiting_event_loop_termination_ = false;
Roshan Pius908a69a2016-10-03 13:33:23 -0700373 android::wifi_system::InterfaceTool if_tool;
374 if_tool.SetWifiUpState(false);
Roshan Piusaabe5752016-09-29 09:03:59 -0700375}
376
Roshan Pius76ff3022016-10-28 10:33:34 -0700377std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
378WifiLegacyHal::getGscanCachedResults() {
379 std::vector<wifi_cached_scan_results> cached_scan_results;
380 cached_scan_results.resize(kMaxCachedGscanResults);
381 int32_t num_results = 0;
382 wifi_error status = global_func_table_.wifi_get_cached_gscan_results(
383 wlan_interface_handle_,
384 true /* always flush */,
385 cached_scan_results.size(),
386 cached_scan_results.data(),
387 &num_results);
388 CHECK(num_results >= 0 &&
389 static_cast<uint32_t>(num_results) <= kMaxCachedGscanResults);
390 cached_scan_results.resize(num_results);
391 // Check for invalid IE lengths in these cached scan results and correct it.
392 for (auto& cached_scan_result : cached_scan_results) {
393 int num_scan_results = cached_scan_result.num_results;
394 for (int i = 0; i < num_scan_results; i++) {
395 auto& scan_result = cached_scan_result.results[i];
396 if (scan_result.ie_length > 0) {
397 LOG(ERROR) << "Cached scan result has non-zero IE length "
398 << scan_result.ie_length;
399 scan_result.ie_length = 0;
400 }
401 }
402 }
403 return {status, std::move(cached_scan_results)};
404}
405
Roshan Pius511cc492016-10-28 09:54:26 -0700406void WifiLegacyHal::invalidate() {
407 global_handle_ = nullptr;
408 wlan_interface_handle_ = nullptr;
409 on_stop_complete_internal_callback = nullptr;
410 on_driver_memory_dump_internal_callback = nullptr;
411 on_firmware_memory_dump_internal_callback = nullptr;
Roshan Pius76ff3022016-10-28 10:33:34 -0700412 on_gscan_event_internal_callback = nullptr;
413 on_gscan_full_result_internal_callback = nullptr;
Roshan Pius511cc492016-10-28 09:54:26 -0700414}
Roshan Pius955542e2016-10-28 09:42:44 -0700415
416} // namespace legacy_hal
Roshan Piusaabe5752016-09-29 09:03:59 -0700417} // namespace implementation
418} // namespace V1_0
419} // namespace wifi
420} // namespace hardware
421} // namespace android