C++程序  |  1154行  |  42.46 KB

/*
 * 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 "wifi_hal.h"
#include "nan_i.h"
#include "nancommand.h"
#include <errno.h>

//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;

    msg_id = getIndicationType();

    ALOGV("handleNanIndication msg_id:%u", msg_id);
    switch (msg_id) {
    case NAN_INDICATION_PUBLISH_TERMINATED:
        NanPublishTerminatedInd publishTerminatedInd;
        memset(&publishTerminatedInd, 0, sizeof(publishTerminatedInd));
        res = getNanPublishTerminated(&publishTerminatedInd);
        if (!res && mHandler.EventPublishTerminated) {
            (*mHandler.EventPublishTerminated)(&publishTerminatedInd);
        }
        break;

    case NAN_INDICATION_MATCH:
        NanMatchInd matchInd;
        memset(&matchInd, 0, sizeof(matchInd));
        res = getNanMatch(&matchInd);
        if (!res && mHandler.EventMatch) {
            (*mHandler.EventMatch)(&matchInd);
        }
        break;

    case NAN_INDICATION_MATCH_EXPIRED:
        NanMatchExpiredInd matchExpiredInd;
        memset(&matchExpiredInd, 0, sizeof(matchExpiredInd));
        res = getNanMatchExpired(&matchExpiredInd);
        if (!res && mHandler.EventMatchExpired) {
            (*mHandler.EventMatchExpired)(&matchExpiredInd);
        }
        break;

    case NAN_INDICATION_SUBSCRIBE_TERMINATED:
        NanSubscribeTerminatedInd subscribeTerminatedInd;
        memset(&subscribeTerminatedInd, 0, sizeof(subscribeTerminatedInd));
        res = getNanSubscribeTerminated(&subscribeTerminatedInd);
        if (!res && mHandler.EventSubscribeTerminated) {
            (*mHandler.EventSubscribeTerminated)(&subscribeTerminatedInd);
        }
        break;

    case NAN_INDICATION_DE_EVENT:
        NanDiscEngEventInd discEngEventInd;
        memset(&discEngEventInd, 0, sizeof(discEngEventInd));
        res = getNanDiscEngEvent(&discEngEventInd);
        if (!res && mHandler.EventDiscEngEvent) {
            (*mHandler.EventDiscEngEvent)(&discEngEventInd);
        }
        break;

    case NAN_INDICATION_FOLLOWUP:
        NanFollowupInd followupInd;
        memset(&followupInd, 0, sizeof(followupInd));
        res = getNanFollowup(&followupInd);
        if (!res && mHandler.EventFollowup) {
            (*mHandler.EventFollowup)(&followupInd);
        }
        break;

    case NAN_INDICATION_DISABLED:
        NanDisabledInd disabledInd;
        memset(&disabledInd, 0, sizeof(disabledInd));
        res = getNanDisabled(&disabledInd);
        if (!res && mHandler.EventDisabled) {
            (*mHandler.EventDisabled)(&disabledInd);
        }
        break;

    case NAN_INDICATION_TCA:
        NanTCAInd tcaInd;
        memset(&tcaInd, 0, sizeof(tcaInd));
        res = getNanTca(&tcaInd);
        if (!res && mHandler.EventTca) {
            (*mHandler.EventTca)(&tcaInd);
        }
        break;

    case NAN_INDICATION_BEACON_SDF_PAYLOAD:
        NanBeaconSdfPayloadInd beaconSdfPayloadInd;
        memset(&beaconSdfPayloadInd, 0, sizeof(beaconSdfPayloadInd));
        res = getNanBeaconSdfPayload(&beaconSdfPayloadInd);
        if (!res && mHandler.EventBeaconSdfPayload) {
            (*mHandler.EventBeaconSdfPayload)(&beaconSdfPayloadInd);
        }
        break;

    case NAN_INDICATION_SELF_TRANSMIT_FOLLOWUP:
        NanTransmitFollowupInd transmitFollowupInd;
        memset(&transmitFollowupInd, 0, sizeof(NanTransmitFollowupInd));
        res = getNanTransmitFollowupInd(&transmitFollowupInd);
        if (!res && mHandler.EventTransmitFollowup) {
            (*mHandler.EventTransmitFollowup)(&transmitFollowupInd);
        }
        break;

    case NAN_INDICATION_RANGING_REQUEST_RECEIVED:
        NanRangeRequestInd rangeRequestInd;
        memset(&rangeRequestInd, 0, sizeof(NanRangeRequestInd));
        res = getNanRangeRequestReceivedInd(&rangeRequestInd);
        if (!res && mHandler.EventRangeRequest) {
            (*mHandler.EventRangeRequest)(&rangeRequestInd);
        }
        break;

    case NAN_INDICATION_RANGING_RESULT:
        NanRangeReportInd rangeReportInd;
        memset(&rangeReportInd, 0, sizeof(NanRangeReportInd));
        res = getNanRangeReportInd(&rangeReportInd);
        if (!res && mHandler.EventRangeReport) {
            (*mHandler.EventRangeReport)(&rangeReportInd);
        }
        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_UNKNOWN;
    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_MATCH_EXPIRED_IND:
        return NAN_INDICATION_MATCH_EXPIRED;
    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;
    case NAN_MSG_ID_BEACON_SDF_IND:
        return NAN_INDICATION_BEACON_SDF_PAYLOAD;
    case NAN_MSG_ID_SELF_TRANSMIT_FOLLOWUP_IND:
        return NAN_INDICATION_SELF_TRANSMIT_FOLLOWUP;
    case NAN_MSG_ID_RANGING_REQUEST_RECEVD_IND:
        return NAN_INDICATION_RANGING_REQUEST_RECEIVED;
    case NAN_MSG_ID_RANGING_RESULT_IND:
        return NAN_INDICATION_RANGING_RESULT;
    default:
        return NAN_INDICATION_UNKNOWN;
    }
}

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->publish_id = pRsp->fwHeader.handle;
    NanErrorTranslation((NanInternalStatusType)pRsp->reason, 0,
                        (void*)event);
    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->publish_subscribe_id = pRsp->fwHeader.handle;
    event->requestor_instance_id = pRsp->matchIndParams.matchHandle;
    event->match_occured_flag = pRsp->matchIndParams.matchOccuredFlag;
    event->out_of_resource_flag = pRsp->matchIndParams.outOfResourceFlag;

    u8 *pInputTlv = pRsp->ptlv;
    NanTlv outputTlv;
    u16 readLen = 0;
    int remainingLen = (mNanDataLen - \
        (sizeof(NanMsgHeader) + sizeof(NanMatchIndParams)));
    int ret = 0, idx = 0;

    //Has SDF match filter and service specific info TLV
    if (remainingLen <= 0) {
        ALOGV("%s: No TLV's present",__func__);
        return WIFI_SUCCESS;
    }
    ALOGV("%s: TLV remaining Len:%d",__func__, remainingLen);
    while ((remainingLen > 0) &&
           (0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv)))) {
        ALOGV("%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;
        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 %zu", 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 */
            idx = event->num_rx_discovery_attr;
            ret = getNanReceivePostDiscoveryVal(outputTlv.value,
                                                outputTlv.length,
                                                &event->discovery_attr[idx]);
            if (ret == 0) {
                event->num_rx_discovery_attr++;
            } 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->num_chans,
                                               &event->famchan[0]);
            if (ret < 0)
                ALOGE("NAN_TLV_TYPE_FURTHER_AVAILABILITY_MAP"
                      "Incorrect");
            break;
        case NAN_TLV_TYPE_CLUSTER_ATTRIBUTE:
            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;
        case NAN_TLV_TYPE_NAN_CSID:
            if (outputTlv.length > sizeof(event->peer_cipher_type)) {
                outputTlv.length = sizeof(event->peer_cipher_type);
            }
            memcpy(&event->peer_cipher_type, outputTlv.value,
                   outputTlv.length);
            break;
        case NAN_TLV_TYPE_NAN_SCID:
            if (outputTlv.length > sizeof(event->scid)) {
                outputTlv.length = sizeof(event->scid);
            }
            event->scid_len = outputTlv.length;
            memcpy(event->scid, outputTlv.value, outputTlv.length);
            break;
        case NAN_TLV_TYPE_SDEA_CTRL_PARAMS:
            if (outputTlv.length != sizeof(u32)) {
                ALOGE("NAN_TLV_TYPE_SDEA_CTRL_PARAMS"
                      "Incorrect size:%d expecting %zu", outputTlv.length,
                      sizeof(u32));
                break;
            }
            getNanReceiveSdeaCtrlParams(outputTlv.value,
                                             &event->peer_sdea_params);
            break;
        case NAN_TLV_TYPE_NAN20_RANGING_RESULT:
            if (outputTlv.length > sizeof(event->range_info)) {
                outputTlv.length = sizeof(event->range_info);
            }
            memcpy(&event->range_info, outputTlv.value, outputTlv.length);
            break;
        case NAN_TLV_TYPE_SDEA_SERVICE_SPECIFIC_INFO:
            if (outputTlv.length > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
                outputTlv.length = NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN;
            }
            event->sdea_service_specific_info_len = outputTlv.length;
            memcpy(event->sdea_service_specific_info, outputTlv.value,
                   outputTlv.length);
            break;
        default:
            ALOGV("Unknown TLV type skipped");
            break;
        }
        remainingLen -= readLen;
        pInputTlv += readLen;
        memset(&outputTlv, 0, sizeof(outputTlv));
    }
    return WIFI_SUCCESS;
}

