diff --git a/os_if/linux/p2p/src/wlan_cfg80211_p2p.c b/os_if/linux/p2p/src/wlan_cfg80211_p2p.c index 2cfe0f3bf3..e4911ae8e2 100644 --- a/os_if/linux/p2p/src/wlan_cfg80211_p2p.c +++ b/os_if/linux/p2p/src/wlan_cfg80211_p2p.c @@ -495,5 +495,5 @@ int wlan_cfg80211_mgmt_tx_cancel(struct wlan_objmgr_vdev *vdev, } return qdf_status_to_os_return( - ucfg_p2p_mgmt_tx_cancel(psoc, cookie)); + ucfg_p2p_mgmt_tx_cancel(psoc, vdev, cookie)); } diff --git a/target_if/p2p/src/target_if_p2p.c b/target_if/p2p/src/target_if_p2p.c index af30938c89..dbce5991f9 100644 --- a/target_if/p2p/src/target_if_p2p.c +++ b/target_if/p2p/src/target_if_p2p.c @@ -368,6 +368,87 @@ QDF_STATUS target_if_p2p_set_noa(struct wlan_objmgr_psoc *psoc, return wmi_unified_vdev_set_param_send(wmi_handle, ¶m); } +static int target_p2p_mac_rx_filter_event_handler(ol_scn_t scn, uint8_t *data, + uint32_t datalen) +{ + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct p2p_set_mac_filter_evt event_info; + struct wlan_lmac_if_p2p_rx_ops *p2p_rx_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!scn || !data) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("null wmi handle"); + return -EINVAL; + } + + if (wmi_extract_mac_addr_rx_filter_evt_param(wmi_handle, data, + &event_info)) { + target_if_err("failed to extract wmi p2p noa event"); + return -EINVAL; + } + target_if_debug("vdev_id %d status %d", event_info.vdev_id, + event_info.status); + p2p_rx_ops = target_if_psoc_get_p2p_rx_ops(psoc); + if (p2p_rx_ops && p2p_rx_ops->add_mac_addr_filter_evt_handler) + status = p2p_rx_ops->add_mac_addr_filter_evt_handler( + psoc, &event_info); + else + target_if_debug("no add mac addr filter event handler"); + + return qdf_status_to_os_return(status); +} + +static QDF_STATUS target_if_p2p_register_macaddr_rx_filter_evt_handler( + struct wlan_objmgr_psoc *psoc, bool reg) +{ + int status; + wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); + + target_if_debug("psoc:%pK, register %d mac addr rx evt", psoc, reg); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + if (reg) + status = wmi_unified_register_event( + wmi_handle, + wmi_vdev_add_macaddr_rx_filter_event_id, + target_p2p_mac_rx_filter_event_handler); + else + status = wmi_unified_unregister_event( + wmi_handle, + wmi_vdev_add_macaddr_rx_filter_event_id); + + return status == 0 ? QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE; +} + +static QDF_STATUS target_if_p2p_set_mac_addr_rx_filter_cmd( + struct wlan_objmgr_psoc *psoc, struct p2p_set_mac_filter *param) +{ + wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_send_set_mac_addr_rx_filter_cmd(wmi_handle, param); +} + void target_if_p2p_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) { struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops; @@ -384,6 +465,10 @@ void target_if_p2p_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) target_if_p2p_register_noa_event_handler; p2p_tx_ops->unreg_noa_ev_handler = target_if_p2p_unregister_noa_event_handler; + p2p_tx_ops->reg_mac_addr_rx_filter_handler = + target_if_p2p_register_macaddr_rx_filter_evt_handler; + p2p_tx_ops->set_mac_addr_rx_filter_cmd = + target_if_p2p_set_mac_addr_rx_filter_cmd; /* register P2P listen offload callbacks */ target_if_p2p_lo_register_tx_ops(p2p_tx_ops); } diff --git a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h index b7c6737fc6..47246da206 100644 --- a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h +++ b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h @@ -201,6 +201,7 @@ struct wlan_lmac_if_scan_rx_ops { /* forward declarations for p2p tx ops */ struct p2p_ps_config; struct p2p_lo_start; +struct p2p_set_mac_filter; /** * struct wlan_lmac_if_p2p_tx_ops - structure of tx function pointers @@ -213,6 +214,9 @@ struct p2p_lo_start; * @reg_noa_ev_handler: function pointer to register noa event handler * @unreg_lo_ev_handler: function pointer to unregister lo event handler * @unreg_noa_ev_handler:function pointer to unregister noa event handler + * @reg_mac_addr_rx_filter_handler: function pointer to register/unregister + * set mac addr status event callback. + * @set_mac_addr_rx_filter_cmd: function pointer to set mac addr rx filter */ struct wlan_lmac_if_p2p_tx_ops { QDF_STATUS (*set_ps)(struct wlan_objmgr_psoc *psoc, @@ -233,6 +237,11 @@ struct wlan_lmac_if_p2p_tx_ops { void *arg); QDF_STATUS (*unreg_noa_ev_handler)(struct wlan_objmgr_psoc *psoc, void *arg); + QDF_STATUS (*reg_mac_addr_rx_filter_handler)( + struct wlan_objmgr_psoc *psoc, bool reg); + QDF_STATUS (*set_mac_addr_rx_filter_cmd)( + struct wlan_objmgr_psoc *psoc, + struct p2p_set_mac_filter *param); }; #endif @@ -829,12 +838,15 @@ struct wlan_lmac_if_reg_rx_ops { /* forward declarations for p2p rx ops */ struct p2p_noa_info; struct p2p_lo_event; +struct p2p_set_mac_filter_evt; /** * struct wlan_lmac_if_p2p_rx_ops - structure of rx function pointers * for P2P component * @lo_ev_handler: function pointer to give listen offload event * @noa_ev_handler: function pointer to give noa event + * @add_mac_addr_filter_evt_handler: function pointer to process add mac addr + * rx filter event */ struct wlan_lmac_if_p2p_rx_ops { #ifdef FEATURE_P2P_LISTEN_OFFLOAD @@ -843,6 +855,10 @@ struct wlan_lmac_if_p2p_rx_ops { #endif QDF_STATUS (*noa_ev_handler)(struct wlan_objmgr_psoc *psoc, struct p2p_noa_info *event_info); + QDF_STATUS (*add_mac_addr_filter_evt_handler)( + struct wlan_objmgr_psoc *psoc, + struct p2p_set_mac_filter_evt *event_info); + }; #endif diff --git a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c index d3157d3943..9e031b1025 100644 --- a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c +++ b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c @@ -298,12 +298,16 @@ static void wlan_lmac_if_umac_rx_ops_register_p2p( { rx_ops->p2p.lo_ev_handler = tgt_p2p_lo_event_cb; rx_ops->p2p.noa_ev_handler = tgt_p2p_noa_event_cb; + rx_ops->p2p.add_mac_addr_filter_evt_handler = + tgt_p2p_add_mac_addr_status_event_cb; } #else static void wlan_lmac_if_umac_rx_ops_register_p2p( struct wlan_lmac_if_rx_ops *rx_ops) { rx_ops->p2p.noa_ev_handler = tgt_p2p_noa_event_cb; + rx_ops->p2p.add_mac_addr_filter_evt_handler = + tgt_p2p_add_mac_addr_status_event_cb; } #endif #else diff --git a/umac/p2p/core/src/wlan_p2p_main.c b/umac/p2p/core/src/wlan_p2p_main.c index a8989ad26a..93d4edf40d 100644 --- a/umac/p2p/core/src/wlan_p2p_main.c +++ b/umac/p2p/core/src/wlan_p2p_main.c @@ -59,6 +59,8 @@ static char *p2p_get_cmd_type_str(enum p2p_cmd_type cmd_type) return "P2P cleanup roc"; case P2P_CLEANUP_TX: return "P2P cleanup tx"; + case P2P_SET_RANDOM_MAC: + return "P2P set random mac"; default: return "Invalid P2P command"; } @@ -85,6 +87,8 @@ static char *p2p_get_event_type_str(enum p2p_event_type event_type) return "P2P lo stop event"; case P2P_EVENT_NOA: return "P2P noa event"; + case P2P_EVENT_ADD_MAC_RSP: + return "P2P add mac filter resp event"; default: return "Invalid P2P event"; } @@ -202,8 +206,12 @@ static QDF_STATUS p2p_vdev_obj_create_notification( mode = wlan_vdev_mlme_get_opmode(vdev); p2p_debug("vdev mode:%d", mode); - if (mode != QDF_P2P_GO_MODE) { - p2p_debug("won't create p2p vdev private object if it is not GO"); + if (mode != QDF_P2P_GO_MODE && + mode != QDF_STA_MODE && + mode != QDF_P2P_CLIENT_MODE && + mode != QDF_P2P_DEVICE_MODE) { + p2p_debug("won't create p2p vdev private object for mode %d", + mode); return QDF_STATUS_SUCCESS; } @@ -217,11 +225,13 @@ static QDF_STATUS p2p_vdev_obj_create_notification( p2p_vdev_obj->vdev = vdev; p2p_vdev_obj->noa_status = true; p2p_vdev_obj->non_p2p_peer_count = 0; + p2p_init_random_mac_vdev(p2p_vdev_obj); status = wlan_objmgr_vdev_component_obj_attach(vdev, WLAN_UMAC_COMP_P2P, p2p_vdev_obj, QDF_STATUS_SUCCESS); if (status != QDF_STATUS_SUCCESS) { + p2p_deinit_random_mac_vdev(p2p_vdev_obj); qdf_mem_free(p2p_vdev_obj); p2p_err("Failed to attach p2p component to vdev, %d", status); @@ -257,8 +267,11 @@ static QDF_STATUS p2p_vdev_obj_destroy_notification( mode = wlan_vdev_mlme_get_opmode(vdev); p2p_debug("vdev mode:%d", mode); - if (mode != QDF_P2P_GO_MODE) { - p2p_debug("no p2p vdev private object if it is not GO"); + if (mode != QDF_P2P_GO_MODE && + mode != QDF_STA_MODE && + mode != QDF_P2P_CLIENT_MODE && + mode != QDF_P2P_DEVICE_MODE){ + p2p_debug("no p2p vdev private object for mode %d", mode); return QDF_STATUS_SUCCESS; } @@ -268,6 +281,7 @@ static QDF_STATUS p2p_vdev_obj_destroy_notification( p2p_debug("p2p vdev object is NULL"); return QDF_STATUS_SUCCESS; } + p2p_deinit_random_mac_vdev(p2p_vdev_obj); p2p_vdev_obj->vdev = NULL; @@ -313,6 +327,10 @@ static QDF_STATUS p2p_peer_obj_create_notification( } vdev = wlan_peer_get_vdev(peer); + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode != QDF_P2P_GO_MODE) + return QDF_STATUS_SUCCESS; + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, WLAN_UMAC_COMP_P2P); peer_type = wlan_peer_get_peer_type(peer); @@ -356,6 +374,10 @@ static QDF_STATUS p2p_peer_obj_destroy_notification( } vdev = wlan_peer_get_vdev(peer); + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode != QDF_P2P_GO_MODE) + return QDF_STATUS_SUCCESS; + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, WLAN_UMAC_COMP_P2P); psoc = wlan_vdev_get_psoc(vdev); @@ -842,6 +864,7 @@ QDF_STATUS p2p_psoc_start(struct wlan_objmgr_psoc *soc, /* register p2p lo stop and noa event */ tgt_p2p_register_lo_ev_handler(soc); tgt_p2p_register_noa_ev_handler(soc); + tgt_p2p_register_macaddr_rx_filter_evt_handler(soc, true); /* register scan request id */ p2p_soc_obj->scan_req_id = ucfg_scan_register_requester( @@ -892,6 +915,7 @@ QDF_STATUS p2p_psoc_stop(struct wlan_objmgr_psoc *soc) ucfg_scan_unregister_requester(soc, p2p_soc_obj->scan_req_id); /* unregister p2p lo stop and noa event */ + tgt_p2p_register_macaddr_rx_filter_evt_handler(soc, false); tgt_p2p_unregister_lo_ev_handler(soc); tgt_p2p_unregister_noa_ev_handler(soc); @@ -954,6 +978,11 @@ QDF_STATUS p2p_process_cmd(struct scheduler_msg *msg) msg->bodyptr); qdf_mem_free(msg->bodyptr); break; + case P2P_SET_RANDOM_MAC: + status = p2p_process_set_rand_mac(msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + default: p2p_err("drop unexpected message received %d", msg->type); @@ -997,6 +1026,11 @@ QDF_STATUS p2p_process_evt(struct scheduler_msg *msg) (struct p2p_noa_event *) msg->bodyptr); break; + case P2P_EVENT_ADD_MAC_RSP: + status = p2p_process_set_rand_mac_rsp( + (struct p2p_mac_filter_rsp *) + msg->bodyptr); + break; default: p2p_err("Drop unexpected message received %d", msg->type); diff --git a/umac/p2p/core/src/wlan_p2p_main.h b/umac/p2p/core/src/wlan_p2p_main.h index ef0fc48479..8a89d93e73 100644 --- a/umac/p2p/core/src/wlan_p2p_main.h +++ b/umac/p2p/core/src/wlan_p2p_main.h @@ -34,6 +34,7 @@ #define P2P_NOA_ATTR_IND 0x1090 #define P2P_MODULE_NAME "P2P" #define P2P_INVALID_VDEV_ID 0xFFFFFFFF +#define MAX_RANDOM_MAC_ADDRS 4 #define p2p_debug(params ...) \ QDF_TRACE_DEBUG(QDF_MODULE_ID_P2P, params) @@ -73,6 +74,7 @@ struct tx_action_context; * @P2P_MGMT_TX_CANCEL: Cancel tx action frame request * @P2P_CLEANUP_ROC: Cleanup roc queue * @P2P_CLEANUP_TX: Cleanup tx mgmt queue + * @P2P_SET_RANDOM_MAC: Set Random MAC addr filter request */ enum p2p_cmd_type { P2P_ROC_REQ = 0, @@ -81,6 +83,7 @@ enum p2p_cmd_type { P2P_MGMT_TX_CANCEL, P2P_CLEANUP_ROC, P2P_CLEANUP_TX, + P2P_SET_RANDOM_MAC, }; /** @@ -90,6 +93,7 @@ enum p2p_cmd_type { * @P2P_EVENT_RX_MGMT: P2P rx mgmt frame * @P2P_EVENT_LO_STOPPED: P2P listen offload stopped event * @P2P_EVENT_NOA: P2P noa event + * @P2P_EVENT_ADD_MAC_RSP: Set Random MAC addr event */ enum p2p_event_type { P2P_EVENT_SCAN_EVENT = 0, @@ -97,6 +101,7 @@ enum p2p_event_type { P2P_EVENT_RX_MGMT, P2P_EVENT_LO_STOPPED, P2P_EVENT_NOA, + P2P_EVENT_ADD_MAC_RSP, }; /** @@ -141,6 +146,18 @@ struct p2p_noa_event { struct p2p_noa_info *noa_info; }; +/** + * struct p2p_mac_filter_rsp - p2p set mac filter respone + * @p2p_soc_obj: p2p soc private object + * @vdev_id: vdev id + * @status: successfully(1) or not (0) + */ +struct p2p_mac_filter_rsp { + struct p2p_soc_priv_obj *p2p_soc_obj; + uint32_t vdev_id; + uint32_t status; +}; + #ifdef WLAN_FEATURE_P2P_DEBUG /** * enum p2p_connection_status - p2p connection status @@ -224,18 +241,92 @@ struct p2p_soc_priv_obj { #endif }; +/** + * struct action_frame_cookie - Action frame cookie item in cookie list + * @cookie_node: qdf_list_node + * @cookie: Cookie value + */ +struct action_frame_cookie { + qdf_list_node_t cookie_node; + uint64_t cookie; +}; + +/** + * struct action_frame_random_mac - Action Frame random mac addr & + * related attrs + * @p2p_vdev_obj: p2p vdev private obj ptr + * @in_use: Checks whether random mac is in use + * @addr: Contains random mac addr + * @freq: Channel frequency + * @clear_timer: timer to clear random mac filter + * @cookie_list: List of cookies tied with random mac + */ +struct action_frame_random_mac { + struct p2p_vdev_priv_obj *p2p_vdev_obj; + bool in_use; + uint8_t addr[QDF_MAC_ADDR_SIZE]; + uint32_t freq; + qdf_mc_timer_t clear_timer; + qdf_list_t cookie_list; +}; + +/** + * p2p_request_mgr_callback_t() - callback to process set mac filter result + * @result: bool + * @context: callback context. + * + * Return: void + */ +typedef void (*p2p_request_mgr_callback_t)(bool result, void *context); + +/** + * struct random_mac_priv - request private data struct + * @result: result of request. + */ +struct random_mac_priv { + bool result; +}; + +/** + * struct p2p_set_mac_filter_req - set mac addr filter cmd data structure + * @soc: soc object + * @vdev_id: vdev id + * @mac: mac address to be set + * @freq: frequency + * @set: set or clear + * @cb: callback func to be called when the request completion + * @req_cookie: cookie to be used when request completed + */ +struct p2p_set_mac_filter_req { + struct wlan_objmgr_psoc *soc; + uint32_t vdev_id; + uint8_t mac[QDF_MAC_ADDR_SIZE]; + uint32_t freq; + bool set; + p2p_request_mgr_callback_t cb; + void *req_cookie; +}; + /** * struct p2p_vdev_priv_obj - Per vdev p2p private object * @vdev: Pointer to vdev context * @noa_info: NoA information * @noa_status: NoA status i.e. Enabled / Disabled (TRUE/FALSE) * @non_p2p_peer_count: Number of legacy stations connected to this GO + * @random_mac_lock: lock for random_mac list + * @random_mac: active random mac filter lists + * @pending_req: pending set mac filter request. */ struct p2p_vdev_priv_obj { struct wlan_objmgr_vdev *vdev; struct p2p_noa_info *noa_info; bool noa_status; uint16_t non_p2p_peer_count; + + /* random address management for management action frames */ + qdf_spinlock_t random_mac_lock; + struct action_frame_random_mac random_mac[MAX_RANDOM_MAC_ADDRS]; + struct p2p_set_mac_filter_req pending_req; }; /** diff --git a/umac/p2p/core/src/wlan_p2p_off_chan_tx.c b/umac/p2p/core/src/wlan_p2p_off_chan_tx.c index 71ac3ee5a8..1309ccd08d 100644 --- a/umac/p2p/core/src/wlan_p2p_off_chan_tx.c +++ b/umac/p2p/core/src/wlan_p2p_off_chan_tx.c @@ -32,6 +32,21 @@ #include "wlan_p2p_roc.h" #include "wlan_p2p_main.h" #include "wlan_p2p_off_chan_tx.h" +#include "wlan_osif_request_manager.h" + +/** + * p2p_psoc_get_tx_ops() - get p2p tx ops + * @psoc: psoc object + * + * This function returns p2p tx ops callbacks. + * + * Return: wlan_lmac_if_p2p_tx_ops + */ +static inline struct wlan_lmac_if_p2p_tx_ops * +p2p_psoc_get_tx_ops(struct wlan_objmgr_psoc *psoc) +{ + return &psoc->soc_cb.tx_ops.p2p; +} /** * p2p_tx_context_check_valid() - check tx action context @@ -469,6 +484,7 @@ static QDF_STATUS p2p_populate_mac_header( void *mac_addr; uint16_t seq_num; uint8_t pdev_id; + struct wlan_objmgr_vdev *vdev; psoc = tx_ctx->p2p_soc_obj->soc; @@ -482,7 +498,17 @@ static QDF_STATUS p2p_populate_mac_header( peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, WLAN_P2P_ID); } - + if (!peer && tx_ctx->rand_mac_tx) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + tx_ctx->vdev_id, + WLAN_P2P_ID); + if (vdev) { + mac_addr = wlan_vdev_mlme_get_macaddr(vdev); + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, + WLAN_P2P_ID); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + } + } if (!peer) { p2p_err("no valid peer"); return QDF_STATUS_E_INVAL; @@ -855,6 +881,8 @@ static QDF_STATUS p2p_send_tx_conf(struct tx_action_context *tx_ctx, tx_cnf.action_cookie, tx_cnf.buf_len, tx_cnf.status, tx_cnf.buf); + p2p_rand_mac_tx_done(p2p_soc_obj->soc, tx_ctx); + start_param->tx_cnf_cb(start_param->tx_cnf_cb_data, &tx_cnf); return QDF_STATUS_SUCCESS; @@ -883,6 +911,7 @@ static QDF_STATUS p2p_mgmt_tx(struct tx_action_context *tx_ctx, struct wlan_objmgr_psoc *psoc; void *mac_addr; uint8_t pdev_id; + struct wlan_objmgr_vdev *vdev; psoc = tx_ctx->p2p_soc_obj->soc; mgmt_param.tx_frame = packet; @@ -907,6 +936,16 @@ static QDF_STATUS p2p_mgmt_tx(struct tx_action_context *tx_ctx, peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, WLAN_P2P_ID); } + if (!peer && tx_ctx->rand_mac_tx) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, tx_ctx->vdev_id, WLAN_P2P_ID); + if (vdev) { + mac_addr = wlan_vdev_mlme_get_macaddr(vdev); + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, + WLAN_P2P_ID); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + } + } if (!peer) { p2p_err("no valid peer"); @@ -1770,6 +1809,857 @@ QDF_STATUS p2p_process_cleanup_tx_queue(struct p2p_cleanup_param *param) return QDF_STATUS_SUCCESS; } +bool p2p_check_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *random_mac_addr) +{ + uint32_t i = 0; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_debug("vdev is null"); + return false; + } + + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("p2p vdev object is NULL"); + return false; + } + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) { + if ((p2p_vdev_obj->random_mac[i].in_use) && + (!qdf_mem_cmp(p2p_vdev_obj->random_mac[i].addr, + random_mac_addr, QDF_MAC_ADDR_SIZE))) { + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + return true; + } + } + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return false; +} + +/** + * find_action_frame_cookie() - Checks for action cookie in cookie list + * @cookie_list: List of cookies + * @rnd_cookie: Cookie to be searched + * + * Return: If search is successful return pointer to action_frame_cookie + * object in which cookie item is encapsulated. + */ +static struct action_frame_cookie * +find_action_frame_cookie(qdf_list_t *cookie_list, uint64_t rnd_cookie) +{ + struct action_frame_cookie *action_cookie; + + qdf_list_for_each(cookie_list, action_cookie, cookie_node) { + if (action_cookie->cookie == rnd_cookie) + return action_cookie; + } + + return NULL; +} + +/** + * allocate_action_frame_cookie() - Allocate and add action cookie to + * given list + * @cookie_list: List of cookies + * @rnd_cookie: Cookie to be added + * + * Return: If allocation and addition is successful return pointer to + * action_frame_cookie object in which cookie item is encapsulated. + */ +static struct action_frame_cookie * +allocate_action_frame_cookie(qdf_list_t *cookie_list, uint64_t rnd_cookie) +{ + struct action_frame_cookie *action_cookie; + + action_cookie = qdf_mem_malloc(sizeof(*action_cookie)); + if (!action_cookie) + return NULL; + + action_cookie->cookie = rnd_cookie; + qdf_list_insert_front(cookie_list, &action_cookie->cookie_node); + + return action_cookie; +} + +/** + * delete_action_frame_cookie() - Delete the cookie from given list + * @cookie_list: List of cookies + * @action_cookie: Cookie to be deleted + * + * This function deletes the cookie item from given list and corresponding + * object in which it is encapsulated. + * + * Return: None + */ +static void +delete_action_frame_cookie(qdf_list_t *cookie_list, + struct action_frame_cookie *action_cookie) +{ + qdf_list_remove_node(cookie_list, &action_cookie->cookie_node); + qdf_mem_free(action_cookie); +} + +/** + * append_action_frame_cookie() - Append action cookie to given list + * @cookie_list: List of cookies + * @rnd_cookie: Cookie to be append + * + * This is a wrapper function which invokes allocate_action_frame_cookie + * if the cookie to be added is not duplicate + * + * Return: true - for successful case + * false - failed. + */ +static bool +append_action_frame_cookie(qdf_list_t *cookie_list, uint64_t rnd_cookie) +{ + struct action_frame_cookie *action_cookie; + + /* + * There should be no mac entry with empty cookie list, + * check and ignore if duplicate + */ + action_cookie = find_action_frame_cookie(cookie_list, rnd_cookie); + if (action_cookie) + /* random mac address is already programmed */ + return true; + + /* insert new cookie in cookie list */ + action_cookie = allocate_action_frame_cookie(cookie_list, rnd_cookie); + if (!action_cookie) + return false; + + return true; +} + +/** + * p2p_add_random_mac() - add or append random mac to given vdev rand mac list + * @soc: soc object + * @vdev_id: vdev id + * @mac: mac addr to be added or append + * @freq: frequency + * @rnd_cookie: random mac mgmt tx cookie + * + * This function will add or append the mac addr entry to vdev random mac list. + * Once the mac addr filter is not needed, it can be removed by + * p2p_del_random_mac. + * + * Return: QDF_STATUS_E_EXISTS - append to existing list + * QDF_STATUS_SUCCESS - add a new entry. + * other : failed to add the mac address entry. + */ +static QDF_STATUS +p2p_add_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *mac, uint32_t freq, uint64_t rnd_cookie) +{ + uint32_t i; + uint32_t first_unused = MAX_RANDOM_MAC_ADDRS; + struct action_frame_cookie *action_cookie; + int32_t append_ret; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct wlan_objmgr_vdev *vdev; + + p2p_debug("random_mac:vdev %d mac_addr:%pM rnd_cookie=%llu freq = %u", + vdev_id, mac, rnd_cookie, freq); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_debug("vdev is null"); + + return QDF_STATUS_E_INVAL; + } + + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) { + p2p_debug("random_mac:p2p vdev object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return QDF_STATUS_E_INVAL; + } + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + /* + * Following loop checks whether random mac entry is already + * present, if present get the index of matched entry else + * get the first unused slot to store this new random mac + */ + for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) { + if (!p2p_vdev_obj->random_mac[i].in_use) { + if (first_unused == MAX_RANDOM_MAC_ADDRS) + first_unused = i; + continue; + } + + if (!qdf_mem_cmp(p2p_vdev_obj->random_mac[i].addr, mac, + QDF_MAC_ADDR_SIZE)) + break; + } + + if (i != MAX_RANDOM_MAC_ADDRS) { + append_ret = append_action_frame_cookie( + &p2p_vdev_obj->random_mac[i].cookie_list, + rnd_cookie); + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("random_mac:append %d vdev %d freq %d %pM rnd_cookie %llu", + append_ret, vdev_id, freq, mac, rnd_cookie); + if (!append_ret) { + p2p_debug("random_mac:failed to append rnd_cookie"); + return QDF_STATUS_E_NOMEM; + } + + return QDF_STATUS_E_EXISTS; + } + + if (first_unused == MAX_RANDOM_MAC_ADDRS) { + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("random_mac:Reached the limit of Max random addresses"); + + return QDF_STATUS_E_RESOURCES; + } + + /* get the first unused buf and store new random mac */ + i = first_unused; + + action_cookie = allocate_action_frame_cookie( + &p2p_vdev_obj->random_mac[i].cookie_list, + rnd_cookie); + if (!action_cookie) { + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_err("random_mac:failed to alloc rnd cookie"); + + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(p2p_vdev_obj->random_mac[i].addr, mac, QDF_MAC_ADDR_SIZE); + p2p_vdev_obj->random_mac[i].in_use = true; + p2p_vdev_obj->random_mac[i].freq = freq; + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("random_mac:add vdev %d freq %d %pM rnd_cookie %llu", + vdev_id, freq, mac, rnd_cookie); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +p2p_del_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint64_t rnd_cookie, uint32_t duration) +{ + uint32_t i; + struct action_frame_cookie *action_cookie; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct wlan_objmgr_vdev *vdev; + + p2p_debug("random_mac:vdev %d cookie %llu duration %d", vdev_id, + rnd_cookie, duration); + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, + WLAN_P2P_ID); + if (!vdev) { + p2p_debug("vdev is null"); + return QDF_STATUS_E_INVAL; + } + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("p2p vdev object is NULL"); + return QDF_STATUS_E_INVAL; + } + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) { + struct action_frame_random_mac *random_mac; + + random_mac = &p2p_vdev_obj->random_mac[i]; + if (!random_mac->in_use) + continue; + + action_cookie = find_action_frame_cookie( + &random_mac->cookie_list, rnd_cookie); + if (!action_cookie) + continue; + + delete_action_frame_cookie( + &random_mac->cookie_list, + action_cookie); + + if (qdf_list_empty(&random_mac->cookie_list)) { + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + if (qdf_mc_timer_get_current_state( + &random_mac->clear_timer) == + QDF_TIMER_STATE_RUNNING) + qdf_mc_timer_stop(&random_mac->clear_timer); + qdf_mc_timer_start(&random_mac->clear_timer, duration); + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + p2p_debug("random_mac:noref on vdev %d addr %pM", + vdev_id, random_mac->addr); + } + break; + } + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return QDF_STATUS_SUCCESS; +} + +void p2p_del_all_rand_mac_vdev(struct wlan_objmgr_vdev *vdev) +{ + int32_t i; + uint32_t freq; + uint8_t addr[QDF_MAC_ADDR_SIZE]; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + + if (!vdev) + return; + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) + return; + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) { + struct action_frame_cookie *action_cookie; + struct action_frame_cookie *action_cookie_next; + + if (!p2p_vdev_obj->random_mac[i].in_use) + continue; + + /* empty the list and clear random addr */ + qdf_list_for_each_del(&p2p_vdev_obj->random_mac[i].cookie_list, + action_cookie, action_cookie_next, + cookie_node) { + qdf_list_remove_node( + &p2p_vdev_obj->random_mac[i].cookie_list, + &action_cookie->cookie_node); + qdf_mem_free(action_cookie); + } + + p2p_vdev_obj->random_mac[i].in_use = false; + freq = p2p_vdev_obj->random_mac[i].freq; + qdf_mem_copy(addr, p2p_vdev_obj->random_mac[i].addr, + QDF_MAC_ADDR_SIZE); + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + qdf_mc_timer_stop(&p2p_vdev_obj->random_mac[i].clear_timer); + p2p_clear_mac_filter(wlan_vdev_get_psoc(vdev), + wlan_vdev_get_id(vdev), addr, freq); + p2p_debug("random_mac:delall vdev %d freq %d addr %pM", + wlan_vdev_get_id(vdev), freq, addr); + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + } + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); +} + +static void +p2p_del_rand_mac_vdev_enum_handler(struct wlan_objmgr_psoc *psoc, + void *obj, void *arg) +{ + struct wlan_objmgr_vdev *vdev = obj; + + if (!vdev) { + p2p_err("random_mac:invalid vdev"); + return; + } + + if (!p2p_is_vdev_support_rand_mac(vdev)) + return; + + p2p_del_all_rand_mac_vdev(vdev); +} + +void p2p_del_all_rand_mac_soc(struct wlan_objmgr_psoc *soc) +{ + if (!soc) { + p2p_err("random_mac:soc object is NULL"); + return; + } + + wlan_objmgr_iterate_obj_list(soc, WLAN_VDEV_OP, + p2p_del_rand_mac_vdev_enum_handler, + NULL, 0, WLAN_P2P_ID); +} + +/** + * p2p_is_random_mac() - check mac addr is random mac for vdev + * @soc: soc object + * @vdev_id: vdev id + * @mac: mac addr to be added or append + * + * This function will check the source mac addr same as vdev's mac addr or not. + * If not same, then the source mac addr should be random mac addr. + * + * Return: true if mac is random mac, otherwise false + */ +static bool +p2p_is_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, uint8_t *mac) +{ + bool ret = false; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_debug("random_mac:vdev is null"); + return false; + } + + if (qdf_mem_cmp(wlan_vdev_mlme_get_macaddr(vdev), + mac, QDF_MAC_ADDR_SIZE)) + ret = true; + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return ret; +} + +static void p2p_set_mac_filter_callback(bool result, void *context) +{ + struct osif_request *request; + struct random_mac_priv *priv; + + p2p_debug("random_mac:set random mac filter result %d", result); + request = osif_request_get(context); + if (!request) { + p2p_err("random_mac:invalid response"); + return; + } + + priv = osif_request_priv(request); + priv->result = result; + + osif_request_complete(request); + osif_request_put(request); +} + +QDF_STATUS p2p_process_set_rand_mac_rsp(struct p2p_mac_filter_rsp *resp) +{ + struct wlan_objmgr_psoc *soc; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct wlan_objmgr_vdev *vdev; + + if (!resp || !resp->p2p_soc_obj || !resp->p2p_soc_obj->soc) { + p2p_debug("random_mac:set_filter_req is null"); + return QDF_STATUS_E_INVAL; + } + p2p_debug("random_mac:process rsp on vdev %d status %d", resp->vdev_id, + resp->status); + soc = resp->p2p_soc_obj->soc; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, resp->vdev_id, + WLAN_P2P_ID); + if (!vdev) { + p2p_debug("random_mac:vdev is null vdev %d", resp->vdev_id); + return QDF_STATUS_E_INVAL; + } + + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("random_mac:p2p_vdev_obj is null vdev %d", + resp->vdev_id); + return QDF_STATUS_E_INVAL; + } + if (!p2p_vdev_obj->pending_req.soc) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("random_mac:no pending set req for vdev %d", + resp->vdev_id); + return QDF_STATUS_E_INVAL; + } + + p2p_debug("random_mac:get pending req on vdev %d set %d mac filter %pM freq %d", + p2p_vdev_obj->pending_req.vdev_id, + p2p_vdev_obj->pending_req.set, p2p_vdev_obj->pending_req.mac, + p2p_vdev_obj->pending_req.freq); + if (p2p_vdev_obj->pending_req.cb) + p2p_vdev_obj->pending_req.cb( + !!resp->status, p2p_vdev_obj->pending_req.req_cookie); + + qdf_mem_zero(&p2p_vdev_obj->pending_req, + sizeof(p2p_vdev_obj->pending_req)); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +p2p_process_set_rand_mac(struct p2p_set_mac_filter_req *set_filter_req) +{ + struct wlan_objmgr_psoc *soc; + struct wlan_lmac_if_p2p_tx_ops *p2p_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct p2p_set_mac_filter param; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct wlan_objmgr_vdev *vdev; + + if (!set_filter_req || !set_filter_req->soc) { + p2p_debug("random_mac:set_filter_req is null"); + return QDF_STATUS_E_INVAL; + } + p2p_debug("random_mac:vdev %d set %d mac filter %pM freq %d", + set_filter_req->vdev_id, set_filter_req->set, + set_filter_req->mac, set_filter_req->freq); + + soc = set_filter_req->soc; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + soc, set_filter_req->vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_debug("random_mac:vdev is null vdev %d", + set_filter_req->vdev_id); + goto get_vdev_failed; + } + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) { + p2p_debug("random_mac:p2p_vdev_obj is null vdev %d", + set_filter_req->vdev_id); + goto get_p2p_obj_failed; + } + if (p2p_vdev_obj->pending_req.soc) { + p2p_debug("random_mac:Busy on vdev %d set %d mac filter %pM freq %d", + p2p_vdev_obj->pending_req.vdev_id, + p2p_vdev_obj->pending_req.set, + p2p_vdev_obj->pending_req.mac, + p2p_vdev_obj->pending_req.freq); + goto get_p2p_obj_failed; + } + + p2p_ops = p2p_psoc_get_tx_ops(soc); + if (p2p_ops && p2p_ops->set_mac_addr_rx_filter_cmd) { + qdf_mem_zero(¶m, sizeof(param)); + param.vdev_id = set_filter_req->vdev_id; + qdf_mem_copy(param.mac, set_filter_req->mac, + QDF_MAC_ADDR_SIZE); + param.freq = set_filter_req->freq; + param.set = set_filter_req->set; + status = p2p_ops->set_mac_addr_rx_filter_cmd(soc, ¶m); + if (status == QDF_STATUS_SUCCESS && set_filter_req->set) + qdf_mem_copy(&p2p_vdev_obj->pending_req, + set_filter_req, sizeof(*set_filter_req)); + p2p_debug("random_mac:p2p set mac addr rx filter, status:%d", + status); + } + +get_p2p_obj_failed: + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + +get_vdev_failed: + if (status != QDF_STATUS_SUCCESS && + set_filter_req->cb) + set_filter_req->cb(false, set_filter_req->req_cookie); + + return status; +} + +/** + * p2p_set_mac_filter() - send set mac addr filter cmd + * @soc: soc + * @vdev_id: vdev id + * @mac: mac addr + * @freq: freq + * @set: set or clear + * @cb: callback func to be called when the request completed. + * @req_cookie: cookie to be returned + * + * This function send set random mac addr filter command to p2p component + * msg core + * + * Return: QDF_STATUS_SUCCESS - if sent successfully. + * otherwise : failed. + */ +static QDF_STATUS +p2p_set_mac_filter(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *mac, uint32_t freq, bool set, + p2p_request_mgr_callback_t cb, void *req_cookie) +{ + struct p2p_set_mac_filter_req *set_filter_req; + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + p2p_debug("random_mac:vdev %d freq %d set %d %pM", + vdev_id, freq, set, mac); + + set_filter_req = qdf_mem_malloc(sizeof(*set_filter_req)); + if (!set_filter_req) + return QDF_STATUS_E_NOMEM; + + set_filter_req->soc = soc; + set_filter_req->vdev_id = vdev_id; + set_filter_req->freq = freq; + qdf_mem_copy(set_filter_req->mac, mac, QDF_MAC_ADDR_SIZE); + set_filter_req->set = set; + set_filter_req->cb = cb; + set_filter_req->req_cookie = req_cookie; + + msg.type = P2P_SET_RANDOM_MAC; + msg.bodyptr = set_filter_req; + msg.callback = p2p_process_cmd; + status = scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg); + if (status != QDF_STATUS_SUCCESS) + qdf_mem_free(set_filter_req); + + return status; +} + +QDF_STATUS +p2p_clear_mac_filter(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *mac, uint32_t freq) +{ + return p2p_set_mac_filter(soc, vdev_id, mac, freq, false, NULL, NULL); +} + +bool +p2p_is_vdev_support_rand_mac(struct wlan_objmgr_vdev *vdev) +{ + enum QDF_OPMODE mode; + + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode == QDF_STA_MODE || + mode == QDF_P2P_CLIENT_MODE || + mode == QDF_P2P_DEVICE_MODE) + return true; + return false; +} + +/** + * p2p_is_vdev_support_rand_mac_by_id() - check vdev type support random mac + * mgmt tx or not + * @soc: soc obj + * @vdev_id: vdev id + * + * Return: true: support random mac mgmt tx + * false: not support random mac mgmt tx. + */ +static bool +p2p_is_vdev_support_rand_mac_by_id(struct wlan_objmgr_psoc *soc, + uint32_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + bool ret = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, WLAN_P2P_ID); + if (!vdev) + return false; + ret = p2p_is_vdev_support_rand_mac(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return ret; +} + +/** + * p2p_set_rand_mac() - set random mac address rx filter + * @soc: soc + * @vdev_id: vdev id + * @mac: mac addr + * @freq: freq + * @rnd_cookie: cookie to be returned + * + * This function will post msg to p2p core to set random mac addr rx filter. + * It will wait the respone and return the result to caller. + * + * Return: true: set successfully + * false: failed + */ +static bool +p2p_set_rand_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *mac, uint32_t freq, uint64_t rnd_cookie) +{ + bool ret = false; + int err; + QDF_STATUS status; + struct osif_request *request; + static const struct osif_request_params params = { + .priv_size = sizeof(struct random_mac_priv), + .timeout_ms = WLAN_WAIT_TIME_SET_RND, + }; + void *req_cookie; + struct random_mac_priv *priv; + + request = osif_request_alloc(¶ms); + if (!request) { + p2p_err("Request allocation failure"); + return false; + } + + req_cookie = osif_request_cookie(request); + + status = p2p_set_mac_filter(soc, vdev_id, mac, freq, true, + p2p_set_mac_filter_callback, req_cookie); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("random_mac:set mac fitler failure %d", status); + } else { + err = osif_request_wait_for_response(request); + if (err) { + p2p_err("random_mac:timeout for set mac fitler %d", + err); + } else { + priv = osif_request_priv(request); + ret = priv->result; + p2p_debug("random_mac:vdev %d freq %d result %d %pM rnd_cookie %llu", + vdev_id, freq, priv->result, mac, rnd_cookie); + } + } + osif_request_put(request); + + return ret; +} + +/** + * p2p_request_random_mac() - request random mac mgmt tx + * @soc: soc + * @vdev_id: vdev id + * @mac: mac addr + * @freq: freq + * @rnd_cookie: cookie to be returned + * @duration: duration of tx timeout + * + * This function will add/append the random mac addr filter entry to vdev. + * If it is new added entry, it will request to set filter in target. + * + * Return: QDF_STATUS_SUCCESS: request successfully + * other: failed + */ +static QDF_STATUS +p2p_request_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *mac, uint32_t freq, uint64_t rnd_cookie, + uint32_t duration) +{ + QDF_STATUS status; + + status = p2p_add_random_mac(soc, vdev_id, mac, freq, rnd_cookie); + if (status == QDF_STATUS_E_EXISTS) + return QDF_STATUS_SUCCESS; + else if (status != QDF_STATUS_SUCCESS) + return status; + + if (!p2p_set_rand_mac(soc, vdev_id, mac, freq, rnd_cookie)) + status = p2p_del_random_mac(soc, vdev_id, rnd_cookie, + duration); + + return status; +} + +void p2p_rand_mac_tx(struct tx_action_context *tx_action) +{ + struct wlan_objmgr_psoc *soc; + QDF_STATUS status; + + if (!tx_action || !tx_action->p2p_soc_obj || + !tx_action->p2p_soc_obj->soc) + return; + soc = tx_action->p2p_soc_obj->soc; + + if (!tx_action->no_ack && tx_action->chan && + tx_action->buf_len > MIN_MAC_HEADER_LEN && + p2p_is_vdev_support_rand_mac_by_id(soc, tx_action->vdev_id) && + p2p_is_random_mac(soc, tx_action->vdev_id, + &tx_action->buf[SRC_MAC_ADDR_OFFSET])) { + status = p2p_request_random_mac( + soc, tx_action->vdev_id, + &tx_action->buf[SRC_MAC_ADDR_OFFSET], + wlan_chan_to_freq(tx_action->chan), + tx_action->id, + tx_action->duration); + if (status == QDF_STATUS_SUCCESS) + tx_action->rand_mac_tx = true; + else + tx_action->rand_mac_tx = false; + } +} + +void +p2p_rand_mac_tx_done(struct wlan_objmgr_psoc *soc, + struct tx_action_context *tx_ctx) +{ + if (!tx_ctx || !tx_ctx->rand_mac_tx || !soc) + return; + + p2p_del_random_mac(soc, tx_ctx->vdev_id, tx_ctx->id, tx_ctx->duration); +} + +/** + * p2p_mac_clear_timeout() - clear random mac filter timeout + * @context: timer context + * + * This function will clear the mac addr rx filter in target if no + * reference to it. + * + * Return: void + */ +static void p2p_mac_clear_timeout(void *context) +{ + struct action_frame_random_mac *random_mac = context; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + uint32_t freq; + uint8_t addr[QDF_MAC_ADDR_SIZE]; + uint32_t vdev_id; + bool clear = false; + + if (!random_mac || !random_mac->p2p_vdev_obj) { + p2p_err("invalid context for mac_clear timeout"); + return; + } + p2p_vdev_obj = random_mac->p2p_vdev_obj; + if (!p2p_vdev_obj || !p2p_vdev_obj->vdev) + return; + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + if (qdf_list_empty(&random_mac->cookie_list)) { + random_mac->in_use = false; + clear = true; + } + freq = random_mac->freq; + qdf_mem_copy(addr, random_mac->addr, QDF_MAC_ADDR_SIZE); + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + + vdev_id = wlan_vdev_get_id(p2p_vdev_obj->vdev); + p2p_debug("random_mac:clear timeout vdev %d %pM freq %d clr %d", + vdev_id, addr, freq, clear); + if (clear) + p2p_clear_mac_filter(wlan_vdev_get_psoc(p2p_vdev_obj->vdev), + vdev_id, addr, freq); +} + +void p2p_init_random_mac_vdev(struct p2p_vdev_priv_obj *p2p_vdev_obj) +{ + int32_t i; + + qdf_spinlock_create(&p2p_vdev_obj->random_mac_lock); + for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) { + qdf_mem_zero(&p2p_vdev_obj->random_mac[i], + sizeof(struct action_frame_random_mac)); + p2p_vdev_obj->random_mac[i].in_use = false; + p2p_vdev_obj->random_mac[i].p2p_vdev_obj = p2p_vdev_obj; + qdf_list_create(&p2p_vdev_obj->random_mac[i].cookie_list, 0); + qdf_mc_timer_init(&p2p_vdev_obj->random_mac[i].clear_timer, + QDF_TIMER_TYPE_SW, p2p_mac_clear_timeout, + &p2p_vdev_obj->random_mac[i]); + } +} + +void p2p_deinit_random_mac_vdev(struct p2p_vdev_priv_obj *p2p_vdev_obj) +{ + int32_t i; + + p2p_del_all_rand_mac_vdev(p2p_vdev_obj->vdev); + for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) { + qdf_mc_timer_destroy(&p2p_vdev_obj->random_mac[i].clear_timer); + qdf_list_destroy(&p2p_vdev_obj->random_mac[i].cookie_list); + } + qdf_spinlock_destroy(&p2p_vdev_obj->random_mac_lock); +} + QDF_STATUS p2p_process_mgmt_tx(struct tx_action_context *tx_ctx) { struct p2p_soc_priv_obj *p2p_soc_obj; @@ -1983,6 +2873,8 @@ QDF_STATUS p2p_process_mgmt_tx_ack_cnf( tx_cnf.action_cookie, tx_cnf.buf_len, tx_cnf.status, tx_cnf.buf); + p2p_rand_mac_tx_done(p2p_soc_obj->soc, tx_ctx); + /* disable tx timer */ p2p_disable_tx_timer(tx_ctx); diff --git a/umac/p2p/core/src/wlan_p2p_off_chan_tx.h b/umac/p2p/core/src/wlan_p2p_off_chan_tx.h index b7bb898765..367ecd6325 100644 --- a/umac/p2p/core/src/wlan_p2p_off_chan_tx.h +++ b/umac/p2p/core/src/wlan_p2p_off_chan_tx.h @@ -59,6 +59,8 @@ #define P2P_GET_TYPE_FRM_FC(__fc__) (((__fc__) & 0x0F) >> 2) #define P2P_GET_SUBTYPE_FRM_FC(__fc__) (((__fc__) & 0xF0) >> 4) +#define WLAN_WAIT_TIME_SET_RND 100 + struct p2p_soc_priv_obj; struct cancel_roc_context; struct p2p_tx_conf_event; @@ -172,12 +174,54 @@ struct tx_action_context { bool off_chan; bool no_cck; bool no_ack; + bool rand_mac_tx; uint32_t duration; qdf_mc_timer_t tx_timer; struct p2p_frame_info frame_info; qdf_nbuf_t nbuf; }; +/** + * p2p_rand_mac_tx_done() - process random mac mgmt tx done + * @soc: soc + * @tx_ctx: tx context + * + * This function will remove the random mac addr filter reference. + * + * Return: void + */ +void +p2p_rand_mac_tx_done(struct wlan_objmgr_psoc *soc, + struct tx_action_context *tx_ctx); + +/** + * p2p_clear_mac_filter() - send clear mac addr filter cmd + * @soc: soc + * @vdev_id: vdev id + * @mac: mac addr + * @freq: freq + * + * This function send clear random mac addr filter command to p2p component + * msg core + * + * Return: QDF_STATUS_SUCCESS - if sent successfully. + * otherwise: failed. + */ +QDF_STATUS +p2p_clear_mac_filter(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *mac, uint32_t freq); + +/** + * p2p_is_vdev_support_rand_mac() - check vdev type support random mac mgmt + * tx or not + * @vdev: vdev object + * + * Return: true: support random mac mgmt tx + * false: not support random mac mgmt tx. + */ +bool +p2p_is_vdev_support_rand_mac(struct wlan_objmgr_vdev *vdev); + /** * p2p_dump_tx_queue() - dump tx queue * @p2p_soc_obj: p2p soc private object @@ -285,4 +329,111 @@ QDF_STATUS p2p_process_rx_mgmt( struct tx_action_context *p2p_find_tx_ctx_by_nbuf( struct p2p_soc_priv_obj *p2p_soc_obj, void *nbuf); +#define P2P_80211_FRM_SA_OFFSET 10 + +/** + * p2p_del_random_mac() - del mac fitler from given vdev rand mac list + * @soc: soc object + * @vdev_id: vdev id + * @rnd_cookie: random mac mgmt tx cookie + * @duration: timeout value to flush the addr in target. + * + * This function will del the mac addr filter from vdev random mac addr list. + * If there is no reference to mac addr, it will set a clear timer to flush it + * in target finally. + * + * Return: QDF_STATUS_SUCCESS - del successfully. + * other : failed to del the mac address entry. + */ +QDF_STATUS +p2p_del_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint64_t rnd_cookie, uint32_t duration); + +/** + * p2p_check_random_mac() - check random mac addr or not + * @soc: soc context + * @vdev_id: vdev id + * @random_mac_addr: mac addr to be checked + * + * This function check the input addr is random mac addr or not for vdev. + * + * Return: true if addr is random mac address else false. + */ +bool p2p_check_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *random_mac_addr); + +/** + * p2p_process_set_rand_mac() - process the set random mac command + * @set_filter_req: request data + * + * This function will process the set mac addr filter command. + * + * Return: QDF_STATUS_SUCCESS: if process successfully + * other: failed. + */ +QDF_STATUS p2p_process_set_rand_mac( + struct p2p_set_mac_filter_req *set_filter_req); + +/** + * p2p_process_set_rand_mac_rsp() - process the set random mac response + * @resp: response date + * + * This function will process the set mac addr filter event. + * + * Return: QDF_STATUS_SUCCESS: if process successfully + * other: failed. + */ +QDF_STATUS p2p_process_set_rand_mac_rsp(struct p2p_mac_filter_rsp *resp); + +/** + * p2p_del_all_rand_mac_vdev() - del all random mac filter in vdev + * @vdev: vdev object + * + * This function will del all random mac filter in vdev + * + * Return: void + */ +void p2p_del_all_rand_mac_vdev(struct wlan_objmgr_vdev *vdev); + +/** + * p2p_del_all_rand_mac_soc() - del all random mac filter in soc + * @soc: soc object + * + * This function will del all random mac filter in all vdev of soc + * + * Return: void + */ +void p2p_del_all_rand_mac_soc(struct wlan_objmgr_psoc *soc); + +/** + * p2p_rand_mac_tx() - handle random mac mgmt tx + * @tx_action: tx action context + * + * This function will check whether need to set random mac tx filter for a + * given mgmt tx request and do the mac addr filter process as needed. + * + * Return: void + */ +void p2p_rand_mac_tx(struct tx_action_context *tx_action); + +/** + * p2p_init_random_mac_vdev() - Init random mac data for vdev + * @p2p_vdev_obj: p2p vdev private object + * + * This function will init the per vdev random mac data structure. + * + * Return: void + */ +void p2p_init_random_mac_vdev(struct p2p_vdev_priv_obj *p2p_vdev_obj); + +/** + * p2p_deinit_random_mac_vdev() - Init random mac data for vdev + * @p2p_vdev_obj: p2p vdev private object + * + * This function will deinit the per vdev random mac data structure. + * + * Return: void + */ +void p2p_deinit_random_mac_vdev(struct p2p_vdev_priv_obj *p2p_vdev_obj); + #endif /* _WLAN_P2P_OFF_CHAN_TX_H_ */ diff --git a/umac/p2p/dispatcher/inc/wlan_p2p_public_struct.h b/umac/p2p/dispatcher/inc/wlan_p2p_public_struct.h index 0c8eb282e4..d1c597ff35 100644 --- a/umac/p2p/dispatcher/inc/wlan_p2p_public_struct.h +++ b/umac/p2p/dispatcher/inc/wlan_p2p_public_struct.h @@ -147,6 +147,30 @@ struct p2p_mgmt_tx { const uint8_t *buf; }; +/** + * struct p2p_set_mac_filter + * @vdev_id: Vdev id + * @mac: mac addr + * @freq: frequency + * @set: set or clear + */ +struct p2p_set_mac_filter { + uint32_t vdev_id; + uint8_t mac[QDF_MAC_ADDR_SIZE]; + uint32_t freq; + bool set; +}; + +/** + * struct p2p_set_mac_filter_evt + * @vdev_id: Vdev id + * @status: target reported result of set mac addr filter + */ +struct p2p_set_mac_filter_evt { + uint32_t vdev_id; + uint32_t status; +}; + /** * struct p2p_ps_config * @vdev_id: Vdev id diff --git a/umac/p2p/dispatcher/inc/wlan_p2p_tgt_api.h b/umac/p2p/dispatcher/inc/wlan_p2p_tgt_api.h index 5412063263..0ca2074989 100644 --- a/umac/p2p/dispatcher/inc/wlan_p2p_tgt_api.h +++ b/umac/p2p/dispatcher/inc/wlan_p2p_tgt_api.h @@ -83,6 +83,19 @@ static inline QDF_STATUS tgt_p2p_unregister_lo_ev_handler( } #endif +/** + * tgt_p2p_register_macaddr_rx_filter_evt_handler() - register add mac rx + * filter status event + * @psoc: soc object + * @register: register or unregister + * + * p2p tgt api to register add mac rx filter status event + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS tgt_p2p_register_macaddr_rx_filter_evt_handler( + struct wlan_objmgr_psoc *psoc, bool register); + /** * tgt_p2p_register_noa_ev_handler() - register noa event * @psoc: soc object @@ -178,4 +191,18 @@ QDF_STATUS tgt_p2p_mgmt_frame_rx_cb(struct wlan_objmgr_psoc *psoc, QDF_STATUS tgt_p2p_noa_event_cb(struct wlan_objmgr_psoc *psoc, struct p2p_noa_info *event_info); +/** + * tgt_p2p_add_mac_addr_status_event_cb() - Callback for set mac addr filter evt + * @psoc: soc object + * @event_info: event information type of p2p_set_mac_filter_evt + * + * This function gets called from target interface. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +tgt_p2p_add_mac_addr_status_event_cb( + struct wlan_objmgr_psoc *psoc, + struct p2p_set_mac_filter_evt *event_info); + #endif /* _WLAN_P2P_TGT_API_H_ */ diff --git a/umac/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h b/umac/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h index 0cdc9bd322..da39720514 100644 --- a/umac/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h +++ b/umac/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h @@ -257,6 +257,7 @@ QDF_STATUS ucfg_p2p_mgmt_tx(struct wlan_objmgr_psoc *soc, /** * ucfg_p2p_mgmt_tx_cancel() - Cancel mgmt frame tx request * @soc: soc context + * @vdev: vdev object * @cookie: Find out the mgmt tx request by cookie * * This function delivers cancel mgmt frame tx request request to P2P @@ -265,7 +266,7 @@ QDF_STATUS ucfg_p2p_mgmt_tx(struct wlan_objmgr_psoc *soc, * Return: QDF_STATUS_SUCCESS - in case of success */ QDF_STATUS ucfg_p2p_mgmt_tx_cancel(struct wlan_objmgr_psoc *soc, - uint64_t cookie); + struct wlan_objmgr_vdev *vdev, uint64_t cookie); /** * ucfg_p2p_set_ps() - P2P set power save @@ -331,6 +332,19 @@ void p2p_peer_authorized(struct wlan_objmgr_vdev *vdev, uint8_t *mac_addr); QDF_STATUS ucfg_p2p_set_noa(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, bool disable_noa); +/** + * ucfg_p2p_check_random_mac() - check random mac addr or not + * @soc: soc context + * @vdev_id: vdev id + * @random_mac_addr: mac addr to be checked + * + * This function check the input addr is random mac addr or not for vdev. + * + * Return: true if addr is random mac address else false. + */ +bool ucfg_p2p_check_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *random_mac_addr); + /** * ucfg_p2p_register_callbacks() - register p2p callbacks * @soc: soc context diff --git a/umac/p2p/dispatcher/src/wlan_p2p_tgt_api.c b/umac/p2p/dispatcher/src/wlan_p2p_tgt_api.c index 3dbc7ff0cd..fd10b349c1 100644 --- a/umac/p2p/dispatcher/src/wlan_p2p_tgt_api.c +++ b/umac/p2p/dispatcher/src/wlan_p2p_tgt_api.c @@ -124,6 +124,67 @@ QDF_STATUS tgt_p2p_lo_event_cb(struct wlan_objmgr_psoc *psoc, } #endif /* FEATURE_P2P_LISTEN_OFFLOAD */ +QDF_STATUS +tgt_p2p_add_mac_addr_status_event_cb(struct wlan_objmgr_psoc *psoc, + struct p2p_set_mac_filter_evt *event_info) +{ + struct p2p_mac_filter_rsp *mac_filter_rsp; + struct scheduler_msg msg = {0}; + struct p2p_soc_priv_obj *p2p_soc_obj; + QDF_STATUS status; + + if (!psoc) { + p2p_err("random_mac:psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + if (!event_info) { + p2p_err("random_mac:invalid event_info"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj( + psoc, WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("random_mac:p2p soc object is NULL"); + return QDF_STATUS_E_INVAL; + } + + mac_filter_rsp = qdf_mem_malloc(sizeof(*mac_filter_rsp)); + if (!mac_filter_rsp) { + p2p_err("random_mac:Failed to allocate mac_filter_rsp"); + return QDF_STATUS_E_NOMEM; + } + + mac_filter_rsp->p2p_soc_obj = p2p_soc_obj; + mac_filter_rsp->vdev_id = event_info->vdev_id; + mac_filter_rsp->status = event_info->status; + + msg.type = P2P_EVENT_ADD_MAC_RSP; + msg.bodyptr = mac_filter_rsp; + msg.callback = p2p_process_evt; + status = scheduler_post_msg(QDF_MODULE_ID_TARGET_IF, &msg); + if (status != QDF_STATUS_SUCCESS) + qdf_mem_free(mac_filter_rsp); + + return status; +} + +QDF_STATUS tgt_p2p_register_macaddr_rx_filter_evt_handler( + struct wlan_objmgr_psoc *psoc, bool reg) +{ + struct wlan_lmac_if_p2p_tx_ops *p2p_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + p2p_ops = wlan_psoc_get_p2p_tx_ops(psoc); + if (p2p_ops && p2p_ops->reg_mac_addr_rx_filter_handler) { + status = p2p_ops->reg_mac_addr_rx_filter_handler(psoc, reg); + p2p_debug("register mac addr rx filter event, register %d status:%d", + reg, status); + } + + return status; +} + QDF_STATUS tgt_p2p_register_noa_ev_handler( struct wlan_objmgr_psoc *psoc) { diff --git a/umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c b/umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c index da0f423b90..08e27a8314 100644 --- a/umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c +++ b/umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c @@ -280,6 +280,7 @@ QDF_STATUS ucfg_p2p_cleanup_tx_by_vdev(struct wlan_objmgr_vdev *vdev) p2p_err("null p2p soc obj"); return QDF_STATUS_E_FAILURE; } + p2p_del_all_rand_mac_vdev(vdev); return p2p_cleanup_tx_sync(obj, vdev); } @@ -298,6 +299,7 @@ QDF_STATUS ucfg_p2p_cleanup_tx_by_psoc(struct wlan_objmgr_psoc *psoc) p2p_err("null p2p soc obj"); return QDF_STATUS_E_FAILURE; } + p2p_del_all_rand_mac_soc(psoc); return p2p_cleanup_tx_sync(obj, NULL); } @@ -365,6 +367,9 @@ QDF_STATUS ucfg_p2p_mgmt_tx(struct wlan_objmgr_psoc *soc, qdf_mem_copy(tx_action->buf, mgmt_frm->buf, tx_action->buf_len); tx_action->nbuf = NULL; tx_action->id = id; + + p2p_rand_mac_tx(tx_action); + msg.type = P2P_MGMT_TX; msg.bodyptr = tx_action; msg.callback = p2p_process_cmd; @@ -376,7 +381,7 @@ QDF_STATUS ucfg_p2p_mgmt_tx(struct wlan_objmgr_psoc *soc, } QDF_STATUS ucfg_p2p_mgmt_tx_cancel(struct wlan_objmgr_psoc *soc, - uint64_t cookie) + struct wlan_objmgr_vdev *vdev, uint64_t cookie) { struct scheduler_msg msg = {0}; struct p2p_soc_priv_obj *p2p_soc_obj; @@ -402,6 +407,7 @@ QDF_STATUS ucfg_p2p_mgmt_tx_cancel(struct wlan_objmgr_psoc *soc, p2p_debug("invalid id"); return QDF_STATUS_E_INVAL; } + p2p_del_random_mac(soc, wlan_vdev_get_id(vdev), cookie, 20); cancel_tx = qdf_mem_malloc(sizeof(*cancel_tx)); if (!cancel_tx) { @@ -421,6 +427,12 @@ QDF_STATUS ucfg_p2p_mgmt_tx_cancel(struct wlan_objmgr_psoc *soc, return QDF_STATUS_SUCCESS; } +bool ucfg_p2p_check_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *random_mac_addr) +{ + return p2p_check_random_mac(soc, vdev_id, random_mac_addr); +} + QDF_STATUS ucfg_p2p_set_ps(struct wlan_objmgr_psoc *soc, struct p2p_ps_config *ps_config) { diff --git a/wmi/inc/wmi_unified_p2p_api.h b/wmi/inc/wmi_unified_p2p_api.h index bfca908fbe..3a571582a1 100644 --- a/wmi/inc/wmi_unified_p2p_api.h +++ b/wmi/inc/wmi_unified_p2p_api.h @@ -56,6 +56,29 @@ QDF_STATUS wmi_extract_p2p_noa_ev_param(void *wmi_hdl, void *evt_buf, struct p2p_noa_info *param); +/** + * wmi_send_set_mac_addr_rx_filter_cmd() - set mac addr rx filter cmd + * @wmi_hdl: wmi handle + * @param: Pointer to set mac filter struct + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_send_set_mac_addr_rx_filter_cmd(void *wmi_hdl, + struct p2p_set_mac_filter *param); + +/** + * wmi_extract_mac_addr_rx_filter_evt_param() - extract mac addr rx filter evt + * @wmi_hdl: wmi handle + * @evt_buf: pointer to event buffer + * @param: Pointer to extracted evt info + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_extract_mac_addr_rx_filter_evt_param(void *wmi_hdl, void *evt_buf, + struct p2p_set_mac_filter_evt *param); + #ifdef FEATURE_P2P_LISTEN_OFFLOAD /** * wmi_unified_p2p_lo_start_cmd() - send p2p lo start request to fw diff --git a/wmi/inc/wmi_unified_param.h b/wmi/inc/wmi_unified_param.h index baf6399c04..aa49e25969 100644 --- a/wmi/inc/wmi_unified_param.h +++ b/wmi/inc/wmi_unified_param.h @@ -4622,6 +4622,7 @@ typedef enum { wmi_p2p_disc_event_id, wmi_p2p_noa_event_id, wmi_p2p_lo_stop_event_id, + wmi_vdev_add_macaddr_rx_filter_event_id, wmi_pdev_resume_event_id, wmi_d0_wow_disable_ack_event_id, wmi_wow_initial_wakeup_event_id, diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index 16c07c9ba3..ef166173d4 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -1439,6 +1439,13 @@ QDF_STATUS (*extract_p2p_lo_stop_ev_param)(wmi_unified_t wmi_handle, QDF_STATUS (*extract_p2p_noa_ev_param)(wmi_unified_t wmi_handle, void *evt_buf, struct p2p_noa_info *param); + +QDF_STATUS (*set_mac_addr_rx_filter)(wmi_unified_t wmi_handle, + struct p2p_set_mac_filter *param); +QDF_STATUS +(*extract_mac_addr_rx_filter_evt_param)(wmi_unified_t wmi_handle, + void *evt_buf, + struct p2p_set_mac_filter_evt *param); #endif QDF_STATUS (*extract_peer_sta_ps_statechange_ev)(wmi_unified_t wmi_handle, diff --git a/wmi/src/wmi_unified_p2p_api.c b/wmi/src/wmi_unified_p2p_api.c index 12a0005f46..a50d8d69e0 100644 --- a/wmi/src/wmi_unified_p2p_api.c +++ b/wmi/src/wmi_unified_p2p_api.c @@ -63,6 +63,42 @@ QDF_STATUS wmi_extract_p2p_noa_ev_param(void *wmi_hdl, void *evt_buf, return QDF_STATUS_E_FAILURE; } +QDF_STATUS +wmi_send_set_mac_addr_rx_filter_cmd(void *wmi_hdl, + struct p2p_set_mac_filter *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t)wmi_hdl; + + if (!wmi_handle) { + WMI_LOGE("wmi handle is null"); + return QDF_STATUS_E_INVAL; + } + + if (wmi_handle->ops->set_mac_addr_rx_filter) + return wmi_handle->ops->set_mac_addr_rx_filter( + wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_mac_addr_rx_filter_evt_param(void *wmi_hdl, void *evt_buf, + struct p2p_set_mac_filter_evt *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t)wmi_hdl; + + if (!wmi_handle) { + WMI_LOGE("wmi handle is null"); + return QDF_STATUS_E_INVAL; + } + + if (wmi_handle->ops->extract_mac_addr_rx_filter_evt_param) + return wmi_handle->ops->extract_mac_addr_rx_filter_evt_param( + wmi_handle, evt_buf, param); + + return QDF_STATUS_E_FAILURE; +} + #ifdef FEATURE_P2P_LISTEN_OFFLOAD QDF_STATUS wmi_unified_p2p_lo_start_cmd(void *wmi_hdl, struct p2p_lo_start *param) diff --git a/wmi/src/wmi_unified_p2p_tlv.c b/wmi/src/wmi_unified_p2p_tlv.c index 3ed9705d2b..4ea6c630b0 100644 --- a/wmi/src/wmi_unified_p2p_tlv.c +++ b/wmi/src/wmi_unified_p2p_tlv.c @@ -213,6 +213,81 @@ static QDF_STATUS extract_p2p_noa_ev_param_tlv( return QDF_STATUS_SUCCESS; } +static QDF_STATUS +send_set_mac_addr_rx_filter_cmd_tlv(wmi_unified_t wmi_handle, + struct p2p_set_mac_filter *param) +{ + wmi_vdev_add_mac_addr_to_rx_filter_cmd_fixed_param *cmd; + uint32_t len; + wmi_buf_t buf; + int ret; + + if (!wmi_handle) { + WMI_LOGE("WMA context is invald!"); + return QDF_STATUS_E_INVAL; + } + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("Failed allocate wmi buffer"); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_vdev_add_mac_addr_to_rx_filter_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_add_mac_addr_to_rx_filter_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_add_mac_addr_to_rx_filter_cmd_fixed_param)); + + cmd->vdev_id = param->vdev_id; + cmd->freq = param->freq; + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->mac, &cmd->mac_addr); + if (param->set) + cmd->enable = 1; + else + cmd->enable = 0; + WMI_LOGD("set random mac rx vdev %d freq %d set %d %pM", + param->vdev_id, param->freq, param->set, param->mac); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID); + if (ret) { + WMI_LOGE("Failed to send action frame random mac cmd"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS extract_mac_addr_rx_filter_evt_param_tlv( + wmi_unified_t wmi_handle, void *evt_buf, + struct p2p_set_mac_filter_evt *param) +{ + WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_STATUS_EVENTID_param_tlvs *param_buf; + wmi_vdev_add_mac_addr_to_rx_filter_status_event_fixed_param *event; + + param_buf = + (WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_STATUS_EVENTID_param_tlvs *) + evt_buf; + if (!param_buf) { + WMI_LOGE("Invalid action frame filter mac event"); + return QDF_STATUS_E_INVAL; + } + event = param_buf->fixed_param; + if (!event) { + WMI_LOGE("Invalid fixed param"); + return QDF_STATUS_E_INVAL; + } + param->vdev_id = event->vdev_id; + param->status = event->status; + + return QDF_STATUS_SUCCESS; +} + #ifdef FEATURE_P2P_LISTEN_OFFLOAD /** * send_p2p_lo_start_cmd_tlv() - send p2p lo start request to fw @@ -406,6 +481,9 @@ void wmi_p2p_attach_tlv(wmi_unified_t wmi_handle) ops->send_set_p2pgo_oppps_req_cmd = send_set_p2pgo_oppps_req_cmd_tlv; ops->send_set_p2pgo_noa_req_cmd = send_set_p2pgo_noa_req_cmd_tlv; ops->extract_p2p_noa_ev_param = extract_p2p_noa_ev_param_tlv; + ops->set_mac_addr_rx_filter = send_set_mac_addr_rx_filter_cmd_tlv, + ops->extract_mac_addr_rx_filter_evt_param = + extract_mac_addr_rx_filter_evt_param_tlv, wmi_p2p_listen_offload_attach_tlv(wmi_handle); } diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index 80efb59819..413ce6a3e0 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -11246,6 +11246,8 @@ static void populate_tlv_events_id(uint32_t *event_ids) event_ids[wmi_p2p_noa_event_id] = WMI_P2P_NOA_EVENTID; event_ids[wmi_p2p_lo_stop_event_id] = WMI_P2P_LISTEN_OFFLOAD_STOPPED_EVENTID; + event_ids[wmi_vdev_add_macaddr_rx_filter_event_id] = + WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_STATUS_EVENTID; event_ids[wmi_pdev_resume_event_id] = WMI_PDEV_RESUME_EVENTID; event_ids[wmi_wow_wakeup_host_event_id] = WMI_WOW_WAKEUP_HOST_EVENTID; event_ids[wmi_d0_wow_disable_ack_event_id] =