Linux Audio

Check our new training course

Loading...
v5.9
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright 2015 Intel Deutschland GmbH
 
  4 */
  5#include <net/mac80211.h>
  6#include "ieee80211_i.h"
  7#include "trace.h"
  8#include "driver-ops.h"
 
  9
 10int drv_start(struct ieee80211_local *local)
 11{
 12	int ret;
 13
 14	might_sleep();
 15
 16	if (WARN_ON(local->started))
 17		return -EALREADY;
 18
 19	trace_drv_start(local);
 20	local->started = true;
 21	/* allow rx frames */
 22	smp_mb();
 23	ret = local->ops->start(&local->hw);
 24	trace_drv_return_int(local, ret);
 25
 26	if (ret)
 27		local->started = false;
 28
 29	return ret;
 30}
 31
 32void drv_stop(struct ieee80211_local *local)
 33{
 34	might_sleep();
 35
 36	if (WARN_ON(!local->started))
 37		return;
 38
 39	trace_drv_stop(local);
 40	local->ops->stop(&local->hw);
 41	trace_drv_return_void(local);
 42
 43	/* sync away all work on the tasklet before clearing started */
 44	tasklet_disable(&local->tasklet);
 45	tasklet_enable(&local->tasklet);
 46
 47	barrier();
 48
 49	local->started = false;
 50}
 51
 52int drv_add_interface(struct ieee80211_local *local,
 53		      struct ieee80211_sub_if_data *sdata)
 54{
 55	int ret;
 56
 57	might_sleep();
 58
 59	if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
 60		    (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
 61		     !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
 62		     !(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))))
 63		return -EINVAL;
 64
 65	trace_drv_add_interface(local, sdata);
 66	ret = local->ops->add_interface(&local->hw, &sdata->vif);
 67	trace_drv_return_int(local, ret);
 68
 69	if (ret == 0)
 70		sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
 71
 72	return ret;
 73}
 74
 75int drv_change_interface(struct ieee80211_local *local,
 76			 struct ieee80211_sub_if_data *sdata,
 77			 enum nl80211_iftype type, bool p2p)
 78{
 79	int ret;
 80
 81	might_sleep();
 82
 83	if (!check_sdata_in_driver(sdata))
 84		return -EIO;
 85
 86	trace_drv_change_interface(local, sdata, type, p2p);
 87	ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
 88	trace_drv_return_int(local, ret);
 89	return ret;
 90}
 91
 92void drv_remove_interface(struct ieee80211_local *local,
 93			  struct ieee80211_sub_if_data *sdata)
 94{
 95	might_sleep();
 96
 97	if (!check_sdata_in_driver(sdata))
 98		return;
 99
100	trace_drv_remove_interface(local, sdata);
101	local->ops->remove_interface(&local->hw, &sdata->vif);
102	sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
103	trace_drv_return_void(local);
104}
105
106__must_check
107int drv_sta_state(struct ieee80211_local *local,
108		  struct ieee80211_sub_if_data *sdata,
109		  struct sta_info *sta,
110		  enum ieee80211_sta_state old_state,
111		  enum ieee80211_sta_state new_state)
112{
113	int ret = 0;
114
115	might_sleep();
116
117	sdata = get_bss_sdata(sdata);
118	if (!check_sdata_in_driver(sdata))
119		return -EIO;
120
121	trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state);
122	if (local->ops->sta_state) {
123		ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta,
124					    old_state, new_state);
125	} else if (old_state == IEEE80211_STA_AUTH &&
126		   new_state == IEEE80211_STA_ASSOC) {
127		ret = drv_sta_add(local, sdata, &sta->sta);
128		if (ret == 0)
129			sta->uploaded = true;
 
 
 
130	} else if (old_state == IEEE80211_STA_ASSOC &&
131		   new_state == IEEE80211_STA_AUTH) {
132		drv_sta_remove(local, sdata, &sta->sta);
133	}
134	trace_drv_return_int(local, ret);
135	return ret;
136}
137
138__must_check
139int drv_sta_set_txpwr(struct ieee80211_local *local,
140		      struct ieee80211_sub_if_data *sdata,
141		      struct sta_info *sta)
142{
143	int ret = -EOPNOTSUPP;
144
145	might_sleep();
146
147	sdata = get_bss_sdata(sdata);
148	if (!check_sdata_in_driver(sdata))
149		return -EIO;
150
151	trace_drv_sta_set_txpwr(local, sdata, &sta->sta);
152	if (local->ops->sta_set_txpwr)
153		ret = local->ops->sta_set_txpwr(&local->hw, &sdata->vif,
154						&sta->sta);
155	trace_drv_return_int(local, ret);
156	return ret;
157}
158
159void drv_sta_rc_update(struct ieee80211_local *local,
160		       struct ieee80211_sub_if_data *sdata,
161		       struct ieee80211_sta *sta, u32 changed)
162{
163	sdata = get_bss_sdata(sdata);
164	if (!check_sdata_in_driver(sdata))
165		return;
166
167	WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED &&
168		(sdata->vif.type != NL80211_IFTYPE_ADHOC &&
169		 sdata->vif.type != NL80211_IFTYPE_MESH_POINT));
170
171	trace_drv_sta_rc_update(local, sdata, sta, changed);
172	if (local->ops->sta_rc_update)
173		local->ops->sta_rc_update(&local->hw, &sdata->vif,
174					  sta, changed);
175
176	trace_drv_return_void(local);
177}
178
179int drv_conf_tx(struct ieee80211_local *local,
180		struct ieee80211_sub_if_data *sdata, u16 ac,
181		const struct ieee80211_tx_queue_params *params)
182{
 
183	int ret = -EOPNOTSUPP;
184
185	might_sleep();
186
187	if (!check_sdata_in_driver(sdata))
188		return -EIO;
189
 
 
 
 
190	if (params->cw_min == 0 || params->cw_min > params->cw_max) {
191		/*
192		 * If we can't configure hardware anyway, don't warn. We may
193		 * never have initialized the CW parameters.
194		 */
195		WARN_ONCE(local->ops->conf_tx,
196			  "%s: invalid CW_min/CW_max: %d/%d\n",
197			  sdata->name, params->cw_min, params->cw_max);
198		return -EINVAL;
199	}
200
201	trace_drv_conf_tx(local, sdata, ac, params);
202	if (local->ops->conf_tx)
203		ret = local->ops->conf_tx(&local->hw, &sdata->vif,
204					  ac, params);
205	trace_drv_return_int(local, ret);
206	return ret;
207}
208
209u64 drv_get_tsf(struct ieee80211_local *local,
210		struct ieee80211_sub_if_data *sdata)
211{
212	u64 ret = -1ULL;
213
214	might_sleep();
215
216	if (!check_sdata_in_driver(sdata))
217		return ret;
218
219	trace_drv_get_tsf(local, sdata);
220	if (local->ops->get_tsf)
221		ret = local->ops->get_tsf(&local->hw, &sdata->vif);
222	trace_drv_return_u64(local, ret);
223	return ret;
224}
225
226void drv_set_tsf(struct ieee80211_local *local,
227		 struct ieee80211_sub_if_data *sdata,
228		 u64 tsf)
229{
230	might_sleep();
231
232	if (!check_sdata_in_driver(sdata))
233		return;
234
235	trace_drv_set_tsf(local, sdata, tsf);
236	if (local->ops->set_tsf)
237		local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
238	trace_drv_return_void(local);
239}
240
241void drv_offset_tsf(struct ieee80211_local *local,
242		    struct ieee80211_sub_if_data *sdata,
243		    s64 offset)
244{
245	might_sleep();
246
247	if (!check_sdata_in_driver(sdata))
248		return;
249
250	trace_drv_offset_tsf(local, sdata, offset);
251	if (local->ops->offset_tsf)
252		local->ops->offset_tsf(&local->hw, &sdata->vif, offset);
253	trace_drv_return_void(local);
254}
255
256void drv_reset_tsf(struct ieee80211_local *local,
257		   struct ieee80211_sub_if_data *sdata)
258{
259	might_sleep();
260
261	if (!check_sdata_in_driver(sdata))
262		return;
263
264	trace_drv_reset_tsf(local, sdata);
265	if (local->ops->reset_tsf)
266		local->ops->reset_tsf(&local->hw, &sdata->vif);
267	trace_drv_return_void(local);
268}
269
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270int drv_switch_vif_chanctx(struct ieee80211_local *local,
271			   struct ieee80211_vif_chanctx_switch *vifs,
272			   int n_vifs, enum ieee80211_chanctx_switch_mode mode)
273{
274	int ret = 0;
275	int i;
276
277	might_sleep();
278
279	if (!local->ops->switch_vif_chanctx)
280		return -EOPNOTSUPP;
281
282	for (i = 0; i < n_vifs; i++) {
283		struct ieee80211_chanctx *new_ctx =
284			container_of(vifs[i].new_ctx,
285				     struct ieee80211_chanctx,
286				     conf);
287		struct ieee80211_chanctx *old_ctx =
288			container_of(vifs[i].old_ctx,
289				     struct ieee80211_chanctx,
290				     conf);
291
292		WARN_ON_ONCE(!old_ctx->driver_present);
293		WARN_ON_ONCE((mode == CHANCTX_SWMODE_SWAP_CONTEXTS &&
294			      new_ctx->driver_present) ||
295			     (mode == CHANCTX_SWMODE_REASSIGN_VIF &&
296			      !new_ctx->driver_present));
297	}
298
299	trace_drv_switch_vif_chanctx(local, vifs, n_vifs, mode);
300	ret = local->ops->switch_vif_chanctx(&local->hw,
301					     vifs, n_vifs, mode);
302	trace_drv_return_int(local, ret);
303
304	if (!ret && mode == CHANCTX_SWMODE_SWAP_CONTEXTS) {
305		for (i = 0; i < n_vifs; i++) {
306			struct ieee80211_chanctx *new_ctx =
307				container_of(vifs[i].new_ctx,
308					     struct ieee80211_chanctx,
309					     conf);
310			struct ieee80211_chanctx *old_ctx =
311				container_of(vifs[i].old_ctx,
312					     struct ieee80211_chanctx,
313					     conf);
314
315			new_ctx->driver_present = true;
316			old_ctx->driver_present = false;
317		}
318	}
319
320	return ret;
321}
322
323int drv_ampdu_action(struct ieee80211_local *local,
324		     struct ieee80211_sub_if_data *sdata,
325		     struct ieee80211_ampdu_params *params)
326{
327	int ret = -EOPNOTSUPP;
328
329	might_sleep();
330
 
 
 
331	sdata = get_bss_sdata(sdata);
332	if (!check_sdata_in_driver(sdata))
333		return -EIO;
334
335	trace_drv_ampdu_action(local, sdata, params);
336
337	if (local->ops->ampdu_action)
338		ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params);
339
340	trace_drv_return_int(local, ret);
341
342	return ret;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343}
v6.2
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright 2015 Intel Deutschland GmbH
  4 * Copyright (C) 2022 Intel Corporation
  5 */
  6#include <net/mac80211.h>
  7#include "ieee80211_i.h"
  8#include "trace.h"
  9#include "driver-ops.h"
 10#include "debugfs_sta.h"
 11
 12int drv_start(struct ieee80211_local *local)
 13{
 14	int ret;
 15
 16	might_sleep();
 17
 18	if (WARN_ON(local->started))
 19		return -EALREADY;
 20
 21	trace_drv_start(local);
 22	local->started = true;
 23	/* allow rx frames */
 24	smp_mb();
 25	ret = local->ops->start(&local->hw);
 26	trace_drv_return_int(local, ret);
 27
 28	if (ret)
 29		local->started = false;
 30
 31	return ret;
 32}
 33
 34void drv_stop(struct ieee80211_local *local)
 35{
 36	might_sleep();
 37
 38	if (WARN_ON(!local->started))
 39		return;
 40
 41	trace_drv_stop(local);
 42	local->ops->stop(&local->hw);
 43	trace_drv_return_void(local);
 44
 45	/* sync away all work on the tasklet before clearing started */
 46	tasklet_disable(&local->tasklet);
 47	tasklet_enable(&local->tasklet);
 48
 49	barrier();
 50
 51	local->started = false;
 52}
 53
 54int drv_add_interface(struct ieee80211_local *local,
 55		      struct ieee80211_sub_if_data *sdata)
 56{
 57	int ret;
 58
 59	might_sleep();
 60
 61	if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
 62		    (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
 63		     !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
 64		     !(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))))
 65		return -EINVAL;
 66
 67	trace_drv_add_interface(local, sdata);
 68	ret = local->ops->add_interface(&local->hw, &sdata->vif);
 69	trace_drv_return_int(local, ret);
 70
 71	if (ret == 0)
 72		sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
 73
 74	return ret;
 75}
 76
 77int drv_change_interface(struct ieee80211_local *local,
 78			 struct ieee80211_sub_if_data *sdata,
 79			 enum nl80211_iftype type, bool p2p)
 80{
 81	int ret;
 82
 83	might_sleep();
 84
 85	if (!check_sdata_in_driver(sdata))
 86		return -EIO;
 87
 88	trace_drv_change_interface(local, sdata, type, p2p);
 89	ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
 90	trace_drv_return_int(local, ret);
 91	return ret;
 92}
 93
 94void drv_remove_interface(struct ieee80211_local *local,
 95			  struct ieee80211_sub_if_data *sdata)
 96{
 97	might_sleep();
 98
 99	if (!check_sdata_in_driver(sdata))
100		return;
101
102	trace_drv_remove_interface(local, sdata);
103	local->ops->remove_interface(&local->hw, &sdata->vif);
104	sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
105	trace_drv_return_void(local);
106}
107
108__must_check
109int drv_sta_state(struct ieee80211_local *local,
110		  struct ieee80211_sub_if_data *sdata,
111		  struct sta_info *sta,
112		  enum ieee80211_sta_state old_state,
113		  enum ieee80211_sta_state new_state)
114{
115	int ret = 0;
116
117	might_sleep();
118
119	sdata = get_bss_sdata(sdata);
120	if (!check_sdata_in_driver(sdata))
121		return -EIO;
122
123	trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state);
124	if (local->ops->sta_state) {
125		ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta,
126					    old_state, new_state);
127	} else if (old_state == IEEE80211_STA_AUTH &&
128		   new_state == IEEE80211_STA_ASSOC) {
129		ret = drv_sta_add(local, sdata, &sta->sta);
130		if (ret == 0) {
131			sta->uploaded = true;
132			if (rcu_access_pointer(sta->sta.rates))
133				drv_sta_rate_tbl_update(local, sdata, &sta->sta);
134		}
135	} else if (old_state == IEEE80211_STA_ASSOC &&
136		   new_state == IEEE80211_STA_AUTH) {
137		drv_sta_remove(local, sdata, &sta->sta);
138	}
139	trace_drv_return_int(local, ret);
140	return ret;
141}
142
143__must_check
144int drv_sta_set_txpwr(struct ieee80211_local *local,
145		      struct ieee80211_sub_if_data *sdata,
146		      struct sta_info *sta)
147{
148	int ret = -EOPNOTSUPP;
149
150	might_sleep();
151
152	sdata = get_bss_sdata(sdata);
153	if (!check_sdata_in_driver(sdata))
154		return -EIO;
155
156	trace_drv_sta_set_txpwr(local, sdata, &sta->sta);
157	if (local->ops->sta_set_txpwr)
158		ret = local->ops->sta_set_txpwr(&local->hw, &sdata->vif,
159						&sta->sta);
160	trace_drv_return_int(local, ret);
161	return ret;
162}
163
164void drv_sta_rc_update(struct ieee80211_local *local,
165		       struct ieee80211_sub_if_data *sdata,
166		       struct ieee80211_sta *sta, u32 changed)
167{
168	sdata = get_bss_sdata(sdata);
169	if (!check_sdata_in_driver(sdata))
170		return;
171
172	WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED &&
173		(sdata->vif.type != NL80211_IFTYPE_ADHOC &&
174		 sdata->vif.type != NL80211_IFTYPE_MESH_POINT));
175
176	trace_drv_sta_rc_update(local, sdata, sta, changed);
177	if (local->ops->sta_rc_update)
178		local->ops->sta_rc_update(&local->hw, &sdata->vif,
179					  sta, changed);
180
181	trace_drv_return_void(local);
182}
183
184int drv_conf_tx(struct ieee80211_local *local,
185		struct ieee80211_link_data *link, u16 ac,
186		const struct ieee80211_tx_queue_params *params)
187{
188	struct ieee80211_sub_if_data *sdata = link->sdata;
189	int ret = -EOPNOTSUPP;
190
191	might_sleep();
192
193	if (!check_sdata_in_driver(sdata))
194		return -EIO;
195
196	if (sdata->vif.active_links &&
197	    !(sdata->vif.active_links & BIT(link->link_id)))
198		return 0;
199
200	if (params->cw_min == 0 || params->cw_min > params->cw_max) {
201		/*
202		 * If we can't configure hardware anyway, don't warn. We may
203		 * never have initialized the CW parameters.
204		 */
205		WARN_ONCE(local->ops->conf_tx,
206			  "%s: invalid CW_min/CW_max: %d/%d\n",
207			  sdata->name, params->cw_min, params->cw_max);
208		return -EINVAL;
209	}
210
211	trace_drv_conf_tx(local, sdata, link->link_id, ac, params);
212	if (local->ops->conf_tx)
213		ret = local->ops->conf_tx(&local->hw, &sdata->vif,
214					  link->link_id, ac, params);
215	trace_drv_return_int(local, ret);
216	return ret;
217}
218
219u64 drv_get_tsf(struct ieee80211_local *local,
220		struct ieee80211_sub_if_data *sdata)
221{
222	u64 ret = -1ULL;
223
224	might_sleep();
225
226	if (!check_sdata_in_driver(sdata))
227		return ret;
228
229	trace_drv_get_tsf(local, sdata);
230	if (local->ops->get_tsf)
231		ret = local->ops->get_tsf(&local->hw, &sdata->vif);
232	trace_drv_return_u64(local, ret);
233	return ret;
234}
235
236void drv_set_tsf(struct ieee80211_local *local,
237		 struct ieee80211_sub_if_data *sdata,
238		 u64 tsf)
239{
240	might_sleep();
241
242	if (!check_sdata_in_driver(sdata))
243		return;
244
245	trace_drv_set_tsf(local, sdata, tsf);
246	if (local->ops->set_tsf)
247		local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
248	trace_drv_return_void(local);
249}
250
251void drv_offset_tsf(struct ieee80211_local *local,
252		    struct ieee80211_sub_if_data *sdata,
253		    s64 offset)
254{
255	might_sleep();
256
257	if (!check_sdata_in_driver(sdata))
258		return;
259
260	trace_drv_offset_tsf(local, sdata, offset);
261	if (local->ops->offset_tsf)
262		local->ops->offset_tsf(&local->hw, &sdata->vif, offset);
263	trace_drv_return_void(local);
264}
265
266void drv_reset_tsf(struct ieee80211_local *local,
267		   struct ieee80211_sub_if_data *sdata)
268{
269	might_sleep();
270
271	if (!check_sdata_in_driver(sdata))
272		return;
273
274	trace_drv_reset_tsf(local, sdata);
275	if (local->ops->reset_tsf)
276		local->ops->reset_tsf(&local->hw, &sdata->vif);
277	trace_drv_return_void(local);
278}
279
280int drv_assign_vif_chanctx(struct ieee80211_local *local,
281			   struct ieee80211_sub_if_data *sdata,
282			   struct ieee80211_bss_conf *link_conf,
283			   struct ieee80211_chanctx *ctx)
284{
285	int ret = 0;
286
287	drv_verify_link_exists(sdata, link_conf);
288	if (!check_sdata_in_driver(sdata))
289		return -EIO;
290
291	if (sdata->vif.active_links &&
292	    !(sdata->vif.active_links & BIT(link_conf->link_id)))
293		return 0;
294
295	trace_drv_assign_vif_chanctx(local, sdata, link_conf, ctx);
296	if (local->ops->assign_vif_chanctx) {
297		WARN_ON_ONCE(!ctx->driver_present);
298		ret = local->ops->assign_vif_chanctx(&local->hw,
299						     &sdata->vif,
300						     link_conf,
301						     &ctx->conf);
302	}
303	trace_drv_return_int(local, ret);
304
305	return ret;
306}
307
308void drv_unassign_vif_chanctx(struct ieee80211_local *local,
309			      struct ieee80211_sub_if_data *sdata,
310			      struct ieee80211_bss_conf *link_conf,
311			      struct ieee80211_chanctx *ctx)
312{
313	might_sleep();
314
315	drv_verify_link_exists(sdata, link_conf);
316	if (!check_sdata_in_driver(sdata))
317		return;
318
319	if (sdata->vif.active_links &&
320	    !(sdata->vif.active_links & BIT(link_conf->link_id)))
321		return;
322
323	trace_drv_unassign_vif_chanctx(local, sdata, link_conf, ctx);
324	if (local->ops->unassign_vif_chanctx) {
325		WARN_ON_ONCE(!ctx->driver_present);
326		local->ops->unassign_vif_chanctx(&local->hw,
327						 &sdata->vif,
328						 link_conf,
329						 &ctx->conf);
330	}
331	trace_drv_return_void(local);
332}
333
334int drv_switch_vif_chanctx(struct ieee80211_local *local,
335			   struct ieee80211_vif_chanctx_switch *vifs,
336			   int n_vifs, enum ieee80211_chanctx_switch_mode mode)
337{
338	int ret = 0;
339	int i;
340
341	might_sleep();
342
343	if (!local->ops->switch_vif_chanctx)
344		return -EOPNOTSUPP;
345
346	for (i = 0; i < n_vifs; i++) {
347		struct ieee80211_chanctx *new_ctx =
348			container_of(vifs[i].new_ctx,
349				     struct ieee80211_chanctx,
350				     conf);
351		struct ieee80211_chanctx *old_ctx =
352			container_of(vifs[i].old_ctx,
353				     struct ieee80211_chanctx,
354				     conf);
355
356		WARN_ON_ONCE(!old_ctx->driver_present);
357		WARN_ON_ONCE((mode == CHANCTX_SWMODE_SWAP_CONTEXTS &&
358			      new_ctx->driver_present) ||
359			     (mode == CHANCTX_SWMODE_REASSIGN_VIF &&
360			      !new_ctx->driver_present));
361	}
362
363	trace_drv_switch_vif_chanctx(local, vifs, n_vifs, mode);
364	ret = local->ops->switch_vif_chanctx(&local->hw,
365					     vifs, n_vifs, mode);
366	trace_drv_return_int(local, ret);
367
368	if (!ret && mode == CHANCTX_SWMODE_SWAP_CONTEXTS) {
369		for (i = 0; i < n_vifs; i++) {
370			struct ieee80211_chanctx *new_ctx =
371				container_of(vifs[i].new_ctx,
372					     struct ieee80211_chanctx,
373					     conf);
374			struct ieee80211_chanctx *old_ctx =
375				container_of(vifs[i].old_ctx,
376					     struct ieee80211_chanctx,
377					     conf);
378
379			new_ctx->driver_present = true;
380			old_ctx->driver_present = false;
381		}
382	}
383
384	return ret;
385}
386
387int drv_ampdu_action(struct ieee80211_local *local,
388		     struct ieee80211_sub_if_data *sdata,
389		     struct ieee80211_ampdu_params *params)
390{
391	int ret = -EOPNOTSUPP;
392
393	might_sleep();
394
395	if (!sdata)
396		return -EIO;
397
398	sdata = get_bss_sdata(sdata);
399	if (!check_sdata_in_driver(sdata))
400		return -EIO;
401
402	trace_drv_ampdu_action(local, sdata, params);
403
404	if (local->ops->ampdu_action)
405		ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params);
406
407	trace_drv_return_int(local, ret);
408
409	return ret;
410}
411
412void drv_link_info_changed(struct ieee80211_local *local,
413			   struct ieee80211_sub_if_data *sdata,
414			   struct ieee80211_bss_conf *info,
415			   int link_id, u64 changed)
416{
417	might_sleep();
418
419	if (WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON |
420				    BSS_CHANGED_BEACON_ENABLED) &&
421			 sdata->vif.type != NL80211_IFTYPE_AP &&
422			 sdata->vif.type != NL80211_IFTYPE_ADHOC &&
423			 sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
424			 sdata->vif.type != NL80211_IFTYPE_OCB))
425		return;
426
427	if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
428			 sdata->vif.type == NL80211_IFTYPE_NAN ||
429			 (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
430			  !sdata->vif.bss_conf.mu_mimo_owner &&
431			  !(changed & BSS_CHANGED_TXPOWER))))
432		return;
433
434	if (!check_sdata_in_driver(sdata))
435		return;
436
437	if (sdata->vif.active_links &&
438	    !(sdata->vif.active_links & BIT(link_id)))
439		return;
440
441	trace_drv_link_info_changed(local, sdata, info, changed);
442	if (local->ops->link_info_changed)
443		local->ops->link_info_changed(&local->hw, &sdata->vif,
444					      info, changed);
445	else if (local->ops->bss_info_changed)
446		local->ops->bss_info_changed(&local->hw, &sdata->vif,
447					     info, changed);
448	trace_drv_return_void(local);
449}
450
451int drv_set_key(struct ieee80211_local *local,
452		enum set_key_cmd cmd,
453		struct ieee80211_sub_if_data *sdata,
454		struct ieee80211_sta *sta,
455		struct ieee80211_key_conf *key)
456{
457	int ret;
458
459	might_sleep();
460
461	sdata = get_bss_sdata(sdata);
462	if (!check_sdata_in_driver(sdata))
463		return -EIO;
464
465	if (WARN_ON(key->link_id >= 0 && sdata->vif.active_links &&
466		    !(sdata->vif.active_links & BIT(key->link_id))))
467		return -ENOLINK;
468
469	trace_drv_set_key(local, cmd, sdata, sta, key);
470	ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
471	trace_drv_return_int(local, ret);
472	return ret;
473}
474
475int drv_change_vif_links(struct ieee80211_local *local,
476			 struct ieee80211_sub_if_data *sdata,
477			 u16 old_links, u16 new_links,
478			 struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])
479{
480	int ret = -EOPNOTSUPP;
481
482	might_sleep();
483
484	if (!check_sdata_in_driver(sdata))
485		return -EIO;
486
487	if (old_links == new_links)
488		return 0;
489
490	trace_drv_change_vif_links(local, sdata, old_links, new_links);
491	if (local->ops->change_vif_links)
492		ret = local->ops->change_vif_links(&local->hw, &sdata->vif,
493						   old_links, new_links, old);
494	trace_drv_return_int(local, ret);
495
496	return ret;
497}
498
499int drv_change_sta_links(struct ieee80211_local *local,
500			 struct ieee80211_sub_if_data *sdata,
501			 struct ieee80211_sta *sta,
502			 u16 old_links, u16 new_links)
503{
504	struct sta_info *info = container_of(sta, struct sta_info, sta);
505	struct link_sta_info *link_sta;
506	unsigned long links_to_add;
507	unsigned long links_to_rem;
508	unsigned int link_id;
509	int ret = -EOPNOTSUPP;
510
511	might_sleep();
512
513	if (!check_sdata_in_driver(sdata))
514		return -EIO;
515
516	old_links &= sdata->vif.active_links;
517	new_links &= sdata->vif.active_links;
518
519	if (old_links == new_links)
520		return 0;
521
522	links_to_add = ~old_links & new_links;
523	links_to_rem = old_links & ~new_links;
524
525	for_each_set_bit(link_id, &links_to_rem, IEEE80211_MLD_MAX_NUM_LINKS) {
526		link_sta = rcu_dereference_protected(info->link[link_id],
527						     lockdep_is_held(&local->sta_mtx));
528
529		ieee80211_link_sta_debugfs_drv_remove(link_sta);
530	}
531
532	trace_drv_change_sta_links(local, sdata, sta, old_links, new_links);
533	if (local->ops->change_sta_links)
534		ret = local->ops->change_sta_links(&local->hw, &sdata->vif, sta,
535						   old_links, new_links);
536	trace_drv_return_int(local, ret);
537
538	if (ret)
539		return ret;
540
541	for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) {
542		link_sta = rcu_dereference_protected(info->link[link_id],
543						     lockdep_is_held(&local->sta_mtx));
544		ieee80211_link_sta_debugfs_drv_add(link_sta);
545	}
546
547	return 0;
548}