aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
authorEliad Peller <eliad@wizery.com>2014-09-03 08:25:03 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-09-05 07:52:08 -0400
commita62a1aed3733d7ec6489adca4c2f69881d78cfd6 (patch)
tree7a071987136868eaa5020b7217ae66ed9c6894b8 /net/wireless/reg.c
parentcd2f5dd709daa8a70f9eb408025dbb1c804929a8 (diff)
cfg80211: avoid duplicate entries on regdomain intersection
The regdom intersection code simply tries intersecting each rule of the source with each rule of the target. Since the resulting intersections are not observed as a whole, this can result in multiple overlapping/duplicate entries. Make the rule addition a bit more smarter, by looking for rules that can be contained within other rules, and adding only extended ones. Signed-off-by: Eliad Peller <eliad@wizery.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r--net/wireless/reg.c81
1 files changed, 60 insertions, 21 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 8bfc9b172a49..b725a31a4751 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -799,6 +799,57 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
799 return 0; 799 return 0;
800} 800}
801 801
802/* check whether old rule contains new rule */
803static bool rule_contains(struct ieee80211_reg_rule *r1,
804 struct ieee80211_reg_rule *r2)
805{
806 /* for simplicity, currently consider only same flags */
807 if (r1->flags != r2->flags)
808 return false;
809
810 /* verify r1 is more restrictive */
811 if ((r1->power_rule.max_antenna_gain >
812 r2->power_rule.max_antenna_gain) ||
813 r1->power_rule.max_eirp > r2->power_rule.max_eirp)
814 return false;
815
816 /* make sure r2's range is contained within r1 */
817 if (r1->freq_range.start_freq_khz > r2->freq_range.start_freq_khz ||
818 r1->freq_range.end_freq_khz < r2->freq_range.end_freq_khz)
819 return false;
820
821 /* and finally verify that r1.max_bw >= r2.max_bw */
822 if (r1->freq_range.max_bandwidth_khz <
823 r2->freq_range.max_bandwidth_khz)
824 return false;
825
826 return true;
827}
828
829/* add or extend current rules. do nothing if rule is already contained */
830static void add_rule(struct ieee80211_reg_rule *rule,
831 struct ieee80211_reg_rule *reg_rules, u32 *n_rules)
832{
833 struct ieee80211_reg_rule *tmp_rule;
834 int i;
835
836 for (i = 0; i < *n_rules; i++) {
837 tmp_rule = &reg_rules[i];
838 /* rule is already contained - do nothing */
839 if (rule_contains(tmp_rule, rule))
840 return;
841
842 /* extend rule if possible */
843 if (rule_contains(rule, tmp_rule)) {
844 memcpy(tmp_rule, rule, sizeof(*rule));
845 return;
846 }
847 }
848
849 memcpy(&reg_rules[*n_rules], rule, sizeof(*rule));
850 (*n_rules)++;
851}
852
802/** 853/**
803 * regdom_intersect - do the intersection between two regulatory domains 854 * regdom_intersect - do the intersection between two regulatory domains
804 * @rd1: first regulatory domain 855 * @rd1: first regulatory domain
@@ -818,12 +869,10 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
818{ 869{
819 int r, size_of_regd; 870 int r, size_of_regd;
820 unsigned int x, y; 871 unsigned int x, y;
821 unsigned int num_rules = 0, rule_idx = 0; 872 unsigned int num_rules = 0;
822 const struct ieee80211_reg_rule *rule1, *rule2; 873 const struct ieee80211_reg_rule *rule1, *rule2;
823 struct ieee80211_reg_rule *intersected_rule; 874 struct ieee80211_reg_rule intersected_rule;
824 struct ieee80211_regdomain *rd; 875 struct ieee80211_regdomain *rd;
825 /* This is just a dummy holder to help us count */
826 struct ieee80211_reg_rule dummy_rule;
827 876
828 if (!rd1 || !rd2) 877 if (!rd1 || !rd2)
829 return NULL; 878 return NULL;
@@ -841,7 +890,7 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
841 for (y = 0; y < rd2->n_reg_rules; y++) { 890 for (y = 0; y < rd2->n_reg_rules; y++) {
842 rule2 = &rd2->reg_rules[y]; 891 rule2 = &rd2->reg_rules[y];
843 if (!reg_rules_intersect(rd1, rd2, rule1, rule2, 892 if (!reg_rules_intersect(rd1, rd2, rule1, rule2,
844 &dummy_rule)) 893 &intersected_rule))
845 num_rules++; 894 num_rules++;
846 } 895 }
847 } 896 }
@@ -856,34 +905,24 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
856 if (!rd) 905 if (!rd)
857 return NULL; 906 return NULL;
858 907
859 for (x = 0; x < rd1->n_reg_rules && rule_idx < num_rules; x++) { 908 for (x = 0; x < rd1->n_reg_rules; x++) {
860 rule1 = &rd1->reg_rules[x]; 909 rule1 = &rd1->reg_rules[x];
861 for (y = 0; y < rd2->n_reg_rules && rule_idx < num_rules; y++) { 910 for (y = 0; y < rd2->n_reg_rules; y++) {
862 rule2 = &rd2->reg_rules[y]; 911 rule2 = &rd2->reg_rules[y];
863 /*
864 * This time around instead of using the stack lets
865 * write to the target rule directly saving ourselves
866 * a memcpy()
867 */
868 intersected_rule = &rd->reg_rules[rule_idx];
869 r = reg_rules_intersect(rd1, rd2, rule1, rule2, 912 r = reg_rules_intersect(rd1, rd2, rule1, rule2,
870 intersected_rule); 913 &intersected_rule);
871 /* 914 /*
872 * No need to memset here the intersected rule here as 915 * No need to memset here the intersected rule here as
873 * we're not using the stack anymore 916 * we're not using the stack anymore
874 */ 917 */
875 if (r) 918 if (r)
876 continue; 919 continue;
877 rule_idx++;
878 }
879 }
880 920
881 if (rule_idx != num_rules) { 921 add_rule(&intersected_rule, rd->reg_rules,
882 kfree(rd); 922 &rd->n_reg_rules);
883 return NULL; 923 }
884 } 924 }
885 925
886 rd->n_reg_rules = num_rules;
887 rd->alpha2[0] = '9'; 926 rd->alpha2[0] = '9';
888 rd->alpha2[1] = '8'; 927 rd->alpha2[1] = '8';
889 rd->dfs_region = reg_intersect_dfs_region(rd1->dfs_region, 928 rd->dfs_region = reg_intersect_dfs_region(rd1->dfs_region,