xref: /linux/drivers/net/wireless/intel/iwlwifi/mld/sta.h (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
1*d1e879ecSMiri Korenblit /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
2*d1e879ecSMiri Korenblit /*
3*d1e879ecSMiri Korenblit  * Copyright (C) 2024-2025 Intel Corporation
4*d1e879ecSMiri Korenblit  */
5*d1e879ecSMiri Korenblit 
6*d1e879ecSMiri Korenblit #ifndef __iwl_mld_sta_h__
7*d1e879ecSMiri Korenblit #define __iwl_mld_sta_h__
8*d1e879ecSMiri Korenblit 
9*d1e879ecSMiri Korenblit #include <net/mac80211.h>
10*d1e879ecSMiri Korenblit 
11*d1e879ecSMiri Korenblit #include "mld.h"
12*d1e879ecSMiri Korenblit #include "tx.h"
13*d1e879ecSMiri Korenblit 
14*d1e879ecSMiri Korenblit /**
15*d1e879ecSMiri Korenblit  * struct iwl_mld_rxq_dup_data - Duplication detection data, per STA & Rx queue
16*d1e879ecSMiri Korenblit  * @last_seq: last sequence per tid.
17*d1e879ecSMiri Korenblit  * @last_sub_frame_idx: the index of the last subframe in an A-MSDU. This value
18*d1e879ecSMiri Korenblit  *	will be zero if the packet is not part of an A-MSDU.
19*d1e879ecSMiri Korenblit  */
20*d1e879ecSMiri Korenblit struct iwl_mld_rxq_dup_data {
21*d1e879ecSMiri Korenblit 	__le16 last_seq[IWL_MAX_TID_COUNT + 1];
22*d1e879ecSMiri Korenblit 	u8 last_sub_frame_idx[IWL_MAX_TID_COUNT + 1];
23*d1e879ecSMiri Korenblit } ____cacheline_aligned_in_smp;
24*d1e879ecSMiri Korenblit 
25*d1e879ecSMiri Korenblit /**
26*d1e879ecSMiri Korenblit  * struct iwl_mld_link_sta - link-level station
27*d1e879ecSMiri Korenblit  *
28*d1e879ecSMiri Korenblit  * This represents the link-level sta - the driver level equivalent to the
29*d1e879ecSMiri Korenblit  * ieee80211_link_sta
30*d1e879ecSMiri Korenblit  *
31*d1e879ecSMiri Korenblit  * @last_rate_n_flags: rate_n_flags from the last &iwl_tlc_update_notif
32*d1e879ecSMiri Korenblit  * @signal_avg: the signal average coming from the firmware
33*d1e879ecSMiri Korenblit  * @in_fw: whether the link STA is uploaded to the FW (false during restart)
34*d1e879ecSMiri Korenblit  * @rcu_head: RCU head for freeing this object
35*d1e879ecSMiri Korenblit  * @fw_id: the FW id of this link sta.
36*d1e879ecSMiri Korenblit  */
37*d1e879ecSMiri Korenblit struct iwl_mld_link_sta {
38*d1e879ecSMiri Korenblit 	/* Add here fields that need clean up on restart */
39*d1e879ecSMiri Korenblit 	struct_group(zeroed_on_hw_restart,
40*d1e879ecSMiri Korenblit 		u32 last_rate_n_flags;
41*d1e879ecSMiri Korenblit 		bool in_fw;
42*d1e879ecSMiri Korenblit 		s8 signal_avg;
43*d1e879ecSMiri Korenblit 	);
44*d1e879ecSMiri Korenblit 	/* And here fields that survive a fw restart */
45*d1e879ecSMiri Korenblit 	struct rcu_head rcu_head;
46*d1e879ecSMiri Korenblit 	u32 fw_id;
47*d1e879ecSMiri Korenblit };
48*d1e879ecSMiri Korenblit 
49*d1e879ecSMiri Korenblit #define iwl_mld_link_sta_dereference_check(mld_sta, link_id)		\
50*d1e879ecSMiri Korenblit 	rcu_dereference_check((mld_sta)->link[link_id],			\
51*d1e879ecSMiri Korenblit 			      lockdep_is_held(&mld_sta->mld->wiphy->mtx))
52*d1e879ecSMiri Korenblit 
53*d1e879ecSMiri Korenblit #define for_each_mld_link_sta(mld_sta, link_sta, link_id)		\
54*d1e879ecSMiri Korenblit 	for (link_id = 0; link_id < ARRAY_SIZE((mld_sta)->link);	\
55*d1e879ecSMiri Korenblit 	     link_id++)							\
56*d1e879ecSMiri Korenblit 		if ((link_sta =						\
57*d1e879ecSMiri Korenblit 			iwl_mld_link_sta_dereference_check(mld_sta, link_id)))
58*d1e879ecSMiri Korenblit 
59*d1e879ecSMiri Korenblit #define IWL_NUM_DEFAULT_KEYS 4
60*d1e879ecSMiri Korenblit 
61*d1e879ecSMiri Korenblit /* struct iwl_mld_ptk_pn - Holds Packet Number (PN) per TID.
62*d1e879ecSMiri Korenblit  * @rcu_head: RCU head for freeing this data.
63*d1e879ecSMiri Korenblit  * @pn: Array storing PN for each TID.
64*d1e879ecSMiri Korenblit  */
65*d1e879ecSMiri Korenblit struct iwl_mld_ptk_pn {
66*d1e879ecSMiri Korenblit 	struct rcu_head rcu_head;
67*d1e879ecSMiri Korenblit 	struct {
68*d1e879ecSMiri Korenblit 		u8 pn[IWL_MAX_TID_COUNT][IEEE80211_CCMP_PN_LEN];
69*d1e879ecSMiri Korenblit 	} ____cacheline_aligned_in_smp q[];
70*d1e879ecSMiri Korenblit };
71*d1e879ecSMiri Korenblit 
72*d1e879ecSMiri Korenblit /**
73*d1e879ecSMiri Korenblit  * struct iwl_mld_per_link_mpdu_counter - per-link TX/RX MPDU counters
74*d1e879ecSMiri Korenblit  *
75*d1e879ecSMiri Korenblit  * @tx: Number of TX MPDUs.
76*d1e879ecSMiri Korenblit  * @rx: Number of RX MPDUs.
77*d1e879ecSMiri Korenblit  */
78*d1e879ecSMiri Korenblit struct iwl_mld_per_link_mpdu_counter {
79*d1e879ecSMiri Korenblit 	u32 tx;
80*d1e879ecSMiri Korenblit 	u32 rx;
81*d1e879ecSMiri Korenblit };
82*d1e879ecSMiri Korenblit 
83*d1e879ecSMiri Korenblit /**
84*d1e879ecSMiri Korenblit  * struct iwl_mld_per_q_mpdu_counter - per-queue MPDU counter
85*d1e879ecSMiri Korenblit  *
86*d1e879ecSMiri Korenblit  * @lock: Needed to protect the counters when modified from statistics.
87*d1e879ecSMiri Korenblit  * @per_link: per-link counters.
88*d1e879ecSMiri Korenblit  * @window_start_time: timestamp of the counting-window start
89*d1e879ecSMiri Korenblit  */
90*d1e879ecSMiri Korenblit struct iwl_mld_per_q_mpdu_counter {
91*d1e879ecSMiri Korenblit 	spinlock_t lock;
92*d1e879ecSMiri Korenblit 	struct iwl_mld_per_link_mpdu_counter per_link[IWL_FW_MAX_LINK_ID + 1];
93*d1e879ecSMiri Korenblit 	unsigned long window_start_time;
94*d1e879ecSMiri Korenblit } ____cacheline_aligned_in_smp;
95*d1e879ecSMiri Korenblit 
96*d1e879ecSMiri Korenblit /**
97*d1e879ecSMiri Korenblit  * struct iwl_mld_sta - representation of a station in the driver.
98*d1e879ecSMiri Korenblit  *
99*d1e879ecSMiri Korenblit  * This represent the MLD-level sta, and will not be added to the FW.
100*d1e879ecSMiri Korenblit  * Embedded in ieee80211_sta.
101*d1e879ecSMiri Korenblit  *
102*d1e879ecSMiri Korenblit  * @vif: pointer the vif object.
103*d1e879ecSMiri Korenblit  * @sta_state: station state according to enum %ieee80211_sta_state
104*d1e879ecSMiri Korenblit  * @sta_type: type of this station. See &enum iwl_fw_sta_type
105*d1e879ecSMiri Korenblit  * @mld: a pointer to the iwl_mld object
106*d1e879ecSMiri Korenblit  * @dup_data: per queue duplicate packet detection data
107*d1e879ecSMiri Korenblit  * @data_tx_ant: stores the last TX antenna index; used for setting
108*d1e879ecSMiri Korenblit  *	TX rate_n_flags for injected data frames (toggles on every TX failure).
109*d1e879ecSMiri Korenblit  * @tid_to_baid: a simple map of TID to Block-Ack fw id
110*d1e879ecSMiri Korenblit  * @deflink: This holds the default link STA information, for non MLO STA all
111*d1e879ecSMiri Korenblit  *	link specific STA information is accessed through @deflink or through
112*d1e879ecSMiri Korenblit  *	link[0] which points to address of @deflink. For MLO Link STA
113*d1e879ecSMiri Korenblit  *	the first added link STA will point to deflink.
114*d1e879ecSMiri Korenblit  * @link: reference to Link Sta entries. For Non MLO STA, except 1st link,
115*d1e879ecSMiri Korenblit  *	i.e link[0] all links would be assigned to NULL by default and
116*d1e879ecSMiri Korenblit  *	would access link information via @deflink or link[0]. For MLO
117*d1e879ecSMiri Korenblit  *	STA, first link STA being added will point its link pointer to
118*d1e879ecSMiri Korenblit  *	@deflink address and remaining would be allocated and the address
119*d1e879ecSMiri Korenblit  *	would be assigned to link[link_id] where link_id is the id assigned
120*d1e879ecSMiri Korenblit  *	by the AP.
121*d1e879ecSMiri Korenblit  * @ptk_pn: Array of pointers to PTK PN data, used to track the Packet Number
122*d1e879ecSMiri Korenblit  *	per key index and per queue (TID).
123*d1e879ecSMiri Korenblit  * @mpdu_counters: RX/TX MPDUs counters for each queue.
124*d1e879ecSMiri Korenblit  */
125*d1e879ecSMiri Korenblit struct iwl_mld_sta {
126*d1e879ecSMiri Korenblit 	/* Add here fields that need clean up on restart */
127*d1e879ecSMiri Korenblit 	struct_group(zeroed_on_hw_restart,
128*d1e879ecSMiri Korenblit 		enum ieee80211_sta_state sta_state;
129*d1e879ecSMiri Korenblit 		enum iwl_fw_sta_type sta_type;
130*d1e879ecSMiri Korenblit 	);
131*d1e879ecSMiri Korenblit 	/* And here fields that survive a fw restart */
132*d1e879ecSMiri Korenblit 	struct iwl_mld *mld;
133*d1e879ecSMiri Korenblit 	struct ieee80211_vif *vif;
134*d1e879ecSMiri Korenblit 	struct iwl_mld_rxq_dup_data *dup_data;
135*d1e879ecSMiri Korenblit 	u8 tid_to_baid[IWL_MAX_TID_COUNT];
136*d1e879ecSMiri Korenblit 	u8 data_tx_ant;
137*d1e879ecSMiri Korenblit 
138*d1e879ecSMiri Korenblit 	struct iwl_mld_link_sta deflink;
139*d1e879ecSMiri Korenblit 	struct iwl_mld_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
140*d1e879ecSMiri Korenblit 	struct iwl_mld_ptk_pn __rcu *ptk_pn[IWL_NUM_DEFAULT_KEYS];
141*d1e879ecSMiri Korenblit 	struct iwl_mld_per_q_mpdu_counter *mpdu_counters;
142*d1e879ecSMiri Korenblit };
143*d1e879ecSMiri Korenblit 
144*d1e879ecSMiri Korenblit static inline struct iwl_mld_sta *
145*d1e879ecSMiri Korenblit iwl_mld_sta_from_mac80211(struct ieee80211_sta *sta)
146*d1e879ecSMiri Korenblit {
147*d1e879ecSMiri Korenblit 	return (void *)sta->drv_priv;
148*d1e879ecSMiri Korenblit }
149*d1e879ecSMiri Korenblit 
150*d1e879ecSMiri Korenblit static inline void
151*d1e879ecSMiri Korenblit iwl_mld_cleanup_sta(void *data, struct ieee80211_sta *sta)
152*d1e879ecSMiri Korenblit {
153*d1e879ecSMiri Korenblit 	struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
154*d1e879ecSMiri Korenblit 	struct iwl_mld_link_sta *mld_link_sta;
155*d1e879ecSMiri Korenblit 	u8 link_id;
156*d1e879ecSMiri Korenblit 
157*d1e879ecSMiri Korenblit 	for (int i = 0; i < ARRAY_SIZE(sta->txq); i++)
158*d1e879ecSMiri Korenblit 		CLEANUP_STRUCT(iwl_mld_txq_from_mac80211(sta->txq[i]));
159*d1e879ecSMiri Korenblit 
160*d1e879ecSMiri Korenblit 	for_each_mld_link_sta(mld_sta, mld_link_sta, link_id) {
161*d1e879ecSMiri Korenblit 		CLEANUP_STRUCT(mld_link_sta);
162*d1e879ecSMiri Korenblit 
163*d1e879ecSMiri Korenblit 		if (!ieee80211_vif_is_mld(mld_sta->vif)) {
164*d1e879ecSMiri Korenblit 			/* not an MLD STA; only has the deflink with ID zero */
165*d1e879ecSMiri Korenblit 			WARN_ON(link_id);
166*d1e879ecSMiri Korenblit 			continue;
167*d1e879ecSMiri Korenblit 		}
168*d1e879ecSMiri Korenblit 
169*d1e879ecSMiri Korenblit 		if (mld_sta->vif->active_links & BIT(link_id))
170*d1e879ecSMiri Korenblit 			continue;
171*d1e879ecSMiri Korenblit 
172*d1e879ecSMiri Korenblit 		/* Should not happen as link removal should always succeed */
173*d1e879ecSMiri Korenblit 		WARN_ON(1);
174*d1e879ecSMiri Korenblit 		RCU_INIT_POINTER(mld_sta->link[link_id], NULL);
175*d1e879ecSMiri Korenblit 		RCU_INIT_POINTER(mld_sta->mld->fw_id_to_link_sta[mld_link_sta->fw_id],
176*d1e879ecSMiri Korenblit 				 NULL);
177*d1e879ecSMiri Korenblit 		if (mld_link_sta != &mld_sta->deflink)
178*d1e879ecSMiri Korenblit 			kfree_rcu(mld_link_sta, rcu_head);
179*d1e879ecSMiri Korenblit 	}
180*d1e879ecSMiri Korenblit 
181*d1e879ecSMiri Korenblit 	CLEANUP_STRUCT(mld_sta);
182*d1e879ecSMiri Korenblit }
183*d1e879ecSMiri Korenblit 
184*d1e879ecSMiri Korenblit static inline struct iwl_mld_link_sta *
185*d1e879ecSMiri Korenblit iwl_mld_link_sta_from_mac80211(struct ieee80211_link_sta *link_sta)
186*d1e879ecSMiri Korenblit {
187*d1e879ecSMiri Korenblit 	struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
188*d1e879ecSMiri Korenblit 
189*d1e879ecSMiri Korenblit 	return iwl_mld_link_sta_dereference_check(mld_sta, link_sta->link_id);
190*d1e879ecSMiri Korenblit }
191*d1e879ecSMiri Korenblit 
192*d1e879ecSMiri Korenblit int iwl_mld_add_sta(struct iwl_mld *mld, struct ieee80211_sta *sta,
193*d1e879ecSMiri Korenblit 		    struct ieee80211_vif *vif, enum iwl_fw_sta_type type);
194*d1e879ecSMiri Korenblit void iwl_mld_remove_sta(struct iwl_mld *mld, struct ieee80211_sta *sta);
195*d1e879ecSMiri Korenblit int iwl_mld_fw_sta_id_from_link_sta(struct iwl_mld *mld,
196*d1e879ecSMiri Korenblit 				    struct ieee80211_link_sta *link_sta);
197*d1e879ecSMiri Korenblit u32 iwl_mld_fw_sta_id_mask(struct iwl_mld *mld, struct ieee80211_sta *sta);
198*d1e879ecSMiri Korenblit int iwl_mld_update_all_link_stations(struct iwl_mld *mld,
199*d1e879ecSMiri Korenblit 				     struct ieee80211_sta *sta);
200*d1e879ecSMiri Korenblit void iwl_mld_flush_sta_txqs(struct iwl_mld *mld, struct ieee80211_sta *sta);
201*d1e879ecSMiri Korenblit void iwl_mld_wait_sta_txqs_empty(struct iwl_mld *mld,
202*d1e879ecSMiri Korenblit 				 struct ieee80211_sta *sta);
203*d1e879ecSMiri Korenblit void iwl_mld_count_mpdu_rx(struct ieee80211_link_sta *link_sta, int queue,
204*d1e879ecSMiri Korenblit 			   u32 count);
205*d1e879ecSMiri Korenblit void iwl_mld_count_mpdu_tx(struct ieee80211_link_sta *link_sta, u32 count);
206*d1e879ecSMiri Korenblit 
207*d1e879ecSMiri Korenblit /**
208*d1e879ecSMiri Korenblit  * struct iwl_mld_int_sta - representation of an internal station
209*d1e879ecSMiri Korenblit  * (a station that exist in FW and in driver, but not in mac80211)
210*d1e879ecSMiri Korenblit  *
211*d1e879ecSMiri Korenblit  * @sta_id: the index of the station in the fw
212*d1e879ecSMiri Korenblit  * @queue_id: the if of the queue used by the station
213*d1e879ecSMiri Korenblit  * @sta_type: station type. One of &iwl_fw_sta_type
214*d1e879ecSMiri Korenblit  */
215*d1e879ecSMiri Korenblit struct iwl_mld_int_sta {
216*d1e879ecSMiri Korenblit 	u8 sta_id;
217*d1e879ecSMiri Korenblit 	u32 queue_id;
218*d1e879ecSMiri Korenblit 	enum iwl_fw_sta_type sta_type;
219*d1e879ecSMiri Korenblit };
220*d1e879ecSMiri Korenblit 
221*d1e879ecSMiri Korenblit static inline void
222*d1e879ecSMiri Korenblit iwl_mld_init_internal_sta(struct iwl_mld_int_sta *internal_sta)
223*d1e879ecSMiri Korenblit {
224*d1e879ecSMiri Korenblit 	internal_sta->sta_id = IWL_INVALID_STA;
225*d1e879ecSMiri Korenblit 	internal_sta->queue_id = IWL_MLD_INVALID_QUEUE;
226*d1e879ecSMiri Korenblit }
227*d1e879ecSMiri Korenblit 
228*d1e879ecSMiri Korenblit static inline void
229*d1e879ecSMiri Korenblit iwl_mld_free_internal_sta(struct iwl_mld *mld,
230*d1e879ecSMiri Korenblit 			  struct iwl_mld_int_sta *internal_sta)
231*d1e879ecSMiri Korenblit {
232*d1e879ecSMiri Korenblit 	if (WARN_ON(internal_sta->sta_id == IWL_INVALID_STA))
233*d1e879ecSMiri Korenblit 		return;
234*d1e879ecSMiri Korenblit 
235*d1e879ecSMiri Korenblit 	RCU_INIT_POINTER(mld->fw_id_to_link_sta[internal_sta->sta_id], NULL);
236*d1e879ecSMiri Korenblit 	iwl_mld_init_internal_sta(internal_sta);
237*d1e879ecSMiri Korenblit }
238*d1e879ecSMiri Korenblit 
239*d1e879ecSMiri Korenblit int iwl_mld_add_bcast_sta(struct iwl_mld *mld,
240*d1e879ecSMiri Korenblit 			  struct ieee80211_vif *vif,
241*d1e879ecSMiri Korenblit 			  struct ieee80211_bss_conf *link);
242*d1e879ecSMiri Korenblit 
243*d1e879ecSMiri Korenblit int iwl_mld_add_mcast_sta(struct iwl_mld *mld,
244*d1e879ecSMiri Korenblit 			  struct ieee80211_vif *vif,
245*d1e879ecSMiri Korenblit 			  struct ieee80211_bss_conf *link);
246*d1e879ecSMiri Korenblit 
247*d1e879ecSMiri Korenblit int iwl_mld_add_aux_sta(struct iwl_mld *mld,
248*d1e879ecSMiri Korenblit 			struct iwl_mld_int_sta *internal_sta);
249*d1e879ecSMiri Korenblit 
250*d1e879ecSMiri Korenblit void iwl_mld_remove_bcast_sta(struct iwl_mld *mld,
251*d1e879ecSMiri Korenblit 			      struct ieee80211_vif *vif,
252*d1e879ecSMiri Korenblit 			      struct ieee80211_bss_conf *link);
253*d1e879ecSMiri Korenblit 
254*d1e879ecSMiri Korenblit void iwl_mld_remove_mcast_sta(struct iwl_mld *mld,
255*d1e879ecSMiri Korenblit 			      struct ieee80211_vif *vif,
256*d1e879ecSMiri Korenblit 			      struct ieee80211_bss_conf *link);
257*d1e879ecSMiri Korenblit 
258*d1e879ecSMiri Korenblit void iwl_mld_remove_aux_sta(struct iwl_mld *mld,
259*d1e879ecSMiri Korenblit 			    struct ieee80211_vif *vif,
260*d1e879ecSMiri Korenblit 			    struct ieee80211_bss_conf *link);
261*d1e879ecSMiri Korenblit 
262*d1e879ecSMiri Korenblit int iwl_mld_update_link_stas(struct iwl_mld *mld,
263*d1e879ecSMiri Korenblit 			     struct ieee80211_vif *vif,
264*d1e879ecSMiri Korenblit 			     struct ieee80211_sta *sta,
265*d1e879ecSMiri Korenblit 			     u16 old_links, u16 new_links);
266*d1e879ecSMiri Korenblit #endif /* __iwl_mld_sta_h__ */
267