summaryrefslogtreecommitdiff
path: root/wcn6740/qcwcn/wifi_hal/nan_req.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'wcn6740/qcwcn/wifi_hal/nan_req.cpp')
-rw-r--r--wcn6740/qcwcn/wifi_hal/nan_req.cpp2028
1 files changed, 2028 insertions, 0 deletions
diff --git a/wcn6740/qcwcn/wifi_hal/nan_req.cpp b/wcn6740/qcwcn/wifi_hal/nan_req.cpp
new file mode 100644
index 0000000..1350623
--- /dev/null
+++ b/wcn6740/qcwcn/wifi_hal/nan_req.cpp
@@ -0,0 +1,2028 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Changes from Qualcomm Innovation Center are provided under the following license:
+ *
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted (subject to the limitations in the
+ * disclaimer below) provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * * Neither the name of Qualcomm Innovation Center, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+ * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+ * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sync.h"
+#include <utils/Log.h>
+#include "wifi_hal.h"
+#include "nan_i.h"
+#include "nancommand.h"
+
+wifi_error NanCommand::putNanEnable(transaction_id id, const NanEnableRequest *pReq)
+{
+ wifi_error ret;
+ ALOGV("NAN_ENABLE");
+ size_t message_len = NAN_MAX_ENABLE_REQ_SIZE;
+ int freq_24g;
+
+ if (pReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ if (pReq->config_24g_channel == 0)
+ freq_24g = 2437;
+ else
+ freq_24g = pReq->channel_24g_val;
+
+ message_len += \
+ (
+ pReq->config_support_5g ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->support_5g_val)) : 0 \
+ ) + \
+ (
+ pReq->config_sid_beacon ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->sid_beacon_val)) : 0 \
+ ) + \
+ (
+ pReq->config_2dot4g_rssi_close ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->rssi_close_2dot4g_val)) : 0 \
+ ) + \
+ (
+ pReq->config_2dot4g_rssi_middle ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->rssi_middle_2dot4g_val)) : 0 \
+ ) + \
+ (
+ pReq->config_hop_count_limit ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->hop_count_limit_val)) : 0 \
+ ) + \
+ (
+ pReq->config_2dot4g_support ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->support_2dot4g_val)) : 0 \
+ ) + \
+ (
+ pReq->config_2dot4g_beacons ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->beacon_2dot4g_val)) : 0 \
+ ) + \
+ (
+ pReq->config_2dot4g_sdf ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->sdf_2dot4g_val)) : 0 \
+ ) + \
+ (
+ pReq->config_5g_beacons ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->beacon_5g_val)) : 0 \
+ ) + \
+ (
+ pReq->config_5g_sdf ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->sdf_5g_val)) : 0 \
+ ) + \
+ (
+ pReq->config_5g_rssi_close ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->rssi_close_5g_val)) : 0 \
+ ) + \
+ (
+ pReq->config_5g_rssi_middle ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->rssi_middle_5g_val)) : 0 \
+ ) + \
+ (
+ pReq->config_2dot4g_rssi_proximity ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->rssi_proximity_2dot4g_val)) : 0 \
+ ) + \
+ (
+ pReq->config_5g_rssi_close_proximity ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->rssi_close_proximity_5g_val)) : 0 \
+ ) + \
+ (
+ pReq->config_rssi_window_size ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->rssi_window_size_val)) : 0 \
+ ) + \
+ (
+ pReq->config_oui ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->oui_val)) : 0 \
+ ) + \
+ (
+ pReq->config_intf_addr ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->intf_addr_val)) : 0 \
+ ) + \
+ (
+ pReq->config_cluster_attribute_val ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->config_cluster_attribute_val)) : 0 \
+ ) + \
+ (
+ pReq->config_scan_params ? NAN_MAX_SOCIAL_CHANNELS *
+ (SIZEOF_TLV_HDR + sizeof(u32)) : 0 \
+ ) + \
+ (
+ pReq->config_random_factor_force ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->random_factor_force_val)) : 0 \
+ ) + \
+ (
+ pReq->config_hop_count_force ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->hop_count_force_val)) : 0 \
+ ) + \
+ (
+ /* always include 24g channel/freq */
+ SIZEOF_TLV_HDR + sizeof(u32) \
+ ) + \
+ (
+ pReq->config_5g_channel ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ ) + \
+ (
+ pReq->config_dw.config_2dot4g_dw_band ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ ) + \
+ (
+ pReq->config_dw.config_5g_dw_band ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ ) + \
+ (
+ pReq->config_disc_mac_addr_randomization ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ ) + \
+ (
+ /* Always include cfg discovery indication TLV */
+ SIZEOF_TLV_HDR + sizeof(u32) \
+ ) + \
+ (
+ pReq->config_subscribe_sid_beacon ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->subscribe_sid_beacon_val)) : 0 \
+ ) + \
+ (
+ pReq->config_discovery_beacon_int ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ ) + \
+ (
+ pReq->config_nss ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ ) + \
+ (
+ pReq->config_enable_ranging ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ ) + \
+ (
+ pReq->config_dw_early_termination ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ );
+
+ pNanEnableReqMsg pFwReq = (pNanEnableReqMsg)malloc(message_len);
+ if (pFwReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ ALOGV("Message Len %zu", message_len);
+ memset (pFwReq, 0, message_len);
+ pFwReq->fwHeader.msgVersion = (u16)NAN_MSG_VERSION1;
+ pFwReq->fwHeader.msgId = NAN_MSG_ID_ENABLE_REQ;
+ pFwReq->fwHeader.msgLen = message_len;
+ pFwReq->fwHeader.transactionId = id;
+
+ u8* tlvs = pFwReq->ptlv;
+
+ /* Write the TLVs to the message. */
+
+ tlvs = addTlv(NAN_TLV_TYPE_CLUSTER_ID_LOW, sizeof(pReq->cluster_low),
+ (const u8*)&pReq->cluster_low, tlvs);
+ tlvs = addTlv(NAN_TLV_TYPE_CLUSTER_ID_HIGH, sizeof(pReq->cluster_high),
+ (const u8*)&pReq->cluster_high, tlvs);
+ tlvs = addTlv(NAN_TLV_TYPE_MASTER_PREFERENCE, sizeof(pReq->master_pref),
+ (const u8*)&pReq->master_pref, tlvs);
+ if (pReq->config_support_5g) {
+ tlvs = addTlv(NAN_TLV_TYPE_5G_SUPPORT, sizeof(pReq->support_5g_val),
+ (const u8*)&pReq->support_5g_val, tlvs);
+ }
+ if (pReq->config_sid_beacon) {
+ tlvs = addTlv(NAN_TLV_TYPE_SID_BEACON, sizeof(pReq->sid_beacon_val),
+ (const u8*)&pReq->sid_beacon_val, tlvs);
+ }
+ if (pReq->config_2dot4g_rssi_close) {
+ tlvs = addTlv(NAN_TLV_TYPE_24G_RSSI_CLOSE,
+ sizeof(pReq->rssi_close_2dot4g_val),
+ (const u8*)&pReq->rssi_close_2dot4g_val, tlvs);
+ }
+ if (pReq->config_2dot4g_rssi_middle) {
+ tlvs = addTlv(NAN_TLV_TYPE_24G_RSSI_MIDDLE,
+ sizeof(pReq->rssi_middle_2dot4g_val),
+ (const u8*)&pReq->rssi_middle_2dot4g_val, tlvs);
+ }
+ if (pReq->config_hop_count_limit) {
+ tlvs = addTlv(NAN_TLV_TYPE_HOP_COUNT_LIMIT,
+ sizeof(pReq->hop_count_limit_val),
+ (const u8*)&pReq->hop_count_limit_val, tlvs);
+ }
+ if (pReq->config_2dot4g_support) {
+ tlvs = addTlv(NAN_TLV_TYPE_24G_SUPPORT, sizeof(pReq->support_2dot4g_val),
+ (const u8*)&pReq->support_2dot4g_val, tlvs);
+ }
+ if (pReq->config_2dot4g_beacons) {
+ tlvs = addTlv(NAN_TLV_TYPE_24G_BEACON, sizeof(pReq->beacon_2dot4g_val),
+ (const u8*)&pReq->beacon_2dot4g_val, tlvs);
+ }
+ if (pReq->config_2dot4g_sdf) {
+ tlvs = addTlv(NAN_TLV_TYPE_24G_SDF, sizeof(pReq->sdf_2dot4g_val),
+ (const u8*)&pReq->sdf_2dot4g_val, tlvs);
+ }
+ if (pReq->config_5g_beacons) {
+ tlvs = addTlv(NAN_TLV_TYPE_5G_BEACON, sizeof(pReq->beacon_5g_val),
+ (const u8*)&pReq->beacon_5g_val, tlvs);
+ }
+ if (pReq->config_5g_sdf) {
+ tlvs = addTlv(NAN_TLV_TYPE_5G_SDF, sizeof(pReq->sdf_5g_val),
+ (const u8*)&pReq->sdf_5g_val, tlvs);
+ }
+ if (pReq->config_2dot4g_rssi_proximity) {
+ tlvs = addTlv(NAN_TLV_TYPE_24G_RSSI_CLOSE_PROXIMITY,
+ sizeof(pReq->rssi_proximity_2dot4g_val),
+ (const u8*)&pReq->rssi_proximity_2dot4g_val, tlvs);
+ }
+ /* Add the support of sending 5G RSSI values */
+ if (pReq->config_5g_rssi_close) {
+ tlvs = addTlv(NAN_TLV_TYPE_5G_RSSI_CLOSE, sizeof(pReq->rssi_close_5g_val),
+ (const u8*)&pReq->rssi_close_5g_val, tlvs);
+ }
+ if (pReq->config_5g_rssi_middle) {
+ tlvs = addTlv(NAN_TLV_TYPE_5G_RSSI_MIDDLE, sizeof(pReq->rssi_middle_5g_val),
+ (const u8*)&pReq->rssi_middle_5g_val, tlvs);
+ }
+ if (pReq->config_5g_rssi_close_proximity) {
+ tlvs = addTlv(NAN_TLV_TYPE_5G_RSSI_CLOSE_PROXIMITY,
+ sizeof(pReq->rssi_close_proximity_5g_val),
+ (const u8*)&pReq->rssi_close_proximity_5g_val, tlvs);
+ }
+ if (pReq->config_rssi_window_size) {
+ tlvs = addTlv(NAN_TLV_TYPE_RSSI_AVERAGING_WINDOW_SIZE, sizeof(pReq->rssi_window_size_val),
+ (const u8*)&pReq->rssi_window_size_val, tlvs);
+ }
+ if (pReq->config_oui) {
+ tlvs = addTlv(NAN_TLV_TYPE_CLUSTER_OUI_NETWORK_ID, sizeof(pReq->oui_val),
+ (const u8*)&pReq->oui_val, tlvs);
+ }
+ if (pReq->config_intf_addr) {
+ tlvs = addTlv(NAN_TLV_TYPE_SOURCE_MAC_ADDRESS, sizeof(pReq->intf_addr_val),
+ (const u8*)&pReq->intf_addr_val[0], tlvs);
+ }
+ if (pReq->config_cluster_attribute_val) {
+ tlvs = addTlv(NAN_TLV_TYPE_CLUSTER_ATTRIBUTE_IN_SDF, sizeof(pReq->config_cluster_attribute_val),
+ (const u8*)&pReq->config_cluster_attribute_val, tlvs);
+ }
+ if (pReq->config_scan_params) {
+ u32 socialChannelParamVal[NAN_MAX_SOCIAL_CHANNELS];
+ /* Fill the social channel param */
+ fillNanSocialChannelParamVal(&pReq->scan_params_val,
+ socialChannelParamVal);
+ int i;
+ for (i = 0; i < NAN_MAX_SOCIAL_CHANNELS; i++) {
+ tlvs = addTlv(NAN_TLV_TYPE_SOCIAL_CHANNEL_SCAN_PARAMS,
+ sizeof(socialChannelParamVal[i]),
+ (const u8*)&socialChannelParamVal[i], tlvs);
+ }
+ }
+ if (pReq->config_random_factor_force) {
+ tlvs = addTlv(NAN_TLV_TYPE_RANDOM_FACTOR_FORCE,
+ sizeof(pReq->random_factor_force_val),
+ (const u8*)&pReq->random_factor_force_val, tlvs);
+ }
+ if (pReq->config_hop_count_force) {
+ tlvs = addTlv(NAN_TLV_TYPE_HOP_COUNT_FORCE,
+ sizeof(pReq->hop_count_force_val),
+ (const u8*)&pReq->hop_count_force_val, tlvs);
+ }
+ tlvs = addTlv(NAN_TLV_TYPE_24G_CHANNEL,
+ sizeof(u32),
+ (const u8*)&freq_24g, tlvs);
+ if (pReq->config_5g_channel) {
+ tlvs = addTlv(NAN_TLV_TYPE_5G_CHANNEL,
+ sizeof(u32),
+ (const u8*)&pReq->channel_5g_val, tlvs);
+ }
+ if (pReq->config_dw.config_2dot4g_dw_band) {
+ tlvs = addTlv(NAN_TLV_TYPE_2G_COMMITTED_DW,
+ sizeof(pReq->config_dw.dw_2dot4g_interval_val),
+ (const u8*)&pReq->config_dw.dw_2dot4g_interval_val, tlvs);
+ }
+ if (pReq->config_dw.config_5g_dw_band) {
+ tlvs = addTlv(NAN_TLV_TYPE_5G_COMMITTED_DW,
+ sizeof(pReq->config_dw.dw_5g_interval_val),
+ (const u8*)&pReq->config_dw.dw_5g_interval_val, tlvs);
+ }
+ if (pReq->config_disc_mac_addr_randomization) {
+ tlvs = addTlv(NAN_TLV_TYPE_DISC_MAC_ADDR_RANDOM_INTERVAL,
+ sizeof(u32),
+ (const u8*)&pReq->disc_mac_addr_rand_interval_sec, tlvs);
+ }
+
+ u32 config_discovery_indications;
+ config_discovery_indications = (u32)pReq->discovery_indication_cfg;
+ /* Save the discovery MAC indication config if it is disabled from the
+ * framework and use it later to decide if the framework to be notified of
+ * the response. And enable the self MAC discovery indication from firmware
+ * by resetting the bit in config to get the Self MAC.
+ */
+ if (config_discovery_indications & NAN_DISC_ADDR_IND_DISABLED) {
+ mNanCommandInstance->mNanDiscAddrIndDisabled = true;
+ config_discovery_indications &= ~NAN_DISC_ADDR_IND_DISABLED;
+ } else {
+ mNanCommandInstance->mNanDiscAddrIndDisabled = false;
+ }
+ tlvs = addTlv(NAN_TLV_TYPE_CONFIG_DISCOVERY_INDICATIONS,
+ sizeof(u32),
+ (const u8*)&config_discovery_indications, tlvs);
+
+ if (pReq->config_subscribe_sid_beacon) {
+ tlvs = addTlv(NAN_TLV_TYPE_SUBSCRIBE_SID_BEACON,
+ sizeof(pReq->subscribe_sid_beacon_val),
+ (const u8*)&pReq->subscribe_sid_beacon_val, tlvs);
+ }
+ if (pReq->config_discovery_beacon_int) {
+ tlvs = addTlv(NAN_TLV_TYPE_DB_INTERVAL, sizeof(u32),
+ (const u8*)&pReq->discovery_beacon_interval, tlvs);
+ }
+ if (pReq->config_nss) {
+ tlvs = addTlv(NAN_TLV_TYPE_TX_RX_CHAINS, sizeof(u32),
+ (const u8*)&pReq->nss, tlvs);
+ }
+ if (pReq->config_enable_ranging) {
+ tlvs = addTlv(NAN_TLV_TYPE_ENABLE_DEVICE_RANGING, sizeof(u32),
+ (const u8*)&pReq->enable_ranging, tlvs);
+ }
+ if (pReq->config_dw_early_termination) {
+ tlvs = addTlv(NAN_TLV_TYPE_DW_EARLY_TERMINATION, sizeof(u32),
+ (const u8*)&pReq->enable_dw_termination, tlvs);
+ }
+
+ mVendorData = (char*)pFwReq;
+ mDataLen = message_len;
+
+ ret = WIFI_SUCCESS;
+ if (mSubcmd == QCA_NL80211_VENDOR_SUBCMD_NAN) {
+ //Insert the vendor specific data
+ ret = mMsg.put_bytes(NL80211_ATTR_VENDOR_DATA, mVendorData, mDataLen);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: put_bytes Error:%d",__func__, ret);
+ cleanup();
+ return ret;
+ }
+ } else {
+ struct nlattr *nl_data;
+
+ nl_data = attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nl_data) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ if (mMsg.put_u32(QCA_WLAN_VENDOR_ATTR_NAN_SUBCMD_TYPE,
+ QCA_WLAN_NAN_EXT_SUBCMD_TYPE_ENABLE_REQ) ||
+ mMsg.put_bytes(QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA,
+ mVendorData, mDataLen)) {
+ ALOGE("%s: put attr error", __func__);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ if (mMsg.put_u32(QCA_WLAN_VENDOR_ATTR_NAN_DISC_24GHZ_BAND_FREQ,
+ freq_24g)) {
+ ALOGE("%s: put attr error", __func__);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ if (pReq->config_5g_channel) {
+ if (mMsg.put_u32(QCA_WLAN_VENDOR_ATTR_NAN_DISC_5GHZ_BAND_FREQ,
+ pReq->channel_5g_val)) {
+ ALOGE("%s: put attr error", __func__);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ }
+ attr_end(nl_data);
+ }
+ hexdump(mVendorData, mDataLen);
+ return ret;
+}
+
+wifi_error NanCommand::putNanDisable(transaction_id id)
+{
+ wifi_error ret;
+ ALOGV("NAN_DISABLE");
+ size_t message_len = sizeof(NanDisableReqMsg);
+
+ pNanDisableReqMsg pFwReq = (pNanDisableReqMsg)malloc(message_len);
+ if (pFwReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ ALOGV("Message Len %zu", message_len);
+ memset (pFwReq, 0, message_len);
+ pFwReq->fwHeader.msgVersion = (u16)NAN_MSG_VERSION1;
+ pFwReq->fwHeader.msgId = NAN_MSG_ID_DISABLE_REQ;
+ pFwReq->fwHeader.msgLen = message_len;
+ pFwReq->fwHeader.transactionId = id;
+
+ mVendorData = (char*)pFwReq;
+ mDataLen = message_len;
+
+ ret = WIFI_SUCCESS;
+ if (mSubcmd == QCA_NL80211_VENDOR_SUBCMD_NAN) {
+ ret = mMsg.put_bytes(NL80211_ATTR_VENDOR_DATA, mVendorData, mDataLen);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: put_bytes Error:%d",__func__, ret);
+ cleanup();
+ return ret;
+ }
+ } else {
+ struct nlattr *nl_data;
+
+ nl_data = attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nl_data) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ if (mMsg.put_u32(QCA_WLAN_VENDOR_ATTR_NAN_SUBCMD_TYPE,
+ QCA_WLAN_NAN_EXT_SUBCMD_TYPE_DISABLE_REQ) ||
+ mMsg.put_bytes(QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA,
+ mVendorData, mDataLen)) {
+ ALOGE("%s: put attr error", __func__);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ attr_end(nl_data);
+ }
+ hexdump(mVendorData, mDataLen);
+ return ret;
+}
+
+wifi_error NanCommand::putNanConfig(transaction_id id, const NanConfigRequest *pReq)
+{
+ wifi_error ret;
+ ALOGV("NAN_CONFIG");
+ size_t message_len = 0;
+ int idx = 0;
+
+ if (pReq == NULL ||
+ pReq->num_config_discovery_attr > NAN_MAX_POSTDISCOVERY_LEN) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ message_len = sizeof(NanMsgHeader);
+
+ message_len += \
+ (
+ pReq->config_sid_beacon ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->sid_beacon)) : 0 \
+ ) + \
+ (
+ pReq->config_master_pref ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->master_pref)) : 0 \
+ ) + \
+ (
+ pReq->config_rssi_proximity ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->rssi_proximity)) : 0 \
+ ) + \
+ (
+ pReq->config_5g_rssi_close_proximity ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->rssi_close_proximity_5g_val)) : 0 \
+ ) + \
+ (
+ pReq->config_rssi_window_size ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->rssi_window_size_val)) : 0 \
+ ) + \
+ (
+ pReq->config_cluster_attribute_val ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->config_cluster_attribute_val)) : 0 \
+ ) + \
+ (
+ pReq->config_scan_params ? NAN_MAX_SOCIAL_CHANNELS *
+ (SIZEOF_TLV_HDR + sizeof(u32)) : 0 \
+ ) + \
+ (
+ pReq->config_random_factor_force ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->random_factor_force_val)) : 0 \
+ ) + \
+ (
+ pReq->config_hop_count_force ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->hop_count_force_val)) : 0 \
+ ) + \
+ (
+ pReq->config_conn_capability ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ ) + \
+ (
+ pReq->config_dw.config_2dot4g_dw_band ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ ) + \
+ (
+ pReq->config_dw.config_5g_dw_band ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ ) + \
+ (
+ pReq->config_disc_mac_addr_randomization ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ ) + \
+ (
+ pReq->config_subscribe_sid_beacon ? (SIZEOF_TLV_HDR + \
+ sizeof(pReq->subscribe_sid_beacon_val)) : 0 \
+ ) + \
+ (
+ /* Always include cfg discovery indication TLV */
+ SIZEOF_TLV_HDR + sizeof(u32) \
+ ) + \
+ (
+ pReq->config_discovery_beacon_int ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ ) + \
+ (
+ pReq->config_nss ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ ) + \
+ (
+ pReq->config_enable_ranging ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ ) + \
+ (
+ pReq->config_dw_early_termination ? (SIZEOF_TLV_HDR + \
+ sizeof(u32)) : 0 \
+ );
+
+ if (pReq->num_config_discovery_attr) {
+ for (idx = 0; idx < pReq->num_config_discovery_attr; idx ++) {
+ message_len += SIZEOF_TLV_HDR +\
+ calcNanTransmitPostDiscoverySize(&pReq->discovery_attr_val[idx]);
+ }
+ }
+
+ if (pReq->config_fam && \
+ calcNanFurtherAvailabilityMapSize(&pReq->fam_val)) {
+ message_len += (SIZEOF_TLV_HDR + \
+ calcNanFurtherAvailabilityMapSize(&pReq->fam_val));
+ }
+
+ pNanConfigurationReqMsg pFwReq = (pNanConfigurationReqMsg)malloc(message_len);
+ if (pFwReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ ALOGV("Message Len %zu", message_len);
+ memset (pFwReq, 0, message_len);
+ pFwReq->fwHeader.msgVersion = (u16)NAN_MSG_VERSION1;
+ pFwReq->fwHeader.msgId = NAN_MSG_ID_CONFIGURATION_REQ;
+ pFwReq->fwHeader.msgLen = message_len;
+ pFwReq->fwHeader.transactionId = id;
+
+ u8* tlvs = pFwReq->ptlv;
+ if (pReq->config_sid_beacon) {
+ tlvs = addTlv(NAN_TLV_TYPE_SID_BEACON, sizeof(pReq->sid_beacon),
+ (const u8*)&pReq->sid_beacon, tlvs);
+ }
+ if (pReq->config_master_pref) {
+ tlvs = addTlv(NAN_TLV_TYPE_MASTER_PREFERENCE, sizeof(pReq->master_pref),
+ (const u8*)&pReq->master_pref, tlvs);
+ }
+ if (pReq->config_rssi_window_size) {
+ tlvs = addTlv(NAN_TLV_TYPE_RSSI_AVERAGING_WINDOW_SIZE, sizeof(pReq->rssi_window_size_val),
+ (const u8*)&pReq->rssi_window_size_val, tlvs);
+ }
+ if (pReq->config_rssi_proximity) {
+ tlvs = addTlv(NAN_TLV_TYPE_24G_RSSI_CLOSE_PROXIMITY, sizeof(pReq->rssi_proximity),
+ (const u8*)&pReq->rssi_proximity, tlvs);
+ }
+ if (pReq->config_5g_rssi_close_proximity) {
+ tlvs = addTlv(NAN_TLV_TYPE_5G_RSSI_CLOSE_PROXIMITY,
+ sizeof(pReq->rssi_close_proximity_5g_val),
+ (const u8*)&pReq->rssi_close_proximity_5g_val, tlvs);
+ }
+ if (pReq->config_cluster_attribute_val) {
+ tlvs = addTlv(NAN_TLV_TYPE_CLUSTER_ATTRIBUTE_IN_SDF, sizeof(pReq->config_cluster_attribute_val),
+ (const u8*)&pReq->config_cluster_attribute_val, tlvs);
+ }
+ if (pReq->config_scan_params) {
+ u32 socialChannelParamVal[NAN_MAX_SOCIAL_CHANNELS];
+ /* Fill the social channel param */
+ fillNanSocialChannelParamVal(&pReq->scan_params_val,
+ socialChannelParamVal);
+ int i;
+ for (i = 0; i < NAN_MAX_SOCIAL_CHANNELS; i++) {
+ tlvs = addTlv(NAN_TLV_TYPE_SOCIAL_CHANNEL_SCAN_PARAMS,
+ sizeof(socialChannelParamVal[i]),
+ (const u8*)&socialChannelParamVal[i], tlvs);
+ }
+ }
+ if (pReq->config_random_factor_force) {
+ tlvs = addTlv(NAN_TLV_TYPE_RANDOM_FACTOR_FORCE,
+ sizeof(pReq->random_factor_force_val),
+ (const u8*)&pReq->random_factor_force_val, tlvs);
+ }
+ if (pReq->config_hop_count_force) {
+ tlvs = addTlv(NAN_TLV_TYPE_HOP_COUNT_FORCE,
+ sizeof(pReq->hop_count_force_val),
+ (const u8*)&pReq->hop_count_force_val, tlvs);
+ }
+ if (pReq->config_conn_capability) {
+ u32 val = \
+ getNanTransmitPostConnectivityCapabilityVal(&pReq->conn_capability_val);
+ tlvs = addTlv(NAN_TLV_TYPE_POST_NAN_CONNECTIVITY_CAPABILITIES_TRANSMIT,
+ sizeof(val), (const u8*)&val, tlvs);
+ }
+ if (pReq->num_config_discovery_attr) {
+ for (idx = 0; idx < pReq->num_config_discovery_attr; idx ++) {
+ fillNanTransmitPostDiscoveryVal(&pReq->discovery_attr_val[idx],
+ (u8*)(tlvs + SIZEOF_TLV_HDR));
+ tlvs = addTlv(NAN_TLV_TYPE_POST_NAN_DISCOVERY_ATTRIBUTE_TRANSMIT,
+ calcNanTransmitPostDiscoverySize(
+ &pReq->discovery_attr_val[idx]),
+ (const u8*)(tlvs + SIZEOF_TLV_HDR), tlvs);
+ }
+ }
+ if (pReq->config_fam && \
+ calcNanFurtherAvailabilityMapSize(&pReq->fam_val)) {
+ fillNanFurtherAvailabilityMapVal(&pReq->fam_val,
+ (u8*)(tlvs + SIZEOF_TLV_HDR));
+ tlvs = addTlv(NAN_TLV_TYPE_FURTHER_AVAILABILITY_MAP,
+ calcNanFurtherAvailabilityMapSize(&pReq->fam_val),
+ (const u8*)(tlvs + SIZEOF_TLV_HDR), tlvs);
+ }
+ if (pReq->config_dw.config_2dot4g_dw_band) {
+ tlvs = addTlv(NAN_TLV_TYPE_2G_COMMITTED_DW,
+ sizeof(pReq->config_dw.dw_2dot4g_interval_val),
+ (const u8*)&pReq->config_dw.dw_2dot4g_interval_val, tlvs);
+ }
+ if (pReq->config_dw.config_5g_dw_band) {
+ tlvs = addTlv(NAN_TLV_TYPE_5G_COMMITTED_DW,
+ sizeof(pReq->config_dw.dw_5g_interval_val),
+ (const u8*)&pReq->config_dw.dw_5g_interval_val, tlvs);
+ }
+ if (pReq->config_disc_mac_addr_randomization) {
+ tlvs = addTlv(NAN_TLV_TYPE_DISC_MAC_ADDR_RANDOM_INTERVAL,
+ sizeof(u32),
+ (const u8*)&pReq->disc_mac_addr_rand_interval_sec, tlvs);
+ }
+ if (pReq->config_subscribe_sid_beacon) {
+ tlvs = addTlv(NAN_TLV_TYPE_SUBSCRIBE_SID_BEACON,
+ sizeof(pReq->subscribe_sid_beacon_val),
+ (const u8*)&pReq->subscribe_sid_beacon_val, tlvs);
+ }
+ if (pReq->config_discovery_beacon_int) {
+ tlvs = addTlv(NAN_TLV_TYPE_DB_INTERVAL, sizeof(u32),
+ (const u8*)&pReq->discovery_beacon_interval, tlvs);
+ }
+
+ u32 config_discovery_indications;
+ config_discovery_indications = (u32)(pReq->discovery_indication_cfg);
+ /* Save the discovery MAC indication config if it is disabled from the
+ * framework and use it later to decide if the framework to be notified of
+ * the response. And enable the self MAC discovery indication from firmware
+ * by resetting the bit in config to get the Self MAC.
+ */
+ if (config_discovery_indications & NAN_DISC_ADDR_IND_DISABLED) {
+ mNanCommandInstance->mNanDiscAddrIndDisabled = true;
+ config_discovery_indications &= ~NAN_DISC_ADDR_IND_DISABLED;
+ } else {
+ mNanCommandInstance->mNanDiscAddrIndDisabled = false;
+ }
+ /* Always include the discovery cfg TLV as there is no cfg flag */
+ tlvs = addTlv(NAN_TLV_TYPE_CONFIG_DISCOVERY_INDICATIONS,
+ sizeof(u32),
+ (const u8*)&config_discovery_indications, tlvs);
+
+ if (pReq->config_nss) {
+ tlvs = addTlv(NAN_TLV_TYPE_TX_RX_CHAINS, sizeof(u32),
+ (const u8*)&pReq->nss, tlvs);
+ }
+ if (pReq->config_enable_ranging) {
+ tlvs = addTlv(NAN_TLV_TYPE_ENABLE_DEVICE_RANGING, sizeof(u32),
+ (const u8*)&pReq->enable_ranging, tlvs);
+ }
+ if (pReq->config_dw_early_termination) {
+ tlvs = addTlv(NAN_TLV_TYPE_DW_EARLY_TERMINATION, sizeof(u32),
+ (const u8*)&pReq->enable_dw_termination, tlvs);
+ }
+
+ mVendorData = (char*)pFwReq;
+ mDataLen = message_len;
+
+ ret = WIFI_SUCCESS;
+ if (mSubcmd == QCA_NL80211_VENDOR_SUBCMD_NAN) {
+ ret = mMsg.put_bytes(NL80211_ATTR_VENDOR_DATA, mVendorData, mDataLen);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: put_bytes Error:%d",__func__, ret);
+ cleanup();
+ return ret;
+ }
+ } else {
+ struct nlattr *nl_data;
+
+ nl_data = attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nl_data) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ if (mMsg.put_bytes(QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA,
+ mVendorData, mDataLen)) {
+ ALOGE("%s: put attr error", __func__);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ attr_end(nl_data);
+ }
+ hexdump(mVendorData, mDataLen);
+ return ret;
+}
+
+wifi_error NanCommand::putNanPublish(transaction_id id, const NanPublishRequest *pReq)
+{
+ wifi_error ret;
+ ALOGV("NAN_PUBLISH");
+ if (pReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ size_t message_len =
+ sizeof(NanMsgHeader) + sizeof(NanPublishServiceReqParams) +
+ (pReq->service_name_len ? SIZEOF_TLV_HDR + pReq->service_name_len : 0) +
+ (pReq->service_specific_info_len ? SIZEOF_TLV_HDR + pReq->service_specific_info_len : 0) +
+ (pReq->rx_match_filter_len ? SIZEOF_TLV_HDR + pReq->rx_match_filter_len : 0) +
+ (pReq->tx_match_filter_len ? SIZEOF_TLV_HDR + pReq->tx_match_filter_len : 0) +
+ (SIZEOF_TLV_HDR + sizeof(NanServiceAcceptPolicy)) +
+ (pReq->cipher_type ? SIZEOF_TLV_HDR + sizeof(NanCsidType) : 0) +
+ ((pReq->sdea_params.config_nan_data_path || pReq->sdea_params.security_cfg ||
+ pReq->sdea_params.ranging_state || pReq->sdea_params.range_report ||
+ pReq->sdea_params.qos_cfg) ?
+ SIZEOF_TLV_HDR + sizeof(NanFWSdeaCtrlParams) : 0) +
+ ((pReq->ranging_cfg.ranging_interval_msec || pReq->ranging_cfg.config_ranging_indications ||
+ pReq->ranging_cfg.distance_ingress_mm || pReq->ranging_cfg.distance_egress_mm) ?
+ SIZEOF_TLV_HDR + sizeof(NanFWRangeConfigParams) : 0) +
+ ((pReq->range_response_cfg.publish_id ||
+ pReq->range_response_cfg.ranging_response) ?
+ SIZEOF_TLV_HDR + sizeof(NanFWRangeReqMsg) : 0) +
+ (pReq->sdea_service_specific_info_len ? SIZEOF_TLV_HDR + pReq->sdea_service_specific_info_len : 0);
+
+ if ((pReq->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK) &&
+ (pReq->key_info.body.pmk_info.pmk_len == NAN_PMK_INFO_LEN))
+ message_len += SIZEOF_TLV_HDR + NAN_PMK_INFO_LEN;
+ else if ((pReq->key_info.key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE) &&
+ (pReq->key_info.body.passphrase_info.passphrase_len >=
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) &&
+ (pReq->key_info.body.passphrase_info.passphrase_len <=
+ NAN_SECURITY_MAX_PASSPHRASE_LEN))
+ message_len += SIZEOF_TLV_HDR +
+ pReq->key_info.body.passphrase_info.passphrase_len;
+
+ pNanPublishServiceReqMsg pFwReq = (pNanPublishServiceReqMsg)malloc(message_len);
+ if (pFwReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ ALOGV("Message Len %zu", message_len);
+ memset(pFwReq, 0, message_len);
+ pFwReq->fwHeader.msgVersion = (u16)NAN_MSG_VERSION1;
+ pFwReq->fwHeader.msgId = NAN_MSG_ID_PUBLISH_SERVICE_REQ;
+ pFwReq->fwHeader.msgLen = message_len;
+ if (pReq->publish_id == 0) {
+ pFwReq->fwHeader.handle = 0xFFFF;
+ } else {
+ pFwReq->fwHeader.handle = (pReq->publish_id & 0xFF);
+ }
+ pFwReq->fwHeader.transactionId = id;
+
+ pFwReq->publishServiceReqParams.ttl = pReq->ttl;
+ pFwReq->publishServiceReqParams.period = pReq->period;
+ pFwReq->publishServiceReqParams.replyIndFlag =
+ (pReq->recv_indication_cfg & BIT_3) ? 0 : 1;
+ pFwReq->publishServiceReqParams.publishType = pReq->publish_type;
+ pFwReq->publishServiceReqParams.txType = pReq->tx_type;
+
+ pFwReq->publishServiceReqParams.rssiThresholdFlag = pReq->rssi_threshold_flag;
+ pFwReq->publishServiceReqParams.matchAlg = pReq->publish_match_indicator;
+ pFwReq->publishServiceReqParams.count = pReq->publish_count;
+ pFwReq->publishServiceReqParams.connmap = pReq->connmap;
+ pFwReq->publishServiceReqParams.pubTerminatedIndDisableFlag =
+ (pReq->recv_indication_cfg & BIT_0) ? 1 : 0;
+ pFwReq->publishServiceReqParams.pubMatchExpiredIndDisableFlag =
+ (pReq->recv_indication_cfg & BIT_1) ? 1 : 0;
+ pFwReq->publishServiceReqParams.followupRxIndDisableFlag =
+ (pReq->recv_indication_cfg & BIT_2) ? 1 : 0;
+
+ pFwReq->publishServiceReqParams.reserved2 = 0;
+
+ u8* tlvs = pFwReq->ptlv;
+ if (pReq->service_name_len) {
+ tlvs = addTlv(NAN_TLV_TYPE_SERVICE_NAME, pReq->service_name_len,
+ (const u8*)&pReq->service_name[0], tlvs);
+ }
+ if (pReq->service_specific_info_len) {
+ tlvs = addTlv(NAN_TLV_TYPE_SERVICE_SPECIFIC_INFO, pReq->service_specific_info_len,
+ (const u8*)&pReq->service_specific_info[0], tlvs);
+ }
+ if (pReq->rx_match_filter_len) {
+ tlvs = addTlv(NAN_TLV_TYPE_RX_MATCH_FILTER, pReq->rx_match_filter_len,
+ (const u8*)&pReq->rx_match_filter[0], tlvs);
+ }
+ if (pReq->tx_match_filter_len) {
+ tlvs = addTlv(NAN_TLV_TYPE_TX_MATCH_FILTER, pReq->tx_match_filter_len,
+ (const u8*)&pReq->tx_match_filter[0], tlvs);
+ }
+
+ /* Pass the Accept policy always */
+ tlvs = addTlv(NAN_TLV_TYPE_NAN_SERVICE_ACCEPT_POLICY, sizeof(NanServiceAcceptPolicy),
+ (const u8*)&pReq->service_responder_policy, tlvs);
+
+ if (pReq->cipher_type) {
+ NanCsidType pNanCsidType;
+ pNanCsidType.csid_type = pReq->cipher_type;
+ tlvs = addTlv(NAN_TLV_TYPE_NAN_CSID, sizeof(NanCsidType),
+ (const u8*)&pNanCsidType, tlvs);
+ }
+
+ if ((pReq->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK) &&
+ (pReq->key_info.body.pmk_info.pmk_len == NAN_PMK_INFO_LEN)) {
+ tlvs = addTlv(NAN_TLV_TYPE_NAN_PMK,
+ pReq->key_info.body.pmk_info.pmk_len,
+ (const u8*)&pReq->key_info.body.pmk_info.pmk[0], tlvs);
+ } else if ((pReq->key_info.key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE) &&
+ (pReq->key_info.body.passphrase_info.passphrase_len >=
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) &&
+ (pReq->key_info.body.passphrase_info.passphrase_len <=
+ NAN_SECURITY_MAX_PASSPHRASE_LEN)) {
+ tlvs = addTlv(NAN_TLV_TYPE_NAN_PASSPHRASE,
+ pReq->key_info.body.passphrase_info.passphrase_len,
+ (const u8*)&pReq->key_info.body.passphrase_info.passphrase[0],
+ tlvs);
+ }
+
+ if (pReq->sdea_params.config_nan_data_path ||
+ pReq->sdea_params.security_cfg ||
+ pReq->sdea_params.ranging_state ||
+ pReq->sdea_params.range_report ||
+ pReq->sdea_params.qos_cfg) {
+ NanFWSdeaCtrlParams pNanFWSdeaCtrlParams;
+ memset(&pNanFWSdeaCtrlParams, 0, sizeof(NanFWSdeaCtrlParams));
+
+ if (pReq->sdea_params.config_nan_data_path) {
+ pNanFWSdeaCtrlParams.data_path_required = 1;
+ pNanFWSdeaCtrlParams.data_path_type =
+ (pReq->sdea_params.ndp_type & BIT_0) ?
+ NAN_DATA_PATH_MULTICAST_MSG :
+ NAN_DATA_PATH_UNICAST_MSG;
+
+ }
+ if (pReq->sdea_params.security_cfg) {
+ pNanFWSdeaCtrlParams.security_required =
+ pReq->sdea_params.security_cfg;
+ }
+ if (pReq->sdea_params.ranging_state) {
+ pNanFWSdeaCtrlParams.ranging_required =
+ pReq->sdea_params.ranging_state;
+ }
+ if (pReq->sdea_params.range_report) {
+ pNanFWSdeaCtrlParams.range_report =
+ (((pReq->sdea_params.range_report & NAN_ENABLE_RANGE_REPORT) >> 1) ? 1 : 0);
+ }
+ if (pReq->sdea_params.qos_cfg) {
+ pNanFWSdeaCtrlParams.qos_required = pReq->sdea_params.qos_cfg;
+ }
+ tlvs = addTlv(NAN_TLV_TYPE_SDEA_CTRL_PARAMS, sizeof(NanFWSdeaCtrlParams),
+ (const u8*)&pNanFWSdeaCtrlParams, tlvs);
+ }
+
+ if (pReq->ranging_cfg.ranging_interval_msec ||
+ pReq->ranging_cfg.config_ranging_indications ||
+ pReq->ranging_cfg.distance_ingress_mm ||
+ pReq->ranging_cfg.distance_egress_mm) {
+ NanFWRangeConfigParams pNanFWRangingCfg;
+
+ memset(&pNanFWRangingCfg, 0, sizeof(NanFWRangeConfigParams));
+ pNanFWRangingCfg.range_interval =
+ pReq->ranging_cfg.ranging_interval_msec;
+ pNanFWRangingCfg.ranging_indication_event =
+ ((pReq->ranging_cfg.config_ranging_indications & NAN_RANGING_INDICATE_CONTINUOUS_MASK) |
+ (pReq->ranging_cfg.config_ranging_indications & NAN_RANGING_INDICATE_INGRESS_MET_MASK) |
+ (pReq->ranging_cfg.config_ranging_indications & NAN_RANGING_INDICATE_EGRESS_MET_MASK));
+
+ pNanFWRangingCfg.ranging_indication_event = pReq->ranging_cfg.config_ranging_indications;
+ if (pReq->ranging_cfg.config_ranging_indications & NAN_RANGING_INDICATE_INGRESS_MET_MASK)
+ pNanFWRangingCfg.geo_fence_threshold.inner_threshold =
+ pReq->ranging_cfg.distance_ingress_mm;
+ if (pReq->ranging_cfg.config_ranging_indications & NAN_RANGING_INDICATE_EGRESS_MET_MASK)
+ pNanFWRangingCfg.geo_fence_threshold.outer_threshold =
+ pReq->ranging_cfg.distance_egress_mm;
+ tlvs = addTlv(NAN_TLV_TYPE_NAN_RANGING_CFG, sizeof(NanFWRangeConfigParams),
+ (const u8*)&pNanFWRangingCfg, tlvs);
+ }
+
+ if (pReq->sdea_service_specific_info_len) {
+ tlvs = addTlv(NAN_TLV_TYPE_SDEA_SERVICE_SPECIFIC_INFO, pReq->sdea_service_specific_info_len,
+ (const u8*)&pReq->sdea_service_specific_info[0], tlvs);
+ }
+
+ if (pReq->range_response_cfg.publish_id || pReq->range_response_cfg.ranging_response) {
+
+ NanFWRangeReqMsg pNanFWRangeReqMsg;
+ memset(&pNanFWRangeReqMsg, 0, sizeof(NanFWRangeReqMsg));
+ pNanFWRangeReqMsg.range_id =
+ (u16)pReq->range_response_cfg.publish_id;
+ CHAR_ARRAY_TO_MAC_ADDR(pReq->range_response_cfg.peer_addr, pNanFWRangeReqMsg.range_mac_addr);
+ pNanFWRangeReqMsg.ranging_accept =
+ ((pReq->range_response_cfg.ranging_response == NAN_RANGE_REQUEST_ACCEPT) ? 1 : 0);
+ pNanFWRangeReqMsg.ranging_reject =
+ ((pReq->range_response_cfg.ranging_response == NAN_RANGE_REQUEST_REJECT) ? 1 : 0);
+ pNanFWRangeReqMsg.ranging_cancel =
+ ((pReq->range_response_cfg.ranging_response == NAN_RANGE_REQUEST_CANCEL) ? 1 : 0);
+ tlvs = addTlv(NAN_TLV_TYPE_NAN20_RANGING_REQUEST, sizeof(NanFWRangeReqMsg),
+ (const u8*)&pNanFWRangeReqMsg, tlvs);
+ }
+
+ mVendorData = (char *)pFwReq;
+ mDataLen = message_len;
+
+ ret = WIFI_SUCCESS;
+ if (mSubcmd == QCA_NL80211_VENDOR_SUBCMD_NAN) {
+ ret = mMsg.put_bytes(NL80211_ATTR_VENDOR_DATA, mVendorData, mDataLen);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: put_bytes Error:%d",__func__, ret);
+ cleanup();
+ return ret;
+ }
+ } else {
+ struct nlattr *nl_data;
+
+ nl_data = attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nl_data) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ if (mMsg.put_bytes(QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA,
+ mVendorData, mDataLen)) {
+ ALOGE("%s: put attr error", __func__);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ attr_end(nl_data);
+ }
+ hexdump(mVendorData, mDataLen);
+ return ret;
+}
+
+wifi_error NanCommand::putNanPublishCancel(transaction_id id, const NanPublishCancelRequest *pReq)
+{
+ wifi_error ret;
+ ALOGV("NAN_PUBLISH_CANCEL");
+ if (pReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ size_t message_len = sizeof(NanPublishServiceCancelReqMsg);
+
+ pNanPublishServiceCancelReqMsg pFwReq =
+ (pNanPublishServiceCancelReqMsg)malloc(message_len);
+ if (pFwReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ ALOGV("Message Len %zu", message_len);
+ memset(pFwReq, 0, message_len);
+ pFwReq->fwHeader.msgVersion = (u16)NAN_MSG_VERSION1;
+ pFwReq->fwHeader.msgId = NAN_MSG_ID_PUBLISH_SERVICE_CANCEL_REQ;
+ pFwReq->fwHeader.msgLen = message_len;
+ pFwReq->fwHeader.handle = (pReq->publish_id & 0xFF);
+ pFwReq->fwHeader.transactionId = id;
+
+ mVendorData = (char *)pFwReq;
+ mDataLen = message_len;
+
+ ret = WIFI_SUCCESS;
+ if (mSubcmd == QCA_NL80211_VENDOR_SUBCMD_NAN) {
+ ret = mMsg.put_bytes(NL80211_ATTR_VENDOR_DATA, mVendorData, mDataLen);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: put_bytes Error:%d",__func__, ret);
+ cleanup();
+ return ret;
+ }
+ } else {
+ struct nlattr *nl_data;
+
+ nl_data = attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nl_data) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ if (mMsg.put_bytes(QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA,
+ mVendorData, mDataLen)) {
+ ALOGE("%s: put attr error", __func__);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ attr_end(nl_data);
+ }
+ hexdump(mVendorData, mDataLen);
+ return ret;
+}
+
+wifi_error NanCommand::putNanSubscribe(transaction_id id,
+ const NanSubscribeRequest *pReq)
+{
+ wifi_error ret;
+
+ ALOGV("NAN_SUBSCRIBE");
+ if (pReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ size_t message_len =
+ sizeof(NanMsgHeader) + sizeof(NanSubscribeServiceReqParams) +
+ (pReq->service_name_len ? SIZEOF_TLV_HDR + pReq->service_name_len : 0) +
+ (pReq->service_specific_info_len ? SIZEOF_TLV_HDR + pReq->service_specific_info_len : 0) +
+ (pReq->rx_match_filter_len ? SIZEOF_TLV_HDR + pReq->rx_match_filter_len : 0) +
+ (pReq->tx_match_filter_len ? SIZEOF_TLV_HDR + pReq->tx_match_filter_len : 0) +
+ (pReq->cipher_type ? SIZEOF_TLV_HDR + sizeof(NanCsidType) : 0) +
+ ((pReq->sdea_params.config_nan_data_path || pReq->sdea_params.security_cfg ||
+ pReq->sdea_params.ranging_state || pReq->sdea_params.range_report ||
+ pReq->sdea_params.qos_cfg) ?
+ SIZEOF_TLV_HDR + sizeof(NanFWSdeaCtrlParams) : 0) +
+ ((pReq->ranging_cfg.ranging_interval_msec || pReq->ranging_cfg.config_ranging_indications ||
+ pReq->ranging_cfg.distance_ingress_mm || pReq->ranging_cfg.distance_egress_mm) ?
+ SIZEOF_TLV_HDR + sizeof(NanFWRangeConfigParams) : 0) +
+ ((pReq->range_response_cfg.requestor_instance_id ||
+ pReq->range_response_cfg.ranging_response) ?
+ SIZEOF_TLV_HDR + sizeof(NanFWRangeReqMsg) : 0) +
+ (pReq->sdea_service_specific_info_len ? SIZEOF_TLV_HDR + pReq->sdea_service_specific_info_len : 0);
+
+ message_len += \
+ (pReq->num_intf_addr_present * (SIZEOF_TLV_HDR + NAN_MAC_ADDR_LEN));
+
+
+ if ((pReq->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK) &&
+ (pReq->key_info.body.pmk_info.pmk_len == NAN_PMK_INFO_LEN))
+ message_len += SIZEOF_TLV_HDR + NAN_PMK_INFO_LEN;
+ else if ((pReq->key_info.key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE) &&
+ (pReq->key_info.body.passphrase_info.passphrase_len >=
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) &&
+ (pReq->key_info.body.passphrase_info.passphrase_len <=
+ NAN_SECURITY_MAX_PASSPHRASE_LEN))
+ message_len += SIZEOF_TLV_HDR +
+ pReq->key_info.body.passphrase_info.passphrase_len;
+
+
+ pNanSubscribeServiceReqMsg pFwReq = (pNanSubscribeServiceReqMsg)malloc(message_len);
+ if (pFwReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ ALOGV("Message Len %zu", message_len);
+ memset(pFwReq, 0, message_len);
+ pFwReq->fwHeader.msgVersion = (u16)NAN_MSG_VERSION1;
+ pFwReq->fwHeader.msgId = NAN_MSG_ID_SUBSCRIBE_SERVICE_REQ;
+ pFwReq->fwHeader.msgLen = message_len;
+ if (pReq->subscribe_id == 0) {
+ pFwReq->fwHeader.handle = 0xFFFF;
+ } else {
+ pFwReq->fwHeader.handle = (pReq->subscribe_id & 0xFF);
+ }
+ pFwReq->fwHeader.transactionId = id;
+
+ pFwReq->subscribeServiceReqParams.ttl = pReq->ttl;
+ pFwReq->subscribeServiceReqParams.period = pReq->period;
+ pFwReq->subscribeServiceReqParams.subscribeType = pReq->subscribe_type;
+ pFwReq->subscribeServiceReqParams.srfAttr = pReq->serviceResponseFilter;
+ pFwReq->subscribeServiceReqParams.srfInclude = pReq->serviceResponseInclude;
+ pFwReq->subscribeServiceReqParams.srfSend = pReq->useServiceResponseFilter;
+ pFwReq->subscribeServiceReqParams.ssiRequired = pReq->ssiRequiredForMatchIndication;
+ pFwReq->subscribeServiceReqParams.matchAlg = pReq->subscribe_match_indicator;
+ pFwReq->subscribeServiceReqParams.count = pReq->subscribe_count;
+ pFwReq->subscribeServiceReqParams.rssiThresholdFlag = pReq->rssi_threshold_flag;
+ pFwReq->subscribeServiceReqParams.subTerminatedIndDisableFlag =
+ (pReq->recv_indication_cfg & BIT_0) ? 1 : 0;
+ pFwReq->subscribeServiceReqParams.subMatchExpiredIndDisableFlag =
+ (pReq->recv_indication_cfg & BIT_1) ? 1 : 0;
+ pFwReq->subscribeServiceReqParams.followupRxIndDisableFlag =
+ (pReq->recv_indication_cfg & BIT_2) ? 1 : 0;
+ pFwReq->subscribeServiceReqParams.connmap = pReq->connmap;
+ pFwReq->subscribeServiceReqParams.reserved = 0;
+
+ u8* tlvs = pFwReq->ptlv;
+ if (pReq->service_name_len) {
+ tlvs = addTlv(NAN_TLV_TYPE_SERVICE_NAME, pReq->service_name_len,
+ (const u8*)&pReq->service_name[0], tlvs);
+ }
+ if (pReq->service_specific_info_len) {
+ tlvs = addTlv(NAN_TLV_TYPE_SERVICE_SPECIFIC_INFO, pReq->service_specific_info_len,
+ (const u8*)&pReq->service_specific_info[0], tlvs);
+ }
+ if (pReq->rx_match_filter_len) {
+ tlvs = addTlv(NAN_TLV_TYPE_RX_MATCH_FILTER, pReq->rx_match_filter_len,
+ (const u8*)&pReq->rx_match_filter[0], tlvs);
+ }
+ if (pReq->tx_match_filter_len) {
+ tlvs = addTlv(NAN_TLV_TYPE_TX_MATCH_FILTER, pReq->tx_match_filter_len,
+ (const u8*)&pReq->tx_match_filter[0], tlvs);
+ }
+
+ int i = 0;
+ for (i = 0; i < pReq->num_intf_addr_present; i++)
+ {
+ tlvs = addTlv(NAN_TLV_TYPE_MAC_ADDRESS,
+ NAN_MAC_ADDR_LEN,
+ (const u8*)&pReq->intf_addr[i][0], tlvs);
+ }
+
+ if (pReq->cipher_type) {
+ NanCsidType pNanCsidType;
+ pNanCsidType.csid_type = pReq->cipher_type;
+ tlvs = addTlv(NAN_TLV_TYPE_NAN_CSID, sizeof(NanCsidType),
+ (const u8*)&pNanCsidType, tlvs);
+ }
+
+ if ((pReq->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK) &&
+ (pReq->key_info.body.pmk_info.pmk_len == NAN_PMK_INFO_LEN)) {
+ tlvs = addTlv(NAN_TLV_TYPE_NAN_PMK,
+ pReq->key_info.body.pmk_info.pmk_len,
+ (const u8*)&pReq->key_info.body.pmk_info.pmk[0], tlvs);
+ } else if ((pReq->key_info.key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE) &&
+ (pReq->key_info.body.passphrase_info.passphrase_len >=
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) &&
+ (pReq->key_info.body.passphrase_info.passphrase_len <=
+ NAN_SECURITY_MAX_PASSPHRASE_LEN)) {
+ tlvs = addTlv(NAN_TLV_TYPE_NAN_PASSPHRASE,
+ pReq->key_info.body.passphrase_info.passphrase_len,
+ (const u8*)&pReq->key_info.body.passphrase_info.passphrase[0],
+ tlvs);
+ }
+
+ if (pReq->sdea_params.config_nan_data_path ||
+ pReq->sdea_params.security_cfg ||
+ pReq->sdea_params.ranging_state ||
+ pReq->sdea_params.range_report ||
+ pReq->sdea_params.qos_cfg) {
+ NanFWSdeaCtrlParams pNanFWSdeaCtrlParams;
+ memset(&pNanFWSdeaCtrlParams, 0, sizeof(NanFWSdeaCtrlParams));
+
+ if (pReq->sdea_params.config_nan_data_path) {
+ pNanFWSdeaCtrlParams.data_path_required = 1;
+ pNanFWSdeaCtrlParams.data_path_type =
+ (pReq->sdea_params.ndp_type & BIT_0) ?
+ NAN_DATA_PATH_MULTICAST_MSG :
+ NAN_DATA_PATH_UNICAST_MSG;
+
+ }
+ if (pReq->sdea_params.security_cfg) {
+ pNanFWSdeaCtrlParams.security_required =
+ pReq->sdea_params.security_cfg;
+ }
+ if (pReq->sdea_params.ranging_state) {
+ pNanFWSdeaCtrlParams.ranging_required =
+ pReq->sdea_params.ranging_state;
+ }
+ if (pReq->sdea_params.range_report) {
+ pNanFWSdeaCtrlParams.range_report =
+ ((pReq->sdea_params.range_report & NAN_ENABLE_RANGE_REPORT >> 1) ? 1 : 0);
+ }
+ if (pReq->sdea_params.qos_cfg) {
+ pNanFWSdeaCtrlParams.qos_required = pReq->sdea_params.qos_cfg;
+ }
+ tlvs = addTlv(NAN_TLV_TYPE_SDEA_CTRL_PARAMS, sizeof(NanFWSdeaCtrlParams),
+ (const u8*)&pNanFWSdeaCtrlParams, tlvs);
+
+ }
+
+ if (pReq->ranging_cfg.ranging_interval_msec || pReq->ranging_cfg.config_ranging_indications || pReq->ranging_cfg.distance_ingress_mm
+ || pReq->ranging_cfg.distance_egress_mm) {
+ NanFWRangeConfigParams pNanFWRangingCfg;
+ memset(&pNanFWRangingCfg, 0, sizeof(NanFWRangeConfigParams));
+ pNanFWRangingCfg.range_interval =
+ pReq->ranging_cfg.ranging_interval_msec;
+ pNanFWRangingCfg.ranging_indication_event =
+ ((pReq->ranging_cfg.config_ranging_indications & NAN_RANGING_INDICATE_CONTINUOUS_MASK) |
+ (pReq->ranging_cfg.config_ranging_indications & NAN_RANGING_INDICATE_INGRESS_MET_MASK) |
+ (pReq->ranging_cfg.config_ranging_indications & NAN_RANGING_INDICATE_EGRESS_MET_MASK));
+
+ pNanFWRangingCfg.ranging_indication_event =
+ pReq->ranging_cfg.config_ranging_indications;
+ if (pReq->ranging_cfg.config_ranging_indications & NAN_RANGING_INDICATE_INGRESS_MET_MASK)
+ pNanFWRangingCfg.geo_fence_threshold.inner_threshold =
+ pReq->ranging_cfg.distance_ingress_mm;
+ if (pReq->ranging_cfg.config_ranging_indications & NAN_RANGING_INDICATE_EGRESS_MET_MASK)
+ pNanFWRangingCfg.geo_fence_threshold.outer_threshold =
+ pReq->ranging_cfg.distance_egress_mm;
+ tlvs = addTlv(NAN_TLV_TYPE_NAN_RANGING_CFG, sizeof(NanFWRangeConfigParams),
+ (const u8*)&pNanFWRangingCfg, tlvs);
+ }
+
+ if (pReq->sdea_service_specific_info_len) {
+ tlvs = addTlv(NAN_TLV_TYPE_SDEA_SERVICE_SPECIFIC_INFO, pReq->sdea_service_specific_info_len,
+ (const u8*)&pReq->sdea_service_specific_info[0], tlvs);
+ }
+
+ if (pReq->range_response_cfg.requestor_instance_id || pReq->range_response_cfg.ranging_response) {
+ NanFWRangeReqMsg pNanFWRangeReqMsg;
+ memset(&pNanFWRangeReqMsg, 0, sizeof(NanFWRangeReqMsg));
+ pNanFWRangeReqMsg.range_id =
+ pReq->range_response_cfg.requestor_instance_id;
+ memcpy(&pNanFWRangeReqMsg.range_mac_addr, &pReq->range_response_cfg.peer_addr, NAN_MAC_ADDR_LEN);
+ pNanFWRangeReqMsg.ranging_accept =
+ ((pReq->range_response_cfg.ranging_response == NAN_RANGE_REQUEST_ACCEPT) ? 1 : 0);
+ pNanFWRangeReqMsg.ranging_reject =
+ ((pReq->range_response_cfg.ranging_response == NAN_RANGE_REQUEST_REJECT) ? 1 : 0);
+ pNanFWRangeReqMsg.ranging_cancel =
+ ((pReq->range_response_cfg.ranging_response == NAN_RANGE_REQUEST_CANCEL) ? 1 : 0);
+ tlvs = addTlv(NAN_TLV_TYPE_NAN20_RANGING_REQUEST, sizeof(NanFWRangeReqMsg),
+ (const u8*)&pNanFWRangeReqMsg, tlvs);
+ }
+
+ mVendorData = (char *)pFwReq;
+ mDataLen = message_len;
+ ret = WIFI_SUCCESS;
+ if (mSubcmd == QCA_NL80211_VENDOR_SUBCMD_NAN) {
+ ret = mMsg.put_bytes(NL80211_ATTR_VENDOR_DATA, mVendorData, mDataLen);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: put_bytes Error:%d",__func__, ret);
+ cleanup();
+ return ret;
+ }
+ } else {
+ struct nlattr *nl_data;
+
+ nl_data = attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nl_data) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ if (mMsg.put_bytes(QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA,
+ mVendorData, mDataLen)) {
+ ALOGE("%s: put attr error", __func__);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ attr_end(nl_data);
+ }
+ hexdump(mVendorData, mDataLen);
+ return ret;
+}
+
+wifi_error NanCommand::putNanSubscribeCancel(transaction_id id,
+ const NanSubscribeCancelRequest *pReq)
+{
+ wifi_error ret;
+ ALOGV("NAN_SUBSCRIBE_CANCEL");
+ if (pReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ size_t message_len = sizeof(NanSubscribeServiceCancelReqMsg);
+
+ pNanSubscribeServiceCancelReqMsg pFwReq =
+ (pNanSubscribeServiceCancelReqMsg)malloc(message_len);
+ if (pFwReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ ALOGV("Message Len %zu", message_len);
+ memset(pFwReq, 0, message_len);
+ pFwReq->fwHeader.msgVersion = (u16)NAN_MSG_VERSION1;
+ pFwReq->fwHeader.msgId = NAN_MSG_ID_SUBSCRIBE_SERVICE_CANCEL_REQ;
+ pFwReq->fwHeader.msgLen = message_len;
+ pFwReq->fwHeader.handle = (pReq->subscribe_id & 0xFF);
+ pFwReq->fwHeader.transactionId = id;
+
+ mVendorData = (char *)pFwReq;
+ mDataLen = message_len;
+ ret = WIFI_SUCCESS;
+ if (mSubcmd == QCA_NL80211_VENDOR_SUBCMD_NAN) {
+ ret = mMsg.put_bytes(NL80211_ATTR_VENDOR_DATA, mVendorData, mDataLen);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: put_bytes Error:%d",__func__, ret);
+ cleanup();
+ return ret;
+ }
+ } else {
+ struct nlattr *nl_data;
+
+ nl_data = attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nl_data) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ if (mMsg.put_bytes(QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA,
+ mVendorData, mDataLen)) {
+ ALOGE("%s: put attr error", __func__);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ attr_end(nl_data);
+ }
+ hexdump(mVendorData, mDataLen);
+ return ret;
+}
+
+wifi_error NanCommand::putNanTransmitFollowup(transaction_id id,
+ const NanTransmitFollowupRequest *pReq)
+{
+ wifi_error ret;
+ ALOGV("TRANSMIT_FOLLOWUP");
+ if (pReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ size_t message_len =
+ sizeof(NanMsgHeader) + sizeof(NanTransmitFollowupReqParams) +
+ (pReq->service_specific_info_len ? SIZEOF_TLV_HDR +
+ pReq->service_specific_info_len : 0) +
+ (pReq->sdea_service_specific_info_len ? SIZEOF_TLV_HDR + pReq->sdea_service_specific_info_len : 0);
+
+ /* Mac address needs to be added in TLV */
+ message_len += (SIZEOF_TLV_HDR + sizeof(pReq->addr));
+
+ pNanTransmitFollowupReqMsg pFwReq = (pNanTransmitFollowupReqMsg)malloc(message_len);
+ if (pFwReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ ALOGV("Message Len %zu", message_len);
+ memset (pFwReq, 0, message_len);
+ pFwReq->fwHeader.msgVersion = (u16)NAN_MSG_VERSION1;
+ pFwReq->fwHeader.msgId = NAN_MSG_ID_TRANSMIT_FOLLOWUP_REQ;
+ pFwReq->fwHeader.msgLen = message_len;
+ pFwReq->fwHeader.handle = (pReq->publish_subscribe_id & 0xFF);
+ pFwReq->fwHeader.transactionId = id;
+
+ pFwReq->transmitFollowupReqParams.matchHandle = pReq->requestor_instance_id;
+ if (pReq->priority != NAN_TX_PRIORITY_HIGH) {
+ pFwReq->transmitFollowupReqParams.priority = 1;
+ } else {
+ pFwReq->transmitFollowupReqParams.priority = 2;
+ }
+ pFwReq->transmitFollowupReqParams.window = pReq->dw_or_faw;
+ pFwReq->transmitFollowupReqParams.followupTxRspDisableFlag =
+ (pReq->recv_indication_cfg & BIT_0) ? 1 : 0;
+ pFwReq->transmitFollowupReqParams.reserved = 0;
+
+ u8* tlvs = pFwReq->ptlv;
+
+ /* Mac address needs to be added in TLV */
+ tlvs = addTlv(NAN_TLV_TYPE_MAC_ADDRESS, sizeof(pReq->addr),
+ (const u8*)&pReq->addr[0], tlvs);
+ u16 tlv_type = NAN_TLV_TYPE_SERVICE_SPECIFIC_INFO;
+
+ if (pReq->service_specific_info_len) {
+ tlvs = addTlv(tlv_type, pReq->service_specific_info_len,
+ (const u8*)&pReq->service_specific_info[0], tlvs);
+ }
+
+ if (pReq->sdea_service_specific_info_len) {
+ tlvs = addTlv(NAN_TLV_TYPE_SDEA_SERVICE_SPECIFIC_INFO, pReq->sdea_service_specific_info_len,
+ (const u8*)&pReq->sdea_service_specific_info[0], tlvs);
+ }
+
+ mVendorData = (char *)pFwReq;
+ mDataLen = message_len;
+
+ ret = WIFI_SUCCESS;
+ if (mSubcmd == QCA_NL80211_VENDOR_SUBCMD_NAN) {
+ ret = mMsg.put_bytes(NL80211_ATTR_VENDOR_DATA, mVendorData, mDataLen);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: put_bytes Error:%d",__func__, ret);
+ cleanup();
+ return ret;
+ }
+ } else {
+ struct nlattr *nl_data;
+
+ nl_data = attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nl_data) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ if (mMsg.put_bytes(QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA,
+ mVendorData, mDataLen)) {
+ ALOGE("%s: put attr error", __func__);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ attr_end(nl_data);
+ }
+ hexdump(mVendorData, mDataLen);
+ return ret;
+}
+
+wifi_error NanCommand::putNanStats(transaction_id id, const NanStatsRequest *pReq)
+{
+ wifi_error ret;
+ ALOGV("NAN_STATS");
+ if (pReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ size_t message_len = sizeof(NanStatsReqMsg);
+
+ pNanStatsReqMsg pFwReq =
+ (pNanStatsReqMsg)malloc(message_len);
+ if (pFwReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ ALOGV("Message Len %zu", message_len);
+ memset(pFwReq, 0, message_len);
+ pFwReq->fwHeader.msgVersion = (u16)NAN_MSG_VERSION1;
+ pFwReq->fwHeader.msgId = NAN_MSG_ID_STATS_REQ;
+ pFwReq->fwHeader.msgLen = message_len;
+ pFwReq->fwHeader.transactionId = id;
+
+ pFwReq->statsReqParams.statsType = pReq->stats_type;
+ pFwReq->statsReqParams.clear = pReq->clear;
+ pFwReq->statsReqParams.reserved = 0;
+
+ mVendorData = (char *)pFwReq;
+ mDataLen = message_len;
+
+ ret = WIFI_SUCCESS;
+ if (mSubcmd == QCA_NL80211_VENDOR_SUBCMD_NAN) {
+ ret = mMsg.put_bytes(NL80211_ATTR_VENDOR_DATA, mVendorData, mDataLen);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: put_bytes Error:%d",__func__, ret);
+ cleanup();
+ return ret;
+ }
+ } else {
+ struct nlattr *nl_data;
+
+ nl_data = attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nl_data) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ if (mMsg.put_bytes(QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA,
+ mVendorData, mDataLen)) {
+ ALOGE("%s: put attr error", __func__);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ attr_end(nl_data);
+ }
+ hexdump(mVendorData, mDataLen);
+ return ret;
+}
+
+wifi_error NanCommand::putNanTCA(transaction_id id, const NanTCARequest *pReq)
+{
+ wifi_error ret;
+ ALOGV("NAN_TCA");
+ if (pReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ size_t message_len = sizeof(NanTcaReqMsg);
+
+ message_len += (SIZEOF_TLV_HDR + 2 * sizeof(u32));
+ pNanTcaReqMsg pFwReq =
+ (pNanTcaReqMsg)malloc(message_len);
+ if (pFwReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ ALOGV("Message Len %zu", message_len);
+ memset(pFwReq, 0, message_len);
+ pFwReq->fwHeader.msgVersion = (u16)NAN_MSG_VERSION1;
+ pFwReq->fwHeader.msgId = NAN_MSG_ID_TCA_REQ;
+ pFwReq->fwHeader.msgLen = message_len;
+ pFwReq->fwHeader.transactionId = id;
+
+ u32 tcaReqParams[2];
+ memset (tcaReqParams, 0, sizeof(tcaReqParams));
+ tcaReqParams[0] = (pReq->rising_direction_evt_flag & 0x01);
+ tcaReqParams[0] |= (pReq->falling_direction_evt_flag & 0x01) << 1;
+ tcaReqParams[0] |= (pReq->clear & 0x01) << 2;
+ tcaReqParams[1] = pReq->threshold;
+
+ u8* tlvs = pFwReq->ptlv;
+
+ if (pReq->tca_type == NAN_TCA_ID_CLUSTER_SIZE) {
+ tlvs = addTlv(NAN_TLV_TYPE_CLUSTER_SIZE_REQ, sizeof(tcaReqParams),
+ (const u8*)&tcaReqParams[0], tlvs);
+ } else {
+ ALOGE("%s: Unrecognized tca_type:%u", __FUNCTION__, pReq->tca_type);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ mVendorData = (char *)pFwReq;
+ mDataLen = message_len;
+
+ ret = WIFI_SUCCESS;
+ if (mSubcmd == QCA_NL80211_VENDOR_SUBCMD_NAN) {
+ ret = mMsg.put_bytes(NL80211_ATTR_VENDOR_DATA, mVendorData, mDataLen);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: put_bytes Error:%d",__func__, ret);
+ cleanup();
+ return ret;
+ }
+ } else {
+ struct nlattr *nl_data;
+
+ nl_data = attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nl_data) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ if (mMsg.put_bytes(QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA,
+ mVendorData, mDataLen)) {
+ ALOGE("%s: put attr error", __func__);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ attr_end(nl_data);
+ }
+ hexdump(mVendorData, mDataLen);
+ return ret;
+}
+
+wifi_error NanCommand::putNanBeaconSdfPayload(transaction_id id,
+ const NanBeaconSdfPayloadRequest *pReq)
+{
+ wifi_error ret;
+ ALOGV("NAN_BEACON_SDF_PAYLAOD");
+ if (pReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ size_t message_len = sizeof(NanMsgHeader) + \
+ SIZEOF_TLV_HDR + sizeof(u32) + \
+ pReq->vsa.vsa_len;
+
+ pNanBeaconSdfPayloadReqMsg pFwReq =
+ (pNanBeaconSdfPayloadReqMsg)malloc(message_len);
+ if (pFwReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ ALOGV("Message Len %zu", message_len);
+ memset(pFwReq, 0, message_len);
+ pFwReq->fwHeader.msgVersion = (u16)NAN_MSG_VERSION1;
+ pFwReq->fwHeader.msgId = NAN_MSG_ID_BEACON_SDF_REQ;
+ pFwReq->fwHeader.msgLen = message_len;
+ pFwReq->fwHeader.transactionId = id;
+
+ /* Construct First 4 bytes of NanBeaconSdfPayloadReqMsg */
+ u32 temp = 0;
+ temp = pReq->vsa.payload_transmit_flag & 0x01;
+ temp |= (pReq->vsa.tx_in_discovery_beacon & 0x01) << 1;
+ temp |= (pReq->vsa.tx_in_sync_beacon & 0x01) << 2;
+ temp |= (pReq->vsa.tx_in_service_discovery & 0x01) << 3;
+ temp |= (pReq->vsa.vendor_oui & 0x00FFFFFF) << 8;
+
+ int tlv_len = sizeof(u32) + pReq->vsa.vsa_len;
+ u8* tempBuf = (u8*)malloc(tlv_len);
+ if (tempBuf == NULL) {
+ ALOGE("%s: Malloc failed", __func__);
+ free(pFwReq);
+ cleanup();
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ memset(tempBuf, 0, tlv_len);
+ memcpy(tempBuf, &temp, sizeof(u32));
+ memcpy((tempBuf + sizeof(u32)), pReq->vsa.vsa, pReq->vsa.vsa_len);
+
+ u8* tlvs = pFwReq->ptlv;
+
+ /* Write the TLVs to the message. */
+ tlvs = addTlv(NAN_TLV_TYPE_VENDOR_SPECIFIC_ATTRIBUTE_TRANSMIT, tlv_len,
+ (const u8*)tempBuf, tlvs);
+ free(tempBuf);
+
+ mVendorData = (char *)pFwReq;
+ mDataLen = message_len;
+
+ ret = WIFI_SUCCESS;
+ if (mSubcmd == QCA_NL80211_VENDOR_SUBCMD_NAN) {
+ ret = mMsg.put_bytes(NL80211_ATTR_VENDOR_DATA, mVendorData, mDataLen);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: put_bytes Error:%d",__func__, ret);
+ cleanup();
+ return ret;
+ }
+ } else {
+ struct nlattr *nl_data;
+
+ nl_data = attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nl_data) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ if (mMsg.put_bytes(QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA,
+ mVendorData, mDataLen)) {
+ ALOGE("%s: put attr error", __func__);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ attr_end(nl_data);
+ }
+ hexdump(mVendorData, mDataLen);
+ return ret;
+}
+
+//callback handlers registered for nl message send
+static int error_handler_nan(struct sockaddr_nl *nla, struct nlmsgerr *err,
+ void *arg)
+{
+ struct sockaddr_nl * tmp;
+ int *ret = (int *)arg;
+ tmp = nla;
+ *ret = err->error;
+ ALOGE("%s: Error code:%d (%s)", __func__, *ret, strerror(-(*ret)));
+ return NL_STOP;
+}
+
+//callback handlers registered for nl message send
+static int ack_handler_nan(struct nl_msg *msg, void *arg)
+{
+ int *ret = (int *)arg;
+ struct nl_msg * a;
+
+ ALOGE("%s: called", __func__);
+ a = msg;
+ *ret = 0;
+ return NL_STOP;
+}
+
+//callback handlers registered for nl message send
+static int finish_handler_nan(struct nl_msg *msg, void *arg)
+{
+ int *ret = (int *)arg;
+ struct nl_msg * a;
+
+ ALOGE("%s: called", __func__);
+ a = msg;
+ *ret = 0;
+ return NL_SKIP;
+}
+
+
+//Override base class requestEvent and implement little differently here
+//This will send the request message
+//We dont wait for any response back in case of Nan as it is asynchronous
+//thus no wait for condition.
+wifi_error NanCommand::requestEvent()
+{
+ wifi_error res;
+ int status;
+ struct nl_cb * cb = NULL;
+
+ cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!cb) {
+ ALOGE("%s: Callback allocation failed",__func__);
+ res = WIFI_ERROR_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ if (!mInfo->cmd_sock) {
+ ALOGE("%s: Command socket is null",__func__);
+ res = WIFI_ERROR_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ /* send message */
+ ALOGV("%s:Handle:%p Socket Value:%p", __func__, mInfo, mInfo->cmd_sock);
+ status = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
+ if (status < 0) {
+ res = mapKernelErrortoWifiHalError(status);
+ goto out;
+ }
+
+ status = 1;
+
+ nl_cb_err(cb, NL_CB_CUSTOM, error_handler_nan, &status);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler_nan, &status);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_nan, &status);
+
+ // err is populated as part of finish_handler
+ while (status > 0)
+ nl_recvmsgs(mInfo->cmd_sock, cb);
+
+ res = mapKernelErrortoWifiHalError(status);
+out:
+ nl_cb_put(cb);
+ //free the VendorData
+ if (mVendorData) {
+ free(mVendorData);
+ }
+ mVendorData = NULL;
+ //cleanup the mMsg
+ mMsg.destroy();
+ return res;
+}
+
+int NanCommand::calcNanTransmitPostDiscoverySize(
+ const NanTransmitPostDiscovery *pPostDiscovery)
+{
+ /* Fixed size of u32 for Conn Type, Device Role and R flag + Dur + Rsvd*/
+ int ret = sizeof(u32);
+ /* size of availability interval bit map is 4 bytes */
+ ret += sizeof(u32);
+ /* size of mac address is 6 bytes*/
+ ret += (SIZEOF_TLV_HDR + NAN_MAC_ADDR_LEN);
+ if (pPostDiscovery &&
+ pPostDiscovery->type == NAN_CONN_WLAN_MESH) {
+ /* size of WLAN_MESH_ID */
+ ret += (SIZEOF_TLV_HDR + \
+ pPostDiscovery->mesh_id_len);
+ }
+ if (pPostDiscovery &&
+ pPostDiscovery->type == NAN_CONN_WLAN_INFRA) {
+ /* size of Infrastructure ssid */
+ ret += (SIZEOF_TLV_HDR + \
+ pPostDiscovery->infrastructure_ssid_len);
+ }
+ ALOGV("%s:size:%d", __func__, ret);
+ return ret;
+}
+
+void NanCommand::fillNanSocialChannelParamVal(
+ const NanSocialChannelScanParams *pScanParams,
+ u32* pChannelParamArr)
+{
+ int i;
+ if (pChannelParamArr) {
+ memset(pChannelParamArr, 0,
+ NAN_MAX_SOCIAL_CHANNELS * sizeof(u32));
+ for (i= 0; i < NAN_MAX_SOCIAL_CHANNELS; i++) {
+ pChannelParamArr[i] = pScanParams->scan_period[i] << 16;
+ pChannelParamArr[i] |= pScanParams->dwell_time[i] << 8;
+ }
+ pChannelParamArr[NAN_CHANNEL_24G_BAND] |= 6;
+ pChannelParamArr[NAN_CHANNEL_5G_BAND_LOW]|= 44;
+ pChannelParamArr[NAN_CHANNEL_5G_BAND_HIGH]|= 149;
+ ALOGV("%s: Filled SocialChannelParamVal", __func__);
+ hexdump((char*)pChannelParamArr, NAN_MAX_SOCIAL_CHANNELS * sizeof(u32));
+ }
+ return;
+}
+
+u32 NanCommand::getNanTransmitPostConnectivityCapabilityVal(
+ const NanTransmitPostConnectivityCapability *pCapab)
+{
+ u32 ret = 0;
+ ret |= (pCapab->payload_transmit_flag? 1:0) << 16;
+ ret |= (pCapab->is_mesh_supported? 1:0) << 5;
+ ret |= (pCapab->is_ibss_supported? 1:0) << 4;
+ ret |= (pCapab->wlan_infra_field? 1:0) << 3;
+ ret |= (pCapab->is_tdls_supported? 1:0) << 2;
+ ret |= (pCapab->is_wfds_supported? 1:0) << 1;
+ ret |= (pCapab->is_wfd_supported? 1:0);
+ ALOGV("%s: val:%d", __func__, ret);
+ return ret;
+}
+
+void NanCommand::fillNanTransmitPostDiscoveryVal(
+ const NanTransmitPostDiscovery *pTxDisc,
+ u8 *pOutValue)
+{
+
+ if (pTxDisc && pOutValue) {
+ u8 *tlvs = &pOutValue[8];
+ pOutValue[0] = pTxDisc->type;
+ pOutValue[1] = pTxDisc->role;
+ pOutValue[2] = (pTxDisc->transmit_freq? 1:0);
+ pOutValue[2] |= ((pTxDisc->duration & 0x03) << 1);
+ memcpy(&pOutValue[4], &pTxDisc->avail_interval_bitmap,
+ sizeof(pTxDisc->avail_interval_bitmap));
+ tlvs = addTlv(NAN_TLV_TYPE_MAC_ADDRESS,
+ NAN_MAC_ADDR_LEN,
+ (const u8*)&pTxDisc->addr[0],
+ tlvs);
+ if (pTxDisc->type == NAN_CONN_WLAN_MESH) {
+ tlvs = addTlv(NAN_TLV_TYPE_WLAN_MESH_ID,
+ pTxDisc->mesh_id_len,
+ (const u8*)&pTxDisc->mesh_id[0],
+ tlvs);
+ }
+ if (pTxDisc->type == NAN_CONN_WLAN_INFRA) {
+ tlvs = addTlv(NAN_TLV_TYPE_WLAN_INFRA_SSID,
+ pTxDisc->infrastructure_ssid_len,
+ (const u8*)&pTxDisc->infrastructure_ssid_val[0],
+ tlvs);
+ }
+ ALOGV("%s: Filled TransmitPostDiscoveryVal", __func__);
+ hexdump((char*)pOutValue, calcNanTransmitPostDiscoverySize(pTxDisc));
+ }
+
+ return;
+}
+
+void NanCommand::fillNanFurtherAvailabilityMapVal(
+ const NanFurtherAvailabilityMap *pFam,
+ u8 *pOutValue)
+{
+ int idx = 0;
+
+ if (pFam && pOutValue) {
+ u32 famsize = calcNanFurtherAvailabilityMapSize(pFam);
+ pNanFurtherAvailabilityMapAttrTlv pFwReq = \
+ (pNanFurtherAvailabilityMapAttrTlv)pOutValue;
+
+ memset(pOutValue, 0, famsize);
+ pFwReq->numChan = pFam->numchans;
+ for (idx = 0; idx < pFam->numchans; idx++) {
+ const NanFurtherAvailabilityChannel *pFamChan = \
+ &pFam->famchan[idx];
+ pNanFurtherAvailabilityChan pFwFamChan = \
+ (pNanFurtherAvailabilityChan)((u8*)&pFwReq->pFaChan[0] + \
+ (idx * sizeof(NanFurtherAvailabilityChan)));
+
+ pFwFamChan->entryCtrl.availIntDuration = \
+ pFamChan->entry_control;
+ pFwFamChan->entryCtrl.mapId = \
+ pFamChan->mapid;
+ pFwFamChan->opClass = pFamChan->class_val;
+ pFwFamChan->channel = pFamChan->channel;
+ memcpy(&pFwFamChan->availIntBitmap,
+ &pFamChan->avail_interval_bitmap,
+ sizeof(pFwFamChan->availIntBitmap));
+ }
+ ALOGV("%s: Filled FurtherAvailabilityMapVal", __func__);
+ hexdump((char*)pOutValue, famsize);
+ }
+ return;
+}
+
+int NanCommand::calcNanFurtherAvailabilityMapSize(
+ const NanFurtherAvailabilityMap *pFam)
+{
+ int ret = 0;
+ if (pFam && pFam->numchans &&
+ pFam->numchans <= NAN_MAX_FAM_CHANNELS) {
+ /* Fixed size of u8 for numchans*/
+ ret = sizeof(u8);
+ /* numchans * sizeof(FamChannels) */
+ ret += (pFam->numchans * sizeof(NanFurtherAvailabilityChan));
+ }
+ ALOGV("%s:size:%d", __func__, ret);
+ return ret;
+}
+
+wifi_error NanCommand::putNanCapabilities(transaction_id id)
+{
+ wifi_error ret;
+ ALOGV("NAN_CAPABILITIES");
+ size_t message_len = sizeof(NanCapabilitiesReqMsg);
+
+ pNanCapabilitiesReqMsg pFwReq = (pNanCapabilitiesReqMsg)malloc(message_len);
+ if (pFwReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ memset (pFwReq, 0, message_len);
+ pFwReq->fwHeader.msgVersion = (u16)NAN_MSG_VERSION1;
+ pFwReq->fwHeader.msgId = NAN_MSG_ID_CAPABILITIES_REQ;
+ pFwReq->fwHeader.msgLen = message_len;
+ pFwReq->fwHeader.transactionId = id;
+
+ mVendorData = (char*)pFwReq;
+ mDataLen = message_len;
+
+ ret = WIFI_SUCCESS;
+ if (mSubcmd == QCA_NL80211_VENDOR_SUBCMD_NAN) {
+ ret = mMsg.put_bytes(NL80211_ATTR_VENDOR_DATA, mVendorData, mDataLen);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: put_bytes Error:%d",__func__, ret);
+ cleanup();
+ return ret;
+ }
+ } else {
+ struct nlattr *nl_data;
+
+ nl_data = attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ if (!nl_data) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ if (mMsg.put_bytes(QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA,
+ mVendorData, mDataLen)) {
+ ALOGE("%s: put attr error", __func__);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ attr_end(nl_data);
+ }
+ hexdump(mVendorData, mDataLen);
+ return ret;
+}
+
+wifi_error NanCommand::putNanDebugCommand(NanDebugParams debug,
+ int debug_msg_length)
+{
+ wifi_error ret;
+ ALOGV("NAN_AVAILABILITY_DEBUG");
+ size_t message_len = sizeof(NanTestModeReqMsg);
+
+ message_len += (SIZEOF_TLV_HDR + debug_msg_length);
+ pNanTestModeReqMsg pFwReq = (pNanTestModeReqMsg)malloc(message_len);
+ if (pFwReq == NULL) {
+ cleanup();
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ ALOGV("Message Len %zu\n", message_len);
+ ALOGV("%s: Debug Command Type = 0x%x \n", __func__, debug.cmd);
+ ALOGV("%s: ** Debug Command Data Start **", __func__);
+ hexdump(debug.debug_cmd_data, debug_msg_length);
+ ALOGV("%s: ** Debug Command Data End **", __func__);
+
+ memset (pFwReq, 0, message_len);
+ pFwReq->fwHeader.msgVersion = (u16)NAN_MSG_VERSION1;
+ pFwReq->fwHeader.msgId = NAN_MSG_ID_TESTMODE_REQ;
+ pFwReq->fwHeader.msgLen = message_len;
+ pFwReq->fwHeader.transactionId = 0;
+
+ u8* tlvs = pFwReq->ptlv;
+ tlvs = addTlv(NAN_TLV_TYPE_TESTMODE_GENERIC_CMD, debug_msg_length,
+ (const u8*)&debug, tlvs);
+
+ mVendorData = (char*)pFwReq;
+ mDataLen = message_len;
+
+ ret = WIFI_SUCCESS;
+ if (mSubcmd == QCA_NL80211_VENDOR_SUBCMD_NAN) {
+ /* Write the TLVs to the message. */
+ ret = mMsg.put_bytes(NL80211_ATTR_VENDOR_DATA, mVendorData, mDataLen);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: put_bytes Error:%d",__func__, ret);
+ cleanup();
+ return ret;
+ }
+ } else {
+ struct nlattr *nl_data;
+
+ nl_data = attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ if (!nl_data) {
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ if (mMsg.put_bytes(QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA,
+ mVendorData, mDataLen)) {
+ ALOGE("%s: put attr error", __func__);
+ cleanup();
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ attr_end(nl_data);
+ }
+ hexdump(mVendorData, mDataLen);
+ return ret;
+}