1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright 2015 Intel Deutschland GmbH 4 */ 5 #include <net/mac80211.h> 6 #include "ieee80211_i.h" 7 #include "trace.h" 8 #include "driver-ops.h" 9 10 int drv_start(struct ieee80211_local *local) 11 { 12 int ret; 13 14 might_sleep(); 15 16 if (WARN_ON(local->started)) 17 return -EALREADY; 18 19 trace_drv_start(local); 20 local->started = true; 21 /* allow rx frames */ 22 smp_mb(); 23 ret = local->ops->start(&local->hw); 24 trace_drv_return_int(local, ret); 25 26 if (ret) 27 local->started = false; 28 29 return ret; 30 } 31 32 void drv_stop(struct ieee80211_local *local) 33 { 34 might_sleep(); 35 36 if (WARN_ON(!local->started)) 37 return; 38 39 trace_drv_stop(local); 40 local->ops->stop(&local->hw); 41 trace_drv_return_void(local); 42 43 /* sync away all work on the tasklet before clearing started */ 44 tasklet_disable(&local->tasklet); 45 tasklet_enable(&local->tasklet); 46 47 barrier(); 48 49 local->started = false; 50 } 51 52 int drv_add_interface(struct ieee80211_local *local, 53 struct ieee80211_sub_if_data *sdata) 54 { 55 int ret; 56 57 might_sleep(); 58 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)))) 63 return -EINVAL; 64 65 trace_drv_add_interface(local, sdata); 66 ret = local->ops->add_interface(&local->hw, &sdata->vif); 67 trace_drv_return_int(local, ret); 68 69 if (ret == 0) 70 sdata->flags |= IEEE80211_SDATA_IN_DRIVER; 71 72 return ret; 73 } 74 75 int drv_change_interface(struct ieee80211_local *local, 76 struct ieee80211_sub_if_data *sdata, 77 enum nl80211_iftype type, bool p2p) 78 { 79 int ret; 80 81 might_sleep(); 82 83 if (!check_sdata_in_driver(sdata)) 84 return -EIO; 85 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); 89 return ret; 90 } 91 92 void drv_remove_interface(struct ieee80211_local *local, 93 struct ieee80211_sub_if_data *sdata) 94 { 95 might_sleep(); 96 97 if (!check_sdata_in_driver(sdata)) 98 return; 99 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); 104 } 105 106 __must_check 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) 112 { 113 int ret = 0; 114 115 might_sleep(); 116 117 sdata = get_bss_sdata(sdata); 118 if (!check_sdata_in_driver(sdata)) 119 return -EIO; 120 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); 128 if (ret == 0) 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); 133 } 134 trace_drv_return_int(local, ret); 135 return ret; 136 } 137 138 __must_check 139 int drv_sta_set_txpwr(struct ieee80211_local *local, 140 struct ieee80211_sub_if_data *sdata, 141 struct sta_info *sta) 142 { 143 int ret = -EOPNOTSUPP; 144 145 might_sleep(); 146 147 sdata = get_bss_sdata(sdata); 148 if (!check_sdata_in_driver(sdata)) 149 return -EIO; 150 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, 154 &sta->sta); 155 trace_drv_return_int(local, ret); 156 return ret; 157 } 158 159 void drv_sta_rc_update(struct ieee80211_local *local, 160 struct ieee80211_sub_if_data *sdata, 161 struct ieee80211_sta *sta, u32 changed) 162 { 163 sdata = get_bss_sdata(sdata); 164 if (!check_sdata_in_driver(sdata)) 165 return; 166 167 WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED && 168 (sdata->vif.type != NL80211_IFTYPE_ADHOC && 169 sdata->vif.type != NL80211_IFTYPE_MESH_POINT)); 170 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, 174 sta, changed); 175 176 trace_drv_return_void(local); 177 } 178 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) 182 { 183 int ret = -EOPNOTSUPP; 184 185 might_sleep(); 186 187 if (!check_sdata_in_driver(sdata)) 188 return -EIO; 189 190 if (params->cw_min == 0 || params->cw_min > params->cw_max) { 191 /* 192 * If we can't configure hardware anyway, don't warn. We may 193 * never have initialized the CW parameters. 194 */ 195 WARN_ONCE(local->ops->conf_tx, 196 "%s: invalid CW_min/CW_max: %d/%d\n", 197 sdata->name, params->cw_min, params->cw_max); 198 return -EINVAL; 199 } 200 201 trace_drv_conf_tx(local, sdata, ac, params); 202 if (local->ops->conf_tx) 203 ret = local->ops->conf_tx(&local->hw, &sdata->vif, 204 ac, params); 205 trace_drv_return_int(local, ret); 206 return ret; 207 } 208 209 u64 drv_get_tsf(struct ieee80211_local *local, 210 struct ieee80211_sub_if_data *sdata) 211 { 212 u64 ret = -1ULL; 213 214 might_sleep(); 215 216 if (!check_sdata_in_driver(sdata)) 217 return ret; 218 219 trace_drv_get_tsf(local, sdata); 220 if (local->ops->get_tsf) 221 ret = local->ops->get_tsf(&local->hw, &sdata->vif); 222 trace_drv_return_u64(local, ret); 223 return ret; 224 } 225 226 void drv_set_tsf(struct ieee80211_local *local, 227 struct ieee80211_sub_if_data *sdata, 228 u64 tsf) 229 { 230 might_sleep(); 231 232 if (!check_sdata_in_driver(sdata)) 233 return; 234 235 trace_drv_set_tsf(local, sdata, tsf); 236 if (local->ops->set_tsf) 237 local->ops->set_tsf(&local->hw, &sdata->vif, tsf); 238 trace_drv_return_void(local); 239 } 240 241 void drv_offset_tsf(struct ieee80211_local *local, 242 struct ieee80211_sub_if_data *sdata, 243 s64 offset) 244 { 245 might_sleep(); 246 247 if (!check_sdata_in_driver(sdata)) 248 return; 249 250 trace_drv_offset_tsf(local, sdata, offset); 251 if (local->ops->offset_tsf) 252 local->ops->offset_tsf(&local->hw, &sdata->vif, offset); 253 trace_drv_return_void(local); 254 } 255 256 void drv_reset_tsf(struct ieee80211_local *local, 257 struct ieee80211_sub_if_data *sdata) 258 { 259 might_sleep(); 260 261 if (!check_sdata_in_driver(sdata)) 262 return; 263 264 trace_drv_reset_tsf(local, sdata); 265 if (local->ops->reset_tsf) 266 local->ops->reset_tsf(&local->hw, &sdata->vif); 267 trace_drv_return_void(local); 268 } 269 270 int drv_switch_vif_chanctx(struct ieee80211_local *local, 271 struct ieee80211_vif_chanctx_switch *vifs, 272 int n_vifs, enum ieee80211_chanctx_switch_mode mode) 273 { 274 int ret = 0; 275 int i; 276 277 might_sleep(); 278 279 if (!local->ops->switch_vif_chanctx) 280 return -EOPNOTSUPP; 281 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 WARN_ON_ONCE(!old_ctx->driver_present); 293 WARN_ON_ONCE((mode == CHANCTX_SWMODE_SWAP_CONTEXTS && 294 new_ctx->driver_present) || 295 (mode == CHANCTX_SWMODE_REASSIGN_VIF && 296 !new_ctx->driver_present)); 297 } 298 299 trace_drv_switch_vif_chanctx(local, vifs, n_vifs, mode); 300 ret = local->ops->switch_vif_chanctx(&local->hw, 301 vifs, n_vifs, mode); 302 trace_drv_return_int(local, ret); 303 304 if (!ret && mode == CHANCTX_SWMODE_SWAP_CONTEXTS) { 305 for (i = 0; i < n_vifs; i++) { 306 struct ieee80211_chanctx *new_ctx = 307 container_of(vifs[i].new_ctx, 308 struct ieee80211_chanctx, 309 conf); 310 struct ieee80211_chanctx *old_ctx = 311 container_of(vifs[i].old_ctx, 312 struct ieee80211_chanctx, 313 conf); 314 315 new_ctx->driver_present = true; 316 old_ctx->driver_present = false; 317 } 318 } 319 320 return ret; 321 } 322 323 int drv_ampdu_action(struct ieee80211_local *local, 324 struct ieee80211_sub_if_data *sdata, 325 struct ieee80211_ampdu_params *params) 326 { 327 int ret = -EOPNOTSUPP; 328 329 might_sleep(); 330 331 sdata = get_bss_sdata(sdata); 332 if (!check_sdata_in_driver(sdata)) 333 return -EIO; 334 335 trace_drv_ampdu_action(local, sdata, params); 336 337 if (local->ops->ampdu_action) 338 ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params); 339 340 trace_drv_return_int(local, ret); 341 342 return ret; 343 } 344