From patchwork Mon Jan 2 13:27:47 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?UmFmYcWCIE1pxYJlY2tp?= X-Patchwork-Id: 9493565 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A7F7D62AB4 for ; Mon, 2 Jan 2017 13:28:40 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 95FCC223B2 for ; Mon, 2 Jan 2017 13:28:40 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 87B79267EC; Mon, 2 Jan 2017 13:28:40 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EE733223B2 for ; Mon, 2 Jan 2017 13:28:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932997AbdABN2i (ORCPT ); Mon, 2 Jan 2017 08:28:38 -0500 Received: from mail-lf0-f67.google.com ([209.85.215.67]:35490 "EHLO mail-lf0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932325AbdABN2g (ORCPT ); Mon, 2 Jan 2017 08:28:36 -0500 Received: by mail-lf0-f67.google.com with SMTP id x140so25782594lfa.2; Mon, 02 Jan 2017 05:28:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=rS/NSTcdjC6mc5St3e3y+EDSM3lbZpOI27i8fSNl7Mg=; b=c+EHMjDBFQF0qnyop007BhYm4hFAX4SpQC+W9jlSRCbdG66qX7y1Flqq6PaLnQpcG8 i1g70bJ3XLTq1zyDlI4W2aB5QbTrys3Jl9JJ69B7A9izSfhwnTUofmK4aQlyHVT84Msq XEKedVd6BakkZnWZ86c1kt/pvTQuDUZmp5s/IkRCXVdV0Dai3YG1CCX9xWX9BnEzB3t5 MeB3PYOddUBE5tx2AG5XUTs3Xm/nqTjqU0gtgXqSMVuyyUszPlunGjMdrz6C4vqaANSy Ye9ohTbl8/kwwa/N/WmiTNqKnhqshcw+bDw74LmeC3YdJCn/Rx9n4tQV/ORJWMFOq/K1 Zflw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=rS/NSTcdjC6mc5St3e3y+EDSM3lbZpOI27i8fSNl7Mg=; b=D+khuo+Ad+nty0TtU5yO+vpgIm8rp1eFdznJpejXcH8PwyyLDQ3d/9w6VUfEb4NClZ qgq/qGDI2sogunZ3A1kbLpU6cCq0FoWuKFQff0wm0SbH7+/GGpaHO7IxtV1P0vhViDm1 kgKHzgtgJbZxVOX8eGpZW9zYzgfEcNUeT/qQ1qHp5UUky6qx40XrgfiKZ/3E7jZz5BYu YCJsV+eJczBnzc6w5fAFzHkJAcmyxChO2Ma6I34dajvw0zYVqdesgeF7YrqcDP3c2FY/ hKUVM85RnbEToB21CVQAxr8a+Coz8gCmbcVbQen23R95kUEmiNndKKIJdDq2y6LjpUhK G8mw== X-Gm-Message-State: AIkVDXLGAqAvu3dkt2m5GyeG6xmC1IGSeSC0NZ7i5u9aIiry6aBkK34cnb+M7UKt0640QQ== X-Received: by 10.25.56.22 with SMTP id f22mr17778492lfa.0.1483363714369; Mon, 02 Jan 2017 05:28:34 -0800 (PST) Received: from linux-samsung.lan (ip-194-187-74-233.konfederacka.maverick.com.pl. [194.187.74.233]) by smtp.gmail.com with ESMTPSA id d79sm15949239lfd.46.2017.01.02.05.28.33 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 02 Jan 2017 05:28:33 -0800 (PST) From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= To: Johannes Berg , linux-wireless@vger.kernel.org Cc: Martin Blumenstingl , Felix Fietkau , Arend van Spriel , Arnd Bergmann , devicetree@vger.kernel.org, =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Subject: [PATCH V2 3/3] cfg80211: support ieee80211-freq-limit DT property Date: Mon, 2 Jan 2017 14:27:47 +0100 Message-Id: <20170102132747.3491-3-zajec5@gmail.com> X-Mailer: git-send-email 2.10.1 In-Reply-To: <20170102132747.3491-1-zajec5@gmail.com> References: <20170102132747.3491-1-zajec5@gmail.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Rafał Miłecki It allows specifying hardware limitations of supported channels. This may be useful for specifying single band devices or devices that support only some part of the whole band. This can be useful for some tri-band routers that have separated radios for lower and higher part of 5 GHz band. Signed-off-by: Rafał Miłecki --- V2: Put main code in core.c as it isn't strictly part of regulatory - pointed by Arend. Update to support ieee80211-freq-limit (new property). --- include/net/cfg80211.h | 6 +++ net/wireless/core.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++ net/wireless/core.h | 2 + net/wireless/reg.c | 8 +++- net/wireless/reg.h | 2 + 5 files changed, 126 insertions(+), 2 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e952cca..6609c39 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3515,6 +3515,9 @@ struct wiphy_iftype_ext_capab { * attribute indices defined in &enum nl80211_bss_select_attr. * * @cookie_counter: unique generic cookie counter, used to identify objects. + * + * @n_freq_limits: number of frequency limits + * @freq_limits: array of extra frequency limits */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -3646,6 +3649,9 @@ struct wiphy { u64 cookie_counter; + unsigned int n_freq_limits; + struct ieee80211_freq_range *freq_limits; + char priv[0] __aligned(NETDEV_ALIGN); }; diff --git a/net/wireless/core.c b/net/wireless/core.c index 398922a..c2a5c81 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -87,6 +87,113 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) return &rdev->wiphy; } +static int wiphy_freq_limits_init(struct wiphy *wiphy) +{ + struct device *dev = wiphy_dev(wiphy); + struct device_node *np; + struct property *prop; + const __be32 *p; + int i; + int err = 0; + + if (wiphy->n_freq_limits) + return 0; + + if (!dev) + return 0; + np = dev->of_node; + if (!np) + return 0; + + prop = of_find_property(np, "ieee80211-freq-limit", &i); + if (!prop) + return 0; + + i = i / sizeof(u32); + if (i % 2) { + dev_err(dev, "ieee80211-freq-limit wrong value"); + return -EPROTO; + } + wiphy->n_freq_limits = i / 2; + + wiphy->freq_limits = kzalloc(wiphy->n_freq_limits * sizeof(*wiphy->freq_limits), + GFP_KERNEL); + if (!wiphy->freq_limits) { + err = -ENOMEM; + goto out; + } + + p = NULL; + for (i = 0; i < wiphy->n_freq_limits; i++) { + struct ieee80211_freq_range *limit = &wiphy->freq_limits[i]; + + p = of_prop_next_u32(prop, p, &limit->start_freq_khz); + if (!p) { + err = -EINVAL; + goto out; + } + + p = of_prop_next_u32(prop, p, &limit->end_freq_khz); + if (!p) { + err = -EINVAL; + goto out; + } + } + +out: + if (err) { + dev_err(dev, "Failed to get limits: %d\n", err); + kfree(wiphy->freq_limits); + wiphy->n_freq_limits = 0; + } + return err; +} + +static bool wiphy_freq_limits_valid_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan) +{ + u32 bw = MHZ_TO_KHZ(20); + int i; + + for (i = 0; i < wiphy->n_freq_limits; i++) { + struct ieee80211_freq_range *limit = &wiphy->freq_limits[i]; + + if (reg_does_bw_fit(limit, MHZ_TO_KHZ(chan->center_freq), bw)) + return true; + } + + return false; +} + +void wiphy_freq_limits_apply(struct wiphy *wiphy) +{ + enum nl80211_band band; + int i; + + if (!wiphy->n_freq_limits) + return; + + for (band = 0; band < NUM_NL80211_BANDS; band++) { + struct ieee80211_supported_band *sband = wiphy->bands[band]; + + if (!sband) + continue; + + for (i = 0; i < sband->n_channels; i++) { + struct ieee80211_channel *chan = &sband->channels[i]; + + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + + if (!wiphy_freq_limits_valid_chan(wiphy, chan)) { + pr_debug("Disabling freq %d MHz as it's out of OF limits\n", + chan->center_freq); + chan->flags |= IEEE80211_CHAN_DISABLED; + } + } + } +} + static int cfg80211_dev_check_name(struct cfg80211_registered_device *rdev, const char *newname) { @@ -481,6 +588,8 @@ struct wiphy *wiphy_new_nm(struct device *dev, const struct cfg80211_ops *ops, init_waitqueue_head(&rdev->dev_wait); + wiphy_freq_limits_init(&rdev->wiphy); + /* * Initialize wiphy parameters to IEEE 802.11 MIB default values. * Fragmentation and RTS threshold are disabled by default with the @@ -942,6 +1051,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev) void wiphy_free(struct wiphy *wiphy) { + kfree(wiphy->freq_limits); put_device(&wiphy->dev); } EXPORT_SYMBOL(wiphy_free); diff --git a/net/wireless/core.h b/net/wireless/core.h index af6e023..ce94f82 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -271,6 +271,8 @@ struct cfg80211_iface_destroy { u32 nlportid; }; +void wiphy_freq_limits_apply(struct wiphy *wiphy); + void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev); /* free object */ diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 5dbac37..cb5a264 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -748,8 +748,8 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd) return true; } -static bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range, - u32 center_freq_khz, u32 bw_khz) +bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range, + u32 center_freq_khz, u32 bw_khz) { u32 start_freq_khz, end_freq_khz; @@ -1693,6 +1693,8 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, for (band = 0; band < NUM_NL80211_BANDS; band++) handle_band(wiphy, initiator, wiphy->bands[band]); + wiphy_freq_limits_apply(wiphy); + reg_process_beacons(wiphy); reg_process_ht_flags(wiphy); reg_call_notifier(wiphy, lr); @@ -1800,6 +1802,8 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, bands_set++; } + wiphy_freq_limits_apply(wiphy); + /* * no point in calling this if it won't have any effect * on your device's supported bands. diff --git a/net/wireless/reg.h b/net/wireless/reg.h index f6ced31..90eddc3 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -25,6 +25,8 @@ extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain; bool reg_is_valid_request(const char *alpha2); bool is_world_regdom(const char *alpha2); +bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range, + u32 center_freq_khz, u32 bw_khz); bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region); enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy);