2 * Copyright 2015 Intel Deutschland GmbH
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 #include <net/mac80211.h>
9 #include "ieee80211_i.h"
11 #include "driver-ops.h"
13 int drv_start(struct ieee80211_local
*local
)
19 if (WARN_ON(local
->started
))
22 trace_drv_start(local
);
23 local
->started
= true;
26 ret
= local
->ops
->start(&local
->hw
);
27 trace_drv_return_int(local
, ret
);
30 local
->started
= false;
35 void drv_stop(struct ieee80211_local
*local
)
39 if (WARN_ON(!local
->started
))
42 trace_drv_stop(local
);
43 local
->ops
->stop(&local
->hw
);
44 trace_drv_return_void(local
);
46 /* sync away all work on the tasklet before clearing started */
47 tasklet_disable(&local
->tasklet
);
48 tasklet_enable(&local
->tasklet
);
52 local
->started
= false;
55 int drv_add_interface(struct ieee80211_local
*local
,
56 struct ieee80211_sub_if_data
*sdata
)
62 if (WARN_ON(sdata
->vif
.type
== NL80211_IFTYPE_AP_VLAN
||
63 (sdata
->vif
.type
== NL80211_IFTYPE_MONITOR
&&
64 !ieee80211_hw_check(&local
->hw
, WANT_MONITOR_VIF
) &&
65 !(sdata
->u
.mntr
.flags
& MONITOR_FLAG_ACTIVE
))))
68 trace_drv_add_interface(local
, sdata
);
69 ret
= local
->ops
->add_interface(&local
->hw
, &sdata
->vif
);
70 trace_drv_return_int(local
, ret
);
73 sdata
->flags
|= IEEE80211_SDATA_IN_DRIVER
;
78 int drv_change_interface(struct ieee80211_local
*local
,
79 struct ieee80211_sub_if_data
*sdata
,
80 enum nl80211_iftype type
, bool p2p
)
86 if (!check_sdata_in_driver(sdata
))
89 trace_drv_change_interface(local
, sdata
, type
, p2p
);
90 ret
= local
->ops
->change_interface(&local
->hw
, &sdata
->vif
, type
, p2p
);
91 trace_drv_return_int(local
, ret
);
95 void drv_remove_interface(struct ieee80211_local
*local
,
96 struct ieee80211_sub_if_data
*sdata
)
100 if (!check_sdata_in_driver(sdata
))
103 trace_drv_remove_interface(local
, sdata
);
104 local
->ops
->remove_interface(&local
->hw
, &sdata
->vif
);
105 sdata
->flags
&= ~IEEE80211_SDATA_IN_DRIVER
;
106 trace_drv_return_void(local
);
110 int drv_sta_state(struct ieee80211_local
*local
,
111 struct ieee80211_sub_if_data
*sdata
,
112 struct sta_info
*sta
,
113 enum ieee80211_sta_state old_state
,
114 enum ieee80211_sta_state new_state
)
120 sdata
= get_bss_sdata(sdata
);
121 if (!check_sdata_in_driver(sdata
))
124 trace_drv_sta_state(local
, sdata
, &sta
->sta
, old_state
, new_state
);
125 if (local
->ops
->sta_state
) {
126 ret
= local
->ops
->sta_state(&local
->hw
, &sdata
->vif
, &sta
->sta
,
127 old_state
, new_state
);
128 } else if (old_state
== IEEE80211_STA_AUTH
&&
129 new_state
== IEEE80211_STA_ASSOC
) {
130 ret
= drv_sta_add(local
, sdata
, &sta
->sta
);
132 sta
->uploaded
= true;
133 } else if (old_state
== IEEE80211_STA_ASSOC
&&
134 new_state
== IEEE80211_STA_AUTH
) {
135 drv_sta_remove(local
, sdata
, &sta
->sta
);
137 trace_drv_return_int(local
, ret
);
142 int drv_sta_set_txpwr(struct ieee80211_local
*local
,
143 struct ieee80211_sub_if_data
*sdata
,
144 struct sta_info
*sta
)
146 int ret
= -EOPNOTSUPP
;
150 sdata
= get_bss_sdata(sdata
);
151 if (!check_sdata_in_driver(sdata
))
154 trace_drv_sta_set_txpwr(local
, sdata
, &sta
->sta
);
155 if (local
->ops
->sta_set_txpwr
)
156 ret
= local
->ops
->sta_set_txpwr(&local
->hw
, &sdata
->vif
,
158 trace_drv_return_int(local
, ret
);
162 void drv_sta_rc_update(struct ieee80211_local
*local
,
163 struct ieee80211_sub_if_data
*sdata
,
164 struct ieee80211_sta
*sta
, u32 changed
)
166 sdata
= get_bss_sdata(sdata
);
167 if (!check_sdata_in_driver(sdata
))
170 WARN_ON(changed
& IEEE80211_RC_SUPP_RATES_CHANGED
&&
171 (sdata
->vif
.type
!= NL80211_IFTYPE_ADHOC
&&
172 sdata
->vif
.type
!= NL80211_IFTYPE_MESH_POINT
));
174 trace_drv_sta_rc_update(local
, sdata
, sta
, changed
);
175 if (local
->ops
->sta_rc_update
)
176 local
->ops
->sta_rc_update(&local
->hw
, &sdata
->vif
,
179 trace_drv_return_void(local
);
182 int drv_conf_tx(struct ieee80211_local
*local
,
183 struct ieee80211_sub_if_data
*sdata
, u16 ac
,
184 const struct ieee80211_tx_queue_params
*params
)
186 int ret
= -EOPNOTSUPP
;
190 if (!check_sdata_in_driver(sdata
))
193 if (WARN_ONCE(params
->cw_min
== 0 ||
194 params
->cw_min
> params
->cw_max
,
195 "%s: invalid CW_min/CW_max: %d/%d\n",
196 sdata
->name
, params
->cw_min
, params
->cw_max
))
199 trace_drv_conf_tx(local
, sdata
, ac
, params
);
200 if (local
->ops
->conf_tx
)
201 ret
= local
->ops
->conf_tx(&local
->hw
, &sdata
->vif
,
203 trace_drv_return_int(local
, ret
);
207 u64
drv_get_tsf(struct ieee80211_local
*local
,
208 struct ieee80211_sub_if_data
*sdata
)
214 if (!check_sdata_in_driver(sdata
))
217 trace_drv_get_tsf(local
, sdata
);
218 if (local
->ops
->get_tsf
)
219 ret
= local
->ops
->get_tsf(&local
->hw
, &sdata
->vif
);
220 trace_drv_return_u64(local
, ret
);
224 void drv_set_tsf(struct ieee80211_local
*local
,
225 struct ieee80211_sub_if_data
*sdata
,
230 if (!check_sdata_in_driver(sdata
))
233 trace_drv_set_tsf(local
, sdata
, tsf
);
234 if (local
->ops
->set_tsf
)
235 local
->ops
->set_tsf(&local
->hw
, &sdata
->vif
, tsf
);
236 trace_drv_return_void(local
);
239 void drv_offset_tsf(struct ieee80211_local
*local
,
240 struct ieee80211_sub_if_data
*sdata
,
245 if (!check_sdata_in_driver(sdata
))
248 trace_drv_offset_tsf(local
, sdata
, offset
);
249 if (local
->ops
->offset_tsf
)
250 local
->ops
->offset_tsf(&local
->hw
, &sdata
->vif
, offset
);
251 trace_drv_return_void(local
);
254 void drv_reset_tsf(struct ieee80211_local
*local
,
255 struct ieee80211_sub_if_data
*sdata
)
259 if (!check_sdata_in_driver(sdata
))
262 trace_drv_reset_tsf(local
, sdata
);
263 if (local
->ops
->reset_tsf
)
264 local
->ops
->reset_tsf(&local
->hw
, &sdata
->vif
);
265 trace_drv_return_void(local
);
268 int drv_switch_vif_chanctx(struct ieee80211_local
*local
,
269 struct ieee80211_vif_chanctx_switch
*vifs
,
270 int n_vifs
, enum ieee80211_chanctx_switch_mode mode
)
277 if (!local
->ops
->switch_vif_chanctx
)
280 for (i
= 0; i
< n_vifs
; i
++) {
281 struct ieee80211_chanctx
*new_ctx
=
282 container_of(vifs
[i
].new_ctx
,
283 struct ieee80211_chanctx
,
285 struct ieee80211_chanctx
*old_ctx
=
286 container_of(vifs
[i
].old_ctx
,
287 struct ieee80211_chanctx
,
290 WARN_ON_ONCE(!old_ctx
->driver_present
);
291 WARN_ON_ONCE((mode
== CHANCTX_SWMODE_SWAP_CONTEXTS
&&
292 new_ctx
->driver_present
) ||
293 (mode
== CHANCTX_SWMODE_REASSIGN_VIF
&&
294 !new_ctx
->driver_present
));
297 trace_drv_switch_vif_chanctx(local
, vifs
, n_vifs
, mode
);
298 ret
= local
->ops
->switch_vif_chanctx(&local
->hw
,
300 trace_drv_return_int(local
, ret
);
302 if (!ret
&& mode
== CHANCTX_SWMODE_SWAP_CONTEXTS
) {
303 for (i
= 0; i
< n_vifs
; i
++) {
304 struct ieee80211_chanctx
*new_ctx
=
305 container_of(vifs
[i
].new_ctx
,
306 struct ieee80211_chanctx
,
308 struct ieee80211_chanctx
*old_ctx
=
309 container_of(vifs
[i
].old_ctx
,
310 struct ieee80211_chanctx
,
313 new_ctx
->driver_present
= true;
314 old_ctx
->driver_present
= false;
321 int drv_ampdu_action(struct ieee80211_local
*local
,
322 struct ieee80211_sub_if_data
*sdata
,
323 struct ieee80211_ampdu_params
*params
)
325 int ret
= -EOPNOTSUPP
;
329 sdata
= get_bss_sdata(sdata
);
330 if (!check_sdata_in_driver(sdata
))
333 trace_drv_ampdu_action(local
, sdata
, params
);
335 if (local
->ops
->ampdu_action
)
336 ret
= local
->ops
->ampdu_action(&local
->hw
, &sdata
->vif
, params
);
338 trace_drv_return_int(local
, ret
);