diff options
-rw-r--r-- | net/wireless/reg.c | 201 |
1 files changed, 68 insertions, 133 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 7188ef9f07b6..aef39243595a 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1322,62 +1322,6 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, } EXPORT_SYMBOL(wiphy_apply_custom_regulatory); -/* This has the logic which determines when a new request - * should be ignored. */ -static enum reg_request_treatment -get_reg_request_treatment(struct wiphy *wiphy, - struct regulatory_request *pending_request) -{ - struct wiphy *last_wiphy = NULL; - struct regulatory_request *lr = get_last_request(); - - /* All initial requests are respected */ - if (!lr) - return REG_REQ_OK; - - switch (pending_request->initiator) { - case NL80211_REGDOM_SET_BY_CORE: - case NL80211_REGDOM_SET_BY_USER: - case NL80211_REGDOM_SET_BY_DRIVER: - return REG_REQ_IGNORE; - case NL80211_REGDOM_SET_BY_COUNTRY_IE: - if (reg_request_cell_base(lr)) { - /* Trust a Cell base station over the AP's country IE */ - if (regdom_changes(pending_request->alpha2)) - return REG_REQ_IGNORE; - return REG_REQ_ALREADY_SET; - } - - last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); - - if (unlikely(!is_an_alpha2(pending_request->alpha2))) - return -EINVAL; - if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { - if (last_wiphy != wiphy) { - /* - * Two cards with two APs claiming different - * Country IE alpha2s. We could - * intersect them, but that seems unlikely - * to be correct. Reject second one for now. - */ - if (regdom_changes(pending_request->alpha2)) - return REG_REQ_IGNORE; - return REG_REQ_ALREADY_SET; - } - /* - * Two consecutive Country IE hints on the same wiphy. - * This should be picked up early by the driver/stack - */ - if (WARN_ON(regdom_changes(pending_request->alpha2))) - return REG_REQ_OK; - return REG_REQ_ALREADY_SET; - } - return REG_REQ_OK; - } - - return REG_REQ_IGNORE; -} - static void reg_set_request_processed(void) { bool need_more_processing = false; @@ -1581,96 +1525,92 @@ reg_process_hint_driver(struct wiphy *wiphy, return REG_REQ_OK; } +static enum reg_request_treatment +__reg_process_hint_country_ie(struct wiphy *wiphy, + struct regulatory_request *country_ie_request) +{ + struct wiphy *last_wiphy = NULL; + struct regulatory_request *lr = get_last_request(); + + if (reg_request_cell_base(lr)) { + /* Trust a Cell base station over the AP's country IE */ + if (regdom_changes(country_ie_request->alpha2)) + return REG_REQ_IGNORE; + return REG_REQ_ALREADY_SET; + } + + last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); + + if (unlikely(!is_an_alpha2(country_ie_request->alpha2))) + return -EINVAL; + if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { + if (last_wiphy != wiphy) { + /* + * Two cards with two APs claiming different + * Country IE alpha2s. We could + * intersect them, but that seems unlikely + * to be correct. Reject second one for now. + */ + if (regdom_changes(country_ie_request->alpha2)) + return REG_REQ_IGNORE; + return REG_REQ_ALREADY_SET; + } + /* + * Two consecutive Country IE hints on the same wiphy. + * This should be picked up early by the driver/stack + */ + if (WARN_ON(regdom_changes(country_ie_request->alpha2))) + return REG_REQ_OK; + return REG_REQ_ALREADY_SET; + } + return REG_REQ_OK; +} + /** - * __regulatory_hint - hint to the wireless core a regulatory domain - * @wiphy: if the hint comes from country information from an AP, this - * is required to be set to the wiphy that received the information - * @pending_request: the regulatory request currently being processed + * reg_process_hint_country_ie - process regulatory requests from country IEs + * @country_ie_request: a regulatory request from a country IE * - * The Wireless subsystem can use this function to hint to the wireless core - * what it believes should be the current regulatory domain. + * The wireless subsystem can use this function to process + * a regulatory request issued by a country Information Element. * * Returns one of the different reg request treatment values. */ static enum reg_request_treatment -__regulatory_hint(struct wiphy *wiphy, - struct regulatory_request *pending_request) +reg_process_hint_country_ie(struct wiphy *wiphy, + struct regulatory_request *country_ie_request) { - const struct ieee80211_regdomain *regd; - bool intersect = false; enum reg_request_treatment treatment; struct regulatory_request *lr; - treatment = get_reg_request_treatment(wiphy, pending_request); + treatment = __reg_process_hint_country_ie(wiphy, country_ie_request); switch (treatment) { - case REG_REQ_INTERSECT: - if (pending_request->initiator == - NL80211_REGDOM_SET_BY_DRIVER) { - regd = reg_copy_regd(get_cfg80211_regdom()); - if (IS_ERR(regd)) { - kfree(pending_request); - return PTR_ERR(regd); - } - rcu_assign_pointer(wiphy->regd, regd); - } - intersect = true; - break; case REG_REQ_OK: break; - default: + case REG_REQ_IGNORE: + /* fall through */ + case REG_REQ_ALREADY_SET: + kfree(country_ie_request); + return treatment; + case REG_REQ_INTERSECT: + kfree(country_ie_request); /* - * If the regulatory domain being requested by the - * driver has already been set just copy it to the - * wiphy + * This doesn't happen yet, not sure we + * ever want to support it for this case. */ - if (treatment == REG_REQ_ALREADY_SET && - pending_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) { - regd = reg_copy_regd(get_cfg80211_regdom()); - if (IS_ERR(regd)) { - kfree(pending_request); - return REG_REQ_IGNORE; - } - treatment = REG_REQ_ALREADY_SET; - rcu_assign_pointer(wiphy->regd, regd); - goto new_request; - } - kfree(pending_request); - return treatment; + WARN_ONCE(1, "Unexpected intersection for country IEs"); + return REG_REQ_IGNORE; } -new_request: lr = get_last_request(); if (lr != &core_request_world && lr) kfree_rcu(lr, rcu_head); - pending_request->intersect = intersect; - pending_request->processed = false; - rcu_assign_pointer(last_request, pending_request); - lr = pending_request; - - pending_request = NULL; + country_ie_request->intersect = false; + country_ie_request->processed = false; + rcu_assign_pointer(last_request, country_ie_request); - if (lr->initiator == NL80211_REGDOM_SET_BY_USER) { - user_alpha2[0] = lr->alpha2[0]; - user_alpha2[1] = lr->alpha2[1]; - } - - /* When r == REG_REQ_INTERSECT we do need to call CRDA */ - if (treatment != REG_REQ_OK && treatment != REG_REQ_INTERSECT) { - /* - * Since CRDA will not be called in this case as we already - * have applied the requested regulatory domain before we just - * inform userspace we have processed the request - */ - if (treatment == REG_REQ_ALREADY_SET) { - nl80211_send_reg_change_event(lr); - reg_set_request_processed(); - } - return treatment; - } - - if (call_crda(lr->alpha2)) + if (call_crda(country_ie_request->alpha2)) return REG_REQ_IGNORE; return REG_REQ_OK; } @@ -1707,22 +1647,17 @@ static void reg_process_hint(struct regulatory_request *reg_request) treatment = reg_process_hint_driver(wiphy, reg_request); break; case NL80211_REGDOM_SET_BY_COUNTRY_IE: - treatment = __regulatory_hint(wiphy, reg_request); + treatment = reg_process_hint_country_ie(wiphy, reg_request); break; default: WARN(1, "invalid initiator %d\n", reg_request->initiator); return; } - switch (treatment) { - case REG_REQ_ALREADY_SET: - /* This is required so that the orig_* parameters are saved */ - if (wiphy && wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) - wiphy_update_regulatory(wiphy, reg_request->initiator); - break; - default: - break; - } + /* This is required so that the orig_* parameters are saved */ + if (treatment == REG_REQ_ALREADY_SET && wiphy && + wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) + wiphy_update_regulatory(wiphy, reg_request->initiator); } /* |