| @@ -65,11 +65,26 @@ · 64 unmodified lines |
| 65 | 65 | #define REG_DBG_PRINT(args...) |
| 66 | 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 | 82 | enum reg_request_treatment { |
| 69 | 83 | REG_REQ_OK, |
| 70 | 84 | REG_REQ_IGNORE, |
| 71 | 85 | REG_REQ_INTERSECT, |
| 72 | 86 | REG_REQ_ALREADY_SET, |
| 87 | + REG_REQ_USER_HINT_HANDLED, |
| 73 | 88 | }; |
| 74 | 89 | |
| 75 | 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 | 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 | 132 | static const struct ieee80211_regdomain *get_cfg80211_regdom(void) |
| 110 | 133 | { |
| 111 | 134 | return rtnl_dereference(cfg80211_regdomain); |
| @@ -1128,6 +1151,13 @@ static bool reg_request_cell_base(struct regulatory_request *request) · 1016 unmodified lines |
| 1128 | 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 | 1161 | bool reg_last_request_cell_base(void) |
| 1132 | 1162 | { |
| 1133 | 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 | 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 | 1608 | if (reg_request_cell_base(user_request)) |
| 1574 | 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 | 1653 | treatment = __reg_process_hint_user(user_request); |
| 1619 | 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 | 1657 | kfree(user_request); |
| 1622 | 1658 | return treatment; |
| 1623 | 1659 | } |
| @@ -1678,6 +1714,7 @@ reg_process_hint_driver(struct wiphy *wiphy, · 54 unmodified lines |
| 1678 | 1714 | case REG_REQ_OK: |
| 1679 | 1715 | break; |
| 1680 | 1716 | case REG_REQ_IGNORE: |
| 1717 | + case REG_REQ_USER_HINT_HANDLED: |
| 1681 | 1718 | kfree(driver_request); |
| 1682 | 1719 | return treatment; |
| 1683 | 1720 | case REG_REQ_INTERSECT: |
| @@ -1777,6 +1814,7 @@ reg_process_hint_country_ie(struct wiphy *wiphy, · 93 unmodified lines |
| 1777 | 1814 | case REG_REQ_OK: |
| 1778 | 1815 | break; |
| 1779 | 1816 | case REG_REQ_IGNORE: |
| 1817 | + case REG_REQ_USER_HINT_HANDLED: |
| 1780 | 1818 | /* fall through */ |
| 1781 | 1819 | case REG_REQ_ALREADY_SET: |
| 1782 | 1820 | kfree(country_ie_request); |
| @@ -1969,6 +2007,22 @@ int regulatory_hint_user(const char *alpha2, · 186 unmodified lines |
| 1969 | 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 | 2026 | /* Driver hints */ |
| 1973 | 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 | 2191 | ASSERT_RTNL(); |
| 2138 | 2192 | |
| 2193 | + reg_is_indoor = false; |
| 2194 | + |
| 2139 | 2195 | reset_regdomains(true, &world_regdom); |
| 2140 | 2196 | restore_alpha2(alpha2, reset_user); |
| 2141 | 2197 | |