1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2015 Intel Deutschland GmbH
5 #include <net/mac80211.h>
6 #include "ieee80211_i.h"
8 #include "driver-ops.h"
10 int drv_start(struct ieee80211_local
*local
)
16 if (WARN_ON(local
->started
))
19 trace_drv_start(local
);
20 local
->started
= true;
23 ret
= local
->ops
->start(&local
->hw
);
24 trace_drv_return_int(local
, ret
);
27 local
->started
= false;
32 void drv_stop(struct ieee80211_local
*local
)
36 if (WARN_ON(!local
->started
))
39 trace_drv_stop(local
);
40 local
->ops
->stop(&local
->hw
);
41 trace_drv_return_void(local
);
43 /* sync away all work on the tasklet before clearing started */
44 tasklet_disable(&local
->tasklet
);
45 tasklet_enable(&local
->tasklet
);
49 local
->started
= false;
52 int drv_add_interface(struct ieee80211_local
*local
,
53 struct ieee80211_sub_if_data
*sdata
)
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
))))
65 trace_drv_add_interface(local
, sdata
);
66 ret
= local
->ops
->add_interface(&local
->hw
, &sdata
->vif
);
67 trace_drv_return_int(local
, ret
);
70 sdata
->flags
|= IEEE80211_SDATA_IN_DRIVER
;
75 int drv_change_interface(struct ieee80211_local
*local
,
76 struct ieee80211_sub_if_data
*sdata
,
77 enum nl80211_iftype type
, bool p2p
)
83 if (!check_sdata_in_driver(sdata
))
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
);
92 void drv_remove_interface(struct ieee80211_local
*local
,
93 struct ieee80211_sub_if_data
*sdata
)
97 if (!check_sdata_in_driver(sdata
))
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
);
107 int 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
)
117 sdata
= get_bss_sdata(sdata
);
118 if (!check_sdata_in_driver(sdata
))
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
);
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
);
134 trace_drv_return_int(local
, ret
);
139 int drv_sta_set_txpwr(struct ieee80211_local
*local
,
140 struct ieee80211_sub_if_data
*sdata
,
141 struct sta_info
*sta
)
143 int ret
= -EOPNOTSUPP
;
147 sdata
= get_bss_sdata(sdata
);
148 if (!check_sdata_in_driver(sdata
))
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
,
155 trace_drv_return_int(local
, ret
);
159 void drv_sta_rc_update(struct ieee80211_local
*local
,
160 struct ieee80211_sub_if_data
*sdata
,
161 struct ieee80211_sta
*sta
, u32 changed
)
163 sdata
= get_bss_sdata(sdata
);
164 if (!check_sdata_in_driver(sdata
))
167 WARN_ON(changed
& IEEE80211_RC_SUPP_RATES_CHANGED
&&
168 (sdata
->vif
.type
!= NL80211_IFTYPE_ADHOC
&&
169 sdata
->vif
.type
!= NL80211_IFTYPE_MESH_POINT
));
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
,
176 trace_drv_return_void(local
);
179 int drv_conf_tx(struct ieee80211_local
*local
,
180 struct ieee80211_sub_if_data
*sdata
, u16 ac
,
181 const struct ieee80211_tx_queue_params
*params
)
183 int ret
= -EOPNOTSUPP
;
187 if (!check_sdata_in_driver(sdata
))
190 if (WARN_ONCE(params
->cw_min
== 0 ||
191 params
->cw_min
> params
->cw_max
,
192 "%s: invalid CW_min/CW_max: %d/%d\n",
193 sdata
->name
, params
->cw_min
, params
->cw_max
))
196 trace_drv_conf_tx(local
, sdata
, ac
, params
);
197 if (local
->ops
->conf_tx
)
198 ret
= local
->ops
->conf_tx(&local
->hw
, &sdata
->vif
,
200 trace_drv_return_int(local
, ret
);
204 u64
drv_get_tsf(struct ieee80211_local
*local
,
205 struct ieee80211_sub_if_data
*sdata
)
211 if (!check_sdata_in_driver(sdata
))
214 trace_drv_get_tsf(local
, sdata
);
215 if (local
->ops
->get_tsf
)
216 ret
= local
->ops
->get_tsf(&local
->hw
, &sdata
->vif
);
217 trace_drv_return_u64(local
, ret
);
221 void drv_set_tsf(struct ieee80211_local
*local
,
222 struct ieee80211_sub_if_data
*sdata
,
227 if (!check_sdata_in_driver(sdata
))
230 trace_drv_set_tsf(local
, sdata
, tsf
);
231 if (local
->ops
->set_tsf
)
232 local
->ops
->set_tsf(&local
->hw
, &sdata
->vif
, tsf
);
233 trace_drv_return_void(local
);
236 void drv_offset_tsf(struct ieee80211_local
*local
,
237 struct ieee80211_sub_if_data
*sdata
,
242 if (!check_sdata_in_driver(sdata
))
245 trace_drv_offset_tsf(local
, sdata
, offset
);
246 if (local
->ops
->offset_tsf
)
247 local
->ops
->offset_tsf(&local
->hw
, &sdata
->vif
, offset
);
248 trace_drv_return_void(local
);
251 void drv_reset_tsf(struct ieee80211_local
*local
,
252 struct ieee80211_sub_if_data
*sdata
)
256 if (!check_sdata_in_driver(sdata
))
259 trace_drv_reset_tsf(local
, sdata
);
260 if (local
->ops
->reset_tsf
)
261 local
->ops
->reset_tsf(&local
->hw
, &sdata
->vif
);
262 trace_drv_return_void(local
);
265 int drv_switch_vif_chanctx(struct ieee80211_local
*local
,
266 struct ieee80211_vif_chanctx_switch
*vifs
,
267 int n_vifs
, enum ieee80211_chanctx_switch_mode mode
)
274 if (!local
->ops
->switch_vif_chanctx
)
277 for (i
= 0; i
< n_vifs
; i
++) {
278 struct ieee80211_chanctx
*new_ctx
=
279 container_of(vifs
[i
].new_ctx
,
280 struct ieee80211_chanctx
,
282 struct ieee80211_chanctx
*old_ctx
=
283 container_of(vifs
[i
].old_ctx
,
284 struct ieee80211_chanctx
,
287 WARN_ON_ONCE(!old_ctx
->driver_present
);
288 WARN_ON_ONCE((mode
== CHANCTX_SWMODE_SWAP_CONTEXTS
&&
289 new_ctx
->driver_present
) ||
290 (mode
== CHANCTX_SWMODE_REASSIGN_VIF
&&
291 !new_ctx
->driver_present
));
294 trace_drv_switch_vif_chanctx(local
, vifs
, n_vifs
, mode
);
295 ret
= local
->ops
->switch_vif_chanctx(&local
->hw
,
297 trace_drv_return_int(local
, ret
);
299 if (!ret
&& mode
== CHANCTX_SWMODE_SWAP_CONTEXTS
) {
300 for (i
= 0; i
< n_vifs
; i
++) {
301 struct ieee80211_chanctx
*new_ctx
=
302 container_of(vifs
[i
].new_ctx
,
303 struct ieee80211_chanctx
,
305 struct ieee80211_chanctx
*old_ctx
=
306 container_of(vifs
[i
].old_ctx
,
307 struct ieee80211_chanctx
,
310 new_ctx
->driver_present
= true;
311 old_ctx
->driver_present
= false;
318 int drv_ampdu_action(struct ieee80211_local
*local
,
319 struct ieee80211_sub_if_data
*sdata
,
320 struct ieee80211_ampdu_params
*params
)
322 int ret
= -EOPNOTSUPP
;
326 sdata
= get_bss_sdata(sdata
);
327 if (!check_sdata_in_driver(sdata
))
330 trace_drv_ampdu_action(local
, sdata
, params
);
332 if (local
->ops
->ampdu_action
)
333 ret
= local
->ops
->ampdu_action(&local
->hw
, &sdata
->vif
, params
);
335 trace_drv_return_int(local
, ret
);