int NanCommand::getNanMatchExpired(NanMatchExpiredInd *event)
{
    if (event == NULL || mNanVendorEvent == NULL) {
        ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p",
              __func__, event, mNanVendorEvent);
        return WIFI_ERROR_INVALID_ARGS;
    }

    pNanMatchExpiredIndMsg pRsp = (pNanMatchExpiredIndMsg)mNanVendorEvent;
    event->publish_subscribe_id = pRsp->fwHeader.handle;
    event->requestor_instance_id = pRsp->matchExpiredIndParams.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->subscribe_id = pRsp->fwHeader.handle;
    NanErrorTranslation((NanInternalStatusType)pRsp->reason, 0,
                        (void*)event);
    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->publish_subscribe_id = pRsp->fwHeader.handle;
    event->requestor_instance_id = pRsp->followupIndParams.matchHandle;
    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) {
        ALOGV("%s: No TLV's present",__func__);
        return WIFI_SUCCESS;
    }
    ALOGV("%s: TLV remaining Len:%d",__func__, remainingLen);
    while ((remainingLen > 0) &&
           (0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv)))) {
        ALOGV("%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;
        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_SDEA_SERVICE_SPECIFIC_INFO:
            if (outputTlv.length > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
                outputTlv.length = NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN;
            }
            event->sdea_service_specific_info_len = outputTlv.length;
            memcpy(event->sdea_service_specific_info, outputTlv.value,
                   outputTlv.length);
            break;
        default:
            ALOGV("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;
    memset(&event->data, 0, sizeof(event->data));

    u8 *pInputTlv = pRsp->ptlv;
    NanTlv outputTlv;
    u16 readLen = 0;
    int remainingLen = (mNanDataLen -  \
        (sizeof(NanMsgHeader)));

    //Has Self-STA Mac TLV
    if (remainingLen <= 0) {
        ALOGE("%s: No TLV's present",__func__);
        return WIFI_SUCCESS;
    }

    ALOGV("%s: TLV remaining Len:%d",__func__, remainingLen);
    while ((remainingLen > 0) &&
           (0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv)))) {
        ALOGV("%s: Remaining Len:%d readLen:%d type:%d length:%d",
              __func__, remainingLen, readLen, outputTlv.type,
              outputTlv.length);
        switch (outputTlv.type) {
        case NAN_TLV_TYPE_EVENT_SELF_STATION_MAC_ADDRESS:
            if (outputTlv.length > NAN_MAC_ADDR_LEN) {
                ALOGV("%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);
            event->event_type = NAN_EVENT_ID_DISC_MAC_ADDR;
            break;
        case NAN_TLV_TYPE_EVENT_STARTED_CLUSTER:
            if (outputTlv.length > NAN_MAC_ADDR_LEN) {
                ALOGV("%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);
            event->event_type = NAN_EVENT_ID_STARTED_CLUSTER;
            break;
        case NAN_TLV_TYPE_EVENT_JOINED_CLUSTER:
            if (outputTlv.length > NAN_MAC_ADDR_LEN) {
                ALOGV("%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);
            event->event_type = NAN_EVENT_ID_JOINED_CLUSTER;
            break;
        default:
            ALOGV("Unhandled TLV type:%d", outputTlv.type);
            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;
    NanErrorTranslation((NanInternalStatusType)pRsp->reason, 0,
                        (void*)event);
    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;
    memset(&event->data, 0, sizeof(event->data));

    u8 *pInputTlv = pRsp->ptlv;
    NanTlv outputTlv;
    u16 readLen = 0;

    int remainingLen = (mNanDataLen -  \
        (sizeof(NanMsgHeader)));

    //Has NAN_TCA_ID_CLUSTER_SIZE
    if (remainingLen <= 0) {
        ALOGE("%s: No TLV's present",__func__);
        return WIFI_SUCCESS;
    }

    ALOGV("%s: TLV remaining Len:%d",__func__, remainingLen);
    while ((remainingLen > 0) &&
           (0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv)))) {
        ALOGV("%s: Remaining Len:%d readLen:%d type:%d length:%d",
              __func__, remainingLen, readLen, outputTlv.type,
              outputTlv.length);
        switch (outputTlv.type) {
        case NAN_TLV_TYPE_CLUSTER_SIZE_RSP:
            if (outputTlv.length != 2 * sizeof(u32)) {
                ALOGE("%s: Wrong length %d in Tca Indication expecting %zu 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));
            event->tca_type = NAN_TCA_ID_CLUSTER_SIZE;
            break;
        default:
            ALOGV("Unhandled TLV type:%d", outputTlv.type);
            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;
    }

    pNanBeaconSdfPayloadIndMsg pRsp = (pNanBeaconSdfPayloadIndMsg)mNanVendorEvent;
    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) {
        ALOGV("%s: No TLV's present",__func__);
        return WIFI_SUCCESS;
    }

    ALOGV("%s: TLV remaining Len:%d",__func__, remainingLen);
    while ((remainingLen > 0) &&
           (0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv)))) {
        ALOGV("%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_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_FRAME_DATA_LEN) {
                event->data.frame_len = NAN_MAX_FRAME_DATA_LEN;
            }
            memcpy(&event->data.frame_data, &outputTlv.value[0],
                   event->data.frame_len);
            break;

        default:
            ALOGV("Unhandled TLV Type:%d", outputTlv.type);
            break;
        }
        remainingLen -= readLen;
        pInputTlv += readLen;
        memset(&outputTlv,0, sizeof(outputTlv));
    }
    return WIFI_SUCCESS;
}

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;
    }
}

void NanCommand::getNanReceiveSdeaCtrlParams(const u8* pInValue,
    NanSdeaCtrlParams *pPeerSdeaParams)
{
    if (pInValue && pPeerSdeaParams) {
        pPeerSdeaParams->security_cfg =
                          (NanDataPathSecurityCfgStatus)((pInValue[0] & BIT_6) ?
                           NAN_DP_CONFIG_SECURITY : NAN_DP_CONFIG_NO_SECURITY);
        pPeerSdeaParams->ranging_state =
                           (NanRangingState)((pInValue[0] & BIT_7) ?
                            NAN_RANGING_ENABLE : NAN_RANGING_DISABLE);
#if 0
        pPeerSdeaParams->enable_ranging_limit =
                         (NanRangingLimitState)((pInValue[0] & BIT_8) ?
                          NAN_RANGING_LIMIT_ENABLE : NAN_RANGING_LIMIT_DISABLE);
#endif
    }
    return;
}

int NanCommand::getNanReceivePostDiscoveryVal(const u8 *pInValue,
                                              u32 length,
                                              NanReceivePostDiscovery *pRxDisc)
{
    int ret = 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;
    }

    ALOGV("%s: TLV remaining Len:%d",__func__, remainingLen);
    while ((remainingLen > 0) &&
           (0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv)))) {
        ALOGV("%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_INFRA_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:
            ALOGV("Unhandled TLV Type:%d", outputTlv.type);
            break;
        }
        remainingLen -= readLen;
        pInputTlv += readLen;
        memset(&outputTlv,0, sizeof(outputTlv));
    }
    return ret;
}

