--- /dev/null
+ifeq ($(BOARD_WLAN_DEVICE), realtek)
+ include $(call all-subdir-makefiles)
+endif
-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
#define LOG_TAG "WifiHAL"
-#include <utils/Log.h>
+#include <log/log.h>
#include "nl80211_copy.h"
#include "sync.h"
+++ /dev/null
-/*
- * 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 <stdint.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
-#include <netlink/genl/ctrl.h>
-#include <linux/rtnetlink.h>
-#include <netpacket/packet.h>
-#include <linux/filter.h>
-#include <linux/errqueue.h>
-
-#include <linux/pkt_sched.h>
-#include <netlink/object-api.h>
-#include <netlink/netlink.h>
-#include <netlink/socket.h>
-#include <netlink/handlers.h>
-
-#include "sync.h"
-
-#define LOG_TAG "WifiHAL"
-//#define LOG_NDEBUG 0 //uncomment to enable verbose logging
-
-#include <utils/Log.h>
-
-#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<wifi_significant_change_result *>(&(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);
-}
+++ /dev/null
-/*
- * 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 <stdint.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
-#include <netlink/genl/ctrl.h>
-#include <linux/rtnetlink.h>
-#include <netpacket/packet.h>
-#include <linux/filter.h>
-#include <linux/errqueue.h>
-
-#include <linux/pkt_sched.h>
-#include <netlink/object-api.h>
-#include <netlink/netlink.h>
-#include <netlink/socket.h>
-#include <netlink/handlers.h>
-
-#include "sync.h"
-
-#define LOG_TAG "WifiHAL"
-
-#include <utils/Log.h>
-
-#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;
-}
+++ /dev/null
-/*
- * 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 <stdint.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
-#include <netlink/genl/ctrl.h>
-#include <linux/rtnetlink.h>
-#include <netpacket/packet.h>
-#include <linux/filter.h>
-#include <linux/errqueue.h>
-
-#include <linux/pkt_sched.h>
-#include <netlink/object-api.h>
-#include <netlink/netlink.h>
-#include <netlink/socket.h>
-#include <netlink-private/object-api.h>
-#include <netlink-private/types.h>
-
-#include "nl80211_copy.h"
-
-#include "sync.h"
-
-#define LOG_TAG "WifiHAL"
-
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#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();
-}
-
--- /dev/null
+/*
+ * 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 <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+//#define LOG_NDEBUG 0 //uncomment to enable verbose logging
+
+#include <log/log.h>
+
+#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<wifi_significant_change_result *>(&(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);
+}
--- /dev/null
+/*
+ * 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 <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+#include <errno.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/attr.h>
+#include <netlink/handlers.h>
+#include <netlink/msg.h>
+
+#include <dirent.h>
+#include <net/if.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <log/log.h>
+
+#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;
+}
+/////////////////////////////////////////////////////////////////////////////
--- /dev/null
+/*
+ * 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 <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <log/log.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <string>
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink-private/object-api.h>
+#include <netlink-private/types.h>
+
+#include "nl80211_copy.h"
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <log/log.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink-private/object-api.h>
+#include <netlink-private/types.h>
+
+
+#include "nl80211_copy.h"
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <log/log.h>
+
+#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;
+ }
+}
--- /dev/null
+/*
+ * 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 <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink-private/object-api.h>
+#include <netlink-private/types.h>
+
+#include "nl80211_copy.h"
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <log/log.h>
+#include <utils/String8.h>
+
+#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();
+}
+
--- /dev/null
+#ifndef VERSION_H
+#define VERSION_H
+
+#define RTW_WIFI_HAL_VERSION "v1.0.3"
+
+#endif /* VERSION_H */
+++ /dev/null
-/*
- * 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 <stdint.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
-#include <netlink/genl/ctrl.h>
-#include <linux/rtnetlink.h>
-#include <netpacket/packet.h>
-#include <linux/filter.h>
-#include <linux/errqueue.h>
-#include <errno.h>
-
-#include <linux/pkt_sched.h>
-#include <netlink/object-api.h>
-#include <netlink/netlink.h>
-#include <netlink/socket.h>
-#include <netlink/attr.h>
-#include <netlink/handlers.h>
-#include <netlink/msg.h>
-
-#include <dirent.h>
-#include <net/if.h>
-
-#include "sync.h"
-
-#define LOG_TAG "WifiHAL"
-
-#include <utils/Log.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");
- 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;
-}
-
-/////////////////////////////////////////////////////////////////////////////
+++ /dev/null
-/*
- * 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 <string>
-#include <stdint.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
-#include <netlink/genl/ctrl.h>
-#include <linux/rtnetlink.h>
-#include <netpacket/packet.h>
-#include <linux/filter.h>
-#include <linux/errqueue.h>
-
-#include <linux/pkt_sched.h>
-#include <netlink/object-api.h>
-#include <netlink/netlink.h>
-#include <netlink/socket.h>
-#include <netlink-private/object-api.h>
-#include <netlink-private/types.h>
-
-#include "nl80211_copy.h"
-#include "sync.h"
-
-#define LOG_TAG "WifiHAL"
-
-#include <log/log.h>
-
-#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;
-}
+++ /dev/null
-/*
- * 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 <stdint.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
-#include <netlink/genl/ctrl.h>
-#include <linux/rtnetlink.h>
-#include <netpacket/packet.h>
-#include <linux/filter.h>
-#include <linux/errqueue.h>
-
-#include <linux/pkt_sched.h>
-#include <netlink/object-api.h>
-#include <netlink/netlink.h>
-#include <netlink/socket.h>
-#include <netlink-private/object-api.h>
-#include <netlink-private/types.h>
-
-
-#include "nl80211_copy.h"
-#include "sync.h"
-
-#define LOG_TAG "WifiHAL"
-
-#include <log/log.h>
-
-#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;
- }
-}
--- /dev/null
+#
+# 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
--- /dev/null
+
+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 <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * 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.
--- /dev/null
+/*
+ * 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 <sys/types.h>
+#include <fcntl.h>
+#include <net/if.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <sys/ioctl.h>
+#include <net/if_arp.h>
+#include <net/if.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * Driver interaction with Linux nl80211/cfg80211
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * 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 <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#ifdef CONFIG_LIBNL3_ROUTE
+#include <netlink/route/neighbour.h>
+#endif /* CONFIG_LIBNL3_ROUTE */
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+#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
--- /dev/null
+#ifndef RTW_VERSION_H
+ #define RTW_VERSION_H
+ #define RTW_VERSION "rtw_r26589.20180227"
+#endif /* RTW_VERSION_H */