From patchwork Mon Sep 10 10:06:36 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mahesh Palivela X-Patchwork-Id: 1431171 Return-Path: X-Original-To: patchwork-linux-wireless@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id C0B0F40220 for ; Mon, 10 Sep 2012 10:06:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751509Ab2IJKGg (ORCPT ); Mon, 10 Sep 2012 06:06:36 -0400 Received: from hub022-nj-6.exch022.serverdata.net ([206.225.164.189]:3991 "EHLO HUB022-nj-6.exch022.serverdata.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751315Ab2IJKGg (ORCPT ); Mon, 10 Sep 2012 06:06:36 -0400 Received: from [192.168.15.102] (49.206.130.53) by east.exch022.serverdata.net (10.240.6.64) with Microsoft SMTP Server (TLS) id 14.2.309.2; Mon, 10 Sep 2012 03:06:34 -0700 Message-ID: <504DBBAC.7040300@posedge.com> Date: Mon, 10 Sep 2012 15:36:36 +0530 From: Mahesh Palivela User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:14.0) Gecko/20120713 Thunderbird/14.0 MIME-Version: 1.0 To: "linux-wireless@vger.kernel.org" CC: "linville@tuxdriver.com" , Johannes Berg , Stanislaw Gruszka Subject: [RFC v3] cfg80211: VHT regulatory Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org VHT (11ac) regulatory new design. VHT channel center freq, bandwidth and primary channel are used to decide if that channel config is permitted in current regulatory domain. Signed-off-by: Mahesh Palivela --- Implementation of review comments by Johannes. include/net/cfg80211.h | 37 ++++++++++++++++ net/wireless/reg.c | 109 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 0 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 60597cf..50180e0 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -83,6 +83,25 @@ enum ieee80211_band { }; /** + * enum ieee80211_chan_width - channel bandwidths + * + * @IEEE80211_CHAN_WIDTH_20MHZ_NOHT: 20 MHz chan bandwidth No HT + * @IEEE80211_CHAN_WIDTH_20MHZ: 20 MHz chan bandwidth + * @IEEE80211_CHAN_WIDTH_40MHZ: 40 MHz chan bandwidth + * @IEEE80211_CHAN_WIDTH_80MHZ: 80 MHz chan bandwidth + * @IEEE80211_CHAN_WIDTH_160MHZ: 160 MHz chan bandwidth + * @IEEE80211_CHAN_WIDTH_80P80MHZ: 80+80 MHz chan bandwidth + */ +enum ieee80211_chan_width { + IEEE80211_CHAN_WIDTH_20MHZ_NOHT, + IEEE80211_CHAN_WIDTH_20MHZ, + IEEE80211_CHAN_WIDTH_40MHZ, + IEEE80211_CHAN_WIDTH_80MHZ, + IEEE80211_CHAN_WIDTH_160MHZ, + IEEE80211_CHAN_WIDTH_80P80MHZ +}; + +/** * enum ieee80211_channel_flags - channel flags * * Channel flags set by the regulatory control code. @@ -144,6 +163,24 @@ struct ieee80211_channel { }; /** + * struct ieee80211_channel_config - channel config definition + * + * This structure describes channel configuration + * + * @chan_width1: channel bandwidth + * @center_freq1: center frequency of 1 st frequency segment + * @center_freq2: center frequency of 2 nd frequency segment + * Used only for 80+80 MHz combination + * @prim_chan_freq: primary channel frequency + */ +struct ieee80211_channel_config { + enum ieee80211_chan_width chan_width; + u16 center_freq1; + u16 center_freq2; + u16 prim_chan_freq; +}; + +/** * enum ieee80211_rate_flags - rate flags * * Hardware/specification flags for rates. These are structured diff --git a/net/wireless/reg.c b/net/wireless/reg.c index c6e0d46..31d6f7a 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1124,6 +1124,115 @@ static void reg_process_beacons(struct wiphy *wiphy) wiphy_update_beacon_reg(wiphy); } +static bool reg_fits_reg_rule_sec_chans(struct wiphy *wiphy, + u32 center_freq, + u32 bw_khz, + const struct ieee80211_regdomain *regd) +{ + int r; + const struct ieee80211_reg_rule *reg_rule; + const struct ieee80211_freq_range *freq_range; + struct ieee80211_channel *chan; + u32 left_end_freq, right_end_freq; + + WARN_ON(!center_freq); + WARN_ON(!bw_khz); + + assert_reg_lock(); + + r = freq_reg_info_regd(wiphy, + center_freq, + bw_khz, + ®_rule, + regd); + + if (r) { + REG_DBG_PRINT("Couldn't find reg rule for freq %d KHz" + "and %d MHz wide channel\n", + center_freq, + KHZ_TO_MHZ(bw_khz)); + return false; + } + + freq_range = ®_rule->freq_range; + + if (freq_range->max_bandwidth_khz < bw_khz) + return false; + + /* find left and right arms of center freq */ + left_end_freq = center_freq - (bw_khz/2); + right_end_freq = center_freq + (bw_khz/2); + + /* left_end_freq and right_end_freq are edge of left and right + * channels. Get center freq of left and right channels + * by adding 10MHz to left_end_freq and subtracting 10 MHZ from + * right_end_freq. + */ + left_end_freq += MHZ_TO_KHZ(10); + right_end_freq -= MHZ_TO_KHZ(10); + + /* find out all possible secondary channels */ + while (left_end_freq < right_end_freq) { + chan = ieee80211_get_channel(wiphy, left_end_freq); + if (chan == NULL || + chan->flags & IEEE80211_CHAN_DISABLED) { + return false; + } + left_end_freq -= MHZ_TO_KHZ(20); + } + + return true; +} + +bool reg_chan_use_permitted(struct wiphy *wiphy, + struct ieee80211_channel_config *chan_config, + const struct ieee80211_regdomain *regd) +{ + u32 desired_bw_khz = MHZ_TO_KHZ(20); + bool ret; + + /* get chan BW from config */ + switch (chan_config->chan_width) { + case IEEE80211_CHAN_WIDTH_20MHZ_NOHT: + case IEEE80211_CHAN_WIDTH_20MHZ: + desired_bw_khz = MHZ_TO_KHZ(20); + break; + + case IEEE80211_CHAN_WIDTH_40MHZ: + desired_bw_khz = MHZ_TO_KHZ(40); + break; + + case IEEE80211_CHAN_WIDTH_80MHZ: + case IEEE80211_CHAN_WIDTH_80P80MHZ: + desired_bw_khz = MHZ_TO_KHZ(80); + break; + + case IEEE80211_CHAN_WIDTH_160MHZ: + desired_bw_khz = MHZ_TO_KHZ(160); + break; + default: + REG_DBG_PRINT("Invalid channel width %d\n", + chan_config->chan_width); + return false; + } + + ret = reg_fits_reg_rule_sec_chans(wiphy, + chan_config->center_freq1, + desired_bw_khz, + regd); + + if (ret == false) + return ret; + + if (chan_config->chan_width == IEEE80211_CHAN_WIDTH_80P80MHZ) { + ret = reg_fits_reg_rule_sec_chans(wiphy, + chan_config->center_freq2, + desired_bw_khz, + regd); + } + return ret; +} + static bool is_ht40_not_allowed(struct ieee80211_channel *chan) { if (!chan)