xref: /linux/drivers/net/wireless/nxp/nxpwifi/uap_event.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
173b01e57SJeff Chen // SPDX-License-Identifier: GPL-2.0-only
273b01e57SJeff Chen /*
373b01e57SJeff Chen  * NXP Wireless LAN device driver: AP event handling
473b01e57SJeff Chen  *
573b01e57SJeff Chen  * Copyright 2011-2024 NXP
673b01e57SJeff Chen  */
773b01e57SJeff Chen 
873b01e57SJeff Chen #include "cfg.h"
973b01e57SJeff Chen #include "main.h"
1073b01e57SJeff Chen #include "cmdevt.h"
1173b01e57SJeff Chen #include "11n.h"
1273b01e57SJeff Chen 
1373b01e57SJeff Chen #define NXPWIFI_BSS_START_EVT_FIX_SIZE    12
1473b01e57SJeff Chen 
1573b01e57SJeff Chen static int
nxpwifi_uap_event_ps_awake(struct nxpwifi_private * priv)1673b01e57SJeff Chen nxpwifi_uap_event_ps_awake(struct nxpwifi_private *priv)
1773b01e57SJeff Chen {
1873b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
1973b01e57SJeff Chen 
2073b01e57SJeff Chen 	if (!adapter->pps_uapsd_mode &&
2173b01e57SJeff Chen 	    priv->media_connected && adapter->sleep_period.period) {
2273b01e57SJeff Chen 		adapter->pps_uapsd_mode = true;
2373b01e57SJeff Chen 		nxpwifi_dbg(adapter, EVENT,
2473b01e57SJeff Chen 			    "event: PPS/UAPSD mode activated\n");
2573b01e57SJeff Chen 	}
2673b01e57SJeff Chen 	adapter->tx_lock_flag = false;
2773b01e57SJeff Chen 	if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
2873b01e57SJeff Chen 		if (nxpwifi_check_last_packet_indication(priv)) {
2973b01e57SJeff Chen 			if (adapter->data_sent) {
3073b01e57SJeff Chen 				adapter->ps_state = PS_STATE_AWAKE;
3173b01e57SJeff Chen 				adapter->pm_wakeup_card_req = false;
3273b01e57SJeff Chen 				adapter->pm_wakeup_fw_try = false;
3373b01e57SJeff Chen 			} else {
3473b01e57SJeff Chen 				if (!nxpwifi_send_null_packet
3573b01e57SJeff Chen 				    (priv,
3673b01e57SJeff Chen 				     NXPWIFI_TxPD_POWER_MGMT_NULL_PACKET |
3773b01e57SJeff Chen 				     NXPWIFI_TxPD_POWER_MGMT_LAST_PACKET))
3873b01e57SJeff Chen 					adapter->ps_state = PS_STATE_SLEEP;
3973b01e57SJeff Chen 			}
4073b01e57SJeff Chen 
4173b01e57SJeff Chen 			return 0;
4273b01e57SJeff Chen 		}
4373b01e57SJeff Chen 	}
4473b01e57SJeff Chen 
4573b01e57SJeff Chen 	adapter->ps_state = PS_STATE_AWAKE;
4673b01e57SJeff Chen 	adapter->pm_wakeup_card_req = false;
4773b01e57SJeff Chen 	adapter->pm_wakeup_fw_try = false;
4873b01e57SJeff Chen 
4973b01e57SJeff Chen 	return 0;
5073b01e57SJeff Chen }
5173b01e57SJeff Chen 
5273b01e57SJeff Chen static int
nxpwifi_uap_event_ps_sleep(struct nxpwifi_private * priv)5373b01e57SJeff Chen nxpwifi_uap_event_ps_sleep(struct nxpwifi_private *priv)
5473b01e57SJeff Chen {
5573b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
5673b01e57SJeff Chen 
5773b01e57SJeff Chen 	adapter->ps_state = PS_STATE_PRE_SLEEP;
5873b01e57SJeff Chen 	nxpwifi_check_ps_cond(adapter);
5973b01e57SJeff Chen 
6073b01e57SJeff Chen 	return 0;
6173b01e57SJeff Chen }
6273b01e57SJeff Chen 
6373b01e57SJeff Chen static int
nxpwifi_uap_event_sta_deauth(struct nxpwifi_private * priv)6473b01e57SJeff Chen nxpwifi_uap_event_sta_deauth(struct nxpwifi_private *priv)
6573b01e57SJeff Chen {
6673b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
6773b01e57SJeff Chen 	u8 *deauth_mac;
6873b01e57SJeff Chen 
6973b01e57SJeff Chen 	deauth_mac = adapter->event_body +
7073b01e57SJeff Chen 		     NXPWIFI_UAP_EVENT_EXTRA_HEADER;
7173b01e57SJeff Chen 	cfg80211_del_sta(priv->netdev->ieee80211_ptr, deauth_mac, GFP_KERNEL);
7273b01e57SJeff Chen 
7373b01e57SJeff Chen 	if (priv->ap_11n_enabled) {
7473b01e57SJeff Chen 		nxpwifi_11n_del_rx_reorder_tbl_by_ta(priv, deauth_mac);
7573b01e57SJeff Chen 		nxpwifi_del_tx_ba_stream_tbl_by_ra(priv, deauth_mac);
7673b01e57SJeff Chen 	}
7773b01e57SJeff Chen 	nxpwifi_wmm_del_peer_ra_list(priv, deauth_mac);
7873b01e57SJeff Chen 
7973b01e57SJeff Chen 	return 0;
8073b01e57SJeff Chen }
8173b01e57SJeff Chen 
8273b01e57SJeff Chen static int
nxpwifi_uap_event_sta_assoc(struct nxpwifi_private * priv)8373b01e57SJeff Chen nxpwifi_uap_event_sta_assoc(struct nxpwifi_private *priv)
8473b01e57SJeff Chen {
8573b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
8673b01e57SJeff Chen 	struct station_info *sinfo;
8773b01e57SJeff Chen 	struct nxpwifi_assoc_event *event;
8873b01e57SJeff Chen 	struct nxpwifi_sta_node *node;
8973b01e57SJeff Chen 	int len, i;
9073b01e57SJeff Chen 
9173b01e57SJeff Chen 	sinfo = kzalloc_obj(*sinfo, GFP_KERNEL);
9273b01e57SJeff Chen 	if (!sinfo)
9373b01e57SJeff Chen 		return -ENOMEM;
9473b01e57SJeff Chen 
9573b01e57SJeff Chen 	event = (struct nxpwifi_assoc_event *)
9673b01e57SJeff Chen 		(adapter->event_body + NXPWIFI_UAP_EVENT_EXTRA_HEADER);
9773b01e57SJeff Chen 	if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
9873b01e57SJeff Chen 		len = -1;
9973b01e57SJeff Chen 
10073b01e57SJeff Chen 		if (ieee80211_is_assoc_req(event->frame_control))
10173b01e57SJeff Chen 			len = 0;
10273b01e57SJeff Chen 		else if (ieee80211_is_reassoc_req(event->frame_control))
10373b01e57SJeff Chen 			/*
10473b01e57SJeff Chen 			 * There will be ETH_ALEN bytes of
10573b01e57SJeff Chen 			 * current_ap_addr before the re-assoc ies.
10673b01e57SJeff Chen 			 */
10773b01e57SJeff Chen 			len = ETH_ALEN;
10873b01e57SJeff Chen 
10973b01e57SJeff Chen 		if (len != -1) {
110*ca800a93SLinmao Li 			u16 evt_len = le16_to_cpu(event->len);
111*ca800a93SLinmao Li 
11273b01e57SJeff Chen 			sinfo->assoc_req_ies = &event->data[len];
11373b01e57SJeff Chen 			len = (u8 *)sinfo->assoc_req_ies -
11473b01e57SJeff Chen 			      (u8 *)&event->frame_control;
115*ca800a93SLinmao Li 
116*ca800a93SLinmao Li 			/*
117*ca800a93SLinmao Li 			 * event->len is reported by the device firmware
118*ca800a93SLinmao Li 			 * and is not otherwise validated. Reject a length
119*ca800a93SLinmao Li 			 * that underflows the header or that would place
120*ca800a93SLinmao Li 			 * the association request IEs outside the fixed
121*ca800a93SLinmao Li 			 * event_body[] buffer.
122*ca800a93SLinmao Li 			 */
123*ca800a93SLinmao Li 			if (evt_len < len ||
124*ca800a93SLinmao Li 			    (u8 *)&event->frame_control + evt_len >
125*ca800a93SLinmao Li 			    adapter->event_body + MAX_EVENT_SIZE) {
126*ca800a93SLinmao Li 				nxpwifi_dbg(adapter, ERROR,
127*ca800a93SLinmao Li 					    "invalid STA assoc event length\n");
128*ca800a93SLinmao Li 				kfree(sinfo);
129*ca800a93SLinmao Li 				return -EINVAL;
130*ca800a93SLinmao Li 			}
131*ca800a93SLinmao Li 
132*ca800a93SLinmao Li 			sinfo->assoc_req_ies_len = evt_len - (u16)len;
13373b01e57SJeff Chen 		}
13473b01e57SJeff Chen 	}
13573b01e57SJeff Chen 	cfg80211_new_sta(priv->netdev->ieee80211_ptr, event->sta_addr, sinfo,
13673b01e57SJeff Chen 			 GFP_KERNEL);
13773b01e57SJeff Chen 
13873b01e57SJeff Chen 	node = nxpwifi_add_sta_entry(priv, event->sta_addr);
13973b01e57SJeff Chen 	if (!node) {
14073b01e57SJeff Chen 		nxpwifi_dbg(adapter, ERROR,
14173b01e57SJeff Chen 			    "could not create station entry!\n");
14273b01e57SJeff Chen 		kfree(sinfo);
14373b01e57SJeff Chen 		return -ENOENT;
14473b01e57SJeff Chen 	}
14573b01e57SJeff Chen 
14673b01e57SJeff Chen 	if (!priv->ap_11n_enabled) {
14773b01e57SJeff Chen 		kfree(sinfo);
14873b01e57SJeff Chen 		return 0;
14973b01e57SJeff Chen 	}
15073b01e57SJeff Chen 
15173b01e57SJeff Chen 	nxpwifi_set_sta_ht_cap(priv, sinfo->assoc_req_ies,
15273b01e57SJeff Chen 			       sinfo->assoc_req_ies_len, node);
15373b01e57SJeff Chen 
15473b01e57SJeff Chen 	for (i = 0; i < MAX_NUM_TID; i++) {
15573b01e57SJeff Chen 		if (node->is_11n_enabled || node->is_11ax_enabled)
15673b01e57SJeff Chen 			node->ampdu_sta[i] =
15773b01e57SJeff Chen 				      priv->aggr_prio_tbl[i].ampdu_user;
15873b01e57SJeff Chen 		else
15973b01e57SJeff Chen 			node->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
16073b01e57SJeff Chen 	}
16173b01e57SJeff Chen 	memset(node->rx_seq, 0xff, sizeof(node->rx_seq));
16273b01e57SJeff Chen 	kfree(sinfo);
16373b01e57SJeff Chen 
16473b01e57SJeff Chen 	return 0;
16573b01e57SJeff Chen }
16673b01e57SJeff Chen 
16773b01e57SJeff Chen static int
nxpwifi_check_uap_capabilities(struct nxpwifi_private * priv,struct sk_buff * event)16873b01e57SJeff Chen nxpwifi_check_uap_capabilities(struct nxpwifi_private *priv,
16973b01e57SJeff Chen 			       struct sk_buff *event)
17073b01e57SJeff Chen {
17173b01e57SJeff Chen 	int evt_len;
17273b01e57SJeff Chen 	u8 *curr;
17373b01e57SJeff Chen 	u16 tlv_len;
17473b01e57SJeff Chen 	struct nxpwifi_ie_types_data *tlv_hdr;
17573b01e57SJeff Chen 	struct ieee80211_wmm_param_ie *wmm_param_ie = NULL;
17673b01e57SJeff Chen 	int mask = IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK;
17773b01e57SJeff Chen 
17873b01e57SJeff Chen 	priv->wmm_enabled = false;
17973b01e57SJeff Chen 	skb_pull(event, NXPWIFI_BSS_START_EVT_FIX_SIZE);
18073b01e57SJeff Chen 	evt_len = event->len;
18173b01e57SJeff Chen 	curr = event->data;
18273b01e57SJeff Chen 
18373b01e57SJeff Chen 	nxpwifi_dbg_dump(priv->adapter, EVT_D, "uap capabilities:",
18473b01e57SJeff Chen 			 event->data, event->len);
18573b01e57SJeff Chen 
18673b01e57SJeff Chen 	skb_push(event, NXPWIFI_BSS_START_EVT_FIX_SIZE);
18773b01e57SJeff Chen 
18873b01e57SJeff Chen 	while ((evt_len >= sizeof(tlv_hdr->header))) {
18973b01e57SJeff Chen 		tlv_hdr = (struct nxpwifi_ie_types_data *)curr;
19073b01e57SJeff Chen 		tlv_len = le16_to_cpu(tlv_hdr->header.len);
19173b01e57SJeff Chen 
19273b01e57SJeff Chen 		if (evt_len < tlv_len + sizeof(tlv_hdr->header))
19373b01e57SJeff Chen 			break;
19473b01e57SJeff Chen 
19573b01e57SJeff Chen 		switch (le16_to_cpu(tlv_hdr->header.type)) {
19673b01e57SJeff Chen 		case WLAN_EID_HT_CAPABILITY:
19773b01e57SJeff Chen 			priv->ap_11n_enabled = true;
19873b01e57SJeff Chen 			break;
19973b01e57SJeff Chen 
20073b01e57SJeff Chen 		case WLAN_EID_VHT_CAPABILITY:
20173b01e57SJeff Chen 			priv->ap_11ac_enabled = true;
20273b01e57SJeff Chen 			break;
20373b01e57SJeff Chen 
20473b01e57SJeff Chen 		case WLAN_EID_VENDOR_SPECIFIC:
20573b01e57SJeff Chen 			/*
20673b01e57SJeff Chen 			 * Point the regular IEEE element 2 bytes into the NXP element
20773b01e57SJeff Chen 			 * and setup the IEEE element type and length byte fields
20873b01e57SJeff Chen 			 */
20973b01e57SJeff Chen 			wmm_param_ie = (void *)(curr + 2);
21073b01e57SJeff Chen 			wmm_param_ie->len = (u8)tlv_len;
21173b01e57SJeff Chen 			wmm_param_ie->element_id =
21273b01e57SJeff Chen 						WLAN_EID_VENDOR_SPECIFIC;
21373b01e57SJeff Chen 			nxpwifi_dbg(priv->adapter, EVENT,
21473b01e57SJeff Chen 				    "info: check uap capabilities:\t"
21573b01e57SJeff Chen 				    "wmm parameter set count: %d\n",
21673b01e57SJeff Chen 				    wmm_param_ie->qos_info & mask);
21773b01e57SJeff Chen 
21873b01e57SJeff Chen 			nxpwifi_wmm_setup_ac_downgrade(priv);
21973b01e57SJeff Chen 			priv->wmm_enabled = true;
22073b01e57SJeff Chen 			nxpwifi_wmm_setup_queue_priorities(priv, wmm_param_ie);
22173b01e57SJeff Chen 			break;
22273b01e57SJeff Chen 
22373b01e57SJeff Chen 		default:
22473b01e57SJeff Chen 			break;
22573b01e57SJeff Chen 		}
22673b01e57SJeff Chen 
22773b01e57SJeff Chen 		curr += (tlv_len + sizeof(tlv_hdr->header));
22873b01e57SJeff Chen 		evt_len -= (tlv_len + sizeof(tlv_hdr->header));
22973b01e57SJeff Chen 	}
23073b01e57SJeff Chen 
23173b01e57SJeff Chen 	return 0;
23273b01e57SJeff Chen }
23373b01e57SJeff Chen 
23473b01e57SJeff Chen static int
nxpwifi_uap_event_bss_start(struct nxpwifi_private * priv)23573b01e57SJeff Chen nxpwifi_uap_event_bss_start(struct nxpwifi_private *priv)
23673b01e57SJeff Chen {
23773b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
23873b01e57SJeff Chen 
23973b01e57SJeff Chen 	priv->port_open = false;
24073b01e57SJeff Chen 	eth_hw_addr_set(priv->netdev, adapter->event_body + 2);
24173b01e57SJeff Chen 	if (priv->hist_data)
24273b01e57SJeff Chen 		nxpwifi_hist_data_reset(priv);
24373b01e57SJeff Chen 	return nxpwifi_check_uap_capabilities(priv, adapter->event_skb);
24473b01e57SJeff Chen }
24573b01e57SJeff Chen 
24673b01e57SJeff Chen static int
nxpwifi_uap_event_addba(struct nxpwifi_private * priv)24773b01e57SJeff Chen nxpwifi_uap_event_addba(struct nxpwifi_private *priv)
24873b01e57SJeff Chen {
24973b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
25073b01e57SJeff Chen 
25173b01e57SJeff Chen 	if (priv->media_connected)
25273b01e57SJeff Chen 		nxpwifi_send_cmd(priv, HOST_CMD_11N_ADDBA_RSP,
25373b01e57SJeff Chen 				 HOST_ACT_GEN_SET, 0,
25473b01e57SJeff Chen 				 adapter->event_body, false);
25573b01e57SJeff Chen 
25673b01e57SJeff Chen 	return 0;
25773b01e57SJeff Chen }
25873b01e57SJeff Chen 
25973b01e57SJeff Chen static int
nxpwifi_uap_event_delba(struct nxpwifi_private * priv)26073b01e57SJeff Chen nxpwifi_uap_event_delba(struct nxpwifi_private *priv)
26173b01e57SJeff Chen {
26273b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
26373b01e57SJeff Chen 
26473b01e57SJeff Chen 	if (priv->media_connected)
26573b01e57SJeff Chen 		nxpwifi_11n_delete_ba_stream(priv, adapter->event_body);
26673b01e57SJeff Chen 
26773b01e57SJeff Chen 	return 0;
26873b01e57SJeff Chen }
26973b01e57SJeff Chen 
27073b01e57SJeff Chen static int
nxpwifi_uap_event_ba_stream_timeout(struct nxpwifi_private * priv)27173b01e57SJeff Chen nxpwifi_uap_event_ba_stream_timeout(struct nxpwifi_private *priv)
27273b01e57SJeff Chen {
27373b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
27473b01e57SJeff Chen 	struct host_cmd_ds_11n_batimeout *ba_timeout;
27573b01e57SJeff Chen 
27673b01e57SJeff Chen 	if (priv->media_connected) {
27773b01e57SJeff Chen 		ba_timeout = (void *)adapter->event_body;
27873b01e57SJeff Chen 		nxpwifi_11n_ba_stream_timeout(priv, ba_timeout);
27973b01e57SJeff Chen 	}
28073b01e57SJeff Chen 
28173b01e57SJeff Chen 	return 0;
28273b01e57SJeff Chen }
28373b01e57SJeff Chen 
28473b01e57SJeff Chen static int
nxpwifi_uap_event_amsdu_aggr_ctrl(struct nxpwifi_private * priv)28573b01e57SJeff Chen nxpwifi_uap_event_amsdu_aggr_ctrl(struct nxpwifi_private *priv)
28673b01e57SJeff Chen {
28773b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
28873b01e57SJeff Chen 	u16 ctrl;
28973b01e57SJeff Chen 
29073b01e57SJeff Chen 	ctrl = get_unaligned_le16(adapter->event_body);
29173b01e57SJeff Chen 	nxpwifi_dbg(adapter, EVENT,
29273b01e57SJeff Chen 		    "event: AMSDU_AGGR_CTRL %d\n", ctrl);
29373b01e57SJeff Chen 
29473b01e57SJeff Chen 	if (priv->media_connected) {
29573b01e57SJeff Chen 		adapter->tx_buf_size =
29673b01e57SJeff Chen 			min_t(u16, adapter->curr_tx_buf_size, ctrl);
29773b01e57SJeff Chen 		nxpwifi_dbg(adapter, EVENT,
29873b01e57SJeff Chen 			    "event: tx_buf_size %d\n",
29973b01e57SJeff Chen 			    adapter->tx_buf_size);
30073b01e57SJeff Chen 	}
30173b01e57SJeff Chen 
30273b01e57SJeff Chen 	return 0;
30373b01e57SJeff Chen }
30473b01e57SJeff Chen 
30573b01e57SJeff Chen static int
nxpwifi_uap_event_bss_idle(struct nxpwifi_private * priv)30673b01e57SJeff Chen nxpwifi_uap_event_bss_idle(struct nxpwifi_private *priv)
30773b01e57SJeff Chen {
30873b01e57SJeff Chen 	priv->media_connected = false;
30973b01e57SJeff Chen 	priv->port_open = false;
31073b01e57SJeff Chen 	nxpwifi_clean_txrx(priv);
31173b01e57SJeff Chen 	nxpwifi_del_all_sta_list(priv);
31273b01e57SJeff Chen 
31373b01e57SJeff Chen 	return 0;
31473b01e57SJeff Chen }
31573b01e57SJeff Chen 
31673b01e57SJeff Chen static int
nxpwifi_uap_event_bss_active(struct nxpwifi_private * priv)31773b01e57SJeff Chen nxpwifi_uap_event_bss_active(struct nxpwifi_private *priv)
31873b01e57SJeff Chen {
31973b01e57SJeff Chen 	priv->media_connected = true;
32073b01e57SJeff Chen 	priv->port_open = true;
32173b01e57SJeff Chen 
32273b01e57SJeff Chen 	return 0;
32373b01e57SJeff Chen }
32473b01e57SJeff Chen 
32573b01e57SJeff Chen static int
nxpwifi_uap_event_mic_countermeasures(struct nxpwifi_private * priv)32673b01e57SJeff Chen nxpwifi_uap_event_mic_countermeasures(struct nxpwifi_private *priv)
32773b01e57SJeff Chen {
32873b01e57SJeff Chen 	/* For future development */
32973b01e57SJeff Chen 
33073b01e57SJeff Chen 	return 0;
33173b01e57SJeff Chen }
33273b01e57SJeff Chen 
33373b01e57SJeff Chen static int
nxpwifi_uap_event_radar_detected(struct nxpwifi_private * priv)33473b01e57SJeff Chen nxpwifi_uap_event_radar_detected(struct nxpwifi_private *priv)
33573b01e57SJeff Chen {
33673b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
33773b01e57SJeff Chen 
33873b01e57SJeff Chen 	return nxpwifi_11h_handle_radar_detected(priv, adapter->event_skb);
33973b01e57SJeff Chen }
34073b01e57SJeff Chen 
34173b01e57SJeff Chen static int
nxpwifi_uap_event_channel_report_rdy(struct nxpwifi_private * priv)34273b01e57SJeff Chen nxpwifi_uap_event_channel_report_rdy(struct nxpwifi_private *priv)
34373b01e57SJeff Chen {
34473b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
34573b01e57SJeff Chen 
34673b01e57SJeff Chen 	return nxpwifi_11h_handle_chanrpt_ready(priv, adapter->event_skb);
34773b01e57SJeff Chen }
34873b01e57SJeff Chen 
34973b01e57SJeff Chen static int
nxpwifi_uap_event_tx_data_pause(struct nxpwifi_private * priv)35073b01e57SJeff Chen nxpwifi_uap_event_tx_data_pause(struct nxpwifi_private *priv)
35173b01e57SJeff Chen {
35273b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
35373b01e57SJeff Chen 
35473b01e57SJeff Chen 	nxpwifi_process_tx_pause_event(priv, adapter->event_skb);
35573b01e57SJeff Chen 
35673b01e57SJeff Chen 	return 0;
35773b01e57SJeff Chen }
35873b01e57SJeff Chen 
35973b01e57SJeff Chen static int
nxpwifi_uap_event_ext_scan_report(struct nxpwifi_private * priv)36073b01e57SJeff Chen nxpwifi_uap_event_ext_scan_report(struct nxpwifi_private *priv)
36173b01e57SJeff Chen {
36273b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
36373b01e57SJeff Chen 	void *buf = adapter->event_skb->data;
36473b01e57SJeff Chen 	int ret = 0;
36573b01e57SJeff Chen 
36673b01e57SJeff Chen 	if (adapter->ext_scan)
36773b01e57SJeff Chen 		ret = nxpwifi_handle_event_ext_scan_report(priv, buf);
36873b01e57SJeff Chen 
36973b01e57SJeff Chen 	return ret;
37073b01e57SJeff Chen }
37173b01e57SJeff Chen 
37273b01e57SJeff Chen static int
nxpwifi_uap_event_rxba_sync(struct nxpwifi_private * priv)37373b01e57SJeff Chen nxpwifi_uap_event_rxba_sync(struct nxpwifi_private *priv)
37473b01e57SJeff Chen {
37573b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
37673b01e57SJeff Chen 
37773b01e57SJeff Chen 	nxpwifi_11n_rxba_sync_event(priv, adapter->event_body,
37873b01e57SJeff Chen 				    adapter->event_skb->len -
37973b01e57SJeff Chen 				    sizeof(adapter->event_cause));
38073b01e57SJeff Chen 
38173b01e57SJeff Chen 	return 0;
38273b01e57SJeff Chen }
38373b01e57SJeff Chen 
38473b01e57SJeff Chen static int
nxpwifi_uap_event_remain_on_chan_expired(struct nxpwifi_private * priv)38573b01e57SJeff Chen nxpwifi_uap_event_remain_on_chan_expired(struct nxpwifi_private *priv)
38673b01e57SJeff Chen {
38773b01e57SJeff Chen 	cfg80211_remain_on_channel_expired(&priv->wdev,
38873b01e57SJeff Chen 					   priv->roc_cfg.cookie,
38973b01e57SJeff Chen 					   &priv->roc_cfg.chan,
39073b01e57SJeff Chen 					   GFP_ATOMIC);
39173b01e57SJeff Chen 	memset(&priv->roc_cfg, 0x00, sizeof(struct nxpwifi_roc_cfg));
39273b01e57SJeff Chen 
39373b01e57SJeff Chen 	return 0;
39473b01e57SJeff Chen }
39573b01e57SJeff Chen 
39673b01e57SJeff Chen static int
nxpwifi_uap_event_multi_chan_info(struct nxpwifi_private * priv)39773b01e57SJeff Chen nxpwifi_uap_event_multi_chan_info(struct nxpwifi_private *priv)
39873b01e57SJeff Chen {
39973b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
40073b01e57SJeff Chen 
40173b01e57SJeff Chen 	nxpwifi_process_multi_chan_event(priv, adapter->event_skb);
40273b01e57SJeff Chen 
40373b01e57SJeff Chen 	return 0;
40473b01e57SJeff Chen }
40573b01e57SJeff Chen 
40673b01e57SJeff Chen static int
nxpwifi_uap_event_tx_status_report(struct nxpwifi_private * priv)40773b01e57SJeff Chen nxpwifi_uap_event_tx_status_report(struct nxpwifi_private *priv)
40873b01e57SJeff Chen {
40973b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
41073b01e57SJeff Chen 
41173b01e57SJeff Chen 	nxpwifi_parse_tx_status_event(priv, adapter->event_body);
41273b01e57SJeff Chen 
41373b01e57SJeff Chen 	return 0;
41473b01e57SJeff Chen }
41573b01e57SJeff Chen 
41673b01e57SJeff Chen static int
nxpwifi_uap_event_bt_coex_wlan_para_change(struct nxpwifi_private * priv)41773b01e57SJeff Chen nxpwifi_uap_event_bt_coex_wlan_para_change(struct nxpwifi_private *priv)
41873b01e57SJeff Chen {
41973b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
42073b01e57SJeff Chen 
42173b01e57SJeff Chen 	nxpwifi_bt_coex_wlan_param_update_event(priv, adapter->event_skb);
42273b01e57SJeff Chen 
42373b01e57SJeff Chen 	return 0;
42473b01e57SJeff Chen }
42573b01e57SJeff Chen 
42673b01e57SJeff Chen static int
nxpwifi_uap_event_vdll_ind(struct nxpwifi_private * priv)42773b01e57SJeff Chen nxpwifi_uap_event_vdll_ind(struct nxpwifi_private *priv)
42873b01e57SJeff Chen {
42973b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
43073b01e57SJeff Chen 
43173b01e57SJeff Chen 	return nxpwifi_process_vdll_event(priv, adapter->event_skb);
43273b01e57SJeff Chen }
43373b01e57SJeff Chen 
43473b01e57SJeff Chen static const struct nxpwifi_evt_entry evt_table_uap[] = {
43573b01e57SJeff Chen 	{.event_cause = EVENT_PS_AWAKE,
43673b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_ps_awake},
43773b01e57SJeff Chen 	{.event_cause = EVENT_PS_SLEEP,
43873b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_ps_sleep},
43973b01e57SJeff Chen 	{.event_cause = EVENT_UAP_STA_DEAUTH,
44073b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_sta_deauth},
44173b01e57SJeff Chen 	{.event_cause = EVENT_UAP_STA_ASSOC,
44273b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_sta_assoc},
44373b01e57SJeff Chen 	{.event_cause = EVENT_UAP_BSS_START,
44473b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_bss_start},
44573b01e57SJeff Chen 	{.event_cause = EVENT_ADDBA,
44673b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_addba},
44773b01e57SJeff Chen 	{.event_cause = EVENT_DELBA,
44873b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_delba},
44973b01e57SJeff Chen 	{.event_cause = EVENT_BA_STREAM_TIEMOUT,
45073b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_ba_stream_timeout},
45173b01e57SJeff Chen 	{.event_cause = EVENT_AMSDU_AGGR_CTRL,
45273b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_amsdu_aggr_ctrl},
45373b01e57SJeff Chen 	{.event_cause = EVENT_UAP_BSS_IDLE,
45473b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_bss_idle},
45573b01e57SJeff Chen 	{.event_cause = EVENT_UAP_BSS_ACTIVE,
45673b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_bss_active},
45773b01e57SJeff Chen 	{.event_cause = EVENT_UAP_MIC_COUNTERMEASURES,
45873b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_mic_countermeasures},
45973b01e57SJeff Chen 	{.event_cause = EVENT_RADAR_DETECTED,
46073b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_radar_detected},
46173b01e57SJeff Chen 	{.event_cause = EVENT_CHANNEL_REPORT_RDY,
46273b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_channel_report_rdy},
46373b01e57SJeff Chen 	{.event_cause = EVENT_TX_DATA_PAUSE,
46473b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_tx_data_pause},
46573b01e57SJeff Chen 	{.event_cause = EVENT_EXT_SCAN_REPORT,
46673b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_ext_scan_report},
46773b01e57SJeff Chen 	{.event_cause = EVENT_RXBA_SYNC,
46873b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_rxba_sync},
46973b01e57SJeff Chen 	{.event_cause = EVENT_REMAIN_ON_CHAN_EXPIRED,
47073b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_remain_on_chan_expired},
47173b01e57SJeff Chen 	{.event_cause = EVENT_MULTI_CHAN_INFO,
47273b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_multi_chan_info},
47373b01e57SJeff Chen 	{.event_cause = EVENT_TX_STATUS_REPORT,
47473b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_tx_status_report},
47573b01e57SJeff Chen 	{.event_cause = EVENT_BT_COEX_WLAN_PARA_CHANGE,
47673b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_bt_coex_wlan_para_change},
47773b01e57SJeff Chen 	{.event_cause = EVENT_VDLL_IND,
47873b01e57SJeff Chen 	 .event_handler = nxpwifi_uap_event_vdll_ind},
47973b01e57SJeff Chen };
48073b01e57SJeff Chen 
48173b01e57SJeff Chen /* Handle AP‑interface events by dispatching them to event‑specific routines. */
nxpwifi_process_uap_event(struct nxpwifi_private * priv)48273b01e57SJeff Chen int nxpwifi_process_uap_event(struct nxpwifi_private *priv)
48373b01e57SJeff Chen {
48473b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
48573b01e57SJeff Chen 	u32 eventcause = adapter->event_cause;
48673b01e57SJeff Chen 	int evt, ret = 0;
48773b01e57SJeff Chen 
48873b01e57SJeff Chen 	for (evt = 0; evt < ARRAY_SIZE(evt_table_uap); evt++) {
48973b01e57SJeff Chen 		if (eventcause == evt_table_uap[evt].event_cause) {
49073b01e57SJeff Chen 			if (evt_table_uap[evt].event_handler)
49173b01e57SJeff Chen 				ret = evt_table_uap[evt].event_handler(priv);
49273b01e57SJeff Chen 			break;
49373b01e57SJeff Chen 		}
49473b01e57SJeff Chen 	}
49573b01e57SJeff Chen 
49673b01e57SJeff Chen 	if (evt == ARRAY_SIZE(evt_table_uap))
49773b01e57SJeff Chen 		nxpwifi_dbg(adapter, EVENT,
49873b01e57SJeff Chen 			    "%s: unknown event id: %#x\n",
49973b01e57SJeff Chen 			    __func__, eventcause);
50073b01e57SJeff Chen 	else
50173b01e57SJeff Chen 		nxpwifi_dbg(adapter, EVENT,
50273b01e57SJeff Chen 			    "%s: event id: %#x\n",
50373b01e57SJeff Chen 			    __func__, eventcause);
50473b01e57SJeff Chen 
50573b01e57SJeff Chen 	return ret;
50673b01e57SJeff Chen }
507