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