1446 lines
45 KiB
C++
1446 lines
45 KiB
C++
/*
|
|
* 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 <utils/Log.h>
|
|
#include <errno.h>
|
|
#include "nancommand.h"
|
|
#include "vendor_definitions.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
|
|
|
|
#define OUT_OF_BAND_SERVICE_INSTANCE_ID 0
|
|
|
|
//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
|
|
wifi_error ret;
|
|
NanCommand *nanCommand = NULL;
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
|
|
nanCommand = NanCommand::instance(wifiHandle);
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error NanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = nanCommand->setCallbackHandler(handlers);
|
|
return 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)
|
|
{
|
|
wifi_error ret;
|
|
NanCommand *nanCommand = NULL;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (info == NULL) {
|
|
ALOGE("%s: Error hal_info NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
nanCommand = new NanCommand(wifiHandle,
|
|
0,
|
|
OUI_QCA,
|
|
info->support_nan_ext_cmd?
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN_EXT :
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN);
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error NanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = nanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = nanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
ret = nanCommand->putNanEnable(id, msg);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: putNanEnable Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d", __FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return ret;
|
|
}
|
|
|
|
/* Function to send disable request to the wifi driver.*/
|
|
wifi_error nan_disable_request(transaction_id id,
|
|
wifi_interface_handle iface)
|
|
{
|
|
wifi_error ret;
|
|
NanCommand *nanCommand = NULL;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (info == NULL) {
|
|
ALOGE("%s: Error hal_info NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
nanCommand = new NanCommand(wifiHandle,
|
|
0,
|
|
OUI_QCA,
|
|
info->support_nan_ext_cmd?
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN_EXT :
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN);
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error NanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = nanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = nanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
ret = nanCommand->putNanDisable(id);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: putNanDisable Error:%d",__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d",__FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return ret;
|
|
}
|
|
|
|
/* Function to send publish request to the wifi driver.*/
|
|
wifi_error nan_publish_request(transaction_id id,
|
|
wifi_interface_handle iface,
|
|
NanPublishRequest* msg)
|
|
{
|
|
wifi_error ret;
|
|
NanCommand *nanCommand = NULL;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (info == NULL) {
|
|
ALOGE("%s: Error hal_info NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
nanCommand = new NanCommand(wifiHandle,
|
|
0,
|
|
OUI_QCA,
|
|
info->support_nan_ext_cmd?
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN_EXT :
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN);
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error NanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = nanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = nanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
ret = nanCommand->putNanPublish(id, msg);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: putNanPublish Error:%d",__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d",__FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return 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)
|
|
{
|
|
wifi_error ret;
|
|
NanCommand *nanCommand = NULL;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (info == NULL) {
|
|
ALOGE("%s: Error hal_info NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
nanCommand = new NanCommand(wifiHandle,
|
|
0,
|
|
OUI_QCA,
|
|
info->support_nan_ext_cmd?
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN_EXT :
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN);
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error NanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = nanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = nanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
ret = nanCommand->putNanPublishCancel(id, msg);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: putNanPublishCancel Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d", __FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return ret;
|
|
}
|
|
|
|
/* Function to send Subscribe request to the wifi driver.*/
|
|
wifi_error nan_subscribe_request(transaction_id id,
|
|
wifi_interface_handle iface,
|
|
NanSubscribeRequest* msg)
|
|
{
|
|
wifi_error ret;
|
|
NanCommand *nanCommand = NULL;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (info == NULL) {
|
|
ALOGE("%s: Error hal_info NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
nanCommand = new NanCommand(wifiHandle,
|
|
0,
|
|
OUI_QCA,
|
|
info->support_nan_ext_cmd?
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN_EXT :
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN);
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error NanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = nanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = nanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
ret = nanCommand->putNanSubscribe(id, msg);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: putNanSubscribe Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d", __FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return ret;
|
|
}
|
|
|
|
/* Function to cancel subscribe to the wifi driver.*/
|
|
wifi_error nan_subscribe_cancel_request(transaction_id id,
|
|
wifi_interface_handle iface,
|
|
NanSubscribeCancelRequest* msg)
|
|
{
|
|
wifi_error ret;
|
|
NanCommand *nanCommand = NULL;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (info == NULL) {
|
|
ALOGE("%s: Error hal_info NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
nanCommand = new NanCommand(wifiHandle,
|
|
0,
|
|
OUI_QCA,
|
|
info->support_nan_ext_cmd?
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN_EXT :
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN);
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error NanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = nanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = nanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
ret = nanCommand->putNanSubscribeCancel(id, msg);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: putNanSubscribeCancel Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d", __FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return 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)
|
|
{
|
|
wifi_error ret;
|
|
NanCommand *nanCommand = NULL;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (info == NULL) {
|
|
ALOGE("%s: Error hal_info NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
nanCommand = new NanCommand(wifiHandle,
|
|
0,
|
|
OUI_QCA,
|
|
info->support_nan_ext_cmd?
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN_EXT :
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN);
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error NanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = nanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = nanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
ret = nanCommand->putNanTransmitFollowup(id, msg);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: putNanTransmitFollowup Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d", __FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return 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)
|
|
{
|
|
wifi_error ret;
|
|
NanCommand *nanCommand = NULL;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (info == NULL) {
|
|
ALOGE("%s: Error hal_info NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
nanCommand = new NanCommand(wifiHandle,
|
|
0,
|
|
OUI_QCA,
|
|
info->support_nan_ext_cmd?
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN_EXT :
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN);
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error NanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = nanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = nanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
ret = nanCommand->putNanStats(id, msg);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: putNanStats Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d", __FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return 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)
|
|
{
|
|
wifi_error ret;
|
|
NanCommand *nanCommand = NULL;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (info == NULL) {
|
|
ALOGE("%s: Error hal_info NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
nanCommand = new NanCommand(wifiHandle,
|
|
0,
|
|
OUI_QCA,
|
|
info->support_nan_ext_cmd?
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN_EXT :
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN);
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error NanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = nanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = nanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
ret = nanCommand->putNanConfig(id, msg);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: putNanConfig Error:%d",__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d",__FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return ret;
|
|
}
|
|
|
|
/* Function to send NAN request to the wifi driver.*/
|
|
wifi_error nan_tca_request(transaction_id id,
|
|
wifi_interface_handle iface,
|
|
NanTCARequest* msg)
|
|
{
|
|
wifi_error ret;
|
|
NanCommand *nanCommand = NULL;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (info == NULL) {
|
|
ALOGE("%s: Error hal_info NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
nanCommand = new NanCommand(wifiHandle,
|
|
0,
|
|
OUI_QCA,
|
|
info->support_nan_ext_cmd?
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN_EXT :
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN);
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error NanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = nanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = nanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
ret = nanCommand->putNanTCA(id, msg);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: putNanTCA Error:%d",__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d",__FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return 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)
|
|
{
|
|
wifi_error ret;
|
|
NanCommand *nanCommand = NULL;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (info == NULL) {
|
|
ALOGE("%s: Error hal_info NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
nanCommand = new NanCommand(wifiHandle,
|
|
0,
|
|
OUI_QCA,
|
|
info->support_nan_ext_cmd?
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN_EXT :
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN);
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error NanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = nanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = nanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
ret = nanCommand->putNanBeaconSdfPayload(id, msg);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: putNanBeaconSdfPayload Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d", __FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return ret;
|
|
}
|
|
|
|
wifi_error nan_get_sta_parameter(transaction_id id,
|
|
wifi_interface_handle iface,
|
|
NanStaParameter* msg)
|
|
{
|
|
wifi_error ret;
|
|
NanCommand *nanCommand = NULL;
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
|
|
nanCommand = NanCommand::instance(wifiHandle);
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error NanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = nanCommand->getNanStaParameter(iface, msg);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: getNanStaParameter Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
return ret;
|
|
}
|
|
|
|
/* Function to get NAN capabilities */
|
|
wifi_error nan_get_capabilities(transaction_id id,
|
|
wifi_interface_handle iface)
|
|
{
|
|
wifi_error ret;
|
|
NanCommand *nanCommand = NULL;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (info == NULL) {
|
|
ALOGE("%s: Error hal_info NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
nanCommand = new NanCommand(wifiHandle,
|
|
0,
|
|
OUI_QCA,
|
|
info->support_nan_ext_cmd?
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN_EXT :
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN);
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error NanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = nanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = nanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
ret = nanCommand->putNanCapabilities(id);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: putNanCapabilities Error:%d",__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d",__FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return ret;
|
|
}
|
|
|
|
/* Function to get NAN capabilities */
|
|
wifi_error nan_debug_command_config(transaction_id id,
|
|
wifi_interface_handle iface,
|
|
NanDebugParams debug,
|
|
int debug_msg_length)
|
|
{
|
|
wifi_error ret;
|
|
NanCommand *nanCommand = NULL;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (info == NULL) {
|
|
ALOGE("%s: Error hal_info NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
if (debug_msg_length <= 0) {
|
|
ALOGE("%s: Invalid debug message length = %d", __FUNCTION__,
|
|
debug_msg_length);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
nanCommand = new NanCommand(wifiHandle,
|
|
0,
|
|
OUI_QCA,
|
|
info->support_nan_ext_cmd?
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN_EXT :
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN);
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error NanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = nanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = nanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
ret = nanCommand->putNanDebugCommand(debug, debug_msg_length);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: putNanDebugCommand Error:%d",__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d",__FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return ret;
|
|
}
|
|
|
|
wifi_error nan_initialize_vendor_cmd(wifi_interface_handle iface,
|
|
NanCommand **nanCommand)
|
|
{
|
|
wifi_error ret;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
|
|
if (nanCommand == NULL) {
|
|
ALOGE("%s: Error nanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_INVALID_ARGS;
|
|
}
|
|
|
|
*nanCommand = new NanCommand(wifiHandle,
|
|
0,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_NDP);
|
|
if (*nanCommand == NULL) {
|
|
ALOGE("%s: Object creation failed", __FUNCTION__);
|
|
return WIFI_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
/* Create the message */
|
|
ret = (*nanCommand)->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
ret = (*nanCommand)->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
return WIFI_SUCCESS;
|
|
|
|
cleanup:
|
|
delete *nanCommand;
|
|
return ret;
|
|
}
|
|
|
|
wifi_error nan_data_interface_create(transaction_id id,
|
|
wifi_interface_handle iface,
|
|
char* iface_name)
|
|
{
|
|
ALOGV("NAN_DP_INTERFACE_CREATE");
|
|
wifi_error ret;
|
|
struct nlattr *nlData;
|
|
NanCommand *nanCommand = NULL;
|
|
|
|
if (iface_name == NULL) {
|
|
ALOGE("%s: Invalid Nan Data Interface Name. \n", __FUNCTION__);
|
|
return WIFI_ERROR_INVALID_ARGS;
|
|
}
|
|
|
|
ret = nan_initialize_vendor_cmd(iface,
|
|
&nanCommand);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Initialization failed", __FUNCTION__);
|
|
return ret;
|
|
}
|
|
|
|
/* Add the vendor specific attributes for the NL command. */
|
|
nlData = nanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
|
|
if (!nlData)
|
|
goto cleanup;
|
|
|
|
if (nanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD,
|
|
QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE) ||
|
|
nanCommand->put_u16(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID,
|
|
id) ||
|
|
nanCommand->put_string(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR,
|
|
iface_name)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
nanCommand->attr_end(nlData);
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d", __FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return ret;
|
|
}
|
|
|
|
wifi_error nan_data_interface_delete(transaction_id id,
|
|
wifi_interface_handle iface,
|
|
char* iface_name)
|
|
{
|
|
ALOGV("NAN_DP_INTERFACE_DELETE");
|
|
wifi_error ret;
|
|
struct nlattr *nlData;
|
|
NanCommand *nanCommand = NULL;
|
|
|
|
if (iface_name == NULL) {
|
|
ALOGE("%s: Invalid Nan Data Interface Name. \n", __FUNCTION__);
|
|
return WIFI_ERROR_INVALID_ARGS;
|
|
}
|
|
ret = nan_initialize_vendor_cmd(iface,
|
|
&nanCommand);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Initialization failed", __FUNCTION__);
|
|
return ret;
|
|
}
|
|
|
|
/* Add the vendor specific attributes for the NL command. */
|
|
nlData = nanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
|
|
if (!nlData)
|
|
goto cleanup;
|
|
|
|
if (nanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD,
|
|
QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE) ||
|
|
nanCommand->put_u16(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID,
|
|
id) ||
|
|
nanCommand->put_string(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR,
|
|
iface_name)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
nanCommand->attr_end(nlData);
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d", __FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return ret;
|
|
}
|
|
|
|
wifi_error nan_data_request_initiator(transaction_id id,
|
|
wifi_interface_handle iface,
|
|
NanDataPathInitiatorRequest* msg)
|
|
{
|
|
ALOGV("NAN_DP_REQUEST_INITIATOR");
|
|
wifi_error ret;
|
|
struct nlattr *nlData, *nlCfgQos;
|
|
NanCommand *nanCommand = NULL;
|
|
|
|
if (msg == NULL)
|
|
return WIFI_ERROR_INVALID_ARGS;
|
|
|
|
ret = nan_initialize_vendor_cmd(iface,
|
|
&nanCommand);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Initialization failed", __FUNCTION__);
|
|
return ret;
|
|
}
|
|
|
|
if ((msg->cipher_type != NAN_CIPHER_SUITE_SHARED_KEY_NONE) &&
|
|
(msg->key_info.body.pmk_info.pmk_len == 0) &&
|
|
(msg->key_info.body.passphrase_info.passphrase_len == 0)) {
|
|
ALOGE("%s: Failed-Initiator req, missing pmk and passphrase",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_INVALID_ARGS;
|
|
}
|
|
|
|
if ((msg->cipher_type != NAN_CIPHER_SUITE_SHARED_KEY_NONE) &&
|
|
(msg->requestor_instance_id == OUT_OF_BAND_SERVICE_INSTANCE_ID) &&
|
|
(msg->service_name_len == 0)) {
|
|
ALOGE("%s: Failed-Initiator req, missing service name for out of band request",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_INVALID_ARGS;
|
|
}
|
|
|
|
/* Add the vendor specific attributes for the NL command. */
|
|
nlData = nanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
|
|
if (!nlData)
|
|
goto cleanup;
|
|
|
|
if (nanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD,
|
|
QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_REQUEST) ||
|
|
nanCommand->put_u16(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID,
|
|
id) ||
|
|
nanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID,
|
|
msg->requestor_instance_id) ||
|
|
nanCommand->put_bytes(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR,
|
|
(char *)msg->peer_disc_mac_addr,
|
|
NAN_MAC_ADDR_LEN) ||
|
|
nanCommand->put_string(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR,
|
|
msg->ndp_iface)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
if (msg->channel_request_type != NAN_DP_CHANNEL_NOT_REQUESTED) {
|
|
if (nanCommand->put_u32 (
|
|
QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG,
|
|
msg->channel_request_type) ||
|
|
nanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL,
|
|
msg->channel))
|
|
goto cleanup;
|
|
}
|
|
|
|
if (msg->app_info.ndp_app_info_len != 0) {
|
|
if (nanCommand->put_bytes(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO,
|
|
(char *)msg->app_info.ndp_app_info,
|
|
msg->app_info.ndp_app_info_len)) {
|
|
goto cleanup;
|
|
}
|
|
}
|
|
if (msg->ndp_cfg.qos_cfg == NAN_DP_CONFIG_QOS) {
|
|
nlCfgQos =
|
|
nanCommand->attr_start(QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS);
|
|
if (!nlCfgQos)
|
|
goto cleanup;
|
|
/* TBD Qos Info */
|
|
nanCommand->attr_end(nlCfgQos);
|
|
}
|
|
if (msg->cipher_type != NAN_CIPHER_SUITE_SHARED_KEY_NONE) {
|
|
if (nanCommand->put_u32(QCA_WLAN_VENDOR_ATTR_NDP_CSID,
|
|
msg->cipher_type))
|
|
goto cleanup;
|
|
}
|
|
if ( msg->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK &&
|
|
msg->key_info.body.pmk_info.pmk_len == NAN_PMK_INFO_LEN) {
|
|
if (nanCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_NDP_PMK,
|
|
(char *)msg->key_info.body.pmk_info.pmk,
|
|
msg->key_info.body.pmk_info.pmk_len))
|
|
goto cleanup;
|
|
} else if (msg->key_info.key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE &&
|
|
msg->key_info.body.passphrase_info.passphrase_len >=
|
|
NAN_SECURITY_MIN_PASSPHRASE_LEN &&
|
|
msg->key_info.body.passphrase_info.passphrase_len <=
|
|
NAN_SECURITY_MAX_PASSPHRASE_LEN) {
|
|
if (nanCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE,
|
|
(char *)msg->key_info.body.passphrase_info.passphrase,
|
|
msg->key_info.body.passphrase_info.passphrase_len))
|
|
goto cleanup;
|
|
}
|
|
if (msg->service_name_len) {
|
|
if (nanCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME,
|
|
(char *)msg->service_name, msg->service_name_len))
|
|
goto cleanup;
|
|
}
|
|
nanCommand->attr_end(nlData);
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d", __FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return ret;
|
|
}
|
|
|
|
wifi_error nan_data_indication_response(transaction_id id,
|
|
wifi_interface_handle iface,
|
|
NanDataPathIndicationResponse* msg)
|
|
{
|
|
ALOGV("NAN_DP_INDICATION_RESPONSE");
|
|
wifi_error ret;
|
|
struct nlattr *nlData, *nlCfgQos;
|
|
NanCommand *nanCommand = NULL;
|
|
|
|
if (msg == NULL)
|
|
return WIFI_ERROR_INVALID_ARGS;
|
|
|
|
ret = nan_initialize_vendor_cmd(iface,
|
|
&nanCommand);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Initialization failed", __FUNCTION__);
|
|
return ret;
|
|
}
|
|
|
|
if ((msg->cipher_type != NAN_CIPHER_SUITE_SHARED_KEY_NONE) &&
|
|
(msg->key_info.body.pmk_info.pmk_len == 0) &&
|
|
(msg->key_info.body.passphrase_info.passphrase_len == 0)) {
|
|
ALOGE("%s: Failed-Initiator req, missing pmk and passphrase",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_INVALID_ARGS;
|
|
}
|
|
|
|
/* Add the vendor specific attributes for the NL command. */
|
|
nlData = nanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
|
|
if (!nlData)
|
|
goto cleanup;
|
|
|
|
if (nanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD,
|
|
QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_REQUEST) ||
|
|
nanCommand->put_u16(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID,
|
|
id) ||
|
|
nanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID,
|
|
msg->ndp_instance_id) ||
|
|
nanCommand->put_string(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR,
|
|
msg->ndp_iface) ||
|
|
nanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE,
|
|
msg->rsp_code)) {
|
|
goto cleanup;
|
|
}
|
|
if (msg->app_info.ndp_app_info_len != 0) {
|
|
if (nanCommand->put_bytes(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO,
|
|
(char *)msg->app_info.ndp_app_info,
|
|
msg->app_info.ndp_app_info_len)) {
|
|
goto cleanup;
|
|
}
|
|
}
|
|
if (msg->ndp_cfg.qos_cfg == NAN_DP_CONFIG_QOS) {
|
|
nlCfgQos =
|
|
nanCommand->attr_start(QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS);
|
|
if (!nlCfgQos)
|
|
goto cleanup;
|
|
|
|
/* TBD Qos Info */
|
|
nanCommand->attr_end(nlCfgQos);
|
|
}
|
|
if (msg->cipher_type != NAN_CIPHER_SUITE_SHARED_KEY_NONE) {
|
|
if (nanCommand->put_u32(QCA_WLAN_VENDOR_ATTR_NDP_CSID,
|
|
msg->cipher_type))
|
|
goto cleanup;
|
|
}
|
|
if ( msg->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK &&
|
|
msg->key_info.body.pmk_info.pmk_len == NAN_PMK_INFO_LEN) {
|
|
if (nanCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_NDP_PMK,
|
|
(char *)msg->key_info.body.pmk_info.pmk,
|
|
msg->key_info.body.pmk_info.pmk_len))
|
|
goto cleanup;
|
|
} else if (msg->key_info.key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE &&
|
|
msg->key_info.body.passphrase_info.passphrase_len >=
|
|
NAN_SECURITY_MIN_PASSPHRASE_LEN &&
|
|
msg->key_info.body.passphrase_info.passphrase_len <=
|
|
NAN_SECURITY_MAX_PASSPHRASE_LEN) {
|
|
if (nanCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE,
|
|
(char *)msg->key_info.body.passphrase_info.passphrase,
|
|
msg->key_info.body.passphrase_info.passphrase_len))
|
|
goto cleanup;
|
|
}
|
|
|
|
if (msg->service_name_len) {
|
|
if (nanCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME,
|
|
(char *)msg->service_name, msg->service_name_len))
|
|
goto cleanup;
|
|
}
|
|
nanCommand->attr_end(nlData);
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d", __FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return ret;
|
|
}
|
|
|
|
wifi_error nan_data_end(transaction_id id,
|
|
wifi_interface_handle iface,
|
|
NanDataPathEndRequest* msg)
|
|
{
|
|
wifi_error ret;
|
|
ALOGV("NAN_DP_END");
|
|
struct nlattr *nlData;
|
|
NanCommand *nanCommand = NULL;
|
|
|
|
if (msg == NULL)
|
|
return WIFI_ERROR_INVALID_ARGS;
|
|
|
|
ret = nan_initialize_vendor_cmd(iface,
|
|
&nanCommand);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Initialization failed", __FUNCTION__);
|
|
return ret;
|
|
}
|
|
|
|
/* Add the vendor specific attributes for the NL command. */
|
|
nlData = nanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
|
|
if (!nlData)
|
|
goto cleanup;
|
|
|
|
if (nanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD,
|
|
QCA_WLAN_VENDOR_ATTR_NDP_END_REQUEST) ||
|
|
nanCommand->put_u16(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID,
|
|
id) ||
|
|
nanCommand->put_bytes(
|
|
QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY,
|
|
(char *)msg->ndp_instance_id,
|
|
msg->num_ndp_instances * sizeof(u32))) {
|
|
goto cleanup;
|
|
}
|
|
nanCommand->attr_end(nlData);
|
|
|
|
ret = nanCommand->requestEvent();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestEvent Error:%d", __FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete nanCommand;
|
|
return 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)
|
|
{
|
|
hal_info *info;
|
|
|
|
if (handle == NULL) {
|
|
ALOGE("Handle is invalid");
|
|
return NULL;
|
|
}
|
|
info = getHalInfo(handle);
|
|
if (info == NULL) {
|
|
ALOGE("%s: Error hal_info NULL", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
|
|
if (mNanCommandInstance == NULL) {
|
|
mNanCommandInstance = new NanCommand(handle, 0,
|
|
OUI_QCA,
|
|
info->support_nan_ext_cmd?
|
|
QCA_NL80211_VENDOR_SUBCMD_NAN_EXT :
|
|
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;
|
|
}
|
|
|
|
wifi_error NanCommand::setCallbackHandler(NanCallbackHandler nHandler)
|
|
{
|
|
wifi_error res;
|
|
mHandler = nHandler;
|
|
res = registerVendorHandler(mVendor_id, QCA_NL80211_VENDOR_SUBCMD_NAN);
|
|
if (res != WIFI_SUCCESS) {
|
|
//error case should not happen print log
|
|
ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x"
|
|
"subcmd=QCA_NL80211_VENDOR_SUBCMD_NAN", __FUNCTION__, mVendor_id);
|
|
return res;
|
|
}
|
|
|
|
res = registerVendorHandler(mVendor_id, QCA_NL80211_VENDOR_SUBCMD_NDP);
|
|
if (res != WIFI_SUCCESS) {
|
|
//error case should not happen print log
|
|
ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x"
|
|
"subcmd=QCA_NL80211_VENDOR_SUBCMD_NDP", __FUNCTION__, mVendor_id);
|
|
return res;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/* This function implements creation of Vendor command */
|
|
wifi_error NanCommand::create() {
|
|
wifi_error ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto out;
|
|
|
|
/* Insert the oui in the msg */
|
|
ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto out;
|
|
/* Insert the subcmd in the msg */
|
|
ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
|
|
|
|
out:
|
|
if (ret != WIFI_SUCCESS)
|
|
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 if (mSubcmd == QCA_NL80211_VENDOR_SUBCMD_NDP) {
|
|
// Parse the vendordata and get the NAN attribute
|
|
u32 ndpCmdType;
|
|
struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX + 1];
|
|
nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX,
|
|
(struct nlattr *)mVendorData,
|
|
mDataLen, NULL);
|
|
|
|
if (tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD]) {
|
|
ndpCmdType =
|
|
nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD]);
|
|
ALOGD("%s: NDP Cmd Type : val 0x%x",
|
|
__FUNCTION__, ndpCmdType);
|
|
switch (ndpCmdType) {
|
|
case QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE:
|
|
handleNdpResponse(NAN_DP_INTERFACE_CREATE, tb_vendor);
|
|
break;
|
|
case QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE:
|
|
handleNdpResponse(NAN_DP_INTERFACE_DELETE, tb_vendor);
|
|
break;
|
|
case QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_RESPONSE:
|
|
handleNdpResponse(NAN_DP_INITIATOR_RESPONSE, tb_vendor);
|
|
break;
|
|
case QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_RESPONSE:
|
|
handleNdpResponse(NAN_DP_RESPONDER_RESPONSE, tb_vendor);
|
|
break;
|
|
case QCA_WLAN_VENDOR_ATTR_NDP_END_RESPONSE:
|
|
handleNdpResponse(NAN_DP_END, tb_vendor);
|
|
break;
|
|
case QCA_WLAN_VENDOR_ATTR_NDP_REQUEST_IND:
|
|
case QCA_WLAN_VENDOR_ATTR_NDP_CONFIRM_IND:
|
|
case QCA_WLAN_VENDOR_ATTR_NDP_END_IND:
|
|
case QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_IND:
|
|
handleNdpIndication(ndpCmdType, tb_vendor);
|
|
break;
|
|
default:
|
|
ALOGE("%s: Invalid NDP subcmd response received %d",
|
|
__FUNCTION__, ndpCmdType);
|
|
}
|
|
}
|
|
} else {
|
|
//error case should not happen print log
|
|
ALOGE("%s: Wrong NAN subcmd received %d", __FUNCTION__, mSubcmd);
|
|
}
|
|
mNanVendorEvent = NULL;
|
|
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);
|
|
}
|