| @@ -65,11 +65,26 @@ · 64 unmodified lines |
| 65 | #define REG_DBG_PRINT(args...) | 65 | #define REG_DBG_PRINT(args...) |
| 66 | #endif | 66 | #endif |
| 67 | | 67 | |
| | 68 | /** |
| | 69 | * enum reg_request_treatment - regulatory request treatment |
| | 70 | * |
| | 71 | * @REG_REQ_OK: continue processing the regulatory request |
| | 72 | * @REG_REQ_IGNORE: ignore the regulatory request |
| | 73 | * @REG_REQ_INTERSECT: the regulatory domain resulting from this request should |
| | 74 | * be intersected with the current one. |
| | 75 | * @REG_REQ_ALREADY_SET: the regulatory request will not change the current |
| | 76 | * regulatory settings, and no further processing is required. |
| | 77 | * @REG_REQ_USER_HINT_HANDLED: a non alpha2 user hint was handled and no |
| | 78 | * further processing is required, i.e., not need to update last_request |
| | 79 | * etc. This should be used for user hints that do not provide an alpha2 |
| | 80 | * but some other type of regulatory hint, i.e., indoor operation. |
| | 81 | */ |
| 68 | enum reg_request_treatment { | 82 | enum reg_request_treatment { |
| 69 | REG_REQ_OK, | 83 | REG_REQ_OK, |
| 70 | REG_REQ_IGNORE, | 84 | REG_REQ_IGNORE, |
| 71 | REG_REQ_INTERSECT, | 85 | REG_REQ_INTERSECT, |
| 72 | REG_REQ_ALREADY_SET, | 86 | REG_REQ_ALREADY_SET, |
| | 87 | REG_REQ_USER_HINT_HANDLED, |
| 73 | }; | 88 | }; |
| 74 | | 89 | |
| 75 | static struct regulatory_request core_request_world = { | 90 | static struct regulatory_request core_request_world = { |
| @@ -106,6 +121,14 @@ const struct ieee80211_regdomain __rcu *cfg80211_regdomain; · 30 unmodified lines |
| 106 | */ | 121 | */ |
| 107 | static int reg_num_devs_support_basehint; | 122 | static int reg_num_devs_support_basehint; |
| 108 | | 123 | |
| | 124 | /* |
| | 125 | * State variable indicating if the platform on which the devices |
| | 126 | * are attached is operating in an indoor environment. The state variable |
| | 127 | * is relevant for all registered devices. |
| | 128 | * (protected by RTNL) |
| | 129 | */ |
| | 130 | static bool reg_is_indoor; |
| | 131 | |
| 109 | static const struct ieee80211_regdomain *get_cfg80211_regdom(void) | 132 | static const struct ieee80211_regdomain *get_cfg80211_regdom(void) |
| 110 | { | 133 | { |
| 111 | return rtnl_dereference(cfg80211_regdomain); | 134 | return rtnl_dereference(cfg80211_regdomain); |
| @@ -1128,6 +1151,13 @@ static bool reg_request_cell_base(struct regulatory_request *request) · 1016 unmodified lines |
| 1128 | return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE; | 1151 | return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE; |
| 1129 | } | 1152 | } |
| 1130 | | 1153 | |
| | 1154 | static bool reg_request_indoor(struct regulatory_request *request) |
| | 1155 | { |
| | 1156 | if (request->initiator != NL80211_REGDOM_SET_BY_USER) |
| | 1157 | return false; |
| | 1158 | return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR; |
| | 1159 | } |
| | 1160 | |
| 1131 | bool reg_last_request_cell_base(void) | 1161 | bool reg_last_request_cell_base(void) |
| 1132 | { | 1162 | { |
| 1133 | return reg_request_cell_base(get_last_request()); | 1163 | return reg_request_cell_base(get_last_request()); |
| @@ -1570,6 +1600,11 @@ __reg_process_hint_user(struct regulatory_request *user_request) · 436 unmodified lines |
| 1570 | { | 1600 | { |
| 1571 | struct regulatory_request *lr = get_last_request(); | 1601 | struct regulatory_request *lr = get_last_request(); |
| 1572 | | 1602 | |
| | 1603 | if (reg_request_indoor(user_request)) { |
| | 1604 | reg_is_indoor = true; |
| | 1605 | return REG_REQ_USER_HINT_HANDLED; |
| | 1606 | } |
| | 1607 | |
| 1573 | if (reg_request_cell_base(user_request)) | 1608 | if (reg_request_cell_base(user_request)) |
| 1574 | return reg_ignore_cell_hint(user_request); | 1609 | return reg_ignore_cell_hint(user_request); |
| 1575 | | 1610 | |
| @@ -1617,7 +1652,8 @@ reg_process_hint_user(struct regulatory_request *user_request) · 41 unmodified lines |
| 1617 | | 1652 | |
| 1618 | treatment = __reg_process_hint_user(user_request); | 1653 | treatment = __reg_process_hint_user(user_request); |
| 1619 | if (treatment == REG_REQ_IGNORE || | 1654 | if (treatment == REG_REQ_IGNORE || |
| 1620 | treatment == REG_REQ_ALREADY_SET) { | 1655 | treatment == REG_REQ_ALREADY_SET || |
| | 1656 | treatment == REG_REQ_USER_HINT_HANDLED) { |
| 1621 | kfree(user_request); | 1657 | kfree(user_request); |
| 1622 | return treatment; | 1658 | return treatment; |
| 1623 | } | 1659 | } |
| @@ -1678,6 +1714,7 @@ reg_process_hint_driver(struct wiphy *wiphy, · 54 unmodified lines |
| 1678 | case REG_REQ_OK: | 1714 | case REG_REQ_OK: |
| 1679 | break; | 1715 | break; |
| 1680 | case REG_REQ_IGNORE: | 1716 | case REG_REQ_IGNORE: |
| | 1717 | case REG_REQ_USER_HINT_HANDLED: |
| 1681 | kfree(driver_request); | 1718 | kfree(driver_request); |
| 1682 | return treatment; | 1719 | return treatment; |
| 1683 | case REG_REQ_INTERSECT: | 1720 | case REG_REQ_INTERSECT: |
| @@ -1777,6 +1814,7 @@ reg_process_hint_country_ie(struct wiphy *wiphy, · 93 unmodified lines |
| 1777 | case REG_REQ_OK: | 1814 | case REG_REQ_OK: |
| 1778 | break; | 1815 | break; |
| 1779 | case REG_REQ_IGNORE: | 1816 | case REG_REQ_IGNORE: |
| | 1817 | case REG_REQ_USER_HINT_HANDLED: |
| 1780 | /* fall through */ | 1818 | /* fall through */ |
| 1781 | case REG_REQ_ALREADY_SET: | 1819 | case REG_REQ_ALREADY_SET: |
| 1782 | kfree(country_ie_request); | 1820 | kfree(country_ie_request); |
| @@ -1969,6 +2007,22 @@ int regulatory_hint_user(const char *alpha2, · 186 unmodified lines |
| 1969 | return 0; | 2007 | return 0; |
| 1970 | } | 2008 | } |
| 1971 | | 2009 | |
| | 2010 | int regulatory_hint_indoor_user(void) |
| | 2011 | { |
| | 2012 | struct regulatory_request *request; |
| | 2013 | |
| | 2014 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); |
| | 2015 | if (!request) |
| | 2016 | return -ENOMEM; |
| | 2017 | |
| | 2018 | request->wiphy_idx = WIPHY_IDX_INVALID; |
| | 2019 | request->initiator = NL80211_REGDOM_SET_BY_USER; |
| | 2020 | request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR; |
| | 2021 | queue_regulatory_request(request); |
| | 2022 | |
| | 2023 | return 0; |
| | 2024 | } |
| | 2025 | |
| 1972 | /* Driver hints */ | 2026 | /* Driver hints */ |
| 1973 | int regulatory_hint(struct wiphy *wiphy, const char *alpha2) | 2027 | int regulatory_hint(struct wiphy *wiphy, const char *alpha2) |
| 1974 | { | 2028 | { |
| @@ -2136,6 +2190,8 @@ static void restore_regulatory_settings(bool reset_user) · 161 unmodified lines |
| 2136 | | 2190 | |
| 2137 | ASSERT_RTNL(); | 2191 | ASSERT_RTNL(); |
| 2138 | | 2192 | |
| | 2193 | reg_is_indoor = false; |
| | 2194 | |
| 2139 | reset_regdomains(true, &world_regdom); | 2195 | reset_regdomains(true, &world_regdom); |
| 2140 | restore_alpha2(alpha2, reset_user); | 2196 | restore_alpha2(alpha2, reset_user); |
| 2141 | | 2197 | |