xref: /linux/drivers/net/wireless/nxp/nxpwifi/11h.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
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