diff --git a/components/nan/core/inc/nan_public_structs.h b/components/nan/core/inc/nan_public_structs.h new file mode 100644 index 000000000000..2a32ffd49dd1 --- /dev/null +++ b/components/nan/core/inc/nan_public_structs.h @@ -0,0 +1,639 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains nan definitions exposed to other modules + */ + +#ifdef WLAN_FEATURE_NAN_CONVERGENCE +#ifndef _NAN_PUBLIC_STRUCTS_H_ +#define _NAN_PUBLIC_STRUCTS_H_ + +#include "qdf_types.h" +#include "qdf_status.h" + +struct wlan_objmgr_psoc; +struct wlan_objmgr_vdev; + +#define IFACE_NAME_SIZE 64 +#define NDP_QOS_INFO_LEN 255 +#define NDP_APP_INFO_LEN 255 +#define NDP_PMK_LEN 32 +#define NDP_SCID_BUF_LEN 256 +#define NDP_NUM_INSTANCE_ID 255 +#define NAN_MAX_SERVICE_NAME_LEN 255 +#define NAN_PASSPHRASE_MIN_LEN 8 +#define NAN_PASSPHRASE_MAX_LEN 63 +#define NAN_CH_INFO_MAX_CHANNELS 4 + +/** + * enum nan_datapath_msg_type - NDP msg type + * @NAN_DATAPATH_INF_CREATE_REQ: ndi create request + * @NAN_DATAPATH_INF_CREATE_RSP: ndi create response + * @NAN_DATAPATH_INF_DELETE_REQ: ndi delete request + * @NAN_DATAPATH_INF_DELETE_RSP: ndi delete response + * @NDP_INITIATOR_REQ: ndp initiator request + * @NDP_INITIATOR_RSP: ndp initiator response + * @NDP_RESPONDER_REQ: ndp responder request + * @NDP_RESPONDER_RSP: ndp responder response + * @NDP_END_REQ: ndp end request + * @NDP_END_RSP: ndp end response + * @NDP_INDICATION: ndp indication + * @NDP_CONFIRM: ndp confirm + * @NDP_END_IND: ndp end indication + * @NDP_NEW_PEER: ndp new peer created + * @NDP_PEER_DEPARTED: ndp peer departed/deleted + * @NDP_SCHEDULE_UPDATE: ndp schedule update + */ +enum nan_datapath_msg_type { + NAN_DATAPATH_INF_CREATE_REQ = 0, + NAN_DATAPATH_INF_CREATE_RSP = 1, + NAN_DATAPATH_INF_DELETE_REQ = 2, + NAN_DATAPATH_INF_DELETE_RSP = 3, + NDP_INITIATOR_REQ = 4, + NDP_INITIATOR_RSP = 5, + NDP_RESPONDER_REQ = 6, + NDP_RESPONDER_RSP = 7, + NDP_END_REQ = 8, + NDP_END_RSP = 9, + NDP_INDICATION = 10, + NDP_CONFIRM = 11, + NDP_END_IND = 12, + NDP_NEW_PEER = 13, + NDP_PEER_DEPARTED = 14, + NDP_SCHEDULE_UPDATE = 15, +}; + +/** + * enum nan_datapath_status_type - NDP status type + * @NAN_DATAPATH_RSP_STATUS_SUCCESS: request was successful + * @NAN_DATAPATH_RSP_STATUS_ERROR: request failed + */ +enum nan_datapath_status_type { + NAN_DATAPATH_RSP_STATUS_SUCCESS = 0x00, + NAN_DATAPATH_RSP_STATUS_ERROR = 0x01, +}; + +/** + * enum nan_datapath_reason_code - NDP command rsp reason code value + * @NDP_UNSUPPORTED_CONCURRENCY: Will be used in unsupported concurrency cases + * @NDP_NAN_DATA_IFACE_CREATE_FAILED: ndi create failed + * @NDP_NAN_DATA_IFACE_DELETE_FAILED: ndi delete failed + * @NDP_DATA_INITIATOR_REQ_FAILED: data initiator request failed + * @NDP_DATA_RESPONDER_REQ_FAILED: data responder request failed + * @NDP_INVALID_SERVICE_INSTANCE_ID: invalid service instance id + * @NDP_INVALID_NDP_INSTANCE_ID: invalid ndp instance id + * @NDP_INVALID_RSP_CODE: invalid response code in ndp responder request + * @NDP_INVALID_APP_INFO_LEN: invalid app info length + * @NDP_NMF_REQ_FAIL: OTA nan mgmt frame failure for data request + * @NDP_NMF_RSP_FAIL: OTA nan mgmt frame failure for data response + * @NDP_NMF_CNF_FAIL: OTA nan mgmt frame failure for confirm + * @NDP_END_FAILED: ndp end failed + * @NDP_NMF_END_REQ_FAIL: OTA nan mgmt frame failure for data end + * @NDP_VENDOR_SPECIFIC_ERROR: other vendor specific failures + */ +enum nan_datapath_reason_code { + NAN_DATAPATH_UNSUPPORTED_CONCURRENCY = 9000, + NAN_DATAPATH_NAN_DATA_IFACE_CREATE_FAILED = 9001, + NAN_DATAPATH_NAN_DATA_IFACE_DELETE_FAILED = 9002, + NAN_DATAPATH_DATA_INITIATOR_REQ_FAILED = 9003, + NAN_DATAPATH_DATA_RESPONDER_REQ_FAILED = 9004, + NAN_DATAPATH_INVALID_SERVICE_INSTANCE_ID = 9005, + NAN_DATAPATH_INVALID_NDP_INSTANCE_ID = 9006, + NAN_DATAPATH_INVALID_RSP_CODE = 9007, + NAN_DATAPATH_INVALID_APP_INFO_LEN = 9008, + NAN_DATAPATH_NMF_REQ_FAIL = 9009, + NAN_DATAPATH_NMF_RSP_FAIL = 9010, + NAN_DATAPATH_NMF_CNF_FAIL = 9011, + NAN_DATAPATH_END_FAILED = 9012, + NAN_DATAPATH_NMF_END_REQ_FAIL = 9013, + /* 9500 onwards vendor specific error codes */ + NAN_DATAPATH_VENDOR_SPECIFIC_ERROR = 9500, +}; + +/** + * enum nan_datapath_response_code - responder's response code to nan data path + * request + * @NAN_DATAPATH_RESPONSE_ACCEPT: ndp request accepted + * @NAN_DATAPATH_RESPONSE_REJECT: ndp request rejected + * @NAN_DATAPATH_RESPONSE_DEFER: ndp request deferred until later (response to + * follow any time later) + * + */ +enum nan_datapath_response_code { + NAN_DATAPATH_RESPONSE_ACCEPT = 0, + NAN_DATAPATH_RESPONSE_REJECT = 1, + NAN_DATAPATH_RESPONSE_DEFER = 2, +}; + +/** + * enum nan_datapath_accept_policy - nan data path accept policy + * @NAN_DATAPATH_ACCEPT_POLICY_NONE: the framework will decide the policy + * @NAN_DATAPATH_ACCEPT_POLICY_ALL: accept policy offloaded to fw + * + */ +enum nan_datapath_accept_policy { + NAN_DATAPATH_ACCEPT_POLICY_NONE = 0, + NAN_DATAPATH_ACCEPT_POLICY_ALL = 1, +}; + +/** + * enum nan_datapath_self_role - nan data path role + * @NAN_DATAPATH_ROLE_INITIATOR: initiator of nan data path request + * @NAN_DATAPATH_ROLE_RESPONDER: responder to nan data path request + * + */ +enum nan_datapath_self_role { + NAN_DATAPATH_ROLE_INITIATOR = 0, + NAN_DATAPATH_ROLE_RESPONDER = 1, +}; + +/** + * enum nan_datapath_end_type - NDP end type + * @NAN_DATAPATH_END_TYPE_UNSPECIFIED: type is unspecified + * @NAN_DATAPATH_END_TYPE_PEER_UNAVAILABLE: type is peer unavailable + * @NAN_DATAPATH_END_TYPE_OTA_FRAME: NDP end frame received from peer + * + */ +enum nan_datapath_end_type { + NAN_DATAPATH_END_TYPE_UNSPECIFIED = 0x00, + NAN_DATAPATH_END_TYPE_PEER_UNAVAILABLE = 0x01, + NAN_DATAPATH_END_TYPE_OTA_FRAME = 0x02, +}; + +/** + * enum nan_datapath_end_reason_code - NDP end reason code + * @NAN_DATAPATH_END_REASON_UNSPECIFIED: reason is unspecified + * @NAN_DATAPATH_END_REASON_INACTIVITY: reason is peer inactivity + * @NAN_DATAPATH_END_REASON_PEER_DATA_END: data end indication received from + * peer + * + */ +enum nan_datapath_end_reason_code { + NAN_DATAPATH_END_REASON_UNSPECIFIED = 0x00, + NAN_DATAPATH_END_REASON_INACTIVITY = 0x01, + NAN_DATAPATH_END_REASON_PEER_DATA_END = 0x02, +}; + +/** enum nan_datapath_state - NAN datapath states + * @NAN_DATA_NDI_CREATING_STATE: NDI create is in progress + * @NAN_DATA_NDI_CREATED_STATE: NDI successfully crated + * @NAN_DATA_NDI_DELETING_STATE: NDI delete is in progress + * @NAN_DATA_NDI_DELETED_STATE: NDI delete is in progress + * @NAN_DATA_PEER_CREATE_STATE: Peer create is in progress + * @NAN_DATA_PEER_DELETE_STATE: Peer delete is in progrss + * @NAN_DATA_CONNECTING_STATE: Data connection in progress + * @NAN_DATA_CONNECTED_STATE: Data connection successful + * @NAN_DATA_END_STATE: NDP end is in progress + * @NAN_DATA_DISCONNECTED_STATE: NDP is in disconnected state + */ +enum nan_datapath_state { + NAN_DATA_INVALID_STATE = -1, + NAN_DATA_NDI_CREATING_STATE = 0, + NAN_DATA_NDI_CREATED_STATE = 1, + NAN_DATA_NDI_DELETING_STATE = 2, + NAN_DATA_NDI_DELETED_STATE = 3, + NAN_DATA_PEER_CREATE_STATE = 4, + NAN_DATA_PEER_DELETE_STATE = 5, + NAN_DATA_CONNECTING_STATE = 6, + NAN_DATA_CONNECTED_STATE = 7, + NAN_DATA_END_STATE = 8, + NAN_DATA_DISCONNECTED_STATE = 9, +}; + +/** + * struct nan_datapath_app_info - application info shared during ndp setup + * @ndp_app_info_len: ndp app info length + * @ndp_app_info: variable length application information + * + */ +struct nan_datapath_app_info { + uint32_t ndp_app_info_len; + uint8_t ndp_app_info[NDP_APP_INFO_LEN]; +}; + +/** + * struct nan_datapath_cfg - ndp configuration + * @ndp_cfg_len: ndp configuration length + * @ndp_cfg: variable length ndp configuration + * + */ +struct nan_datapath_cfg { + uint32_t ndp_cfg_len; + uint8_t ndp_cfg[NDP_QOS_INFO_LEN]; +}; + +/** + * struct nan_datapath_pmk - structure to hold pairwise master key + * @pmk_len: length of pairwise master key + * @pmk: buffer containing pairwise master key + * + */ +struct nan_datapath_pmk { + uint32_t pmk_len; + uint8_t pmk[NDP_PMK_LEN]; +}; + +/** + * struct nan_datapath_scid - structure to hold sceurity context identifier + * @scid_len: length of scid + * @scid: scid + * + */ +struct nan_datapath_scid { + uint32_t scid_len; + uint8_t scid[NDP_SCID_BUF_LEN]; +}; + +/** + * struct ndp_passphrase - structure to hold passphrase + * @passphrase_len: length of passphrase + * @passphrase: buffer containing passphrase + * + */ +struct ndp_passphrase { + uint32_t passphrase_len; + uint8_t passphrase[NAN_PASSPHRASE_MAX_LEN]; +}; + +/** + * struct ndp_service_name - structure to hold service_name + * @service_name_len: length of service_name + * @service_name: buffer containing service_name + * + */ +struct ndp_service_name { + uint32_t service_name_len; + uint8_t service_name[NAN_MAX_SERVICE_NAME_LEN]; +}; + +/** + * struct peer_nan_datapath_map - mapping of NDP instances to peer to VDEV + * @vdev_id: session id of the interface over which ndp is being created + * @peer_ndi_mac_addr: peer NDI mac address + * @num_active_ndp_sessions: number of active NDP sessions on the peer + * @type: NDP end indication type + * @reason_code: NDP end indication reason code + * @ndp_instance_id: NDP instance ID + * + */ +struct peer_nan_datapath_map { + uint32_t vdev_id; + struct qdf_mac_addr peer_ndi_mac_addr; + uint32_t num_active_ndp_sessions; + enum nan_datapath_end_type type; + enum nan_datapath_end_reason_code reason_code; + uint32_t ndp_instance_id; +}; + +/** + * struct nan_datapath_channel_info - ndp channel and channel bandwidth + * @channel: channel freq in mhz of the ndp connection + * @ch_width: channel width (wmi_channel_width) of the ndp connection + * @nss: nss used for ndp connection + * + */ +struct nan_datapath_channel_info { + uint32_t channel; + uint32_t ch_width; + uint32_t nss; +}; + +#define NAN_CH_INFO_MAX_LEN \ + (NAN_CH_INFO_MAX_CHANNELS * sizeof(struct nan_datapath_channel_info)) + +/** + * struct nan_datapath_inf_create_req - ndi create request params + * @transaction_id: unique identifier + * @iface_name: interface name + * + */ +struct nan_datapath_inf_create_req { + uint32_t transaction_id; + char iface_name[IFACE_NAME_SIZE]; +}; + +/* + * struct nan_datapath_inf_create_rsp - ndi create response params + * @status: request status + * @reason: reason if any + * + */ +struct nan_datapath_inf_create_rsp { + uint32_t status; + uint32_t reason; + uint8_t sta_id; +}; + +/** + * struct nan_datapath_inf_delete_rsp - ndi delete response params + * @status: request status + * @reason: reason if any + * + */ +struct nan_datapath_inf_delete_rsp { + uint32_t status; + uint32_t reason; +}; + +/** + * struct nan_datapath_initiator_req - ndp initiator request params + * @vdev: pointer to vdev object + * @transaction_id: unique identifier + * @channel: suggested channel for ndp creation + * @channel_cfg: channel config, 0=no channel, 1=optional, 2=mandatory + * @service_instance_id: Service identifier + * @peer_discovery_mac_addr: Peer's discovery mac address + * @self_ndi_mac_addr: self NDI mac address + * @ndp_config: ndp configuration params + * @ndp_info: ndp application info + * @ncs_sk_type: indicates NCS_SK_128 or NCS_SK_256 + * @pmk: pairwise master key + * @passphrase: passphrase + * @service_name: service name + * @is_ipv6_addr_present: indicates if following ipv6 address is valid + * @ipv6_addr: ipv6 address address used by ndp + */ +struct nan_datapath_initiator_req { + struct wlan_objmgr_vdev *vdev; + uint32_t transaction_id; + uint32_t channel; + uint32_t channel_cfg; + uint32_t service_instance_id; + uint32_t ncs_sk_type; + struct qdf_mac_addr peer_discovery_mac_addr; + struct qdf_mac_addr self_ndi_mac_addr; + struct nan_datapath_cfg ndp_config; + struct nan_datapath_app_info ndp_info; + struct nan_datapath_pmk pmk; + struct ndp_passphrase passphrase; + struct ndp_service_name service_name; + bool is_ipv6_addr_present; + uint8_t ipv6_addr[QDF_IPV6_ADDR_SIZE]; +}; + +/** + * struct nan_datapath_initiator_rsp - response event from FW + * @vdev: pointer to vdev object + * @transaction_id: unique identifier + * @ndp_instance_id: locally created NDP instance ID + * @status: status of the ndp request + * @reason: reason for failure if any + * + */ +struct nan_datapath_initiator_rsp { + struct wlan_objmgr_vdev *vdev; + uint32_t transaction_id; + uint32_t ndp_instance_id; + uint32_t status; + uint32_t reason; +}; + +/** + * struct nan_datapath_responder_req - responder's response to ndp create + * request + * @vdev: pointer to vdev object + * @transaction_id: unique identifier + * @ndp_instance_id: locally created NDP instance ID + * @ndp_rsp: response to the ndp create request + * @ndp_config: ndp configuration params + * @ndp_info: ndp application info + * @pmk: pairwise master key + * @ncs_sk_type: indicates NCS_SK_128 or NCS_SK_256 + * @passphrase: passphrase + * @service_name: service name + * @is_ipv6_addr_present: indicates if following ipv6 address is valid + * @ipv6_addr: ipv6 address address used by ndp + * @is_port_present: indicates if following port is valid + * @port: port specified by for this NDP + * @is_protocol_present: indicates if following protocol is valid + * @protocol: protocol used by this NDP + * + */ +struct nan_datapath_responder_req { + struct wlan_objmgr_vdev *vdev; + uint32_t transaction_id; + uint32_t ndp_instance_id; + enum nan_datapath_response_code ndp_rsp; + struct nan_datapath_cfg ndp_config; + struct nan_datapath_app_info ndp_info; + struct nan_datapath_pmk pmk; + uint32_t ncs_sk_type; + struct ndp_passphrase passphrase; + struct ndp_service_name service_name; + bool is_ipv6_addr_present; + uint8_t ipv6_addr[QDF_IPV6_ADDR_SIZE]; + bool is_port_present; + uint16_t port; + bool is_protocol_present; + uint8_t protocol; +}; + +/** + * struct nan_datapath_responder_rsp - response to responder's request + * @vdev: pointer to vdev object + * @transaction_id: unique identifier + * @status: command status + * @reason: reason for failure if any + * @peer_mac_addr: Peer's mac address + * @create_peer: Flag to indicate to create peer + */ +struct nan_datapath_responder_rsp { + struct wlan_objmgr_vdev *vdev; + uint32_t transaction_id; + uint32_t status; + uint32_t reason; + struct qdf_mac_addr peer_mac_addr; + bool create_peer; +}; + +/** + * struct nan_datapath_end_req - ndp end request + * @vdev: pointer to vdev object + * @transaction_id: unique transaction identifier + * @num_ndp_instances: number of ndp instances to be terminated + * @ndp_ids: array of ndp_instance_id to be terminated + * + */ +struct nan_datapath_end_req { + struct wlan_objmgr_vdev *vdev; + uint32_t transaction_id; + uint32_t num_ndp_instances; + uint32_t ndp_ids[NDP_NUM_INSTANCE_ID]; +}; + +/** + * struct nan_datapath_end_rsp_event - firmware response to ndp end request + * @vdev: pointer to vdev object + * @transaction_id: unique identifier for the request + * @status: status of operation + * @reason: reason(opaque to host driver) + * + */ +struct nan_datapath_end_rsp_event { + struct wlan_objmgr_vdev *vdev; + uint32_t transaction_id; + uint32_t status; + uint32_t reason; +}; + +/** + * struct nan_datapath_end_indication_event - ndp termination notification from + * FW + * @vdev: pointer to vdev object + * @num_ndp_ids: number of NDP ids + * @ndp_map: mapping of NDP instances to peer and vdev + * + */ +struct nan_datapath_end_indication_event { + struct wlan_objmgr_vdev *vdev; + uint32_t num_ndp_ids; + struct peer_nan_datapath_map ndp_map[]; +}; + +/** + * struct nan_datapath_confirm_event - ndp confirmation event from FW + * @vdev: pointer to vdev object + * @ndp_instance_id: ndp instance id for which confirm is being generated + * @reason_code : reason code(opaque to driver) + * @num_active_ndps_on_peer: number of ndp instances on peer + * @peer_ndi_mac_addr: peer NDI mac address + * @rsp_code: ndp response code + * @num_channels: num channels + * @ch: channel info struct array + * @ndp_info: ndp application info + * @is_ipv6_addr_present: indicates if following ipv6 address is valid + * @ipv6_addr: ipv6 address address used by ndp + * @is_port_present: indicates if following port is valid + * @port: port specified by for this NDP + * @is_protocol_present: indicates if following protocol is valid + * @protocol: protocol used by this NDP + * + */ +struct nan_datapath_confirm_event { + struct wlan_objmgr_vdev *vdev; + uint32_t ndp_instance_id; + uint32_t reason_code; + uint32_t num_active_ndps_on_peer; + struct qdf_mac_addr peer_ndi_mac_addr; + enum nan_datapath_response_code rsp_code; + uint32_t num_channels; + struct nan_datapath_channel_info ch[NAN_CH_INFO_MAX_CHANNELS]; + struct nan_datapath_app_info ndp_info; + bool is_ipv6_addr_present; + uint8_t ipv6_addr[QDF_IPV6_ADDR_SIZE]; + bool is_port_present; + uint16_t port; + bool is_protocol_present; + uint8_t protocol; +}; + +/** + * struct nan_datapath_indication_event - create ndp indication on the responder + * @vdev: pointer to vdev object + * @service_instance_id: Service identifier + * @peer_discovery_mac_addr: Peer's discovery mac address + * @peer_mac_addr: Peer's NDI mac address + * @ndp_initiator_mac_addr: NDI mac address of the peer initiating NDP + * @ndp_instance_id: locally created NDP instance ID + * @role: self role for NDP + * @ndp_accept_policy: accept policy configured by the upper layer + * @ndp_config: ndp configuration params + * @ndp_info: ndp application info + * @ncs_sk_type: indicates NCS_SK_128 or NCS_SK_256 + * @scid: security context identifier + * @is_ipv6_addr_present: indicates if following ipv6 address is valid + * @ipv6_addr: ipv6 address address used by ndp + * + */ +struct nan_datapath_indication_event { + struct wlan_objmgr_vdev *vdev; + uint32_t service_instance_id; + struct qdf_mac_addr peer_discovery_mac_addr; + struct qdf_mac_addr peer_mac_addr; + uint32_t ndp_instance_id; + enum nan_datapath_self_role role; + enum nan_datapath_accept_policy policy; + struct nan_datapath_cfg ndp_config; + struct nan_datapath_app_info ndp_info; + uint32_t ncs_sk_type; + struct nan_datapath_scid scid; + bool is_ipv6_addr_present; + uint8_t ipv6_addr[QDF_IPV6_ADDR_SIZE]; +}; + +/** + * struct nan_datapath_peer_ind - ndp peer indication + * @peer_mac_addr: peer mac address + * @sta_id: station id + * + */ +struct nan_datapath_peer_ind { + struct qdf_mac_addr peer_mac_addr; + uint16_t sta_id; +}; + +/** + * struct nan_datapath_sch_update_event - ndp schedule update indication + * @vdev: vdev schedule update was received + * @peer_addr: peer for which schedule update was received + * @flags: reason for sch update (opaque to driver) + * @num_channels: num of channels + * @num_ndp_instances: num of ndp instances + * @ch: channel info array + * @ndp_instances: array of ndp instances + * + */ +struct nan_datapath_sch_update_event { + struct wlan_objmgr_vdev *vdev; + struct qdf_mac_addr peer_addr; + uint32_t flags; + uint32_t num_channels; + uint32_t num_ndp_instances; + struct nan_datapath_channel_info ch[NAN_CH_INFO_MAX_CHANNELS]; + uint32_t ndp_instances[NDP_NUM_INSTANCE_ID]; +}; + +/** + * struct nan_callbacks - struct containing callback to non-converged driver + * + */ +struct nan_callbacks { + /* callback to os_if layer from umac */ + void (*os_if_event_handler)(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t type, void *msg); + + int (*ndi_open)(char *iface_name); + int (*ndi_start)(char *iface_name, uint16_t); + void (*ndi_close)(uint8_t); + int (*ndi_delete)(uint8_t, char *iface_name, uint16_t transaction_id); + void (*drv_ndi_create_rsp_handler) + (uint8_t, struct nan_datapath_inf_create_rsp *); + void (*drv_ndi_delete_rsp_handler)(uint8_t); + int (*new_peer_ind)(uint8_t, uint16_t, struct qdf_mac_addr *, bool); + int (*get_peer_idx)(uint8_t, struct qdf_mac_addr *); + QDF_STATUS (*add_ndi_peer)(uint32_t, struct qdf_mac_addr); + void (*peer_departed_ind)(uint8_t, uint16_t, struct qdf_mac_addr *, + bool); + void (*ndp_delete_peers)(struct peer_nan_datapath_map*, uint8_t); + void (*delete_peers_by_addr)(uint8_t, struct qdf_mac_addr); +}; + +#endif +#endif /* WLAN_FEATURE_NAN_CONVERGENCE */ diff --git a/components/nan/core/inc/wlan_nan_api.h b/components/nan/core/inc/wlan_nan_api.h new file mode 100644 index 000000000000..e2bc40f3fcde --- /dev/null +++ b/components/nan/core/inc/wlan_nan_api.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains nan definitions exposed to other modules + */ + +#ifndef _WLAN_NAN_API_H_ +#define _WLAN_NAN_API_H_ + +#include "qdf_status.h" + +struct wlan_objmgr_psoc; + +/** + * nan_init: initializes NAN component, called by dispatcher init + * + * Return: status of operation + */ +QDF_STATUS nan_init(void); + +/** + * nan_deinit: de-initializes NAN component, called by dispatcher init + * + * Return: status of operation + */ +QDF_STATUS nan_deinit(void); + +/** + * nan_psoc_enable: psoc enable API for NANitioning component + * @psoc: pointer to PSOC + * + * Return: status of operation + */ +QDF_STATUS nan_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * nan_psoc_disable: psoc disable API for NANitioning component + * @psoc: pointer to PSOC + * + * Return: status of operation + */ +QDF_STATUS nan_psoc_disable(struct wlan_objmgr_psoc *psoc); + +#endif diff --git a/components/nan/core/src/nan_api.c b/components/nan/core/src/nan_api.c new file mode 100644 index 000000000000..4e03a12dbf86 --- /dev/null +++ b/components/nan/core/src/nan_api.c @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains nan public API function definitions + */ + +#include "nan_main_i.h" +#include "wlan_nan_api.h" +#include "target_if_nan.h" +#include "nan_public_structs.h" +#include "wlan_objmgr_cmn.h" +#include "wlan_objmgr_global_obj.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "cfg_nan.h" +#include "cfg_ucfg_api.h" + +/** + * nan_cfg_init() - Initialize NAN config params + * @psoc: Pointer to PSOC Object + * @nan_obj: Pointer to NAN private object + * + * This function initialize NAN config params + */ +#ifdef WLAN_FEATURE_NAN +static void nan_cfg_init(struct wlan_objmgr_psoc *psoc, + struct nan_psoc_priv_obj *nan_obj) +{ + if (!psoc || !nan_obj) + return; + + nan_obj->cfg_param.enable = cfg_get(psoc, CFG_NAN_ENABLE); +} +#else +static void nan_cfg_init(struct wlan_objmgr_psoc *psoc, + struct nan_psoc_priv_obj *nan_obj) +{ +} +#endif + +/** + * nan_cfg_dp_init() - Initialize NAN Datapath config params + * @psoc: Pointer to PSOC Object + * @nan_obj: Pointer to NAN private object + * + * This function initialize NAN config params + */ +#ifdef WLAN_FEATURE_NAN_DATAPATH +static void nan_cfg_dp_init(struct wlan_objmgr_psoc *psoc, + struct nan_psoc_priv_obj *nan_obj) +{ + if (!psoc || !nan_obj) + return; + nan_obj->cfg_param.dp_enable = cfg_get(psoc, + CFG_NAN_DATAPATH_ENABLE); + nan_obj->cfg_param.ndi_ch = cfg_get(psoc, CFG_NAN_NDI_CHANNEL); + nan_obj->cfg_param.ndi_mac_randomize = + cfg_get(psoc, CFG_NAN_RANDOMIZE_NDI_MAC); +} +#else +static void nan_cfg_dp_init(struct wlan_objmgr_psoc *psoc, + struct nan_psoc_priv_obj *nan_obj) +{ +} +#endif + +static QDF_STATUS nan_psoc_obj_created_notification( + struct wlan_objmgr_psoc *psoc, void *arg_list) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct nan_psoc_priv_obj *nan_obj; + + nan_debug("nan_psoc_create_notif called"); + nan_obj = qdf_mem_malloc(sizeof(*nan_obj)); + if (!nan_obj) { + nan_alert("malloc failed for nan prv obj"); + return QDF_STATUS_E_NOMEM; + } + + qdf_spinlock_create(&nan_obj->lock); + status = wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_NAN, + nan_obj, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + nan_alert("obj attach with psoc failed"); + goto nan_psoc_notif_failed; + } + + nan_cfg_init(psoc, nan_obj); + nan_cfg_dp_init(psoc, nan_obj); + + return QDF_STATUS_SUCCESS; + +nan_psoc_notif_failed: + + qdf_spinlock_destroy(&nan_obj->lock); + qdf_mem_free(nan_obj); + return status; +} + +static void nan_psoc_delete_peer(struct wlan_objmgr_psoc *psoc, + void *peer, void *arg) +{ + if (WLAN_PEER_NDP == wlan_peer_get_peer_type(peer)) + wlan_objmgr_peer_obj_delete(peer); +} + +static void nan_psoc_delete_vdev(struct wlan_objmgr_psoc *psoc, + void *vdev, void *arg) +{ + enum nan_datapath_state state; + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return; + } + /* + * user may issue rrmod wlan without explicitly NDI Delete. + * In that case pending NDI vdev state will not be DELETED/DELETEING + * Forcefully delete vdev object + */ + if (QDF_NDI_MODE != wlan_vdev_mlme_get_opmode(vdev)) + return; + + qdf_spin_lock_bh(&priv_obj->lock); + state = priv_obj->state; + qdf_spin_unlock_bh(&priv_obj->lock); + + /* if already in deleted or deleting state - do not delete */ + if (state == NAN_DATA_NDI_DELETED_STATE || + state == NAN_DATA_NDI_DELETING_STATE) + return; + + wlan_objmgr_vdev_obj_delete(vdev); +} + +static QDF_STATUS nan_psoc_obj_destroyed_notification( + struct wlan_objmgr_psoc *psoc, void *arg_list) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct nan_psoc_priv_obj *nan_obj = nan_get_psoc_priv_obj(psoc); + + nan_debug("nan_psoc_delete_notif called"); + if (!nan_obj) { + nan_err("nan_obj is NULL"); + return QDF_STATUS_E_FAULT; + } + + wlan_objmgr_iterate_obj_list(psoc, WLAN_PEER_OP, + nan_psoc_delete_peer, + NULL, 1, WLAN_NAN_ID); + + wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, + nan_psoc_delete_vdev, + NULL, 1, WLAN_NAN_ID); + + status = wlan_objmgr_psoc_component_obj_detach(psoc, WLAN_UMAC_COMP_NAN, + nan_obj); + if (QDF_IS_STATUS_ERROR(status)) + nan_err("nan_obj detach failed"); + + nan_debug("nan_obj deleted with status %d", status); + qdf_spinlock_destroy(&nan_obj->lock); + qdf_mem_free(nan_obj); + + return status; +} + +static QDF_STATUS nan_vdev_obj_created_notification( + struct wlan_objmgr_vdev *vdev, void *arg_list) +{ + struct nan_vdev_priv_obj *nan_obj; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + nan_debug("nan_vdev_create_notif called"); + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_NDI_MODE) { + nan_debug("not a ndi vdev. do nothing"); + return QDF_STATUS_SUCCESS; + } + + nan_obj = qdf_mem_malloc(sizeof(*nan_obj)); + if (!nan_obj) { + nan_err("malloc failed for nan prv obj"); + return QDF_STATUS_E_NOMEM; + } + + qdf_spinlock_create(&nan_obj->lock); + status = wlan_objmgr_vdev_component_obj_attach(vdev, WLAN_UMAC_COMP_NAN, + (void *)nan_obj, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + nan_alert("obj attach with vdev failed"); + goto nan_vdev_notif_failed; + } + + return QDF_STATUS_SUCCESS; + +nan_vdev_notif_failed: + + qdf_spinlock_destroy(&nan_obj->lock); + qdf_mem_free(nan_obj); + return status; +} + +static QDF_STATUS nan_vdev_obj_destroyed_notification( + struct wlan_objmgr_vdev *vdev, void *arg_list) +{ + struct nan_vdev_priv_obj *nan_obj; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + nan_debug("nan_vdev_delete_notif called"); + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_NDI_MODE) { + nan_debug("not a ndi vdev. do nothing"); + return QDF_STATUS_SUCCESS; + } + + nan_obj = nan_get_vdev_priv_obj(vdev); + if (!nan_obj) { + nan_err("nan_obj is NULL"); + return QDF_STATUS_E_FAULT; + } + + status = wlan_objmgr_vdev_component_obj_detach(vdev, WLAN_UMAC_COMP_NAN, + nan_obj); + if (QDF_IS_STATUS_ERROR(status)) + nan_err("nan_obj detach failed"); + + nan_debug("nan_obj deleted with status %d", status); + qdf_spinlock_destroy(&nan_obj->lock); + qdf_mem_free(nan_obj); + + return status; +} + +QDF_STATUS nan_init(void) +{ + QDF_STATUS status; + + /* register psoc create handler functions. */ + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_NAN, + nan_psoc_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_register_psoc_create_handler failed"); + return status; + } + + /* register psoc delete handler functions. */ + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_NAN, + nan_psoc_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_register_psoc_destroy_handler failed"); + nan_deinit(); + return status; + } + + /* register vdev create handler functions. */ + status = wlan_objmgr_register_vdev_create_handler( + WLAN_UMAC_COMP_NAN, + nan_vdev_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_register_psoc_create_handler failed"); + nan_deinit(); + return status; + } + + /* register vdev delete handler functions. */ + status = wlan_objmgr_register_vdev_destroy_handler( + WLAN_UMAC_COMP_NAN, + nan_vdev_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_register_psoc_destroy_handler failed"); + nan_deinit(); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS nan_deinit(void) +{ + QDF_STATUS ret = QDF_STATUS_SUCCESS, status; + + /* register psoc create handler functions. */ + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_NAN, + nan_psoc_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_unregister_psoc_create_handler failed"); + ret = status; + } + + /* register vdev create handler functions. */ + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_NAN, + nan_psoc_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_deregister_psoc_destroy_handler failed"); + ret = status; + } + + /* de-register vdev create handler functions. */ + status = wlan_objmgr_unregister_vdev_create_handler( + WLAN_UMAC_COMP_NAN, + nan_vdev_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_unregister_psoc_create_handler failed"); + ret = status; + } + + /* de-register vdev delete handler functions. */ + status = wlan_objmgr_unregister_vdev_destroy_handler( + WLAN_UMAC_COMP_NAN, + nan_vdev_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_deregister_psoc_destroy_handler failed"); + ret = status; + } + + return ret; +} + +QDF_STATUS nan_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status = target_if_nan_register_events(psoc); + + if (QDF_IS_STATUS_ERROR(status)) + nan_err("target_if_nan_register_events failed"); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS nan_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status = target_if_nan_deregister_events(psoc); + + if (QDF_IS_STATUS_ERROR(status)) + nan_err("target_if_nan_deregister_events failed"); + + return QDF_STATUS_SUCCESS; +} diff --git a/components/nan/core/src/nan_main.c b/components/nan/core/src/nan_main.c new file mode 100644 index 000000000000..eef744fd80f5 --- /dev/null +++ b/components/nan/core/src/nan_main.c @@ -0,0 +1,521 @@ +/* + * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains core nan function definitions + */ + +#include "nan_main_i.h" +#include "nan_ucfg_api.h" +#include "wlan_nan_api.h" +#include "target_if_nan.h" +#include "scheduler_api.h" +#include "wlan_serialization_api.h" +#include "wlan_objmgr_cmn.h" +#include "wlan_objmgr_global_obj.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" + +struct nan_vdev_priv_obj *nan_get_vdev_priv_obj( + struct wlan_objmgr_vdev *vdev) +{ + struct nan_vdev_priv_obj *obj; + + if (!vdev) { + nan_err("vdev is null"); + return NULL; + } + obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, WLAN_UMAC_COMP_NAN); + + return obj; +} + +struct nan_psoc_priv_obj *nan_get_psoc_priv_obj( + struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *obj; + + if (!psoc) { + nan_err("psoc is null"); + return NULL; + } + obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_NAN); + + return obj; +} + +void nan_release_cmd(void *in_req, uint32_t cmdtype) +{ + struct wlan_objmgr_vdev *vdev = NULL; + + if (!in_req) + return; + + switch (cmdtype) { + case WLAN_SER_CMD_NDP_INIT_REQ: { + struct nan_datapath_initiator_req *req = in_req; + + vdev = req->vdev; + break; + } + case WLAN_SER_CMD_NDP_RESP_REQ: { + struct nan_datapath_responder_req *req = in_req; + + vdev = req->vdev; + break; + } + case WLAN_SER_CMD_NDP_DATA_END_INIT_REQ: { + struct nan_datapath_end_req *req = in_req; + + vdev = req->vdev; + break; + } + default: + nan_err("invalid req type: %d", cmdtype); + break; + } + + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + else + nan_err("vdev is null"); + + qdf_mem_free(in_req); +} + +static void nan_req_incomplete(void *req, uint32_t cmdtype) +{ + /* send msg to userspace if needed that cmd got incomplete */ +} + +static void nan_req_activated(void *in_req, uint32_t cmdtype) +{ + uint32_t req_type; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev; + struct wlan_lmac_if_nan_tx_ops *tx_ops; + + switch (cmdtype) { + case WLAN_SER_CMD_NDP_INIT_REQ: { + struct nan_datapath_initiator_req *req = in_req; + + vdev = req->vdev; + req_type = NDP_INITIATOR_REQ; + break; + } + case WLAN_SER_CMD_NDP_RESP_REQ: { + struct nan_datapath_responder_req *req = in_req; + + vdev = req->vdev; + req_type = NDP_RESPONDER_REQ; + break; + } + case WLAN_SER_CMD_NDP_DATA_END_INIT_REQ: { + struct nan_datapath_end_req *req = in_req; + + vdev = req->vdev; + req_type = NDP_END_REQ; + break; + } + default: + nan_alert("in correct cmdtype: %d", cmdtype); + return; + } + + if (!vdev) { + nan_alert("vdev is null"); + return; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + nan_alert("psoc is null"); + return; + } + + tx_ops = target_if_nan_get_tx_ops(psoc); + if (!tx_ops) { + nan_alert("tx_ops is null"); + return; + } + + /* send ndp_intiator_req/responder_req/end_req to FW */ + tx_ops->nan_req_tx(in_req, req_type); +} + +static QDF_STATUS nan_serialized_cb(void *cmd, + enum wlan_serialization_cb_reason reason) +{ + void *req; + struct wlan_serialization_command *ser_cmd = cmd; + + if (!ser_cmd || !ser_cmd->umac_cmd) { + nan_alert("cmd or umac_cmd is null"); + return QDF_STATUS_E_NULL_VALUE; + } + req = ser_cmd->umac_cmd; + + switch (reason) { + case WLAN_SER_CB_ACTIVATE_CMD: + nan_req_activated(req, ser_cmd->cmd_type); + break; + case WLAN_SER_CB_CANCEL_CMD: + case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: + nan_req_incomplete(req, ser_cmd->cmd_type); + break; + case WLAN_SER_CB_RELEASE_MEM_CMD: + nan_release_cmd(req, ser_cmd->cmd_type); + break; + default: + /* Do nothing but logging */ + nan_alert("invalid serialized cb reason: %d", reason); + break; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS nan_scheduled_msg_handler(struct scheduler_msg *msg) +{ + enum wlan_serialization_status status = 0; + struct wlan_serialization_command cmd = {0}; + + if (!msg || !msg->bodyptr) { + nan_alert("msg or bodyptr is null"); + return QDF_STATUS_E_NULL_VALUE; + } + switch (msg->type) { + case NDP_INITIATOR_REQ: { + struct nan_datapath_initiator_req *req = msg->bodyptr; + + cmd.cmd_type = WLAN_SER_CMD_NDP_INIT_REQ; + cmd.vdev = req->vdev; + break; + } + case NDP_RESPONDER_REQ: { + struct nan_datapath_responder_req *req = msg->bodyptr; + + cmd.cmd_type = WLAN_SER_CMD_NDP_RESP_REQ; + cmd.vdev = req->vdev; + break; + } + case NDP_END_REQ: { + struct nan_datapath_end_req *req = msg->bodyptr; + + cmd.cmd_type = WLAN_SER_CMD_NDP_DATA_END_INIT_REQ; + cmd.vdev = req->vdev; + break; + } + default: + nan_err("wrong request type: %d", msg->type); + return QDF_STATUS_E_INVAL; + } + + /* TBD - support more than one req of same type or avoid */ + cmd.cmd_id = 0; + cmd.cmd_cb = nan_serialized_cb; + cmd.umac_cmd = msg->bodyptr; + cmd.source = WLAN_UMAC_COMP_NAN; + cmd.is_high_priority = false; + cmd.cmd_timeout_duration = 30000 /* 30 sec for now. TBD */; + nan_debug("cmd_type: %d", cmd.cmd_type); + cmd.is_blocking = true; + + status = wlan_serialization_request(&cmd); + /* following is TBD */ + if (status != WLAN_SER_CMD_ACTIVE && status != WLAN_SER_CMD_PENDING) { + nan_err("unable to serialize command"); + wlan_objmgr_vdev_release_ref(cmd.vdev, WLAN_NAN_ID); + return QDF_STATUS_E_INVAL; + } + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS nan_handle_confirm( + struct nan_datapath_confirm_event *confirm) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + struct nan_psoc_priv_obj *psoc_nan_obj; + + vdev_id = wlan_vdev_get_id(confirm->vdev); + psoc = wlan_vdev_get_psoc(confirm->vdev); + if (!psoc) { + nan_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (confirm->rsp_code != NAN_DATAPATH_RESPONSE_ACCEPT && + confirm->num_active_ndps_on_peer == 0) { + /* + * This peer was created at ndp_indication but + * confirm failed, so it needs to be deleted + */ + nan_err("NDP confirm with reject and no active ndp sessions. deleting peer: "QDF_MAC_ADDR_STR" on vdev_id: %d", + QDF_MAC_ADDR_ARRAY(confirm->peer_ndi_mac_addr.bytes), + vdev_id); + psoc_nan_obj->cb_obj.delete_peers_by_addr(vdev_id, + confirm->peer_ndi_mac_addr); + } + psoc_nan_obj->cb_obj.os_if_event_handler(psoc, confirm->vdev, + NDP_CONFIRM, confirm); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS nan_handle_initiator_rsp( + struct nan_datapath_initiator_rsp *rsp, + struct wlan_objmgr_vdev **vdev) +{ + struct wlan_objmgr_psoc *psoc; + struct nan_psoc_priv_obj *psoc_nan_obj; + + *vdev = rsp->vdev; + psoc = wlan_vdev_get_psoc(rsp->vdev); + if (!psoc) { + nan_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj->cb_obj.os_if_event_handler(psoc, rsp->vdev, + NDP_INITIATOR_RSP, rsp); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS nan_handle_ndp_ind( + struct nan_datapath_indication_event *ndp_ind) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct nan_psoc_priv_obj *psoc_nan_obj; + + vdev_id = wlan_vdev_get_id(ndp_ind->vdev); + psoc = wlan_vdev_get_psoc(ndp_ind->vdev); + if (!psoc) { + nan_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + nan_debug("role: %d, vdev: %d, csid: %d, peer_mac_addr " + QDF_MAC_ADDR_STR, + ndp_ind->role, vdev_id, ndp_ind->ncs_sk_type, + QDF_MAC_ADDR_ARRAY(ndp_ind->peer_mac_addr.bytes)); + + if ((ndp_ind->role == NAN_DATAPATH_ROLE_INITIATOR) || + ((NAN_DATAPATH_ROLE_RESPONDER == ndp_ind->role) && + (NAN_DATAPATH_ACCEPT_POLICY_ALL == ndp_ind->policy))) { + status = psoc_nan_obj->cb_obj.add_ndi_peer(vdev_id, + ndp_ind->peer_mac_addr); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("Couldn't add ndi peer, ndp_role: %d", + ndp_ind->role); + return status; + } + } + if (NAN_DATAPATH_ROLE_RESPONDER == ndp_ind->role) + psoc_nan_obj->cb_obj.os_if_event_handler(psoc, ndp_ind->vdev, + NDP_INDICATION, ndp_ind); + + return status; +} + +static QDF_STATUS nan_handle_responder_rsp( + struct nan_datapath_responder_rsp *rsp, + struct wlan_objmgr_vdev **vdev) +{ + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct nan_psoc_priv_obj *psoc_nan_obj; + + *vdev = rsp->vdev; + psoc = wlan_vdev_get_psoc(rsp->vdev); + if (!psoc) { + nan_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (QDF_IS_STATUS_SUCCESS(rsp->status) && rsp->create_peer) { + status = psoc_nan_obj->cb_obj.add_ndi_peer( + wlan_vdev_get_id(rsp->vdev), + rsp->peer_mac_addr); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("Couldn't add ndi peer"); + rsp->status = QDF_STATUS_E_FAILURE; + } + } + psoc_nan_obj->cb_obj.os_if_event_handler(psoc, rsp->vdev, + NDP_RESPONDER_RSP, rsp); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS nan_handle_ndp_end_rsp( + struct nan_datapath_end_rsp_event *rsp, + struct wlan_objmgr_vdev **vdev) +{ + struct wlan_objmgr_psoc *psoc; + struct nan_psoc_priv_obj *psoc_nan_obj; + + *vdev = rsp->vdev; + psoc = wlan_vdev_get_psoc(rsp->vdev); + if (!psoc) { + nan_err("psoc is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj->cb_obj.os_if_event_handler(psoc, rsp->vdev, + NDP_END_RSP, rsp); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS nan_handle_end_ind( + struct nan_datapath_end_indication_event *ind) +{ + struct wlan_objmgr_psoc *psoc; + struct nan_psoc_priv_obj *psoc_nan_obj; + + psoc = wlan_vdev_get_psoc(ind->vdev); + if (!psoc) { + nan_err("psoc is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj->cb_obj.ndp_delete_peers(ind->ndp_map, ind->num_ndp_ids); + psoc_nan_obj->cb_obj.os_if_event_handler(psoc, ind->vdev, + NDP_END_IND, ind); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS nan_handle_schedule_update( + struct nan_datapath_sch_update_event *ind) +{ + struct wlan_objmgr_psoc *psoc; + struct nan_psoc_priv_obj *psoc_nan_obj; + + psoc = wlan_vdev_get_psoc(ind->vdev); + if (!psoc) { + nan_err("psoc is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj->cb_obj.os_if_event_handler(psoc, ind->vdev, + NDP_SCHEDULE_UPDATE, ind); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS nan_event_handler(struct scheduler_msg *pe_msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_serialization_queued_cmd_info cmd; + + cmd.requestor = WLAN_UMAC_COMP_NAN; + cmd.cmd_id = 0; + cmd.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD; + cmd.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE; + + if (!pe_msg->bodyptr) { + nan_err("msg body is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + switch (pe_msg->type) { + case NDP_CONFIRM: { + nan_handle_confirm(pe_msg->bodyptr); + break; + } + case NDP_INITIATOR_RSP: { + nan_handle_initiator_rsp(pe_msg->bodyptr, &cmd.vdev); + cmd.cmd_type = WLAN_SER_CMD_NDP_INIT_REQ; + wlan_serialization_remove_cmd(&cmd); + break; + } + case NDP_INDICATION: { + nan_handle_ndp_ind(pe_msg->bodyptr); + break; + } + case NDP_RESPONDER_RSP: + nan_handle_responder_rsp(pe_msg->bodyptr, &cmd.vdev); + cmd.cmd_type = WLAN_SER_CMD_NDP_RESP_REQ; + wlan_serialization_remove_cmd(&cmd); + break; + case NDP_END_RSP: + nan_handle_ndp_end_rsp(pe_msg->bodyptr, &cmd.vdev); + cmd.cmd_type = WLAN_SER_CMD_NDP_DATA_END_INIT_REQ; + wlan_serialization_remove_cmd(&cmd); + break; + case NDP_END_IND: + nan_handle_end_ind(pe_msg->bodyptr); + break; + case NDP_SCHEDULE_UPDATE: + nan_handle_schedule_update(pe_msg->bodyptr); + break; + default: + nan_alert("Unhandled NDP event: %d", pe_msg->type); + status = QDF_STATUS_E_NOSUPPORT; + break; + } + return status; +} diff --git a/components/nan/core/src/nan_main_i.h b/components/nan/core/src/nan_main_i.h new file mode 100644 index 000000000000..07f1619951ed --- /dev/null +++ b/components/nan/core/src/nan_main_i.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains declaration of common utility APIs and private structs to be + * used in NAN modules + */ + +#ifndef _WLAN_NAN_MAIN_I_H_ +#define _WLAN_NAN_MAIN_I_H_ + +#include "qdf_types.h" +#include "qdf_status.h" +#include "nan_public_structs.h" +#include "wlan_objmgr_cmn.h" + +struct wlan_objmgr_vdev; +struct wlan_objmgr_psoc; +struct scheduler_msg; + +#define nan_alert(params...) \ + QDF_TRACE_FATAL(QDF_MODULE_ID_NAN, params) +#define nan_err(params...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_NAN, params) +#define nan_warn(params...) \ + QDF_TRACE_WARN(QDF_MODULE_ID_NAN, params) +#define nan_notice(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_NAN, params) +#define nan_info(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_NAN, params) +#define nan_debug(params...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_NAN, params) + +#define nan_nofl_alert(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_NAN, params) +#define nan_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_NAN, params) +#define nan_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_NAN, params) +#define nan_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_NAN, params) +#define nan_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_NAN, params) + +#ifndef MAX_PEERS +#define MAX_PEERS 32 +#endif + +/** + * struct nan_cfg_params - NAN INI config params + * @enable: NAN feature enable + * @dp_enable: NAN Datapath feature enable + * @ndi_ch: NAN Datapath channel + * @ndi_mac_randomize: Randomize NAN datapath interface MAC + */ +struct nan_cfg_params { +#ifdef WLAN_FEATURE_NAN + bool enable; +#endif +#ifdef WLAN_FEATURE_NAN_DATAPATH + bool dp_enable; + uint32_t ndi_ch; + bool ndi_mac_randomize; +#endif +}; + +/** + * struct nan_psoc_priv_obj - nan private psoc obj + * @lock: lock to be acquired before reading or writing to object + * @cb_obj: struct contaning callback pointers + */ +struct nan_psoc_priv_obj { + qdf_spinlock_t lock; + struct nan_callbacks cb_obj; + struct nan_cfg_params cfg_param; +}; + +/** + * struct nan_vdev_priv_obj - nan private vdev obj + * @lock: lock to be acquired before reading or writing to object + * @state: Current state of NDP + * @active_ndp_sessions: active ndp sessions per adapter + * @active_ndp_peers: number of active ndp peers + * @ndp_create_transaction_id: transaction id for create req + * @ndp_delete_transaction_id: transaction id for delete req + * @ndi_delete_rsp_reason: reason code for ndi_delete rsp + * @ndi_delete_rsp_status: status for ndi_delete rsp + */ +struct nan_vdev_priv_obj { + qdf_spinlock_t lock; + enum nan_datapath_state state; + /* idx in following array should follow conn_info.peerMacAddress */ + uint32_t active_ndp_sessions[MAX_PEERS]; + uint32_t active_ndp_peers; + uint16_t ndp_create_transaction_id; + uint16_t ndp_delete_transaction_id; + uint32_t ndi_delete_rsp_reason; + uint32_t ndi_delete_rsp_status; +}; + +/** + * nan_get_vdev_priv_obj: get NAN priv object from vdev object + * @vdev: pointer to vdev object + * + * Return: pointer to NAN vdev private object + */ +struct nan_vdev_priv_obj *nan_get_vdev_priv_obj(struct wlan_objmgr_vdev *vdev); + +/** + * nan_get_psoc_priv_obj: get NAN priv object from psoc object + * @psoc: pointer to psoc object + * + * Return: pointer to NAN psoc private object + */ +struct nan_psoc_priv_obj *nan_get_psoc_priv_obj(struct wlan_objmgr_psoc *psoc); + +/** + * nan_release_cmd: frees resources for NAN command. + * @in_req: pointer to msg buffer to be freed + * @req_type: type of request + * + * Return: None + */ +void nan_release_cmd(void *in_req, uint32_t req_type); + +/** + * nan_scheduled_msg_handler: callback pointer to be called when scheduler + * starts executing enqueued NAN command. + * @msg: pointer to msg + * + * Return: status of operation + */ +QDF_STATUS nan_scheduled_msg_handler(struct scheduler_msg *msg); + +/* + * nan_event_handler: function to process events from firmware + * @msg: message received from lmac + * + * Return: status of operation + */ +QDF_STATUS nan_event_handler(struct scheduler_msg *msg); + +#endif diff --git a/components/nan/dispatcher/inc/cfg_nan.h b/components/nan/dispatcher/inc/cfg_nan.h new file mode 100644 index 000000000000..394ff20d4d90 --- /dev/null +++ b/components/nan/dispatcher/inc/cfg_nan.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__NAN_CFG_H__) +#define __NAN_CFG_H__ + +/** + * + * DOC: nan_cfg.h + * + * NAN feature INI configuration parameter definitions + */ +#include "cfg_define.h" +#include "cfg_converged.h" +#include "qdf_types.h" + +/* + * + * gEnableNanSupport - NAN feature support configuration + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * When set to 1 NAN feature will be enabled. + * + * Related: None + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ +#define CFG_NAN_ENABLE CFG_INI_BOOL("gEnableNanSupport", \ + 0, \ + "Enable NAN Support") +/* + * + * genable_nan_datapath - Enable NaN data path feature. NaN data path + * enables NAN supported devices to exchange + * data over TCP/UDP network stack. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * When set to 1 NAN Datapath feature will be enabled. + * + * Related: gEnableNanSupport + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ +#define CFG_NAN_DATAPATH_ENABLE CFG_INI_BOOL("genable_nan_datapath", \ + 0, \ + "Enable NAN Datapath support") + +/* + * + * gnan_datapath_ndi_channel - Default channel for NAN Datapath + * @Min: 6 + * @Max: 149 + * @Default: 6 + * + * Host suggests this channel for NAN datapath. But FW is free to + * choose other channels based on system constraints. + * + * Related: genable_nan_datapath + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ +/* + * NAN channel on which NAN data interface to start + */ +#define CFG_NAN_NDI_CHANNEL CFG_INI_UINT("gnan_datapath_ndi_channel", \ + 6, 149, 6, \ + CFG_VALUE_OR_DEFAULT, \ + "NAN Datapath Channel") +/* + * + * gEnableNDIMacRandomization - When enabled this will randomize NDI Mac + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * When enabled this will randomize NDI Mac + * + * Related: gEnableNanSupport + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ +#define CFG_NAN_RANDOMIZE_NDI_MAC CFG_INI_BOOL("gEnableNDIMacRandomization", \ + 1, \ + "Enable NAN MAC Randomization") + +#ifdef WLAN_FEATURE_NAN +#define CFG_NAN_DISC CFG(CFG_NAN_ENABLE) +#else +#define CFG_NAN_DISC +#endif + +#ifdef WLAN_FEATURE_NAN_DATAPATH +#define CFG_NAN_DP CFG(CFG_NAN_DATAPATH_ENABLE) \ + CFG(CFG_NAN_NDI_CHANNEL) \ + CFG(CFG_NAN_RANDOMIZE_NDI_MAC) +#else +#define CFG_NAN_DP +#endif + +#define CFG_NAN_ALL CFG_NAN_DISC \ + CFG_NAN_DP + +#endif diff --git a/components/nan/dispatcher/inc/cfg_nan_api.h b/components/nan/dispatcher/inc/cfg_nan_api.h new file mode 100644 index 000000000000..c37821c97357 --- /dev/null +++ b/components/nan/dispatcher/inc/cfg_nan_api.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__NAN_CFG_API_H__) +#define __NAN_CFG_API_H__ + +/** + * + * DOC: nan_cfg_api.h + * + * NAN feature INI configuration parameters get/set APIs + */ +#include "qdf_types.h" + +struct wlan_objmgr_psoc; + +#ifdef WLAN_FEATURE_NAN +/** + * cfg_nan_get_enable() - get NAN support enable status + * @psoc: pointer to psoc object + * + * This function returns NAN enable status + */ +bool cfg_nan_get_enable(struct wlan_objmgr_psoc *psoc); +#else +static inline bool cfg_nan_get_enable(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_NAN_DATAPATH +/** + * cfg_nan_get_datapath_enable() - get NAN Datapath support enable status + * @psoc: pointer to psoc object + * + * This function returns NAN Datapath enable status + */ +bool cfg_nan_get_datapath_enable(struct wlan_objmgr_psoc *psoc); + +/** + * cfg_nan_get_ndi_channel() - get NAN Datapath channel + * @psoc: pointer to psoc object + * + * This function returns NAN Datapath channel + */ +uint32_t cfg_nan_get_ndi_channel(struct wlan_objmgr_psoc *psoc); + +/** + * cfg_nan_get_ndi_mac_randomize() - get NDI MAC randomize enable status + * @psoc: pointer to psoc object + * + * This function returns NAN Datapath Interface MAC randomization status + */ +bool cfg_nan_get_ndi_mac_randomize(struct wlan_objmgr_psoc *psoc); +#else +static inline bool cfg_nan_get_datapath_enable(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline uint32_t cfg_nan_get_ndi_channel(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline bool cfg_nan_get_ndi_mac_randomize(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif +#endif + diff --git a/components/nan/dispatcher/inc/nan_ucfg_api.h b/components/nan/dispatcher/inc/nan_ucfg_api.h new file mode 100644 index 000000000000..4462eca50f5f --- /dev/null +++ b/components/nan/dispatcher/inc/nan_ucfg_api.h @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains interface prototypes for OS_IF layer + */ + +#ifndef _NAN_UCFG_API_H_ +#define _NAN_UCFG_API_H_ + +#include "qdf_types.h" +#include "qdf_status.h" +#include "wlan_objmgr_cmn.h" + +struct nan_callbacks; +struct wlan_objmgr_vdev; +struct wlan_objmgr_psoc; +struct wlan_objmgr_vdev; +struct nan_callbacks; + +/** + * ucfg_nan_set_ndi_state: set ndi state + * @vdev: pointer to vdev object + * @state: value to set + * + * Return: status of operation + */ +QDF_STATUS ucfg_nan_set_ndi_state(struct wlan_objmgr_vdev *vdev, + uint32_t state); + +/** + * ucfg_nan_get_ndi_state: get ndi state from vdev obj + * @vdev: pointer to vdev object + * + * Return: ndi state + */ +enum nan_datapath_state ucfg_nan_get_ndi_state(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_nan_set_active_peers: set active ndi peer + * @vdev: pointer to vdev object + * @val: value to set + * + * Return: status of operation + */ +QDF_STATUS ucfg_nan_set_active_peers(struct wlan_objmgr_vdev *vdev, + uint32_t val); + +/** + * ucfg_nan_get_active_peers: get active ndi peer from vdev obj + * @vdev: pointer to vdev object + * + * Return: active ndi peer + */ +uint32_t ucfg_nan_get_active_peers(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_nan_set_active_ndp_sessions: set active ndp sessions + * @vdev: pointer to vdev object + * + * Return: status of operation + */ +QDF_STATUS ucfg_nan_set_active_ndp_sessions(struct wlan_objmgr_vdev *vdev, + uint32_t val, uint8_t idx); + +/** + * ucfg_nan_get_active_ndp_sessions: get active ndp sessions from vdev obj + * @vdev: pointer to vdev object + * + * Return: pointer to NAN psoc private object + */ +uint32_t ucfg_nan_get_active_ndp_sessions(struct wlan_objmgr_vdev *vdev, + uint8_t idx); + +/** + * ucfg_nan_set_ndp_create_transaction_id: set ndp create transaction id + * @vdev: pointer to vdev object + * @val: value to set + * + * Return: status of operation + */ +QDF_STATUS ucfg_nan_set_ndp_create_transaction_id(struct wlan_objmgr_vdev *vdev, + uint16_t val); + +/** + * ucfg_nan_get_ndp_create_transaction_id: get ndp create transaction id + * vdev obj + * @vdev: pointer to vdev object + * + * Return: ndp create transaction_id + */ +uint16_t ucfg_nan_get_ndp_create_transaction_id(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_nan_set_ndp_delete_transaction_id: set ndp delete transaction id + * @vdev: pointer to vdev object + * @val: value to set + * + * Return: status of operation + */ +QDF_STATUS ucfg_nan_set_ndp_delete_transaction_id(struct wlan_objmgr_vdev *vdev, + uint16_t val); + +/** + * ucfg_nan_get_ndp_delete_transaction_id: get ndp delete transaction id from + * vdev obj + * @vdev: pointer to vdev object + * + * Return: ndp delete transaction_id + */ +uint16_t ucfg_nan_get_ndp_delete_transaction_id(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_nan_set_ndi_delete_rsp_reason: set ndi delete response reason + * @vdev: pointer to vdev object + * @val: value to set + * + * Return: status of operation + */ +QDF_STATUS ucfg_nan_set_ndi_delete_rsp_reason(struct wlan_objmgr_vdev *vdev, + uint32_t val); + +/** + * ucfg_nan_get_ndi_delete_rsp_reason: get ndi delete response reason from vdev + * obj + * @vdev: pointer to vdev object + * + * Return: ndi delete rsp reason + */ +uint32_t ucfg_nan_get_ndi_delete_rsp_reason(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_nan_set_ndi_delete_rsp_status: set ndi delete response reason + * @vdev: pointer to vdev object + * @val: value to set + * + * Return: status of operation + */ +QDF_STATUS ucfg_nan_set_ndi_delete_rsp_status(struct wlan_objmgr_vdev *vdev, + uint32_t val); + +/** + * ucfg_nan_get_ndi_delete_rsp_status: get ndi delete response status from vdev + * obj + * @vdev: pointer to vdev object + * + * Return: ndi delete rsp status + */ +uint32_t ucfg_nan_get_ndi_delete_rsp_status(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_nan_get_callbacks: ucfg API to return callbacks + * @psoc: pointer to psoc object + * @cb_obj: callback struct to populate + * + * Return: callback struct on success, NULL otherwise + */ +QDF_STATUS ucfg_nan_get_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj); + +/** + * ucfg_nan_req_processor: ucfg API to be called from HDD/OS_IF to + * process nan datapath initiator request from userspace + * @vdev: nan vdev pointer + * @in_req: NDP request + * @psoc: pointer to psoc object + * @req_type: type of request + * + * Return: status of operation + */ +QDF_STATUS ucfg_nan_req_processor(struct wlan_objmgr_vdev *vdev, + void *in_req, uint32_t req_type); + +/** + * ucfg_nan_event_handler: ucfg API to be called from legacy code to + * post events to os_if/hdd layer + * @psoc: pointer to psoc object + * @vdev: pointer to vdev object + * @type: message type + * @msg: msg buffer + * + * Return: None + */ +void ucfg_nan_event_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t type, void *msg); + +/** + * ucfg_nan_register_hdd_callbacks: ucfg API to set hdd callbacks + * @psoc: pointer to psoc object + * @cb_obj: structs containing callbacks + * @os_if_event_handler: os if event handler callback + * + * Return: status of operation + */ +int ucfg_nan_register_hdd_callbacks(struct wlan_objmgr_psoc *, + struct nan_callbacks *, + void (os_if_event_handler) + (struct wlan_objmgr_psoc *, + struct wlan_objmgr_vdev *, + uint32_t, void *)); + +/* + * ucfg_nan_register_lim_callbacks: ucfg API to set lim callbacks + * @psoc: pointer to psoc object + * @cb_obj: structs containing callbacks + * + * Return: status of operation + */ +int ucfg_nan_register_lim_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj); + +/** + * ucfg_nan_get_callbacks: ucfg API to return callbacks + * @psoc: pointer to psoc object + * @cb_obj: callback struct to populate + * + * Return: callback struct on success, NULL otherwise + */ +QDF_STATUS ucfg_nan_get_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj); + +#endif /* _NAN_UCFG_API_H_ */ + diff --git a/components/nan/dispatcher/src/cfg_nan.c b/components/nan/dispatcher/src/cfg_nan.c new file mode 100644 index 000000000000..5b852da1f947 --- /dev/null +++ b/components/nan/dispatcher/src/cfg_nan.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains NAN INI configurations + */ + +#include "wlan_objmgr_psoc_obj.h" +#include "cfg_nan_api.h" +#include "../../core/src/nan_main_i.h" + +static inline struct nan_psoc_priv_obj + *cfg_nan_get_priv_obj(struct wlan_objmgr_psoc *psoc) +{ + if (!psoc) { + nan_err("PSOC obj null"); + return NULL; + } + return wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_NAN); +} + +bool cfg_nan_get_enable(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *nan_obj = cfg_nan_get_priv_obj(psoc); + + if (!nan_obj) { + nan_err("NAN obj null"); + return false; + } + return nan_obj->cfg_param.enable; +} + +bool cfg_nan_get_datapath_enable(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *nan_obj = cfg_nan_get_priv_obj(psoc); + + if (!nan_obj) { + nan_err("NAN obj null"); + return false; + } + return nan_obj->cfg_param.dp_enable; +} + +uint32_t cfg_nan_get_ndi_channel(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *nan_obj = cfg_nan_get_priv_obj(psoc); + + if (!nan_obj) { + nan_err("NAN obj null"); + return 0; + } + return nan_obj->cfg_param.ndi_ch; +} + +bool cfg_nan_get_ndi_mac_randomize(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *nan_obj = cfg_nan_get_priv_obj(psoc); + + if (!nan_obj) { + nan_err("NAN obj null"); + return false; + } + return nan_obj->cfg_param.ndi_mac_randomize; +} + diff --git a/components/nan/dispatcher/src/nan_ucfg_api.c b/components/nan/dispatcher/src/nan_ucfg_api.c new file mode 100644 index 000000000000..b196ae30bfba --- /dev/null +++ b/components/nan/dispatcher/src/nan_ucfg_api.c @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains interface definitions for OS_IF layer + */ + +#include "nan_ucfg_api.h" +#include "nan_public_structs.h" +#include "../../core/src/nan_main_i.h" +#include "scheduler_api.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" + +struct wlan_objmgr_psoc; +struct wlan_objmgr_vdev; + +inline QDF_STATUS ucfg_nan_set_ndi_state(struct wlan_objmgr_vdev *vdev, + uint32_t state) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + qdf_spin_lock_bh(&priv_obj->lock); + priv_obj->state = state; + qdf_spin_unlock_bh(&priv_obj->lock); + + return QDF_STATUS_SUCCESS; +} + +inline enum nan_datapath_state ucfg_nan_get_ndi_state( + struct wlan_objmgr_vdev *vdev) +{ + enum nan_datapath_state val; + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return NAN_DATA_INVALID_STATE; + } + + qdf_spin_lock_bh(&priv_obj->lock); + val = priv_obj->state; + qdf_spin_unlock_bh(&priv_obj->lock); + + return val; +} + +inline QDF_STATUS ucfg_nan_set_active_peers(struct wlan_objmgr_vdev *vdev, + uint32_t val) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&priv_obj->lock); + priv_obj->active_ndp_peers = val; + qdf_spin_unlock_bh(&priv_obj->lock); + + return QDF_STATUS_SUCCESS; +} + +inline uint32_t ucfg_nan_get_active_peers(struct wlan_objmgr_vdev *vdev) +{ + uint32_t val; + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return 0; + } + + qdf_spin_lock_bh(&priv_obj->lock); + val = priv_obj->active_ndp_peers; + qdf_spin_unlock_bh(&priv_obj->lock); + + return val; +} + +inline QDF_STATUS ucfg_nan_set_active_ndp_sessions( + struct wlan_objmgr_vdev *vdev, uint32_t val, uint8_t idx) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (idx >= MAX_PEERS) { + nan_err("peer_idx(%d), MAX(%d)", + idx, MAX_PEERS); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&priv_obj->lock); + priv_obj->active_ndp_sessions[idx] = val; + qdf_spin_unlock_bh(&priv_obj->lock); + + return QDF_STATUS_SUCCESS; +} + +inline uint32_t ucfg_nan_get_active_ndp_sessions(struct wlan_objmgr_vdev *vdev, + uint8_t idx) +{ + uint32_t val; + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return 0; + } + + if (idx >= MAX_PEERS) { + nan_err("peer_idx(%d), MAX(%d)", + idx, MAX_PEERS); + return 0; + } + + qdf_spin_lock_bh(&priv_obj->lock); + val = priv_obj->active_ndp_sessions[idx]; + qdf_spin_unlock_bh(&priv_obj->lock); + + return val; +} + +inline QDF_STATUS ucfg_nan_set_ndp_create_transaction_id( + struct wlan_objmgr_vdev *vdev, uint16_t val) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&priv_obj->lock); + priv_obj->ndp_create_transaction_id = val; + qdf_spin_unlock_bh(&priv_obj->lock); + + return QDF_STATUS_SUCCESS; +} + +inline uint16_t ucfg_nan_get_ndp_create_transaction_id( + struct wlan_objmgr_vdev *vdev) +{ + uint16_t val; + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return 0; + } + + qdf_spin_lock_bh(&priv_obj->lock); + val = priv_obj->ndp_create_transaction_id; + qdf_spin_unlock_bh(&priv_obj->lock); + + return val; +} + +inline QDF_STATUS ucfg_nan_set_ndp_delete_transaction_id( + struct wlan_objmgr_vdev *vdev, uint16_t val) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&priv_obj->lock); + priv_obj->ndp_delete_transaction_id = val; + qdf_spin_unlock_bh(&priv_obj->lock); + + return QDF_STATUS_SUCCESS; +} + +inline uint16_t ucfg_nan_get_ndp_delete_transaction_id( + struct wlan_objmgr_vdev *vdev) +{ + uint16_t val; + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return 0; + } + + qdf_spin_lock_bh(&priv_obj->lock); + val = priv_obj->ndp_delete_transaction_id; + qdf_spin_unlock_bh(&priv_obj->lock); + + return val; +} + +inline QDF_STATUS ucfg_nan_set_ndi_delete_rsp_reason( + struct wlan_objmgr_vdev *vdev, uint32_t val) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&priv_obj->lock); + priv_obj->ndi_delete_rsp_reason = val; + qdf_spin_unlock_bh(&priv_obj->lock); + + return QDF_STATUS_SUCCESS; +} + +inline uint32_t ucfg_nan_get_ndi_delete_rsp_reason( + struct wlan_objmgr_vdev *vdev) +{ + uint32_t val; + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return 0; + } + + qdf_spin_lock_bh(&priv_obj->lock); + val = priv_obj->ndi_delete_rsp_reason; + qdf_spin_unlock_bh(&priv_obj->lock); + + return val; +} + +inline QDF_STATUS ucfg_nan_set_ndi_delete_rsp_status( + struct wlan_objmgr_vdev *vdev, uint32_t val) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&priv_obj->lock); + priv_obj->ndi_delete_rsp_status = val; + qdf_spin_unlock_bh(&priv_obj->lock); + + return QDF_STATUS_SUCCESS; +} + +inline uint32_t ucfg_nan_get_ndi_delete_rsp_status( + struct wlan_objmgr_vdev *vdev) +{ + uint32_t val; + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&priv_obj->lock); + val = priv_obj->ndi_delete_rsp_status; + qdf_spin_unlock_bh(&priv_obj->lock); + + return val; +} + +inline QDF_STATUS ucfg_nan_get_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj) +{ + struct nan_psoc_priv_obj *psoc_obj = nan_get_psoc_priv_obj(psoc); + + if (!psoc_obj) { + nan_err("nan psoc priv object is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + qdf_spin_lock_bh(&psoc_obj->lock); + qdf_mem_copy(cb_obj, &psoc_obj->cb_obj, sizeof(*cb_obj)); + qdf_spin_unlock_bh(&psoc_obj->lock); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS ucfg_nan_sch_msg_flush_cb(struct scheduler_msg *msg) +{ + struct wlan_objmgr_vdev *vdev = NULL; + + if (!msg || !msg->bodyptr) + return QDF_STATUS_E_NULL_VALUE; + + switch (msg->type) { + case NDP_INITIATOR_REQ: + vdev = ((struct nan_datapath_initiator_req *) + msg->bodyptr)->vdev; + break; + case NDP_RESPONDER_REQ: + vdev = ((struct nan_datapath_responder_req *) + msg->bodyptr)->vdev; + break; + case NDP_END_REQ: + vdev = ((struct nan_datapath_end_req *)msg->bodyptr)->vdev; + break; + default: + nan_err("Invalid NAN msg type during sch flush"); + return QDF_STATUS_E_INVAL; + } + + if (vdev) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + qdf_mem_free(msg->bodyptr); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_nan_req_processor(struct wlan_objmgr_vdev *vdev, + void *in_req, uint32_t req_type) +{ + uint32_t len; + QDF_STATUS status; + struct scheduler_msg msg = {0}; + + if (!in_req) { + nan_alert("req is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + switch (req_type) { + case NDP_INITIATOR_REQ: + len = sizeof(struct nan_datapath_initiator_req); + break; + case NDP_RESPONDER_REQ: + len = sizeof(struct nan_datapath_responder_req); + break; + case NDP_END_REQ: + len = sizeof(struct nan_datapath_end_req); + break; + default: + nan_err("in correct message req type: %d", req_type); + return QDF_STATUS_E_INVAL; + } + + msg.bodyptr = qdf_mem_malloc(len); + if (!msg.bodyptr) { + nan_err("malloc failed"); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(msg.bodyptr, in_req, len); + msg.type = req_type; + msg.callback = nan_scheduled_msg_handler; + msg.flush_callback = ucfg_nan_sch_msg_flush_cb; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_NAN, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("failed to post msg to NAN component, status: %d", + status); + qdf_mem_free(msg.bodyptr); + } + + return status; +} + +void ucfg_nan_event_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t type, void *msg) +{ + struct nan_psoc_priv_obj *psoc_obj = nan_get_psoc_priv_obj(psoc); + + if (!psoc_obj) { + nan_err("nan psoc priv object is NULL"); + return; + } + + psoc_obj->cb_obj.os_if_event_handler(psoc, vdev, type, msg); +} + +int ucfg_nan_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj, + void (os_if_event_handler)( + struct wlan_objmgr_psoc *, + struct wlan_objmgr_vdev *, + uint32_t, void *)) +{ + struct nan_psoc_priv_obj *psoc_obj = nan_get_psoc_priv_obj(psoc); + + if (!psoc_obj) { + nan_err("nan psoc priv object is NULL"); + return -EINVAL; + } + + psoc_obj->cb_obj.os_if_event_handler = os_if_event_handler; + + psoc_obj->cb_obj.ndi_open = cb_obj->ndi_open; + psoc_obj->cb_obj.ndi_start = cb_obj->ndi_start; + psoc_obj->cb_obj.ndi_delete = cb_obj->ndi_delete; + psoc_obj->cb_obj.ndi_close = cb_obj->ndi_close; + psoc_obj->cb_obj.drv_ndi_create_rsp_handler = + cb_obj->drv_ndi_create_rsp_handler; + psoc_obj->cb_obj.drv_ndi_delete_rsp_handler = + cb_obj->drv_ndi_delete_rsp_handler; + + psoc_obj->cb_obj.get_peer_idx = cb_obj->get_peer_idx; + psoc_obj->cb_obj.new_peer_ind = cb_obj->new_peer_ind; + psoc_obj->cb_obj.peer_departed_ind = cb_obj->peer_departed_ind; + + return 0; +} + +int ucfg_nan_register_lim_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj) +{ + struct nan_psoc_priv_obj *psoc_obj = nan_get_psoc_priv_obj(psoc); + + if (!psoc_obj) { + nan_err("nan psoc priv object is NULL"); + return -EINVAL; + } + + psoc_obj->cb_obj.add_ndi_peer = cb_obj->add_ndi_peer; + psoc_obj->cb_obj.ndp_delete_peers = cb_obj->ndp_delete_peers; + psoc_obj->cb_obj.delete_peers_by_addr = cb_obj->delete_peers_by_addr; + + return 0; +} diff --git a/components/target_if/nan/inc/target_if_nan.h b/components/target_if/nan/inc/target_if_nan.h new file mode 100644 index 000000000000..45109e3869f3 --- /dev/null +++ b/components/target_if/nan/inc/target_if_nan.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains nan target if declarations + */ + +#ifndef _WLAN_NAN_TGT_IF_H_ +#define _WLAN_NAN_TGT_IF_H_ + +#include "qdf_types.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct wlan_objmgr_psoc; +struct wlan_lmac_if_rx_ops; +struct wlan_lmac_if_tx_ops; +struct wlan_lmac_if_nan_rx_ops; + +/** + * target_if_nan_get_tx_ops() - retrieve the nan tx_ops + * @psoc: psoc context + * + * API to retrieve the nan tx_ops from the psoc context + * + * Return: nan tx_ops pointer + */ +struct wlan_lmac_if_nan_tx_ops *target_if_nan_get_tx_ops( + struct wlan_objmgr_psoc *psoc); + +/** + * target_if_nan_get_rx_ops() - retrieve the nan rx_ops + * @psoc: psoc context + * + * API to retrieve the nan rx_ops from the psoc context + * + * Return: nan rx_ops pointer + */ +struct wlan_lmac_if_nan_rx_ops *target_if_nan_get_rx_ops( + struct wlan_objmgr_psoc *psoc); + +/** + * target_if_nan_register_tx_ops() - registers nan tx ops + * @tx_ops: tx ops + * + * Return: none + */ +void target_if_nan_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops); + +/** + * target_if_nan_register_rx_ops() - registers nan rx ops + * @tx_ops: rx ops + * + * Return: none + */ +void target_if_nan_register_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops); + +/** + * target_if_nan_register_events() - registers with NDP events + * @psoc: pointer to psoc object + * + * Return: status of operation + */ +QDF_STATUS target_if_nan_register_events(struct wlan_objmgr_psoc *psoc); + +/** + * target_if_nan_deregister_events() - registers nan rx ops + * @psoc: pointer to psoc object + * + * Return: status of operation + */ +QDF_STATUS target_if_nan_deregister_events(struct wlan_objmgr_psoc *psoc); + +#endif /* _WIFI_POS_TGT_IF_H_ */ diff --git a/components/target_if/nan/src/target_if_nan.c b/components/target_if/nan/src/target_if_nan.c new file mode 100644 index 000000000000..abb5eec245a9 --- /dev/null +++ b/components/target_if/nan/src/target_if_nan.c @@ -0,0 +1,834 @@ +/* + * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains nan target if functions + */ + +#include "../../../umac/nan/core/src/nan_main_i.h" +#include "nan_public_structs.h" +#include "nan_ucfg_api.h" +#include "target_if_nan.h" +#include "wmi_unified_api.h" +#include "scheduler_api.h" + +static QDF_STATUS target_if_nan_event_flush_cb(struct scheduler_msg *msg) +{ + void *ptr = msg->bodyptr; + struct wlan_objmgr_vdev *vdev = NULL; + + switch (msg->type) { + case NDP_INITIATOR_RSP: + vdev = ((struct nan_datapath_initiator_rsp *)ptr)->vdev; + break; + case NDP_INDICATION: + vdev = ((struct nan_datapath_indication_event *)ptr)->vdev; + break; + case NDP_CONFIRM: + vdev = ((struct nan_datapath_confirm_event *)ptr)->vdev; + break; + case NDP_RESPONDER_RSP: + vdev = ((struct nan_datapath_responder_rsp *)ptr)->vdev; + break; + case NDP_END_RSP: + vdev = ((struct nan_datapath_end_rsp_event *)ptr)->vdev; + break; + case NDP_END_IND: + vdev = ((struct nan_datapath_end_indication_event *)ptr)->vdev; + break; + case NDP_SCHEDULE_UPDATE: + vdev = ((struct nan_datapath_sch_update_event *)ptr)->vdev; + break; + default: + break; + } + + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS target_if_nan_event_dispatcher(struct scheduler_msg *msg) +{ + QDF_STATUS status; + void *ptr = msg->bodyptr; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev = NULL; + struct wlan_lmac_if_nan_rx_ops *nan_rx_ops; + + switch (msg->type) { + case NDP_INITIATOR_RSP: + vdev = ((struct nan_datapath_initiator_rsp *)ptr)->vdev; + break; + case NDP_INDICATION: + vdev = ((struct nan_datapath_indication_event *)ptr)->vdev; + break; + case NDP_CONFIRM: + vdev = ((struct nan_datapath_confirm_event *)ptr)->vdev; + break; + case NDP_RESPONDER_RSP: + vdev = ((struct nan_datapath_responder_rsp *)ptr)->vdev; + break; + case NDP_END_RSP: + vdev = ((struct nan_datapath_end_rsp_event *)ptr)->vdev; + break; + case NDP_END_IND: + vdev = ((struct nan_datapath_end_indication_event *)ptr)->vdev; + break; + case NDP_SCHEDULE_UPDATE: + vdev = ((struct nan_datapath_sch_update_event *)ptr)->vdev; + break; + default: + target_if_err("invalid msg type %d", msg->type); + status = QDF_STATUS_E_INVAL; + goto free_res; + } + + if (!vdev) { + target_if_err("vdev is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto free_res; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + target_if_err("psoc is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto free_res; + } + + nan_rx_ops = target_if_nan_get_rx_ops(psoc); + if (!nan_rx_ops) { + target_if_err("nan_rx_ops is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto free_res; + } + + status = nan_rx_ops->nan_event_rx(msg); +free_res: + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return status; +} + +static QDF_STATUS target_if_nan_ndp_initiator_req( + struct nan_datapath_initiator_req *ndp_req) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct scheduler_msg pe_msg = {0}; + struct wlan_lmac_if_nan_rx_ops *nan_rx_ops; + struct nan_datapath_initiator_rsp ndp_rsp = {0}; + + if (!ndp_req) { + target_if_err("ndp_req is null."); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(ndp_req->vdev); + if (!psoc) { + target_if_err("psoc is null."); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return QDF_STATUS_E_INVAL; + } + + nan_rx_ops = target_if_nan_get_rx_ops(psoc); + if (!nan_rx_ops) { + target_if_err("nan_rx_ops is null."); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_ndp_initiator_req_cmd_send(wmi_handle, ndp_req); + if (QDF_IS_STATUS_SUCCESS(status)) + return status; + + ndp_rsp.vdev = ndp_req->vdev; + ndp_rsp.transaction_id = ndp_req->transaction_id; + ndp_rsp.ndp_instance_id = ndp_req->service_instance_id; + ndp_rsp.status = NAN_DATAPATH_DATA_INITIATOR_REQ_FAILED; + pe_msg.type = NDP_INITIATOR_RSP; + pe_msg.bodyptr = &ndp_rsp; + if (nan_rx_ops->nan_event_rx) + nan_rx_ops->nan_event_rx(&pe_msg); + + return status; +} + +static int target_if_ndp_initiator_rsp_handler(ol_scn_t scn, uint8_t *data, + uint32_t len) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct scheduler_msg msg = {0}; + struct nan_datapath_initiator_rsp *rsp; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + rsp = qdf_mem_malloc(sizeof(*rsp)); + if (!rsp) { + target_if_err("malloc failed"); + return -ENOMEM; + } + + status = wmi_extract_ndp_initiator_rsp(wmi_handle, data, rsp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + qdf_mem_free(rsp); + return -EINVAL; + } + + msg.bodyptr = rsp; + msg.type = NDP_INITIATOR_RSP; + msg.callback = target_if_nan_event_dispatcher; + msg.flush_callback = target_if_nan_event_flush_cb; + target_if_debug("NDP_INITIATOR_RSP sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("failed to post msg, status: %d", status); + target_if_nan_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +static int target_if_ndp_ind_handler(ol_scn_t scn, uint8_t *data, + uint32_t data_len) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct scheduler_msg msg = {0}; + struct nan_datapath_indication_event *rsp; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + rsp = qdf_mem_malloc(sizeof(*rsp)); + if (!rsp) { + target_if_err("malloc failed"); + return -ENOMEM; + } + + status = wmi_extract_ndp_ind(wmi_handle, data, rsp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + qdf_mem_free(rsp); + return -EINVAL; + } + + msg.bodyptr = rsp; + msg.type = NDP_INDICATION; + msg.callback = target_if_nan_event_dispatcher; + msg.flush_callback = target_if_nan_event_flush_cb; + target_if_debug("NDP_INDICATION sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("failed to post msg, status: %d", status); + target_if_nan_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +static int target_if_ndp_confirm_handler(ol_scn_t scn, uint8_t *data, + uint32_t data_len) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct scheduler_msg msg = {0}; + struct nan_datapath_confirm_event *rsp; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + rsp = qdf_mem_malloc(sizeof(*rsp)); + if (!rsp) { + target_if_err("malloc failed"); + return -ENOMEM; + } + + status = wmi_extract_ndp_confirm(wmi_handle, data, rsp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + qdf_mem_free(rsp); + return -EINVAL; + } + + msg.bodyptr = rsp; + msg.type = NDP_CONFIRM; + msg.callback = target_if_nan_event_dispatcher; + msg.flush_callback = target_if_nan_event_flush_cb; + target_if_debug("NDP_CONFIRM sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("failed to post msg, status: %d", status); + target_if_nan_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +static QDF_STATUS target_if_nan_ndp_responder_req( + struct nan_datapath_responder_req *req) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct scheduler_msg pe_msg = {0}; + struct wlan_lmac_if_nan_rx_ops *nan_rx_ops; + struct nan_datapath_responder_rsp rsp = {0}; + + if (!req) { + target_if_err("Invalid req."); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(req->vdev); + if (!psoc) { + target_if_err("psoc is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + nan_rx_ops = target_if_nan_get_rx_ops(psoc); + if (!nan_rx_ops) { + target_if_err("nan_rx_ops is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + status = wmi_unified_ndp_responder_req_cmd_send(wmi_handle, req); + if (QDF_IS_STATUS_SUCCESS(status)) + return status; + + rsp.vdev = req->vdev; + rsp.transaction_id = req->transaction_id; + rsp.status = NAN_DATAPATH_RSP_STATUS_ERROR; + rsp.reason = NAN_DATAPATH_DATA_RESPONDER_REQ_FAILED; + pe_msg.bodyptr = &rsp; + pe_msg.type = NDP_RESPONDER_RSP; + if (nan_rx_ops->nan_event_rx) + nan_rx_ops->nan_event_rx(&pe_msg); + + return status; +} + +static int target_if_ndp_responder_rsp_handler(ol_scn_t scn, uint8_t *data, + uint32_t len) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct scheduler_msg msg = {0}; + struct nan_datapath_responder_rsp *rsp; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return -EINVAL; + } + + rsp = qdf_mem_malloc(sizeof(*rsp)); + if (!rsp) { + target_if_err("malloc failed"); + return -ENOMEM; + } + + status = wmi_extract_ndp_responder_rsp(wmi_handle, data, rsp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + qdf_mem_free(rsp); + return -EINVAL; + } + + msg.bodyptr = rsp; + msg.type = NDP_RESPONDER_RSP; + msg.callback = target_if_nan_event_dispatcher; + msg.flush_callback = target_if_nan_event_flush_cb; + target_if_debug("NDP_INITIATOR_RSP sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("failed to post msg, status: %d", status); + target_if_nan_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +static QDF_STATUS target_if_nan_ndp_end_req(struct nan_datapath_end_req *req) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct scheduler_msg msg = {0}; + struct wlan_lmac_if_nan_rx_ops *nan_rx_ops; + struct nan_datapath_end_rsp_event end_rsp = {0}; + + if (!req) { + target_if_err("req is null"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(req->vdev); + if (!psoc) { + target_if_err("psoc is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + nan_rx_ops = target_if_nan_get_rx_ops(psoc); + if (!nan_rx_ops) { + target_if_err("nan_rx_ops is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + status = wmi_unified_ndp_end_req_cmd_send(wmi_handle, req); + if (QDF_IS_STATUS_SUCCESS(status)) + return status; + + end_rsp.vdev = req->vdev; + msg.type = NDP_END_RSP; + end_rsp.status = NAN_DATAPATH_RSP_STATUS_ERROR; + end_rsp.reason = NAN_DATAPATH_END_FAILED; + end_rsp.transaction_id = req->transaction_id; + msg.bodyptr = &end_rsp; + + if (nan_rx_ops->nan_event_rx) + nan_rx_ops->nan_event_rx(&msg); + + return status; +} + +static int target_if_ndp_end_rsp_handler(ol_scn_t scn, uint8_t *data, + uint32_t data_len) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct scheduler_msg msg = {0}; + struct nan_datapath_end_rsp_event *end_rsp; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return -EINVAL; + } + + end_rsp = qdf_mem_malloc(sizeof(*end_rsp)); + if (!end_rsp) { + target_if_err("malloc failed"); + return -ENOMEM; + } + + status = wmi_extract_ndp_end_rsp(wmi_handle, data, end_rsp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + qdf_mem_free(end_rsp); + return -EINVAL; + } + + msg.bodyptr = end_rsp; + msg.type = NDP_END_RSP; + msg.callback = target_if_nan_event_dispatcher; + msg.flush_callback = target_if_nan_event_flush_cb; + target_if_debug("NDP_END_RSP sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("failed to post msg, status: %d", status); + target_if_nan_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +static int target_if_ndp_end_ind_handler(ol_scn_t scn, uint8_t *data, + uint32_t data_len) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct scheduler_msg msg = {0}; + struct nan_datapath_end_indication_event *rsp = NULL; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return -EINVAL; + } + + status = wmi_extract_ndp_end_ind(wmi_handle, data, &rsp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + return -EINVAL; + } + + rsp->vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc( + wmi_handle->soc->wmi_psoc, QDF_NDI_MODE, WLAN_NAN_ID); + if (!rsp->vdev) { + target_if_err("vdev is null"); + qdf_mem_free(rsp); + return -EINVAL; + } + + msg.bodyptr = rsp; + msg.type = NDP_END_IND; + msg.callback = target_if_nan_event_dispatcher; + msg.flush_callback = target_if_nan_event_flush_cb; + target_if_debug("NDP_END_IND sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("failed to post msg, status: %d", status); + target_if_nan_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +static int target_if_ndp_sch_update_handler(ol_scn_t scn, uint8_t *data, + uint32_t data_len) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct scheduler_msg msg = {0}; + struct nan_datapath_sch_update_event *rsp; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return -EINVAL; + } + + rsp = qdf_mem_malloc(sizeof(*rsp)); + if (!rsp) { + target_if_err("malloc failed"); + return -ENOMEM; + } + + status = wmi_extract_ndp_sch_update(wmi_handle, data, rsp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + qdf_mem_free(rsp); + return -EINVAL; + } + + msg.bodyptr = rsp; + msg.type = NDP_SCHEDULE_UPDATE; + msg.callback = target_if_nan_event_dispatcher; + msg.flush_callback = target_if_nan_event_flush_cb; + target_if_debug("NDP_SCHEDULE_UPDATE sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("failed to post msg, status: %d", status); + target_if_nan_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +static QDF_STATUS target_if_nan_req(void *req, uint32_t req_type) +{ + /* send cmd to fw */ + switch (req_type) { + case NDP_INITIATOR_REQ: + target_if_nan_ndp_initiator_req(req); + break; + case NDP_RESPONDER_REQ: + target_if_nan_ndp_responder_req(req); + break; + case NDP_END_REQ: + target_if_nan_ndp_end_req(req); + break; + default: + target_if_err("invalid req type"); + break; + } + return QDF_STATUS_SUCCESS; +} + +void target_if_nan_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) +{ + tx_ops->nan_tx_ops.nan_req_tx = target_if_nan_req; +} + +void target_if_nan_register_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops) +{ + rx_ops->nan_rx_ops.nan_event_rx = nan_event_handler; +} + +inline struct wlan_lmac_if_nan_tx_ops *target_if_nan_get_tx_ops( + struct wlan_objmgr_psoc *psoc) +{ + if (!psoc) { + target_if_err("psoc is null"); + return NULL; + } + + return &psoc->soc_cb.tx_ops.nan_tx_ops; +} + +inline struct wlan_lmac_if_nan_rx_ops *target_if_nan_get_rx_ops( + struct wlan_objmgr_psoc *psoc) +{ + if (!psoc) { + target_if_err("psoc is null"); + return NULL; + } + + return &psoc->soc_cb.rx_ops.nan_rx_ops; +} + +QDF_STATUS target_if_nan_register_events(struct wlan_objmgr_psoc *psoc) +{ + int ret; + wmi_unified_t handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!handle) { + target_if_err("handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + ret = wmi_unified_register_event_handler(handle, + wmi_ndp_initiator_rsp_event_id, + target_if_ndp_initiator_rsp_handler, + WMI_RX_UMAC_CTX); + if (ret) { + target_if_err("wmi event registration failed, ret: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_ndp_indication_event_id, + target_if_ndp_ind_handler, + WMI_RX_UMAC_CTX); + if (ret) { + target_if_err("wmi event registration failed, ret: %d", ret); + target_if_nan_deregister_events(psoc); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_ndp_confirm_event_id, + target_if_ndp_confirm_handler, + WMI_RX_UMAC_CTX); + if (ret) { + target_if_err("wmi event registration failed, ret: %d", ret); + target_if_nan_deregister_events(psoc); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_ndp_responder_rsp_event_id, + target_if_ndp_responder_rsp_handler, + WMI_RX_UMAC_CTX); + if (ret) { + target_if_err("wmi event registration failed, ret: %d", ret); + target_if_nan_deregister_events(psoc); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_ndp_end_indication_event_id, + target_if_ndp_end_ind_handler, + WMI_RX_UMAC_CTX); + if (ret) { + target_if_err("wmi event registration failed, ret: %d", ret); + target_if_nan_deregister_events(psoc); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_ndp_end_rsp_event_id, + target_if_ndp_end_rsp_handler, + WMI_RX_UMAC_CTX); + if (ret) { + target_if_err("wmi event registration failed, ret: %d", ret); + target_if_nan_deregister_events(psoc); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_ndl_schedule_update_event_id, + target_if_ndp_sch_update_handler, + WMI_RX_UMAC_CTX); + if (ret) { + target_if_err("wmi event registration failed, ret: %d", ret); + target_if_nan_deregister_events(psoc); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS target_if_nan_deregister_events(struct wlan_objmgr_psoc *psoc) +{ + int ret, status = 0; + wmi_unified_t handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!handle) { + target_if_err("handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + ret = wmi_unified_unregister_event_handler(handle, + wmi_ndl_schedule_update_event_id); + if (ret) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + ret = wmi_unified_unregister_event_handler(handle, + wmi_ndp_end_rsp_event_id); + if (ret) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + ret = wmi_unified_unregister_event_handler(handle, + wmi_ndp_end_indication_event_id); + if (ret) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + ret = wmi_unified_unregister_event_handler(handle, + wmi_ndp_responder_rsp_event_id); + if (ret) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + ret = wmi_unified_unregister_event_handler(handle, + wmi_ndp_confirm_event_id); + if (ret) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + ret = wmi_unified_unregister_event_handler(handle, + wmi_ndp_indication_event_id); + if (ret) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + ret = wmi_unified_unregister_event_handler(handle, + wmi_ndp_initiator_rsp_event_id); + if (ret) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + if (status) + return QDF_STATUS_E_FAILURE; + else + return QDF_STATUS_SUCCESS; +} diff --git a/os_if/nan/inc/os_if_nan.h b/os_if/nan/inc/os_if_nan.h new file mode 100644 index 000000000000..338ea7462d45 --- /dev/null +++ b/os_if/nan/inc/os_if_nan.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: declares nan component os interface APIs + */ + +#ifndef _OS_IF_NAN_H_ +#define _OS_IF_NAN_H_ + +#include "qdf_types.h" +#include "nan_public_structs.h" +#include "nan_ucfg_api.h" + +struct wlan_objmgr_psoc; +struct wlan_objmgr_vdev; + +#ifdef WLAN_FEATURE_NAN_CONVERGENCE + +/** + * os_if_nan_process_ndp_cmd: os_if api to handle nan request message + * @psoc: pointer to psoc object + * @data: request data. contains vendor cmd tlvs + * @data_len: length of data + * + * Return: status of operation + */ +int os_if_nan_process_ndp_cmd(struct wlan_objmgr_psoc *psoc, + const void *data, int data_len); + +/** + * os_if_nan_event_handler: os_if handler api for nan response messages + * @psoc: pointer to psoc object + * @vdev: pointer to vdev object + * @type: message type + * @msg: msg buffer + * + * Return: None + */ +void os_if_nan_event_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t type, void *msg); + +/** + * os_if_nan_register_hdd_callbacks: os_if api to register hdd callbacks + * @psoc: pointer to psoc object + * @cb_obj: struct pointer containing callbacks + * + * Return: status of operation + */ +int os_if_nan_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj); + +/** + * os_if_nan_register_lim_callbacks: os_if api to register lim callbacks + * @psoc: pointer to psoc object + * @cb_obj: struct pointer containing callbacks + * + * Return: status of operation + */ +int os_if_nan_register_lim_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj); + +/** + * os_if_nan_post_ndi_create_rsp: os_if api to pos ndi create rsp to umac nan + * component + * @psoc: pointer to psoc object + * @vdev_id: vdev id of ndi + * @success: if create was success or failure + * + * Return: None + */ +void os_if_nan_post_ndi_create_rsp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool success); + +/** + * os_if_nan_post_ndi_delete_rsp: os_if api to pos ndi delete rsp to umac nan + * component + * @psoc: pointer to psoc object + * @vdev_id: vdev id of ndi + * @success: if delete was success or failure + * + * Return: None + */ +void os_if_nan_post_ndi_delete_rsp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool success); + +/** + * os_if_nan_ndi_session_end: os_if api to process ndi session end + * component + * @vdev: pointer to vdev deleted + * + * Return: None + */ +void os_if_nan_ndi_session_end(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_nan_set_ndi_state: os_if api set NDI state + * @vdev: pointer to vdev deleted + * @state: value to set + * + * Return: status of operation + */ +static inline QDF_STATUS os_if_nan_set_ndi_state(struct wlan_objmgr_vdev *vdev, + uint32_t state) +{ + return ucfg_nan_set_ndi_state(vdev, state); +} + +/** + * os_if_nan_set_ndp_create_transaction_id: set ndp create transaction id + * @vdev: pointer to vdev object + * @val: value to set + * + * Return: status of operation + */ +static inline QDF_STATUS os_if_nan_set_ndp_create_transaction_id( + struct wlan_objmgr_vdev *vdev, + uint16_t val) +{ + return ucfg_nan_set_ndp_create_transaction_id(vdev, val); +} + +/** + * os_if_nan_set_ndp_delete_transaction_id: set ndp delete transaction id + * @vdev: pointer to vdev object + * @val: value to set + * + * Return: status of operation + */ +static inline QDF_STATUS os_if_nan_set_ndp_delete_transaction_id( + struct wlan_objmgr_vdev *vdev, + uint16_t val) +{ + return ucfg_nan_set_ndp_delete_transaction_id(vdev, val); +} + +#else + +static inline void os_if_nan_post_ndi_create_rsp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool success) +{ +} + +static inline void os_if_nan_post_ndi_delete_rsp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool success) +{ +} + +#endif /* WLAN_FEATURE_NAN_CONVERGENCE */ + +#endif diff --git a/os_if/nan/src/os_if_nan.c b/os_if/nan/src/os_if_nan.c new file mode 100644 index 000000000000..6f98e93dd2b2 --- /dev/null +++ b/os_if/nan/src/os_if_nan.c @@ -0,0 +1,2170 @@ +/* + * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: defines nan component os interface APIs + */ + +#include "qdf_str.h" +#include "qdf_trace.h" +#include "qdf_types.h" +#include "os_if_nan.h" +#include "wlan_nan_api.h" +#include "nan_ucfg_api.h" +#include "nan_public_structs.h" +#include "wlan_osif_priv.h" +#include +#include "wlan_cfg80211.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_objmgr_peer_obj.h" +#include "wlan_utility.h" + +/* NLA policy */ +static const struct nla_policy +vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID] = { + .type = NLA_U16, + .len = sizeof(uint16_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR] = { + .type = NLA_NUL_STRING, + .len = IFNAMSIZ - 1 + }, + [QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR] = { + .type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE + }, + [QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_SECURITY] = { + .type = NLA_U16, + .len = sizeof(uint16_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO] = { + .type = NLA_BINARY, + .len = NDP_APP_INFO_LEN + }, + [QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR] = { + .type = NLA_BINARY, + .len = QDF_MAC_ADDR_SIZE + }, + [QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY] = { + .type = NLA_BINARY, + .len = NDP_NUM_INSTANCE_ID + }, + [QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_CSID] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_PMK] = { + .type = NLA_BINARY, + .len = NDP_PMK_LEN + }, + [QCA_WLAN_VENDOR_ATTR_NDP_SCID] = { + .type = NLA_BINARY, + .len = NDP_SCID_BUF_LEN + }, + [QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE] = { + .type = NLA_BINARY, + .len = NAN_PASSPHRASE_MAX_LEN + }, + [QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME] = { + .type = NLA_BINARY, + .len = NAN_MAX_SERVICE_NAME_LEN + }, + [QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO] = { + .type = NLA_BINARY, + .len = NAN_CH_INFO_MAX_LEN + }, + [QCA_WLAN_VENDOR_ATTR_NDP_NSS] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR] = { + .type = NLA_UNSPEC, + .len = QDF_IPV6_ADDR_SIZE + }, + [QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PORT] = { + .type = NLA_U16, + .len = sizeof(uint16_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL] = { + .type = NLA_U8, + .len = sizeof(uint8_t) + }, +}; + +static int os_if_nan_process_ndi_create(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + int ret; + char *iface_name; + QDF_STATUS status; + uint16_t transaction_id; + struct wlan_objmgr_vdev *nan_vdev; + struct nan_callbacks cb_obj; + + cfg80211_debug("enter"); + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { + cfg80211_err("Interface name string is unavailable"); + return -EINVAL; + } + iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); + + nan_vdev = wlan_util_get_vdev_by_ifname(psoc, iface_name, WLAN_NAN_ID); + if (nan_vdev) { + cfg80211_err("NAN data interface %s is already present", + iface_name); + wlan_objmgr_vdev_release_ref(nan_vdev, WLAN_NAN_ID); + return -EEXIST; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + cfg80211_err("transaction id is unavailable"); + return -EINVAL; + } + transaction_id = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + cfg80211_err("Couldn't get ballback object"); + return -EINVAL; + } + + ret = cb_obj.ndi_open(iface_name); + if (ret) { + cfg80211_err("ndi_open failed"); + return ret; + } + + return cb_obj.ndi_start(iface_name, transaction_id); +} + +static void os_if_nan_vdev_delete_peer(struct wlan_objmgr_psoc *psoc, + void *peer, void *nan_vdev) +{ + /* if peer belongs to nan vdev */ + if (nan_vdev == wlan_peer_get_vdev(peer)) { + cfg80211_debug("deleting peer: %pM", + wlan_peer_get_macaddr(peer)); + wlan_objmgr_peer_obj_delete(peer); + } +} + +static int os_if_nan_process_ndi_delete(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + uint8_t vdev_id; + char *iface_name; + QDF_STATUS status; + uint32_t num_peers; + uint16_t transaction_id; + struct nan_callbacks cb_obj; + struct wlan_objmgr_vdev *nan_vdev = NULL; + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { + cfg80211_err("Interface name string is unavailable"); + return -EINVAL; + } + + iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + cfg80211_err("Transaction id is unavailable"); + return -EINVAL; + } + + nan_vdev = wlan_util_get_vdev_by_ifname(psoc, iface_name, WLAN_NAN_ID); + if (!nan_vdev) { + cfg80211_err("Nan datapath interface is not present"); + return -EINVAL; + } + + transaction_id = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + vdev_id = wlan_vdev_get_id(nan_vdev); + num_peers = ucfg_nan_get_active_peers(nan_vdev); + + /* delete all peer for this interface first */ + wlan_objmgr_iterate_obj_list(psoc, WLAN_PEER_OP, + os_if_nan_vdev_delete_peer, + nan_vdev, 1, WLAN_NAN_ID); + + /* + * wlan_util_get_vdev_by_ifname increments ref count + * decrement here since vdev returned by that api is not used any more + */ + wlan_objmgr_vdev_release_ref(nan_vdev, WLAN_NAN_ID); + + /* check if there are active peers on the adapter */ + if (num_peers) + cfg80211_err("NDP peers active: %d, active NDPs may not be terminated", + num_peers); + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + cfg80211_err("Couldn't get ballback object"); + return -EINVAL; + } + + return cb_obj.ndi_delete(vdev_id, iface_name, transaction_id); +} + +/** + * os_if_nan_parse_security_params() - parse vendor attributes for security + * params. + * @tb: parsed NL attribute list + * @ncs_sk_type: out parameter to populate ncs_sk_type + * @pmk: out parameter to populate pmk + * @passphrase: out parameter to populate passphrase + * @service_name: out parameter to populate service_name + * + * Return: 0 on success or error code on failure + */ +static int os_if_nan_parse_security_params(struct nlattr **tb, + uint32_t *ncs_sk_type, struct nan_datapath_pmk *pmk, + struct ndp_passphrase *passphrase, + struct ndp_service_name *service_name) +{ + if (!ncs_sk_type || !pmk || !passphrase || !service_name) { + cfg80211_err("out buffers for one ore more parameters is null"); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_CSID]) { + *ncs_sk_type = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_CSID]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_PMK]) { + pmk->pmk_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_PMK]); + qdf_mem_copy(pmk->pmk, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_PMK]), + pmk->pmk_len); + cfg80211_err("pmk len: %d", pmk->pmk_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + pmk->pmk, pmk->pmk_len); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE]) { + passphrase->passphrase_len = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE]); + qdf_mem_copy(passphrase->passphrase, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE]), + passphrase->passphrase_len); + cfg80211_err("passphrase len: %d", passphrase->passphrase_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + passphrase->passphrase, + passphrase->passphrase_len); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME]) { + service_name->service_name_len = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME]); + qdf_mem_copy(service_name->service_name, + nla_data( + tb[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME]), + service_name->service_name_len); + cfg80211_err("service_name len: %d", + service_name->service_name_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + service_name->service_name, + service_name->service_name_len); + } + + return 0; +} + +/** + * os_if_nan_process_ndp_initiator_req() - NDP initiator request handler + * @ctx: hdd context + * @tb: parsed NL attribute list + * + * tb will contain following vendor attributes: + * QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID + * QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL - optional + * QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG + * QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID + * QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR + * QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO - optional + * QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS - optional + * QCA_WLAN_VENDOR_ATTR_NDP_PMK - optional + * QCA_WLAN_VENDOR_ATTR_NDP_CSID - optional + * QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE - optional + * QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME - optional + * + * Return: 0 on success or error code on failure + */ +static int os_if_nan_process_ndp_initiator_req(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + int ret = 0; + char *iface_name; + QDF_STATUS status; + enum nan_datapath_state state; + struct wlan_objmgr_vdev *nan_vdev; + struct nan_datapath_initiator_req req = {0}; + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { + cfg80211_err("Interface name string is unavailable"); + return -EINVAL; + } + + iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); + nan_vdev = wlan_util_get_vdev_by_ifname(psoc, iface_name, WLAN_NAN_ID); + if (!nan_vdev) { + cfg80211_err("NAN data interface %s not available", iface_name); + return -EINVAL; + } + + if (nan_vdev->vdev_mlme.vdev_opmode != QDF_NDI_MODE) { + cfg80211_err("Interface found is not NDI"); + ret = -EINVAL; + goto initiator_req_failed; + } + + state = ucfg_nan_get_ndi_state(nan_vdev); + if (state == NAN_DATA_NDI_DELETED_STATE || + state == NAN_DATA_NDI_DELETING_STATE || + state == NAN_DATA_NDI_CREATING_STATE) { + cfg80211_err("Data request not allowed in NDI current state: %d", + state); + ret = -EINVAL; + goto initiator_req_failed; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + cfg80211_err("Transaction ID is unavailable"); + ret = -EINVAL; + goto initiator_req_failed; + } + req.transaction_id = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL]) { + req.channel = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL]); + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG]) { + req.channel_cfg = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG]); + } else { + cfg80211_err("Channel config is unavailable"); + ret = -EINVAL; + goto initiator_req_failed; + } + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID]) { + cfg80211_err("NDP service instance ID is unavailable"); + ret = -EINVAL; + goto initiator_req_failed; + } + req.service_instance_id = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID]); + + qdf_mem_copy(req.self_ndi_mac_addr.bytes, + wlan_vdev_mlme_get_macaddr(nan_vdev), QDF_MAC_ADDR_SIZE); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR]) { + cfg80211_err("NDI peer discovery mac addr is unavailable"); + ret = -EINVAL; + goto initiator_req_failed; + } + qdf_mem_copy(req.peer_discovery_mac_addr.bytes, + nla_data( + tb[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR]), + QDF_MAC_ADDR_SIZE); + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]) { + req.ndp_info.ndp_app_info_len = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]); + qdf_mem_copy(req.ndp_info.ndp_app_info, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]), + req.ndp_info.ndp_app_info_len); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS]) { + /* at present ndp config stores 4 bytes QOS info only */ + req.ndp_config.ndp_cfg_len = 4; + *((uint32_t *)req.ndp_config.ndp_cfg) = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR]) { + req.is_ipv6_addr_present = true; + qdf_mem_copy(req.ipv6_addr, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR]), + QDF_IPV6_ADDR_SIZE); + } + cfg80211_debug("ipv6 addr present: %d, addr: %pI6", + req.is_ipv6_addr_present, req.ipv6_addr); + + if (os_if_nan_parse_security_params(tb, &req.ncs_sk_type, &req.pmk, + &req.passphrase, + &req.service_name)) { + cfg80211_err("inconsistent security params in request."); + ret = -EINVAL; + goto initiator_req_failed; + } + + cfg80211_debug("vdev_id: %d, transaction_id: %d, channel: %d, service_instance_id: %d, ndp_app_info_len: %d, csid: %d, peer_discovery_mac_addr: %pM", + wlan_vdev_get_id(nan_vdev), req.transaction_id, + req.channel, req.service_instance_id, + req.ndp_info.ndp_app_info_len, req.ncs_sk_type, + req.peer_discovery_mac_addr.bytes); + + req.vdev = nan_vdev; + status = ucfg_nan_req_processor(nan_vdev, &req, NDP_INITIATOR_REQ); + ret = qdf_status_to_os_return(status); +initiator_req_failed: + if (ret) + wlan_objmgr_vdev_release_ref(nan_vdev, WLAN_NAN_ID); + + return ret; +} + +/** + * os_if_nan_process_ndp_responder_req() - NDP responder request handler + * @nan_ctx: hdd context + * @tb: parsed NL attribute list + * + * tb includes following vendor attributes: + * QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID + * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID + * QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE + * QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO - optional + * QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS - optional + * QCA_WLAN_VENDOR_ATTR_NDP_PMK - optional + * QCA_WLAN_VENDOR_ATTR_NDP_CSID - optional + * QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE - optional + * QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME - optional + * + * Return: 0 on success or error code on failure + */ +static int os_if_nan_process_ndp_responder_req(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + int ret = 0; + char *iface_name; + QDF_STATUS status; + enum nan_datapath_state state; + struct wlan_objmgr_vdev *nan_vdev = NULL; + struct nan_datapath_responder_req req = {0}; + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE]) { + cfg80211_err("ndp_rsp is unavailable"); + return -EINVAL; + } + req.ndp_rsp = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE]); + + if (req.ndp_rsp == NAN_DATAPATH_RESPONSE_ACCEPT) { + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { + cfg80211_err("Interface not provided"); + return -ENODEV; + } + iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); + + /* Check for an existing NAN interface */ + nan_vdev = wlan_util_get_vdev_by_ifname(psoc, iface_name, + WLAN_NAN_ID); + if (!nan_vdev) { + cfg80211_err("NAN data iface %s not available", + iface_name); + return -ENODEV; + } + + if (nan_vdev->vdev_mlme.vdev_opmode != QDF_NDI_MODE) { + cfg80211_err("Interface found is not NDI"); + ret = -ENODEV; + goto responder_req_failed; + } + } else { + /* + * If the data indication is rejected, the userspace + * may not send the iface name. Use the first NDI + * in that case + */ + cfg80211_debug("ndp rsp rejected, using first NDI"); + + nan_vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc( + psoc, QDF_NDI_MODE, WLAN_NAN_ID); + if (!nan_vdev) { + cfg80211_err("NAN data iface is not available"); + return -ENODEV; + } + } + + state = ucfg_nan_get_ndi_state(nan_vdev); + if (state == NAN_DATA_NDI_DELETED_STATE || + state == NAN_DATA_NDI_DELETING_STATE || + state == NAN_DATA_NDI_CREATING_STATE) { + cfg80211_err("Data request not allowed in current NDI state:%d", + state); + ret = -EAGAIN; + goto responder_req_failed; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + cfg80211_err("Transaction ID is unavailable"); + ret = -EINVAL; + goto responder_req_failed; + } + req.transaction_id = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID]) { + cfg80211_err("Instance ID is unavailable"); + ret = -EINVAL; + goto responder_req_failed; + } + req.ndp_instance_id = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID]); + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]) { + req.ndp_info.ndp_app_info_len = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]); + qdf_mem_copy(req.ndp_info.ndp_app_info, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]), + req.ndp_info.ndp_app_info_len); + } else { + cfg80211_debug("NDP app info is unavailable"); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS]) { + /* at present ndp config stores 4 bytes QOS info only */ + req.ndp_config.ndp_cfg_len = 4; + *((uint32_t *)req.ndp_config.ndp_cfg) = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS]); + } else { + cfg80211_debug("NDP config data is unavailable"); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR]) { + req.is_ipv6_addr_present = true; + qdf_mem_copy(req.ipv6_addr, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR]), + QDF_IPV6_ADDR_SIZE); + } + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PORT]) { + req.is_port_present = true; + req.port = nla_get_u16( + tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PORT]); + } + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL]) { + req.is_protocol_present = true; + req.protocol = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL]); + } + cfg80211_debug("ipv6 addr present: %d, addr: %pI6", + req.is_ipv6_addr_present, req.ipv6_addr); + cfg80211_debug("port %d, present: %d", req.port, req.is_port_present); + cfg80211_debug("protocol %d, present: %d", + req.protocol, req.is_protocol_present); + + if (os_if_nan_parse_security_params(tb, &req.ncs_sk_type, &req.pmk, + &req.passphrase, &req.service_name)) { + cfg80211_err("inconsistent security params in request."); + ret = -EINVAL; + goto responder_req_failed; + } + + cfg80211_debug("vdev_id: %d, transaction_id: %d, ndp_rsp %d, ndp_instance_id: %d, ndp_app_info_len: %d, csid: %d", + wlan_vdev_get_id(nan_vdev), req.transaction_id, req.ndp_rsp, + req.ndp_instance_id, req.ndp_info.ndp_app_info_len, + req.ncs_sk_type); + + req.vdev = nan_vdev; + status = ucfg_nan_req_processor(nan_vdev, &req, NDP_RESPONDER_REQ); + ret = qdf_status_to_os_return(status); + +responder_req_failed: + if (ret) + wlan_objmgr_vdev_release_ref(nan_vdev, WLAN_NAN_ID); + + return ret; + +} + +/** + * os_if_nan_process_ndp_end_req() - NDP end request handler + * @psoc: pointer to psoc object + * + * @tb: parsed NL attribute list + * tb includes following vendor attributes: + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID + * + * Return: 0 on success or error code on failure + */ +static int os_if_nan_process_ndp_end_req(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + int ret = 0; + QDF_STATUS status; + struct wlan_objmgr_vdev *nan_vdev; + struct nan_datapath_end_req req = {0}; + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + cfg80211_err("Transaction ID is unavailable"); + return -EINVAL; + } + req.transaction_id = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY]) { + cfg80211_err("NDP instance ID array is unavailable"); + return -EINVAL; + } + + req.num_ndp_instances = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY]) / + sizeof(uint32_t); + if (0 >= req.num_ndp_instances) { + cfg80211_err("Num NDP instances is 0"); + return -EINVAL; + } + qdf_mem_copy(req.ndp_ids, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY]), + req.num_ndp_instances * sizeof(uint32_t)); + + cfg80211_debug("sending ndp_end_req to SME, transaction_id: %d", + req.transaction_id); + + nan_vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc(psoc, QDF_NDI_MODE, + WLAN_NAN_ID); + if (!nan_vdev) { + cfg80211_err("NAN data interface is not available"); + return -EINVAL; + } + + req.vdev = nan_vdev; + status = ucfg_nan_req_processor(nan_vdev, &req, NDP_END_REQ); + ret = qdf_status_to_os_return(status); + if (ret) + wlan_objmgr_vdev_release_ref(nan_vdev, WLAN_NAN_ID); + + return ret; +} + +int os_if_nan_process_ndp_cmd(struct wlan_objmgr_psoc *psoc, + const void *data, int data_len) +{ + uint32_t ndp_cmd_type; + uint16_t transaction_id; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX + 1]; + char *iface_name; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX, + data, data_len, vendor_attr_policy)) { + cfg80211_err("Invalid NDP vendor command attributes"); + return -EINVAL; + } + + /* Parse and fetch NDP Command Type*/ + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD]) { + cfg80211_err("NAN datapath cmd type failed"); + return -EINVAL; + } + ndp_cmd_type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + cfg80211_err("attr transaction id failed"); + return -EINVAL; + } + transaction_id = nla_get_u16( + tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { + iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); + cfg80211_err("Transaction Id: %d NDPCmd: %d iface_name: %s", + transaction_id, ndp_cmd_type, iface_name); + } else { + cfg80211_err("Transaction Id: %d NDPCmd: %d iface_name: unspecified", + transaction_id, ndp_cmd_type); + } + + cfg80211_debug("Received NDP cmd: %d", ndp_cmd_type); + switch (ndp_cmd_type) { + case QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE: + return os_if_nan_process_ndi_create(psoc, tb); + case QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE: + return os_if_nan_process_ndi_delete(psoc, tb); + case QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_REQUEST: + return os_if_nan_process_ndp_initiator_req(psoc, tb); + case QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_REQUEST: + return os_if_nan_process_ndp_responder_req(psoc, tb); + case QCA_WLAN_VENDOR_ATTR_NDP_END_REQUEST: + return os_if_nan_process_ndp_end_req(psoc, tb); + default: + cfg80211_err("Unrecognized NDP vendor cmd %d", ndp_cmd_type); + return -EINVAL; + } + + return -EINVAL; +} + +static inline uint32_t osif_ndp_get_ndp_initiator_rsp_len(void) +{ + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE].len); + + return data_len; +} + +/** + * os_if_ndp_initiator_rsp_handler() - NDP initiator response handler + * @vdev: pointer to vdev object + * @rsp_params: response parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_RESPONSE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID (2 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE (4 bytes) + * + * Return: none + */ +static void os_if_ndp_initiator_rsp_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_initiator_rsp *rsp) +{ + uint32_t data_len; + struct sk_buff *vendor_event; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + + if (!rsp) { + cfg80211_err("Invalid NDP Initator response"); + return; + } + + data_len = osif_ndp_get_ndp_initiator_rsp_len(); + vendor_event = cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, + data_len, QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_ATOMIC); + if (!vendor_event) { + cfg80211_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_RESPONSE)) + goto ndp_initiator_rsp_nla_failed; + + if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + rsp->transaction_id)) + goto ndp_initiator_rsp_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID, + rsp->ndp_instance_id)) + goto ndp_initiator_rsp_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + rsp->status)) + goto ndp_initiator_rsp_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + rsp->reason)) + goto ndp_initiator_rsp_nla_failed; + + cfg80211_debug("NDP Initiator rsp sent, tid:%d, instance id:%d, status:%d, reason: %d", + rsp->transaction_id, rsp->ndp_instance_id, rsp->status, + rsp->reason); + cfg80211_vendor_event(vendor_event, GFP_ATOMIC); + return; +ndp_initiator_rsp_nla_failed: + cfg80211_err("nla_put api failed"); + kfree_skb(vendor_event); +} + +static inline uint32_t osif_ndp_get_ndp_responder_rsp_len(void) +{ + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE].len); + + return data_len; +} + +/* + * os_if_ndp_responder_rsp_handler() - NDP responder response handler + * @vdev: pointer to vdev object + * @rsp: response parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_RESPONSE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID (2 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE (4 bytes) + * + * Return: none + */ +static void os_if_ndp_responder_rsp_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_responder_rsp *rsp) +{ + uint16_t data_len; + struct sk_buff *vendor_event; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + + if (!rsp) { + cfg80211_err("Invalid NDP Responder response"); + return; + } + + cfg80211_debug("NDP Responder,vdev id %d transaction_id %d status code: %d reason %d", + wlan_vdev_get_id(rsp->vdev), rsp->transaction_id, + rsp->status, rsp->reason); + data_len = osif_ndp_get_ndp_responder_rsp_len(); + vendor_event = cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, + data_len, QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_ATOMIC); + if (!vendor_event) { + cfg80211_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_RESPONSE)) + goto ndp_responder_rsp_nla_failed; + + if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + rsp->transaction_id)) + goto ndp_responder_rsp_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + rsp->status)) + goto ndp_responder_rsp_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + rsp->reason)) + goto ndp_responder_rsp_nla_failed; + + cfg80211_vendor_event(vendor_event, GFP_ATOMIC); + return; +ndp_responder_rsp_nla_failed: + cfg80211_err("nla_put api failed"); + kfree_skb(vendor_event); +} + +static inline uint32_t osif_ndp_get_ndp_req_ind_len( + struct nan_datapath_indication_event *event) +{ + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_CSID].len); + /* allocate space including NULL terminator */ + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR].len + 1); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR].len); + if (event->is_ipv6_addr_present) + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR].len); + if (event->scid.scid_len) + data_len += nla_total_size(event->scid.scid_len); + if (event->ndp_info.ndp_app_info_len) + data_len += nla_total_size(event->ndp_info.ndp_app_info_len); + + return data_len; +} + +/** + * os_if_ndp_indication_handler() - NDP indication handler + * @vdev: pointer to vdev object + * @ind_params: indication parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_REQUEST_IND (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR (IFNAMSIZ) + * QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR (6 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR (6 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO (ndp_app_info_len size) + * QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_CSID(4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_SCID(scid_len in size) + * QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR (16 bytes) + * + * Return: none + */ +static void os_if_ndp_indication_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_indication_event *event) +{ + uint8_t *ifname; + uint16_t data_len; + qdf_size_t ifname_len; + uint32_t ndp_qos_config; + struct sk_buff *vendor_event; + enum nan_datapath_state state; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + + if (!event) { + cfg80211_err("Invalid NDP Indication"); + return; + } + + cfg80211_debug("NDP Indication, policy: %d", event->policy); + state = ucfg_nan_get_ndi_state(vdev); + /* check if we are in middle of deleting/creating the interface */ + + if (state == NAN_DATA_NDI_DELETED_STATE || + state == NAN_DATA_NDI_DELETING_STATE || + state == NAN_DATA_NDI_CREATING_STATE) { + cfg80211_err("Data request not allowed in current NDI state: %d", + state); + return; + } + + ifname = wlan_util_vdev_get_if_name(vdev); + if (!ifname) { + cfg80211_err("ifname is null"); + return; + } + ifname_len = qdf_str_len(ifname); + if (ifname_len > IFNAMSIZ) { + cfg80211_err("ifname(%zu) too long", ifname_len); + return; + } + + data_len = osif_ndp_get_ndp_req_ind_len(event); + /* notify response to the upper layer */ + vendor_event = cfg80211_vendor_event_alloc(os_priv->wiphy, + NULL, data_len, + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_ATOMIC); + if (!vendor_event) { + cfg80211_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_REQUEST_IND)) + goto ndp_indication_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, + ifname_len, ifname)) + goto ndp_indication_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID, + event->service_instance_id)) + goto ndp_indication_nla_failed; + + if (nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR, + QDF_MAC_ADDR_SIZE, event->peer_mac_addr.bytes)) + goto ndp_indication_nla_failed; + + if (nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR, + QDF_MAC_ADDR_SIZE, event->peer_discovery_mac_addr.bytes)) + goto ndp_indication_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID, + event->ndp_instance_id)) + goto ndp_indication_nla_failed; + + if (event->ndp_info.ndp_app_info_len) + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO, + event->ndp_info.ndp_app_info_len, + event->ndp_info.ndp_app_info)) + goto ndp_indication_nla_failed; + + if (event->ndp_config.ndp_cfg_len) { + ndp_qos_config = *((uint32_t *)event->ndp_config.ndp_cfg); + /* at present ndp config stores 4 bytes QOS info only */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS, + ndp_qos_config)) + goto ndp_indication_nla_failed; + } + + if (event->scid.scid_len) { + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_CSID, + event->ncs_sk_type)) + goto ndp_indication_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SCID, + event->scid.scid_len, + event->scid.scid)) + goto ndp_indication_nla_failed; + + cfg80211_debug("csid: %d, scid_len: %d", + event->ncs_sk_type, event->scid.scid_len); + + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + event->scid.scid, event->scid.scid_len); + } + + if (event->is_ipv6_addr_present) { + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR, + QDF_IPV6_ADDR_SIZE, event->ipv6_addr)) + goto ndp_indication_nla_failed; + } + cfg80211_debug("ipv6 addr present: %d, addr: %pI6", + event->is_ipv6_addr_present, event->ipv6_addr); + + cfg80211_vendor_event(vendor_event, GFP_ATOMIC); + return; +ndp_indication_nla_failed: + cfg80211_err("nla_put api failed"); + kfree_skb(vendor_event); +} + +static inline uint32_t osif_ndp_get_ndp_confirm_ind_len( + struct nan_datapath_confirm_event *ndp_confirm) +{ + uint32_t ch_info_len = 0; + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR].len); + /* allocate space including NULL terminator */ + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR].len + 1); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE].len); + if (ndp_confirm->ndp_info.ndp_app_info_len) + data_len += + nla_total_size(ndp_confirm->ndp_info.ndp_app_info_len); + + if (ndp_confirm->is_ipv6_addr_present) + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR].len); + if (ndp_confirm->is_port_present) + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PORT].len); + if (ndp_confirm->is_protocol_present) + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL].len); + + /* ch_info is a nested array of following attributes */ + ch_info_len += nla_total_size( + vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL].len); + ch_info_len += nla_total_size( + vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH].len); + ch_info_len += nla_total_size( + vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_NDP_NSS].len); + + if (ndp_confirm->num_channels) + data_len += ndp_confirm->num_channels * + nla_total_size(ch_info_len); + + return data_len; +} + +static QDF_STATUS os_if_ndp_confirm_pack_ch_info(struct sk_buff *event, + struct nan_datapath_confirm_event *ndp_confirm) +{ + int idx = 0; + struct nlattr *ch_array, *ch_element; + + cfg80211_debug("num_ch: %d", ndp_confirm->num_channels); + if (!ndp_confirm->num_channels) + return QDF_STATUS_SUCCESS; + + ch_array = nla_nest_start(event, QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO); + if (!ch_array) + return QDF_STATUS_E_FAULT; + + for (idx = 0; idx < ndp_confirm->num_channels; idx++) { + cfg80211_debug("ch[%d]: freq: %d, width: %d, nss: %d", + idx, ndp_confirm->ch[idx].channel, + ndp_confirm->ch[idx].ch_width, + ndp_confirm->ch[idx].nss); + ch_element = nla_nest_start(event, idx); + if (!ch_element) + return QDF_STATUS_E_FAULT; + + if (nla_put_u32(event, QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL, + ndp_confirm->ch[idx].channel)) + return QDF_STATUS_E_FAULT; + + if (nla_put_u32(event, QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH, + ndp_confirm->ch[idx].ch_width)) + return QDF_STATUS_E_FAULT; + + if (nla_put_u32(event, QCA_WLAN_VENDOR_ATTR_NDP_NSS, + ndp_confirm->ch[idx].nss)) + return QDF_STATUS_E_FAULT; + nla_nest_end(event, ch_element); + } + nla_nest_end(event, ch_array); + + return QDF_STATUS_SUCCESS; +} + +/** + * os_if_ndp_confirm_ind_handler() - NDP confirm indication handler + * @vdev: pointer to vdev object + * @ind_params: indication parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_CONFIRM_IND (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR (6 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR (IFNAMSIZ) + * QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO (ndp_app_info_len size) + * QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR (16 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PORT (2 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL (1 byte) + * + * Return: none + */ +static void +os_if_ndp_confirm_ind_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_confirm_event *ndp_confirm) +{ + int idx = 0; + uint8_t *ifname; + uint32_t data_len; + QDF_STATUS status; + qdf_size_t ifname_len; + struct nan_callbacks cb_obj; + struct sk_buff *vendor_event; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + + if (!ndp_confirm) { + cfg80211_err("Invalid NDP Initator response"); + return; + } + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + cfg80211_err("couldn't get callbacks"); + return; + } + + /* ndp_confirm is called each time user generated ndp req succeeds */ + idx = cb_obj.get_peer_idx(wlan_vdev_get_id(vdev), + &ndp_confirm->peer_ndi_mac_addr); + + if (idx < 0) + cfg80211_err("can't find addr: %pM in vdev_id: %d, peer table.", + &ndp_confirm->peer_ndi_mac_addr, + wlan_vdev_get_id(vdev)); + else if (ndp_confirm->rsp_code == NAN_DATAPATH_RESPONSE_ACCEPT) { + uint32_t active_sessions = + ucfg_nan_get_active_ndp_sessions(vdev, idx); + ucfg_nan_set_active_ndp_sessions(vdev, active_sessions + 1, + idx); + } + + ifname = wlan_util_vdev_get_if_name(vdev); + if (!ifname) { + cfg80211_err("ifname is null"); + return; + } + ifname_len = qdf_str_len(ifname); + if (ifname_len > IFNAMSIZ) { + cfg80211_err("ifname(%zu) too long", ifname_len); + return; + } + + data_len = osif_ndp_get_ndp_confirm_ind_len(ndp_confirm); + vendor_event = cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, + data_len, QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_ATOMIC); + if (!vendor_event) { + cfg80211_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_CONFIRM_IND)) + goto ndp_confirm_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID, + ndp_confirm->ndp_instance_id)) + goto ndp_confirm_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR, + QDF_MAC_ADDR_SIZE, ndp_confirm->peer_ndi_mac_addr.bytes)) + goto ndp_confirm_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, + ifname_len, ifname)) + goto ndp_confirm_nla_failed; + + if (ndp_confirm->ndp_info.ndp_app_info_len && + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO, + ndp_confirm->ndp_info.ndp_app_info_len, + ndp_confirm->ndp_info.ndp_app_info)) + goto ndp_confirm_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE, + ndp_confirm->rsp_code)) + goto ndp_confirm_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + ndp_confirm->reason_code)) + goto ndp_confirm_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_NUM_CHANNELS, + ndp_confirm->num_channels)) + goto ndp_confirm_nla_failed; + + status = os_if_ndp_confirm_pack_ch_info(vendor_event, ndp_confirm); + if (QDF_IS_STATUS_ERROR(status)) + goto ndp_confirm_nla_failed; + + if (ndp_confirm->is_ipv6_addr_present) { + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR, + QDF_IPV6_ADDR_SIZE, ndp_confirm->ipv6_addr)) + goto ndp_confirm_nla_failed; + } + if (ndp_confirm->is_port_present) + if (nla_put_u16(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PORT, + ndp_confirm->port)) + goto ndp_confirm_nla_failed; + if (ndp_confirm->is_protocol_present) + if (nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL, + ndp_confirm->protocol)) + goto ndp_confirm_nla_failed; + cfg80211_debug("ipv6 addr present: %d, addr: %pI6", + ndp_confirm->is_ipv6_addr_present, + ndp_confirm->ipv6_addr); + cfg80211_debug("port %d, present: %d", + ndp_confirm->port, ndp_confirm->is_port_present); + cfg80211_debug("protocol %d, present: %d", + ndp_confirm->protocol, ndp_confirm->is_protocol_present); + + cfg80211_vendor_event(vendor_event, GFP_ATOMIC); + cfg80211_debug("NDP confim sent, ndp instance id: %d, peer addr: %pM rsp_code: %d, reason_code: %d", + ndp_confirm->ndp_instance_id, + ndp_confirm->peer_ndi_mac_addr.bytes, + ndp_confirm->rsp_code, ndp_confirm->reason_code); + + cfg80211_debug("NDP confim, ndp app info dump"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + ndp_confirm->ndp_info.ndp_app_info, + ndp_confirm->ndp_info.ndp_app_info_len); + return; +ndp_confirm_nla_failed: + cfg80211_err("nla_put api failed"); + kfree_skb(vendor_event); +} + +static inline uint32_t osif_ndp_get_ndp_end_rsp_len(void) +{ + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID].len); + + return data_len; +} + +/** + * os_if_ndp_end_rsp_handler() - NDP end response handler + * @vdev: pointer to vdev object + * @rsp_params: response parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_END_RESPONSE(4 bytest) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID (2 bytes) + * + * Return: none + */ +static void os_if_ndp_end_rsp_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_end_rsp_event *rsp) +{ + uint32_t data_len; + struct sk_buff *vendor_event; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + + if (!rsp) { + cfg80211_err("Invalid ndp end response"); + return; + } + + data_len = osif_ndp_get_ndp_end_rsp_len(); + vendor_event = cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, + data_len, QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_ATOMIC); + if (!vendor_event) { + cfg80211_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_END_RESPONSE)) + goto ndp_end_rsp_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + rsp->status)) + goto ndp_end_rsp_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + rsp->reason)) + goto ndp_end_rsp_nla_failed; + + if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + rsp->transaction_id)) + goto ndp_end_rsp_nla_failed; + + cfg80211_debug("NDP End rsp sent, transaction id: %d, status: %d, reason: %d", + rsp->transaction_id, rsp->status, rsp->reason); + cfg80211_vendor_event(vendor_event, GFP_ATOMIC); + return; + +ndp_end_rsp_nla_failed: + cfg80211_err("nla_put api failed"); + kfree_skb(vendor_event); +} + +static inline uint32_t osif_ndp_get_ndp_end_ind_len( + struct nan_datapath_end_indication_event *end_ind) +{ + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + if (end_ind->num_ndp_ids) + data_len += nla_total_size(end_ind->num_ndp_ids * + sizeof(uint32_t)); + + return data_len; +} + +/** + * os_if_ndp_end_ind_handler() - NDP end indication handler + * @vdev: pointer to vdev object + * @ind_params: indication parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_END_IND (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY (4 * num of NDP Instances) + * + * Return: none + */ +static void os_if_ndp_end_ind_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_end_indication_event *end_ind) +{ + QDF_STATUS status; + uint32_t data_len, i; + struct nan_callbacks cb_obj; + uint32_t *ndp_instance_array; + struct sk_buff *vendor_event; + struct wlan_objmgr_vdev *vdev_itr; + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + cfg80211_err("failed to get callbacks"); + return; + } + + if (!end_ind) { + cfg80211_err("Invalid ndp end indication"); + return; + } + + ndp_instance_array = qdf_mem_malloc(end_ind->num_ndp_ids * + sizeof(*ndp_instance_array)); + if (!ndp_instance_array) { + cfg80211_err("Failed to allocate ndp_instance_array"); + return; + } + for (i = 0; i < end_ind->num_ndp_ids; i++) { + int idx = 0; + + ndp_instance_array[i] = end_ind->ndp_map[i].ndp_instance_id; + vdev_itr = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + end_ind->ndp_map[i].vdev_id, WLAN_NAN_ID); + + if (vdev_itr == NULL) { + cfg80211_err("vdev not found for vdev_id: %d", + end_ind->ndp_map[i].vdev_id); + continue; + } + + idx = cb_obj.get_peer_idx(wlan_vdev_get_id(vdev_itr), + &end_ind->ndp_map[i].peer_ndi_mac_addr); + if (idx < 0) { + cfg80211_err("can't find addr: %pM in sta_ctx.", + &end_ind->ndp_map[i].peer_ndi_mac_addr); + wlan_objmgr_vdev_release_ref(vdev_itr, WLAN_NAN_ID); + continue; + } + /* save the value of active sessions on each peer */ + ucfg_nan_set_active_ndp_sessions(vdev_itr, + end_ind->ndp_map[i].num_active_ndp_sessions, + idx); + wlan_objmgr_vdev_release_ref(vdev_itr, WLAN_NAN_ID); + } + + data_len = osif_ndp_get_ndp_end_ind_len(end_ind); + vendor_event = cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, + data_len, QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_ATOMIC); + if (!vendor_event) { + cfg80211_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_END_IND)) + goto ndp_end_ind_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY, + end_ind->num_ndp_ids * sizeof(*ndp_instance_array), + ndp_instance_array)) + goto ndp_end_ind_nla_failed; + + cfg80211_vendor_event(vendor_event, GFP_ATOMIC); + qdf_mem_free(ndp_instance_array); + return; + +ndp_end_ind_nla_failed: + cfg80211_err("nla_put api failed"); + kfree_skb(vendor_event); + qdf_mem_free(ndp_instance_array); +} + +/** + * os_if_new_peer_ind_handler() - NDP new peer indication handler + * @adapter: pointer to adapter context + * @ind_params: indication parameters + * + * Return: none + */ +static void os_if_new_peer_ind_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_peer_ind *peer_ind) +{ + int ret; + QDF_STATUS status; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + uint32_t active_peers = ucfg_nan_get_active_peers(vdev); + struct nan_callbacks cb_obj; + + if (NULL == peer_ind) { + cfg80211_err("Invalid new NDP peer params"); + return; + } + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + cfg80211_err("failed to get callbacks"); + return; + } + + cfg80211_debug("vdev_id: %d, peer_mac: %pM, sta_id: %d", + vdev_id, peer_ind->peer_mac_addr.bytes, + peer_ind->sta_id); + ret = cb_obj.new_peer_ind(vdev_id, peer_ind->sta_id, + &peer_ind->peer_mac_addr, + (active_peers == 0 ? true : false)); + if (ret) { + cfg80211_err("new peer handling at HDD failed %d", ret); + return; + } + + active_peers++; + ucfg_nan_set_active_peers(vdev, active_peers); + cfg80211_debug("vdev_id: %d, num_peers: %d", vdev_id, active_peers); +} + +/** + * os_if_peer_departed_ind_handler() - Handle NDP peer departed indication + * @adapter: pointer to adapter context + * @ind_params: indication parameters + * + * Return: none + */ +static void os_if_peer_departed_ind_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_peer_ind *peer_ind) +{ + QDF_STATUS status; + struct nan_callbacks cb_obj; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + uint32_t active_peers = ucfg_nan_get_active_peers(vdev); + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + cfg80211_err("failed to get callbacks"); + return; + } + + if (NULL == peer_ind) { + cfg80211_err("Invalid new NDP peer params"); + return; + } + cfg80211_debug("vdev_id: %d, peer_mac: %pM, sta_id: %d", + vdev_id, peer_ind->peer_mac_addr.bytes, + peer_ind->sta_id); + active_peers--; + ucfg_nan_set_active_peers(vdev, active_peers); + cb_obj.peer_departed_ind(vdev_id, peer_ind->sta_id, + &peer_ind->peer_mac_addr, + (active_peers == 0 ? true : false)); +} + +static inline uint32_t osif_ndp_get_ndi_create_rsp_len(void) +{ + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE].len); + + return data_len; +} + +/** + * os_if_ndp_iface_create_rsp_handler() - NDP iface create response handler + * @adapter: pointer to adapter context + * @rsp_params: response parameters + * + * The function is expected to send a response back to the user space + * even if the creation of BSS has failed + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID (2 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE + * + * Return: none + */ +static void os_if_ndp_iface_create_rsp_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + void *rsp_params) +{ + uint32_t data_len; + QDF_STATUS status; + bool create_fail = false; + struct nan_callbacks cb_obj; + struct sk_buff *vendor_event; + uint16_t create_transaction_id; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + uint32_t create_status = NAN_DATAPATH_RSP_STATUS_ERROR; + uint32_t create_reason = NAN_DATAPATH_NAN_DATA_IFACE_CREATE_FAILED; + struct nan_datapath_inf_create_rsp *ndi_rsp = + (struct nan_datapath_inf_create_rsp *)rsp_params; + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + cfg80211_err("Couldn't get ballback object"); + return; + } + + if (ndi_rsp) { + create_status = ndi_rsp->status; + create_reason = ndi_rsp->reason; + } else { + cfg80211_err("Invalid ndi create response"); + create_fail = true; + } + + create_transaction_id = ucfg_nan_get_ndp_create_transaction_id(vdev); + data_len = osif_ndp_get_ndi_create_rsp_len(); + /* notify response to the upper layer */ + vendor_event = cfg80211_vendor_event_alloc(os_priv->wiphy, + NULL, + data_len, + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_KERNEL); + if (!vendor_event) { + cfg80211_err("cfg80211_vendor_event_alloc failed"); + create_fail = true; + goto close_ndi; + } + + /* Sub vendor command */ + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE)) { + cfg80211_err("QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD put fail"); + goto nla_put_failure; + } + + /* Transaction id */ + if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + create_transaction_id)) { + cfg80211_err("VENDOR_ATTR_NDP_TRANSACTION_ID put fail"); + goto nla_put_failure; + } + + /* Status code */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + create_status)) { + cfg80211_err("VENDOR_ATTR_NDP_DRV_RETURN_TYPE put fail"); + goto nla_put_failure; + } + + /* Status return value */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + create_reason)) { + cfg80211_err("VENDOR_ATTR_NDP_DRV_RETURN_VALUE put fail"); + goto nla_put_failure; + } + + cfg80211_debug("sub command: %d, value: %d", + QCA_NL80211_VENDOR_SUBCMD_NDP, + QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE); + cfg80211_debug("create transaction id: %d, value: %d", + QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + create_transaction_id); + cfg80211_debug("status code: %d, value: %d", + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + create_status); + cfg80211_debug("Return value: %d, value: %d", + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + create_reason); + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + + if (!create_fail) { + /* update txrx queues and register self sta */ + cb_obj.drv_ndi_create_rsp_handler(wlan_vdev_get_id(vdev), + ndi_rsp); + } else { + cfg80211_err("NDI interface creation failed with reason %d", + create_reason); + goto close_ndi; + } + + return; + +nla_put_failure: + kfree_skb(vendor_event); +close_ndi: + cb_obj.ndi_close(wlan_vdev_get_id(vdev)); + return; +} + +/** + * os_if_ndp_iface_delete_rsp_handler() - NDP iface delete response handler + * @adapter: pointer to adapter context + * @rsp_params: response parameters + * + * Return: none + */ +static void os_if_ndp_iface_delete_rsp_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + void *rsp_params) +{ + QDF_STATUS status; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct nan_datapath_inf_delete_rsp *ndi_rsp = rsp_params; + struct nan_callbacks cb_obj; + + if (!ndi_rsp) { + cfg80211_err("Invalid ndi delete response"); + return; + } + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + cfg80211_err("Couldn't get ballback object"); + return; + } + + if (ndi_rsp->status == NAN_DATAPATH_RSP_STATUS_SUCCESS) + cfg80211_debug("NDI BSS successfully stopped"); + else + cfg80211_debug("NDI BSS stop failed with reason %d", + ndi_rsp->reason); + + ucfg_nan_set_ndi_delete_rsp_reason(vdev, ndi_rsp->reason); + ucfg_nan_set_ndi_delete_rsp_status(vdev, ndi_rsp->status); + cb_obj.drv_ndi_delete_rsp_handler(vdev_id); +} + +static inline uint32_t osif_ndp_get_ndp_sch_update_ind_len( + struct nan_datapath_sch_update_event *sch_update) +{ + uint32_t ch_info_len = 0; + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR].len); + if (sch_update->num_ndp_instances) + data_len += nla_total_size(sch_update->num_ndp_instances * + sizeof(uint32_t)); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_REASON].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_NUM_CHANNELS].len); + /* ch_info is a nested array of following attributes */ + ch_info_len += nla_total_size( + vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL].len); + ch_info_len += nla_total_size( + vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH].len); + ch_info_len += nla_total_size( + vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_NDP_NSS].len); + + if (sch_update->num_ndp_instances) + data_len += sch_update->num_ndp_instances * + nla_total_size(ch_info_len); + + return data_len; +} + +static QDF_STATUS os_if_ndp_sch_update_pack_ch_info(struct sk_buff *event, + struct nan_datapath_sch_update_event *sch_update) +{ + int idx = 0; + struct nlattr *ch_array, *ch_element; + + cfg80211_debug("num_ch: %d", sch_update->num_channels); + if (!sch_update->num_channels) + return QDF_STATUS_SUCCESS; + + ch_array = nla_nest_start(event, QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO); + if (!ch_array) + return QDF_STATUS_E_FAULT; + + for (idx = 0; idx < sch_update->num_channels; idx++) { + cfg80211_debug("ch[%d]: freq: %d, width: %d, nss: %d", + idx, sch_update->ch[idx].channel, + sch_update->ch[idx].ch_width, + sch_update->ch[idx].nss); + ch_element = nla_nest_start(event, idx); + if (!ch_element) + return QDF_STATUS_E_FAULT; + + if (nla_put_u32(event, QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL, + sch_update->ch[idx].channel)) + return QDF_STATUS_E_FAULT; + + if (nla_put_u32(event, QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH, + sch_update->ch[idx].ch_width)) + return QDF_STATUS_E_FAULT; + + if (nla_put_u32(event, QCA_WLAN_VENDOR_ATTR_NDP_NSS, + sch_update->ch[idx].nss)) + return QDF_STATUS_E_FAULT; + nla_nest_end(event, ch_element); + } + nla_nest_end(event, ch_array); + + return QDF_STATUS_SUCCESS; +} + +/** + * os_if_ndp_sch_update_ind_handler() - NDP schedule update handler + * @vdev: vdev object pointer + * @ind: sch update pointer + * + * Following vendor event is sent to cfg80211: + * + * Return: none + */ +static void os_if_ndp_sch_update_ind_handler(struct wlan_objmgr_vdev *vdev, + void *ind) +{ + int idx = 0; + uint8_t *ifname; + QDF_STATUS status; + uint32_t data_len; + uint8_t ifname_len; + struct sk_buff *vendor_event; + struct nan_datapath_sch_update_event *sch_update = ind; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + + if (!sch_update) { + cfg80211_err("Invalid sch update params"); + return; + } + + ifname = wlan_util_vdev_get_if_name(vdev); + if (!ifname) { + cfg80211_err("ifname is null"); + return; + } + ifname_len = qdf_str_len(ifname); + if (ifname_len > IFNAMSIZ) { + cfg80211_err("ifname(%d) too long", ifname_len); + return; + } + + data_len = osif_ndp_get_ndp_sch_update_ind_len(sch_update); + vendor_event = cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, + data_len, QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_ATOMIC); + if (!vendor_event) { + cfg80211_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_IND)) + goto ndp_sch_ind_nla_failed; + + if (nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR, + QDF_MAC_ADDR_SIZE, sch_update->peer_addr.bytes)) + goto ndp_sch_ind_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY, + sch_update->num_ndp_instances * sizeof(uint32_t), + sch_update->ndp_instances)) + goto ndp_sch_ind_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_REASON, + sch_update->flags)) + goto ndp_sch_ind_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_NUM_CHANNELS, + sch_update->num_channels)) + goto ndp_sch_ind_nla_failed; + + status = os_if_ndp_sch_update_pack_ch_info(vendor_event, sch_update); + if (QDF_IS_STATUS_ERROR(status)) + goto ndp_sch_ind_nla_failed; + + cfg80211_debug("Flags: %d, num_instance_id: %d", sch_update->flags, + sch_update->num_ndp_instances); + + for (idx = 0; idx < sch_update->num_ndp_instances; idx++) + cfg80211_debug("ndp_instance[%d]: %d", idx, + sch_update->ndp_instances[idx]); + + cfg80211_vendor_event(vendor_event, GFP_ATOMIC); + return; + +ndp_sch_ind_nla_failed: + cfg80211_err("nla_put api failed"); + kfree_skb(vendor_event); +} + +void os_if_nan_event_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t type, void *msg) +{ + switch (type) { + case NAN_DATAPATH_INF_CREATE_RSP: + os_if_ndp_iface_create_rsp_handler(psoc, vdev, msg); + break; + case NAN_DATAPATH_INF_DELETE_RSP: + os_if_ndp_iface_delete_rsp_handler(psoc, vdev, msg); + break; + case NDP_CONFIRM: + os_if_ndp_confirm_ind_handler(vdev, msg); + break; + case NDP_INITIATOR_RSP: + os_if_ndp_initiator_rsp_handler(vdev, msg); + break; + case NDP_INDICATION: + os_if_ndp_indication_handler(vdev, msg); + break; + case NDP_NEW_PEER: + os_if_new_peer_ind_handler(vdev, msg); + break; + case NDP_RESPONDER_RSP: + os_if_ndp_responder_rsp_handler(vdev, msg); + break; + case NDP_END_RSP: + os_if_ndp_end_rsp_handler(vdev, msg); + break; + case NDP_END_IND: + os_if_ndp_end_ind_handler(vdev, msg); + break; + case NDP_PEER_DEPARTED: + os_if_peer_departed_ind_handler(vdev, msg); + break; + case NDP_SCHEDULE_UPDATE: + os_if_ndp_sch_update_ind_handler(vdev, msg); + break; + default: + break; + } +} + +int os_if_nan_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj) +{ + return ucfg_nan_register_hdd_callbacks(psoc, cb_obj, + os_if_nan_event_handler); +} + +int os_if_nan_register_lim_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj) +{ + return ucfg_nan_register_lim_callbacks(psoc, cb_obj); +} + +void os_if_nan_post_ndi_create_rsp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool success) +{ + struct nan_datapath_inf_create_rsp rsp = {0}; + struct wlan_objmgr_vdev *vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, vdev_id, WLAN_NAN_ID); + + if (!vdev) { + cfg80211_err("vdev is null"); + return; + } + + if (success) { + rsp.status = NAN_DATAPATH_RSP_STATUS_SUCCESS; + rsp.reason = 0; + os_if_nan_event_handler(psoc, vdev, + NAN_DATAPATH_INF_CREATE_RSP, &rsp); + } else { + rsp.status = NAN_DATAPATH_RSP_STATUS_ERROR; + rsp.reason = NAN_DATAPATH_NAN_DATA_IFACE_CREATE_FAILED; + os_if_nan_event_handler(psoc, vdev, + NAN_DATAPATH_INF_CREATE_RSP, &rsp); + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); +} + +void os_if_nan_post_ndi_delete_rsp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool success) +{ + struct nan_datapath_inf_delete_rsp rsp = {0}; + struct wlan_objmgr_vdev *vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, vdev_id, WLAN_NAN_ID); + if (!vdev) { + cfg80211_err("vdev is null"); + return; + } + + if (success) { + rsp.status = NAN_DATAPATH_RSP_STATUS_SUCCESS; + rsp.reason = 0; + os_if_nan_event_handler(psoc, vdev, + NAN_DATAPATH_INF_DELETE_RSP, &rsp); + } else { + rsp.status = NAN_DATAPATH_RSP_STATUS_ERROR; + rsp.reason = NAN_DATAPATH_NAN_DATA_IFACE_DELETE_FAILED; + os_if_nan_event_handler(psoc, vdev, + NAN_DATAPATH_INF_DELETE_RSP, &rsp); + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); +} + +static inline uint32_t osif_ndp_get_ndi_delete_rsp_len(void) +{ + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE].len); + + return data_len; +} + +void os_if_nan_ndi_session_end(struct wlan_objmgr_vdev *vdev) +{ + uint32_t data_len; + struct sk_buff *vendor_event; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + + /* + * The virtual adapters are stopped and closed even during + * driver unload or stop, the service layer is not required + * to be informed in that case (response is not expected) + */ + if (NAN_DATA_NDI_DELETING_STATE != ucfg_nan_get_ndi_state(vdev)) { + cfg80211_err("NDI interface deleted"); + return; + } + + data_len = osif_ndp_get_ndi_delete_rsp_len(); + /* notify response to the upper layer */ + vendor_event = cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, + data_len, QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + cfg80211_err("cfg80211_vendor_event_alloc failed"); + return; + } + + /* Sub vendor command goes first */ + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE)) { + cfg80211_err("VENDOR_ATTR_NDP_SUBCMD put fail"); + goto failure; + } + + /* Transaction id */ + if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + ucfg_nan_get_ndp_delete_transaction_id(vdev))) { + cfg80211_err("VENDOR_ATTR_NDP_TRANSACTION_ID put fail"); + goto failure; + } + + /* Status code */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + ucfg_nan_get_ndi_delete_rsp_status(vdev))) { + cfg80211_err("VENDOR_ATTR_NDP_DRV_RETURN_TYPE put fail"); + goto failure; + } + + /* Status return value */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + ucfg_nan_get_ndi_delete_rsp_reason(vdev))) { + cfg80211_err("VENDOR_ATTR_NDP_DRV_RETURN_VALUE put fail"); + goto failure; + } + + cfg80211_debug("sub command: %d, value: %d", + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE); + cfg80211_debug("delete transaction id: %d, value: %d", + QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + ucfg_nan_get_ndp_delete_transaction_id(vdev)); + cfg80211_debug("status code: %d, value: %d", + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + ucfg_nan_get_ndi_delete_rsp_status(vdev)); + cfg80211_debug("Return value: %d, value: %d", + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + ucfg_nan_get_ndi_delete_rsp_reason(vdev)); + + ucfg_nan_set_ndp_delete_transaction_id(vdev, 0); + ucfg_nan_set_ndi_state(vdev, NAN_DATA_NDI_DELETED_STATE); + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + + return; +failure: + kfree_skb(vendor_event); +}