1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * nxpwifi: 802.11h helpers
4 *
5 * Copyright 2011-2024 NXP
6 */
7
8 #include "main.h"
9 #include "cmdevt.h"
10 #include "fw.h"
11 #include "cfg80211.h"
12
nxpwifi_init_11h_params(struct nxpwifi_private * priv)13 void nxpwifi_init_11h_params(struct nxpwifi_private *priv)
14 {
15 priv->state_11h.is_11h_enabled = true;
16 priv->state_11h.is_11h_active = false;
17 }
18
nxpwifi_is_11h_active(struct nxpwifi_private * priv)19 int nxpwifi_is_11h_active(struct nxpwifi_private *priv)
20 {
21 return priv->state_11h.is_11h_active;
22 }
23
24 /* appends 11h info to a buffer while joining an infrastructure BSS */
25 static void
nxpwifi_11h_process_infra_join(struct nxpwifi_private * priv,u8 ** buffer,struct nxpwifi_bssdescriptor * bss_desc)26 nxpwifi_11h_process_infra_join(struct nxpwifi_private *priv, u8 **buffer,
27 struct nxpwifi_bssdescriptor *bss_desc)
28 {
29 struct nxpwifi_ie_types_header *ie_header;
30 struct nxpwifi_ie_types_pwr_capability *cap;
31 struct nxpwifi_ie_types_local_pwr_constraint *constraint;
32 struct ieee80211_supported_band *sband;
33 u8 radio_type;
34 int i;
35
36 if (!buffer || !(*buffer))
37 return;
38
39 radio_type = nxpwifi_band_to_radio_type((u8)bss_desc->bss_band);
40 sband = priv->wdev.wiphy->bands[radio_type];
41
42 cap = (struct nxpwifi_ie_types_pwr_capability *)*buffer;
43 cap->header.type = cpu_to_le16(WLAN_EID_PWR_CAPABILITY);
44 cap->header.len = cpu_to_le16(2);
45 cap->min_pwr = 0;
46 cap->max_pwr = 0;
47 *buffer += sizeof(*cap);
48
49 constraint = (struct nxpwifi_ie_types_local_pwr_constraint *)*buffer;
50 constraint->header.type = cpu_to_le16(WLAN_EID_PWR_CONSTRAINT);
51 constraint->header.len = cpu_to_le16(2);
52 constraint->chan = bss_desc->channel;
53 constraint->constraint = bss_desc->local_constraint;
54 *buffer += sizeof(*constraint);
55
56 ie_header = (struct nxpwifi_ie_types_header *)*buffer;
57 ie_header->type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
58 ie_header->len = cpu_to_le16(2 * sband->n_channels + 2);
59 *buffer += sizeof(*ie_header);
60 *(*buffer)++ = WLAN_EID_SUPPORTED_CHANNELS;
61 *(*buffer)++ = 2 * sband->n_channels;
62 for (i = 0; i < sband->n_channels; i++) {
63 u32 center_freq;
64
65 center_freq = sband->channels[i].center_freq;
66 *(*buffer)++ = ieee80211_frequency_to_channel(center_freq);
67 *(*buffer)++ = 1; /* one channel in the subband */
68 }
69 }
70
71 /* Enable or disable the 11h extensions in the firmware */
nxpwifi_11h_activate(struct nxpwifi_private * priv,bool flag)72 int nxpwifi_11h_activate(struct nxpwifi_private *priv, bool flag)
73 {
74 u32 enable = flag;
75
76 /* enable master mode radar detection on AP interface */
77 if ((GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) && enable)
78 enable |= NXPWIFI_MASTER_RADAR_DET_MASK;
79
80 return nxpwifi_send_cmd(priv, HOST_CMD_802_11_SNMP_MIB,
81 HOST_ACT_GEN_SET, DOT11H_I, &enable, true);
82 }
83
84 /*
85 * Process TLV buffer for a pending BSS join. Enable 11h in firmware when the
86 * network advertises spectrum management, and add required TLVs based on the
87 * BSS's 11h capability.
88 */
nxpwifi_11h_process_join(struct nxpwifi_private * priv,u8 ** buffer,struct nxpwifi_bssdescriptor * bss_desc)89 void nxpwifi_11h_process_join(struct nxpwifi_private *priv, u8 **buffer,
90 struct nxpwifi_bssdescriptor *bss_desc)
91 {
92 if (bss_desc->sensed_11h) {
93 /* Activate 11h functions in firmware, turns on capability bit */
94 nxpwifi_11h_activate(priv, true);
95 priv->state_11h.is_11h_active = true;
96 bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_SPECTRUM_MGMT;
97 nxpwifi_11h_process_infra_join(priv, buffer, bss_desc);
98 } else {
99 /* Deactivate 11h functions in the firmware */
100 nxpwifi_11h_activate(priv, false);
101 priv->state_11h.is_11h_active = false;
102 bss_desc->cap_info_bitmap &= ~WLAN_CAPABILITY_SPECTRUM_MGMT;
103 }
104 }
105
106 /*
107 * DFS CAC work function. This delayed work emits CAC finished event for cfg80211
108 * if CAC was started earlier
109 */
nxpwifi_dfs_cac_work(struct wiphy * wiphy,struct wiphy_work * work)110 void nxpwifi_dfs_cac_work(struct wiphy *wiphy, struct wiphy_work *work)
111 {
112 struct cfg80211_chan_def chandef;
113 struct wiphy_delayed_work *delayed_work =
114 container_of(work, struct wiphy_delayed_work, work);
115 struct nxpwifi_private *priv = container_of(delayed_work,
116 struct nxpwifi_private,
117 dfs_cac_work);
118
119 chandef = priv->dfs_chandef;
120 if (priv->wdev.links[0].cac_started) {
121 nxpwifi_dbg(priv->adapter, MSG,
122 "CAC timer finished; No radar detected\n");
123 cfg80211_cac_event(priv->netdev, &chandef,
124 NL80211_RADAR_CAC_FINISHED,
125 GFP_KERNEL, 0);
126 }
127 }
128
129 /* prepares channel report request command to FW for starting radar detection */
nxpwifi_cmd_issue_chan_report_request(struct nxpwifi_private * priv,struct host_cmd_ds_command * cmd,void * data_buf)130 int nxpwifi_cmd_issue_chan_report_request(struct nxpwifi_private *priv,
131 struct host_cmd_ds_command *cmd,
132 void *data_buf)
133 {
134 struct host_cmd_ds_chan_rpt_req *cr_req = &cmd->params.chan_rpt_req;
135 struct nxpwifi_radar_params *radar_params = (void *)data_buf;
136 u16 size;
137
138 cmd->command = cpu_to_le16(HOST_CMD_CHAN_REPORT_REQUEST);
139 size = S_DS_GEN;
140
141 cr_req->chan_desc.start_freq = cpu_to_le16(NXPWIFI_A_BAND_START_FREQ);
142 nxpwifi_convert_chan_to_band_cfg(priv,
143 &cr_req->chan_desc.band_cfg,
144 radar_params->chandef);
145 cr_req->chan_desc.chan_num = radar_params->chandef->chan->hw_value;
146 cr_req->msec_dwell_time = cpu_to_le32(radar_params->cac_time_ms);
147 size += sizeof(*cr_req);
148
149 if (radar_params->cac_time_ms) {
150 struct nxpwifi_ie_types_chan_rpt_data *rpt;
151
152 rpt = (struct nxpwifi_ie_types_chan_rpt_data *)((u8 *)cmd + size);
153 rpt->header.type = cpu_to_le16(TLV_TYPE_CHANRPT_11H_BASIC);
154 rpt->header.len = cpu_to_le16(sizeof(u8));
155 rpt->meas_rpt_map = 1 << MEAS_RPT_MAP_RADAR_SHIFT_BIT;
156 size += sizeof(*rpt);
157
158 nxpwifi_dbg(priv->adapter, MSG,
159 "11h: issuing DFS Radar check for channel=%d\n",
160 radar_params->chandef->chan->hw_value);
161 } else {
162 nxpwifi_dbg(priv->adapter, MSG, "cancelling CAC\n");
163 }
164
165 cmd->size = cpu_to_le16(size);
166
167 return 0;
168 }
169
nxpwifi_stop_radar_detection(struct nxpwifi_private * priv,struct cfg80211_chan_def * chandef)170 int nxpwifi_stop_radar_detection(struct nxpwifi_private *priv,
171 struct cfg80211_chan_def *chandef)
172 {
173 struct nxpwifi_radar_params radar_params;
174
175 memset(&radar_params, 0, sizeof(struct nxpwifi_radar_params));
176 radar_params.chandef = chandef;
177 radar_params.cac_time_ms = 0;
178
179 return nxpwifi_send_cmd(priv, HOST_CMD_CHAN_REPORT_REQUEST,
180 HOST_ACT_GEN_SET, 0, &radar_params, true);
181 }
182
183 /* Abort ongoing CAC when stopping AP operations or during unload */
nxpwifi_abort_cac(struct nxpwifi_private * priv)184 void nxpwifi_abort_cac(struct nxpwifi_private *priv)
185 {
186 if (priv->wdev.links[0].cac_started) {
187 if (nxpwifi_stop_radar_detection(priv, &priv->dfs_chandef))
188 nxpwifi_dbg(priv->adapter, ERROR,
189 "failed to stop CAC in FW\n");
190 nxpwifi_dbg(priv->adapter, MSG,
191 "Aborting delayed work for CAC.\n");
192 wiphy_delayed_work_cancel(priv->adapter->wiphy, &priv->dfs_cac_work);
193 cfg80211_cac_event(priv->netdev, &priv->dfs_chandef,
194 NL80211_RADAR_CAC_ABORTED, GFP_KERNEL, 0);
195 }
196 }
197
198 /*
199 * handles channel report event from FW during CAC period. If radar is detected
200 * during CAC, driver indicates the same to cfg80211 and also cancels ongoing
201 * delayed work
202 */
nxpwifi_11h_handle_chanrpt_ready(struct nxpwifi_private * priv,struct sk_buff * skb)203 int nxpwifi_11h_handle_chanrpt_ready(struct nxpwifi_private *priv,
204 struct sk_buff *skb)
205 {
206 struct host_cmd_ds_chan_rpt_event *rpt_event;
207 struct nxpwifi_ie_types_chan_rpt_data *rpt;
208 u16 event_len, tlv_len;
209
210 rpt_event = (void *)(skb->data + sizeof(u32));
211 event_len = skb->len - (sizeof(struct host_cmd_ds_chan_rpt_event) +
212 sizeof(u32));
213
214 if (le32_to_cpu(rpt_event->result) != HOST_RESULT_OK) {
215 nxpwifi_dbg(priv->adapter, ERROR,
216 "Error in channel report event\n");
217 return -EINVAL;
218 }
219
220 while (event_len >= sizeof(struct nxpwifi_ie_types_header)) {
221 rpt = (void *)&rpt_event->tlvbuf;
222 tlv_len = le16_to_cpu(rpt->header.len);
223
224 switch (le16_to_cpu(rpt->header.type)) {
225 case TLV_TYPE_CHANRPT_11H_BASIC:
226 if (rpt->meas_rpt_map & MEAS_RPT_MAP_RADAR_MASK) {
227 nxpwifi_dbg(priv->adapter, MSG,
228 "RADAR Detected on channel %d!\n",
229 priv->dfs_chandef.chan->hw_value);
230
231 wiphy_delayed_work_cancel(priv->adapter->wiphy,
232 &priv->dfs_cac_work);
233 cfg80211_cac_event(priv->netdev,
234 &priv->dfs_chandef,
235 NL80211_RADAR_CAC_ABORTED,
236 GFP_KERNEL, 0);
237 cfg80211_radar_event(priv->adapter->wiphy,
238 &priv->dfs_chandef,
239 GFP_KERNEL);
240 }
241 break;
242 default:
243 break;
244 }
245
246 event_len -= (tlv_len + sizeof(rpt->header));
247 }
248
249 return 0;
250 }
251
252 /* Handler for radar detected event from FW */
nxpwifi_11h_handle_radar_detected(struct nxpwifi_private * priv,struct sk_buff * skb)253 int nxpwifi_11h_handle_radar_detected(struct nxpwifi_private *priv,
254 struct sk_buff *skb)
255 {
256 struct nxpwifi_radar_det_event *rdr_event;
257
258 rdr_event = (void *)(skb->data + sizeof(u32));
259
260 nxpwifi_dbg(priv->adapter, MSG,
261 "radar detected; indicating kernel\n");
262
263 if (priv->wdev.links[0].cac_started) {
264 if (nxpwifi_stop_radar_detection(priv, &priv->dfs_chandef))
265 nxpwifi_dbg(priv->adapter, ERROR,
266 "Failed to stop CAC in FW\n");
267 wiphy_delayed_work_cancel(priv->adapter->wiphy, &priv->dfs_cac_work);
268 cfg80211_cac_event(priv->netdev, &priv->dfs_chandef,
269 NL80211_RADAR_CAC_ABORTED, GFP_KERNEL, 0);
270 }
271 cfg80211_radar_event(priv->adapter->wiphy, &priv->dfs_chandef,
272 GFP_KERNEL);
273 nxpwifi_dbg(priv->adapter, MSG, "regdomain: %d\n",
274 rdr_event->reg_domain);
275 nxpwifi_dbg(priv->adapter, MSG, "radar detection type: %d\n",
276 rdr_event->det_type);
277
278 return 0;
279 }
280
281 /*
282 * work function for channel switch handling. takes care of updating new channel
283 * definitin to bss config structure, restart AP and indicate channel switch
284 * success to cfg80211
285 */
nxpwifi_dfs_chan_sw_work(struct wiphy * wiphy,struct wiphy_work * work)286 void nxpwifi_dfs_chan_sw_work(struct wiphy *wiphy, struct wiphy_work *work)
287 {
288 struct nxpwifi_uap_bss_param *bss_cfg;
289 struct wiphy_delayed_work *delayed_work =
290 container_of(work, struct wiphy_delayed_work, work);
291 struct nxpwifi_private *priv = container_of(delayed_work,
292 struct nxpwifi_private,
293 dfs_chan_sw_work);
294 struct nxpwifi_adapter *adapter = priv->adapter;
295
296 if (nxpwifi_del_mgmt_ies(priv))
297 nxpwifi_dbg(priv->adapter, ERROR,
298 "Failed to delete mgmt IEs!\n");
299
300 bss_cfg = &priv->bss_cfg;
301 if (!bss_cfg->beacon_period) {
302 nxpwifi_dbg(adapter, ERROR,
303 "channel switch: AP already stopped\n");
304 return;
305 }
306
307 if (nxpwifi_send_cmd(priv, HOST_CMD_UAP_BSS_STOP,
308 HOST_ACT_GEN_SET, 0, NULL, true)) {
309 nxpwifi_dbg(adapter, ERROR,
310 "channel switch: Failed to stop the BSS\n");
311 return;
312 }
313
314 if (nxpwifi_cfg80211_change_beacon(adapter->wiphy, priv->netdev,
315 &priv->ap_update_info)) {
316 nxpwifi_dbg(adapter, ERROR,
317 "channel switch: Failed to set beacon\n");
318 return;
319 }
320
321 nxpwifi_uap_set_channel(priv, bss_cfg, priv->dfs_chandef);
322
323 if (nxpwifi_config_start_uap(priv, bss_cfg)) {
324 nxpwifi_dbg(adapter, ERROR,
325 "Failed to start AP after channel switch\n");
326 return;
327 }
328
329 nxpwifi_dbg(adapter, MSG,
330 "indicating channel switch completion to kernel\n");
331
332 cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef, 0);
333
334 if (priv->uap_stop_tx) {
335 netif_carrier_on(priv->netdev);
336 nxpwifi_wake_up_net_dev_queue(priv->netdev, adapter);
337 priv->uap_stop_tx = false;
338 }
339 }
340