1 // SPDX-License-Identifier: ISC 2 /* 3 * Copyright (C) 2017 Rafał Miłecki <rafal@milecki.pl> 4 */ 5 6 #include <linux/of.h> 7 #include <net/cfg80211.h> 8 #include "core.h" 9 10 static 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 30 static 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 63 void 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 122 out_kfree: 123 kfree(freq_limits); 124 if (err) 125 dev_err(dev, "Failed to get limits: %d\n", err); 126 } 127 EXPORT_SYMBOL(wiphy_read_of_freq_limits); 128