| /* |
| * 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; |
| |
| 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; |
| 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; |
| event->reason = (NanStatusType)pRsp->reason; |
| return WIFI_SUCCESS; |
| } |
| |
| int NanCommand::getNanMatch(NanMatchInd *event) |
| { |
| if (event == NULL || mNanVendorEvent == NULL) { |
| ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p", |
| __func__, event, mNanVendorEvent); |
| return WIFI_ERROR_INVALID_ARGS; |
| } |
| |
| pNanMatchIndMsg pRsp = (pNanMatchIndMsg)mNanVendorEvent; |
| event->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; |
| 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; |
| event->reason = (NanStatusType)pRsp->reason; |
| return WIFI_SUCCESS; |
| } |
| |
| int NanCommand::getNanFollowup(NanFollowupInd *event) |
| { |
| if (event == NULL || mNanVendorEvent == NULL) { |
| ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p", |
| __func__, event, mNanVendorEvent); |
| return WIFI_ERROR_INVALID_ARGS; |
| } |
| |
| pNanFollowupIndMsg pRsp = (pNanFollowupIndMsg)mNanVendorEvent; |
| event->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; |
| 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; |
| event->reason = (NanStatusType)pRsp->reason; |
| return WIFI_SUCCESS; |
| |
| } |
| |
| int NanCommand::getNanTca(NanTCAInd *event) |
| { |
| if (event == NULL || mNanVendorEvent == NULL) { |
| ALOGE("%s: Invalid input argument event:%p mNanVendorEvent:%p", |
| __func__, event, mNanVendorEvent); |
| return WIFI_ERROR_INVALID_ARGS; |
| } |
| |
| pNanTcaIndMsg pRsp = (pNanTcaIndMsg)mNanVendorEvent; |
| 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; |
| } |
| } |
| |
| 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; |
| int id = 1; |
| NanCommand *nanCommand = NULL; |
| interface_info *ifaceInfo = getIfaceInfo(iface); |
| wifi_handle wifiHandle = getWifiHandle(iface); |
| |
| nanCommand = NanCommand::instance(wifiHandle); |
| if (nanCommand == NULL) { |
| ALOGE("%s: Error NanCommand NULL", __func__); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| |
| ret = nanCommand->create(); |
| if (ret < 0) |
| goto cleanup; |
| |
| /* Set the interface Id of the message. */ |
| ret = nanCommand->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", __func__, |
| pRsp->master_pref, pRsp->random_factor, |
| pRsp->hop_count, pRsp->beacon_transmit_time); |
| cleanup: |
| mStaParam = NULL; |
| return (int)ret; |
| } |