aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/chan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/chan.c')
-rw-r--r--net/mac80211/chan.c191
1 files changed, 95 insertions, 96 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 399ad82c997f..4c74e8da64b9 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -549,12 +549,12 @@ static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
549 549
550 compat = cfg80211_chandef_compatible( 550 compat = cfg80211_chandef_compatible(
551 &sdata->vif.bss_conf.chandef, compat); 551 &sdata->vif.bss_conf.chandef, compat);
552 if (!compat) 552 if (WARN_ON_ONCE(!compat))
553 break; 553 break;
554 } 554 }
555 rcu_read_unlock(); 555 rcu_read_unlock();
556 556
557 if (WARN_ON_ONCE(!compat)) 557 if (!compat)
558 return; 558 return;
559 559
560 ieee80211_change_chanctx(local, ctx, compat); 560 ieee80211_change_chanctx(local, ctx, compat);
@@ -639,41 +639,6 @@ out:
639 return ret; 639 return ret;
640} 640}
641 641
642static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
643{
644 struct ieee80211_local *local = sdata->local;
645 struct ieee80211_chanctx_conf *conf;
646 struct ieee80211_chanctx *ctx;
647 bool use_reserved_switch = false;
648
649 lockdep_assert_held(&local->chanctx_mtx);
650
651 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
652 lockdep_is_held(&local->chanctx_mtx));
653 if (!conf)
654 return;
655
656 ctx = container_of(conf, struct ieee80211_chanctx, conf);
657
658 if (sdata->reserved_chanctx) {
659 if (sdata->reserved_chanctx->replace_state ==
660 IEEE80211_CHANCTX_REPLACES_OTHER &&
661 ieee80211_chanctx_num_reserved(local,
662 sdata->reserved_chanctx) > 1)
663 use_reserved_switch = true;
664
665 ieee80211_vif_unreserve_chanctx(sdata);
666 }
667
668 ieee80211_assign_vif_chanctx(sdata, NULL);
669 if (ieee80211_chanctx_refcount(local, ctx) == 0)
670 ieee80211_free_chanctx(local, ctx);
671
672 /* Unreserving may ready an in-place reservation. */
673 if (use_reserved_switch)
674 ieee80211_vif_use_reserved_switch(local);
675}
676
677void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, 642void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
678 struct ieee80211_chanctx *chanctx) 643 struct ieee80211_chanctx *chanctx)
679{ 644{
@@ -764,63 +729,6 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
764 drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS); 729 drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
765} 730}
766 731
767int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
768 const struct cfg80211_chan_def *chandef,
769 enum ieee80211_chanctx_mode mode)
770{
771 struct ieee80211_local *local = sdata->local;
772 struct ieee80211_chanctx *ctx;
773 u8 radar_detect_width = 0;
774 int ret;
775
776 lockdep_assert_held(&local->mtx);
777
778 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
779
780 mutex_lock(&local->chanctx_mtx);
781
782 ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
783 chandef,
784 sdata->wdev.iftype);
785 if (ret < 0)
786 goto out;
787 if (ret > 0)
788 radar_detect_width = BIT(chandef->width);
789
790 sdata->radar_required = ret;
791
792 ret = ieee80211_check_combinations(sdata, chandef, mode,
793 radar_detect_width);
794 if (ret < 0)
795 goto out;
796
797 __ieee80211_vif_release_channel(sdata);
798
799 ctx = ieee80211_find_chanctx(local, chandef, mode);
800 if (!ctx)
801 ctx = ieee80211_new_chanctx(local, chandef, mode);
802 if (IS_ERR(ctx)) {
803 ret = PTR_ERR(ctx);
804 goto out;
805 }
806
807 sdata->vif.bss_conf.chandef = *chandef;
808
809 ret = ieee80211_assign_vif_chanctx(sdata, ctx);
810 if (ret) {
811 /* if assign fails refcount stays the same */
812 if (ieee80211_chanctx_refcount(local, ctx) == 0)
813 ieee80211_free_chanctx(local, ctx);
814 goto out;
815 }
816
817 ieee80211_recalc_smps_chanctx(local, ctx);
818 ieee80211_recalc_radar_chanctx(local, ctx);
819 out:
820 mutex_unlock(&local->chanctx_mtx);
821 return ret;
822}
823
824static void 732static void
825__ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, 733__ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
826 bool clear) 734 bool clear)
@@ -1269,8 +1177,7 @@ err:
1269 return err; 1177 return err;
1270} 1178}
1271 1179
1272int 1180static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
1273ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
1274{ 1181{
1275 struct ieee80211_sub_if_data *sdata, *sdata_tmp; 1182 struct ieee80211_sub_if_data *sdata, *sdata_tmp;
1276 struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx; 1183 struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx;
@@ -1522,6 +1429,98 @@ err:
1522 return err; 1429 return err;
1523} 1430}
1524 1431
1432static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
1433{
1434 struct ieee80211_local *local = sdata->local;
1435 struct ieee80211_chanctx_conf *conf;
1436 struct ieee80211_chanctx *ctx;
1437 bool use_reserved_switch = false;
1438
1439 lockdep_assert_held(&local->chanctx_mtx);
1440
1441 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
1442 lockdep_is_held(&local->chanctx_mtx));
1443 if (!conf)
1444 return;
1445
1446 ctx = container_of(conf, struct ieee80211_chanctx, conf);
1447
1448 if (sdata->reserved_chanctx) {
1449 if (sdata->reserved_chanctx->replace_state ==
1450 IEEE80211_CHANCTX_REPLACES_OTHER &&
1451 ieee80211_chanctx_num_reserved(local,
1452 sdata->reserved_chanctx) > 1)
1453 use_reserved_switch = true;
1454
1455 ieee80211_vif_unreserve_chanctx(sdata);
1456 }
1457
1458 ieee80211_assign_vif_chanctx(sdata, NULL);
1459 if (ieee80211_chanctx_refcount(local, ctx) == 0)
1460 ieee80211_free_chanctx(local, ctx);
1461
1462 /* Unreserving may ready an in-place reservation. */
1463 if (use_reserved_switch)
1464 ieee80211_vif_use_reserved_switch(local);
1465}
1466
1467int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
1468 const struct cfg80211_chan_def *chandef,
1469 enum ieee80211_chanctx_mode mode)
1470{
1471 struct ieee80211_local *local = sdata->local;
1472 struct ieee80211_chanctx *ctx;
1473 u8 radar_detect_width = 0;
1474 int ret;
1475
1476 lockdep_assert_held(&local->mtx);
1477
1478 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
1479
1480 mutex_lock(&local->chanctx_mtx);
1481
1482 ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
1483 chandef,
1484 sdata->wdev.iftype);
1485 if (ret < 0)
1486 goto out;
1487 if (ret > 0)
1488 radar_detect_width = BIT(chandef->width);
1489
1490 sdata->radar_required = ret;
1491
1492 ret = ieee80211_check_combinations(sdata, chandef, mode,
1493 radar_detect_width);
1494 if (ret < 0)
1495 goto out;
1496
1497 __ieee80211_vif_release_channel(sdata);
1498
1499 ctx = ieee80211_find_chanctx(local, chandef, mode);
1500 if (!ctx)
1501 ctx = ieee80211_new_chanctx(local, chandef, mode);
1502 if (IS_ERR(ctx)) {
1503 ret = PTR_ERR(ctx);
1504 goto out;
1505 }
1506
1507 sdata->vif.bss_conf.chandef = *chandef;
1508
1509 ret = ieee80211_assign_vif_chanctx(sdata, ctx);
1510 if (ret) {
1511 /* if assign fails refcount stays the same */
1512 if (ieee80211_chanctx_refcount(local, ctx) == 0)
1513 ieee80211_free_chanctx(local, ctx);
1514 goto out;
1515 }
1516
1517 ieee80211_recalc_smps_chanctx(local, ctx);
1518 ieee80211_recalc_radar_chanctx(local, ctx);
1519 out:
1520 mutex_unlock(&local->chanctx_mtx);
1521 return ret;
1522}
1523
1525int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata) 1524int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
1526{ 1525{
1527 struct ieee80211_local *local = sdata->local; 1526 struct ieee80211_local *local = sdata->local;