diff options
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r-- | net/wireless/reg.c | 81 |
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 */ | ||
803 | static 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 */ | ||
830 | static 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 = ®_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(®_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, |