diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 23680310c696..47c3a1fa4e7e 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -767,6 +767,8 @@ enum bss_state { * When a STA is disassociated userspace thread can wait on this * event. The event will be set when the STA Disassociation * processing in UMAC has completed. + * @qdf_sta_eap_frm_done_event: Event to synchronize P2P GO disassoc + * frame and EAP frame. * @qdf_status: Used to communicate state from other threads to the * userspace thread. */ @@ -775,6 +777,7 @@ struct hdd_hostapd_state { qdf_event_t qdf_event; qdf_event_t qdf_stop_bss_event; qdf_event_t qdf_sta_disassoc_event; + qdf_event_t qdf_sta_eap_frm_done_event; QDF_STATUS qdf_status; }; diff --git a/core/hdd/inc/wlan_hdd_softap_tx_rx.h b/core/hdd/inc/wlan_hdd_softap_tx_rx.h index 77f637aa08ad..883c0fde449c 100644 --- a/core/hdd/inc/wlan_hdd_softap_tx_rx.h +++ b/core/hdd/inc/wlan_hdd_softap_tx_rx.h @@ -258,4 +258,16 @@ int hdd_softap_inspect_dhcp_packet(struct hdd_adapter *adapter, } #endif +/** + * hdd_softap_check_wait_for_tx_eap_pkt() - Check and wait for eap failure + * pkt completion event + * @adapter: pointer to hdd adapter + * @mac_addr: mac address of peer + * + * Check and wait for eap failure pkt tx completion. + * + * Return: void + */ +void hdd_softap_check_wait_for_tx_eap_pkt(struct hdd_adapter *adapter, + struct qdf_mac_addr *mac_addr); #endif /* end #if !defined(WLAN_HDD_SOFTAP_TX_RX_H) */ diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 25ae6e09a1d0..cc2bdd2da53a 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -20767,6 +20767,10 @@ int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, param))) goto fn_end; } else { + if (param->reason_code == eSIR_MAC_1X_AUTH_FAILURE_REASON) + hdd_softap_check_wait_for_tx_eap_pkt( + adapter, (struct qdf_mac_addr *)mac); + sta_info = hdd_get_sta_info_by_mac(&adapter->sta_info_list, mac); diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index d6bfb8b82602..84b236a1a94f 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -3479,6 +3479,12 @@ QDF_STATUS hdd_init_ap_mode(struct hdd_adapter *adapter, bool reinit) goto error_deinit_sap_session; } + status = qdf_event_create(&phostapdBuf->qdf_sta_eap_frm_done_event); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Hostapd HDD sta eap frm done event init failed!!"); + goto error_deinit_sap_session; + } + /* Register as a wireless device */ hdd_register_hostapd_wext(adapter->dev); diff --git a/core/hdd/src/wlan_hdd_softap_tx_rx.c b/core/hdd/src/wlan_hdd_softap_tx_rx.c index fbf873a63b9d..c1e0c9c57702 100644 --- a/core/hdd/src/wlan_hdd_softap_tx_rx.c +++ b/core/hdd/src/wlan_hdd_softap_tx_rx.c @@ -239,6 +239,106 @@ static inline struct sk_buff *hdd_skb_orphan(struct hdd_adapter *adapter, } #endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ +#define IEEE8021X_AUTH_TYPE_EAP 0 +#define EAP_CODE_OFFSET 18 +#define EAP_CODE_FAILURE 4 + +/* Wait EAP Failure frame timeout in (MS) */ +#define EAP_FRM_TIME_OUT 80 + +/** + * hdd_softap_inspect_tx_eap_pkt() - Inspect eap pkt tx/tx-completion + * @adapter: pointer to hdd adapter + * @skb: sk_buff + * @tx_comp: tx sending or tx completion + * + * Inspect the EAP-Failure pkt tx sending and tx completion. + * + * Return: void + */ +static void hdd_softap_inspect_tx_eap_pkt(struct hdd_adapter *adapter, + struct sk_buff *skb, + bool tx_comp) +{ + struct qdf_mac_addr *mac_addr; + uint8_t *data; + uint8_t auth_type, eap_code; + struct hdd_station_info *sta_info; + struct hdd_hostapd_state *hapd_state; + + if (qdf_likely(QDF_NBUF_CB_GET_PACKET_TYPE(skb) != + QDF_NBUF_CB_PACKET_TYPE_EAPOL) || skb->len < (EAP_CODE_OFFSET + 1)) + return; + + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state() || + cds_is_load_or_unload_in_progress()) { + hdd_debug("Recovery/(Un)load in Progress. Ignore!!!"); + return; + } + if (adapter->device_mode != QDF_P2P_GO_MODE) + return; + hapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + if (!hapd_state || hapd_state->bss_state != BSS_START) { + hdd_debug("Hostapd State is not START"); + return; + } + data = skb->data; + auth_type = *(uint8_t *)(data + EAPOL_PACKET_TYPE_OFFSET); + if (auth_type != IEEE8021X_AUTH_TYPE_EAP) + return; + eap_code = *(uint8_t *)(data + EAP_CODE_OFFSET); + if (eap_code != EAP_CODE_FAILURE) + return; + mac_addr = (struct qdf_mac_addr *)skb->data; + sta_info = hdd_get_sta_info_by_mac(&adapter->sta_info_list, + mac_addr->bytes); + if (!sta_info) + return; + if (tx_comp) { + hdd_debug("eap_failure frm tx done %pM", mac_addr); + qdf_atomic_clear_bit(PENDING_TYPE_EAP_FAILURE, + &sta_info->pending_eap_frm_type); + qdf_event_set(&hapd_state->qdf_sta_eap_frm_done_event); + } else { + hdd_debug("eap_failure frm tx pending %pM", mac_addr); + qdf_event_reset(&hapd_state->qdf_sta_eap_frm_done_event); + qdf_atomic_set_bit(PENDING_TYPE_EAP_FAILURE, + &sta_info->pending_eap_frm_type); + QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(skb) = 1; + } + hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true); +} + +void hdd_softap_check_wait_for_tx_eap_pkt(struct hdd_adapter *adapter, + struct qdf_mac_addr *mac_addr) +{ + struct hdd_station_info *sta_info; + QDF_STATUS qdf_status; + struct hdd_hostapd_state *hapd_state; + + if (adapter->device_mode != QDF_P2P_GO_MODE) + return; + hapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + if (!hapd_state || hapd_state->bss_state != BSS_START) { + hdd_err("Hostapd State is not START"); + return; + } + sta_info = hdd_get_sta_info_by_mac(&adapter->sta_info_list, + mac_addr->bytes); + if (!sta_info) + return; + if (qdf_atomic_test_bit(PENDING_TYPE_EAP_FAILURE, + &sta_info->pending_eap_frm_type)) { + hdd_debug("eap_failure frm pending %pM", mac_addr); + qdf_status = qdf_wait_for_event_completion( + &hapd_state->qdf_sta_eap_frm_done_event, + EAP_FRM_TIME_OUT); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_debug("eap_failure tx timeout"); + } + hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true); +} + #ifdef SAP_DHCP_FW_IND /** * hdd_post_dhcp_ind() - Send DHCP START/STOP indication to FW @@ -576,6 +676,7 @@ static void __hdd_softap_hard_start_xmit(struct sk_buff *skb, QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(skb) = 0; hdd_softap_inspect_dhcp_packet(adapter, skb, QDF_TX); + hdd_softap_inspect_tx_eap_pkt(adapter, skb, false); hdd_event_eapol_log(skb, QDF_TX); QDF_NBUF_CB_TX_PACKET_TRACK(skb) = QDF_NBUF_TX_PKT_DATA_TRACK; @@ -817,6 +918,9 @@ static void hdd_softap_notify_tx_compl_cbk(struct sk_buff *skb, if (QDF_NBUF_CB_PACKET_TYPE_DHCP == QDF_NBUF_CB_GET_PACKET_TYPE(skb)) { hdd_debug("sending DHCP indication"); hdd_softap_notify_dhcp_ind(context, skb); + } else if (QDF_NBUF_CB_GET_PACKET_TYPE(skb) == + QDF_NBUF_CB_PACKET_TYPE_EAPOL) { + hdd_softap_inspect_tx_eap_pkt(adapter, skb, true); } } diff --git a/core/hdd/src/wlan_hdd_sta_info.h b/core/hdd/src/wlan_hdd_sta_info.h index ff311b8dce7f..b8a19de41fe4 100644 --- a/core/hdd/src/wlan_hdd_sta_info.h +++ b/core/hdd/src/wlan_hdd_sta_info.h @@ -67,6 +67,12 @@ enum dhcp_nego_status { DHCP_NEGO_IN_PROGRESS }; +/** + * Pending frame type of EAP_FAILURE, bit number used in "pending_eap_frm_type" + * of sta_info. + */ +#define PENDING_TYPE_EAP_FAILURE 0 + /** * struct hdd_station_info - Per station structure kept in HDD for * multiple station support for SoftAP @@ -123,6 +129,7 @@ enum dhcp_nego_status { * @sta_info: The sta_info node for the station info list maintained in adapter * @assoc_req_ies: Assoc request IEs of the peer station * @ref_cnt: Reference count to synchronize sta_info access + * @pending_eap_frm_type: EAP frame type in tx queue without tx completion */ struct hdd_station_info { bool in_use; @@ -173,6 +180,7 @@ struct hdd_station_info { struct qdf_ht_entry sta_node; struct wlan_ies assoc_req_ies; qdf_atomic_t ref_cnt; + unsigned long pending_eap_frm_type; }; /**