1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * NAN mode implementation 4 * Copyright(c) 2025-2026 Intel Corporation 5 */ 6 #include <net/mac80211.h> 7 8 #include "ieee80211_i.h" 9 #include "driver-ops.h" 10 #include "sta_info.h" 11 12 static void 13 ieee80211_nan_init_channel(struct ieee80211_nan_channel *nan_channel, 14 struct cfg80211_nan_channel *cfg_nan_channel) 15 { 16 memset(nan_channel, 0, sizeof(*nan_channel)); 17 18 nan_channel->chanreq.oper = cfg_nan_channel->chandef; 19 memcpy(nan_channel->channel_entry, cfg_nan_channel->channel_entry, 20 sizeof(nan_channel->channel_entry)); 21 nan_channel->needed_rx_chains = cfg_nan_channel->rx_nss; 22 } 23 24 static void 25 ieee80211_nan_update_channel(struct ieee80211_local *local, 26 struct ieee80211_nan_channel *nan_channel, 27 struct cfg80211_nan_channel *cfg_nan_channel, 28 bool deferred) 29 { 30 struct ieee80211_chanctx_conf *conf; 31 bool reducing_nss; 32 33 if (WARN_ON(!cfg80211_chandef_identical(&nan_channel->chanreq.oper, 34 &cfg_nan_channel->chandef))) 35 return; 36 37 if (WARN_ON(memcmp(nan_channel->channel_entry, 38 cfg_nan_channel->channel_entry, 39 sizeof(nan_channel->channel_entry)))) 40 return; 41 42 if (nan_channel->needed_rx_chains == cfg_nan_channel->rx_nss) 43 return; 44 45 reducing_nss = nan_channel->needed_rx_chains > cfg_nan_channel->rx_nss; 46 nan_channel->needed_rx_chains = cfg_nan_channel->rx_nss; 47 48 conf = nan_channel->chanctx_conf; 49 50 /* 51 * If we are adding NSSs, we need to be ready before notifying the peer, 52 * if we are reducing NSSs, we need to wait until the peer is notified. 53 */ 54 if (!conf || (deferred && reducing_nss)) 55 return; 56 57 ieee80211_recalc_smps_chanctx(local, container_of(conf, 58 struct ieee80211_chanctx, 59 conf)); 60 } 61 62 static int 63 ieee80211_nan_use_chanctx(struct ieee80211_sub_if_data *sdata, 64 struct ieee80211_nan_channel *nan_channel, 65 bool assign_on_failure) 66 { 67 struct ieee80211_chanctx *ctx; 68 bool reused_ctx; 69 70 if (!nan_channel->chanreq.oper.chan) 71 return -EINVAL; 72 73 if (ieee80211_check_combinations(sdata, &nan_channel->chanreq.oper, 74 IEEE80211_CHANCTX_SHARED, 0, -1)) 75 return -EBUSY; 76 77 ctx = ieee80211_find_or_create_chanctx(sdata, &nan_channel->chanreq, 78 IEEE80211_CHANCTX_SHARED, 79 assign_on_failure, 80 &reused_ctx); 81 if (IS_ERR(ctx)) 82 return PTR_ERR(ctx); 83 84 nan_channel->chanctx_conf = &ctx->conf; 85 86 /* 87 * In case an existing channel context is being used, we marked it as 88 * will_be_used, now that it is assigned - clear this indication 89 */ 90 if (reused_ctx) { 91 WARN_ON(!ctx->will_be_used); 92 ctx->will_be_used = false; 93 } 94 ieee80211_recalc_chanctx_min_def(sdata->local, ctx); 95 ieee80211_recalc_smps_chanctx(sdata->local, ctx); 96 97 return 0; 98 } 99 100 static void 101 ieee80211_nan_update_peer_channels(struct ieee80211_sub_if_data *sdata, 102 struct ieee80211_chanctx_conf *removed_conf) 103 { 104 struct ieee80211_local *local = sdata->local; 105 struct sta_info *sta; 106 107 lockdep_assert_wiphy(local->hw.wiphy); 108 109 list_for_each_entry(sta, &local->sta_list, list) { 110 struct ieee80211_nan_peer_sched *peer_sched; 111 int write_idx = 0; 112 bool updated = false; 113 114 if (sta->sdata != sdata) 115 continue; 116 117 peer_sched = sta->sta.nan_sched; 118 if (!peer_sched) 119 continue; 120 121 /* NULL out map slots for channels being removed */ 122 for (int i = 0; i < peer_sched->n_channels; i++) { 123 if (peer_sched->channels[i].chanctx_conf != removed_conf) 124 continue; 125 126 for (int m = 0; m < CFG80211_NAN_MAX_PEER_MAPS; m++) { 127 struct ieee80211_nan_peer_map *map = 128 &peer_sched->maps[m]; 129 130 if (map->map_id == CFG80211_NAN_INVALID_MAP_ID) 131 continue; 132 133 for (int s = 0; s < ARRAY_SIZE(map->slots); s++) 134 if (map->slots[s] == &peer_sched->channels[i]) 135 map->slots[s] = NULL; 136 } 137 } 138 139 /* Compact channels array, removing those with removed_conf */ 140 for (int i = 0; i < peer_sched->n_channels; i++) { 141 if (peer_sched->channels[i].chanctx_conf == removed_conf) { 142 updated = true; 143 continue; 144 } 145 146 if (write_idx != i) { 147 /* Update map pointers before moving */ 148 for (int m = 0; m < CFG80211_NAN_MAX_PEER_MAPS; m++) { 149 struct ieee80211_nan_peer_map *map = 150 &peer_sched->maps[m]; 151 152 if (map->map_id == CFG80211_NAN_INVALID_MAP_ID) 153 continue; 154 155 for (int s = 0; s < ARRAY_SIZE(map->slots); s++) 156 if (map->slots[s] == &peer_sched->channels[i]) 157 map->slots[s] = &peer_sched->channels[write_idx]; 158 } 159 160 peer_sched->channels[write_idx] = peer_sched->channels[i]; 161 } 162 write_idx++; 163 } 164 165 /* Clear any remaining entries at the end */ 166 for (int i = write_idx; i < peer_sched->n_channels; i++) 167 memset(&peer_sched->channels[i], 0, sizeof(peer_sched->channels[i])); 168 169 peer_sched->n_channels = write_idx; 170 171 if (updated) 172 drv_nan_peer_sched_changed(local, sdata, sta); 173 } 174 } 175 176 static void 177 ieee80211_nan_remove_channel(struct ieee80211_sub_if_data *sdata, 178 struct ieee80211_nan_channel *nan_channel) 179 { 180 struct ieee80211_chanctx_conf *conf; 181 struct ieee80211_chanctx *ctx; 182 struct ieee80211_nan_sched_cfg *sched_cfg = &sdata->vif.cfg.nan_sched; 183 184 if (WARN_ON(!nan_channel)) 185 return; 186 187 lockdep_assert_wiphy(sdata->local->hw.wiphy); 188 189 if (!nan_channel->chanreq.oper.chan) 190 return; 191 192 for (int slot = 0; slot < ARRAY_SIZE(sched_cfg->schedule); slot++) 193 if (sched_cfg->schedule[slot] == nan_channel) 194 sched_cfg->schedule[slot] = NULL; 195 196 conf = nan_channel->chanctx_conf; 197 198 /* If any peer nan schedule uses this chanctx, update them */ 199 if (conf) 200 ieee80211_nan_update_peer_channels(sdata, conf); 201 202 memset(nan_channel, 0, sizeof(*nan_channel)); 203 204 /* Update the driver before (possibly) releasing the channel context */ 205 drv_vif_cfg_changed(sdata->local, sdata, BSS_CHANGED_NAN_LOCAL_SCHED); 206 207 /* Channel might not have a chanctx if it was ULWed */ 208 if (!conf) 209 return; 210 211 ctx = container_of(conf, struct ieee80211_chanctx, conf); 212 213 if (ieee80211_chanctx_num_assigned(sdata->local, ctx) > 0) { 214 ieee80211_recalc_chanctx_chantype(sdata->local, ctx); 215 ieee80211_recalc_smps_chanctx(sdata->local, ctx); 216 ieee80211_recalc_chanctx_min_def(sdata->local, ctx); 217 } 218 219 if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) 220 ieee80211_free_chanctx(sdata->local, ctx, false); 221 } 222 223 static void 224 ieee80211_nan_update_all_ndi_carriers(struct ieee80211_local *local) 225 { 226 struct ieee80211_sub_if_data *sdata; 227 228 lockdep_assert_wiphy(local->hw.wiphy); 229 230 /* Iterate all interfaces and update carrier for NDI interfaces */ 231 list_for_each_entry(sdata, &local->interfaces, list) { 232 if (!ieee80211_sdata_running(sdata) || 233 sdata->vif.type != NL80211_IFTYPE_NAN_DATA) 234 continue; 235 236 ieee80211_nan_update_ndi_carrier(sdata); 237 } 238 } 239 240 static struct ieee80211_nan_channel * 241 ieee80211_nan_find_free_channel(struct ieee80211_nan_sched_cfg *sched_cfg) 242 { 243 for (int i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) { 244 if (!sched_cfg->channels[i].chanreq.oper.chan) 245 return &sched_cfg->channels[i]; 246 } 247 248 return NULL; 249 } 250 251 int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata, 252 struct cfg80211_nan_local_sched *sched) 253 { 254 struct ieee80211_nan_channel *sched_idx_to_chan[IEEE80211_NAN_MAX_CHANNELS] = {}; 255 struct ieee80211_nan_sched_cfg *sched_cfg = &sdata->vif.cfg.nan_sched; 256 struct ieee80211_nan_sched_cfg backup_sched; 257 int ret; 258 259 if (sched->n_channels > IEEE80211_NAN_MAX_CHANNELS) 260 return -EOPNOTSUPP; 261 262 if (sched->nan_avail_blob_len > IEEE80211_NAN_AVAIL_BLOB_MAX_LEN) 263 return -EINVAL; 264 265 /* 266 * If a deferred schedule update is pending completion, new updates are 267 * not allowed. Only allow to configure an empty schedule so NAN can be 268 * stopped in the middle of a deferred update. This is fine because 269 * empty schedule means the local NAN device will not be available for 270 * peers anymore so there is no need to update peers about a new 271 * schedule. 272 */ 273 if (WARN_ON(sched_cfg->deferred && sched->n_channels)) 274 return -EBUSY; 275 276 bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS); 277 278 memcpy(backup_sched.schedule, sched_cfg->schedule, 279 sizeof(backup_sched.schedule)); 280 memcpy(backup_sched.channels, sched_cfg->channels, 281 sizeof(backup_sched.channels)); 282 memcpy(backup_sched.avail_blob, sched_cfg->avail_blob, 283 sizeof(backup_sched.avail_blob)); 284 backup_sched.avail_blob_len = sched_cfg->avail_blob_len; 285 286 memcpy(sched_cfg->avail_blob, sched->nan_avail_blob, 287 sched->nan_avail_blob_len); 288 sched_cfg->avail_blob_len = sched->nan_avail_blob_len; 289 290 /* 291 * Remove channels that are no longer in the new schedule to free up 292 * resources before adding new channels. For deferred schedule, channels 293 * will be removed when the schedule is applied. 294 * Create a mapping from sched index to sched_cfg channel 295 */ 296 for (int i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) { 297 bool still_needed = false; 298 299 if (!sched_cfg->channels[i].chanreq.oper.chan) 300 continue; 301 302 for (int j = 0; j < sched->n_channels; j++) { 303 if (cfg80211_chandef_identical(&sched_cfg->channels[i].chanreq.oper, 304 &sched->nan_channels[j].chandef)) { 305 sched_idx_to_chan[j] = 306 &sched_cfg->channels[i]; 307 still_needed = true; 308 break; 309 } 310 } 311 312 if (!still_needed) { 313 __set_bit(i, sdata->u.nan.removed_channels); 314 if (!sched->deferred) 315 ieee80211_nan_remove_channel(sdata, 316 &sched_cfg->channels[i]); 317 } 318 } 319 320 for (int i = 0; i < sched->n_channels; i++) { 321 struct ieee80211_nan_channel *chan = sched_idx_to_chan[i]; 322 323 if (chan) { 324 ieee80211_nan_update_channel(sdata->local, chan, 325 &sched->nan_channels[i], 326 sched->deferred); 327 } else { 328 chan = ieee80211_nan_find_free_channel(sched_cfg); 329 if (WARN_ON(!chan)) { 330 ret = -EINVAL; 331 goto err; 332 } 333 334 sched_idx_to_chan[i] = chan; 335 ieee80211_nan_init_channel(chan, 336 &sched->nan_channels[i]); 337 } 338 339 /* Also a pre-existing channel might have been ULWed, so no chanctx */ 340 if (!chan->chanctx_conf) { 341 ret = ieee80211_nan_use_chanctx(sdata, chan, false); 342 if (ret) { 343 memset(chan, 0, sizeof(*chan)); 344 goto err; 345 } 346 } 347 } 348 349 for (int s = 0; s < ARRAY_SIZE(sched_cfg->schedule); s++) { 350 if (sched->schedule[s] < ARRAY_SIZE(sched_idx_to_chan)) 351 sched_cfg->schedule[s] = 352 sched_idx_to_chan[sched->schedule[s]]; 353 else 354 sched_cfg->schedule[s] = NULL; 355 } 356 357 sched_cfg->deferred = sched->deferred; 358 359 drv_vif_cfg_changed(sdata->local, sdata, BSS_CHANGED_NAN_LOCAL_SCHED); 360 361 /* 362 * For deferred update, don't update NDI carriers yet as the new 363 * schedule is not yet applied so common slots don't change. The NDI 364 * carrier will be updated once the driver notifies the new schedule is 365 * applied. 366 */ 367 if (sched_cfg->deferred) 368 return 0; 369 370 ieee80211_nan_update_all_ndi_carriers(sdata->local); 371 bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS); 372 373 return 0; 374 err: 375 /* Remove newly added channels */ 376 for (int i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) { 377 struct cfg80211_chan_def *chan_def = 378 &sched_cfg->channels[i].chanreq.oper; 379 380 if (!chan_def->chan) 381 continue; 382 383 if (!cfg80211_chandef_identical(&backup_sched.channels[i].chanreq.oper, 384 chan_def)) 385 ieee80211_nan_remove_channel(sdata, 386 &sched_cfg->channels[i]); 387 } 388 389 /* Re-add all backed up channels */ 390 for (int i = 0; i < ARRAY_SIZE(backup_sched.channels); i++) { 391 struct ieee80211_nan_channel *chan = &sched_cfg->channels[i]; 392 393 *chan = backup_sched.channels[i]; 394 395 /* 396 * For deferred update, no channels were removed and the channel 397 * context didn't change, so nothing else to do. 398 */ 399 if (!chan->chanctx_conf || sched->deferred) 400 continue; 401 402 if (test_bit(i, sdata->u.nan.removed_channels)) { 403 /* Clear the stale chanctx pointer */ 404 chan->chanctx_conf = NULL; 405 /* 406 * We removed the newly added channels so we don't lack 407 * resources. So the only reason that this would fail 408 * is a FW error which we ignore. Therefore, this 409 * should never fail. 410 */ 411 WARN_ON(ieee80211_nan_use_chanctx(sdata, chan, true)); 412 } else { 413 struct ieee80211_chanctx_conf *conf = chan->chanctx_conf; 414 415 /* FIXME: detect no-op? */ 416 /* Channel was not removed but may have been updated */ 417 ieee80211_recalc_smps_chanctx(sdata->local, 418 container_of(conf, 419 struct ieee80211_chanctx, 420 conf)); 421 } 422 } 423 424 memcpy(sched_cfg->schedule, backup_sched.schedule, 425 sizeof(backup_sched.schedule)); 426 memcpy(sched_cfg->avail_blob, backup_sched.avail_blob, 427 sizeof(backup_sched.avail_blob)); 428 sched_cfg->avail_blob_len = backup_sched.avail_blob_len; 429 sched_cfg->deferred = false; 430 bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS); 431 432 drv_vif_cfg_changed(sdata->local, sdata, BSS_CHANGED_NAN_LOCAL_SCHED); 433 ieee80211_nan_update_all_ndi_carriers(sdata->local); 434 return ret; 435 } 436 437 void ieee80211_nan_sched_update_done(struct ieee80211_vif *vif) 438 { 439 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 440 struct ieee80211_nan_sched_cfg *sched_cfg = &vif->cfg.nan_sched; 441 unsigned int i; 442 443 lockdep_assert_wiphy(sdata->local->hw.wiphy); 444 445 if (WARN_ON(!sched_cfg->deferred)) 446 return; 447 448 ieee80211_nan_update_all_ndi_carriers(sdata->local); 449 450 /* 451 * Clear the deferred flag before removing channels. Removing channels 452 * will trigger another schedule update to the driver, and there is no 453 * need for this update to be deferred since removed channels are not 454 * part of the schedule anymore, so no need to notify peers about 455 * removing them. 456 */ 457 sched_cfg->deferred = false; 458 459 for (i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) { 460 struct ieee80211_nan_channel *chan = &sched_cfg->channels[i]; 461 struct ieee80211_chanctx_conf *conf = chan->chanctx_conf; 462 463 if (!chan->chanreq.oper.chan) 464 continue; 465 466 if (test_bit(i, sdata->u.nan.removed_channels)) 467 ieee80211_nan_remove_channel(sdata, chan); 468 else if (conf) 469 /* 470 * We might have called this already for some channels, 471 * but this knows to handle a no-op. 472 */ 473 ieee80211_recalc_smps_chanctx(sdata->local, 474 container_of(conf, 475 struct ieee80211_chanctx, 476 conf)); 477 } 478 479 bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS); 480 cfg80211_nan_sched_update_done(ieee80211_vif_to_wdev(vif), true, 481 GFP_KERNEL); 482 } 483 EXPORT_SYMBOL(ieee80211_nan_sched_update_done); 484 485 void ieee80211_nan_free_peer_sched(struct ieee80211_nan_peer_sched *sched) 486 { 487 if (!sched) 488 return; 489 490 kfree(sched->init_ulw); 491 kfree(sched); 492 } 493 494 static int 495 ieee80211_nan_init_peer_channel(struct ieee80211_sub_if_data *sdata, 496 const struct sta_info *sta, 497 const struct cfg80211_nan_channel *cfg_chan, 498 struct ieee80211_nan_channel *new_chan) 499 { 500 struct ieee80211_nan_sched_cfg *sched_cfg = &sdata->vif.cfg.nan_sched; 501 502 /* Find compatible local channel */ 503 for (int j = 0; j < ARRAY_SIZE(sched_cfg->channels); j++) { 504 struct ieee80211_nan_channel *local_chan = 505 &sched_cfg->channels[j]; 506 const struct cfg80211_chan_def *compat; 507 508 if (!local_chan->chanreq.oper.chan) 509 continue; 510 511 compat = cfg80211_chandef_compatible(&local_chan->chanreq.oper, 512 &cfg_chan->chandef); 513 if (!compat) 514 continue; 515 516 /* compat is the wider chandef, and we want the narrower one */ 517 new_chan->chanreq.oper = compat == &local_chan->chanreq.oper ? 518 cfg_chan->chandef : local_chan->chanreq.oper; 519 new_chan->needed_rx_chains = min(local_chan->needed_rx_chains, 520 cfg_chan->rx_nss); 521 new_chan->chanctx_conf = local_chan->chanctx_conf; 522 523 break; 524 } 525 526 /* 527 * nl80211 already validated that each peer channel is compatible 528 * with at least one local channel, so this should never happen. 529 */ 530 if (WARN_ON(!new_chan->chanreq.oper.chan)) 531 return -EINVAL; 532 533 memcpy(new_chan->channel_entry, cfg_chan->channel_entry, 534 sizeof(new_chan->channel_entry)); 535 536 return 0; 537 } 538 539 static void 540 ieee80211_nan_init_peer_map(struct ieee80211_nan_peer_sched *peer_sched, 541 const struct cfg80211_nan_peer_map *cfg_map, 542 struct ieee80211_nan_peer_map *new_map) 543 { 544 new_map->map_id = cfg_map->map_id; 545 546 if (new_map->map_id == CFG80211_NAN_INVALID_MAP_ID) 547 return; 548 549 /* Set up the slots array */ 550 for (int slot = 0; slot < ARRAY_SIZE(new_map->slots); slot++) { 551 u8 chan_idx = cfg_map->schedule[slot]; 552 553 if (chan_idx < peer_sched->n_channels) 554 new_map->slots[slot] = &peer_sched->channels[chan_idx]; 555 } 556 } 557 558 /* 559 * Check if the local schedule and a peer schedule have at least one common 560 * slot - a slot where both schedules are active on compatible channels. 561 */ 562 static bool 563 ieee80211_nan_has_common_slots(struct ieee80211_sub_if_data *sdata, 564 struct ieee80211_nan_peer_sched *peer_sched) 565 { 566 for (int slot = 0; slot < CFG80211_NAN_SCHED_NUM_TIME_SLOTS; slot++) { 567 struct ieee80211_nan_channel *local_chan = 568 sdata->vif.cfg.nan_sched.schedule[slot]; 569 570 if (!local_chan || !local_chan->chanctx_conf) 571 continue; 572 573 /* Check all peer maps for this slot */ 574 for (int m = 0; m < CFG80211_NAN_MAX_PEER_MAPS; m++) { 575 struct ieee80211_nan_peer_map *map = &peer_sched->maps[m]; 576 struct ieee80211_nan_channel *peer_chan; 577 578 if (map->map_id == CFG80211_NAN_INVALID_MAP_ID) 579 continue; 580 581 peer_chan = map->slots[slot]; 582 if (!peer_chan) 583 continue; 584 585 if (local_chan->chanctx_conf == peer_chan->chanctx_conf) 586 return true; 587 } 588 } 589 590 return false; 591 } 592 593 void ieee80211_nan_update_ndi_carrier(struct ieee80211_sub_if_data *ndi_sdata) 594 { 595 struct ieee80211_local *local = ndi_sdata->local; 596 struct ieee80211_sub_if_data *nmi_sdata; 597 struct sta_info *sta; 598 599 lockdep_assert_wiphy(local->hw.wiphy); 600 601 if (WARN_ON(ndi_sdata->vif.type != NL80211_IFTYPE_NAN_DATA || 602 !ndi_sdata->dev) || !ieee80211_sdata_running(ndi_sdata)) 603 return; 604 605 nmi_sdata = wiphy_dereference(local->hw.wiphy, ndi_sdata->u.nan_data.nmi); 606 if (WARN_ON(!nmi_sdata)) 607 return; 608 609 list_for_each_entry(sta, &local->sta_list, list) { 610 struct ieee80211_sta *nmi_sta; 611 612 if (sta->sdata != ndi_sdata || 613 !test_sta_flag(sta, WLAN_STA_AUTHORIZED)) 614 continue; 615 616 nmi_sta = wiphy_dereference(local->hw.wiphy, sta->sta.nmi); 617 if (WARN_ON(!nmi_sta) || !nmi_sta->nan_sched) 618 continue; 619 620 if (ieee80211_nan_has_common_slots(nmi_sdata, nmi_sta->nan_sched)) { 621 netif_carrier_on(ndi_sdata->dev); 622 return; 623 } 624 } 625 626 netif_carrier_off(ndi_sdata->dev); 627 } 628 629 static void 630 ieee80211_nan_update_peer_ndis_carrier(struct ieee80211_local *local, 631 struct sta_info *nmi_sta) 632 { 633 struct sta_info *sta; 634 635 lockdep_assert_wiphy(local->hw.wiphy); 636 637 list_for_each_entry(sta, &local->sta_list, list) { 638 if (rcu_access_pointer(sta->sta.nmi) == &nmi_sta->sta) 639 ieee80211_nan_update_ndi_carrier(sta->sdata); 640 } 641 } 642 643 int ieee80211_nan_set_peer_sched(struct ieee80211_sub_if_data *sdata, 644 struct cfg80211_nan_peer_sched *sched) 645 { 646 struct ieee80211_nan_peer_sched *new_sched, *old_sched, *to_free; 647 struct sta_info *sta; 648 int ret; 649 650 lockdep_assert_wiphy(sdata->local->hw.wiphy); 651 652 if (!sdata->u.nan.started) 653 return -EINVAL; 654 655 sta = sta_info_get(sdata, sched->peer_addr); 656 if (!sta) 657 return -ENOENT; 658 659 new_sched = kzalloc(struct_size(new_sched, channels, sched->n_channels), 660 GFP_KERNEL); 661 if (!new_sched) 662 return -ENOMEM; 663 664 to_free = new_sched; 665 666 new_sched->seq_id = sched->seq_id; 667 new_sched->committed_dw = sched->committed_dw; 668 new_sched->max_chan_switch = sched->max_chan_switch; 669 new_sched->n_channels = sched->n_channels; 670 671 if (sched->ulw_size && sched->init_ulw) { 672 new_sched->init_ulw = kmemdup(sched->init_ulw, sched->ulw_size, 673 GFP_KERNEL); 674 if (!new_sched->init_ulw) { 675 ret = -ENOMEM; 676 goto out; 677 } 678 new_sched->ulw_size = sched->ulw_size; 679 } 680 681 for (int i = 0; i < sched->n_channels; i++) { 682 ret = ieee80211_nan_init_peer_channel(sdata, sta, 683 &sched->nan_channels[i], 684 &new_sched->channels[i]); 685 if (ret) 686 goto out; 687 } 688 689 for (int m = 0; m < ARRAY_SIZE(sched->maps); m++) 690 ieee80211_nan_init_peer_map(new_sched, &sched->maps[m], 691 &new_sched->maps[m]); 692 693 /* Install the new schedule before calling the driver */ 694 old_sched = sta->sta.nan_sched; 695 sta->sta.nan_sched = new_sched; 696 697 ret = drv_nan_peer_sched_changed(sdata->local, sdata, sta); 698 if (ret) { 699 /* Revert to old schedule */ 700 sta->sta.nan_sched = old_sched; 701 goto out; 702 } 703 704 ieee80211_nan_update_peer_ndis_carrier(sdata->local, sta); 705 706 /* Success - free old schedule */ 707 to_free = old_sched; 708 ret = 0; 709 710 out: 711 ieee80211_nan_free_peer_sched(to_free); 712 return ret; 713 } 714 715 static void 716 ieee80211_nan_evacuate_channel(struct ieee80211_sub_if_data *sdata, 717 struct ieee80211_nan_channel *nan_channel) 718 { 719 struct ieee80211_chanctx_conf *conf; 720 struct ieee80211_chanctx *ctx; 721 722 lockdep_assert_wiphy(sdata->local->hw.wiphy); 723 724 if (WARN_ON(!nan_channel || !nan_channel->chanreq.oper.chan)) 725 return; 726 727 conf = nan_channel->chanctx_conf; 728 if (WARN_ON(!conf)) 729 return; 730 731 nan_channel->chanctx_conf = NULL; 732 733 /* Update all peer channels that reference this chanctx */ 734 ieee80211_nan_update_peer_channels(sdata, conf); 735 736 drv_vif_cfg_changed(sdata->local, sdata, BSS_CHANGED_NAN_LOCAL_SCHED); 737 738 cfg80211_nan_channel_evac(&sdata->wdev, &nan_channel->chanreq.oper, 739 GFP_KERNEL); 740 741 /* Update NDI carrier states */ 742 ieee80211_nan_update_all_ndi_carriers(sdata->local); 743 744 /* Clean up the channel context if no longer used */ 745 ctx = container_of(conf, struct ieee80211_chanctx, conf); 746 747 if (ieee80211_chanctx_num_assigned(sdata->local, ctx) > 0) { 748 ieee80211_recalc_chanctx_chantype(sdata->local, ctx); 749 ieee80211_recalc_smps_chanctx(sdata->local, ctx); 750 ieee80211_recalc_chanctx_min_def(sdata->local, ctx); 751 } 752 753 if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) 754 ieee80211_free_chanctx(sdata->local, ctx, false); 755 } 756 757 bool ieee80211_nan_try_evacuate(struct ieee80211_hw *hw, 758 struct ieee80211_chanctx_conf *conf) 759 { 760 struct ieee80211_sub_if_data *sdata = NULL, *tmp; 761 struct ieee80211_local *local = hw_to_local(hw); 762 struct ieee80211_nan_channel *evac_chan = NULL; 763 struct ieee80211_nan_sched_cfg *sched_cfg; 764 struct ieee80211_chanctx *ctx = NULL; 765 int min_slot_count = INT_MAX; 766 int usable_channels = 0; 767 768 lockdep_assert_wiphy(local->hw.wiphy); 769 770 if (conf) 771 ctx = container_of(conf, struct ieee80211_chanctx, conf); 772 773 /* Find the NAN interface - there can only be one */ 774 list_for_each_entry(tmp, &local->interfaces, list) { 775 if (ieee80211_sdata_running(tmp) && 776 tmp->vif.type == NL80211_IFTYPE_NAN) { 777 sdata = tmp; 778 break; 779 } 780 } 781 782 if (!sdata) 783 return false; 784 785 sched_cfg = &sdata->vif.cfg.nan_sched; 786 787 /* Find the channel to evacuate and count usable channels */ 788 for (int i = 0; i < IEEE80211_NAN_MAX_CHANNELS; i++) { 789 struct ieee80211_nan_channel *chan = 790 &sched_cfg->channels[i]; 791 struct ieee80211_chanctx *chan_ctx; 792 int slot_count = 0; 793 794 if (!chan->chanreq.oper.chan || !chan->chanctx_conf) 795 continue; 796 797 usable_channels++; 798 799 chan_ctx = container_of(chan->chanctx_conf, 800 struct ieee80211_chanctx, conf); 801 802 /* If ctx specified, only consider that specific chanctx */ 803 if (ctx) { 804 if (chan_ctx == ctx) 805 evac_chan = chan; 806 continue; 807 } 808 809 /* Can only evacuate channels whose chanctx is NAN-only */ 810 if (ieee80211_chanctx_refcount(local, chan_ctx) > 1) 811 continue; 812 813 /* Count how many time slots use this channel */ 814 for (int s = 0; s < CFG80211_NAN_SCHED_NUM_TIME_SLOTS; s++) 815 if (sched_cfg->schedule[s] == chan) 816 slot_count++; 817 818 if (slot_count < min_slot_count) { 819 min_slot_count = slot_count; 820 evac_chan = chan; 821 } 822 } 823 824 /* No suitable NAN channel found */ 825 if (!evac_chan) 826 return false; 827 828 /* NAN needs at least one remaining usable channel after evacuation */ 829 if (usable_channels < 2) 830 return false; 831 832 ieee80211_nan_evacuate_channel(sdata, evac_chan); 833 834 return true; 835 } 836 EXPORT_SYMBOL(ieee80211_nan_try_evacuate); 837