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