| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * Changes from Qualcomm Innovation Center are provided under the following license: |
| * |
| * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted (subject to the limitations in the |
| * disclaimer below) provided that the following conditions are met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * |
| * * Neither the name of Qualcomm Innovation Center, Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE |
| * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT |
| * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
| * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
| * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "sync.h" |
| #include <utils/Log.h> |
| #include <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_REPLIED: |
| NanPublishRepliedInd publishRepliedInd; |
| memset(&publishRepliedInd, 0, sizeof(publishRepliedInd)); |
| res = getNanPublishReplied(&publishRepliedInd); |
| if (!res && mHandler.EventPublishReplied) { |
| (*mHandler.EventPublishReplied)(&publishRepliedInd); |
| } |
| break; |
| |
| 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); |
| /* Save the self MAC address received in DE indication event to use it |
| * in Passphrase to PMK calculation. And do not call the handler if the |
| * framework has disabled the self MAC address indication. |
| */ |
| if (!res && |
| (discEngEventInd.event_type == NAN_EVENT_ID_DISC_MAC_ADDR)) { |
| mNanCommandInstance->saveNmi(discEngEventInd.data.mac_addr.addr); |
| if (mNanCommandInstance->mNanDiscAddrIndDisabled) |
| break; |
| } |
| 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_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_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::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->requestor_instance_id = pRsp->publishRepliedIndParams.matchHandle; |
| |
| event->rssi_value = 0; |
| u8 *pInputTlv = pRsp->ptlv; |
| NanTlv outputTlv; |
| u16 readLen = 0; |
| int remainingLen = (mNanDataLen - \ |
| (sizeof(NanMsgHeader))); |
| |
| if (remainingLen <= 0) { |
| ALOGI("%s: No TLV's present",__func__); |
| return WIFI_SUCCESS; |
| } |
| while ((remainingLen > 0) && |
| (0 != (readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv, remainingLen)))) { |
| 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; |
| default: |
| ALOGI("Unknown TLV type skipped"); |
| break; |
| } |
| remainingLen -= readLen; |
| pInputTlv += readLen; |
| memset(&outputTlv, 0, sizeof(outputTlv)); |
| } |
| 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->publish_id = pRsp->fwHeader.handle; |
| NanErrorTranslation((NanInternalStatusType)pRsp->reason, 0, |
| (void*)event, false); |
| 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, remainingLen)))) { |
| 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; |
| if (idx < 0 || idx >= NAN_MAX_POSTDISCOVERY_LEN) { |
| ALOGE("NAN_TLV_TYPE_POST_NAN_DISCOVERY_ATTRIBUTE_RECEIVE" |
| " Incorrect index:%d >= %d", idx, NAN_MAX_POSTDISCOVERY_LEN); |
| break; |
| } |
| 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; |
| case NAN_TLV_TYPE_SERVICE_ID: |
| mNanCommandInstance->saveServiceId(outputTlv.value, |
| event->publish_subscribe_id, |
| event->requestor_instance_id, |
| NAN_ROLE_SUBSCRIBER); |
| 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, false); |
| 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, remainingLen)))) { |
| 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, remainingLen)))) { |
| 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, false); |
| 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, remainingLen)))) { |
| 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, remainingLen)))) { |
| 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, remainingLen)))) { |
| 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; |
| break; |
| 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; |
| } |
| |
| wifi_error NanCommand::getNanStaParameter(wifi_interface_handle iface, |
| NanStaParameter *pRsp) |
| { |
| wifi_error ret = WIFI_ERROR_NONE; |
| transaction_id id = 1; |
| interface_info *ifaceInfo = getIfaceInfo(iface); |
| |
| ret = create(); |
| if (ret != WIFI_SUCCESS) |
| goto cleanup; |
| |
| /* Set the interface Id of the message. */ |
| ret = set_iface_id(ifaceInfo->name); |
| if (ret != WIFI_SUCCESS) |
| 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 != WIFI_SUCCESS) { |
| 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; |
| ret = mCondition.wait(abstime); |
| if (ret == WIFI_ERROR_TIMED_OUT) |
| { |
| ALOGE("%s: Time out happened.", __func__); |
| 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 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, false); |
| 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_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; |
| u8 i; |
| |
| 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); |
| } |
| for (i = 0; i < num_ndp_ids; i++) { |
| mNanCommandInstance->deleteServiceId(0, |
| ndpEndInd->ndp_instance_id[i], |
| NAN_ROLE_PUBLISHER); |
| } |
| if (mHandler.EventDataEnd) { |
| (*mHandler.EventDataEnd)(ndpEndInd); |
| } |
| free(ndpEndInd); |
| break; |
| } |
| |
| case QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_IND: |
| { |
| NanDataPathScheduleUpdateInd *pNdpScheduleUpdateInd; |
| u32 num_channels = 0, num_ndp_ids = 0; |
| |
| if ((!tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR]) || |
| (!tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_REASON]) || |
| (!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; |
| } |
| if (tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_NUM_CHANNELS]) { |
| num_channels = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_NUM_CHANNELS]); |
| ALOGD("%s: num_channels = %d", __FUNCTION__, num_channels); |
| if ((num_channels > NAN_MAX_CHANNEL_INFO_SUPPORTED) && |
| (!tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO])) { |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO 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); |
| |
| pNdpScheduleUpdateInd = |
| (NanDataPathScheduleUpdateInd *)malloc(sizeof(NanDataPathScheduleUpdateInd) |
| + (sizeof(u32) * num_ndp_ids)); |
| if (!pNdpScheduleUpdateInd) { |
| ALOGE("%s: NdpScheduleUpdate malloc Failed", __FUNCTION__); |
| return WIFI_ERROR_OUT_OF_MEMORY; |
| } |
| pNdpScheduleUpdateInd->num_channels = num_channels; |
| pNdpScheduleUpdateInd->num_ndp_instances = num_ndp_ids; |
| |
| res = getNdpScheduleUpdate(tb_vendor, pNdpScheduleUpdateInd); |
| if (!res && mHandler.EventScheduleUpdate) { |
| (*mHandler.EventScheduleUpdate)(pNdpScheduleUpdateInd); |
| } |
| free(pNdpScheduleUpdateInd); |
| 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__); |
| } |
| |
| if (tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_ID]) { |
| mNanCommandInstance->saveServiceId((u8 *)nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_ID]), |
| event->service_instance_id, |
| event->ndp_instance_id, |
| NAN_ROLE_PUBLISHER); |
| } else { |
| ALOGD("%s: Service ID not present", __FUNCTION__); |
| } |
| |
| return WIFI_SUCCESS; |
| } |
| |
| int NanCommand::getNdpConfirm(struct nlattr **tb_vendor, |
| NanDataPathConfirmInd *event) |
| { |
| u32 len = 0; |
| NanInternalStatusType drv_reason_code; |
| struct nlattr *chInfo; |
| NanChannelInfo *pChInfo; |
| int rem; |
| u32 i = 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__); |
| } |
| drv_reason_code = (NanInternalStatusType)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE]); |
| ALOGD("%s: Drv reason code %d", __FUNCTION__, drv_reason_code); |
| switch (drv_reason_code) { |
| case NDP_I_MGMT_FRAME_REQUEST_FAILED: |
| case NDP_I_MGMT_FRAME_RESPONSE_FAILED: |
| case NDP_I_MGMT_FRAME_CONFIRM_FAILED: |
| case NDP_I_MGMT_FRAME_END_REQUEST_FAILED: |
| case NDP_I_MGMT_FRAME_SECURITY_INSTALL_FAILED: |
| event->reason_code = NAN_STATUS_PROTOCOL_FAILURE; |
| break; |
| case NDP_I_END_FAILED: |
| event->reason_code = NAN_STATUS_INTERNAL_FAILURE; |
| break; |
| default: |
| event->reason_code = (NanStatusType)drv_reason_code; |
| break; |
| } |
| ALOGD("%s: Reason code %d", __FUNCTION__, event->reason_code); |
| |
| if (tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_NUM_CHANNELS]) { |
| event->num_channels = |
| nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_NUM_CHANNELS]); |
| ALOGD("%s: num_channels = %d", __FUNCTION__, event->num_channels); |
| if ((event->num_channels > NAN_MAX_CHANNEL_INFO_SUPPORTED) && |
| (!tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO])) { |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO not found", __FUNCTION__); |
| return WIFI_ERROR_INVALID_ARGS; |
| } |
| } |
| |
| if (event->num_channels != 0) { |
| for (chInfo = |
| (struct nlattr *) nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO]), |
| rem = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO]); |
| (i < NAN_MAX_CHANNEL_INFO_SUPPORTED && nla_ok(chInfo, rem)); |
| chInfo = nla_next(chInfo, &(rem))) { |
| struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX + 1]; |
| |
| pChInfo = |
| (NanChannelInfo *) ((u8 *)event->channel_info + (i++ * (sizeof(NanChannelInfo)))); |
| nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX, |
| (struct nlattr *) nla_data(chInfo), nla_len(chInfo), NULL); |
| |
| if (!tb2[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL]) { |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_CHANNEL not found", __FUNCTION__); |
| return WIFI_ERROR_INVALID_ARGS; |
| } |
| pChInfo->channel = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL]); |
| ALOGD("%s: Channel = %d", __FUNCTION__, pChInfo->channel); |
| |
| if (!tb2[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH]) { |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH not found", __FUNCTION__); |
| return WIFI_ERROR_INVALID_ARGS; |
| } |
| pChInfo->bandwidth = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH]); |
| ALOGD("%s: Channel BW = %d", __FUNCTION__, pChInfo->bandwidth); |
| |
| if (!tb2[QCA_WLAN_VENDOR_ATTR_NDP_NSS]) { |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_NDP_NSS not found", __FUNCTION__); |
| return WIFI_ERROR_INVALID_ARGS; |
| } |
| pChInfo->nss = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_NDP_NSS]); |
| ALOGD("%s: No. Spatial Stream = %d", __FUNCTION__, pChInfo->nss); |
| } |
| } |
| return WIFI_SUCCESS; |
| } |
| |
| int NanCommand::getNdpScheduleUpdate(struct nlattr **tb_vendor, |
| NanDataPathScheduleUpdateInd *event) |
| { |
| u32 len = 0; |
| struct nlattr *chInfo; |
| NanChannelInfo *pChInfo; |
| int rem; |
| u32 i = 0; |
| |
| len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR]); |
| len = ((sizeof(event->peer_mac_addr) <= len) ? sizeof(event->peer_mac_addr) : len); |
| memcpy(&event->peer_mac_addr[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR]), len); |
| |
| event->schedule_update_reason_code = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_REASON]); |
| ALOGD("%s: Reason code %d", __FUNCTION__, event->schedule_update_reason_code); |
| |
| if (event->num_channels != 0) { |
| for (chInfo = |
| (struct nlattr *) nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO]), |
| rem = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO]); |
| (i < NAN_MAX_CHANNEL_INFO_SUPPORTED && nla_ok(chInfo, rem)); |
| chInfo = nla_next(chInfo, &(rem))) { |
| struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX + 1]; |
| |
| pChInfo = |
| (NanChannelInfo *) ((u8 *)event->channel_info + (i++ * (sizeof(NanChannelInfo)))); |
| nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX, |
| (struct nlattr *) nla_data(chInfo), nla_len(chInfo), NULL); |
| |
| if (!tb2[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL]) { |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_CHANNEL not found", __FUNCTION__); |
| return WIFI_ERROR_INVALID_ARGS; |
| } |
| pChInfo->channel = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL]); |
| ALOGD("%s: Channel = %d", __FUNCTION__, pChInfo->channel); |
| |
| if (!tb2[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH]) { |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH not found", __FUNCTION__); |
| return WIFI_ERROR_INVALID_ARGS; |
| } |
| pChInfo->bandwidth = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH]); |
| ALOGD("%s: Channel BW = %d", __FUNCTION__, pChInfo->bandwidth); |
| |
| if (!tb2[QCA_WLAN_VENDOR_ATTR_NDP_NSS]) { |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_NDP_NSS not found", __FUNCTION__); |
| return WIFI_ERROR_INVALID_ARGS; |
| } |
| pChInfo->nss = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_NDP_NSS]); |
| ALOGD("%s: No. Spatial Stream = %d", __FUNCTION__, pChInfo->nss); |
| } |
| } |
| |
| if (event->num_ndp_instances) { |
| nla_memcpy(event->ndp_instance_id, |
| tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY], |
| sizeof(u32) * event->num_ndp_instances); |
| } |
| 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, remainingLen)))) { |
| 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, remainingLen)))) { |
| 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_mm = 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; |
| } |