Loading include/uapi/linux/nl80211.h +3 −0 Original line number Diff line number Diff line Loading @@ -2602,10 +2602,13 @@ enum nl80211_dfs_regions { * present has been registered with the wireless core that * has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a * supported feature. * @NL80211_USER_REG_HINT_INDOOR: a user sent an hint indicating that the * platform is operating in an indoor environment. */ enum nl80211_user_reg_hint_type { NL80211_USER_REG_HINT_USER = 0, NL80211_USER_REG_HINT_CELL_BASE = 1, NL80211_USER_REG_HINT_INDOOR = 2, }; /** Loading net/wireless/nl80211.c +7 −11 Original line number Diff line number Diff line Loading @@ -4677,7 +4677,6 @@ static int parse_reg_rule(struct nlattr *tb[], static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) { int r; char *data = NULL; enum nl80211_user_reg_hint_type user_reg_hint_type; Loading @@ -4690,11 +4689,6 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) if (unlikely(!rcu_access_pointer(cfg80211_regdomain))) return -EINPROGRESS; if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) return -EINVAL; data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]) user_reg_hint_type = nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]); Loading @@ -4704,14 +4698,16 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) switch (user_reg_hint_type) { case NL80211_USER_REG_HINT_USER: case NL80211_USER_REG_HINT_CELL_BASE: break; if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) return -EINVAL; data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); return regulatory_hint_user(data, user_reg_hint_type); case NL80211_USER_REG_HINT_INDOOR: return regulatory_hint_indoor_user(); default: return -EINVAL; } r = regulatory_hint_user(data, user_reg_hint_type); return r; } static int nl80211_get_mesh_config(struct sk_buff *skb, Loading net/wireless/reg.c +57 −1 Original line number Diff line number Diff line Loading @@ -65,11 +65,26 @@ #define REG_DBG_PRINT(args...) #endif /** * enum reg_request_treatment - regulatory request treatment * * @REG_REQ_OK: continue processing the regulatory request * @REG_REQ_IGNORE: ignore the regulatory request * @REG_REQ_INTERSECT: the regulatory domain resulting from this request should * be intersected with the current one. * @REG_REQ_ALREADY_SET: the regulatory request will not change the current * regulatory settings, and no further processing is required. * @REG_REQ_USER_HINT_HANDLED: a non alpha2 user hint was handled and no * further processing is required, i.e., not need to update last_request * etc. This should be used for user hints that do not provide an alpha2 * but some other type of regulatory hint, i.e., indoor operation. */ enum reg_request_treatment { REG_REQ_OK, REG_REQ_IGNORE, REG_REQ_INTERSECT, REG_REQ_ALREADY_SET, REG_REQ_USER_HINT_HANDLED, }; static struct regulatory_request core_request_world = { Loading Loading @@ -106,6 +121,14 @@ const struct ieee80211_regdomain __rcu *cfg80211_regdomain; */ static int reg_num_devs_support_basehint; /* * State variable indicating if the platform on which the devices * are attached is operating in an indoor environment. The state variable * is relevant for all registered devices. * (protected by RTNL) */ static bool reg_is_indoor; static const struct ieee80211_regdomain *get_cfg80211_regdom(void) { return rtnl_dereference(cfg80211_regdomain); Loading Loading @@ -1128,6 +1151,13 @@ static bool reg_request_cell_base(struct regulatory_request *request) return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE; } static bool reg_request_indoor(struct regulatory_request *request) { if (request->initiator != NL80211_REGDOM_SET_BY_USER) return false; return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR; } bool reg_last_request_cell_base(void) { return reg_request_cell_base(get_last_request()); Loading Loading @@ -1570,6 +1600,11 @@ __reg_process_hint_user(struct regulatory_request *user_request) { struct regulatory_request *lr = get_last_request(); if (reg_request_indoor(user_request)) { reg_is_indoor = true; return REG_REQ_USER_HINT_HANDLED; } if (reg_request_cell_base(user_request)) return reg_ignore_cell_hint(user_request); Loading Loading @@ -1617,7 +1652,8 @@ reg_process_hint_user(struct regulatory_request *user_request) treatment = __reg_process_hint_user(user_request); if (treatment == REG_REQ_IGNORE || treatment == REG_REQ_ALREADY_SET) { treatment == REG_REQ_ALREADY_SET || treatment == REG_REQ_USER_HINT_HANDLED) { kfree(user_request); return treatment; } Loading Loading @@ -1678,6 +1714,7 @@ reg_process_hint_driver(struct wiphy *wiphy, case REG_REQ_OK: break; case REG_REQ_IGNORE: case REG_REQ_USER_HINT_HANDLED: kfree(driver_request); return treatment; case REG_REQ_INTERSECT: Loading Loading @@ -1777,6 +1814,7 @@ reg_process_hint_country_ie(struct wiphy *wiphy, case REG_REQ_OK: break; case REG_REQ_IGNORE: case REG_REQ_USER_HINT_HANDLED: /* fall through */ case REG_REQ_ALREADY_SET: kfree(country_ie_request); Loading Loading @@ -1969,6 +2007,22 @@ int regulatory_hint_user(const char *alpha2, return 0; } int regulatory_hint_indoor_user(void) { struct regulatory_request *request; request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); if (!request) return -ENOMEM; request->wiphy_idx = WIPHY_IDX_INVALID; request->initiator = NL80211_REGDOM_SET_BY_USER; request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR; queue_regulatory_request(request); return 0; } /* Driver hints */ int regulatory_hint(struct wiphy *wiphy, const char *alpha2) { Loading Loading @@ -2136,6 +2190,8 @@ static void restore_regulatory_settings(bool reset_user) ASSERT_RTNL(); reg_is_indoor = false; reset_regdomains(true, &world_regdom); restore_alpha2(alpha2, reset_user); Loading net/wireless/reg.h +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy); int regulatory_hint_user(const char *alpha2, enum nl80211_user_reg_hint_type user_reg_hint_type); int regulatory_hint_indoor_user(void); void wiphy_regulatory_register(struct wiphy *wiphy); void wiphy_regulatory_deregister(struct wiphy *wiphy); Loading Loading
include/uapi/linux/nl80211.h +3 −0 Original line number Diff line number Diff line Loading @@ -2602,10 +2602,13 @@ enum nl80211_dfs_regions { * present has been registered with the wireless core that * has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a * supported feature. * @NL80211_USER_REG_HINT_INDOOR: a user sent an hint indicating that the * platform is operating in an indoor environment. */ enum nl80211_user_reg_hint_type { NL80211_USER_REG_HINT_USER = 0, NL80211_USER_REG_HINT_CELL_BASE = 1, NL80211_USER_REG_HINT_INDOOR = 2, }; /** Loading
net/wireless/nl80211.c +7 −11 Original line number Diff line number Diff line Loading @@ -4677,7 +4677,6 @@ static int parse_reg_rule(struct nlattr *tb[], static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) { int r; char *data = NULL; enum nl80211_user_reg_hint_type user_reg_hint_type; Loading @@ -4690,11 +4689,6 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) if (unlikely(!rcu_access_pointer(cfg80211_regdomain))) return -EINPROGRESS; if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) return -EINVAL; data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]) user_reg_hint_type = nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]); Loading @@ -4704,14 +4698,16 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) switch (user_reg_hint_type) { case NL80211_USER_REG_HINT_USER: case NL80211_USER_REG_HINT_CELL_BASE: break; if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) return -EINVAL; data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); return regulatory_hint_user(data, user_reg_hint_type); case NL80211_USER_REG_HINT_INDOOR: return regulatory_hint_indoor_user(); default: return -EINVAL; } r = regulatory_hint_user(data, user_reg_hint_type); return r; } static int nl80211_get_mesh_config(struct sk_buff *skb, Loading
net/wireless/reg.c +57 −1 Original line number Diff line number Diff line Loading @@ -65,11 +65,26 @@ #define REG_DBG_PRINT(args...) #endif /** * enum reg_request_treatment - regulatory request treatment * * @REG_REQ_OK: continue processing the regulatory request * @REG_REQ_IGNORE: ignore the regulatory request * @REG_REQ_INTERSECT: the regulatory domain resulting from this request should * be intersected with the current one. * @REG_REQ_ALREADY_SET: the regulatory request will not change the current * regulatory settings, and no further processing is required. * @REG_REQ_USER_HINT_HANDLED: a non alpha2 user hint was handled and no * further processing is required, i.e., not need to update last_request * etc. This should be used for user hints that do not provide an alpha2 * but some other type of regulatory hint, i.e., indoor operation. */ enum reg_request_treatment { REG_REQ_OK, REG_REQ_IGNORE, REG_REQ_INTERSECT, REG_REQ_ALREADY_SET, REG_REQ_USER_HINT_HANDLED, }; static struct regulatory_request core_request_world = { Loading Loading @@ -106,6 +121,14 @@ const struct ieee80211_regdomain __rcu *cfg80211_regdomain; */ static int reg_num_devs_support_basehint; /* * State variable indicating if the platform on which the devices * are attached is operating in an indoor environment. The state variable * is relevant for all registered devices. * (protected by RTNL) */ static bool reg_is_indoor; static const struct ieee80211_regdomain *get_cfg80211_regdom(void) { return rtnl_dereference(cfg80211_regdomain); Loading Loading @@ -1128,6 +1151,13 @@ static bool reg_request_cell_base(struct regulatory_request *request) return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE; } static bool reg_request_indoor(struct regulatory_request *request) { if (request->initiator != NL80211_REGDOM_SET_BY_USER) return false; return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR; } bool reg_last_request_cell_base(void) { return reg_request_cell_base(get_last_request()); Loading Loading @@ -1570,6 +1600,11 @@ __reg_process_hint_user(struct regulatory_request *user_request) { struct regulatory_request *lr = get_last_request(); if (reg_request_indoor(user_request)) { reg_is_indoor = true; return REG_REQ_USER_HINT_HANDLED; } if (reg_request_cell_base(user_request)) return reg_ignore_cell_hint(user_request); Loading Loading @@ -1617,7 +1652,8 @@ reg_process_hint_user(struct regulatory_request *user_request) treatment = __reg_process_hint_user(user_request); if (treatment == REG_REQ_IGNORE || treatment == REG_REQ_ALREADY_SET) { treatment == REG_REQ_ALREADY_SET || treatment == REG_REQ_USER_HINT_HANDLED) { kfree(user_request); return treatment; } Loading Loading @@ -1678,6 +1714,7 @@ reg_process_hint_driver(struct wiphy *wiphy, case REG_REQ_OK: break; case REG_REQ_IGNORE: case REG_REQ_USER_HINT_HANDLED: kfree(driver_request); return treatment; case REG_REQ_INTERSECT: Loading Loading @@ -1777,6 +1814,7 @@ reg_process_hint_country_ie(struct wiphy *wiphy, case REG_REQ_OK: break; case REG_REQ_IGNORE: case REG_REQ_USER_HINT_HANDLED: /* fall through */ case REG_REQ_ALREADY_SET: kfree(country_ie_request); Loading Loading @@ -1969,6 +2007,22 @@ int regulatory_hint_user(const char *alpha2, return 0; } int regulatory_hint_indoor_user(void) { struct regulatory_request *request; request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); if (!request) return -ENOMEM; request->wiphy_idx = WIPHY_IDX_INVALID; request->initiator = NL80211_REGDOM_SET_BY_USER; request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR; queue_regulatory_request(request); return 0; } /* Driver hints */ int regulatory_hint(struct wiphy *wiphy, const char *alpha2) { Loading Loading @@ -2136,6 +2190,8 @@ static void restore_regulatory_settings(bool reset_user) ASSERT_RTNL(); reg_is_indoor = false; reset_regdomains(true, &world_regdom); restore_alpha2(alpha2, reset_user); Loading
net/wireless/reg.h +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy); int regulatory_hint_user(const char *alpha2, enum nl80211_user_reg_hint_type user_reg_hint_type); int regulatory_hint_indoor_user(void); void wiphy_regulatory_register(struct wiphy *wiphy); void wiphy_regulatory_deregister(struct wiphy *wiphy); Loading