Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2017 Rafał Miłecki <rafal@milecki.pl>
3 : : *
4 : : * Permission to use, copy, modify, and/or distribute this software for any
5 : : * purpose with or without fee is hereby granted, provided that the above
6 : : * copyright notice and this permission notice appear in all copies.
7 : : *
8 : : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 : : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 : : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 : : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 : : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 : : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 : : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 : : */
16 : :
17 : : #include <linux/of.h>
18 : : #include <net/cfg80211.h>
19 : : #include "core.h"
20 : :
21 : 0 : static bool wiphy_freq_limits_valid_chan(struct wiphy *wiphy,
22 : : struct ieee80211_freq_range *freq_limits,
23 : : unsigned int n_freq_limits,
24 : : struct ieee80211_channel *chan)
25 : : {
26 : : u32 bw = MHZ_TO_KHZ(20);
27 : : int i;
28 : :
29 [ # # ]: 0 : for (i = 0; i < n_freq_limits; i++) {
30 : 0 : struct ieee80211_freq_range *limit = &freq_limits[i];
31 : :
32 [ # # ]: 0 : if (cfg80211_does_bw_fit_range(limit,
33 : 0 : MHZ_TO_KHZ(chan->center_freq),
34 : : bw))
35 : : return true;
36 : : }
37 : :
38 : : return false;
39 : : }
40 : :
41 : 0 : static void wiphy_freq_limits_apply(struct wiphy *wiphy,
42 : : struct ieee80211_freq_range *freq_limits,
43 : : unsigned int n_freq_limits)
44 : : {
45 : : enum nl80211_band band;
46 : : int i;
47 : :
48 [ # # # # ]: 0 : if (WARN_ON(!n_freq_limits))
49 : 0 : return;
50 : :
51 [ # # ]: 0 : for (band = 0; band < NUM_NL80211_BANDS; band++) {
52 : 0 : struct ieee80211_supported_band *sband = wiphy->bands[band];
53 : :
54 [ # # ]: 0 : if (!sband)
55 : 0 : continue;
56 : :
57 [ # # ]: 0 : for (i = 0; i < sband->n_channels; i++) {
58 : 0 : struct ieee80211_channel *chan = &sband->channels[i];
59 : :
60 [ # # ]: 0 : if (chan->flags & IEEE80211_CHAN_DISABLED)
61 : 0 : continue;
62 : :
63 [ # # ]: 0 : if (!wiphy_freq_limits_valid_chan(wiphy, freq_limits,
64 : : n_freq_limits,
65 : : chan)) {
66 : : pr_debug("Disabling freq %d MHz as it's out of OF limits\n",
67 : : chan->center_freq);
68 : 0 : chan->flags |= IEEE80211_CHAN_DISABLED;
69 : : }
70 : : }
71 : : }
72 : : }
73 : :
74 : 0 : void wiphy_read_of_freq_limits(struct wiphy *wiphy)
75 : : {
76 : : struct device *dev = wiphy_dev(wiphy);
77 : : struct device_node *np;
78 : : struct property *prop;
79 : : struct ieee80211_freq_range *freq_limits;
80 : : unsigned int n_freq_limits;
81 : : const __be32 *p;
82 : : int len, i;
83 : : int err = 0;
84 : :
85 [ # # ]: 0 : if (!dev)
86 : 0 : return;
87 : : np = dev_of_node(dev);
88 [ # # ]: 0 : if (!np)
89 : : return;
90 : :
91 : 0 : prop = of_find_property(np, "ieee80211-freq-limit", &len);
92 [ # # ]: 0 : if (!prop)
93 : : return;
94 : :
95 [ # # # # : 0 : if (!len || len % sizeof(u32) || len / sizeof(u32) % 2) {
# # ]
96 : 0 : dev_err(dev, "ieee80211-freq-limit wrong format");
97 : 0 : return;
98 : : }
99 : 0 : n_freq_limits = len / sizeof(u32) / 2;
100 : :
101 : : freq_limits = kcalloc(n_freq_limits, sizeof(*freq_limits), GFP_KERNEL);
102 [ # # ]: 0 : if (!freq_limits) {
103 : : err = -ENOMEM;
104 : : goto out_kfree;
105 : : }
106 : :
107 : : p = NULL;
108 [ # # ]: 0 : for (i = 0; i < n_freq_limits; i++) {
109 : 0 : struct ieee80211_freq_range *limit = &freq_limits[i];
110 : :
111 : 0 : p = of_prop_next_u32(prop, p, &limit->start_freq_khz);
112 [ # # ]: 0 : if (!p) {
113 : : err = -EINVAL;
114 : : goto out_kfree;
115 : : }
116 : :
117 : 0 : p = of_prop_next_u32(prop, p, &limit->end_freq_khz);
118 [ # # ]: 0 : if (!p) {
119 : : err = -EINVAL;
120 : : goto out_kfree;
121 : : }
122 : :
123 [ # # # # ]: 0 : if (!limit->start_freq_khz ||
124 [ # # ]: 0 : !limit->end_freq_khz ||
125 : : limit->start_freq_khz >= limit->end_freq_khz) {
126 : : err = -EINVAL;
127 : : goto out_kfree;
128 : : }
129 : : }
130 : :
131 : 0 : wiphy_freq_limits_apply(wiphy, freq_limits, n_freq_limits);
132 : :
133 : : out_kfree:
134 : 0 : kfree(freq_limits);
135 [ # # ]: 0 : if (err)
136 : 0 : dev_err(dev, "Failed to get limits: %d\n", err);
137 : : }
138 : : EXPORT_SYMBOL(wiphy_read_of_freq_limits);
|