1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright 2015 Intel Deutschland GmbH 4 * Copyright (C) 2022-2023 Intel Corporation 5 */ 6 #include <net/mac80211.h> 7 #include "ieee80211_i.h" 8 #include "trace.h" 9 #include "driver-ops.h" 10 #include "debugfs_sta.h" 11 #include "debugfs_netdev.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 if (rcu_access_pointer(sta->sta.rates)) 134 drv_sta_rate_tbl_update(local, sdata, &sta->sta); 135 } 136 } else if (old_state == IEEE80211_STA_ASSOC && 137 new_state == IEEE80211_STA_AUTH) { 138 drv_sta_remove(local, sdata, &sta->sta); 139 } 140 trace_drv_return_int(local, ret); 141 return ret; 142 } 143 144 __must_check 145 int drv_sta_set_txpwr(struct ieee80211_local *local, 146 struct ieee80211_sub_if_data *sdata, 147 struct sta_info *sta) 148 { 149 int ret = -EOPNOTSUPP; 150 151 might_sleep(); 152 153 sdata = get_bss_sdata(sdata); 154 if (!check_sdata_in_driver(sdata)) 155 return -EIO; 156 157 trace_drv_sta_set_txpwr(local, sdata, &sta->sta); 158 if (local->ops->sta_set_txpwr) 159 ret = local->ops->sta_set_txpwr(&local->hw, &sdata->vif, 160 &sta->sta); 161 trace_drv_return_int(local, ret); 162 return ret; 163 } 164 165 void drv_sta_rc_update(struct ieee80211_local *local, 166 struct ieee80211_sub_if_data *sdata, 167 struct ieee80211_sta *sta, u32 changed) 168 { 169 sdata = get_bss_sdata(sdata); 170 if (!check_sdata_in_driver(sdata)) 171 return; 172 173 WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED && 174 (sdata->vif.type != NL80211_IFTYPE_ADHOC && 175 sdata->vif.type != NL80211_IFTYPE_MESH_POINT)); 176 177 trace_drv_sta_rc_update(local, sdata, sta, changed); 178 if (local->ops->sta_rc_update) 179 local->ops->sta_rc_update(&local->hw, &sdata->vif, 180 sta, changed); 181 182 trace_drv_return_void(local); 183 } 184 185 int drv_conf_tx(struct ieee80211_local *local, 186 struct ieee80211_link_data *link, u16 ac, 187 const struct ieee80211_tx_queue_params *params) 188 { 189 struct ieee80211_sub_if_data *sdata = link->sdata; 190 int ret = -EOPNOTSUPP; 191 192 might_sleep(); 193 194 if (!check_sdata_in_driver(sdata)) 195 return -EIO; 196 197 if (sdata->vif.active_links && 198 !(sdata->vif.active_links & BIT(link->link_id))) 199 return 0; 200 201 if (params->cw_min == 0 || params->cw_min > params->cw_max) { 202 /* 203 * If we can't configure hardware anyway, don't warn. We may 204 * never have initialized the CW parameters. 205 */ 206 WARN_ONCE(local->ops->conf_tx, 207 "%s: invalid CW_min/CW_max: %d/%d\n", 208 sdata->name, params->cw_min, params->cw_max); 209 return -EINVAL; 210 } 211 212 trace_drv_conf_tx(local, sdata, link->link_id, ac, params); 213 if (local->ops->conf_tx) 214 ret = local->ops->conf_tx(&local->hw, &sdata->vif, 215 link->link_id, ac, params); 216 trace_drv_return_int(local, ret); 217 return ret; 218 } 219 220 u64 drv_get_tsf(struct ieee80211_local *local, 221 struct ieee80211_sub_if_data *sdata) 222 { 223 u64 ret = -1ULL; 224 225 might_sleep(); 226 227 if (!check_sdata_in_driver(sdata)) 228 return ret; 229 230 trace_drv_get_tsf(local, sdata); 231 if (local->ops->get_tsf) 232 ret = local->ops->get_tsf(&local->hw, &sdata->vif); 233 trace_drv_return_u64(local, ret); 234 return ret; 235 } 236 237 void drv_set_tsf(struct ieee80211_local *local, 238 struct ieee80211_sub_if_data *sdata, 239 u64 tsf) 240 { 241 might_sleep(); 242 243 if (!check_sdata_in_driver(sdata)) 244 return; 245 246 trace_drv_set_tsf(local, sdata, tsf); 247 if (local->ops->set_tsf) 248 local->ops->set_tsf(&local->hw, &sdata->vif, tsf); 249 trace_drv_return_void(local); 250 } 251 252 void drv_offset_tsf(struct ieee80211_local *local, 253 struct ieee80211_sub_if_data *sdata, 254 s64 offset) 255 { 256 might_sleep(); 257 258 if (!check_sdata_in_driver(sdata)) 259 return; 260 261 trace_drv_offset_tsf(local, sdata, offset); 262 if (local->ops->offset_tsf) 263 local->ops->offset_tsf(&local->hw, &sdata->vif, offset); 264 trace_drv_return_void(local); 265 } 266 267 void drv_reset_tsf(struct ieee80211_local *local, 268 struct ieee80211_sub_if_data *sdata) 269 { 270 might_sleep(); 271 272 if (!check_sdata_in_driver(sdata)) 273 return; 274 275 trace_drv_reset_tsf(local, sdata); 276 if (local->ops->reset_tsf) 277 local->ops->reset_tsf(&local->hw, &sdata->vif); 278 trace_drv_return_void(local); 279 } 280 281 int drv_assign_vif_chanctx(struct ieee80211_local *local, 282 struct ieee80211_sub_if_data *sdata, 283 struct ieee80211_bss_conf *link_conf, 284 struct ieee80211_chanctx *ctx) 285 { 286 int ret = 0; 287 288 drv_verify_link_exists(sdata, link_conf); 289 if (!check_sdata_in_driver(sdata)) 290 return -EIO; 291 292 if (sdata->vif.active_links && 293 !(sdata->vif.active_links & BIT(link_conf->link_id))) 294 return 0; 295 296 trace_drv_assign_vif_chanctx(local, sdata, link_conf, ctx); 297 if (local->ops->assign_vif_chanctx) { 298 WARN_ON_ONCE(!ctx->driver_present); 299 ret = local->ops->assign_vif_chanctx(&local->hw, 300 &sdata->vif, 301 link_conf, 302 &ctx->conf); 303 } 304 trace_drv_return_int(local, ret); 305 306 return ret; 307 } 308 309 void drv_unassign_vif_chanctx(struct ieee80211_local *local, 310 struct ieee80211_sub_if_data *sdata, 311 struct ieee80211_bss_conf *link_conf, 312 struct ieee80211_chanctx *ctx) 313 { 314 might_sleep(); 315 316 drv_verify_link_exists(sdata, link_conf); 317 if (!check_sdata_in_driver(sdata)) 318 return; 319 320 if (sdata->vif.active_links && 321 !(sdata->vif.active_links & BIT(link_conf->link_id))) 322 return; 323 324 trace_drv_unassign_vif_chanctx(local, sdata, link_conf, ctx); 325 if (local->ops->unassign_vif_chanctx) { 326 WARN_ON_ONCE(!ctx->driver_present); 327 local->ops->unassign_vif_chanctx(&local->hw, 328 &sdata->vif, 329 link_conf, 330 &ctx->conf); 331 } 332 trace_drv_return_void(local); 333 } 334 335 int drv_switch_vif_chanctx(struct ieee80211_local *local, 336 struct ieee80211_vif_chanctx_switch *vifs, 337 int n_vifs, enum ieee80211_chanctx_switch_mode mode) 338 { 339 int ret = 0; 340 int i; 341 342 might_sleep(); 343 344 if (!local->ops->switch_vif_chanctx) 345 return -EOPNOTSUPP; 346 347 for (i = 0; i < n_vifs; i++) { 348 struct ieee80211_chanctx *new_ctx = 349 container_of(vifs[i].new_ctx, 350 struct ieee80211_chanctx, 351 conf); 352 struct ieee80211_chanctx *old_ctx = 353 container_of(vifs[i].old_ctx, 354 struct ieee80211_chanctx, 355 conf); 356 357 WARN_ON_ONCE(!old_ctx->driver_present); 358 WARN_ON_ONCE((mode == CHANCTX_SWMODE_SWAP_CONTEXTS && 359 new_ctx->driver_present) || 360 (mode == CHANCTX_SWMODE_REASSIGN_VIF && 361 !new_ctx->driver_present)); 362 } 363 364 trace_drv_switch_vif_chanctx(local, vifs, n_vifs, mode); 365 ret = local->ops->switch_vif_chanctx(&local->hw, 366 vifs, n_vifs, mode); 367 trace_drv_return_int(local, ret); 368 369 if (!ret && mode == CHANCTX_SWMODE_SWAP_CONTEXTS) { 370 for (i = 0; i < n_vifs; i++) { 371 struct ieee80211_chanctx *new_ctx = 372 container_of(vifs[i].new_ctx, 373 struct ieee80211_chanctx, 374 conf); 375 struct ieee80211_chanctx *old_ctx = 376 container_of(vifs[i].old_ctx, 377 struct ieee80211_chanctx, 378 conf); 379 380 new_ctx->driver_present = true; 381 old_ctx->driver_present = false; 382 } 383 } 384 385 return ret; 386 } 387 388 int drv_ampdu_action(struct ieee80211_local *local, 389 struct ieee80211_sub_if_data *sdata, 390 struct ieee80211_ampdu_params *params) 391 { 392 int ret = -EOPNOTSUPP; 393 394 might_sleep(); 395 396 sdata = get_bss_sdata(sdata); 397 if (!check_sdata_in_driver(sdata)) 398 return -EIO; 399 400 trace_drv_ampdu_action(local, sdata, params); 401 402 if (local->ops->ampdu_action) 403 ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params); 404 405 trace_drv_return_int(local, ret); 406 407 return ret; 408 } 409 410 void drv_link_info_changed(struct ieee80211_local *local, 411 struct ieee80211_sub_if_data *sdata, 412 struct ieee80211_bss_conf *info, 413 int link_id, u64 changed) 414 { 415 might_sleep(); 416 417 if (WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON | 418 BSS_CHANGED_BEACON_ENABLED) && 419 sdata->vif.type != NL80211_IFTYPE_AP && 420 sdata->vif.type != NL80211_IFTYPE_ADHOC && 421 sdata->vif.type != NL80211_IFTYPE_MESH_POINT && 422 sdata->vif.type != NL80211_IFTYPE_OCB)) 423 return; 424 425 if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || 426 sdata->vif.type == NL80211_IFTYPE_NAN || 427 (sdata->vif.type == NL80211_IFTYPE_MONITOR && 428 !sdata->vif.bss_conf.mu_mimo_owner && 429 !(changed & BSS_CHANGED_TXPOWER)))) 430 return; 431 432 if (!check_sdata_in_driver(sdata)) 433 return; 434 435 if (sdata->vif.active_links && 436 !(sdata->vif.active_links & BIT(link_id))) 437 return; 438 439 trace_drv_link_info_changed(local, sdata, info, changed); 440 if (local->ops->link_info_changed) 441 local->ops->link_info_changed(&local->hw, &sdata->vif, 442 info, changed); 443 else if (local->ops->bss_info_changed) 444 local->ops->bss_info_changed(&local->hw, &sdata->vif, 445 info, changed); 446 trace_drv_return_void(local); 447 } 448 449 int drv_set_key(struct ieee80211_local *local, 450 enum set_key_cmd cmd, 451 struct ieee80211_sub_if_data *sdata, 452 struct ieee80211_sta *sta, 453 struct ieee80211_key_conf *key) 454 { 455 int ret; 456 457 might_sleep(); 458 459 sdata = get_bss_sdata(sdata); 460 if (!check_sdata_in_driver(sdata)) 461 return -EIO; 462 463 if (WARN_ON(key->link_id >= 0 && sdata->vif.active_links && 464 !(sdata->vif.active_links & BIT(key->link_id)))) 465 return -ENOLINK; 466 467 trace_drv_set_key(local, cmd, sdata, sta, key); 468 ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key); 469 trace_drv_return_int(local, ret); 470 return ret; 471 } 472 473 int drv_change_vif_links(struct ieee80211_local *local, 474 struct ieee80211_sub_if_data *sdata, 475 u16 old_links, u16 new_links, 476 struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) 477 { 478 struct ieee80211_link_data *link; 479 unsigned long links_to_add; 480 unsigned long links_to_rem; 481 unsigned int link_id; 482 int ret = -EOPNOTSUPP; 483 484 might_sleep(); 485 486 if (!check_sdata_in_driver(sdata)) 487 return -EIO; 488 489 if (old_links == new_links) 490 return 0; 491 492 links_to_add = ~old_links & new_links; 493 links_to_rem = old_links & ~new_links; 494 495 for_each_set_bit(link_id, &links_to_rem, IEEE80211_MLD_MAX_NUM_LINKS) { 496 link = rcu_access_pointer(sdata->link[link_id]); 497 498 ieee80211_link_debugfs_drv_remove(link); 499 } 500 501 trace_drv_change_vif_links(local, sdata, old_links, new_links); 502 if (local->ops->change_vif_links) 503 ret = local->ops->change_vif_links(&local->hw, &sdata->vif, 504 old_links, new_links, old); 505 trace_drv_return_int(local, ret); 506 507 if (ret) 508 return ret; 509 510 if (!local->in_reconfig) { 511 for_each_set_bit(link_id, &links_to_add, 512 IEEE80211_MLD_MAX_NUM_LINKS) { 513 link = rcu_access_pointer(sdata->link[link_id]); 514 515 ieee80211_link_debugfs_drv_add(link); 516 } 517 } 518 519 return 0; 520 } 521 522 int drv_change_sta_links(struct ieee80211_local *local, 523 struct ieee80211_sub_if_data *sdata, 524 struct ieee80211_sta *sta, 525 u16 old_links, u16 new_links) 526 { 527 struct sta_info *info = container_of(sta, struct sta_info, sta); 528 struct link_sta_info *link_sta; 529 unsigned long links_to_add; 530 unsigned long links_to_rem; 531 unsigned int link_id; 532 int ret = -EOPNOTSUPP; 533 534 might_sleep(); 535 536 if (!check_sdata_in_driver(sdata)) 537 return -EIO; 538 539 old_links &= sdata->vif.active_links; 540 new_links &= sdata->vif.active_links; 541 542 if (old_links == new_links) 543 return 0; 544 545 links_to_add = ~old_links & new_links; 546 links_to_rem = old_links & ~new_links; 547 548 for_each_set_bit(link_id, &links_to_rem, IEEE80211_MLD_MAX_NUM_LINKS) { 549 link_sta = rcu_dereference_protected(info->link[link_id], 550 lockdep_is_held(&local->sta_mtx)); 551 552 ieee80211_link_sta_debugfs_drv_remove(link_sta); 553 } 554 555 trace_drv_change_sta_links(local, sdata, sta, old_links, new_links); 556 if (local->ops->change_sta_links) 557 ret = local->ops->change_sta_links(&local->hw, &sdata->vif, sta, 558 old_links, new_links); 559 trace_drv_return_int(local, ret); 560 561 if (ret) 562 return ret; 563 564 /* during reconfig don't add it to debugfs again */ 565 if (local->in_reconfig) 566 return 0; 567 568 for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) { 569 link_sta = rcu_dereference_protected(info->link[link_id], 570 lockdep_is_held(&local->sta_mtx)); 571 ieee80211_link_sta_debugfs_drv_add(link_sta); 572 } 573 574 return 0; 575 } 576