diff options
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r-- | net/wireless/reg.c | 156 |
1 files changed, 153 insertions, 3 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index b725a31a4751..47be6163381c 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include <net/cfg80211.h> | 56 | #include <net/cfg80211.h> |
57 | #include "core.h" | 57 | #include "core.h" |
58 | #include "reg.h" | 58 | #include "reg.h" |
59 | #include "rdev-ops.h" | ||
59 | #include "regdb.h" | 60 | #include "regdb.h" |
60 | #include "nl80211.h" | 61 | #include "nl80211.h" |
61 | 62 | ||
@@ -66,6 +67,12 @@ | |||
66 | #define REG_DBG_PRINT(args...) | 67 | #define REG_DBG_PRINT(args...) |
67 | #endif | 68 | #endif |
68 | 69 | ||
70 | /* | ||
71 | * Grace period we give before making sure all current interfaces reside on | ||
72 | * channels allowed by the current regulatory domain. | ||
73 | */ | ||
74 | #define REG_ENFORCE_GRACE_MS 60000 | ||
75 | |||
69 | /** | 76 | /** |
70 | * enum reg_request_treatment - regulatory request treatment | 77 | * enum reg_request_treatment - regulatory request treatment |
71 | * | 78 | * |
@@ -210,6 +217,9 @@ struct reg_beacon { | |||
210 | struct ieee80211_channel chan; | 217 | struct ieee80211_channel chan; |
211 | }; | 218 | }; |
212 | 219 | ||
220 | static void reg_check_chans_work(struct work_struct *work); | ||
221 | static DECLARE_DELAYED_WORK(reg_check_chans, reg_check_chans_work); | ||
222 | |||
213 | static void reg_todo(struct work_struct *work); | 223 | static void reg_todo(struct work_struct *work); |
214 | static DECLARE_WORK(reg_work, reg_todo); | 224 | static DECLARE_WORK(reg_work, reg_todo); |
215 | 225 | ||
@@ -573,8 +583,9 @@ static const struct ieee80211_regdomain *reg_get_regdomain(struct wiphy *wiphy) | |||
573 | return get_cfg80211_regdom(); | 583 | return get_cfg80211_regdom(); |
574 | } | 584 | } |
575 | 585 | ||
576 | unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | 586 | static unsigned int |
577 | const struct ieee80211_reg_rule *rule) | 587 | reg_get_max_bandwidth_from_range(const struct ieee80211_regdomain *rd, |
588 | const struct ieee80211_reg_rule *rule) | ||
578 | { | 589 | { |
579 | const struct ieee80211_freq_range *freq_range = &rule->freq_range; | 590 | const struct ieee80211_freq_range *freq_range = &rule->freq_range; |
580 | const struct ieee80211_freq_range *freq_range_tmp; | 591 | const struct ieee80211_freq_range *freq_range_tmp; |
@@ -622,6 +633,27 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | |||
622 | return end_freq - start_freq; | 633 | return end_freq - start_freq; |
623 | } | 634 | } |
624 | 635 | ||
636 | unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | ||
637 | const struct ieee80211_reg_rule *rule) | ||
638 | { | ||
639 | unsigned int bw = reg_get_max_bandwidth_from_range(rd, rule); | ||
640 | |||
641 | if (rule->flags & NL80211_RRF_NO_160MHZ) | ||
642 | bw = min_t(unsigned int, bw, MHZ_TO_KHZ(80)); | ||
643 | if (rule->flags & NL80211_RRF_NO_80MHZ) | ||
644 | bw = min_t(unsigned int, bw, MHZ_TO_KHZ(40)); | ||
645 | |||
646 | /* | ||
647 | * HT40+/HT40- limits are handled per-channel. Only limit BW if both | ||
648 | * are not allowed. | ||
649 | */ | ||
650 | if (rule->flags & NL80211_RRF_NO_HT40MINUS && | ||
651 | rule->flags & NL80211_RRF_NO_HT40PLUS) | ||
652 | bw = min_t(unsigned int, bw, MHZ_TO_KHZ(20)); | ||
653 | |||
654 | return bw; | ||
655 | } | ||
656 | |||
625 | /* Sanity check on a regulatory rule */ | 657 | /* Sanity check on a regulatory rule */ |
626 | static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) | 658 | static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) |
627 | { | 659 | { |
@@ -946,6 +978,16 @@ static u32 map_regdom_flags(u32 rd_flags) | |||
946 | channel_flags |= IEEE80211_CHAN_NO_OFDM; | 978 | channel_flags |= IEEE80211_CHAN_NO_OFDM; |
947 | if (rd_flags & NL80211_RRF_NO_OUTDOOR) | 979 | if (rd_flags & NL80211_RRF_NO_OUTDOOR) |
948 | channel_flags |= IEEE80211_CHAN_INDOOR_ONLY; | 980 | channel_flags |= IEEE80211_CHAN_INDOOR_ONLY; |
981 | if (rd_flags & NL80211_RRF_GO_CONCURRENT) | ||
982 | channel_flags |= IEEE80211_CHAN_GO_CONCURRENT; | ||
983 | if (rd_flags & NL80211_RRF_NO_HT40MINUS) | ||
984 | channel_flags |= IEEE80211_CHAN_NO_HT40MINUS; | ||
985 | if (rd_flags & NL80211_RRF_NO_HT40PLUS) | ||
986 | channel_flags |= IEEE80211_CHAN_NO_HT40PLUS; | ||
987 | if (rd_flags & NL80211_RRF_NO_80MHZ) | ||
988 | channel_flags |= IEEE80211_CHAN_NO_80MHZ; | ||
989 | if (rd_flags & NL80211_RRF_NO_160MHZ) | ||
990 | channel_flags |= IEEE80211_CHAN_NO_160MHZ; | ||
949 | return channel_flags; | 991 | return channel_flags; |
950 | } | 992 | } |
951 | 993 | ||
@@ -1486,6 +1528,96 @@ static void reg_call_notifier(struct wiphy *wiphy, | |||
1486 | wiphy->reg_notifier(wiphy, request); | 1528 | wiphy->reg_notifier(wiphy, request); |
1487 | } | 1529 | } |
1488 | 1530 | ||
1531 | static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) | ||
1532 | { | ||
1533 | struct ieee80211_channel *ch; | ||
1534 | struct cfg80211_chan_def chandef; | ||
1535 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | ||
1536 | bool ret = true; | ||
1537 | |||
1538 | wdev_lock(wdev); | ||
1539 | |||
1540 | if (!wdev->netdev || !netif_running(wdev->netdev)) | ||
1541 | goto out; | ||
1542 | |||
1543 | switch (wdev->iftype) { | ||
1544 | case NL80211_IFTYPE_AP: | ||
1545 | case NL80211_IFTYPE_P2P_GO: | ||
1546 | if (!wdev->beacon_interval) | ||
1547 | goto out; | ||
1548 | |||
1549 | ret = cfg80211_reg_can_beacon(wiphy, | ||
1550 | &wdev->chandef, wdev->iftype); | ||
1551 | break; | ||
1552 | case NL80211_IFTYPE_STATION: | ||
1553 | case NL80211_IFTYPE_P2P_CLIENT: | ||
1554 | case NL80211_IFTYPE_ADHOC: | ||
1555 | if (!wdev->current_bss || | ||
1556 | !wdev->current_bss->pub.channel) | ||
1557 | goto out; | ||
1558 | |||
1559 | ch = wdev->current_bss->pub.channel; | ||
1560 | if (rdev->ops->get_channel && | ||
1561 | !rdev_get_channel(rdev, wdev, &chandef)) | ||
1562 | ret = cfg80211_chandef_usable(wiphy, &chandef, | ||
1563 | IEEE80211_CHAN_DISABLED); | ||
1564 | else | ||
1565 | ret = !(ch->flags & IEEE80211_CHAN_DISABLED); | ||
1566 | break; | ||
1567 | case NL80211_IFTYPE_MONITOR: | ||
1568 | case NL80211_IFTYPE_AP_VLAN: | ||
1569 | case NL80211_IFTYPE_P2P_DEVICE: | ||
1570 | /* no enforcement required */ | ||
1571 | break; | ||
1572 | default: | ||
1573 | /* others not implemented for now */ | ||
1574 | WARN_ON(1); | ||
1575 | break; | ||
1576 | } | ||
1577 | |||
1578 | out: | ||
1579 | wdev_unlock(wdev); | ||
1580 | return ret; | ||
1581 | } | ||
1582 | |||
1583 | static void reg_leave_invalid_chans(struct wiphy *wiphy) | ||
1584 | { | ||
1585 | struct wireless_dev *wdev; | ||
1586 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | ||
1587 | |||
1588 | ASSERT_RTNL(); | ||
1589 | |||
1590 | list_for_each_entry(wdev, &rdev->wdev_list, list) | ||
1591 | if (!reg_wdev_chan_valid(wiphy, wdev)) | ||
1592 | cfg80211_leave(rdev, wdev); | ||
1593 | } | ||
1594 | |||
1595 | static void reg_check_chans_work(struct work_struct *work) | ||
1596 | { | ||
1597 | struct cfg80211_registered_device *rdev; | ||
1598 | |||
1599 | REG_DBG_PRINT("Verifying active interfaces after reg change\n"); | ||
1600 | rtnl_lock(); | ||
1601 | |||
1602 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) | ||
1603 | if (!(rdev->wiphy.regulatory_flags & | ||
1604 | REGULATORY_IGNORE_STALE_KICKOFF)) | ||
1605 | reg_leave_invalid_chans(&rdev->wiphy); | ||
1606 | |||
1607 | rtnl_unlock(); | ||
1608 | } | ||
1609 | |||
1610 | static void reg_check_channels(void) | ||
1611 | { | ||
1612 | /* | ||
1613 | * Give usermode a chance to do something nicer (move to another | ||
1614 | * channel, orderly disconnection), before forcing a disconnection. | ||
1615 | */ | ||
1616 | mod_delayed_work(system_power_efficient_wq, | ||
1617 | ®_check_chans, | ||
1618 | msecs_to_jiffies(REG_ENFORCE_GRACE_MS)); | ||
1619 | } | ||
1620 | |||
1489 | static void wiphy_update_regulatory(struct wiphy *wiphy, | 1621 | static void wiphy_update_regulatory(struct wiphy *wiphy, |
1490 | enum nl80211_reg_initiator initiator) | 1622 | enum nl80211_reg_initiator initiator) |
1491 | { | 1623 | { |
@@ -1525,6 +1657,8 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) | |||
1525 | wiphy = &rdev->wiphy; | 1657 | wiphy = &rdev->wiphy; |
1526 | wiphy_update_regulatory(wiphy, initiator); | 1658 | wiphy_update_regulatory(wiphy, initiator); |
1527 | } | 1659 | } |
1660 | |||
1661 | reg_check_channels(); | ||
1528 | } | 1662 | } |
1529 | 1663 | ||
1530 | static void handle_channel_custom(struct wiphy *wiphy, | 1664 | static void handle_channel_custom(struct wiphy *wiphy, |
@@ -1565,10 +1699,23 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1565 | if (max_bandwidth_khz < MHZ_TO_KHZ(160)) | 1699 | if (max_bandwidth_khz < MHZ_TO_KHZ(160)) |
1566 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; | 1700 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; |
1567 | 1701 | ||
1702 | chan->dfs_state_entered = jiffies; | ||
1703 | chan->dfs_state = NL80211_DFS_USABLE; | ||
1704 | |||
1705 | chan->beacon_found = false; | ||
1568 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | 1706 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; |
1569 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1707 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
1570 | chan->max_reg_power = chan->max_power = | 1708 | chan->max_reg_power = chan->max_power = |
1571 | (int) MBM_TO_DBM(power_rule->max_eirp); | 1709 | (int) MBM_TO_DBM(power_rule->max_eirp); |
1710 | |||
1711 | if (chan->flags & IEEE80211_CHAN_RADAR) { | ||
1712 | if (reg_rule->dfs_cac_ms) | ||
1713 | chan->dfs_cac_ms = reg_rule->dfs_cac_ms; | ||
1714 | else | ||
1715 | chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; | ||
1716 | } | ||
1717 | |||
1718 | chan->max_power = chan->max_reg_power; | ||
1572 | } | 1719 | } |
1573 | 1720 | ||
1574 | static void handle_band_custom(struct wiphy *wiphy, | 1721 | static void handle_band_custom(struct wiphy *wiphy, |
@@ -1931,8 +2078,10 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1931 | 2078 | ||
1932 | /* This is required so that the orig_* parameters are saved */ | 2079 | /* This is required so that the orig_* parameters are saved */ |
1933 | if (treatment == REG_REQ_ALREADY_SET && wiphy && | 2080 | if (treatment == REG_REQ_ALREADY_SET && wiphy && |
1934 | wiphy->regulatory_flags & REGULATORY_STRICT_REG) | 2081 | wiphy->regulatory_flags & REGULATORY_STRICT_REG) { |
1935 | wiphy_update_regulatory(wiphy, reg_request->initiator); | 2082 | wiphy_update_regulatory(wiphy, reg_request->initiator); |
2083 | reg_check_channels(); | ||
2084 | } | ||
1936 | 2085 | ||
1937 | return; | 2086 | return; |
1938 | 2087 | ||
@@ -2813,6 +2962,7 @@ void regulatory_exit(void) | |||
2813 | 2962 | ||
2814 | cancel_work_sync(®_work); | 2963 | cancel_work_sync(®_work); |
2815 | cancel_delayed_work_sync(®_timeout); | 2964 | cancel_delayed_work_sync(®_timeout); |
2965 | cancel_delayed_work_sync(®_check_chans); | ||
2816 | 2966 | ||
2817 | /* Lock to suppress warnings */ | 2967 | /* Lock to suppress warnings */ |
2818 | rtnl_lock(); | 2968 | rtnl_lock(); |