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