1 /* 2 * Copyright 2015 Intel Deutschland GmbH 3 * 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. 7 */ 8 #include <net/mac80211.h> 9 #include "ieee80211_i.h" 10 #include "trace.h" 11 #include "driver-ops.h" 12 13 int drv_start(struct ieee80211_local *local) 14 { 15 int ret; 16 17 might_sleep(); 18 19 if (WARN_ON(local->started)) 20 return -EALREADY; 21 22 trace_drv_start(local); 23 local->started = true; 24 /* allow rx frames */ 25 smp_mb(); 26 ret = local->ops->start(&local->hw); 27 trace_drv_return_int(local, ret); 28 29 if (ret) 30 local->started = false; 31 32 return ret; 33 } 34 35 void drv_stop(struct ieee80211_local *local) 36 { 37 might_sleep(); 38 39 if (WARN_ON(!local->started)) 40 return; 41 42 trace_drv_stop(local); 43 local->ops->stop(&local->hw); 44 trace_drv_return_void(local); 45 46 /* sync away all work on the tasklet before clearing started */ 47 tasklet_disable(&local->tasklet); 48 tasklet_enable(&local->tasklet); 49 50 barrier(); 51 52 local->started = false; 53 } 54 55 int drv_add_interface(struct ieee80211_local *local, 56 struct ieee80211_sub_if_data *sdata) 57 { 58 int ret; 59 60 might_sleep(); 61 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)))) 66 return -EINVAL; 67 68 trace_drv_add_interface(local, sdata); 69 ret = local->ops->add_interface(&local->hw, &sdata->vif); 70 trace_drv_return_int(local, ret); 71 72 if (ret == 0) 73 sdata->flags |= IEEE80211_SDATA_IN_DRIVER; 74 75 return ret; 76 } 77 78 int drv_change_interface(struct ieee80211_local *local, 79 struct ieee80211_sub_if_data *sdata, 80 enum nl80211_iftype type, bool p2p) 81 { 82 int ret; 83 84 might_sleep(); 85 86 if (!check_sdata_in_driver(sdata)) 87 return -EIO; 88 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); 92 return ret; 93 } 94 95 void drv_remove_interface(struct ieee80211_local *local, 96 struct ieee80211_sub_if_data *sdata) 97 { 98 might_sleep(); 99 100 if (!check_sdata_in_driver(sdata)) 101 return; 102 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); 107 } 108 109 __must_check 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) 115 { 116 int ret = 0; 117 118 might_sleep(); 119 120 sdata = get_bss_sdata(sdata); 121 if (!check_sdata_in_driver(sdata)) 122 return -EIO; 123 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); 131 if (ret == 0) 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); 136 } 137 trace_drv_return_int(local, ret); 138 return ret; 139 } 140 141 void drv_sta_rc_update(struct ieee80211_local *local, 142 struct ieee80211_sub_if_data *sdata, 143 struct ieee80211_sta *sta, u32 changed) 144 { 145 sdata = get_bss_sdata(sdata); 146 if (!check_sdata_in_driver(sdata)) 147 return; 148 149 WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED && 150 (sdata->vif.type != NL80211_IFTYPE_ADHOC && 151 sdata->vif.type != NL80211_IFTYPE_MESH_POINT)); 152 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, 156 sta, changed); 157 158 trace_drv_return_void(local); 159 } 160 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) 164 { 165 int ret = -EOPNOTSUPP; 166 167 might_sleep(); 168 169 if (!check_sdata_in_driver(sdata)) 170 return -EIO; 171 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)) 176 return -EINVAL; 177 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, 181 ac, params); 182 trace_drv_return_int(local, ret); 183 return ret; 184 } 185 186 u64 drv_get_tsf(struct ieee80211_local *local, 187 struct ieee80211_sub_if_data *sdata) 188 { 189 u64 ret = -1ULL; 190 191 might_sleep(); 192 193 if (!check_sdata_in_driver(sdata)) 194 return ret; 195 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); 200 return ret; 201 } 202 203 void drv_set_tsf(struct ieee80211_local *local, 204 struct ieee80211_sub_if_data *sdata, 205 u64 tsf) 206 { 207 might_sleep(); 208 209 if (!check_sdata_in_driver(sdata)) 210 return; 211 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); 216 } 217 218 void drv_offset_tsf(struct ieee80211_local *local, 219 struct ieee80211_sub_if_data *sdata, 220 s64 offset) 221 { 222 might_sleep(); 223 224 if (!check_sdata_in_driver(sdata)) 225 return; 226 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); 231 } 232 233 void drv_reset_tsf(struct ieee80211_local *local, 234 struct ieee80211_sub_if_data *sdata) 235 { 236 might_sleep(); 237 238 if (!check_sdata_in_driver(sdata)) 239 return; 240 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); 245 } 246 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) 250 { 251 int ret = 0; 252 int i; 253 254 might_sleep(); 255 256 if (!local->ops->switch_vif_chanctx) 257 return -EOPNOTSUPP; 258 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, 263 conf); 264 struct ieee80211_chanctx *old_ctx = 265 container_of(vifs[i].old_ctx, 266 struct ieee80211_chanctx, 267 conf); 268 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)); 274 } 275 276 trace_drv_switch_vif_chanctx(local, vifs, n_vifs, mode); 277 ret = local->ops->switch_vif_chanctx(&local->hw, 278 vifs, n_vifs, mode); 279 trace_drv_return_int(local, ret); 280 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, 286 conf); 287 struct ieee80211_chanctx *old_ctx = 288 container_of(vifs[i].old_ctx, 289 struct ieee80211_chanctx, 290 conf); 291 292 new_ctx->driver_present = true; 293 old_ctx->driver_present = false; 294 } 295 } 296 297 return ret; 298 } 299 300 int drv_ampdu_action(struct ieee80211_local *local, 301 struct ieee80211_sub_if_data *sdata, 302 struct ieee80211_ampdu_params *params) 303 { 304 int ret = -EOPNOTSUPP; 305 306 might_sleep(); 307 308 sdata = get_bss_sdata(sdata); 309 if (!check_sdata_in_driver(sdata)) 310 return -EIO; 311 312 trace_drv_ampdu_action(local, sdata, params); 313 314 if (local->ops->ampdu_action) 315 ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params); 316 317 trace_drv_return_int(local, ret); 318 319 return ret; 320 } 321