| /* |
| * 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; |
|