0001
0002
0003
0004
0005
0006 #include <net/mac80211.h>
0007 #include "ieee80211_i.h"
0008 #include "trace.h"
0009 #include "driver-ops.h"
0010
0011 int drv_start(struct ieee80211_local *local)
0012 {
0013 int ret;
0014
0015 might_sleep();
0016
0017 if (WARN_ON(local->started))
0018 return -EALREADY;
0019
0020 trace_drv_start(local);
0021 local->started = true;
0022
0023 smp_mb();
0024 ret = local->ops->start(&local->hw);
0025 trace_drv_return_int(local, ret);
0026
0027 if (ret)
0028 local->started = false;
0029
0030 return ret;
0031 }
0032
0033 void drv_stop(struct ieee80211_local *local)
0034 {
0035 might_sleep();
0036
0037 if (WARN_ON(!local->started))
0038 return;
0039
0040 trace_drv_stop(local);
0041 local->ops->stop(&local->hw);
0042 trace_drv_return_void(local);
0043
0044
0045 tasklet_disable(&local->tasklet);
0046 tasklet_enable(&local->tasklet);
0047
0048 barrier();
0049
0050 local->started = false;
0051 }
0052
0053 int drv_add_interface(struct ieee80211_local *local,
0054 struct ieee80211_sub_if_data *sdata)
0055 {
0056 int ret;
0057
0058 might_sleep();
0059
0060 if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
0061 (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
0062 !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
0063 !(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))))
0064 return -EINVAL;
0065
0066 trace_drv_add_interface(local, sdata);
0067 ret = local->ops->add_interface(&local->hw, &sdata->vif);
0068 trace_drv_return_int(local, ret);
0069
0070 if (ret == 0)
0071 sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
0072
0073 return ret;
0074 }
0075
0076 int drv_change_interface(struct ieee80211_local *local,
0077 struct ieee80211_sub_if_data *sdata,
0078 enum nl80211_iftype type, bool p2p)
0079 {
0080 int ret;
0081
0082 might_sleep();
0083
0084 if (!check_sdata_in_driver(sdata))
0085 return -EIO;
0086
0087 trace_drv_change_interface(local, sdata, type, p2p);
0088 ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
0089 trace_drv_return_int(local, ret);
0090 return ret;
0091 }
0092
0093 void drv_remove_interface(struct ieee80211_local *local,
0094 struct ieee80211_sub_if_data *sdata)
0095 {
0096 might_sleep();
0097
0098 if (!check_sdata_in_driver(sdata))
0099 return;
0100
0101 trace_drv_remove_interface(local, sdata);
0102 local->ops->remove_interface(&local->hw, &sdata->vif);
0103 sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
0104 trace_drv_return_void(local);
0105 }
0106
0107 __must_check
0108 int drv_sta_state(struct ieee80211_local *local,
0109 struct ieee80211_sub_if_data *sdata,
0110 struct sta_info *sta,
0111 enum ieee80211_sta_state old_state,
0112 enum ieee80211_sta_state new_state)
0113 {
0114 int ret = 0;
0115
0116 might_sleep();
0117
0118 sdata = get_bss_sdata(sdata);
0119 if (!check_sdata_in_driver(sdata))
0120 return -EIO;
0121
0122 trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state);
0123 if (local->ops->sta_state) {
0124 ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta,
0125 old_state, new_state);
0126 } else if (old_state == IEEE80211_STA_AUTH &&
0127 new_state == IEEE80211_STA_ASSOC) {
0128 ret = drv_sta_add(local, sdata, &sta->sta);
0129 if (ret == 0) {
0130 sta->uploaded = true;
0131 if (rcu_access_pointer(sta->sta.rates))
0132 drv_sta_rate_tbl_update(local, sdata, &sta->sta);
0133 }
0134 } else if (old_state == IEEE80211_STA_ASSOC &&
0135 new_state == IEEE80211_STA_AUTH) {
0136 drv_sta_remove(local, sdata, &sta->sta);
0137 }
0138 trace_drv_return_int(local, ret);
0139 return ret;
0140 }
0141
0142 __must_check
0143 int drv_sta_set_txpwr(struct ieee80211_local *local,
0144 struct ieee80211_sub_if_data *sdata,
0145 struct sta_info *sta)
0146 {
0147 int ret = -EOPNOTSUPP;
0148
0149 might_sleep();
0150
0151 sdata = get_bss_sdata(sdata);
0152 if (!check_sdata_in_driver(sdata))
0153 return -EIO;
0154
0155 trace_drv_sta_set_txpwr(local, sdata, &sta->sta);
0156 if (local->ops->sta_set_txpwr)
0157 ret = local->ops->sta_set_txpwr(&local->hw, &sdata->vif,
0158 &sta->sta);
0159 trace_drv_return_int(local, ret);
0160 return ret;
0161 }
0162
0163 void drv_sta_rc_update(struct ieee80211_local *local,
0164 struct ieee80211_sub_if_data *sdata,
0165 struct ieee80211_sta *sta, u32 changed)
0166 {
0167 sdata = get_bss_sdata(sdata);
0168 if (!check_sdata_in_driver(sdata))
0169 return;
0170
0171 WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED &&
0172 (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
0173 sdata->vif.type != NL80211_IFTYPE_MESH_POINT));
0174
0175 trace_drv_sta_rc_update(local, sdata, sta, changed);
0176 if (local->ops->sta_rc_update)
0177 local->ops->sta_rc_update(&local->hw, &sdata->vif,
0178 sta, changed);
0179
0180 trace_drv_return_void(local);
0181 }
0182
0183 int drv_conf_tx(struct ieee80211_local *local,
0184 struct ieee80211_link_data *link, u16 ac,
0185 const struct ieee80211_tx_queue_params *params)
0186 {
0187 struct ieee80211_sub_if_data *sdata = link->sdata;
0188 int ret = -EOPNOTSUPP;
0189
0190 might_sleep();
0191
0192 if (!check_sdata_in_driver(sdata))
0193 return -EIO;
0194
0195 if (params->cw_min == 0 || params->cw_min > params->cw_max) {
0196
0197
0198
0199
0200 WARN_ONCE(local->ops->conf_tx,
0201 "%s: invalid CW_min/CW_max: %d/%d\n",
0202 sdata->name, params->cw_min, params->cw_max);
0203 return -EINVAL;
0204 }
0205
0206 trace_drv_conf_tx(local, sdata, link->link_id, ac, params);
0207 if (local->ops->conf_tx)
0208 ret = local->ops->conf_tx(&local->hw, &sdata->vif,
0209 link->link_id, ac, params);
0210 trace_drv_return_int(local, ret);
0211 return ret;
0212 }
0213
0214 u64 drv_get_tsf(struct ieee80211_local *local,
0215 struct ieee80211_sub_if_data *sdata)
0216 {
0217 u64 ret = -1ULL;
0218
0219 might_sleep();
0220
0221 if (!check_sdata_in_driver(sdata))
0222 return ret;
0223
0224 trace_drv_get_tsf(local, sdata);
0225 if (local->ops->get_tsf)
0226 ret = local->ops->get_tsf(&local->hw, &sdata->vif);
0227 trace_drv_return_u64(local, ret);
0228 return ret;
0229 }
0230
0231 void drv_set_tsf(struct ieee80211_local *local,
0232 struct ieee80211_sub_if_data *sdata,
0233 u64 tsf)
0234 {
0235 might_sleep();
0236
0237 if (!check_sdata_in_driver(sdata))
0238 return;
0239
0240 trace_drv_set_tsf(local, sdata, tsf);
0241 if (local->ops->set_tsf)
0242 local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
0243 trace_drv_return_void(local);
0244 }
0245
0246 void drv_offset_tsf(struct ieee80211_local *local,
0247 struct ieee80211_sub_if_data *sdata,
0248 s64 offset)
0249 {
0250 might_sleep();
0251
0252 if (!check_sdata_in_driver(sdata))
0253 return;
0254
0255 trace_drv_offset_tsf(local, sdata, offset);
0256 if (local->ops->offset_tsf)
0257 local->ops->offset_tsf(&local->hw, &sdata->vif, offset);
0258 trace_drv_return_void(local);
0259 }
0260
0261 void drv_reset_tsf(struct ieee80211_local *local,
0262 struct ieee80211_sub_if_data *sdata)
0263 {
0264 might_sleep();
0265
0266 if (!check_sdata_in_driver(sdata))
0267 return;
0268
0269 trace_drv_reset_tsf(local, sdata);
0270 if (local->ops->reset_tsf)
0271 local->ops->reset_tsf(&local->hw, &sdata->vif);
0272 trace_drv_return_void(local);
0273 }
0274
0275 int drv_switch_vif_chanctx(struct ieee80211_local *local,
0276 struct ieee80211_vif_chanctx_switch *vifs,
0277 int n_vifs, enum ieee80211_chanctx_switch_mode mode)
0278 {
0279 int ret = 0;
0280 int i;
0281
0282 might_sleep();
0283
0284 if (!local->ops->switch_vif_chanctx)
0285 return -EOPNOTSUPP;
0286
0287 for (i = 0; i < n_vifs; i++) {
0288 struct ieee80211_chanctx *new_ctx =
0289 container_of(vifs[i].new_ctx,
0290 struct ieee80211_chanctx,
0291 conf);
0292 struct ieee80211_chanctx *old_ctx =
0293 container_of(vifs[i].old_ctx,
0294 struct ieee80211_chanctx,
0295 conf);
0296
0297 WARN_ON_ONCE(!old_ctx->driver_present);
0298 WARN_ON_ONCE((mode == CHANCTX_SWMODE_SWAP_CONTEXTS &&
0299 new_ctx->driver_present) ||
0300 (mode == CHANCTX_SWMODE_REASSIGN_VIF &&
0301 !new_ctx->driver_present));
0302 }
0303
0304 trace_drv_switch_vif_chanctx(local, vifs, n_vifs, mode);
0305 ret = local->ops->switch_vif_chanctx(&local->hw,
0306 vifs, n_vifs, mode);
0307 trace_drv_return_int(local, ret);
0308
0309 if (!ret && mode == CHANCTX_SWMODE_SWAP_CONTEXTS) {
0310 for (i = 0; i < n_vifs; i++) {
0311 struct ieee80211_chanctx *new_ctx =
0312 container_of(vifs[i].new_ctx,
0313 struct ieee80211_chanctx,
0314 conf);
0315 struct ieee80211_chanctx *old_ctx =
0316 container_of(vifs[i].old_ctx,
0317 struct ieee80211_chanctx,
0318 conf);
0319
0320 new_ctx->driver_present = true;
0321 old_ctx->driver_present = false;
0322 }
0323 }
0324
0325 return ret;
0326 }
0327
0328 int drv_ampdu_action(struct ieee80211_local *local,
0329 struct ieee80211_sub_if_data *sdata,
0330 struct ieee80211_ampdu_params *params)
0331 {
0332 int ret = -EOPNOTSUPP;
0333
0334 might_sleep();
0335
0336 sdata = get_bss_sdata(sdata);
0337 if (!check_sdata_in_driver(sdata))
0338 return -EIO;
0339
0340 trace_drv_ampdu_action(local, sdata, params);
0341
0342 if (local->ops->ampdu_action)
0343 ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params);
0344
0345 trace_drv_return_int(local, ret);
0346
0347 return ret;
0348 }