projects/linux·blob master · refs

127 lines · 2.7 KiB

1// SPDX-License-Identifier: ISC
2/*
3 * Copyright (C) 2017 Rafał Miłecki <[email protected]>
4 */
5
6#include <linux/of.h>
7#include <net/cfg80211.h>
8#include "core.h"
9
10static bool wiphy_freq_limits_valid_chan(struct wiphy *wiphy,
11 struct ieee80211_freq_range *freq_limits,
12 unsigned int n_freq_limits,
13 struct ieee80211_channel *chan)
14{
15 u32 bw = MHZ_TO_KHZ(20);
16 int i;
17
18 for (i = 0; i < n_freq_limits; i++) {
19 struct ieee80211_freq_range *limit = &freq_limits[i];
20
21 if (cfg80211_does_bw_fit_range(limit,
22 MHZ_TO_KHZ(chan->center_freq),
23 bw))
24 return true;
25 }
26
27 return false;
28}
29
30static void wiphy_freq_limits_apply(struct wiphy *wiphy,
31 struct ieee80211_freq_range *freq_limits,
32 unsigned int n_freq_limits)
33{
34 enum nl80211_band band;
35 int i;
36
37 if (WARN_ON(!n_freq_limits))
38 return;
39
40 for (band = 0; band < NUM_NL80211_BANDS; band++) {
41 struct ieee80211_supported_band *sband = wiphy->bands[band];
42
43 if (!sband)
44 continue;
45
46 for (i = 0; i < sband->n_channels; i++) {
47 struct ieee80211_channel *chan = &sband->channels[i];
48
49 if (chan->flags & IEEE80211_CHAN_DISABLED)
50 continue;
51
52 if (!wiphy_freq_limits_valid_chan(wiphy, freq_limits,
53 n_freq_limits,
54 chan)) {
55 pr_debug("Disabling freq %d MHz as it's out of OF limits\n",
56 chan->center_freq);
57 chan->flags |= IEEE80211_CHAN_DISABLED;
58 }
59 }
60 }
61}
62
63void wiphy_read_of_freq_limits(struct wiphy *wiphy)
64{
65 struct device *dev = wiphy_dev(wiphy);
66 struct device_node *np;
67 struct property *prop;
68 struct ieee80211_freq_range *freq_limits;
69 unsigned int n_freq_limits;
70 const __be32 *p;
71 int len, i;
72 int err = 0;
73
74 if (!dev)
75 return;
76 np = dev_of_node(dev);
77 if (!np)
78 return;
79
80 prop = of_find_property(np, "ieee80211-freq-limit", &len);
81 if (!prop)
82 return;
83
84 if (!len || len % sizeof(u32) || len / sizeof(u32) % 2) {
85 dev_err(dev, "ieee80211-freq-limit wrong format");
86 return;
87 }
88 n_freq_limits = len / sizeof(u32) / 2;
89
90 freq_limits = kzalloc_objs(*freq_limits, n_freq_limits);
91 if (!freq_limits) {
92 err = -ENOMEM;
93 goto out_kfree;
94 }
95
96 p = NULL;
97 for (i = 0; i < n_freq_limits; i++) {
98 struct ieee80211_freq_range *limit = &freq_limits[i];
99
100 p = of_prop_next_u32(prop, p, &limit->start_freq_khz);
101 if (!p) {
102 err = -EINVAL;
103 goto out_kfree;
104 }
105
106 p = of_prop_next_u32(prop, p, &limit->end_freq_khz);
107 if (!p) {
108 err = -EINVAL;
109 goto out_kfree;
110 }
111
112 if (!limit->start_freq_khz ||
113 !limit->end_freq_khz ||
114 limit->start_freq_khz >= limit->end_freq_khz) {
115 err = -EINVAL;
116 goto out_kfree;
117 }
118 }
119
120 wiphy_freq_limits_apply(wiphy, freq_limits, n_freq_limits);
121
122out_kfree:
123 kfree(freq_limits);
124 if (err)
125 dev_err(dev, "Failed to get limits: %d\n", err);
126}
127EXPORT_SYMBOL(wiphy_read_of_freq_limits);