blob: a2d2d47aea7998dcd82b2acb9fdfcffb6ee99f56 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Portions copyright (C) 2017 Broadcom Limited
*
* 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 <stdint.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
#include <linux/errqueue.h>
#include <ctype.h>
#include <linux/pkt_sched.h>
#include <netlink/object-api.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include "nl80211_copy.h"
#include "sync.h"
#define LOG_TAG "WifiHAL"
#include <utils/Log.h>
#include <log/log.h>
#include <hardware_legacy/wifi_hal.h>
#include "common.h"
#include "cpp_bindings.h"
#include "netinet/in.h"
#include "arpa/inet.h"
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <sys/ioctl.h>
/* Changes between incompatible Version of NAN */
#define NAN_MAJOR_REL_VERSION 1
/* Changes between Source and Binary compatible Version of NAN */
#define NAN_MINOR_REL_VERSION 2
/* Changes between perfectly compatible Version of NAN */
#define NAN_PATCH_REL_VERSION 3
#define SVC_NAME_TO_HASH 1
#define NAN_SVC_HASH_SIZE 6
#define C2S(x) case x: return #x;
#define NAN_PUB_RECV_FLAG_MAX 15
#define NAN_SUB_RECV_FLAG_MAX 7
#define NAN_DISC_IND_MAX 7
#define NAN_MAX 255
#define NAN_MIN 0
#define INVALID 0xFF
#define NAN_MAX_PERIOD 16
#define ISGREATER(i, x) (i > x) ? 1 : 0
#define NAN_MAX_RSSI 90
#define NAN_SECURITY_SALT_SIZE 14
#define NAN_MAC_INVALID_TRANSID 0xFFFF
#define SVCHASH_ISNULL(svc_hash) ((((u8 *)(svc_hash))[0] | \
((u8 *)(svc_hash))[1] | \
((u8 *)(svc_hash))[2] | \
((u8 *)(svc_hash))[3] | \
((u8 *)(svc_hash))[4] | \
((u8 *)(svc_hash))[5]) == 0)
#define ETHER_ISNULLADDR(ea) ((((u8 *)(ea))[0] | \
((u8 *)(ea))[1] | \
((u8 *)(ea))[2] | \
((u8 *)(ea))[3] | \
((u8 *)(ea))[4] | \
((u8 *)(ea))[5]) == 0)
/* NAN structs versioning b/w DHD and HAL
* TODO:add versions for each struct*/
#define NAN_HAL_VERSION_1 0x2
struct nan_dbg_cntrs {
u32 dp_req; /* cmd */
u32 dp_resp; /* cmd */
u32 dp_req_evt;
u32 dp_confirm_evt;
u32 transmit_req; /* cmd */
u32 transmit_txs; /* event */
u32 transmit_recv; /* event */
};
nan_dbg_cntrs counters;
u32 current_dhd_hal_ver = 0;
/* TODO: Known bug in Android which was discovered too late and then left in for backward compatibility.
* The issue is that the Service Name selected by the framework is invalid - it contains a space.
* Therefore, the underlying implementation partially converts it to lower case and uses the results for PMK generation.
* I.e. the PMK is generated based on the following service name: "Wi-Fi Aware Data Path"
*/
/* SVC Hash generated for svc name string "Wi-Fi Aware Data Path" */
u8 NAN_OOB_INTEROP_SVC_HASH[NAN_SVC_HASH_SIZE] = {0x05, 0x9e, 0xd4, 0xcf, 0x89, 0x1a};
#define NAN_OOB_INTEROP_SVC_NAME "Wi-Fi Aware Data Path"
static const char *NanStatusToString(NanStatusType status)
{
switch (status) {
C2S(NAN_STATUS_SUCCESS)
C2S(NAN_STATUS_INTERNAL_FAILURE)
C2S(NAN_STATUS_PROTOCOL_FAILURE)
C2S(NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID)
C2S(NAN_STATUS_NO_RESOURCE_AVAILABLE)
C2S(NAN_STATUS_INVALID_PARAM)
C2S(NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID)
C2S(NAN_STATUS_INVALID_NDP_ID)
C2S(NAN_STATUS_NAN_NOT_ALLOWED)
C2S(NAN_STATUS_NO_OTA_ACK)
C2S(NAN_STATUS_ALREADY_ENABLED)
C2S(NAN_STATUS_FOLLOWUP_QUEUE_FULL)
C2S(NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED)
default:
return "NAN_STATUS_INTERNAL_FAILURE";
}
}
/* Nan Data Path Security Information */
typedef struct {
/*
Unique Instance Id identifying the Responder's service.
This is same as publish_id notified on the subscribe side
in a publish/subscribe scenario
*/
u32 requestor_instance_id; /* Value 0 for no publish/subscribe */
/*
Discovery MAC addr of the publisher/peer
*/
u8 peer_disc_mac_addr[NAN_MAC_ADDR_LEN];
/*
Unique token Id generated on the initiator/responder
side used for a NDP session between two NAN devices
*/
NanDataPathId ndp_instance_id;
} NanDataPathSecInfoRequest;
/*
* Note: NAN_ATTRIBUTE should match with one that on driver side, wl_cfgnan.h and
* NanAttrToString as well for enum to string.
*/
typedef enum {
NAN_ATTRIBUTE_HEADER = 100,
NAN_ATTRIBUTE_HANDLE = 101,
NAN_ATTRIBUTE_TRANSAC_ID = 102,
/* NAN Enable request attributes */
NAN_ATTRIBUTE_2G_SUPPORT = 103,
NAN_ATTRIBUTE_5G_SUPPORT = 104,
NAN_ATTRIBUTE_CLUSTER_LOW = 105,
NAN_ATTRIBUTE_CLUSTER_HIGH = 106,
NAN_ATTRIBUTE_SID_BEACON = 107,
NAN_ATTRIBUTE_SYNC_DISC_2G_BEACON = 108,
NAN_ATTRIBUTE_SYNC_DISC_5G_BEACON = 109,
NAN_ATTRIBUTE_SDF_2G_SUPPORT = 110,
NAN_ATTRIBUTE_SDF_5G_SUPPORT = 111,
NAN_ATTRIBUTE_RSSI_CLOSE = 112,
NAN_ATTRIBUTE_RSSI_MIDDLE = 113,
NAN_ATTRIBUTE_RSSI_PROXIMITY = 114,
NAN_ATTRIBUTE_HOP_COUNT_LIMIT = 115,
NAN_ATTRIBUTE_RANDOM_FACTOR = 116,
NAN_ATTRIBUTE_MASTER_PREF = 117,
NAN_ATTRIBUTE_PERIODIC_SCAN_INTERVAL = 118,
/* Nan Publish/Subscribe request attributes */
NAN_ATTRIBUTE_PUBLISH_ID = 119,
NAN_ATTRIBUTE_TTL = 120,
NAN_ATTRIBUTE_PERIOD = 121,
NAN_ATTRIBUTE_REPLIED_EVENT_FLAG = 122,
NAN_ATTRIBUTE_PUBLISH_TYPE = 123,
NAN_ATTRIBUTE_TX_TYPE = 124,
NAN_ATTRIBUTE_PUBLISH_COUNT = 125,
NAN_ATTRIBUTE_SERVICE_NAME_LEN = 126,
NAN_ATTRIBUTE_SERVICE_NAME = 127,
NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN = 128,
NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO = 129,
NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN = 130,
NAN_ATTRIBUTE_RX_MATCH_FILTER = 131,
NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN = 132,
NAN_ATTRIBUTE_TX_MATCH_FILTER = 133,
NAN_ATTRIBUTE_SUBSCRIBE_ID = 134,
NAN_ATTRIBUTE_SUBSCRIBE_TYPE = 135,
NAN_ATTRIBUTE_SERVICERESPONSEFILTER = 136,
NAN_ATTRIBUTE_SERVICERESPONSEINCLUDE = 137,
NAN_ATTRIBUTE_USESERVICERESPONSEFILTER = 138,
NAN_ATTRIBUTE_SSIREQUIREDFORMATCHINDICATION = 139,
NAN_ATTRIBUTE_SUBSCRIBE_MATCH = 140,
NAN_ATTRIBUTE_SUBSCRIBE_COUNT = 141,
NAN_ATTRIBUTE_MAC_ADDR = 142,
NAN_ATTRIBUTE_MAC_ADDR_LIST = 143,
NAN_ATTRIBUTE_MAC_ADDR_LIST_NUM_ENTRIES = 144,
NAN_ATTRIBUTE_PUBLISH_MATCH = 145,
/* Nan Event attributes */
NAN_ATTRIBUTE_ENABLE_STATUS = 146,
NAN_ATTRIBUTE_JOIN_STATUS = 147,
NAN_ATTRIBUTE_ROLE = 148,
NAN_ATTRIBUTE_MASTER_RANK = 149,
NAN_ATTRIBUTE_ANCHOR_MASTER_RANK = 150,
NAN_ATTRIBUTE_CNT_PEND_TXFRM = 151,
NAN_ATTRIBUTE_CNT_BCN_TX = 152,
NAN_ATTRIBUTE_CNT_BCN_RX = 153,
NAN_ATTRIBUTE_CNT_SVC_DISC_TX = 154,
NAN_ATTRIBUTE_CNT_SVC_DISC_RX = 155,
NAN_ATTRIBUTE_AMBTT = 156,
NAN_ATTRIBUTE_CLUSTER_ID = 157,
NAN_ATTRIBUTE_INST_ID = 158,
NAN_ATTRIBUTE_OUI = 159,
NAN_ATTRIBUTE_STATUS = 160,
NAN_ATTRIBUTE_DE_EVENT_TYPE = 161,
NAN_ATTRIBUTE_MERGE = 162,
NAN_ATTRIBUTE_IFACE = 163,
NAN_ATTRIBUTE_CHANNEL = 164,
NAN_ATTRIBUTE_PEER_ID = 165,
NAN_ATTRIBUTE_NDP_ID = 167,
NAN_ATTRIBUTE_SECURITY = 168,
NAN_ATTRIBUTE_QOS = 169,
NAN_ATTRIBUTE_RSP_CODE = 170,
NAN_ATTRIBUTE_INST_COUNT = 171,
NAN_ATTRIBUTE_PEER_DISC_MAC_ADDR = 172,
NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR = 173,
NAN_ATTRIBUTE_IF_ADDR = 174,
NAN_ATTRIBUTE_WARMUP_TIME = 175,
NAN_ATTRIBUTE_RECV_IND_CFG = 176,
NAN_ATTRIBUTE_RSSI_CLOSE_5G = 177,
NAN_ATTRIBUTE_RSSI_MIDDLE_5G = 178,
NAN_ATTRIBUTE_RSSI_PROXIMITY_5G = 179,
NAN_ATTRIBUTE_CONNMAP = 180,
NAN_ATTRIBUTE_24G_CHANNEL = 181,
NAN_ATTRIBUTE_5G_CHANNEL = 182,
NAN_ATTRIBUTE_DWELL_TIME = 183,
NAN_ATTRIBUTE_SCAN_PERIOD = 184,
NAN_ATTRIBUTE_RSSI_WINDOW_SIZE = 185,
NAN_ATTRIBUTE_CONF_CLUSTER_VAL = 186,
NAN_ATTRIBUTE_AVAIL_BIT_MAP = 187,
NAN_ATTRIBUTE_ENTRY_CONTROL = 188,
NAN_ATTRIBUTE_CIPHER_SUITE_TYPE = 189,
NAN_ATTRIBUTE_KEY_TYPE = 190,
NAN_ATTRIBUTE_KEY_LEN = 191,
NAN_ATTRIBUTE_SCID = 192,
NAN_ATTRIBUTE_SCID_LEN = 193,
NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP = 194,
NAN_ATTRIBUTE_SDE_CONTROL_SECURITY = 195,
NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE = 196,
NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT = 197,
NAN_ATTRIBUTE_NO_CONFIG_AVAIL = 198,
NAN_ATTRIBUTE_2G_AWAKE_DW = 199,
NAN_ATTRIBUTE_5G_AWAKE_DW = 200,
NAN_ATTRIBUTE_RANGING_INTERVAL = 201,
NAN_ATTRIBUTE_RANGING_INDICATION = 202,
NAN_ATTRIBUTE_RANGING_INGRESS_LIMIT = 203,
NAN_ATTRIBUTE_RANGING_EGRESS_LIMIT = 204,
NAN_ATTRIBUTE_RANGING_AUTO_ACCEPT = 205,
NAN_ATTRIBUTE_RANGING_RESULT = 206,
NAN_ATTRIBUTE_DISC_IND_CFG = 207,
NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG = 208,
NAN_ATTRIBUTE_KEY_DATA = 209,
NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN = 210,
NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO = 211,
NAN_ATTRIBUTE_REASON = 212,
NAN_ATTRIBUTE_MATCH_OCCURRED_FLAG = 213,
NAN_ATTRIBUTE_OUT_OF_RESOURCE_FLAG = 214,
NAN_ATTRIBUTE_DWELL_TIME_5G = 215,
NAN_ATTRIBUTE_SCAN_PERIOD_5G = 216,
NAN_ATTRIBUTE_SVC_RESPONDER_POLICY = 217,
NAN_ATTRIBUTE_EVENT_MASK = 218,
NAN_ATTRIBUTE_SUB_SID_BEACON = 219,
NAN_ATTRIBUTE_RANDOMIZATION_INTERVAL = 220,
NAN_ATTRIBUTE_CMD_RESP_DATA = 221,
NAN_ATTRIBUTE_CMD_USE_NDPE = 222,
NAN_ATTRIBUTE_ENABLE_MERGE = 223,
NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL = 224,
NAN_ATTRIBUTE_NSS = 225,
NAN_ATTRIBUTE_ENABLE_RANGING = 226,
NAN_ATTRIBUTE_DW_EARLY_TERM = 227,
NAN_ATTRIBUTE_CHANNEL_INFO = 228,
NAN_ATTRIBUTE_NUM_CHANNELS = 229,
NAN_ATTRIBUTE_INSTANT_MODE_ENABLE = 230,
NAN_ATTRIBUTE_INSTANT_COMM_CHAN = 231,
NAN_ATTRIBUTE_CHRE_REQUEST = 232,
} NAN_ATTRIBUTE;
typedef enum {
NAN_REQUEST_ENABLE = 0,
NAN_REQUEST_DISABLE = 1,
NAN_REQUEST_PUBLISH = 2,
NAN_REQUEST_PUBLISH_CANCEL = 3,
NAN_REQUEST_TRANSMIT_FOLLOWUP = 4,
NAN_REQUEST_SUBSCRIBE = 5,
NAN_REQUEST_SUBSCRIBE_CANCEL = 6,
NAN_REQUEST_STATS = 7,
NAN_REQUEST_CONFIG = 8,
NAN_REQUEST_TCA = 9,
NAN_REQUEST_EVENT_CHECK = 10,
NAN_REQUEST_GET_CAPABILTIES = 11,
NAN_DATA_PATH_IFACE_CREATE = 12,
NAN_DATA_PATH_IFACE_DELETE = 13,
NAN_DATA_PATH_INIT_REQUEST = 14,
NAN_DATA_PATH_IND_RESPONSE = 15,
NAN_DATA_PATH_END = 16,
NAN_DATA_PATH_IFACE_UP = 17,
NAN_DATA_PATH_SEC_INFO = 18,
NAN_VERSION_INFO = 19,
NAN_REQUEST_LAST = 0xFFFF
} NanRequestType;
/*
* The enum is based on the BCME Response defs
* used in the firmware and defined at
* path: src/include/bcmeutils.h
*/
enum nan_response_status {
BCME_OK = 0,
BCME_ERROR = -1,
BCME_BADARG = -2,
BCME_BADRATESET = -12,
BCME_BADBAND = -13,
BCME_BUSY = -16,
BCME_BADCHAN = -20,
BCME_UNSUPPORTED = -23,
BCME_BADLEN = -24,
BCME_NOTREADY = -25,
BCME_NOMEM = -27,
BCME_NOTFOUND = -30,
BCME_TXFAIL = -38,
BCME_RXFAIL = -39,
BCME_SCANREJECT = -43,
BCME_USAGE_ERROR = -44,
BCME_IOCTL_ERROR = -45
};
enum nan_de_event_type {
NAN_EVENT_IFACE = 0,
NAN_EVENT_START = 1,
NAN_EVENT_JOIN = 2,
NAN_EVENT_ROLE_CHANGE = 3,
NAN_EVENT_MERGE = 4
};
typedef struct _nan_hal_resp {
u16 instance_id;
u16 subcmd;
int32_t status;
int32_t value;
/* Identifier for the instance of the NDP */
u16 ndp_instance_id;
/* Publisher NMI */
u8 pub_nmi[NAN_MAC_ADDR_LEN];
/* SVC_HASH */
u8 svc_hash[NAN_SVC_HASH_SIZE];
char nan_reason[NAN_ERROR_STR_LEN]; /* Describe the NAN reason type */
char pad[3];
NanCapabilities capabilities;
} nan_hal_resp_t;
typedef int (*match_fn)(void *p1, void *data);
typedef struct _nan_hal_info {
void *nan_handle;
void *nan_mac_control;
void *nan_disc_control;
void *nan_dp_control;
} nan_hal_info_t;
u8 mNmi[NAN_MAC_ADDR_LEN];
/* Static functions */
static int is_de_event(int cmd);
static int is_dp_event(int cmd);
static int is_cmd_response(int cmd);
static int get_svc_hash(unsigned char *svc_name, u16 svc_name_len,
u8 *svc_hash, u16 svc_hash_len);
NanResponseType get_response_type(WIFI_SUB_COMMAND nan_subcmd);
NanResponseType get_response_type_frm_req_type(NanRequestType cmdType);
static NanStatusType nan_map_response_status(int vendor_status);
/* Function to separate the common events to NAN1.0 events */
static int is_de_event(int cmd) {
bool is_de_evt = false;
switch(cmd) {
case NAN_EVENT_SUBSCRIBE_UNMATCH:
case NAN_EVENT_SUBSCRIBE_TERMINATED:
case NAN_EVENT_PUBLISH_TERMINATED:
case NAN_EVENT_SUBSCRIBE_MATCH:
case NAN_EVENT_FOLLOWUP:
case NAN_EVENT_TRANSMIT_FOLLOWUP_IND:
case NAN_EVENT_PUBLISH_REPLIED_IND:
case NAN_EVENT_MATCH_EXPIRY:
is_de_evt = true;
break;
default:
/* Not used */
break;
}
return is_de_evt;
}
/* Function to separate NAN2.0 events */
static int is_dp_event(int cmd) {
bool is_dp_evt = false;
switch(cmd) {
case NAN_EVENT_DATA_REQUEST:
case NAN_EVENT_DATA_CONFIRMATION:
case NAN_EVENT_DATA_END:
is_dp_evt = true;
break;
default:
/* Not used */
break;
}
return is_dp_evt;
}
static int is_cmd_response(int cmd) {
bool is_cmd_resp = false;
switch(cmd) {
case NAN_ASYNC_RESPONSE_DISABLED:
is_cmd_resp = true;
break;
default:
break;
}
return is_cmd_resp;
}
static NanStatusType nan_map_response_status (int vendor_status) {
NanStatusType hal_status;
switch(vendor_status) {
case BCME_OK:
hal_status = NAN_STATUS_SUCCESS;
break;
case BCME_BUSY:
hal_status = NAN_STATUS_NO_RESOURCE_AVAILABLE;
break;
case BCME_NOTREADY:
hal_status = NAN_STATUS_NAN_NOT_ALLOWED;
break;
case BCME_BADLEN:
case BCME_BADBAND:
hal_status = NAN_STATUS_INVALID_PARAM;
break;
case BCME_NOMEM:
hal_status = NAN_STATUS_NO_RESOURCE_AVAILABLE;
break;
case NAN_STATUS_INTERNAL_FAILURE:
case NAN_STATUS_PROTOCOL_FAILURE:
case NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID:
case NAN_STATUS_NO_RESOURCE_AVAILABLE:
case NAN_STATUS_INVALID_PARAM:
case NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID:
case NAN_STATUS_INVALID_NDP_ID:
case NAN_STATUS_NAN_NOT_ALLOWED:
case NAN_STATUS_NO_OTA_ACK:
case NAN_STATUS_ALREADY_ENABLED:
case NAN_STATUS_FOLLOWUP_QUEUE_FULL:
case NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED:
hal_status = (NanStatusType)vendor_status;
break;
default:
ALOGE("%s Unknown vendor status, status = %d\n",
__func__, vendor_status);
/* Generic error */
hal_status = NAN_STATUS_INTERNAL_FAILURE;
}
return hal_status;
}
static void prhex(const char *msg, u8 *buf, u32 nbytes);
static const char *NanAttrToString(u16 cmd);
static const char *NanCmdToString(int cmd);
static const char *NanRspToString(int cmd);
#define NAN_DBG_ENTER() {ALOGI("Enter: %s\n", __func__);}
#define NAN_DBG_EXIT() {ALOGI("Exit: %s\n", __func__);}
static int passphrase_to_pmk(u8 *peer_mac, u32 cipher_type,
u8 *svc_hash, NanSecurityKeyInfo *key_info, u8 *pmk_hex) {
int result = NAN_STATUS_SUCCESS;
u8 salt[NAN_SECURITY_SALT_SIZE];
NAN_DBG_ENTER();
salt[0] = 0; /* salt_version */
salt[1] = cipher_type;
if (svc_hash && peer_mac) {
memcpy(&salt[2], svc_hash, NAN_SVC_HASH_SIZE);
memcpy(&salt[2 + NAN_SVC_HASH_SIZE], peer_mac,
ETHER_ADDR_LEN);
prhex("Salt", salt, NAN_SECURITY_SALT_SIZE);
} else {
ALOGE("Mandory parameters are not present\n");
return WIFI_ERROR_INVALID_ARGS;
}
if (key_info->body.passphrase_info.passphrase_len < NAN_SECURITY_MIN_PASSPHRASE_LEN ||
key_info->body.passphrase_info.passphrase_len > NAN_SECURITY_MAX_PASSPHRASE_LEN) {
ALOGE("passphrase must be between %d and %d characters long\n",
NAN_SECURITY_MIN_PASSPHRASE_LEN,
NAN_SECURITY_MAX_PASSPHRASE_LEN);
return WIFI_ERROR_INVALID_ARGS;
}
result = PKCS5_PBKDF2_HMAC((const char *) key_info->body.passphrase_info.passphrase,
key_info->body.passphrase_info.passphrase_len, salt, sizeof(salt),
4096, ((cipher_type == NAN_CIPHER_SUITE_SHARED_KEY_128_MASK) ?
(const EVP_MD *)EVP_sha256():(const EVP_MD *)EVP_sha384()), NAN_PMK_INFO_LEN, pmk_hex);
prhex("PMK_HEX", pmk_hex, 32);
NAN_DBG_EXIT();
return result;
}
typedef void *NanRequest;
nan_hal_info_t info;
#define SVC_LIST(info) ((info).svc_list)
#define SVC_LIST_SIZE(info) ((info).svc_list.total_items)
#define DP_SVC_LIST(info) ((info).dp_svc_list)
#define DP_SVC_LIST_SIZE(info) ((info).dp_svc_list.total_items)
#define NAN_HANDLE(info) ((info).nan_handle)
#define GET_NAN_HANDLE(info) ((NanHandle *)info.nan_handle)
#define NAN_MAC_CONTROL(info) ((info).nan_mac_control)
///////////////////////////////////////////////////////////////////////////////
class NanHandle
{
public:
NanCallbackHandler mHandlers;
NanHandle(wifi_handle handle, NanCallbackHandler handlers):mHandlers(handlers)
{}
};
void HandleExpiryEvent(nan_hal_info_t info, nlattr *vendor_data) {
ALOGI("Received NAN_EVENT_MATCH_EXPIRY\n");
u16 attr_type;
NanMatchExpiredInd expired_event;
memset(&expired_event, 0, sizeof(NanMatchExpiredInd));
for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
attr_type = it.get_type();
if (attr_type == NAN_ATTRIBUTE_SUBSCRIBE_ID) {
expired_event.publish_subscribe_id = it.get_u16();
ALOGI("pub_sub id = %u\n",
expired_event.publish_subscribe_id);
} else if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
expired_event.requestor_instance_id = it.get_u32();
ALOGI("req_inst id = %u\n", expired_event.requestor_instance_id);
}
}
if (expired_event.requestor_instance_id && expired_event.publish_subscribe_id) {
GET_NAN_HANDLE(info)->mHandlers.EventMatchExpired(&expired_event);
} else {
ALOGE("Invalid values for notifying the expired event, dropping the event\n");
}
}
///////////////////////////////////////////////////////////////////////////////
class NanDiscEnginePrimitive : public WifiCommand
{
NanRequest mParams;
NanRequestType mType;
u16 mInstId;
u32 mPeerId;
u16 mTxId;
public:
NanDiscEnginePrimitive(wifi_interface_handle iface, int id,
NanRequest params, NanRequestType cmdType)
: WifiCommand("NanCommand", iface, id), mParams(params), mType(cmdType)
{
mInstId = 0;
mPeerId = 0;
setTransactionId(id);
}
~NanDiscEnginePrimitive() {
ALOGE("NanDiscEnginePrimitive destroyed\n");
}
void setType(NanRequestType type) {
mType = type;
}
void setInstId(u16 inst_id) {
mInstId = inst_id;
}
int getInstanceId() {
return mInstId;
}
void setTransactionId(u16 tx_id) {
mTxId = tx_id;
}
int getTransactionId() {
return mTxId;
}
void setParams(NanRequest params) {
mParams = params;
}
int createRequest(WifiRequest& request)
{
ALOGI("NAN CMD: %s\n", NanCmdToString(mType));
if (mType == NAN_REQUEST_SUBSCRIBE) {
return createSubscribeRequest(request,
(NanSubscribeRequest *)mParams);
} else if (mType == NAN_REQUEST_SUBSCRIBE_CANCEL) {
return createSubscribeCancelRequest(request,
(NanSubscribeCancelRequest *)mParams);
} else if (mType == NAN_REQUEST_PUBLISH) {
return createPublishRequest(request,
(NanPublishRequest *)mParams);
} else if (mType == NAN_REQUEST_PUBLISH_CANCEL) {
return createPublishCancelRequest(request,
(NanPublishCancelRequest *)mParams);
} else if (mType == NAN_REQUEST_TRANSMIT_FOLLOWUP) {
return createTransmitFollowupRequest(request,
(NanTransmitFollowupRequest *)mParams);
} else if (mType == NAN_REQUEST_GET_CAPABILTIES) {
return getCapabilitiesRequest(request);
} else {
ALOGE("%s Unknown Nan request\n", __func__);
}
return WIFI_SUCCESS;
}
int createPublishRequest(WifiRequest& request, NanPublishRequest *mParams)
{
NAN_DBG_ENTER();
u8 pmk_hex[NAN_PMK_INFO_LEN];
int result = request.create(GOOGLE_OUI, NAN_SUBCMD_PUBLISH);
if (result < 0) {
ALOGE("%s Failed to create request, result = %d\n", __func__, result);
return result;
}
/* If handle is 0xFFFF, then update instance_id in response of this request
* otherwise, update not needed
*/
mInstId = mParams->publish_id;
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
result = request.put_u32(NAN_ATTRIBUTE_PUBLISH_ID, mInstId);
if (result < 0) {
ALOGE("%s: Failed to fill pub id, result = %d\n", __func__, result);
return result;
}
result = request.put_u16(NAN_ATTRIBUTE_TTL, mParams->ttl);
if (result < 0) {
ALOGE("%s: Failed to fill ttl, result = %d\n", __func__, result);
return result;
}
if (ISGREATER(mParams->period, NAN_MAX_PERIOD)) {
ALOGE("%s:Invalid period value.\n", __FUNCTION__);
return WIFI_ERROR_NOT_SUPPORTED;
}
result = request.put_u16(NAN_ATTRIBUTE_PERIOD, mParams->period);
if (result < 0) {
ALOGE("%s: Failed to fill period, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_PUBLISH_TYPE, mParams->publish_type);
if (result < 0) {
ALOGE("%s: Failed to fill pub type, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_TX_TYPE, mParams->tx_type);
if (result < 0) {
ALOGE("%s: Failed to fill tx type, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_PUBLISH_COUNT, mParams->publish_count);
if (result < 0) {
ALOGE("%s: Failed to fill pub cnt, result = %d\n", __func__, result);
return result;
}
if (mParams->service_name_len) {
u8 svc_hash[NAN_SVC_HASH_SIZE];
u16 len = min(mParams->service_name_len, sizeof(mParams->service_name) - 1);
mParams->service_name[len] = '\0';
result = get_svc_hash(mParams->service_name, mParams->service_name_len,
svc_hash, NAN_SVC_HASH_SIZE);
if (result < 0) {
ALOGE("%s: Failed to get hashed svc name\n", __func__);
return result;
}
mParams->service_name_len = NAN_SVC_HASH_SIZE;
memcpy(mParams->service_name, svc_hash, mParams->service_name_len);
result = request.put_u16(NAN_ATTRIBUTE_SERVICE_NAME_LEN, mParams->service_name_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc name len, result = %d\n", __func__, result);
return result;
}
result = request.put(NAN_ATTRIBUTE_SERVICE_NAME, (void *)mParams->service_name,
mParams->service_name_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc name, result = %d\n", __func__, result);
return result;
}
}
if (mParams->service_specific_info_len) {
result = request.put_u16(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
mParams->service_specific_info_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc info len, result = %d\n", __func__, result);
return result;
}
result = request.put(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
(void *)mParams->service_specific_info, mParams->service_specific_info_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc info, result = %d\n", __func__, result);
return result;
}
}
if (mParams->rx_match_filter_len) {
result = request.put_u16(NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN,
mParams->rx_match_filter_len);
if (result < 0) {
ALOGE("%s: Failed to fill rx match filter len, result = %d\n",
__func__, result);
return result;
}
prhex(NULL, mParams->rx_match_filter, mParams->rx_match_filter_len);
result = request.put(NAN_ATTRIBUTE_RX_MATCH_FILTER,
(void *)mParams->rx_match_filter, mParams->rx_match_filter_len);
if (result < 0) {
ALOGE("%s: Failed to fill rx match filter, result = %d\n", __func__, result);
return result;
}
}
if (mParams->tx_match_filter_len) {
result = request.put_u16(NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN,
mParams->tx_match_filter_len);
if (result < 0) {
ALOGE("%s: Failed to fill tx match filter, result = %d\n", __func__, result);
return result;
}
prhex(NULL, mParams->tx_match_filter, mParams->tx_match_filter_len);
result = request.put(NAN_ATTRIBUTE_TX_MATCH_FILTER,
(void *)mParams->tx_match_filter, mParams->tx_match_filter_len);
if (result < 0) {
ALOGE("%s: Failed to fill tx match filter, result = %d\n",
__func__, result);
return result;
}
}
result = request.put_u8(NAN_ATTRIBUTE_PUBLISH_MATCH, mParams->publish_match_indicator);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_PUBLISH_MATCH, result = %d\n",
__func__, result);
return result;
}
if (ISGREATER(mParams->recv_indication_cfg, NAN_PUB_RECV_FLAG_MAX)) {
ALOGE("%s:Invalid recv_flag value.\n", __FUNCTION__);
return WIFI_ERROR_NOT_SUPPORTED;
}
result = request.put_u8(NAN_ATTRIBUTE_RECV_IND_CFG,
mParams->recv_indication_cfg);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_RECV_IND_CFG, result = %d\n",
__func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_CIPHER_SUITE_TYPE,
mParams->cipher_type);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_CIPHER_SUITE_TYPE, result = %d\n",
__func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_KEY_TYPE,
mParams->key_info.key_type);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_KEY_TYPE, result = %d\n",
__func__, result);
return result;
}
if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK) {
if (mParams->key_info.body.pmk_info.pmk_len) {
result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN,
mParams->key_info.body.pmk_info.pmk_len);
if (result < 0) {
ALOGE("%s: Failed to fill pmk len, result = %d\n", __func__, result);
return result;
}
result = request.put(NAN_ATTRIBUTE_KEY_DATA,
(void *)mParams->key_info.body.pmk_info.pmk,
mParams->key_info.body.pmk_info.pmk_len);
if (result < 0) {
ALOGE("%s: Failed to fill pmk, result = %d\n", __func__, result);
return result;
}
}
}
if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE) {
if (mParams->key_info.body.passphrase_info.passphrase_len < NAN_SECURITY_MIN_PASSPHRASE_LEN ||
mParams->key_info.body.passphrase_info.passphrase_len > NAN_SECURITY_MAX_PASSPHRASE_LEN) {
ALOGE("passphrase must be between %d and %d characters long\n",
NAN_SECURITY_MIN_PASSPHRASE_LEN,
NAN_SECURITY_MAX_PASSPHRASE_LEN);
return NAN_STATUS_INVALID_PARAM;
} else {
memset(pmk_hex, 0, NAN_PMK_INFO_LEN);
result = passphrase_to_pmk(mNmi, mParams->cipher_type,
mParams->service_name, &mParams->key_info, pmk_hex);
if (result < 0) {
ALOGE("%s: Failed to convert passphrase to key data, result = %d\n", __func__, result);
return result;
}
result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN, NAN_PMK_INFO_LEN);
if (result < 0) {
ALOGE("%s: Failed to fill passphrase len, result = %d\n", __func__, result);
return result;
}
result = request.put(NAN_ATTRIBUTE_KEY_DATA, pmk_hex, NAN_PMK_INFO_LEN);
if (result < 0) {
ALOGE("%s: Failed to fill passphrase, result = %d\n", __func__, result);
return result;
}
}
}
if (mParams->scid_len) {
if ((mParams->scid_len > NAN_MAX_SCID_BUF_LEN) ||
(mParams->scid_len % NAN_SCID_INFO_LEN)) {
ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len);
return NAN_STATUS_INVALID_PARAM;
}
result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN,
mParams->scid_len);
if (result < 0) {
ALOGE("%s: Failed to fill scid len, result = %d\n", __func__, result);
return result;
}
prhex(NULL, mParams->scid, mParams->scid_len);
result = request.put(NAN_ATTRIBUTE_SCID,
(void *)mParams->scid, mParams->scid_len);
if (result < 0) {
ALOGE("%s: Failed to fill scid, result = %d\n", __func__, result);
return result;
}
}
result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP,
mParams->sdea_params.config_nan_data_path);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_SECURITY,
mParams->sdea_params.security_cfg);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_SDE_CONTROL_SECURITY, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE,
mParams->sdea_params.ndp_type);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT,
mParams->sdea_params.ranging_state);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG,
mParams->rssi_threshold_flag);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG, result = %d\n",
__func__, result);
return result;
}
if (mParams->sdea_service_specific_info_len) {
result = request.put_u16(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN,
mParams->sdea_service_specific_info_len);
if (result < 0) {
ALOGE("%s: Failed to fill sdea svc info len, result = %d\n", __func__, result);
return result;
}
prhex(NULL, mParams->sdea_service_specific_info, mParams->sdea_service_specific_info_len);
result = request.put(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO,
(void *)mParams->sdea_service_specific_info, mParams->sdea_service_specific_info_len);
if (result < 0) {
ALOGE("%s: Failed to fill sdea svc info, result = %d\n", __func__, result);
return result;
}
}
result = request.put_u8(NAN_ATTRIBUTE_SVC_RESPONDER_POLICY,
mParams->service_responder_policy);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_SVC_RESPONDER_POLICY, result = %d\n",
__func__, result);
return result;
}
request.attr_end(data);
ALOGI("Returning successfully\n");
NAN_DBG_EXIT();
return result;
}
int createPublishCancelRequest(WifiRequest& request, NanPublishCancelRequest *mParams)
{
int result = request.create(GOOGLE_OUI, NAN_SUBCMD_PUBLISH_CANCEL);
if (result < 0) {
ALOGE("%s: Failed to create request, result = %d\n", __func__, result);
return result;
}
NAN_DBG_ENTER();
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
if (ISGREATER(mInstId, NAN_MAX)) {
ALOGE("%s:Invalid publish count value.\n", __FUNCTION__);
return WIFI_ERROR_NOT_SUPPORTED;
}
ALOGI("%s: pub id = %d, inst_id = %d\n", __func__, mParams->publish_id, mInstId);
result = request.put_u32(NAN_ATTRIBUTE_PUBLISH_ID, mInstId);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_PUBLISH_ID, result = %d\n",
__func__, result);
return result;
}
request.attr_end(data);
NAN_DBG_EXIT();
return WIFI_SUCCESS;
}
int createSubscribeRequest(WifiRequest& request, NanSubscribeRequest *mParams)
{
int result = request.create(GOOGLE_OUI, NAN_SUBCMD_SUBSCRIBE);
if (result < 0) {
ALOGE("%s Failed to create request\n", __func__);
return result;
}
NAN_DBG_ENTER();
/* If handle is 0xFFFF, then update instance_id in response of this request
* otherwise, update not needed
*/
mInstId = mParams->subscribe_id;
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
result = request.put_u16(NAN_ATTRIBUTE_SUBSCRIBE_ID, mInstId);
if (result < 0) {
ALOGE("%s: Failed to fill sub id, result = %d\n", __func__, result);
return result;
}
result = request.put_u16(NAN_ATTRIBUTE_TTL, mParams->ttl);
if (result < 0) {
ALOGE("%s: Failed to fill ttl, result = %d\n", __func__, result);
return result;
}
if (ISGREATER(mParams->period, NAN_MAX_PERIOD)) {
ALOGE("%s:Invalid period value.\n", __FUNCTION__);
return WIFI_ERROR_NOT_SUPPORTED;
}
result = request.put_u16(NAN_ATTRIBUTE_PERIOD, mParams->period);
if (result < 0) {
ALOGE("%s: Failed to fill period, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_SUBSCRIBE_TYPE, mParams->subscribe_type);
if (result < 0) {
ALOGE("%s: Failed to fill sub type, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_SERVICERESPONSEFILTER,
mParams->serviceResponseFilter);
if (result < 0) {
ALOGE("%s: Failed to fill svc resp filter, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_SERVICERESPONSEINCLUDE,
mParams->serviceResponseInclude);
if (result < 0) {
ALOGE("%s: Failed to fill svc resp include, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_USESERVICERESPONSEFILTER,
mParams->useServiceResponseFilter);
if (result < 0) {
ALOGE("%s: Failed to fill use svc resp filter, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_SSIREQUIREDFORMATCHINDICATION,
mParams->ssiRequiredForMatchIndication);
if (result < 0) {
ALOGE("%s: Failed to fill ssi req match ind, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_SUBSCRIBE_MATCH,
mParams->subscribe_match_indicator);
if (result < 0) {
ALOGE("%s: Failed to fill sub match, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_SUBSCRIBE_COUNT, mParams->subscribe_count);
if (result < 0) {
ALOGE("%s: Failed to fill sub cnt, result = %d\n", __func__, result);
return result;
}
if (mParams->service_name_len) {
u8 svc_hash[NAN_SVC_HASH_SIZE];
u16 len = min(mParams->service_name_len, sizeof(mParams->service_name) - 1);
mParams->service_name[len] = '\0';
result = get_svc_hash(mParams->service_name, mParams->service_name_len,
svc_hash, NAN_SVC_HASH_SIZE);
if (result < 0) {
ALOGE("%s: Failed to get hashed svc name\n", __func__);
return result;
}
mParams->service_name_len = NAN_SVC_HASH_SIZE;
memcpy(mParams->service_name, svc_hash, mParams->service_name_len);
result = request.put_u16(NAN_ATTRIBUTE_SERVICE_NAME_LEN, mParams->service_name_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc hash len, result = %d\n",
__func__, result);
return result;
}
result = request.put(NAN_ATTRIBUTE_SERVICE_NAME, (void *)mParams->service_name,
mParams->service_name_len);
if (result < 0) {
ALOGE("%s: Failed to fill hashed svc name, result = %d\n", __func__, result);
return result;
}
}
if (mParams->service_specific_info_len) {
result = request.put_u16(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
mParams->service_specific_info_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc info len, result = %d\n", __func__, result);
return result;
}
result = request.put(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
(void *)mParams->service_specific_info, mParams->service_specific_info_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc info, result = %d\n", __func__, result);
return result;
}
}
if (mParams->rx_match_filter_len) {
result = request.put_u16(NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN,
mParams->rx_match_filter_len);
if (result < 0) {
ALOGE("%s: Failed to fill rx match filter len, result = %d\n", __func__, result);
return result;
}
prhex(NULL, mParams->rx_match_filter, mParams->rx_match_filter_len);
result = request.put(NAN_ATTRIBUTE_RX_MATCH_FILTER,
(void *)mParams->rx_match_filter, mParams->rx_match_filter_len);
if (result < 0) {
ALOGE("%s: Failed to fill rx match filter, result = %d\n", __func__, result);
return result;
}
}
if (mParams->tx_match_filter_len) {
result = request.put_u16(NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN,
mParams->tx_match_filter_len);
if (result < 0) {
ALOGE("%s: Failed to fill tx match filter len, result = %d\n", __func__, result);
return result;
}
prhex(NULL, mParams->tx_match_filter, mParams->tx_match_filter_len);
result = request.put(NAN_ATTRIBUTE_TX_MATCH_FILTER,
(void *)mParams->tx_match_filter, mParams->tx_match_filter_len);
if (result < 0) {
ALOGE("%s: Failed to fill tx match filter, result = %d\n", __func__, result);
return result;
}
}
if (mParams->num_intf_addr_present > NAN_MAX_SUBSCRIBE_MAX_ADDRESS) {
ALOGE("%s: Number of mac addrs: %d have crossed the threshold, fail to subscribe\n",
__func__, mParams->num_intf_addr_present);
return WIFI_ERROR_NOT_SUPPORTED;
} else if (mParams->num_intf_addr_present) {
result = request.put_u16(NAN_ATTRIBUTE_MAC_ADDR_LIST_NUM_ENTRIES,
mParams->num_intf_addr_present);
if (result < 0) {
ALOGE("%s: Failed to fill mac addr list no, result = %d\n",
__func__, result);
return result;
}
prhex(NULL, (u8 *)mParams->intf_addr,
(mParams->num_intf_addr_present * NAN_MAC_ADDR_LEN));
result = request.put(NAN_ATTRIBUTE_MAC_ADDR_LIST, (void *)mParams->intf_addr,
(mParams->num_intf_addr_present * NAN_MAC_ADDR_LEN));
if (result < 0) {
ALOGE("%s: Failed to fill mac addr list, result = %d\n", __func__, result);
return result;
}
}
if (ISGREATER(mParams->recv_indication_cfg, NAN_SUB_RECV_FLAG_MAX)) {
ALOGE("%s:Invalid recv_flag value.\n", __FUNCTION__);
return WIFI_ERROR_NOT_SUPPORTED;
}
result = request.put_u8(NAN_ATTRIBUTE_RECV_IND_CFG,
mParams->recv_indication_cfg);
if (result < 0) {
ALOGE("%s: Failed to fill recv_indication_cfg, result = %d\n",
__func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_CIPHER_SUITE_TYPE,
mParams->cipher_type);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_CIPHER_SUITE_TYPE, result = %d\n",
__func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_KEY_TYPE,
mParams->key_info.key_type);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_KEY_TYPE, result = %d\n",
__func__, result);
return result;
}
if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK) {
if (mParams->key_info.body.pmk_info.pmk_len) {
result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN,
mParams->key_info.body.pmk_info.pmk_len);
if (result < 0) {
ALOGE("%s: Failed to fill pmk len, result = %d\n", __func__, result);
return result;
}
result = request.put(NAN_ATTRIBUTE_KEY_DATA,
(void *)mParams->key_info.body.pmk_info.pmk,
mParams->key_info.body.pmk_info.pmk_len);
if (result < 0) {
ALOGE("%s: Failed to fill pmk, result = %d\n", __func__, result);
return result;
}
}
}
if (mParams->scid_len) {
if (mParams->scid_len != NAN_SCID_INFO_LEN) {
ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len);
return NAN_STATUS_INVALID_PARAM;
}
result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN,
mParams->scid_len);
if (result < 0) {
ALOGE("%s: Failed to fill scid len, result = %d\n", __func__, result);
return result;
}
result = request.put(NAN_ATTRIBUTE_SCID,
(void *)mParams->scid, mParams->scid_len);
if (result < 0) {
ALOGE("%s: Failed to fill scid, result = %d\n", __func__, result);
return result;
}
}
result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP,
mParams->sdea_params.config_nan_data_path);
if (result < 0) {
ALOGE("%s: Failed to fill config_nan_data_path, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_SECURITY,
mParams->sdea_params.security_cfg);
if (result < 0) {
ALOGE("%s: Failed to fill security_cfg, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE,
mParams->sdea_params.ndp_type);
if (result < 0) {
ALOGE("%s: Failed to fill ndp_type, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT,
mParams->sdea_params.ranging_state);
if (result < 0) {
ALOGE("%s: Failed to fill ranging state, result = %d\n", __func__, result);
return result;
}
if (mParams->sdea_params.ranging_state == NAN_RANGING_ENABLE) {
result = request.put_u32(NAN_ATTRIBUTE_RANGING_INTERVAL,
mParams->ranging_cfg.ranging_interval_msec);
if (result < 0) {
ALOGE("%s: Failed to fill ranging_interval_msec, result = %d\n", __func__, result);
return result;
}
result = request.put_u32(NAN_ATTRIBUTE_RANGING_EGRESS_LIMIT,
mParams->ranging_cfg.distance_egress_mm);
if (result < 0) {
ALOGE("%s: Failed to fill distance_egress_mm, result = %d\n", __func__, result);
return result;
}
result = request.put_u32(NAN_ATTRIBUTE_RANGING_INDICATION,
mParams->ranging_cfg.config_ranging_indications);
if (result < 0) {
ALOGE("%s: Failed to fill config_ranging_indications, result = %d\n", __func__, result);
return result;
}
result = request.put_u32(NAN_ATTRIBUTE_RANGING_INGRESS_LIMIT,
mParams->ranging_cfg.distance_ingress_mm);
if (result < 0) {
ALOGE("%s: Failed to fill distance_ingress_mm, result = %d\n", __func__, result);
return result;
}
}
ALOGI("%s:RSSI threshold flag %d", __func__, mParams->rssi_threshold_flag);
result = request.put_u8(NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG,
mParams->rssi_threshold_flag);
if (result < 0) {
ALOGE("%s: Failed to fill rssi_threshold_flag, result = %d\n",
__func__, result);
return result;
}
if (mParams->sdea_service_specific_info_len) {
result = request.put_u16(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN,
mParams->sdea_service_specific_info_len);
if (result < 0) {
ALOGE("%s: Failed to fill sdea svc info len, result = %d\n", __func__, result);
return result;
}
prhex(NULL, mParams->sdea_service_specific_info, mParams->sdea_service_specific_info_len);
result = request.put(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO,
(void *)mParams->sdea_service_specific_info, mParams->sdea_service_specific_info_len);
if (result < 0) {
ALOGE("%s: Failed to fill sdea svc info, result = %d\n", __func__, result);
return result;
}
}
request.attr_end(data);
NAN_DBG_EXIT();
return WIFI_SUCCESS;
}
int createSubscribeCancelRequest(WifiRequest& request,
NanSubscribeCancelRequest *mParams) {
int result = request.create(GOOGLE_OUI, NAN_SUBCMD_SUBSCRIBE_CANCEL);
if (result < 0) {
ALOGE("%s Failed to create request \n", __func__);
return result;
}
NAN_DBG_ENTER();
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
if (ISGREATER(mInstId, NAN_MAX)) {
ALOGE("%s:Invalid subscribe id value.\n", __FUNCTION__);
return WIFI_ERROR_NOT_SUPPORTED;
}
ALOGI("%s: sub id = %u\n", __func__, mInstId);
result = request.put_u16(NAN_ATTRIBUTE_SUBSCRIBE_ID, mInstId);
if (result < 0) {
ALOGE("%s: Failed to fill sub id, result = %d\n", __func__, result);
return result;
}
request.attr_end(data);
NAN_DBG_EXIT();
return WIFI_SUCCESS;
}
int createTransmitFollowupRequest(WifiRequest& request,
NanTransmitFollowupRequest *mParams)
{
int result = request.create(GOOGLE_OUI, NAN_SUBCMD_TRANSMIT_FOLLOWUP);
if (result < 0) {
ALOGE("%s Failed to create request \n", __func__);
return result;
}
NAN_DBG_ENTER();
/* If handle is 0xFFFF, then update instance_id in response of this request
* otherwise, update not needed
*/
mInstId = mParams->publish_subscribe_id;
mPeerId = mParams->requestor_instance_id;
mTxId = getTransactionId();
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
result = request.put_u32(NAN_ATTRIBUTE_PEER_ID, mPeerId);
if (result < 0) {
ALOGE("%s: Failed to fill peer id, result = %d\n", __func__, result);
return result;
}
result = request.put_u16(NAN_ATTRIBUTE_INST_ID, mInstId);
if (result < 0) {
ALOGE("%s Failed to fill inst id = %d \n", __func__, mInstId);
return result;
}
result = request.put_addr(NAN_ATTRIBUTE_MAC_ADDR, mParams->addr);
if (result < 0) {
ALOGE("%s: Failed to fill mac addr\n", __func__);
return result;
}
if (mParams->service_specific_info_len > 0) {
u16 len = min(mParams->service_specific_info_len,
sizeof(mParams->service_specific_info) - 1);
result = request.put_u16(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
mParams->service_specific_info_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc info len \n", __func__);
return result;
}
prhex(NULL, mParams->service_specific_info, mParams->service_specific_info_len);
result = request.put(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
(void *)mParams->service_specific_info, mParams->service_specific_info_len);
if (result < 0) {
ALOGE("%s: Failed to put svc info, result = %d", __func__, result);
return result;
}
mParams->service_specific_info[len] = '\0';
ALOGI("Transmit service info string is %s\n", mParams->service_specific_info);
}
if (ISGREATER(mParams->recv_indication_cfg, NAN_PUB_RECV_FLAG_MAX)) {
ALOGE("%s:Invalid recv_flag value.\n", __FUNCTION__);
return WIFI_ERROR_NOT_SUPPORTED;
}
result = request.put_u8(NAN_ATTRIBUTE_RECV_IND_CFG,
mParams->recv_indication_cfg);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_RECV_IND_CFG, result = %d\n",
__func__, result);
return result;
}
result = request.put_u16(NAN_ATTRIBUTE_TRANSAC_ID, mTxId);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_TRANSAC_ID, result = %d\n",
__func__, result);
return result;
}
if (mParams->sdea_service_specific_info_len) {
result = request.put_u16(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN,
mParams->sdea_service_specific_info_len);
if (result < 0) {
ALOGE("%s: Failed to fill sdea svc info len, result = %d\n", __func__, result);
return result;
}
prhex(NULL, mParams->sdea_service_specific_info, mParams->sdea_service_specific_info_len);
result = request.put(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO,
(void *)mParams->sdea_service_specific_info, mParams->sdea_service_specific_info_len);
if (result < 0) {
ALOGE("%s: Failed to fill sdea svc info, result = %d\n", __func__, result);
return result;
}
}
request.attr_end(data);
NAN_DBG_EXIT();
return WIFI_SUCCESS;
}
int getCapabilitiesRequest(WifiRequest& request) {
int result = 0;
NAN_DBG_ENTER();
result = request.create(GOOGLE_OUI, NAN_SUBCMD_GET_CAPABILITIES);
if (result < 0) {
ALOGE("%s Failed to create request \n", __func__);
return result;
}
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
request.attr_end(data);
NAN_DBG_EXIT();
return WIFI_SUCCESS;
}
int start()
{
int result = 0;
WifiRequest request(familyId(), ifaceId());
result = createRequest(request);
if (result != WIFI_SUCCESS) {
ALOGE("%s: Failed to create setup request; result = %d\n", __func__, result);
return result;
}
result = requestResponse(request);
if (result != WIFI_SUCCESS) {
ALOGE("%s: Failed to configure setup; result = %d\n", __func__, result);
return result;
}
request.destroy();
return WIFI_SUCCESS;
}
virtual bool valid_disc_response_type(int response_type) {
bool valid = false;
switch(response_type) {
case NAN_RESPONSE_PUBLISH:
case NAN_RESPONSE_SUBSCRIBE:
case NAN_GET_CAPABILITIES:
case NAN_RESPONSE_PUBLISH_CANCEL:
case NAN_RESPONSE_SUBSCRIBE_CANCEL:
case NAN_RESPONSE_TRANSMIT_FOLLOWUP:
valid = true;
break;
default:
ALOGE("NanDiscEnginePrmitive:Unknown cmd Response: %d\n", response_type);
break;
}
return valid;
}
int handleResponse(WifiEvent& reply)
{
nan_hal_resp_t *rsp_vndr_data = NULL;
NanResponseMsg rsp_data;
if (reply.get_cmd() != NL80211_CMD_VENDOR || reply.get_vendor_data() == NULL) {
ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
return NL_SKIP;
}
rsp_vndr_data = (nan_hal_resp_t *)reply.get_vendor_data();
ALOGI("NanDiscEnginePrmitive::handle response\n");
memset(&rsp_data, 0, sizeof(NanResponseMsg));
rsp_data.response_type = get_response_type((WIFI_SUB_COMMAND)rsp_vndr_data->subcmd);
if (!valid_disc_response_type(rsp_data.response_type))
return NL_SKIP;
rsp_data.status = nan_map_response_status(rsp_vndr_data->status);
ALOGE("Mapped hal status = %d\n", rsp_data.status);
if (rsp_vndr_data->nan_reason[0] == '\0') {
memcpy(rsp_data.nan_error, NanStatusToString(rsp_data.status),
strlen(NanStatusToString(rsp_data.status)));
rsp_data.nan_error[strlen(NanStatusToString(rsp_data.status))] = '\0';
}
rsp_data.nan_error[NAN_ERROR_STR_LEN - 1] = '\0';
ALOGI("\n Received nan_error string %s\n", (u8*)rsp_data.nan_error);
if (mInstId == 0 &&
(rsp_data.response_type == NAN_RESPONSE_PUBLISH ||
rsp_data.response_type == NAN_RESPONSE_SUBSCRIBE)) {
ALOGI("Received service instance_id %d\n", rsp_vndr_data->instance_id);
mInstId = rsp_vndr_data->instance_id;
}
if (rsp_data.response_type == NAN_RESPONSE_PUBLISH) {
rsp_data.body.publish_response.publish_id = mInstId;
} else if (rsp_data.response_type == NAN_RESPONSE_SUBSCRIBE) {
rsp_data.body.subscribe_response.subscribe_id = mInstId;
} else if (rsp_data.response_type == NAN_GET_CAPABILITIES) {
memcpy((void *)&rsp_data.body.nan_capabilities, (void *)&rsp_vndr_data->capabilities,
sizeof(rsp_data.body.nan_capabilities));
}
GET_NAN_HANDLE(info)->mHandlers.NotifyResponse(id(), &rsp_data);
ALOGI("NanDiscEnginePrmitive:Received response for cmd [%s], ret %d\n",
NanRspToString(rsp_data.response_type), rsp_data.status);
return NL_SKIP;
}
int handleEvent(WifiEvent& event) {
int cmd = event.get_vendor_subcmd();
u16 attr_type;
ALOGI("Received NanDiscEnginePrimitive event: %d\n", event.get_cmd());
nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
switch(cmd) {
case NAN_EVENT_PUBLISH_TERMINATED:
NanPublishTerminatedInd pub_term_event;
memset(&pub_term_event, 0, sizeof(NanPublishTerminatedInd));
for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
attr_type = it.get_type();
if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
pub_term_event.publish_id = it.get_u32();
ALOGI("pub id = %u", pub_term_event.publish_id);
} else if (attr_type == NAN_ATTRIBUTE_STATUS) {
pub_term_event.reason = (NanStatusType)it.get_u8();
ALOGI("pub termination status %u", pub_term_event.reason);
} else if (attr_type == NAN_ATTRIBUTE_REASON) {
u8 len = min(it.get_len(), sizeof(pub_term_event.nan_reason) - 1);
memcpy(pub_term_event.nan_reason, it.get_data(), len);
pub_term_event.nan_reason[len] = '\0';
ALOGI("pub termination reason: %s, len = %d\n",
pub_term_event.nan_reason, len);
} else {
ALOGE("Unknown attr: %u\n", attr_type);
}
}
GET_NAN_HANDLE(info)->mHandlers.EventPublishTerminated(&pub_term_event);
break;
case NAN_EVENT_SUBSCRIBE_MATCH:
NanMatchInd subscribe_event;
memset(&subscribe_event, 0, sizeof(NanMatchInd));
/* By default FW is unable to cache this match */
subscribe_event.out_of_resource_flag = true;
for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
attr_type = it.get_type();
if (attr_type == NAN_ATTRIBUTE_SUBSCRIBE_ID) {
ALOGI("sub id: %u", it.get_u16());
subscribe_event.publish_subscribe_id = it.get_u8();
} else if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
ALOGI("pub id: %u", it.get_u32());
subscribe_event.requestor_instance_id = it.get_u8();
} else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
memcpy(subscribe_event.addr, it.get_data(), NAN_MAC_ADDR_LEN);
ALOGI("Publisher mac: " MACSTR, MAC2STR(subscribe_event.addr));
} else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
ALOGI("svc length %d", it.get_u16());
subscribe_event.service_specific_info_len = it.get_u16();
} else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO) {
memcpy(subscribe_event.service_specific_info, it.get_data(),
subscribe_event.service_specific_info_len);
subscribe_event.service_specific_info
[subscribe_event.service_specific_info_len] = '\0';
ALOGI("service info: %s", subscribe_event.service_specific_info);
} else if (attr_type == NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN) {
ALOGI("sdf match filter length: %d", subscribe_event.sdf_match_filter_len);
subscribe_event.sdf_match_filter_len = it.get_u16();
} else if (attr_type == NAN_ATTRIBUTE_TX_MATCH_FILTER) {
memcpy(subscribe_event.sdf_match_filter, it.get_data(),
subscribe_event.sdf_match_filter_len);
subscribe_event.sdf_match_filter
[subscribe_event.sdf_match_filter_len] = '\0';
ALOGI("sdf match filter: %s", subscribe_event.sdf_match_filter);
} else if (attr_type == NAN_ATTRIBUTE_CIPHER_SUITE_TYPE) {
ALOGI("Peer Cipher suite type: %u", it.get_u8());
subscribe_event.peer_cipher_type = it.get_u8();
} else if (attr_type == NAN_ATTRIBUTE_SCID_LEN) {
ALOGI("scid length %d", it.get_u32());
subscribe_event.scid_len= it.get_u32();
} else if (attr_type == NAN_ATTRIBUTE_SCID) {
memcpy(subscribe_event.scid, it.get_data(),
subscribe_event.scid_len);
subscribe_event.scid
[subscribe_event.scid_len] = '\0';
ALOGI("scid: %s", subscribe_event.scid);
} else if (attr_type == NAN_ATTRIBUTE_RANGING_INDICATION) {
subscribe_event.range_info.ranging_event_type = it.get_u32();
ALOGI("ranging indication %d", it.get_u32());
} else if (attr_type == NAN_ATTRIBUTE_RANGING_RESULT) {
subscribe_event.range_info.range_measurement_mm = it.get_u32();
ALOGI("ranging result %d", it.get_u32());
} else if (attr_type == NAN_ATTRIBUTE_RSSI_PROXIMITY) {
subscribe_event.rssi_value = it.get_u8();
ALOGI("rssi value : %u", it.get_u8());
} else if (attr_type == NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
ALOGI("sdea svc length %d", it.get_u16());
subscribe_event.sdea_service_specific_info_len = it.get_u16();
} else if (attr_type == NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO) {
memcpy(subscribe_event.sdea_service_specific_info, it.get_data(),
subscribe_event.sdea_service_specific_info_len);
subscribe_event.sdea_service_specific_info
[subscribe_event.sdea_service_specific_info_len] = '\0';
ALOGI("sdea service info: %s", subscribe_event.sdea_service_specific_info);
} else if (attr_type == NAN_ATTRIBUTE_MATCH_OCCURRED_FLAG) {
ALOGI("match occurred flag: %u", it.get_u8());
subscribe_event.match_occured_flag = it.get_u8();
} else if (attr_type == NAN_ATTRIBUTE_OUT_OF_RESOURCE_FLAG) {
ALOGI("Out of resource flag: %u", it.get_u8());
subscribe_event.out_of_resource_flag = it.get_u8();
} else if (attr_type == NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP) {
ALOGI("Peer config for data path needed: %u", it.get_u8());
subscribe_event.peer_sdea_params.config_nan_data_path = it.get_u8();
} else if (attr_type == NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE) {
ALOGI("Data Path type: %u", it.get_u8());
subscribe_event.peer_sdea_params.ndp_type = (NdpType)it.get_u8();
} else if (attr_type == NAN_ATTRIBUTE_SDE_CONTROL_SECURITY) {
ALOGI("Security configuration: %u", it.get_u8());
subscribe_event.peer_sdea_params.security_cfg =
(NanDataPathSecurityCfgStatus)it.get_u8();
} else if (attr_type == NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT) {
ALOGI("Ranging report state: %u", it.get_u8());
subscribe_event.peer_sdea_params.range_report = (NanRangeReport)it.get_u8();
}
}
GET_NAN_HANDLE(info)->mHandlers.EventMatch(&subscribe_event);
break;
case NAN_EVENT_SUBSCRIBE_UNMATCH:
ALOGE("%s: Not applicable yet\n", __func__);
break;
case NAN_EVENT_SUBSCRIBE_TERMINATED:
NanSubscribeTerminatedInd sub_term_event;
memset(&sub_term_event, 0, sizeof(NanSubscribeTerminatedInd));
for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
attr_type = it.get_type();
if (attr_type == NAN_ATTRIBUTE_SUBSCRIBE_ID) {
sub_term_event.subscribe_id = it.get_u16();
ALOGI("sub id = %u", sub_term_event.subscribe_id);
} else if (attr_type == NAN_ATTRIBUTE_STATUS) {
sub_term_event.reason = (NanStatusType)it.get_u16();
ALOGI("sub termination status %u", sub_term_event.reason);
} else if (attr_type == NAN_ATTRIBUTE_REASON) {
u8 len = min(it.get_len(), sizeof(sub_term_event.nan_reason) - 1);
memcpy(sub_term_event.nan_reason, it.get_data(), len);
sub_term_event.nan_reason[len] = '\0';
ALOGI("sub termination nan reason: %s, len = %d\n",
sub_term_event.nan_reason, len);
} else {
ALOGI("Unknown attr: %d\n", attr_type);
}
}
GET_NAN_HANDLE(info)->mHandlers.EventSubscribeTerminated(&sub_term_event);
break;
case NAN_EVENT_MATCH_EXPIRY:
HandleExpiryEvent(info, vendor_data);
break;
case NAN_EVENT_FOLLOWUP:
NanFollowupInd followup_event;
memset(&followup_event, 0, sizeof(NanFollowupInd));
for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
attr_type = it.get_type();
if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
memcpy(followup_event.addr, it.get_data(), NAN_MAC_ADDR_LEN);
} else if (attr_type == NAN_ATTRIBUTE_PEER_ID) {
followup_event.publish_subscribe_id = it.get_u16();
} else if (attr_type == NAN_ATTRIBUTE_INST_ID) {
followup_event.requestor_instance_id = it.get_u32();
} else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
followup_event.service_specific_info_len = it.get_u16();
} else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO) {
memcpy(followup_event.service_specific_info, it.get_data(),
followup_event.service_specific_info_len);
} else if (attr_type == NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO) {
memcpy(followup_event.sdea_service_specific_info, it.get_data(),
followup_event.sdea_service_specific_info_len);
}
}
counters.transmit_recv++;
GET_NAN_HANDLE(info)->mHandlers.EventFollowup(&followup_event);
break;
case NAN_EVENT_TRANSMIT_FOLLOWUP_IND:
NanTransmitFollowupInd followup_ind;
counters.transmit_txs++;
memset(&followup_ind, 0, sizeof(NanTransmitFollowupInd));
for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
attr_type = it.get_type();
if (attr_type == NAN_ATTRIBUTE_TRANSAC_ID) {
followup_ind.id = it.get_u16();
} else if (attr_type == NAN_ATTRIBUTE_STATUS) {
followup_ind.reason = (NanStatusType)it.get_u8();
} else if (attr_type == NAN_ATTRIBUTE_REASON) {
u8 len = min(it.get_len(), sizeof(followup_ind.nan_reason) - 1);
memcpy(followup_ind.nan_reason, it.get_data(), len);
followup_ind.nan_reason[len] = '\0';
ALOGI("nan transmit followup ind: reason: %s, len = %d\n",
followup_ind.nan_reason, len);
}
}
GET_NAN_HANDLE(info)->mHandlers.EventTransmitFollowup(&followup_ind);
break;
#ifdef NOT_YET
case NAN_EVENT_PUBLISH_REPLIED_IND:
NanPublishRepliedInd pub_reply_event;
memset(&pub_reply_event, 0, sizeof(pub_reply_event));
for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
attr_type = it.get_type();
if (attr_type == NAN_ATTRIBUTE_SUBSCRIBE_ID) {
ALOGI("sub id: %u", it.get_u16());
pub_reply_event.requestor_instance_id = it.get_u8();
} else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
memcpy(pub_reply_event.addr, it.get_data(), NAN_MAC_ADDR_LEN);
ALOGI("Subscriber mac: " MACSTR, MAC2STR(pub_reply_event.addr));
} else if (attr_type == NAN_ATTRIBUTE_RSSI_PROXIMITY) {
pub_reply_event.rssi_value = it.get_u8();
ALOGI("Received rssi value : %u", it.get_u8());
}
}
GET_NAN_HANDLE(info)->mHandlers.EventPublishReplied(&pub_reply_event);
break;
#endif /* NOT_YET */
} // end-of-switch-case
return NL_SKIP;
}
};
///////////////////////////////////////////////////////////////////////////////
class NanDataPathPrimitive : public WifiCommand
{
NanRequest reqContext;
u32 mNdpId;
NanRequestType mType;
u8 count;
public:
NanDataPathPrimitive(wifi_interface_handle iface, int id,
NanRequest params, NanRequestType cmdType)
: WifiCommand("NanCommand", iface, id), reqContext(params), mType(cmdType)
{
mNdpId = 0;
count = 0;
}
~NanDataPathPrimitive() {
ALOGE("NanDataPathPrimitive destroyed\n");
}
u8 mSvcHash[NAN_SVC_HASH_SIZE];
u8 mPubNmi[NAN_MAC_ADDR_LEN];
void setType(NanRequestType type ) {
mType = type;
}
int getNdpId() {
return mNdpId;
}
int createRequest(WifiRequest& request)
{
ALOGI("NAN CMD: %s\n", NanCmdToString(mType));
if (mType == NAN_DATA_PATH_IFACE_CREATE) {
return createDataPathIfaceRequest(request, (char *)reqContext);
} else if (mType == NAN_DATA_PATH_IFACE_DELETE) {
return deleteDataPathIfaceRequest(request, (char *)reqContext);
} else if (mType == NAN_DATA_PATH_INIT_REQUEST) {
return createDataPathInitRequest(request,
(NanDataPathInitiatorRequest *)reqContext);
} else if (mType == NAN_DATA_PATH_IND_RESPONSE) {
return createDataPathIndResponse(request,
(NanDataPathIndicationResponse *)reqContext);
} else if (mType == NAN_DATA_PATH_END) {
return createDataPathEndRequest(request,
(NanDataPathEndRequest *)reqContext);
} else if (mType == NAN_DATA_PATH_SEC_INFO) {
return createDataPathSecInfoRequest(request,
(NanDataPathSecInfoRequest *)reqContext);
} else {
ALOGE("%s: Unknown NDP request: %d\n", __func__, mType);
}
return WIFI_SUCCESS;
}
int createDataPathIfaceRequest(WifiRequest& request, char *iface_name)
{
ALOGD("add ifname = %s, iface_type = %d", iface_name, NL80211_IFTYPE_STATION);
u32 wlan0_id = if_nametoindex("wlan0");
if (!wlan0_id) {
ALOGE("%s: Error wlan0 not present\n", __FUNCTION__);
return WIFI_ERROR_UNKNOWN;
}
/* Do not create interface if already exist. */
if (if_nametoindex(iface_name)) {
ALOGD("%s: if_nametoindex(%s) = %d already exists, skip create \n",
__FUNCTION__, iface_name, if_nametoindex(iface_name));
return WIFI_SUCCESS;
}
int result = request.create(NL80211_CMD_NEW_INTERFACE);
if (result < 0) {
ALOGE("failed to create NL80211_CMD_NEW_INTERFACE; result = %d", result);
return result;
}
result = request.put_u32(NL80211_ATTR_IFINDEX, wlan0_id);
if (result < 0) {
ALOGE("failed to put NL80211_ATTR_IFINDEX; result = %d", result);
return result;
}
result = request.put_string(NL80211_ATTR_IFNAME, iface_name);
if (result < 0) {
ALOGE("failed to put NL80211_ATTR_IFNAME = %s; result = %d", iface_name, result);
return result;
}
result = request.put_u32(NL80211_ATTR_IFTYPE, NL80211_IFTYPE_STATION);
if (result < 0) {
ALOGE("failed to put NL80211_ATTR_IFTYPE; result = %d", result);
return result;
}
return WIFI_SUCCESS;
}
int deleteDataPathIfaceRequest(WifiRequest& request, char *iface_name)
{
ALOGD("delete ifname = %s\n", iface_name);
int result = request.create(NL80211_CMD_DEL_INTERFACE);
if (result < 0) {
ALOGE("failed to create NL80211_CMD_DEL_INTERFACE; result = %d", result);
return result;
}
result = request.put_u32(NL80211_ATTR_IFINDEX, if_nametoindex(iface_name));
if (result < 0) {
ALOGE("failed to put NL80211_ATTR_IFINDEX = %d; result = %d",
if_nametoindex(iface_name), result);
return result;
}
result = request.put_string(NL80211_ATTR_IFNAME, iface_name);
if (result < 0) {
ALOGE("failed to put NL80211_ATTR_IFNAME = %s; result = %d", iface_name, result);
return result;
}
return WIFI_SUCCESS;
}
int createDataPathSecInfoRequest(WifiRequest& request, NanDataPathSecInfoRequest *mParams)
{
int result = request.create(GOOGLE_OUI, NAN_SUBCMD_DATA_PATH_SEC_INFO);
if (result < 0) {
ALOGE("%s Failed to create request\n", __func__);
return result;
}
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
result = request.put_u32(NAN_ATTRIBUTE_PUBLISH_ID, mParams->requestor_instance_id);
if (result < 0) {
ALOGE("%s: Failed to fill instance id = %d, result = %d\n",
__func__, mParams->requestor_instance_id, result);
return result;
}
result = request.put_addr(NAN_ATTRIBUTE_MAC_ADDR, mParams->peer_disc_mac_addr);
if (result < 0) {
ALOGE("%s: Failed to fill mac addr, result = %d\n", __func__, result);
return result;
}
result = request.put_u32(NAN_ATTRIBUTE_NDP_ID, mParams->ndp_instance_id);
if (result < 0) {
ALOGE("%s: Failed to fill ndp_instance_id = %d, result = %d\n",
__func__, mParams->ndp_instance_id, result);
return result;
}
request.attr_end(data);
return WIFI_SUCCESS;
}
int createDataPathInitRequest(WifiRequest& request, NanDataPathInitiatorRequest *mParams)
{
int result = request.create(GOOGLE_OUI, NAN_SUBCMD_DATA_PATH_REQUEST);
u8 pmk_hex[NAN_PMK_INFO_LEN];
if (result < 0) {
ALOGE("%s: Failed to create request, result = %d\n", __func__, result);
return result;
}
mNdpId = mParams->requestor_instance_id;
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
result = request.put_u32(NAN_ATTRIBUTE_PUBLISH_ID, mParams->requestor_instance_id);
if (result < 0) {
ALOGE("%s: Failed to fill pub id = %d, result = %d\n",
__func__, mParams->requestor_instance_id, result);
return result;
}
result = request.put_u32(NAN_ATTRIBUTE_CHANNEL, (u32)mParams->channel);
if (result < 0) {
ALOGE("%s: Failed to fill channel = %d, result = %d\n",
__func__, mParams->channel, result);
return result;
}
result = request.put_addr(NAN_ATTRIBUTE_MAC_ADDR, mParams->peer_disc_mac_addr);
if (result < 0) {
ALOGE("%s: Failed to fill mac addr, result = %d\n", __func__, result);
return result;
}
result = request.put_string(NAN_ATTRIBUTE_IFACE, mParams->ndp_iface);
if (result < 0) {
ALOGE("%s: Failed to fill ndp_iface, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_SECURITY,
(NanDataPathSecurityCfgStatus)mParams->ndp_cfg.security_cfg);
if (result < 0) {
ALOGE("%s: Failed to fill security, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_QOS,
(NanDataPathQosCfg) mParams->ndp_cfg.qos_cfg);
if (result < 0) {
ALOGE("%s: Failed to fill QoS, result = %d\n", __func__, result);
return result;
}
if (mParams->app_info.ndp_app_info_len) {
result = request.put_u16(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
mParams->app_info.ndp_app_info_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc info len = %d, result = %d\n",
__func__, mParams->app_info.ndp_app_info_len, result);
return result;
}
result = request.put(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
(void *)mParams->app_info.ndp_app_info, mParams->app_info.ndp_app_info_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc info, result = %d\n", __func__, result);
return result;
}
}
result = request.put_u8(NAN_ATTRIBUTE_CIPHER_SUITE_TYPE,
mParams->cipher_type);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_CIPHER_SUITE_TYPE, result = %d\n",
__func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_KEY_TYPE,
mParams->key_info.key_type);
if (result < 0) {
ALOGE("%s: Failed to fill NAN_ATTRIBUTE_KEY_TYPE, result = %d\n",
__func__, result);
return result;
}
if (mParams->service_name_len) {
result = request.put_u16(NAN_ATTRIBUTE_SERVICE_NAME_LEN, mParams->service_name_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc name len, result = %d\n", __func__, result);
return result;
}
prhex(NULL, mParams->service_name, mParams->service_name_len);
result = request.put(NAN_ATTRIBUTE_SERVICE_NAME, (void *)mParams->service_name,
mParams->service_name_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc name, result = %d\n", __func__, result);
return result;
}
}
if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK) {
if (mParams->key_info.body.pmk_info.pmk_len) {
result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN,
mParams->key_info.body.pmk_info.pmk_len);
if (result < 0) {
ALOGE("%s: Failed to fill pmk len, result = %d\n", __func__, result);
return result;
}
result = request.put(NAN_ATTRIBUTE_KEY_DATA,
(void *)mParams->key_info.body.pmk_info.pmk,
mParams->key_info.body.pmk_info.pmk_len);
if (result < 0) {
ALOGE("%s: Failed to fill pmk, result = %d\n", __func__, result);
return result;
}
}
}
if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE) {
if (mParams->key_info.body.passphrase_info.passphrase_len < NAN_SECURITY_MIN_PASSPHRASE_LEN ||
mParams->key_info.body.passphrase_info.passphrase_len > NAN_SECURITY_MAX_PASSPHRASE_LEN) {
ALOGE("passphrase must be between %d and %d characters long\n",
NAN_SECURITY_MIN_PASSPHRASE_LEN,
NAN_SECURITY_MAX_PASSPHRASE_LEN);
return NAN_STATUS_INVALID_PARAM;
} else {
memset(pmk_hex, 0, NAN_PMK_INFO_LEN);
result = passphrase_to_pmk(mParams->peer_disc_mac_addr, mParams->cipher_type,
mParams->service_name, &mParams->key_info, pmk_hex);
if (result < 0) {
ALOGE("%s: Failed to convert passphrase to key data, result = %d\n", __func__, result);
return result;
}
result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN, NAN_PMK_INFO_LEN);
if (result < 0) {
ALOGE("%s: Failed to fill passphrase len, result = %d\n", __func__, result);
return result;
}
result = request.put(NAN_ATTRIBUTE_KEY_DATA, pmk_hex, NAN_PMK_INFO_LEN);
if (result < 0) {
ALOGE("%s: Failed to fill passphrase, result = %d\n", __func__, result);
return result;
}
prhex("PMK", pmk_hex, NAN_PMK_INFO_LEN);
}
}
if (mParams->scid_len) {
if (mParams->scid_len != NAN_SCID_INFO_LEN) {
ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len);
return NAN_STATUS_INVALID_PARAM;
}
result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN,
mParams->scid_len);
if (result < 0) {
ALOGE("%s: Failed to fill scid len, result = %d\n", __func__, result);
return result;
}
result = request.put(NAN_ATTRIBUTE_SCID,
(void *)mParams->scid, mParams->scid_len);
if (result < 0) {
ALOGE("%s: Failed to fill scid, result = %d\n", __func__, result);
return result;
}
}
request.attr_end(data);
return WIFI_SUCCESS;
}
int createDataPathIndResponse(WifiRequest& request,
NanDataPathIndicationResponse *mParams)
{
int result = request.create(GOOGLE_OUI, NAN_SUBCMD_DATA_PATH_RESPONSE);
u8 pmk_hex[NAN_PMK_INFO_LEN];
if (result < 0) {
ALOGE("%s: Failed to create request, result = %d\n", __func__, result);
return result;
}
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
result = request.put_u32(NAN_ATTRIBUTE_NDP_ID, mParams->ndp_instance_id);
if (result < 0) {
ALOGE("%s: Failed to fill ndp_instance_id = %d, result = %d\n",
__func__, mParams->ndp_instance_id, result);
return result;
}
result = request.put_string(NAN_ATTRIBUTE_IFACE, mParams->ndp_iface);
if (result < 0) {
ALOGE("%s: Failed to fill ndp_iface, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_SECURITY,
(NanDataPathSecurityCfgStatus)mParams->ndp_cfg.security_cfg);
if (result < 0) {
ALOGE("%s: Failed to fill security_cfg, result = %d\n", __func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_QOS,
(NanDataPathQosCfg)mParams->ndp_cfg.qos_cfg);
if (result < 0) {
ALOGE("%s: Failed to fill qos_cfg, result = %d\n", __func__, result);
return result;
}
if (mParams->app_info.ndp_app_info_len) {
result = request.put_u16(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
mParams->app_info.ndp_app_info_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc info len = %d, result = %d\n",
__func__, mParams->app_info.ndp_app_info_len, result);
return result;
}
result = request.put(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
(void *)mParams->app_info.ndp_app_info, mParams->app_info.ndp_app_info_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc info, result = %d\n", __func__, result);
return result;
}
}
result = request.put_u8(NAN_ATTRIBUTE_RSP_CODE, mParams->rsp_code);
if (result < 0) {
ALOGE("%s: Failed to fill resp code = %d, result = %d\n",
__func__, mParams->rsp_code, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_CIPHER_SUITE_TYPE,
mParams->cipher_type);
if (result < 0) {
ALOGE("%s: Failed to fill cipher_type, result = %d\n",
__func__, result);
return result;
}
result = request.put_u8(NAN_ATTRIBUTE_KEY_TYPE,
mParams->key_info.key_type);
if (result < 0) {
ALOGE("%s: Failed to fill key type, result = %d\n",
__func__, result);
return result;
}
if (mParams->service_name_len) {
result = request.put_u16(NAN_ATTRIBUTE_SERVICE_NAME_LEN, mParams->service_name_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc name len, result = %d\n", __func__, result);
return result;
}
prhex(NULL, mParams->service_name, mParams->service_name_len);
result = request.put(NAN_ATTRIBUTE_SERVICE_NAME, (void *)mParams->service_name,
mParams->service_name_len);
if (result < 0) {
ALOGE("%s: Failed to fill svc name, result = %d\n", __func__, result);
return result;
}
}
if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK) {
if (mParams->key_info.body.pmk_info.pmk_len) {
result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN,
mParams->key_info.body.pmk_info.pmk_len);
if (result < 0) {
ALOGE("%s: Failed to fill pmk len, result = %d\n", __func__, result);
return result;
}
result = request.put(NAN_ATTRIBUTE_KEY_DATA,
(void *)mParams->key_info.body.pmk_info.pmk,
mParams->key_info.body.pmk_info.pmk_len);
if (result < 0) {
ALOGE("%s: Failed to fill pmk, result = %d\n", __func__, result);
return result;
}
}
}
if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE) {
if (mParams->key_info.body.passphrase_info.passphrase_len < NAN_SECURITY_MIN_PASSPHRASE_LEN ||
mParams->key_info.body.passphrase_info.passphrase_len > NAN_SECURITY_MAX_PASSPHRASE_LEN) {
ALOGE("passphrase must be between %d and %d characters long\n",
NAN_SECURITY_MIN_PASSPHRASE_LEN,
NAN_SECURITY_MAX_PASSPHRASE_LEN);
return NAN_STATUS_INVALID_PARAM;
} else {
memset(pmk_hex, 0, NAN_PMK_INFO_LEN);
result = passphrase_to_pmk(mPubNmi, mParams->cipher_type,
mParams->service_name, &mParams->key_info, pmk_hex);
if (result < 0) {
ALOGE("%s: Failed to convert passphrase to key data, result = %d\n", __func__, result);
return result;
}
result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN, NAN_PMK_INFO_LEN);
if (result < 0) {
ALOGE("%s: Failed to fill passphrase len, result = %d\n", __func__, result);
return result;
}
result = request.put(NAN_ATTRIBUTE_KEY_DATA, pmk_hex, NAN_PMK_INFO_LEN);
if (result < 0) {
ALOGE("%s: Failed to fill passphrase, result = %d\n", __func__, result);
return result;
}
}
}
if (mParams->scid_len) {
if (mParams->scid_len != NAN_SCID_INFO_LEN) {
ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len);
return NAN_STATUS_INVALID_PARAM;
}
result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN,
mParams->scid_len);
if (result < 0) {
ALOGE("%s: Failed to fill scid len, result = %d\n", __func__, result);
return result;
}
prhex(NULL, mParams->scid, mParams->scid_len);
result = request.put(NAN_ATTRIBUTE_SCID,
(void *)mParams->scid, mParams->scid_len);
if (result < 0) {
ALOGE("%s: Failed to fill scid, result = %d\n", __func__, result);
return result;
}
}
request.attr_end(data);
return WIFI_SUCCESS;
}
int createDataPathEndRequest(WifiRequest& request, NanDataPathEndRequest *mParams)
{
int result = request.create(GOOGLE_OUI, NAN_SUBCMD_DATA_PATH_END);
if (result < 0) {
ALOGE("%s: Failed to create request, result = %d\n", __func__, result);
return result;
}
count = mParams->num_ndp_instances;
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
result = request.put_u8(NAN_ATTRIBUTE_INST_COUNT, mParams->num_ndp_instances);
if (result < 0) {
ALOGE("%s: Failed to fill num_ndp_instances = %d, result = %d\n",
__func__, mParams->num_ndp_instances, result);
return result;
}
while (count) {
result = request.put_u32(NAN_ATTRIBUTE_NDP_ID, mParams->ndp_instance_id[count-1]);
if (result < 0) {
ALOGE("%s: Failed to fill ndp id = %d, result = %d\n",
__func__, mParams->ndp_instance_id[count-1], result);
return result;
}
ALOGE("%s:NDP ID = %d\n", __func__, mParams->ndp_instance_id[count-1]);
count -= 1;
}
request.attr_end(data);
return WIFI_SUCCESS;
}
int open()
{
WifiRequest request(familyId(), ifaceId());
int result = createRequest(request);
if (result != WIFI_SUCCESS) {
ALOGE("%s: failed to create setup request; result = %d", __func__, result);
return result;
}
result = requestResponse(request);
if (result != WIFI_SUCCESS) {
ALOGE("%s: failed to configure setup; result = %d", __func__, result);
return result;
}
ALOGI("NanDataPathPrmitive::request Response\n");
if (mType == NAN_DATA_PATH_IFACE_DELETE) {
NanResponseMsg rsp_data;
memset(&rsp_data, 0, sizeof(NanResponseMsg));
/* Prepare the NanResponseMsg payload */
rsp_data.response_type = get_response_type_frm_req_type((NanRequestType)mType);
/* Return success even for no dev case also, nothing to do */
rsp_data.status = NAN_STATUS_SUCCESS;
memcpy(rsp_data.nan_error, NanStatusToString(rsp_data.status),
strlen(NanStatusToString(rsp_data.status)));
rsp_data.nan_error[strlen(NanStatusToString(rsp_data.status))] = '\0';
rsp_data.nan_error[NAN_ERROR_STR_LEN - 1] = '\0';
ALOGI("Mapped hal status = %d\n", rsp_data.status);
ALOGI("Received nan_error string %s\n", (u8*)rsp_data.nan_error);
GET_NAN_HANDLE(info)->mHandlers.NotifyResponse(id(), &rsp_data);
ALOGE("Notified by cmd ret!!");
}
request.destroy();
return WIFI_SUCCESS;
}
virtual bool valid_dp_response_type(int response_type) {
bool valid = false;
switch(response_type) {
case NAN_DP_INTERFACE_CREATE:
case NAN_DP_INTERFACE_DELETE:
case NAN_DP_INITIATOR_RESPONSE:
case NAN_DP_RESPONDER_RESPONSE:
case NAN_DP_END:
valid = true;
break;
default:
ALOGE("NanDataPathPrmitive::Unknown cmd Response: %d\n", response_type);
break;
}
return valid;
}
int handleResponse(WifiEvent& reply)
{
nan_hal_resp_t *rsp_vndr_data = NULL;
NanResponseMsg rsp_data;
int32_t result = BCME_OK;
ALOGI("NanDataPathPrmitive::handle Response\n");
memset(&rsp_data, 0, sizeof(NanResponseMsg));
if (mType == NAN_DATA_PATH_IFACE_CREATE) {
/* NDI creation and deletion are done through vendor ops,
* driver does not send the cmd response payload,
* but for framework,
* mimicking the NanResponseMsg for iface create and delete nan cmds
*/
rsp_data.response_type = get_response_type_frm_req_type((NanRequestType)mType);
/* Return success even for no dev case also, nothing to do */
if (result == WIFI_SUCCESS || result == WIFI_ERROR_NOT_AVAILABLE) {
rsp_data.status = NAN_STATUS_SUCCESS;
} else {
rsp_data.status = NAN_STATUS_INTERNAL_FAILURE;
}
} else if (reply.get_cmd() != NL80211_CMD_VENDOR || reply.get_vendor_data() == NULL) {
ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
return NL_SKIP;
} else {
rsp_vndr_data = (nan_hal_resp_t *)reply.get_vendor_data();
result = rsp_vndr_data->value;
rsp_data.response_type = get_response_type((WIFI_SUB_COMMAND)rsp_vndr_data->subcmd);
if ((WIFI_SUB_COMMAND)rsp_vndr_data->subcmd == NAN_SUBCMD_DATA_PATH_SEC_INFO) {
/* Follow through */
} else if (!valid_dp_response_type(rsp_data.response_type)) {
return NL_SKIP;
}
rsp_data.status = nan_map_response_status(rsp_vndr_data->status);
if (rsp_data.response_type == NAN_DP_INITIATOR_RESPONSE) {
ALOGI("received ndp instance_id %d and ret = %d\n",
rsp_vndr_data->ndp_instance_id, result);
rsp_data.body.data_request_response.ndp_instance_id =
rsp_vndr_data->ndp_instance_id;
mNdpId = rsp_vndr_data->ndp_instance_id;
} else if ((WIFI_SUB_COMMAND)rsp_vndr_data->subcmd == NAN_SUBCMD_DATA_PATH_SEC_INFO) {
memcpy(mPubNmi, rsp_vndr_data->pub_nmi, NAN_MAC_ADDR_LEN);
memcpy(mSvcHash, rsp_vndr_data->svc_hash, NAN_SVC_HASH_SIZE);
return NL_SKIP;
}
}
memcpy(rsp_data.nan_error, NanStatusToString(rsp_data.status),
strlen(NanStatusToString(rsp_data.status)));
rsp_data.nan_error[strlen(NanStatusToString(rsp_data.status))] = '\0';
rsp_data.nan_error[NAN_ERROR_STR_LEN - 1] = '\0';
ALOGI("Mapped hal status = %d\n", rsp_data.status);
ALOGI("Received nan_error string %s\n", (u8*)rsp_data.nan_error);
ALOGI("NanDataPathPrmitive:Received response for cmd [%s], ret %d\n",
NanRspToString(rsp_data.response_type), rsp_data.status);
GET_NAN_HANDLE(info)->mHandlers.NotifyResponse(id(), &rsp_data);
ALOGE("Notified by cmd reply!!");
return NL_SKIP;
}
int handleEvent(WifiEvent& event)
{
int cmd = event.get_vendor_subcmd();
u16 attr_type;
nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
switch(cmd) {
case NAN_EVENT_DATA_REQUEST: {
NanDataPathRequestInd ndp_request_event;
memset(&ndp_request_event, 0, sizeof(NanDataPathRequestInd));
u16 ndp_ind_app_info_len = 0;
counters.dp_req_evt++;
ALOGI("Received NAN_EVENT_DATA_REQUEST_INDICATION\n");
for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
attr_type = it.get_type();
if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
ALOGI("publish_id: %u\n", it.get_u32());
ndp_request_event.service_instance_id = it.get_u32();
} else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
memcpy(ndp_request_event.peer_disc_mac_addr,
it.get_data(), NAN_MAC_ADDR_LEN);
ALOGI("Discovery MAC addr of the peer/initiator: " MACSTR "\n",
MAC2STR(ndp_request_event.peer_disc_mac_addr));
} else if (attr_type == NAN_ATTRIBUTE_NDP_ID) {
ALOGI("ndp id: %u\n", it.get_u32());
ndp_request_event.ndp_instance_id = it.get_u32();
} else if (attr_type == NAN_ATTRIBUTE_SECURITY) {
ALOGI("security: %u\n",
(NanDataPathSecurityCfgStatus)it.get_u8());
ndp_request_event.ndp_cfg.security_cfg =
(NanDataPathSecurityCfgStatus)it.get_u8();
} else if (attr_type == NAN_ATTRIBUTE_QOS) {
ALOGI("QoS: %u\n", (NanDataPathQosCfg)it.get_u8());
ndp_request_event.ndp_cfg.qos_cfg = (NanDataPathQosCfg)it.get_u8();
} else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
ndp_request_event.app_info.ndp_app_info_len = it.get_u16();
ndp_ind_app_info_len = ndp_request_event.app_info.ndp_app_info_len;
} else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO) {
memcpy(ndp_request_event.app_info.ndp_app_info, it.get_data(),
ndp_ind_app_info_len);
ndp_request_event.app_info.ndp_app_info
[ndp_ind_app_info_len] = '\0';
ALOGI("service info: %s\n", ndp_request_event.app_info.ndp_app_info);
} else if (attr_type == NAN_ATTRIBUTE_SCID_LEN) {
ALOGI("scid len: %u\n", it.get_u32());
ndp_request_event.scid_len = it.get_u32();
} else if (attr_type == NAN_ATTRIBUTE_SCID) {
memcpy(ndp_request_event.scid, it.get_data(),
ndp_request_event.scid_len);
ndp_request_event.scid[ndp_request_event.scid_len] = '\0';
ALOGI("scid : %s\n", ndp_request_event.scid);
}
}
GET_NAN_HANDLE(info)->mHandlers.EventDataRequest(&ndp_request_event);
break;
}
case NAN_EVENT_DATA_CONFIRMATION: {
NanDataPathConfirmInd ndp_create_confirmation_event;
memset(&ndp_create_confirmation_event, 0, sizeof(NanDataPathConfirmInd));
u16 ndp_conf_app_info_len = 0;
u8 chan_idx = 0;
counters.dp_confirm_evt++;
ALOGI("Received NAN_EVENT_DATA_CONFIRMATION\n");
for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
attr_type = it.get_type();
if (attr_type == NAN_ATTRIBUTE_NDP_ID) {
ALOGI("ndp id: %u", it.get_u32());
ndp_create_confirmation_event.ndp_instance_id = it.get_u32();
} else if (attr_type == NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR) {
memcpy(ndp_create_confirmation_event.peer_ndi_mac_addr, it.get_data(),
NAN_MAC_ADDR_LEN);
ALOGI("NDI mac address of the peer: " MACSTR "\n",
MAC2STR(ndp_create_confirmation_event.peer_ndi_mac_addr));
} else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
ALOGI("service info len: %d", it.get_u16());
ndp_create_confirmation_event.app_info.ndp_app_info_len = it.get_u16();
ndp_conf_app_info_len = ndp_create_confirmation_event.app_info.ndp_app_info_len;
} else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO) {
memcpy(ndp_create_confirmation_event.app_info.ndp_app_info,
it.get_data(), ndp_conf_app_info_len);
ndp_create_confirmation_event.app_info.ndp_app_info[ndp_conf_app_info_len]
= '\0';
ALOGI("service info: %s",
ndp_create_confirmation_event.app_info.ndp_app_info);
} else if (attr_type == NAN_ATTRIBUTE_RSP_CODE) {
ALOGI("response code: %u", (NanDataPathResponseCode)it.get_u8());
ndp_create_confirmation_event.rsp_code =
(NanDataPathResponseCode)it.get_u8();
} else if (attr_type == NAN_ATTRIBUTE_STATUS) {
ALOGI("reason code %u", (NanDataPathResponseCode)it.get_u8());
ndp_create_confirmation_event.rsp_code =
(NanDataPathResponseCode)it.get_u8();
} else if (attr_type == NAN_ATTRIBUTE_NUM_CHANNELS) {
ALOGI("num channels %u", it.get_u32());
if (it.get_u32() <= NAN_MAX_CHANNEL_INFO_SUPPORTED) {
ndp_create_confirmation_event.num_channels = it.get_u32();
} else {
ndp_create_confirmation_event.num_channels =
NAN_MAX_CHANNEL_INFO_SUPPORTED;
ALOGE("num channels reset to max allowed %u",
ndp_create_confirmation_event.num_channels);
}
} else if (attr_type == NAN_ATTRIBUTE_CHANNEL_INFO) {
ALOGI("Channel info \n");
memcpy((u8 *)ndp_create_confirmation_event.channel_info, it.get_data(),
ndp_create_confirmation_event.num_channels * sizeof(NanChannelInfo));
while (chan_idx < ndp_create_confirmation_event.num_channels) {
ALOGI("channel: %u, Bandwidth: %u, nss: %u\n",
ndp_create_confirmation_event.channel_info[chan_idx].channel,
ndp_create_confirmation_event.channel_info[chan_idx].bandwidth,
ndp_create_confirmation_event.channel_info[chan_idx].nss);
chan_idx++;
}
}
}
GET_NAN_HANDLE(info)->mHandlers.EventDataConfirm(&ndp_create_confirmation_event);
break;
}
case NAN_EVENT_DATA_END: {
NanDataPathEndInd ndp_end_event;
memset(&ndp_end_event, 0, sizeof(NanDataPathEndInd));
u16 attr_type;
ALOGI("Received NAN_EVENT_DATA_END\n");
for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
attr_type = it.get_type();
if (attr_type == NAN_ATTRIBUTE_INST_COUNT) {
ALOGI("ndp count: %u\n", it.get_u8());
ndp_end_event.num_ndp_instances = it.get_u8();
count = it.get_u8();
} else if (attr_type == NAN_ATTRIBUTE_NDP_ID) {
while (count) {
ndp_end_event.ndp_instance_id[count-1] = it.get_u32();
ALOGI("NDP Id from the Event = %u\n", ndp_end_event.ndp_instance_id[count-1]);
count -= 1;
}
} else {
ALOGI("Unknown attr_type: %s\n", NanAttrToString(attr_type));
}
}
GET_NAN_HANDLE(info)->mHandlers.EventDataEnd(&ndp_end_event);
break;
}
} // end-of-switch
return NL_SKIP;
}
};
///////////////////////////////////////////////////////////////////////////////
class NanMacControl : public WifiCommand
{
NanRequest mParams;
transaction_id mId = NAN_MAC_INVALID_TRANSID;
wifi_interface_handle mIface;
NanRequestType mType;
u32 mVersion;
u8 mChreNan;
public:
NanMacControl(wifi_interface_handle iface, int id,
NanRequest params, NanRequestType cmdType)
: WifiCommand("NanCommand", iface, id), mParams(params), mType(cmdType)
{
mVersion = 0;
setIface(iface);
setId(id);
}
~NanMacControl() {
ALOGE("NanMacControl destroyed\n");
}
void setIface(wifi_interface_handle iface ) {
mIface = iface;
}
void setId(transaction_id id) {
if (id != NAN_MAC_INVALID_TRANSID) {
mId = id;
}
}
transaction_id getId() {
return mId;
}
void setType(NanRequestType type) {
mType = type;
}
u32 getVersion() {
return mVersion;
}
void setMsg(NanRequest params) {
mParams = params;
}
void setChreNan(u8 chre_nan) {
mChreNan = chre_nan;
}
int createRequest(WifiRequest& request) {
ALOGI("NAN CMD: %s\n", NanCmdToString(mType));
if (mType == NAN_REQUEST_ENABLE) {
return createEnableRequest(request, (NanEnableRequest *)mParams);
} else if (mType == NAN_REQUEST_DISABLE) {
return createDisableRequest(request);
} else if (mType == NAN_REQUEST_CONFIG) {
return createConfigRequest(request, (NanConfigRequest*)mParams);
} else if (mType == NAN_REQUEST_STATS) {
/* TODO: Not yet implemented */
} else if (mType == NAN_REQUEST_TCA) {
/* TODO: Not yet implemented */
} else if (mType == NAN_VERSION_INFO) {
return createVersionRequest(request);
} else {
ALOGE("Unknown Nan request\n");
}
return WIFI_SUCCESS;
}
int createVersionRequest(WifiRequest& request) {
int result = request.create(GOOGLE_OUI, NAN_SUBCMD_VERSION_INFO);
if (result < 0) {
ALOGE("%s: Fail to create request\n", __func__);
return result;
}
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
request.attr_end(data);
NAN_DBG_EXIT();
return WIFI_SUCCESS;
}
int createEnableRequest(WifiRequest& request, NanEnableRequest *mParams) {
int result = request.create(GOOGLE_OUI, NAN_SUBCMD_ENABLE);
s8 rssi;
if (result < 0) {
ALOGE("%s: Fail to create request\n", __func__);
return result;
}
NAN_DBG_ENTER();
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
if (mParams->config_2dot4g_support) {
result = request.put_u8(NAN_ATTRIBUTE_2G_SUPPORT, mParams->support_2dot4g_val);
if (result < 0) {
ALOGE("%s: Failing in 2g support, result = %d\n", __func__, result);
return result;
}
}
if (mParams->config_support_5g) {
result = request.put_u8(NAN_ATTRIBUTE_5G_SUPPORT, mParams->support_5g_val);
if (result < 0) {
ALOGE("%s: Failing in 5g support, result = %d\n", __func__, result);
return result;
}
}
result = request.put_u16(NAN_ATTRIBUTE_CLUSTER_LOW, mParams->cluster_low);
if (result < 0) {
ALOGE("%s: Failing in cluster low, result = %d\n", __func__, result);
return result;
}
result = request.put_u16(NAN_ATTRIBUTE_CLUSTER_HIGH, mParams->cluster_high);
if (result < 0) {
ALOGE("%s: Failing in cluster high, result = %d\n", __func__, result);
return result;
}
if (mParams->config_sid_beacon) {
result = request.put_u8(NAN_ATTRIBUTE_SID_BEACON, mParams->sid_beacon_val);
if (result < 0) {
ALOGE("%s: Failing in sid beacon, result = %d\n", __func__, result);
return result;
}
}
if (mParams->config_subscribe_sid_beacon) {
result = request.put_u8(NAN_ATTRIBUTE_SUB_SID_BEACON, mParams->subscribe_sid_beacon_val);
if (result < 0) {
ALOGE("%s: Failing in sub sid beacon, result = %d\n", __func__, result);
return result;
}
}
if (mParams->config_2dot4g_beacons) {
result = request.put_u8(NAN_ATTRIBUTE_SYNC_DISC_2G_BEACON, mParams->beacon_2dot4g_val);
if (result < 0) {
ALOGE("%s: Failing in beacon_2dot4g_val, result = %d\n", __func__, result);
return result;
}
}
if (mParams->config_5g_beacons) {
result = request.put_u8(NAN_ATTRIBUTE_SYNC_DISC_5G_BEACON, mParams->beacon_5g_val);
if (result < 0) {
ALOGE("%s: Failing in 5g beacon, result = %d\n", __func__, result);
return result;
}
}
if (mParams->config_2dot4g_sdf) {
result = request.put_u8(NAN_ATTRIBUTE_SDF_2G_SUPPORT, mParams->sdf_2dot4g_val);
if (result < 0) {
ALOGE("%s: Failing in 2dot4g sdf, result = %d\n", __func__, result);
return result;
}
}
if (mParams->config_5g_sdf) {
result = request.put_u8(NAN_ATTRIBUTE_SDF_5G_SUPPORT, mParams->sdf_5g_val);
if (result < 0) {
ALOGE("%s: Failing in 5g sdf, result = %d\n", __func__, result);
return result;
}
}
if (mParams->config_2dot4g_rssi_close) {
if (ISGREATER(mParams->rssi_close_2dot4g_val, NAN_MAX_RSSI)) {
ALOGI("%s: Invalid rssi param \n", __func__);
return WIFI_ERROR_INVALID_ARGS;
}
rssi = -mParams->rssi_close_2dot4g_val;