diff options
author | Johannes Berg <johannes.berg@intel.com> | 2015-10-15 07:05:55 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2015-10-16 03:15:44 -0400 |
commit | d34265a3eebe994b3b9a0e4cabbc2dbb8436388b (patch) | |
tree | c185e722bdda0c7ea9abfdaecb7c1d1e42ab6e2c /net/wireless | |
parent | 480908a7ec5f2d37d5610b7d9bc48a38f2093876 (diff) |
cfg80211: reg: centralize freeing ignored requests
Instead of having a lot of places that free ignored requests
and then return REG_REQ_OK, make reg_process_hint() process
REG_REQ_IGNORE by freeing the request, and let functions it
calls return that instead of freeing.
This also fixes a leak when a second (different) country IE
hint was ignored.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/reg.c | 64 |
1 files changed, 35 insertions, 29 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index a95fc3abb8e1..5775f2fda31f 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -273,6 +273,9 @@ MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); | |||
273 | 273 | ||
274 | static void reg_free_request(struct regulatory_request *request) | 274 | static void reg_free_request(struct regulatory_request *request) |
275 | { | 275 | { |
276 | if (request == &core_request_world) | ||
277 | return; | ||
278 | |||
276 | if (request != get_last_request()) | 279 | if (request != get_last_request()) |
277 | kfree(request); | 280 | kfree(request); |
278 | } | 281 | } |
@@ -1905,13 +1908,17 @@ static void reg_set_request_processed(void) | |||
1905 | * The wireless subsystem can use this function to process | 1908 | * The wireless subsystem can use this function to process |
1906 | * a regulatory request issued by the regulatory core. | 1909 | * a regulatory request issued by the regulatory core. |
1907 | */ | 1910 | */ |
1908 | static void reg_process_hint_core(struct regulatory_request *core_request) | 1911 | static enum reg_request_treatment |
1912 | reg_process_hint_core(struct regulatory_request *core_request) | ||
1909 | { | 1913 | { |
1910 | if (reg_query_database(core_request)) { | 1914 | if (reg_query_database(core_request)) { |
1911 | core_request->intersect = false; | 1915 | core_request->intersect = false; |
1912 | core_request->processed = false; | 1916 | core_request->processed = false; |
1913 | reg_update_last_request(core_request); | 1917 | reg_update_last_request(core_request); |
1918 | return REG_REQ_OK; | ||
1914 | } | 1919 | } |
1920 | |||
1921 | return REG_REQ_IGNORE; | ||
1915 | } | 1922 | } |
1916 | 1923 | ||
1917 | static enum reg_request_treatment | 1924 | static enum reg_request_treatment |
@@ -1957,16 +1964,15 @@ __reg_process_hint_user(struct regulatory_request *user_request) | |||
1957 | * The wireless subsystem can use this function to process | 1964 | * The wireless subsystem can use this function to process |
1958 | * a regulatory request initiated by userspace. | 1965 | * a regulatory request initiated by userspace. |
1959 | */ | 1966 | */ |
1960 | static void reg_process_hint_user(struct regulatory_request *user_request) | 1967 | static enum reg_request_treatment |
1968 | reg_process_hint_user(struct regulatory_request *user_request) | ||
1961 | { | 1969 | { |
1962 | enum reg_request_treatment treatment; | 1970 | enum reg_request_treatment treatment; |
1963 | 1971 | ||
1964 | treatment = __reg_process_hint_user(user_request); | 1972 | treatment = __reg_process_hint_user(user_request); |
1965 | if (treatment == REG_REQ_IGNORE || | 1973 | if (treatment == REG_REQ_IGNORE || |
1966 | treatment == REG_REQ_ALREADY_SET) { | 1974 | treatment == REG_REQ_ALREADY_SET) |
1967 | reg_free_request(user_request); | 1975 | return REG_REQ_IGNORE; |
1968 | return; | ||
1969 | } | ||
1970 | 1976 | ||
1971 | user_request->intersect = treatment == REG_REQ_INTERSECT; | 1977 | user_request->intersect = treatment == REG_REQ_INTERSECT; |
1972 | user_request->processed = false; | 1978 | user_request->processed = false; |
@@ -1975,9 +1981,10 @@ static void reg_process_hint_user(struct regulatory_request *user_request) | |||
1975 | reg_update_last_request(user_request); | 1981 | reg_update_last_request(user_request); |
1976 | user_alpha2[0] = user_request->alpha2[0]; | 1982 | user_alpha2[0] = user_request->alpha2[0]; |
1977 | user_alpha2[1] = user_request->alpha2[1]; | 1983 | user_alpha2[1] = user_request->alpha2[1]; |
1978 | } else { | 1984 | return REG_REQ_OK; |
1979 | reg_free_request(user_request); | ||
1980 | } | 1985 | } |
1986 | |||
1987 | return REG_REQ_IGNORE; | ||
1981 | } | 1988 | } |
1982 | 1989 | ||
1983 | static enum reg_request_treatment | 1990 | static enum reg_request_treatment |
@@ -2025,15 +2032,12 @@ reg_process_hint_driver(struct wiphy *wiphy, | |||
2025 | case REG_REQ_OK: | 2032 | case REG_REQ_OK: |
2026 | break; | 2033 | break; |
2027 | case REG_REQ_IGNORE: | 2034 | case REG_REQ_IGNORE: |
2028 | reg_free_request(driver_request); | 2035 | return REG_REQ_IGNORE; |
2029 | return REG_REQ_OK; | ||
2030 | case REG_REQ_INTERSECT: | 2036 | case REG_REQ_INTERSECT: |
2031 | case REG_REQ_ALREADY_SET: | 2037 | case REG_REQ_ALREADY_SET: |
2032 | regd = reg_copy_regd(get_cfg80211_regdom()); | 2038 | regd = reg_copy_regd(get_cfg80211_regdom()); |
2033 | if (IS_ERR(regd)) { | 2039 | if (IS_ERR(regd)) |
2034 | reg_free_request(driver_request); | 2040 | return REG_REQ_IGNORE; |
2035 | return REG_REQ_OK; | ||
2036 | } | ||
2037 | 2041 | ||
2038 | tmp = get_wiphy_regdom(wiphy); | 2042 | tmp = get_wiphy_regdom(wiphy); |
2039 | rcu_assign_pointer(wiphy->regd, regd); | 2043 | rcu_assign_pointer(wiphy->regd, regd); |
@@ -2056,12 +2060,12 @@ reg_process_hint_driver(struct wiphy *wiphy, | |||
2056 | return REG_REQ_ALREADY_SET; | 2060 | return REG_REQ_ALREADY_SET; |
2057 | } | 2061 | } |
2058 | 2062 | ||
2059 | if (reg_query_database(driver_request)) | 2063 | if (reg_query_database(driver_request)) { |
2060 | reg_update_last_request(driver_request); | 2064 | reg_update_last_request(driver_request); |
2061 | else | 2065 | return REG_REQ_OK; |
2062 | reg_free_request(driver_request); | 2066 | } |
2063 | 2067 | ||
2064 | return REG_REQ_OK; | 2068 | return REG_REQ_IGNORE; |
2065 | } | 2069 | } |
2066 | 2070 | ||
2067 | static enum reg_request_treatment | 2071 | static enum reg_request_treatment |
@@ -2127,29 +2131,28 @@ reg_process_hint_country_ie(struct wiphy *wiphy, | |||
2127 | case REG_REQ_OK: | 2131 | case REG_REQ_OK: |
2128 | break; | 2132 | break; |
2129 | case REG_REQ_IGNORE: | 2133 | case REG_REQ_IGNORE: |
2130 | return REG_REQ_OK; | 2134 | return REG_REQ_IGNORE; |
2131 | case REG_REQ_ALREADY_SET: | 2135 | case REG_REQ_ALREADY_SET: |
2132 | reg_free_request(country_ie_request); | 2136 | reg_free_request(country_ie_request); |
2133 | return REG_REQ_ALREADY_SET; | 2137 | return REG_REQ_ALREADY_SET; |
2134 | case REG_REQ_INTERSECT: | 2138 | case REG_REQ_INTERSECT: |
2135 | reg_free_request(country_ie_request); | ||
2136 | /* | 2139 | /* |
2137 | * This doesn't happen yet, not sure we | 2140 | * This doesn't happen yet, not sure we |
2138 | * ever want to support it for this case. | 2141 | * ever want to support it for this case. |
2139 | */ | 2142 | */ |
2140 | WARN_ONCE(1, "Unexpected intersection for country IEs"); | 2143 | WARN_ONCE(1, "Unexpected intersection for country IEs"); |
2141 | return REG_REQ_OK; | 2144 | return REG_REQ_IGNORE; |
2142 | } | 2145 | } |
2143 | 2146 | ||
2144 | country_ie_request->intersect = false; | 2147 | country_ie_request->intersect = false; |
2145 | country_ie_request->processed = false; | 2148 | country_ie_request->processed = false; |
2146 | 2149 | ||
2147 | if (reg_query_database(country_ie_request)) | 2150 | if (reg_query_database(country_ie_request)) { |
2148 | reg_update_last_request(country_ie_request); | 2151 | reg_update_last_request(country_ie_request); |
2149 | else | 2152 | return REG_REQ_OK; |
2150 | reg_free_request(country_ie_request); | 2153 | } |
2151 | 2154 | ||
2152 | return REG_REQ_OK; | 2155 | return REG_REQ_IGNORE; |
2153 | } | 2156 | } |
2154 | 2157 | ||
2155 | /* This processes *all* regulatory hints */ | 2158 | /* This processes *all* regulatory hints */ |
@@ -2163,11 +2166,11 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
2163 | 2166 | ||
2164 | switch (reg_request->initiator) { | 2167 | switch (reg_request->initiator) { |
2165 | case NL80211_REGDOM_SET_BY_CORE: | 2168 | case NL80211_REGDOM_SET_BY_CORE: |
2166 | reg_process_hint_core(reg_request); | 2169 | treatment = reg_process_hint_core(reg_request); |
2167 | return; | 2170 | break; |
2168 | case NL80211_REGDOM_SET_BY_USER: | 2171 | case NL80211_REGDOM_SET_BY_USER: |
2169 | reg_process_hint_user(reg_request); | 2172 | treatment = reg_process_hint_user(reg_request); |
2170 | return; | 2173 | break; |
2171 | case NL80211_REGDOM_SET_BY_DRIVER: | 2174 | case NL80211_REGDOM_SET_BY_DRIVER: |
2172 | if (!wiphy) | 2175 | if (!wiphy) |
2173 | goto out_free; | 2176 | goto out_free; |
@@ -2183,6 +2186,9 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
2183 | goto out_free; | 2186 | goto out_free; |
2184 | } | 2187 | } |
2185 | 2188 | ||
2189 | if (treatment == REG_REQ_IGNORE) | ||
2190 | goto out_free; | ||
2191 | |||
2186 | WARN(treatment != REG_REQ_OK && treatment != REG_REQ_ALREADY_SET, | 2192 | WARN(treatment != REG_REQ_OK && treatment != REG_REQ_ALREADY_SET, |
2187 | "unexpected treatment value %d\n", treatment); | 2193 | "unexpected treatment value %d\n", treatment); |
2188 | 2194 | ||