/* * 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 "wifi_hal.h" #include "nan_i.h" #include "common.h" #include "cpp_bindings.h" #include #include "nancommand.h" #ifdef __GNUC__ #define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b)))) #define STRUCT_PACKED __attribute__ ((packed)) #else #define PRINTF_FORMAT(a,b) #define STRUCT_PACKED #endif #include "qca-vendor.h" //Singleton Static Instance NanCommand* NanCommand::mNanCommandInstance = NULL; //Implementation of the functions exposed in nan.h wifi_error nan_register_handler(wifi_interface_handle iface, NanCallbackHandler handlers) { // Obtain the singleton instance int ret = 0; 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->setCallbackHandler(handlers); return (wifi_error)ret; cleanup: return (wifi_error)ret; } wifi_error nan_get_version(wifi_handle handle, NanVersion* version) { *version = (NAN_MAJOR_VERSION <<16 | NAN_MINOR_VERSION << 8 | NAN_MICRO_VERSION); return WIFI_SUCCESS; } /* Function to send enable request to the wifi driver.*/ wifi_error nan_enable_request(transaction_id id, wifi_interface_handle iface, NanEnableRequest* msg) { int ret = 0; NanCommand *nanCommand = NULL; interface_info *ifaceInfo = getIfaceInfo(iface); wifi_handle wifiHandle = getWifiHandle(iface); nanCommand = new NanCommand(wifiHandle, 0, OUI_QCA, QCA_NL80211_VENDOR_SUBCMD_NAN); 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; ret = nanCommand->putNanEnable(id, msg); if (ret != 0) { ALOGE("%s: putNanEnable Error:%d",__func__, ret); goto cleanup; } ret = nanCommand->requestEvent(); if (ret != 0) { ALOGE("%s: requestEvent Error:%d",__func__, ret); } cleanup: delete nanCommand; return (wifi_error)ret; } /* Function to send disable request to the wifi driver.*/ wifi_error nan_disable_request(transaction_id id, wifi_interface_handle iface) { int ret = 0; NanCommand *nanCommand = NULL; interface_info *ifaceInfo = getIfaceInfo(iface); wifi_handle wifiHandle = getWifiHandle(iface); nanCommand = new NanCommand(wifiHandle, 0, OUI_QCA, QCA_NL80211_VENDOR_SUBCMD_NAN); 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; ret = nanCommand->putNanDisable(id); if (ret != 0) { ALOGE("%s: putNanDisable Error:%d",__func__, ret); goto cleanup; } ret = nanCommand->requestEvent(); if (ret != 0) { ALOGE("%s: requestEvent Error:%d",__func__, ret); } cleanup: delete nanCommand; return (wifi_error)ret; } /* Function to send publish request to the wifi driver.*/ wifi_error nan_publish_request(transaction_id id, wifi_interface_handle iface, NanPublishRequest* msg) { int ret = 0; NanCommand *nanCommand = NULL; interface_info *ifaceInfo = getIfaceInfo(iface); wifi_handle wifiHandle = getWifiHandle(iface); nanCommand = new NanCommand(wifiHandle, 0, OUI_QCA, QCA_NL80211_VENDOR_SUBCMD_NAN); 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; ret = nanCommand->putNanPublish(id, msg); if (ret != 0) { ALOGE("%s: putNanPublish Error:%d",__func__, ret); goto cleanup; } ret = nanCommand->requestEvent(); if (ret != 0) { ALOGE("%s: requestEvent Error:%d",__func__, ret); } cleanup: delete nanCommand; return (wifi_error)ret; } /* Function to send publish cancel to the wifi driver.*/ wifi_error nan_publish_cancel_request(transaction_id id, wifi_interface_handle iface, NanPublishCancelRequest* msg) { int ret = 0; NanCommand *nanCommand = NULL; interface_info *ifaceInfo = getIfaceInfo(iface); wifi_handle wifiHandle = getWifiHandle(iface); nanCommand = new NanCommand(wifiHandle, 0, OUI_QCA, QCA_NL80211_VENDOR_SUBCMD_NAN); 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; ret = nanCommand->putNanPublishCancel(id, msg); if (ret != 0) { ALOGE("%s: putNanPublishCancel Error:%d",__func__, ret); goto cleanup; } ret = nanCommand->requestEvent(); if (ret != 0) { ALOGE("%s: requestEvent Error:%d",__func__, ret); } cleanup: delete nanCommand; return (wifi_error)ret; } /* Function to send Subscribe request to the wifi driver.*/ wifi_error nan_subscribe_request(transaction_id id, wifi_interface_handle iface, NanSubscribeRequest* msg) { int ret = 0; NanCommand *nanCommand = NULL; interface_info *ifaceInfo = getIfaceInfo(iface); wifi_handle wifiHandle = getWifiHandle(iface); nanCommand = new NanCommand(wifiHandle, 0, OUI_QCA, QCA_NL80211_VENDOR_SUBCMD_NAN); 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; ret = nanCommand->putNanSubscribe(id, msg); if (ret != 0) { ALOGE("%s: putNanSubscribe Error:%d",__func__, ret); goto cleanup; } ret = nanCommand->requestEvent(); if (ret != 0) { ALOGE("%s: requestEvent Error:%d",__func__, ret); } cleanup: delete nanCommand; return (wifi_error)ret; } /* Function to cancel subscribe to the wifi driver.*/ wifi_error nan_subscribe_cancel_request(transaction_id id, wifi_interface_handle iface, NanSubscribeCancelRequest* msg) { int ret = 0; NanCommand *nanCommand = NULL; interface_info *ifaceInfo = getIfaceInfo(iface); wifi_handle wifiHandle = getWifiHandle(iface); nanCommand = new NanCommand(wifiHandle, 0, OUI_QCA, QCA_NL80211_VENDOR_SUBCMD_NAN); 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; ret = nanCommand->putNanSubscribeCancel(id, msg); if (ret != 0) { ALOGE("%s: putNanSubscribeCancel Error:%d",__func__, ret); goto cleanup; } ret = nanCommand->requestEvent(); if (ret != 0) { ALOGE("%s: requestEvent Error:%d",__func__, ret); } cleanup: delete nanCommand; return (wifi_error)ret; } /* Function to send NAN follow up request to the wifi driver.*/ wifi_error nan_transmit_followup_request(transaction_id id, wifi_interface_handle iface, NanTransmitFollowupRequest* msg) { int ret = 0; NanCommand *nanCommand = NULL; interface_info *ifaceInfo = getIfaceInfo(iface); wifi_handle wifiHandle = getWifiHandle(iface); nanCommand = new NanCommand(wifiHandle, 0, OUI_QCA, QCA_NL80211_VENDOR_SUBCMD_NAN); 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; ret = nanCommand->putNanTransmitFollowup(id, msg); if (ret != 0) { ALOGE("%s: putNanTransmitFollowup Error:%d",__func__, ret); goto cleanup; } ret = nanCommand->requestEvent(); if (ret != 0) { ALOGE("%s: requestEvent Error:%d",__func__, ret); } cleanup: delete nanCommand; return (wifi_error)ret; } /* Function to send NAN statistics request to the wifi driver.*/ wifi_error nan_stats_request(transaction_id id, wifi_interface_handle iface, NanStatsRequest* msg) { int ret = 0; NanCommand *nanCommand = NULL; interface_info *ifaceInfo = getIfaceInfo(iface); wifi_handle wifiHandle = getWifiHandle(iface); nanCommand = new NanCommand(wifiHandle, 0, OUI_QCA, QCA_NL80211_VENDOR_SUBCMD_NAN); 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; ret = nanCommand->putNanStats(id, msg); if (ret != 0) { ALOGE("%s: putNanStats Error:%d",__func__, ret); goto cleanup; } ret = nanCommand->requestEvent(); if (ret != 0) { ALOGE("%s: requestEvent Error:%d",__func__, ret); } cleanup: delete nanCommand; return (wifi_error)ret; } /* Function to send NAN configuration request to the wifi driver.*/ wifi_error nan_config_request(transaction_id id, wifi_interface_handle iface, NanConfigRequest* msg) { int ret = 0; NanCommand *nanCommand = NULL; interface_info *ifaceInfo = getIfaceInfo(iface); wifi_handle wifiHandle = getWifiHandle(iface); nanCommand = new NanCommand(wifiHandle, 0, OUI_QCA, QCA_NL80211_VENDOR_SUBCMD_NAN); 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; ret = nanCommand->putNanConfig(id, msg); if (ret != 0) { ALOGE("%s: putNanConfig Error:%d",__func__, ret); goto cleanup; } ret = nanCommand->requestEvent(); if (ret != 0) { ALOGE("%s: requestEvent Error:%d",__func__, ret); } cleanup: delete nanCommand; return (wifi_error)ret; } /* Function to send NAN request to the wifi driver.*/ wifi_error nan_tca_request(transaction_id id, wifi_interface_handle iface, NanTCARequest* msg) { int ret = 0; NanCommand *nanCommand = NULL; interface_info *ifaceInfo = getIfaceInfo(iface); wifi_handle wifiHandle = getWifiHandle(iface); nanCommand = new NanCommand(wifiHandle, 0, OUI_QCA, QCA_NL80211_VENDOR_SUBCMD_NAN); 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; ret = nanCommand->putNanTCA(id, msg); if (ret != 0) { ALOGE("%s: putNanTCA Error:%d",__func__, ret); goto cleanup; } ret = nanCommand->requestEvent(); if (ret != 0) { ALOGE("%s: requestEvent Error:%d",__func__, ret); } cleanup: delete nanCommand; return (wifi_error)ret; } /* Function to send NAN Beacon sdf payload to the wifi driver. This instructs the Discovery Engine to begin publishing the received payload in any Beacon or Service Discovery Frame transmitted*/ wifi_error nan_beacon_sdf_payload_request(transaction_id id, wifi_interface_handle iface, NanBeaconSdfPayloadRequest* msg) { int ret = WIFI_ERROR_NOT_SUPPORTED; NanCommand *nanCommand = NULL; interface_info *ifaceInfo = getIfaceInfo(iface); wifi_handle wifiHandle = getWifiHandle(iface); nanCommand = new NanCommand(wifiHandle, 0, OUI_QCA, QCA_NL80211_VENDOR_SUBCMD_NAN); 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; ret = nanCommand->putNanBeaconSdfPayload(id, msg); if (ret != 0) { ALOGE("%s: putNanBeaconSdfPayload Error:%d",__func__, ret); goto cleanup; } ret = nanCommand->requestEvent(); if (ret != 0) { ALOGE("%s: requestEvent Error:%d",__func__, ret); } cleanup: delete nanCommand; return (wifi_error)ret; } wifi_error nan_get_sta_parameter(transaction_id id, wifi_interface_handle iface, NanStaParameter* msg) { int ret = WIFI_ERROR_NOT_SUPPORTED; 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->getNanStaParameter(iface, msg); if (ret != 0) { ALOGE("%s: getNanStaParameter Error:%d",__func__, ret); goto cleanup; } cleanup: return (wifi_error)ret; } /* Function to get NAN capabilities */ wifi_error nan_get_capabilities(transaction_id id, wifi_interface_handle iface) { int ret = 0; NanCommand *nanCommand = NULL; interface_info *ifaceInfo = getIfaceInfo(iface); wifi_handle wifiHandle = getWifiHandle(iface); nanCommand = new NanCommand(wifiHandle, 0, OUI_QCA, QCA_NL80211_VENDOR_SUBCMD_NAN); 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; ret = nanCommand->putNanCapabilities(id); if (ret != 0) { ALOGE("%s: putNanCapabilities Error:%d",__func__, ret); goto cleanup; } ret = nanCommand->requestEvent(); if (ret != 0) { ALOGE("%s: requestEvent Error:%d",__func__, ret); } cleanup: delete nanCommand; return (wifi_error)ret; } // Implementation related to nan class common functions // Constructor //Making the constructor private since this class is a singleton NanCommand::NanCommand(wifi_handle handle, int id, u32 vendor_id, u32 subcmd) : WifiVendorCommand(handle, id, vendor_id, subcmd) { memset(&mHandler, 0,sizeof(mHandler)); mNanVendorEvent = NULL; mNanDataLen = 0; mStaParam = NULL; } NanCommand* NanCommand::instance(wifi_handle handle) { if (handle == NULL) { ALOGE("Handle is invalid"); return NULL; } if (mNanCommandInstance == NULL) { mNanCommandInstance = new NanCommand(handle, 0, OUI_QCA, QCA_NL80211_VENDOR_SUBCMD_NAN); ALOGV("NanCommand %p created", mNanCommandInstance); return mNanCommandInstance; } else { if (handle != getWifiHandle(mNanCommandInstance->mInfo)) { /* upper layer must have cleaned up the handle and reinitialized, so we need to update the same */ ALOGI("Handle different, update the handle"); mNanCommandInstance->mInfo = (hal_info *)handle; } } ALOGV("NanCommand %p created already", mNanCommandInstance); return mNanCommandInstance; } void NanCommand::cleanup() { //free the VendorData if (mVendorData) { free(mVendorData); } mVendorData = NULL; //cleanup the mMsg mMsg.destroy(); } NanCommand::~NanCommand() { ALOGV("NanCommand %p destroyed", this); } int NanCommand::handleResponse(WifiEvent &reply){ return NL_SKIP; } int NanCommand::setCallbackHandler(NanCallbackHandler nHandler) { int res = 0; mHandler = nHandler; res = registerVendorHandler(mVendor_id, mSubcmd); if (res != 0) { //error case should not happen print log ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u", __func__, mVendor_id, mSubcmd); } return res; } /* This function implements creation of Vendor command */ int NanCommand::create() { int ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0); if (ret < 0) { goto out; } /* Insert the oui in the msg */ ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id); if (ret < 0) goto out; /* Insert the subcmd in the msg */ ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd); if (ret < 0) goto out; out: if (ret < 0) { mMsg.destroy(); } return ret; } // This function will be the main handler for incoming event // QCA_NL80211_VENDOR_SUBCMD_NAN //Call the appropriate callback handler after parsing the vendor data. int NanCommand::handleEvent(WifiEvent &event) { WifiVendorCommand::handleEvent(event); ALOGV("%s: Subcmd=%u Vendor data len received:%d", __FUNCTION__, mSubcmd, mDataLen); hexdump(mVendorData, mDataLen); if (mSubcmd == QCA_NL80211_VENDOR_SUBCMD_NAN){ // Parse the vendordata and get the NAN attribute struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1]; nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX, (struct nlattr *)mVendorData, mDataLen, NULL); // Populating the mNanVendorEvent and mNanDataLen to point to NAN data. mNanVendorEvent = (char *)nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_NAN]); mNanDataLen = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_NAN]); if (isNanResponse()) { //handleNanResponse will parse the data and call //the response callback handler with the populated //NanResponseMsg handleNanResponse(); } else { //handleNanIndication will parse the data and call //the corresponding Indication callback handler //with the corresponding populated Indication event handleNanIndication(); } } else { //error case should not happen print log ALOGE("%s: Wrong NAN subcmd received %d", __func__, mSubcmd); } return NL_SKIP; } /*Helper function to Write and Read TLV called in indication as well as request */ u16 NANTLV_WriteTlv(pNanTlv pInTlv, u8 *pOutTlv) { u16 writeLen = 0; u16 i; if (!pInTlv) { ALOGE("NULL pInTlv"); return writeLen; } if (!pOutTlv) { ALOGE("NULL pOutTlv"); return writeLen; } *pOutTlv++ = pInTlv->type & 0xFF; *pOutTlv++ = (pInTlv->type & 0xFF00) >> 8; writeLen += 2; ALOGV("WRITE TLV type %u, writeLen %u", pInTlv->type, writeLen); *pOutTlv++ = pInTlv->length & 0xFF; *pOutTlv++ = (pInTlv->length & 0xFF00) >> 8; writeLen += 2; ALOGV("WRITE TLV length %u, writeLen %u", pInTlv->length, writeLen); for (i=0; i < pInTlv->length; ++i) { *pOutTlv++ = pInTlv->value[i]; } writeLen += pInTlv->length; ALOGV("WRITE TLV value, writeLen %u", writeLen); return writeLen; } u16 NANTLV_ReadTlv(u8 *pInTlv, pNanTlv pOutTlv) { u16 readLen = 0; if (!pInTlv) { ALOGE("NULL pInTlv"); return readLen; } if (!pOutTlv) { ALOGE("NULL pOutTlv"); return readLen; } pOutTlv->type = *pInTlv++; pOutTlv->type |= *pInTlv++ << 8; readLen += 2; ALOGV("READ TLV type %u, readLen %u", pOutTlv->type, readLen); pOutTlv->length = *pInTlv++; pOutTlv->length |= *pInTlv++ << 8; readLen += 2; ALOGV("READ TLV length %u, readLen %u", pOutTlv->length, readLen); if (pOutTlv->length) { pOutTlv->value = pInTlv; readLen += pOutTlv->length; } else { pOutTlv->value = NULL; } ALOGV("READ TLV readLen %u", readLen); return readLen; } u8* addTlv(u16 type, u16 length, const u8* value, u8* pOutTlv) { NanTlv nanTlv; u16 len; nanTlv.type = type; nanTlv.length = length; nanTlv.value = (u8*)value; len = NANTLV_WriteTlv(&nanTlv, pOutTlv); return (pOutTlv + len); }