blob: dd9b787211896d8a74bbaa37b8dedc5ec4009f8a [file] [log] [blame]
/*
* 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.
*/
#include "sync.h"
#include <utils/Log.h>
#include "nan.h"
#include "wifi_hal.h"
#include "nan_i.h"
#include "nancommand.h"
int NanCommand::putNanEnable(const NanEnableRequest *pReq)
{
ALOGI("NAN_ENABLE");
size_t message_len = NAN_MAX_ENABLE_REQ_SIZE;
if (pReq == NULL) {
return WIFI_ERROR_INVALID_ARGS;
}
#ifdef NAN_2_0
/* Removing the unsupported ones */
message_len -= \
(SIZEOF_TLV_HDR + sizeof(u8) /* Random Time */ + \
SIZEOF_TLV_HDR + sizeof(u8) /* Full Scan Int */);
message_len += \
(
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_discovery ? (SIZEOF_TLV_HDR + \
sizeof(pReq->discovery_2dot4g_val)) : 0 \
) + \
(
pReq->config_5g_beacons ? (SIZEOF_TLV_HDR + \
sizeof(pReq->beacon_5g_val)) : 0 \
) + \
(
pReq->config_5g_discovery ? (SIZEOF_TLV_HDR + \
sizeof(pReq->discovery_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_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 ? (SIZEOF_TLV_HDR + \
NAN_MAX_SOCIAL_CHANNEL * sizeof(u32)) : 0 \
) + \
(
pReq->config_debug_flags ? (SIZEOF_TLV_HDR + \
sizeof(u64)) : 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 \
);
#endif /* NAN_2_0 */
pNanEnableReqMsg pFwReq = (pNanEnableReqMsg)malloc(message_len);
if (pFwReq == NULL) {
return WIFI_ERROR_OUT_OF_MEMORY;
}
ALOGI("Message Len %d", 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.handle = pReq->header.handle;
pFwReq->fwHeader.transactionId = pReq->header.transaction_id;
u8* tlvs = pFwReq->ptlv;
/* Write the TLVs to the message. */
tlvs = addTlv(NAN_TLV_TYPE_5G_SUPPORT, sizeof(pReq->support_5g),
(const u8*)&pReq->support_5g, tlvs);
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_SID_BEACON, sizeof(pReq->sid_beacon),
(const u8*)&pReq->sid_beacon, tlvs);
tlvs = addTlv(NAN_TLV_TYPE_RSSI_CLOSE, sizeof(pReq->rssi_close),
(const u8*)&pReq->rssi_close, tlvs);
tlvs = addTlv(NAN_TLV_TYPE_RSSI_MEDIUM, sizeof(pReq->rssi_middle),
(const u8*)&pReq->rssi_middle, tlvs);
tlvs = addTlv(NAN_TLV_TYPE_HOP_COUNT_LIMIT, sizeof(pReq->hop_count_limit),
(const u8*)&pReq->hop_count_limit, tlvs);
#ifndef NAN_2_0
tlvs = addTlv(NAN_TLV_TYPE_RANDOM_UPDATE_TIME, sizeof(pReq->random_time),
(const u8*)&pReq->random_time, tlvs);
#endif /* NAN_2_0 */
tlvs = addTlv(NAN_TLV_TYPE_MASTER_PREFERENCE, sizeof(pReq->master_pref),
(const u8*)&pReq->master_pref, tlvs);
#ifndef NAN_2_0
tlvs = addTlv(NAN_TLV_TYPE_PERIODIC_SCAN_INTERVAL, sizeof(pReq->periodic_scan_interval),
(const u8*)&pReq->periodic_scan_interval, tlvs);
#endif /* NAN_2_0 */
#ifdef NAN_2_0
if (pReq->config_2dot4g_support) {
tlvs = addTlv(NAN_TLV_TYPE_2DOT4G_SUPPORT, sizeof(pReq->support_2dot4g_val),
(const u8*)&pReq->support_2dot4g_val, tlvs);
}
if (pReq->config_2dot4g_beacons) {
tlvs = addTlv(NAN_TLV_TYPE_2DOT4G_BEACONS, sizeof(pReq->beacon_2dot4g_val),
(const u8*)&pReq->beacon_2dot4g_val, tlvs);
}
if (pReq->config_2dot4g_discovery) {
tlvs = addTlv(NAN_TLV_TYPE_2DOT4G_SDF, sizeof(pReq->discovery_2dot4g_val),
(const u8*)&pReq->discovery_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_discovery) {
tlvs = addTlv(NAN_TLV_TYPE_5G_SDF, sizeof(pReq->discovery_5g_val),
(const u8*)&pReq->discovery_5g_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_MEDIUM, 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_CHANNEL];
/* Fill the social channel param */
fillNanSocialChannelParamVal(&pReq->scan_params_val,
socialChannelParamVal);
int i;
for (i = 0; i < NAN_MAX_SOCIAL_CHANNEL; i++) {
tlvs = addTlv(NAN_TLV_TYPE_SOCIAL_CHANNEL_SCAN_PARAMETERS,
sizeof(socialChannelParamVal[i]),
(const u8*)&socialChannelParamVal[i], tlvs);
}
}
if (pReq->config_debug_flags) {
tlvs = addTlv(NAN_TLV_TYPE_DEBUGGING_FLAGS,
sizeof(pReq->debug_flags_val),
(const u8*)&pReq->debug_flags_val, 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);
}
#endif /* NAN_2_0 */
mVendorData = (char*)pFwReq;
mDataLen = message_len;
return WIFI_SUCCESS;
}
int NanCommand::putNanDisable(const NanDisableRequest *pReq)
{
ALOGI("NAN_DISABLE");
size_t message_len = sizeof(NanDisableReqMsg);
if (pReq == NULL) {
return WIFI_ERROR_INVALID_ARGS;
}
pNanDisableReqMsg pFwReq = (pNanDisableReqMsg)malloc(message_len);
if (pFwReq == NULL) {
return WIFI_ERROR_OUT_OF_MEMORY;
}
ALOGI("Message Len %d", 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.handle = pReq->header.handle;
pFwReq->fwHeader.transactionId = pReq->header.transaction_id;
mVendorData = (char*)pFwReq;
mDataLen = message_len;
return WIFI_SUCCESS;
}
int NanCommand::putNanConfig(const NanConfigRequest *pReq)
{
ALOGI("NAN_CONFIG");
size_t message_len = NAN_MAX_CONFIGURATION_REQ_SIZE;
if (pReq == NULL) {
return WIFI_ERROR_INVALID_ARGS;
}
#ifndef NAN_2_0
// Add additional message size for transmitting
// further availability attribute if
// additional_disc_window_slots is Non-zero value.
if (pReq->additional_disc_window_slots != 0) {
message_len += (SIZEOF_TLV_HDR + \
sizeof(pReq->additional_disc_window_slots));
}
#endif /* NAN_2_0 */
#ifdef NAN_2_0
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_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 ? (SIZEOF_TLV_HDR + \
NAN_MAX_SOCIAL_CHANNEL * sizeof(u32)) : 0 \
) + \
(
pReq->config_debug_flags ? (SIZEOF_TLV_HDR + \
sizeof(u64)) : 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_discovery_attr ? (SIZEOF_TLV_HDR + \
calcNanTransmitPostDiscoverySize(&pReq->discovery_attr_val)) : 0 \
);
if (pReq->config_fam && \
calcNanFurtherAvailabilityMapSize(&pReq->fam_val)) {
message_len += (SIZEOF_TLV_HDR + \
calcNanFurtherAvailabilityMapSize(&pReq->fam_val));
}
#endif /* NAN_2_0 */
pNanConfigurationReqMsg pFwReq = (pNanConfigurationReqMsg)malloc(message_len);
if (pFwReq == NULL) {
return WIFI_ERROR_OUT_OF_MEMORY;
}
ALOGI("Message Len %d", 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.handle = pReq->header.handle;
pFwReq->fwHeader.transactionId = pReq->header.transaction_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);
}
#ifndef NAN_2_0
tlvs = addTlv(NAN_TLV_TYPE_RANDOM_UPDATE_TIME, sizeof(pReq->random_time),
(const u8*)&pReq->random_time, tlvs);
#endif /* NAN_2_0 */
if (pReq->config_master_pref) {
tlvs = addTlv(NAN_TLV_TYPE_MASTER_PREFERENCE, sizeof(pReq->master_pref),
(const u8*)&pReq->master_pref, tlvs);
}
#ifndef NAN_2_0
tlvs = addTlv(NAN_TLV_TYPE_PERIODIC_SCAN_INTERVAL, sizeof(pReq->periodic_scan_interval),
(const u8*)&pReq->periodic_scan_interval, tlvs);
#endif /* NAN_2_0 */
/* In 2.0 Version of NAN this parameter does not have any significance */
#ifndef NAN_2_0
if (pReq->additional_disc_window_slots != 0) {
/*
Construct the value in this manner
Bit0 ==> 1/0 Enable/Disable FAW
Bit1-2 ==> reserved
Bit3-7 ==> FAW Slot Value.
*/
u8 faw_value = 0x01; /* Enable the first bit */
/* Shifting the disc_window_slots by 3 and masking it with 0xf8
so that the Bit 3 to 7 are updated
*/
faw_value |= ((pReq->additional_disc_window_slots << 3) & (0xf8));
tlvs = addTlv(NAN_TLV_TYPE_FURTHER_AVAILABILITY,
sizeof(faw_value),
(const u8*)&faw_value, tlvs);
}
#endif /* NAN_2_0 */
#ifdef NAN_2_0
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_scan_params) {
u32 socialChannelParamVal[NAN_MAX_SOCIAL_CHANNEL];
/* Fill the social channel param */
fillNanSocialChannelParamVal(&pReq->scan_params_val,
socialChannelParamVal);
int i;
for (i = 0; i < NAN_MAX_SOCIAL_CHANNEL; i++) {
tlvs = addTlv(NAN_TLV_TYPE_SOCIAL_CHANNEL_SCAN_PARAMETERS,
sizeof(socialChannelParamVal[i]),
(const u8*)&socialChannelParamVal[i], tlvs);
}
}
if (pReq->config_debug_flags) {
tlvs = addTlv(NAN_TLV_TYPE_DEBUGGING_FLAGS,
sizeof(pReq->debug_flags_val),
(const u8*)&pReq->debug_flags_val, 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->config_discovery_attr) {
fillNanTransmitPostDiscoveryVal(&pReq->discovery_attr_val,
(u8*)(tlvs + SIZEOF_TLV_HDR));
tlvs = addTlv(NAN_TLV_TYPE_POST_NAN_DISCOVERY_ATTRIBUTE_TRANSMIT,
calcNanTransmitPostDiscoverySize(&pReq->discovery_attr_val),
(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);
}
#endif /* NAN_2_0 */
mVendorData = (char*)pFwReq;
mDataLen = message_len;
return WIFI_SUCCESS;
}
int NanCommand::putNanPublish(const NanPublishRequest *pReq)
{
ALOGI("NAN_PUBLISH");
if (pReq == NULL) {
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);
pNanPublishServiceReqMsg pFwReq = (pNanPublishServiceReqMsg)malloc(message_len);
if (pFwReq == NULL) {
return WIFI_ERROR_OUT_OF_MEMORY;
}
ALOGI("Message Len %d", 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;
pFwReq->fwHeader.handle = pReq->header.handle;
pFwReq->fwHeader.transactionId = pReq->header.transaction_id;
pFwReq->publishServiceReqParams.ttl = pReq->ttl;
pFwReq->publishServiceReqParams.period = pReq->period;
pFwReq->publishServiceReqParams.replyIndFlag = pReq->replied_event_flag;
pFwReq->publishServiceReqParams.publishType = pReq->publish_type;
pFwReq->publishServiceReqParams.txType = pReq->tx_type;
#ifdef NAN_2_0
/* Overwriting replyIndFlag to 0 based on v17 Nan Spec */
pFwReq->publishServiceReqParams.replyIndFlag = 0;
pFwReq->publishServiceReqParams.rssiThresholdFlag = pReq->rssi_threshold_flag;
pFwReq->publishServiceReqParams.ota_flag = pReq->ota_flag;
pFwReq->publishServiceReqParams.matchAlg = pReq->publish_match;
#endif /* NAN_2_0 */
pFwReq->publishServiceReqParams.count = pReq->publish_count;
#ifdef NAN_2_0
pFwReq->publishServiceReqParams.connmap = pReq->connmap;
#endif /* NAN_2_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);
}
mVendorData = (char *)pFwReq;
mDataLen = message_len;
return WIFI_SUCCESS;
}
int NanCommand::putNanPublishCancel(const NanPublishCancelRequest *pReq)
{
ALOGI("NAN_PUBLISH_CANCEL");
if (pReq == NULL) {
return WIFI_ERROR_INVALID_ARGS;
}
size_t message_len = sizeof(NanPublishServiceCancelReqMsg);
pNanPublishServiceCancelReqMsg pFwReq =
(pNanPublishServiceCancelReqMsg)malloc(message_len);
if (pFwReq == NULL) {
return WIFI_ERROR_INVALID_ARGS;
}
ALOGI("Message Len %d", 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->header.handle;
pFwReq->fwHeader.transactionId = pReq->header.transaction_id;
mVendorData = (char *)pFwReq;
mDataLen = message_len;
return WIFI_SUCCESS;
}
int NanCommand::putNanSubscribe(const NanSubscribeRequest *pReq)
{
ALOGI("NAN_SUBSCRIBE");
if (pReq == NULL) {
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);
#ifdef NAN_2_0
message_len += \
(pReq->num_intf_addr_present * (SIZEOF_TLV_HDR + NAN_MAC_ADDR_LEN));
#endif /* NAN_2_0 */
pNanSubscribeServiceReqMsg pFwReq = (pNanSubscribeServiceReqMsg)malloc(message_len);
if (pFwReq == NULL) {
return WIFI_ERROR_INVALID_ARGS;
}
ALOGI("Message Len %d", 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;
pFwReq->fwHeader.handle = pReq->header.handle;
pFwReq->fwHeader.transactionId = pReq->header.transaction_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;
pFwReq->subscribeServiceReqParams.count = pReq->subscribe_count;
#ifdef NAN_2_0
pFwReq->subscribeServiceReqParams.rssiThresholdFlag = pReq->rssi_threshold_flag;
pFwReq->subscribeServiceReqParams.ota_flag = pReq->ota_flag;
pFwReq->subscribeServiceReqParams.connmap = pReq->connmap;
#endif /* NAN_2_0 */
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);
}
#ifdef NAN_2_0
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);
}
#endif /* NAN_2_0 */
mVendorData = (char *)pFwReq;
mDataLen = message_len;
return WIFI_SUCCESS;
}
int NanCommand::putNanSubscribeCancel(const NanSubscribeCancelRequest *pReq)
{
ALOGI("NAN_SUBSCRIBE_CANCEL");
if (pReq == NULL) {
return WIFI_ERROR_INVALID_ARGS;
}
size_t message_len = sizeof(NanSubscribeServiceCancelReqMsg);
pNanSubscribeServiceCancelReqMsg pFwReq =
(pNanSubscribeServiceCancelReqMsg)malloc(message_len);
if (pFwReq == NULL) {
return WIFI_ERROR_INVALID_ARGS;
}
ALOGI("Message Len %d", 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->header.handle;
pFwReq->fwHeader.transactionId = pReq->header.transaction_id;
mVendorData = (char *)pFwReq;
mDataLen = message_len;
return WIFI_SUCCESS;
}
int NanCommand::putNanTransmitFollowup(const NanTransmitFollowupRequest *pReq)
{
ALOGI("TRANSMIT_FOLLOWUP");
if (pReq == NULL) {
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);
#ifdef NAN_2_0
/* Mac address needs to be added in TLV */
message_len += (SIZEOF_TLV_HDR + sizeof(pReq->addr));
#endif
pNanTransmitFollowupReqMsg pFwReq = (pNanTransmitFollowupReqMsg)malloc(message_len);
if (pFwReq == NULL) {
return WIFI_ERROR_INVALID_ARGS;
}
ALOGI("Message Len %d", 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->header.handle;
pFwReq->fwHeader.transactionId = pReq->header.transaction_id;
#ifndef NAN_2_0
memcpy(pFwReq->transmitFollowupReqParams.macAddr, pReq->addr,
sizeof(pFwReq->transmitFollowupReqParams.macAddr));
#else /* NAN_2_0 */
pFwReq->transmitFollowupReqParams.matchHandle = pReq->match_handle;
#endif /* NAN_2_0 */
pFwReq->transmitFollowupReqParams.priority = pReq->priority;
pFwReq->transmitFollowupReqParams.window = pReq->dw_or_faw;
pFwReq->transmitFollowupReqParams.reserved = 0;
u8* tlvs = pFwReq->ptlv;
#ifdef NAN_2_0
/* 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;
#else /* NAN_2_0 */
u16 tlv_type = (pReq->dw_or_faw == 0)? NAN_TLV_TYPE_SERVICE_SPECIFIC_INFO :
NAN_TLV_TYPE_EXT_SERVICE_SPECIFIC_INFO;
#endif /* NAN_2_0 */
if (pReq->service_specific_info_len) {
tlvs = addTlv(tlv_type, pReq->service_specific_info_len,
(const u8*)&pReq->service_specific_info[0], tlvs);
}
mVendorData = (char *)pFwReq;
mDataLen = message_len;
return WIFI_SUCCESS;
}
int NanCommand::putNanStats(const NanStatsRequest *pReq)
{
ALOGI("NAN_STATS");
if (pReq == NULL) {
return WIFI_ERROR_INVALID_ARGS;
}
size_t message_len = sizeof(NanStatsReqMsg);
pNanStatsReqMsg pFwReq =
(pNanStatsReqMsg)malloc(message_len);
if (pFwReq == NULL) {
return WIFI_ERROR_INVALID_ARGS;
}
ALOGI("Message Len %d", 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.handle = pReq->header.handle;
pFwReq->fwHeader.transactionId = pReq->header.transaction_id;
pFwReq->statsReqParams.statsId = pReq->stats_id;
pFwReq->statsReqParams.clear = pReq->clear;
pFwReq->statsReqParams.reserved = 0;
mVendorData = (char *)pFwReq;
mDataLen = message_len;
return WIFI_SUCCESS;
}
int NanCommand::putNanTCA(const NanTCARequest *pReq)
{
ALOGI("NAN_TCA");
if (pReq == NULL) {
return WIFI_ERROR_INVALID_ARGS;
}
size_t message_len = sizeof(NanTcaReqMsg);
#ifdef NAN_2_0
message_len += (SIZEOF_TLV_HDR + 2 * sizeof(u32));
#endif
pNanTcaReqMsg pFwReq =
(pNanTcaReqMsg)malloc(message_len);
if (pFwReq == NULL) {
return WIFI_ERROR_INVALID_ARGS;
}
ALOGI("Message Len %d", 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.handle = pReq->header.handle;
pFwReq->fwHeader.transactionId = pReq->header.transaction_id;
#ifndef NAN_2_0
pFwReq->tcaReqParams.tcaId = pReq->tca_id;
pFwReq->tcaReqParams.rising = pReq->rising_direction_evt_flag;
pFwReq->tcaReqParams.falling = pReq->falling_direction_evt_flag;
pFwReq->tcaReqParams.clear = pReq->clear;
pFwReq->tcaReqParams.reserved = 0;
pFwReq->tcaReqParams.threshold = pReq->threshold;
#else /* NAN_2_0 */
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;
tlvs = addTlv(NAN_TLV_TYPE_TCA_CLUSTER_SIZE_REQ, sizeof(tcaReqParams),
(const u8*)&tcaReqParams[0], tlvs);
#endif
mVendorData = (char *)pFwReq;
mDataLen = message_len;
return WIFI_SUCCESS;
}
int NanCommand::putNanBeaconSdfPayload(const NanBeaconSdfPayloadRequest *pReq)
{
int ret = WIFI_ERROR_NOT_SUPPORTED;
#ifdef NAN_2_0
ALOGI("NAN_BEACON_SDF_PAYLAOD");
if (pReq == NULL) {
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) {
return WIFI_ERROR_INVALID_ARGS;
}
ALOGI("Message Len %d", 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.handle = pReq->header.handle;
pFwReq->fwHeader.transactionId = pReq->header.transaction_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);
return WIFI_ERROR_INVALID_ARGS;
}
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;
#endif /* NAN_2_0 */
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.
int NanCommand::requestEvent()
{
int res;
struct nl_cb * cb;
cb = nl_cb_alloc(NL_CB_DEFAULT);
if (!cb) {
ALOGE("%s: Callback allocation failed",__func__);
res = -1;
goto out;
}
/* create the message */
res = create();
if (res < 0)
goto out;
/* send message */
ALOGE("%s:Handle:%p Socket Value:%p", __func__, mInfo, mInfo->cmd_sock);
res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
if (res < 0)
goto out;
res = 1;
nl_cb_err(cb, NL_CB_CUSTOM, error_handler_nan, &res);
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler_nan, &res);
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_nan, &res);
// err is populated as part of finish_handler
while (res > 0)
nl_recvmsgs(mInfo->cmd_sock, cb);
ALOGD("%s: Command invoked return value:%d",__func__, res);
out:
//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);
}
ALOGI("%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_CHANNEL * sizeof(u32));
for (i= 0; i < NAN_MAX_SOCIAL_CHANNEL; i++) {
pChannelParamArr[i] = pScanParams->scan_period[i] << 16;
pChannelParamArr[i] |= pScanParams->dwell_time[i] << 8;
}
pChannelParamArr[NAN_CHANNEL_6] |= 6;
pChannelParamArr[NAN_CHANNEL_44]|= 44;
pChannelParamArr[NAN_CHANNEL_149]|= 149;
ALOGI("%s: Filled SocialChannelParamVal", __func__);
hexdump((char*)pChannelParamArr, NAN_MAX_SOCIAL_CHANNEL * 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);
ALOGI("%s: val:%d", __func__, ret);
return ret;
}
void NanCommand::fillNanTransmitPostDiscoveryVal(
const NanTransmitPostDiscovery *pTxDisc,
u8 *pOutValue)
{
#ifdef NAN_2_0
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_FW_WLAN_INFRASTRUCTURE_SSID,
pTxDisc->infrastructure_ssid_len,
(const u8*)&pTxDisc->infrastructure_ssid_val[0],
tlvs);
}
ALOGI("%s: Filled TransmitPostDiscoveryVal", __func__);
hexdump((char*)pOutValue, calcNanTransmitPostDiscoverySize(pTxDisc));
}
#endif /* NAN_2_0 */
return;
}
void NanCommand::fillNanFurtherAvailabilityMapVal(
const NanFurtherAvailabilityMap *pFam,
u8 *pOutValue)
{
//ToDo: Fixme - build issue
#if 0
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));
}
ALOGI("%s: Filled FurtherAvailabilityMapVal", __func__);
hexdump((char*)pOutValue, famsize);
}
#endif
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) */
//ToDo: Fix build
//ret += (pFam->numchans * sizeof(NanFurtherAvailabilityChan));
}
ALOGI("%s:size:%d", __func__, ret);
return ret;
}