From patchwork Sun Nov 23 15:02:19 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arik Nemtsov X-Patchwork-Id: 5361731 Return-Path: X-Original-To: patchwork-linux-wireless@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 4BC1FC11AC for ; Sun, 23 Nov 2014 15:02:32 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 3A49620253 for ; Sun, 23 Nov 2014 15:02:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B497020251 for ; Sun, 23 Nov 2014 15:02:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751458AbaKWPC1 (ORCPT ); Sun, 23 Nov 2014 10:02:27 -0500 Received: from mail-wi0-f171.google.com ([209.85.212.171]:61535 "EHLO mail-wi0-f171.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751290AbaKWPC0 (ORCPT ); Sun, 23 Nov 2014 10:02:26 -0500 Received: by mail-wi0-f171.google.com with SMTP id bs8so3406212wib.10 for ; Sun, 23 Nov 2014 07:02:25 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=aQCVe6d99Um65APgE5r+Q4CDNHd2Va+AaZjx2FuA40k=; b=g2TgZ7dtGjLXA+C7yGm93Ars98IpIDkiV+A3flY5RDBxIySXnwIg2LDb8yRSoMrjYd KTRkRm26Jwh7aYCMVGk+bTzBFvK7sskGlYHwSlwrdmBmp+FkpNzWJxGKh7PIRmuaeH0q 1xOe8l8pSLzoB9lcoha4gL2gSiuYAjvfSvanJEJ9u4Ou/eiVjN59tdkNPVV00uIyV6RF qHSvlRIMHz63jmGggmZnM3I7U0ID3DhAyAhyq1xNvai9tYdvzy6x//kVEptaRqoIg9/L 7Ij4jPZeR1Lre3gN4mGpSFWD4bkduVilMS3+PQ796MIPLjWd7x+wtcVs2I91e0ne8Rta zwsg== X-Gm-Message-State: ALoCoQko1LhLb8ER0M40p3Qar6Y5wFd1usAhcyXwLu+jNTV1bzu93lJfa8PLwtO621V+H9p9JhFu X-Received: by 10.194.77.142 with SMTP id s14mr26153138wjw.94.1416754945108; Sun, 23 Nov 2014 07:02:25 -0800 (PST) Received: from cube.amr.corp.intel.com (85-250-108-142.bb.netvision.net.il. [85.250.108.142]) by mx.google.com with ESMTPSA id gs9sm16651444wjc.47.2014.11.23.07.02.23 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 23 Nov 2014 07:02:24 -0800 (PST) From: Arik Nemtsov To: Cc: Johannes Berg , "Luis R. Rodriguez" , Arik Nemtsov Subject: [PATCH v3 1/3] cfg80211: leave invalid channels on regdomain change Date: Sun, 23 Nov 2014 17:02:19 +0200 Message-Id: <1416754941-4439-1-git-send-email-arik@wizery.com> X-Mailer: git-send-email 1.9.1 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 chekcing code. Signed-off-by: Arik Nemtsov --- include/net/regulatory.h | 6 +++ net/wireless/core.c | 13 ++++++ net/wireless/reg.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 124 insertions(+), 1 deletion(-) diff --git a/include/net/regulatory.h b/include/net/regulatory.h index dad7ab2..701177c 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -136,6 +136,11 @@ struct regulatory_request { * otherwise initiating radiation is not allowed. This will enable the * relaxations enabled under the CFG80211_REG_RELAX_NO_IR configuration * option + * @REGULATORY_ENFORCE_CHANNELS: the regulatory core will make sure all + * interfaces on this wiphy reside on allowed channels. Upon a regdomain + * change, the interfaces are given a grace period to disconnect or move + * to an allowed channels. Interfaces on forbidden channels are forcibly + * disconnected. */ enum ieee80211_regulatory_flags { REGULATORY_CUSTOM_REG = BIT(0), @@ -144,6 +149,7 @@ enum ieee80211_regulatory_flags { REGULATORY_COUNTRY_IE_FOLLOW_POWER = BIT(3), REGULATORY_COUNTRY_IE_IGNORE = BIT(4), REGULATORY_ENABLE_RELAX_NO_IR = BIT(5), + REGULATORY_ENFORCE_CHANNELS = BIT(6), }; struct ieee80211_freq_range { diff --git a/net/wireless/core.c b/net/wireless/core.c index 4c2e501..5295456 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -546,6 +546,19 @@ int wiphy_register(struct wiphy *wiphy) !rdev->ops->tdls_cancel_channel_switch))) return -EINVAL; + /* + * a wiphy that wishes to enable channel enforcement must have only + * modes where enforcement is supported. + */ + if (WARN_ON((wiphy->regulatory_flags & REGULATORY_ENFORCE_CHANNELS) && + (wiphy->interface_modes & ~(BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_AP_VLAN) | + BIT(NL80211_IFTYPE_MONITOR))))) + return -EINVAL; + if (WARN_ON(wiphy->coalesce && (!wiphy->coalesce->n_rules || !wiphy->coalesce->n_patterns) && diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 32d8310..922d00a 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -56,6 +56,7 @@ #include #include "core.h" #include "reg.h" +#include "rdev-ops.h" #include "regdb.h" #include "nl80211.h" @@ -66,6 +67,12 @@ #define REG_DBG_PRINT(args...) #endif +/* + * Grace period we give before making sure all current interfaces reside on + * channels allowed by the current regulatory domain. + */ +#define REG_ENFORCE_GRACE_MS 60000 + /** * enum reg_request_treatment - regulatory request treatment * @@ -210,6 +217,9 @@ struct reg_beacon { struct ieee80211_channel chan; }; +static void reg_check_chans_work(struct work_struct *work); +static DECLARE_DELAYED_WORK(reg_check_chans, reg_check_chans_work); + static void reg_todo(struct work_struct *work); static DECLARE_WORK(reg_work, reg_todo); @@ -1518,6 +1528,95 @@ static void reg_call_notifier(struct wiphy *wiphy, wiphy->reg_notifier(wiphy, request); } +static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + struct ieee80211_channel *ch; + struct cfg80211_chan_def chandef; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + bool ret = true; + + wdev_lock(wdev); + + if (!wdev->netdev || !netif_running(wdev->netdev)) + goto out; + + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + if (!wdev->beacon_interval) + goto out; + + ret = cfg80211_reg_can_beacon(wiphy, + &wdev->chandef, wdev->iftype); + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_ADHOC: + if (!wdev->current_bss || + !wdev->current_bss->pub.channel) + goto out; + + ch = wdev->current_bss->pub.channel; + if (rdev->ops->get_channel && + !rdev_get_channel(rdev, wdev, &chandef)) + ret = cfg80211_chandef_usable(wiphy, &chandef, + IEEE80211_CHAN_DISABLED); + else + ret = !(ch->flags & IEEE80211_CHAN_DISABLED); + break; + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_DEVICE: + /* no enforcement required */ + break; + default: + /* others not implemented for now */ + WARN_ON(1); + break; + } + +out: + wdev_unlock(wdev); + return ret; +} + +static void reg_leave_invalid_chans(struct wiphy *wiphy) +{ + struct wireless_dev *wdev; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + + ASSERT_RTNL(); + + list_for_each_entry(wdev, &rdev->wdev_list, list) + if (!reg_wdev_chan_valid(wiphy, wdev)) + cfg80211_leave(rdev, wdev); +} + +static void reg_check_chans_work(struct work_struct *work) +{ + struct cfg80211_registered_device *rdev; + + REG_DBG_PRINT("Verifying active interfaces after reg change\n"); + rtnl_lock(); + + list_for_each_entry(rdev, &cfg80211_rdev_list, list) + if (rdev->wiphy.regulatory_flags & REGULATORY_ENFORCE_CHANNELS) + reg_leave_invalid_chans(&rdev->wiphy); + + rtnl_unlock(); +} + +static void reg_check_channels(void) +{ + /* + * Give usermode a chance to do something nicer (move to another + * channel, orderly disconnection), before forcing a disconnection. + */ + mod_delayed_work(system_power_efficient_wq, + ®_check_chans, + msecs_to_jiffies(REG_ENFORCE_GRACE_MS)); +} + static void wiphy_update_regulatory(struct wiphy *wiphy, enum nl80211_reg_initiator initiator) { @@ -1557,6 +1656,8 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) wiphy = &rdev->wiphy; wiphy_update_regulatory(wiphy, initiator); } + + reg_check_channels(); } static void handle_channel_custom(struct wiphy *wiphy, @@ -1976,8 +2077,10 @@ static void reg_process_hint(struct regulatory_request *reg_request) /* This is required so that the orig_* parameters are saved */ if (treatment == REG_REQ_ALREADY_SET && wiphy && - wiphy->regulatory_flags & REGULATORY_STRICT_REG) + wiphy->regulatory_flags & REGULATORY_STRICT_REG) { wiphy_update_regulatory(wiphy, reg_request->initiator); + reg_check_channels(); + } return; @@ -2858,6 +2961,7 @@ void regulatory_exit(void) cancel_work_sync(®_work); cancel_delayed_work_sync(®_timeout); + cancel_delayed_work_sync(®_check_chans); /* Lock to suppress warnings */ rtnl_lock();