]> Git Repo - linux.git/blob - drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c
Linux 6.14-rc3
[linux.git] / drivers / net / wireless / intel / iwlwifi / mvm / mld-mac.c
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (C) 2022 - 2024 Intel Corporation
4  */
5 #include "mvm.h"
6
7 static void iwl_mvm_mld_set_he_support(struct iwl_mvm *mvm,
8                                        struct ieee80211_vif *vif,
9                                        struct iwl_mac_config_cmd *cmd)
10 {
11         if (vif->type == NL80211_IFTYPE_AP)
12                 cmd->he_ap_support = cpu_to_le16(1);
13         else
14                 cmd->he_support = cpu_to_le16(1);
15 }
16
17 static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
18                                             struct ieee80211_vif *vif,
19                                             struct iwl_mac_config_cmd *cmd,
20                                             u32 action)
21 {
22         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
23         struct ieee80211_bss_conf *link_conf;
24         unsigned int link_id;
25
26         cmd->id_and_color = cpu_to_le32(mvmvif->id);
27         cmd->action = cpu_to_le32(action);
28
29         cmd->mac_type = cpu_to_le32(iwl_mvm_get_mac_type(vif));
30
31         memcpy(cmd->local_mld_addr, vif->addr, ETH_ALEN);
32
33         cmd->he_support = 0;
34         cmd->eht_support = 0;
35
36         /* should be set by specific context type handler */
37         cmd->filter_flags = 0;
38
39         cmd->nic_not_ack_enabled =
40                 cpu_to_le32(!iwl_mvm_is_nic_ack_enabled(mvm, vif));
41
42         if (iwlwifi_mod_params.disable_11ax)
43                 return;
44
45         /* If we have MLO enabled, then the firmware needs to enable
46          * address translation for the station(s) we add. That depends
47          * on having EHT enabled in firmware, which in turn depends on
48          * mac80211 in the code below.
49          * However, mac80211 doesn't enable HE/EHT until it has parsed
50          * the association response successfully, so just skip all that
51          * and enable both when we have MLO.
52          */
53         if (ieee80211_vif_is_mld(vif)) {
54                 iwl_mvm_mld_set_he_support(mvm, vif, cmd);
55                 cmd->eht_support = cpu_to_le32(1);
56                 return;
57         }
58
59         rcu_read_lock();
60         for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) {
61                 link_conf = rcu_dereference(vif->link_conf[link_id]);
62                 if (!link_conf)
63                         continue;
64
65                 if (link_conf->he_support)
66                         iwl_mvm_mld_set_he_support(mvm, vif, cmd);
67
68                 /* it's not reasonable to have EHT without HE and FW API doesn't
69                  * support it. Ignore EHT in this case.
70                  */
71                 if (!link_conf->he_support && link_conf->eht_support)
72                         continue;
73
74                 if (link_conf->eht_support) {
75                         cmd->eht_support = cpu_to_le32(1);
76                         break;
77                 }
78         }
79         rcu_read_unlock();
80 }
81
82 static int iwl_mvm_mld_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
83                                          struct iwl_mac_config_cmd *cmd)
84 {
85         int ret = iwl_mvm_send_cmd_pdu(mvm,
86                                        WIDE_ID(MAC_CONF_GROUP, MAC_CONFIG_CMD),
87                                        0, sizeof(*cmd), cmd);
88         if (ret)
89                 IWL_ERR(mvm, "Failed to send MAC_CONFIG_CMD (action:%d): %d\n",
90                         le32_to_cpu(cmd->action), ret);
91         return ret;
92 }
93
94 static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
95                                         struct ieee80211_vif *vif,
96                                         u32 action, bool force_assoc_off)
97 {
98         struct iwl_mac_config_cmd cmd = {};
99         u16 esr_transition_timeout;
100
101         WARN_ON(vif->type != NL80211_IFTYPE_STATION);
102
103         /* Fill the common data for all mac context types */
104         iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
105
106         /*
107          * We always want to hear MCAST frames, if we're not authorized yet,
108          * we'll drop them.
109          */
110         cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_GRP);
111
112         if (vif->p2p)
113                 cmd.client.ctwin =
114                         iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(mvm, vif);
115
116         if (vif->cfg.assoc && !force_assoc_off) {
117                 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
118
119                 cmd.client.is_assoc = 1;
120
121                 if (!mvmvif->authorized &&
122                     fw_has_capa(&mvm->fw->ucode_capa,
123                                 IWL_UCODE_TLV_CAPA_COEX_HIGH_PRIO))
124                         cmd.client.data_policy |=
125                                 cpu_to_le16(COEX_HIGH_PRIORITY_ENABLE);
126
127         } else {
128                 cmd.client.is_assoc = 0;
129
130                 /* Allow beacons to pass through as long as we are not
131                  * associated, or we do not have dtim period information.
132                  */
133                 cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON);
134         }
135
136         cmd.client.assoc_id = cpu_to_le16(vif->cfg.aid);
137         if (ieee80211_vif_is_mld(vif)) {
138                 esr_transition_timeout =
139                         u16_get_bits(vif->cfg.eml_cap,
140                                      IEEE80211_EML_CAP_TRANSITION_TIMEOUT);
141
142                 cmd.client.esr_transition_timeout =
143                         min_t(u16, IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU,
144                               esr_transition_timeout);
145                 cmd.client.medium_sync_delay =
146                         cpu_to_le16(vif->cfg.eml_med_sync_delay);
147         }
148
149         if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p)
150                 cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ);
151
152         if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax)
153                 cmd.client.data_policy |=
154                         cpu_to_le16(iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif));
155
156         return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
157 }
158
159 static int iwl_mvm_mld_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
160                                              struct ieee80211_vif *vif,
161                                              u32 action)
162 {
163         struct iwl_mac_config_cmd cmd = {};
164
165         WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);
166
167         iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
168
169         cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_PROMISC |
170                                        MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT |
171                                        MAC_CFG_FILTER_ACCEPT_BEACON |
172                                        MAC_CFG_FILTER_ACCEPT_PROBE_REQ |
173                                        MAC_CFG_FILTER_ACCEPT_GRP);
174
175         return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
176 }
177
178 static int iwl_mvm_mld_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm,
179                                          struct ieee80211_vif *vif,
180                                          u32 action)
181 {
182         struct iwl_mac_config_cmd cmd = {};
183
184         WARN_ON(vif->type != NL80211_IFTYPE_ADHOC);
185
186         iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
187
188         cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON |
189                                        MAC_CFG_FILTER_ACCEPT_PROBE_REQ |
190                                        MAC_CFG_FILTER_ACCEPT_GRP);
191
192         return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
193 }
194
195 static int iwl_mvm_mld_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
196                                                struct ieee80211_vif *vif,
197                                                u32 action)
198 {
199         struct iwl_mac_config_cmd cmd = {};
200
201         WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE);
202
203         iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
204
205         cmd.p2p_dev.is_disc_extended =
206                 iwl_mac_ctxt_p2p_dev_has_extended_disc(mvm, vif);
207
208         /* Override the filter flags to accept all management frames. This is
209          * needed to support both P2P device discovery using probe requests and
210          * P2P service discovery using action frames
211          */
212         cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT);
213
214         return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
215 }
216
217 static int iwl_mvm_mld_mac_ctxt_cmd_ap_go(struct iwl_mvm *mvm,
218                                           struct ieee80211_vif *vif,
219                                           u32 action)
220 {
221         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
222         struct iwl_mac_config_cmd cmd = {};
223
224         WARN_ON(vif->type != NL80211_IFTYPE_AP);
225
226         /* Fill the common data for all mac context types */
227         iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
228
229         iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(mvm, mvmvif,
230                                                  &cmd.filter_flags,
231                                                  MAC_CFG_FILTER_ACCEPT_PROBE_REQ,
232                                                  MAC_CFG_FILTER_ACCEPT_BEACON);
233
234         return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
235 }
236
237 static int iwl_mvm_mld_mac_ctx_send(struct iwl_mvm *mvm,
238                                     struct ieee80211_vif *vif,
239                                     u32 action, bool force_assoc_off)
240 {
241         switch (vif->type) {
242         case NL80211_IFTYPE_STATION:
243                 return iwl_mvm_mld_mac_ctxt_cmd_sta(mvm, vif, action,
244                                                     force_assoc_off);
245         case NL80211_IFTYPE_AP:
246                 return iwl_mvm_mld_mac_ctxt_cmd_ap_go(mvm, vif, action);
247         case NL80211_IFTYPE_MONITOR:
248                 return iwl_mvm_mld_mac_ctxt_cmd_listener(mvm, vif, action);
249         case NL80211_IFTYPE_P2P_DEVICE:
250                 return iwl_mvm_mld_mac_ctxt_cmd_p2p_device(mvm, vif, action);
251         case NL80211_IFTYPE_ADHOC:
252                 return iwl_mvm_mld_mac_ctxt_cmd_ibss(mvm, vif, action);
253         default:
254                 break;
255         }
256
257         return -EOPNOTSUPP;
258 }
259
260 int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
261 {
262         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
263         int ret;
264
265         if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))
266                 return -EOPNOTSUPP;
267
268         if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n",
269                       vif->addr, ieee80211_vif_type_p2p(vif)))
270                 return -EIO;
271
272         ret = iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD,
273                                        true);
274         if (ret)
275                 return ret;
276
277         /* will only do anything at resume from D3 time */
278         iwl_mvm_set_last_nonqos_seq(mvm, vif);
279
280         mvmvif->uploaded = true;
281         return 0;
282 }
283
284 int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm,
285                                  struct ieee80211_vif *vif,
286                                  bool force_assoc_off)
287 {
288         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
289
290         if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))
291                 return -EOPNOTSUPP;
292
293         if (WARN_ONCE(!mvmvif->uploaded, "Changing inactive MAC %pM/%d\n",
294                       vif->addr, ieee80211_vif_type_p2p(vif)))
295                 return -EIO;
296
297         return iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY,
298                                         force_assoc_off);
299 }
300
301 int iwl_mvm_mld_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
302 {
303         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
304         struct iwl_mac_config_cmd cmd = {
305                 .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
306                 .id_and_color = cpu_to_le32(mvmvif->id),
307         };
308         int ret;
309
310         if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))
311                 return -EOPNOTSUPP;
312
313         if (WARN_ONCE(!mvmvif->uploaded, "Removing inactive MAC %pM/%d\n",
314                       vif->addr, ieee80211_vif_type_p2p(vif)))
315                 return -EIO;
316
317         ret = iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
318         if (ret)
319                 return ret;
320
321         mvmvif->uploaded = false;
322
323         return 0;
324 }
This page took 0.054416 seconds and 4 git commands to generate.