diff options
author | Arik Nemtsov <arik@wizery.com> | 2014-11-27 02:44:55 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2014-11-28 08:33:41 -0500 |
commit | ad932f046fbe9839479350e7b88082a7d1dea498 (patch) | |
tree | bde027962f8f061558db060102872d7de0435adf /net/wireless/reg.c | |
parent | 336004e29115e47253f7e7d007df9e1f9e73dcdd (diff) |
cfg80211: leave invalid channels on regdomain change
When the regulatory settings change, some channels might become invalid.
Disconnect interfaces acting on these channels, after giving userspace
code a grace period to leave them.
This mode is currently opt-in, and not all interface operating modes are
supported for regulatory-enforcement checks. A wiphy that wishes to use
the new enforcement code must specify an appropriate regulatory flag,
and all its supported interface modes must be supported by the checking
code.
Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
Reviewed-by: Luis R. Rodriguez <mcgrof@suse.com>
[fix some indentation, typos]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r-- | net/wireless/reg.c | 107 |
1 files changed, 106 insertions, 1 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 32d8310b0f85..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 | ||
@@ -1518,6 +1528,96 @@ static void reg_call_notifier(struct wiphy *wiphy, | |||
1518 | wiphy->reg_notifier(wiphy, request); | 1528 | wiphy->reg_notifier(wiphy, request); |
1519 | } | 1529 | } |
1520 | 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 | |||
1521 | static void wiphy_update_regulatory(struct wiphy *wiphy, | 1621 | static void wiphy_update_regulatory(struct wiphy *wiphy, |
1522 | enum nl80211_reg_initiator initiator) | 1622 | enum nl80211_reg_initiator initiator) |
1523 | { | 1623 | { |
@@ -1557,6 +1657,8 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) | |||
1557 | wiphy = &rdev->wiphy; | 1657 | wiphy = &rdev->wiphy; |
1558 | wiphy_update_regulatory(wiphy, initiator); | 1658 | wiphy_update_regulatory(wiphy, initiator); |
1559 | } | 1659 | } |
1660 | |||
1661 | reg_check_channels(); | ||
1560 | } | 1662 | } |
1561 | 1663 | ||
1562 | static void handle_channel_custom(struct wiphy *wiphy, | 1664 | static void handle_channel_custom(struct wiphy *wiphy, |
@@ -1976,8 +2078,10 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1976 | 2078 | ||
1977 | /* This is required so that the orig_* parameters are saved */ | 2079 | /* This is required so that the orig_* parameters are saved */ |
1978 | if (treatment == REG_REQ_ALREADY_SET && wiphy && | 2080 | if (treatment == REG_REQ_ALREADY_SET && wiphy && |
1979 | wiphy->regulatory_flags & REGULATORY_STRICT_REG) | 2081 | wiphy->regulatory_flags & REGULATORY_STRICT_REG) { |
1980 | wiphy_update_regulatory(wiphy, reg_request->initiator); | 2082 | wiphy_update_regulatory(wiphy, reg_request->initiator); |
2083 | reg_check_channels(); | ||
2084 | } | ||
1981 | 2085 | ||
1982 | return; | 2086 | return; |
1983 | 2087 | ||
@@ -2858,6 +2962,7 @@ void regulatory_exit(void) | |||
2858 | 2962 | ||
2859 | cancel_work_sync(®_work); | 2963 | cancel_work_sync(®_work); |
2860 | cancel_delayed_work_sync(®_timeout); | 2964 | cancel_delayed_work_sync(®_timeout); |
2965 | cancel_delayed_work_sync(®_check_chans); | ||
2861 | 2966 | ||
2862 | /* Lock to suppress warnings */ | 2967 | /* Lock to suppress warnings */ |
2863 | rtnl_lock(); | 2968 | rtnl_lock(); |