diff options
-rw-r--r-- | METADATA | 3 | ||||
-rw-r--r-- | OWNERS | 3 | ||||
-rw-r--r-- | bcmdhd/dhdutil/Android.mk | 3 | ||||
-rw-r--r-- | bcmdhd/dhdutil/bcmutils.c | 2 | ||||
-rwxr-xr-x | bcmdhd/wifi_hal/Android.mk | 14 | ||||
-rwxr-xr-x | bcmdhd/wifi_hal/brcm_version.h | 2 | ||||
-rwxr-xr-x | bcmdhd/wifi_hal/common.cpp | 64 | ||||
-rwxr-xr-x | bcmdhd/wifi_hal/common.h | 246 | ||||
-rwxr-xr-x | bcmdhd/wifi_hal/cpp_bindings.cpp | 47 | ||||
-rwxr-xr-x | bcmdhd/wifi_hal/cpp_bindings.h | 8 | ||||
-rwxr-xr-x | bcmdhd/wifi_hal/gscan.cpp | 132 | ||||
-rw-r--r-- | bcmdhd/wifi_hal/link_layer_stats.cpp | 171 | ||||
-rwxr-xr-x | bcmdhd/wifi_hal/nan.cpp | 695 | ||||
-rw-r--r-- | bcmdhd/wifi_hal/rtt.cpp | 121 | ||||
-rw-r--r-- | bcmdhd/wifi_hal/sync.h | 2 | ||||
-rwxr-xr-x | bcmdhd/wifi_hal/twt.cpp | 947 | ||||
-rwxr-xr-x | bcmdhd/wifi_hal/wifi_hal.cpp | 1541 | ||||
-rwxr-xr-x | bcmdhd/wifi_hal/wifi_logger.cpp | 1385 | ||||
-rw-r--r-- | bcmdhd/wifi_hal/wifi_offload.cpp | 17 | ||||
-rw-r--r-- | bcmdhd/wpa_supplicant_8_lib/Android.mk | 3 |
20 files changed, 4885 insertions, 521 deletions
diff --git a/METADATA b/METADATA new file mode 100644 index 0000000..d97975c --- /dev/null +++ b/METADATA @@ -0,0 +1,3 @@ +third_party { + license_type: NOTICE +} @@ -0,0 +1,3 @@ +arabawy@google.com +etancohen@google.com +kumachang@google.com diff --git a/bcmdhd/dhdutil/Android.mk b/bcmdhd/dhdutil/Android.mk index 2385abd..c7e7fdc 100644 --- a/bcmdhd/dhdutil/Android.mk +++ b/bcmdhd/dhdutil/Android.mk @@ -26,6 +26,9 @@ LOCAL_SRC_FILES := \ miniopt.c LOCAL_MODULE := dhdutil +LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD SPDX-license-identifier-ISC +LOCAL_LICENSE_CONDITIONS := notice +LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE LOCAL_CFLAGS := -DSDTEST -DTARGETENV_android -Dlinux -DLINUX ifeq ($(TARGET_ARCH),arm) LOCAL_CFLAGS += -mabi=aapcs-linux diff --git a/bcmdhd/dhdutil/bcmutils.c b/bcmdhd/dhdutil/bcmutils.c index 0fdbe73..655d267 100644 --- a/bcmdhd/dhdutil/bcmutils.c +++ b/bcmdhd/dhdutil/bcmutils.c @@ -1776,7 +1776,7 @@ static const char *crypto_algo_names[] = { "AES_CCM", "AES_OCB_MSDU", "AES_OCB_MPDU", - "NALG" + "NALG", "UNDEF", "UNDEF", "UNDEF", diff --git a/bcmdhd/wifi_hal/Android.mk b/bcmdhd/wifi_hal/Android.mk index 5763789..471c312 100755 --- a/bcmdhd/wifi_hal/Android.mk +++ b/bcmdhd/wifi_hal/Android.mk @@ -41,6 +41,14 @@ LOCAL_C_INCLUDES += \ LOCAL_HEADER_LIBRARIES := libutils_headers liblog_headers +ifneq ($(wildcard vendor/google/libraries/GoogleWifiConfigLib),) +LOCAL_SHARED_LIBRARIES += \ + google_wifi_firmware_config_version_c_wrapper +LOCAL_CFLAGS += -DGOOGLE_WIFI_FW_CONFIG_VERSION_C_WRAPPER +#only for pixel feature +LOCAL_CFLAGS += -DRING_DUMP +endif + LOCAL_SRC_FILES := \ wifi_hal.cpp \ rtt.cpp \ @@ -50,10 +58,12 @@ LOCAL_SRC_FILES := \ nan.cpp \ link_layer_stats.cpp \ wifi_logger.cpp \ - wifi_offload.cpp + wifi_offload.cpp \ + twt.cpp LOCAL_MODULE := libwifi-hal-bcm +LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 +LOCAL_LICENSE_CONDITIONS := notice LOCAL_PROPRIETARY_MODULE := true include $(BUILD_STATIC_LIBRARY) - diff --git a/bcmdhd/wifi_hal/brcm_version.h b/bcmdhd/wifi_hal/brcm_version.h index 14efbee..184d5d5 100755 --- a/bcmdhd/wifi_hal/brcm_version.h +++ b/bcmdhd/wifi_hal/brcm_version.h @@ -1 +1 @@ -#define HAL_VERSION "Android-10-FRC2-SDK_29 59.0 (r854927) 2019-12-06 23:33:52 +0530 (Fri, 06 Dec 2019)" +#define HAL_VERSION "BCMDHD vendor HAL" diff --git a/bcmdhd/wifi_hal/common.cpp b/bcmdhd/wifi_hal/common.cpp index c164ba4..5a9d5ab 100755 --- a/bcmdhd/wifi_hal/common.cpp +++ b/bcmdhd/wifi_hal/common.cpp @@ -105,14 +105,34 @@ wifi_error wifi_register_vendor_handler(wifi_handle handle, wifi_error result = WIFI_ERROR_OUT_OF_MEMORY; if (info->num_event_cb < info->alloc_event_cb) { - info->event_cb[info->num_event_cb].nl_cmd = NL80211_CMD_VENDOR; - info->event_cb[info->num_event_cb].vendor_id = id; - info->event_cb[info->num_event_cb].vendor_subcmd = subcmd; - info->event_cb[info->num_event_cb].cb_func = func; - info->event_cb[info->num_event_cb].cb_arg = arg; - ALOGV("Added event handler %p:%p for vendor 0x%0x and subcmd 0x%0x at %d", - arg, func, id, subcmd, info->num_event_cb); - info->num_event_cb++; + /* To avoid an unwanted duplication of the record, find first. + * Update it if the same record is already exist. + * KEY => [nl_cmd, vendor_id, vendor_subcmd] + */ + int i = 0; + bool is_update = false; + for (i = 0; i < info->num_event_cb; i++) { + if ((info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR) && + (info->event_cb[i].vendor_id == id) && + (info->event_cb[i].vendor_subcmd == subcmd)) { + is_update = true; + break; + } + } + + if (is_update) { + info->event_cb[i].cb_func = func; + info->event_cb[i].cb_arg = arg; + } else { + info->event_cb[info->num_event_cb].nl_cmd = NL80211_CMD_VENDOR; + info->event_cb[info->num_event_cb].vendor_id = id; + info->event_cb[info->num_event_cb].vendor_subcmd = subcmd; + info->event_cb[info->num_event_cb].cb_func = func; + info->event_cb[info->num_event_cb].cb_arg = arg; + info->num_event_cb++; + } + ALOGI("%s ""event handler %p:%p for vendor 0x%0x and subcmd 0x%0x at %d", + is_update ? "Updated" : "Added", arg, func, id, subcmd, info->num_event_cb); result = WIFI_SUCCESS; } @@ -146,18 +166,15 @@ void wifi_unregister_handler(wifi_handle handle, int cmd) pthread_mutex_unlock(&info->cb_lock); } -void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd) +void wifi_unregister_vendor_handler_without_lock(wifi_handle handle, uint32_t id, int subcmd) { hal_info *info = (hal_info *)handle; - pthread_mutex_lock(&info->cb_lock); - for (int i = 0; i < info->num_event_cb; i++) { - if (info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR && info->event_cb[i].vendor_id == id && info->event_cb[i].vendor_subcmd == subcmd) { - ALOGV("Successfully removed event handler %p:%p for vendor 0x%0x, subcmd 0x%0x from %d", + ALOGI("Successfully removed event handler %p:%p for vendor 0x%0x, subcmd 0x%0x from %d", info->event_cb[i].cb_arg, info->event_cb[i].cb_func, id, subcmd, i); memmove(&info->event_cb[i], &info->event_cb[i+1], (info->num_event_cb - i - 1) * sizeof(cb_info)); @@ -165,11 +182,17 @@ void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd) break; } } +} +void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd) +{ + hal_info *info = (hal_info *)handle; + + pthread_mutex_lock(&info->cb_lock); + wifi_unregister_vendor_handler_without_lock(handle, id, subcmd); pthread_mutex_unlock(&info->cb_lock); } - wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd) { hal_info *info = (hal_info *)handle; @@ -263,6 +286,19 @@ wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface) return WIFI_ERROR_INVALID_ARGS; } +wifi_error wifi_get_cancel_cmd(wifi_request_id id, wifi_interface_handle iface) +{ + wifi_handle handle = getWifiHandle(iface); + WifiCommand *cmd = wifi_get_cmd(handle, id); + ALOGV("Get Cancel WifiCommand = %p", cmd); + if (cmd) { + cmd->cancel(); + cmd->releaseRef(); + return WIFI_SUCCESS; + } + + return WIFI_ERROR_INVALID_ARGS; +} void set_hautil_mode(bool util_mode) { halutil_mode = util_mode; diff --git a/bcmdhd/wifi_hal/common.h b/bcmdhd/wifi_hal/common.h index 98801b2..ecc1abf 100755 --- a/bcmdhd/wifi_hal/common.h +++ b/bcmdhd/wifi_hal/common.h @@ -44,6 +44,7 @@ */ const uint32_t GOOGLE_OUI = 0x001A11; +const uint32_t BRCM_OUI = 0x001018; /* TODO: define vendor OUI here */ @@ -53,7 +54,11 @@ const uint32_t GOOGLE_OUI = 0x001A11; #define NMR2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5], (a)[6], (a)[7] #define NMRSTR "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x" #define NAN_MASTER_RANK_LEN 8 +#define NAN_SCID_INFO_LEN 16 +#define SAR_CONFIG_SCENARIO_COUNT 100 +#define MAX_NUM_RADIOS 3 +#define MAX_CMD_RESP_BUF_LEN 8192 /* This enum defines ranges for various commands; commands themselves @@ -102,8 +107,40 @@ typedef enum { ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_END = 0x18FF, /* define all tx power related commands between 0x1900 and 0x1910 */ - ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_START = 0x1900, - ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_END = 0x1910, + ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_START = 0x1900, + ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_END = 0x1910, + + /* define all thermal mode related commands between 0x1920 and 0x192F */ + ANDROID_NL80211_SUBCMD_MITIGATION_RANGE_START = 0x1920, + ANDROID_NL80211_SUBCMD_MITIGATION_RANGE_END = 0x192F, + + /* define all DSCP related commands between 0x2000 and 0x20FF */ + ANDROID_NL80211_SUBCMD_DSCP_RANGE_START = 0x2000, + ANDROID_NL80211_SUBCMD_DSCP_RANGE_END = 0x20FF, + + /* define all Channel Avoidance related commands between 0x2100 and 0x211F */ + ANDROID_NL80211_SUBCMD_CHAVOID_RANGE_START = 0x2100, + ANDROID_NL80211_SUBCMD_CHAVOID_RANGE_END = 0x211F, + + /* define all OTA Download related commands between 0x2120 and 0x212F */ + ANDROID_NL80211_SUBCMD_OTA_DOWNLOAD_START = 0x2120, + ANDROID_NL80211_SUBCMD_OTA_DOWNLOAD_END = 0x212F, + + /* define all VOIP mode config related commands between 0x2130 and 0x213F */ + ANDROID_NL80211_SUBCMD_VIOP_MODE_START = 0x2130, + ANDROID_NL80211_SUBCMD_VIOP_MODE_END = 0x213F, + + /* define all TWT related commands between 0x2140 and 0x214F */ + ANDROID_NL80211_SUBCMD_TWT_START = 0x2140, + ANDROID_NL80211_SUBCMD_TWT_END = 0x214F, + + /* define all Usable Channel related commands between 0x2150 and 0x215F */ + ANDROID_NL80211_SUBCMD_USABLE_CHANNEL_START = 0x2150, + ANDROID_NL80211_SUBCMD_USABLE_CHANNEL_END = 0x215F, + + /* define all init/deinit related commands between 0x2160 and 0x216F */ + ANDROID_NL80211_SUBCMD_INIT_DEINIT_RANGE_START = 0x2160, + ANDROID_NL80211_SUBCMD_INIT_DEINIT_RANGE_END = 0x216F, /* This is reserved for future usage */ @@ -147,6 +184,9 @@ typedef enum { WIFI_SUBCMD_FW_ROAM_POLICY, /* 0x1019 */ WIFI_SUBCMD_ROAM_CAPABILITY, /* 0x101a */ WIFI_SUBCMD_SET_LATENCY_MODE, /* 0x101b */ + WIFI_SUBCMD_SET_MULTISTA_PRIMARY_CONNECTION, /* 0x101c */ + WIFI_SUBCMD_SET_MULTISTA_USE_CASE, /* 0x101d */ + WIFI_SUBCMD_SET_DTIM_CONFIG, /* 0x101e */ GSCAN_SUBCMD_MAX, @@ -172,7 +212,27 @@ typedef enum { NAN_SUBCMD_ENABLE_MERGE, /* 0x1712 */ APF_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START, APF_SUBCMD_SET_FILTER, + APF_SUBCMD_READ_FILTER, WIFI_SUBCMD_TX_POWER_SCENARIO = ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_START, + WIFI_SUBCMD_THERMAL_MITIGATION = ANDROID_NL80211_SUBCMD_MITIGATION_RANGE_START, + DSCP_SUBCMD_SET_TABLE = ANDROID_NL80211_SUBCMD_DSCP_RANGE_START, + DSCP_SUBCMD_RESET_TABLE, /* 0x2001 */ + CHAVOID_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_CHAVOID_RANGE_START, + + TWT_SUBCMD_GETCAPABILITY = ANDROID_NL80211_SUBCMD_TWT_START, + TWT_SUBCMD_SETUP_REQUEST, + TWT_SUBCMD_TEAR_DOWN_REQUEST, + TWT_SUBCMD_INFO_FRAME_REQUEST, + TWT_SUBCMD_GETSTATS, + TWT_SUBCMD_CLR_STATS, + + WIFI_SUBCMD_CONFIG_VOIP_MODE = ANDROID_NL80211_SUBCMD_VIOP_MODE_START, + + WIFI_SUBCMD_GET_OTA_CURRUNT_INFO = ANDROID_NL80211_SUBCMD_OTA_DOWNLOAD_START, + WIFI_SUBCMD_OTA_UPDATE, + WIFI_SUBCMD_USABLE_CHANNEL = ANDROID_NL80211_SUBCMD_USABLE_CHANNEL_START, + WIFI_SUBCMD_TRIGGER_SSR = ANDROID_NL80211_SUBCMD_INIT_DEINIT_RANGE_START, + WIFI_SUBCMD_GET_RADIO_COMBO_MATRIX, } WIFI_SUB_COMMAND; typedef enum { @@ -212,10 +272,14 @@ typedef enum { NAN_EVENT_SDF = 28, NAN_EVENT_TCA = 29, NAN_EVENT_SUBSCRIBE_UNMATCH = 30, - NAN_EVENT_UNKNOWN, + NAN_EVENT_UNKNOWN = 31, + BRCM_VENDOR_EVENT_HANGED = 33, ROAM_EVENT_START, GOOGLE_FILE_DUMP_EVENT = 37, - NAN_ASYNC_RESPONSE_DISABLED = 40 + NAN_ASYNC_RESPONSE_DISABLED = 40, + BRCM_VENDOR_EVENT_TWT = 43, + BRCM_TPUT_DUMP_EVENT = 44, + NAN_EVENT_MATCH_EXPIRY = 45 } WIFI_EVENT; typedef void (*wifi_internal_event_handler) (wifi_handle handle, int events); @@ -239,8 +303,15 @@ typedef struct { wifi_handle handle; // handle to wifi data char name[IFNAMSIZ+1]; // interface name + trailing null int id; // id to use when talking to driver + bool is_virtual; // mark each iface as virtual or static } interface_info; +typedef enum { + NAN_STATE_DISABLED = 0, + NAN_STATE_AP = 1, + NAN_STATE_CHRE = 2, +} nan_enab_state_t; + typedef struct { struct nl_sock *cmd_sock; // command socket object @@ -265,7 +336,11 @@ typedef struct { interface_info **interfaces; // array of interfaces int num_interfaces; // number of interfaces + int max_num_interfaces; // max number of interfaces + wifi_subsystem_restart_handler restart_handler; // trigger sub system handler + wifi_chre_handler chre_nan_cb; // chre CB for nan status + nan_enab_state_t nan_state; // Nan enable state // add other details } hal_info; @@ -302,11 +377,65 @@ typedef struct wifi_gscan_full_result { u8 ie_data[1]; // IE data to follow } wifi_gscan_full_result_t; +void twt_deinit_handler(); + +typedef enum { + TWT_EVENT_INVALID = 0, + TWT_SETUP_RESPONSE = 1, + TWT_TEARDOWN_COMPLETION = 2, + TWT_INFORM_FRAME = 3, + TWT_NOTIFY = 4, + TWT_EVENT_LAST +} TwtEventType; + +typedef enum { + TWT_INVALID = 0, + TWT_SETUP_REQUEST = 1, + TWT_INFO_FRAME_REQUEST = 2, + TWT_TEAR_DOWN_REQUEST = 3, + TWT_LAST +} TwtRequestType; + +typedef enum { + TWT_ATTRIBUTE_INVALID = 0, + TWT_ATTRIBUTE_CONFIG_ID = 1, + TWT_ATTRIBUTE_NEG_TYPE = 2, + TWT_ATTRIBUTE_TRIGGER_TYPE = 3, + TWT_ATTRIBUTE_WAKE_DUR_US = 4, + TWT_ATTRIBUTE_WAKE_INT_US = 5, + TWT_ATTRIBUTE_WAKE_INT_MIN_US = 6, + TWT_ATTRIBUTE_WAKE_INT_MAX_US = 7, + TWT_ATTRIBUTE_WAKE_DUR_MIN_US = 8, + TWT_ATTRIBUTE_WAKE_DUR_MAX_US = 9, + TWT_ATTRIBUTE_AVG_PKT_SIZE = 10, + TWT_ATTRIBUTE_AVG_PKT_NUM = 11, + TWT_ATTRIBUTE_WAKE_TIME_OFF_US = 12, + TWT_ATTRIBUTE_ALL_TWT = 13, + TWT_ATTRIBUTE_RESUME_TIME_US = 14, + TWT_ATTRIBUTE_AVG_EOSP_DUR = 15, + TWT_ATTRIBUTE_EOSP_COUNT = 16, + TWT_ATTRIBUTE_NUM_SP = 17, + TWT_ATTRIBUTE_DEVICE_CAP = 18, + TWT_ATTRIBUTE_PEER_CAP = 19, + TWT_ATTRIBUTE_STATUS = 20, + TWT_ATTRIBUTE_REASON_CODE = 21, + TWT_ATTRIBUTE_RESUMED = 22, + TWT_ATTRIBUTE_NOTIFICATION = 23, + TWT_ATTRIBUTE_SUB_EVENT = 24, + TWT_ATTRIBUTE_NUM_PEER_STATS = 25, + TWT_ATTRIBUTE_AVG_PKT_NUM_TX = 26, + TWT_ATTRIBUTE_AVG_PKT_SIZE_TX = 27, + TWT_ATTRIBUTE_AVG_PKT_NUM_RX = 28, + TWT_ATTRIBUTE_AVG_PKT_SIZE_RX = 29, + TWT_ATTRIBUTE_MAX +} TWT_ATTRIBUTE; + wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg); wifi_error wifi_register_vendor_handler(wifi_handle handle, uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg); void wifi_unregister_handler(wifi_handle handle, int cmd); +void wifi_unregister_vendor_handler_without_lock(wifi_handle handle, uint32_t id, int subcmd); void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd); wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd); @@ -321,18 +450,127 @@ hal_info *getHalInfo(wifi_interface_handle handle); wifi_handle getWifiHandle(hal_info *info); wifi_interface_handle getIfaceHandle(interface_info *info); wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface); +wifi_error wifi_get_cancel_cmd(wifi_request_id id, wifi_interface_handle iface); wifi_error nan_deinit_handler(); wifi_error wifi_start_hal(wifi_interface_handle iface); wifi_error wifi_stop_hal(wifi_interface_handle iface); wifi_interface_handle wifi_get_wlan_interface(wifi_handle info, wifi_interface_handle *ifaceHandles, int numIfaceHandles); +#ifdef RING_DUMP +wifi_error wifi_start_ring_dump(wifi_interface_handle iface, + wifi_ring_buffer_data_handler ring_handle); +wifi_error wifi_stop_ring_dump(wifi_interface_handle iface, + wifi_ring_buffer_data_handler ring_handle); +#endif /* RING_DUMP */ +wifi_error wifi_hal_ota_update(wifi_interface_handle iface, uint32_t ota_version); wifi_error wifi_hal_preInit(wifi_interface_handle iface); /* API to get wake reason statistics */ wifi_error wifi_get_wake_reason_stats(wifi_interface_handle handle, WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt); +wifi_error wifi_virtual_interface_create(wifi_handle handle, const char* ifname, + wifi_interface_type iface_type); +wifi_error wifi_virtual_interface_delete(wifi_handle handle, const char* ifname); +wifi_error wifi_set_coex_unsafe_channels(wifi_handle handle, u32 num_channels, + wifi_coex_unsafe_channel channels[], u32 restrictions); +wifi_error wifi_set_voip_mode(wifi_interface_handle handle, wifi_voip_mode mode); +wifi_error wifi_set_dtim_config(wifi_interface_handle handle, u32 multiplier); void set_hautil_mode(bool halutil_mode); bool get_halutil_mode(); +/* API's to support TWT */ + +/**@brief twt_get_capability + * Request TWT capability + * @param wifi_interface_handle: + * @return Synchronous wifi_error and TwtCapabilitySet + */ +wifi_error twt_get_capability(wifi_interface_handle iface, TwtCapabilitySet* twt_cap_set); + +/**@brief twt_register_handler + * Request to register TWT callback + * @param wifi_interface_handle: + * @param TwtCallbackHandler: + * @return Synchronous wifi_error + */ +wifi_error twt_register_handler(wifi_interface_handle iface, TwtCallbackHandler handler); + +/**@brief twt_setup_request + * Request to send TWT setup frame + * @param wifi_interface_handle: + * @param TwtSetupRequest: + * @return Synchronous wifi_error + * @return Asynchronous EventTwtSetupResponse CB return TwtSetupResponse + */ +wifi_error twt_setup_request(wifi_interface_handle iface, TwtSetupRequest* msg); + +/**@brief twt_teardown_request + * Request to send TWT teardown frame + * @param wifi_interface_handle: + * @param TwtTeardownRequest: + * @return Synchronous wifi_error + * @return Asynchronous EventTwtTeardownCompletion CB return TwtTeardownCompletion + * TwtTeardownCompletion may also be received due to other events + * like CSA, BTCX, TWT scheduler, MultiConnection, peer-initiated teardown, etc. + */ +wifi_error twt_teardown_request(wifi_interface_handle iface, TwtTeardownRequest* msg); + +/**@brief twt_info_frame_request + * Request to send TWT info frame + * @param wifi_interface_handle: + * @param TwtInfoFrameRequest: + * @return Synchronous wifi_error + * @return Asynchronous EventTwtInfoFrameReceived CB return TwtInfoFrameReceived + * Driver may also receive Peer-initiated TwtInfoFrame + */ +wifi_error twt_info_frame_request(wifi_interface_handle iface, TwtInfoFrameRequest* msg); + +/**@brief twt_get_stats + * Request to get TWT stats + * @param wifi_interface_handle: + * @param config_id: + * @return Synchronous wifi_error and TwtStats + */ +wifi_error twt_get_stats(wifi_interface_handle iface, u8 config_id, TwtStats* stats); + +/**@brief twt_clear_stats + * Request to clear TWT stats + * @param wifi_interface_handle: + * @param config_id: + * @return Synchronous wifi_error + */ +wifi_error twt_clear_stats(wifi_interface_handle iface, u8 config_id); + +wifi_error wifi_trigger_subsystem_restart(wifi_handle handle); + +/**@brief nan_chre_enable_request + * Request from CHRE to enable NAN + * @param transaction id: + * @param wifi_interface_handle: + * @param NanEnableRequest: + * @return Synchronous wifi_error + */ +wifi_error nan_chre_enable_request(transaction_id id, + wifi_interface_handle iface, + NanEnableRequest* msg); + +/**@brief nan_chre_disable_request + * Request from CHRE to disable NAN + * @param transaction id: + * @param wifi_interface_handle: + * @return Synchronous wifi_error + */ +wifi_error nan_chre_disable_request(transaction_id id, + wifi_interface_handle iface); + +/**@brief nan_chre_register_handler + * Register chre handler to handle NAN status + * @param wifi_interface_handle: + * @param wifi_chre_handler: + * @return Synchronous wifi_error + */ +wifi_error nan_chre_register_handler(wifi_interface_handle iface, + wifi_chre_handler handler); + // some common macros #define min(x, y) ((x) < (y) ? (x) : (y)) diff --git a/bcmdhd/wifi_hal/cpp_bindings.cpp b/bcmdhd/wifi_hal/cpp_bindings.cpp index 5ca6431..7a634bd 100755 --- a/bcmdhd/wifi_hal/cpp_bindings.cpp +++ b/bcmdhd/wifi_hal/cpp_bindings.cpp @@ -579,27 +579,56 @@ int WifiRequest::create(int family, uint8_t cmd, int flags, int hdrlen) { } } +static int mapErrorCodes(int err) +{ + int ret; + if (!err) { + return WIFI_SUCCESS; + } + switch (err) { + case -EOPNOTSUPP: + ret = WIFI_ERROR_NOT_SUPPORTED; + break; + case -ETIMEDOUT: + ret = WIFI_ERROR_TIMED_OUT; + break; + case -EINVAL: + ret = WIFI_ERROR_INVALID_ARGS; + break; + case -ENOMEM: + ret = WIFI_ERROR_OUT_OF_MEMORY; + break; + case -EBUSY: + ret = WIFI_ERROR_BUSY; + break; + default: + ret = WIFI_ERROR_UNKNOWN; + } + ALOGD("error code %d mapped to %d", err, ret); + return ret; +} + int WifiRequest::create(uint32_t id, int subcmd) { int res = create(NL80211_CMD_VENDOR); if (res < 0) { - return res; + return mapErrorCodes(res); } res = put_u32(NL80211_ATTR_VENDOR_ID, id); if (res < 0) { - return res; + return mapErrorCodes(res); } res = put_u32(NL80211_ATTR_VENDOR_SUBCMD, subcmd); if (res < 0) { - return res; + return mapErrorCodes(res); } if (mIface != -1) { res = set_iface_id(mIface); } - return res; + return mapErrorCodes(res); } @@ -618,8 +647,7 @@ int WifiCommand::requestResponse() { } int WifiCommand::requestResponse(WifiRequest& request) { - pthread_mutex_lock(&ResponseMutex); - int err = 0, res = 0; + int err = 0; struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT); if (!cb) @@ -645,8 +673,7 @@ int WifiCommand::requestResponse(WifiRequest& request) { } out: nl_cb_put(cb); - pthread_mutex_unlock(&ResponseMutex); - return err; + return mapErrorCodes(err); } int WifiCommand::requestEvent(int cmd) { @@ -675,7 +702,7 @@ int WifiCommand::requestEvent(int cmd) { out: wifi_unregister_handler(wifiHandle(), cmd); - return res; + return mapErrorCodes(res); } int WifiCommand::requestVendorEvent(uint32_t id, int subcmd) { @@ -699,7 +726,7 @@ int WifiCommand::requestVendorEvent(uint32_t id, int subcmd) { out: wifi_unregister_vendor_handler(wifiHandle(), id, subcmd); - return res; + return mapErrorCodes(res); } /* Event handlers */ diff --git a/bcmdhd/wifi_hal/cpp_bindings.h b/bcmdhd/wifi_hal/cpp_bindings.h index 8839a72..8b5600a 100755 --- a/bcmdhd/wifi_hal/cpp_bindings.h +++ b/bcmdhd/wifi_hal/cpp_bindings.h @@ -126,7 +126,7 @@ public: return pos; } uint16_t get_type() { - return pos->nla_type; + return nla_type(pos); } uint8_t get_u8() { return nla_get_u8(pos); @@ -278,7 +278,7 @@ public: virtual void addRef() { int refs = __sync_add_and_fetch(&mRefs, 1); - // ALOGD("addRef: WifiCommand %p has %d references", this, refs); + ALOGV("addRef: WifiCommand %p has %d references", this, refs); } virtual void releaseRef() { @@ -347,6 +347,10 @@ protected: return wifi_register_vendor_handler(wifiHandle(), id, subcmd, &event_handler, this); } + void unregisterVendorHandlerWithoutLock(uint32_t id, int subcmd) { + wifi_unregister_vendor_handler_without_lock(wifiHandle(), id, subcmd); + } + void unregisterVendorHandler(uint32_t id, int subcmd) { wifi_unregister_vendor_handler(wifiHandle(), id, subcmd); } diff --git a/bcmdhd/wifi_hal/gscan.cpp b/bcmdhd/wifi_hal/gscan.cpp index f5722f2..995c989 100755 --- a/bcmdhd/wifi_hal/gscan.cpp +++ b/bcmdhd/wifi_hal/gscan.cpp @@ -235,7 +235,7 @@ class GetCapabilitiesCommand : public WifiCommand void *data = reply.get_vendor_data(); int len = reply.get_vendor_data_len(); - ALOGV("Id = %0x, subcmd = 0x%x, len = %d, expected len = %zd", id, subcmd, len, + ALOGV("Id = %0x, subcmd = 0x%x, len = %d, expected len = %d", id, subcmd, len, mRequestsize); memcpy(mCapabilities, data, min(len, mRequestsize)); @@ -252,6 +252,7 @@ wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle, return (wifi_error) command.requestResponse(); } +/* Function to get chipset supported roaming capabilities */ wifi_error wifi_get_roaming_capabilities(wifi_interface_handle handle, wifi_roaming_capabilities *capabilities) { @@ -345,48 +346,6 @@ wifi_error wifi_get_valid_channels(wifi_interface_handle handle, ///////////////////////////////////////////////////////////////////////////// /* 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); @@ -413,7 +372,7 @@ public: FullScanResultsCommand(wifi_interface_handle iface, int id, int *params, wifi_scan_result_handler handler) : WifiCommand("FullScanResultsCommand", iface, id), mParams(params), mHandler(handler) - { } + {*mParams = 0;} int createRequest(WifiRequest& request, int subcmd, int enable) { int result = request.create(GOOGLE_OUI, subcmd); @@ -445,8 +404,8 @@ public: 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); + ALOGE("failed to enable full scan results; result = %d", result); return result; } @@ -607,6 +566,12 @@ public: return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 0); } + void unregisterVendorHandlerAll() { + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN); + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); + } + int start() { ALOGV("GSCAN start"); WifiRequest request(familyId(), ifaceId()); @@ -616,8 +581,13 @@ public: 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) { + unregisterVendorHandlerAll(); ALOGE("failed to configure setup; result = %d", result); return result; } @@ -626,12 +596,14 @@ public: result = createScanConfigRequest(request); if (result != WIFI_SUCCESS) { + unregisterVendorHandlerAll(); ALOGE("failed to create scan config request; result = %d", result); return result; } result = requestResponse(request); if (result != WIFI_SUCCESS) { + unregisterVendorHandlerAll(); ALOGE("failed to configure scan; result = %d", result); return result; } @@ -640,20 +612,15 @@ public: result = createStartRequest(request); if (result != WIFI_SUCCESS) { + unregisterVendorHandlerAll(); 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) { + unregisterVendorHandlerAll(); 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; @@ -673,9 +640,7 @@ public: } } - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN); - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); + unregisterVendorHandlerAll(); return WIFI_SUCCESS; } @@ -744,7 +709,6 @@ wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface) 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); @@ -803,7 +767,7 @@ int wifi_handle_full_scan_event( 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, + ALOGE("BAD event data, len %d ie_len %d fixed length %lu!\n", len, ie_len, offsetof(wifi_gscan_full_result_t, ie_data)); return NL_SKIP; } @@ -818,7 +782,7 @@ int wifi_handle_full_scan_event( 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", + ALOGV("Full scan result: %-32s %02x:%02x:%02x:%02x:%02x:%02x %d %d %ld %lx %lx %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); @@ -830,11 +794,9 @@ int wifi_handle_full_scan_event( 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)); @@ -1101,6 +1063,11 @@ public: return result; } + void unregisterVendorHandlerAll() { + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND); + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST); + } + int start() { ALOGI("Executing hotlist setup request, num = %d", mParams.num_bssid); WifiRequest request(familyId(), ifaceId()); @@ -1109,27 +1076,26 @@ public: return result; } + registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND); + registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST); + result = requestResponse(request); if (result < 0) { + unregisterVendorHandlerAll(); 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) { + unregisterVendorHandlerAll(); 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); + unregisterVendorHandlerAll(); return result; } @@ -1139,8 +1105,7 @@ public: virtual int cancel() { /* unregister event handler */ - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND); - unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST); + unregisterVendorHandlerAll(); /* create set hotlist message with empty hotlist */ WifiRequest request(familyId(), ifaceId()); int result = createTeardownRequest(request); @@ -1329,15 +1294,15 @@ public: return result; } + registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT); result = requestResponse(request); if (result < 0) { - ALOGI("Failed to execute ePNO setup request, result = %d", result); unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT); + ALOGI("Failed to execute ePNO setup request, result = %d", result); 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; } @@ -1368,7 +1333,6 @@ public: 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); @@ -1537,8 +1501,11 @@ public: return result; } + registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); + result = requestResponse(request); if (result < 0) { + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); ALOGI("failed to set significant wifi change config %d", result); return result; } @@ -1547,11 +1514,10 @@ public: result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); if (result < 0) { + unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); return result; } - registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); - result = requestResponse(request); if (result < 0) { unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); @@ -1661,7 +1627,6 @@ 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); @@ -1677,6 +1642,9 @@ 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); + if (handler.on_network_found == NULL) { + return WIFI_ERROR_INVALID_ARGS; + } ePNOCommand *cmd = new ePNOCommand(iface, id, params, handler); NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); @@ -1761,8 +1729,6 @@ class BssidBlacklistCommand : public WifiCommand wifi_error wifi_set_bssid_blacklist(wifi_request_id id, wifi_interface_handle iface, wifi_bssid_params params) { - wifi_handle handle = getWifiHandle(iface); - BssidBlacklistCommand *cmd = new BssidBlacklistCommand(iface, id, ¶ms); NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); wifi_error result = (wifi_error)cmd->start(); @@ -1936,8 +1902,8 @@ public: result = requestResponse(request); if (result != WIFI_SUCCESS) { - ALOGE("failed to set ANQPO networks; result = %d", result); unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_ANQPO_HOTSPOT_MATCH); + ALOGE("failed to set ANQPO networks; result = %d", result); return result; } @@ -2004,11 +1970,11 @@ public: 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); + ALOGI("rssi:%d\t", mResult->rssi); + ALOGI("channel:%d\t", mResult->channel); + ALOGI("ts:0x%jx\t", mResult->ts); + ALOGI("rtt:0x%jx\t", mResult->rtt); + ALOGI("rtt_sd:0x%jx\n", mResult->rtt_sd); if(*mHandler.on_passpoint_network_found) (*mHandler.on_passpoint_network_found)(id(), networkId, mResult, anqp_len, anqp); diff --git a/bcmdhd/wifi_hal/link_layer_stats.cpp b/bcmdhd/wifi_hal/link_layer_stats.cpp index 34226f4..3a922db 100644 --- a/bcmdhd/wifi_hal/link_layer_stats.cpp +++ b/bcmdhd/wifi_hal/link_layer_stats.cpp @@ -37,12 +37,19 @@ #define LOG_TAG "WifiHAL" -#include <log/log.h> +#include <utils/Log.h> #include "wifi_hal.h" #include "common.h" #include "cpp_bindings.h" +typedef enum { + ANDR_WIFI_ATTRIBUTE_INVALID = 0, + ANDR_WIFI_ATTRIBUTE_NUM_RADIO = 1, + ANDR_WIFI_ATTRIBUTE_STATS_INFO = 2, + ANDR_WIFI_ATTRIBUTE_STATS_MAX = 3 +} LINK_STAT_ATTRIBUTE; + /* Internal radio statistics structure in the driver */ typedef struct { wifi_radio radio; @@ -85,6 +92,12 @@ public: protected: virtual int handleResponse(WifiEvent& reply) { + void *data = NULL; + wifi_radio_stat *radio_stat_ptr = NULL; + u8 *iface_stat = NULL; + u8 *radioStatsBuf = NULL, *output = NULL, *data_ptr = NULL; + uint32_t total_size = 0, per_radio_size = 0, data_len = 0, rem_len = 0; + int num_radios = 0, id = 0, subcmd = 0, len = 0; // ALOGI("In GetLinkStatsCommand::handleResponse"); @@ -93,31 +106,153 @@ protected: return NL_SKIP; } - int id = reply.get_vendor_id(); - int subcmd = reply.get_vendor_subcmd(); - - // ALOGI("Id = %0x, subcmd = %d", id, subcmd); + id = reply.get_vendor_id(); + subcmd = reply.get_vendor_subcmd(); + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + len = reply.get_vendor_data_len(); - 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"); + ALOGV("Id = %0x, subcmd = %d, len = %d\n", id, subcmd, len); + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in GetLinkStatCommand response; ignoring it"); return NL_SKIP; } - wifi_iface_stat *iface_stat = - (wifi_iface_stat *)((char *)&((wifi_radio_stat_internal *)data)->channels - + radio_stat->num_channels * sizeof(wifi_channel_stat)); - (*mHandler.on_link_stats_results)(id, iface_stat, 1, radio_stat); - free(radio_stat); + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == ANDR_WIFI_ATTRIBUTE_NUM_RADIO) { + num_radios = it.get_u32(); + } else if (it.get_type() == ANDR_WIFI_ATTRIBUTE_STATS_INFO) { + data = it.get_data(); + data_len = it.get_len(); + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d\n", + it.get_type(), it.get_len()); + } + } + + if (num_radios) { + rem_len = MAX_CMD_RESP_BUF_LEN; + radioStatsBuf = (u8 *)malloc(MAX_CMD_RESP_BUF_LEN); + if (!radioStatsBuf) { + ALOGE("No memory\n"); + return NL_SKIP; + } + memset(radioStatsBuf, 0, MAX_CMD_RESP_BUF_LEN); + output = radioStatsBuf; + + if (!data || !data_len) { + ALOGE("%s: null data\n", __func__); + return NL_SKIP; + } + + data_ptr = (u8*)data; + for (int i = 0; i < num_radios; i++) { + rem_len -= per_radio_size; + if (rem_len < per_radio_size) { + ALOGE("No data left for radio %d\n", i); + goto exit; + } + data_ptr = (u8*)data + total_size; + if (!data_ptr) { + ALOGE("Invalid data for radio index = %d\n", i); + goto exit; + } + radio_stat_ptr = + convertToExternalRadioStatStructure((wifi_radio_stat*)data_ptr, + &per_radio_size); + if (!radio_stat_ptr || !per_radio_size) { + ALOGE("No data for radio %d\n", i); + continue; + } + memcpy(output, radio_stat_ptr, per_radio_size); + output += per_radio_size; + total_size += per_radio_size; + } + + iface_stat = ((u8*)data + total_size); + if (!iface_stat || data_len < total_size) { + ALOGE("No data for iface stats!!, data_len = %d, total_size = %d\n", + data_len, total_size); + goto exit; + } + (*mHandler.on_link_stats_results)(id, (wifi_iface_stat *)iface_stat, + num_radios, (wifi_radio_stat *)radioStatsBuf); + } else { + /* To be deprecated, adding it to keep it backward compatible */ + ALOGD("GetLinkStatCommand: zero radio case\n"); + data = reply.get_vendor_data(); + if (!data) { + ALOGE("Invalid vendor data received\n"); + return NL_SKIP; + } + + num_radios = 1; + data = reply.get_vendor_data(); + len = reply.get_vendor_data_len(); + if (!data || !len) { + ALOGE("Invalid vendor data received\n"); + return NL_SKIP; + } + radio_stat_ptr = + convertToExternalRadioStatStructureLegacy((wifi_radio_stat_internal *)data); + if (!radio_stat_ptr) { + ALOGE("Invalid stats pointer received\n"); + return NL_SKIP; + } + wifi_iface_stat *iface_stat = + (wifi_iface_stat *)((char *)&((wifi_radio_stat_internal *)data)->channels + + radio_stat_ptr->num_channels * sizeof(wifi_channel_stat)); + (*mHandler.on_link_stats_results)(id, iface_stat, num_radios, radio_stat_ptr); + } +exit: + if (radio_stat_ptr) { + free(radio_stat_ptr); + radio_stat_ptr = NULL; + } + if (radioStatsBuf) { + free(radioStatsBuf); + radioStatsBuf = NULL; + } return NL_OK; } private: - wifi_radio_stat *convertToExternalRadioStatStructure(wifi_radio_stat_internal *internal_stat_ptr) { + wifi_radio_stat *convertToExternalRadioStatStructure(wifi_radio_stat *internal_stat_ptr, + uint32_t *per_radio_size) { + wifi_radio_stat *external_stat_ptr = NULL; + if (!internal_stat_ptr) { + ALOGE("Incoming data is null\n"); + } else { + uint32_t channel_size = internal_stat_ptr->num_channels * sizeof(wifi_channel_stat); + *per_radio_size = offsetof(wifi_radio_stat, channels) + channel_size; + external_stat_ptr = (wifi_radio_stat *)malloc(*per_radio_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->num_tx_levels = internal_stat_ptr->num_tx_levels; + external_stat_ptr->tx_time_per_levels = NULL; + external_stat_ptr->rx_time = internal_stat_ptr->rx_time; + 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_radio_stat *convertToExternalRadioStatStructureLegacy(wifi_radio_stat_internal *internal_stat_ptr) { wifi_radio_stat *external_stat_ptr = NULL; - if (internal_stat_ptr) { + if (!internal_stat_ptr) { + ALOGE("Sta_ptr is null\n"); + } else { 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); diff --git a/bcmdhd/wifi_hal/nan.cpp b/bcmdhd/wifi_hal/nan.cpp index cfabfa8..52f29e3 100755 --- a/bcmdhd/wifi_hal/nan.cpp +++ b/bcmdhd/wifi_hal/nan.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 2017 The Android Open Source Project * - * Portions copyright (C) 2019 Broadcom Limited + * Portions copyright (C) 2017 Broadcom Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -286,7 +286,12 @@ typedef enum { NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL = 224, NAN_ATTRIBUTE_NSS = 225, NAN_ATTRIBUTE_ENABLE_RANGING = 226, - NAN_ATTRIBUTE_DW_EARLY_TERM = 227 + NAN_ATTRIBUTE_DW_EARLY_TERM = 227, + NAN_ATTRIBUTE_CHANNEL_INFO = 228, + NAN_ATTRIBUTE_NUM_CHANNELS = 229, + NAN_ATTRIBUTE_INSTANT_MODE_ENABLE = 230, + NAN_ATTRIBUTE_INSTANT_COMM_CHAN = 231, + NAN_ATTRIBUTE_CHRE_REQUEST = 232, } NAN_ATTRIBUTE; typedef enum { @@ -310,7 +315,6 @@ typedef enum { NAN_DATA_PATH_IFACE_UP = 17, NAN_DATA_PATH_SEC_INFO = 18, NAN_VERSION_INFO = 19, - NAN_REQUEST_ENABLE_MERGE = 20, NAN_REQUEST_LAST = 0xFFFF } NanRequestType; @@ -381,41 +385,7 @@ static int is_cmd_response(int cmd); static int get_svc_hash(unsigned char *svc_name, u16 svc_name_len, u8 *svc_hash, u16 svc_hash_len); NanResponseType get_response_type(WIFI_SUB_COMMAND nan_subcmd); -static NanStatusType nan_map_term_status(u32 vendor_reason); static NanStatusType nan_map_response_status(int vendor_status); -static int ioctl_sock = 0; - -static int setFlags(int s, struct ifreq *ifr, int set, int clr) -{ - if(ioctl(s, SIOCGIFFLAGS, ifr) < 0) { - return WIFI_ERROR_UNKNOWN; - } - - ifr->ifr_flags = (ifr->ifr_flags & (~clr)) | set; - if (ioctl(s, SIOCSIFFLAGS, ifr) < 0) { - return WIFI_ERROR_UNKNOWN; - } - - return WIFI_SUCCESS; -} - -static inline void init_sockaddr_in(struct sockaddr_in *sin, const char *addr) -{ - sin->sin_family = AF_INET; - sin->sin_port = 0; - sin->sin_addr.s_addr = inet_addr(addr); -} - -static int setAddr(int s, struct ifreq *ifr, const char *addr) -{ - init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_addr, addr); - - if (ioctl(s, SIOCSIFADDR, ifr) < 0) { - return WIFI_ERROR_UNKNOWN; - } - - return WIFI_SUCCESS; -} /* Function to separate the common events to NAN1.0 events */ static int is_de_event(int cmd) { @@ -429,6 +399,7 @@ static int is_de_event(int cmd) { case NAN_EVENT_FOLLOWUP: case NAN_EVENT_TRANSMIT_FOLLOWUP_IND: case NAN_EVENT_PUBLISH_REPLIED_IND: + case NAN_EVENT_MATCH_EXPIRY: is_de_evt = true; break; default: @@ -574,6 +545,30 @@ class NanHandle }; +void HandleExpiryEvent(nan_hal_info_t info, nlattr *vendor_data) { + ALOGI("Received NAN_EVENT_MATCH_EXPIRY\n"); + u16 attr_type; + NanMatchExpiredInd expired_event; + memset(&expired_event, 0, sizeof(NanMatchExpiredInd)); + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + attr_type = it.get_type(); + if (attr_type == NAN_ATTRIBUTE_SUBSCRIBE_ID) { + expired_event.publish_subscribe_id = it.get_u16(); + ALOGI("pub_sub id = %u\n", + expired_event.publish_subscribe_id); + } else if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) { + expired_event.requestor_instance_id = it.get_u32(); + ALOGI("req_inst id = %u\n", expired_event.requestor_instance_id); + } + } + + if (expired_event.requestor_instance_id && expired_event.publish_subscribe_id) { + GET_NAN_HANDLE(info)->mHandlers.EventMatchExpired(&expired_event); + } else { + ALOGE("Invalid values for notifying the expired event, dropping the event\n"); + } +} /////////////////////////////////////////////////////////////////////////////// class NanDiscEnginePrimitive : public WifiCommand @@ -664,7 +659,7 @@ class NanDiscEnginePrimitive : public WifiCommand mInstId = mParams->publish_id; nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u16(NAN_ATTRIBUTE_PUBLISH_ID, mInstId); + result = request.put_u32(NAN_ATTRIBUTE_PUBLISH_ID, mInstId); if (result < 0) { ALOGE("%s: Failed to fill pub id, result = %d\n", __func__, result); return result; @@ -865,6 +860,11 @@ class NanDiscEnginePrimitive : public WifiCommand } if (mParams->scid_len) { + if ((mParams->scid_len > NAN_MAX_SCID_BUF_LEN) || + (mParams->scid_len % NAN_SCID_INFO_LEN)) { + ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len); + return NAN_STATUS_INVALID_PARAM; + } result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN, mParams->scid_len); if (result < 0) { @@ -967,7 +967,7 @@ class NanDiscEnginePrimitive : public WifiCommand } ALOGI("%s: pub id = %d, inst_id = %d\n", __func__, mParams->publish_id, mInstId); - result = request.put_u16(NAN_ATTRIBUTE_PUBLISH_ID, mInstId); + result = request.put_u32(NAN_ATTRIBUTE_PUBLISH_ID, mInstId); if (result < 0) { ALOGE("%s: Failed to fill NAN_ATTRIBUTE_PUBLISH_ID, result = %d\n", __func__, result); @@ -1176,7 +1176,45 @@ class NanDiscEnginePrimitive : public WifiCommand return result; } + result = request.put_u8(NAN_ATTRIBUTE_CIPHER_SUITE_TYPE, + mParams->cipher_type); + if (result < 0) { + ALOGE("%s: Failed to fill NAN_ATTRIBUTE_CIPHER_SUITE_TYPE, result = %d\n", + __func__, result); + return result; + } + + result = request.put_u8(NAN_ATTRIBUTE_KEY_TYPE, + mParams->key_info.key_type); + if (result < 0) { + ALOGE("%s: Failed to fill NAN_ATTRIBUTE_KEY_TYPE, result = %d\n", + __func__, result); + return result; + } + + if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK) { + if (mParams->key_info.body.pmk_info.pmk_len) { + result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN, + mParams->key_info.body.pmk_info.pmk_len); + if (result < 0) { + ALOGE("%s: Failed to fill pmk len, result = %d\n", __func__, result); + return result; + } + result = request.put(NAN_ATTRIBUTE_KEY_DATA, + (void *)mParams->key_info.body.pmk_info.pmk, + mParams->key_info.body.pmk_info.pmk_len); + if (result < 0) { + ALOGE("%s: Failed to fill pmk, result = %d\n", __func__, result); + return result; + } + } + } + if (mParams->scid_len) { + if (mParams->scid_len != NAN_SCID_INFO_LEN) { + ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len); + return NAN_STATUS_INVALID_PARAM; + } result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN, mParams->scid_len); if (result < 0) { @@ -1184,7 +1222,6 @@ class NanDiscEnginePrimitive : public WifiCommand return result; } - prhex(NULL, mParams->scid, mParams->scid_len); result = request.put(NAN_ATTRIBUTE_SCID, (void *)mParams->scid, mParams->scid_len); if (result < 0) { @@ -1513,7 +1550,6 @@ class NanDiscEnginePrimitive : public WifiCommand int handleEvent(WifiEvent& event) { int cmd = event.get_vendor_subcmd(); u16 attr_type; - int result; ALOGI("Received NanDiscEnginePrimitive event: %d\n", event.get_cmd()); nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); @@ -1528,15 +1564,16 @@ class NanDiscEnginePrimitive : public WifiCommand attr_type = it.get_type(); if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) { - pub_term_event.publish_id = it.get_u16(); + pub_term_event.publish_id = it.get_u32(); ALOGI("pub id = %u", pub_term_event.publish_id); } else if (attr_type == NAN_ATTRIBUTE_STATUS) { pub_term_event.reason = (NanStatusType)it.get_u8(); ALOGI("pub termination status %u", pub_term_event.reason); } else if (attr_type == NAN_ATTRIBUTE_REASON) { - memcpy(pub_term_event.nan_reason, it.get_data(), - sizeof(pub_term_event.nan_reason)); - ALOGI("pub termination reason: %s", pub_term_event.nan_reason); + u8 len = min(it.get_len(), sizeof(pub_term_event.nan_reason)); + memcpy(pub_term_event.nan_reason, it.get_data(), len); + ALOGI("pub termination reason: %s, len = %d\n", + pub_term_event.nan_reason, len); } else { ALOGE("Unknown attr: %u\n", attr_type); } @@ -1560,7 +1597,7 @@ class NanDiscEnginePrimitive : public WifiCommand ALOGI("sub id: %u", it.get_u16()); subscribe_event.publish_subscribe_id = it.get_u8(); } else if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) { - ALOGI("pub id: %u", it.get_u16()); + ALOGI("pub id: %u", it.get_u32()); subscribe_event.requestor_instance_id = it.get_u8(); } else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) { memcpy(subscribe_event.addr, it.get_data(), NAN_MAC_ADDR_LEN); @@ -1656,9 +1693,10 @@ class NanDiscEnginePrimitive : public WifiCommand sub_term_event.reason = (NanStatusType)it.get_u16(); ALOGI("sub termination status %u", sub_term_event.reason); } else if (attr_type == NAN_ATTRIBUTE_REASON) { - memcpy(sub_term_event.nan_reason, it.get_data(), - sizeof(sub_term_event.nan_reason)); - ALOGI("sub termination reason: %s", sub_term_event.nan_reason); + u8 len = min(it.get_len(), sizeof(sub_term_event.nan_reason)); + memcpy(sub_term_event.nan_reason, it.get_data(), len); + ALOGI("sub termination nan reason: %s, len = %d\n", + sub_term_event.nan_reason, len); } else { ALOGI("Unknown attr: %d\n", attr_type); } @@ -1666,7 +1704,9 @@ class NanDiscEnginePrimitive : public WifiCommand GET_NAN_HANDLE(info)->mHandlers.EventSubscribeTerminated(&sub_term_event); break; - + case NAN_EVENT_MATCH_EXPIRY: + HandleExpiryEvent(info, vendor_data); + break; case NAN_EVENT_FOLLOWUP: NanFollowupInd followup_event; memset(&followup_event, 0, sizeof(NanFollowupInd)); @@ -1705,9 +1745,10 @@ class NanDiscEnginePrimitive : public WifiCommand } else if (attr_type == NAN_ATTRIBUTE_STATUS) { followup_ind.reason = (NanStatusType)it.get_u8(); } else if (attr_type == NAN_ATTRIBUTE_REASON) { - memcpy(followup_ind.nan_reason, it.get_data(), - sizeof(followup_ind.nan_reason)); - ALOGI("nan transmit followup ind: reason: %s", followup_ind.nan_reason); + u8 len = min(it.get_len(), sizeof(followup_ind.nan_reason)); + memcpy(followup_ind.nan_reason, it.get_data(), len); + ALOGI("nan transmit followup ind: reason: %s, len = %d\n", + followup_ind.nan_reason, len); } } GET_NAN_HANDLE(info)->mHandlers.EventTransmitFollowup(&followup_ind); @@ -1845,7 +1886,7 @@ class NanDataPathPrimitive : public WifiCommand nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u8(NAN_ATTRIBUTE_PUBLISH_ID, mParams->requestor_instance_id); + result = request.put_u32(NAN_ATTRIBUTE_PUBLISH_ID, mParams->requestor_instance_id); if (result < 0) { ALOGE("%s: Failed to fill instance id = %d, result = %d\n", __func__, mParams->requestor_instance_id, result); @@ -2018,6 +2059,26 @@ class NanDataPathPrimitive : public WifiCommand } } + if (mParams->scid_len) { + if (mParams->scid_len != NAN_SCID_INFO_LEN) { + ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len); + return NAN_STATUS_INVALID_PARAM; + } + result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN, + mParams->scid_len); + if (result < 0) { + ALOGE("%s: Failed to fill scid len, result = %d\n", __func__, result); + return result; + } + + result = request.put(NAN_ATTRIBUTE_SCID, + (void *)mParams->scid, mParams->scid_len); + if (result < 0) { + ALOGE("%s: Failed to fill scid, result = %d\n", __func__, result); + return result; + } + } + request.attr_end(data); return WIFI_SUCCESS; } @@ -2163,6 +2224,27 @@ class NanDataPathPrimitive : public WifiCommand } } + if (mParams->scid_len) { + if (mParams->scid_len != NAN_SCID_INFO_LEN) { + ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len); + return NAN_STATUS_INVALID_PARAM; + } + result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN, + mParams->scid_len); + if (result < 0) { + ALOGE("%s: Failed to fill scid len, result = %d\n", __func__, result); + return result; + } + + prhex(NULL, mParams->scid, mParams->scid_len); + result = request.put(NAN_ATTRIBUTE_SCID, + (void *)mParams->scid, mParams->scid_len); + if (result < 0) { + ALOGE("%s: Failed to fill scid, result = %d\n", __func__, result); + return result; + } + } + request.attr_end(data); return WIFI_SUCCESS; } @@ -2226,10 +2308,10 @@ class NanDataPathPrimitive : public WifiCommand case NAN_DP_INTERFACE_DELETE: case NAN_DP_INITIATOR_RESPONSE: case NAN_DP_RESPONDER_RESPONSE: - case NAN_DP_END: + case NAN_DP_END: valid = true; break; - default: + default: ALOGE("NanDataPathPrmitive::Unknown cmd Response: %d\n", response_type); break; } @@ -2304,8 +2386,8 @@ class NanDataPathPrimitive : public WifiCommand attr_type = it.get_type(); if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) { - ALOGI("publish_id: %u", it.get_u16()); - ndp_request_event.service_instance_id = it.get_u16(); + ALOGI("publish_id: %u\n", it.get_u32()); + ndp_request_event.service_instance_id = it.get_u32(); } else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) { memcpy(ndp_request_event.peer_disc_mac_addr, @@ -2314,17 +2396,17 @@ class NanDataPathPrimitive : public WifiCommand MAC2STR(ndp_request_event.peer_disc_mac_addr)); } else if (attr_type == NAN_ATTRIBUTE_NDP_ID) { - ALOGI("ndp id: %u", it.get_u32()); + ALOGI("ndp id: %u\n", it.get_u32()); ndp_request_event.ndp_instance_id = it.get_u32(); } else if (attr_type == NAN_ATTRIBUTE_SECURITY) { - ALOGI("security: %u", + ALOGI("security: %u\n", (NanDataPathSecurityCfgStatus)it.get_u8()); ndp_request_event.ndp_cfg.security_cfg = (NanDataPathSecurityCfgStatus)it.get_u8(); } else if (attr_type == NAN_ATTRIBUTE_QOS) { - ALOGI("QoS: %u", (NanDataPathQosCfg)it.get_u8()); + ALOGI("QoS: %u\n", (NanDataPathQosCfg)it.get_u8()); ndp_request_event.ndp_cfg.qos_cfg = (NanDataPathQosCfg)it.get_u8(); } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) { @@ -2336,7 +2418,17 @@ class NanDataPathPrimitive : public WifiCommand ndp_ind_app_info_len); ndp_request_event.app_info.ndp_app_info [ndp_ind_app_info_len] = '\0'; - ALOGI("service info: %s", ndp_request_event.app_info.ndp_app_info); + ALOGI("service info: %s\n", ndp_request_event.app_info.ndp_app_info); + + } else if (attr_type == NAN_ATTRIBUTE_SCID_LEN) { + ALOGI("scid len: %u\n", it.get_u32()); + ndp_request_event.scid_len = it.get_u32(); + + } else if (attr_type == NAN_ATTRIBUTE_SCID) { + memcpy(ndp_request_event.scid, it.get_data(), + ndp_request_event.scid_len); + ndp_request_event.scid[ndp_request_event.scid_len] = '\0'; + ALOGI("scid : %s\n", ndp_request_event.scid); } } @@ -2348,6 +2440,7 @@ class NanDataPathPrimitive : public WifiCommand NanDataPathConfirmInd ndp_create_confirmation_event; memset(&ndp_create_confirmation_event, 0, sizeof(NanDataPathConfirmInd)); u16 ndp_conf_app_info_len = 0; + u8 chan_idx = 0; counters.dp_confirm_evt++; ALOGI("Received NAN_EVENT_DATA_CONFIRMATION\n"); @@ -2384,9 +2477,29 @@ class NanDataPathPrimitive : public WifiCommand ALOGI("reason code %u", (NanDataPathResponseCode)it.get_u8()); ndp_create_confirmation_event.rsp_code = (NanDataPathResponseCode)it.get_u8(); + } else if (attr_type == NAN_ATTRIBUTE_NUM_CHANNELS) { + ALOGI("num channels %u", it.get_u32()); + if (it.get_u32() <= NAN_MAX_CHANNEL_INFO_SUPPORTED) { + ndp_create_confirmation_event.num_channels = it.get_u32(); + } else { + ndp_create_confirmation_event.num_channels = + NAN_MAX_CHANNEL_INFO_SUPPORTED; + ALOGE("num channels reset to max allowed %u", + ndp_create_confirmation_event.num_channels); + } + } else if (attr_type == NAN_ATTRIBUTE_CHANNEL_INFO) { + ALOGI("Channel info \n"); + memcpy((u8 *)ndp_create_confirmation_event.channel_info, it.get_data(), + ndp_create_confirmation_event.num_channels * sizeof(NanChannelInfo)); + while (chan_idx < ndp_create_confirmation_event.num_channels) { + ALOGI("channel: %u, Bandwidth: %u, nss: %u\n", + ndp_create_confirmation_event.channel_info[chan_idx].channel, + ndp_create_confirmation_event.channel_info[chan_idx].bandwidth, + ndp_create_confirmation_event.channel_info[chan_idx].nss); + chan_idx++; + } } } - GET_NAN_HANDLE(info)->mHandlers.EventDataConfirm(&ndp_create_confirmation_event); break; } @@ -2431,6 +2544,7 @@ class NanMacControl : public WifiCommand wifi_interface_handle mIface; NanRequestType mType; u32 mVersion; + u8 mChreNan; public: NanMacControl(wifi_interface_handle iface, int id, @@ -2470,6 +2584,10 @@ class NanMacControl : public WifiCommand mParams = params; } + void setChreNan(u8 chre_nan) { + mChreNan = chre_nan; + } + int createRequest(WifiRequest& request) { ALOGI("NAN CMD: %s\n", NanCmdToString(mType)); if (mType == NAN_REQUEST_ENABLE) { @@ -2484,10 +2602,6 @@ class NanMacControl : public WifiCommand /* TODO: Not yet implemented */ } else if (mType == NAN_VERSION_INFO) { return createVersionRequest(request); -#ifdef NAN_CLUSTER_MERGE - } else if (mType == NAN_REQUEST_ENABLE_MERGE) { - return createEnableMergeRequest(request, (NanEnableMergeRequest *)mParams); -#endif /* NAN_CLUSTER_MERGE */ } else { ALOGE("Unknown Nan request\n"); } @@ -2853,6 +2967,32 @@ class NanMacControl : public WifiCommand } } + if (mParams->config_enable_instant_mode) { + result = request.put_u32(NAN_ATTRIBUTE_INSTANT_MODE_ENABLE, + mParams->enable_instant_mode); + if (result < 0) { + ALOGE("%s: Failing to fill enable instant mode, result = %d\n", __func__, result); + return result; + } + } + + if (mParams->enable_instant_mode && mParams->config_instant_mode_channel + && mParams->instant_mode_channel) { + result = request.put_u32(NAN_ATTRIBUTE_INSTANT_COMM_CHAN, + mParams->instant_mode_channel); + if (result < 0) { + ALOGE("%s: Failing in config instant channel, result = %d\n", __func__, result); + return result; + } + ALOGI("%s: instant mode channel = %d\n", __func__, mParams->instant_mode_channel); + } + + result = request.put_u8(NAN_ATTRIBUTE_CHRE_REQUEST, mChreNan); + if (result < 0) { + ALOGE("%s: Failing in config chreNan, result = %d\n", __func__, result); + return result; + } + request.attr_end(data); NAN_DBG_EXIT(); return WIFI_SUCCESS; @@ -2869,31 +3009,17 @@ class NanMacControl : public WifiCommand nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - request.attr_end(data); - - NAN_DBG_EXIT(); - return result; - } - -#ifdef NAN_CLUSTER_MERGE - int createEnableMergeRequest(WifiRequest& request, - NanEnableMergeRequest *mParams) { - int result = request.create(GOOGLE_OUI, NAN_SUBCMD_ENABLE_MERGE); - if (result < 0) { - ALOGE("%s: Fail to create request\n", __func__); - return result; - } - nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - result = request.put_u8(NAN_ATTRIBUTE_ENABLE_MERGE, mParams->enable); + result = request.put_u8(NAN_ATTRIBUTE_CHRE_REQUEST, mChreNan); if (result < 0) { - ALOGE("%s: Failing in enable merge, result = %d\n", __func__, result); + ALOGE("%s: Failing in config chreNan, result = %d\n", __func__, result); return result; } + request.attr_end(data); + NAN_DBG_EXIT(); - return WIFI_SUCCESS; + return result; } -#endif /* NAN_CLUSTER_MERGE */ int createConfigRequest(WifiRequest& request, NanConfigRequest *mParams) { @@ -3136,6 +3262,27 @@ class NanMacControl : public WifiCommand return result; } } + + if (mParams->config_enable_instant_mode) { + result = request.put_u32(NAN_ATTRIBUTE_INSTANT_MODE_ENABLE, + mParams->enable_instant_mode); + if (result < 0) { + ALOGE("%s: Failing to fill enable instant mode, result = %d\n", __func__, result); + return result; + } + } + + if (mParams->enable_instant_mode && mParams->config_instant_mode_channel + && mParams->instant_mode_channel) { + result = request.put_u32(NAN_ATTRIBUTE_INSTANT_COMM_CHAN, + mParams->instant_mode_channel); + if (result < 0) { + ALOGE("%s: Failing in config instant channel, result = %d\n", __func__, result); + return result; + } + ALOGI("%s: instant mode channel = %d\n", __func__, mParams->instant_mode_channel); + } + request.attr_end(data); NAN_DBG_EXIT(); return WIFI_SUCCESS; @@ -3193,6 +3340,10 @@ class NanMacControl : public WifiCommand return NL_SKIP; } + if (mChreNan) { + return NL_SKIP; + } + rsp_vndr_data = (nan_hal_resp_t *)reply.get_vendor_data(); ALOGI("NanMacControl::handleResponse\n"); if (mType == NAN_VERSION_INFO) { @@ -3258,7 +3409,6 @@ class NanMacControl : public WifiCommand } int handleEvent(WifiEvent& event) { - u16 inst_id; u32 ndp_instance_id = 0; int event_id = event.get_vendor_subcmd(); nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); @@ -3273,16 +3423,19 @@ class NanMacControl : public WifiCommand return NL_SKIP; } + if (mChreNan) { + return NL_SKIP; + } + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { attr_type = it.get_type(); if (it.get_type() == NAN_ATTRIBUTE_HANDLE) { - inst_id = it.get_u8(); } else if (it.get_type() == NAN_ATTRIBUTE_NDP_ID) { ndp_instance_id = it.get_u32(); ALOGI("handleEvent: ndp_instance_id = [%d]\n", ndp_instance_id); } else if (attr_type == NAN_ATTRIBUTE_CMD_RESP_DATA) { - ALOGI("sizeof cmd response data: %d, it.get_len() = %d\n", + ALOGI("sizeof cmd response data: %ld, it.get_len() = %d\n", sizeof(nan_hal_resp_t), it.get_len()); if (it.get_len() == sizeof(nan_hal_resp_t)) { rsp_vndr_data = (nan_hal_resp_t*)it.get_data(); @@ -3316,12 +3469,17 @@ class NanMacControl : public WifiCommand ALOGE("%s: dp_primitive is no more available\n", __func__); } return NL_SKIP; - } else { - if (is_cmd_response(event_id)) { - ALOGE("Handling cmd response asynchronously\n"); - handleAsyncResponse(rsp_vndr_data); - } - } + } else { + if (is_cmd_response(event_id)) { + ALOGE("Handling cmd response asynchronously\n"); + if (rsp_vndr_data != NULL) { + handleAsyncResponse(rsp_vndr_data); + } else { + ALOGE("Wrong response data, rsp_vndr_data is NULL\n"); + return NL_SKIP; + } + } + } switch(event_id) { case NAN_EVENT_DE_EVENT: @@ -3395,9 +3553,10 @@ class NanMacControl : public WifiCommand disabled_ind.reason = (NanStatusType)it.get_u8(); ALOGI("Nan Disable:status %u", disabled_ind.reason); } else if (attr_type == NAN_ATTRIBUTE_REASON) { - memcpy(disabled_ind.nan_reason, it.get_data(), - sizeof(disabled_ind.nan_reason)); - ALOGI("Disable nan reason: %s", disabled_ind.nan_reason); + u8 len = min(it.get_len(), sizeof(disabled_ind.nan_reason)); + memcpy(disabled_ind.nan_reason, it.get_data(), len); + ALOGI("Disabled nan reason: %s, len = %d\n", + disabled_ind.nan_reason, len); } } @@ -3415,7 +3574,7 @@ class NanMacControl : public WifiCommand attr_type = it.get_type(); if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) { - sdfInd.data.frame_len = it.get_u32(); + sdfInd.data.frame_len = it.get_u16(); if (sdfInd.data.frame_len > NAN_MAX_FRAME_DATA_LEN) { sdfInd.data.frame_len = NAN_MAX_FRAME_DATA_LEN; } @@ -3450,6 +3609,7 @@ class NanMacControl : public WifiCommand unregisterVendorHandler(GOOGLE_OUI, i); } unregisterVendorHandler(GOOGLE_OUI, NAN_ASYNC_RESPONSE_DISABLED); + unregisterVendorHandler(GOOGLE_OUI, NAN_EVENT_MATCH_EXPIRY); } void registerNanVendorEvents() { @@ -3458,6 +3618,7 @@ class NanMacControl : public WifiCommand registerVendorHandler(GOOGLE_OUI, i); } registerVendorHandler(GOOGLE_OUI, NAN_ASYNC_RESPONSE_DISABLED); + registerVendorHandler(GOOGLE_OUI, NAN_EVENT_MATCH_EXPIRY); } }; @@ -3550,8 +3711,6 @@ static const char *NanCmdToString(int cmd) C2S(NAN_DATA_PATH_IFACE_UP) C2S(NAN_DATA_PATH_SEC_INFO) C2S(NAN_VERSION_INFO) - C2S(NAN_REQUEST_ENABLE_MERGE) - default: return "UNKNOWN_NAN_CMD"; } @@ -3737,7 +3896,6 @@ static int get_svc_hash(unsigned char *svc_name, return WIFI_SUCCESS; } -#ifdef CONFIG_BRCM static int dump_NanEnableRequest(NanEnableRequest* msg) { ALOGI("%s: Dump NanEnableRequest msg:\n", __func__); @@ -3831,10 +3989,19 @@ static int dump_NanEnableRequest(NanEnableRequest* msg) if (msg->config_disc_mac_addr_randomization) { ALOGI("disc_mac_addr_rand_interval_sec =%u\n", msg->disc_mac_addr_rand_interval_sec); } + ALOGI("config_enable_instant_mode =%u\n", msg->config_enable_instant_mode); + if (msg->config_enable_instant_mode) { + ALOGI("enable_instant_mode =%u\n", msg->enable_instant_mode); + } + ALOGI("config_instant_mode_channel=%u\n", msg->config_instant_mode_channel); + if (msg->config_instant_mode_channel) { + ALOGI("instant_mode_channel=%u\n", msg->instant_mode_channel); + } return WIFI_SUCCESS; } +#ifdef CONFIG_BRCM static int dump_NanConfigRequestRequest(NanConfigRequest* msg) { ALOGI("%s: Dump NanConfigRequest msg:\n", __func__); @@ -3896,13 +4063,21 @@ static int dump_NanConfigRequestRequest(NanConfigRequest* msg) if (msg->config_disc_mac_addr_randomization) { ALOGI("disc_mac_addr_rand_interval_sec =%u\n", msg->disc_mac_addr_rand_interval_sec); } + ALOGI("config_enable_instant_mode =%u\n", msg->config_enable_instant_mode); + if (msg->config_enable_instant_mode) { + ALOGI("enable_instant_mode =%u\n", msg->enable_instant_mode); + } + ALOGI("config_instant_mode_channel=%u\n", msg->config_instant_mode_channel); + if (msg->config_instant_mode_channel) { + ALOGI("instant_mode_channel=%u\n", msg->instant_mode_channel); + } + return WIFI_SUCCESS; } static int dump_NanPublishRequest(NanPublishRequest* msg) { ALOGI("%s: Dump NanPublishRequest msg:\n", __func__); - u8 i = 0; if (msg == NULL) { ALOGE("Invalid msg\n"); return WIFI_ERROR_UNKNOWN; @@ -3916,17 +4091,21 @@ static int dump_NanPublishRequest(NanPublishRequest* msg) ALOGI("publish_match_indicator=%u\n", msg->publish_match_indicator); ALOGI("service_responder_policy=%u\n", msg->service_responder_policy); ALOGI("service_name_len=%u\n", msg->service_name_len); - if (msg->service_name_len) + if (msg->service_name_len) { ALOGI("service_name=%s\n", msg->service_name); + } ALOGI("service_specific_info_len=%u\n", msg->service_specific_info_len); - if (msg->service_specific_info_len) + if (msg->service_specific_info_len) { ALOGI("service_specific_info=%s\n", msg->service_specific_info); + } ALOGI("rx_match_filter_len=%u\n", msg->rx_match_filter_len); - if (msg->rx_match_filter_len) + if (msg->rx_match_filter_len) { prhex("rx_match_filter", msg->rx_match_filter, msg->rx_match_filter_len); + } ALOGI("tx_match_filter_len=%u\n", msg->tx_match_filter_len); - if (msg->tx_match_filter_len) + if (msg->tx_match_filter_len) { prhex("tx_match_filter", msg->tx_match_filter, msg->tx_match_filter_len); + } ALOGI("rssi_threshold_flag=%u\n", msg->rssi_threshold_flag); ALOGI("connmap=%u\n", msg->connmap); ALOGI("recv_indication_cfg=%u\n", msg->recv_indication_cfg); @@ -3935,8 +4114,9 @@ static int dump_NanPublishRequest(NanPublishRequest* msg) ALOGI("key_info: pmk info=%s\n", msg->key_info.body.pmk_info.pmk); ALOGI("key_info: passphrase_info=%s\n", msg->key_info.body.passphrase_info.passphrase); ALOGI("scid_len=%u\n", msg->scid_len); - if (msg->scid_len) + if (msg->scid_len) { ALOGI("scid=%s\n", msg->scid); + } ALOGI("NanSdeaCtrlParams NdpType=%u\n", msg->sdea_params.ndp_type); ALOGI("NanSdeaCtrlParams security_cfg=%u\n", msg->sdea_params.security_cfg); ALOGI("NanSdeaCtrlParams ranging_state=%u\n", msg->sdea_params.ranging_state); @@ -3949,8 +4129,9 @@ static int dump_NanPublishRequest(NanPublishRequest* msg) ALOGI("range_response_cfg=%u\n", msg->range_response_cfg.ranging_response); ALOGI("sdea_service_specific_info_len=%u\n", msg->sdea_service_specific_info_len); - if (msg->sdea_service_specific_info_len) + if (msg->sdea_service_specific_info_len) { ALOGI("sdea_service_specific_info=%s\n", msg->sdea_service_specific_info); + } return WIFI_SUCCESS; } @@ -3999,8 +4180,9 @@ static int dump_NanSubscribeRequest(NanSubscribeRequest* msg) ALOGI("key_info: pmk info=%s\n", msg->key_info.body.pmk_info.pmk); ALOGI("key_info: passphrase_info=%s\n", msg->key_info.body.passphrase_info.passphrase); ALOGI("scid_len=%u\n", msg->scid_len); - if (msg->scid_len) + if (msg->scid_len) { ALOGI("scid=%s\n", msg->scid); + } ALOGI("NanSdeaCtrlParams NdpType=%u\n", msg->sdea_params.ndp_type); ALOGI("NanSdeaCtrlParams security_cfg=%u\n", msg->sdea_params.security_cfg); ALOGI("NanSdeaCtrlParams ranging_state=%u\n", msg->sdea_params.ranging_state); @@ -4022,7 +4204,6 @@ static int dump_NanSubscribeRequest(NanSubscribeRequest* msg) static int dump_NanTransmitFollowupRequest(NanTransmitFollowupRequest* msg) { ALOGI("%s: Dump NanTransmitFollowupRequest msg:\n", __func__); - u8 i = 0; if (msg == NULL) { ALOGE("Invalid msg\n"); return WIFI_ERROR_UNKNOWN; @@ -4068,6 +4249,10 @@ static int dump_NanDataPathInitiatorRequest(NanDataPathInitiatorRequest* msg) ALOGI("key_info: key_type =%u\n", msg->key_info.key_type); ALOGI("key_info: pmk info=%s\n", msg->key_info.body.pmk_info.pmk); ALOGI("key_info: passphrase_info=%s\n", msg->key_info.body.passphrase_info.passphrase); + ALOGI("scid_len=%u\n", msg->scid_len); + if (msg->scid_len) { + ALOGI("scid=%s\n", msg->scid); + } if (msg->service_name_len) { ALOGI("service_name=%s\n", msg->service_name); } @@ -4098,6 +4283,10 @@ static int dump_NanDataPathIndicationResponse(NanDataPathIndicationResponse* msg ALOGI("key_info: pmk info=%s\n", msg->key_info.body.pmk_info.pmk); ALOGI("key_info: passphrase_info=%s\n", msg->key_info.body.passphrase_info.passphrase); ALOGI("service_name_len=%u\n", msg->service_name_len); + ALOGI("scid_len=%u\n", msg->scid_len); + if (msg->scid_len) { + ALOGI("scid=%s\n", msg->scid); + } if (msg->service_name_len) { ALOGI("service_name=%s\n", msg->service_name); } @@ -4111,32 +4300,66 @@ void nan_reset_dbg_counters() } /////////////////////////////////////////////////////////////////////////////// -wifi_error nan_enable_request(transaction_id id, - wifi_interface_handle iface, NanEnableRequest* msg) +wifi_error nan_cmn_enabe_request(transaction_id id, + NanMacControl *cmd, NanEnableRequest* msg) { wifi_error ret = WIFI_SUCCESS; - wifi_handle handle = getWifiHandle(iface); - NanRequestType cmdType = NAN_REQUEST_ENABLE; - - ALOGI("Enabling Nan, Handle = %p\n", handle); - #ifdef CONFIG_BRCM // check up nan enable params from Nan manager level dump_NanEnableRequest(msg); #endif /* CONFIG_BRCM */ nan_reset_dbg_counters(); - /* XXX: WAR posting async enable response */ - //NanMacControl *cmd = new NanMacControl(iface, id, (void *)msg, cmdType); - NanMacControl *cmd = (NanMacControl*)(info.nan_mac_control); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - cmd->setType(cmdType); + + cmd->setType(NAN_REQUEST_ENABLE); cmd->setId(id); cmd->setMsg((void *)msg); + ret = (wifi_error)cmd->start(); if (ret != WIFI_SUCCESS) { ALOGE("%s : failed in start, error = %d\n", __func__, ret); } - //cmd->releaseRef(); + + return ret; +} + +wifi_error nan_enable_request(transaction_id id, + wifi_interface_handle iface, NanEnableRequest* msg) +{ + wifi_error ret = WIFI_SUCCESS; + hal_info *h_info = getHalInfo(iface); + + ALOGE("nan_enable_request: nan_state = %d\n", h_info->nan_state); + +#ifdef CHRE_NAN + //check if host NAN is pre-empting CHRE NAN + if (h_info->nan_state == NAN_STATE_CHRE) { + /* notify pre-empt to chre */ + if (h_info->chre_nan_cb.on_chre_nan_rtt_change != NULL) { + h_info->chre_nan_cb.on_chre_nan_rtt_change(CHRE_PREMPTED); + } + /* first disable NAN for chre */ + ret = nan_chre_disable_request(1, iface); + if (ret != WIFI_SUCCESS) { + ALOGE("Failed to disable NAN for CHRE ret %d\n", ret); + return ret; + } + } + + /* notify unavailable status to chre */ + if (h_info->chre_nan_cb.on_chre_nan_rtt_change != NULL) { + h_info->chre_nan_cb.on_chre_nan_rtt_change(CHRE_UNAVAILABLE); + } +#endif /* CHRE_NAN */ + + NanMacControl *cmd = (NanMacControl*)(info.nan_mac_control); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + cmd->setChreNan(0); + ret = nan_cmn_enabe_request(id, cmd, msg); + + if (ret == WIFI_SUCCESS) { + h_info->nan_state = NAN_STATE_AP; + } + return ret; } @@ -4151,16 +4374,40 @@ void nan_dump_dbg_counters() ALOGI("Num Transmit Success %d\n", counters.transmit_txs); } +wifi_error nan_cmn_disable_request(transaction_id id, NanMacControl *mac) +{ + wifi_error ret = WIFI_SUCCESS; + + nan_dump_dbg_counters(); + + mac->setType(NAN_REQUEST_DISABLE); + ret = (wifi_error)mac->cancel(); + if (ret != WIFI_SUCCESS) { + ALOGE("cancel failed, error = %d\n", ret); + } else { + ALOGE("Deinitializing Nan Mac Control = %p\n", mac); + } + mac->releaseRef(); + + return ret; +} wifi_error nan_disable_request(transaction_id id, wifi_interface_handle iface) { - wifi_handle handle = getWifiHandle(iface); - NanRequestType cmdType = NAN_REQUEST_DISABLE; wifi_error ret = WIFI_SUCCESS; + hal_info *h_info = getHalInfo(iface); + + ALOGE("nan_disable_request: nan_state %d\n", h_info->nan_state); + + if (h_info->nan_state == NAN_STATE_CHRE) { + ALOGE("nan_disable_request: Not enabled for AP.. return\n"); + return ret; + } - ALOGI("Disabling Nan, Handle = %p\n", handle); - NanMacControl *cmd = new NanMacControl(iface, id, NULL, cmdType); NanMacControl *mac_prim = (NanMacControl*)(info.nan_mac_control); + NanMacControl *cmd = new NanMacControl(iface, id, NULL, NAN_REQUEST_LAST); + + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); if (id != NAN_MAC_INVALID_TRANSID) { ALOGE("Disable NAN MAC transId= %d\n", id); @@ -4169,17 +4416,15 @@ wifi_error nan_disable_request(transaction_id id, ALOGE("Invalid transId= %d cur= %d\n", id, mac_prim->getId()); } - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - - nan_dump_dbg_counters(); - - ret = (wifi_error)cmd->cancel(); - if (ret != WIFI_SUCCESS) { - ALOGE("cancel failed, error = %d\n", ret); - } else { - ALOGE("Deinitializing Nan Mac Control = %p\n", cmd); + cmd->setChreNan(0); + ret = nan_cmn_disable_request(id, cmd); + if (ret == WIFI_SUCCESS) { + h_info->nan_state = NAN_STATE_DISABLED; + /* notify pre-empt / unavailable status to chre */ + if (h_info->chre_nan_cb.on_chre_nan_rtt_change != NULL) { + h_info->chre_nan_cb.on_chre_nan_rtt_change(CHRE_AVAILABLE); + } } - cmd->releaseRef(); return ret; } @@ -4211,7 +4456,6 @@ wifi_error nan_publish_cancel_request(transaction_id id, { wifi_error ret = WIFI_SUCCESS; NanDiscEnginePrimitive *cmd; - wifi_handle handle = getWifiHandle(iface); NanRequestType cmdType = NAN_REQUEST_PUBLISH_CANCEL; ALOGE("Cancellling publish request %d\n", msg->publish_id); @@ -4258,7 +4502,6 @@ wifi_error nan_subscribe_cancel_request(transaction_id id, { wifi_error ret = WIFI_SUCCESS; NanDiscEnginePrimitive *cmd; - wifi_handle handle = getWifiHandle(iface); NanRequestType cmdType = NAN_REQUEST_SUBSCRIBE_CANCEL; ALOGE("creating new instance + %d\n", msg->subscribe_id); @@ -4274,36 +4517,11 @@ wifi_error nan_subscribe_cancel_request(transaction_id id, return ret; } -#ifdef NAN_CLUSTER_MERGE -/* Function to send NAN cluster merge enable/disable request to the wifi driver.*/ -wifi_error nan_enable_cluster_merge_request(transaction_id id, - wifi_interface_handle iface, NanEnableMergeRequest* msg) -{ - wifi_error ret = WIFI_SUCCESS; - wifi_handle handle = getWifiHandle(iface); - NanRequestType cmdType = NAN_REQUEST_ENABLE_MERGE; - - NanMacControl *cmd = new NanMacControl(iface, id, (void *)msg, cmdType); - NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); - cmd->setType(cmdType); - cmd->setId(id); - cmd->setMsg((void *)msg); - ret = (wifi_error)cmd->start(); - if (ret != WIFI_SUCCESS) { - ALOGE("%s :enable nan cluster merge failed in start, error = %d\n", __func__, ret); - } - cmd->releaseRef(); - - return ret; -} -#endif /* NAN_CLUSTER_MERGE */ - /* Function to send nan transmit followup Request to the wifi driver.*/ wifi_error nan_transmit_followup_request(transaction_id id, wifi_interface_handle iface, NanTransmitFollowupRequest* msg) { NanDiscEnginePrimitive *cmd = NULL; - wifi_handle handle = getWifiHandle(iface); NanRequestType cmdType = NAN_REQUEST_TRANSMIT_FOLLOWUP; wifi_error ret = WIFI_SUCCESS; @@ -4330,9 +4548,9 @@ wifi_error nan_stats_request(transaction_id id, wifi_handle handle = getWifiHandle(iface); ALOGI("Nan Stats, halHandle = %p", handle); - NanRequestType cmdType = NAN_REQUEST_STATS; #ifdef NOT_SUPPORTED + NanRequestType cmdType = NAN_REQUEST_STATS; wifi_error ret = WIFI_SUCCESS; NanCommand *cmd = new NanCommand(iface, id, (void *)msg, cmdType); NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); @@ -4383,9 +4601,9 @@ wifi_error nan_tca_request(transaction_id id, wifi_handle handle = getWifiHandle(iface); ALOGI("Nan TCA, halHandle = %p", handle); - NanRequestType cmdType = NAN_REQUEST_TCA; #ifdef NOT_SUPPORTED + NanRequestType cmdType = NAN_REQUEST_TCA; wifi_error ret = WIFI_SUCCESS; NanCommand *cmd = new NanCommand(iface, id, (void *)msg, cmdType); NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); @@ -4480,6 +4698,7 @@ wifi_error nan_deinit_handler() delete GET_NAN_HANDLE(info); NAN_HANDLE(info) = NULL; } + ALOGI("wifi nan internal clean up done"); return WIFI_SUCCESS; } wifi_error nan_register_handler(wifi_interface_handle iface, @@ -4552,6 +4771,7 @@ class NanEventCap : public WifiCommand unregisterVendorHandler(GOOGLE_OUI, i); } unregisterVendorHandler(GOOGLE_OUI, NAN_ASYNC_RESPONSE_DISABLED); + unregisterVendorHandler(GOOGLE_OUI, NAN_EVENT_MATCH_EXPIRY); } void registerNanVendorEvents() { @@ -4560,6 +4780,7 @@ class NanEventCap : public WifiCommand registerVendorHandler(GOOGLE_OUI, i); } registerVendorHandler(GOOGLE_OUI, NAN_ASYNC_RESPONSE_DISABLED); + registerVendorHandler(GOOGLE_OUI, NAN_EVENT_MATCH_EXPIRY); } int handleEvent(WifiEvent& event) { @@ -4623,9 +4844,10 @@ class NanEventCap : public WifiCommand disabled_ind.reason = (NanStatusType)it.get_u8(); ALOGI("Nan Disable:status %u", disabled_ind.reason); } else if (attr_type == NAN_ATTRIBUTE_REASON) { - memcpy(disabled_ind.nan_reason, it.get_data(), - sizeof(disabled_ind.nan_reason)); - ALOGI("nan disable reason: %s", disabled_ind.nan_reason); + u8 len = min(it.get_len(), sizeof(disabled_ind.nan_reason)); + memcpy(disabled_ind.nan_reason, it.get_data(), len); + ALOGI("nan disabled reason: %s, len = %d\n", + disabled_ind.nan_reason, len); } } @@ -4642,15 +4864,16 @@ class NanEventCap : public WifiCommand attr_type = it.get_type(); if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) { - pub_term_event.publish_id = it.get_u16(); + pub_term_event.publish_id = it.get_u32(); ALOGI("pub id %u", pub_term_event.publish_id); } else if (attr_type == NAN_ATTRIBUTE_STATUS) { pub_term_event.reason = (NanStatusType)it.get_u8(); ALOGI("pub termination status %u", pub_term_event.reason); } else if (attr_type == NAN_ATTRIBUTE_REASON) { - memcpy(pub_term_event.nan_reason, it.get_data(), - sizeof(pub_term_event.nan_reason)); - ALOGI("Pub termination nan reason: %s", pub_term_event.nan_reason); + u8 len = min(it.get_len(), sizeof(pub_term_event.nan_reason)); + memcpy(pub_term_event.nan_reason, it.get_data(), len); + ALOGI("Pub termination nan reason: %s, len = %d\n", + pub_term_event.nan_reason, len); } else { ALOGE("Unknown attr\n"); } @@ -4778,9 +5001,10 @@ class NanEventCap : public WifiCommand sub_term_event.reason = (NanStatusType)it.get_u8(); ALOGI("sub termination status %u", sub_term_event.reason); } else if (attr_type == NAN_ATTRIBUTE_REASON) { - memcpy(sub_term_event.nan_reason, it.get_data(), - sizeof(sub_term_event.nan_reason)); - ALOGI("sub termination nan reason: %s", sub_term_event.nan_reason); + u8 len = min(it.get_len(), sizeof(sub_term_event.nan_reason)); + memcpy(sub_term_event.nan_reason, it.get_data(), len); + ALOGI("sub termination nan reason: %s, len = %d\n", + sub_term_event.nan_reason, len); } else { ALOGE("Unknown attr: %u\n", attr_type); } @@ -4789,6 +5013,9 @@ class NanEventCap : public WifiCommand GET_NAN_HANDLE(info)->mHandlers.EventSubscribeTerminated(&sub_term_event); break; } + case NAN_EVENT_MATCH_EXPIRY: + HandleExpiryEvent(info, vendor_data); + break; case NAN_EVENT_FOLLOWUP: { NanFollowupInd followup_event; memset(&followup_event, 0, sizeof(NanFollowupInd)); @@ -4837,7 +5064,7 @@ class NanEventCap : public WifiCommand attr_type = it.get_type(); if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) { - sdfInd.data.frame_len = it.get_u32(); + sdfInd.data.frame_len = it.get_u16(); if (sdfInd.data.frame_len > NAN_MAX_FRAME_DATA_LEN) { sdfInd.data.frame_len = NAN_MAX_FRAME_DATA_LEN; } @@ -4893,8 +5120,8 @@ class NanEventCap : public WifiCommand attr_type = it.get_type(); if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) { - ALOGI("publish_id: %u\n", it.get_u16()); - ndp_request_event.service_instance_id = it.get_u16(); + ALOGI("publish_id: %u\n", it.get_u32()); + ndp_request_event.service_instance_id = it.get_u32(); } else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) { memcpy(ndp_request_event.peer_disc_mac_addr, @@ -4926,6 +5153,15 @@ class NanEventCap : public WifiCommand ndp_request_event.app_info.ndp_app_info[ndp_ind_app_info_len] = '\0'; ALOGI("service info: %s\n", ndp_request_event.app_info.ndp_app_info); + } else if (attr_type == NAN_ATTRIBUTE_SCID_LEN) { + ALOGI("scid length %d\n", it.get_u32()); + ndp_request_event.scid_len= it.get_u32(); + + } else if (attr_type == NAN_ATTRIBUTE_SCID) { + memcpy(ndp_request_event.scid, it.get_data(), + ndp_request_event.scid_len); + ndp_request_event.scid[ndp_request_event.scid_len] = '\0'; + ALOGI("scid: %s\n", ndp_request_event.scid); } } @@ -5014,9 +5250,10 @@ class NanEventCap : public WifiCommand } else if (attr_type == NAN_ATTRIBUTE_STATUS) { followup_ind.reason = (NanStatusType)it.get_u8(); } else if (attr_type == NAN_ATTRIBUTE_REASON) { - memcpy(followup_ind.nan_reason, it.get_data(), - sizeof(followup_ind.nan_reason)); - ALOGI("nan transmit followup ind: reason: %s", followup_ind.nan_reason); + u8 len = min(it.get_len(), sizeof(followup_ind.nan_reason)); + memcpy(followup_ind.nan_reason, it.get_data(), len); + ALOGI("nan transmit followup ind: reason: %s, len = %d\n", + followup_ind.nan_reason, len); } } @@ -5034,7 +5271,6 @@ class NanEventCap : public WifiCommand /* To see event prints in console */ wifi_error nan_event_check_request(transaction_id id, wifi_interface_handle iface) { - wifi_handle handle = getWifiHandle(iface); NanEventCap *cmd = new NanEventCap(iface, id); if (cmd == NULL) { return WIFI_ERROR_NOT_SUPPORTED; @@ -5047,7 +5283,6 @@ wifi_error nan_data_interface_create(transaction_id id, wifi_interface_handle iface, char* iface_name) { wifi_error ret = WIFI_SUCCESS; - wifi_handle handle = getWifiHandle(iface); NAN_DBG_ENTER(); NanRequestType cmdType = NAN_DATA_PATH_IFACE_CREATE; @@ -5070,7 +5305,6 @@ wifi_error nan_data_interface_delete(transaction_id id, wifi_interface_handle iface, char* iface_name) { wifi_error ret = WIFI_SUCCESS; - wifi_handle handle = getWifiHandle(iface); NAN_DBG_ENTER(); NanRequestType cmdType = NAN_DATA_PATH_IFACE_DELETE; @@ -5093,7 +5327,6 @@ wifi_error nan_data_request_initiator(transaction_id id, wifi_interface_handle iface, NanDataPathInitiatorRequest* msg) { wifi_error ret = WIFI_SUCCESS; - wifi_handle handle = getWifiHandle(iface); NAN_DBG_ENTER(); NanRequestType cmdType; @@ -5179,7 +5412,6 @@ wifi_error nan_data_indication_response(transaction_id id, wifi_interface_handle iface, NanDataPathIndicationResponse* msg) { wifi_error ret = WIFI_SUCCESS; - wifi_handle handle = getWifiHandle(iface); NAN_DBG_ENTER(); NanRequestType cmdType; u8 pub_nmi[NAN_MAC_ADDR_LEN] = {0}; @@ -5275,7 +5507,6 @@ wifi_error nan_data_end(transaction_id id, { wifi_error ret = WIFI_SUCCESS; NanDataPathPrimitive *cmd; - wifi_handle handle = getWifiHandle(iface); NanRequestType cmdType = NAN_DATA_PATH_END; NAN_DBG_ENTER(); @@ -5290,3 +5521,89 @@ wifi_error nan_data_end(transaction_id id, NAN_DBG_EXIT(); return ret; } + +wifi_error nan_chre_enable_request(transaction_id id, + wifi_interface_handle iface, NanEnableRequest* msg) +{ + wifi_error ret = WIFI_SUCCESS; + NanEnableRequest def_msg; + hal_info *h_info = getHalInfo(iface); + + ALOGI("nan_chre_enable_request: nan_state %d\n", h_info->nan_state); + + if (h_info->nan_state == NAN_STATE_CHRE) { + return WIFI_SUCCESS; + } else if (h_info->nan_state == NAN_STATE_AP) { + ALOGE("nan_chre_enable_request: Nan is enabled for AP. Fail CHRE request\n"); + return WIFI_ERROR_BUSY; + } + + NanMacControl *mac = new NanMacControl(iface, 0, NULL, NAN_REQUEST_LAST); + NULL_CHECK_RETURN(mac, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + + mac->setChreNan(1); + if (msg == NULL) { + /* default enable params */ + ALOGI("Input Enable config is NULL, use default config\n"); + memset(&def_msg, 0, sizeof(def_msg)); + def_msg.hop_count_limit_val = 5; + def_msg.config_2dot4g_support = 1; + def_msg.support_2dot4g_val = 1; + def_msg.config_2dot4g_beacons = 1; + def_msg.beacon_2dot4g_val = 1; + def_msg.config_2dot4g_sdf = 1; + def_msg.sdf_2dot4g_val = 1; + def_msg.config_disc_mac_addr_randomization = true; + def_msg.disc_mac_addr_rand_interval_sec = 0; + def_msg.config_ndpe_attr = false; + ret = nan_cmn_enabe_request(id, mac, &def_msg); + } else { + ret = nan_cmn_enabe_request(id, mac, msg); + } + + if (ret == WIFI_SUCCESS) { + h_info->nan_state = NAN_STATE_CHRE; + } + + return ret; +} + +wifi_error nan_chre_disable_request(transaction_id id, + wifi_interface_handle iface) +{ + wifi_error ret = WIFI_SUCCESS; + hal_info *h_info = getHalInfo(iface); + + ALOGI("nan_chre_disable_request: nan_state %d\n", h_info->nan_state); + + if (h_info->nan_state == NAN_STATE_AP) { + ALOGE("nan_chre_disable_request: Not enabled for CHRE.. return\n"); + return ret; + } + + NanMacControl *cmd = new NanMacControl(iface, id, NULL, NAN_REQUEST_LAST); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + + cmd->setChreNan(1); + ret = nan_cmn_disable_request(id, cmd); + + if (ret == WIFI_SUCCESS) { + h_info->nan_state = NAN_STATE_DISABLED; + } + + return ret; +} + +wifi_error nan_chre_register_handler(wifi_interface_handle iface, + wifi_chre_handler handler) +{ + wifi_error ret = WIFI_SUCCESS; + hal_info *h_info = getHalInfo(iface); + + if (h_info) { + ALOGE("Registering CHRE handler for Nan Status %p\n", handler.on_chre_nan_rtt_change); + h_info->chre_nan_cb = handler; + } + + return ret; +} diff --git a/bcmdhd/wifi_hal/rtt.cpp b/bcmdhd/wifi_hal/rtt.cpp index 81eb17f..6bb0a49 100644 --- a/bcmdhd/wifi_hal/rtt.cpp +++ b/bcmdhd/wifi_hal/rtt.cpp @@ -60,26 +60,30 @@ typedef enum { } 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_TARGET_INVALID = 0, + RTT_ATTRIBUTE_TARGET_CNT = 1, + RTT_ATTRIBUTE_TARGET_INFO = 2, + RTT_ATTRIBUTE_TARGET_MAC = 3, + RTT_ATTRIBUTE_TARGET_TYPE = 4, + RTT_ATTRIBUTE_TARGET_PEER = 5, + RTT_ATTRIBUTE_TARGET_CHAN = 6, + RTT_ATTRIBUTE_TARGET_PERIOD = 7, + RTT_ATTRIBUTE_TARGET_NUM_BURST = 8, + RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST = 9, + RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM = 10, + RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR = 11, + RTT_ATTRIBUTE_TARGET_LCI = 12, + RTT_ATTRIBUTE_TARGET_LCR = 13, + RTT_ATTRIBUTE_TARGET_BURST_DURATION = 14, + RTT_ATTRIBUTE_TARGET_PREAMBLE = 15, + RTT_ATTRIBUTE_TARGET_BW = 16, + RTT_ATTRIBUTE_RESULTS_COMPLETE = 30, + RTT_ATTRIBUTE_RESULTS_PER_TARGET = 31, + RTT_ATTRIBUTE_RESULT_CNT = 32, + RTT_ATTRIBUTE_RESULT = 33, + RTT_ATTRIBUTE_RESUTL_DETAIL = 34, + /* Add any new RTT_ATTRIBUTE prior to RTT_ATTRIBUTE_MAX */ + RTT_ATTRIBUTE_MAX } RTT_ATTRIBUTE; typedef struct strmap_entry { int id; @@ -96,6 +100,7 @@ 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_MNG_MEASURE_REPORT_ID 39 /* 11H MeasurementResponse */ #define DOT11_MEASURE_TYPE_LCI 8 /* d11 measurement LCI type */ #define DOT11_MEASURE_TYPE_CIVICLOC 11 /* d11 measurement location civic */ @@ -313,6 +318,7 @@ class RttCommand : public WifiCommand unsigned numRttParams; int mCompleted; int currentIdx; + int currDtlIdx; int totalCnt; static const int MAX_RESULTS = 1024; wifi_rtt_result *rttResults[MAX_RESULTS]; @@ -328,6 +334,7 @@ public: currentIdx = 0; mCompleted = 0; totalCnt = 0; + currDtlIdx = 0; } RttCommand(wifi_interface_handle iface, int id) @@ -336,7 +343,11 @@ public: currentIdx = 0; mCompleted = 0; totalCnt = 0; + currDtlIdx = 0; numRttParams = 0; + memset(rttResults, 0, sizeof(rttResults)); + rttParams = NULL; + rttHandler.on_rtt_results = NULL; } int createSetupRequest(WifiRequest& request) { @@ -451,7 +462,11 @@ public: } nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); - request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, num_devices); + result = request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, num_devices); + + if (result < 0) { + return result; + } for(unsigned i = 0; i < num_devices; i++) { result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, addr[i]); if (result < 0) { @@ -470,13 +485,14 @@ public: return result; } + registerVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); result = requestResponse(request); if (result != WIFI_SUCCESS) { + unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); ALOGE("failed to configure RTT setup; result = %d", result); return result; } - registerVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); ALOGI("Successfully started RTT operation"); return result; } @@ -528,6 +544,7 @@ public: int len = event.get_vendor_data_len(); if (vendor_data == NULL || len == 0) { ALOGI("No rtt results found"); + return NL_STOP; } for (nl_iterator it(vendor_data); it.has_next(); it.next()) { if (it.get_type() == RTT_ATTRIBUTE_RESULTS_COMPLETE) { @@ -561,19 +578,18 @@ public: 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->id == DOT11_MNG_MEASURE_REPORT_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) && + if ((ele_2->id == DOT11_MNG_MEASURE_REPORT_ID) && (ele_2->type == DOT11_MEASURE_TYPE_CIVICLOC)) { rtt_result->LCR = (wifi_information_element *)ele_2; } @@ -584,7 +600,7 @@ public: /* 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) && + if ((ele_2->id == DOT11_MNG_MEASURE_REPORT_ID) && (ele_2->type == DOT11_MEASURE_TYPE_LCI)) { rtt_result->LCI = (wifi_information_element *)ele_2; } @@ -595,13 +611,14 @@ public: 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", + "\trssi : %d dbm, rx_rate : %d Kbps, rtt : %lu ns, rtt_sd : %lu\n" + "\tdistance : %d cm, 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, + (unsigned long)rtt_result->rtt/1000, (unsigned long)rtt_result->rtt_sd, + rtt_result->distance_mm / 10, rtt_result->burst_duration, rtt_result->negotiated_burst_num); currentIdx++; } @@ -611,7 +628,9 @@ public: } if (mCompleted) { unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); - (*rttHandler.on_rtt_results)(id(), totalCnt, rttResults); + if (*rttHandler.on_rtt_results) { + (*rttHandler.on_rtt_results)(id(), totalCnt, rttResults); + } for (int i = 0; i < currentIdx; i++) { free(rttResults[i]); rttResults[i] = NULL; @@ -630,7 +649,19 @@ public: 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) { + if (iface == NULL) { + ALOGE("wifi_rtt_range_request: NULL iface pointer provided." + " Exit."); + return WIFI_ERROR_INVALID_ARGS; + } + wifi_handle handle = getWifiHandle(iface); + if (handle == NULL) { + ALOGE("wifi_rtt_range_request: NULL handle pointer provided." + " Exit."); + return WIFI_ERROR_INVALID_ARGS; + } + 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); @@ -651,7 +682,19 @@ wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle ifac wifi_error wifi_rtt_range_cancel(wifi_request_id id, wifi_interface_handle iface, unsigned num_devices, mac_addr addr[]) { + if (iface == NULL) { + ALOGE("wifi_rtt_range_cancel: NULL iface pointer provided." + " Exit."); + return WIFI_ERROR_INVALID_ARGS; + } + wifi_handle handle = getWifiHandle(iface); + if (handle == NULL) { + ALOGE("wifi_rtt_range_cancel: NULL handle pointer provided." + " Exit."); + return WIFI_ERROR_INVALID_ARGS; + } + RttCommand *cmd = new RttCommand(iface, id); NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); cmd->cancel_specific(num_devices, addr); @@ -663,6 +706,18 @@ wifi_error wifi_rtt_range_cancel(wifi_request_id id, wifi_interface_handle ifac wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface, wifi_rtt_capabilities *capabilities) { + if (iface == NULL) { + ALOGE("wifi_get_rtt_capabilities: NULL iface pointer provided." + " Exit."); + return WIFI_ERROR_INVALID_ARGS; + } + + if (capabilities == NULL) { + ALOGE("wifi_get_rtt_capabilities: NULL capabilities pointer provided." + " Exit."); + return WIFI_ERROR_INVALID_ARGS; + } + GetRttCapabilitiesCommand command(iface, capabilities); return (wifi_error) command.requestResponse(); } @@ -671,6 +726,12 @@ wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface, wifi_error wifi_rtt_get_responder_info(wifi_interface_handle iface, wifi_rtt_responder* responderInfo) { + if (iface == NULL) { + ALOGE("wifi_rtt_get_responder_info: NULL iface pointer provided." + " Exit."); + return WIFI_ERROR_INVALID_ARGS; + } + GetRttResponderInfoCommand command(iface, responderInfo); return (wifi_error) command.requestResponse(); diff --git a/bcmdhd/wifi_hal/sync.h b/bcmdhd/wifi_hal/sync.h index 64f8d39..1118c71 100644 --- a/bcmdhd/wifi_hal/sync.h +++ b/bcmdhd/wifi_hal/sync.h @@ -68,4 +68,4 @@ public: } }; -#endif
\ No newline at end of file +#endif diff --git a/bcmdhd/wifi_hal/twt.cpp b/bcmdhd/wifi_hal/twt.cpp new file mode 100755 index 0000000..15bb738 --- /dev/null +++ b/bcmdhd/wifi_hal/twt.cpp @@ -0,0 +1,947 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Portions copyright (C) 2020 Broadcom Limited + * + * 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" + +static const char *TwtCmdToString(int cmd); +static void EventGetAttributeData(u8 sub_event_type, nlattr *vendor_data); +typedef void *TwtRequest; + +#define C2S(x) case x: return #x; + +typedef struct _twt_hal_info { + void *twt_handle; + void *twt_feature_request; +} twt_hal_info_t; + +twt_hal_info_t twt_info; + +#define TWT_HANDLE(twt_info) ((twt_info).twt_handle) +#define GET_TWT_HANDLE(twt_info) ((TwtHandle *)twt_info.twt_handle) + +#define WL_TWT_CAP_FLAGS_REQ_SUPPORT (1u << 0u) +#define WL_TWT_CAP_FLAGS_RESP_SUPPORT (1u << 1u) +#define WL_TWT_CAP_FLAGS_BTWT_SUPPORT (1u << 2u) +#define WL_TWT_CAP_FLAGS_FLEX_SUPPORT (1u << 3u) + +class TwtHandle +{ + public: + TwtCallbackHandler mHandlers; + TwtHandle(wifi_handle handle, TwtCallbackHandler handlers):mHandlers(handlers) + {} + +}; + + +static const char *TwtCmdToString(int cmd) +{ + switch (cmd) { + C2S(TWT_SETUP_REQUEST); + C2S(TWT_INFO_FRAME_REQUEST); + C2S(TWT_TEAR_DOWN_REQUEST); + default: + return "UNKNOWN_NAN_CMD"; + } +} + +static bool is_twt_sub_event(int sub_event_type) +{ + bool is_twt_event = false; + switch (sub_event_type) { + case TWT_SETUP_RESPONSE: + case TWT_TEARDOWN_COMPLETION: + case TWT_INFORM_FRAME: + case TWT_NOTIFY: + is_twt_event = true; + } + return is_twt_event; +} + +void EventGetAttributeData(u8 sub_event_type, nlattr *vendor_data) +{ + u8 attr_type = 0; + + switch (sub_event_type) { + case TWT_SETUP_RESPONSE: + TwtSetupResponse setup_response; + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + attr_type = it.get_type(); + switch (attr_type) { + case TWT_ATTRIBUTE_CONFIG_ID: + ALOGI("config_id = %u\n", it.get_u8()); + setup_response.config_id = it.get_u8(); + break; + case TWT_ATTRIBUTE_NEG_TYPE: + ALOGI("neg type = %u\n", it.get_u8()); + setup_response.negotiation_type = it.get_u8(); + break; + case TWT_ATTRIBUTE_REASON_CODE: + setup_response.reason_code = (TwtSetupReasonCode)it.get_u8(); + ALOGI("reason code = %u\n", setup_response.reason_code); + break; + case TWT_ATTRIBUTE_STATUS: + setup_response.status = it.get_u8(); + ALOGI("status = %u\n", setup_response.status); + break; + case TWT_ATTRIBUTE_TRIGGER_TYPE: + setup_response.trigger_type = it.get_u8(); + ALOGI("trigger type = %u\n", setup_response.trigger_type); + break; + case TWT_ATTRIBUTE_WAKE_DUR_US: + setup_response.wake_dur_us = it.get_u32(); + ALOGI("wake_dur_us = %d\n", setup_response.wake_dur_us); + break; + case TWT_ATTRIBUTE_WAKE_INT_US: + setup_response.wake_int_us = it.get_u32(); + ALOGI("wake_int_us = %d\n", setup_response.wake_int_us); + break; + case TWT_ATTRIBUTE_WAKE_TIME_OFF_US: + setup_response.wake_time_off_us = it.get_u32(); + ALOGI("wake_time_off_us = %d\n", setup_response.wake_time_off_us); + break; + default: + if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) { + ALOGE("Unknown attr_type: %d\n", attr_type); + } + break; + } + } + GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtSetupResponse(&setup_response); + break; + case TWT_TEARDOWN_COMPLETION: + TwtTeardownCompletion teardown_event; + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + attr_type = it.get_type(); + switch (attr_type) { + case TWT_ATTRIBUTE_CONFIG_ID: + ALOGI("config_id = %u\n", it.get_u8()); + teardown_event.config_id = it.get_u8(); + break; + case TWT_ATTRIBUTE_STATUS: + teardown_event.status = it.get_u8(); + ALOGI("status = %u\n", teardown_event.status); + break; + case TWT_ATTRIBUTE_ALL_TWT: + teardown_event.all_twt = it.get_u8(); + ALOGI("all_twt = %d\n", teardown_event.all_twt); + break; + case TWT_ATTRIBUTE_REASON_CODE: + teardown_event.reason = (TwtTeardownReason)it.get_u8(); + ALOGI("reason = %u\n", teardown_event.reason); + break; + default: + if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) { + ALOGE("Unknown attr_type: %d\n", attr_type); + } + break; + } + } + GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtTeardownCompletion(&teardown_event); + break; + case TWT_INFORM_FRAME: + TwtInfoFrameReceived info_frame_event; + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + attr_type = it.get_type(); + switch (attr_type) { + case TWT_ATTRIBUTE_CONFIG_ID: + ALOGI("config_id = %u\n", it.get_u8()); + info_frame_event.config_id = it.get_u8(); + break; + case TWT_ATTRIBUTE_REASON_CODE: + info_frame_event.reason = (TwtInfoFrameReason)it.get_u8(); + ALOGI("reason = %u\n", info_frame_event.reason); + break; + case TWT_ATTRIBUTE_STATUS: + info_frame_event.status = it.get_u8(); + ALOGI("status = %u\n", info_frame_event.status); + break; + case TWT_ATTRIBUTE_ALL_TWT: + info_frame_event.all_twt = it.get_u8(); + ALOGI("all_twt = %d\n", info_frame_event.all_twt); + break; + case TWT_ATTRIBUTE_RESUMED: + info_frame_event.twt_resumed = it.get_u8(); + ALOGI("twt_resumed = %u\n", info_frame_event.twt_resumed); + break; + default: + if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) { + ALOGE("Unknown attr_type: %d\n", attr_type); + } + break; + } + } + GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtInfoFrameReceived(&info_frame_event); + break; + case TWT_NOTIFY: + TwtDeviceNotify notif_event; + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + attr_type = it.get_type(); + switch (attr_type) { + case TWT_ATTRIBUTE_NOTIFICATION: + notif_event.notification = (TwtNotification)it.get_u8(); + ALOGI("notification = %u\n", notif_event.notification); + break; + default: + if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) { + ALOGE("Unknown attr_type: %d\n", attr_type); + } + break; + } + } + GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtDeviceNotify(¬if_event); + break; + default: + ALOGE("Unknown event_type: %d\n", sub_event_type); + break; + } + return; +} + +void HandleTwtEvent(nlattr *vendor_data) { + u8 sub_event_type = 0; + u8 event_type = 0; + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + event_type = it.get_type(); + if (event_type == TWT_ATTRIBUTE_SUB_EVENT) { + sub_event_type = it.get_u8(); + if (is_twt_sub_event(sub_event_type)) { + EventGetAttributeData(sub_event_type, vendor_data); + } + } + } + return; +} + +class TwtEventCap : public WifiCommand +{ + public: + TwtEventCap(wifi_interface_handle iface, int id) + : WifiCommand("TwtCommand", iface, id) + {} + + int start() + { + registerTwtVendorEvents(); + return WIFI_SUCCESS; + } + + int handleResponse(WifiEvent& reply) { + return NL_SKIP; + } + + void registerTwtVendorEvents() + { + registerVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT); + } + + void unregisterTwtVendorEvents() + { + unregisterVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT); + } + + int handleEvent(WifiEvent& event) { + u16 attr_type; + TwtEventType twt_event; + + 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("EventCapture: Received TWT event: %d\n", event_id); + if (!vendor_data || len == 0) { + ALOGE("No event data found"); + return NL_SKIP; + } + + switch (event_id) { + case BRCM_VENDOR_EVENT_TWT: { + ALOGE("Handle TWT event: %d\n", event_id); + HandleTwtEvent(vendor_data); + break; + } + default: + break; + } + return NL_SKIP; + } +}; + +/* To see event prints in console */ +wifi_error twt_event_check_request(transaction_id id, wifi_interface_handle iface) +{ + TwtEventCap *cmd = new TwtEventCap(iface, id); + if (cmd == NULL) { + return WIFI_ERROR_NOT_SUPPORTED; + } + return (wifi_error)cmd->start(); +} + +////////////////////////////////////////////////////////////////////////// +class GetTwtCapabilitiesCommand : public WifiCommand +{ + TwtCapabilitySet *mCapabilities; +public: + GetTwtCapabilitiesCommand(wifi_interface_handle iface, TwtCapabilitySet *capabilities) + : WifiCommand("GetTwtCapabilitiesCommand", iface, 0), mCapabilities(capabilities) + { + memset(mCapabilities, 0, sizeof(*mCapabilities)); + } + + virtual int create() { + ALOGD("Creating message to get twt capabilities; iface\n"); + + int ret = mMsg.create(GOOGLE_OUI, TWT_SUBCMD_GETCAPABILITY); + if (ret < 0) { + ALOGE("Failed to send the twt cap cmd, err = %d\n", ret); + } + ALOGD("Success to send twt cap cmd, err = %d\n", ret); + return ret; + } + +private: + TwtCapability parseTwtCap(uint32_t twt_peer_cap) { + TwtCapability cap; + cap.requester_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT) ? 1 : 0; + cap.responder_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT) ? 1 : 0; + cap.broadcast_twt_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT) ? 1 : 0; + cap.flexibile_twt_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT) ? 1 : 0; + return cap; + } + +protected: + virtual int handleResponse(WifiEvent& reply) { + + ALOGI("In GetTwtCapabilitiesCommand::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(); + uint32_t twt_device_cap, twt_peer_cap; + + nlattr *data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + + ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len); + if (data == NULL || len == 0) { + ALOGE("no vendor data in GetTwtCapabilitiesCommand response; ignoring it\n"); + return NL_SKIP; + } + + for (nl_iterator it(data); it.has_next(); it.next()) { + switch (it.get_type()) { + case TWT_ATTRIBUTE_DEVICE_CAP: + twt_device_cap = it.get_u32(); + mCapabilities->device_capability = parseTwtCap(twt_device_cap); + break; + case TWT_ATTRIBUTE_PEER_CAP: + twt_peer_cap = it.get_u32(); + mCapabilities->peer_capability = parseTwtCap(twt_peer_cap); + break; + default: + ALOGE("Ignoring invalid attribute type = %d, size = %d\n", + it.get_type(), it.get_len()); + break; + } + } + + ALOGE("Out GetTwtCapabilitiesCommand::handleResponse\n"); + return NL_OK; + } +}; + +/* API to get TWT capability */ +wifi_error twt_get_capability(wifi_interface_handle iface, + TwtCapabilitySet *twt_cap_set) +{ + if (iface == NULL) { + ALOGE("twt_get_capability: NULL iface pointer provided." + " Exit."); + return WIFI_ERROR_INVALID_ARGS; + } + + if (twt_cap_set == NULL) { + ALOGE("twt_get_capability: NULL capabilities pointer provided." + " Exit."); + return WIFI_ERROR_INVALID_ARGS; + } + + GetTwtCapabilitiesCommand command(iface, twt_cap_set); + return (wifi_error) command.requestResponse(); +} + +////////////////////////////////////////////////////////////////////////// +class GetTwtStatsCommand : public WifiCommand +{ + TwtStats* mStats; + u8 mConfig_id; +public: + GetTwtStatsCommand(wifi_interface_handle iface, u8 config_id, TwtStats *stats) + : WifiCommand("GetTwtStatsCommand", iface, 0), mConfig_id(config_id), mStats(stats) + { + memset(mStats, 0, sizeof(*mStats)); + } + + virtual int create() { + ALOGD("Creating message to get twt stats; iface = %d", mIfaceInfo->id); + + int ret = mMsg.create(GOOGLE_OUI, TWT_SUBCMD_GETSTATS); + if (ret < 0) { + return ret; + } + + nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA); + ret = mMsg.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mConfig_id); + if (ret < 0) { + ALOGE("Failed to set mConfig_id %d\n", mConfig_id); + return ret; + } + + ALOGI("Successfully configured config id %d\n", mConfig_id); + mMsg.attr_end(data); + return WIFI_SUCCESS; + } + +protected: + virtual int handleResponse(WifiEvent& reply) { + + ALOGI("In GetTwtStatsCommand::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 *data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + + ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len); + if (data == NULL || len == 0) { + ALOGE("no vendor data in GetTwtStatsCommand response; ignoring it\n"); + return NL_SKIP; + } + + for (nl_iterator it(data); it.has_next(); it.next()) { + switch (it.get_type()) { + case TWT_ATTRIBUTE_CONFIG_ID: + mStats->config_id = it.get_u8(); + break; + case TWT_ATTRIBUTE_AVG_PKT_NUM_TX: + mStats->avg_pkt_num_tx = it.get_u32(); + break; + case TWT_ATTRIBUTE_AVG_PKT_NUM_RX: + mStats->avg_pkt_num_rx = it.get_u32(); + break; + case TWT_ATTRIBUTE_AVG_PKT_SIZE_TX: + mStats->avg_tx_pkt_size = it.get_u32(); + break; + case TWT_ATTRIBUTE_AVG_PKT_SIZE_RX: + mStats->avg_rx_pkt_size = it.get_u32(); + break; + case TWT_ATTRIBUTE_AVG_EOSP_DUR: + mStats->avg_eosp_dur_us = it.get_u32(); + break; + case TWT_ATTRIBUTE_EOSP_COUNT: + mStats->eosp_count = it.get_u32(); + break; + case TWT_ATTRIBUTE_NUM_SP: + mStats->num_sp = it.get_u32(); + break; + default: + ALOGE("Ignoring invalid attribute type = %d, size = %d\n", + it.get_type(), it.get_len()); + break; + } + } + + return NL_OK; + } +}; + +/* API to get TWT stats */ +wifi_error twt_get_stats(wifi_interface_handle iface, u8 config_id, TwtStats* stats) +{ + if (iface == NULL) { + ALOGE("twt_get_stats: NULL iface pointer provided." + " Exit."); + return WIFI_ERROR_INVALID_ARGS; + } + + if (stats == NULL) { + ALOGE("TwtCapabilitySet: NULL capabilities pointer provided." + " Exit."); + return WIFI_ERROR_INVALID_ARGS; + } + + GetTwtStatsCommand command(iface, config_id, stats); + return (wifi_error) command.requestResponse(); +} + +////////////////////////////////////////////////////////////////////////////////////// +class ClearTwtStatsCommand : public WifiCommand +{ + u8 mConfig_id; +public: + ClearTwtStatsCommand(wifi_interface_handle iface, u8 config_id) + : WifiCommand("ClearTwtStatsCommand", iface, 0), mConfig_id(config_id) + { + } + + virtual int create() { + ALOGD("Creating message to clear twt stats; config_id = %d\n", mConfig_id); + + int ret = mMsg.create(GOOGLE_OUI, TWT_SUBCMD_CLR_STATS); + if (ret < 0) { + return ret; + } + + nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA); + ret = mMsg.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mConfig_id); + if (ret < 0) { + ALOGE("Failed to set mConfig_id %d\n", mConfig_id); + return ret; + } + + ALOGI("Successfully configured config id %d\n", mConfig_id); + mMsg.attr_end(data); + return WIFI_SUCCESS; + } + +protected: + virtual int handleResponse(WifiEvent& reply) { + ALOGD("In ClearTwtStatsCommand::handleResponse"); + /* Nothing to do on response! */ + return NL_SKIP; + } +}; + +/* API to clear TWT stats */ +wifi_error twt_clear_stats(wifi_interface_handle iface, u8 config_id) +{ + if (iface == NULL || !config_id) { + ALOGE("twt_clear_stats: NULL iface pointer provided." + " Exit."); + return WIFI_ERROR_INVALID_ARGS; + } + ALOGE("twt_clear_stats: config id: %d\n", config_id); + + ClearTwtStatsCommand command(iface, config_id); + return (wifi_error) command.requestResponse(); +} + +//////////////////////////////////////////////////////////////////////////////// +class TwtFeatureRequest : public WifiCommand +{ + TwtRequest reqContext; + TwtRequestType mType; + + public: + TwtFeatureRequest(wifi_interface_handle iface, + TwtRequest params, TwtRequestType cmdType) + : WifiCommand("TwtFeatureRequest", iface, 0), reqContext(params), mType(cmdType) + { + } + + int createRequest(WifiRequest& request) + { + ALOGI("TWT CMD: %s\n", TwtCmdToString(mType)); + if (mType == TWT_SETUP_REQUEST) { + return createTwtSetupRequest(request, (TwtSetupRequest *)reqContext); + } else if (mType == TWT_INFO_FRAME_REQUEST) { + return createInfoFrameRequest(request, (TwtInfoFrameRequest *)reqContext); + } else if (mType == TWT_TEAR_DOWN_REQUEST) { + return createTearDownRequest(request, (TwtTeardownRequest *)reqContext); + } else { + ALOGE("%s: Unknown TWT request: %d\n", __func__, mType); + return WIFI_ERROR_UNKNOWN; + } + + return WIFI_SUCCESS; + } + + int createTwtSetupRequest(WifiRequest& request, TwtSetupRequest *mParams) + { + int result = request.create(GOOGLE_OUI, TWT_SUBCMD_SETUP_REQUEST); + if (result < 0) { + ALOGE("%s Failed to create request, result = %d\n", __func__, result); + return result; + } + + /* If handle is 0xFFFF, then update instance_id in response of this request + * otherwise, update not needed + */ + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + if (mParams->config_id) { + result = request.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mParams->config_id); + if (result < 0) { + ALOGE("%s: Failed to fill config_id = %d, result = %d\n", + __func__, mParams->config_id, result); + return result; + } + } + + if (mParams->negotiation_type) { + result = request.put_u8(TWT_ATTRIBUTE_NEG_TYPE, mParams->negotiation_type); + if (result < 0) { + ALOGE("%s: Failed to fill negotiation_type = %d, result = %d\n", + __func__, mParams->negotiation_type, result); + return result; + } + } + if (mParams->trigger_type) { + result = request.put_u8(TWT_ATTRIBUTE_TRIGGER_TYPE, mParams->trigger_type); + if (result < 0) { + ALOGE("%s: Failed to fill trigger_type = %d, result = %d\n", + __func__, mParams->trigger_type, result); + return result; + } + } + if (mParams->wake_dur_us) { + result = request.put_u32(TWT_ATTRIBUTE_WAKE_DUR_US, mParams->wake_dur_us); + if (result < 0) { + ALOGE("%s: Failed to fill wake_dur_us = %d, result = %d\n", + __func__, mParams->wake_dur_us, result); + return result; + } + } + if (mParams->wake_int_us) { + result = request.put_u32(TWT_ATTRIBUTE_WAKE_INT_US, mParams->wake_int_us); + if (result < 0) { + ALOGE("%s: Failed to fill wake_int_us = %d, result = %d\n", + __func__, mParams->wake_int_us, result); + return result; + } + } + if (mParams->wake_int_min_us) { + result = request.put_u32(TWT_ATTRIBUTE_WAKE_INT_MIN_US, mParams->wake_int_min_us); + if (result < 0) { + ALOGE("%s: Failed to fill wake_int_min_us = %d, result = %d\n", + __func__, mParams->wake_int_min_us, result); + return result; + } + } + if (mParams->wake_int_max_us) { + result = request.put_u32(TWT_ATTRIBUTE_WAKE_INT_MAX_US, mParams->wake_int_max_us); + if (result < 0) { + ALOGE("%s: Failed to fill wake_int_max_us = %d, result = %d\n", + __func__, mParams->wake_int_max_us, result); + return result; + } + } + if (mParams->wake_dur_min_us) { + result = request.put_u32(TWT_ATTRIBUTE_WAKE_DUR_MIN_US, mParams->wake_dur_min_us); + if (result < 0) { + ALOGE("%s: Failed to fill wake_dur_min_us = %d, result = %d\n", + __func__, mParams->wake_dur_min_us, result); + return result; + } + } + if (mParams->wake_dur_max_us) { + result = request.put_u32(TWT_ATTRIBUTE_WAKE_DUR_MAX_US, mParams->wake_dur_max_us); + if (result < 0) { + ALOGE("%s: Failed to fill wake_dur_max_us = %d, result = %d\n", + __func__, mParams->wake_dur_max_us, result); + return result; + } + } + if (mParams->avg_pkt_size) { + result = request.put_u32(TWT_ATTRIBUTE_AVG_PKT_SIZE, mParams->avg_pkt_size); + if (result < 0) { + ALOGE("%s: Failed to fill avg_pkt_size = %d, result = %d\n", + __func__, mParams->avg_pkt_size, result); + return result; + } + } + if (mParams->avg_pkt_num) { + result = request.put_u32(TWT_ATTRIBUTE_AVG_PKT_NUM, mParams->avg_pkt_num); + if (result < 0) { + ALOGE("%s: Failed to fill avg_pkt_num = %d, result = %d\n", + __func__, mParams->avg_pkt_num, result); + return result; + } + } + if (mParams->wake_time_off_us) { + result = request.put_u32(TWT_ATTRIBUTE_WAKE_TIME_OFF_US, mParams->wake_time_off_us); + if (result < 0) { + ALOGE("%s: Failed to fill wake_time_off_us = %d, result = %d\n", + __func__, mParams->wake_time_off_us, result); + return result; + } + } + request.attr_end(data); + + ALOGI("Returning successfully\n"); + return result; + } + + int createInfoFrameRequest(WifiRequest& request, TwtInfoFrameRequest *mParams) + { + int result = request.create(GOOGLE_OUI, TWT_SUBCMD_INFO_FRAME_REQUEST); + if (result < 0) { + ALOGE("%s: Failed to create request, result = %d\n", __func__, result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + if (mParams->config_id) { + result = request.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mParams->config_id); + if (result < 0) { + ALOGE("%s: Failed to fill config_id = %d, result = %d\n", + __func__, mParams->config_id, result); + return result; + } + } + if (mParams->resume_time_us) { + result = request.put_u32(TWT_ATTRIBUTE_RESUME_TIME_US, mParams->resume_time_us); + if (result < 0) { + ALOGE("%s: Failed to fill resume_time_us = %d, result = %d\n", + __func__, mParams->resume_time_us, result); + return result; + } + } + if (mParams->all_twt) { + result = request.put_u8(TWT_ATTRIBUTE_ALL_TWT, mParams->all_twt); + if (result < 0) { + ALOGE("%s: Failed to fill all_twt = %d, result = %d\n", + __func__, mParams->all_twt, result); + return result; + } + } + request.attr_end(data); + return WIFI_SUCCESS; + } + + int createTearDownRequest(WifiRequest& request, TwtTeardownRequest *mParams) + { + int result = request.create(GOOGLE_OUI, TWT_SUBCMD_TEAR_DOWN_REQUEST); + if (result < 0) { + ALOGE("%s: Failed to create request, result = %d\n", __func__, result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + if (mParams->config_id) { + result = request.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mParams->config_id); + if (result < 0) { + ALOGE("%s: Failed to fill config_id = %d, result = %d\n", + __func__, mParams->config_id, result); + return result; + } + } + if (mParams->negotiation_type) { + result = request.put_u8(TWT_ATTRIBUTE_NEG_TYPE, mParams->negotiation_type); + if (result < 0) { + ALOGE("%s: Failed to fill negotiation_type = %d, result = %d\n", + __func__, mParams->negotiation_type, result); + return result; + } + } + if (mParams->all_twt) { + result = request.put_u8(TWT_ATTRIBUTE_ALL_TWT, mParams->all_twt); + if (result < 0) { + ALOGE("%s: Failed to fill all_twt = %d, result = %d\n", + __func__, mParams->all_twt, result); + return result; + } + } + request.attr_end(data); + return WIFI_SUCCESS; + } + + int open() + { + WifiRequest request(familyId(), ifaceId()); + int result = createRequest(request); + if (result != WIFI_SUCCESS) { + ALOGE("%s: failed to create setup request; result = %d", __func__, result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("%s: failed to configure setup; result = %d", __func__, result); + return result; + } + + request.destroy(); + return WIFI_SUCCESS; + } + + void registerTwtVendorEvents() + { + registerVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT); + } + + void unregisterTwtVendorEvents() + { + unregisterVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT); + } + + virtual int handleResponse(WifiEvent& reply) { + ALOGD("Request complete!"); + /* Nothing to do on response! */ + return NL_SKIP; + } + + int handleEvent(WifiEvent& event) { + u16 attr_type; + TwtEventType twt_event; + + 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("Received TWT event: %d\n", event_id); + + if (!vendor_data || len == 0) { + ALOGE("No event data found"); + return NL_SKIP; + } + + switch (event_id) { + case BRCM_VENDOR_EVENT_TWT: { + HandleTwtEvent(vendor_data); + break; + } + default: + ALOGE("Unknown event: %d\n", event_id); + break; + } + return NL_SKIP; + } + +}; + +void twt_deinit_handler() +{ + if (twt_info.twt_feature_request) { + /* register for Twt vendor events with info mac class*/ + TwtFeatureRequest *cmd_event = (TwtFeatureRequest*)(twt_info.twt_feature_request); + cmd_event->unregisterTwtVendorEvents(); + delete (TwtFeatureRequest*)twt_info.twt_feature_request; + twt_info.twt_feature_request = NULL; + } + if (TWT_HANDLE(twt_info)) { + delete GET_TWT_HANDLE(twt_info); + TWT_HANDLE(twt_info) = NULL; + } + ALOGI("wifi twt internal clean up done"); + return; +} + +wifi_error twt_register_handler(wifi_interface_handle iface, + TwtCallbackHandler handlers) +{ + wifi_handle handle = getWifiHandle(iface); + if (TWT_HANDLE(twt_info)) { + /* cleanup and re-register */ + twt_deinit_handler(); + } + memset(&twt_info, 0, sizeof(twt_info)); + TWT_HANDLE(twt_info) = new TwtHandle(handle, handlers); + twt_info.twt_feature_request = + (void*)new TwtFeatureRequest(iface, NULL, TWT_LAST); + NULL_CHECK_RETURN(twt_info.twt_feature_request, + "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + TwtFeatureRequest *cmd_event = (TwtFeatureRequest*)(twt_info.twt_feature_request); + cmd_event->registerTwtVendorEvents(); + return WIFI_SUCCESS; +} + +wifi_error twt_setup_request(wifi_interface_handle iface, TwtSetupRequest* msg) +{ + wifi_error ret = WIFI_SUCCESS; + TwtFeatureRequest *cmd; + TwtRequestType cmdType = TWT_SETUP_REQUEST; + + cmd = new TwtFeatureRequest(iface, (void *)msg, cmdType); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + + ret = (wifi_error)cmd->open(); + if (ret != WIFI_SUCCESS) { + ALOGE("%s : failed in open, error = %d\n", __func__, ret); + } + cmd->releaseRef(); + return ret; +} + +wifi_error twt_info_frame_request(wifi_interface_handle iface, TwtInfoFrameRequest* msg) +{ + wifi_error ret = WIFI_SUCCESS; + TwtFeatureRequest *cmd; + TwtRequestType cmdType = TWT_INFO_FRAME_REQUEST; + + cmd = new TwtFeatureRequest(iface, (void *)msg, cmdType); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + + ret = (wifi_error)cmd->open(); + if (ret != WIFI_SUCCESS) { + ALOGE("%s : failed in open, error = %d\n", __func__, ret); + } + cmd->releaseRef(); + return ret; +} + +wifi_error twt_teardown_request(wifi_interface_handle iface, TwtTeardownRequest* msg) +{ + wifi_error ret = WIFI_SUCCESS; + TwtFeatureRequest *cmd; + TwtRequestType cmdType = TWT_TEAR_DOWN_REQUEST; + + cmd = new TwtFeatureRequest(iface, (void *)msg, cmdType); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + + ret = (wifi_error)cmd->open(); + if (ret != WIFI_SUCCESS) { + ALOGE("%s : failed in open, error = %d\n", __func__, ret); + } + cmd->releaseRef(); + return ret; +} diff --git a/bcmdhd/wifi_hal/wifi_hal.cpp b/bcmdhd/wifi_hal/wifi_hal.cpp index 258725c..fe679ab 100755 --- a/bcmdhd/wifi_hal/wifi_hal.cpp +++ b/bcmdhd/wifi_hal/wifi_hal.cpp @@ -53,6 +53,8 @@ #include "rtt.h" #include "brcm_version.h" #include <stdio.h> +#include <string> +#include <vector> /* 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 @@ -63,6 +65,8 @@ #define WIFI_HAL_CMD_SOCK_PORT 644 #define WIFI_HAL_EVENT_SOCK_PORT 645 +#define MAX_VIRTUAL_IFACES 5 +#define WIFI_HAL_EVENT_BUFFER_NOT_AVAILABLE 105 /* * Defines for wifi_wait_for_driver_ready() @@ -71,8 +75,8 @@ #define POLL_DRIVER_DURATION_US (100000) #define POLL_DRIVER_MAX_TIME_MS (10000) #define EVENT_BUF_SIZE 2048 +#define C2S(x) case x: return #x; -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); @@ -83,28 +87,51 @@ static wifi_error wifi_start_rssi_monitoring(wifi_request_id id, wifi_interface_ 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_read_packet_filter(wifi_interface_handle handle, u32 src_offset, + u8 *host_dst, u32 length); 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_usable_channels(wifi_handle handle, u32 band_mask, u32 iface_mode_mask, + u32 filter_mask, u32 max_size, u32* size, wifi_usable_channel* channels); +static wifi_error wifi_get_supported_radio_combinations_matrix(wifi_handle handle, + u32 max_size, u32* size, wifi_radio_combination_matrix *radio_combination_matrix); +static void wifi_cleanup_dynamic_ifaces(wifi_handle handle); 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, - ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE, - ANDR_WIFI_ATTRIBUTE_LATENCY_MODE, - ANDR_WIFI_ATTRIBUTE_RANDOM_MAC, - ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO - // Add more attribute here + ANDR_WIFI_ATTRIBUTE_INVALID = 0, + ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET = 1, + ANDR_WIFI_ATTRIBUTE_FEATURE_SET = 2, + ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI = 3, + ANDR_WIFI_ATTRIBUTE_NODFS_SET = 4, + ANDR_WIFI_ATTRIBUTE_COUNTRY = 5, + ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE = 6, + ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE = 7, + ANDR_WIFI_ATTRIBUTE_LATENCY_MODE = 8, + ANDR_WIFI_ATTRIBUTE_RANDOM_MAC = 9, + ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO = 10, + ANDR_WIFI_ATTRIBUTE_THERMAL_MITIGATION = 11, + ANDR_WIFI_ATTRIBUTE_THERMAL_COMPLETION_WINDOW = 12, + ANDR_WIFI_ATTRIBUTE_VOIP_MODE = 13, + ANDR_WIFI_ATTRIBUTE_DTIM_MULTIPLIER = 14, + // Add more attribute here + ANDR_WIFI_ATTRIBUTE_MAX } wifi_attr_t; +enum wifi_radio_combo_attributes { + ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_INVALID = 0, + ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MATRIX = 1, + // Add more attribute here + ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MAX +}; + enum wifi_rssi_monitor_attr { - RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, - RSSI_MONITOR_ATTRIBUTE_MIN_RSSI, - RSSI_MONITOR_ATTRIBUTE_START, + RSSI_MONITOR_ATTRIBUTE_INVALID = 0, + RSSI_MONITOR_ATTRIBUTE_MAX_RSSI = 1, + RSSI_MONITOR_ATTRIBUTE_MIN_RSSI = 2, + RSSI_MONITOR_ATTRIBUTE_START = 3, + // Add more attribute here + RSSI_MONITOR_ATTRIBUTE_MAX }; enum wifi_apf_attr { @@ -116,7 +143,57 @@ enum wifi_apf_attr { enum apf_request_type { GET_APF_CAPABILITIES, - SET_APF_PROGRAM + SET_APF_PROGRAM, + READ_APF_PROGRAM +}; + +enum wifi_dscp_attr { + DSCP_ATTRIBUTE_INVALID = 0, + DSCP_ATTRIBUTE_START = 1, + DSCP_ATTRIBUTE_END = 2, + DSCP_ATTRIBUTE_AC = 3, + /* Add more attributes here */ + DSCP_ATTRIBUTE_MAX +}; + +enum wifi_dscp_request_type { + SET_DSCP_TABLE, + RESET_DSCP_TABLE +}; + +enum wifi_chavoid_attr { + CHAVOID_ATTRIBUTE_INVALID = 0, + CHAVOID_ATTRIBUTE_CNT = 1, + CHAVOID_ATTRIBUTE_CONFIG = 2, + CHAVOID_ATTRIBUTE_BAND = 3, + CHAVOID_ATTRIBUTE_CHANNEL = 4, + CHAVOID_ATTRIBUTE_PWRCAP = 5, + CHAVOID_ATTRIBUTE_MANDATORY = 6, + /* Add more attributes here */ + CHAVOID_ATTRIBUTE_MAX +}; + +enum wifi_usable_channel_attributes { + USABLECHAN_ATTRIBUTE_INVALID = 0, + USABLECHAN_ATTRIBUTE_BAND = 1, + USABLECHAN_ATTRIBUTE_IFACE = 2, + USABLECHAN_ATTRIBUTE_FILTER = 3, + USABLECHAN_ATTRIBUTE_MAX_SIZE = 4, + USABLECHAN_ATTRIBUTE_SIZE = 5, + USABLECHAN_ATTRIBUTE_CHANNELS = 6, + USABLECHAN_ATTRIBUTE_MAX +}; + +enum wifi_multista_attr { + MULTISTA_ATTRIBUTE_PRIM_CONN_IFACE, + MULTISTA_ATTRIBUTE_USE_CASE, + /* Add more attributes here */ + MULTISTA_ATTRIBUTE_MAX +}; + +enum multista_request_type { + SET_PRIMARY_CONNECTION, + SET_USE_CASE }; /* Initialize/Cleanup */ @@ -138,26 +215,24 @@ static nl_sock * wifi_create_nl_socket(int port) 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; } + return sock; +} - // ALOGI("Making socket nonblocking"); - /* - if (nl_socket_set_nonblocking(sock)) { - ALOGE("Could make socket non-blocking"); - nl_socket_free(sock); - return NULL; +static const char *IfaceTypeToString(wifi_interface_type iface_type) +{ + switch (iface_type) { + C2S(WIFI_INTERFACE_TYPE_STA) + C2S(WIFI_INTERFACE_TYPE_AP) + C2S(WIFI_INTERFACE_TYPE_P2P) + C2S(WIFI_INTERFACE_TYPE_NAN) + default: + return "UNKNOWN_WIFI_INTERFACE_TYPE"; } - */ - - return sock; } /*initialize function pointer table with Broadcom HHAL API*/ @@ -242,14 +317,60 @@ wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn *fn) fn->wifi_nan_data_indication_response = nan_data_indication_response; fn->wifi_nan_data_end = nan_data_end; fn->wifi_set_latency_mode = wifi_set_latency_mode; -#ifdef NAN_CLUSTER_MERGE - fn->wifi_nan_enable_merge_request = nan_enable_cluster_merge_request; -#endif /* NAN_CLUSTER_MERGE */ fn->wifi_select_tx_power_scenario = wifi_select_tx_power_scenario; fn->wifi_reset_tx_power_scenario = wifi_reset_tx_power_scenario; + fn->wifi_read_packet_filter = wifi_read_packet_filter; + fn->wifi_set_subsystem_restart_handler = wifi_set_subsystem_restart_handler; + fn->wifi_set_thermal_mitigation_mode = wifi_set_thermal_mitigation_mode; + fn->wifi_map_dscp_access_category = wifi_map_dscp_access_category; + fn->wifi_reset_dscp_mapping = wifi_reset_dscp_mapping; + fn->wifi_virtual_interface_create = wifi_virtual_interface_create; + fn->wifi_virtual_interface_delete = wifi_virtual_interface_delete; + fn->wifi_set_coex_unsafe_channels = wifi_set_coex_unsafe_channels; + fn->wifi_twt_get_capability = twt_get_capability; + fn->wifi_twt_register_handler = twt_register_handler; + fn->wifi_twt_setup_request = twt_setup_request; + fn->wifi_twt_teardown_request = twt_teardown_request; + fn->wifi_twt_info_frame_request = twt_info_frame_request; + fn->wifi_twt_get_stats = twt_get_stats; + fn->wifi_twt_clear_stats = twt_clear_stats; + fn->wifi_multi_sta_set_primary_connection = wifi_multi_sta_set_primary_connection; + fn->wifi_multi_sta_set_use_case = wifi_multi_sta_set_use_case; + fn->wifi_set_voip_mode = wifi_set_voip_mode; + fn->wifi_set_dtim_config = wifi_set_dtim_config; + fn->wifi_get_usable_channels = wifi_get_usable_channels; + fn->wifi_trigger_subsystem_restart = wifi_trigger_subsystem_restart; + fn->wifi_get_supported_radio_combinations_matrix = wifi_get_supported_radio_combinations_matrix; + fn->wifi_nan_rtt_chre_enable_request = nan_chre_enable_request; + fn->wifi_nan_rtt_chre_disable_request = nan_chre_disable_request; + fn->wifi_chre_register_handler = nan_chre_register_handler; return WIFI_SUCCESS; } +#ifdef GOOGLE_WIFI_FW_CONFIG_VERSION_C_WRAPPER +#include <google_wifi_firmware_config_version_info.h> + +static void +wifi_check_valid_ota_version(wifi_interface_handle handle) +{ + bool valid = false; + int32_t default_ver = get_google_default_vendor_wifi_config_version(); + int32_t ota_ver = get_google_ota_updated_wifi_config_version(); + ALOGE("default_ver %d, ota_ver %d", default_ver, ota_ver); + + if (ota_ver > default_ver) { + valid = verify_google_ota_updated_wifi_config_integrity(); + } + + if (valid) { + ALOGE("Valid config files of OTA."); + wifi_hal_ota_update(handle, ota_ver); + } + else { + ALOGE("Do not valid config files of OTA."); + } +} +#endif // GOOGLE_WIFI_FW_CONFIG_VERSION_C_WRAPPER hal_info *halInfo = NULL; wifi_error wifi_pre_initialize(void) @@ -302,7 +423,7 @@ wifi_error wifi_pre_initialize(void) } /* Set the socket buffer size */ - if (nl_socket_set_buffer_size(event_sock, (512*1024), 0) < 0) { + if (nl_socket_set_buffer_size(event_sock, (4*1024*1024), 0) < 0) { ALOGE("Could not set size for event_sock: %s", strerror(errno)); } else { @@ -376,6 +497,9 @@ wifi_error wifi_pre_initialize(void) if (wlan0Handle != NULL) { ALOGE("Calling preInit"); if (!get_halutil_mode()) { +#ifdef GOOGLE_WIFI_FW_CONFIG_VERSION_C_WRAPPER + (void) wifi_check_valid_ota_version(wlan0Handle); +#endif // GOOGLE_WIFI_FW_CONFIG_VERSION_C_WRAPPER result = wifi_hal_preInit(wlan0Handle); if (result != WIFI_SUCCESS) { ALOGE("wifi_hal_preInit failed"); @@ -416,18 +540,10 @@ wifi_error wifi_initialize(wifi_handle *handle) if (result != WIFI_SUCCESS) { ALOGE("wifi_start_hal failed"); } -#ifdef FILE_DUMP - else { - ALOGE("Calling start file dump"); - result = wifi_start_file_dump(wlan0Handle); - if (result != WIFI_SUCCESS) { - ALOGE("wifi_start_file_dump failed"); - } - } -#endif /* FILE_DUMP */ } } else { ALOGI("Not Calling set alert handler as global_iface is NULL"); + return WIFI_ERROR_UNKNOWN; } return WIFI_SUCCESS; } @@ -500,15 +616,21 @@ static void internal_cleaned_up_handler(wifi_handle handle) ALOGI("Internal cleanup completed"); } + void wifi_internal_module_cleanup() { nan_deinit_handler(); + twt_deinit_handler(); } void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler) { + if (!handle) { + ALOGE("Handle is null"); + return; + } + hal_info *info = getHalInfo(handle); - char buf[64]; wifi_error result; int numIfaceHandles = 0; @@ -528,39 +650,12 @@ void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler) } } -#ifdef FILE_DUMP - ALOGE("Calling stop file dump"); - result = wifi_stop_file_dump(wlan0Handle); - if (result != WIFI_SUCCESS) { - ALOGE("wifi_stop_file_dump failed"); - } -#endif /* FILE_DUMP */ } else { ALOGE("Not cleaning up hal as global_iface is NULL"); } - 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; + /* calling internal modules or cleanup */ wifi_internal_module_cleanup(); - ALOGI("wifi nan internal clean up done"); pthread_mutex_lock(&info->cb_lock); int bad_commands = 0; @@ -608,8 +703,17 @@ void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler) WifiCommand *cmd = (WifiCommand *)cbi->cb_arg; ALOGE("Leaked command %p", cmd); } + if (!get_halutil_mode()) { + wifi_cleanup_dynamic_ifaces(handle); + } pthread_mutex_unlock(&info->cb_lock); - internal_cleaned_up_handler(handle); + + info->clean_up = true; + + 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"); + } ALOGE("wifi_clean_up done"); } @@ -657,31 +761,25 @@ void wifi_event_loop(wifi_handle handle) 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)); + if (errno == WIFI_HAL_EVENT_BUFFER_NOT_AVAILABLE) { + ALOGE("Exit, No buffer space"); + break; + } } else if (pfd[0].revents & POLLHUP) { ALOGE("Remote side hung up"); break; - } else if (pfd[0].revents & POLLIN) { + } else if (pfd[0].revents & POLLIN && !info->clean_up) { // 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); - } + ALOGI("Got a signal to exit!!!"); } else { ALOGE("Unknown event - %0x, %0x", pfd[0].revents, pfd[1].revents); } } while (!info->clean_up); - ALOGI("Exit %s", __FUNCTION__); + + internal_cleaned_up_handler(handle); + ALOGE("Exit %s", __FUNCTION__); } /////////////////////////////////////////////////////////////////////////////////////// @@ -721,8 +819,6 @@ static int internal_valid_message_handler(nl_msg *msg, void *arg) // 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++) { @@ -794,7 +890,6 @@ public: // ALOGI("handling reponse in %s", __func__); struct nlattr **tb = reply.attributes(); - struct genlmsghdr *gnlh = reply.header(); struct nlattr *mcgrp = NULL; int i; @@ -961,7 +1056,36 @@ public: : WifiCommand("SetRSSIMonitorCommand", handle, id), mMax_rssi(max_rssi), mMin_rssi (min_rssi), mHandler(eh) { + ALOGI("SetRSSIMonitorCommand %p created", this); + } + + virtual ~SetRSSIMonitorCommand() { + /* + * Mostly, this call will be no effect. However, this could be valid + * when object destroy without calling unregisterVendorHandler(). + * This is added to protect hal crash due to use-after-free. + */ + ALOGI("Try to remove event handler if exist, vendor 0x%0x, subcmd 0x%x", + GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT); + unregisterVendorHandlerWithoutLock(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT); + ALOGI("SetRSSIMonitorCommand %p destroyed", this); + } + + virtual void addRef() { + int refs = __sync_add_and_fetch(&mRefs, 1); + ALOGI("addRef: WifiCommand %p has %d references", this, refs); + } + + virtual void releaseRef() { + int refs = __sync_sub_and_fetch(&mRefs, 1); + if (refs == 0) { + ALOGI("releaseRef: WifiCommand %p has deleted", this); + delete this; + } else { + ALOGI("releaseRef: WifiCommand %p has %d references", this, refs); } + } + int createRequest(WifiRequest& request, int enable) { int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_SET_RSSI_MONITOR); if (result < 0) { @@ -989,27 +1113,27 @@ public: 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); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create request; result = %d", result); return result; } - ALOGI("Successfully set RSSI monitoring"); - result = registerVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT); + registerVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT); + ALOGI("Register GOOGLE_RSSI_MONITOR_EVENT handler"); - if (result < 0) { + result = requestResponse(request); + if (result != WIFI_SUCCESS) { unregisterVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT); + ALOGE("Failed to set RSSI Monitor, result = %d", result); return result; } - ALOGI("Done!"); + + ALOGI("Successfully set RSSI monitoring"); return result; } virtual int cancel() { + unregisterVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT); WifiRequest request(familyId(), ifaceId()); int result = createRequest(request, 0); @@ -1021,7 +1145,6 @@ public: ALOGE("failed to stop RSSI monitoring = %d", result); } } - unregisterVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT); return WIFI_SUCCESS; } @@ -1069,6 +1192,7 @@ public: class AndroidPktFilterCommand : public WifiCommand { private: const u8* mProgram; + u8* mReadProgram; u32 mProgramLen; u32* mVersion; u32* mMaxLen; @@ -1094,13 +1218,24 @@ class AndroidPktFilterCommand : public WifiCommand { mMaxLen = NULL; } + AndroidPktFilterCommand(wifi_interface_handle handle, + u8* host_dst, u32 length) + : WifiCommand("AndroidPktFilterCommand", handle, 0), + mReadProgram(host_dst), mProgramLen(length), + mReqType(READ_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); + return createGetPktFilterCapabilitesRequest(request); + } else if (mReqType == READ_APF_PROGRAM) { + ALOGI("\n%s: APF read packet filter request\n", __FUNCTION__); + return createReadPktFilterRequest(request); } else { ALOGE("\n%s Unknown APF request\n", __FUNCTION__); return WIFI_ERROR_NOT_SUPPORTED; @@ -1143,6 +1278,16 @@ exit: request.attr_end(data); return result; } + int createReadPktFilterRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, APF_SUBCMD_READ_FILTER); + 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); @@ -1182,11 +1327,11 @@ exit: request.attr_end(data); return NL_SKIP; } if( mReqType == SET_APF_PROGRAM) { - ALOGD("Response recieved for set packet filter command\n"); + ALOGD("Response received 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"); + ALOGD("Response received 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(); @@ -1199,12 +1344,24 @@ exit: request.attr_end(data); it.get_type(), it.get_len()); } } + } else if (mReqType == READ_APF_PROGRAM) { + ALOGD("Read packet filter, mProgramLen = %d\n", mProgramLen); + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == APF_ATTRIBUTE_PROGRAM) { + u8 *buffer = NULL; + buffer = (u8 *)it.get_data(); + memcpy(mReadProgram, buffer, mProgramLen); + } else if (it.get_type() == APF_ATTRIBUTE_PROGRAM_LEN) { + int apf_length = it.get_u32(); + ALOGD("apf program length = %d\n", apf_length); + } + } } return NL_OK; } int handleEvent(WifiEvent& event) { - /* No Event to recieve for APF commands */ + /* No Event to receive for APF commands */ return NL_SKIP; } }; @@ -1335,6 +1492,93 @@ protected: } }; +///////////////////////////////////////////////////////////////////// +class GetRadioComboCommand : public WifiCommand { +private: + wifi_radio_combination_matrix *rcmatrix; + u32* rc_size; + u32 set_size_max; + int ret = 0; + +public: + GetRadioComboCommand(wifi_interface_handle handle, u32 max_size, u32* size, + wifi_radio_combination_matrix *radio_combination_matrix) + : WifiCommand("GetRadioComboCommand", handle, 0), rcmatrix(radio_combination_matrix), + rc_size(size), set_size_max(max_size) + { + } + + virtual int createRequest(WifiRequest& mMsg) { + ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_RADIO_COMBO_MATRIX); + if (ret < 0) { + ALOGE("Can't create message to send to driver - %d", ret); + } + nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA); + mMsg.attr_end(data); + + return ret; + } + + int start() { + WifiRequest request(familyId(), ifaceId()); + ret = createRequest(request); + if (ret < 0) { + ALOGE("Request failed for radio_combo_matrix, result = %d", ret); + return ret; + } + ret = requestResponse(request); + if (ret < 0) { + ALOGE("Request Response failed for radio_combo_matrix, result = %d", ret); + return ret; + } + ALOGD("Done! %s", __FUNCTION__); + return ret; + } + +protected: + virtual int handleResponse(WifiEvent& reply) { + ALOGD("In GetRadioComboCommand::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 GetRadioComboCommand response; ignoring it"); + return NL_SKIP; + } + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MATRIX) { + void *data = it.get_data(); + *rc_size = it.get_len(); + if (!data || !*rc_size) { + ALOGE("Buffers pointers not set"); + return NL_SKIP; + } + if (set_size_max < *rc_size) { + ALOGE("Unexpected buffers size"); + return NL_SKIP; + } + memcpy(rcmatrix, data, min(len, *rc_size)); + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + + ALOGD("GetRadioComboCommand::Success"); + return NL_OK; + } +}; +///////////////////////////////////////////////////////////////////// class SetLatencyModeCommand : public WifiCommand { private: @@ -1385,7 +1629,8 @@ static int wifi_get_multicast_id(wifi_handle handle, const char *name, const cha static bool is_wifi_interface(const char *name) { - if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "swlan", 5) != 0 && strncmp(name, "p2p", 3) != 0) { + if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "swlan", 5) != 0 && + strncmp(name, "p2p", 3) != 0 && strncmp(name, "aware", 5) != 0) { /* not a wifi interface; ignore it */ return false; } else { @@ -1395,7 +1640,11 @@ static bool is_wifi_interface(const char *name) static int get_interface(const char *name, interface_info *info) { - strlcpy(info->name, name, sizeof(info->name)); + int size = 0; + size = strlcpy(info->name, name, sizeof(info->name)); + if (size >= sizeof(info->name)) { + return WIFI_ERROR_OUT_OF_MEMORY; + } info->id = if_nametoindex(name); // ALOGI("found an interface : %s, id = %d", name, info->id); return WIFI_SUCCESS; @@ -1429,7 +1678,9 @@ wifi_error wifi_init_interfaces(wifi_handle handle) if (d == 0) return WIFI_ERROR_UNKNOWN; - info->interfaces = (interface_info **)malloc(sizeof(interface_info *) * n); + /* Have place holder for 3 virtual interfaces */ + n += MAX_VIRTUAL_IFACES; + info->interfaces = (interface_info **)calloc(n, sizeof(interface_info *) * n); if (!info->interfaces) { info->num_interfaces = 0; closedir(d); @@ -1448,10 +1699,12 @@ wifi_error wifi_init_interfaces(wifi_handle handle) closedir(d); return WIFI_ERROR_OUT_OF_MEMORY; } + memset(ifinfo, 0, sizeof(interface_info)); if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) { - free(ifinfo); continue; } + /* Mark as static iface */ + ifinfo->is_virtual = false; ifinfo->handle = handle; info->interfaces[i] = ifinfo; i++; @@ -1460,7 +1713,8 @@ wifi_error wifi_init_interfaces(wifi_handle handle) closedir(d); - info->num_interfaces = n; + info->num_interfaces = i; + info->max_num_interfaces = n; return WIFI_SUCCESS; } @@ -1474,6 +1728,74 @@ wifi_error wifi_get_ifaces(wifi_handle handle, int *num, wifi_interface_handle * return WIFI_SUCCESS; } +wifi_error wifi_add_iface_hal_info(wifi_handle handle, const char* ifname) +{ + hal_info *info = NULL; + int i = 0; + + info = (hal_info *)handle; + if (info == NULL) { + ALOGE("Could not find info\n"); + return WIFI_ERROR_UNKNOWN; + } + + ALOGI("%s: add interface_info for iface: %s\n", __FUNCTION__, ifname); + if (info->num_interfaces == MAX_VIRTUAL_IFACES) { + ALOGE("No space. max limit reached for virtual interfaces %d\n", info->num_interfaces); + return WIFI_ERROR_OUT_OF_MEMORY; + } + + interface_info *ifinfo = (interface_info *)malloc(sizeof(interface_info)); + if (!ifinfo) { + free(info->interfaces); + info->num_interfaces = 0; + return WIFI_ERROR_OUT_OF_MEMORY; + } + + ifinfo->handle = handle; + while (i < info->max_num_interfaces) { + if (info->interfaces[i] == NULL) { + if (get_interface(ifname, ifinfo) != WIFI_SUCCESS) { + continue; + } + ifinfo->is_virtual = true; + info->interfaces[i] = ifinfo; + info->num_interfaces++; + ALOGI("%s: Added iface: %s at the index %d\n", __FUNCTION__, ifname, i); + break; + } + i++; + } + return WIFI_SUCCESS; +} + +wifi_error wifi_clear_iface_hal_info(wifi_handle handle, const char* ifname) +{ + hal_info *info = (hal_info *)handle; + int i = 0; + + ALOGI("%s: clear hal info for iface: %s\n", __FUNCTION__, ifname); + while (i < info->max_num_interfaces) { + if ((info->interfaces[i] != NULL) && + strncmp(info->interfaces[i]->name, ifname, + sizeof(info->interfaces[i]->name)) == 0) { + free(info->interfaces[i]); + info->interfaces[i] = NULL; + info->num_interfaces--; + ALOGI("%s: Cleared the index = %d for iface: %s\n", __FUNCTION__, i, ifname); + break; + } + i++; + } + if (i < info->num_interfaces) { + for (int j = i; j < info->num_interfaces; j++) { + info->interfaces[j] = info->interfaces[j+1]; + } + info->interfaces[info->num_interfaces] = NULL; + } + return WIFI_SUCCESS; +} + wifi_interface_handle wifi_get_wlan_interface(wifi_handle info, wifi_interface_handle *ifaceHandles, int numIfaceHandles) { char buf[EVENT_BUF_SIZE]; @@ -1484,7 +1806,7 @@ wifi_interface_handle wifi_get_wlan_interface(wifi_handle info, wifi_interface_h } for (int i = 0; i < numIfaceHandles; i++) { if (wifi_get_iface_name(ifaceHandles[i], buf, sizeof(buf)) == WIFI_SUCCESS) { - if (strcmp(buf, "wlan0") == 0) { + if (strncmp(buf, "wlan0", 5) == 0) { ALOGI("found interface %s\n", buf); wlan0Handle = ifaceHandles[i]; return wlan0Handle; @@ -1501,6 +1823,29 @@ wifi_error wifi_get_iface_name(wifi_interface_handle handle, char *name, size_t return WIFI_SUCCESS; } +wifi_interface_handle wifi_get_iface_handle(wifi_handle handle, char *name) +{ + char buf[EVENT_BUF_SIZE]; + wifi_interface_handle *ifaceHandles; + int numIfaceHandles; + wifi_interface_handle ifHandle; + + wifi_error res = wifi_get_ifaces((wifi_handle)handle, &numIfaceHandles, &ifaceHandles); + if (res < 0) { + return NULL; + } + for (int i = 0; i < numIfaceHandles; i++) { + if (wifi_get_iface_name(ifaceHandles[i], buf, sizeof(buf)) == WIFI_SUCCESS) { + if (strcmp(buf, name) == 0) { + ALOGI("found interface %s\n", buf); + ifHandle = ifaceHandles[i]; + return ifHandle; + } + } + } + return NULL; +} + 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); @@ -1515,6 +1860,27 @@ wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int set_siz return (wifi_error) command.requestResponse(); } +wifi_error wifi_get_supported_radio_combinations_matrix(wifi_handle handle, + u32 max_size, u32* size, wifi_radio_combination_matrix *radio_combination_matrix) +{ + int numIfaceHandles = 0; + wifi_interface_handle *ifaceHandles = NULL; + wifi_interface_handle wlan0Handle; + + wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles); + GetRadioComboCommand *cmd = new GetRadioComboCommand(wlan0Handle, max_size, + size, radio_combination_matrix); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + if (result == WIFI_SUCCESS) { + ALOGD("Get radio combo matrix success"); + } else { + ALOGE("Get radio combo matrix failed\n"); + } + cmd->releaseRef(); + return result; +} + wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui) { SetPnoMacAddrOuiCommand command(handle, scan_oui); @@ -1537,17 +1903,19 @@ wifi_error wifi_set_country_code(wifi_interface_handle handle, const char *count 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); + ALOGI("Starting 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) { + ALOGI("wifi_register_cmd() is failed %d", id); cmd->releaseRef(); return result; } result = (wifi_error)cmd->start(); if (result != WIFI_SUCCESS) { + ALOGI("start() is failed %d", id); wifi_unregister_cmd(handle, id); cmd->releaseRef(); return result; @@ -1557,12 +1925,11 @@ static wifi_error wifi_start_rssi_monitoring(wifi_request_id id, wifi_interface_ static wifi_error wifi_stop_rssi_monitoring(wifi_request_id id, wifi_interface_handle iface) { - ALOGD("Stopping RSSI monitor"); + ALOGI("Stopping RSSI monitor %d", id); 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); @@ -1599,6 +1966,19 @@ static wifi_error wifi_set_packet_filter(wifi_interface_handle handle, return result; } +static wifi_error wifi_read_packet_filter(wifi_interface_handle handle, + u32 src_offset, u8 *host_dst, u32 length) +{ + ALOGD("Read APF program, halHandle = %p, length = %d\n", handle, length); + AndroidPktFilterCommand *cmd = new AndroidPktFilterCommand(handle, host_dst, length); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + if (result == WIFI_SUCCESS) { + ALOGI("Read APF program success\n"); + } + cmd->releaseRef(); + return result; +} static wifi_error wifi_configure_nd_offload(wifi_interface_handle handle, u8 enable) { SetNdoffloadCommand command(handle, enable); @@ -1636,7 +2016,7 @@ public: } if ((mScenario <= WIFI_POWER_SCENARIO_INVALID) || - (mScenario > WIFI_POWER_SCENARIO_ON_BODY_BT)) { + (mScenario >= SAR_CONFIG_SCENARIO_COUNT)) { ALOGE("Unsupported tx power value:%d\n", mScenario); return WIFI_ERROR_NOT_SUPPORTED; } @@ -1690,3 +2070,934 @@ wifi_error wifi_reset_tx_power_scenario(wifi_interface_handle handle) } ///////////////////////////////////////////////////////////////////////////// + +class ThermalMitigation : public WifiCommand { +private: + wifi_thermal_mode mMitigation; + u32 mCompletionWindow; +public: + // constructor for thermal mitigation setting + ThermalMitigation(wifi_interface_handle handle, + wifi_thermal_mode mitigation, u32 completion_window) + : WifiCommand("ThermalMitigation", handle, 0) + { + mMitigation = mitigation; + mCompletionWindow = completion_window; + } + + int createRequest(WifiRequest& request, int subcmd, + wifi_thermal_mode mitigation, u32 completion_window) { + int result = request.create(GOOGLE_OUI, subcmd); + if (result < 0) { + return result; + } + + if ((mitigation < WIFI_MITIGATION_NONE) || + (mitigation > WIFI_MITIGATION_EMERGENCY)) { + ALOGE("Unsupported tx mitigation value:%d\n", mitigation); + return WIFI_ERROR_NOT_SUPPORTED; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_s8(ANDR_WIFI_ATTRIBUTE_THERMAL_MITIGATION, mitigation); + if (result < 0) { + ALOGE("Failed to put tx power scenario request; result = %d", result); + return result; + } + result = request.put_u32(ANDR_WIFI_ATTRIBUTE_THERMAL_COMPLETION_WINDOW, + completion_window); + if (result < 0) { + ALOGE("Failed to put tx power scenario request; result = %d", result); + return result; + } + + request.attr_end(data); + return WIFI_SUCCESS; + } + + int start() { + WifiRequest request(familyId(), ifaceId()); + int result = createRequest(request, WIFI_SUBCMD_THERMAL_MITIGATION, mMitigation, + mCompletionWindow); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create request; result = %d", result); + return result; + } + + ALOGD("try to get resp; mitigation=%d, delay=%d", mMitigation, mCompletionWindow); + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to send thermal mitigation; result = %d", result); + } + return result; + } +protected: + virtual int handleResponse(WifiEvent& reply) { + ALOGD("Request complete!"); + /* Nothing to do on response! */ + return NL_SKIP; + } +}; + +wifi_error wifi_set_thermal_mitigation_mode(wifi_handle handle, + wifi_thermal_mode mode, + u32 completion_window) +{ + int numIfaceHandles = 0; + wifi_interface_handle *ifaceHandles = NULL; + wifi_interface_handle wlan0Handle; + + wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles); + ThermalMitigation command(wlan0Handle, mode, completion_window); + return (wifi_error)command.start(); +} + +///////////////////////////////////////////////////////////////////////////// + +class ChAvoidCommand : public WifiCommand { + private: + u32 mNumParams; + wifi_coex_unsafe_channel *chavoidParams; + u32 mMandatory; + + public: + ChAvoidCommand(wifi_interface_handle handle, + u32 num, wifi_coex_unsafe_channel channels[], u32 mandatory) + : WifiCommand("ChAvoidCommand", handle, 0), + mNumParams(num), chavoidParams(channels), mMandatory(mandatory) + { + } + + int createRequest(WifiRequest& request) { + return createSetChAvoidRequest(request); + } + + int createSetChAvoidRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, CHAVOID_SUBCMD_SET_CONFIG); + if (result < 0) { + ALOGE("%s : Failed to create SUBCMD\n", __func__); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(CHAVOID_ATTRIBUTE_CNT, mNumParams); + if (result < 0) { + ALOGE("%s : Failed to set cound\n", __func__); + return result; + } + result = request.put_u32(CHAVOID_ATTRIBUTE_MANDATORY, mMandatory); + if (result < 0) { + ALOGE("%s : Failed to set mandatory cap\n", __func__); + return result; + } + + nlattr *chavoid_config = request.attr_start(CHAVOID_ATTRIBUTE_CONFIG); + for (int i = 0; i< mNumParams; i++) { + nlattr *item = request.attr_start(i); + if (item == NULL) { + ALOGE("%s : Failed to alloc item\n", __func__); + return WIFI_ERROR_OUT_OF_MEMORY; + } + result = request.put_u32(CHAVOID_ATTRIBUTE_BAND, chavoidParams[i].band); + if (result < 0) { + ALOGE("%s : Failed to set band\n", __func__); + return result; + } + result = request.put_u32(CHAVOID_ATTRIBUTE_CHANNEL, chavoidParams[i].channel); + if (result < 0) { + ALOGE("%s : Failed to set channel\n", __func__); + return result; + } + result = request.put_u32(CHAVOID_ATTRIBUTE_PWRCAP, chavoidParams[i].power_cap_dbm); + if (result < 0) { + ALOGE("%s : Failed to set power cap\n", __func__); + return result; + } + request.attr_end(item); + } + request.attr_end(chavoid_config); + request.attr_end(data); + return WIFI_SUCCESS; + } + + 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 ChAvoid, result = %d", result); + return result; + } + return result; + } + + int handleResponse(WifiEvent& reply) { + ALOGD("In ChAvoidCommand::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(); + + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in ChAvoidCommand response; ignoring it"); + return NL_SKIP; + } + ALOGD("Response received for ChAvoid command\n"); + return NL_OK; + } + + int handleEvent(WifiEvent& event) { + /* No Event to receive for ChAvoid commands */ + ALOGD("ChAvoid command %s\n", __FUNCTION__); + return NL_SKIP; + } +}; + +wifi_error wifi_set_coex_unsafe_channels(wifi_handle handle, + u32 num, wifi_coex_unsafe_channel channels[], u32 mandatory) +{ + int numIfaceHandles = 0; + wifi_interface_handle *ifaceHandles = NULL; + wifi_interface_handle wlan0Handle; + + wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles); + + ChAvoidCommand *cmd = new ChAvoidCommand(wlan0Handle, num, channels, mandatory); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + if (result == WIFI_SUCCESS) { + ALOGI("Setting Channel Avoidance success\n"); + } else { + ALOGE("Setting Channel Avoidance failed\n"); + } + cmd->releaseRef(); + return result; +} + +///////////////////////////////////////////////////////////////////////////// + +class DscpCommand : public WifiCommand { + private: + u32 mStart; + u32 mEnd; + u32 mAc; + int mReqType; + public: + DscpCommand(wifi_interface_handle handle, + u32 start, u32 end, u32 ac) + : WifiCommand("DscpCommand", handle, 0), + mStart(start), mEnd(end), mAc(ac), + mReqType(SET_DSCP_TABLE) + { + } + + DscpCommand(wifi_interface_handle handle) + : WifiCommand("DscpCommand", handle, 0), + mReqType(RESET_DSCP_TABLE) + { + } + + int createRequest(WifiRequest& request) { + if (mReqType == SET_DSCP_TABLE) { + ALOGI("\n%s: DSCP set table request\n", __FUNCTION__); + return createSetDscpRequest(request); + } else if (mReqType == RESET_DSCP_TABLE) { + ALOGI("\n%s: DSCP reset table request\n", __FUNCTION__); + return createResetDscpRequest(request); + } else { + ALOGE("\n%s Unknown DSCP request\n", __FUNCTION__); + return WIFI_ERROR_NOT_SUPPORTED; + } + return WIFI_SUCCESS; + } + + int createSetDscpRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, DSCP_SUBCMD_SET_TABLE); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(DSCP_ATTRIBUTE_START, mStart); + if (result < 0) { + goto exit; + } + result = request.put_u32(DSCP_ATTRIBUTE_END, mEnd); + if (result < 0) { + goto exit; + } + result = request.put_u32(DSCP_ATTRIBUTE_AC, mAc); + if (result < 0) { + goto exit; + } + request.attr_end(data); +exit: + return result; + } + + int createResetDscpRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, DSCP_SUBCMD_RESET_TABLE); + 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 DSCP, result = %d", result); + return result; + } + return result; + } + + int handleResponse(WifiEvent& reply) { + ALOGD("In DscpCommand::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(); + + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in DscpCommand response; ignoring it"); + return NL_SKIP; + } + if( mReqType == SET_DSCP_TABLE) { + ALOGD("Response received for Set DSCP command\n"); + } else if (mReqType == RESET_DSCP_TABLE) { + ALOGD("Response received for Reset DSCP command\n"); + } + return NL_OK; + } + + int handleEvent(WifiEvent& event) { + /* No Event to receive for DSCP commands */ + ALOGD("DSCP command %s\n", __FUNCTION__); + return NL_SKIP; + } +}; + +wifi_error wifi_map_dscp_access_category(wifi_handle handle, + u32 start, u32 end, u32 ac) +{ + int numIfaceHandles = 0; + wifi_interface_handle *ifaceHandles = NULL; + wifi_interface_handle wlan0Handle; + + wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles); + + DscpCommand *cmd = new DscpCommand(wlan0Handle, start, end, ac); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + if (result == WIFI_SUCCESS) { + ALOGI("Mapping DSCP table success\n"); + } else { + ALOGE("Mapping DSCP table fail\n"); + } + cmd->releaseRef(); + return result; +} + +wifi_error wifi_reset_dscp_mapping(wifi_handle handle) +{ + int numIfaceHandles = 0; + wifi_interface_handle *ifaceHandles = NULL; + wifi_interface_handle wlan0Handle; + + wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles); + + DscpCommand *cmd = new DscpCommand(wlan0Handle); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + if (result == WIFI_SUCCESS) { + ALOGI("Resetting DSCP table success\n"); + } else { + ALOGE("Resetting DSCP table fail\n"); + } + cmd->releaseRef(); + return result; +} + +class VirtualIfaceConfig : public WifiCommand { + const char *mIfname; + nl80211_iftype mType; + u32 mwlan0_id; + +public: + VirtualIfaceConfig(wifi_interface_handle handle, const char* ifname, + nl80211_iftype iface_type, u32 wlan0_id) + : WifiCommand("VirtualIfaceConfig", handle, 0), mIfname(ifname), mType(iface_type), + mwlan0_id(wlan0_id) + { + mIfname = ifname; + mType = iface_type; + mwlan0_id = wlan0_id; + } + int createRequest(WifiRequest& request, const char* ifname, + nl80211_iftype iface_type, u32 wlan0_id) { + ALOGD("add ifname = %s, iface_type = %d, wlan0_id = %d", + ifname, iface_type, wlan0_id); + + int result = request.create(NL80211_CMD_NEW_INTERFACE); + if (result < 0) { + ALOGE("failed to create NL80211_CMD_NEW_INTERFACE; result = %d", result); + return result; + } + + result = request.put_u32(NL80211_ATTR_IFINDEX, wlan0_id); + if (result < 0) { + ALOGE("failed to put NL80211_ATTR_IFINDEX; result = %d", result); + return result; + } + + result = request.put_string(NL80211_ATTR_IFNAME, ifname); + if (result < 0) { + ALOGE("failed to put NL80211_ATTR_IFNAME = %s; result = %d", ifname, result); + return result; + } + + result = request.put_u32(NL80211_ATTR_IFTYPE, iface_type); + if (result < 0) { + ALOGE("failed to put NL80211_ATTR_IFTYPE = %d; result = %d", iface_type, result); + return result; + } + return WIFI_SUCCESS; + } + + int deleteRequest(WifiRequest& request, const char* ifname) { + ALOGD("delete ifname = %s\n", ifname); + int result = request.create(NL80211_CMD_DEL_INTERFACE); + if (result < 0) { + ALOGE("failed to create NL80211_CMD_DEL_INTERFACE; result = %d", result); + return result; + } + result = request.put_u32(NL80211_ATTR_IFINDEX, if_nametoindex(ifname)); + if (result < 0) { + ALOGE("failed to put NL80211_ATTR_IFINDEX = %d; result = %d", + if_nametoindex(ifname), result); + return result; + } + result = request.put_string(NL80211_ATTR_IFNAME, ifname); + if (result < 0) { + ALOGE("failed to put NL80211_ATTR_IFNAME = %s; result = %d", ifname, result); + return result; + } + return WIFI_SUCCESS; + } + + int createIface() { + ALOGE("Creating virtual interface"); + WifiRequest request(familyId(), ifaceId()); + int result = createRequest(request, mIfname, mType, mwlan0_id); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create virtual iface request; result = %d\n", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to get the virtual iface create response; result = %d\n", result); + return result; + } + ALOGE("Created virtual interface"); + return WIFI_SUCCESS; + } + + int deleteIface() { + ALOGD("Deleting virtual interface"); + WifiRequest request(familyId(), ifaceId()); + int result = deleteRequest(request, mIfname); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create virtual iface delete request; result = %d\n", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to get response of delete virtual interface; result = %d\n", result); + return result; + } + return WIFI_SUCCESS; + } +protected: + virtual int handleResponse(WifiEvent& reply) { + ALOGD("Request complete!"); + /* Nothing to do on response! */ + return NL_SKIP; + } +}; + +static std::vector<std::string> added_ifaces; + +static void wifi_cleanup_dynamic_ifaces(wifi_handle handle) +{ + int len = added_ifaces.size(); + while (len--) { + wifi_virtual_interface_delete(handle, added_ifaces.front().c_str()); + } + added_ifaces.clear(); +} + +wifi_error wifi_virtual_interface_create(wifi_handle handle, const char* ifname, + wifi_interface_type iface_type) +{ + int numIfaceHandles = 0; + wifi_error ret = WIFI_SUCCESS; + wifi_interface_handle *ifaceHandles = NULL; + wifi_interface_handle wlan0Handle; + nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; + u32 wlan0_id = if_nametoindex("wlan0"); + + if (!handle || !wlan0_id) { + ALOGE("%s: Error wifi_handle NULL or wlan0 not present\n", __FUNCTION__); + return WIFI_ERROR_UNKNOWN; + } + + /* Do not create interface if already exist. */ + if (if_nametoindex(ifname)) { + ALOGD("%s: if_nametoindex(%s) = %d already exists, skip create \n", + __FUNCTION__, ifname, if_nametoindex(ifname)); + return WIFI_SUCCESS; + } + + ALOGD("%s: ifname name = %s, type = %s\n", __FUNCTION__, ifname, + IfaceTypeToString(iface_type)); + + switch (iface_type) { + case WIFI_INTERFACE_TYPE_STA: + type = NL80211_IFTYPE_STATION; + break; + case WIFI_INTERFACE_TYPE_AP: + type = NL80211_IFTYPE_AP; + break; + case WIFI_INTERFACE_TYPE_P2P: + type = NL80211_IFTYPE_P2P_DEVICE; + break; + case WIFI_INTERFACE_TYPE_NAN: + type = NL80211_IFTYPE_NAN; + break; + default: + ALOGE("%s: Wrong interface type %u\n", __FUNCTION__, iface_type); + return WIFI_ERROR_UNKNOWN; + } + + wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles); + VirtualIfaceConfig command(wlan0Handle, ifname, type, wlan0_id); + + ret = (wifi_error)command.createIface(); + if (ret != WIFI_SUCCESS) { + ALOGE("%s: Iface add Error:%d", __FUNCTION__,ret); + return ret; + } + /* Update dynamic interface list */ + added_ifaces.push_back(std::string(ifname)); + ret = wifi_add_iface_hal_info((wifi_handle)handle, ifname); + return ret; +} + +wifi_error wifi_virtual_interface_delete(wifi_handle handle, const char* ifname) +{ + int numIfaceHandles = 0; + int i = 0; + wifi_error ret = WIFI_SUCCESS; + wifi_interface_handle *ifaceHandles = NULL; + wifi_interface_handle wlan0Handle; + hal_info *info = (hal_info *)handle; + u32 wlan0_id = if_nametoindex("wlan0"); + + if (!handle || !wlan0_id) { + ALOGE("%s: Error wifi_handle NULL or wlan0 not present\n", __FUNCTION__); + return WIFI_ERROR_UNKNOWN; + } + + while (i < info->max_num_interfaces) { + if (info->interfaces[i] != NULL && + strncmp(info->interfaces[i]->name, + ifname, sizeof(info->interfaces[i]->name)) == 0) { + if (info->interfaces[i]->is_virtual == false) { + ALOGI("%s: %s is static iface, skip delete\n", + __FUNCTION__, ifname); + return WIFI_SUCCESS; + } + } + i++; + } + + ALOGD("%s: iface name=%s\n", __FUNCTION__, ifname); + wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles); + VirtualIfaceConfig command(wlan0Handle, ifname, (nl80211_iftype)0, 0); + ret = (wifi_error)command.deleteIface(); + if (ret != WIFI_SUCCESS) { + ALOGE("%s: Iface delete Error:%d", __FUNCTION__,ret); + return ret; + } + /* Update dynamic interface list */ + added_ifaces.erase(std::remove(added_ifaces.begin(), added_ifaces.end(), std::string(ifname)), + added_ifaces.end()); + ret = wifi_clear_iface_hal_info((wifi_handle)handle, ifname); + return ret; +} +///////////////////////////////////////////////////////////////////////////// + +class MultiStaConfig : public WifiCommand { + wifi_multi_sta_use_case mUseCase; + int mReqType; + +public: + MultiStaConfig(wifi_interface_handle handle) + : WifiCommand("MultiStaConfig", handle, 0), mReqType(SET_PRIMARY_CONNECTION) + { + } + MultiStaConfig(wifi_interface_handle handle, wifi_multi_sta_use_case use_case) + : WifiCommand("MultiStaConfig", handle, 0), mUseCase(use_case), mReqType(SET_USE_CASE) + { + mUseCase = use_case; + } + + int createRequest(WifiRequest& request) { + if (mReqType == SET_PRIMARY_CONNECTION) { + ALOGI("\n%s: MultiSta set primary connection\n", __FUNCTION__); + return createSetPrimaryConnectionRequest(request); + } else if (mReqType == SET_USE_CASE) { + ALOGI("\n%s: MultiSta set use case\n", __FUNCTION__); + return createSetUsecaseRequest(request); + } else { + ALOGE("\n%s Unknown MultiSta request\n", __FUNCTION__); + return WIFI_ERROR_NOT_SUPPORTED; + } + return WIFI_SUCCESS; + } + + int createSetPrimaryConnectionRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_SET_MULTISTA_PRIMARY_CONNECTION); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + request.attr_end(data); + + return result; + } + + int createSetUsecaseRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_SET_MULTISTA_USE_CASE); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(MULTISTA_ATTRIBUTE_USE_CASE, mUseCase); + if (result < 0) { + ALOGE("failed to put MULTISTA_ATTRIBUTE_USE_CASE = %d; result = %d", mUseCase, result); + goto exit; + } + +exit: 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 MultiSta, result = %d", result); + return result; + } + ALOGI("Done!"); + return result; + } +protected: + virtual int handleResponse(WifiEvent& reply) { + ALOGD("Request complete!"); + /* Nothing to do on response! */ + return NL_SKIP; + } +}; + +wifi_error wifi_multi_sta_set_primary_connection(wifi_handle handle, wifi_interface_handle iface) +{ + wifi_error ret = WIFI_SUCCESS; + char buf[IFNAMSIZ]; + + if (!handle || !iface) { + ALOGE("%s: Error wifi_handle NULL or invalid wifi interface handle\n", __FUNCTION__); + return WIFI_ERROR_UNKNOWN; + } + + if (wifi_get_iface_name(iface, buf, sizeof(buf)) != WIFI_SUCCESS) { + ALOGE("%s : Invalid interface handle\n", __func__); + return WIFI_ERROR_INVALID_ARGS; + } + + ALOGD("Setting Multista primary connection for iface = %s\n", buf); + + MultiStaConfig *cmd = new MultiStaConfig(iface); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + ret = (wifi_error)cmd->start(); + cmd->releaseRef(); + return ret; +} + +wifi_error wifi_multi_sta_set_use_case(wifi_handle handle, wifi_multi_sta_use_case use_case) +{ + int numIfaceHandles = 0; + wifi_error ret = WIFI_SUCCESS; + wifi_interface_handle *ifaceHandles = NULL; + wifi_interface_handle wlan0Handle; + + if (!handle) { + ALOGE("%s: Error wifi_handle NULL\n", __FUNCTION__); + return WIFI_ERROR_UNKNOWN; + } + + if (!(use_case >= WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY && + use_case <= WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED)) { + ALOGE("%s: Invalid multi_sta usecase %d\n", __FUNCTION__, use_case); + return WIFI_ERROR_INVALID_ARGS; + } + + wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles); + ALOGD("Setting Multista usecase = %d\n", use_case); + MultiStaConfig *cmd = new MultiStaConfig(wlan0Handle, use_case); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + ret = (wifi_error)cmd->start(); + cmd->releaseRef(); + return ret; +} +///////////////////////////////////////////////////////////////////////////////////////////////// + +class SetVoipModeCommand : public WifiCommand { + +private: + wifi_voip_mode mMode; +public: + SetVoipModeCommand(wifi_interface_handle handle, wifi_voip_mode mode) + : WifiCommand("SetVoipModeCommand", handle, 0) { + mMode = mode; + } + virtual int create() { + int ret; + + ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_CONFIG_VOIP_MODE); + 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_VOIP_MODE, mMode); + ALOGE("mMode - %d", mMode); + if (ret < 0) { + ALOGE("Failed to set voip mode %d\n", mMode); + return ret; + } + + ALOGI("Successfully configured voip mode %d\n", mMode); + mMsg.attr_end(data); + return WIFI_SUCCESS; + } +}; + +wifi_error wifi_set_voip_mode(wifi_interface_handle handle, wifi_voip_mode mode) +{ + ALOGD("Setting VOIP mode, halHandle = %p Mode = %d\n", handle, mode); + SetVoipModeCommand command(handle, mode); + return (wifi_error) command.requestResponse(); +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +class SetDtimConfigCommand : public WifiCommand { + +private: + uint32_t multiplier; +public: + SetDtimConfigCommand(wifi_interface_handle handle, u32 dtim_multiplier) + : WifiCommand("SetDtimConfigCommand", handle, 0) { + multiplier = dtim_multiplier; + } + virtual int create() { + int ret; + + ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_SET_DTIM_CONFIG); + 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_DTIM_MULTIPLIER, multiplier); + if (ret < 0) { + ALOGE("Failed to set dtim mutiplier %d\n", multiplier); + return ret; + } + + ALOGI("Successfully configured dtim multiplier %d\n", multiplier); + mMsg.attr_end(data); + return WIFI_SUCCESS; + } +}; + +wifi_error wifi_set_dtim_config(wifi_interface_handle handle, u32 multiplier) +{ + ALOGD("Setting DTIM config , halHandle = %p Multiplier = %d\n", handle, multiplier); + SetDtimConfigCommand command(handle, multiplier); + return (wifi_error) command.requestResponse(); +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +class UsableChannelCommand : public WifiCommand { + +private: + u32 mBandMask; + u32 mIfaceModeMask; + u32 mFilterMask; + u32 mMaxSize; + u32* mSize; + wifi_usable_channel* mChannels; + +public: + UsableChannelCommand(wifi_interface_handle handle, u32 band_mask, u32 iface_mode_mask, + u32 filter_mask, u32 max_size, u32* size, wifi_usable_channel* channels) + : WifiCommand("UsableChannelCommand", handle, 0), + mBandMask(band_mask), mIfaceModeMask(iface_mode_mask), + mFilterMask(filter_mask), mMaxSize(max_size), + mSize(size), mChannels(channels) + { + } + + int createRequest(WifiRequest& request) { + createUsableChannelRequest(request); + return WIFI_SUCCESS; + } + + int createUsableChannelRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_USABLE_CHANNEL); + if (result < 0) { + ALOGE("Failed to create UsableChannel request; result = %d", result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + result = request.put_u32(USABLECHAN_ATTRIBUTE_BAND, mBandMask); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put log level; result = %d", result); + return result; + } + result = request.put_u32(USABLECHAN_ATTRIBUTE_IFACE, mIfaceModeMask); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put ring flags; result = %d", result); + return result; + } + result = request.put_u32(USABLECHAN_ATTRIBUTE_FILTER, mFilterMask); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put usablechan filter; result = %d", result); + return result; + } + result = request.put_u32(USABLECHAN_ATTRIBUTE_MAX_SIZE, mMaxSize); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put usablechan max_size; result = %d", result); + return result; + } + request.attr_end(data); + + return WIFI_SUCCESS; + } + + int start() { + WifiRequest request(familyId(), ifaceId()); + int result = createRequest(request); + 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; + } + + 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; + } + + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + wifi_usable_channel *channels(mChannels); + + if (vendor_data == NULL || len == 0) { + ALOGE("No Debug data found"); + return NL_SKIP; + } + + nl_iterator it(vendor_data); + if (it.get_type() == USABLECHAN_ATTRIBUTE_SIZE) { + *mSize = it.get_u32(); + } else { + ALOGE("Unknown attribute: %d expecting %d", + it.get_type(), USABLECHAN_ATTRIBUTE_SIZE); + return NL_SKIP; + } + + it.next(); + if (it.get_type() == USABLECHAN_ATTRIBUTE_CHANNELS) { + memcpy(channels, it.get_data(), sizeof(wifi_usable_channel) * *mSize); + } else { + ALOGE("Unknown attribute: %d expecting %d", + it.get_type(), USABLECHAN_ATTRIBUTE_SIZE); + return NL_SKIP; + } + + return NL_OK; + } + + virtual int handleEvent(WifiEvent& event) { + /* NO events! */ + return NL_SKIP; + } +}; + +wifi_error wifi_get_usable_channels(wifi_handle handle, u32 band_mask, u32 iface_mode_mask, + u32 filter_mask, u32 max_size, u32* size, wifi_usable_channel* channels) +{ + int numIfaceHandles = 0; + wifi_interface_handle *ifaceHandles = NULL; + wifi_interface_handle wlan0Handle; + + wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles); + UsableChannelCommand command(wlan0Handle, band_mask, iface_mode_mask, + filter_mask, max_size, size, channels); + return (wifi_error)command.start(); +} diff --git a/bcmdhd/wifi_hal/wifi_logger.cpp b/bcmdhd/wifi_hal/wifi_logger.cpp index e35bf9b..4d2d8dd 100755 --- a/bcmdhd/wifi_hal/wifi_logger.cpp +++ b/bcmdhd/wifi_hal/wifi_logger.cpp @@ -26,6 +26,7 @@ #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> @@ -34,6 +35,7 @@ #include <netlink-private/object-api.h> #include <netlink-private/types.h> #include <unistd.h> +#include <cutils/properties.h> #include "nl80211_copy.h" @@ -46,6 +48,7 @@ #include "wifi_hal.h" #include "common.h" #include "cpp_bindings.h" +#include <sys/stat.h> #include "brcm_version.h" #define WIFI_HAL_EVENT_SOCK_PORT 645 @@ -69,28 +72,58 @@ typedef enum { LOGGER_FILE_DUMP_DONE_IND, LOGGER_SET_HAL_START, LOGGER_HAL_STOP, - LOGGER_SET_HAL_PID + LOGGER_SET_HAL_PID, + LOGGER_SET_TPUT_DEBUG_DUMP_CMD, + LOGGER_GET_BUF_RING_MAP } DEBUG_SUB_COMMAND; +#define MAX_NV_FILE 4 +#define MAX_SKU_NAME_LEN 5 +#define OTA_PATH "/data/vendor/firmware/wifi/" +#define OTA_CLM_FILE "bcmdhd_clm.blob" +#define OTA_NVRAM_FILE "bcmdhd.cal" +#define HW_DEV_PROP "ro.revision" +#define HW_SKU_PROP "ro.boot.hardware.sku" + +typedef enum { + NVRAM, + CLM_BLOB +} OTA_TYPE; + +char ota_nvram_ext[10]; +typedef struct ota_info_buf { + u32 ota_clm_len; + const void *ota_clm_buf[1]; + u32 ota_nvram_len; + const void *ota_nvram_buf[1]; +} ota_info_buf_t; +u32 applied_ota_version = 0; + 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_INVALID = 0, + LOGGER_ATTRIBUTE_DRIVER_VER = 1, + LOGGER_ATTRIBUTE_FW_VER = 2, + LOGGER_ATTRIBUTE_RING_ID = 3, + LOGGER_ATTRIBUTE_RING_NAME = 4, + LOGGER_ATTRIBUTE_RING_FLAGS = 5, + LOGGER_ATTRIBUTE_LOG_LEVEL = 6, + LOGGER_ATTRIBUTE_LOG_TIME_INTVAL = 7, + LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE = 8, + LOGGER_ATTRIBUTE_FW_DUMP_LEN = 9, + LOGGER_ATTRIBUTE_FW_DUMP_DATA = 10, + LOGGER_ATTRIBUTE_FW_ERR_CODE = 11, + LOGGER_ATTRIBUTE_RING_DATA = 12, + LOGGER_ATTRIBUTE_RING_STATUS = 13, + LOGGER_ATTRIBUTE_RING_NUM = 14, + LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN = 15, + LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA = 16, + LOGGER_ATTRIBUTE_PKT_FATE_NUM = 17, + LOGGER_ATTRIBUTE_PKT_FATE_DATA = 18, + LOGGER_ATTRIBUTE_HANG_REASON = 19, + LOGGER_ATTRIBUTE_BUF_RING_NUM = 20, + LOGGER_ATTRIBUTE_BUF_RING_MAP = 21, + /* Add new attributes just above this */ + LOGGER_ATTRIBUTE_MAX } LOGGER_ATTRIBUTE; typedef enum { @@ -108,6 +141,7 @@ typedef enum { GET_RING_STATUS, GET_FEATURE, START_RING_LOG, + GET_BUF_RING_MAP, } GetCmdType; typedef enum { @@ -117,9 +151,10 @@ typedef enum { } PktFateReqType; enum wake_stat_attributes { - WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT, - WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE, - WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT, + WAKE_STAT_ATTRIBUTE_INVALID, + WAKE_STAT_ATTRIBUTE_TOTAL, + WAKE_STAT_ATTRIBUTE_WAKE, + WAKE_STAT_ATTRIBUTE_COUNT, WAKE_STAT_ATTRIBUTE_CMD_COUNT_USED, WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW, WAKE_STAT_ATTRIBUTE_DRIVER_FW_WAKE, @@ -136,8 +171,9 @@ enum wake_stat_attributes { WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS, WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT, WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT, - WAKE_STAT_ATTRIBUTE_OTHER__RX_MULTICAST_ADD_CNT, - WAKE_STAT_ATTRIBUTE_RX_MULTICAST_PKT_INFO + WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT, + WAKE_STAT_ATTRIBUTE_RX_MULTICAST_PKT_INFO, + WAKE_STAT_ATTRIBUTE_MAX }; typedef enum { @@ -146,8 +182,362 @@ typedef enum { SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID = 0x0003 } SET_HAL_START_ATTRIBUTE; +typedef enum { + OTA_DOWNLOAD_CLM_LENGTH_ATTR = 0x0001, + OTA_DOWNLOAD_CLM_ATTR = 0x0002, + OTA_DOWNLOAD_NVRAM_LENGTH_ATTR = 0x0003, + OTA_DOWNLOAD_NVRAM_ATTR = 0x0004, + OTA_SET_FORCE_REG_ON = 0x0005, + OTA_CUR_NVRAM_EXT_ATTR = 0x0006, +} OTA_DOWNLOAD_ATTRIBUTE; + #define HAL_START_REQUEST_ID 2 +#define HAL_RESTART_ID 3 +#define FILE_NAME_LEN 256 +#define RING_NAME_LEN 32 +#if defined(RING_DUMP) +/* Loglevel */ +#define DUMP_DEBUG(x) +#define DUMP_INFO(x) ALOGI x +#define FILE_DUMP_REQUEST_ID 2 +#define C2S(x) case x: return #x; +static const char *EWP_EventAttrToString(int len_attr); +static const char *EWP_CmdAttrToString(int data_attr); + +typedef struct buf_data { + u32 ver; /* version of struct */ + u32 len; /* Total len */ + /* size of each buffer in case of split buffers (0 - single buffer). */ + u32 buf_threshold; + const void *data_buf[1]; /* array of user space buffer pointers.*/ +} buf_data_t; + +/* Attributes associated with GOOGLE_FILE_DUMP_EVENT */ +typedef enum { + DUMP_LEN_ATTR_INVALID = 0, + DUMP_LEN_ATTR_MEMDUMP = 1, + DUMP_LEN_ATTR_SSSR_C0_BEFORE = 2, + DUMP_LEN_ATTR_SSSR_C0_AFTER = 3, + DUMP_LEN_ATTR_SSSR_C1_BEFORE = 4, + DUMP_LEN_ATTR_SSSR_C1_AFTER = 5, + DUMP_LEN_ATTR_SSSR_C2_BEFORE = 6, + DUMP_LEN_ATTR_SSSR_C2_AFTER = 7, + DUMP_LEN_ATTR_SSSR_DIG_BEFORE = 8, + DUMP_LEN_ATTR_SSSR_DIG_AFTER = 9, + DUMP_LEN_ATTR_TIMESTAMP = 10, + DUMP_LEN_ATTR_GENERAL_LOG = 11, + DUMP_LEN_ATTR_ECNTRS = 12, + DUMP_LEN_ATTR_SPECIAL_LOG = 13, + DUMP_LEN_ATTR_DHD_DUMP = 14, + DUMP_LEN_ATTR_EXT_TRAP = 15, + DUMP_LEN_ATTR_HEALTH_CHK = 16, + DUMP_LEN_ATTR_PRESERVE_LOG = 17, + DUMP_LEN_ATTR_COOKIE = 18, + DUMP_LEN_ATTR_FLOWRING_DUMP = 19, + DUMP_LEN_ATTR_PKTLOG = 20, + DUMP_LEN_ATTR_PKTLOG_DEBUG = 21, + DUMP_FILENAME_ATTR_DEBUG_DUMP = 22, + DUMP_FILENAME_ATTR_MEM_DUMP = 23, + DUMP_FILENAME_ATTR_SSSR_CORE_0_BEFORE_DUMP = 24, + DUMP_FILENAME_ATTR_SSSR_CORE_0_AFTER_DUMP = 25, + DUMP_FILENAME_ATTR_SSSR_CORE_1_BEFORE_DUMP = 26, + DUMP_FILENAME_ATTR_SSSR_CORE_1_AFTER_DUMP = 27, + DUMP_FILENAME_ATTR_SSSR_CORE_2_BEFORE_DUMP = 28, + DUMP_FILENAME_ATTR_SSSR_CORE_2_AFTER_DUMP = 29, + DUMP_FILENAME_ATTR_SSSR_DIG_BEFORE_DUMP = 30, + DUMP_FILENAME_ATTR_SSSR_DIG_AFTER_DUMP = 31, + DUMP_FILENAME_ATTR_PKTLOG_DUMP = 32, + DUMP_FILENAME_ATTR_PKTLOG_DEBUG_DUMP = 33, + DUMP_LEN_ATTR_STATUS_LOG = 34, + DUMP_LEN_ATTR_AXI_ERROR = 35, + DUMP_FILENAME_ATTR_AXI_ERROR_DUMP = 36, + DUMP_LEN_ATTR_RTT_LOG = 37, + DUMP_LEN_ATTR_SDTC_ETB_DUMP = 38, + DUMP_FILENAME_ATTR_SDTC_ETB_DUMP = 39, + DUMP_LEN_ATTR_PKTID_MAP_LOG = 40, + DUMP_LEN_ATTR_PKTID_UNMAP_LOG = 41, + DUMP_LEN_ATTR_EWP_HW_INIT_LOG = 42, + DUMP_LEN_ATTR_EWP_HW_MOD_DUMP = 43, + DUMP_LEN_ATTR_EWP_HW_REG_DUMP = 44, + /* Please add new attributes from here to sync up old DHD */ + DUMP_EVENT_ATTR_MAX = 45, +} EWP_DUMP_EVENT_ATTRIBUTE; + +/* Attributes associated with DEBUG_GET_DUMP_BUF */ +typedef enum { + DUMP_BUF_ATTR_INVALID = 0, + DUMP_BUF_ATTR_MEMDUMP = 1, + DUMP_BUF_ATTR_SSSR_C0_BEFORE = 2, + DUMP_BUF_ATTR_SSSR_C0_AFTER = 3, + DUMP_BUF_ATTR_SSSR_C1_BEFORE = 4, + DUMP_BUF_ATTR_SSSR_C1_AFTER = 5, + DUMP_BUF_ATTR_SSSR_C2_BEFORE = 6, + DUMP_BUF_ATTR_SSSR_C2_AFTER = 7, + DUMP_BUF_ATTR_SSSR_DIG_BEFORE = 8, + DUMP_BUF_ATTR_SSSR_DIG_AFTER = 9, + DUMP_BUF_ATTR_TIMESTAMP = 10, + DUMP_BUF_ATTR_GENERAL_LOG = 11, + DUMP_BUF_ATTR_ECNTRS = 12, + DUMP_BUF_ATTR_SPECIAL_LOG = 13, + DUMP_BUF_ATTR_DHD_DUMP = 14, + DUMP_BUF_ATTR_EXT_TRAP = 15, + DUMP_BUF_ATTR_HEALTH_CHK = 16, + DUMP_BUF_ATTR_PRESERVE_LOG = 17, + DUMP_BUF_ATTR_COOKIE = 18, + DUMP_BUF_ATTR_FLOWRING_DUMP = 19, + DUMP_BUF_ATTR_PKTLOG = 20, + DUMP_BUF_ATTR_PKTLOG_DEBUG = 21, + DUMP_BUF_ATTR_STATUS_LOG = 22, + DUMP_BUF_ATTR_AXI_ERROR = 23, + DUMP_BUF_ATTR_RTT_LOG = 24, + DUMP_BUF_ATTR_SDTC_ETB_DUMP = 25, + DUMP_BUF_ATTR_PKTID_MAP_LOG = 26, + DUMP_BUF_ATTR_PKTID_UNMAP_LOG = 27, + DUMP_BUF_ATTR_EWP_HW_INIT_LOG = 28, + DUMP_BUF_ATTR_EWP_HW_MOD_DUMP = 29, + DUMP_BUF_ATTR_EWP_HW_REG_DUMP = 30, + /* Please add new attributes from here to sync up old DHD */ + DUMP_BUF_ATTR_MAX = 31, +} EWP_DUMP_CMD_ATTRIBUTE; + +typedef enum { + DUMP_TYPE_MEM_DUMP = 0, + DUMP_TYPE_DEBUG_DUMP = 1, + DUMP_TYPE_SSSR_CORE0_BEF_DUMP = 2, + DUMP_TYPE_SSSR_CORE0_AFT_DUMP = 3, + DUMP_TYPE_SSSR_CORE1_BEF_DUMP = 4, + DUMP_TYPE_SSSR_CORE1_AFT_DUMP = 5, + DUMP_TYPE_SSSR_CORE2_BEF_DUMP = 6, + DUMP_TYPE_SSSR_CORE2_AFT_DUMP = 7, + DUMP_TYPE_SSSR_DIG_BEF_DUMP = 8, + DUMP_TYPE_SSSR_DIG_AFT_DUMP = 9, + DUMP_TYPE_PKTLOG_DUMP = 10, + DUMP_TYPE_PKTLOG_DEBUG_DUMP = 11, + DUMP_TYPE_AXI_ERROR_DUMP = 12, + DUMP_TYPE_D2H_MINI_DUMP = 13, + DUMP_TYPE_SDTC_ETB_DUMP = 14, + /* Please add new attributes from here to sync up old DHD */ + DUMP_TYPE_MAX = 15, +} EWP_DUMP_TYPE; + +/* Struct for table which has len_attr, data_attr and dump file type attr */ +typedef struct logger_attr_entry { + u8 attr_type; /* Type of attribute */ + u8 buf_attr; /* Buffer associated with the attribute */ + u8 dump_type; /* Each attribute will be linked to a dump type */ +} logger_attr_entry_t; + +logger_attr_entry_t attr_lookup_tbl[] = { + /* Mem Dump Block */ + {DUMP_FILENAME_ATTR_MEM_DUMP, 0, DUMP_TYPE_MEM_DUMP}, + {DUMP_LEN_ATTR_MEMDUMP, DUMP_BUF_ATTR_MEMDUMP, DUMP_TYPE_MEM_DUMP}, + /* SSSR Dump Block */ + {DUMP_FILENAME_ATTR_SSSR_CORE_0_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_CORE0_BEF_DUMP}, + {DUMP_LEN_ATTR_SSSR_C0_BEFORE, DUMP_BUF_ATTR_SSSR_C0_BEFORE, DUMP_TYPE_SSSR_CORE0_BEF_DUMP}, + + {DUMP_FILENAME_ATTR_SSSR_CORE_0_AFTER_DUMP, 0, DUMP_TYPE_SSSR_CORE0_AFT_DUMP}, + {DUMP_LEN_ATTR_SSSR_C0_AFTER, DUMP_BUF_ATTR_SSSR_C0_AFTER, DUMP_TYPE_SSSR_CORE0_AFT_DUMP}, + + {DUMP_FILENAME_ATTR_SSSR_CORE_1_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_CORE1_BEF_DUMP}, + {DUMP_LEN_ATTR_SSSR_C1_BEFORE, DUMP_BUF_ATTR_SSSR_C1_BEFORE, DUMP_TYPE_SSSR_CORE1_BEF_DUMP}, + + {DUMP_FILENAME_ATTR_SSSR_CORE_1_AFTER_DUMP, 0, DUMP_TYPE_SSSR_CORE1_AFT_DUMP}, + {DUMP_LEN_ATTR_SSSR_C1_AFTER, DUMP_BUF_ATTR_SSSR_C1_AFTER, DUMP_TYPE_SSSR_CORE1_AFT_DUMP}, + + {DUMP_FILENAME_ATTR_SSSR_CORE_2_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_CORE2_BEF_DUMP}, + {DUMP_LEN_ATTR_SSSR_C2_BEFORE, DUMP_BUF_ATTR_SSSR_C2_BEFORE, DUMP_TYPE_SSSR_CORE2_BEF_DUMP}, + + {DUMP_FILENAME_ATTR_SSSR_CORE_2_AFTER_DUMP, 0, DUMP_TYPE_SSSR_CORE2_AFT_DUMP}, + {DUMP_LEN_ATTR_SSSR_C2_AFTER, DUMP_BUF_ATTR_SSSR_C2_AFTER, DUMP_TYPE_SSSR_CORE2_AFT_DUMP}, + + {DUMP_FILENAME_ATTR_SSSR_DIG_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_DIG_BEF_DUMP}, + {DUMP_LEN_ATTR_SSSR_DIG_BEFORE, DUMP_BUF_ATTR_SSSR_DIG_BEFORE, DUMP_TYPE_SSSR_DIG_BEF_DUMP}, + + {DUMP_FILENAME_ATTR_SSSR_DIG_AFTER_DUMP, 0, DUMP_TYPE_SSSR_DIG_AFT_DUMP}, + {DUMP_LEN_ATTR_SSSR_DIG_AFTER, DUMP_BUF_ATTR_SSSR_DIG_AFTER, DUMP_TYPE_SSSR_DIG_AFT_DUMP}, + + /* Debug Dump Block */ + {DUMP_FILENAME_ATTR_DEBUG_DUMP, 0, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_TIMESTAMP, DUMP_BUF_ATTR_TIMESTAMP, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_GENERAL_LOG, DUMP_BUF_ATTR_GENERAL_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_ECNTRS, DUMP_BUF_ATTR_ECNTRS, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_SPECIAL_LOG, DUMP_BUF_ATTR_SPECIAL_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_DHD_DUMP, DUMP_BUF_ATTR_DHD_DUMP, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_EXT_TRAP, DUMP_BUF_ATTR_EXT_TRAP, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_HEALTH_CHK, DUMP_BUF_ATTR_HEALTH_CHK, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_PRESERVE_LOG, DUMP_BUF_ATTR_PRESERVE_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_COOKIE, DUMP_BUF_ATTR_COOKIE, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_FLOWRING_DUMP, DUMP_BUF_ATTR_FLOWRING_DUMP, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_STATUS_LOG, DUMP_BUF_ATTR_STATUS_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_RTT_LOG, DUMP_BUF_ATTR_RTT_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_PKTID_MAP_LOG, DUMP_BUF_ATTR_PKTID_MAP_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_PKTID_UNMAP_LOG, DUMP_BUF_ATTR_PKTID_UNMAP_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_EWP_HW_INIT_LOG, DUMP_BUF_ATTR_EWP_HW_INIT_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_EWP_HW_MOD_DUMP, DUMP_BUF_ATTR_EWP_HW_MOD_DUMP, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_EWP_HW_REG_DUMP, DUMP_BUF_ATTR_EWP_HW_REG_DUMP, DUMP_TYPE_DEBUG_DUMP}, + + /* PKT log dump block */ + {DUMP_FILENAME_ATTR_PKTLOG_DUMP, 0, DUMP_TYPE_PKTLOG_DUMP}, + {DUMP_LEN_ATTR_PKTLOG, DUMP_BUF_ATTR_PKTLOG, DUMP_TYPE_PKTLOG_DUMP}, + {DUMP_FILENAME_ATTR_PKTLOG_DEBUG_DUMP, 0, DUMP_TYPE_PKTLOG_DEBUG_DUMP}, + {DUMP_LEN_ATTR_PKTLOG_DEBUG, DUMP_BUF_ATTR_PKTLOG_DEBUG, DUMP_TYPE_PKTLOG_DEBUG_DUMP}, + /* AXI error log dump block */ + {DUMP_FILENAME_ATTR_AXI_ERROR_DUMP, 0, DUMP_TYPE_AXI_ERROR_DUMP}, + {DUMP_LEN_ATTR_AXI_ERROR, DUMP_BUF_ATTR_AXI_ERROR, DUMP_TYPE_AXI_ERROR_DUMP}, + /* SDTC etb log dump block */ + {DUMP_FILENAME_ATTR_SDTC_ETB_DUMP, 0, DUMP_TYPE_SDTC_ETB_DUMP}, + {DUMP_LEN_ATTR_SDTC_ETB_DUMP, DUMP_BUF_ATTR_SDTC_ETB_DUMP, DUMP_TYPE_SDTC_ETB_DUMP}, + {DUMP_EVENT_ATTR_MAX, 0, 0}, +}; + +static const char *EWP_EventAttrToString(int len_attr) +{ + switch (len_attr) { + C2S(DUMP_LEN_ATTR_MEMDUMP) + C2S(DUMP_LEN_ATTR_SSSR_C0_BEFORE) + C2S(DUMP_LEN_ATTR_SSSR_C0_AFTER) + C2S(DUMP_LEN_ATTR_SSSR_C1_BEFORE) + C2S(DUMP_LEN_ATTR_SSSR_C1_AFTER) + C2S(DUMP_LEN_ATTR_SSSR_C2_BEFORE) + C2S(DUMP_LEN_ATTR_SSSR_C2_AFTER) + C2S(DUMP_LEN_ATTR_SSSR_DIG_BEFORE) + C2S(DUMP_LEN_ATTR_SSSR_DIG_AFTER) + C2S(DUMP_LEN_ATTR_TIMESTAMP) + C2S(DUMP_LEN_ATTR_GENERAL_LOG) + C2S(DUMP_LEN_ATTR_ECNTRS) + C2S(DUMP_LEN_ATTR_SPECIAL_LOG) + C2S(DUMP_LEN_ATTR_DHD_DUMP) + C2S(DUMP_LEN_ATTR_EXT_TRAP) + C2S(DUMP_LEN_ATTR_HEALTH_CHK) + C2S(DUMP_LEN_ATTR_PRESERVE_LOG) + C2S(DUMP_LEN_ATTR_COOKIE) + C2S(DUMP_LEN_ATTR_FLOWRING_DUMP) + C2S(DUMP_LEN_ATTR_PKTLOG) + C2S(DUMP_LEN_ATTR_PKTLOG_DEBUG) + C2S(DUMP_LEN_ATTR_STATUS_LOG) + C2S(DUMP_FILENAME_ATTR_DEBUG_DUMP) + C2S(DUMP_FILENAME_ATTR_MEM_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_CORE_0_BEFORE_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_CORE_0_AFTER_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_CORE_1_BEFORE_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_CORE_1_AFTER_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_CORE_2_BEFORE_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_CORE_2_AFTER_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_DIG_BEFORE_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_DIG_AFTER_DUMP) + C2S(DUMP_FILENAME_ATTR_PKTLOG_DUMP) + C2S(DUMP_FILENAME_ATTR_PKTLOG_DEBUG_DUMP) + C2S(DUMP_LEN_ATTR_AXI_ERROR) + C2S(DUMP_FILENAME_ATTR_AXI_ERROR_DUMP) + C2S(DUMP_LEN_ATTR_RTT_LOG) + C2S(DUMP_FILENAME_ATTR_SDTC_ETB_DUMP) + C2S(DUMP_LEN_ATTR_SDTC_ETB_DUMP) + C2S(DUMP_LEN_ATTR_PKTID_MAP_LOG) + C2S(DUMP_LEN_ATTR_PKTID_UNMAP_LOG) + C2S(DUMP_LEN_ATTR_EWP_HW_INIT_LOG) + C2S(DUMP_LEN_ATTR_EWP_HW_MOD_DUMP) + C2S(DUMP_LEN_ATTR_EWP_HW_REG_DUMP) + default: + return "DUMP_LEN_ATTR_INVALID"; + } +} +static const char *EWP_CmdAttrToString(int attr) +{ + switch (attr) { + C2S(DUMP_BUF_ATTR_MEMDUMP) + C2S(DUMP_BUF_ATTR_SSSR_C0_BEFORE) + C2S(DUMP_BUF_ATTR_SSSR_C0_AFTER) + C2S(DUMP_BUF_ATTR_SSSR_C1_BEFORE) + C2S(DUMP_BUF_ATTR_SSSR_C1_AFTER) + C2S(DUMP_BUF_ATTR_SSSR_C2_BEFORE) + C2S(DUMP_BUF_ATTR_SSSR_C2_AFTER) + C2S(DUMP_BUF_ATTR_SSSR_DIG_BEFORE) + C2S(DUMP_BUF_ATTR_SSSR_DIG_AFTER) + C2S(DUMP_BUF_ATTR_TIMESTAMP) + C2S(DUMP_BUF_ATTR_GENERAL_LOG) + C2S(DUMP_BUF_ATTR_ECNTRS) + C2S(DUMP_BUF_ATTR_SPECIAL_LOG) + C2S(DUMP_BUF_ATTR_DHD_DUMP) + C2S(DUMP_BUF_ATTR_EXT_TRAP) + C2S(DUMP_BUF_ATTR_HEALTH_CHK) + C2S(DUMP_BUF_ATTR_PRESERVE_LOG) + C2S(DUMP_BUF_ATTR_COOKIE) + C2S(DUMP_BUF_ATTR_FLOWRING_DUMP) + C2S(DUMP_BUF_ATTR_PKTLOG) + C2S(DUMP_BUF_ATTR_PKTLOG_DEBUG) + C2S(DUMP_BUF_ATTR_STATUS_LOG) + C2S(DUMP_BUF_ATTR_AXI_ERROR) + C2S(DUMP_BUF_ATTR_RTT_LOG) + C2S(DUMP_BUF_ATTR_SDTC_ETB_DUMP) + C2S(DUMP_BUF_ATTR_PKTID_MAP_LOG) + C2S(DUMP_BUF_ATTR_PKTID_UNMAP_LOG) + C2S(DUMP_BUF_ATTR_EWP_HW_INIT_LOG) + C2S(DUMP_BUF_ATTR_EWP_HW_MOD_DUMP) + C2S(DUMP_BUF_ATTR_EWP_HW_REG_DUMP) + default: + return "DUMP_BUF_ATTR_INVALID"; + } +} + +/* Return index for matching buffer attribute */ +static int logger_attr_buffer_lookup(u8 attr) { + for (u8 i = 0; i < ARRAYSIZE(attr_lookup_tbl); i++) { + if (attr == attr_lookup_tbl[i].buf_attr) { + return i; + } + } + ALOGE("Lookup for buf attr = %s failed\n", + EWP_CmdAttrToString(attr)); + return -1; +} + +/* Return index matching the length attribute */ +static int logger_attr_lookup(u8 attr) { + for (u8 i = 0; i < ARRAYSIZE(attr_lookup_tbl); i++) { + if (attr == attr_lookup_tbl[i].attr_type) { + return i; + } + } + ALOGE("Lookup for len attr = %s failed\n", + EWP_EventAttrToString(attr)); + return -1; +} +#endif /* RING_DUMP */ + +#define DBGRING_NAME_MAX 32 //Copy from legacy hal +typedef struct wifi_buf_ring_map_entry { + uint32_t type; + uint32_t ring_id; + char ring_name[DBGRING_NAME_MAX]; +} wifi_buf_ring_map_entry_t; + +typedef struct { + char hw_id[PROPERTY_VALUE_MAX]; + char sku[MAX_SKU_NAME_LEN]; +} sku_info_t; + +sku_info_t sku_table[] = { + { {"G9S9B"}, {"MMW"} }, + { {"G8V0U"}, {"MMW"} }, + { {"GFQM1"}, {"MMW"} }, + { {"GB62Z"}, {"MMW"} }, + { {"GE2AE"}, {"MMW"} }, + { {"GQML3"}, {"MMW"} }, + { {"GB7N6"}, {"ROW"} }, + { {"GLU0G"}, {"ROW"} }, + { {"GNA8F"}, {"ROW"} }, + { {"GX7AS"}, {"ROW"} }, + { {"GP4BC"}, {"ROW"} }, + { {"GVU6C"}, {"ROW"} }, + { {"GR1YH"}, {"JPN"} }, + { {"GF5KQ"}, {"JPN"} }, + { {"GPQ72"}, {"JPN"} }, + { {"GB17L"}, {"JPN"} }, + { {"GFE4J"}, {"JPN"} }, + { {"G03Z5"}, {"JPN"} }, + { {"G1AZG"}, {"EU"} } +}; /////////////////////////////////////////////////////////////////////////////// class DebugCommand : public WifiCommand { @@ -155,6 +545,8 @@ class DebugCommand : public WifiCommand int *mBuffSize; u32 *mNumRings; wifi_ring_buffer_status *mStatus; + u32 *mNumMaps; + wifi_buf_ring_map_entry_t *mMaps; unsigned int *mSupport; u32 mVerboseLevel; u32 mFlags; @@ -228,6 +620,14 @@ public: mRingName = NULL; } + // constructor for buf ring map + DebugCommand(wifi_interface_handle iface, u32 *num_maps, + wifi_buf_ring_map_entry_t *map, GetCmdType cmdType) + : WifiCommand("DebugCommand", iface, 0), mNumMaps(num_maps), mMaps(map), mType(cmdType) + { + memset(mMaps, 0, sizeof(wifi_buf_ring_map_entry_t) * (*mNumMaps)); + } + // 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) @@ -366,6 +766,16 @@ public: break; } + case GET_BUF_RING_MAP: + { + result = request.create(GOOGLE_OUI, LOGGER_GET_BUF_RING_MAP); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get ring status request; result = %d", result); + return result; + } + break; + } + case START_RING_LOG: result = createRingRequest(request); break; @@ -378,7 +788,7 @@ public: } int start() { - // ALOGD("Start debug command"); + ALOGD("Start debug command"); WifiRequest request(familyId(), ifaceId()); int result = createRequest(request); if (result != WIFI_SUCCESS) { @@ -394,7 +804,7 @@ public: } virtual int handleResponse(WifiEvent& reply) { - ALOGD("In DebugCommand::handleResponse"); + ALOGD("In DebugCommand::handleResponse, mType:%d\n", mType); if (reply.get_cmd() != NL80211_CMD_VENDOR) { ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); @@ -449,9 +859,15 @@ public: 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++; + if (it.get_len() > sizeof(wifi_ring_buffer_status)) { + ALOGE("ring status unexpected len = %d, dest len = %lu", + it.get_len(), sizeof(wifi_ring_buffer_status)); + return NL_SKIP; + } else { + 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()); @@ -465,11 +881,57 @@ public: void *data = reply.get_vendor_data(); int len = reply.get_vendor_data_len(); - ALOGD("len = %d, expected len = %d", len, sizeof(unsigned int)); + ALOGD("len = %d, expected len = %lu", len, sizeof(unsigned int)); memcpy(mSupport, data, sizeof(unsigned int)); break; } + case GET_BUF_RING_MAP: + { + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + wifi_buf_ring_map_entry_t *map(mMaps); + + 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_BUF_RING_NUM) { + unsigned int num_maps = it.get_u32(); + if (*mNumMaps < num_maps) { + ALOGE("Not enough status buffers provided, available: %d required: %d", + *mNumMaps, num_maps); + } else { + *mNumMaps = num_maps; + } + } else { + ALOGE("Unknown attribute: %d expecting %d", + it.get_type(), LOGGER_ATTRIBUTE_BUF_RING_NUM); + return NL_SKIP; + } + + it.next(); + for (unsigned int i = 0; it.has_next() && i < *mNumMaps; it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_BUF_RING_MAP) { + if (it.get_len() > sizeof(wifi_buf_ring_map_entry_t)) { + ALOGE("GET_BUF_RING_MAP: unexpected len = %d, dest len = %lu", + it.get_len(), sizeof(wifi_buf_ring_map_entry_t)); + return NL_SKIP; + } else { + memcpy(map, it.get_data(), sizeof(wifi_buf_ring_map_entry_t)); + } + i++; + map++; + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + break; + } + default: ALOGW("Unknown Debug command"); } @@ -559,6 +1021,8 @@ 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) { + ALOGE("Ring name: level:%d sec:%d ring_name:%s", + verbose_level, max_interval_sec, 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); @@ -586,7 +1050,6 @@ public: ALOGV("Register loghandler"); int result; uint32_t event_sock_pid = getpid() + (WIFI_HAL_EVENT_SOCK_PORT << 22); - registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); WifiRequest request(familyId(), ifaceId()); @@ -596,14 +1059,18 @@ public: ALOGV("Failed to set Hal preInit; result = %d", result); return result; } + registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); result = request.put_u32(SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID, event_sock_pid); if (result != WIFI_SUCCESS) { + unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); ALOGV("Hal preInit Failed to put pic = %d", result); return result; } if (result != WIFI_SUCCESS) { + unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); ALOGV("Hal preInit Failed to put pid= %d", result); return result; } @@ -612,6 +1079,7 @@ public: result = requestResponse(request); if (result != WIFI_SUCCESS) { + unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); ALOGE("Failed to register set Hal preInit; result = %d", result); return result; } @@ -624,6 +1092,7 @@ public: /* unregister event handler */ unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); + wifi_unregister_cmd(wifiHandle(), id()); WifiRequest request(familyId(), ifaceId()); int result = request.create(GOOGLE_OUI, LOGGER_RESET_LOGGING); @@ -657,16 +1126,23 @@ public: return NL_SKIP; } - if(event_id == GOOGLE_DEBUG_RING_EVENT) { + 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)); + if (it.get_len() > sizeof(wifi_ring_buffer_status)) { + ALOGE("SetLogHandler: ring status unexpected len = %d, dest len = %lu", + it.get_len(), sizeof(wifi_ring_buffer_status)); + return NL_SKIP; + } else { + memcpy(&status, it.get_data(), sizeof(wifi_ring_buffer_status)); + } } else if (it.get_type() == LOGGER_ATTRIBUTE_RING_DATA) { buffer_size = it.get_len(); buffer = (char *)it.get_data(); + ALOGV("SetLogHandler: ring data size = %d", buffer_size); } else { ALOGW("Ignoring invalid attribute type = %d, size = %d", it.get_type(), it.get_len()); @@ -695,7 +1171,7 @@ 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); + ALOGE("Loghandler start, handle = %p", handle); SetLogHandler *cmd = new SetLogHandler(iface, id, handler); NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); @@ -710,13 +1186,17 @@ wifi_error wifi_set_log_handler(wifi_request_id id, wifi_interface_handle iface, cmd->releaseRef(); return result; } + +#ifdef RING_DUMP + wifi_start_ring_dump(iface, handler); +#endif /* RING_DUMP */ 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); + ALOGE("Loghandler reset, wifi_request_id = %d, handle = %p", id, handle); if (id == -1) { wifi_ring_buffer_data_handler handler; @@ -726,10 +1206,14 @@ wifi_error wifi_reset_log_handler(wifi_request_id id, wifi_interface_handle ifac NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); cmd->cancel(); cmd->releaseRef(); + +#ifdef RING_DUMP + wifi_stop_ring_dump(iface, handler); +#endif /* RING_DUMP */ return WIFI_SUCCESS; } - return wifi_cancel_cmd(id, iface); + return wifi_get_cancel_cmd(id, iface); } /////////////////////////////////////////////////////////////////////////////// @@ -795,7 +1279,6 @@ public: } virtual int handleEvent(WifiEvent& event) { - wifi_ring_buffer_id ring_id; char *buffer = NULL; int buffer_size = 0; bool is_err_alert = false; @@ -827,7 +1310,7 @@ public: } } - if(is_err_alert) { + if (is_err_alert) { mBuffSize = sizeof(mErrCode); if (mBuff) free(mBuff); mBuff = (char *)malloc(mBuffSize); @@ -896,6 +1379,114 @@ public: } }; +class SetRestartHandler : public WifiCommand +{ + wifi_subsystem_restart_handler mHandler; + char *mBuff; +public: + SetRestartHandler(wifi_handle handle, wifi_request_id id, wifi_subsystem_restart_handler handler) + : WifiCommand("SetRestartHandler", handle, id), mHandler(handler), mBuff(NULL) + { } + int start() { + ALOGI("Start Restart Handler handler"); + registerVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_HANGED); + return WIFI_SUCCESS; + } + virtual int cancel() { + ALOGI("Clear Restart Handler"); + + /* unregister alert handler */ + unregisterVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_HANGED); + wifi_unregister_cmd(wifiHandle(), id()); + ALOGI("Success to clear restarthandler"); + return WIFI_SUCCESS; + } + + virtual int handleResponse(WifiEvent& reply) { + /* Nothing to do on response! */ + return NL_OK; + } + + virtual int handleEvent(WifiEvent& event) { + 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 == BRCM_VENDOR_EVENT_HANGED) { + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_HANG_REASON) { + mBuff = (char *)it.get_data(); + } else { + ALOGI("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + + if (*mHandler.on_subsystem_restart) { + (*mHandler.on_subsystem_restart)(mBuff); + ALOGI("Hang event received. Trigger SSR handler:%p", + mHandler.on_subsystem_restart); + } else { + ALOGI("No Restart handler registered"); + } + } + return NL_OK; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +class SubSystemRestart : public WifiCommand +{ + public: + SubSystemRestart(wifi_interface_handle iface) + : WifiCommand("SubSystemRestart", iface, 0) + { } + + int createRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_TRIGGER_SSR); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + request.attr_end(data); + return WIFI_SUCCESS; + } + + int create() { + WifiRequest request(familyId(), ifaceId()); + + int result = createRequest(request); + if (result < 0) { + ALOGE("Failed to create ssr request result = %d\n", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register ssr response; result = %d\n", result); + } + return result; + } + + protected: + int handleResponse(WifiEvent& reply) { + /* Nothing to do on response! */ + return NL_OK; + } + + int handleEvent(WifiEvent& event) { + /* NO events to handle here! */ + return NL_SKIP; + } + +}; /////////////////////////////////////////////////////////////////////////////// class HalInit : public WifiCommand { @@ -939,6 +1530,7 @@ class HalInit : public WifiCommand ALOGE("Failed to register set hal start response; result = %d", result); } wifi_unregister_cmd(wifiHandle(), id()); + ALOGV("Stop HAL Successfully Completed, mErrCode = %d\n", mErrCode); return result; } @@ -983,6 +1575,338 @@ class HalInit : public WifiCommand } }; +#ifdef RING_DUMP +/////////////////////////////////////////////////////////////////////////////// +class RingDump : public WifiCommand +{ + int mLargestBuffSize; + char *mBuff; + int mErrCode; + int mNumMaps; + wifi_buf_ring_map_entry_t *mMap; + int attr_type_len[DUMP_EVENT_ATTR_MAX]; + char *ring_name[DUMP_BUF_ATTR_MAX]; + wifi_ring_buffer_data_handler mHandle; + +public: + RingDump(wifi_interface_handle iface, int id, int num_maps, wifi_buf_ring_map_entry_t *map, + wifi_ring_buffer_data_handler ring_handle) + : WifiCommand("RingDump", iface, id), mLargestBuffSize(0), mBuff(NULL), + mErrCode(0), mNumMaps(num_maps), mMap(map), mHandle(ring_handle) + { + memset(attr_type_len, 0, sizeof(attr_type_len)); + for (int i = 0; i < DUMP_BUF_ATTR_MAX; i++) { + ring_name[i] = NULL; + } + } + RingDump(wifi_interface_handle iface, int id) + : WifiCommand("RingDump", iface, id), mLargestBuffSize(0), mBuff(NULL), + mErrCode(0) + { + } + + int start() { + DUMP_INFO(("Start Ring Dump Map_cnt:%d\n", mNumMaps)); + registerVendorHandler(GOOGLE_OUI, GOOGLE_FILE_DUMP_EVENT); + + //Set ringname to buf hashmap + for (int i = 0; i < mNumMaps; i++) { + int type = mMap[i].type; + ring_name[type] = (char *)malloc(DBGRING_NAME_MAX); + memset(ring_name[type], 0, DBGRING_NAME_MAX); + memcpy(ring_name[type], mMap[i].ring_name, strlen(mMap[i].ring_name)); + DUMP_DEBUG(("Set ringname Buf:%s Ringname:%s len:%lu", + EWP_CmdAttrToString(type), ring_name[type], strlen(mMap[i].ring_name))); + } + return WIFI_SUCCESS; + } + + virtual int freeup() { + DUMP_DEBUG(("freeup:Enter\n")); + if (mBuff) { + free(mBuff); + mBuff = NULL; + DUMP_INFO(("freed allocated memory\n")); + } + return WIFI_SUCCESS; + } + + virtual int cancel() { + /* unregister file dump handler */ + unregisterVendorHandler(GOOGLE_OUI, GOOGLE_FILE_DUMP_EVENT); + wifi_unregister_cmd(wifiHandle(), id()); + + /* Free up the ring names allocated */ + for (u8 i = 0; i < DUMP_BUF_ATTR_MAX; i++) { + if (ring_name[i]) { + free(ring_name[i]); + ring_name[i] = NULL; + } + } + if (mBuff) { + free(mBuff); + } + + DUMP_INFO(("Stop Ring Dump Successfully Completed, mErrCode = %d\n", mErrCode)); + return WIFI_SUCCESS; + } + + virtual int handleResponse(WifiEvent& reply) { + DUMP_DEBUG(("RingDump::handleResponse\n")); + int buf_attr = DUMP_BUF_ATTR_INVALID; + int len_attr = DUMP_LEN_ATTR_INVALID; + int index = -1; + + 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(); + + 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()) { + buf_attr = it.get_type(); + switch (buf_attr) { + case DUMP_BUF_ATTR_MEMDUMP: + case DUMP_BUF_ATTR_TIMESTAMP: + case DUMP_BUF_ATTR_ECNTRS: + case DUMP_BUF_ATTR_DHD_DUMP: + case DUMP_BUF_ATTR_EXT_TRAP: + case DUMP_BUF_ATTR_HEALTH_CHK: + case DUMP_BUF_ATTR_COOKIE: + case DUMP_BUF_ATTR_FLOWRING_DUMP: + case DUMP_BUF_ATTR_STATUS_LOG: + case DUMP_BUF_ATTR_RTT_LOG: + case DUMP_BUF_ATTR_PKTID_MAP_LOG: + case DUMP_BUF_ATTR_PKTID_UNMAP_LOG: { + if (it.get_u32()) { + ALOGE("Copying data to userspace failed, status = %d\n", it.get_u32()); + return WIFI_ERROR_UNKNOWN; + } + index = logger_attr_buffer_lookup(buf_attr); + if (index == -1) { + ALOGE("Invalid index. buf attr = %s\n", EWP_CmdAttrToString(buf_attr)); + return WIFI_ERROR_UNKNOWN; + } + len_attr = attr_lookup_tbl[index].attr_type; + if (len_attr == DUMP_EVENT_ATTR_MAX) { + ALOGE("Invalid len attr = %s\n", EWP_EventAttrToString(len_attr)); + return WIFI_ERROR_UNKNOWN; + } + if (!mBuff || attr_type_len[len_attr] <= 0) { + return WIFI_ERROR_UNKNOWN; + } + + if (!ring_name[buf_attr]) { + ALOGE("Not allocated buf attr = %s\n", EWP_CmdAttrToString(buf_attr)); + return WIFI_ERROR_UNKNOWN; + } + DUMP_INFO(("RingDump:: buf_attr:%s size = %d ring_name:%s\n", + EWP_CmdAttrToString(buf_attr), attr_type_len[len_attr], + ring_name[buf_attr])); + if (mHandle.on_ring_buffer_data) { + /* on_ring_buffer_data callback requires status memory + * so should pass status memory */ + wifi_ring_buffer_status status; + memset(&status, 0, sizeof(status)); + /* Skip msg header. Retrieved log */ + (*mHandle.on_ring_buffer_data)(ring_name[buf_attr], mBuff, + attr_type_len[len_attr], &status); + } + if (mBuff) { + memset(mBuff, 0, mLargestBuffSize); + } + break; + } + default: { + DUMP_DEBUG(("Ignoring invalid attribute buf_attr = %d, size = %d", + buf_attr, it.get_len())); + break; + } + } + } + return NL_OK; + } + + virtual int request_logger_dump(WifiRequest& request, + buf_data_t *buf, int len_attr) { + + int result = 0; + int buf_attr = DUMP_BUF_ATTR_INVALID; + int index = -1; + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + index = logger_attr_lookup(len_attr); + if (index == -1) { + ALOGE("Invalid index\n"); + return WIFI_ERROR_UNKNOWN; + } + buf_attr = attr_lookup_tbl[index].buf_attr; + + if (buf_attr != DUMP_BUF_ATTR_INVALID) { + result = request.put(buf_attr, buf, sizeof(buf_data_t)); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put get memory dump request; result = %d", result); + return result; + } + } else { + ALOGE("Invalid buf attr = %s, index = %d\n", + EWP_CmdAttrToString(buf_attr), index); + return WIFI_ERROR_UNKNOWN; + } + DUMP_INFO(("Trigger get dump for buf attr = %s\n", + EWP_CmdAttrToString(buf_attr))); + + request.attr_end(data); + return result; + } + + virtual int handleEvent(WifiEvent& event) { + mLargestBuffSize = 0; + mBuff = NULL; + memset(attr_type_len, 0, sizeof(attr_type_len)); + u8 i = 0; + int result = 0; + int mActualBuffSize = 0; + int index = -1; + + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = event.get_vendor_data_len(); + int event_id = event.get_vendor_subcmd(); + int req_attr_cnt = 0; + int req_attr[DUMP_EVENT_ATTR_MAX]; + int buf_attr = DUMP_BUF_ATTR_INVALID; + + if (vendor_data == NULL || len == 0) { + ALOGE("No Debug data found"); + return NL_SKIP; + } + DUMP_INFO(("Ring Dump handler. Got event: %d", event_id)); + + buf_data_t buf; + + memset(&buf, 0, sizeof(buf_data_t)); + buf.ver = 0; + buf.buf_threshold = 0; + + if (event_id == GOOGLE_FILE_DUMP_EVENT) { + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + int attr = it.get_type(); + switch (attr) { + case DUMP_LEN_ATTR_MEMDUMP: + case DUMP_LEN_ATTR_TIMESTAMP: + case DUMP_LEN_ATTR_ECNTRS: + case DUMP_LEN_ATTR_DHD_DUMP: + case DUMP_LEN_ATTR_EXT_TRAP: + case DUMP_LEN_ATTR_HEALTH_CHK: + case DUMP_LEN_ATTR_COOKIE: + case DUMP_LEN_ATTR_FLOWRING_DUMP: + case DUMP_LEN_ATTR_STATUS_LOG: + case DUMP_LEN_ATTR_RTT_LOG: + case DUMP_LEN_ATTR_PKTID_MAP_LOG: + case DUMP_LEN_ATTR_PKTID_UNMAP_LOG: { + mActualBuffSize = it.get_u32(); + DUMP_DEBUG(("len attr %s, len %d\n", + EWP_EventAttrToString(attr), mActualBuffSize)); + if (mActualBuffSize > mLargestBuffSize) + mLargestBuffSize = mActualBuffSize; + attr_type_len[attr] = mActualBuffSize; + + /* Store the order in which attributes are received + * so that file dump can be done in the same order + */ + req_attr[req_attr_cnt++] = attr; + break; + } + default: { + ALOGE("Ignoring invalid attribute type = %d, size = %d", + attr, it.get_len()); + break; + } + } + } + /* Allocation for the largest buffer size to use it recursively for other buf attr. */ + if (mLargestBuffSize) { + DUMP_INFO(("Max dump size: %d", mLargestBuffSize)); + mBuff = (char *)malloc(mLargestBuffSize); + if (!mBuff) { + ALOGE("Buffer allocation failed"); + return NL_SKIP; + } + memset(mBuff, 0, mLargestBuffSize); + } + + WifiRequest request(familyId(), ifaceId()); + result = request.create(GOOGLE_OUI, LOGGER_DEBUG_GET_DUMP); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get memory dump request; result = %d", result); + freeup(); + goto exit; + } + + /* Requesting logger dump for each received attr */ + for (i = 0; i < req_attr_cnt; i++) { + int attr = req_attr[i]; + + if (attr_type_len[attr] == 0) { + continue; + } + + index = logger_attr_lookup(attr); + buf_attr = attr_lookup_tbl[index].buf_attr; + if (!ring_name[buf_attr]) { + ALOGE("Failed to find ringname index:%d buf_attr:%d", index, buf_attr); + continue; + } + + buf.len = attr_type_len[attr]; + buf.data_buf[0] = mBuff; + DUMP_DEBUG(("buf len = %d, buf ptr= %p for attr = %s\n", + buf.len, buf.data_buf[0], EWP_EventAttrToString(attr))); + result = request_logger_dump(request, &buf, attr); + if (result != WIFI_SUCCESS) { + /* Proceeding further for other attributes */ + ALOGE("Failed to request the logger dump for attr = %s; result = %d", + EWP_EventAttrToString(attr), result); + continue; + } + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register get memory dump response for attr = %s; result = %d", + EWP_EventAttrToString(attr), result); + /* Proceeding further for other attributes */ + continue; + } + } + + WifiRequest request2(familyId(), ifaceId()); + result = request2.create(GOOGLE_OUI, LOGGER_FILE_DUMP_DONE_IND); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to trigger dev close; result = %d", result); + freeup(); + goto exit; + } + requestResponse(request2); + freeup(); + } else { + ALOGE("dump event missing dump length attribute"); + return NL_SKIP; + } + exit: + if (result != WIFI_SUCCESS) { + return NL_SKIP; + } + return NL_OK; + } +}; +/////////////////////////////////////////////////////////////////////////////// +#endif /* RING_DUMP */ wifi_error wifi_start_hal(wifi_interface_handle iface) { @@ -1026,10 +1950,54 @@ wifi_error wifi_hal_preInit(wifi_interface_handle iface) return result; } -wifi_error wifi_stop_hal(wifi_interface_handle iface) +#ifdef RING_DUMP +wifi_error wifi_start_ring_dump(wifi_interface_handle iface, + wifi_ring_buffer_data_handler ring_handle) { wifi_handle handle = getWifiHandle(iface); + DUMP_INFO(("start ring dump, handle = %p", handle)); + wifi_buf_ring_map_entry_t map[DUMP_BUF_ATTR_MAX]; + unsigned int num_maps = DUMP_BUF_ATTR_MAX; + wifi_error result; + + /* Get mapping table from driver */ + DebugCommand *debug_cmd = new DebugCommand(iface, &num_maps, map, GET_BUF_RING_MAP); + NULL_CHECK_RETURN(debug_cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + result = (wifi_error)debug_cmd->start(); + debug_cmd->releaseRef(); + + /* Set ringname to corresponding buf attr */ + RingDump *cmd = new RingDump(iface, FILE_DUMP_REQUEST_ID, num_maps, map, ring_handle); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + result = wifi_register_cmd(handle, FILE_DUMP_REQUEST_ID, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, FILE_DUMP_REQUEST_ID); + cmd->releaseRef(); + return result; + } + return result; +} +wifi_error wifi_stop_ring_dump(wifi_interface_handle iface, + wifi_ring_buffer_data_handler ring_handle) +{ + RingDump *cmd = new RingDump(iface, FILE_DUMP_REQUEST_ID); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + DUMP_INFO(("stop ring dump")); + cmd->cancel(); + cmd->releaseRef(); + return WIFI_SUCCESS; +} +#endif /* RING_DUMP */ + +wifi_error wifi_stop_hal(wifi_interface_handle iface) +{ HalInit *cmd = new HalInit(iface, HAL_START_REQUEST_ID); NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); cmd->cancel(); @@ -1037,6 +2005,85 @@ wifi_error wifi_stop_hal(wifi_interface_handle iface) return WIFI_SUCCESS; } + +wifi_error wifi_set_subsystem_restart_handler(wifi_handle handle, + wifi_subsystem_restart_handler handler) +{ + hal_info *info = NULL; + + info = (hal_info *)handle; + if (info == NULL) { + ALOGE("Could not find hal info\n"); + return WIFI_ERROR_UNKNOWN; + } + + SetRestartHandler *cmd = new SetRestartHandler(handle, HAL_RESTART_ID, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, HAL_RESTART_ID, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, HAL_RESTART_ID); + cmd->releaseRef(); + return result; + } + + /* Cache the handler to use it for trigger subsystem restart */ + ALOGI("Register SSR handler:%p", handler); + info->restart_handler = handler; + return result; +} + +wifi_error wifi_trigger_subsystem_restart(wifi_handle handle) +{ + wifi_error result = WIFI_SUCCESS; + hal_info *info = NULL; + char error_str[20]; + SubSystemRestart *cmd = NULL; + wifi_interface_handle *ifaceHandles = NULL; + wifi_interface_handle wlan0Handle; + int numIfaceHandles = 0; + + info = (hal_info *)handle; + if (handle == NULL || info == NULL) { + ALOGE("Could not find hal info\n"); + result = WIFI_ERROR_UNKNOWN; + goto exit; + } + + ALOGI("Trigger subsystem restart\n"); + + wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles); + + cmd = new SubSystemRestart(wlan0Handle); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + + result = (wifi_error)cmd->create(); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + strncpy(error_str, "WIFI_ERROR_UNKNOWN", sizeof(error_str)); + ALOGE("Failed to create SSR"); + goto exit; + } + + strncpy(error_str, "WIFI_SUCCESS", sizeof(error_str)); + +exit: + if (info->restart_handler.on_subsystem_restart) { + ALOGI("Trigger ssr handler registered handler:%p", + info->restart_handler.on_subsystem_restart); + (info->restart_handler.on_subsystem_restart)(error_str); + } else { + ALOGI("No trigger ssr handler registered"); + } + + return result; +} + wifi_error wifi_set_alert_handler(wifi_request_id id, wifi_interface_handle iface, wifi_alert_handler handler) { @@ -1075,7 +2122,7 @@ wifi_error wifi_reset_alert_handler(wifi_request_id id, wifi_interface_handle if return WIFI_SUCCESS; } - return wifi_cancel_cmd(id, iface); + return wifi_get_cancel_cmd(id, iface); } /////////////////////////////////////////////////////////////////////////////// @@ -1345,7 +2392,7 @@ public: 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); + ALOGI("No: of pkt fates provided is %zu\n", *mNoProvidedFates); } else { ALOGE("Ignoring invalid attribute type = %d, size = %d\n", it.get_type(), it.get_len()); @@ -1429,7 +2476,7 @@ class GetWakeReasonCountCommand : public WifiCommand { mWakeReasonCnt->total_driver_fw_local_wake = it.get_u32(); break; - case WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT: + case WAKE_STAT_ATTRIBUTE_TOTAL: mWakeReasonCnt->total_cmd_event_wake = it.get_u32(); break; @@ -1437,7 +2484,7 @@ class GetWakeReasonCountCommand : public WifiCommand { mWakeReasonCnt->cmd_event_wake_cnt_used = it.get_u32(); break; - case WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE: + case WAKE_STAT_ATTRIBUTE_WAKE: memcpy(mCmdEventWakeCount, it.get_data(), (mWakeReasonCnt->cmd_event_wake_cnt_used * sizeof(int))); break; @@ -1485,7 +2532,7 @@ class GetWakeReasonCountCommand : public WifiCommand { mWakeReasonCnt->rx_multicast_wake_pkt_info.ipv6_rx_multicast_addr_cnt = it.get_u32(); break; - case WAKE_STAT_ATTRIBUTE_OTHER__RX_MULTICAST_ADD_CNT: + case WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT: mWakeReasonCnt->rx_multicast_wake_pkt_info.other_rx_multicast_addr_cnt = it.get_u32(); break; @@ -1540,3 +2587,253 @@ wifi_error wifi_get_wake_reason_stats(wifi_interface_handle handle, cmd->releaseRef(); return result; } + +/////////////////////////////////////////////////////////////////////////////// +class OtaUpdateCommand : public WifiCommand +{ + + public: + OtaUpdateCommand(wifi_interface_handle iface) + : WifiCommand("OtaUpdateCommand", iface, 0) + { } + + int start() { + ALOGE("Start OtaUpdateCommand"); + WifiRequest request(familyId(), ifaceId()); + + int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_GET_OTA_CURRUNT_INFO); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to set hal start; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register set hal start response; result = %d", result); + } + return result; + } + + int otaDownload(ota_info_buf_t* buf, uint32_t ota_version) { + u32 force_reg_on = false; + WifiRequest request(familyId(), ifaceId()); + int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_OTA_UPDATE); + + ALOGE("Download the OTA configuration"); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to set Hal preInit; result = %d", result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + result = request.put_u32(OTA_DOWNLOAD_CLM_LENGTH_ATTR, buf->ota_clm_len); + if (result != WIFI_SUCCESS) { + ALOGE("otaDownload Failed to put data= %d", result); + return result; + } + + result = request.put(OTA_DOWNLOAD_CLM_ATTR, buf->ota_clm_buf, sizeof(*buf->ota_clm_buf)); + if (result != WIFI_SUCCESS) { + ALOGE("otaDownload Failed to put data= %d", result); + return result; + } + + result = request.put_u32(OTA_DOWNLOAD_NVRAM_LENGTH_ATTR, buf->ota_nvram_len); + if (result != WIFI_SUCCESS) { + ALOGE("otaDownload Failed to put data= %d", result); + return result; + } + + result = request.put(OTA_DOWNLOAD_NVRAM_ATTR, + buf->ota_nvram_buf, sizeof(*buf->ota_nvram_buf)); + if (result != WIFI_SUCCESS) { + ALOGE("otaDownload Failed to put data= %d", result); + return result; + } + + if (applied_ota_version != ota_version) { + force_reg_on = true; + applied_ota_version = ota_version; + } + result = request.put_u32(OTA_SET_FORCE_REG_ON, force_reg_on); + if (result != WIFI_SUCCESS) { + ALOGE("otaDownload Failed to put data= %d", result); + return result; + } + + request.attr_end(data); + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register set otaDownload; result = %d", result); + } + + return result; + } + + virtual int handleResponse(WifiEvent& reply) { + ALOGD("In OtaUpdateCommand::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(); + + ALOGI("Id = %0x, subcmd = %d, len = %d", id, subcmd, len); + + 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()) { + switch (it.get_type()) { + case OTA_CUR_NVRAM_EXT_ATTR: + strncpy(ota_nvram_ext, (char*)it.get_string(), it.get_len()); + ALOGI("Current Nvram ext [%s]\n", ota_nvram_ext); + break; + default: + ALOGE("Ignoring invalid attribute type = %d, size = %d\n", + it.get_type(), it.get_len()); + break; + } + } + return NL_OK; + } + + virtual int handleEvent(WifiEvent& event) { + /* NO events! */ + return NL_SKIP; + } +}; + +wifi_error read_ota_file(char* file, char** buffer, uint32_t* size) +{ + FILE* fp = NULL; + int file_size; + char* buf; + fp = fopen(file, "r"); + + if (fp == NULL) { + ALOGI("File [%s] doesn't exist.", file); + return WIFI_ERROR_NOT_AVAILABLE; + } + + fseek(fp, 0, SEEK_END); + file_size = ftell(fp); + + buf = (char *)malloc(file_size + 1); + if (buf == NULL) { + fclose(fp); + return WIFI_ERROR_UNKNOWN; + } + memset(buf, 0, file_size + 1); + fseek(fp, 0, SEEK_SET); + fread(buf, file_size, 1, fp); + + *buffer = (char*) buf; + *size = file_size; + fclose(fp); + return WIFI_SUCCESS; +} + +wifi_error check_multiple_nvram_clm(uint32_t type, char* hw_revision, char* hw_sku, + char** buffer, uint32_t* buffer_len) +{ + char file_name[MAX_NV_FILE][FILE_NAME_LEN]; + char nvram_clmblob_default_file[FILE_NAME_LEN] = {0,}; + wifi_error result = WIFI_SUCCESS; + + if (type == CLM_BLOB) { + sprintf(nvram_clmblob_default_file, "%s%s", OTA_PATH, OTA_CLM_FILE); + } + else if (type == NVRAM) { + sprintf(nvram_clmblob_default_file, "%s%s", OTA_PATH, OTA_NVRAM_FILE); + } + for (unsigned int i = 0; i < MAX_NV_FILE; i++) { + memset(file_name[i], 0, FILE_NAME_LEN); + } + + sprintf(file_name[0], "%s_%s_%s", nvram_clmblob_default_file, hw_revision, hw_sku); + sprintf(file_name[1], "%s_%s", nvram_clmblob_default_file, hw_revision); + sprintf(file_name[2], "%s_%s", nvram_clmblob_default_file, hw_sku); + sprintf(file_name[3], "%s", nvram_clmblob_default_file); + + for (unsigned int i = 0; i < MAX_NV_FILE; i++) { + result = read_ota_file(file_name[i], buffer, buffer_len); + if (result == WIFI_SUCCESS) { + ALOGI("[OTA] %s PATH %s", type == NVRAM ? "NVRAM" : "CLM", file_name[i]); + break; + } + } + return result; +} + +wifi_error wifi_hal_ota_update(wifi_interface_handle iface, uint32_t ota_version) +{ + wifi_handle handle = getWifiHandle(iface); + wifi_error result = WIFI_SUCCESS; + ota_info_buf_t buf; + char *buffer_nvram = NULL; + char *buffer_clm = NULL; + char prop_revision_buf[PROPERTY_VALUE_MAX] = {0,}; + char prop_sku_buf[PROPERTY_VALUE_MAX] = {0,}; + char sku_name[MAX_SKU_NAME_LEN] = {0,}; + + OtaUpdateCommand *cmd = new OtaUpdateCommand(iface); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + + ALOGD("wifi_hal_ota_update, handle = %p, ota_version %d\n", handle, ota_version); + + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + + property_get(HW_DEV_PROP, prop_revision_buf, NULL); + property_get(HW_SKU_PROP, prop_sku_buf, NULL); + + strncpy(sku_name, "NA", MAX_SKU_NAME_LEN); + for (int i = 0; i < ARRAYSIZE(sku_table); i ++) { + if (strcmp(prop_sku_buf, sku_table[i].hw_id) == 0) { + strncpy(sku_name, sku_table[i].sku, MAX_SKU_NAME_LEN); + break; + } + } + ALOGD("prop_sku_buf is %s, sku_name is %s", prop_sku_buf, sku_name); + + check_multiple_nvram_clm(CLM_BLOB, prop_revision_buf, sku_name, &buffer_clm, &buf.ota_clm_len); + if (buffer_clm == NULL) { + ALOGE("buffer_clm is null"); + goto exit; + } + buf.ota_clm_buf[0] = buffer_clm; + + check_multiple_nvram_clm(NVRAM, prop_revision_buf, sku_name, + &buffer_nvram, &buf.ota_nvram_len); + if (buffer_nvram == NULL) { + ALOGE("buffer_nvram is null"); + goto exit; + } + buf.ota_nvram_buf[0] = buffer_nvram; + cmd->otaDownload(&buf, ota_version); + +exit: + if (buffer_clm != NULL) { + free(buffer_clm); + } + if (buffer_nvram != NULL) { + free(buffer_nvram); + } + + cmd->releaseRef(); + + return result; +} diff --git a/bcmdhd/wifi_hal/wifi_offload.cpp b/bcmdhd/wifi_hal/wifi_offload.cpp index 8054f49..1702ffd 100644 --- a/bcmdhd/wifi_hal/wifi_offload.cpp +++ b/bcmdhd/wifi_hal/wifi_offload.cpp @@ -52,13 +52,16 @@ typedef enum { } 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, - MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE + MKEEP_ALIVE_ATTRIBUTE_INVALID = 0, + MKEEP_ALIVE_ATTRIBUTE_ID = 1, + MKEEP_ALIVE_ATTRIBUTE_IP_PKT = 2, + MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN = 3, + MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR = 4, + MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR = 5, + MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC = 6, + MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE = 7, + /* Add new attributes just above this */ + MKEEP_ALIVE_ATTRIBUTE_MAX } WIFI_MKEEP_ALIVE_ATTRIBUTE; typedef enum { diff --git a/bcmdhd/wpa_supplicant_8_lib/Android.mk b/bcmdhd/wpa_supplicant_8_lib/Android.mk index 518f0ca..448a7ca 100644 --- a/bcmdhd/wpa_supplicant_8_lib/Android.mk +++ b/bcmdhd/wpa_supplicant_8_lib/Android.mk @@ -66,6 +66,9 @@ L_CFLAGS += -Wall -Werror -Wno-unused-parameter -Wno-macro-redefined include $(CLEAR_VARS) LOCAL_MODULE := lib_driver_cmd_bcmdhd +LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD +LOCAL_LICENSE_CONDITIONS := notice +LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE LOCAL_SHARED_LIBRARIES := libc libcutils LOCAL_CFLAGS := $(L_CFLAGS) LOCAL_SRC_FILES := $(WPA_SRC_FILE) |