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