From: Aaron Kling Date: Sat, 3 Jul 2021 05:50:53 +0000 (-0500) Subject: Update to android 10 wifi hal X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=refs%2Fheads%2Flineage-18.1;p=GitHub%2FLineageOS%2FG12%2Fandroid_hardware_realtek.git Update to android 10 wifi hal --- diff --git a/wlan/Android.mk b/wlan/Android.mk new file mode 100644 index 0000000..644f883 --- /dev/null +++ b/wlan/Android.mk @@ -0,0 +1,3 @@ +ifeq ($(BOARD_WLAN_DEVICE), realtek) + include $(call all-subdir-makefiles) +endif diff --git a/wlan/wifi_hal/Android.mk b/wlan/wifi_hal/Android.mk index fc8267e..43683c8 100644 --- a/wlan/wifi_hal/Android.mk +++ b/wlan/wifi_hal/Android.mk @@ -26,22 +26,24 @@ LOCAL_CFLAGS := \ -Wno-unused-function \ -Wno-unused-parameter \ -Wno-unused-private-field \ - -Wno-unused-variable \ + -Wno-unused-variable +# -DCONFIG_WIFI_HAL_DEBUG LOCAL_C_INCLUDES += \ external/libnl/include \ $(call include-path-for, libhardware_legacy)/hardware_legacy \ external/wpa_supplicant_8/src/drivers +LOCAL_HEADER_LIBRARIES := libutils_headers liblog_headers LOCAL_SRC_FILES := \ - wifi_hal.cpp \ - rtt.cpp \ + rtw_wifi_hal.cpp \ + rtw_wifi_rtt.cpp \ common.cpp \ cpp_bindings.cpp \ - gscan.cpp \ - link_layer_stats.cpp \ - wifi_logger.cpp \ - wifi_offload.cpp + rtw_wifi_gscan.cpp \ + rtw_wifi_llstats.cpp \ + rtw_wifi_logger.cpp \ + rtw_wifi_offload.cpp LOCAL_MODULE := libwifi-hal-rtk LOCAL_PROPRIETARY_MODULE := true diff --git a/wlan/wifi_hal/common.h b/wlan/wifi_hal/common.h index a8d60b7..27101b7 100644 --- a/wlan/wifi_hal/common.h +++ b/wlan/wifi_hal/common.h @@ -21,7 +21,7 @@ #define LOG_TAG "WifiHAL" -#include +#include #include "nl80211_copy.h" #include "sync.h" diff --git a/wlan/wifi_hal/gscan.cpp b/wlan/wifi_hal/gscan.cpp deleted file mode 100644 index d33ac93..0000000 --- a/wlan/wifi_hal/gscan.cpp +++ /dev/null @@ -1,1856 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "sync.h" - -#define LOG_TAG "WifiHAL" -//#define LOG_NDEBUG 0 //uncomment to enable verbose logging - -#include - -#include "wifi_hal.h" -#include "common.h" -#include "cpp_bindings.h" - -typedef enum { - - GSCAN_ATTRIBUTE_NUM_BUCKETS = 10, - GSCAN_ATTRIBUTE_BASE_PERIOD, - GSCAN_ATTRIBUTE_BUCKETS_BAND, - GSCAN_ATTRIBUTE_BUCKET_ID, - GSCAN_ATTRIBUTE_BUCKET_PERIOD, - GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS, - GSCAN_ATTRIBUTE_BUCKET_CHANNELS, - GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, - GSCAN_ATTRIBUTE_REPORT_THRESHOLD, - GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, - GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND, - - GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20, - GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, /* indicates no more results */ - GSCAN_ATTRIBUTE_FLUSH_FEATURE, /* Flush all the configs */ - GSCAN_ENABLE_FULL_SCAN_RESULTS, - GSCAN_ATTRIBUTE_REPORT_EVENTS, - - /* remaining reserved for additional attributes */ - GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30, - GSCAN_ATTRIBUTE_FLUSH_RESULTS, - GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */ - GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */ - GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */ - GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */ - GSCAN_ATTRIBUTE_NUM_CHANNELS, - GSCAN_ATTRIBUTE_CHANNEL_LIST, - GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK, - /* remaining reserved for additional attributes */ - - GSCAN_ATTRIBUTE_SSID = 40, - GSCAN_ATTRIBUTE_BSSID, - GSCAN_ATTRIBUTE_CHANNEL, - GSCAN_ATTRIBUTE_RSSI, - GSCAN_ATTRIBUTE_TIMESTAMP, - GSCAN_ATTRIBUTE_RTT, - GSCAN_ATTRIBUTE_RTTSD, - - /* remaining reserved for additional attributes */ - - GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50, - GSCAN_ATTRIBUTE_RSSI_LOW, - GSCAN_ATTRIBUTE_RSSI_HIGH, - GSCAN_ATTRIBUTE_HOTLIST_ELEM, - GSCAN_ATTRIBUTE_HOTLIST_FLUSH, - GSCAN_ATTRIBUTE_HOTLIST_BSSID_COUNT, - - /* remaining reserved for additional attributes */ - GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60, - GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, - GSCAN_ATTRIBUTE_MIN_BREACHING, - GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS, - GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, - - /* EPNO */ - GSCAN_ATTRIBUTE_EPNO_SSID_LIST = 70, - GSCAN_ATTRIBUTE_EPNO_SSID, - GSCAN_ATTRIBUTE_EPNO_SSID_LEN, - GSCAN_ATTRIBUTE_EPNO_RSSI, - GSCAN_ATTRIBUTE_EPNO_FLAGS, - GSCAN_ATTRIBUTE_EPNO_AUTH, - GSCAN_ATTRIBUTE_EPNO_SSID_NUM, - GSCAN_ATTRIBUTE_EPNO_FLUSH, - - /* remaining reserved for additional attributes */ - - GSCAN_ATTRIBUTE_WHITELIST_SSID = 80, - GSCAN_ATTRIBUTE_NUM_WL_SSID, - GSCAN_ATTRIBUTE_WL_SSID_LEN, - GSCAN_ATTRIBUTE_WL_SSID_FLUSH, - GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM, - GSCAN_ATTRIBUTE_NUM_BSSID, - GSCAN_ATTRIBUTE_BSSID_PREF_LIST, - GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH, - GSCAN_ATTRIBUTE_BSSID_PREF, - GSCAN_ATTRIBUTE_RSSI_MODIFIER, - - /* remaining reserved for additional attributes */ - - GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD = 90, - GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD, - GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR, - GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR, - GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST, - GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS, - GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER, - GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE, - - /* BSSID blacklist */ - GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH = 100, - GSCAN_ATTRIBUTE_BLACKLIST_BSSID, - - /* ANQPO */ - GSCAN_ATTRIBUTE_ANQPO_HS_LIST = 110, - GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE, - GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID, - GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM, - GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID, - GSCAN_ATTRIBUTE_ANQPO_HS_PLMN, - - /* Adaptive scan attributes */ - GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT = 120, - GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD, - - /* ePNO cfg */ - GSCAN_ATTRIBUTE_EPNO_5G_RSSI_THR = 130, - GSCAN_ATTRIBUTE_EPNO_2G_RSSI_THR, - GSCAN_ATTRIBUTE_EPNO_INIT_SCORE_MAX, - GSCAN_ATTRIBUTE_EPNO_CUR_CONN_BONUS, - GSCAN_ATTRIBUTE_EPNO_SAME_NETWORK_BONUS, - GSCAN_ATTRIBUTE_EPNO_SECURE_BONUS, - GSCAN_ATTRIBUTE_EPNO_5G_BONUS, - - GSCAN_ATTRIBUTE_MAX - -} GSCAN_ATTRIBUTE; - - -// helper methods -wifi_error wifi_enable_full_scan_results(wifi_request_id id, wifi_interface_handle iface, - wifi_scan_result_handler handler); -wifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface); -int wifi_handle_full_scan_event(wifi_request_id id, WifiEvent& event, - wifi_scan_result_handler handler); -void convert_to_hal_result(wifi_scan_result *to, wifi_gscan_result_t *from); - - -void convert_to_hal_result(wifi_scan_result *to, wifi_gscan_result_t *from) -{ - to->ts = from->ts; - to->channel = from->channel; - to->rssi = from->rssi; - to->rtt = from->rtt; - to->rtt_sd = from->rtt_sd; - to->beacon_period = from->beacon_period; - to->capability = from->capability; - memcpy(to->ssid, from->ssid, (DOT11_MAX_SSID_LEN+1)); - memcpy(&to->bssid, &from->bssid, sizeof(mac_addr)); -} - -///////////////////////////////////////////////////////////////////////////// - -class GetCapabilitiesCommand : public WifiCommand -{ - wifi_gscan_capabilities *mCapabilities; -public: - GetCapabilitiesCommand(wifi_interface_handle iface, wifi_gscan_capabilities *capabitlites) - : WifiCommand("GetGscanCapabilitiesCommand", iface, 0), mCapabilities(capabitlites) - { - memset(mCapabilities, 0, sizeof(*mCapabilities)); - } - - virtual int create() { - ALOGV("Creating message to get scan capablities; iface = %d", mIfaceInfo->id); - - int ret = mMsg.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_CAPABILITIES); - if (ret < 0) { - return ret; - } - - return ret; - } - -protected: - virtual int handleResponse(WifiEvent& reply) { - - ALOGV("In GetCapabilities::handleResponse"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - int id = reply.get_vendor_id(); - int subcmd = reply.get_vendor_subcmd(); - - void *data = reply.get_vendor_data(); - int len = reply.get_vendor_data_len(); - - ALOGV("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len, - sizeof(*mCapabilities)); - - memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities))); - - return NL_OK; - } -}; - - -wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle, - wifi_gscan_capabilities *capabilities) -{ - GetCapabilitiesCommand command(handle, capabilities); - return (wifi_error) command.requestResponse(); -} - -class GetChannelListCommand : public WifiCommand -{ - wifi_channel *channels; - int max_channels; - int *num_channels; - int band; -public: - GetChannelListCommand(wifi_interface_handle iface, wifi_channel *channel_buf, int *ch_num, - int num_max_ch, int band) - : WifiCommand("GetChannelListCommand", iface, 0), channels(channel_buf), - max_channels(num_max_ch), num_channels(ch_num), band(band) - { - memset(channels, 0, sizeof(wifi_channel) * max_channels); - } - virtual int create() { - ALOGV("Creating message to get channel list; iface = %d", mIfaceInfo->id); - - int ret = mMsg.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_CHANNEL_LIST); - if (ret < 0) { - return ret; - } - - nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA); - ret = mMsg.put_u32(GSCAN_ATTRIBUTE_BAND, band); - if (ret < 0) { - return ret; - } - - mMsg.attr_end(data); - - return ret; - } - -protected: - virtual int handleResponse(WifiEvent& reply) { - - ALOGV("In GetChannelList::handleResponse"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - int id = reply.get_vendor_id(); - int subcmd = reply.get_vendor_subcmd(); - int num_channels_to_copy = 0; - - nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = reply.get_vendor_data_len(); - - ALOGV("Id = %0x, subcmd = %d, len = %d", id, subcmd, len); - if (vendor_data == NULL || len == 0) { - ALOGE("no vendor data in GetChannelList response; ignoring it"); - return NL_SKIP; - } - - for (nl_iterator it(vendor_data); it.has_next(); it.next()) { - if (it.get_type() == GSCAN_ATTRIBUTE_NUM_CHANNELS) { - num_channels_to_copy = it.get_u32(); - ALOGI("Got channel list with %d channels", num_channels_to_copy); - if(num_channels_to_copy > max_channels) - num_channels_to_copy = max_channels; - *num_channels = num_channels_to_copy; - } else if (it.get_type() == GSCAN_ATTRIBUTE_CHANNEL_LIST && num_channels_to_copy) { - memcpy(channels, it.get_data(), sizeof(int) * num_channels_to_copy); - } else { - ALOGW("Ignoring invalid attribute type = %d, size = %d", - it.get_type(), it.get_len()); - } - } - - return NL_OK; - } -}; - -wifi_error wifi_get_valid_channels(wifi_interface_handle handle, - int band, int max_channels, wifi_channel *channels, int *num_channels) -{ -#if 0 - GetChannelListCommand command(handle, channels, num_channels, - max_channels, band); - return (wifi_error) command.requestResponse(); -#endif - *num_channels = 12; - return WIFI_SUCCESS; -} -///////////////////////////////////////////////////////////////////////////// - -/* helper functions */ - -static int parseScanResults(wifi_scan_result *results, int num, nlattr *attr) -{ - memset(results, 0, sizeof(wifi_scan_result) * num); - - int i = 0; - for (nl_iterator it(attr); it.has_next() && i < num; it.next(), i++) { - - int index = it.get_type(); - ALOGI("retrieved scan result %d", index); - nlattr *sc_data = (nlattr *) it.get_data(); - wifi_scan_result *result = results + i; - - for (nl_iterator it2(sc_data); it2.has_next(); it2.next()) { - int type = it2.get_type(); - if (type == GSCAN_ATTRIBUTE_SSID) { - strncpy(result->ssid, (char *) it2.get_data(), it2.get_len()); - result->ssid[it2.get_len()] = 0; - } else if (type == GSCAN_ATTRIBUTE_BSSID) { - memcpy(result->bssid, (byte *) it2.get_data(), sizeof(mac_addr)); - } else if (type == GSCAN_ATTRIBUTE_TIMESTAMP) { - result->ts = it2.get_u64(); - } else if (type == GSCAN_ATTRIBUTE_CHANNEL) { - result->ts = it2.get_u16(); - } else if (type == GSCAN_ATTRIBUTE_RSSI) { - result->rssi = it2.get_u8(); - } else if (type == GSCAN_ATTRIBUTE_RTT) { - result->rtt = it2.get_u64(); - } else if (type == GSCAN_ATTRIBUTE_RTTSD) { - result->rtt_sd = it2.get_u64(); - } - } - - } - - if (i >= num) { - ALOGE("Got too many results; skipping some"); - } - - return i; -} - -int createFeatureRequest(WifiRequest& request, int subcmd, int enable) { - - int result = request.create(GOOGLE_OUI, subcmd); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u32(GSCAN_ATTRIBUTE_ENABLE_FEATURE, enable); - if (result < 0) { - return result; - } - - request.attr_end(data); - return WIFI_SUCCESS; -} - -///////////////////////////////////////////////////////////////////////////// -class FullScanResultsCommand : public WifiCommand -{ - int *mParams; - wifi_scan_result_handler mHandler; -public: - FullScanResultsCommand(wifi_interface_handle iface, int id, int *params, - wifi_scan_result_handler handler) - : WifiCommand("FullScanResultsCommand", iface, id), mParams(params), mHandler(handler) - { } - - int createRequest(WifiRequest& request, int subcmd, int enable) { - int result = request.create(GOOGLE_OUI, subcmd); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u32(GSCAN_ENABLE_FULL_SCAN_RESULTS, enable); - if (result < 0) { - return result; - } - - request.attr_end(data); - return WIFI_SUCCESS; - - } - - int start() { - ALOGV("Enabling Full scan results"); - WifiRequest request(familyId(), ifaceId()); - int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 1); - if (result != WIFI_SUCCESS) { - ALOGE("failed to create request; result = %d", result); - return result; - } - - registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); - - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to enable full scan results; result = %d", result); - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); - return result; - } - - return result; - } - - virtual int cancel() { - ALOGV("Disabling Full scan results"); - - WifiRequest request(familyId(), ifaceId()); - int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 0); - if (result != WIFI_SUCCESS) { - ALOGE("failed to create request; result = %d", result); - } else { - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to disable full scan results;result = %d", result); - } - } - - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); - return WIFI_SUCCESS; - } - - virtual int handleResponse(WifiEvent& reply) { - ALOGD("Request complete!"); - /* Nothing to do on response! */ - return NL_SKIP; - } - - virtual int handleEvent(WifiEvent& event) { - ALOGV("Full scan results: Got an event"); - return wifi_handle_full_scan_event(id(), event, mHandler); - } - -}; -///////////////////////////////////////////////////////////////////////////// - -class ScanCommand : public WifiCommand -{ - wifi_scan_cmd_params *mParams; - wifi_scan_result_handler mHandler; -public: - ScanCommand(wifi_interface_handle iface, int id, wifi_scan_cmd_params *params, - wifi_scan_result_handler handler) - : WifiCommand("ScanCommand", iface, id), mParams(params), mHandler(handler) - { } - - int createSetupRequest(WifiRequest& request) { - int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_CONFIG); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u32(GSCAN_ATTRIBUTE_BASE_PERIOD, mParams->base_period); - if (result < 0) { - return result; - } - - result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BUCKETS, mParams->num_buckets); - if (result < 0) { - return result; - } - - for (int i = 0; i < mParams->num_buckets; i++) { - nlattr * bucket = request.attr_start(i); // next bucket - result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_ID, mParams->buckets[i].bucket); - if (result < 0) { - return result; - } - result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_PERIOD, mParams->buckets[i].period); - if (result < 0) { - return result; - } - result = request.put_u32(GSCAN_ATTRIBUTE_BUCKETS_BAND, - mParams->buckets[i].band); - if (result < 0) { - return result; - } - result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT, - mParams->buckets[i].step_count); - if (result < 0) { - return result; - } - result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD, - mParams->buckets[i].max_period); - if (result < 0) { - return result; - } - result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_EVENTS, - mParams->buckets[i].report_events); - if (result < 0) { - return result; - } - - result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS, - mParams->buckets[i].num_channels); - if (result < 0) { - return result; - } - - if (mParams->buckets[i].num_channels) { - nlattr *channels = request.attr_start(GSCAN_ATTRIBUTE_BUCKET_CHANNELS); - ALOGV(" channels: "); - for (int j = 0; j < mParams->buckets[i].num_channels; j++) { - result = request.put_u32(j, mParams->buckets[i].channels[j].channel); - ALOGV(" %u", mParams->buckets[i].channels[j].channel); - - if (result < 0) { - return result; - } - } - request.attr_end(channels); - } - - request.attr_end(bucket); - } - - request.attr_end(data); - return WIFI_SUCCESS; - } - - int createScanConfigRequest(WifiRequest& request) { - int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SCAN_CONFIG); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u32(GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, mParams->max_ap_per_scan); - if (result < 0) { - return result; - } - - result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD, - mParams->report_threshold_percent); - if (result < 0) { - return result; - } - - int num_scans = mParams->report_threshold_num_scans; - - result = request.put_u32(GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, num_scans); - if (result < 0) { - return result; - } - - request.attr_end(data); - return WIFI_SUCCESS; - } - - int createStartRequest(WifiRequest& request) { - return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); - } - - int createStopRequest(WifiRequest& request) { - return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 0); - } - - int start() { - ALOGV("GSCAN start"); - WifiRequest request(familyId(), ifaceId()); - int result = createSetupRequest(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to create setup request; result = %d", result); - return result; - } - - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to configure setup; result = %d", result); - return result; - } - - request.destroy(); - - result = createScanConfigRequest(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to create scan config request; result = %d", result); - return result; - } - - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to configure scan; result = %d", result); - return result; - } - - ALOGV(" ....starting scan"); - - result = createStartRequest(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to create start request; result = %d", result); - return result; - } - - registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); - registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN); - registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); - - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to start scan; result = %d", result); - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN); - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); - return result; - } - return result; - } - - virtual int cancel() { - ALOGV("Stopping scan"); - - WifiRequest request(familyId(), ifaceId()); - int result = createStopRequest(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to create stop request; result = %d", result); - } else { - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to stop scan; result = %d", result); - } - } - - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN); - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); - return WIFI_SUCCESS; - } - - virtual int handleResponse(WifiEvent& reply) { - /* Nothing to do on response! */ - return NL_SKIP; - } - - virtual int handleEvent(WifiEvent& event) { - ALOGV("Got a scan results event"); - //event.log(); - - nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = event.get_vendor_data_len(); - int event_id = event.get_vendor_subcmd(); - - if ((event_id == GSCAN_EVENT_COMPLETE_SCAN) || - (event_id == GSCAN_EVENT_SCAN_RESULTS_AVAILABLE)) { - if (vendor_data == NULL || len != 4) { - ALOGI("Bad event data!"); - return NL_SKIP; - } - wifi_scan_event evt_type; - evt_type = (wifi_scan_event) event.get_u32(NL80211_ATTR_VENDOR_DATA); - ALOGV("Received event type %d", evt_type); - if(*mHandler.on_scan_event) - (*mHandler.on_scan_event)(id(), evt_type); - } else if (event_id == GSCAN_EVENT_FULL_SCAN_RESULTS) { - wifi_handle_full_scan_event(id(), event, mHandler); - } - return NL_SKIP; - } -}; - -wifi_error wifi_start_gscan( - wifi_request_id id, - wifi_interface_handle iface, - wifi_scan_cmd_params params, - wifi_scan_result_handler handler) -{ - wifi_handle handle = getWifiHandle(iface); - - ALOGV("Starting GScan, halHandle = %p", handle); - - ScanCommand *cmd = new ScanCommand(iface, id, ¶ms, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = wifi_register_cmd(handle, id, cmd); - if (result != WIFI_SUCCESS) { - cmd->releaseRef(); - return result; - } - result = (wifi_error)cmd->start(); - if (result != WIFI_SUCCESS) { - wifi_unregister_cmd(handle, id); - cmd->releaseRef(); - return result; - } - return result; -} - -wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface) -{ - wifi_handle handle = getWifiHandle(iface); - ALOGV("Stopping GScan, wifi_request_id = %d, halHandle = %p", id, handle); - - if (id == -1) { - wifi_scan_result_handler handler; - wifi_scan_cmd_params dummy_params; - wifi_handle handle = getWifiHandle(iface); - memset(&handler, 0, sizeof(handler)); - - ScanCommand *cmd = new ScanCommand(iface, id, &dummy_params, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - cmd->cancel(); - cmd->releaseRef(); - return WIFI_SUCCESS; - } - - return wifi_cancel_cmd(id, iface); -} - -wifi_error wifi_enable_full_scan_results( - wifi_request_id id, - wifi_interface_handle iface, - wifi_scan_result_handler handler) -{ - wifi_handle handle = getWifiHandle(iface); - int params_dummy; - - ALOGV("Enabling full scan results, halHandle = %p", handle); - - FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, id, ¶ms_dummy, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = wifi_register_cmd(handle, id, cmd); - if (result != WIFI_SUCCESS) { - cmd->releaseRef(); - return result; - } - result = (wifi_error)cmd->start(); - if (result != WIFI_SUCCESS) { - wifi_unregister_cmd(handle, id); - cmd->releaseRef(); - return result; - } - return result; -} - -int wifi_handle_full_scan_event( - wifi_request_id id, - WifiEvent& event, - wifi_scan_result_handler handler) -{ - nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); - unsigned int len = event.get_vendor_data_len(); - - if (vendor_data == NULL || len < sizeof(wifi_gscan_full_result_t)) { - ALOGI("Full scan results: No scan results found"); - return NL_SKIP; - } - - wifi_gscan_full_result_t *drv_res = (wifi_gscan_full_result_t *)event.get_vendor_data(); - /* To protect against corrupted data, put a ceiling */ - int ie_len = min(MAX_PROBE_RESP_IE_LEN, drv_res->ie_length); - wifi_scan_result *full_scan_result; - wifi_gscan_result_t *fixed = &drv_res->fixed; - - if ((ie_len + offsetof(wifi_gscan_full_result_t, ie_data)) > len) { - ALOGE("BAD event data, len %d ie_len %d fixed length %d!\n", len, - ie_len, offsetof(wifi_gscan_full_result_t, ie_data)); - return NL_SKIP; - } - full_scan_result = (wifi_scan_result *) malloc((ie_len + offsetof(wifi_scan_result, ie_data))); - if (!full_scan_result) { - ALOGE("Full scan results: Can't malloc!\n"); - return NL_SKIP; - } - convert_to_hal_result(full_scan_result, fixed); - full_scan_result->ie_length = ie_len; - memcpy(full_scan_result->ie_data, drv_res->ie_data, ie_len); - if(handler.on_full_scan_result) - handler.on_full_scan_result(id, full_scan_result, drv_res->scan_ch_bucket); - - ALOGV("Full scan result: %-32s %02x:%02x:%02x:%02x:%02x:%02x %d %d %lld %lld %lld %x %d\n", - fixed->ssid, fixed->bssid[0], fixed->bssid[1], fixed->bssid[2], fixed->bssid[3], - fixed->bssid[4], fixed->bssid[5], fixed->rssi, fixed->channel, fixed->ts, - fixed->rtt, fixed->rtt_sd, drv_res->scan_ch_bucket, drv_res->ie_length); - free(full_scan_result); - return NL_SKIP; -} - - -wifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface) -{ - ALOGV("Disabling full scan results"); - wifi_handle handle = getWifiHandle(iface); - - if(id == -1) { - wifi_scan_result_handler handler; - wifi_handle handle = getWifiHandle(iface); - int params_dummy; - - memset(&handler, 0, sizeof(handler)); - FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, 0, ¶ms_dummy, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - cmd->cancel(); - cmd->releaseRef(); - return WIFI_SUCCESS; - } - - return wifi_cancel_cmd(id, iface); -} - - -///////////////////////////////////////////////////////////////////////////// - -class GetScanResultsCommand : public WifiCommand { - wifi_cached_scan_results *mScans; - int mMax; - int *mNum; - int mRetrieved; - byte mFlush; - int mCompleted; -public: - GetScanResultsCommand(wifi_interface_handle iface, byte flush, - wifi_cached_scan_results *results, int max, int *num) - : WifiCommand("GetScanResultsCommand", iface, -1), mScans(results), mMax(max), mNum(num), - mRetrieved(0), mFlush(flush), mCompleted(0) - { } - - int createRequest(WifiRequest& request, int num, byte flush) { - int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_SCAN_RESULTS); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num); - if (result < 0) { - return result; - } - - result = request.put_u8(GSCAN_ATTRIBUTE_FLUSH_RESULTS, flush); - if (result < 0) { - return result; - } - - request.attr_end(data); - return WIFI_SUCCESS; - } - - int execute() { - WifiRequest request(familyId(), ifaceId()); - ALOGV("retrieving %d scan results", mMax); - - for (int i = 0; i < 10 && mRetrieved < mMax; i++) { - int num_to_retrieve = mMax - mRetrieved; - // ALOGI("retrieving %d scan results in one shot", num_to_retrieve); - int result = createRequest(request, num_to_retrieve, mFlush); - if (result < 0) { - ALOGE("failed to create request"); - return result; - } - - int prev_retrieved = mRetrieved; - - result = requestResponse(request); - - if (result != WIFI_SUCCESS) { - ALOGE("failed to retrieve scan results; result = %d", result); - return result; - } - - if (mRetrieved == prev_retrieved || mCompleted) { - /* no more items left to retrieve */ - break; - } - - request.destroy(); - } - - ALOGV("GetScanResults read %d results", mRetrieved); - *mNum = mRetrieved; - return WIFI_SUCCESS; - } - - virtual int handleResponse(WifiEvent& reply) { - ALOGV("In GetScanResultsCommand::handleResponse"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - int id = reply.get_vendor_id(); - int subcmd = reply.get_vendor_subcmd(); - - ALOGV("Id = %0x, subcmd = %d", id, subcmd); - - /* - if (subcmd != GSCAN_SUBCMD_SCAN_RESULTS) { - ALOGE("Invalid response to GetScanResultsCommand; ignoring it"); - return NL_SKIP; - } - */ - - nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = reply.get_vendor_data_len(); - - if (vendor_data == NULL || len == 0) { - ALOGE("no vendor data in GetScanResults response; ignoring it"); - return NL_SKIP; - } - - for (nl_iterator it(vendor_data); it.has_next(); it.next()) { - if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE) { - mCompleted = it.get_u8(); - ALOGV("retrieved mCompleted flag : %d", mCompleted); - } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS || it.get_type() == 0) { - int scan_id = 0, flags = 0, num = 0, scan_ch_bucket_mask = 0; - for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) { - if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_ID) { - scan_id = it2.get_u32(); - ALOGV("retrieved scan_id : 0x%0x", scan_id); - } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_FLAGS) { - flags = it2.get_u8(); - ALOGV("retrieved scan_flags : 0x%0x", flags); - } else if (it2.get_type() == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) { - num = it2.get_u32(); - ALOGV("retrieved num_results: %d", num); - } else if (it2.get_type() == GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK) { - scan_ch_bucket_mask = it2.get_u32(); - ALOGD("retrieved scan_ch_bucket_mask: %x", scan_ch_bucket_mask); - } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS && num) { - if (mRetrieved >= mMax) { - ALOGW("Stored %d scans, ignoring excess results", mRetrieved); - break; - } - num = min(num, (int)(it2.get_len()/sizeof(wifi_gscan_result))); - num = min(num, (int)MAX_AP_CACHE_PER_SCAN); - ALOGV("Copying %d scan results", num); - wifi_gscan_result_t *results = (wifi_gscan_result_t *)it2.get_data(); - wifi_scan_result *mScanResults = mScans[mRetrieved].results; - - for (int i = 0; i < num; i++) { - wifi_gscan_result_t *result = &results[i]; - convert_to_hal_result(&mScanResults[i], result); - mScanResults[i].ie_length = 0; - ALOGV("%02d %-32s %02x:%02x:%02x:%02x:%02x:%02x %04d", i, - result->ssid, result->bssid[0], result->bssid[1], result->bssid[2], - result->bssid[3], result->bssid[4], result->bssid[5], - result->rssi); - } - mScans[mRetrieved].scan_id = scan_id; - mScans[mRetrieved].flags = flags; - mScans[mRetrieved].num_results = num; - mScans[mRetrieved].buckets_scanned = scan_ch_bucket_mask; - ALOGV("Setting result of scan_id : 0x%0x", mScans[mRetrieved].scan_id); - mRetrieved++; - } else { - ALOGW("Ignoring invalid attribute type = %d, size = %d", - it.get_type(), it.get_len()); - } - } - } else { - ALOGW("Ignoring invalid attribute type = %d, size = %d", - it.get_type(), it.get_len()); - } - } - ALOGV("GetScanResults read %d results", mRetrieved); - return NL_OK; - } -}; - -wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush, - int max, wifi_cached_scan_results *results, int *num) { - ALOGV("Getting cached scan results, iface handle = %p, num = %d", iface, *num); - - GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, max, num); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error err = (wifi_error)cmd->execute(); - cmd->releaseRef(); - return err; -} - -///////////////////////////////////////////////////////////////////////////// - -class BssidHotlistCommand : public WifiCommand -{ -private: - wifi_bssid_hotlist_params mParams; - wifi_hotlist_ap_found_handler mHandler; - static const int MAX_RESULTS = 64; - wifi_scan_result mResults[MAX_RESULTS]; -public: - BssidHotlistCommand(wifi_interface_handle handle, int id, - wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler) - : WifiCommand("BssidHotlistCommand", handle, id), mParams(params), mHandler(handler) - { } - - int createSetupRequest(WifiRequest& request) { - int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1); - if (result < 0) { - return result; - } - - result = request.put_u32(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size); - if (result < 0) { - return result; - } - - result = request.put_u32(GSCAN_ATTRIBUTE_HOTLIST_BSSID_COUNT, mParams.num_bssid); - if (result < 0) { - return result; - } - - struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS); - for (int i = 0; i < mParams.num_bssid; i++) { - nlattr *attr2 = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_ELEM); - if (attr2 == NULL) { - return WIFI_ERROR_OUT_OF_MEMORY; - } - result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid); - if (result < 0) { - return result; - } - result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high); - if (result < 0) { - return result; - } - result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low); - if (result < 0) { - return result; - } - request.attr_end(attr2); - } - - request.attr_end(attr); - request.attr_end(data); - return result; - } - - int createTeardownRequest(WifiRequest& request) { - int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1); - if (result < 0) { - return result; - } - - struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS); - request.attr_end(attr); - request.attr_end(data); - return result; - } - - int start() { - ALOGI("Executing hotlist setup request, num = %d", mParams.num_bssid); - WifiRequest request(familyId(), ifaceId()); - int result = createSetupRequest(request); - if (result < 0) { - return result; - } - - result = requestResponse(request); - if (result < 0) { - ALOGI("Failed to execute hotlist setup request, result = %d", result); - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND); - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST); - return result; - } - - ALOGI("Successfully set %d APs in the hotlist ", mParams.num_bssid); - result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); - if (result < 0) { - return result; - } - - registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND); - registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST); - - result = requestResponse(request); - if (result < 0) { - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND); - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST); - return result; - } - - ALOGI("successfully restarted the scan"); - return result; - } - - virtual int cancel() { - /* unregister event handler */ - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND); - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST); - /* create set hotlist message with empty hotlist */ - WifiRequest request(familyId(), ifaceId()); - int result = createTeardownRequest(request); - if (result < 0) { - return result; - } - - result = requestResponse(request); - if (result < 0) { - return result; - } - - ALOGI("Successfully reset APs in current hotlist"); - return result; - } - - virtual int handleResponse(WifiEvent& reply) { - /* Nothing to do on response! */ - return NL_SKIP; - } - - virtual int handleEvent(WifiEvent& event) { - ALOGI("Hotlist AP event"); - int event_id = event.get_vendor_subcmd(); - // event.log(); - - nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = event.get_vendor_data_len(); - - if (vendor_data == NULL || len == 0) { - ALOGI("No scan results found"); - return NL_SKIP; - } - - memset(mResults, 0, sizeof(wifi_scan_result) * MAX_RESULTS); - - int num = len / sizeof(wifi_gscan_result_t); - wifi_gscan_result_t *inp = (wifi_gscan_result_t *)event.get_vendor_data(); - num = min(MAX_RESULTS, num); - for (int i = 0; i < num; i++, inp++) { - convert_to_hal_result(&(mResults[i]), inp); - } - - if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_FOUND) { - ALOGI("FOUND %d hotlist APs", num); - if (*mHandler.on_hotlist_ap_found) - (*mHandler.on_hotlist_ap_found)(id(), num, mResults); - } else if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_LOST) { - ALOGI("LOST %d hotlist APs", num); - if (*mHandler.on_hotlist_ap_lost) - (*mHandler.on_hotlist_ap_lost)(id(), num, mResults); - } - return NL_SKIP; - } -}; - -class ePNOCommand : public WifiCommand -{ -private: - wifi_epno_params epno_params; - wifi_epno_handler mHandler; - wifi_scan_result mResults[MAX_EPNO_NETWORKS]; -public: - ePNOCommand(wifi_interface_handle handle, int id, - const wifi_epno_params *params, wifi_epno_handler handler) - : WifiCommand("ePNOCommand", handle, id), mHandler(handler) - { - if (params != NULL) { - memcpy(&epno_params, params, sizeof(wifi_epno_params)); - } else { - memset(&epno_params, 0, sizeof(wifi_epno_params)); - } - } - int createSetupRequest(WifiRequest& request) { - if (epno_params.num_networks > MAX_EPNO_NETWORKS) { - ALOGE("wrong epno num_networks:%d", epno_params.num_networks); - return WIFI_ERROR_INVALID_ARGS; - } - int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_EPNO_SSID); - if (result < 0) { - return result; - } - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_FLUSH, 1); - if (result < 0) { - return result; - } - - result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_5G_RSSI_THR, - (u8)epno_params.min5GHz_rssi); - if (result < 0) { - return result; - } - result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_2G_RSSI_THR, - (u8)epno_params.min24GHz_rssi); - if (result < 0) { - return result; - } - result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_INIT_SCORE_MAX, - epno_params.initial_score_max); - if (result < 0) { - return result; - } - result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_CUR_CONN_BONUS, - epno_params.current_connection_bonus); - if (result < 0) { - return result; - } - result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_SAME_NETWORK_BONUS, - epno_params.same_network_bonus); - if (result < 0) { - return result; - } - result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_SECURE_BONUS, - epno_params.secure_bonus); - if (result < 0) { - return result; - } - result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_5G_BONUS, - epno_params.band5GHz_bonus); - if (result < 0) { - return result; - } - result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_SSID_NUM, - epno_params.num_networks); - if (result < 0) { - return result; - } - struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_EPNO_SSID_LIST); - wifi_epno_network *ssid_list = epno_params.networks; - for (int i = 0; i < epno_params.num_networks; i++) { - nlattr *attr2 = request.attr_start(i); - if (attr2 == NULL) { - return WIFI_ERROR_OUT_OF_MEMORY; - } - result = request.put(GSCAN_ATTRIBUTE_EPNO_SSID, ssid_list[i].ssid, DOT11_MAX_SSID_LEN); - ALOGI("PNO network: SSID %s flags %x auth %x", ssid_list[i].ssid, - ssid_list[i].flags, - ssid_list[i].auth_bit_field); - if (result < 0) { - return result; - } - result = request.put_u32(GSCAN_ATTRIBUTE_EPNO_SSID_LEN, strlen(ssid_list[i].ssid)); - if (result < 0) { - return result; - } - result = request.put_u32(GSCAN_ATTRIBUTE_EPNO_FLAGS, ssid_list[i].flags); - if (result < 0) { - return result; - } - result = request.put_u32(GSCAN_ATTRIBUTE_EPNO_AUTH, ssid_list[i].auth_bit_field); - if (result < 0) { - return result; - } - request.attr_end(attr2); - } - request.attr_end(attr); - request.attr_end(data); - return result; - } - - int createTeardownRequest(WifiRequest& request) { - int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_EPNO_SSID); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_FLUSH, 1); - if (result < 0) { - return result; - } - request.attr_end(data); - return result; - } - - int start() { - ALOGI("Executing ePNO setup request, num = %d", epno_params.num_networks); - WifiRequest request(familyId(), ifaceId()); - int result = createSetupRequest(request); - if (result < 0) { - return result; - } - - result = requestResponse(request); - if (result < 0) { - ALOGI("Failed to execute ePNO setup request, result = %d", result); - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT); - return result; - } - - ALOGI("Successfully set %d SSIDs for ePNO", epno_params.num_networks); - registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT); - ALOGI("successfully restarted the scan"); - return result; - } - - virtual int cancel() { - /* unregister event handler */ - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT); - /* create set hotlist message with empty hotlist */ - WifiRequest request(familyId(), ifaceId()); - int result = createTeardownRequest(request); - if (result < 0) { - return result; - } - - result = requestResponse(request); - if (result < 0) { - return result; - } - - ALOGI("Successfully reset APs in current hotlist"); - return result; - } - - virtual int handleResponse(WifiEvent& reply) { - /* Nothing to do on response! */ - return NL_SKIP; - } - - virtual int handleEvent(WifiEvent& event) { - ALOGI("ePNO event"); - int event_id = event.get_vendor_subcmd(); - // event.log(); - - nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = event.get_vendor_data_len(); - - if (vendor_data == NULL || len == 0) { - ALOGI("No scan results found"); - return NL_SKIP; - } - - memset(mResults, 0, sizeof(wifi_scan_result) * MAX_EPNO_NETWORKS); - - unsigned int num = len / sizeof(wifi_pno_result_t); - unsigned int i; - num = min(MAX_EPNO_NETWORKS, num); - wifi_pno_result_t *res = (wifi_pno_result_t *) event.get_vendor_data(); - for (i = 0; i < num; i++) { - if (res[i].flags == PNO_SSID_FOUND) { - memcpy(mResults[i].ssid, res[i].ssid, res[i].ssid_len); - memcpy(mResults[i].bssid, res[i].bssid, sizeof(mac_addr)); - - mResults[i].ssid[res[i].ssid_len] = '\0'; - mResults[i].channel = res[i].channel; - mResults[i].rssi = res[i].rssi; - } - } - if (*mHandler.on_network_found) - (*mHandler.on_network_found)(id(), num, mResults); - return NL_SKIP; - } -}; - -wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface, - wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler) -{ - wifi_handle handle = getWifiHandle(iface); - - BssidHotlistCommand *cmd = new BssidHotlistCommand(iface, id, params, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = wifi_register_cmd(handle, id, cmd); - if (result != WIFI_SUCCESS) { - cmd->releaseRef(); - return result; - } - result = (wifi_error)cmd->start(); - if (result != WIFI_SUCCESS) { - wifi_unregister_cmd(handle, id); - cmd->releaseRef(); - return result; - } - return result; -} - -wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface) -{ - return wifi_cancel_cmd(id, iface); -} - - -///////////////////////////////////////////////////////////////////////////// - -class SignificantWifiChangeCommand : public WifiCommand -{ - typedef struct { - mac_addr bssid; // BSSID - wifi_channel channel; // channel frequency in MHz - int num_rssi; // number of rssi samples - wifi_rssi rssi[8]; // RSSI history in db - } wifi_significant_change_result_internal; - -private: - wifi_significant_change_params mParams; - wifi_significant_change_handler mHandler; - static const int MAX_RESULTS = 64; - wifi_significant_change_result_internal mResultsBuffer[MAX_RESULTS]; - wifi_significant_change_result *mResults[MAX_RESULTS]; -public: - SignificantWifiChangeCommand(wifi_interface_handle handle, int id, - wifi_significant_change_params params, wifi_significant_change_handler handler) - : WifiCommand("SignificantWifiChangeCommand", handle, id), mParams(params), - mHandler(handler) - { } - - int createSetupRequest(WifiRequest& request) { - int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u8(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1); - if (result < 0) { - return result; - } - result = request.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE, mParams.rssi_sample_size); - if (result < 0) { - return result; - } - result = request.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size); - if (result < 0) { - return result; - } - result = request.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING, mParams.min_breaching); - if (result < 0) { - return result; - } - result = request.put_u16(GSCAN_ATTRIBUTE_NUM_BSSID, mParams.num_bssid); - if (result < 0) { - return result; - } - if (mParams.num_bssid != 0) { - nlattr* attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS); - if (attr == NULL) { - return WIFI_ERROR_OUT_OF_MEMORY; - } - - for (int i = 0; i < mParams.num_bssid; i++) { - nlattr* attr2 = request.attr_start(i); - if (attr2 == NULL) { - return WIFI_ERROR_OUT_OF_MEMORY; - } - result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid); - if (result < 0) { - return result; - } - result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high); - if (result < 0) { - return result; - } - result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low); - if (result < 0) { - return result; - } - request.attr_end(attr2); - } - - request.attr_end(attr); - } - request.attr_end(data); - - return result; - } - - int createTeardownRequest(WifiRequest& request) { - int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u16(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1); - if (result < 0) { - return result; - } - - request.attr_end(data); - return result; - } - - int start() { - ALOGI("Set significant wifi change config"); - WifiRequest request(familyId(), ifaceId()); - - int result = createSetupRequest(request); - if (result < 0) { - return result; - } - - result = requestResponse(request); - if (result < 0) { - ALOGI("failed to set significant wifi change config %d", result); - return result; - } - - ALOGI("successfully set significant wifi change config"); - - result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); - if (result < 0) { - return result; - } - - registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); - - result = requestResponse(request); - if (result < 0) { - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); - return result; - } - - ALOGI("successfully restarted the scan"); - return result; - } - - virtual int cancel() { - /* unregister event handler */ - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); - - /* create set significant change monitor message with empty hotlist */ - WifiRequest request(familyId(), ifaceId()); - - int result = createTeardownRequest(request); - if (result < 0) { - return result; - } - - result = requestResponse(request); - if (result < 0) { - return result; - } - - ALOGI("successfully reset significant wifi change config"); - return result; - } - - virtual int handleResponse(WifiEvent& reply) { - /* Nothing to do on response! */ - return NL_SKIP; - } - - virtual int handleEvent(WifiEvent& event) { - ALOGV("Got a significant wifi change event"); - - nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = event.get_vendor_data_len(); - - if (vendor_data == NULL || len == 0) { - ALOGI("No scan results found"); - return NL_SKIP; - } - - typedef struct { - uint16_t flags; - uint16_t channel; - mac_addr bssid; - s8 rssi_history[8]; - } ChangeInfo; - - int num = min(len / sizeof(ChangeInfo), MAX_RESULTS); - ChangeInfo *ci = (ChangeInfo *)event.get_vendor_data(); - - for (int i = 0; i < num; i++) { - memcpy(mResultsBuffer[i].bssid, ci[i].bssid, sizeof(mac_addr)); - mResultsBuffer[i].channel = ci[i].channel; - mResultsBuffer[i].num_rssi = 8; - for (int j = 0; j < mResultsBuffer[i].num_rssi; j++) - mResultsBuffer[i].rssi[j] = (int) ci[i].rssi_history[j]; - mResults[i] = reinterpret_cast(&(mResultsBuffer[i])); - } - - ALOGV("Retrieved %d scan results", num); - - if (num != 0) { - (*mHandler.on_significant_change)(id(), num, mResults); - } else { - ALOGW("No significant change reported"); - } - - return NL_SKIP; - } -}; - -wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface, - wifi_significant_change_params params, wifi_significant_change_handler handler) -{ - wifi_handle handle = getWifiHandle(iface); - - SignificantWifiChangeCommand *cmd = new SignificantWifiChangeCommand( - iface, id, params, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = wifi_register_cmd(handle, id, cmd); - if (result != WIFI_SUCCESS) { - cmd->releaseRef(); - return result; - } - result = (wifi_error)cmd->start(); - if (result != WIFI_SUCCESS) { - wifi_unregister_cmd(handle, id); - cmd->releaseRef(); - return result; - } - return result; -} - -wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface) -{ - return wifi_cancel_cmd(id, iface); -} - -wifi_error wifi_reset_epno_list(wifi_request_id id, wifi_interface_handle iface) -{ - if (id == -1) { - wifi_epno_handler handler; - wifi_handle handle = getWifiHandle(iface); - - memset(&handler, 0, sizeof(handler)); - ePNOCommand *cmd = new ePNOCommand(iface, id, NULL, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - cmd->cancel(); - cmd->releaseRef(); - return WIFI_SUCCESS; - } - return wifi_cancel_cmd(id, iface); -} - -wifi_error wifi_set_epno_list(wifi_request_id id, wifi_interface_handle iface, - const wifi_epno_params *params, wifi_epno_handler handler) -{ - wifi_handle handle = getWifiHandle(iface); - - ePNOCommand *cmd = new ePNOCommand(iface, id, params, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = wifi_register_cmd(handle, id, cmd); - if (result != WIFI_SUCCESS) { - cmd->releaseRef(); - return result; - } - result = (wifi_error)cmd->start(); - if (result != WIFI_SUCCESS) { - wifi_unregister_cmd(handle, id); - cmd->releaseRef(); - return result; - } - return result; -} - - -//////////////////////////////////////////////////////////////////////////////// - -class AnqpoConfigureCommand : public WifiCommand -{ - int num_hs; - wifi_passpoint_network *mNetworks; - wifi_passpoint_event_handler mHandler; - wifi_scan_result *mResult; -public: - AnqpoConfigureCommand(wifi_request_id id, wifi_interface_handle iface, - int num, wifi_passpoint_network *hs_list, wifi_passpoint_event_handler handler) - : WifiCommand("AnqpoConfigureCommand", iface, id), num_hs(num), mNetworks(hs_list), - mHandler(handler) - { - mResult = NULL; - } - - int createRequest(WifiRequest& request, int val) { - - int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_ANQPO_CONFIG); - result = request.put_u32(GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE, num_hs); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - - struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_ANQPO_HS_LIST); - for (int i = 0; i < num_hs; i++) { - nlattr *attr2 = request.attr_start(i); - if (attr2 == NULL) { - return WIFI_ERROR_OUT_OF_MEMORY; - } - result = request.put_u32(GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID, mNetworks[i].id); - if (result < 0) { - return result; - } - result = request.put(GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM, mNetworks[i].realm, 256); - if (result < 0) { - return result; - } - result = request.put(GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID, - mNetworks[i].roamingConsortiumIds, 128); - if (result < 0) { - return result; - } - result = request.put(GSCAN_ATTRIBUTE_ANQPO_HS_PLMN, mNetworks[i].plmn, 3); - if (result < 0) { - return result; - } - - request.attr_end(attr2); - } - - request.attr_end(attr); - request.attr_end(data); - - return WIFI_SUCCESS; - } - - int start() { - - WifiRequest request(familyId(), ifaceId()); - int result = createRequest(request, num_hs); - if (result != WIFI_SUCCESS) { - ALOGE("failed to create request; result = %d", result); - return result; - } - - registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_ANQPO_HOTSPOT_MATCH); - - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to set ANQPO networks; result = %d", result); - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_ANQPO_HOTSPOT_MATCH); - return result; - } - - return result; - } - - virtual int cancel() { - - WifiRequest request(familyId(), ifaceId()); - int result = createRequest(request, 0); - if (result != WIFI_SUCCESS) { - ALOGE("failed to create request; result = %d", result); - } else { - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to reset ANQPO networks;result = %d", result); - } - } - - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_ANQPO_HOTSPOT_MATCH); - return WIFI_SUCCESS; - } - - virtual int handleResponse(WifiEvent& reply) { - ALOGD("Request complete!"); - /* Nothing to do on response! */ - return NL_SKIP; - } - - virtual int handleEvent(WifiEvent& event) { - typedef struct { - u16 channel; /* channel of GAS protocol */ - u8 dialog_token; /* GAS dialog token */ - u8 fragment_id; /* fragment id */ - u16 status_code; /* status code on GAS completion */ - u16 data_len; /* length of data to follow */ - u8 data[1]; /* variable length specified by data_len */ - } wifi_anqp_gas_resp; - - ALOGI("ANQPO hotspot matched event!"); - - nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); - unsigned int len = event.get_vendor_data_len(); - - if (vendor_data == NULL || len < sizeof(wifi_scan_result)) { - ALOGI("No scan results found"); - return NL_SKIP; - } - mResult = (wifi_scan_result *)malloc(sizeof(wifi_scan_result)); - if (!mResult) { - return NL_SKIP; - } - wifi_gscan_full_result_t *drv_res = (wifi_gscan_full_result_t *)event.get_vendor_data(); - wifi_gscan_result_t *fixed = &drv_res->fixed; - convert_to_hal_result(mResult, fixed); - - byte *anqp = (byte *)drv_res + offsetof(wifi_gscan_full_result_t, ie_data) + drv_res->ie_length; - wifi_anqp_gas_resp *gas = (wifi_anqp_gas_resp *)anqp; - int anqp_len = offsetof(wifi_anqp_gas_resp, data) + gas->data_len; - int networkId = *(int *)((byte *)anqp + anqp_len); - - ALOGI("%-32s\t", mResult->ssid); - - ALOGI("%02x:%02x:%02x:%02x:%02x:%02x ", mResult->bssid[0], mResult->bssid[1], - mResult->bssid[2], mResult->bssid[3], mResult->bssid[4], mResult->bssid[5]); - - ALOGI("%d\t", mResult->rssi); - ALOGI("%d\t", mResult->channel); - ALOGI("%lld\t", mResult->ts); - ALOGI("%lld\t", mResult->rtt); - ALOGI("%lld\n", mResult->rtt_sd); - - if(*mHandler.on_passpoint_network_found) - (*mHandler.on_passpoint_network_found)(id(), networkId, mResult, anqp_len, anqp); - free(mResult); - return NL_SKIP; - } -}; - -wifi_error wifi_set_passpoint_list(wifi_request_id id, wifi_interface_handle iface, int num, - wifi_passpoint_network *networks, wifi_passpoint_event_handler handler) -{ - wifi_handle handle = getWifiHandle(iface); - - AnqpoConfigureCommand *cmd = new AnqpoConfigureCommand(id, iface, num, networks, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = wifi_register_cmd(handle, id, cmd); - if (result != WIFI_SUCCESS) { - cmd->releaseRef(); - return result; - } - result = (wifi_error)cmd->start(); - if (result != WIFI_SUCCESS) { - wifi_unregister_cmd(handle, id); - cmd->releaseRef(); - return result; - } - return result; -} - -wifi_error wifi_reset_passpoint_list(wifi_request_id id, wifi_interface_handle iface) -{ - return wifi_cancel_cmd(id, iface); -} diff --git a/wlan/wifi_hal/link_layer_stats.cpp b/wlan/wifi_hal/link_layer_stats.cpp deleted file mode 100644 index 31e43e6..0000000 --- a/wlan/wifi_hal/link_layer_stats.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "sync.h" - -#define LOG_TAG "WifiHAL" - -#include - -#include "wifi_hal.h" -#include "common.h" -#include "cpp_bindings.h" - -/* Internal radio statistics structure in the driver */ -typedef struct { - wifi_radio radio; - uint32_t on_time; - uint32_t tx_time; - uint32_t rx_time; - uint32_t on_time_scan; - uint32_t on_time_nbd; - uint32_t on_time_gscan; - uint32_t on_time_roam_scan; - uint32_t on_time_pno_scan; - uint32_t on_time_hs20; - uint32_t num_channels; - wifi_channel_stat channels[]; -} wifi_radio_stat_internal; - -enum { - LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START, - LSTATS_SUBCMD_SET_INFO, - LSTATS_SUBCMD_CLEAR_INFO, -}; - -class GetLinkStatsCommand : public WifiCommand -{ - wifi_stats_result_handler mHandler; -public: - GetLinkStatsCommand(wifi_interface_handle iface, wifi_stats_result_handler handler) - : WifiCommand("GetLinkStatsCommand", iface, 0), mHandler(handler) - { } - - virtual int create() { - // ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id); - - int ret = mMsg.create(GOOGLE_OUI, LSTATS_SUBCMD_GET_INFO); - if (ret < 0) { - ALOGE("Failed to create %x - %d", LSTATS_SUBCMD_GET_INFO, ret); - return ret; - } - - return ret; - } - -protected: - virtual int handleResponse(WifiEvent& reply) { - - // ALOGI("In GetLinkStatsCommand::handleResponse"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - int id = reply.get_vendor_id(); - int subcmd = reply.get_vendor_subcmd(); - - // ALOGI("Id = %0x, subcmd = %d", id, subcmd); - - void *data = reply.get_vendor_data(); - int len = reply.get_vendor_data_len(); - wifi_radio_stat *radio_stat = (wifi_radio_stat *)data; - ALOGE("radio: = %d", radio_stat->radio); - ALOGE("on_time: = %u ms", radio_stat->on_time); - ALOGE("tx_time: = %u ms", radio_stat->tx_time); - ALOGE("num_tx_levels: = %u", radio_stat->num_tx_levels); - radio_stat->tx_time_per_levels = (u32*)((char*)data + sizeof(wifi_radio_stat) + sizeof(wifi_iface_stat)); - ALOGE("tx_time_per_levels: = %u ms", radio_stat->tx_time_per_levels[0]); - ALOGE("rx_time: = %u ms", radio_stat->rx_time); - ALOGE("on_time_scan: = %u ms", radio_stat->on_time_scan); - ALOGE("on_time_nbd: = %u ms", radio_stat->on_time_nbd); - ALOGE("on_time_gscan: = %u ms", radio_stat->on_time_gscan); - ALOGE("on_time_pno_scan: = %u ms", radio_stat->on_time_pno_scan); - ALOGE("on_time_hs20: = %u ms", radio_stat->on_time_hs20); - if (!radio_stat) { - ALOGE("Invalid stats pointer received"); - return NL_SKIP; - } - if (radio_stat->num_channels > 11) { - ALOGE("Incorrect number of channels = %d", radio_stat->num_channels); - // dump data before num_channels - ALOGE("radio: = %d", radio_stat->radio); - ALOGE("on_time: = %u ms", radio_stat->on_time); - ALOGE("tx_time: = %u ms", radio_stat->tx_time); - ALOGE("rx_time: = %u ms", radio_stat->rx_time); - ALOGE("on_time_scan: = %u ms", radio_stat->on_time_scan); - ALOGE("on_time_nbd: = %u ms", radio_stat->on_time_nbd); - ALOGE("on_time_gscan: = %u ms", radio_stat->on_time_gscan); - ALOGE("on_time_pno_scan: = %u ms", radio_stat->on_time_pno_scan); - ALOGE("on_time_hs20: = %u ms", radio_stat->on_time_hs20); - free(radio_stat); - return NL_SKIP; - } - wifi_iface_stat *iface_stat = NULL; - iface_stat = (wifi_iface_stat *)((char* )data + sizeof(wifi_radio_stat)); - - if(*mHandler.on_link_stats_results == NULL) { - ALOGE("*mHandler.on_link_stats_results is NULL"); - } else { - (*mHandler.on_link_stats_results)(id, iface_stat, 1, radio_stat); - } - //free(radio_stat); - return NL_OK; - } - -}; - -class SetLinkStatsCommand : public WifiCommand -{ - wifi_stats_result_handler mHandler; -public: - SetLinkStatsCommand(wifi_interface_handle iface) - : WifiCommand("SetLinkStatsCommand", iface, 0) - { } - - virtual int create() { - // ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id); - - int ret = mMsg.create(GOOGLE_OUI, LSTATS_SUBCMD_SET_INFO); - if (ret < 0) { - ALOGE("Failed to create %x - %d", LSTATS_SUBCMD_SET_INFO, ret); - return ret; - } - - return ret; - } - -protected: - virtual int handleResponse(WifiEvent& reply) { - - // ALOGI("In GetLinkStatsCommand::handleResponse"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - int id = reply.get_vendor_id(); - int subcmd = reply.get_vendor_subcmd(); - - // ALOGI("Id = %0x, subcmd = %d", id, subcmd); - - void *data = reply.get_vendor_data(); - int len = reply.get_vendor_data_len(); - return NL_OK; - } - -}; - -class ClearLinkStatsCommand : public WifiCommand -{ - wifi_stats_result_handler mHandler; -public: - ClearLinkStatsCommand(wifi_interface_handle iface) - : WifiCommand("ClearLinkStatsCommand", iface, 0) - { } - - virtual int create() { - // ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id); - - int ret = mMsg.create(GOOGLE_OUI, LSTATS_SUBCMD_CLEAR_INFO); - if (ret < 0) { - ALOGE("Failed to create %x - %d", LSTATS_SUBCMD_CLEAR_INFO, ret); - return ret; - } - - return ret; - } - -protected: - virtual int handleResponse(WifiEvent& reply) { - - // ALOGI("In GetLinkStatsCommand::handleResponse"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - int id = reply.get_vendor_id(); - int subcmd = reply.get_vendor_subcmd(); - - // ALOGI("Id = %0x, subcmd = %d", id, subcmd); - - void *data = reply.get_vendor_data(); - int len = reply.get_vendor_data_len(); - return NL_OK; - } - -}; - -wifi_error wifi_get_link_stats(wifi_request_id id, - wifi_interface_handle iface, wifi_stats_result_handler handler) -{ - GetLinkStatsCommand command(iface, handler); - return (wifi_error) command.requestResponse(); -} - -wifi_error wifi_set_link_stats( - wifi_interface_handle iface, wifi_link_layer_params params) -{ - - SetLinkStatsCommand command(iface); - return (wifi_error) command.requestResponse(); - //return WIFI_SUCCESS; -} - -wifi_error wifi_clear_link_stats(wifi_interface_handle iface, - u32 stats_clear_req_mask, u32 *stats_clear_rsp_mask, u8 stop_req, u8 *stop_rsp) -{ - - ClearLinkStatsCommand command(iface); - return (wifi_error) command.requestResponse(); - //return WIFI_SUCCESS; -} diff --git a/wlan/wifi_hal/rtt.cpp b/wlan/wifi_hal/rtt.cpp deleted file mode 100644 index 048f339..0000000 --- a/wlan/wifi_hal/rtt.cpp +++ /dev/null @@ -1,699 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "nl80211_copy.h" - -#include "sync.h" - -#define LOG_TAG "WifiHAL" - -#include -#include - -#include "wifi_hal.h" -#include "common.h" -#include "cpp_bindings.h" - -using namespace android; -#define RTT_RESULT_SIZE (sizeof(wifi_rtt_result)); -typedef enum { - - RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START, - RTT_SUBCMD_CANCEL_CONFIG, - RTT_SUBCMD_GETCAPABILITY, - RTT_SUBCMD_GETAVAILCHANNEL, - RTT_SUBCMD_SET_RESPONDER, - RTT_SUBCMD_CANCEL_RESPONDER, -} RTT_SUB_COMMAND; - -typedef enum { - RTT_ATTRIBUTE_TARGET_CNT = 0, - RTT_ATTRIBUTE_TARGET_INFO, - RTT_ATTRIBUTE_TARGET_MAC, - RTT_ATTRIBUTE_TARGET_TYPE, - RTT_ATTRIBUTE_TARGET_PEER, - RTT_ATTRIBUTE_TARGET_CHAN, - RTT_ATTRIBUTE_TARGET_PERIOD, - RTT_ATTRIBUTE_TARGET_NUM_BURST, - RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST, - RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM, - RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR, - RTT_ATTRIBUTE_TARGET_LCI, - RTT_ATTRIBUTE_TARGET_LCR, - RTT_ATTRIBUTE_TARGET_BURST_DURATION, - RTT_ATTRIBUTE_TARGET_PREAMBLE, - RTT_ATTRIBUTE_TARGET_BW, - RTT_ATTRIBUTE_RESULTS_COMPLETE = 30, - RTT_ATTRIBUTE_RESULTS_PER_TARGET, - RTT_ATTRIBUTE_RESULT_CNT, - RTT_ATTRIBUTE_RESULT -} RTT_ATTRIBUTE; -typedef struct strmap_entry { - int id; - String8 text; -} strmap_entry_t; -struct dot11_rm_ie { - u8 id; - u8 len; - u8 token; - u8 mode; - u8 type; -} __attribute__ ((packed)); -typedef struct dot11_rm_ie dot11_rm_ie_t; -#define DOT11_HDR_LEN 2 -#define DOT11_RM_IE_LEN 5 -#define DOT11_MNG_MEASURE_REQUEST_ID 38 /* 11H MeasurementRequest */ -#define DOT11_MEASURE_TYPE_LCI 8 /* d11 measurement LCI type */ -#define DOT11_MEASURE_TYPE_CIVICLOC 11 /* d11 measurement location civic */ - -static const strmap_entry_t err_info[] = { - {RTT_STATUS_SUCCESS, String8("Success")}, - {RTT_STATUS_FAILURE, String8("Failure")}, - {RTT_STATUS_FAIL_NO_RSP, String8("No reponse")}, - {RTT_STATUS_FAIL_INVALID_TS, String8("Invalid Timestamp")}, - {RTT_STATUS_FAIL_PROTOCOL, String8("Protocol error")}, - {RTT_STATUS_FAIL_REJECTED, String8("Rejected")}, - {RTT_STATUS_FAIL_NOT_SCHEDULED_YET, String8("not scheduled")}, - {RTT_STATUS_FAIL_SCHEDULE, String8("schedule failed")}, - {RTT_STATUS_FAIL_TM_TIMEOUT, String8("timeout")}, - {RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL, String8("AP is on difference channel")}, - {RTT_STATUS_FAIL_NO_CAPABILITY, String8("no capability")}, - {RTT_STATUS_FAIL_BUSY_TRY_LATER, String8("busy and try later")}, - {RTT_STATUS_ABORTED, String8("aborted")} -}; - - static const char* -get_err_info(int status) -{ - int i; - const strmap_entry_t *p_entry; - int num_entries = sizeof(err_info)/ sizeof(err_info[0]); - /* scan thru the table till end */ - p_entry = err_info; - for (i = 0; i < (int) num_entries; i++) - { - if (p_entry->id == status) - return p_entry->text; - p_entry++; /* next entry */ - } - return "unknown error"; /* not found */ -} - -class GetRttCapabilitiesCommand : public WifiCommand -{ - wifi_rtt_capabilities *mCapabilities; -public: - GetRttCapabilitiesCommand(wifi_interface_handle iface, wifi_rtt_capabilities *capabitlites) - : WifiCommand("GetRttCapabilitiesCommand", iface, 0), mCapabilities(capabitlites) - { - memset(mCapabilities, 0, sizeof(*mCapabilities)); - } - - virtual int create() { - ALOGD("Creating message to get scan capablities; iface = %d", mIfaceInfo->id); - - int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_GETCAPABILITY); - if (ret < 0) { - return ret; - } - - return ret; - } - -protected: - virtual int handleResponse(WifiEvent& reply) { - - ALOGD("In GetRttCapabilitiesCommand::handleResponse"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - int id = reply.get_vendor_id(); - int subcmd = reply.get_vendor_subcmd(); - - void *data = reply.get_vendor_data(); - int len = reply.get_vendor_data_len(); - - ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len, - sizeof(*mCapabilities)); - - memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities))); - - return NL_OK; - } -}; - - -class GetRttResponderInfoCommand : public WifiCommand -{ - wifi_rtt_responder* mResponderInfo; -public: - GetRttResponderInfoCommand(wifi_interface_handle iface, wifi_rtt_responder *responderInfo) - : WifiCommand("GetRttResponderInfoCommand", iface, 0), mResponderInfo(responderInfo) - { - memset(mResponderInfo, 0 , sizeof(*mResponderInfo)); - - } - - virtual int create() { - ALOGD("Creating message to get responder info ; iface = %d", mIfaceInfo->id); - - int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_GETAVAILCHANNEL); - if (ret < 0) { - return ret; - } - - return ret; - } - -protected: - virtual int handleResponse(WifiEvent& reply) { - - ALOGD("In GetRttResponderInfoCommand::handleResponse"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - int id = reply.get_vendor_id(); - int subcmd = reply.get_vendor_subcmd(); - - void *data = reply.get_vendor_data(); - int len = reply.get_vendor_data_len(); - - ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len, - sizeof(*mResponderInfo)); - - memcpy(mResponderInfo, data, min(len, (int) sizeof(*mResponderInfo))); - - return NL_OK; - } -}; - - -class EnableResponderCommand : public WifiCommand -{ - wifi_channel_info mChannelInfo; - wifi_rtt_responder* mResponderInfo; - unsigned m_max_duration_sec; -public: - EnableResponderCommand(wifi_interface_handle iface, int id, wifi_channel_info channel_hint, - unsigned max_duration_seconds, wifi_rtt_responder *responderInfo) - : WifiCommand("EnableResponderCommand", iface, 0), mChannelInfo(channel_hint), - m_max_duration_sec(max_duration_seconds), mResponderInfo(responderInfo) - { - memset(mResponderInfo, 0, sizeof(*mResponderInfo)); - } - - virtual int create() { - ALOGD("Creating message to set responder ; iface = %d", mIfaceInfo->id); - - int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_SET_RESPONDER); - if (ret < 0) { - return ret; - } - - return ret; - } - -protected: - virtual int handleResponse(WifiEvent& reply) { - - ALOGD("In EnableResponderCommand::handleResponse"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - int id = reply.get_vendor_id(); - int subcmd = reply.get_vendor_subcmd(); - - void *data = reply.get_vendor_data(); - int len = reply.get_vendor_data_len(); - - ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len, - sizeof(*mResponderInfo)); - - memcpy(mResponderInfo, data, min(len, (int) sizeof(*mResponderInfo))); - - return NL_OK; - } -}; - - -class CancelResponderCommand : public WifiCommand -{ - -public: - CancelResponderCommand(wifi_interface_handle iface, int id) - : WifiCommand("CancelResponderCommand", iface, 0)/*, mChannelInfo(channel)*/ - { - - } - - virtual int create() { - ALOGD("Creating message to cancel responder ; iface = %d", mIfaceInfo->id); - - int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_CANCEL_RESPONDER); - if (ret < 0) { - return ret; - } - - return ret; - } - -protected: - virtual int handleResponse(WifiEvent& reply) { - /* Nothing to do on response! */ - return NL_SKIP; - } - -}; - - -class RttCommand : public WifiCommand -{ - unsigned numRttParams; - int mCompleted; - int currentIdx; - int totalCnt; - static const int MAX_RESULTS = 1024; - wifi_rtt_result *rttResults[MAX_RESULTS]; - wifi_rtt_config *rttParams; - wifi_rtt_event_handler rttHandler; -public: - RttCommand(wifi_interface_handle iface, int id, unsigned num_rtt_config, - wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler) - : WifiCommand("RttCommand", iface, id), numRttParams(num_rtt_config), rttParams(rtt_config), - rttHandler(handler) - { - memset(rttResults, 0, sizeof(rttResults)); - currentIdx = 0; - mCompleted = 0; - totalCnt = 0; - } - - RttCommand(wifi_interface_handle iface, int id) - : WifiCommand("RttCommand", iface, id) - { - currentIdx = 0; - mCompleted = 0; - totalCnt = 0; - numRttParams = 0; - } - - int createSetupRequest(WifiRequest& request) { - int result = request.create(GOOGLE_OUI, RTT_SUBCMD_SET_CONFIG); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, numRttParams); - if (result < 0) { - return result; - } - nlattr *rtt_config = request.attr_start(RTT_ATTRIBUTE_TARGET_INFO); - for (unsigned i = 0; i < numRttParams; i++) { - nlattr *attr2 = request.attr_start(i); - if (attr2 == NULL) { - return WIFI_ERROR_OUT_OF_MEMORY; - } - - result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, rttParams[i].addr); - if (result < 0) { - return result; - } - - result = request.put_u8(RTT_ATTRIBUTE_TARGET_TYPE, rttParams[i].type); - if (result < 0) { - return result; - } - - result = request.put_u8(RTT_ATTRIBUTE_TARGET_PEER, rttParams[i].peer); - if (result < 0) { - return result; - } - - result = request.put(RTT_ATTRIBUTE_TARGET_CHAN, &rttParams[i].channel, - sizeof(wifi_channel_info)); - if (result < 0) { - return result; - } - - result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_BURST, rttParams[i].num_burst); - if (result < 0) { - return result; - } - - result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST, - rttParams[i].num_frames_per_burst); - if (result < 0) { - return result; - } - - result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM, - rttParams[i].num_retries_per_rtt_frame); - if (result < 0) { - return result; - } - - result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR, - rttParams[i].num_retries_per_ftmr); - if (result < 0) { - return result; - } - - result = request.put_u32(RTT_ATTRIBUTE_TARGET_PERIOD, - rttParams[i].burst_period); - if (result < 0) { - return result; - } - - result = request.put_u32(RTT_ATTRIBUTE_TARGET_BURST_DURATION, - rttParams[i].burst_duration); - if (result < 0) { - return result; - } - - result = request.put_u8(RTT_ATTRIBUTE_TARGET_LCI, - rttParams[i].LCI_request); - if (result < 0) { - return result; - } - - result = request.put_u8(RTT_ATTRIBUTE_TARGET_LCR, - rttParams[i].LCR_request); - if (result < 0) { - return result; - } - - result = request.put_u8(RTT_ATTRIBUTE_TARGET_BW, - rttParams[i].bw); - if (result < 0) { - return result; - } - - result = request.put_u8(RTT_ATTRIBUTE_TARGET_PREAMBLE, - rttParams[i].preamble); - if (result < 0) { - return result; - } - request.attr_end(attr2); - } - - request.attr_end(rtt_config); - request.attr_end(data); - return WIFI_SUCCESS; - } - - int createTeardownRequest(WifiRequest& request, unsigned num_devices, mac_addr addr[]) { - int result = request.create(GOOGLE_OUI, RTT_SUBCMD_CANCEL_CONFIG); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, num_devices); - for(unsigned i = 0; i < num_devices; i++) { - result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, addr[i]); - if (result < 0) { - return result; - } - } - request.attr_end(data); - return result; - } - int start() { - ALOGD("Setting RTT configuration"); - WifiRequest request(familyId(), ifaceId()); - int result = createSetupRequest(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to create setup request; result = %d", result); - return result; - } - - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to configure RTT setup; result = %d", result); - return result; - } - - registerVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); - ALOGI("Successfully started RTT operation"); - return result; - } - - virtual int cancel() { - ALOGD("Stopping RTT"); - - WifiRequest request(familyId(), ifaceId()); - int result = createTeardownRequest(request, 0, NULL); - if (result != WIFI_SUCCESS) { - ALOGE("failed to create stop request; result = %d", result); - } else { - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to stop scan; result = %d", result); - } - } - - unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); - return WIFI_SUCCESS; - } - - int cancel_specific(unsigned num_devices, mac_addr addr[]) { - ALOGE("Stopping RTT"); - - WifiRequest request(familyId(), ifaceId()); - int result = createTeardownRequest(request, num_devices, addr); - if (result != WIFI_SUCCESS) { - ALOGE("failed to create stop request; result = %d", result); - } else { - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to stop RTT; result = %d", result); - } - } - - unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); - return WIFI_SUCCESS; - } - - virtual int handleResponse(WifiEvent& reply) { - /* Nothing to do on response! */ - return NL_SKIP; - } - - virtual int handleEvent(WifiEvent& event) { - ALOGI("Got an RTT event"); - nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = event.get_vendor_data_len(); - if (vendor_data == NULL || len == 0) { - ALOGI("No rtt results found"); - } - for (nl_iterator it(vendor_data); it.has_next(); it.next()) { - if (it.get_type() == RTT_ATTRIBUTE_RESULTS_COMPLETE) { - mCompleted = it.get_u32(); - ALOGI("retrieved completed flag : %d\n", mCompleted); - } else if (it.get_type() == RTT_ATTRIBUTE_RESULTS_PER_TARGET) { - int result_cnt = 0; - mac_addr bssid; - for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) { - if (it2.get_type() == RTT_ATTRIBUTE_TARGET_MAC) { - memcpy(bssid, it2.get_data(), sizeof(mac_addr)); - ALOGI("retrived target mac : %02x:%02x:%02x:%02x:%02x:%02x\n", - bssid[0], - bssid[1], - bssid[2], - bssid[3], - bssid[4], - bssid[5]); - } else if (it2.get_type() == RTT_ATTRIBUTE_RESULT_CNT) { - result_cnt = it2.get_u32(); - ALOGI("retrieved result_cnt : %d\n", result_cnt); - } else if (it2.get_type() == RTT_ATTRIBUTE_RESULT) { - int result_len = it2.get_len(); - rttResults[currentIdx] = (wifi_rtt_result *)malloc(it2.get_len()); - wifi_rtt_result *rtt_result = rttResults[currentIdx]; - if (rtt_result == NULL) { - mCompleted = 1; - ALOGE("failed to allocate the wifi_rtt_result\n"); - break; - } - memcpy(rtt_result, it2.get_data(), it2.get_len()); - result_len -= sizeof(wifi_rtt_result); - if (result_len > 0) { - result_len -= sizeof(wifi_rtt_result); - dot11_rm_ie_t *ele_1; - dot11_rm_ie_t *ele_2; - /* The result has LCI or LCR element */ - ele_1 = (dot11_rm_ie_t *)(rtt_result + 1); - if (ele_1->id == DOT11_MNG_MEASURE_REQUEST_ID) { - if (ele_1->type == DOT11_MEASURE_TYPE_LCI) { - rtt_result->LCI = (wifi_information_element *)ele_1; - result_len -= (ele_1->len + DOT11_HDR_LEN); - /* get a next rm ie */ - if (result_len > 0) { - ele_2 = (dot11_rm_ie_t *)((char *)ele_1 + (ele_1->len + DOT11_HDR_LEN)); - if ((ele_2->id == DOT11_MNG_MEASURE_REQUEST_ID) && - (ele_2->type == DOT11_MEASURE_TYPE_CIVICLOC)) { - rtt_result->LCR = (wifi_information_element *)ele_2; - } - } - } else if (ele_1->type == DOT11_MEASURE_TYPE_CIVICLOC){ - rtt_result->LCR = (wifi_information_element *)ele_1; - result_len -= (ele_1->len + DOT11_HDR_LEN); - /* get a next rm ie */ - if (result_len > 0) { - ele_2 = (dot11_rm_ie_t *)((char *)ele_1 + (ele_1->len + DOT11_HDR_LEN)); - if ((ele_2->id == DOT11_MNG_MEASURE_REQUEST_ID) && - (ele_2->type == DOT11_MEASURE_TYPE_LCI)) { - rtt_result->LCI = (wifi_information_element *)ele_2; - } - } - } - } - } - totalCnt++; - ALOGI("retrived rtt_result : \n\tburst_num :%d, measurement_number : %d, success_number : %d\n" - "\tnumber_per_burst_peer : %d, status : %s, retry_after_duration : %d s\n" - "\trssi : %d dbm, rx_rate : %d Kbps, rtt : %llu ns, rtt_sd : %llu\n" - "\tdistance : %d, burst_duration : %d ms, negotiated_burst_num : %d\n", - rtt_result->burst_num, rtt_result->measurement_number, - rtt_result->success_number, rtt_result->number_per_burst_peer, - get_err_info(rtt_result->status), rtt_result->retry_after_duration, - rtt_result->rssi, rtt_result->rx_rate.bitrate * 100, - rtt_result->rtt/10, rtt_result->rtt_sd, rtt_result->distance_mm / 10, - rtt_result->burst_duration, rtt_result->negotiated_burst_num); - currentIdx++; - } - } - } - - } - if (mCompleted) { - unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); - (*rttHandler.on_rtt_results)(id(), totalCnt, rttResults); - for (int i = 0; i < currentIdx; i++) { - free(rttResults[i]); - rttResults[i] = NULL; - } - totalCnt = currentIdx = 0; - WifiCommand *cmd = wifi_unregister_cmd(wifiHandle(), id()); - if (cmd) - cmd->releaseRef(); - } - return NL_SKIP; - } -}; - - -/* API to request RTT measurement */ -wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle iface, - unsigned num_rtt_config, wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler) -{ - wifi_handle handle = getWifiHandle(iface); - RttCommand *cmd = new RttCommand(iface, id, num_rtt_config, rtt_config, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = wifi_register_cmd(handle, id, cmd); - if (result != WIFI_SUCCESS) { - cmd->releaseRef(); - return result; - } - result = (wifi_error)cmd->start(); - if (result != WIFI_SUCCESS) { - wifi_unregister_cmd(handle, id); - cmd->releaseRef(); - return result; - } - return result; -} - -/* API to cancel RTT measurements */ -wifi_error wifi_rtt_range_cancel(wifi_request_id id, wifi_interface_handle iface, - unsigned num_devices, mac_addr addr[]) -{ - wifi_handle handle = getWifiHandle(iface); - RttCommand *cmd = new RttCommand(iface, id); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - cmd->cancel_specific(num_devices, addr); - cmd->releaseRef(); - return WIFI_SUCCESS; -} - -/* API to get RTT capability */ -wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface, - wifi_rtt_capabilities *capabilities) -{ - GetRttCapabilitiesCommand command(iface, capabilities); - return (wifi_error) command.requestResponse(); -} - -/* API to get the responder information */ -wifi_error wifi_rtt_get_responder_info(wifi_interface_handle iface, - wifi_rtt_responder* responderInfo) -{ - GetRttResponderInfoCommand command(iface, responderInfo); - return (wifi_error) command.requestResponse(); - -} - -/** - * Enable RTT responder mode. - * channel_hint - hint of the channel information where RTT responder should be enabled on. - * max_duration_seconds - timeout of responder mode. - * wifi_rtt_responder - information for RTT responder e.g. channel used and preamble supported. - */ -wifi_error wifi_enable_responder(wifi_request_id id, wifi_interface_handle iface, - wifi_channel_info channel_hint, unsigned max_duration_seconds, - wifi_rtt_responder* responderInfo) -{ - EnableResponderCommand command(iface, id, channel_hint, max_duration_seconds, responderInfo); - return (wifi_error) command.requestResponse(); -} - -/** - * Disable RTT responder mode. - */ -wifi_error wifi_disable_responder(wifi_request_id id, wifi_interface_handle iface) -{ - CancelResponderCommand command(iface, id); - return (wifi_error) command.requestResponse(); -} - diff --git a/wlan/wifi_hal/rtw_wifi_gscan.cpp b/wlan/wifi_hal/rtw_wifi_gscan.cpp new file mode 100644 index 0000000..10b588a --- /dev/null +++ b/wlan/wifi_hal/rtw_wifi_gscan.cpp @@ -0,0 +1,1856 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "sync.h" + +#define LOG_TAG "WifiHAL" +//#define LOG_NDEBUG 0 //uncomment to enable verbose logging + +#include + +#include "wifi_hal.h" +#include "common.h" +#include "cpp_bindings.h" + +typedef enum { + + GSCAN_ATTRIBUTE_NUM_BUCKETS = 10, + GSCAN_ATTRIBUTE_BASE_PERIOD, + GSCAN_ATTRIBUTE_BUCKETS_BAND, + GSCAN_ATTRIBUTE_BUCKET_ID, + GSCAN_ATTRIBUTE_BUCKET_PERIOD, + GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS, + GSCAN_ATTRIBUTE_BUCKET_CHANNELS, + GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, + GSCAN_ATTRIBUTE_REPORT_THRESHOLD, + GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, + GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND, + + GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20, + GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, /* indicates no more results */ + GSCAN_ATTRIBUTE_FLUSH_FEATURE, /* Flush all the configs */ + GSCAN_ENABLE_FULL_SCAN_RESULTS, + GSCAN_ATTRIBUTE_REPORT_EVENTS, + + /* remaining reserved for additional attributes */ + GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30, + GSCAN_ATTRIBUTE_FLUSH_RESULTS, + GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */ + GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */ + GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */ + GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */ + GSCAN_ATTRIBUTE_NUM_CHANNELS, + GSCAN_ATTRIBUTE_CHANNEL_LIST, + GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK, + /* remaining reserved for additional attributes */ + + GSCAN_ATTRIBUTE_SSID = 40, + GSCAN_ATTRIBUTE_BSSID, + GSCAN_ATTRIBUTE_CHANNEL, + GSCAN_ATTRIBUTE_RSSI, + GSCAN_ATTRIBUTE_TIMESTAMP, + GSCAN_ATTRIBUTE_RTT, + GSCAN_ATTRIBUTE_RTTSD, + + /* remaining reserved for additional attributes */ + + GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50, + GSCAN_ATTRIBUTE_RSSI_LOW, + GSCAN_ATTRIBUTE_RSSI_HIGH, + GSCAN_ATTRIBUTE_HOTLIST_ELEM, + GSCAN_ATTRIBUTE_HOTLIST_FLUSH, + GSCAN_ATTRIBUTE_HOTLIST_BSSID_COUNT, + + /* remaining reserved for additional attributes */ + GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60, + GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, + GSCAN_ATTRIBUTE_MIN_BREACHING, + GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS, + GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, + + /* EPNO */ + GSCAN_ATTRIBUTE_EPNO_SSID_LIST = 70, + GSCAN_ATTRIBUTE_EPNO_SSID, + GSCAN_ATTRIBUTE_EPNO_SSID_LEN, + GSCAN_ATTRIBUTE_EPNO_RSSI, + GSCAN_ATTRIBUTE_EPNO_FLAGS, + GSCAN_ATTRIBUTE_EPNO_AUTH, + GSCAN_ATTRIBUTE_EPNO_SSID_NUM, + GSCAN_ATTRIBUTE_EPNO_FLUSH, + + /* remaining reserved for additional attributes */ + + GSCAN_ATTRIBUTE_WHITELIST_SSID = 80, + GSCAN_ATTRIBUTE_NUM_WL_SSID, + GSCAN_ATTRIBUTE_WL_SSID_LEN, + GSCAN_ATTRIBUTE_WL_SSID_FLUSH, + GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM, + GSCAN_ATTRIBUTE_NUM_BSSID, + GSCAN_ATTRIBUTE_BSSID_PREF_LIST, + GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH, + GSCAN_ATTRIBUTE_BSSID_PREF, + GSCAN_ATTRIBUTE_RSSI_MODIFIER, + + /* remaining reserved for additional attributes */ + + GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD = 90, + GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD, + GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR, + GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR, + GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST, + GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS, + GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER, + GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE, + + /* BSSID blacklist */ + GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH = 100, + GSCAN_ATTRIBUTE_BLACKLIST_BSSID, + + /* ANQPO */ + GSCAN_ATTRIBUTE_ANQPO_HS_LIST = 110, + GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE, + GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID, + GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM, + GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID, + GSCAN_ATTRIBUTE_ANQPO_HS_PLMN, + + /* Adaptive scan attributes */ + GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT = 120, + GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD, + + /* ePNO cfg */ + GSCAN_ATTRIBUTE_EPNO_5G_RSSI_THR = 130, + GSCAN_ATTRIBUTE_EPNO_2G_RSSI_THR, + GSCAN_ATTRIBUTE_EPNO_INIT_SCORE_MAX, + GSCAN_ATTRIBUTE_EPNO_CUR_CONN_BONUS, + GSCAN_ATTRIBUTE_EPNO_SAME_NETWORK_BONUS, + GSCAN_ATTRIBUTE_EPNO_SECURE_BONUS, + GSCAN_ATTRIBUTE_EPNO_5G_BONUS, + + GSCAN_ATTRIBUTE_MAX + +} GSCAN_ATTRIBUTE; + + +// helper methods +wifi_error wifi_enable_full_scan_results(wifi_request_id id, wifi_interface_handle iface, + wifi_scan_result_handler handler); +wifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface); +int wifi_handle_full_scan_event(wifi_request_id id, WifiEvent& event, + wifi_scan_result_handler handler); +void convert_to_hal_result(wifi_scan_result *to, wifi_gscan_result_t *from); + + +void convert_to_hal_result(wifi_scan_result *to, wifi_gscan_result_t *from) +{ + to->ts = from->ts; + to->channel = from->channel; + to->rssi = from->rssi; + to->rtt = from->rtt; + to->rtt_sd = from->rtt_sd; + to->beacon_period = from->beacon_period; + to->capability = from->capability; + memcpy(to->ssid, from->ssid, (DOT11_MAX_SSID_LEN+1)); + memcpy(&to->bssid, &from->bssid, sizeof(mac_addr)); +} + +///////////////////////////////////////////////////////////////////////////// + +class GetCapabilitiesCommand : public WifiCommand +{ + wifi_gscan_capabilities *mCapabilities; +public: + GetCapabilitiesCommand(wifi_interface_handle iface, wifi_gscan_capabilities *capabitlites) + : WifiCommand("GetGscanCapabilitiesCommand", iface, 0), mCapabilities(capabitlites) + { + memset(mCapabilities, 0, sizeof(*mCapabilities)); + } + + virtual int create() { + ALOGV("Creating message to get scan capablities; iface = %d", mIfaceInfo->id); + + int ret = mMsg.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_CAPABILITIES); + if (ret < 0) { + return ret; + } + + return ret; + } + +protected: + virtual int handleResponse(WifiEvent& reply) { + + ALOGV("In GetCapabilities::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + int id = reply.get_vendor_id(); + int subcmd = reply.get_vendor_subcmd(); + + void *data = reply.get_vendor_data(); + int len = reply.get_vendor_data_len(); + + ALOGV("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len, + sizeof(*mCapabilities)); + + memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities))); + + return NL_OK; + } +}; + + +wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle, + wifi_gscan_capabilities *capabilities) +{ + GetCapabilitiesCommand command(handle, capabilities); + return (wifi_error) command.requestResponse(); +} + +class GetChannelListCommand : public WifiCommand +{ + wifi_channel *channels; + int max_channels; + int *num_channels; + int band; +public: + GetChannelListCommand(wifi_interface_handle iface, wifi_channel *channel_buf, int *ch_num, + int num_max_ch, int band) + : WifiCommand("GetChannelListCommand", iface, 0), channels(channel_buf), + max_channels(num_max_ch), num_channels(ch_num), band(band) + { + memset(channels, 0, sizeof(wifi_channel) * max_channels); + } + virtual int create() { + ALOGV("Creating message to get channel list; iface = %d", mIfaceInfo->id); + + int ret = mMsg.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_CHANNEL_LIST); + if (ret < 0) { + return ret; + } + + nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA); + ret = mMsg.put_u32(GSCAN_ATTRIBUTE_BAND, band); + if (ret < 0) { + return ret; + } + + mMsg.attr_end(data); + + return ret; + } + +protected: + virtual int handleResponse(WifiEvent& reply) { + + ALOGV("In GetChannelList::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + int id = reply.get_vendor_id(); + int subcmd = reply.get_vendor_subcmd(); + int num_channels_to_copy = 0; + + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + + ALOGV("Id = %0x, subcmd = %d, len = %d", id, subcmd, len); + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in GetChannelList response; ignoring it"); + return NL_SKIP; + } + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == GSCAN_ATTRIBUTE_NUM_CHANNELS) { + num_channels_to_copy = it.get_u32(); + ALOGI("Got channel list with %d channels", num_channels_to_copy); + if(num_channels_to_copy > max_channels) + num_channels_to_copy = max_channels; + *num_channels = num_channels_to_copy; + } else if (it.get_type() == GSCAN_ATTRIBUTE_CHANNEL_LIST && num_channels_to_copy) { + memcpy(channels, it.get_data(), sizeof(int) * num_channels_to_copy); + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + + return NL_OK; + } +}; + +wifi_error wifi_get_valid_channels(wifi_interface_handle handle, + int band, int max_channels, wifi_channel *channels, int *num_channels) +{ +#if 0 + GetChannelListCommand command(handle, channels, num_channels, + max_channels, band); + return (wifi_error) command.requestResponse(); +#endif + *num_channels = 12; + return WIFI_SUCCESS; +} +///////////////////////////////////////////////////////////////////////////// + +/* helper functions */ + +static int parseScanResults(wifi_scan_result *results, int num, nlattr *attr) +{ + memset(results, 0, sizeof(wifi_scan_result) * num); + + int i = 0; + for (nl_iterator it(attr); it.has_next() && i < num; it.next(), i++) { + + int index = it.get_type(); + ALOGI("retrieved scan result %d", index); + nlattr *sc_data = (nlattr *) it.get_data(); + wifi_scan_result *result = results + i; + + for (nl_iterator it2(sc_data); it2.has_next(); it2.next()) { + int type = it2.get_type(); + if (type == GSCAN_ATTRIBUTE_SSID) { + strncpy(result->ssid, (char *) it2.get_data(), it2.get_len()); + result->ssid[it2.get_len()] = 0; + } else if (type == GSCAN_ATTRIBUTE_BSSID) { + memcpy(result->bssid, (byte *) it2.get_data(), sizeof(mac_addr)); + } else if (type == GSCAN_ATTRIBUTE_TIMESTAMP) { + result->ts = it2.get_u64(); + } else if (type == GSCAN_ATTRIBUTE_CHANNEL) { + result->ts = it2.get_u16(); + } else if (type == GSCAN_ATTRIBUTE_RSSI) { + result->rssi = it2.get_u8(); + } else if (type == GSCAN_ATTRIBUTE_RTT) { + result->rtt = it2.get_u64(); + } else if (type == GSCAN_ATTRIBUTE_RTTSD) { + result->rtt_sd = it2.get_u64(); + } + } + + } + + if (i >= num) { + ALOGE("Got too many results; skipping some"); + } + + return i; +} + +int createFeatureRequest(WifiRequest& request, int subcmd, int enable) { + + int result = request.create(GOOGLE_OUI, subcmd); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(GSCAN_ATTRIBUTE_ENABLE_FEATURE, enable); + if (result < 0) { + return result; + } + + request.attr_end(data); + return WIFI_SUCCESS; +} + +///////////////////////////////////////////////////////////////////////////// +class FullScanResultsCommand : public WifiCommand +{ + int *mParams; + wifi_scan_result_handler mHandler; +public: + FullScanResultsCommand(wifi_interface_handle iface, int id, int *params, + wifi_scan_result_handler handler) + : WifiCommand("FullScanResultsCommand", iface, id), mParams(params), mHandler(handler) + { } + + int createRequest(WifiRequest& request, int subcmd, int enable) { + int result = request.create(GOOGLE_OUI, subcmd); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(GSCAN_ENABLE_FULL_SCAN_RESULTS, enable); + if (result < 0) { + return result; + } + + request.attr_end(data); + return WIFI_SUCCESS; + + } + + int start() { + ALOGV("Enabling Full scan results"); + WifiRequest request(familyId(), ifaceId()); + int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 1); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create request; result = %d", result); + return result; + } + + registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to enable full scan results; result = %d", result); + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); + return result; + } + + return result; + } + + virtual int cancel() { + ALOGV("Disabling Full scan results"); + + WifiRequest request(familyId(), ifaceId()); + int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 0); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create request; result = %d", result); + } else { + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to disable full scan results;result = %d", result); + } + } + + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); + return WIFI_SUCCESS; + } + + virtual int handleResponse(WifiEvent& reply) { + ALOGD("Request complete!"); + /* Nothing to do on response! */ + return NL_SKIP; + } + + virtual int handleEvent(WifiEvent& event) { + ALOGV("Full scan results: Got an event"); + return wifi_handle_full_scan_event(id(), event, mHandler); + } + +}; +///////////////////////////////////////////////////////////////////////////// + +class ScanCommand : public WifiCommand +{ + wifi_scan_cmd_params *mParams; + wifi_scan_result_handler mHandler; +public: + ScanCommand(wifi_interface_handle iface, int id, wifi_scan_cmd_params *params, + wifi_scan_result_handler handler) + : WifiCommand("ScanCommand", iface, id), mParams(params), mHandler(handler) + { } + + int createSetupRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_CONFIG); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(GSCAN_ATTRIBUTE_BASE_PERIOD, mParams->base_period); + if (result < 0) { + return result; + } + + result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BUCKETS, mParams->num_buckets); + if (result < 0) { + return result; + } + + for (int i = 0; i < mParams->num_buckets; i++) { + nlattr * bucket = request.attr_start(i); // next bucket + result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_ID, mParams->buckets[i].bucket); + if (result < 0) { + return result; + } + result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_PERIOD, mParams->buckets[i].period); + if (result < 0) { + return result; + } + result = request.put_u32(GSCAN_ATTRIBUTE_BUCKETS_BAND, + mParams->buckets[i].band); + if (result < 0) { + return result; + } + result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT, + mParams->buckets[i].step_count); + if (result < 0) { + return result; + } + result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD, + mParams->buckets[i].max_period); + if (result < 0) { + return result; + } + result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_EVENTS, + mParams->buckets[i].report_events); + if (result < 0) { + return result; + } + + result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS, + mParams->buckets[i].num_channels); + if (result < 0) { + return result; + } + + if (mParams->buckets[i].num_channels) { + nlattr *channels = request.attr_start(GSCAN_ATTRIBUTE_BUCKET_CHANNELS); + ALOGV(" channels: "); + for (int j = 0; j < mParams->buckets[i].num_channels; j++) { + result = request.put_u32(j, mParams->buckets[i].channels[j].channel); + ALOGV(" %u", mParams->buckets[i].channels[j].channel); + + if (result < 0) { + return result; + } + } + request.attr_end(channels); + } + + request.attr_end(bucket); + } + + request.attr_end(data); + return WIFI_SUCCESS; + } + + int createScanConfigRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SCAN_CONFIG); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, mParams->max_ap_per_scan); + if (result < 0) { + return result; + } + + result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD, + mParams->report_threshold_percent); + if (result < 0) { + return result; + } + + int num_scans = mParams->report_threshold_num_scans; + + result = request.put_u32(GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, num_scans); + if (result < 0) { + return result; + } + + request.attr_end(data); + return WIFI_SUCCESS; + } + + int createStartRequest(WifiRequest& request) { + return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); + } + + int createStopRequest(WifiRequest& request) { + return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 0); + } + + int start() { + ALOGV("GSCAN start"); + WifiRequest request(familyId(), ifaceId()); + int result = createSetupRequest(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create setup request; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to configure setup; result = %d", result); + return result; + } + + request.destroy(); + + result = createScanConfigRequest(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create scan config request; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to configure scan; result = %d", result); + return result; + } + + ALOGV(" ....starting scan"); + + result = createStartRequest(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create start request; result = %d", result); + return result; + } + + registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); + registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN); + registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to start scan; result = %d", result); + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN); + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); + return result; + } + return result; + } + + virtual int cancel() { + ALOGV("Stopping scan"); + + WifiRequest request(familyId(), ifaceId()); + int result = createStopRequest(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create stop request; result = %d", result); + } else { + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to stop scan; result = %d", result); + } + } + + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN); + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); + return WIFI_SUCCESS; + } + + virtual int handleResponse(WifiEvent& reply) { + /* Nothing to do on response! */ + return NL_SKIP; + } + + virtual int handleEvent(WifiEvent& event) { + ALOGV("Got a scan results event"); + //event.log(); + + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = event.get_vendor_data_len(); + int event_id = event.get_vendor_subcmd(); + + if ((event_id == GSCAN_EVENT_COMPLETE_SCAN) || + (event_id == GSCAN_EVENT_SCAN_RESULTS_AVAILABLE)) { + if (vendor_data == NULL || len != 4) { + ALOGI("Bad event data!"); + return NL_SKIP; + } + wifi_scan_event evt_type; + evt_type = (wifi_scan_event) event.get_u32(NL80211_ATTR_VENDOR_DATA); + ALOGV("Received event type %d", evt_type); + if(*mHandler.on_scan_event) + (*mHandler.on_scan_event)(id(), evt_type); + } else if (event_id == GSCAN_EVENT_FULL_SCAN_RESULTS) { + wifi_handle_full_scan_event(id(), event, mHandler); + } + return NL_SKIP; + } +}; + +wifi_error wifi_start_gscan( + wifi_request_id id, + wifi_interface_handle iface, + wifi_scan_cmd_params params, + wifi_scan_result_handler handler) +{ + wifi_handle handle = getWifiHandle(iface); + + ALOGV("Starting GScan, halHandle = %p", handle); + + ScanCommand *cmd = new ScanCommand(iface, id, ¶ms, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, id, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, id); + cmd->releaseRef(); + return result; + } + return result; +} + +wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface) +{ + wifi_handle handle = getWifiHandle(iface); + ALOGV("Stopping GScan, wifi_request_id = %d, halHandle = %p", id, handle); + + if (id == -1) { + wifi_scan_result_handler handler; + wifi_scan_cmd_params dummy_params; + wifi_handle handle = getWifiHandle(iface); + memset(&handler, 0, sizeof(handler)); + + ScanCommand *cmd = new ScanCommand(iface, id, &dummy_params, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + cmd->cancel(); + cmd->releaseRef(); + return WIFI_SUCCESS; + } + + return wifi_cancel_cmd(id, iface); +} + +wifi_error wifi_enable_full_scan_results( + wifi_request_id id, + wifi_interface_handle iface, + wifi_scan_result_handler handler) +{ + wifi_handle handle = getWifiHandle(iface); + int params_dummy; + + ALOGV("Enabling full scan results, halHandle = %p", handle); + + FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, id, ¶ms_dummy, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, id, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, id); + cmd->releaseRef(); + return result; + } + return result; +} + +int wifi_handle_full_scan_event( + wifi_request_id id, + WifiEvent& event, + wifi_scan_result_handler handler) +{ + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + unsigned int len = event.get_vendor_data_len(); + + if (vendor_data == NULL || len < sizeof(wifi_gscan_full_result_t)) { + ALOGI("Full scan results: No scan results found"); + return NL_SKIP; + } + + wifi_gscan_full_result_t *drv_res = (wifi_gscan_full_result_t *)event.get_vendor_data(); + /* To protect against corrupted data, put a ceiling */ + int ie_len = min(MAX_PROBE_RESP_IE_LEN, drv_res->ie_length); + wifi_scan_result *full_scan_result; + wifi_gscan_result_t *fixed = &drv_res->fixed; + + if ((ie_len + offsetof(wifi_gscan_full_result_t, ie_data)) > len) { + ALOGE("BAD event data, len %d ie_len %d fixed length %d!\n", len, + ie_len, offsetof(wifi_gscan_full_result_t, ie_data)); + return NL_SKIP; + } + full_scan_result = (wifi_scan_result *) malloc((ie_len + offsetof(wifi_scan_result, ie_data))); + if (!full_scan_result) { + ALOGE("Full scan results: Can't malloc!\n"); + return NL_SKIP; + } + convert_to_hal_result(full_scan_result, fixed); + full_scan_result->ie_length = ie_len; + memcpy(full_scan_result->ie_data, drv_res->ie_data, ie_len); + if(handler.on_full_scan_result) + handler.on_full_scan_result(id, full_scan_result, drv_res->scan_ch_bucket); + + ALOGV("Full scan result: %-32s %02x:%02x:%02x:%02x:%02x:%02x %d %d %lld %lld %lld %x %d\n", + fixed->ssid, fixed->bssid[0], fixed->bssid[1], fixed->bssid[2], fixed->bssid[3], + fixed->bssid[4], fixed->bssid[5], fixed->rssi, fixed->channel, fixed->ts, + fixed->rtt, fixed->rtt_sd, drv_res->scan_ch_bucket, drv_res->ie_length); + free(full_scan_result); + return NL_SKIP; +} + + +wifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface) +{ + ALOGV("Disabling full scan results"); + wifi_handle handle = getWifiHandle(iface); + + if(id == -1) { + wifi_scan_result_handler handler; + wifi_handle handle = getWifiHandle(iface); + int params_dummy; + + memset(&handler, 0, sizeof(handler)); + FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, 0, ¶ms_dummy, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + cmd->cancel(); + cmd->releaseRef(); + return WIFI_SUCCESS; + } + + return wifi_cancel_cmd(id, iface); +} + + +///////////////////////////////////////////////////////////////////////////// + +class GetScanResultsCommand : public WifiCommand { + wifi_cached_scan_results *mScans; + int mMax; + int *mNum; + int mRetrieved; + byte mFlush; + int mCompleted; +public: + GetScanResultsCommand(wifi_interface_handle iface, byte flush, + wifi_cached_scan_results *results, int max, int *num) + : WifiCommand("GetScanResultsCommand", iface, -1), mScans(results), mMax(max), mNum(num), + mRetrieved(0), mFlush(flush), mCompleted(0) + { } + + int createRequest(WifiRequest& request, int num, byte flush) { + int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_SCAN_RESULTS); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num); + if (result < 0) { + return result; + } + + result = request.put_u8(GSCAN_ATTRIBUTE_FLUSH_RESULTS, flush); + if (result < 0) { + return result; + } + + request.attr_end(data); + return WIFI_SUCCESS; + } + + int execute() { + WifiRequest request(familyId(), ifaceId()); + ALOGV("retrieving %d scan results", mMax); + + for (int i = 0; i < 10 && mRetrieved < mMax; i++) { + int num_to_retrieve = mMax - mRetrieved; + // ALOGI("retrieving %d scan results in one shot", num_to_retrieve); + int result = createRequest(request, num_to_retrieve, mFlush); + if (result < 0) { + ALOGE("failed to create request"); + return result; + } + + int prev_retrieved = mRetrieved; + + result = requestResponse(request); + + if (result != WIFI_SUCCESS) { + ALOGE("failed to retrieve scan results; result = %d", result); + return result; + } + + if (mRetrieved == prev_retrieved || mCompleted) { + /* no more items left to retrieve */ + break; + } + + request.destroy(); + } + + ALOGV("GetScanResults read %d results", mRetrieved); + *mNum = mRetrieved; + return WIFI_SUCCESS; + } + + virtual int handleResponse(WifiEvent& reply) { + ALOGV("In GetScanResultsCommand::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + int id = reply.get_vendor_id(); + int subcmd = reply.get_vendor_subcmd(); + + ALOGV("Id = %0x, subcmd = %d", id, subcmd); + + /* + if (subcmd != GSCAN_SUBCMD_SCAN_RESULTS) { + ALOGE("Invalid response to GetScanResultsCommand; ignoring it"); + return NL_SKIP; + } + */ + + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in GetScanResults response; ignoring it"); + return NL_SKIP; + } + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE) { + mCompleted = it.get_u8(); + ALOGV("retrieved mCompleted flag : %d", mCompleted); + } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS || it.get_type() == 0) { + int scan_id = 0, flags = 0, num = 0, scan_ch_bucket_mask = 0; + for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) { + if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_ID) { + scan_id = it2.get_u32(); + ALOGV("retrieved scan_id : 0x%0x", scan_id); + } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_FLAGS) { + flags = it2.get_u8(); + ALOGV("retrieved scan_flags : 0x%0x", flags); + } else if (it2.get_type() == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) { + num = it2.get_u32(); + ALOGV("retrieved num_results: %d", num); + } else if (it2.get_type() == GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK) { + scan_ch_bucket_mask = it2.get_u32(); + ALOGD("retrieved scan_ch_bucket_mask: %x", scan_ch_bucket_mask); + } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS && num) { + if (mRetrieved >= mMax) { + ALOGW("Stored %d scans, ignoring excess results", mRetrieved); + break; + } + num = min(num, (int)(it2.get_len()/sizeof(wifi_gscan_result))); + num = min(num, (int)MAX_AP_CACHE_PER_SCAN); + ALOGV("Copying %d scan results", num); + wifi_gscan_result_t *results = (wifi_gscan_result_t *)it2.get_data(); + wifi_scan_result *mScanResults = mScans[mRetrieved].results; + + for (int i = 0; i < num; i++) { + wifi_gscan_result_t *result = &results[i]; + convert_to_hal_result(&mScanResults[i], result); + mScanResults[i].ie_length = 0; + ALOGV("%02d %-32s %02x:%02x:%02x:%02x:%02x:%02x %04d", i, + result->ssid, result->bssid[0], result->bssid[1], result->bssid[2], + result->bssid[3], result->bssid[4], result->bssid[5], + result->rssi); + } + mScans[mRetrieved].scan_id = scan_id; + mScans[mRetrieved].flags = flags; + mScans[mRetrieved].num_results = num; + mScans[mRetrieved].buckets_scanned = scan_ch_bucket_mask; + ALOGV("Setting result of scan_id : 0x%0x", mScans[mRetrieved].scan_id); + mRetrieved++; + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + ALOGV("GetScanResults read %d results", mRetrieved); + return NL_OK; + } +}; + +wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush, + int max, wifi_cached_scan_results *results, int *num) { + ALOGV("Getting cached scan results, iface handle = %p, num = %d", iface, *num); + + GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, max, num); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error err = (wifi_error)cmd->execute(); + cmd->releaseRef(); + return err; +} + +///////////////////////////////////////////////////////////////////////////// + +class BssidHotlistCommand : public WifiCommand +{ +private: + wifi_bssid_hotlist_params mParams; + wifi_hotlist_ap_found_handler mHandler; + static const int MAX_RESULTS = 64; + wifi_scan_result mResults[MAX_RESULTS]; +public: + BssidHotlistCommand(wifi_interface_handle handle, int id, + wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler) + : WifiCommand("BssidHotlistCommand", handle, id), mParams(params), mHandler(handler) + { } + + int createSetupRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1); + if (result < 0) { + return result; + } + + result = request.put_u32(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size); + if (result < 0) { + return result; + } + + result = request.put_u32(GSCAN_ATTRIBUTE_HOTLIST_BSSID_COUNT, mParams.num_bssid); + if (result < 0) { + return result; + } + + struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS); + for (int i = 0; i < mParams.num_bssid; i++) { + nlattr *attr2 = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_ELEM); + if (attr2 == NULL) { + return WIFI_ERROR_OUT_OF_MEMORY; + } + result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid); + if (result < 0) { + return result; + } + result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high); + if (result < 0) { + return result; + } + result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low); + if (result < 0) { + return result; + } + request.attr_end(attr2); + } + + request.attr_end(attr); + request.attr_end(data); + return result; + } + + int createTeardownRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1); + if (result < 0) { + return result; + } + + struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS); + request.attr_end(attr); + request.attr_end(data); + return result; + } + + int start() { + ALOGI("Executing hotlist setup request, num = %d", mParams.num_bssid); + WifiRequest request(familyId(), ifaceId()); + int result = createSetupRequest(request); + if (result < 0) { + return result; + } + + result = requestResponse(request); + if (result < 0) { + ALOGI("Failed to execute hotlist setup request, result = %d", result); + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND); + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST); + return result; + } + + ALOGI("Successfully set %d APs in the hotlist ", mParams.num_bssid); + result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); + if (result < 0) { + return result; + } + + registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND); + registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST); + + result = requestResponse(request); + if (result < 0) { + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND); + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST); + return result; + } + + ALOGI("successfully restarted the scan"); + return result; + } + + virtual int cancel() { + /* unregister event handler */ + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND); + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST); + /* create set hotlist message with empty hotlist */ + WifiRequest request(familyId(), ifaceId()); + int result = createTeardownRequest(request); + if (result < 0) { + return result; + } + + result = requestResponse(request); + if (result < 0) { + return result; + } + + ALOGI("Successfully reset APs in current hotlist"); + return result; + } + + virtual int handleResponse(WifiEvent& reply) { + /* Nothing to do on response! */ + return NL_SKIP; + } + + virtual int handleEvent(WifiEvent& event) { + ALOGI("Hotlist AP event"); + int event_id = event.get_vendor_subcmd(); + // event.log(); + + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = event.get_vendor_data_len(); + + if (vendor_data == NULL || len == 0) { + ALOGI("No scan results found"); + return NL_SKIP; + } + + memset(mResults, 0, sizeof(wifi_scan_result) * MAX_RESULTS); + + int num = len / sizeof(wifi_gscan_result_t); + wifi_gscan_result_t *inp = (wifi_gscan_result_t *)event.get_vendor_data(); + num = min(MAX_RESULTS, num); + for (int i = 0; i < num; i++, inp++) { + convert_to_hal_result(&(mResults[i]), inp); + } + + if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_FOUND) { + ALOGI("FOUND %d hotlist APs", num); + if (*mHandler.on_hotlist_ap_found) + (*mHandler.on_hotlist_ap_found)(id(), num, mResults); + } else if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_LOST) { + ALOGI("LOST %d hotlist APs", num); + if (*mHandler.on_hotlist_ap_lost) + (*mHandler.on_hotlist_ap_lost)(id(), num, mResults); + } + return NL_SKIP; + } +}; + +class ePNOCommand : public WifiCommand +{ +private: + wifi_epno_params epno_params; + wifi_epno_handler mHandler; + wifi_scan_result mResults[MAX_EPNO_NETWORKS]; +public: + ePNOCommand(wifi_interface_handle handle, int id, + const wifi_epno_params *params, wifi_epno_handler handler) + : WifiCommand("ePNOCommand", handle, id), mHandler(handler) + { + if (params != NULL) { + memcpy(&epno_params, params, sizeof(wifi_epno_params)); + } else { + memset(&epno_params, 0, sizeof(wifi_epno_params)); + } + } + int createSetupRequest(WifiRequest& request) { + if (epno_params.num_networks > MAX_EPNO_NETWORKS) { + ALOGE("wrong epno num_networks:%d", epno_params.num_networks); + return WIFI_ERROR_INVALID_ARGS; + } + int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_EPNO_SSID); + if (result < 0) { + return result; + } + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_FLUSH, 1); + if (result < 0) { + return result; + } + + result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_5G_RSSI_THR, + (u8)epno_params.min5GHz_rssi); + if (result < 0) { + return result; + } + result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_2G_RSSI_THR, + (u8)epno_params.min24GHz_rssi); + if (result < 0) { + return result; + } + result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_INIT_SCORE_MAX, + epno_params.initial_score_max); + if (result < 0) { + return result; + } + result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_CUR_CONN_BONUS, + epno_params.current_connection_bonus); + if (result < 0) { + return result; + } + result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_SAME_NETWORK_BONUS, + epno_params.same_network_bonus); + if (result < 0) { + return result; + } + result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_SECURE_BONUS, + epno_params.secure_bonus); + if (result < 0) { + return result; + } + result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_5G_BONUS, + epno_params.band5GHz_bonus); + if (result < 0) { + return result; + } + result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_SSID_NUM, + epno_params.num_networks); + if (result < 0) { + return result; + } + struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_EPNO_SSID_LIST); + wifi_epno_network *ssid_list = epno_params.networks; + for (int i = 0; i < epno_params.num_networks; i++) { + nlattr *attr2 = request.attr_start(i); + if (attr2 == NULL) { + return WIFI_ERROR_OUT_OF_MEMORY; + } + result = request.put(GSCAN_ATTRIBUTE_EPNO_SSID, ssid_list[i].ssid, DOT11_MAX_SSID_LEN); + ALOGI("PNO network: SSID %s flags %x auth %x", ssid_list[i].ssid, + ssid_list[i].flags, + ssid_list[i].auth_bit_field); + if (result < 0) { + return result; + } + result = request.put_u32(GSCAN_ATTRIBUTE_EPNO_SSID_LEN, strlen(ssid_list[i].ssid)); + if (result < 0) { + return result; + } + result = request.put_u32(GSCAN_ATTRIBUTE_EPNO_FLAGS, ssid_list[i].flags); + if (result < 0) { + return result; + } + result = request.put_u32(GSCAN_ATTRIBUTE_EPNO_AUTH, ssid_list[i].auth_bit_field); + if (result < 0) { + return result; + } + request.attr_end(attr2); + } + request.attr_end(attr); + request.attr_end(data); + return result; + } + + int createTeardownRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_EPNO_SSID); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_FLUSH, 1); + if (result < 0) { + return result; + } + request.attr_end(data); + return result; + } + + int start() { + ALOGI("Executing ePNO setup request, num = %d", epno_params.num_networks); + WifiRequest request(familyId(), ifaceId()); + int result = createSetupRequest(request); + if (result < 0) { + return result; + } + + result = requestResponse(request); + if (result < 0) { + ALOGI("Failed to execute ePNO setup request, result = %d", result); + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT); + return result; + } + + ALOGI("Successfully set %d SSIDs for ePNO", epno_params.num_networks); + registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT); + ALOGI("successfully restarted the scan"); + return result; + } + + virtual int cancel() { + /* unregister event handler */ + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT); + /* create set hotlist message with empty hotlist */ + WifiRequest request(familyId(), ifaceId()); + int result = createTeardownRequest(request); + if (result < 0) { + return result; + } + + result = requestResponse(request); + if (result < 0) { + return result; + } + + ALOGI("Successfully reset APs in current hotlist"); + return result; + } + + virtual int handleResponse(WifiEvent& reply) { + /* Nothing to do on response! */ + return NL_SKIP; + } + + virtual int handleEvent(WifiEvent& event) { + ALOGI("ePNO event"); + int event_id = event.get_vendor_subcmd(); + // event.log(); + + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = event.get_vendor_data_len(); + + if (vendor_data == NULL || len == 0) { + ALOGI("No scan results found"); + return NL_SKIP; + } + + memset(mResults, 0, sizeof(wifi_scan_result) * MAX_EPNO_NETWORKS); + + unsigned int num = len / sizeof(wifi_pno_result_t); + unsigned int i; + num = min(MAX_EPNO_NETWORKS, num); + wifi_pno_result_t *res = (wifi_pno_result_t *) event.get_vendor_data(); + for (i = 0; i < num; i++) { + if (res[i].flags == PNO_SSID_FOUND) { + memcpy(mResults[i].ssid, res[i].ssid, res[i].ssid_len); + memcpy(mResults[i].bssid, res[i].bssid, sizeof(mac_addr)); + + mResults[i].ssid[res[i].ssid_len] = '\0'; + mResults[i].channel = res[i].channel; + mResults[i].rssi = res[i].rssi; + } + } + if (*mHandler.on_network_found) + (*mHandler.on_network_found)(id(), num, mResults); + return NL_SKIP; + } +}; + +wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface, + wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler) +{ + wifi_handle handle = getWifiHandle(iface); + + BssidHotlistCommand *cmd = new BssidHotlistCommand(iface, id, params, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, id, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, id); + cmd->releaseRef(); + return result; + } + return result; +} + +wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface) +{ + return wifi_cancel_cmd(id, iface); +} + + +///////////////////////////////////////////////////////////////////////////// + +class SignificantWifiChangeCommand : public WifiCommand +{ + typedef struct { + mac_addr bssid; // BSSID + wifi_channel channel; // channel frequency in MHz + int num_rssi; // number of rssi samples + wifi_rssi rssi[8]; // RSSI history in db + } wifi_significant_change_result_internal; + +private: + wifi_significant_change_params mParams; + wifi_significant_change_handler mHandler; + static const int MAX_RESULTS = 64; + wifi_significant_change_result_internal mResultsBuffer[MAX_RESULTS]; + wifi_significant_change_result *mResults[MAX_RESULTS]; +public: + SignificantWifiChangeCommand(wifi_interface_handle handle, int id, + wifi_significant_change_params params, wifi_significant_change_handler handler) + : WifiCommand("SignificantWifiChangeCommand", handle, id), mParams(params), + mHandler(handler) + { } + + int createSetupRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u8(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1); + if (result < 0) { + return result; + } + result = request.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE, mParams.rssi_sample_size); + if (result < 0) { + return result; + } + result = request.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size); + if (result < 0) { + return result; + } + result = request.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING, mParams.min_breaching); + if (result < 0) { + return result; + } + result = request.put_u16(GSCAN_ATTRIBUTE_NUM_BSSID, mParams.num_bssid); + if (result < 0) { + return result; + } + if (mParams.num_bssid != 0) { + nlattr* attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS); + if (attr == NULL) { + return WIFI_ERROR_OUT_OF_MEMORY; + } + + for (int i = 0; i < mParams.num_bssid; i++) { + nlattr* attr2 = request.attr_start(i); + if (attr2 == NULL) { + return WIFI_ERROR_OUT_OF_MEMORY; + } + result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid); + if (result < 0) { + return result; + } + result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high); + if (result < 0) { + return result; + } + result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low); + if (result < 0) { + return result; + } + request.attr_end(attr2); + } + + request.attr_end(attr); + } + request.attr_end(data); + + return result; + } + + int createTeardownRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u16(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1); + if (result < 0) { + return result; + } + + request.attr_end(data); + return result; + } + + int start() { + ALOGI("Set significant wifi change config"); + WifiRequest request(familyId(), ifaceId()); + + int result = createSetupRequest(request); + if (result < 0) { + return result; + } + + result = requestResponse(request); + if (result < 0) { + ALOGI("failed to set significant wifi change config %d", result); + return result; + } + + ALOGI("successfully set significant wifi change config"); + + result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); + if (result < 0) { + return result; + } + + registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); + + result = requestResponse(request); + if (result < 0) { + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); + return result; + } + + ALOGI("successfully restarted the scan"); + return result; + } + + virtual int cancel() { + /* unregister event handler */ + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); + + /* create set significant change monitor message with empty hotlist */ + WifiRequest request(familyId(), ifaceId()); + + int result = createTeardownRequest(request); + if (result < 0) { + return result; + } + + result = requestResponse(request); + if (result < 0) { + return result; + } + + ALOGI("successfully reset significant wifi change config"); + return result; + } + + virtual int handleResponse(WifiEvent& reply) { + /* Nothing to do on response! */ + return NL_SKIP; + } + + virtual int handleEvent(WifiEvent& event) { + ALOGV("Got a significant wifi change event"); + + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = event.get_vendor_data_len(); + + if (vendor_data == NULL || len == 0) { + ALOGI("No scan results found"); + return NL_SKIP; + } + + typedef struct { + uint16_t flags; + uint16_t channel; + mac_addr bssid; + s8 rssi_history[8]; + } ChangeInfo; + + int num = min(len / sizeof(ChangeInfo), MAX_RESULTS); + ChangeInfo *ci = (ChangeInfo *)event.get_vendor_data(); + + for (int i = 0; i < num; i++) { + memcpy(mResultsBuffer[i].bssid, ci[i].bssid, sizeof(mac_addr)); + mResultsBuffer[i].channel = ci[i].channel; + mResultsBuffer[i].num_rssi = 8; + for (int j = 0; j < mResultsBuffer[i].num_rssi; j++) + mResultsBuffer[i].rssi[j] = (int) ci[i].rssi_history[j]; + mResults[i] = reinterpret_cast(&(mResultsBuffer[i])); + } + + ALOGV("Retrieved %d scan results", num); + + if (num != 0) { + (*mHandler.on_significant_change)(id(), num, mResults); + } else { + ALOGW("No significant change reported"); + } + + return NL_SKIP; + } +}; + +wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface, + wifi_significant_change_params params, wifi_significant_change_handler handler) +{ + wifi_handle handle = getWifiHandle(iface); + + SignificantWifiChangeCommand *cmd = new SignificantWifiChangeCommand( + iface, id, params, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, id, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, id); + cmd->releaseRef(); + return result; + } + return result; +} + +wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface) +{ + return wifi_cancel_cmd(id, iface); +} + +wifi_error wifi_reset_epno_list(wifi_request_id id, wifi_interface_handle iface) +{ + if (id == -1) { + wifi_epno_handler handler; + wifi_handle handle = getWifiHandle(iface); + + memset(&handler, 0, sizeof(handler)); + ePNOCommand *cmd = new ePNOCommand(iface, id, NULL, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + cmd->cancel(); + cmd->releaseRef(); + return WIFI_SUCCESS; + } + return wifi_cancel_cmd(id, iface); +} + +wifi_error wifi_set_epno_list(wifi_request_id id, wifi_interface_handle iface, + const wifi_epno_params *params, wifi_epno_handler handler) +{ + wifi_handle handle = getWifiHandle(iface); + + ePNOCommand *cmd = new ePNOCommand(iface, id, params, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, id, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, id); + cmd->releaseRef(); + return result; + } + return result; +} + + +//////////////////////////////////////////////////////////////////////////////// + +class AnqpoConfigureCommand : public WifiCommand +{ + int num_hs; + wifi_passpoint_network *mNetworks; + wifi_passpoint_event_handler mHandler; + wifi_scan_result *mResult; +public: + AnqpoConfigureCommand(wifi_request_id id, wifi_interface_handle iface, + int num, wifi_passpoint_network *hs_list, wifi_passpoint_event_handler handler) + : WifiCommand("AnqpoConfigureCommand", iface, id), num_hs(num), mNetworks(hs_list), + mHandler(handler) + { + mResult = NULL; + } + + int createRequest(WifiRequest& request, int val) { + + int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_ANQPO_CONFIG); + result = request.put_u32(GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE, num_hs); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_ANQPO_HS_LIST); + for (int i = 0; i < num_hs; i++) { + nlattr *attr2 = request.attr_start(i); + if (attr2 == NULL) { + return WIFI_ERROR_OUT_OF_MEMORY; + } + result = request.put_u32(GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID, mNetworks[i].id); + if (result < 0) { + return result; + } + result = request.put(GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM, mNetworks[i].realm, 256); + if (result < 0) { + return result; + } + result = request.put(GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID, + mNetworks[i].roamingConsortiumIds, 128); + if (result < 0) { + return result; + } + result = request.put(GSCAN_ATTRIBUTE_ANQPO_HS_PLMN, mNetworks[i].plmn, 3); + if (result < 0) { + return result; + } + + request.attr_end(attr2); + } + + request.attr_end(attr); + request.attr_end(data); + + return WIFI_SUCCESS; + } + + int start() { + + WifiRequest request(familyId(), ifaceId()); + int result = createRequest(request, num_hs); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create request; result = %d", result); + return result; + } + + registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_ANQPO_HOTSPOT_MATCH); + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to set ANQPO networks; result = %d", result); + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_ANQPO_HOTSPOT_MATCH); + return result; + } + + return result; + } + + virtual int cancel() { + + WifiRequest request(familyId(), ifaceId()); + int result = createRequest(request, 0); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create request; result = %d", result); + } else { + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to reset ANQPO networks;result = %d", result); + } + } + + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_ANQPO_HOTSPOT_MATCH); + return WIFI_SUCCESS; + } + + virtual int handleResponse(WifiEvent& reply) { + ALOGD("Request complete!"); + /* Nothing to do on response! */ + return NL_SKIP; + } + + virtual int handleEvent(WifiEvent& event) { + typedef struct { + u16 channel; /* channel of GAS protocol */ + u8 dialog_token; /* GAS dialog token */ + u8 fragment_id; /* fragment id */ + u16 status_code; /* status code on GAS completion */ + u16 data_len; /* length of data to follow */ + u8 data[1]; /* variable length specified by data_len */ + } wifi_anqp_gas_resp; + + ALOGI("ANQPO hotspot matched event!"); + + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + unsigned int len = event.get_vendor_data_len(); + + if (vendor_data == NULL || len < sizeof(wifi_scan_result)) { + ALOGI("No scan results found"); + return NL_SKIP; + } + mResult = (wifi_scan_result *)malloc(sizeof(wifi_scan_result)); + if (!mResult) { + return NL_SKIP; + } + wifi_gscan_full_result_t *drv_res = (wifi_gscan_full_result_t *)event.get_vendor_data(); + wifi_gscan_result_t *fixed = &drv_res->fixed; + convert_to_hal_result(mResult, fixed); + + byte *anqp = (byte *)drv_res + offsetof(wifi_gscan_full_result_t, ie_data) + drv_res->ie_length; + wifi_anqp_gas_resp *gas = (wifi_anqp_gas_resp *)anqp; + int anqp_len = offsetof(wifi_anqp_gas_resp, data) + gas->data_len; + int networkId = *(int *)((byte *)anqp + anqp_len); + + ALOGI("%-32s\t", mResult->ssid); + + ALOGI("%02x:%02x:%02x:%02x:%02x:%02x ", mResult->bssid[0], mResult->bssid[1], + mResult->bssid[2], mResult->bssid[3], mResult->bssid[4], mResult->bssid[5]); + + ALOGI("%d\t", mResult->rssi); + ALOGI("%d\t", mResult->channel); + ALOGI("%lld\t", mResult->ts); + ALOGI("%lld\t", mResult->rtt); + ALOGI("%lld\n", mResult->rtt_sd); + + if(*mHandler.on_passpoint_network_found) + (*mHandler.on_passpoint_network_found)(id(), networkId, mResult, anqp_len, anqp); + free(mResult); + return NL_SKIP; + } +}; + +wifi_error wifi_set_passpoint_list(wifi_request_id id, wifi_interface_handle iface, int num, + wifi_passpoint_network *networks, wifi_passpoint_event_handler handler) +{ + wifi_handle handle = getWifiHandle(iface); + + AnqpoConfigureCommand *cmd = new AnqpoConfigureCommand(id, iface, num, networks, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, id, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, id); + cmd->releaseRef(); + return result; + } + return result; +} + +wifi_error wifi_reset_passpoint_list(wifi_request_id id, wifi_interface_handle iface) +{ + return wifi_cancel_cmd(id, iface); +} diff --git a/wlan/wifi_hal/rtw_wifi_hal.cpp b/wlan/wifi_hal/rtw_wifi_hal.cpp new file mode 100644 index 0000000..c5d47eb --- /dev/null +++ b/wlan/wifi_hal/rtw_wifi_hal.cpp @@ -0,0 +1,1344 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "sync.h" + +#define LOG_TAG "WifiHAL" + +#include + +#include "version.h" +#include "wifi_hal.h" +#include "common.h" +#include "cpp_bindings.h" +#include "rtt.h" + +/* + BUGBUG: normally, libnl allocates ports for all connections it makes; but + being a static library, it doesn't really know how many other netlink connections + are made by the same process, if connections come from different shared libraries. + These port assignments exist to solve that problem - temporarily. We need to fix + libnl to try and allocate ports across the entire process. + */ + +#define WIFI_HAL_CMD_SOCK_PORT 644 +#define WIFI_HAL_EVENT_SOCK_PORT 645 + +static void internal_event_handler(wifi_handle handle, int events); +static int internal_no_seq_check(nl_msg *msg, void *arg); +static int internal_valid_message_handler(nl_msg *msg, void *arg); +static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group); +static int wifi_add_membership(wifi_handle handle, const char *group); +static wifi_error wifi_init_interfaces(wifi_handle handle); +static wifi_error wifi_start_rssi_monitoring(wifi_request_id id, wifi_interface_handle + iface, s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh); +static wifi_error wifi_stop_rssi_monitoring(wifi_request_id id, wifi_interface_handle iface); +static wifi_error wifi_set_packet_filter(wifi_interface_handle handle, + const u8 *program, u32 len); +static wifi_error wifi_get_packet_filter_capabilities(wifi_interface_handle handle, + u32 *version, u32 *max_len); +static wifi_error wifi_configure_nd_offload(wifi_interface_handle iface, u8 enable); +static wifi_error wifi_get_wake_reason_stats(wifi_interface_handle iface, + WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt); + +typedef enum wifi_attr { + ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, + ANDR_WIFI_ATTRIBUTE_FEATURE_SET, + ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI, + ANDR_WIFI_ATTRIBUTE_NODFS_SET, + ANDR_WIFI_ATTRIBUTE_COUNTRY, + ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE + // Add more attribute here +} wifi_attr_t; + +enum wifi_rssi_monitor_attr { + RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, + RSSI_MONITOR_ATTRIBUTE_MIN_RSSI, + RSSI_MONITOR_ATTRIBUTE_START, +}; + +enum wifi_apf_attr { + APF_ATTRIBUTE_VERSION, + APF_ATTRIBUTE_MAX_LEN, + APF_ATTRIBUTE_PROGRAM, + APF_ATTRIBUTE_PROGRAM_LEN +}; + +enum apf_request_type { + GET_APF_CAPABILITIES, + SET_APF_PROGRAM +}; + +/* Initialize/Cleanup */ + +void wifi_socket_set_local_port(struct nl_sock *sock, uint32_t port) +{ + uint32_t pid = getpid() & 0x3FFFFF; + nl_socket_set_local_port(sock, pid + (port << 22)); +} + +static nl_sock * wifi_create_nl_socket(int port) +{ + // ALOGI("Creating socket"); + struct nl_sock *sock = nl_socket_alloc(); + if (sock == NULL) { + ALOGE("Could not create handle"); + return NULL; + } + + wifi_socket_set_local_port(sock, port); + + struct sockaddr *addr = NULL; + // ALOGI("sizeof(sockaddr) = %d, sizeof(sockaddr_nl) = %d", sizeof(*addr), sizeof(*addr_nl)); + + // ALOGI("Connecting socket"); + if (nl_connect(sock, NETLINK_GENERIC)) { + ALOGE("Could not connect handle"); + nl_socket_free(sock); + return NULL; + } + + // ALOGI("Making socket nonblocking"); + /* + if (nl_socket_set_nonblocking(sock)) { + ALOGE("Could make socket non-blocking"); + nl_socket_free(sock); + return NULL; + } + */ + + return sock; +} + +/*initialize function pointer table with Realtek HAL API*/ +wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn *fn) +{ + if (fn == NULL) { + return WIFI_ERROR_UNKNOWN; + } + fn->wifi_initialize = wifi_initialize; + fn->wifi_cleanup = wifi_cleanup; + fn->wifi_event_loop = wifi_event_loop; + fn->wifi_get_supported_feature_set = wifi_get_supported_feature_set; + fn->wifi_get_concurrency_matrix = wifi_get_concurrency_matrix; + fn->wifi_set_scanning_mac_oui = wifi_set_scanning_mac_oui; + fn->wifi_get_ifaces = wifi_get_ifaces; + fn->wifi_get_iface_name = wifi_get_iface_name; + fn->wifi_start_gscan = wifi_start_gscan; + fn->wifi_stop_gscan = wifi_stop_gscan; + fn->wifi_get_cached_gscan_results = wifi_get_cached_gscan_results; + fn->wifi_set_bssid_hotlist = wifi_set_bssid_hotlist; + fn->wifi_reset_bssid_hotlist = wifi_reset_bssid_hotlist; + fn->wifi_set_significant_change_handler = wifi_set_significant_change_handler; + fn->wifi_reset_significant_change_handler = wifi_reset_significant_change_handler; + fn->wifi_get_gscan_capabilities = wifi_get_gscan_capabilities; + fn->wifi_get_link_stats = wifi_get_link_stats; + fn->wifi_set_link_stats = wifi_set_link_stats; + fn->wifi_clear_link_stats = wifi_clear_link_stats; + fn->wifi_get_valid_channels = wifi_get_valid_channels; + fn->wifi_rtt_range_request = wifi_rtt_range_request; + fn->wifi_rtt_range_cancel = wifi_rtt_range_cancel; + fn->wifi_get_rtt_capabilities = wifi_get_rtt_capabilities; + fn->wifi_rtt_get_responder_info = wifi_rtt_get_responder_info; + fn->wifi_enable_responder = wifi_enable_responder; + fn->wifi_disable_responder = wifi_disable_responder; + fn->wifi_set_nodfs_flag = wifi_set_nodfs_flag; + fn->wifi_start_logging = wifi_start_logging; + fn->wifi_set_epno_list = wifi_set_epno_list; + fn->wifi_reset_epno_list = wifi_reset_epno_list; + fn->wifi_set_country_code = wifi_set_country_code; + fn->wifi_get_firmware_memory_dump = wifi_get_firmware_memory_dump; + fn->wifi_set_log_handler = wifi_set_log_handler; + fn->wifi_reset_log_handler = wifi_reset_log_handler; + fn->wifi_set_alert_handler = wifi_set_alert_handler; + fn->wifi_reset_alert_handler = wifi_reset_alert_handler; + fn->wifi_get_firmware_version = wifi_get_firmware_version; + fn->wifi_get_ring_buffers_status = wifi_get_ring_buffers_status; + fn->wifi_get_logger_supported_feature_set = wifi_get_logger_supported_feature_set; + fn->wifi_get_ring_data = wifi_get_ring_data; + fn->wifi_get_driver_version = wifi_get_driver_version; + fn->wifi_start_rssi_monitoring = wifi_start_rssi_monitoring; + fn->wifi_stop_rssi_monitoring = wifi_stop_rssi_monitoring; + fn->wifi_configure_nd_offload = wifi_configure_nd_offload; + fn->wifi_start_sending_offloaded_packet = wifi_start_sending_offloaded_packet; + fn->wifi_stop_sending_offloaded_packet = wifi_stop_sending_offloaded_packet; + fn->wifi_start_pkt_fate_monitoring = wifi_start_pkt_fate_monitoring; + fn->wifi_get_tx_pkt_fates = wifi_get_tx_pkt_fates; + fn->wifi_get_rx_pkt_fates = wifi_get_rx_pkt_fates; + fn->wifi_get_packet_filter_capabilities = wifi_get_packet_filter_capabilities; + fn->wifi_set_packet_filter = wifi_set_packet_filter; + fn->wifi_get_wake_reason_stats = wifi_get_wake_reason_stats; + return WIFI_SUCCESS; +} + +wifi_error wifi_initialize(wifi_handle *handle) +{ + srand(getpid()); + + ALOGI("Initializing wifi, version : %s", RTW_WIFI_HAL_VERSION); + hal_info *info = (hal_info *)malloc(sizeof(hal_info)); + if (info == NULL) { + ALOGE("Could not allocate hal_info"); + return WIFI_ERROR_UNKNOWN; + } + + memset(info, 0, sizeof(*info)); + + ALOGI("Creating socket"); + if (socketpair(AF_UNIX, SOCK_STREAM, 0, info->cleanup_socks) == -1) { + ALOGE("Could not create cleanup sockets"); + free(info); + return WIFI_ERROR_UNKNOWN; + } + + struct nl_sock *cmd_sock = wifi_create_nl_socket(WIFI_HAL_CMD_SOCK_PORT); + if (cmd_sock == NULL) { + ALOGE("Could not create handle"); + free(info); + return WIFI_ERROR_UNKNOWN; + } + + struct nl_sock *event_sock = wifi_create_nl_socket(WIFI_HAL_EVENT_SOCK_PORT); + if (event_sock == NULL) { + ALOGE("Could not create handle"); + nl_socket_free(cmd_sock); + free(info); + return WIFI_ERROR_UNKNOWN; + } + + struct nl_cb *cb = nl_socket_get_cb(event_sock); + if (cb == NULL) { + ALOGE("Could not create handle"); + nl_socket_free(cmd_sock); + nl_socket_free(event_sock); + free(info); + return WIFI_ERROR_UNKNOWN; + } + + // ALOGI("cb->refcnt = %d", cb->cb_refcnt); + nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, internal_no_seq_check, info); + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, internal_valid_message_handler, info); + nl_cb_put(cb); + + info->cmd_sock = cmd_sock; + info->event_sock = event_sock; + info->clean_up = false; + info->in_event_loop = false; + + info->event_cb = (cb_info *)malloc(sizeof(cb_info) * DEFAULT_EVENT_CB_SIZE); + info->alloc_event_cb = DEFAULT_EVENT_CB_SIZE; + info->num_event_cb = 0; + + info->cmd = (cmd_info *)malloc(sizeof(cmd_info) * DEFAULT_CMD_SIZE); + info->alloc_cmd = DEFAULT_CMD_SIZE; + info->num_cmd = 0; + + info->nl80211_family_id = genl_ctrl_resolve(cmd_sock, "nl80211"); + if (info->nl80211_family_id < 0) { + ALOGE("Could not resolve nl80211 familty id"); + nl_socket_free(cmd_sock); + nl_socket_free(event_sock); + free(info); + return WIFI_ERROR_UNKNOWN; + } + + pthread_mutex_init(&info->cb_lock, NULL); + + *handle = (wifi_handle) info; + + if (wifi_init_interfaces(*handle) != WIFI_SUCCESS) { + ALOGE("No wifi interface found"); + nl_socket_free(cmd_sock); + nl_socket_free(event_sock); + pthread_mutex_destroy(&info->cb_lock); + free(info); + return WIFI_ERROR_NOT_AVAILABLE; + } + + if ((wifi_add_membership(*handle, "scan") < 0) || + (wifi_add_membership(*handle, "mlme") < 0) || + (wifi_add_membership(*handle, "regulatory") < 0) || + (wifi_add_membership(*handle, "vendor") < 0)) { + ALOGE("Add membership failed"); + nl_socket_free(cmd_sock); + nl_socket_free(event_sock); + pthread_mutex_destroy(&info->cb_lock); + free(info); + return WIFI_ERROR_NOT_AVAILABLE; + } + + // ALOGI("Found %d interfaces", info->num_interfaces); + + ALOGI("Initialized Wifi HAL Successfully; vendor cmd = %d", NL80211_CMD_VENDOR); + return WIFI_SUCCESS; +} + +static int wifi_add_membership(wifi_handle handle, const char *group) +{ + hal_info *info = getHalInfo(handle); + + int id = wifi_get_multicast_id(handle, "nl80211", group); + if (id < 0) { + ALOGE("Could not find group %s", group); + return id; + } + + int ret = nl_socket_add_membership(info->event_sock, id); + if (ret < 0) { + ALOGE("Could not add membership to group %s", group); + } + + // ALOGI("Successfully added membership for group %s", group); + return ret; +} + +static void internal_cleaned_up_handler(wifi_handle handle) +{ + hal_info *info = getHalInfo(handle); + wifi_cleaned_up_handler cleaned_up_handler = info->cleaned_up_handler; + + if (info->cmd_sock != 0) { + close(info->cleanup_socks[0]); + close(info->cleanup_socks[1]); + nl_socket_free(info->cmd_sock); + nl_socket_free(info->event_sock); + info->cmd_sock = NULL; + info->event_sock = NULL; + } + + (*cleaned_up_handler)(handle); + pthread_mutex_destroy(&info->cb_lock); + free(info); + + ALOGI("Internal cleanup completed"); +} + +void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler) +{ + hal_info *info = getHalInfo(handle); + char buf[64]; + + info->cleaned_up_handler = handler; + if (TEMP_FAILURE_RETRY(write(info->cleanup_socks[0], "Exit", 4)) < 1) { + // As a fallback set the cleanup flag to TRUE + ALOGE("could not write to the cleanup socket"); + } else { + // Listen to the response + // Hopefully we dont get errors or get hung up + // Not much can be done in that case, but assume that + // it has rx'ed the Exit message to exit the thread. + // As a fallback set the cleanup flag to TRUE + memset(buf, 0, sizeof(buf)); + ssize_t result = TEMP_FAILURE_RETRY(read(info->cleanup_socks[0], buf, sizeof(buf))); + ALOGE("%s: Read after POLL returned %zd, error no = %d (%s)", __FUNCTION__, + result, errno, strerror(errno)); + if (strncmp(buf, "Done", 4) == 0) { + ALOGE("Event processing terminated"); + } else { + ALOGD("Rx'ed %s", buf); + } + } + info->clean_up = true; + pthread_mutex_lock(&info->cb_lock); + + int bad_commands = 0; + + for (int i = 0; i < info->num_event_cb; i++) { + cb_info *cbi = &(info->event_cb[i]); + WifiCommand *cmd = (WifiCommand *)cbi->cb_arg; + ALOGI("Command left in event_cb %p:%s", cmd, (cmd ? cmd->getType(): "")); + } + + while (info->num_cmd > bad_commands) { + int num_cmd = info->num_cmd; + cmd_info *cmdi = &(info->cmd[bad_commands]); + WifiCommand *cmd = cmdi->cmd; + if (cmd != NULL) { + ALOGI("Cancelling command %p:%s", cmd, cmd->getType()); + pthread_mutex_unlock(&info->cb_lock); + cmd->cancel(); + pthread_mutex_lock(&info->cb_lock); + if (num_cmd == info->num_cmd) { + ALOGI("Cancelling command %p:%s did not work", cmd, (cmd ? cmd->getType(): "")); + bad_commands++; + } + /* release reference added when command is saved */ + cmd->releaseRef(); + } + } + + for (int i = 0; i < info->num_event_cb; i++) { + cb_info *cbi = &(info->event_cb[i]); + WifiCommand *cmd = (WifiCommand *)cbi->cb_arg; + ALOGE("Leaked command %p", cmd); + } + pthread_mutex_unlock(&info->cb_lock); + internal_cleaned_up_handler(handle); +} + +static int internal_pollin_handler(wifi_handle handle) +{ + hal_info *info = getHalInfo(handle); + struct nl_cb *cb = nl_socket_get_cb(info->event_sock); + int res = nl_recvmsgs(info->event_sock, cb); + // ALOGD("nl_recvmsgs returned %d", res); + nl_cb_put(cb); + return res; +} + +/* Run event handler */ +void wifi_event_loop(wifi_handle handle) +{ + hal_info *info = getHalInfo(handle); + if (info->in_event_loop) { + return; + } else { + info->in_event_loop = true; + } + + pollfd pfd[2]; + memset(&pfd[0], 0, sizeof(pollfd) * 2); + + pfd[0].fd = nl_socket_get_fd(info->event_sock); + pfd[0].events = POLLIN; + pfd[1].fd = info->cleanup_socks[1]; + pfd[1].events = POLLIN; + + char buf[2048]; + /* TODO: Add support for timeouts */ + + do { + int timeout = -1; /* Infinite timeout */ + pfd[0].revents = 0; + pfd[1].revents = 0; + // ALOGI("Polling socket"); + int result = TEMP_FAILURE_RETRY(poll(pfd, 2, timeout)); + if (result < 0) { + // ALOGE("Error polling socket"); + } else if (pfd[0].revents & POLLERR) { + ALOGE("POLL Error; error no = %d (%s)", errno, strerror(errno)); + ssize_t result2 = TEMP_FAILURE_RETRY(read(pfd[0].fd, buf, sizeof(buf))); + ALOGE("Read after POLL returned %zd, error no = %d (%s)", result2, + errno, strerror(errno)); + } else if (pfd[0].revents & POLLHUP) { + ALOGE("Remote side hung up"); + break; + } else if (pfd[0].revents & POLLIN) { + // ALOGI("Found some events!!!"); + internal_pollin_handler(handle); + } else if (pfd[1].revents & POLLIN) { + memset(buf, 0, sizeof(buf)); + ssize_t result2 = TEMP_FAILURE_RETRY(read(pfd[1].fd, buf, sizeof(buf))); + ALOGE("%s: Read after POLL returned %zd, error no = %d (%s)", __FUNCTION__, + result2, errno, strerror(errno)); + if (strncmp(buf, "Exit", 4) == 0) { + ALOGD("Got a signal to exit!!!"); + if (TEMP_FAILURE_RETRY(write(pfd[1].fd, "Done", 4)) < 1) { + ALOGE("could not write to the cleanup socket"); + } + break; + } else { + ALOGD("Rx'ed %s on the cleanup socket\n", buf); + } + } else { + ALOGE("Unknown event - %0x, %0x", pfd[0].revents, pfd[1].revents); + } + } while (!info->clean_up); + ALOGI("Exit %s", __FUNCTION__); +} + +/////////////////////////////////////////////////////////////////////////////////////// + +static int internal_no_seq_check(struct nl_msg *msg, void *arg) +{ + return NL_OK; +} + +static int internal_valid_message_handler(nl_msg *msg, void *arg) +{ + // ALOGI("got an event"); + + wifi_handle handle = (wifi_handle)arg; + hal_info *info = getHalInfo(handle); + + WifiEvent event(msg); + int res = event.parse(); + if (res < 0) { + ALOGE("Failed to parse event: %d", res); + return NL_SKIP; + } + + int cmd = event.get_cmd(); + uint32_t vendor_id = 0; + int subcmd = 0; + + if (cmd == NL80211_CMD_VENDOR) { + vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID); + subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD); + ALOGV("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x", + event.get_cmdString(), vendor_id, subcmd); + } else { + // ALOGV("event received %s", event.get_cmdString()); + } + + // ALOGV("event received %s, vendor_id = 0x%0x", event.get_cmdString(), vendor_id); + // event.log(); + + bool dispatched = false; + + pthread_mutex_lock(&info->cb_lock); + + for (int i = 0; i < info->num_event_cb; i++) { + if (cmd == info->event_cb[i].nl_cmd) { + if (cmd == NL80211_CMD_VENDOR + && ((vendor_id != info->event_cb[i].vendor_id) + || (subcmd != info->event_cb[i].vendor_subcmd))) + { + /* event for a different vendor, ignore it */ + continue; + } + + cb_info *cbi = &(info->event_cb[i]); + nl_recvmsg_msg_cb_t cb_func = cbi->cb_func; + void *cb_arg = cbi->cb_arg; + WifiCommand *cmd = (WifiCommand *)cbi->cb_arg; + if (cmd != NULL) { + cmd->addRef(); + } + pthread_mutex_unlock(&info->cb_lock); + if (cb_func) + (*cb_func)(msg, cb_arg); + if (cmd != NULL) { + cmd->releaseRef(); + } + + return NL_OK; + } + } + + pthread_mutex_unlock(&info->cb_lock); + return NL_OK; +} + +/////////////////////////////////////////////////////////////////////////////////////// + +class GetMulticastIdCommand : public WifiCommand +{ +private: + const char *mName; + const char *mGroup; + int mId; +public: + GetMulticastIdCommand(wifi_handle handle, const char *name, const char *group) + : WifiCommand("GetMulticastIdCommand", handle, 0) + { + mName = name; + mGroup = group; + mId = -1; + } + + int getId() { + return mId; + } + + virtual int create() { + int nlctrlFamily = genl_ctrl_resolve(mInfo->cmd_sock, "nlctrl"); + // ALOGI("ctrl family = %d", nlctrlFamily); + int ret = mMsg.create(nlctrlFamily, CTRL_CMD_GETFAMILY, 0, 0); + if (ret < 0) { + return ret; + } + ret = mMsg.put_string(CTRL_ATTR_FAMILY_NAME, mName); + return ret; + } + + virtual int handleResponse(WifiEvent& reply) { + + // ALOGI("handling reponse in %s", __func__); + + struct nlattr **tb = reply.attributes(); + struct genlmsghdr *gnlh = reply.header(); + struct nlattr *mcgrp = NULL; + int i; + + if (!tb[CTRL_ATTR_MCAST_GROUPS]) { + ALOGI("No multicast groups found"); + return NL_SKIP; + } else { + // ALOGI("Multicast groups attr size = %d", nla_len(tb[CTRL_ATTR_MCAST_GROUPS])); + } + + for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) { + + // ALOGI("Processing group"); + struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1]; + nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, (nlattr *)nla_data(mcgrp), + nla_len(mcgrp), NULL); + if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID]) { + continue; + } + + char *grpName = (char *)nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]); + int grpNameLen = nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME]); + + // ALOGI("Found group name %s", grpName); + + if (strncmp(grpName, mGroup, grpNameLen) != 0) + continue; + + mId = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]); + break; + } + + return NL_SKIP; + } + +}; + +class SetPnoMacAddrOuiCommand : public WifiCommand { + +private: + byte *mOui; + feature_set *fset; + feature_set *feature_matrix; + int *fm_size; + int set_size_max; +public: + SetPnoMacAddrOuiCommand(wifi_interface_handle handle, oui scan_oui) + : WifiCommand("SetPnoMacAddrOuiCommand", handle, 0) + { + mOui = scan_oui; + } + + int createRequest(WifiRequest& request, int subcmd, byte *scan_oui) { + int result = request.create(GOOGLE_OUI, subcmd); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put(ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI, scan_oui, DOT11_OUI_LEN); + if (result < 0) { + return result; + } + + request.attr_end(data); + return WIFI_SUCCESS; + + } + + int start() { + ALOGD("Sending mac address OUI"); + WifiRequest request(familyId(), ifaceId()); + int result = createRequest(request, WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI, mOui); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create request; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to set scanning mac OUI; result = %d", result); + } + + return result; + } +protected: + virtual int handleResponse(WifiEvent& reply) { + ALOGD("Request complete!"); + /* Nothing to do on response! */ + return NL_SKIP; + } +}; + +class SetNodfsCommand : public WifiCommand { + +private: + u32 mNoDfs; +public: + SetNodfsCommand(wifi_interface_handle handle, u32 nodfs) + : WifiCommand("SetNodfsCommand", handle, 0) { + mNoDfs = nodfs; + } + virtual int create() { + int ret; + + ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_NODFS_SET); + if (ret < 0) { + ALOGE("Can't create message to send to driver - %d", ret); + return ret; + } + + nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA); + ret = mMsg.put_u32(ANDR_WIFI_ATTRIBUTE_NODFS_SET, mNoDfs); + if (ret < 0) { + return ret; + } + + mMsg.attr_end(data); + return WIFI_SUCCESS; + } +}; + +class SetCountryCodeCommand : public WifiCommand { +private: + const char *mCountryCode; +public: + SetCountryCodeCommand(wifi_interface_handle handle, const char *country_code) + : WifiCommand("SetCountryCodeCommand", handle, 0) { + mCountryCode = country_code; + } + virtual int create() { + int ret; + + ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_SET_COUNTRY_CODE); + if (ret < 0) { + ALOGE("Can't create message to send to driver - %d", ret); + return ret; + } + + nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA); + ret = mMsg.put_string(ANDR_WIFI_ATTRIBUTE_COUNTRY, mCountryCode); + if (ret < 0) { + return ret; + } + + mMsg.attr_end(data); + return WIFI_SUCCESS; + + } +}; + +class SetRSSIMonitorCommand : public WifiCommand { +private: + s8 mMax_rssi; + s8 mMin_rssi; + wifi_rssi_event_handler mHandler; +public: + SetRSSIMonitorCommand(wifi_request_id id, wifi_interface_handle handle, + s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh) + : WifiCommand("SetRSSIMonitorCommand", handle, id), mMax_rssi(max_rssi), mMin_rssi + (min_rssi), mHandler(eh) + { + } + int createRequest(WifiRequest& request, int enable) { + int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_SET_RSSI_MONITOR); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, (enable ? mMax_rssi: 0)); + if (result < 0) { + return result; + } + ALOGD("create request"); + result = request.put_u32(RSSI_MONITOR_ATTRIBUTE_MIN_RSSI, (enable? mMin_rssi: 0)); + if (result < 0) { + return result; + } + result = request.put_u32(RSSI_MONITOR_ATTRIBUTE_START, enable); + if (result < 0) { + return result; + } + request.attr_end(data); + return result; + } + + int start() { + WifiRequest request(familyId(), ifaceId()); + int result = createRequest(request, 1); + if (result < 0) { + return result; + } + result = requestResponse(request); + if (result < 0) { + ALOGI("Failed to set RSSI Monitor, result = %d", result); + return result; + } + ALOGI("Successfully set RSSI monitoring"); + registerVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT); + + + if (result < 0) { + unregisterVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT); + return result; + } + ALOGI("Done!"); + return result; + } + + virtual int cancel() { + + WifiRequest request(familyId(), ifaceId()); + int result = createRequest(request, 0); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create request; result = %d", result); + } else { + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to stop RSSI monitoring = %d", result); + } + } + unregisterVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT); + return WIFI_SUCCESS; + } + + virtual int handleResponse(WifiEvent& reply) { + /* Nothing to do on response! */ + return NL_SKIP; + } + + virtual int handleEvent(WifiEvent& event) { + ALOGI("Got a RSSI monitor event"); + + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = event.get_vendor_data_len(); + + if (vendor_data == NULL || len == 0) { + ALOGI("RSSI monitor: No data"); + return NL_SKIP; + } + /* driver<->HAL event structure */ + #define RSSI_MONITOR_EVT_VERSION 1 + typedef struct { + u8 version; + s8 cur_rssi; + mac_addr BSSID; + } rssi_monitor_evt; + + rssi_monitor_evt *data = (rssi_monitor_evt *)event.get_vendor_data(); + + if (data->version != RSSI_MONITOR_EVT_VERSION) { + ALOGI("Event version mismatch %d, expected %d", data->version, RSSI_MONITOR_EVT_VERSION); + return NL_SKIP; + } + + if (*mHandler.on_rssi_threshold_breached) { + (*mHandler.on_rssi_threshold_breached)(id(), data->BSSID, data->cur_rssi); + } else { + ALOGW("No RSSI monitor handler registered"); + } + + return NL_SKIP; + } + +}; + +class AndroidPktFilterCommand : public WifiCommand { + private: + const u8* mProgram; + u32 mProgramLen; + u32* mVersion; + u32* mMaxLen; + int mReqType; + public: + AndroidPktFilterCommand(wifi_interface_handle handle, + u32* version, u32* max_len) + : WifiCommand("AndroidPktFilterCommand", handle, 0), + mVersion(version), mMaxLen(max_len), + mReqType(GET_APF_CAPABILITIES) + { + } + + AndroidPktFilterCommand(wifi_interface_handle handle, + const u8* program, u32 len) + : WifiCommand("AndroidPktFilterCommand", handle, 0), + mProgram(program), mProgramLen(len), + mReqType(SET_APF_PROGRAM) + { + } + + int createRequest(WifiRequest& request) { + if (mReqType == SET_APF_PROGRAM) { + ALOGI("\n%s: APF set program request\n", __FUNCTION__); + return createSetPktFilterRequest(request); + } else if (mReqType == GET_APF_CAPABILITIES) { + ALOGI("\n%s: APF get capabilities request\n", __FUNCTION__); + return createGetPktFilterCapabilitesRequest(request); + } else { + ALOGE("\n%s Unknown APF request\n", __FUNCTION__); + return WIFI_ERROR_NOT_SUPPORTED; + } + return WIFI_SUCCESS; + } + + int createSetPktFilterRequest(WifiRequest& request) { + u8 *program = new u8[mProgramLen]; + NULL_CHECK_RETURN(program, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + int result = request.create(GOOGLE_OUI, APF_SUBCMD_SET_FILTER); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(APF_ATTRIBUTE_PROGRAM_LEN, mProgramLen); + if (result < 0) { + return result; + } + memcpy(program, mProgram, mProgramLen); + result = request.put(APF_ATTRIBUTE_PROGRAM, program, mProgramLen); + if (result < 0) { + return result; + } + request.attr_end(data); + delete[] program; + return result; + } + + int createGetPktFilterCapabilitesRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, APF_SUBCMD_GET_CAPABILITIES); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + request.attr_end(data); + return result; + } + + int start() { + WifiRequest request(familyId(), ifaceId()); + int result = createRequest(request); + if (result < 0) { + return result; + } + result = requestResponse(request); + if (result < 0) { + ALOGI("Request Response failed for APF, result = %d", result); + return result; + } + ALOGI("Done!"); + return result; + } + + int cancel() { + return WIFI_SUCCESS; + } + + int handleResponse(WifiEvent& reply) { + ALOGD("In SetAPFCommand::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + int id = reply.get_vendor_id(); + int subcmd = reply.get_vendor_subcmd(); + + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + + ALOGD("Id = %0x, subcmd = %d, len = %d", id, subcmd, len); + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in SetAPFCommand response; ignoring it"); + return NL_SKIP; + } + if( mReqType == SET_APF_PROGRAM) { + ALOGD("Response recieved for set packet filter command\n"); + } else if (mReqType == GET_APF_CAPABILITIES) { + *mVersion = 0; + *mMaxLen = 0; + ALOGD("Response recieved for get packet filter capabilities command\n"); + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == APF_ATTRIBUTE_VERSION) { + *mVersion = it.get_u32(); + ALOGI("APF version is %d\n", *mVersion); + } else if (it.get_type() == APF_ATTRIBUTE_MAX_LEN) { + *mMaxLen = it.get_u32(); + ALOGI("APF max len is %d\n", *mMaxLen); + } else { + ALOGE("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + } + return NL_OK; + } + + int handleEvent(WifiEvent& event) { + /* No Event to recieve for APF commands */ + return NL_SKIP; + } +}; + +class SetNdoffloadCommand : public WifiCommand { + +private: + u8 mEnable; +public: + SetNdoffloadCommand(wifi_interface_handle handle, u8 enable) + : WifiCommand("SetNdoffloadCommand", handle, 0) { + mEnable = enable; + } + virtual int create() { + int ret; + + ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_CONFIG_ND_OFFLOAD); + if (ret < 0) { + ALOGE("Can't create message to send to driver - %d", ret); + return ret; + } + + nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA); + ret = mMsg.put_u8(ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE, mEnable); + if (ret < 0) { + return ret; + } + + mMsg.attr_end(data); + return WIFI_SUCCESS; + } +}; + +class GetFeatureSetCommand : public WifiCommand { + +private: + int feature_type; + feature_set *fset; + feature_set *feature_matrix; + int *fm_size; + int set_size_max; +public: + GetFeatureSetCommand(wifi_interface_handle handle, int feature, feature_set *set, + feature_set set_matrix[], int *size, int max_size) + : WifiCommand("GetFeatureSetCommand", handle, 0) + { + feature_type = feature; + fset = set; + feature_matrix = set_matrix; + fm_size = size; + set_size_max = max_size; + } + + virtual int create() { + int ret; + + if(feature_type == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) { + ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_FEATURE_SET); + } else if (feature_type == ANDR_WIFI_ATTRIBUTE_FEATURE_SET) { + ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_FEATURE_SET_MATRIX); + } else { + ALOGE("Unknown feature type %d", feature_type); + return -1; + } + + if (ret < 0) { + ALOGE("Can't create message to send to driver - %d", ret); + } + + return ret; + } + +protected: + virtual int handleResponse(WifiEvent& reply) { + + ALOGV("In GetFeatureSetCommand::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + int id = reply.get_vendor_id(); + int subcmd = reply.get_vendor_subcmd(); + + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + + ALOGV("Id = %0x, subcmd = %d, len = %d", id, subcmd, len); + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in GetFeatureSetCommand response; ignoring it"); + return NL_SKIP; + } + if(feature_type == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) { + void *data = reply.get_vendor_data(); + if(!fset) { + ALOGE("Buffers pointers not set"); + return NL_SKIP; + } + memcpy(fset, data, min(len, (int) sizeof(*fset))); + } else { + int num_features_set = 0; + int i = 0; + + if(!feature_matrix || !fm_size) { + ALOGE("Buffers pointers not set"); + return NL_SKIP; + } + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) { + num_features_set = it.get_u32(); + ALOGV("Got feature list with %d concurrent sets", num_features_set); + if(set_size_max && (num_features_set > set_size_max)) + num_features_set = set_size_max; + *fm_size = num_features_set; + } else if ((it.get_type() == ANDR_WIFI_ATTRIBUTE_FEATURE_SET) && + i < num_features_set) { + feature_matrix[i] = it.get_u32(); + i++; + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + + } + return NL_OK; + } + +}; + +static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group) +{ + GetMulticastIdCommand cmd(handle, name, group); + int res = cmd.requestResponse(); + if (res < 0) + return res; + else + return cmd.getId(); +} + +///////////////////////////////////////////////////////////////////////// + +static bool is_wifi_interface(const char *name) +{ + if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "p2p", 3) != 0) { + /* not a wifi interface; ignore it */ + return false; + } else { + return true; + } +} + +static int get_interface(const char *name, interface_info *info) +{ + strcpy(info->name, name); + info->id = if_nametoindex(name); + // ALOGI("found an interface : %s, id = %d", name, info->id); + return WIFI_SUCCESS; +} + +wifi_error wifi_init_interfaces(wifi_handle handle) +{ + hal_info *info = (hal_info *)handle; + + struct dirent *de; + + DIR *d = opendir("/sys/class/net"); + if (d == 0) + return WIFI_ERROR_UNKNOWN; + + int n = 0; + while ((de = readdir(d))) { + if (de->d_name[0] == '.') + continue; + if (is_wifi_interface(de->d_name) ) { + n++; + } + } + + closedir(d); + + if (n == 0) + return WIFI_ERROR_NOT_AVAILABLE; + + d = opendir("/sys/class/net"); + if (d == 0) + return WIFI_ERROR_UNKNOWN; + + info->interfaces = (interface_info **)malloc(sizeof(interface_info *) * n); + + int i = 0; + while ((de = readdir(d))) { + if (de->d_name[0] == '.') + continue; + if (is_wifi_interface(de->d_name)) { + interface_info *ifinfo = (interface_info *)malloc(sizeof(interface_info)); + if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) { + free(ifinfo); + continue; + } + ifinfo->handle = handle; + info->interfaces[i] = ifinfo; + i++; + } + } + + closedir(d); + + info->num_interfaces = n; + return WIFI_SUCCESS; +} + +wifi_error wifi_get_ifaces(wifi_handle handle, int *num, wifi_interface_handle **interfaces) +{ + hal_info *info = (hal_info *)handle; + + *interfaces = (wifi_interface_handle *)info->interfaces; + *num = info->num_interfaces; + + return WIFI_SUCCESS; +} + +wifi_error wifi_get_iface_name(wifi_interface_handle handle, char *name, size_t size) +{ + interface_info *info = (interface_info *)handle; + strcpy(name, info->name); + return WIFI_SUCCESS; +} + +wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set *set) +{ + GetFeatureSetCommand command(handle, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, set, NULL, NULL, 1); + return (wifi_error) command.requestResponse(); +} + +wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int set_size_max, + feature_set set[], int *set_size) +{ + GetFeatureSetCommand command(handle, ANDR_WIFI_ATTRIBUTE_FEATURE_SET, NULL, + set, set_size, set_size_max); + return (wifi_error) command.requestResponse(); +} + +wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui) +{ + SetPnoMacAddrOuiCommand command(handle, scan_oui); + return (wifi_error)command.start(); +} + +wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs) +{ + SetNodfsCommand command(handle, nodfs); + return (wifi_error) command.requestResponse(); +} + +wifi_error wifi_set_country_code(wifi_interface_handle handle, const char *country_code) +{ + SetCountryCodeCommand command(handle, country_code); + return (wifi_error) command.requestResponse(); +} + +static wifi_error wifi_start_rssi_monitoring(wifi_request_id id, wifi_interface_handle + iface, s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh) +{ + ALOGD("Start RSSI monitor %d", id); + wifi_handle handle = getWifiHandle(iface); + SetRSSIMonitorCommand *cmd = new SetRSSIMonitorCommand(id, iface, max_rssi, min_rssi, eh); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, id, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, id); + cmd->releaseRef(); + return result; + } + return WIFI_ERROR_UNKNOWN; +} + +static wifi_error wifi_stop_rssi_monitoring(wifi_request_id id, wifi_interface_handle iface) +{ + ALOGD("Stopping RSSI monitor"); + + if(id == -1) { + wifi_rssi_event_handler handler; + s8 max_rssi = 0, min_rssi = 0; + wifi_handle handle = getWifiHandle(iface); + memset(&handler, 0, sizeof(handler)); + SetRSSIMonitorCommand *cmd = new SetRSSIMonitorCommand(id, iface, + max_rssi, min_rssi, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + cmd->cancel(); + cmd->releaseRef(); + return WIFI_SUCCESS; + } + wifi_cancel_cmd(id, iface); + return WIFI_ERROR_UNKNOWN; +} + +static wifi_error wifi_get_packet_filter_capabilities(wifi_interface_handle handle, + u32 *version, u32 *max_len) +{ +#if 0 + ALOGD("Getting APF capabilities, halHandle = %p\n", handle); + AndroidPktFilterCommand *cmd = new AndroidPktFilterCommand(handle, version, max_len); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + if (result == WIFI_SUCCESS) { + ALOGD("Getting APF capability, version = %d, max_len = %d\n", *version, *max_len); + } + cmd->releaseRef(); + return result; +#endif + return WIFI_SUCCESS; +} + +static wifi_error wifi_set_packet_filter(wifi_interface_handle handle, + const u8 *program, u32 len) +{ + ALOGD("Setting APF program, halHandle = %p\n", handle); + AndroidPktFilterCommand *cmd = new AndroidPktFilterCommand(handle, program, len); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; +} + +static wifi_error wifi_configure_nd_offload(wifi_interface_handle handle, u8 enable) +{ + SetNdoffloadCommand command(handle, enable); + return (wifi_error) command.requestResponse(); +} + +static wifi_error wifi_get_wake_reason_stats (wifi_interface_handle handle, + WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt) { + + return WIFI_SUCCESS; +} +///////////////////////////////////////////////////////////////////////////// diff --git a/wlan/wifi_hal/rtw_wifi_llstats.cpp b/wlan/wifi_hal/rtw_wifi_llstats.cpp new file mode 100644 index 0000000..93efb54 --- /dev/null +++ b/wlan/wifi_hal/rtw_wifi_llstats.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "sync.h" + +#define LOG_TAG "WifiHAL" + +#include + +#include "wifi_hal.h" +#include "common.h" +#include "cpp_bindings.h" + +/* Internal radio statistics structure in the driver */ +typedef struct { + wifi_radio radio; + uint32_t on_time; + uint32_t tx_time; + uint32_t rx_time; + uint32_t on_time_scan; + uint32_t on_time_nbd; + uint32_t on_time_gscan; + uint32_t on_time_roam_scan; + uint32_t on_time_pno_scan; + uint32_t on_time_hs20; + uint32_t num_channels; + wifi_channel_stat channels[]; +} wifi_radio_stat_internal; + +enum { + LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START, +}; + +class GetLinkStatsCommand : public WifiCommand +{ + wifi_stats_result_handler mHandler; +public: + GetLinkStatsCommand(wifi_interface_handle iface, wifi_stats_result_handler handler) + : WifiCommand("GetLinkStatsCommand", iface, 0), mHandler(handler) + { } + + virtual int create() { + // ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id); + + int ret = mMsg.create(GOOGLE_OUI, LSTATS_SUBCMD_GET_INFO); + if (ret < 0) { + ALOGE("Failed to create %x - %d", LSTATS_SUBCMD_GET_INFO, ret); + return ret; + } + + return ret; + } + +protected: + virtual int handleResponse(WifiEvent& reply) { + + // ALOGI("In GetLinkStatsCommand::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + int id = reply.get_vendor_id(); + int subcmd = reply.get_vendor_subcmd(); + + // ALOGI("Id = %0x, subcmd = %d", id, subcmd); + + void *data = reply.get_vendor_data(); + int len = reply.get_vendor_data_len(); + wifi_radio_stat *radio_stat = + convertToExternalRadioStatStructure((wifi_radio_stat_internal *)data); + if (!radio_stat) { + ALOGE("Invalid stats pointer received"); + return NL_SKIP; + } + +#ifdef CONFIG_WIFI_HAL_DEBUG + ALOGE("radio: = %d", radio_stat->radio); + ALOGE("on_time: = %u ms", radio_stat->on_time); + ALOGE("tx_time: = %u ms", radio_stat->tx_time); + ALOGE("num_tx_levels: = %u", radio_stat->num_tx_levels); + ALOGE("rx_time: = %u ms", radio_stat->rx_time); + ALOGE("on_time_scan: = %u ms", radio_stat->on_time_scan); + ALOGE("on_time_nbd: = %u ms", radio_stat->on_time_nbd); + ALOGE("on_time_gscan: = %u ms", radio_stat->on_time_gscan); + ALOGE("on_time_pno_scan: = %u ms", radio_stat->on_time_pno_scan); + ALOGE("on_time_hs20: = %u ms", radio_stat->on_time_hs20); +#endif + if (!radio_stat) { + ALOGE("Invalid stats pointer received"); + return NL_SKIP; + } + if (radio_stat->num_channels > 11) { + ALOGE("Incorrect number of channels = %d", radio_stat->num_channels); + // dump data before num_channels + ALOGE("radio: = %d", radio_stat->radio); + ALOGE("on_time: = %u ms", radio_stat->on_time); + ALOGE("tx_time: = %u ms", radio_stat->tx_time); + ALOGE("rx_time: = %u ms", radio_stat->rx_time); + ALOGE("on_time_scan: = %u ms", radio_stat->on_time_scan); + ALOGE("on_time_nbd: = %u ms", radio_stat->on_time_nbd); + ALOGE("on_time_gscan: = %u ms", radio_stat->on_time_gscan); + ALOGE("on_time_pno_scan: = %u ms", radio_stat->on_time_pno_scan); + ALOGE("on_time_hs20: = %u ms", radio_stat->on_time_hs20); + free(radio_stat); + return NL_SKIP; + } + wifi_iface_stat *iface_stat = NULL; + iface_stat = (wifi_iface_stat *)((char* )data + sizeof(wifi_radio_stat)); + + if(*mHandler.on_link_stats_results == NULL) { + ALOGE("*mHandler.on_link_stats_results is NULL"); + } else { + (*mHandler.on_link_stats_results)(id, iface_stat, 1, radio_stat); + } + free(radio_stat); + return NL_OK; + } +private: + wifi_radio_stat *convertToExternalRadioStatStructure(wifi_radio_stat_internal *internal_stat_ptr) { + wifi_radio_stat *external_stat_ptr = NULL; + if (internal_stat_ptr) { + uint32_t channel_size = internal_stat_ptr->num_channels * sizeof(wifi_channel_stat); + uint32_t total_size = sizeof(wifi_radio_stat) + channel_size; + external_stat_ptr = (wifi_radio_stat *)malloc(total_size); + if (external_stat_ptr) { + external_stat_ptr->radio = internal_stat_ptr->radio; + external_stat_ptr->on_time = internal_stat_ptr->on_time; + external_stat_ptr->tx_time = internal_stat_ptr->tx_time; + external_stat_ptr->rx_time = internal_stat_ptr->rx_time; + external_stat_ptr->tx_time_per_levels = NULL; + external_stat_ptr->num_tx_levels = 0; + external_stat_ptr->on_time_scan = internal_stat_ptr->on_time_scan; + external_stat_ptr->on_time_nbd = internal_stat_ptr->on_time_nbd; + external_stat_ptr->on_time_gscan = internal_stat_ptr->on_time_gscan; + external_stat_ptr->on_time_roam_scan = internal_stat_ptr->on_time_roam_scan; + external_stat_ptr->on_time_pno_scan = internal_stat_ptr->on_time_pno_scan; + external_stat_ptr->on_time_hs20 = internal_stat_ptr->on_time_hs20; + external_stat_ptr->num_channels = internal_stat_ptr->num_channels; + if (internal_stat_ptr->num_channels) { + memcpy(&(external_stat_ptr->channels), &(internal_stat_ptr->channels), + channel_size); + } + } + } + return external_stat_ptr; + } + +}; + +wifi_error wifi_get_link_stats(wifi_request_id id, + wifi_interface_handle iface, wifi_stats_result_handler handler) +{ + GetLinkStatsCommand command(iface, handler); + return (wifi_error) command.requestResponse(); +} + +wifi_error wifi_set_link_stats( + wifi_interface_handle /* iface */, wifi_link_layer_params /* params */) +{ + /* Return success here since bcom HAL does not need set link stats. */ + return WIFI_SUCCESS; +} + +wifi_error wifi_clear_link_stats( + wifi_interface_handle /* iface */, u32 /* stats_clear_req_mask */, + u32 * /* stats_clear_rsp_mask */, u8 /* stop_req */, u8 * /* stop_rsp */) +{ + /* Return success here since bcom HAL does not support clear link stats. */ + return WIFI_SUCCESS; +} diff --git a/wlan/wifi_hal/rtw_wifi_logger.cpp b/wlan/wifi_hal/rtw_wifi_logger.cpp new file mode 100644 index 0000000..2e214dd --- /dev/null +++ b/wlan/wifi_hal/rtw_wifi_logger.cpp @@ -0,0 +1,1107 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "nl80211_copy.h" +#include "sync.h" + +#define LOG_TAG "WifiHAL" + +#include + +#include "wifi_hal.h" +#include "common.h" +#include "cpp_bindings.h" + +typedef enum { + LOGGER_START_LOGGING = ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START, + LOGGER_TRIGGER_MEM_DUMP, + LOGGER_GET_MEM_DUMP, + LOGGER_GET_VER, + LOGGER_GET_RING_STATUS, + LOGGER_GET_RING_DATA, + LOGGER_GET_FEATURE, + LOGGER_RESET_LOGGING, + LOGGER_TRIGGER_DRIVER_MEM_DUMP, + LOGGER_GET_DRIVER_MEM_DUMP, + LOGGER_START_PKT_FATE_MONITORING, + LOGGER_GET_TX_PKT_FATES, + LOGGER_GET_RX_PKT_FATES, +} DEBUG_SUB_COMMAND; + +typedef enum { + LOGGER_ATTRIBUTE_DRIVER_VER, + LOGGER_ATTRIBUTE_FW_VER, + LOGGER_ATTRIBUTE_RING_ID, + LOGGER_ATTRIBUTE_RING_NAME, + LOGGER_ATTRIBUTE_RING_FLAGS, + LOGGER_ATTRIBUTE_LOG_LEVEL, + LOGGER_ATTRIBUTE_LOG_TIME_INTVAL, + LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE, + LOGGER_ATTRIBUTE_FW_DUMP_LEN, + LOGGER_ATTRIBUTE_FW_DUMP_DATA, + // LOGGER_ATTRIBUTE_FW_ERR_CODE, + LOGGER_ATTRIBUTE_RING_DATA, + LOGGER_ATTRIBUTE_RING_STATUS, + LOGGER_ATTRIBUTE_RING_NUM, + LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN, + LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA, + LOGGER_ATTRIBUTE_PKT_FATE_NUM, + LOGGER_ATTRIBUTE_PKT_FATE_DATA, +} LOGGER_ATTRIBUTE; + +typedef enum { + DEBUG_OFF = 0, + DEBUG_NORMAL, + DEBUG_VERBOSE, + DEBUG_VERY, + DEBUG_VERY_VERY, +} LOGGER_LEVEL; + +typedef enum { + GET_FW_VER, + GET_DRV_VER, + GET_RING_DATA, + GET_RING_STATUS, + GET_FEATURE, + START_RING_LOG, +} GetCmdType; + +typedef enum { + PACKET_MONITOR_START, + TX_PACKET_FATE, + RX_PACKET_FATE, +} PktFateReqType; + + +/////////////////////////////////////////////////////////////////////////////// +class DebugCommand : public WifiCommand +{ + char *mBuff; + int *mBuffSize; + u32 *mNumRings; + wifi_ring_buffer_status *mStatus; + unsigned int *mSupport; + u32 mVerboseLevel; + u32 mFlags; + u32 mMaxIntervalSec; + u32 mMinDataSize; + char *mRingName; + GetCmdType mType; + +public: + + // constructor for get version + DebugCommand(wifi_interface_handle iface, char *buffer, int *buffer_size, + GetCmdType cmdType) + : WifiCommand("DebugCommand", iface, 0), mBuff(buffer), mBuffSize(buffer_size), mType + (cmdType) + { + memset(mBuff, 0, *mBuffSize); + } + + // constructor for ring data + DebugCommand(wifi_interface_handle iface, char *ring_name, GetCmdType cmdType) + : WifiCommand("DebugCommand", iface, 0), mRingName(ring_name), mType(cmdType) + { } + + // constructor for ring status + DebugCommand(wifi_interface_handle iface, u32 *num_rings, + wifi_ring_buffer_status *status, GetCmdType cmdType) + : WifiCommand("DebugCommand", iface, 0), mNumRings(num_rings), mStatus(status), mType(cmdType) + { + memset(mStatus, 0, sizeof(wifi_ring_buffer_status) * (*mNumRings)); + } + + // constructor for feature set + DebugCommand(wifi_interface_handle iface, unsigned int *support, GetCmdType cmdType) + : WifiCommand("DebugCommand", iface, 0), mSupport(support), mType(cmdType) + { } + + // constructor for ring params + DebugCommand(wifi_interface_handle iface, u32 verbose_level, u32 flags, + u32 max_interval_sec, u32 min_data_size, char *ring_name, GetCmdType cmdType) + : WifiCommand("DebugCommand", iface, 0), mVerboseLevel(verbose_level), mFlags(flags), + mMaxIntervalSec(max_interval_sec), mMinDataSize(min_data_size), + mRingName(ring_name), mType(cmdType) + { } + + int createRingRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, LOGGER_START_LOGGING); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create start ring logger request; result = %d", result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + result = request.put_u32(LOGGER_ATTRIBUTE_LOG_LEVEL, mVerboseLevel); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put log level; result = %d", result); + return result; + } + result = request.put_u32(LOGGER_ATTRIBUTE_RING_FLAGS, mFlags); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put ring flags; result = %d", result); + return result; + } + result = request.put_u32(LOGGER_ATTRIBUTE_LOG_TIME_INTVAL, mMaxIntervalSec); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put log time interval; result = %d", result); + return result; + } + result = request.put_u32(LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE, mMinDataSize); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put min data size; result = %d", result); + return result; + } + result = request.put_string(LOGGER_ATTRIBUTE_RING_NAME, mRingName); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put ringbuffer name; result = %d", result); + return result; + } + request.attr_end(data); + + return WIFI_SUCCESS; + } + + int createRequest(WifiRequest &request) { + int result; + + switch (mType) { + case GET_FW_VER: + { + result = request.create(GOOGLE_OUI, LOGGER_GET_VER); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get fw version request; result = %d", result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + // Driver expecting only attribute type, passing mbuff as data with + // length 0 to avoid undefined state + result = request.put(LOGGER_ATTRIBUTE_FW_VER, mBuff, 0); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put get fw version request; result = %d", result); + return result; + } + request.attr_end(data); + break; + } + + case GET_DRV_VER: + { + result = request.create(GOOGLE_OUI, LOGGER_GET_VER); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get drv version request; result = %d", result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + // Driver expecting only attribute type, passing mbuff as data with + // length 0 to avoid undefined state + result = request.put(LOGGER_ATTRIBUTE_DRIVER_VER, mBuff, 0); + + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put get drv version request; result = %d", result); + return result; + } + request.attr_end(data); + break; + } + + case GET_RING_DATA: + { + result = request.create(GOOGLE_OUI, LOGGER_GET_RING_DATA); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get ring data request; result = %d", result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_string(LOGGER_ATTRIBUTE_RING_NAME, mRingName); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put ring data request; result = %d", result); + return result; + } + request.attr_end(data); + break; + } + + case GET_RING_STATUS: + { + result = request.create(GOOGLE_OUI, LOGGER_GET_RING_STATUS); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get ring status request; result = %d", result); + return result; + } + break; + } + + case GET_FEATURE: + { + result = request.create(GOOGLE_OUI, LOGGER_GET_FEATURE); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get feature request; result = %d", result); + return result; + } + break; + } + + case START_RING_LOG: + result = createRingRequest(request); + break; + + default: + ALOGE("Unknown Debug command"); + result = WIFI_ERROR_UNKNOWN; + } + return result; + } + + int start() { + // ALOGD("Start debug command"); + WifiRequest request(familyId(), ifaceId()); + int result = createRequest(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create debug request; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register debug response; result = %d", result); + } + return result; + } + + virtual int handleResponse(WifiEvent& reply) { + ALOGD("In DebugCommand::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + switch (mType) { + case GET_DRV_VER: + case GET_FW_VER: + { + void *data = reply.get_vendor_data(); + int len = reply.get_vendor_data_len(); + + ALOGD("len = %d, expected len = %d", len, *mBuffSize); + memcpy(mBuff, data, min(len, *mBuffSize)); + if (*mBuffSize < len) + return NL_SKIP; + *mBuffSize = len; + break; + } + + case START_RING_LOG: + case GET_RING_DATA: + break; + + case GET_RING_STATUS: + { + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + wifi_ring_buffer_status *status(mStatus); + + if (vendor_data == NULL || len == 0) { + ALOGE("No Debug data found"); + return NL_SKIP; + } + + nl_iterator it(vendor_data); + if (it.get_type() == LOGGER_ATTRIBUTE_RING_NUM) { + unsigned int num_rings = it.get_u32(); + if (*mNumRings < num_rings) { + ALOGE("Not enough status buffers provided, available: %d required: %d", + *mNumRings, num_rings); + } else { + *mNumRings = num_rings; + } + } else { + ALOGE("Unknown attribute: %d expecting %d", + it.get_type(), LOGGER_ATTRIBUTE_RING_NUM); + return NL_SKIP; + } + + it.next(); + for (unsigned int i = 0; it.has_next() && i < *mNumRings; it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_RING_STATUS) { + memcpy(status, it.get_data(), sizeof(wifi_ring_buffer_status)); + i++; + status++; + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + break; + } + + case GET_FEATURE: + { + void *data = reply.get_vendor_data(); + int len = reply.get_vendor_data_len(); + + ALOGD("len = %d, expected len = %d", len, sizeof(unsigned int)); + memcpy(mSupport, data, sizeof(unsigned int)); + break; + } + + default: + ALOGW("Unknown Debug command"); + } + return NL_OK; + } + + virtual int handleEvent(WifiEvent& event) { + /* NO events! */ + return NL_SKIP; + } +}; + +/* API to collect a firmware version string */ +wifi_error wifi_get_firmware_version(wifi_interface_handle iface, char *buffer, + int buffer_size) +{ + if (buffer && (buffer_size > 0)) { + DebugCommand *cmd = new DebugCommand(iface, buffer, &buffer_size, GET_FW_VER); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; + } else { + ALOGE("FW version buffer NULL"); + return WIFI_ERROR_INVALID_ARGS; + } +} + +/* API to collect a driver version string */ +wifi_error wifi_get_driver_version(wifi_interface_handle iface, char *buffer, int buffer_size) +{ + if (buffer && (buffer_size > 0)) { + DebugCommand *cmd = new DebugCommand(iface, buffer, &buffer_size, GET_DRV_VER); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; + } else { + ALOGE("Driver version buffer NULL"); + return WIFI_ERROR_INVALID_ARGS; + } +} + +/* API to collect driver records */ +wifi_error wifi_get_ring_data(wifi_interface_handle iface, char *ring_name) +{ + DebugCommand *cmd = new DebugCommand(iface, ring_name, GET_RING_DATA); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; +} + +/* API to get the status of all ring buffers supported by driver */ +wifi_error wifi_get_ring_buffers_status(wifi_interface_handle iface, + u32 *num_rings, wifi_ring_buffer_status *status) +{ + if (status && num_rings) { + DebugCommand *cmd = new DebugCommand(iface, num_rings, status, GET_RING_STATUS); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; + } else { + ALOGE("Ring status buffer NULL"); + return WIFI_ERROR_INVALID_ARGS; + } +} + +/* API to get supportable feature */ +wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface, + unsigned int *support) +{ + if (support) { + DebugCommand *cmd = new DebugCommand(iface, support, GET_FEATURE); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; + } else { + ALOGE("Get support buffer NULL"); + return WIFI_ERROR_INVALID_ARGS; + } +} + +wifi_error wifi_start_logging(wifi_interface_handle iface, u32 verbose_level, + u32 flags, u32 max_interval_sec, u32 min_data_size, char *ring_name) +{ + if (ring_name) { + DebugCommand *cmd = new DebugCommand(iface, verbose_level, flags, max_interval_sec, + min_data_size, ring_name, START_RING_LOG); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; + } else { + ALOGE("Ring name NULL"); + return WIFI_ERROR_INVALID_ARGS; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +class SetLogHandler : public WifiCommand +{ + wifi_ring_buffer_data_handler mHandler; + +public: + SetLogHandler(wifi_interface_handle iface, int id, wifi_ring_buffer_data_handler handler) + : WifiCommand("SetLogHandler", iface, id), mHandler(handler) + { } + + int start() { + ALOGV("Register loghandler"); + registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); + return WIFI_SUCCESS; + } + + virtual int cancel() { + /* Send a command to driver to stop generating logging events */ + ALOGV("Clear loghandler"); + + /* unregister event handler */ + unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); + + WifiRequest request(familyId(), ifaceId()); + int result = request.create(GOOGLE_OUI, LOGGER_RESET_LOGGING); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create reset request; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to request reset; result = %d", result); + return result; + } + + ALOGD("Success to clear loghandler"); + return WIFI_SUCCESS; + } + + virtual int handleEvent(WifiEvent& event) { + char *buffer = NULL; + int buffer_size = 0; + + // ALOGD("In SetLogHandler::handleEvent"); + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = event.get_vendor_data_len(); + int event_id = event.get_vendor_subcmd(); + // ALOGI("Got Logger event: %d", event_id); + + if (vendor_data == NULL || len == 0) { + ALOGE("No Debug data found"); + return NL_SKIP; + } + + if(event_id == GOOGLE_DEBUG_RING_EVENT) { + wifi_ring_buffer_status status; + memset(&status, 0, sizeof(status)); + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_RING_STATUS) { + memcpy(&status, it.get_data(), sizeof(status)); + } else if (it.get_type() == LOGGER_ATTRIBUTE_RING_DATA) { + buffer_size = it.get_len(); + buffer = (char *)it.get_data(); + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + + // ALOGI("Retrieved Debug data"); + if (mHandler.on_ring_buffer_data) { + (*mHandler.on_ring_buffer_data)((char *)status.name, buffer, buffer_size, + &status); + } + } else { + ALOGE("Unknown Event"); + return NL_SKIP; + } + return NL_OK; + } +}; + +wifi_error wifi_set_log_handler(wifi_request_id id, wifi_interface_handle iface, + wifi_ring_buffer_data_handler handler) +{ + wifi_handle handle = getWifiHandle(iface); + ALOGV("Loghandler start, handle = %p", handle); + + SetLogHandler *cmd = new SetLogHandler(iface, id, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, id, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, id); + cmd->releaseRef(); + return result; + } + return result; +} + +wifi_error wifi_reset_log_handler(wifi_request_id id, wifi_interface_handle iface) +{ + wifi_handle handle = getWifiHandle(iface); + ALOGV("Loghandler reset, wifi_request_id = %d, handle = %p", id, handle); + + if (id == -1) { + wifi_ring_buffer_data_handler handler; + memset(&handler, 0, sizeof(handler)); + + SetLogHandler *cmd = new SetLogHandler(iface, id, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + cmd->cancel(); + cmd->releaseRef(); + return WIFI_SUCCESS; + } + + return wifi_cancel_cmd(id, iface); +} + +/////////////////////////////////////////////////////////////////////////////// +class SetAlertHandler : public WifiCommand +{ + wifi_alert_handler mHandler; + int mBuffSize; + char *mBuff; + int mErrCode; + +public: + SetAlertHandler(wifi_interface_handle iface, int id, wifi_alert_handler handler) + : WifiCommand("SetAlertHandler", iface, id), mHandler(handler), mBuffSize(0), mBuff(NULL), + mErrCode(0) + { } + + int start() { + ALOGV("Start Alerting"); + registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_MEM_DUMP_EVENT); + return WIFI_SUCCESS; + } + + virtual int cancel() { + ALOGV("Clear alerthandler"); + + /* unregister alert handler */ + unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_MEM_DUMP_EVENT); + wifi_unregister_cmd(wifiHandle(), id()); + ALOGD("Success to clear alerthandler"); + return WIFI_SUCCESS; + } + + virtual int handleResponse(WifiEvent& reply) { + ALOGD("In SetAlertHandler::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + + ALOGD("len = %d", len); + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in memory dump response; ignoring it"); + return NL_SKIP; + } + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_DATA) { + ALOGI("Initiating alert callback"); + if (mHandler.on_alert) { + (*mHandler.on_alert)(id(), mBuff, mBuffSize, mErrCode); + } + if (mBuff) { + free(mBuff); + mBuff = NULL; + } + } + } + return NL_OK; + } + + virtual int handleEvent(WifiEvent& event) { + wifi_ring_buffer_id ring_id; + char *buffer = NULL; + int buffer_size = 0; + + + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = event.get_vendor_data_len(); + int event_id = event.get_vendor_subcmd(); + ALOGI("Got event: %d", event_id); + + if (vendor_data == NULL || len == 0) { + ALOGE("No Debug data found"); + return NL_SKIP; + } + + if (event_id == GOOGLE_DEBUG_MEM_DUMP_EVENT) { + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_LEN) { + mBuffSize = it.get_u32(); + } else if (it.get_type() == LOGGER_ATTRIBUTE_RING_DATA) { + buffer_size = it.get_len(); + buffer = (char *)it.get_data(); + /* + } else if (it.get_type() == LOGGER_ATTRIBUTE_FW_ERR_CODE) { + mErrCode = it.get_u32(); + */ + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + if (mBuffSize) { + ALOGD("dump size: %d meta data size: %d", mBuffSize, buffer_size); + if (mBuff) free(mBuff); + mBuff = (char *)malloc(mBuffSize + buffer_size); + if (!mBuff) { + ALOGE("Buffer allocation failed"); + return NL_SKIP; + } + memcpy(mBuff, buffer, buffer_size); + + WifiRequest request(familyId(), ifaceId()); + int result = request.create(GOOGLE_OUI, LOGGER_GET_MEM_DUMP); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get memory dump request; result = %d", result); + free(mBuff); + return NL_SKIP; + } + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(LOGGER_ATTRIBUTE_FW_DUMP_LEN, mBuffSize); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put get memory dump request; result = %d", result); + return result; + } + + result = request.put_u64(LOGGER_ATTRIBUTE_FW_DUMP_DATA, + (uint64_t)(mBuff+buffer_size)); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put get memory dump request; result = %d", result); + return result; + } + + request.attr_end(data); + mBuffSize += buffer_size; + + result = requestResponse(request); + + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register get momory dump response; result = %d", result); + } + } else { + ALOGE("dump event missing dump length attribute"); + return NL_SKIP; + } + } + return NL_OK; + } +}; + +wifi_error wifi_set_alert_handler(wifi_request_id id, wifi_interface_handle iface, + wifi_alert_handler handler) +{ + wifi_handle handle = getWifiHandle(iface); + ALOGV("Alerthandler start, handle = %p", handle); + + SetAlertHandler *cmd = new SetAlertHandler(iface, id, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, id, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, id); + cmd->releaseRef(); + return result; + } + return result; +} + +wifi_error wifi_reset_alert_handler(wifi_request_id id, wifi_interface_handle iface) +{ + wifi_handle handle = getWifiHandle(iface); + ALOGV("Alerthandler reset, wifi_request_id = %d, handle = %p", id, handle); + + if (id == -1) { + wifi_alert_handler handler; + memset(&handler, 0, sizeof(handler)); + + SetAlertHandler *cmd = new SetAlertHandler(iface, id, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + cmd->cancel(); + cmd->releaseRef(); + return WIFI_SUCCESS; + } + + return wifi_cancel_cmd(id, iface); +} + +/////////////////////////////////////////////////////////////////////////////// +class MemoryDumpCommand: public WifiCommand +{ + wifi_firmware_memory_dump_handler mHandler; + int mBuffSize; + char *mBuff; + +public: + MemoryDumpCommand(wifi_interface_handle iface, wifi_firmware_memory_dump_handler handler) + : WifiCommand("MemoryDumpCommand", iface, 0), mHandler(handler), mBuffSize(0), mBuff(NULL) + { } + + int start() { + ALOGD("Start memory dump command"); + WifiRequest request(familyId(), ifaceId()); + + int result = request.create(GOOGLE_OUI, LOGGER_TRIGGER_MEM_DUMP); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create trigger fw memory dump request; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register trigger memory dump response; result = %d", result); + } + return result; + } + + virtual int handleResponse(WifiEvent& reply) { + ALOGD("In MemoryDumpCommand::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + + ALOGD("len = %d", len); + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in memory dump response; ignoring it"); + return NL_SKIP; + } + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_LEN) { + mBuffSize = it.get_u32(); + + if (mBuff) + free(mBuff); + mBuff = (char *)malloc(mBuffSize); + if (!mBuff) { + ALOGE("Buffer allocation failed"); + return NL_SKIP; + } + WifiRequest request(familyId(), ifaceId()); + int result = request.create(GOOGLE_OUI, LOGGER_GET_MEM_DUMP); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get memory dump request; result = %d", result); + free(mBuff); + return NL_SKIP; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(LOGGER_ATTRIBUTE_FW_DUMP_LEN, mBuffSize); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put get memory dump request; result = %d", result); + return result; + } + + result = request.put_u64(LOGGER_ATTRIBUTE_FW_DUMP_DATA, (uint64_t)mBuff); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put get memory dump request; result = %d", result); + return result; + } + request.attr_end(data); + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register get momory dump response; result = %d", result); + } + } else if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_DATA) { + ALOGI("Initiating memory dump callback"); + if (mHandler.on_firmware_memory_dump) { + (*mHandler.on_firmware_memory_dump)(mBuff, mBuffSize); + } + if (mBuff) { + free(mBuff); + mBuff = NULL; + } + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + return NL_OK; + } + + virtual int handleEvent(WifiEvent& event) { + /* NO events! */ + return NL_SKIP; + } +}; + +/* API to collect a firmware memory dump for a given iface */ +wifi_error wifi_get_firmware_memory_dump( wifi_interface_handle iface, + wifi_firmware_memory_dump_handler handler) +{ + MemoryDumpCommand *cmd = new MemoryDumpCommand(iface, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; +} + +class PacketFateCommand: public WifiCommand +{ + void *mReportBufs; + size_t mNoReqFates; + size_t *mNoProvidedFates; + PktFateReqType mReqType; + +public: + PacketFateCommand(wifi_interface_handle handle) + : WifiCommand("PacketFateCommand", handle, 0), mReqType(PACKET_MONITOR_START) + { } + + PacketFateCommand(wifi_interface_handle handle, wifi_tx_report *tx_report_bufs, + size_t n_requested_fates, size_t *n_provided_fates) + : WifiCommand("PacketFateCommand", handle, 0), mReportBufs(tx_report_bufs), + mNoReqFates(n_requested_fates), mNoProvidedFates(n_provided_fates), + mReqType(TX_PACKET_FATE) + { } + + PacketFateCommand(wifi_interface_handle handle, wifi_rx_report *rx_report_bufs, + size_t n_requested_fates, size_t *n_provided_fates) + : WifiCommand("PacketFateCommand", handle, 0), mReportBufs(rx_report_bufs), + mNoReqFates(n_requested_fates), mNoProvidedFates(n_provided_fates), + mReqType(RX_PACKET_FATE) + { } + + int createRequest(WifiRequest& request) { + if (mReqType == TX_PACKET_FATE) { + ALOGD("%s Get Tx packet fate request\n", __FUNCTION__); + return createTxPktFateRequest(request); + } else if (mReqType == RX_PACKET_FATE) { + ALOGD("%s Get Rx packet fate request\n", __FUNCTION__); + return createRxPktFateRequest(request); + } else if (mReqType == PACKET_MONITOR_START) { + ALOGD("%s Monitor packet fate request\n", __FUNCTION__); + return createMonitorPktFateRequest(request); + } else { + ALOGE("%s Unknown packet fate request\n", __FUNCTION__); + return WIFI_ERROR_NOT_SUPPORTED; + } + return WIFI_SUCCESS; + } + + int createMonitorPktFateRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, LOGGER_START_PKT_FATE_MONITORING); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + request.attr_end(data); + return result; + } + + int createTxPktFateRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, LOGGER_GET_TX_PKT_FATES); + if (result < 0) { + return result; + } + + memset(mReportBufs, 0, (mNoReqFates * sizeof(wifi_tx_report))); + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(LOGGER_ATTRIBUTE_PKT_FATE_NUM, mNoReqFates); + if (result < 0) { + return result; + } + result = request.put_u64(LOGGER_ATTRIBUTE_PKT_FATE_DATA, (uint64_t)mReportBufs); + if (result < 0) { + return result; + } + request.attr_end(data); + return result; + } + + int createRxPktFateRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, LOGGER_GET_RX_PKT_FATES); + if (result < 0) { + return result; + } + + memset(mReportBufs, 0, (mNoReqFates * sizeof(wifi_rx_report))); + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(LOGGER_ATTRIBUTE_PKT_FATE_NUM, mNoReqFates); + if (result < 0) { + return result; + } + result = request.put_u64(LOGGER_ATTRIBUTE_PKT_FATE_DATA, (uint64_t)mReportBufs); + if (result < 0) { + return result; + } + request.attr_end(data); + return result; + } + + int start() { + ALOGD("Start get packet fate command\n"); + WifiRequest request(familyId(), ifaceId()); + + int result = createRequest(request); + if (result < 0) { + ALOGE("Failed to create get pkt fate request; result = %d\n", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register get pkt fate response; result = %d\n", result); + } + return result; + } + + int handleResponse(WifiEvent& reply) { + ALOGD("In GetPktFateCommand::handleResponse\n"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGI("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + int id = reply.get_vendor_id(); + int subcmd = reply.get_vendor_subcmd(); + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + + ALOGI("Id = %0x, subcmd = %d, len = %d", id, subcmd, len); + + if (mReqType == TX_PACKET_FATE) { + ALOGI("Response recieved for get TX pkt fate command\n"); + } else if (mReqType == RX_PACKET_FATE) { + ALOGI("Response recieved for get RX pkt fate command\n"); + } else if (mReqType == PACKET_MONITOR_START) { + ALOGI("Response recieved for monitor pkt fate command\n"); + return NL_OK; + } else { + ALOGE("Response recieved for unknown pkt fate command\n"); + return NL_SKIP; + } + + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in GetPktFateCommand response; ignoring it\n"); + return NL_SKIP; + } + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_PKT_FATE_NUM) { + *mNoProvidedFates = it.get_u32(); + ALOGI("No: of pkt fates provided is %d\n", *mNoProvidedFates); + } else { + ALOGE("Ignoring invalid attribute type = %d, size = %d\n", + it.get_type(), it.get_len()); + } + } + + return NL_OK; + } + + int handleEvent(WifiEvent& event) { + /* NO events to handle here! */ + return NL_SKIP; + } +}; + +wifi_error wifi_start_pkt_fate_monitoring(wifi_interface_handle handle) +{ + PacketFateCommand *cmd = new PacketFateCommand(handle); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; +} + +wifi_error wifi_get_tx_pkt_fates(wifi_interface_handle handle, + wifi_tx_report *tx_report_bufs, size_t n_requested_fates, + size_t *n_provided_fates) +{ + PacketFateCommand *cmd = new PacketFateCommand(handle, tx_report_bufs, + n_requested_fates, n_provided_fates); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; +} + +wifi_error wifi_get_rx_pkt_fates(wifi_interface_handle handle, + wifi_rx_report *rx_report_bufs, size_t n_requested_fates, + size_t *n_provided_fates) +{ + PacketFateCommand *cmd = new PacketFateCommand(handle, rx_report_bufs, + n_requested_fates, n_provided_fates); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; +} diff --git a/wlan/wifi_hal/rtw_wifi_offload.cpp b/wlan/wifi_hal/rtw_wifi_offload.cpp new file mode 100644 index 0000000..51720c6 --- /dev/null +++ b/wlan/wifi_hal/rtw_wifi_offload.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include "nl80211_copy.h" +#include "sync.h" + +#define LOG_TAG "WifiHAL" + +#include + +#include "wifi_hal.h" +#include "common.h" +#include "cpp_bindings.h" + +typedef enum { + WIFI_OFFLOAD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START, + WIFI_OFFLOAD_STOP_MKEEP_ALIVE, +} WIFI_OFFLOAD_SUB_COMMAND; + +typedef enum { + MKEEP_ALIVE_ATTRIBUTE_ID, + MKEEP_ALIVE_ATTRIBUTE_IP_PKT, + MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, + MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, + MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, + MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC +} WIFI_MKEEP_ALIVE_ATTRIBUTE; + +typedef enum { + START_MKEEP_ALIVE, + STOP_MKEEP_ALIVE, +} GetCmdType; + +/////////////////////////////////////////////////////////////////////////////// +class MKeepAliveCommand : public WifiCommand +{ + u8 mIndex; + u8 *mIpPkt; + u16 mIpPktLen; + u8 *mSrcMacAddr; + u8 *mDstMacAddr; + u32 mPeriodMsec; + GetCmdType mType; + +public: + + // constructor for start sending + MKeepAliveCommand(wifi_interface_handle iface, u8 index, u8 *ip_packet, u16 ip_packet_len, + u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec, GetCmdType cmdType) + : WifiCommand("MKeepAliveCommand", iface, 0), mIndex(index), mIpPkt(ip_packet), + mIpPktLen(ip_packet_len), mSrcMacAddr(src_mac_addr), mDstMacAddr(dst_mac_addr), + mPeriodMsec(period_msec), mType(cmdType) + { } + + // constructor for stop sending + MKeepAliveCommand(wifi_interface_handle iface, u8 index, GetCmdType cmdType) + : WifiCommand("MKeepAliveCommand", iface, 0), mIndex(index), mType(cmdType) + { } + + int createRequest(WifiRequest &request) { + int result; + + switch (mType) { + case START_MKEEP_ALIVE: + { + result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_START_MKEEP_ALIVE); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create start keep alive request; result = %d", result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex); + if (result < 0) { + ALOGE("Failed to put id request; result = %d", result); + return result; + } + + result = request.put_u16(MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, mIpPktLen); + if (result < 0) { + ALOGE("Failed to put ip pkt len request; result = %d", result); + return result; + } + + result = request.put(MKEEP_ALIVE_ATTRIBUTE_IP_PKT, (u8*)mIpPkt, mIpPktLen); + if (result < 0) { + ALOGE("Failed to put ip pkt request; result = %d", result); + return result; + } + + result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, mSrcMacAddr); + if (result < 0) { + ALOGE("Failed to put src mac address request; result = %d", result); + return result; + } + + result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, mDstMacAddr); + if (result < 0) { + ALOGE("Failed to put dst mac address request; result = %d", result); + return result; + } + + result = request.put_u32(MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC, mPeriodMsec); + if (result < 0) { + ALOGE("Failed to put period request; result = %d", result); + return result; + } + + request.attr_end(data); + break; + } + + case STOP_MKEEP_ALIVE: + { + result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_STOP_MKEEP_ALIVE); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create stop keep alive request; result = %d", result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex); + if (result < 0) { + ALOGE("Failed to put id request; result = %d", result); + return result; + } + + request.attr_end(data); + break; + } + + default: + ALOGE("Unknown wifi keep alive command"); + result = WIFI_ERROR_UNKNOWN; + } + return result; + } + + int start() { + ALOGD("Start mkeep_alive command"); + WifiRequest request(familyId(), ifaceId()); + int result = createRequest(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create keep alive request; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register keep alive response; result = %d", result); + } + return result; + } + + virtual int handleResponse(WifiEvent& reply) { + ALOGD("In MKeepAliveCommand::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + switch (mType) { + case START_MKEEP_ALIVE: + case STOP_MKEEP_ALIVE: + break; + + default: + ALOGW("Unknown mkeep_alive command"); + } + return NL_OK; + } + + virtual int handleEvent(WifiEvent& event) { + /* NO events! */ + return NL_SKIP; + } +}; + +/* API to send specified mkeep_alive packet periodically. */ +wifi_error wifi_start_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface, + u16 /* ether_type */, u8 *ip_packet, u16 ip_packet_len, u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec) +{ + if ((index > 0 && index <= N_AVAIL_ID) && (ip_packet != NULL) && (src_mac_addr != NULL) + && (dst_mac_addr != NULL) && (period_msec > 0) + && (ip_packet_len <= MKEEP_ALIVE_IP_PKT_MAX)) { + MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, ip_packet, ip_packet_len, + src_mac_addr, dst_mac_addr, period_msec, START_MKEEP_ALIVE); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; + } else { + ALOGE("Invalid mkeep_alive parameters"); + return WIFI_ERROR_INVALID_ARGS; + } +} + +/* API to stop sending mkeep_alive packet. */ +wifi_error wifi_stop_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface) +{ + if (index > 0 && index <= N_AVAIL_ID) { + MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, STOP_MKEEP_ALIVE); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; + } else { + ALOGE("Invalid mkeep_alive parameters"); + return WIFI_ERROR_INVALID_ARGS; + } +} diff --git a/wlan/wifi_hal/rtw_wifi_rtt.cpp b/wlan/wifi_hal/rtw_wifi_rtt.cpp new file mode 100644 index 0000000..813be0e --- /dev/null +++ b/wlan/wifi_hal/rtw_wifi_rtt.cpp @@ -0,0 +1,699 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "nl80211_copy.h" + +#include "sync.h" + +#define LOG_TAG "WifiHAL" + +#include +#include + +#include "wifi_hal.h" +#include "common.h" +#include "cpp_bindings.h" + +using namespace android; +#define RTT_RESULT_SIZE (sizeof(wifi_rtt_result)); +typedef enum { + + RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START, + RTT_SUBCMD_CANCEL_CONFIG, + RTT_SUBCMD_GETCAPABILITY, + RTT_SUBCMD_GETAVAILCHANNEL, + RTT_SUBCMD_SET_RESPONDER, + RTT_SUBCMD_CANCEL_RESPONDER, +} RTT_SUB_COMMAND; + +typedef enum { + RTT_ATTRIBUTE_TARGET_CNT = 0, + RTT_ATTRIBUTE_TARGET_INFO, + RTT_ATTRIBUTE_TARGET_MAC, + RTT_ATTRIBUTE_TARGET_TYPE, + RTT_ATTRIBUTE_TARGET_PEER, + RTT_ATTRIBUTE_TARGET_CHAN, + RTT_ATTRIBUTE_TARGET_PERIOD, + RTT_ATTRIBUTE_TARGET_NUM_BURST, + RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST, + RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM, + RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR, + RTT_ATTRIBUTE_TARGET_LCI, + RTT_ATTRIBUTE_TARGET_LCR, + RTT_ATTRIBUTE_TARGET_BURST_DURATION, + RTT_ATTRIBUTE_TARGET_PREAMBLE, + RTT_ATTRIBUTE_TARGET_BW, + RTT_ATTRIBUTE_RESULTS_COMPLETE = 30, + RTT_ATTRIBUTE_RESULTS_PER_TARGET, + RTT_ATTRIBUTE_RESULT_CNT, + RTT_ATTRIBUTE_RESULT +} RTT_ATTRIBUTE; +typedef struct strmap_entry { + int id; + String8 text; +} strmap_entry_t; +struct dot11_rm_ie { + u8 id; + u8 len; + u8 token; + u8 mode; + u8 type; +} __attribute__ ((packed)); +typedef struct dot11_rm_ie dot11_rm_ie_t; +#define DOT11_HDR_LEN 2 +#define DOT11_RM_IE_LEN 5 +#define DOT11_MNG_MEASURE_REQUEST_ID 38 /* 11H MeasurementRequest */ +#define DOT11_MEASURE_TYPE_LCI 8 /* d11 measurement LCI type */ +#define DOT11_MEASURE_TYPE_CIVICLOC 11 /* d11 measurement location civic */ + +static const strmap_entry_t err_info[] = { + {RTT_STATUS_SUCCESS, String8("Success")}, + {RTT_STATUS_FAILURE, String8("Failure")}, + {RTT_STATUS_FAIL_NO_RSP, String8("No reponse")}, + {RTT_STATUS_FAIL_INVALID_TS, String8("Invalid Timestamp")}, + {RTT_STATUS_FAIL_PROTOCOL, String8("Protocol error")}, + {RTT_STATUS_FAIL_REJECTED, String8("Rejected")}, + {RTT_STATUS_FAIL_NOT_SCHEDULED_YET, String8("not scheduled")}, + {RTT_STATUS_FAIL_SCHEDULE, String8("schedule failed")}, + {RTT_STATUS_FAIL_TM_TIMEOUT, String8("timeout")}, + {RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL, String8("AP is on difference channel")}, + {RTT_STATUS_FAIL_NO_CAPABILITY, String8("no capability")}, + {RTT_STATUS_FAIL_BUSY_TRY_LATER, String8("busy and try later")}, + {RTT_STATUS_ABORTED, String8("aborted")} +}; + + static const char* +get_err_info(int status) +{ + int i; + const strmap_entry_t *p_entry; + int num_entries = sizeof(err_info)/ sizeof(err_info[0]); + /* scan thru the table till end */ + p_entry = err_info; + for (i = 0; i < (int) num_entries; i++) + { + if (p_entry->id == status) + return p_entry->text; + p_entry++; /* next entry */ + } + return "unknown error"; /* not found */ +} + +class GetRttCapabilitiesCommand : public WifiCommand +{ + wifi_rtt_capabilities *mCapabilities; +public: + GetRttCapabilitiesCommand(wifi_interface_handle iface, wifi_rtt_capabilities *capabitlites) + : WifiCommand("GetRttCapabilitiesCommand", iface, 0), mCapabilities(capabitlites) + { + memset(mCapabilities, 0, sizeof(*mCapabilities)); + } + + virtual int create() { + ALOGD("Creating message to get scan capablities; iface = %d", mIfaceInfo->id); + + int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_GETCAPABILITY); + if (ret < 0) { + return ret; + } + + return ret; + } + +protected: + virtual int handleResponse(WifiEvent& reply) { + + ALOGD("In GetRttCapabilitiesCommand::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + int id = reply.get_vendor_id(); + int subcmd = reply.get_vendor_subcmd(); + + void *data = reply.get_vendor_data(); + int len = reply.get_vendor_data_len(); + + ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len, + sizeof(*mCapabilities)); + + memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities))); + + return NL_OK; + } +}; + + +class GetRttResponderInfoCommand : public WifiCommand +{ + wifi_rtt_responder* mResponderInfo; +public: + GetRttResponderInfoCommand(wifi_interface_handle iface, wifi_rtt_responder *responderInfo) + : WifiCommand("GetRttResponderInfoCommand", iface, 0), mResponderInfo(responderInfo) + { + memset(mResponderInfo, 0 , sizeof(*mResponderInfo)); + + } + + virtual int create() { + ALOGD("Creating message to get responder info ; iface = %d", mIfaceInfo->id); + + int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_GETAVAILCHANNEL); + if (ret < 0) { + return ret; + } + + return ret; + } + +protected: + virtual int handleResponse(WifiEvent& reply) { + + ALOGD("In GetRttResponderInfoCommand::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + int id = reply.get_vendor_id(); + int subcmd = reply.get_vendor_subcmd(); + + void *data = reply.get_vendor_data(); + int len = reply.get_vendor_data_len(); + + ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len, + sizeof(*mResponderInfo)); + + memcpy(mResponderInfo, data, min(len, (int) sizeof(*mResponderInfo))); + + return NL_OK; + } +}; + + +class EnableResponderCommand : public WifiCommand +{ + wifi_channel_info mChannelInfo; + wifi_rtt_responder* mResponderInfo; + unsigned m_max_duration_sec; +public: + EnableResponderCommand(wifi_interface_handle iface, int id, wifi_channel_info channel_hint, + unsigned max_duration_seconds, wifi_rtt_responder *responderInfo) + : WifiCommand("EnableResponderCommand", iface, 0), mChannelInfo(channel_hint), + m_max_duration_sec(max_duration_seconds), mResponderInfo(responderInfo) + { + memset(mResponderInfo, 0, sizeof(*mResponderInfo)); + } + + virtual int create() { + ALOGD("Creating message to set responder ; iface = %d", mIfaceInfo->id); + + int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_SET_RESPONDER); + if (ret < 0) { + return ret; + } + + return ret; + } + +protected: + virtual int handleResponse(WifiEvent& reply) { + + ALOGD("In EnableResponderCommand::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + int id = reply.get_vendor_id(); + int subcmd = reply.get_vendor_subcmd(); + + void *data = reply.get_vendor_data(); + int len = reply.get_vendor_data_len(); + + ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len, + sizeof(*mResponderInfo)); + + memcpy(mResponderInfo, data, min(len, (int) sizeof(*mResponderInfo))); + + return NL_OK; + } +}; + + +class CancelResponderCommand : public WifiCommand +{ + +public: + CancelResponderCommand(wifi_interface_handle iface, int id) + : WifiCommand("CancelResponderCommand", iface, 0)/*, mChannelInfo(channel)*/ + { + + } + + virtual int create() { + ALOGD("Creating message to cancel responder ; iface = %d", mIfaceInfo->id); + + int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_CANCEL_RESPONDER); + if (ret < 0) { + return ret; + } + + return ret; + } + +protected: + virtual int handleResponse(WifiEvent& reply) { + /* Nothing to do on response! */ + return NL_SKIP; + } + +}; + + +class RttCommand : public WifiCommand +{ + unsigned numRttParams; + int mCompleted; + int currentIdx; + int totalCnt; + static const int MAX_RESULTS = 1024; + wifi_rtt_result *rttResults[MAX_RESULTS]; + wifi_rtt_config *rttParams; + wifi_rtt_event_handler rttHandler; +public: + RttCommand(wifi_interface_handle iface, int id, unsigned num_rtt_config, + wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler) + : WifiCommand("RttCommand", iface, id), numRttParams(num_rtt_config), rttParams(rtt_config), + rttHandler(handler) + { + memset(rttResults, 0, sizeof(rttResults)); + currentIdx = 0; + mCompleted = 0; + totalCnt = 0; + } + + RttCommand(wifi_interface_handle iface, int id) + : WifiCommand("RttCommand", iface, id) + { + currentIdx = 0; + mCompleted = 0; + totalCnt = 0; + numRttParams = 0; + } + + int createSetupRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, RTT_SUBCMD_SET_CONFIG); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, numRttParams); + if (result < 0) { + return result; + } + nlattr *rtt_config = request.attr_start(RTT_ATTRIBUTE_TARGET_INFO); + for (unsigned i = 0; i < numRttParams; i++) { + nlattr *attr2 = request.attr_start(i); + if (attr2 == NULL) { + return WIFI_ERROR_OUT_OF_MEMORY; + } + + result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, rttParams[i].addr); + if (result < 0) { + return result; + } + + result = request.put_u8(RTT_ATTRIBUTE_TARGET_TYPE, rttParams[i].type); + if (result < 0) { + return result; + } + + result = request.put_u8(RTT_ATTRIBUTE_TARGET_PEER, rttParams[i].peer); + if (result < 0) { + return result; + } + + result = request.put(RTT_ATTRIBUTE_TARGET_CHAN, &rttParams[i].channel, + sizeof(wifi_channel_info)); + if (result < 0) { + return result; + } + + result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_BURST, rttParams[i].num_burst); + if (result < 0) { + return result; + } + + result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST, + rttParams[i].num_frames_per_burst); + if (result < 0) { + return result; + } + + result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM, + rttParams[i].num_retries_per_rtt_frame); + if (result < 0) { + return result; + } + + result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR, + rttParams[i].num_retries_per_ftmr); + if (result < 0) { + return result; + } + + result = request.put_u32(RTT_ATTRIBUTE_TARGET_PERIOD, + rttParams[i].burst_period); + if (result < 0) { + return result; + } + + result = request.put_u32(RTT_ATTRIBUTE_TARGET_BURST_DURATION, + rttParams[i].burst_duration); + if (result < 0) { + return result; + } + + result = request.put_u8(RTT_ATTRIBUTE_TARGET_LCI, + rttParams[i].LCI_request); + if (result < 0) { + return result; + } + + result = request.put_u8(RTT_ATTRIBUTE_TARGET_LCR, + rttParams[i].LCR_request); + if (result < 0) { + return result; + } + + result = request.put_u8(RTT_ATTRIBUTE_TARGET_BW, + rttParams[i].bw); + if (result < 0) { + return result; + } + + result = request.put_u8(RTT_ATTRIBUTE_TARGET_PREAMBLE, + rttParams[i].preamble); + if (result < 0) { + return result; + } + request.attr_end(attr2); + } + + request.attr_end(rtt_config); + request.attr_end(data); + return WIFI_SUCCESS; + } + + int createTeardownRequest(WifiRequest& request, unsigned num_devices, mac_addr addr[]) { + int result = request.create(GOOGLE_OUI, RTT_SUBCMD_CANCEL_CONFIG); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, num_devices); + for(unsigned i = 0; i < num_devices; i++) { + result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, addr[i]); + if (result < 0) { + return result; + } + } + request.attr_end(data); + return result; + } + int start() { + ALOGD("Setting RTT configuration"); + WifiRequest request(familyId(), ifaceId()); + int result = createSetupRequest(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create setup request; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to configure RTT setup; result = %d", result); + return result; + } + + registerVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); + ALOGI("Successfully started RTT operation"); + return result; + } + + virtual int cancel() { + ALOGD("Stopping RTT"); + + WifiRequest request(familyId(), ifaceId()); + int result = createTeardownRequest(request, 0, NULL); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create stop request; result = %d", result); + } else { + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to stop scan; result = %d", result); + } + } + + unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); + return WIFI_SUCCESS; + } + + int cancel_specific(unsigned num_devices, mac_addr addr[]) { + ALOGE("Stopping RTT"); + + WifiRequest request(familyId(), ifaceId()); + int result = createTeardownRequest(request, num_devices, addr); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create stop request; result = %d", result); + } else { + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to stop RTT; result = %d", result); + } + } + + unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); + return WIFI_SUCCESS; + } + + virtual int handleResponse(WifiEvent& reply) { + /* Nothing to do on response! */ + return NL_SKIP; + } + + virtual int handleEvent(WifiEvent& event) { + ALOGI("Got an RTT event"); + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = event.get_vendor_data_len(); + if (vendor_data == NULL || len == 0) { + ALOGI("No rtt results found"); + } + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == RTT_ATTRIBUTE_RESULTS_COMPLETE) { + mCompleted = it.get_u32(); + ALOGI("retrieved completed flag : %d\n", mCompleted); + } else if (it.get_type() == RTT_ATTRIBUTE_RESULTS_PER_TARGET) { + int result_cnt = 0; + mac_addr bssid; + for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) { + if (it2.get_type() == RTT_ATTRIBUTE_TARGET_MAC) { + memcpy(bssid, it2.get_data(), sizeof(mac_addr)); + ALOGI("retrived target mac : %02x:%02x:%02x:%02x:%02x:%02x\n", + bssid[0], + bssid[1], + bssid[2], + bssid[3], + bssid[4], + bssid[5]); + } else if (it2.get_type() == RTT_ATTRIBUTE_RESULT_CNT) { + result_cnt = it2.get_u32(); + ALOGI("retrieved result_cnt : %d\n", result_cnt); + } else if (it2.get_type() == RTT_ATTRIBUTE_RESULT) { + int result_len = it2.get_len(); + rttResults[currentIdx] = (wifi_rtt_result *)malloc(it2.get_len()); + wifi_rtt_result *rtt_result = rttResults[currentIdx]; + if (rtt_result == NULL) { + mCompleted = 1; + ALOGE("failed to allocate the wifi_rtt_result\n"); + break; + } + memcpy(rtt_result, it2.get_data(), it2.get_len()); + result_len -= sizeof(wifi_rtt_result); + if (result_len > 0) { + result_len -= sizeof(wifi_rtt_result); + dot11_rm_ie_t *ele_1; + dot11_rm_ie_t *ele_2; + /* The result has LCI or LCR element */ + ele_1 = (dot11_rm_ie_t *)(rtt_result + 1); + if (ele_1->id == DOT11_MNG_MEASURE_REQUEST_ID) { + if (ele_1->type == DOT11_MEASURE_TYPE_LCI) { + rtt_result->LCI = (wifi_information_element *)ele_1; + result_len -= (ele_1->len + DOT11_HDR_LEN); + /* get a next rm ie */ + if (result_len > 0) { + ele_2 = (dot11_rm_ie_t *)((char *)ele_1 + (ele_1->len + DOT11_HDR_LEN)); + if ((ele_2->id == DOT11_MNG_MEASURE_REQUEST_ID) && + (ele_2->type == DOT11_MEASURE_TYPE_CIVICLOC)) { + rtt_result->LCR = (wifi_information_element *)ele_2; + } + } + } else if (ele_1->type == DOT11_MEASURE_TYPE_CIVICLOC){ + rtt_result->LCR = (wifi_information_element *)ele_1; + result_len -= (ele_1->len + DOT11_HDR_LEN); + /* get a next rm ie */ + if (result_len > 0) { + ele_2 = (dot11_rm_ie_t *)((char *)ele_1 + (ele_1->len + DOT11_HDR_LEN)); + if ((ele_2->id == DOT11_MNG_MEASURE_REQUEST_ID) && + (ele_2->type == DOT11_MEASURE_TYPE_LCI)) { + rtt_result->LCI = (wifi_information_element *)ele_2; + } + } + } + } + } + totalCnt++; + ALOGI("retrived rtt_result : \n\tburst_num :%d, measurement_number : %d, success_number : %d\n" + "\tnumber_per_burst_peer : %d, status : %s, retry_after_duration : %d s\n" + "\trssi : %d dbm, rx_rate : %d Kbps, rtt : %llu ns, rtt_sd : %llu\n" + "\tdistance : %d, burst_duration : %d ms, negotiated_burst_num : %d\n", + rtt_result->burst_num, rtt_result->measurement_number, + rtt_result->success_number, rtt_result->number_per_burst_peer, + get_err_info(rtt_result->status), rtt_result->retry_after_duration, + rtt_result->rssi, rtt_result->rx_rate.bitrate * 100, + rtt_result->rtt/10, rtt_result->rtt_sd, rtt_result->distance_mm / 10, + rtt_result->burst_duration, rtt_result->negotiated_burst_num); + currentIdx++; + } + } + } + + } + if (mCompleted) { + unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); + (*rttHandler.on_rtt_results)(id(), totalCnt, rttResults); + for (int i = 0; i < currentIdx; i++) { + free(rttResults[i]); + rttResults[i] = NULL; + } + totalCnt = currentIdx = 0; + WifiCommand *cmd = wifi_unregister_cmd(wifiHandle(), id()); + if (cmd) + cmd->releaseRef(); + } + return NL_SKIP; + } +}; + + +/* API to request RTT measurement */ +wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle iface, + unsigned num_rtt_config, wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler) +{ + wifi_handle handle = getWifiHandle(iface); + RttCommand *cmd = new RttCommand(iface, id, num_rtt_config, rtt_config, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, id, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, id); + cmd->releaseRef(); + return result; + } + return result; +} + +/* API to cancel RTT measurements */ +wifi_error wifi_rtt_range_cancel(wifi_request_id id, wifi_interface_handle iface, + unsigned num_devices, mac_addr addr[]) +{ + wifi_handle handle = getWifiHandle(iface); + RttCommand *cmd = new RttCommand(iface, id); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + cmd->cancel_specific(num_devices, addr); + cmd->releaseRef(); + return WIFI_SUCCESS; +} + +/* API to get RTT capability */ +wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface, + wifi_rtt_capabilities *capabilities) +{ + GetRttCapabilitiesCommand command(iface, capabilities); + return (wifi_error) command.requestResponse(); +} + +/* API to get the responder information */ +wifi_error wifi_rtt_get_responder_info(wifi_interface_handle iface, + wifi_rtt_responder* responderInfo) +{ + GetRttResponderInfoCommand command(iface, responderInfo); + return (wifi_error) command.requestResponse(); + +} + +/** + * Enable RTT responder mode. + * channel_hint - hint of the channel information where RTT responder should be enabled on. + * max_duration_seconds - timeout of responder mode. + * wifi_rtt_responder - information for RTT responder e.g. channel used and preamble supported. + */ +wifi_error wifi_enable_responder(wifi_request_id id, wifi_interface_handle iface, + wifi_channel_info channel_hint, unsigned max_duration_seconds, + wifi_rtt_responder* responderInfo) +{ + EnableResponderCommand command(iface, id, channel_hint, max_duration_seconds, responderInfo); + return (wifi_error) command.requestResponse(); +} + +/** + * Disable RTT responder mode. + */ +wifi_error wifi_disable_responder(wifi_request_id id, wifi_interface_handle iface) +{ + CancelResponderCommand command(iface, id); + return (wifi_error) command.requestResponse(); +} + diff --git a/wlan/wifi_hal/version.h b/wlan/wifi_hal/version.h new file mode 100644 index 0000000..ad2e795 --- /dev/null +++ b/wlan/wifi_hal/version.h @@ -0,0 +1,6 @@ +#ifndef VERSION_H +#define VERSION_H + +#define RTW_WIFI_HAL_VERSION "v1.0.3" + +#endif /* VERSION_H */ diff --git a/wlan/wifi_hal/wifi_hal.cpp b/wlan/wifi_hal/wifi_hal.cpp deleted file mode 100644 index cfc5e23..0000000 --- a/wlan/wifi_hal/wifi_hal.cpp +++ /dev/null @@ -1,1349 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "sync.h" - -#define LOG_TAG "WifiHAL" - -#include - -#include "wifi_hal.h" -#include "common.h" -#include "cpp_bindings.h" -#include "rtt.h" -/* - BUGBUG: normally, libnl allocates ports for all connections it makes; but - being a static library, it doesn't really know how many other netlink connections - are made by the same process, if connections come from different shared libraries. - These port assignments exist to solve that problem - temporarily. We need to fix - libnl to try and allocate ports across the entire process. - */ - -#define WIFI_HAL_CMD_SOCK_PORT 644 -#define WIFI_HAL_EVENT_SOCK_PORT 645 - -static void internal_event_handler(wifi_handle handle, int events); -static int internal_no_seq_check(nl_msg *msg, void *arg); -static int internal_valid_message_handler(nl_msg *msg, void *arg); -static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group); -static int wifi_add_membership(wifi_handle handle, const char *group); -static wifi_error wifi_init_interfaces(wifi_handle handle); -static wifi_error wifi_start_rssi_monitoring(wifi_request_id id, wifi_interface_handle - iface, s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh); -static wifi_error wifi_stop_rssi_monitoring(wifi_request_id id, wifi_interface_handle iface); -static wifi_error wifi_set_packet_filter(wifi_interface_handle handle, - const u8 *program, u32 len); -static wifi_error wifi_get_packet_filter_capabilities(wifi_interface_handle handle, - u32 *version, u32 *max_len); -static wifi_error wifi_configure_nd_offload(wifi_interface_handle iface, u8 enable); -static wifi_error wifi_get_wake_reason_stats(wifi_interface_handle iface, - WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt); - -typedef enum wifi_attr { - ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, - ANDR_WIFI_ATTRIBUTE_FEATURE_SET, - ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI, - ANDR_WIFI_ATTRIBUTE_NODFS_SET, - ANDR_WIFI_ATTRIBUTE_COUNTRY, - ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE - // Add more attribute here -} wifi_attr_t; - -enum wifi_rssi_monitor_attr { - RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, - RSSI_MONITOR_ATTRIBUTE_MIN_RSSI, - RSSI_MONITOR_ATTRIBUTE_START, -}; - -enum wifi_apf_attr { - APF_ATTRIBUTE_VERSION, - APF_ATTRIBUTE_MAX_LEN, - APF_ATTRIBUTE_PROGRAM, - APF_ATTRIBUTE_PROGRAM_LEN -}; - -enum apf_request_type { - GET_APF_CAPABILITIES, - SET_APF_PROGRAM -}; - -/* Initialize/Cleanup */ - -void wifi_socket_set_local_port(struct nl_sock *sock, uint32_t port) -{ - uint32_t pid = getpid() & 0x3FFFFF; - nl_socket_set_local_port(sock, pid + (port << 22)); -} - -static nl_sock * wifi_create_nl_socket(int port) -{ - // ALOGI("Creating socket"); - struct nl_sock *sock = nl_socket_alloc(); - if (sock == NULL) { - ALOGE("Could not create handle"); - return NULL; - } - - wifi_socket_set_local_port(sock, port); - - struct sockaddr *addr = NULL; - // ALOGI("sizeof(sockaddr) = %d, sizeof(sockaddr_nl) = %d", sizeof(*addr), sizeof(*addr_nl)); - - // ALOGI("Connecting socket"); - if (nl_connect(sock, NETLINK_GENERIC)) { - ALOGE("Could not connect handle"); - nl_socket_free(sock); - return NULL; - } - - // ALOGI("Making socket nonblocking"); - /* - if (nl_socket_set_nonblocking(sock)) { - ALOGE("Could make socket non-blocking"); - nl_socket_free(sock); - return NULL; - } - */ - - return sock; -} - -/*initialize function pointer table with Realtek HAL API*/ -wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn *fn) -{ - if (fn == NULL) { - return WIFI_ERROR_UNKNOWN; - } - fn->wifi_initialize = wifi_initialize; - fn->wifi_cleanup = wifi_cleanup; - fn->wifi_event_loop = wifi_event_loop; - fn->wifi_get_supported_feature_set = wifi_get_supported_feature_set; - fn->wifi_get_concurrency_matrix = wifi_get_concurrency_matrix; - fn->wifi_set_scanning_mac_oui = wifi_set_scanning_mac_oui; - fn->wifi_get_ifaces = wifi_get_ifaces; - fn->wifi_get_iface_name = wifi_get_iface_name; - fn->wifi_start_gscan = wifi_start_gscan; - fn->wifi_stop_gscan = wifi_stop_gscan; - fn->wifi_get_cached_gscan_results = wifi_get_cached_gscan_results; - fn->wifi_set_bssid_hotlist = wifi_set_bssid_hotlist; - fn->wifi_reset_bssid_hotlist = wifi_reset_bssid_hotlist; - fn->wifi_set_significant_change_handler = wifi_set_significant_change_handler; - fn->wifi_reset_significant_change_handler = wifi_reset_significant_change_handler; - fn->wifi_get_gscan_capabilities = wifi_get_gscan_capabilities; - fn->wifi_get_link_stats = wifi_get_link_stats; - fn->wifi_set_link_stats = wifi_set_link_stats; - fn->wifi_clear_link_stats = wifi_clear_link_stats; - fn->wifi_get_valid_channels = wifi_get_valid_channels; - fn->wifi_rtt_range_request = wifi_rtt_range_request; - fn->wifi_rtt_range_cancel = wifi_rtt_range_cancel; - fn->wifi_get_rtt_capabilities = wifi_get_rtt_capabilities; - fn->wifi_rtt_get_responder_info = wifi_rtt_get_responder_info; - fn->wifi_enable_responder = wifi_enable_responder; - fn->wifi_disable_responder = wifi_disable_responder; - fn->wifi_set_nodfs_flag = wifi_set_nodfs_flag; - fn->wifi_start_logging = wifi_start_logging; - fn->wifi_set_epno_list = wifi_set_epno_list; - fn->wifi_reset_epno_list = wifi_reset_epno_list; - fn->wifi_set_country_code = wifi_set_country_code; - fn->wifi_get_firmware_memory_dump = wifi_get_firmware_memory_dump; - fn->wifi_set_log_handler = wifi_set_log_handler; - fn->wifi_reset_log_handler = wifi_reset_log_handler; - fn->wifi_set_alert_handler = wifi_set_alert_handler; - fn->wifi_reset_alert_handler = wifi_reset_alert_handler; - fn->wifi_get_firmware_version = wifi_get_firmware_version; - fn->wifi_get_ring_buffers_status = wifi_get_ring_buffers_status; - fn->wifi_get_logger_supported_feature_set = wifi_get_logger_supported_feature_set; - fn->wifi_get_ring_data = wifi_get_ring_data; - fn->wifi_get_driver_version = wifi_get_driver_version; - fn->wifi_start_rssi_monitoring = wifi_start_rssi_monitoring; - fn->wifi_stop_rssi_monitoring = wifi_stop_rssi_monitoring; - fn->wifi_configure_nd_offload = wifi_configure_nd_offload; - fn->wifi_start_sending_offloaded_packet = wifi_start_sending_offloaded_packet; - fn->wifi_stop_sending_offloaded_packet = wifi_stop_sending_offloaded_packet; - fn->wifi_start_pkt_fate_monitoring = wifi_start_pkt_fate_monitoring; - fn->wifi_get_tx_pkt_fates = wifi_get_tx_pkt_fates; - fn->wifi_get_rx_pkt_fates = wifi_get_rx_pkt_fates; - fn->wifi_get_packet_filter_capabilities = wifi_get_packet_filter_capabilities; - fn->wifi_set_packet_filter = wifi_set_packet_filter; - fn->wifi_get_wake_reason_stats = wifi_get_wake_reason_stats; - return WIFI_SUCCESS; -} - -wifi_error wifi_initialize(wifi_handle *handle) -{ - srand(getpid()); - - ALOGI("Initializing wifi"); - hal_info *info = (hal_info *)malloc(sizeof(hal_info)); - if (info == NULL) { - ALOGE("Could not allocate hal_info"); - return WIFI_ERROR_UNKNOWN; - } - - memset(info, 0, sizeof(*info)); - - ALOGI("Creating socket"); - if (socketpair(AF_UNIX, SOCK_STREAM, 0, info->cleanup_socks) == -1) { - ALOGE("Could not create cleanup sockets"); - free(info); - return WIFI_ERROR_UNKNOWN; - } - - struct nl_sock *cmd_sock = wifi_create_nl_socket(WIFI_HAL_CMD_SOCK_PORT); - if (cmd_sock == NULL) { - ALOGE("Could not create handle"); - free(info); - return WIFI_ERROR_UNKNOWN; - } - - struct nl_sock *event_sock = wifi_create_nl_socket(WIFI_HAL_EVENT_SOCK_PORT); - if (event_sock == NULL) { - ALOGE("Could not create handle"); - nl_socket_free(cmd_sock); - free(info); - return WIFI_ERROR_UNKNOWN; - } - - struct nl_cb *cb = nl_socket_get_cb(event_sock); - if (cb == NULL) { - ALOGE("Could not create handle"); - nl_socket_free(cmd_sock); - nl_socket_free(event_sock); - free(info); - return WIFI_ERROR_UNKNOWN; - } - - // ALOGI("cb->refcnt = %d", cb->cb_refcnt); - nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, internal_no_seq_check, info); - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, internal_valid_message_handler, info); - nl_cb_put(cb); - - info->cmd_sock = cmd_sock; - info->event_sock = event_sock; - info->clean_up = false; - info->in_event_loop = false; - - info->event_cb = (cb_info *)malloc(sizeof(cb_info) * DEFAULT_EVENT_CB_SIZE); - info->alloc_event_cb = DEFAULT_EVENT_CB_SIZE; - info->num_event_cb = 0; - - info->cmd = (cmd_info *)malloc(sizeof(cmd_info) * DEFAULT_CMD_SIZE); - info->alloc_cmd = DEFAULT_CMD_SIZE; - info->num_cmd = 0; - - info->nl80211_family_id = genl_ctrl_resolve(cmd_sock, "nl80211"); - if (info->nl80211_family_id < 0) { - ALOGE("Could not resolve nl80211 familty id"); - nl_socket_free(cmd_sock); - nl_socket_free(event_sock); - free(info); - return WIFI_ERROR_UNKNOWN; - } - - pthread_mutex_init(&info->cb_lock, NULL); - - *handle = (wifi_handle) info; - - if (wifi_init_interfaces(*handle) != WIFI_SUCCESS) { - ALOGE("No wifi interface found"); - nl_socket_free(cmd_sock); - nl_socket_free(event_sock); - pthread_mutex_destroy(&info->cb_lock); - free(info); - return WIFI_ERROR_NOT_AVAILABLE; - } - - if ((wifi_add_membership(*handle, "scan") < 0) || - (wifi_add_membership(*handle, "mlme") < 0) || - (wifi_add_membership(*handle, "regulatory") < 0) || - (wifi_add_membership(*handle, "vendor") < 0)) { - ALOGE("Add membership failed"); - nl_socket_free(cmd_sock); - nl_socket_free(event_sock); - pthread_mutex_destroy(&info->cb_lock); - free(info); - return WIFI_ERROR_NOT_AVAILABLE; - } - - // ALOGI("Found %d interfaces", info->num_interfaces); - - ALOGI("Initialized Wifi HAL Successfully; vendor cmd = %d", NL80211_CMD_VENDOR); - return WIFI_SUCCESS; -} - -static int wifi_add_membership(wifi_handle handle, const char *group) -{ - hal_info *info = getHalInfo(handle); - - int id = wifi_get_multicast_id(handle, "nl80211", group); - if (id < 0) { - ALOGE("Could not find group %s", group); - return id; - } - - int ret = nl_socket_add_membership(info->event_sock, id); - if (ret < 0) { - ALOGE("Could not add membership to group %s", group); - } - - // ALOGI("Successfully added membership for group %s", group); - return ret; -} - -static void internal_cleaned_up_handler(wifi_handle handle) -{ - hal_info *info = getHalInfo(handle); - wifi_cleaned_up_handler cleaned_up_handler = info->cleaned_up_handler; - - if (info->cmd_sock != 0) { - close(info->cleanup_socks[0]); - close(info->cleanup_socks[1]); - nl_socket_free(info->cmd_sock); - nl_socket_free(info->event_sock); - info->cmd_sock = NULL; - info->event_sock = NULL; - } - - (*cleaned_up_handler)(handle); - pthread_mutex_destroy(&info->cb_lock); - free(info); - - ALOGI("Internal cleanup completed"); -} - -void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler) -{ - hal_info *info = getHalInfo(handle); - char buf[64]; - - info->cleaned_up_handler = handler; - if (TEMP_FAILURE_RETRY(write(info->cleanup_socks[0], "Exit", 4)) < 1) { - // As a fallback set the cleanup flag to TRUE - ALOGE("could not write to the cleanup socket"); - } else { - // Listen to the response - // Hopefully we dont get errors or get hung up - // Not much can be done in that case, but assume that - // it has rx'ed the Exit message to exit the thread. - // As a fallback set the cleanup flag to TRUE - memset(buf, 0, sizeof(buf)); - ssize_t result = TEMP_FAILURE_RETRY(read(info->cleanup_socks[0], buf, sizeof(buf))); - ALOGE("%s: Read after POLL returned %zd, error no = %d (%s)", __FUNCTION__, - result, errno, strerror(errno)); - if (strncmp(buf, "Done", 4) == 0) { - ALOGE("Event processing terminated"); - } else { - ALOGD("Rx'ed %s", buf); - } - } - info->clean_up = true; - pthread_mutex_lock(&info->cb_lock); - - int bad_commands = 0; - - for (int i = 0; i < info->num_event_cb; i++) { - cb_info *cbi = &(info->event_cb[i]); - WifiCommand *cmd = (WifiCommand *)cbi->cb_arg; - ALOGI("Command left in event_cb %p:%s", cmd, (cmd ? cmd->getType(): "")); - } - - while (info->num_cmd > bad_commands) { - int num_cmd = info->num_cmd; - cmd_info *cmdi = &(info->cmd[bad_commands]); - WifiCommand *cmd = cmdi->cmd; - if (cmd != NULL) { - ALOGI("Cancelling command %p:%s", cmd, cmd->getType()); - pthread_mutex_unlock(&info->cb_lock); - cmd->cancel(); - pthread_mutex_lock(&info->cb_lock); - if (num_cmd == info->num_cmd) { - ALOGI("Cancelling command %p:%s did not work", cmd, (cmd ? cmd->getType(): "")); - bad_commands++; - } - /* release reference added when command is saved */ - cmd->releaseRef(); - } - } - - for (int i = 0; i < info->num_event_cb; i++) { - cb_info *cbi = &(info->event_cb[i]); - WifiCommand *cmd = (WifiCommand *)cbi->cb_arg; - ALOGE("Leaked command %p", cmd); - } - pthread_mutex_unlock(&info->cb_lock); - internal_cleaned_up_handler(handle); -} - -static int internal_pollin_handler(wifi_handle handle) -{ - hal_info *info = getHalInfo(handle); - struct nl_cb *cb = nl_socket_get_cb(info->event_sock); - int res = nl_recvmsgs(info->event_sock, cb); - // ALOGD("nl_recvmsgs returned %d", res); - nl_cb_put(cb); - return res; -} - -/* Run event handler */ -void wifi_event_loop(wifi_handle handle) -{ - hal_info *info = getHalInfo(handle); - if (info->in_event_loop) { - return; - } else { - info->in_event_loop = true; - } - - pollfd pfd[2]; - memset(&pfd[0], 0, sizeof(pollfd) * 2); - - pfd[0].fd = nl_socket_get_fd(info->event_sock); - pfd[0].events = POLLIN; - pfd[1].fd = info->cleanup_socks[1]; - pfd[1].events = POLLIN; - - char buf[2048]; - /* TODO: Add support for timeouts */ - - do { - int timeout = -1; /* Infinite timeout */ - pfd[0].revents = 0; - pfd[1].revents = 0; - // ALOGI("Polling socket"); - int result = TEMP_FAILURE_RETRY(poll(pfd, 2, timeout)); - if (result < 0) { - // ALOGE("Error polling socket"); - } else if (pfd[0].revents & POLLERR) { - ALOGE("POLL Error; error no = %d (%s)", errno, strerror(errno)); - ssize_t result2 = TEMP_FAILURE_RETRY(read(pfd[0].fd, buf, sizeof(buf))); - ALOGE("Read after POLL returned %zd, error no = %d (%s)", result2, - errno, strerror(errno)); - } else if (pfd[0].revents & POLLHUP) { - ALOGE("Remote side hung up"); - break; - } else if (pfd[0].revents & POLLIN) { - // ALOGI("Found some events!!!"); - internal_pollin_handler(handle); - } else if (pfd[1].revents & POLLIN) { - memset(buf, 0, sizeof(buf)); - ssize_t result2 = TEMP_FAILURE_RETRY(read(pfd[1].fd, buf, sizeof(buf))); - ALOGE("%s: Read after POLL returned %zd, error no = %d (%s)", __FUNCTION__, - result2, errno, strerror(errno)); - if (strncmp(buf, "Exit", 4) == 0) { - ALOGD("Got a signal to exit!!!"); - if (TEMP_FAILURE_RETRY(write(pfd[1].fd, "Done", 4)) < 1) { - ALOGE("could not write to the cleanup socket"); - } - break; - } else { - ALOGD("Rx'ed %s on the cleanup socket\n", buf); - } - } else { - ALOGE("Unknown event - %0x, %0x", pfd[0].revents, pfd[1].revents); - } - } while (!info->clean_up); - ALOGI("Exit %s", __FUNCTION__); -} - -/////////////////////////////////////////////////////////////////////////////////////// - -static int internal_no_seq_check(struct nl_msg *msg, void *arg) -{ - return NL_OK; -} - -static int internal_valid_message_handler(nl_msg *msg, void *arg) -{ - // ALOGI("got an event"); - - wifi_handle handle = (wifi_handle)arg; - hal_info *info = getHalInfo(handle); - - WifiEvent event(msg); - int res = event.parse(); - if (res < 0) { - ALOGE("Failed to parse event: %d", res); - return NL_SKIP; - } - - int cmd = event.get_cmd(); - uint32_t vendor_id = 0; - int subcmd = 0; - - if (cmd == NL80211_CMD_VENDOR) { - vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID); - subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD); - ALOGV("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x", - event.get_cmdString(), vendor_id, subcmd); - } else { - // ALOGV("event received %s", event.get_cmdString()); - } - - // ALOGV("event received %s, vendor_id = 0x%0x", event.get_cmdString(), vendor_id); - // event.log(); - - bool dispatched = false; - - pthread_mutex_lock(&info->cb_lock); - - for (int i = 0; i < info->num_event_cb; i++) { - if (cmd == info->event_cb[i].nl_cmd) { - if (cmd == NL80211_CMD_VENDOR - && ((vendor_id != info->event_cb[i].vendor_id) - || (subcmd != info->event_cb[i].vendor_subcmd))) - { - /* event for a different vendor, ignore it */ - continue; - } - - cb_info *cbi = &(info->event_cb[i]); - nl_recvmsg_msg_cb_t cb_func = cbi->cb_func; - void *cb_arg = cbi->cb_arg; - WifiCommand *cmd = (WifiCommand *)cbi->cb_arg; - if (cmd != NULL) { - cmd->addRef(); - } - pthread_mutex_unlock(&info->cb_lock); - if (cb_func) - (*cb_func)(msg, cb_arg); - if (cmd != NULL) { - cmd->releaseRef(); - } - - return NL_OK; - } - } - - pthread_mutex_unlock(&info->cb_lock); - return NL_OK; -} - -/////////////////////////////////////////////////////////////////////////////////////// - -class GetMulticastIdCommand : public WifiCommand -{ -private: - const char *mName; - const char *mGroup; - int mId; -public: - GetMulticastIdCommand(wifi_handle handle, const char *name, const char *group) - : WifiCommand("GetMulticastIdCommand", handle, 0) - { - mName = name; - mGroup = group; - mId = -1; - } - - int getId() { - return mId; - } - - virtual int create() { - int nlctrlFamily = genl_ctrl_resolve(mInfo->cmd_sock, "nlctrl"); - // ALOGI("ctrl family = %d", nlctrlFamily); - int ret = mMsg.create(nlctrlFamily, CTRL_CMD_GETFAMILY, 0, 0); - if (ret < 0) { - return ret; - } - ret = mMsg.put_string(CTRL_ATTR_FAMILY_NAME, mName); - return ret; - } - - virtual int handleResponse(WifiEvent& reply) { - - // ALOGI("handling reponse in %s", __func__); - - struct nlattr **tb = reply.attributes(); - struct genlmsghdr *gnlh = reply.header(); - struct nlattr *mcgrp = NULL; - int i; - - if (!tb[CTRL_ATTR_MCAST_GROUPS]) { - ALOGI("No multicast groups found"); - return NL_SKIP; - } else { - // ALOGI("Multicast groups attr size = %d", nla_len(tb[CTRL_ATTR_MCAST_GROUPS])); - } - - for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) { - - // ALOGI("Processing group"); - struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1]; - nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, (nlattr *)nla_data(mcgrp), - nla_len(mcgrp), NULL); - if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID]) { - continue; - } - - char *grpName = (char *)nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]); - int grpNameLen = nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME]); - - // ALOGI("Found group name %s", grpName); - - if (strncmp(grpName, mGroup, grpNameLen) != 0) - continue; - - mId = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]); - break; - } - - return NL_SKIP; - } - -}; - -class SetPnoMacAddrOuiCommand : public WifiCommand { - -private: - byte *mOui; - feature_set *fset; - feature_set *feature_matrix; - int *fm_size; - int set_size_max; -public: - SetPnoMacAddrOuiCommand(wifi_interface_handle handle, oui scan_oui) - : WifiCommand("SetPnoMacAddrOuiCommand", handle, 0) - { - mOui = scan_oui; - } - - int createRequest(WifiRequest& request, int subcmd, byte *scan_oui) { - int result = request.create(GOOGLE_OUI, subcmd); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put(ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI, scan_oui, DOT11_OUI_LEN); - if (result < 0) { - return result; - } - - request.attr_end(data); - return WIFI_SUCCESS; - - } - - int start() { - ALOGD("Sending mac address OUI"); - WifiRequest request(familyId(), ifaceId()); - int result = createRequest(request, WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI, mOui); - if (result != WIFI_SUCCESS) { - ALOGE("failed to create request; result = %d", result); - return result; - } - - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to set scanning mac OUI; result = %d", result); - } - - return result; - } -protected: - virtual int handleResponse(WifiEvent& reply) { - ALOGD("Request complete!"); - /* Nothing to do on response! */ - return NL_SKIP; - } -}; - -class SetNodfsCommand : public WifiCommand { - -private: - u32 mNoDfs; -public: - SetNodfsCommand(wifi_interface_handle handle, u32 nodfs) - : WifiCommand("SetNodfsCommand", handle, 0) { - mNoDfs = nodfs; - } - virtual int create() { - int ret; - - ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_NODFS_SET); - if (ret < 0) { - ALOGE("Can't create message to send to driver - %d", ret); - return ret; - } - - nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA); - ret = mMsg.put_u32(ANDR_WIFI_ATTRIBUTE_NODFS_SET, mNoDfs); - if (ret < 0) { - return ret; - } - - mMsg.attr_end(data); - return WIFI_SUCCESS; - } -}; - -class SetCountryCodeCommand : public WifiCommand { -private: - const char *mCountryCode; -public: - SetCountryCodeCommand(wifi_interface_handle handle, const char *country_code) - : WifiCommand("SetCountryCodeCommand", handle, 0) { - mCountryCode = country_code; - } - virtual int create() { - int ret; - - ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_SET_COUNTRY_CODE); - if (ret < 0) { - ALOGE("Can't create message to send to driver - %d", ret); - return ret; - } - - nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA); - ret = mMsg.put_string(ANDR_WIFI_ATTRIBUTE_COUNTRY, mCountryCode); - if (ret < 0) { - return ret; - } - - mMsg.attr_end(data); - return WIFI_SUCCESS; - - } -}; - -class SetRSSIMonitorCommand : public WifiCommand { -private: - s8 mMax_rssi; - s8 mMin_rssi; - wifi_rssi_event_handler mHandler; -public: - SetRSSIMonitorCommand(wifi_request_id id, wifi_interface_handle handle, - s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh) - : WifiCommand("SetRSSIMonitorCommand", handle, id), mMax_rssi(max_rssi), mMin_rssi - (min_rssi), mHandler(eh) - { - } - int createRequest(WifiRequest& request, int enable) { - int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_SET_RSSI_MONITOR); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u32(RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, (enable ? mMax_rssi: 0)); - if (result < 0) { - return result; - } - ALOGD("create request"); - result = request.put_u32(RSSI_MONITOR_ATTRIBUTE_MIN_RSSI, (enable? mMin_rssi: 0)); - if (result < 0) { - return result; - } - result = request.put_u32(RSSI_MONITOR_ATTRIBUTE_START, enable); - if (result < 0) { - return result; - } - request.attr_end(data); - return result; - } - - int start() { - WifiRequest request(familyId(), ifaceId()); - int result = createRequest(request, 1); - if (result < 0) { - return result; - } - result = requestResponse(request); - if (result < 0) { - ALOGI("Failed to set RSSI Monitor, result = %d", result); - return result; - } - ALOGI("Successfully set RSSI monitoring"); - registerVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT); - - - if (result < 0) { - unregisterVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT); - return result; - } - ALOGI("Done!"); - return result; - } - - virtual int cancel() { - - WifiRequest request(familyId(), ifaceId()); - int result = createRequest(request, 0); - if (result != WIFI_SUCCESS) { - ALOGE("failed to create request; result = %d", result); - } else { - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to stop RSSI monitoring = %d", result); - } - } - unregisterVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT); - return WIFI_SUCCESS; - } - - virtual int handleResponse(WifiEvent& reply) { - /* Nothing to do on response! */ - return NL_SKIP; - } - - virtual int handleEvent(WifiEvent& event) { - ALOGI("Got a RSSI monitor event"); - - nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = event.get_vendor_data_len(); - - if (vendor_data == NULL || len == 0) { - ALOGI("RSSI monitor: No data"); - return NL_SKIP; - } - /* driver<->HAL event structure */ - #define RSSI_MONITOR_EVT_VERSION 1 - typedef struct { - u8 version; - s8 cur_rssi; - mac_addr BSSID; - } rssi_monitor_evt; - - rssi_monitor_evt *data = (rssi_monitor_evt *)event.get_vendor_data(); - - if (data->version != RSSI_MONITOR_EVT_VERSION) { - ALOGI("Event version mismatch %d, expected %d", data->version, RSSI_MONITOR_EVT_VERSION); - return NL_SKIP; - } - - if (*mHandler.on_rssi_threshold_breached) { - (*mHandler.on_rssi_threshold_breached)(id(), data->BSSID, data->cur_rssi); - } else { - ALOGW("No RSSI monitor handler registered"); - } - - return NL_SKIP; - } - -}; - -class AndroidPktFilterCommand : public WifiCommand { - private: - const u8* mProgram; - u32 mProgramLen; - u32* mVersion; - u32* mMaxLen; - int mReqType; - public: - AndroidPktFilterCommand(wifi_interface_handle handle, - u32* version, u32* max_len) - : WifiCommand("AndroidPktFilterCommand", handle, 0), - mVersion(version), mMaxLen(max_len), - mReqType(GET_APF_CAPABILITIES) - { - } - - AndroidPktFilterCommand(wifi_interface_handle handle, - const u8* program, u32 len) - : WifiCommand("AndroidPktFilterCommand", handle, 0), - mProgram(program), mProgramLen(len), - mReqType(SET_APF_PROGRAM) - { - } - - int createRequest(WifiRequest& request) { - if (mReqType == SET_APF_PROGRAM) { - ALOGI("\n%s: APF set program request\n", __FUNCTION__); - return createSetPktFilterRequest(request); - } else if (mReqType == GET_APF_CAPABILITIES) { - ALOGI("\n%s: APF get capabilities request\n", __FUNCTION__); - return createGetPktFilterCapabilitesRequest(request); - } else { - ALOGE("\n%s Unknown APF request\n", __FUNCTION__); - return WIFI_ERROR_NOT_SUPPORTED; - } - return WIFI_SUCCESS; - } - - int createSetPktFilterRequest(WifiRequest& request) { - u8 *program = new u8[mProgramLen]; - NULL_CHECK_RETURN(program, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - int result = request.create(GOOGLE_OUI, APF_SUBCMD_SET_FILTER); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u32(APF_ATTRIBUTE_PROGRAM_LEN, mProgramLen); - if (result < 0) { - return result; - } - memcpy(program, mProgram, mProgramLen); - result = request.put(APF_ATTRIBUTE_PROGRAM, program, mProgramLen); - if (result < 0) { - return result; - } - request.attr_end(data); - delete[] program; - return result; - } - - int createGetPktFilterCapabilitesRequest(WifiRequest& request) { - int result = request.create(GOOGLE_OUI, APF_SUBCMD_GET_CAPABILITIES); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - request.attr_end(data); - return result; - } - - int start() { - WifiRequest request(familyId(), ifaceId()); - int result = createRequest(request); - if (result < 0) { - return result; - } - result = requestResponse(request); - if (result < 0) { - ALOGI("Request Response failed for APF, result = %d", result); - return result; - } - ALOGI("Done!"); - return result; - } - - int cancel() { - return WIFI_SUCCESS; - } - - int handleResponse(WifiEvent& reply) { - ALOGD("In SetAPFCommand::handleResponse"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - int id = reply.get_vendor_id(); - int subcmd = reply.get_vendor_subcmd(); - - nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = reply.get_vendor_data_len(); - - ALOGD("Id = %0x, subcmd = %d, len = %d", id, subcmd, len); - if (vendor_data == NULL || len == 0) { - ALOGE("no vendor data in SetAPFCommand response; ignoring it"); - return NL_SKIP; - } - if( mReqType == SET_APF_PROGRAM) { - ALOGD("Response recieved for set packet filter command\n"); - } else if (mReqType == GET_APF_CAPABILITIES) { - *mVersion = 0; - *mMaxLen = 0; - ALOGD("Response recieved for get packet filter capabilities command\n"); - for (nl_iterator it(vendor_data); it.has_next(); it.next()) { - if (it.get_type() == APF_ATTRIBUTE_VERSION) { - *mVersion = it.get_u32(); - ALOGI("APF version is %d\n", *mVersion); - } else if (it.get_type() == APF_ATTRIBUTE_MAX_LEN) { - *mMaxLen = it.get_u32(); - ALOGI("APF max len is %d\n", *mMaxLen); - } else { - ALOGE("Ignoring invalid attribute type = %d, size = %d", - it.get_type(), it.get_len()); - } - } - } - return NL_OK; - } - - int handleEvent(WifiEvent& event) { - /* No Event to recieve for APF commands */ - return NL_SKIP; - } -}; - -class SetNdoffloadCommand : public WifiCommand { - -private: - u8 mEnable; -public: - SetNdoffloadCommand(wifi_interface_handle handle, u8 enable) - : WifiCommand("SetNdoffloadCommand", handle, 0) { - mEnable = enable; - } - virtual int create() { - int ret; - - ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_CONFIG_ND_OFFLOAD); - if (ret < 0) { - ALOGE("Can't create message to send to driver - %d", ret); - return ret; - } - - nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA); - ret = mMsg.put_u8(ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE, mEnable); - if (ret < 0) { - return ret; - } - - mMsg.attr_end(data); - return WIFI_SUCCESS; - } -}; - -class GetFeatureSetCommand : public WifiCommand { - -private: - int feature_type; - feature_set *fset; - feature_set *feature_matrix; - int *fm_size; - int set_size_max; -public: - GetFeatureSetCommand(wifi_interface_handle handle, int feature, feature_set *set, - feature_set set_matrix[], int *size, int max_size) - : WifiCommand("GetFeatureSetCommand", handle, 0) - { - feature_type = feature; - fset = set; - feature_matrix = set_matrix; - fm_size = size; - set_size_max = max_size; - } - - virtual int create() { - int ret; - - if(feature_type == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) { - ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_FEATURE_SET); - } else if (feature_type == ANDR_WIFI_ATTRIBUTE_FEATURE_SET) { - ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_FEATURE_SET_MATRIX); - } else { - ALOGE("Unknown feature type %d", feature_type); - return -1; - } - - if (ret < 0) { - ALOGE("Can't create message to send to driver - %d", ret); - } - - return ret; - } - -protected: - virtual int handleResponse(WifiEvent& reply) { - - ALOGV("In GetFeatureSetCommand::handleResponse"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - int id = reply.get_vendor_id(); - int subcmd = reply.get_vendor_subcmd(); - - nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = reply.get_vendor_data_len(); - - ALOGV("Id = %0x, subcmd = %d, len = %d", id, subcmd, len); - if (vendor_data == NULL || len == 0) { - ALOGE("no vendor data in GetFeatureSetCommand response; ignoring it"); - return NL_SKIP; - } - if(feature_type == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) { - void *data = reply.get_vendor_data(); - if(!fset) { - ALOGE("Buffers pointers not set"); - return NL_SKIP; - } - memcpy(fset, data, min(len, (int) sizeof(*fset))); - } else { - int num_features_set = 0; - int i = 0; - - if(!feature_matrix || !fm_size) { - ALOGE("Buffers pointers not set"); - return NL_SKIP; - } - - for (nl_iterator it(vendor_data); it.has_next(); it.next()) { - if (it.get_type() == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) { - num_features_set = it.get_u32(); - ALOGV("Got feature list with %d concurrent sets", num_features_set); - if(set_size_max && (num_features_set > set_size_max)) - num_features_set = set_size_max; - *fm_size = num_features_set; - } else if ((it.get_type() == ANDR_WIFI_ATTRIBUTE_FEATURE_SET) && - i < num_features_set) { - feature_matrix[i] = it.get_u32(); - i++; - } else { - ALOGW("Ignoring invalid attribute type = %d, size = %d", - it.get_type(), it.get_len()); - } - } - - } - return NL_OK; - } - -}; - -static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group) -{ - GetMulticastIdCommand cmd(handle, name, group); - int res = cmd.requestResponse(); - if (res < 0) - return res; - else - return cmd.getId(); -} - -///////////////////////////////////////////////////////////////////////// - -static bool is_wifi_interface(const char *name) -{ - if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "p2p", 3) != 0) { - /* not a wifi interface; ignore it */ - return false; - } else { - return true; - } -} - -static int get_interface(const char *name, interface_info *info) -{ - strcpy(info->name, name); - info->id = if_nametoindex(name); - // ALOGI("found an interface : %s, id = %d", name, info->id); - return WIFI_SUCCESS; -} - -wifi_error wifi_init_interfaces(wifi_handle handle) -{ - hal_info *info = (hal_info *)handle; - - struct dirent *de; - - DIR *d = opendir("/sys/class/net"); - if (d == 0) - return WIFI_ERROR_UNKNOWN; - - int n = 0; - while ((de = readdir(d))) { - if (de->d_name[0] == '.') - continue; - if (is_wifi_interface(de->d_name) ) { - n++; - } - } - - closedir(d); - - if (n == 0) - return WIFI_ERROR_NOT_AVAILABLE; - - d = opendir("/sys/class/net"); - if (d == 0) - return WIFI_ERROR_UNKNOWN; - - info->interfaces = (interface_info **)malloc(sizeof(interface_info *) * n); - - int i = 0; - while ((de = readdir(d))) { - if (de->d_name[0] == '.') - continue; - if (is_wifi_interface(de->d_name)) { - interface_info *ifinfo = (interface_info *)malloc(sizeof(interface_info)); - if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) { - free(ifinfo); - continue; - } - ifinfo->handle = handle; - info->interfaces[i] = ifinfo; - i++; - } - } - - closedir(d); - - info->num_interfaces = n; - return WIFI_SUCCESS; -} - -wifi_error wifi_get_ifaces(wifi_handle handle, int *num, wifi_interface_handle **interfaces) -{ - hal_info *info = (hal_info *)handle; - - *interfaces = (wifi_interface_handle *)info->interfaces; - *num = info->num_interfaces; - - return WIFI_SUCCESS; -} - -wifi_error wifi_get_iface_name(wifi_interface_handle handle, char *name, size_t size) -{ - interface_info *info = (interface_info *)handle; - strcpy(name, info->name); - return WIFI_SUCCESS; -} - -wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set *set) -{ - GetFeatureSetCommand command(handle, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, set, NULL, NULL, 1); - return (wifi_error) command.requestResponse(); -} - -wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int set_size_max, - feature_set set[], int *set_size) -{ - GetFeatureSetCommand command(handle, ANDR_WIFI_ATTRIBUTE_FEATURE_SET, NULL, - set, set_size, set_size_max); - return (wifi_error) command.requestResponse(); -} - -wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui) -{ -#if 0 - SetPnoMacAddrOuiCommand command(handle, scan_oui); - return (wifi_error)command.start(); -#endif - return WIFI_SUCCESS; - -} - -wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs) -{ - SetNodfsCommand command(handle, nodfs); - return (wifi_error) command.requestResponse(); -} - -wifi_error wifi_set_country_code(wifi_interface_handle handle, const char *country_code) -{ -#if 0 - SetCountryCodeCommand command(handle, country_code); - return (wifi_error) command.requestResponse(); -#endif - return WIFI_SUCCESS ; -} - -static wifi_error wifi_start_rssi_monitoring(wifi_request_id id, wifi_interface_handle - iface, s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh) -{ - ALOGD("Start RSSI monitor %d", id); - wifi_handle handle = getWifiHandle(iface); - SetRSSIMonitorCommand *cmd = new SetRSSIMonitorCommand(id, iface, max_rssi, min_rssi, eh); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = wifi_register_cmd(handle, id, cmd); - if (result != WIFI_SUCCESS) { - cmd->releaseRef(); - return result; - } - result = (wifi_error)cmd->start(); - if (result != WIFI_SUCCESS) { - wifi_unregister_cmd(handle, id); - cmd->releaseRef(); - return result; - } - return result; -} - -static wifi_error wifi_stop_rssi_monitoring(wifi_request_id id, wifi_interface_handle iface) -{ - ALOGD("Stopping RSSI monitor"); - - if(id == -1) { - wifi_rssi_event_handler handler; - s8 max_rssi = 0, min_rssi = 0; - wifi_handle handle = getWifiHandle(iface); - memset(&handler, 0, sizeof(handler)); - SetRSSIMonitorCommand *cmd = new SetRSSIMonitorCommand(id, iface, - max_rssi, min_rssi, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - cmd->cancel(); - cmd->releaseRef(); - return WIFI_SUCCESS; - } - return wifi_cancel_cmd(id, iface); -} - -static wifi_error wifi_get_packet_filter_capabilities(wifi_interface_handle handle, - u32 *version, u32 *max_len) -{ -#if 0 - ALOGD("Getting APF capabilities, halHandle = %p\n", handle); - AndroidPktFilterCommand *cmd = new AndroidPktFilterCommand(handle, version, max_len); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = (wifi_error)cmd->start(); - if (result == WIFI_SUCCESS) { - ALOGD("Getting APF capability, version = %d, max_len = %d\n", *version, *max_len); - } - cmd->releaseRef(); - return result; -#endif - return WIFI_SUCCESS; -} - -static wifi_error wifi_set_packet_filter(wifi_interface_handle handle, - const u8 *program, u32 len) -{ - ALOGD("Setting APF program, halHandle = %p\n", handle); - AndroidPktFilterCommand *cmd = new AndroidPktFilterCommand(handle, program, len); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = (wifi_error)cmd->start(); - cmd->releaseRef(); - return result; -} - -static wifi_error wifi_configure_nd_offload(wifi_interface_handle handle, u8 enable) -{ -#if 0 - SetNdoffloadCommand command(handle, enable); - return (wifi_error) command.requestResponse(); -#endif - return WIFI_SUCCESS; -} - -static wifi_error wifi_get_wake_reason_stats (wifi_interface_handle handle, - WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt) { - - return WIFI_SUCCESS; -} - -///////////////////////////////////////////////////////////////////////////// diff --git a/wlan/wifi_hal/wifi_logger.cpp b/wlan/wifi_hal/wifi_logger.cpp deleted file mode 100644 index d53a010..0000000 --- a/wlan/wifi_hal/wifi_logger.cpp +++ /dev/null @@ -1,1148 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "nl80211_copy.h" -#include "sync.h" - -#define LOG_TAG "WifiHAL" - -#include - -#include "wifi_hal.h" -#include "common.h" -#include "cpp_bindings.h" - -typedef enum { - LOGGER_START_LOGGING = ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START, - LOGGER_TRIGGER_MEM_DUMP, - LOGGER_GET_MEM_DUMP, - LOGGER_GET_VER, - LOGGER_GET_RING_STATUS, - LOGGER_GET_RING_DATA, - LOGGER_GET_FEATURE, - LOGGER_RESET_LOGGING, - LOGGER_TRIGGER_DRIVER_MEM_DUMP, - LOGGER_GET_DRIVER_MEM_DUMP, - LOGGER_START_PKT_FATE_MONITORING, - LOGGER_GET_TX_PKT_FATES, - LOGGER_GET_RX_PKT_FATES, -} DEBUG_SUB_COMMAND; - -typedef enum { - LOGGER_ATTRIBUTE_DRIVER_VER, - LOGGER_ATTRIBUTE_FW_VER, - LOGGER_ATTRIBUTE_RING_ID, - LOGGER_ATTRIBUTE_RING_NAME, - LOGGER_ATTRIBUTE_RING_FLAGS, - LOGGER_ATTRIBUTE_LOG_LEVEL, - LOGGER_ATTRIBUTE_LOG_TIME_INTVAL, - LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE, - LOGGER_ATTRIBUTE_FW_DUMP_LEN, - LOGGER_ATTRIBUTE_FW_DUMP_DATA, - // LOGGER_ATTRIBUTE_FW_ERR_CODE, - LOGGER_ATTRIBUTE_RING_DATA, - LOGGER_ATTRIBUTE_RING_STATUS, - LOGGER_ATTRIBUTE_RING_NUM, - LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN, - LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA, - LOGGER_ATTRIBUTE_PKT_FATE_NUM, - LOGGER_ATTRIBUTE_PKT_FATE_DATA, -} LOGGER_ATTRIBUTE; - -typedef enum { - DEBUG_OFF = 0, - DEBUG_NORMAL, - DEBUG_VERBOSE, - DEBUG_VERY, - DEBUG_VERY_VERY, -} LOGGER_LEVEL; - -typedef enum { - GET_FW_VER, - GET_DRV_VER, - GET_RING_DATA, - GET_RING_STATUS, - GET_FEATURE, - START_RING_LOG, -} GetCmdType; - -typedef enum { - PACKET_MONITOR_START, - TX_PACKET_FATE, - RX_PACKET_FATE, -} PktFateReqType; - - -/////////////////////////////////////////////////////////////////////////////// -class DebugCommand : public WifiCommand -{ - char *mBuff; - int *mBuffSize; - u32 *mNumRings; - wifi_ring_buffer_status *mStatus; - unsigned int *mSupport; - u32 mVerboseLevel; - u32 mFlags; - u32 mMaxIntervalSec; - u32 mMinDataSize; - char *mRingName; - GetCmdType mType; - -public: - - // constructor for get version - DebugCommand(wifi_interface_handle iface, char *buffer, int *buffer_size, - GetCmdType cmdType) - : WifiCommand("DebugCommand", iface, 0), mBuff(buffer), mBuffSize(buffer_size), mType - (cmdType) - { - memset(mBuff, 0, *mBuffSize); - } - - // constructor for ring data - DebugCommand(wifi_interface_handle iface, char *ring_name, GetCmdType cmdType) - : WifiCommand("DebugCommand", iface, 0), mRingName(ring_name), mType(cmdType) - { } - - // constructor for ring status - DebugCommand(wifi_interface_handle iface, u32 *num_rings, - wifi_ring_buffer_status *status, GetCmdType cmdType) - : WifiCommand("DebugCommand", iface, 0), mNumRings(num_rings), mStatus(status), mType(cmdType) - { - memset(mStatus, 0, sizeof(wifi_ring_buffer_status) * (*mNumRings)); - } - - // constructor for feature set - DebugCommand(wifi_interface_handle iface, unsigned int *support, GetCmdType cmdType) - : WifiCommand("DebugCommand", iface, 0), mSupport(support), mType(cmdType) - { } - - // constructor for ring params - DebugCommand(wifi_interface_handle iface, u32 verbose_level, u32 flags, - u32 max_interval_sec, u32 min_data_size, char *ring_name, GetCmdType cmdType) - : WifiCommand("DebugCommand", iface, 0), mVerboseLevel(verbose_level), mFlags(flags), - mMaxIntervalSec(max_interval_sec), mMinDataSize(min_data_size), - mRingName(ring_name), mType(cmdType) - { } - - int createRingRequest(WifiRequest& request) { - int result = request.create(GOOGLE_OUI, LOGGER_START_LOGGING); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to create start ring logger request; result = %d", result); - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - - result = request.put_u32(LOGGER_ATTRIBUTE_LOG_LEVEL, mVerboseLevel); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to put log level; result = %d", result); - return result; - } - result = request.put_u32(LOGGER_ATTRIBUTE_RING_FLAGS, mFlags); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to put ring flags; result = %d", result); - return result; - } - result = request.put_u32(LOGGER_ATTRIBUTE_LOG_TIME_INTVAL, mMaxIntervalSec); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to put log time interval; result = %d", result); - return result; - } - result = request.put_u32(LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE, mMinDataSize); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to put min data size; result = %d", result); - return result; - } - result = request.put_string(LOGGER_ATTRIBUTE_RING_NAME, mRingName); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to put ringbuffer name; result = %d", result); - return result; - } - request.attr_end(data); - - return WIFI_SUCCESS; - } - - int createRequest(WifiRequest &request) { - int result; - - switch (mType) { - case GET_FW_VER: - { - result = request.create(GOOGLE_OUI, LOGGER_GET_VER); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to create get fw version request; result = %d", result); - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - - // Driver expecting only attribute type, passing mbuff as data with - // length 0 to avoid undefined state - result = request.put(LOGGER_ATTRIBUTE_FW_VER, mBuff, 0); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to put get fw version request; result = %d", result); - return result; - } - request.attr_end(data); - break; - } - - case GET_DRV_VER: - { - result = request.create(GOOGLE_OUI, LOGGER_GET_VER); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to create get drv version request; result = %d", result); - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - - // Driver expecting only attribute type, passing mbuff as data with - // length 0 to avoid undefined state - result = request.put(LOGGER_ATTRIBUTE_DRIVER_VER, mBuff, 0); - - if (result != WIFI_SUCCESS) { - ALOGE("Failed to put get drv version request; result = %d", result); - return result; - } - request.attr_end(data); - break; - } - - case GET_RING_DATA: - { - result = request.create(GOOGLE_OUI, LOGGER_GET_RING_DATA); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to create get ring data request; result = %d", result); - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_string(LOGGER_ATTRIBUTE_RING_NAME, mRingName); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to put ring data request; result = %d", result); - return result; - } - request.attr_end(data); - break; - } - - case GET_RING_STATUS: - { - result = request.create(GOOGLE_OUI, LOGGER_GET_RING_STATUS); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to create get ring status request; result = %d", result); - return result; - } - break; - } - - case GET_FEATURE: - { - result = request.create(GOOGLE_OUI, LOGGER_GET_FEATURE); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to create get feature request; result = %d", result); - return result; - } - break; - } - - case START_RING_LOG: - result = createRingRequest(request); - break; - - default: - ALOGE("Unknown Debug command"); - result = WIFI_ERROR_UNKNOWN; - } - return result; - } - - int start() { - // ALOGD("Start debug command"); - WifiRequest request(familyId(), ifaceId()); - int result = createRequest(request); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to create debug request; result = %d", result); - return result; - } - - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to register debug response; result = %d", result); - } - return result; - } - - virtual int handleResponse(WifiEvent& reply) { - ALOGD("In DebugCommand::handleResponse"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - switch (mType) { - case GET_DRV_VER: - case GET_FW_VER: - { - void *data = reply.get_vendor_data(); - int len = reply.get_vendor_data_len(); - - ALOGD("len = %d, expected len = %d", len, *mBuffSize); - memcpy(mBuff, data, min(len, *mBuffSize)); - if (*mBuffSize < len) - return NL_SKIP; - *mBuffSize = len; - break; - } - - case START_RING_LOG: - case GET_RING_DATA: - break; - - case GET_RING_STATUS: - { - nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = reply.get_vendor_data_len(); - wifi_ring_buffer_status *status(mStatus); - - if (vendor_data == NULL || len == 0) { - ALOGE("No Debug data found"); - return NL_SKIP; - } - - nl_iterator it(vendor_data); - if (it.get_type() == LOGGER_ATTRIBUTE_RING_NUM) { - unsigned int num_rings = it.get_u32(); - if (*mNumRings < num_rings) { - ALOGE("Not enough status buffers provided, available: %d required: %d", - *mNumRings, num_rings); - } else { - *mNumRings = num_rings; - } - } else { - ALOGE("Unknown attribute: %d expecting %d", - it.get_type(), LOGGER_ATTRIBUTE_RING_NUM); - return NL_SKIP; - } - - it.next(); - for (unsigned int i = 0; it.has_next() && i < *mNumRings; it.next()) { - if (it.get_type() == LOGGER_ATTRIBUTE_RING_STATUS) { - memcpy(status, it.get_data(), sizeof(wifi_ring_buffer_status)); - i++; - status++; - } else { - ALOGW("Ignoring invalid attribute type = %d, size = %d", - it.get_type(), it.get_len()); - } - } - break; - } - - case GET_FEATURE: - { - void *data = reply.get_vendor_data(); - int len = reply.get_vendor_data_len(); - - ALOGD("len = %d, expected len = %d", len, sizeof(unsigned int)); - memcpy(mSupport, data, sizeof(unsigned int)); - break; - } - - default: - ALOGW("Unknown Debug command"); - } - return NL_OK; - } - - virtual int handleEvent(WifiEvent& event) { - /* NO events! */ - return NL_SKIP; - } -}; - -/* API to collect a firmware version string */ -wifi_error wifi_get_firmware_version(wifi_interface_handle iface, char *buffer, - int buffer_size) -{ -#if 0 - if (buffer && (buffer_size > 0)) { - DebugCommand *cmd = new DebugCommand(iface, buffer, &buffer_size, GET_FW_VER); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = (wifi_error)cmd->start(); - cmd->releaseRef(); - return result; - } else { - ALOGE("FW version buffer NULL"); - return WIFI_ERROR_INVALID_ARGS; - } -#endif - std::string pFirmwareVer = "RTK_FIRMWARE"; - memcpy(buffer, pFirmwareVer.c_str(), pFirmwareVer.length()+1); - return WIFI_SUCCESS; -} - -/* API to collect a driver version string */ -wifi_error wifi_get_driver_version(wifi_interface_handle iface, char *buffer, int buffer_size) -{ -#if 0 - if (buffer && (buffer_size > 0)) { - DebugCommand *cmd = new DebugCommand(iface, buffer, &buffer_size, GET_DRV_VER); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = (wifi_error)cmd->start(); - cmd->releaseRef(); - return result; - } else { - ALOGE("Driver version buffer NULL"); - return WIFI_ERROR_INVALID_ARGS; - } -#endif - std::string pDriverVer = "RTK_DRIVER"; - memcpy(buffer, pDriverVer.c_str(), pDriverVer.length()+1); - return WIFI_SUCCESS; -} - -/* API to collect driver records */ -wifi_error wifi_get_ring_data(wifi_interface_handle iface, char *ring_name) -{ -#if 0 - DebugCommand *cmd = new DebugCommand(iface, ring_name, GET_RING_DATA); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = (wifi_error)cmd->start(); - cmd->releaseRef(); - return result; -#endif - return WIFI_SUCCESS; -} - -/* API to get the status of all ring buffers supported by driver */ -wifi_error wifi_get_ring_buffers_status(wifi_interface_handle iface, - u32 *num_rings, wifi_ring_buffer_status *status) -{ -#if 0 - if (status && num_rings) { - DebugCommand *cmd = new DebugCommand(iface, num_rings, status, GET_RING_STATUS); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = (wifi_error)cmd->start(); - cmd->releaseRef(); - return result; - } else { - ALOGE("Ring status buffer NULL"); - return WIFI_ERROR_INVALID_ARGS; - } -#endif - wifi_ring_buffer_status* pLocalstatus = NULL; - std::string from = "RTK_RING"; - memcpy(status->name, from.c_str(), strlen(from.c_str())+1); - *num_rings = 1; - - return WIFI_SUCCESS; -} - -/* API to get supportable feature */ -wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface, - unsigned int *support) -{ - if (support) { - wifi_error result = WIFI_SUCCESS; - #if 0 - DebugCommand *cmd = new DebugCommand(iface, support, GET_FEATURE); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = (wifi_error)cmd->start(); - cmd->releaseRef(); - #endif - *support = WIFI_LOGGER_MEMORY_DUMP_SUPPORTED; - - return result; - } else { - ALOGE("Get support buffer NULL"); - return WIFI_ERROR_INVALID_ARGS; - } -} - -wifi_error wifi_start_logging(wifi_interface_handle iface, u32 verbose_level, - u32 flags, u32 max_interval_sec, u32 min_data_size, char *ring_name) -{ -#if 0 - if (ring_name) { - DebugCommand *cmd = new DebugCommand(iface, verbose_level, flags, max_interval_sec, - min_data_size, ring_name, START_RING_LOG); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = (wifi_error)cmd->start(); - cmd->releaseRef(); - return result; - } else { - ALOGE("Ring name NULL"); - return WIFI_ERROR_INVALID_ARGS; - } -#endif - return WIFI_SUCCESS; -} - - -/////////////////////////////////////////////////////////////////////////////// -class SetLogHandler : public WifiCommand -{ - wifi_ring_buffer_data_handler mHandler; - -public: - SetLogHandler(wifi_interface_handle iface, int id, wifi_ring_buffer_data_handler handler) - : WifiCommand("SetLogHandler", iface, id), mHandler(handler) - { } - - int start() { - ALOGV("Register loghandler"); - registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); - return WIFI_SUCCESS; - } - - virtual int cancel() { - /* Send a command to driver to stop generating logging events */ - ALOGV("Clear loghandler"); - - /* unregister event handler */ - unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); - - WifiRequest request(familyId(), ifaceId()); - int result = request.create(GOOGLE_OUI, LOGGER_RESET_LOGGING); - if (result != WIFI_SUCCESS) { - ALOGE("failed to create reset request; result = %d", result); - return result; - } - - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("failed to request reset; result = %d", result); - return result; - } - - ALOGD("Success to clear loghandler"); - return WIFI_SUCCESS; - } - - virtual int handleEvent(WifiEvent& event) { - char *buffer = NULL; - int buffer_size = 0; - - // ALOGD("In SetLogHandler::handleEvent"); - nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = event.get_vendor_data_len(); - int event_id = event.get_vendor_subcmd(); - // ALOGI("Got Logger event: %d", event_id); - - if (vendor_data == NULL || len == 0) { - ALOGE("No Debug data found"); - return NL_SKIP; - } - - if(event_id == GOOGLE_DEBUG_RING_EVENT) { - wifi_ring_buffer_status status; - memset(&status, 0, sizeof(status)); - - for (nl_iterator it(vendor_data); it.has_next(); it.next()) { - if (it.get_type() == LOGGER_ATTRIBUTE_RING_STATUS) { - memcpy(&status, it.get_data(), sizeof(status)); - } else if (it.get_type() == LOGGER_ATTRIBUTE_RING_DATA) { - buffer_size = it.get_len(); - buffer = (char *)it.get_data(); - } else { - ALOGW("Ignoring invalid attribute type = %d, size = %d", - it.get_type(), it.get_len()); - } - } - - // ALOGI("Retrieved Debug data"); - if (mHandler.on_ring_buffer_data) { - (*mHandler.on_ring_buffer_data)((char *)status.name, buffer, buffer_size, - &status); - } - } else { - ALOGE("Unknown Event"); - return NL_SKIP; - } - return NL_OK; - } -}; - -wifi_error wifi_set_log_handler(wifi_request_id id, wifi_interface_handle iface, - wifi_ring_buffer_data_handler handler) -{ - wifi_handle handle = getWifiHandle(iface); - ALOGV("Loghandler start, handle = %p", handle); - - SetLogHandler *cmd = new SetLogHandler(iface, id, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = wifi_register_cmd(handle, id, cmd); - if (result != WIFI_SUCCESS) { - cmd->releaseRef(); - return result; - } - result = (wifi_error)cmd->start(); - if (result != WIFI_SUCCESS) { - wifi_unregister_cmd(handle, id); - cmd->releaseRef(); - return result; - } - return result; -} - -wifi_error wifi_reset_log_handler(wifi_request_id id, wifi_interface_handle iface) -{ - wifi_handle handle = getWifiHandle(iface); - ALOGV("Loghandler reset, wifi_request_id = %d, handle = %p", id, handle); - - if (id == -1) { - wifi_ring_buffer_data_handler handler; - memset(&handler, 0, sizeof(handler)); - - SetLogHandler *cmd = new SetLogHandler(iface, id, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - cmd->cancel(); - cmd->releaseRef(); - return WIFI_SUCCESS; - } - - return wifi_cancel_cmd(id, iface); -} - -/////////////////////////////////////////////////////////////////////////////// -class SetAlertHandler : public WifiCommand -{ - wifi_alert_handler mHandler; - int mBuffSize; - char *mBuff; - int mErrCode; - -public: - SetAlertHandler(wifi_interface_handle iface, int id, wifi_alert_handler handler) - : WifiCommand("SetAlertHandler", iface, id), mHandler(handler), mBuffSize(0), mBuff(NULL), - mErrCode(0) - { } - - int start() { - ALOGV("Start Alerting"); - registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_MEM_DUMP_EVENT); - return WIFI_SUCCESS; - } - - virtual int cancel() { - ALOGV("Clear alerthandler"); - - /* unregister alert handler */ - unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_MEM_DUMP_EVENT); - wifi_unregister_cmd(wifiHandle(), id()); - ALOGD("Success to clear alerthandler"); - return WIFI_SUCCESS; - } - - virtual int handleResponse(WifiEvent& reply) { - ALOGD("In SetAlertHandler::handleResponse"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = reply.get_vendor_data_len(); - - ALOGD("len = %d", len); - if (vendor_data == NULL || len == 0) { - ALOGE("no vendor data in memory dump response; ignoring it"); - return NL_SKIP; - } - - for (nl_iterator it(vendor_data); it.has_next(); it.next()) { - if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_DATA) { - ALOGI("Initiating alert callback"); - if (mHandler.on_alert) { - (*mHandler.on_alert)(id(), mBuff, mBuffSize, mErrCode); - } - if (mBuff) { - free(mBuff); - mBuff = NULL; - } - } - } - return NL_OK; - } - - virtual int handleEvent(WifiEvent& event) { - wifi_ring_buffer_id ring_id; - char *buffer = NULL; - int buffer_size = 0; - - - nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = event.get_vendor_data_len(); - int event_id = event.get_vendor_subcmd(); - ALOGI("Got event: %d", event_id); - - if (vendor_data == NULL || len == 0) { - ALOGE("No Debug data found"); - return NL_SKIP; - } - - if (event_id == GOOGLE_DEBUG_MEM_DUMP_EVENT) { - for (nl_iterator it(vendor_data); it.has_next(); it.next()) { - if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_LEN) { - mBuffSize = it.get_u32(); - } else if (it.get_type() == LOGGER_ATTRIBUTE_RING_DATA) { - buffer_size = it.get_len(); - buffer = (char *)it.get_data(); - /* - } else if (it.get_type() == LOGGER_ATTRIBUTE_FW_ERR_CODE) { - mErrCode = it.get_u32(); - */ - } else { - ALOGW("Ignoring invalid attribute type = %d, size = %d", - it.get_type(), it.get_len()); - } - } - if (mBuffSize) { - ALOGD("dump size: %d meta data size: %d", mBuffSize, buffer_size); - if (mBuff) free(mBuff); - mBuff = (char *)malloc(mBuffSize + buffer_size); - if (!mBuff) { - ALOGE("Buffer allocation failed"); - return NL_SKIP; - } - memcpy(mBuff, buffer, buffer_size); - - WifiRequest request(familyId(), ifaceId()); - int result = request.create(GOOGLE_OUI, LOGGER_GET_MEM_DUMP); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to create get memory dump request; result = %d", result); - free(mBuff); - return NL_SKIP; - } - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u32(LOGGER_ATTRIBUTE_FW_DUMP_LEN, mBuffSize); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to put get memory dump request; result = %d", result); - return result; - } - - result = request.put_u64(LOGGER_ATTRIBUTE_FW_DUMP_DATA, - (uint64_t)(mBuff+buffer_size)); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to put get memory dump request; result = %d", result); - return result; - } - - request.attr_end(data); - mBuffSize += buffer_size; - - result = requestResponse(request); - - if (result != WIFI_SUCCESS) { - ALOGE("Failed to register get momory dump response; result = %d", result); - } - } else { - ALOGE("dump event missing dump length attribute"); - return NL_SKIP; - } - } - return NL_OK; - } -}; - -wifi_error wifi_set_alert_handler(wifi_request_id id, wifi_interface_handle iface, - wifi_alert_handler handler) -{ - wifi_handle handle = getWifiHandle(iface); - ALOGV("Alerthandler start, handle = %p", handle); - - SetAlertHandler *cmd = new SetAlertHandler(iface, id, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = wifi_register_cmd(handle, id, cmd); - if (result != WIFI_SUCCESS) { - cmd->releaseRef(); - return result; - } - result = (wifi_error)cmd->start(); - if (result != WIFI_SUCCESS) { - wifi_unregister_cmd(handle, id); - cmd->releaseRef(); - return result; - } - return result; -} - -wifi_error wifi_reset_alert_handler(wifi_request_id id, wifi_interface_handle iface) -{ - wifi_handle handle = getWifiHandle(iface); - ALOGV("Alerthandler reset, wifi_request_id = %d, handle = %p", id, handle); - - if (id == -1) { - wifi_alert_handler handler; - memset(&handler, 0, sizeof(handler)); - - SetAlertHandler *cmd = new SetAlertHandler(iface, id, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - cmd->cancel(); - cmd->releaseRef(); - return WIFI_SUCCESS; - } - - return wifi_cancel_cmd(id, iface); -} - -/////////////////////////////////////////////////////////////////////////////// -class MemoryDumpCommand: public WifiCommand -{ - wifi_firmware_memory_dump_handler mHandler; - int mBuffSize; - char *mBuff; - -public: - MemoryDumpCommand(wifi_interface_handle iface, wifi_firmware_memory_dump_handler handler) - : WifiCommand("MemoryDumpCommand", iface, 0), mHandler(handler), mBuffSize(0), mBuff(NULL) - { } - - int start() { - ALOGD("Start memory dump command"); - WifiRequest request(familyId(), ifaceId()); - - int result = request.create(GOOGLE_OUI, LOGGER_TRIGGER_MEM_DUMP); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to create trigger fw memory dump request; result = %d", result); - return result; - } - - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to register trigger memory dump response; result = %d", result); - } - return result; - } - - virtual int handleResponse(WifiEvent& reply) { - ALOGD("In MemoryDumpCommand::handleResponse"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = reply.get_vendor_data_len(); - - ALOGD("len = %d", len); - if (vendor_data == NULL || len == 0) { - ALOGE("no vendor data in memory dump response; ignoring it"); - return NL_SKIP; - } - - for (nl_iterator it(vendor_data); it.has_next(); it.next()) { - if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_LEN) { - mBuffSize = it.get_u32(); - - if (mBuff) - free(mBuff); - mBuff = (char *)malloc(mBuffSize); - if (!mBuff) { - ALOGE("Buffer allocation failed"); - return NL_SKIP; - } - WifiRequest request(familyId(), ifaceId()); - int result = request.create(GOOGLE_OUI, LOGGER_GET_MEM_DUMP); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to create get memory dump request; result = %d", result); - free(mBuff); - return NL_SKIP; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u32(LOGGER_ATTRIBUTE_FW_DUMP_LEN, mBuffSize); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to put get memory dump request; result = %d", result); - return result; - } - - result = request.put_u64(LOGGER_ATTRIBUTE_FW_DUMP_DATA, (uint64_t)mBuff); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to put get memory dump request; result = %d", result); - return result; - } - request.attr_end(data); - - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to register get momory dump response; result = %d", result); - } - } else if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_DATA) { - ALOGI("Initiating memory dump callback"); - if (mHandler.on_firmware_memory_dump) { - (*mHandler.on_firmware_memory_dump)(mBuff, mBuffSize); - } - if (mBuff) { - free(mBuff); - mBuff = NULL; - } - } else { - ALOGW("Ignoring invalid attribute type = %d, size = %d", - it.get_type(), it.get_len()); - } - } - return NL_OK; - } - - virtual int handleEvent(WifiEvent& event) { - /* NO events! */ - return NL_SKIP; - } -}; - -/* API to collect a firmware memory dump for a given iface */ -wifi_error wifi_get_firmware_memory_dump( wifi_interface_handle iface, - wifi_firmware_memory_dump_handler handler) -{ -#if 0 - MemoryDumpCommand *cmd = new MemoryDumpCommand(iface, handler); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = (wifi_error)cmd->start(); - cmd->releaseRef(); - return result; -#endif - return WIFI_SUCCESS; -} - -class PacketFateCommand: public WifiCommand -{ - void *mReportBufs; - size_t mNoReqFates; - size_t *mNoProvidedFates; - PktFateReqType mReqType; - -public: - PacketFateCommand(wifi_interface_handle handle) - : WifiCommand("PacketFateCommand", handle, 0), mReqType(PACKET_MONITOR_START) - { } - - PacketFateCommand(wifi_interface_handle handle, wifi_tx_report *tx_report_bufs, - size_t n_requested_fates, size_t *n_provided_fates) - : WifiCommand("PacketFateCommand", handle, 0), mReportBufs(tx_report_bufs), - mNoReqFates(n_requested_fates), mNoProvidedFates(n_provided_fates), - mReqType(TX_PACKET_FATE) - { } - - PacketFateCommand(wifi_interface_handle handle, wifi_rx_report *rx_report_bufs, - size_t n_requested_fates, size_t *n_provided_fates) - : WifiCommand("PacketFateCommand", handle, 0), mReportBufs(rx_report_bufs), - mNoReqFates(n_requested_fates), mNoProvidedFates(n_provided_fates), - mReqType(RX_PACKET_FATE) - { } - - int createRequest(WifiRequest& request) { - if (mReqType == TX_PACKET_FATE) { - ALOGD("%s Get Tx packet fate request\n", __FUNCTION__); - return createTxPktFateRequest(request); - } else if (mReqType == RX_PACKET_FATE) { - ALOGD("%s Get Rx packet fate request\n", __FUNCTION__); - return createRxPktFateRequest(request); - } else if (mReqType == PACKET_MONITOR_START) { - ALOGD("%s Monitor packet fate request\n", __FUNCTION__); - return createMonitorPktFateRequest(request); - } else { - ALOGE("%s Unknown packet fate request\n", __FUNCTION__); - return WIFI_ERROR_NOT_SUPPORTED; - } - return WIFI_SUCCESS; - } - - int createMonitorPktFateRequest(WifiRequest& request) { - int result = request.create(GOOGLE_OUI, LOGGER_START_PKT_FATE_MONITORING); - if (result < 0) { - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - request.attr_end(data); - return result; - } - - int createTxPktFateRequest(WifiRequest& request) { - int result = request.create(GOOGLE_OUI, LOGGER_GET_TX_PKT_FATES); - if (result < 0) { - return result; - } - - memset(mReportBufs, 0, (mNoReqFates * sizeof(wifi_tx_report))); - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u32(LOGGER_ATTRIBUTE_PKT_FATE_NUM, mNoReqFates); - if (result < 0) { - return result; - } - result = request.put_u64(LOGGER_ATTRIBUTE_PKT_FATE_DATA, (uint64_t)mReportBufs); - if (result < 0) { - return result; - } - request.attr_end(data); - return result; - } - - int createRxPktFateRequest(WifiRequest& request) { - int result = request.create(GOOGLE_OUI, LOGGER_GET_RX_PKT_FATES); - if (result < 0) { - return result; - } - - memset(mReportBufs, 0, (mNoReqFates * sizeof(wifi_rx_report))); - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u32(LOGGER_ATTRIBUTE_PKT_FATE_NUM, mNoReqFates); - if (result < 0) { - return result; - } - result = request.put_u64(LOGGER_ATTRIBUTE_PKT_FATE_DATA, (uint64_t)mReportBufs); - if (result < 0) { - return result; - } - request.attr_end(data); - return result; - } - - int start() { - ALOGD("Start get packet fate command\n"); - WifiRequest request(familyId(), ifaceId()); - - int result = createRequest(request); - if (result < 0) { - ALOGE("Failed to create get pkt fate request; result = %d\n", result); - return result; - } - - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to register get pkt fate response; result = %d\n", result); - } - return result; - } - - int handleResponse(WifiEvent& reply) { - ALOGD("In GetPktFateCommand::handleResponse\n"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGI("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - int id = reply.get_vendor_id(); - int subcmd = reply.get_vendor_subcmd(); - nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); - int len = reply.get_vendor_data_len(); - - ALOGI("Id = %0x, subcmd = %d, len = %d", id, subcmd, len); - - if (mReqType == TX_PACKET_FATE) { - ALOGI("Response recieved for get TX pkt fate command\n"); - } else if (mReqType == RX_PACKET_FATE) { - ALOGI("Response recieved for get RX pkt fate command\n"); - } else if (mReqType == PACKET_MONITOR_START) { - ALOGI("Response recieved for monitor pkt fate command\n"); - return NL_OK; - } else { - ALOGE("Response recieved for unknown pkt fate command\n"); - return NL_SKIP; - } - - if (vendor_data == NULL || len == 0) { - ALOGE("no vendor data in GetPktFateCommand response; ignoring it\n"); - return NL_SKIP; - } - - for (nl_iterator it(vendor_data); it.has_next(); it.next()) { - if (it.get_type() == LOGGER_ATTRIBUTE_PKT_FATE_NUM) { - *mNoProvidedFates = it.get_u32(); - ALOGI("No: of pkt fates provided is %d\n", *mNoProvidedFates); - } else { - ALOGE("Ignoring invalid attribute type = %d, size = %d\n", - it.get_type(), it.get_len()); - } - } - - return NL_OK; - } - - int handleEvent(WifiEvent& event) { - /* NO events to handle here! */ - return NL_SKIP; - } -}; - -wifi_error wifi_start_pkt_fate_monitoring(wifi_interface_handle handle) -{ -#if 0 - PacketFateCommand *cmd = new PacketFateCommand(handle); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = (wifi_error)cmd->start(); - cmd->releaseRef(); - return result; -#endif - return WIFI_SUCCESS; -} - -wifi_error wifi_get_tx_pkt_fates(wifi_interface_handle handle, - wifi_tx_report *tx_report_bufs, size_t n_requested_fates, - size_t *n_provided_fates) -{ -#if 0 - PacketFateCommand *cmd = new PacketFateCommand(handle, tx_report_bufs, - n_requested_fates, n_provided_fates); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = (wifi_error)cmd->start(); - cmd->releaseRef(); - return result; -#endif - return WIFI_SUCCESS; -} - -wifi_error wifi_get_rx_pkt_fates(wifi_interface_handle handle, - wifi_rx_report *rx_report_bufs, size_t n_requested_fates, - size_t *n_provided_fates) -{ -#if 0 - PacketFateCommand *cmd = new PacketFateCommand(handle, rx_report_bufs, - n_requested_fates, n_provided_fates); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = (wifi_error)cmd->start(); - cmd->releaseRef(); - return result; -#endif - return WIFI_SUCCESS; -} diff --git a/wlan/wifi_hal/wifi_offload.cpp b/wlan/wifi_hal/wifi_offload.cpp deleted file mode 100644 index 397b792..0000000 --- a/wlan/wifi_hal/wifi_offload.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - - -#include "nl80211_copy.h" -#include "sync.h" - -#define LOG_TAG "WifiHAL" - -#include - -#include "wifi_hal.h" -#include "common.h" -#include "cpp_bindings.h" - -typedef enum { - WIFI_OFFLOAD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START, - WIFI_OFFLOAD_STOP_MKEEP_ALIVE, -} WIFI_OFFLOAD_SUB_COMMAND; - -typedef enum { - MKEEP_ALIVE_ATTRIBUTE_ID, - MKEEP_ALIVE_ATTRIBUTE_IP_PKT, - MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, - MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, - MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, - MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC -} WIFI_MKEEP_ALIVE_ATTRIBUTE; - -typedef enum { - START_MKEEP_ALIVE, - STOP_MKEEP_ALIVE, -} GetCmdType; - -/////////////////////////////////////////////////////////////////////////////// -class MKeepAliveCommand : public WifiCommand -{ - u8 mIndex; - u8 *mIpPkt; - u16 mIpPktLen; - u8 *mSrcMacAddr; - u8 *mDstMacAddr; - u32 mPeriodMsec; - GetCmdType mType; - -public: - - // constructor for start sending - MKeepAliveCommand(wifi_interface_handle iface, u8 index, u8 *ip_packet, u16 ip_packet_len, - u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec, GetCmdType cmdType) - : WifiCommand("MKeepAliveCommand", iface, 0), mIndex(index), mIpPkt(ip_packet), - mIpPktLen(ip_packet_len), mSrcMacAddr(src_mac_addr), mDstMacAddr(dst_mac_addr), - mPeriodMsec(period_msec), mType(cmdType) - { } - - // constructor for stop sending - MKeepAliveCommand(wifi_interface_handle iface, u8 index, GetCmdType cmdType) - : WifiCommand("MKeepAliveCommand", iface, 0), mIndex(index), mType(cmdType) - { } - - int createRequest(WifiRequest &request) { - int result; - - switch (mType) { - case START_MKEEP_ALIVE: - { - result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_START_MKEEP_ALIVE); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to create start keep alive request; result = %d", result); - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - - result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex); - if (result < 0) { - ALOGE("Failed to put id request; result = %d", result); - return result; - } - - result = request.put_u16(MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, mIpPktLen); - if (result < 0) { - ALOGE("Failed to put ip pkt len request; result = %d", result); - return result; - } - - result = request.put(MKEEP_ALIVE_ATTRIBUTE_IP_PKT, (u8*)mIpPkt, mIpPktLen); - if (result < 0) { - ALOGE("Failed to put ip pkt request; result = %d", result); - return result; - } - - result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, mSrcMacAddr); - if (result < 0) { - ALOGE("Failed to put src mac address request; result = %d", result); - return result; - } - - result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, mDstMacAddr); - if (result < 0) { - ALOGE("Failed to put dst mac address request; result = %d", result); - return result; - } - - result = request.put_u32(MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC, mPeriodMsec); - if (result < 0) { - ALOGE("Failed to put period request; result = %d", result); - return result; - } - - request.attr_end(data); - break; - } - - case STOP_MKEEP_ALIVE: - { - result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_STOP_MKEEP_ALIVE); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to create stop keep alive request; result = %d", result); - return result; - } - - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - - result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex); - if (result < 0) { - ALOGE("Failed to put id request; result = %d", result); - return result; - } - - request.attr_end(data); - break; - } - - default: - ALOGE("Unknown wifi keep alive command"); - result = WIFI_ERROR_UNKNOWN; - } - return result; - } - - int start() { - ALOGD("Start mkeep_alive command"); - WifiRequest request(familyId(), ifaceId()); - int result = createRequest(request); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to create keep alive request; result = %d", result); - return result; - } - - result = requestResponse(request); - if (result != WIFI_SUCCESS) { - ALOGE("Failed to register keep alive response; result = %d", result); - } - return result; - } - - virtual int handleResponse(WifiEvent& reply) { - ALOGD("In MKeepAliveCommand::handleResponse"); - - if (reply.get_cmd() != NL80211_CMD_VENDOR) { - ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); - return NL_SKIP; - } - - switch (mType) { - case START_MKEEP_ALIVE: - case STOP_MKEEP_ALIVE: - break; - - default: - ALOGW("Unknown mkeep_alive command"); - } - return NL_OK; - } - - virtual int handleEvent(WifiEvent& event) { - /* NO events! */ - return NL_SKIP; - } -}; - - -/* API to send specified mkeep_alive packet periodically. */ -wifi_error wifi_start_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface, - u8 *ip_packet, u16 ip_packet_len, u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec) -{ - if ((index > 0 && index <= N_AVAIL_ID) && (ip_packet != NULL) && (src_mac_addr != NULL) - && (dst_mac_addr != NULL) && (period_msec > 0) - && (ip_packet_len <= MKEEP_ALIVE_IP_PKT_MAX)) { - MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, ip_packet, ip_packet_len, - src_mac_addr, dst_mac_addr, period_msec, START_MKEEP_ALIVE); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = (wifi_error)cmd->start(); - cmd->releaseRef(); - return result; - } else { - ALOGE("Invalid mkeep_alive parameters"); - return WIFI_ERROR_INVALID_ARGS; - } -} - -/* API to stop sending mkeep_alive packet. */ -wifi_error wifi_stop_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface) -{ - if (index > 0 && index <= N_AVAIL_ID) { - MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, STOP_MKEEP_ALIVE); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - wifi_error result = (wifi_error)cmd->start(); - cmd->releaseRef(); - return result; - } else { - ALOGE("Invalid mkeep_alive parameters"); - return WIFI_ERROR_INVALID_ARGS; - } -} diff --git a/wlan/wpa_supplicant_8_lib/Android.mk b/wlan/wpa_supplicant_8_lib/Android.mk new file mode 100644 index 0000000..09d862c --- /dev/null +++ b/wlan/wpa_supplicant_8_lib/Android.mk @@ -0,0 +1,71 @@ +# +# Copyright (C) 2008 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +LOCAL_PATH := $(call my-dir) + +ifeq ($(WPA_SUPPLICANT_VERSION),VER_0_8_X) + +ifneq ($(BOARD_WPA_SUPPLICANT_DRIVER),) + CONFIG_DRIVER_$(BOARD_WPA_SUPPLICANT_DRIVER) := y +endif + +WPA_SUPPL_DIR = external/wpa_supplicant_8 +WPA_SRC_FILE := + +include $(WPA_SUPPL_DIR)/wpa_supplicant/android.config + +WPA_SUPPL_DIR_INCLUDE = $(WPA_SUPPL_DIR)/src \ + $(WPA_SUPPL_DIR)/src/common \ + $(WPA_SUPPL_DIR)/src/drivers \ + $(WPA_SUPPL_DIR)/src/l2_packet \ + $(WPA_SUPPL_DIR)/src/utils \ + $(WPA_SUPPL_DIR)/src/wps \ + $(WPA_SUPPL_DIR)/wpa_supplicant + +ifdef CONFIG_DRIVER_NL80211 +WPA_SUPPL_DIR_INCLUDE += external/libnl/include +WPA_SRC_FILE += driver_cmd_nl80211.c +endif + +ifdef CONFIG_DRIVER_WEXT +WPA_SRC_FILE += driver_cmd_wext.c +endif + +ifeq ($(TARGET_ARCH),arm) +# To force sizeof(enum) = 4 +L_CFLAGS += -mabi=aapcs-linux +endif + +ifdef CONFIG_ANDROID_LOG +L_CFLAGS += -DCONFIG_ANDROID_LOG +endif + +ifdef CONFIG_P2P +L_CFLAGS += -DCONFIG_P2P +endif +######################## + +include $(CLEAR_VARS) +LOCAL_MODULE := lib_driver_cmd_rtl +LOCAL_SHARED_LIBRARIES := libc libcutils +LOCAL_CFLAGS := $(L_CFLAGS) +LOCAL_SRC_FILES := $(WPA_SRC_FILE) +LOCAL_C_INCLUDES := $(WPA_SUPPL_DIR_INCLUDE) +LOCAL_VENDOR_MODULE := true +include $(BUILD_STATIC_LIBRARY) + +######################## + +endif diff --git a/wlan/wpa_supplicant_8_lib/MODULE_LICENSE_BSD b/wlan/wpa_supplicant_8_lib/MODULE_LICENSE_BSD new file mode 100644 index 0000000..e69de29 diff --git a/wlan/wpa_supplicant_8_lib/NOTICE b/wlan/wpa_supplicant_8_lib/NOTICE new file mode 100644 index 0000000..f9d25ea --- /dev/null +++ b/wlan/wpa_supplicant_8_lib/NOTICE @@ -0,0 +1,43 @@ + +Copyright (c) 2005-2010, The Android Open Source Project +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of The Android Open Source Project nor the names + of its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + + * Copyright (c) 2002-2010, Jouni Malinen + * Copyright (c) 2003-2004, Instant802 Networks, Inc. + * Copyright (c) 2005-2006, Devicescape Software, Inc. + * Copyright (c) 2007, Johannes Berg + * Copyright (c) 2009-2010, Atheros Communications + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. diff --git a/wlan/wpa_supplicant_8_lib/driver_cmd_nl80211.c b/wlan/wpa_supplicant_8_lib/driver_cmd_nl80211.c new file mode 100644 index 0000000..c0fa3bc --- /dev/null +++ b/wlan/wpa_supplicant_8_lib/driver_cmd_nl80211.c @@ -0,0 +1,224 @@ +/* + * Driver interaction with extended Linux CFG8021 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + */ + +#include "includes.h" +#include +#include +#include + +#include "common.h" +#include "linux_ioctl.h" +#include "driver_nl80211.h" +#include "rtw_version.h" +#ifdef PURE_LINUX +#ifndef SIOCDEVPRIVATE +#define SIOCDEVPRIVATE 0x89F0 /* to 89FF */ +#endif +#ifndef __unused +#if __GNUC_PREREQ(2, 95) || defined(__INTEL_COMPILER) +#define __unused __attribute__((__unused__)) +#else +#define __unused +#endif +#endif +#endif /* PURE_LINUX */ +#include "wpa_supplicant_i.h" +#include "config.h" +#ifdef ANDROID +#include "android_drv.h" +#endif + +typedef struct android_wifi_priv_cmd { + char *bufaddr; + int used_len; + int total_len; +} android_wifi_priv_cmd; + +static int drv_errors = 0; + +static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv) +{ + drv_errors++; + if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { + drv_errors = 0; + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); + } +} + +static void wpa_driver_notify_country_change(void *ctx, char *cmd) +{ + if ((os_strncasecmp(cmd, "COUNTRY", 7) == 0) || + (os_strncasecmp(cmd, "SETBAND", 7) == 0)) { + union wpa_event_data event; + + os_memset(&event, 0, sizeof(event)); + event.channel_list_changed.initiator = REGDOM_SET_BY_USER; + if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) { + event.channel_list_changed.type = REGDOM_TYPE_COUNTRY; + if (os_strlen(cmd) > 9) { + event.channel_list_changed.alpha2[0] = cmd[8]; + event.channel_list_changed.alpha2[1] = cmd[9]; + } + } else { + event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN; + } + wpa_supplicant_event(ctx, EVENT_CHANNEL_LIST_CHANGED, &event); + } +} + +int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, + size_t buf_len ) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct ifreq ifr; + android_wifi_priv_cmd priv_cmd; + int ret = 0; + + if (bss->ifindex <= 0 && bss->wdev_id > 0) { + /* DRIVER CMD received on the DEDICATED P2P Interface which doesn't + * have an NETDEVICE associated with it. So we have to re-route the + * command to the parent NETDEVICE + */ + struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)(drv->ctx); + + wpa_printf(MSG_DEBUG, "Re-routing DRIVER cmd to parent iface"); + if (wpa_s && wpa_s->parent) { + /* Update the nl80211 pointers corresponding to parent iface */ + bss = wpa_s->parent->drv_priv; + drv = bss->drv; + wpa_printf(MSG_DEBUG, "Re-routing command to iface: %s" + " cmd (%s)", bss->ifname, cmd); + } + } + + if (os_strcasecmp(cmd, "STOP") == 0) { + linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0); + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); + } else if (os_strcasecmp(cmd, "START") == 0) { + linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1); + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); + } else if (os_strcasecmp(cmd, "lib_version") == 0) { + wpa_msg(drv->ctx, MSG_INFO, RTW_VERSION); + } else if (os_strcasecmp(cmd, "P2P_DISABLE") == 0) { + os_memcpy(buf, "P2P_DISABLE", 12); + wpa_printf(MSG_DEBUG, "P2P_DISABLE"); + } else if (os_strcasecmp(cmd, "MACADDR") == 0) { + u8 macaddr[ETH_ALEN] = {}; + + ret = linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, macaddr); + if (!ret) + ret = os_snprintf(buf, buf_len, + "Macaddr = " MACSTR "\n", MAC2STR(macaddr)); + } else { /* Use private command */ + os_memcpy(buf, cmd, strlen(cmd) + 1); + memset(&ifr, 0, sizeof(ifr)); + memset(&priv_cmd, 0, sizeof(priv_cmd)); + os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); + priv_cmd.bufaddr = buf; + priv_cmd.used_len = buf_len; + priv_cmd.total_len = buf_len; + ifr.ifr_data = (void *)&priv_cmd; + + if ((ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr)) < 0) { + wpa_printf(MSG_ERROR, "%s: failed to issue private command: %s", __func__, cmd); + wpa_driver_send_hang_msg(drv); + } else { + drv_errors = 0; + ret = 0; + if ((os_strcasecmp(cmd, "LINKSPEED") == 0) || + (os_strcasecmp(cmd, "RSSI") == 0) || + (os_strcasecmp(cmd, "GETBAND") == 0) || + (os_strncasecmp(cmd, "WLS_BATCHING", 12) == 0)) + ret = strlen(buf); + wpa_driver_notify_country_change(drv->ctx, cmd); + wpa_printf(MSG_DEBUG, "%s %s len = %d, %zu", __func__, buf, ret, strlen(buf)); + } + } + return ret; +} + +int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration) +{ + char buf[MAX_DRV_CMD_SIZE]; + + memset(buf, 0, sizeof(buf)); + wpa_printf(MSG_DEBUG, "%s: Entry", __func__); + snprintf(buf, sizeof(buf), "P2P_SET_NOA %d %d %d", count, start, duration); + return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf)+1); +} + +int wpa_driver_get_p2p_noa(void *priv __unused, u8 *buf __unused, size_t len __unused) +{ + /* Return 0 till we handle p2p_presence request completely in the driver */ + return 0; +} + +int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow) +{ + char buf[MAX_DRV_CMD_SIZE]; + + memset(buf, 0, sizeof(buf)); + wpa_printf(MSG_DEBUG, "%s: Entry", __func__); + snprintf(buf, sizeof(buf), "P2P_SET_PS %d %d %d", legacy_ps, opp_ps, ctwindow); + return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf) + 1); +} + +int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon, + const struct wpabuf *proberesp, + const struct wpabuf *assocresp) +{ + char *buf; + const struct wpabuf *ap_wps_p2p_ie = NULL; + + char *_cmd = "SET_AP_WPS_P2P_IE"; + char *pbuf; + int ret = 0; + int i, buf_len; + struct cmd_desc { + int cmd; + const struct wpabuf *src; + } cmd_arr[] = { + {0x1, beacon}, + {0x2, proberesp}, + {0x4, assocresp}, + {-1, NULL} + }; + + wpa_printf(MSG_DEBUG, "%s: Entry", __func__); + for (i = 0; cmd_arr[i].cmd != -1; i++) { + ap_wps_p2p_ie = cmd_arr[i].src; + if (ap_wps_p2p_ie) { + buf_len = strlen(_cmd) + 3 + wpabuf_len(ap_wps_p2p_ie); + buf = os_zalloc(buf_len); + if (NULL == buf) { + wpa_printf(MSG_ERROR, "%s: Out of memory", + __func__); + ret = -1; + break; + } + } else { + continue; + } + pbuf = buf; + pbuf += snprintf(pbuf, buf_len - wpabuf_len(ap_wps_p2p_ie), + "%s %d",_cmd, cmd_arr[i].cmd); + *pbuf++ = '\0'; + os_memcpy(pbuf, wpabuf_head(ap_wps_p2p_ie), wpabuf_len(ap_wps_p2p_ie)); + ret = wpa_driver_nl80211_driver_cmd(priv, buf, buf, buf_len); + os_free(buf); + if (ret < 0) + break; + } + + return ret; +} diff --git a/wlan/wpa_supplicant_8_lib/driver_cmd_wext.c b/wlan/wpa_supplicant_8_lib/driver_cmd_wext.c new file mode 100644 index 0000000..3734cb0 --- /dev/null +++ b/wlan/wpa_supplicant_8_lib/driver_cmd_wext.c @@ -0,0 +1,396 @@ +/* + * Driver interaction with extended Linux Wireless Extensions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + */ + +#include "includes.h" +#include +#include +#include + +#include "linux_wext.h" +#include "common.h" +#include "driver.h" +#include "eloop.h" +#include "priv_netlink.h" +#include "driver_wext.h" +#include "ieee802_11_defs.h" +#include "wpa_common.h" +#include "wpa_ctrl.h" +#include "wpa_supplicant_i.h" +#include "config.h" +#include "linux_ioctl.h" +#include "scan.h" + +#include "driver_cmd_wext.h" +#ifdef ANDROID +#include "android_drv.h" +#endif /* ANDROID */ + +#define RSSI_CMD "RSSI" +#define LINKSPEED_CMD "LINKSPEED" + +/** + * wpa_driver_wext_set_scan_timeout - Set scan timeout to report scan completion + * @priv: Pointer to private wext data from wpa_driver_wext_init() + * + * This function can be used to set registered timeout when starting a scan to + * generate a scan completed event if the driver does not report this. + */ +static void wpa_driver_wext_set_scan_timeout(void *priv) +{ + struct wpa_driver_wext_data *drv = priv; + int timeout = 10; /* In case scan A and B bands it can be long */ + + /* Not all drivers generate "scan completed" wireless event, so try to + * read results after a timeout. */ + if (drv->scan_complete_events) { + /* + * The driver seems to deliver SIOCGIWSCAN events to notify + * when scan is complete, so use longer timeout to avoid race + * conditions with scanning and following association request. + */ + timeout = 30; + } + wpa_printf(MSG_DEBUG, "Scan requested - scan timeout %d seconds", + timeout); + eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx); + eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv, + drv->ctx); +} + +/** + * wpa_driver_wext_combo_scan - Request the driver to initiate combo scan + * @priv: Pointer to private wext data from wpa_driver_wext_init() + * @params: Scan parameters + * Returns: 0 on success, -1 on failure + */ +int wpa_driver_wext_combo_scan(void *priv, struct wpa_driver_scan_params *params) +{ + char buf[WEXT_CSCAN_BUF_LEN]; + struct wpa_driver_wext_data *drv = priv; + struct iwreq iwr; + int ret, bp; + unsigned i; + + if (!drv->driver_is_started) { + wpa_printf(MSG_DEBUG, "%s: Driver stopped", __func__); + return 0; + } + + wpa_printf(MSG_DEBUG, "%s: Start", __func__); + + /* Set list of SSIDs */ + bp = WEXT_CSCAN_HEADER_SIZE; + os_memcpy(buf, WEXT_CSCAN_HEADER, bp); + for(i=0; i < params->num_ssids; i++) { + if ((bp + IW_ESSID_MAX_SIZE + 10) >= (int)sizeof(buf)) + break; + wpa_printf(MSG_DEBUG, "For Scan: %s", params->ssids[i].ssid); + buf[bp++] = WEXT_CSCAN_SSID_SECTION; + buf[bp++] = params->ssids[i].ssid_len; + os_memcpy(&buf[bp], params->ssids[i].ssid, params->ssids[i].ssid_len); + bp += params->ssids[i].ssid_len; + } + + /* Set list of channels */ + buf[bp++] = WEXT_CSCAN_CHANNEL_SECTION; + buf[bp++] = 0; + + /* Set passive dwell time (default is 250) */ + buf[bp++] = WEXT_CSCAN_PASV_DWELL_SECTION; + buf[bp++] = (u8)WEXT_CSCAN_PASV_DWELL_TIME; + buf[bp++] = (u8)(WEXT_CSCAN_PASV_DWELL_TIME >> 8); + + /* Set home dwell time (default is 40) */ + buf[bp++] = WEXT_CSCAN_HOME_DWELL_SECTION; + buf[bp++] = (u8)WEXT_CSCAN_HOME_DWELL_TIME; + buf[bp++] = (u8)(WEXT_CSCAN_HOME_DWELL_TIME >> 8); + + os_memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); + iwr.u.data.pointer = buf; + iwr.u.data.length = bp; + + if ((ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr)) < 0) { + if (!drv->bgscan_enabled) + wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (cscan): %d", ret); + else + ret = 0; /* Hide error in case of bg scan */ + } + return ret; +} + +static int wpa_driver_wext_set_cscan_params(char *buf, size_t buf_len, char *cmd) +{ + char *pasv_ptr; + int bp, i; + u16 pasv_dwell = WEXT_CSCAN_PASV_DWELL_TIME_DEF; + u8 channel; + + wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd); + + /* Get command parameters */ + pasv_ptr = os_strstr(cmd, ",TIME="); + if (pasv_ptr) { + *pasv_ptr = '\0'; + pasv_ptr += 6; + pasv_dwell = (u16)atoi(pasv_ptr); + if (pasv_dwell == 0) + pasv_dwell = WEXT_CSCAN_PASV_DWELL_TIME_DEF; + } + channel = (u8)atoi(cmd + 5); + + bp = WEXT_CSCAN_HEADER_SIZE; + os_memcpy(buf, WEXT_CSCAN_HEADER, bp); + + /* Set list of channels */ + buf[bp++] = WEXT_CSCAN_CHANNEL_SECTION; + buf[bp++] = channel; + if (channel != 0) { + i = (pasv_dwell - 1) / WEXT_CSCAN_PASV_DWELL_TIME_DEF; + for (; i > 0; i--) { + if ((size_t)(bp + 12) >= buf_len) + break; + buf[bp++] = WEXT_CSCAN_CHANNEL_SECTION; + buf[bp++] = channel; + } + } else { + if (pasv_dwell > WEXT_CSCAN_PASV_DWELL_TIME_MAX) + pasv_dwell = WEXT_CSCAN_PASV_DWELL_TIME_MAX; + } + + /* Set passive dwell time (default is 250) */ + buf[bp++] = WEXT_CSCAN_PASV_DWELL_SECTION; + if (channel != 0) { + buf[bp++] = (u8)WEXT_CSCAN_PASV_DWELL_TIME_DEF; + buf[bp++] = (u8)(WEXT_CSCAN_PASV_DWELL_TIME_DEF >> 8); + } else { + buf[bp++] = (u8)pasv_dwell; + buf[bp++] = (u8)(pasv_dwell >> 8); + } + + /* Set home dwell time (default is 40) */ + buf[bp++] = WEXT_CSCAN_HOME_DWELL_SECTION; + buf[bp++] = (u8)WEXT_CSCAN_HOME_DWELL_TIME; + buf[bp++] = (u8)(WEXT_CSCAN_HOME_DWELL_TIME >> 8); + + /* Set cscan type */ + buf[bp++] = WEXT_CSCAN_TYPE_SECTION; + buf[bp++] = WEXT_CSCAN_TYPE_PASSIVE; + return bp; +} + +static char *wpa_driver_get_country_code(int channels) +{ + char *country = "US"; /* WEXT_NUMBER_SCAN_CHANNELS_FCC */ + + if (channels == WEXT_NUMBER_SCAN_CHANNELS_ETSI) + country = "EU"; + else if( channels == WEXT_NUMBER_SCAN_CHANNELS_MKK1) + country = "JP"; + return country; +} + +static int wpa_driver_set_backgroundscan_params(void *priv) +{ + struct wpa_driver_wext_data *drv = priv; + struct wpa_supplicant *wpa_s; + struct iwreq iwr; + int ret = 0, i = 0, bp; + char buf[WEXT_PNO_MAX_COMMAND_SIZE]; + struct wpa_ssid *ssid_conf; + + if (drv == NULL) { + wpa_printf(MSG_ERROR, "%s: drv is NULL. Exiting", __func__); + return -1; + } + if (drv->ctx == NULL) { + wpa_printf(MSG_ERROR, "%s: drv->ctx is NULL. Exiting", __func__); + return -1; + } + wpa_s = (struct wpa_supplicant *)(drv->ctx); + if (wpa_s->conf == NULL) { + wpa_printf(MSG_ERROR, "%s: wpa_s->conf is NULL. Exiting", __func__); + return -1; + } + ssid_conf = wpa_s->conf->ssid; + + bp = WEXT_PNOSETUP_HEADER_SIZE; + os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp); + buf[bp++] = WEXT_PNO_TLV_PREFIX; + buf[bp++] = WEXT_PNO_TLV_VERSION; + buf[bp++] = WEXT_PNO_TLV_SUBVERSION; + buf[bp++] = WEXT_PNO_TLV_RESERVED; + + while ((i < WEXT_PNO_AMOUNT) && (ssid_conf != NULL)) { + /* Check that there is enough space needed for 1 more SSID, the other sections and null termination */ + if ((bp + WEXT_PNO_SSID_HEADER_SIZE + IW_ESSID_MAX_SIZE + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int)sizeof(buf)) + break; + if ((!ssid_conf->disabled) && (ssid_conf->ssid_len <= IW_ESSID_MAX_SIZE)){ + wpa_printf(MSG_DEBUG, "For PNO Scan: %s", ssid_conf->ssid); + buf[bp++] = WEXT_PNO_SSID_SECTION; + buf[bp++] = ssid_conf->ssid_len; + os_memcpy(&buf[bp], ssid_conf->ssid, ssid_conf->ssid_len); + bp += ssid_conf->ssid_len; + i++; + } + ssid_conf = ssid_conf->next; + } + + buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x", WEXT_PNO_SCAN_INTERVAL); + bp += WEXT_PNO_SCAN_INTERVAL_LENGTH; + + buf[bp++] = WEXT_PNO_REPEAT_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x", WEXT_PNO_REPEAT); + bp += WEXT_PNO_REPEAT_LENGTH; + + buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION; + os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x", WEXT_PNO_MAX_REPEAT); + bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1; + + os_memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); + iwr.u.data.pointer = buf; + iwr.u.data.length = bp; + + ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr); + + if (ret < 0) { + wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d", ret); + drv->errors++; + if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { + drv->errors = 0; + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); + } + } else { + drv->errors = 0; + } + return ret; + +} + +int wpa_driver_wext_driver_cmd( void *priv, char *cmd, char *buf, size_t buf_len ) +{ + struct wpa_driver_wext_data *drv = priv; + struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)(drv->ctx); + struct iwreq iwr; + int ret = 0, flags; + + wpa_printf(MSG_DEBUG, "%s %s len = %d", __func__, cmd, buf_len); + + if (!drv->driver_is_started && (os_strcasecmp(cmd, "START") != 0)) { + wpa_printf(MSG_ERROR,"WEXT: Driver not initialized yet"); + return -1; + } + + if (os_strcasecmp(cmd, "RSSI-APPROX") == 0) { + os_strlcpy(cmd, RSSI_CMD, MAX_DRV_CMD_SIZE); + } else if( os_strncasecmp(cmd, "SCAN-CHANNELS", 13) == 0 ) { + int no_of_chan; + + no_of_chan = atoi(cmd + 13); + os_snprintf(cmd, MAX_DRV_CMD_SIZE, "COUNTRY %s", + wpa_driver_get_country_code(no_of_chan)); + } else if (os_strcasecmp(cmd, "STOP") == 0) { + linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); + } else if( os_strcasecmp(cmd, "RELOAD") == 0 ) { + wpa_printf(MSG_DEBUG,"Reload command"); + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); + return ret; + } else if( os_strcasecmp(cmd, "BGSCAN-START") == 0 ) { + ret = wpa_driver_set_backgroundscan_params(priv); + if (ret < 0) { + return ret; + } + os_strlcpy(cmd, "PNOFORCE 1", MAX_DRV_CMD_SIZE); + drv->bgscan_enabled = 1; + } else if( os_strcasecmp(cmd, "BGSCAN-STOP") == 0 ) { + os_strlcpy(cmd, "PNOFORCE 0", MAX_DRV_CMD_SIZE); + drv->bgscan_enabled = 0; + } + + os_memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); + os_memcpy(buf, cmd, strlen(cmd) + 1); + iwr.u.data.pointer = buf; + iwr.u.data.length = buf_len; + + if( os_strncasecmp(cmd, "CSCAN", 5) == 0 ) { + if (!wpa_s->scanning && ((wpa_s->wpa_state <= WPA_SCANNING) || + (wpa_s->wpa_state >= WPA_COMPLETED))) { + iwr.u.data.length = wpa_driver_wext_set_cscan_params(buf, buf_len, cmd); + } else { + wpa_printf(MSG_ERROR, "Ongoing Scan action..."); + return ret; + } + } + + ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr); + + if (ret < 0) { + wpa_printf(MSG_ERROR, "%s failed (%d): %s", __func__, ret, cmd); + drv->errors++; + if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { + drv->errors = 0; + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); + } + } else { + drv->errors = 0; + ret = 0; + if ((os_strcasecmp(cmd, RSSI_CMD) == 0) || + (os_strcasecmp(cmd, LINKSPEED_CMD) == 0) || + (os_strcasecmp(cmd, "MACADDR") == 0) || + (os_strcasecmp(cmd, "GETPOWER") == 0) || + (os_strcasecmp(cmd, "GETBAND") == 0)) { + ret = strlen(buf); + } else if (os_strcasecmp(cmd, "START") == 0) { + drv->driver_is_started = TRUE; + linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1); + /* os_sleep(0, WPA_DRIVER_WEXT_WAIT_US); + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); */ + } else if (os_strcasecmp(cmd, "STOP") == 0) { + drv->driver_is_started = FALSE; + /* wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); */ + } else if (os_strncasecmp(cmd, "CSCAN", 5) == 0) { + wpa_driver_wext_set_scan_timeout(priv); + wpa_supplicant_notify_scanning(wpa_s, 1); + } + wpa_printf(MSG_DEBUG, "%s %s len = %d, %d", __func__, buf, ret, strlen(buf)); + } + return ret; +} + +int wpa_driver_signal_poll(void *priv, struct wpa_signal_info *si) +{ + char buf[MAX_DRV_CMD_SIZE]; + struct wpa_driver_wext_data *drv = priv; + char *prssi; + int res; + + os_memset(si, 0, sizeof(*si)); + res = wpa_driver_wext_driver_cmd(priv, RSSI_CMD, buf, sizeof(buf)); + /* Answer: SSID rssi -Val */ + if (res < 0) + return res; + prssi = strcasestr(buf, RSSI_CMD); + if (!prssi) + return -1; + si->current_signal = atoi(prssi + strlen(RSSI_CMD) + 1); + + res = wpa_driver_wext_driver_cmd(priv, LINKSPEED_CMD, buf, sizeof(buf)); + /* Answer: LinkSpeed Val */ + if (res < 0) + return res; + si->current_txrate = atoi(buf + strlen(LINKSPEED_CMD) + 1) * 1000; + + return 0; +} diff --git a/wlan/wpa_supplicant_8_lib/driver_cmd_wext.h b/wlan/wpa_supplicant_8_lib/driver_cmd_wext.h new file mode 100644 index 0000000..56d54fc --- /dev/null +++ b/wlan/wpa_supplicant_8_lib/driver_cmd_wext.h @@ -0,0 +1,37 @@ +/* + * Driver interaction with extended Linux Wireless Extensions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + */ +#ifndef DRIVER_CMD_WEXT_H +#define DRIVER_CMD_WEXT_H + +#define WEXT_NUMBER_SCAN_CHANNELS_FCC 11 +#define WEXT_NUMBER_SCAN_CHANNELS_ETSI 13 +#define WEXT_NUMBER_SCAN_CHANNELS_MKK1 14 + +#define WPA_DRIVER_WEXT_WAIT_US 400000 +#define WEXT_CSCAN_BUF_LEN 360 +#define WEXT_CSCAN_HEADER "CSCAN S\x01\x00\x00S\x00" +#define WEXT_CSCAN_HEADER_SIZE 12 +#define WEXT_CSCAN_SSID_SECTION 'S' +#define WEXT_CSCAN_CHANNEL_SECTION 'C' +#define WEXT_CSCAN_NPROBE_SECTION 'N' +#define WEXT_CSCAN_ACTV_DWELL_SECTION 'A' +#define WEXT_CSCAN_PASV_DWELL_SECTION 'P' +#define WEXT_CSCAN_HOME_DWELL_SECTION 'H' +#define WEXT_CSCAN_TYPE_SECTION 'T' +#define WEXT_CSCAN_TYPE_DEFAULT 0 +#define WEXT_CSCAN_TYPE_PASSIVE 1 +#define WEXT_CSCAN_PASV_DWELL_TIME 130 +#define WEXT_CSCAN_PASV_DWELL_TIME_DEF 250 +#define WEXT_CSCAN_PASV_DWELL_TIME_MAX 3000 +#define WEXT_CSCAN_HOME_DWELL_TIME 130 + +#endif /* DRIVER_CMD_WEXT_H */ diff --git a/wlan/wpa_supplicant_8_lib/driver_nl80211.h b/wlan/wpa_supplicant_8_lib/driver_nl80211.h new file mode 100644 index 0000000..081eee3 --- /dev/null +++ b/wlan/wpa_supplicant_8_lib/driver_nl80211.h @@ -0,0 +1,251 @@ +/* + * Driver interaction with Linux nl80211/cfg80211 + * Copyright (c) 2002-2014, Jouni Malinen + * Copyright (c) 2003-2004, Instant802 Networks, Inc. + * Copyright (c) 2005-2006, Devicescape Software, Inc. + * Copyright (c) 2007, Johannes Berg + * Copyright (c) 2009-2010, Atheros Communications + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef _DRIVER_NL80211_H_ +#define _DRIVER_NL80211_H_ + +#include "includes.h" +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_LIBNL3_ROUTE +#include +#endif /* CONFIG_LIBNL3_ROUTE */ +#include +#include +#include +#include +#include "nl80211_copy.h" + +#include "common.h" +#include "eloop.h" +#include "utils/list.h" +#include "common/qca-vendor.h" +#include "common/qca-vendor-attr.h" +#include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" +#include "l2_packet/l2_packet.h" +#include "netlink.h" +#include "linux_ioctl.h" +#include "radiotap.h" +#include "radiotap_iter.h" +#include "rfkill.h" +#include "driver.h" + +#ifdef CONFIG_LIBNL20 +/* libnl 2.0 compatibility code */ +#define nl_handle nl_sock +#define nl80211_handle_alloc nl_socket_alloc_cb +#define nl80211_handle_destroy nl_socket_free +#endif /* CONFIG_LIBNL20 */ + +#ifndef IFF_LOWER_UP +#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ +#endif +#ifndef IFF_DORMANT +#define IFF_DORMANT 0x20000 /* driver signals dormant */ +#endif + +#ifndef IF_OPER_DORMANT +#define IF_OPER_DORMANT 5 +#endif +#ifndef IF_OPER_UP +#define IF_OPER_UP 6 +#endif + +struct nl80211_global { + void *ctx; + struct dl_list interfaces; + int if_add_ifindex; + u64 if_add_wdevid; + int if_add_wdevid_set; + struct netlink_data *netlink; + struct nl_cb *nl_cb; + struct nl_handle *nl; + int nl80211_id; + int ioctl_sock; /* socket for ioctl() use */ + + struct nl_handle *nl_event; +}; + +struct nl80211_wiphy_data { + struct dl_list list; + struct dl_list bsss; + struct dl_list drvs; + + struct nl_handle *nl_beacons; + struct nl_cb *nl_cb; + + int wiphy_idx; +}; + +struct i802_bss { + struct wpa_driver_nl80211_data *drv; + struct i802_bss *next; + int ifindex; + int br_ifindex; + u64 wdev_id; + char ifname[IFNAMSIZ + 1]; + char brname[IFNAMSIZ]; + unsigned int beacon_set:1; + unsigned int added_if_into_bridge:1; + unsigned int added_bridge:1; + unsigned int in_deinit:1; + unsigned int wdev_id_set:1; + unsigned int added_if:1; + unsigned int static_ap:1; + + u8 addr[ETH_ALEN]; + + int freq; + int bandwidth; + int if_dynamic; + + void *ctx; + struct nl_handle *nl_preq, *nl_mgmt; + struct nl_cb *nl_cb; + + struct nl80211_wiphy_data *wiphy_data; + struct dl_list wiphy_list; +}; + +struct wpa_driver_nl80211_data { + struct nl80211_global *global; + struct dl_list list; + struct dl_list wiphy_list; + char phyname[32]; + unsigned int wiphy_idx; + u8 perm_addr[ETH_ALEN]; + void *ctx; + int ifindex; + int if_removed; + int if_disabled; + int ignore_if_down_event; + struct rfkill_data *rfkill; + struct wpa_driver_capa capa; + u8 *extended_capa, *extended_capa_mask; + unsigned int extended_capa_len; + int has_capability; + + int operstate; + + int scan_complete_events; + enum scan_states { + NO_SCAN, SCAN_REQUESTED, SCAN_STARTED, SCAN_COMPLETED, + SCAN_ABORTED, SCHED_SCAN_STARTED, SCHED_SCAN_STOPPED, + SCHED_SCAN_RESULTS + } scan_state; + + //struct nl_cb *nl_cb; + + u8 auth_bssid[ETH_ALEN]; + u8 auth_attempt_bssid[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u8 prev_bssid[ETH_ALEN]; + int associated; + u8 ssid[32]; + size_t ssid_len; + enum nl80211_iftype nlmode; + enum nl80211_iftype ap_scan_as_station; + unsigned int assoc_freq; + + int monitor_sock; + int monitor_ifidx; + int monitor_refcount; + + unsigned int disabled_11b_rates:1; + unsigned int pending_remain_on_chan:1; + unsigned int in_interface_list:1; + unsigned int device_ap_sme:1; + unsigned int poll_command_supported:1; + unsigned int data_tx_status:1; + unsigned int scan_for_auth:1; + unsigned int retry_auth:1; + unsigned int use_monitor:1; + unsigned int ignore_next_local_disconnect:1; + unsigned int ignore_next_local_deauth:1; + //unsigned int allow_p2p_device:1; + unsigned int hostapd:1; + unsigned int start_mode_ap:1; + unsigned int start_iface_up:1; + unsigned int test_use_roc_tx:1; + unsigned int ignore_deauth_event:1; + unsigned int vendor_cmd_test_avail:1; + unsigned int roaming_vendor_cmd_avail:1; + unsigned int dfs_vendor_cmd_avail:1; + unsigned int have_low_prio_scan:1; + unsigned int force_connect_cmd:1; + unsigned int addr_changed:1; + unsigned int get_features_vendor_cmd_avail:1; + unsigned int set_rekey_offload:1; + unsigned int p2p_go_ctwindow_supported:1; + unsigned int setband_vendor_cmd_avail:1; + unsigned int get_pref_freq_list:1; + unsigned int set_prob_oper_freq:1; + unsigned int scan_vendor_cmd_avail:1; + unsigned int connect_reassoc:1; + + u64 vendor_scan_cookie; + u64 remain_on_chan_cookie; + u64 send_action_cookie; +#define MAX_SEND_ACTION_COOKIES 20 + u64 send_action_cookies[MAX_SEND_ACTION_COOKIES]; + unsigned int num_send_action_cookies; + + unsigned int last_mgmt_freq; + + struct wpa_driver_scan_filter *filter_ssids; + size_t num_filter_ssids; + + struct i802_bss *first_bss; + + int eapol_tx_sock; + + int eapol_sock; /* socket for EAPOL frames */ + + struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */ + + int default_if_indices[16]; + /* the AP/AP_VLAN iface that is in this bridge */ + int default_if_indices_reason[16]; + int *if_indices; + int *if_indices_reason; + int num_if_indices; + + /* From failed authentication command */ + int auth_freq; + u8 auth_bssid_[ETH_ALEN]; + u8 auth_ssid[32]; + size_t auth_ssid_len; + int auth_alg; + u8 *auth_ie; + size_t auth_ie_len; + u8 auth_wep_key[4][16]; + size_t auth_wep_key_len[4]; + int auth_wep_tx_keyidx; + int auth_local_state_change; + int auth_p2p; + + /* + * Tells whether the last scan issued from wpa_supplicant was a normal + * scan (NL80211_CMD_TRIGGER_SCAN) or a vendor scan + * (NL80211_CMD_VENDOR). 0 if no pending scan request. + */ + int last_scan_cmd; +}; + +#endif diff --git a/wlan/wpa_supplicant_8_lib/rtw_version.h b/wlan/wpa_supplicant_8_lib/rtw_version.h new file mode 100644 index 0000000..48edbdc --- /dev/null +++ b/wlan/wpa_supplicant_8_lib/rtw_version.h @@ -0,0 +1,4 @@ +#ifndef RTW_VERSION_H + #define RTW_VERSION_H + #define RTW_VERSION "rtw_r26589.20180227" +#endif /* RTW_VERSION_H */