int NanCommand::getNanFurtherAvailabilityMap(const u8 *pInValue,
                                             u32 length,
                                             u8 *num_chans,
                                             NanFurtherAvailabilityChannel *pFac)
{
    int idx = 0;

    if ((length == 0) || pInValue == NULL) {
        ALOGE("%s: Invalid Arg TLV Len %d or pInValue NULL",
              __func__, length);
        return -1;
    }

    *num_chans = pInValue[0];
    if (*num_chans > NAN_MAX_FAM_CHANNELS) {
        ALOGE("%s: Unable to accommodate numchans %d",
              __func__, *num_chans);
        return -1;
    }

    if (length < (sizeof(u8) +
        (*num_chans * sizeof(NanFurtherAvailabilityChan)))) {
        ALOGE("%s: Invalid TLV Length", __func__);
        return -1;
    }

    for (idx = 0; idx < *num_chans; idx++) {
        pNanFurtherAvailabilityChan pRsp = \
              (pNanFurtherAvailabilityChan)((u8 *)&pInValue[1] + \
              (idx * sizeof(NanFurtherAvailabilityChan)));

        pFac->entry_control = \
            (NanAvailDuration)(pRsp->entryCtrl.availIntDuration);
        pFac->mapid = pRsp->entryCtrl.mapId;
        pFac->class_val = pRsp->opClass;
        pFac->channel = pRsp->channel;
        memcpy(&pFac->avail_interval_bitmap,
               &pRsp->availIntBitmap,
               sizeof(pFac->avail_interval_bitmap));
        pFac++;
    }
    return 0;
}

