/*
* 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 <errno.h>
#include "nan.h"
#include "wifi_hal.h"
#include "nan_i.h"
#include "nancommand.h"
#include <errno.h>
#define NAN_TERMINATED_BEGINNING_OFFSET 8192
//Function which calls the necessaryIndication callback
//based on the indication type
int NanCommand::handleNanIndication()
{
//Based on the message_id in the header determine the Indication type
//and call the necessary callback handler
u16 msg_id;
int res = 0;
ALOGI("handleNanIndication called %p", this);
msg_id = getIndicationType();
ALOGI("handleNanIndication msg_id:%u", msg_id);
switch (msg_id) {
case NAN_INDICATION_PUBLISH_REPLIED:
NanPublishRepliedInd publishRepliedInd;
memset(&publishRepliedInd, 0, sizeof(publishRepliedInd));
res = getNanPublishReplied(&publishRepliedInd);
if (!res && mHandler.EventPublishReplied) {
(*mHandler.EventPublishReplied)(&publishRepliedInd,
mUserData);
}
break;
case NAN_INDICATION_PUBLISH_TERMINATED:
NanPublishTerminatedInd publishTerminatedInd;
memset(&publishTerminatedInd, 0, sizeof(publishTerminatedInd));
res = getNanPublishTerminated(&publishTerminatedInd);
if (!res && mHandler.EventPublishTerminated) {
(*mHandler.EventPublishTerminated)(&publishTerminatedInd,
mUserData);
}
break;
case NAN_INDICATION_MATCH:
NanMatchInd matchInd;
memset(&matchInd, 0, sizeof(matchInd));
res = getNanMatch(&matchInd);
if (!res && mHandler.EventMatch) {
(*mHandler.EventMatch)(&matchInd, mUserData);
}
break;
case NAN_INDICATION_UNMATCH:
NanUnmatchInd unMatchInd;
memset(&unMatchInd, 0, sizeof(unMatchInd));
res = getNanUnMatch(&unMatchInd);
if (!res && mHandler.EventUnMatch) {
(*mHandler.EventUnMatch)(&unMatchInd, mUserData);
}
break;
case NAN_INDICATION_SUBSCRIBE_TERMINATED:
NanSubscribeTerminatedInd subscribeTerminatedInd;
memset(&subscribeTerminatedInd, 0, sizeof(subscribeTerminatedInd));
res = getNanSubscribeTerminated(&subscribeTerminatedInd);
if (!res && mHandler.EventSubscribeTerminated) {
(*mHandler.EventSubscribeTerminated)(&subscribeTerminatedInd,
mUserData);
}
break;
case NAN_INDICATION_DE_EVENT:
NanDiscEngEventInd discEngEventInd;
memset(&discEngEventInd, 0, sizeof(discEngEventInd));
res = getNanDiscEngEvent(&discEngEventInd);
if (!res && mHandler.EventDiscEngEvent) {
(*mHandler.EventDiscEngEvent)(&discEngEventInd,
mUserData);
}
break;
case NAN_INDICATION_FOLLOWUP:
NanFollowupInd followupInd;
memset(&followupInd, 0, sizeof(followupInd));
res = getNanFollowup(&followupInd);
if (!res && mHandler.EventFollowup) {
(*mHandler.EventFollowup)(&followupInd,
mUserData);
}
break;
case NAN_INDICATION_DISABLED:
NanDisabledInd disabledInd;
memset(&disabledInd, 0, sizeof(disabledInd));
res = getNanDisabled(&disabledInd);
if (!res && mHandler.EventDisabled) {
(*mHandler.EventDisabled)(&disabledInd,
mUserData);
}
break;
case NAN_INDICATION_TCA:
NanTCAInd tcaInd;
memset(&tcaInd, 0, sizeof(tcaInd));
res = getNanTca(&tcaInd);
if (!res && mHandler.EventTca) {
(*mHandler.EventTca)(&tcaInd,
mUserData);
}
break;
case NAN_INDICATION_BEACON_SDF_PAYLOAD:
NanBeaconSdfPayloadInd beaconSdfPayloadInd;
memset(&beaconSdfPayloadInd, 0, sizeof(beaconSdfPayloadInd));
res = getNanBeaconSdfPayload(&beaconSdfPayloadInd);
if (!res && mHandler.EventSdfPayload) {
(*mHandler.EventSdfPayload)(&beaconSdfPayloadInd,
mUserData);
}
break;
default:
ALOGE("handleNanIndication error invalid msg_id:%u", msg_id);
res = (int)WIFI_ERROR_INVALID_REQUEST_ID;
break;
}
return res;
}
//Function which will return the Nan Indication type based on
//the initial few bytes of mNanVendorEvent
NanIndicationType NanCommand::getIndicationType()
{
if (mNanVendorEvent == NULL) {
ALOGE("%s: Invalid argument mNanVendorEvent:%p",
__func__, mNanVendorEvent);
return NAN_INDICATION_UNKNOWN;
}
NanMsgHeader *pHeader = (NanMsgHeader *)mNanVendorEvent;
switch (pHeader->msgId) {
case NAN_MSG_ID_PUBLISH_REPLIED_IND:
return NAN_INDICATION_PUBLISH_REPLIED;
case NAN_MSG_ID_PUBLISH_TERMINATED_IND:
return NAN_INDICATION_PUBLISH_TERMINATED;
case NAN_MSG_ID_MATCH_IND:
return NAN_INDICATION_MATCH;
case NAN_MSG_ID_UNMATCH_IND:
return NAN_INDICATION_UNMATCH;
case NAN_MSG_ID_FOLLOWUP_IND:
return NAN_INDICATION_FOLLOWUP;
case NAN_MSG_ID_SUBSCRIBE_TERMINATED_IND:
return NAN_INDICATION_SUBSCRIBE_TERMINATED;
case NAN_MSG_ID_DE_EVENT_IND:
return NAN_INDICATION_DE_EVENT;
case NAN_MSG_ID_DISABLE_IND:
return NAN_INDICATION_DISABLED;
case NAN_MSG_ID_TCA_IND:
return NAN_INDICATION_TCA;
#ifdef NAN_2_0
case NAN_MSG_ID_BEACON_SDF_IND:
return NAN_INDICATION_BEACON_SDF_PAYLOAD;
#endif /* NAN_2_0 */
default:
return NAN_INDICATION_UNKNOWN;
}
}
int NanCommand::getNanPublishReplied(NanPublishRepliedInd *event)
{
if (event == NULL || mNanVendorEvent == NULL) {
ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p",
__func__, event, mNanVendorEvent);
return WIFI_ERROR_INVALID_ARGS;
}
pNanPublishRepliedIndMsg pRsp = (pNanPublishRepliedIndMsg)mNanVendorEvent;
event->header.handle = pRsp->fwHeader.handle;
event->header.transaction_id = pRsp->fwHeader.transactionId;
#ifndef NAN_2_0
memcpy(event->addr, pRsp->publishRepliedIndParams.macAddr, sizeof(event->addr));
#else /* NAN_2_0 */
event->rssi_value = 0;
u8 *pInputTlv = pRsp->ptlv;
NanTlv outputTlv;
u16 readLen = 0;
int ret = 0;
int remainingLen = (mNanDataLen - \
(sizeof(NanMsgHeader)));
//Has NAN Mac address mandatory, received RSSI value optional
//POST_NAN_CONNECTIVITY_CAPABILITIES_RECEIVE
//POST_NAN_DISCOVERY_ATTRIBUTE_RECEIVE
//NAN_FURTHER_AVAILABILITY_MAP
//NAN_CLUSTER_ATTRIBUTE
if (remainingLen <= 0) {
ALOGI("%s: No TLV's present",__func__);
return WIFI_SUCCESS;
}
ALOGI("%s: TLV remaining Len:%d",__func__, remainingLen);
while ((remainingLen > 0) &&
(0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv)))) {
ALOGI("%s: Remaining Len:%d readLen:%d type:%d length:%d",
__func__, remainingLen, readLen, outputTlv.type,
outputTlv.length);
switch (outputTlv.type) {
case NAN_TLV_TYPE_MAC_ADDRESS:
if (outputTlv.length > sizeof(event->addr)) {
outputTlv.length = sizeof(event->addr);
}
memcpy(event->addr, outputTlv.value, outputTlv.length);
break;
case NAN_TLV_TYPE_RECEIVED_RSSI_VALUE:
if (outputTlv.length > sizeof(event->rssi_value)) {
outputTlv.length = sizeof(event->rssi_value);
}
memcpy(&event->rssi_value, outputTlv.value,
outputTlv.length);
break;
case NAN_TLV_TYPE_POST_NAN_CONNECTIVITY_CAPABILITIES_RECEIVE:
if (outputTlv.length != sizeof(u32)) {
ALOGE("NAN_TLV_TYPE_POST_NAN_CONNECTIVITY_CAPABILITIES_RECEIVE"
"Incorrect size:%d expecting %d", outputTlv.length,
sizeof(u32));
break;
}
event->is_conn_capability_valid = 1;
/* Populate conn_capability from received TLV */
getNanReceivePostConnectivityCapabilityVal(outputTlv.value,
&event->conn_capability);
break;
case NAN_TLV_TYPE_POST_NAN_DISCOVERY_ATTRIBUTE_RECEIVE:
/* Populate receive discovery attribute from
received TLV */
ret = getNanReceivePostDiscoveryVal(outputTlv.value,
outputTlv.length,
&event->discovery_attr);
if (ret == 0) {
event->is_discovery_attr_valid = 1;
}
else {
ALOGE("NAN_TLV_TYPE_POST_NAN_DISCOVERY_ATTRIBUTE_RECEIVE"
"Incorrect");
}
break;
case NAN_TLV_TYPE_FURTHER_AVAILABILITY_MAP:
/* Populate further availability bitmap from
received TLV */
ret = getNanFurtherAvailabilityMap(outputTlv.value,
outputTlv.length,
&event->fam);
if (ret == 0) {
event->is_fam_valid = 1;
}
else {
ALOGE("NAN_TLV_TYPE_FURTHER_AVAILABILITY_MAP"
"Incorrect");
}
break;
case NAN_TLV_TYPE_CLUSTER_ATTIBUTE:
if (outputTlv.length > sizeof(event->cluster_attribute)) {
outputTlv.length = sizeof(event->cluster_attribute);
}
memcpy(event->cluster_attribute,
outputTlv.value, outputTlv.length);
event->cluster_attribute_len = outputTlv.length;
break;
default:
ALOGI("Unknown TLV type skipped");
break;
}
remainingLen -= readLen;
pInputTlv += readLen;
memset(&outputTlv, 0, sizeof(outputTlv));
}
#endif /* NAN_2_0 */
return WIFI_SUCCESS;
}
int NanCommand::getNanPublishTerminated(NanPublishTerminatedInd *event)
{
if (event == NULL || mNanVendorEvent == NULL) {
ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p",
__func__, event, mNanVendorEvent);
return WIFI_ERROR_INVALID_ARGS;
}
pNanPublishTerminatedIndMsg pRsp = (pNanPublishTerminatedIndMsg)mNanVendorEvent;
event->header.handle = pRsp->fwHeader.handle;
event->header.transaction_id = pRsp->fwHeader.transactionId;
#ifdef NAN_2_0
pRsp->reason -= NAN_TERMINATED_BEGINNING_OFFSET;
#endif /* NAN_2_0 */
event->reason = (NanTerminatedStatus)pRsp->reason;
return WIFI_SUCCESS;
}
int NanCommand::getNanMatch(NanMatchInd *event)
{
if (event == NULL || mNanVendorEvent == NULL) {
ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p",
__func__, event, mNanVendorEvent);
return WIFI_ERROR_INVALID_ARGS;
}
pNanMatchIndMsg pRsp = (pNanMatchIndMsg)mNanVendorEvent;
event->header.handle = pRsp->fwHeader.handle;
event->header.transaction_id = pRsp->fwHeader.transactionId;
event->match_handle = pRsp->matchIndParams.matchHandle;
#ifndef NAN_2_0
memcpy(event->addr, pRsp->matchIndParams.macAddr, sizeof(event->addr));
#else /* NAN_2_0 */
event->match_occured_flag = pRsp->matchIndParams.matchOccuredFlag;
event->out_of_resource_flag = pRsp->matchIndParams.outOfResourceFlag;
#endif /* NAN_2_0 */
u8 *pInputTlv = pRsp->ptlv;
NanTlv outputTlv;
u16 readLen = 0;
int remainingLen = (mNanDataLen - \
(sizeof(NanMsgHeader) + sizeof(NanMatchIndParams)));
int ret = 0;
//Has SDF match filter and service specific info TLV
if (remainingLen <= 0) {
ALOGI("%s: No TLV's present",__func__);
return WIFI_SUCCESS;
}
ALOGI("%s: TLV remaining Len:%d",__func__, remainingLen);
while ((remainingLen > 0) &&
(0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv)))) {
ALOGI("%s: Remaining Len:%d readLen:%d type:%d length:%d",
__func__, remainingLen, readLen, outputTlv.type,
outputTlv.length);
switch (outputTlv.type) {
case NAN_TLV_TYPE_SERVICE_SPECIFIC_INFO:
if (outputTlv.length > NAN_MAX_SERVICE_NAME_LEN) {
outputTlv.length = NAN_MAX_SERVICE_NAME_LEN;
}
event->service_specific_info_len = outputTlv.length;
memcpy(event->service_specific_info, outputTlv.value,
outputTlv.length);
break;
case NAN_TLV_TYPE_SDF_MATCH_FILTER:
if (outputTlv.length > NAN_MAX_MATCH_FILTER_LEN) {
outputTlv.length = NAN_MAX_MATCH_FILTER_LEN;
}
event->sdf_match_filter_len = outputTlv.length;
memcpy(event->sdf_match_filter, outputTlv.value,
outputTlv.length);
break;
#ifdef NAN_2_0
case NAN_TLV_TYPE_MAC_ADDRESS:
if (outputTlv.length > sizeof(event->addr)) {
outputTlv.length = sizeof(event->addr);
}
memcpy(event->addr, outputTlv.value, outputTlv.length);
break;
case NAN_TLV_TYPE_RECEIVED_RSSI_VALUE:
if (outputTlv.length > sizeof(event->rssi_value)) {
outputTlv.length = sizeof(event->rssi_value);
}
memcpy(&event->rssi_value, outputTlv.value,
outputTlv.length);
break;
case NAN_TLV_TYPE_POST_NAN_CONNECTIVITY_CAPABILITIES_RECEIVE:
if (outputTlv.length != sizeof(u32)) {
ALOGE("NAN_TLV_TYPE_POST_NAN_CONNECTIVITY_CAPABILITIES_RECEIVE"
"Incorrect size:%d expecting %d", outputTlv.length,
sizeof(u32));
break;
}
event->is_conn_capability_valid = 1;
/* Populate conn_capability from received TLV */
getNanReceivePostConnectivityCapabilityVal(outputTlv.value,
&event->conn_capability);
break;
case NAN_TLV_TYPE_POST_NAN_DISCOVERY_ATTRIBUTE_RECEIVE:
/* Populate receive discovery attribute from
received TLV */
ret = getNanReceivePostDiscoveryVal(outputTlv.value,
outputTlv.length,
&event->discovery_attr);
if (ret == 0) {
event->is_discovery_attr_valid = 1;
}
else {
ALOGE("NAN_TLV_TYPE_POST_NAN_DISCOVERY_ATTRIBUTE_RECEIVE"
"Incorrect");
}
break;
case NAN_TLV_TYPE_FURTHER_AVAILABILITY_MAP:
/* Populate further availability bitmap from
received TLV */
ret = getNanFurtherAvailabilityMap(outputTlv.value,
outputTlv.length,
&event->fam);
if (ret == 0) {
event->is_fam_valid = 1;
}
else {
ALOGE("NAN_TLV_TYPE_FURTHER_AVAILABILITY_MAP"
"Incorrect");
}
break;
case NAN_TLV_TYPE_CLUSTER_ATTIBUTE:
if (outputTlv.length > sizeof(event->cluster_attribute)) {
outputTlv.length = sizeof(event->cluster_attribute);
}
memcpy(event->cluster_attribute,
outputTlv.value, outputTlv.length);
event->cluster_attribute_len = outputTlv.length;
break;
#endif /* NAN_2_0 */
default:
ALOGI("Unknown TLV type skipped");
break;
}
remainingLen -= readLen;
pInputTlv += readLen;
memset(&outputTlv, 0, sizeof(outputTlv));
}
return WIFI_SUCCESS;
}
int NanCommand::getNanUnMatch(NanUnmatchInd *event)
{
if (event == NULL || mNanVendorEvent == NULL) {
ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p",
__func__, event, mNanVendorEvent);
return WIFI_ERROR_INVALID_ARGS;
}
pNanUnmatchIndMsg pRsp = (pNanUnmatchIndMsg)mNanVendorEvent;
event->header.handle = pRsp->fwHeader.handle;
event->header.transaction_id = pRsp->fwHeader.transactionId;
event->match_handle = pRsp->unmatchIndParams.matchHandle;
return WIFI_SUCCESS;
}
int NanCommand::getNanSubscribeTerminated(NanSubscribeTerminatedInd *event)
{
if (event == NULL || mNanVendorEvent == NULL) {
ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p",
__func__, event, mNanVendorEvent);
return WIFI_ERROR_INVALID_ARGS;
}
pNanSubscribeTerminatedIndMsg pRsp = (pNanSubscribeTerminatedIndMsg)mNanVendorEvent;
event->header.handle = pRsp->fwHeader.handle;
event->header.transaction_id = pRsp->fwHeader.transactionId;
#ifdef NAN_2_0
pRsp->reason -= NAN_TERMINATED_BEGINNING_OFFSET;
#endif /* NAN_2_0 */
event->reason = (NanTerminatedStatus)pRsp->reason;
return WIFI_SUCCESS;
}
int NanCommand::getNanFollowup(NanFollowupInd *event)
{
if (event == NULL || mNanVendorEvent == NULL) {
ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p",
__func__, event, mNanVendorEvent);
return WIFI_ERROR_INVALID_ARGS;
}
pNanFollowupIndMsg pRsp = (pNanFollowupIndMsg)mNanVendorEvent;
event->header.handle = pRsp->fwHeader.handle;
event->header.transaction_id = pRsp->fwHeader.transactionId;
#ifndef NAN_2_0
memcpy(event->addr, pRsp->followupIndParams.macAddr, sizeof(event->addr));
#else /* NAN_2_0*/
event->match_handle = pRsp->followupIndParams.matchHandle;
#endif
event->dw_or_faw = pRsp->followupIndParams.window;
u8 *pInputTlv = pRsp->ptlv;
NanTlv outputTlv;
u16 readLen = 0;
int remainingLen = (mNanDataLen - \
(sizeof(NanMsgHeader) + sizeof(NanFollowupIndParams)));
//Has service specific info and extended service specific info TLV
if (remainingLen <= 0) {
ALOGI("%s: No TLV's present",__func__);
return WIFI_SUCCESS;
}
ALOGI("%s: TLV remaining Len:%d",__func__, remainingLen);
while ((remainingLen > 0) &&
(0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv)))) {
ALOGI("%s: Remaining Len:%d readLen:%d type:%d length:%d",
__func__, remainingLen, readLen, outputTlv.type,
outputTlv.length);
switch (outputTlv.type) {
case NAN_TLV_TYPE_SERVICE_SPECIFIC_INFO:
case NAN_TLV_TYPE_EXT_SERVICE_SPECIFIC_INFO:
if (outputTlv.length > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
outputTlv.length = NAN_MAX_SERVICE_SPECIFIC_INFO_LEN;
}
event->service_specific_info_len = outputTlv.length;
memcpy(event->service_specific_info, outputTlv.value,
outputTlv.length);
break;
#ifdef NAN_2_0
case NAN_TLV_TYPE_MAC_ADDRESS:
if (outputTlv.length > sizeof(event->addr)) {
outputTlv.length = sizeof(event->addr);
}
memcpy(event->addr, outputTlv.value, outputTlv.length);
break;
#endif /* NAN_2_0 */
default:
ALOGI("Unknown TLV type skipped");
break;
}
remainingLen -= readLen;
pInputTlv += readLen;
memset(&outputTlv, 0, sizeof(outputTlv));
}
return WIFI_SUCCESS;
}
int NanCommand::getNanDiscEngEvent(NanDiscEngEventInd *event)
{
if (event == NULL || mNanVendorEvent == NULL) {
ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p",
__func__, event, mNanVendorEvent);
return WIFI_ERROR_INVALID_ARGS;
}
pNanEventIndMsg pRsp = (pNanEventIndMsg)mNanVendorEvent;
event->header.handle = pRsp->fwHeader.handle;
event->header.transaction_id = pRsp->fwHeader.transactionId;
#ifndef NAN_2_0
event->event_id = (NanEventId)pRsp->eventIndParams.eventId;
#endif /* NAN_2_0 */
memset(&event->data, 0, sizeof(event->data));
u8 *pInputTlv = pRsp->ptlv;
NanTlv outputTlv;
u16 readLen = 0;
#ifndef NAN_2_0
int remainingLen = (mNanDataLen - \
(sizeof(NanMsgHeader) + sizeof(NanEventIndParams)));
#else /* NAN_2_0 */
int remainingLen = (mNanDataLen - \
(sizeof(NanMsgHeader)));
#endif /* NAN_2_0 */
//Has Self-STA Mac TLV
if (remainingLen <= 0) {
ALOGI("%s: No TLV's present",__func__);
return WIFI_SUCCESS;
}
ALOGI("%s: TLV remaining Len:%d event_id:%d",__func__,
remainingLen, event->event_id);
while ((remainingLen > 0) &&
(0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv)))) {
ALOGI("%s: Remaining Len:%d readLen:%d type:%d length:%d",
__func__, remainingLen, readLen, outputTlv.type,
outputTlv.length);
#ifdef NAN_2_0
event->event_id = (NanEventId)outputTlv.type;
#endif /* NAN_2_0 */
//Here we should check on the event_id
switch (event->event_id) {
case NAN_EVENT_ID_STA_MAC_ADDR:
if (outputTlv.length > NAN_MAC_ADDR_LEN) {
ALOGI("%s: Reading only first %d bytes of TLV",
__func__, NAN_MAC_ADDR_LEN);
outputTlv.length = NAN_MAC_ADDR_LEN;
}
memcpy(event->data.mac_addr.addr, outputTlv.value,
outputTlv.length);
break;
case NAN_EVENT_ID_STARTED_CLUSTER:
case NAN_EVENT_ID_JOINED_CLUSTER:
if (outputTlv.length > NAN_MAC_ADDR_LEN) {
ALOGI("%s: Reading only first %d bytes of TLV",
__func__, NAN_MAC_ADDR_LEN);
outputTlv.length = NAN_MAC_ADDR_LEN;
}
memcpy(event->data.cluster.addr, outputTlv.value,
outputTlv.length);
break;
default:
ALOGI("Unhandled eventId:%d", event->event_id);
break;
}
remainingLen -= readLen;
pInputTlv += readLen;
memset(&outputTlv,0, sizeof(outputTlv));
}
return WIFI_SUCCESS;
}
int NanCommand::getNanDisabled(NanDisabledInd *event)
{
if (event == NULL || mNanVendorEvent == NULL) {
ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p",
__func__, event, mNanVendorEvent);
return WIFI_ERROR_INVALID_ARGS;
}
pNanDisableIndMsg pRsp = (pNanDisableIndMsg)mNanVendorEvent;
event->header.handle = pRsp->fwHeader.handle;
event->header.transaction_id = pRsp->fwHeader.transactionId;
event->reason = (NanStatusType)pRsp->reason;
return WIFI_SUCCESS;
}
int NanCommand::getNanTca(NanTCAInd *event)
{
if (event == NULL || mNanVendorEvent == NULL) {
ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p",
__func__, event, mNanVendorEvent);
return WIFI_ERROR_INVALID_ARGS;
}
pNanTcaIndMsg pRsp = (pNanTcaIndMsg)mNanVendorEvent;
event->header.handle = pRsp->fwHeader.handle;
event->header.transaction_id = pRsp->fwHeader.transactionId;
memset(&event->data, 0, sizeof(event->data));
#ifndef NAN_2_0
event->tca_id = (NanTcaId)pRsp->tcaIndParams.tcaId;
#else /* NAN_2_0 */
event->tca_id = (NanTcaId)0;
#endif /* NAN_2_0 */
u8 *pInputTlv = pRsp->ptlv;
NanTlv outputTlv;
u16 readLen = 0;
#ifndef NAN_2_0
int remainingLen = (mNanDataLen - \
(sizeof(NanMsgHeader) + sizeof(NanTcaIndParams)));
#else
int remainingLen = (mNanDataLen - \
(sizeof(NanMsgHeader)));
#endif
//Has NAN_TCA_ID_CLUSTER_SIZE
if (remainingLen <= 0) {
ALOGI("%s: No TLV's present",__func__);
return WIFI_SUCCESS;
}
ALOGI("%s: TLV remaining Len:%d tca_id:%d",__func__,
remainingLen, event->tca_id);
while ((remainingLen > 0) &&
(0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv)))) {
ALOGI("%s: Remaining Len:%d readLen:%d type:%d length:%d",
__func__, remainingLen, readLen, outputTlv.type,
outputTlv.length);
//Here we should check on the event_id
switch (event->tca_id) {
case NAN_TCA_ID_CLUSTER_SIZE:
#ifndef NAN_2_0
if (outputTlv.length > sizeof(event->data.cluster.cluster_size)) {
outputTlv.length = sizeof(event->data.cluster.cluster_size);
}
memcpy(&(event->data.cluster.cluster_size), outputTlv.value,
outputTlv.length);
#else /* NAN_2_0 */
if (outputTlv.length != 2 * sizeof(u32)) {
ALOGE("%s: Wrong length %d in Tca Indication expecting %d bytes",
__func__, outputTlv.length, 2 * sizeof(u32));
break;
}
event->rising_direction_evt_flag = outputTlv.value[0] & 0x01;
event->falling_direction_evt_flag = (outputTlv.value[0] & 0x02) >> 1;
memcpy(&(event->data.cluster.cluster_size), &outputTlv.value[4],
sizeof(event->data.cluster.cluster_size));
#endif /* NAN_2_0 */
break;
default:
ALOGI("Unhandled eventId:%d", event->tca_id);
break;
}
remainingLen -= readLen;
pInputTlv += readLen;
memset(&outputTlv,0, sizeof(outputTlv));
}
return WIFI_SUCCESS;
}
int NanCommand::getNanBeaconSdfPayload(NanBeaconSdfPayloadInd *event)
{
if (event == NULL || mNanVendorEvent == NULL) {
ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p",
__func__, event, mNanVendorEvent);
return WIFI_ERROR_INVALID_ARGS;
}
#ifdef NAN_2_0
pNanBeaconSdfPayloadIndMsg pRsp = (pNanBeaconSdfPayloadIndMsg)mNanVendorEvent;
event->header.handle = pRsp->fwHeader.handle;
event->header.transaction_id = pRsp->fwHeader.transactionId;
memset(&event->data, 0, sizeof(event->data));
u8 *pInputTlv = pRsp->ptlv;
NanTlv outputTlv;
u16 readLen = 0;
int remainingLen = (mNanDataLen - \
(sizeof(NanMsgHeader)));
//Has Mac address
if (remainingLen <= 0) {
ALOGI("%s: No TLV's present",__func__);
return WIFI_SUCCESS;
}
ALOGI("%s: TLV remaining Len:%d",__func__, remainingLen);
while ((remainingLen > 0) &&
(0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv)))) {
ALOGI("%s: Remaining Len:%d readLen:%d type:%d length:%d",
__func__, remainingLen, readLen, outputTlv.type,
outputTlv.length);
//Here we should check on the event_id
switch (outputTlv.type) {
case NAN_TLV_TYPE_SELF_MAC_ADDR:
if (outputTlv.length > sizeof(event->addr)) {
outputTlv.length = sizeof(event->addr);
}
memcpy(event->addr, outputTlv.value,
outputTlv.length);
break;
case NAN_TLV_TYPE_VENDOR_SPECIFIC_ATTRIBUTE_RECEIVE:
{
NanReceiveVendorSpecificAttribute* recvVsaattr = &event->vsa;
if (outputTlv.length < sizeof(u32)) {
ALOGE("NAN_TLV_TYPE_VENDOR_SPECIFIC_ATTRIBUTE_RECEIVE"
"Incorrect length:%d", outputTlv.length);
break;
}
event->is_vsa_received = 1;
recvVsaattr->vsa_received_on = (outputTlv.value[0] >> 1) & 0x07;
memcpy(&recvVsaattr->vendor_oui, &outputTlv.value[1],
3);
recvVsaattr->attr_len = outputTlv.length - 4;
if (recvVsaattr->attr_len > NAN_MAX_VSA_DATA_LEN) {
recvVsaattr->attr_len = NAN_MAX_VSA_DATA_LEN;
}
if (recvVsaattr->attr_len) {
memcpy(recvVsaattr->vsa, &outputTlv.value[4],
recvVsaattr->attr_len);
}
break;
}
case NAN_TLV_TYPE_BEACON_SDF_PAYLOAD_RECEIVE:
event->is_beacon_sdf_payload_received = 1;
event->data.frame_len = outputTlv.length;
if (event->data.frame_len > NAN_MAX_VSA_DATA_LEN) {
event->data.frame_len = NAN_MAX_VSA_DATA_LEN;
}
memcpy(&event->data.frame_data, &outputTlv.value[0],
event->data.frame_len);
break;
default:
ALOGI("Unhandled TLV Type:%d", outputTlv.type);
break;
}
remainingLen -= readLen;
pInputTlv += readLen;
memset(&outputTlv,0, sizeof(outputTlv));
}
return WIFI_SUCCESS;
#else /* NAN_2_0 */
return WIFI_ERROR_INVALID_ARGS;
#endif /* NAN_2_0 */
}
void NanCommand::getNanReceivePostConnectivityCapabilityVal(
const u8 *pInValue,
NanReceivePostConnectivityCapability *pRxCapab)
{
if (pInValue && pRxCapab) {
pRxCapab->is_mesh_supported = (pInValue[0] && (0x01 << 5));
pRxCapab->is_ibss_supported = (pInValue[0] && (0x01 << 4));
pRxCapab->wlan_infra_field = (pInValue[0] && (0x01 << 3));
pRxCapab->is_tdls_supported = (pInValue[0] && (0x01 << 2));
pRxCapab->is_wfds_supported = (pInValue[0] && (0x01 << 1));
pRxCapab->is_wfd_supported = pInValue[0] && 0x01;
}
}
int NanCommand::getNanReceivePostDiscoveryVal(const u8 *pInValue,
u32 length,
NanReceivePostDiscovery *pRxDisc)
{
int ret = 0;
#ifdef NAN_2_0
if (length <= 8 || pInValue == NULL) {
ALOGE("%s: Invalid Arg TLV Len %d < 4",
__func__, length);
return -1;
}
pRxDisc->type = (NanConnectionType) pInValue[0];
pRxDisc->role = (NanDeviceRole) pInValue[1];
pRxDisc->duration = (NanAvailDuration) (pInValue[2] & 0x03);
pRxDisc->mapid = ((pInValue[2] >> 2) & 0x0F);
memcpy(&pRxDisc->avail_interval_bitmap,
&pInValue[4],
sizeof(pRxDisc->avail_interval_bitmap));
u8 *pInputTlv = (u8 *)&pInValue[8];
NanTlv outputTlv;
u16 readLen = 0;
int remainingLen = (length - 8);
//Has Mac address
if (remainingLen <= 0) {
ALOGE("%s: No TLV's present",__func__);
return -1;
}
ALOGI("%s: TLV remaining Len:%d",__func__, remainingLen);
while ((remainingLen > 0) &&
(0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv)))) {
ALOGI("%s: Remaining Len:%d readLen:%d type:%d length:%d",
__func__, remainingLen, readLen, outputTlv.type,
outputTlv.length);
switch (outputTlv.type) {
case NAN_TLV_TYPE_MAC_ADDRESS:
if (outputTlv.length > sizeof(pRxDisc->addr)) {
outputTlv.length = sizeof(pRxDisc->addr);
}
memcpy(pRxDisc->addr, outputTlv.value, outputTlv.length);
break;
case NAN_TLV_TYPE_WLAN_MESH_ID:
if (outputTlv.length > sizeof(pRxDisc->mesh_id)) {
outputTlv.length = sizeof(pRxDisc->mesh_id);
}
memcpy(pRxDisc->mesh_id, outputTlv.value, outputTlv.length);
pRxDisc->mesh_id_len = outputTlv.length;
break;
case NAN_TLV_TYPE_WLAN_INFRASTRUCTURE_SSID:
if (outputTlv.length > sizeof(pRxDisc->infrastructure_ssid_val)) {
outputTlv.length = sizeof(pRxDisc->infrastructure_ssid_val);
}
memcpy(pRxDisc->infrastructure_ssid_val, outputTlv.value,
outputTlv.length);
pRxDisc->infrastructure_ssid_len = outputTlv.length;
default:
ALOGI("Unhandled TLV Type:%d", outputTlv.type);
break;
}
remainingLen -= readLen;
pInputTlv += readLen;
memset(&outputTlv,0, sizeof(outputTlv));
}
#endif /* NAN_2_0 */
return ret;
}
int NanCommand::getNanFurtherAvailabilityMap(const u8 *pInValue,
u32 length,
NanFurtherAvailabilityMap *pFam)
{
#ifdef NAN_2_0
int idx = 0;
if ((length == 0) || pInValue == NULL) {
ALOGE("%s: Invalid Arg TLV Len %d or pInValue NULL",
__func__, length);
return -1;
}
pFam->numchans = pInValue[0];
if (pFam->numchans > NAN_MAX_FAM_CHANNELS) {
ALOGE("%s: Unable to accommodate numchans %d",
__func__, pFam->numchans);
return -1;
}
if (length < (sizeof(u8) +
(pFam->numchans * sizeof(NanFurtherAvailabilityChan)))) {
ALOGE("%s: Invalid TLV Length", __func__);
return -1;
}
for (idx = 0; idx < pFam->numchans; idx++) {
pNanFurtherAvailabilityChan pRsp = \
(pNanFurtherAvailabilityChan)((u8 *)&pInValue[1] + \
(idx * sizeof(NanFurtherAvailabilityChan)));
NanFurtherAvailabilityChannel *pFamChan = &pFam->famchan[idx];
pFamChan->entry_control = \
(NanAvailDuration)(pRsp->entryCtrl.availIntDuration);
pFamChan->mapid = pRsp->entryCtrl.mapId;
pFamChan->class_val = pRsp->opClass;
pFamChan->channel = pRsp->channel;
memcpy(&pFamChan->avail_interval_bitmap,
&pRsp->availIntBitmap,
sizeof(pFamChan->avail_interval_bitmap));
}
#endif /* NAN_2_0*/
return 0;
}
int NanCommand::getNanStaParameter(NanStaParameter *pRsp)
{
int ret = WIFI_ERROR_NONE;
int res = -1;
/*
Construct NL message to get the sync stats parameter
which has all the parameter required by staparameter.
*/
NanStatsRequest syncStats;
memset(&syncStats, 0, sizeof(syncStats));
syncStats.header.handle = 0x0;
syncStats.header.transaction_id = 0x1234;
syncStats.stats_id = NAN_STATS_ID_DE_TIMING_SYNC;
syncStats.clear = 0;
mStaParam = pRsp;
ret = putNanStats(&syncStats);
if (ret != 0) {
ALOGE("%s: putNanStats Error:%d",__func__, ret);
goto cleanup;
}
ret = requestEvent();
if (ret != 0) {
ALOGE("%s: requestEvent Error:%d",__func__, ret);
goto cleanup;
}
struct timespec abstime;
abstime.tv_sec = 4;
abstime.tv_nsec = 0;
res = mCondition.wait(abstime);
if (res == ETIMEDOUT)
{
ALOGE("%s: Time out happened.", __func__);
ret = WIFI_ERROR_TIMED_OUT;
goto cleanup;
}
ALOGI("%s: NanStaparameter Master_pref:%x," \
" Random_factor:%x, hop_count:%x " \
" beacon_transmit_time:%d", __func__,
pRsp->master_pref, pRsp->random_factor,
pRsp->hop_count, pRsp->beacon_transmit_time);
cleanup:
mStaParam = NULL;
return (int)ret;
}