Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (C) 2017 Rafał Miłecki <rafal@milecki.pl>
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include <linux/of.h>
0018 #include <net/cfg80211.h>
0019 #include "core.h"
0020 
0021 static bool wiphy_freq_limits_valid_chan(struct wiphy *wiphy,
0022                      struct ieee80211_freq_range *freq_limits,
0023                      unsigned int n_freq_limits,
0024                      struct ieee80211_channel *chan)
0025 {
0026     u32 bw = MHZ_TO_KHZ(20);
0027     int i;
0028 
0029     for (i = 0; i < n_freq_limits; i++) {
0030         struct ieee80211_freq_range *limit = &freq_limits[i];
0031 
0032         if (cfg80211_does_bw_fit_range(limit,
0033                            MHZ_TO_KHZ(chan->center_freq),
0034                            bw))
0035             return true;
0036     }
0037 
0038     return false;
0039 }
0040 
0041 static void wiphy_freq_limits_apply(struct wiphy *wiphy,
0042                     struct ieee80211_freq_range *freq_limits,
0043                     unsigned int n_freq_limits)
0044 {
0045     enum nl80211_band band;
0046     int i;
0047 
0048     if (WARN_ON(!n_freq_limits))
0049         return;
0050 
0051     for (band = 0; band < NUM_NL80211_BANDS; band++) {
0052         struct ieee80211_supported_band *sband = wiphy->bands[band];
0053 
0054         if (!sband)
0055             continue;
0056 
0057         for (i = 0; i < sband->n_channels; i++) {
0058             struct ieee80211_channel *chan = &sband->channels[i];
0059 
0060             if (chan->flags & IEEE80211_CHAN_DISABLED)
0061                 continue;
0062 
0063             if (!wiphy_freq_limits_valid_chan(wiphy, freq_limits,
0064                               n_freq_limits,
0065                               chan)) {
0066                 pr_debug("Disabling freq %d MHz as it's out of OF limits\n",
0067                      chan->center_freq);
0068                 chan->flags |= IEEE80211_CHAN_DISABLED;
0069             }
0070         }
0071     }
0072 }
0073 
0074 void wiphy_read_of_freq_limits(struct wiphy *wiphy)
0075 {
0076     struct device *dev = wiphy_dev(wiphy);
0077     struct device_node *np;
0078     struct property *prop;
0079     struct ieee80211_freq_range *freq_limits;
0080     unsigned int n_freq_limits;
0081     const __be32 *p;
0082     int len, i;
0083     int err = 0;
0084 
0085     if (!dev)
0086         return;
0087     np = dev_of_node(dev);
0088     if (!np)
0089         return;
0090 
0091     prop = of_find_property(np, "ieee80211-freq-limit", &len);
0092     if (!prop)
0093         return;
0094 
0095     if (!len || len % sizeof(u32) || len / sizeof(u32) % 2) {
0096         dev_err(dev, "ieee80211-freq-limit wrong format");
0097         return;
0098     }
0099     n_freq_limits = len / sizeof(u32) / 2;
0100 
0101     freq_limits = kcalloc(n_freq_limits, sizeof(*freq_limits), GFP_KERNEL);
0102     if (!freq_limits) {
0103         err = -ENOMEM;
0104         goto out_kfree;
0105     }
0106 
0107     p = NULL;
0108     for (i = 0; i < n_freq_limits; i++) {
0109         struct ieee80211_freq_range *limit = &freq_limits[i];
0110 
0111         p = of_prop_next_u32(prop, p, &limit->start_freq_khz);
0112         if (!p) {
0113             err = -EINVAL;
0114             goto out_kfree;
0115         }
0116 
0117         p = of_prop_next_u32(prop, p, &limit->end_freq_khz);
0118         if (!p) {
0119             err = -EINVAL;
0120             goto out_kfree;
0121         }
0122 
0123         if (!limit->start_freq_khz ||
0124             !limit->end_freq_khz ||
0125             limit->start_freq_khz >= limit->end_freq_khz) {
0126             err = -EINVAL;
0127             goto out_kfree;
0128         }
0129     }
0130 
0131     wiphy_freq_limits_apply(wiphy, freq_limits, n_freq_limits);
0132 
0133 out_kfree:
0134     kfree(freq_limits);
0135     if (err)
0136         dev_err(dev, "Failed to get limits: %d\n", err);
0137 }
0138 EXPORT_SYMBOL(wiphy_read_of_freq_limits);