int NanCommand::getNanStaParameter(wifi_interface_handle iface,
                                   NanStaParameter *pRsp)
{
    int ret = WIFI_ERROR_NONE;
    int res = -1;
    transaction_id id = 1;
    interface_info *ifaceInfo = getIfaceInfo(iface);

    ret = create();
    if (ret < 0)
        goto cleanup;

    /* Set the interface Id of the message. */
    ret = set_iface_id(ifaceInfo->name);
    if (ret < 0)
        goto cleanup;

    /*
       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.stats_type = NAN_STATS_ID_DE_TIMING_SYNC;
    syncStats.clear = 0;

    mStaParam = pRsp;
    ret = putNanStats(id, &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;
    }
    ALOGV("%s: NanStaparameter Master_pref:%x," \
          " Random_factor:%x, hop_count:%x " \
          " beacon_transmit_time:%d" \
          " ndp_channel_freq:%d", __func__,
          pRsp->master_pref, pRsp->random_factor,
          pRsp->hop_count, pRsp->beacon_transmit_time, pRsp->ndp_channel_freq);
cleanup:
    mStaParam = NULL;
    return (int)ret;
}

int NanCommand::getNanTransmitFollowupInd(NanTransmitFollowupInd *event)
{
    if (event == NULL || mNanVendorEvent == NULL) {
        ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p",
              __func__, event, mNanVendorEvent);
        return WIFI_ERROR_INVALID_ARGS;
    }

    pNanSelfTransmitFollowupIndMsg pRsp = (pNanSelfTransmitFollowupIndMsg)mNanVendorEvent;
    event->id = pRsp->fwHeader.transactionId;
    NanErrorTranslation((NanInternalStatusType)pRsp->reason, 0,
                        (void*)event);
    return WIFI_SUCCESS;
}

//Function which calls the necessaryIndication callback
//based on the indication type
int NanCommand::handleNdpIndication(u32 ndpCmdType, struct nlattr **tb_vendor)
{
    //Based on the message_id in the header determine the Indication type
    //and call the necessary callback handler
    int res = 0;

    ALOGI("handleNdpIndication msg_id:%u", ndpCmdType);
    switch (ndpCmdType) {
    case QCA_WLAN_VENDOR_ATTR_NDP_DATA_REQUEST_IND:
        NanDataPathRequestInd ndpRequestInd;
        memset(&ndpRequestInd, 0, sizeof(ndpRequestInd));

        res = getNdpRequest(tb_vendor, &ndpRequestInd);
        if (!res && mHandler.EventDataRequest) {
            (*mHandler.EventDataRequest)(&ndpRequestInd);
        }
        break;

    case QCA_WLAN_VENDOR_ATTR_NDP_CONFIRM_IND:
        NanDataPathConfirmInd ndpConfirmInd;
        memset(&ndpConfirmInd, 0, sizeof(ndpConfirmInd));

        res = getNdpConfirm(tb_vendor, &ndpConfirmInd);
        if (!res && mHandler.EventDataConfirm) {
            (*mHandler.EventDataConfirm)(&ndpConfirmInd);
        }
        break;

    case QCA_WLAN_VENDOR_ATTR_NDP_END_IND:
    {
        NanDataPathEndInd *ndpEndInd = NULL;
        u8 num_ndp_ids = 0;

        if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY]) {
            ALOGE("%s: QCA_WLAN_VENDOR_ATTR_NDP not found", __FUNCTION__);
            return WIFI_ERROR_INVALID_ARGS;
        }

        num_ndp_ids = (u8)(nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY])/sizeof(u32));
        ALOGD("%s: NDP Num Instance Ids : val %d", __FUNCTION__, num_ndp_ids);

        if (num_ndp_ids) {
            ndpEndInd =
                (NanDataPathEndInd *)malloc(sizeof(NanDataPathEndInd)+ (sizeof(u32) * num_ndp_ids));
            if (!ndpEndInd) {
                ALOGE("%s: ndp_instance_id malloc Failed", __FUNCTION__);
                return WIFI_ERROR_OUT_OF_MEMORY;
            }
            ndpEndInd->num_ndp_instances = num_ndp_ids;
            nla_memcpy(ndpEndInd->ndp_instance_id,
                       tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY],
                       sizeof(u32) * ndpEndInd->num_ndp_instances);
        }
        if (mHandler.EventDataEnd) {
            (*mHandler.EventDataEnd)(ndpEndInd);
        }
        free(ndpEndInd);
        break;
    }
    default:
        ALOGE("handleNdpIndication error invalid ndpCmdType:%u", ndpCmdType);
        res = (int)WIFI_ERROR_INVALID_REQUEST_ID;
        break;
    }
    return res;
}

int NanCommand::getNdpRequest(struct nlattr **tb_vendor,
                              NanDataPathRequestInd *event)
{
    u32 len = 0;

    if (event == NULL || tb_vendor == NULL) {
        ALOGE("%s: Invalid input argument event:%p tb_vendor:%p",
              __FUNCTION__, event, tb_vendor);
        return WIFI_ERROR_INVALID_ARGS;
    }
    if ((!tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID]) ||
        (!tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR]) ||
        (!tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID])) {
        ALOGE("%s: QCA_WLAN_VENDOR_ATTR_NDP not found", __FUNCTION__);
        return WIFI_ERROR_INVALID_ARGS;
    }

    event->service_instance_id = nla_get_u16(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID]);
    ALOGD("%s: Service Instance id : val %d", __FUNCTION__, event->service_instance_id);

    len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR]);
    len = ((sizeof(event->peer_disc_mac_addr) <= len) ? sizeof(event->peer_disc_mac_addr) : len);
    memcpy(&event->peer_disc_mac_addr[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR]), len);

    event->ndp_instance_id = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID]);
    ALOGD("%s: Ndp Instance id: %d", __FUNCTION__, event->ndp_instance_id);
    if (tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]) {
        len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]);
        len = ((sizeof(event->app_info.ndp_app_info) <= len) ? sizeof(event->app_info.ndp_app_info) : len);
        memcpy(&event->app_info.ndp_app_info[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]), len);
        event->app_info.ndp_app_info_len = len;
    } else {
        ALOGD("%s: NDP App Info not present", __FUNCTION__);
    }
    return WIFI_SUCCESS;
}

int NanCommand::getNdpConfirm(struct nlattr **tb_vendor,
                              NanDataPathConfirmInd *event)
{
    u32 len = 0;

    if (event == NULL || tb_vendor == NULL) {
        ALOGE("%s: Invalid input argument event:%p tb_vendor:%p",
              __FUNCTION__, event, tb_vendor);
        return WIFI_ERROR_INVALID_ARGS;
    }
    if ((!tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID]) ||
        (!tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR]) ||
        (!tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE])) {
        ALOGE("%s: QCA_WLAN_VENDOR_ATTR_NDP not found", __FUNCTION__);
        return WIFI_ERROR_INVALID_ARGS;
    }

    event->ndp_instance_id = nla_get_u16(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID]);
    ALOGD("%s: Service Instance id : val %d", __FUNCTION__, event->ndp_instance_id);

    len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR]);
    len = ((sizeof(event->peer_ndi_mac_addr) <= len) ? sizeof(event->peer_ndi_mac_addr) : len);
    memcpy(&event->peer_ndi_mac_addr[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR]), len);

    event->rsp_code = (NanDataPathResponseCode)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE]);
    ALOGD("%s: Response code %d", __FUNCTION__, event->rsp_code);

    if (tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]) {
        len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]);
        len = ((sizeof(event->app_info.ndp_app_info) <= len) ? sizeof(event->app_info.ndp_app_info) : len);
        memcpy(&event->app_info.ndp_app_info[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]), len);
        event->app_info.ndp_app_info_len = len;
    } else {
        ALOGD("%s: NDP App Info not present", __FUNCTION__);
    }
    return WIFI_SUCCESS;
}

int NanCommand::getNanRangeRequestReceivedInd(NanRangeRequestInd *event)
{
    if (event == NULL || mNanVendorEvent == NULL) {
        ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p",
              __func__, event, mNanVendorEvent);
        return WIFI_ERROR_INVALID_ARGS;
    }

    pNanFWRangeReqRecvdInd pRsp = (pNanFWRangeReqRecvdInd)mNanVendorEvent;

    u8 *pInputTlv = pRsp->ptlv;
    NanTlv outputTlv;
    u16 readLen = 0;

    int remainingLen = (mNanDataLen -  \
        (sizeof(NanMsgHeader)));

    if (remainingLen <= 0) {
        ALOGE("%s: No TLV's present",__func__);
        return WIFI_SUCCESS;
    }

    ALOGV("%s: TLV remaining Len:%d",__func__, remainingLen);
    while ((remainingLen > 0) &&
           (0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv)))) {
        ALOGV("%s: Remaining Len:%d readLen:%d type:%d length:%d",
              __func__, remainingLen, readLen, outputTlv.type,
              outputTlv.length);
        switch (outputTlv.type) {
        case NAN_TLV_TYPE_NAN20_RANGING_REQUEST_RECEIVED:
            NanFWRangeReqRecvdMsg fwRangeReqRecvd;
            if (outputTlv.length > sizeof(fwRangeReqRecvd)) {
                outputTlv.length = sizeof(fwRangeReqRecvd);
            }
            memcpy(&fwRangeReqRecvd, outputTlv.value, outputTlv.length);
            FW_MAC_ADDR_TO_CHAR_ARRAY(fwRangeReqRecvd.range_mac_addr, event->range_req_intf_addr);
            event->publish_id = fwRangeReqRecvd.range_id;
            break;
        default:
            ALOGV("Unhandled TLV type:%d", outputTlv.type);
            break;
        }
        remainingLen -= readLen;
        pInputTlv += readLen;
        memset(&outputTlv,0, sizeof(outputTlv));
    }
    return WIFI_SUCCESS;
}

int NanCommand::getNanRangeReportInd(NanRangeReportInd *event)
{
    if (event == NULL || mNanVendorEvent == NULL) {
        ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p",
              __func__, event, mNanVendorEvent);
        return WIFI_ERROR_INVALID_ARGS;
    }

    pNanFWRangeReportInd pRsp = (pNanFWRangeReportInd)mNanVendorEvent;

    u8 *pInputTlv = pRsp->ptlv;
    NanTlv outputTlv;
    u16 readLen = 0;

    int remainingLen = (mNanDataLen -  \
        (sizeof(NanMsgHeader)));

    if (remainingLen <= 0) {
        ALOGE("%s: No TLV's present",__func__);
        return WIFI_SUCCESS;
    }

    ALOGV("%s: TLV remaining Len:%d",__func__, remainingLen);
    while ((remainingLen > 0) &&
           (0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv)))) {
        ALOGV("%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 > NAN_MAC_ADDR_LEN) {
                outputTlv.length = NAN_MAC_ADDR_LEN;
            }
            memcpy(event->range_req_intf_addr, outputTlv.value, outputTlv.length);
            break;

        case NAN_TLV_TYPE_NAN20_RANGING_RESULT:
            NanFWRangeReportParams range_params;
            if (outputTlv.length > sizeof(NanFWRangeReportParams)) {
                outputTlv.length = sizeof(NanFWRangeReportParams);
            }
            memcpy(&range_params, outputTlv.value, outputTlv.length);
            event->range_measurement_cm = range_params.range_measurement;
            event->publish_id = range_params.publish_id;
//          event->event_type = range_params.event_type;
            break;
        default:
            ALOGV("Unhandled TLV type:%d", outputTlv.type);
            break;
        }
        remainingLen -= readLen;
        pInputTlv += readLen;
        memset(&outputTlv,0, sizeof(outputTlv));
    }
    return WIFI_SUCCESS;
}