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
);
141 void drv_sta_rc_update(struct ieee80211_local
*local
,
142 struct ieee80211_sub_if_data
*sdata
,
143 struct ieee80211_sta
*sta
, u32 changed
)
145 sdata
= get_bss_sdata(sdata
);
146 if (!check_sdata_in_driver(sdata
))
149 WARN_ON(changed
& IEEE80211_RC_SUPP_RATES_CHANGED
&&
150 (sdata
->vif
.type
!= NL80211_IFTYPE_ADHOC
&&
151 sdata
->vif
.type
!= NL80211_IFTYPE_MESH_POINT
));
153 trace_drv_sta_rc_update(local
, sdata
, sta
, changed
);
154 if (local
->ops
->sta_rc_update
)
155 local
->ops
->sta_rc_update(&local
->hw
, &sdata
->vif
,
158 trace_drv_return_void(local
);
161 int drv_conf_tx(struct ieee80211_local
*local
,
162 struct ieee80211_sub_if_data
*sdata
, u16 ac
,
163 const struct ieee80211_tx_queue_params
*params
)
165 int ret
= -EOPNOTSUPP
;
169 if (!check_sdata_in_driver(sdata
))
172 if (WARN_ONCE(params
->cw_min
== 0 ||
173 params
->cw_min
> params
->cw_max
,
174 "%s: invalid CW_min/CW_max: %d/%d\n",
175 sdata
->name
, params
->cw_min
, params
->cw_max
))
178 trace_drv_conf_tx(local
, sdata
, ac
, params
);
179 if (local
->ops
->conf_tx
)
180 ret
= local
->ops
->conf_tx(&local
->hw
, &sdata
->vif
,
182 trace_drv_return_int(local
, ret
);
186 u64
drv_get_tsf(struct ieee80211_local
*local
,
187 struct ieee80211_sub_if_data
*sdata
)
193 if (!check_sdata_in_driver(sdata
))
196 trace_drv_get_tsf(local
, sdata
);
197 if (local
->ops
->get_tsf
)
198 ret
= local
->ops
->get_tsf(&local
->hw
, &sdata
->vif
);
199 trace_drv_return_u64(local
, ret
);
203 void drv_set_tsf(struct ieee80211_local
*local
,
204 struct ieee80211_sub_if_data
*sdata
,
209 if (!check_sdata_in_driver(sdata
))
212 trace_drv_set_tsf(local
, sdata
, tsf
);
213 if (local
->ops
->set_tsf
)
214 local
->ops
->set_tsf(&local
->hw
, &sdata
->vif
, tsf
);
215 trace_drv_return_void(local
);
218 void drv_offset_tsf(struct ieee80211_local
*local
,
219 struct ieee80211_sub_if_data
*sdata
,
224 if (!check_sdata_in_driver(sdata
))
227 trace_drv_offset_tsf(local
, sdata
, offset
);
228 if (local
->ops
->offset_tsf
)
229 local
->ops
->offset_tsf(&local
->hw
, &sdata
->vif
, offset
);
230 trace_drv_return_void(local
);
233 void drv_reset_tsf(struct ieee80211_local
*local
,
234 struct ieee80211_sub_if_data
*sdata
)
238 if (!check_sdata_in_driver(sdata
))
241 trace_drv_reset_tsf(local
, sdata
);
242 if (local
->ops
->reset_tsf
)
243 local
->ops
->reset_tsf(&local
->hw
, &sdata
->vif
);
244 trace_drv_return_void(local
);
247 int drv_switch_vif_chanctx(struct ieee80211_local
*local
,
248 struct ieee80211_vif_chanctx_switch
*vifs
,
249 int n_vifs
, enum ieee80211_chanctx_switch_mode mode
)
256 if (!local
->ops
->switch_vif_chanctx
)
259 for (i
= 0; i
< n_vifs
; i
++) {
260 struct ieee80211_chanctx
*new_ctx
=
261 container_of(vifs
[i
].new_ctx
,
262 struct ieee80211_chanctx
,
264 struct ieee80211_chanctx
*old_ctx
=
265 container_of(vifs
[i
].old_ctx
,
266 struct ieee80211_chanctx
,
269 WARN_ON_ONCE(!old_ctx
->driver_present
);
270 WARN_ON_ONCE((mode
== CHANCTX_SWMODE_SWAP_CONTEXTS
&&
271 new_ctx
->driver_present
) ||
272 (mode
== CHANCTX_SWMODE_REASSIGN_VIF
&&
273 !new_ctx
->driver_present
));
276 trace_drv_switch_vif_chanctx(local
, vifs
, n_vifs
, mode
);
277 ret
= local
->ops
->switch_vif_chanctx(&local
->hw
,
279 trace_drv_return_int(local
, ret
);
281 if (!ret
&& mode
== CHANCTX_SWMODE_SWAP_CONTEXTS
) {
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
,
287 struct ieee80211_chanctx
*old_ctx
=
288 container_of(vifs
[i
].old_ctx
,
289 struct ieee80211_chanctx
,
292 new_ctx
->driver_present
= true;
293 old_ctx
->driver_present
= false;
300 int drv_ampdu_action(struct ieee80211_local
*local
,
301 struct ieee80211_sub_if_data
*sdata
,
302 struct ieee80211_ampdu_params
*params
)
304 int ret
= -EOPNOTSUPP
;
308 sdata
= get_bss_sdata(sdata
);
309 if (!check_sdata_in_driver(sdata
))
312 trace_drv_ampdu_action(local
, sdata
, params
);
314 if (local
->ops
->ampdu_action
)
315 ret
= local
->ops
->ampdu_action(&local
->hw
, &sdata
->vif
, params
);
317 trace_drv_return_int(local
, ret
);