diff options
Diffstat (limited to 'net/mac80211/chan.c')
-rw-r--r-- | net/mac80211/chan.c | 191 |
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 | ||
642 | static 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 | |||
677 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | 642 | void 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 | ||
767 | int 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 | |||
824 | static void | 732 | static 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 | ||
1272 | int | 1180 | static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) |
1273 | ieee80211_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 | ||
1432 | static 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 | |||
1467 | int 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 | |||
1525 | int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata) | 1524 | int 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; |