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 (sdata->vif.active_links && 196 !(sdata->vif.active_links & BIT(link->link_id))) 197 return 0; 198 199 if (params->cw_min == 0 || params->cw_min > params->cw_max) { 200 /* 201 * If we can't configure hardware anyway, don't warn. We may 202 * never have initialized the CW parameters. 203 */ 204 WARN_ONCE(local->ops->conf_tx, 205 "%s: invalid CW_min/CW_max: %d/%d\n", 206 sdata->name, params->cw_min, params->cw_max); 207 return -EINVAL; 208 } 209 210 trace_drv_conf_tx(local, sdata, link->link_id, ac, params); 211 if (local->ops->conf_tx) 212 ret = local->ops->conf_tx(&local->hw, &sdata->vif, 213 link->link_id, ac, params); 214 trace_drv_return_int(local, ret); 215 return ret; 216 } 217 218 u64 drv_get_tsf(struct ieee80211_local *local, 219 struct ieee80211_sub_if_data *sdata) 220 { 221 u64 ret = -1ULL; 222 223 might_sleep(); 224 225 if (!check_sdata_in_driver(sdata)) 226 return ret; 227 228 trace_drv_get_tsf(local, sdata); 229 if (local->ops->get_tsf) 230 ret = local->ops->get_tsf(&local->hw, &sdata->vif); 231 trace_drv_return_u64(local, ret); 232 return ret; 233 } 234 235 void drv_set_tsf(struct ieee80211_local *local, 236 struct ieee80211_sub_if_data *sdata, 237 u64 tsf) 238 { 239 might_sleep(); 240 241 if (!check_sdata_in_driver(sdata)) 242 return; 243 244 trace_drv_set_tsf(local, sdata, tsf); 245 if (local->ops->set_tsf) 246 local->ops->set_tsf(&local->hw, &sdata->vif, tsf); 247 trace_drv_return_void(local); 248 } 249 250 void drv_offset_tsf(struct ieee80211_local *local, 251 struct ieee80211_sub_if_data *sdata, 252 s64 offset) 253 { 254 might_sleep(); 255 256 if (!check_sdata_in_driver(sdata)) 257 return; 258 259 trace_drv_offset_tsf(local, sdata, offset); 260 if (local->ops->offset_tsf) 261 local->ops->offset_tsf(&local->hw, &sdata->vif, offset); 262 trace_drv_return_void(local); 263 } 264 265 void drv_reset_tsf(struct ieee80211_local *local, 266 struct ieee80211_sub_if_data *sdata) 267 { 268 might_sleep(); 269 270 if (!check_sdata_in_driver(sdata)) 271 return; 272 273 trace_drv_reset_tsf(local, sdata); 274 if (local->ops->reset_tsf) 275 local->ops->reset_tsf(&local->hw, &sdata->vif); 276 trace_drv_return_void(local); 277 } 278 279 int drv_assign_vif_chanctx(struct ieee80211_local *local, 280 struct ieee80211_sub_if_data *sdata, 281 struct ieee80211_bss_conf *link_conf, 282 struct ieee80211_chanctx *ctx) 283 { 284 int ret = 0; 285 286 drv_verify_link_exists(sdata, link_conf); 287 if (!check_sdata_in_driver(sdata)) 288 return -EIO; 289 290 if (sdata->vif.active_links && 291 !(sdata->vif.active_links & BIT(link_conf->link_id))) 292 return 0; 293 294 trace_drv_assign_vif_chanctx(local, sdata, link_conf, ctx); 295 if (local->ops->assign_vif_chanctx) { 296 WARN_ON_ONCE(!ctx->driver_present); 297 ret = local->ops->assign_vif_chanctx(&local->hw, 298 &sdata->vif, 299 link_conf, 300 &ctx->conf); 301 } 302 trace_drv_return_int(local, ret); 303 304 return ret; 305 } 306 307 void drv_unassign_vif_chanctx(struct ieee80211_local *local, 308 struct ieee80211_sub_if_data *sdata, 309 struct ieee80211_bss_conf *link_conf, 310 struct ieee80211_chanctx *ctx) 311 { 312 might_sleep(); 313 314 drv_verify_link_exists(sdata, link_conf); 315 if (!check_sdata_in_driver(sdata)) 316 return; 317 318 if (sdata->vif.active_links && 319 !(sdata->vif.active_links & BIT(link_conf->link_id))) 320 return; 321 322 trace_drv_unassign_vif_chanctx(local, sdata, link_conf, ctx); 323 if (local->ops->unassign_vif_chanctx) { 324 WARN_ON_ONCE(!ctx->driver_present); 325 local->ops->unassign_vif_chanctx(&local->hw, 326 &sdata->vif, 327 link_conf, 328 &ctx->conf); 329 } 330 trace_drv_return_void(local); 331 } 332 333 int drv_switch_vif_chanctx(struct ieee80211_local *local, 334 struct ieee80211_vif_chanctx_switch *vifs, 335 int n_vifs, enum ieee80211_chanctx_switch_mode mode) 336 { 337 int ret = 0; 338 int i; 339 340 might_sleep(); 341 342 if (!local->ops->switch_vif_chanctx) 343 return -EOPNOTSUPP; 344 345 for (i = 0; i < n_vifs; i++) { 346 struct ieee80211_chanctx *new_ctx = 347 container_of(vifs[i].new_ctx, 348 struct ieee80211_chanctx, 349 conf); 350 struct ieee80211_chanctx *old_ctx = 351 container_of(vifs[i].old_ctx, 352 struct ieee80211_chanctx, 353 conf); 354 355 WARN_ON_ONCE(!old_ctx->driver_present); 356 WARN_ON_ONCE((mode == CHANCTX_SWMODE_SWAP_CONTEXTS && 357 new_ctx->driver_present) || 358 (mode == CHANCTX_SWMODE_REASSIGN_VIF && 359 !new_ctx->driver_present)); 360 } 361 362 trace_drv_switch_vif_chanctx(local, vifs, n_vifs, mode); 363 ret = local->ops->switch_vif_chanctx(&local->hw, 364 vifs, n_vifs, mode); 365 trace_drv_return_int(local, ret); 366 367 if (!ret && mode == CHANCTX_SWMODE_SWAP_CONTEXTS) { 368 for (i = 0; i < n_vifs; i++) { 369 struct ieee80211_chanctx *new_ctx = 370 container_of(vifs[i].new_ctx, 371 struct ieee80211_chanctx, 372 conf); 373 struct ieee80211_chanctx *old_ctx = 374 container_of(vifs[i].old_ctx, 375 struct ieee80211_chanctx, 376 conf); 377 378 new_ctx->driver_present = true; 379 old_ctx->driver_present = false; 380 } 381 } 382 383 return ret; 384 } 385 386 int drv_ampdu_action(struct ieee80211_local *local, 387 struct ieee80211_sub_if_data *sdata, 388 struct ieee80211_ampdu_params *params) 389 { 390 int ret = -EOPNOTSUPP; 391 392 might_sleep(); 393 394 sdata = get_bss_sdata(sdata); 395 if (!check_sdata_in_driver(sdata)) 396 return -EIO; 397 398 trace_drv_ampdu_action(local, sdata, params); 399 400 if (local->ops->ampdu_action) 401 ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params); 402 403 trace_drv_return_int(local, ret); 404 405 return ret; 406 } 407 408 void drv_link_info_changed(struct ieee80211_local *local, 409 struct ieee80211_sub_if_data *sdata, 410 struct ieee80211_bss_conf *info, 411 int link_id, u64 changed) 412 { 413 might_sleep(); 414 415 if (WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON | 416 BSS_CHANGED_BEACON_ENABLED) && 417 sdata->vif.type != NL80211_IFTYPE_AP && 418 sdata->vif.type != NL80211_IFTYPE_ADHOC && 419 sdata->vif.type != NL80211_IFTYPE_MESH_POINT && 420 sdata->vif.type != NL80211_IFTYPE_OCB)) 421 return; 422 423 if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || 424 sdata->vif.type == NL80211_IFTYPE_NAN || 425 (sdata->vif.type == NL80211_IFTYPE_MONITOR && 426 !sdata->vif.bss_conf.mu_mimo_owner && 427 !(changed & BSS_CHANGED_TXPOWER)))) 428 return; 429 430 if (!check_sdata_in_driver(sdata)) 431 return; 432 433 if (sdata->vif.active_links && 434 !(sdata->vif.active_links & BIT(link_id))) 435 return; 436 437 trace_drv_link_info_changed(local, sdata, info, changed); 438 if (local->ops->link_info_changed) 439 local->ops->link_info_changed(&local->hw, &sdata->vif, 440 info, changed); 441 else if (local->ops->bss_info_changed) 442 local->ops->bss_info_changed(&local->hw, &sdata->vif, 443 info, changed); 444 trace_drv_return_void(local); 445 } 446 447 int drv_set_key(struct ieee80211_local *local, 448 enum set_key_cmd cmd, 449 struct ieee80211_sub_if_data *sdata, 450 struct ieee80211_sta *sta, 451 struct ieee80211_key_conf *key) 452 { 453 int ret; 454 455 might_sleep(); 456 457 sdata = get_bss_sdata(sdata); 458 if (!check_sdata_in_driver(sdata)) 459 return -EIO; 460 461 if (WARN_ON(key->link_id >= 0 && sdata->vif.active_links && 462 !(sdata->vif.active_links & BIT(key->link_id)))) 463 return -ENOLINK; 464 465 trace_drv_set_key(local, cmd, sdata, sta, key); 466 ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key); 467 trace_drv_return_int(local, ret); 468 return ret; 469 } 470 471 int drv_change_vif_links(struct ieee80211_local *local, 472 struct ieee80211_sub_if_data *sdata, 473 u16 old_links, u16 new_links, 474 struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) 475 { 476 int ret = -EOPNOTSUPP; 477 478 might_sleep(); 479 480 if (!check_sdata_in_driver(sdata)) 481 return -EIO; 482 483 if (old_links == new_links) 484 return 0; 485 486 trace_drv_change_vif_links(local, sdata, old_links, new_links); 487 if (local->ops->change_vif_links) 488 ret = local->ops->change_vif_links(&local->hw, &sdata->vif, 489 old_links, new_links, old); 490 trace_drv_return_int(local, ret); 491 492 return ret; 493 } 494 495 int drv_change_sta_links(struct ieee80211_local *local, 496 struct ieee80211_sub_if_data *sdata, 497 struct ieee80211_sta *sta, 498 u16 old_links, u16 new_links) 499 { 500 int ret = -EOPNOTSUPP; 501 502 might_sleep(); 503 504 if (!check_sdata_in_driver(sdata)) 505 return -EIO; 506 507 old_links &= sdata->vif.active_links; 508 new_links &= sdata->vif.active_links; 509 510 if (old_links == new_links) 511 return 0; 512 513 trace_drv_change_sta_links(local, sdata, sta, old_links, new_links); 514 if (local->ops->change_sta_links) 515 ret = local->ops->change_sta_links(&local->hw, &sdata->vif, sta, 516 old_links, new_links); 517 trace_drv_return_int(local, ret); 518 519 return ret; 520 } 521