From fe7ef5e9ba0c60bab01390493a4c6790f7b093af Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 4 Dec 2012 15:07:34 +0100 Subject: regulatory: remove handling of channel bandwidth The channel bandwidth handling isn't really quite right, it assumes that a 40 MHz channel is really two 20 MHz channels, which isn't strictly true. This is the way the regulatory database handling is defined right now though so remove the logic to handle other channel widths. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 8e6a6b73b9c9..c222e5fbf53a 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2938,10 +2938,6 @@ extern void wiphy_apply_custom_regulatory( * freq_reg_info - get regulatory information for the given frequency * @wiphy: the wiphy for which we want to process this rule for * @center_freq: Frequency in KHz for which we want regulatory information for - * @desired_bw_khz: the desired max bandwidth you want to use per - * channel. Note that this is still 20 MHz if you want to use HT40 - * as HT40 makes use of two channels for its 40 MHz width bandwidth. - * If set to 0 we'll assume you want the standard 20 MHz. * @reg_rule: the regulatory rule which we have for this frequency * * Use this function to get the regulatory rule for a specific frequency on @@ -2956,9 +2952,7 @@ extern void wiphy_apply_custom_regulatory( * freq_in_rule_band() for our current definition of a band -- this is purely * subjective and right now its 802.11 specific. */ -extern int freq_reg_info(struct wiphy *wiphy, - u32 center_freq, - u32 desired_bw_khz, +extern int freq_reg_info(struct wiphy *wiphy, u32 center_freq, const struct ieee80211_reg_rule **reg_rule); /* -- cgit v1.2.3-59-g8ed1b From 458f4f9e960b9a3b674c4b87d996eef186b1fe83 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 6 Dec 2012 15:47:38 +0100 Subject: regulatory: use RCU to protect global and wiphy regdomains To simplify the locking and not require cfg80211_mutex (which nl80211 uses to access the global regdomain) and also to make it possible for drivers to access their wiphy->regd safely, use RCU to protect these pointers. Acked-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 +- include/net/regulatory.h | 2 + net/wireless/nl80211.c | 35 ++++++++------- net/wireless/reg.c | 113 +++++++++++++++++++++++++++-------------------- net/wireless/reg.h | 2 +- 5 files changed, 88 insertions(+), 66 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index c222e5fbf53a..f3be58a29642 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2369,7 +2369,7 @@ struct wiphy { /* fields below are read-only, assigned by cfg80211 */ - const struct ieee80211_regdomain *regd; + const struct ieee80211_regdomain __rcu *regd; /* the item in /sys/class/ieee80211/ points to this, * you need use set_wiphy_dev() (see below) */ diff --git a/include/net/regulatory.h b/include/net/regulatory.h index 7dcaa2794fde..96b0f07cb85b 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -18,6 +18,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include /** * enum environment_cap - Environment parsed from country IE @@ -101,6 +102,7 @@ struct ieee80211_reg_rule { }; struct ieee80211_regdomain { + struct rcu_head rcu_head; u32 n_reg_rules; char alpha2[2]; u8 dfs_region; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b387deaf1132..b3cf7cc0d4a1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3787,12 +3787,8 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) * window between nl80211_init() and regulatory_init(), if that is * even possible. */ - mutex_lock(&cfg80211_mutex); - if (unlikely(!cfg80211_regdomain)) { - mutex_unlock(&cfg80211_mutex); + if (unlikely(!rcu_access_pointer(cfg80211_regdomain))) return -EINPROGRESS; - } - mutex_unlock(&cfg80211_mutex); if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) return -EINVAL; @@ -4152,6 +4148,7 @@ static int nl80211_update_mesh_config(struct sk_buff *skb, static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) { + const struct ieee80211_regdomain *regdom; struct sk_buff *msg; void *hdr = NULL; struct nlattr *nl_reg_rules; @@ -4174,35 +4171,36 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) if (!hdr) goto put_failure; - if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, - cfg80211_regdomain->alpha2) || - (cfg80211_regdomain->dfs_region && - nla_put_u8(msg, NL80211_ATTR_DFS_REGION, - cfg80211_regdomain->dfs_region))) - goto nla_put_failure; - if (reg_last_request_cell_base() && nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, NL80211_USER_REG_HINT_CELL_BASE)) goto nla_put_failure; + rcu_read_lock(); + regdom = rcu_dereference(cfg80211_regdomain); + + if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) || + (regdom->dfs_region && + nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region))) + goto nla_put_failure_rcu; + nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); if (!nl_reg_rules) - goto nla_put_failure; + goto nla_put_failure_rcu; - for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) { + for (i = 0; i < regdom->n_reg_rules; i++) { struct nlattr *nl_reg_rule; const struct ieee80211_reg_rule *reg_rule; const struct ieee80211_freq_range *freq_range; const struct ieee80211_power_rule *power_rule; - reg_rule = &cfg80211_regdomain->reg_rules[i]; + reg_rule = ®dom->reg_rules[i]; freq_range = ®_rule->freq_range; power_rule = ®_rule->power_rule; nl_reg_rule = nla_nest_start(msg, i); if (!nl_reg_rule) - goto nla_put_failure; + goto nla_put_failure_rcu; if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS, reg_rule->flags) || @@ -4216,10 +4214,11 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) power_rule->max_antenna_gain) || nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, power_rule->max_eirp)) - goto nla_put_failure; + goto nla_put_failure_rcu; nla_nest_end(msg, nl_reg_rule); } + rcu_read_unlock(); nla_nest_end(msg, nl_reg_rules); @@ -4227,6 +4226,8 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) err = genlmsg_reply(msg, info); goto out; +nla_put_failure_rcu: + rcu_read_unlock(); nla_put_failure: genlmsg_cancel(msg, hdr); put_failure: diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 35541d6d4145..9b64b201cdf1 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -95,15 +95,15 @@ static struct device_type reg_device_type = { * Central wireless core regulatory domains, we only need two, * the current one and a world regulatory domain in case we have no * information to give us an alpha2. - * Protected by the cfg80211_mutex. */ -const struct ieee80211_regdomain *cfg80211_regdomain; +const struct ieee80211_regdomain __rcu *cfg80211_regdomain; /* * Protects static reg.c components: - * - cfg80211_world_regdom - * - last_request - * - reg_num_devs_support_basehint + * - cfg80211_regdomain (if not used with RCU) + * - cfg80211_world_regdom + * - last_request + * - reg_num_devs_support_basehint */ static DEFINE_MUTEX(reg_mutex); @@ -118,6 +118,25 @@ static inline void assert_reg_lock(void) lockdep_assert_held(®_mutex); } +static const struct ieee80211_regdomain *get_cfg80211_regdom(void) +{ + return rcu_dereference_protected(cfg80211_regdomain, + lockdep_is_held(®_mutex)); +} + +static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy) +{ + return rcu_dereference_protected(wiphy->regd, + lockdep_is_held(®_mutex)); +} + +static void rcu_free_regdom(const struct ieee80211_regdomain *r) +{ + if (!r) + return; + kfree_rcu((struct ieee80211_regdomain *)r, rcu_head); +} + /* Used to queue up regulatory hints */ static LIST_HEAD(reg_requests_list); static spinlock_t reg_requests_lock; @@ -186,22 +205,25 @@ MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); static void reset_regdomains(bool full_reset, const struct ieee80211_regdomain *new_regdom) { - assert_cfg80211_lock(); + const struct ieee80211_regdomain *r; + assert_reg_lock(); + r = get_cfg80211_regdom(); + /* avoid freeing static information or freeing something twice */ - if (cfg80211_regdomain == cfg80211_world_regdom) - cfg80211_regdomain = NULL; + if (r == cfg80211_world_regdom) + r = NULL; if (cfg80211_world_regdom == &world_regdom) cfg80211_world_regdom = NULL; - if (cfg80211_regdomain == &world_regdom) - cfg80211_regdomain = NULL; + if (r == &world_regdom) + r = NULL; - kfree(cfg80211_regdomain); - kfree(cfg80211_world_regdom); + rcu_free_regdom(r); + rcu_free_regdom(cfg80211_world_regdom); cfg80211_world_regdom = &world_regdom; - cfg80211_regdomain = new_regdom; + rcu_assign_pointer(cfg80211_regdomain, new_regdom); if (!full_reset) return; @@ -219,7 +241,6 @@ static void update_world_regdomain(const struct ieee80211_regdomain *rd) { WARN_ON(!last_request); - assert_cfg80211_lock(); assert_reg_lock(); reset_regdomains(false, rd); @@ -280,11 +301,11 @@ static bool alpha2_equal(const char *alpha2_x, const char *alpha2_y) static bool regdom_changes(const char *alpha2) { - assert_cfg80211_lock(); + const struct ieee80211_regdomain *r = get_cfg80211_regdom(); - if (!cfg80211_regdomain) + if (!r) return true; - return !alpha2_equal(cfg80211_regdomain->alpha2, alpha2); + return !alpha2_equal(r->alpha2, alpha2); } /* @@ -727,7 +748,6 @@ int freq_reg_info(struct wiphy *wiphy, u32 center_freq, const struct ieee80211_regdomain *regd; assert_reg_lock(); - assert_cfg80211_lock(); /* * Follow the driver's regulatory domain, if present, unless a country @@ -736,9 +756,9 @@ int freq_reg_info(struct wiphy *wiphy, u32 center_freq, if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && last_request->initiator != NL80211_REGDOM_SET_BY_USER && wiphy->regd) - regd = wiphy->regd; + regd = get_wiphy_regdom(wiphy); else - regd = cfg80211_regdomain; + regd = get_cfg80211_regdom(); return freq_reg_info_regd(wiphy, center_freq, reg_rule, regd); } @@ -809,8 +829,6 @@ static void handle_channel(struct wiphy *wiphy, const struct ieee80211_freq_range *freq_range = NULL; struct wiphy *request_wiphy = NULL; - assert_cfg80211_lock(); - request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); flags = chan->orig_flags; @@ -1060,15 +1078,17 @@ static void wiphy_update_beacon_reg(struct wiphy *wiphy) static bool reg_is_world_roaming(struct wiphy *wiphy) { - assert_cfg80211_lock(); + const struct ieee80211_regdomain *cr = get_cfg80211_regdom(); + const struct ieee80211_regdomain *wr = get_wiphy_regdom(wiphy); - if (is_world_regdom(cfg80211_regdomain->alpha2) || - (wiphy->regd && is_world_regdom(wiphy->regd->alpha2))) + if (is_world_regdom(cr->alpha2) || (wr && is_world_regdom(wr->alpha2))) return true; + if (last_request && last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) return true; + return false; } @@ -1165,13 +1185,12 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, { enum ieee80211_band band; - assert_cfg80211_lock(); assert_reg_lock(); if (ignore_reg_update(wiphy, initiator)) return; - last_request->dfs_region = cfg80211_regdomain->dfs_region; + last_request->dfs_region = get_cfg80211_regdom()->dfs_region; for (band = 0; band < IEEE80211_NUM_BANDS; band++) handle_band(wiphy, initiator, wiphy->bands[band]); @@ -1188,6 +1207,8 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) struct cfg80211_registered_device *rdev; struct wiphy *wiphy; + assert_cfg80211_lock(); + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { wiphy = &rdev->wiphy; wiphy_update_regulatory(wiphy, initiator); @@ -1402,7 +1423,7 @@ static void reg_set_request_processed(void) * * Returns one of the different reg request treatment values. * - * Caller must hold &cfg80211_mutex and ®_mutex + * Caller must hold ®_mutex */ static enum reg_request_treatment __regulatory_hint(struct wiphy *wiphy, @@ -1412,20 +1433,18 @@ __regulatory_hint(struct wiphy *wiphy, bool intersect = false; enum reg_request_treatment treatment; - assert_cfg80211_lock(); - treatment = get_reg_request_treatment(wiphy, pending_request); switch (treatment) { case REG_REQ_INTERSECT: if (pending_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) { - regd = reg_copy_regd(cfg80211_regdomain); + regd = reg_copy_regd(get_cfg80211_regdom()); if (IS_ERR(regd)) { kfree(pending_request); return PTR_ERR(regd); } - wiphy->regd = regd; + rcu_assign_pointer(wiphy->regd, regd); } intersect = true; break; @@ -1439,13 +1458,13 @@ __regulatory_hint(struct wiphy *wiphy, */ if (treatment == REG_REQ_ALREADY_SET && pending_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) { - regd = reg_copy_regd(cfg80211_regdomain); + regd = reg_copy_regd(get_cfg80211_regdom()); if (IS_ERR(regd)) { kfree(pending_request); return REG_REQ_IGNORE; } treatment = REG_REQ_ALREADY_SET; - wiphy->regd = regd; + rcu_assign_pointer(wiphy->regd, regd); goto new_request; } kfree(pending_request); @@ -2051,6 +2070,8 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) /* Some basic sanity checks first */ + assert_reg_lock(); + if (!reg_is_valid_request(rd->alpha2)) return -EINVAL; @@ -2120,7 +2141,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) if (IS_ERR(regd)) return PTR_ERR(regd); - request_wiphy->regd = regd; + rcu_assign_pointer(request_wiphy->regd, regd); reset_regdomains(false, rd); return 0; } @@ -2128,7 +2149,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) /* Intersection requires a bit more work */ if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { - intersected_rd = regdom_intersect(rd, cfg80211_regdomain); + intersected_rd = regdom_intersect(rd, get_cfg80211_regdom()); if (!intersected_rd) return -EINVAL; @@ -2138,7 +2159,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) * domain we keep it for its private use */ if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) - request_wiphy->regd = rd; + rcu_assign_pointer(request_wiphy->regd, rd); else kfree(rd); @@ -2156,14 +2177,12 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) /* * Use this call to set the current regulatory domain. Conflicts with * multiple drivers can be ironed out later. Caller must've already - * kmalloc'd the rd structure. Caller must hold cfg80211_mutex + * kmalloc'd the rd structure. */ int set_regdom(const struct ieee80211_regdomain *rd) { int r; - assert_cfg80211_lock(); - mutex_lock(®_mutex); /* Note that this doesn't update the wiphys, this is done below */ @@ -2177,7 +2196,8 @@ int set_regdom(const struct ieee80211_regdomain *rd) } /* This would make this whole thing pointless */ - if (WARN_ON(!last_request->intersect && rd != cfg80211_regdomain)) { + if (WARN_ON(!last_request->intersect && + rd != get_cfg80211_regdom())) { r = -EINVAL; goto out; } @@ -2185,7 +2205,7 @@ int set_regdom(const struct ieee80211_regdomain *rd) /* update all wiphys now with the new established regulatory domain */ update_all_wiphy_regulatory(last_request->initiator); - print_regdomain(cfg80211_regdomain); + print_regdomain(get_cfg80211_regdom()); nl80211_send_reg_change_event(last_request); @@ -2238,7 +2258,8 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy) if (!reg_dev_ignore_cell_hint(wiphy)) reg_num_devs_support_basehint--; - kfree(wiphy->regd); + rcu_free_regdom(get_wiphy_regdom(wiphy)); + rcu_assign_pointer(wiphy->regd, NULL); if (last_request) request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); @@ -2273,13 +2294,13 @@ int __init regulatory_init(void) reg_regdb_size_check(); - cfg80211_regdomain = cfg80211_world_regdom; + rcu_assign_pointer(cfg80211_regdomain, cfg80211_world_regdom); user_alpha2[0] = '9'; user_alpha2[1] = '7'; /* We always try to get an update for the static regdomain */ - err = regulatory_hint_core(cfg80211_regdomain->alpha2); + err = regulatory_hint_core(cfg80211_world_regdom->alpha2); if (err) { if (err == -ENOMEM) return err; @@ -2313,10 +2334,8 @@ void regulatory_exit(void) cancel_delayed_work_sync(®_timeout); /* Lock to suppress warnings */ - mutex_lock(&cfg80211_mutex); mutex_lock(®_mutex); reset_regdomains(true, NULL); - mutex_unlock(&cfg80211_mutex); mutex_unlock(®_mutex); dev_set_uevent_suppress(®_pdev->dev, true); diff --git a/net/wireless/reg.h b/net/wireless/reg.h index d391b50d2829..af2d5f8a5d82 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -extern const struct ieee80211_regdomain *cfg80211_regdomain; +extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain; bool is_world_regdom(const char *alpha2); bool reg_supported_dfs_region(u8 dfs_region); -- cgit v1.2.3-59-g8ed1b From c492db370c17c428a0a58d3673294d4e99634b7d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 6 Dec 2012 16:29:25 +0100 Subject: regulatory: use RCU to protect last_request This will allow making freq_reg_info() lock-free. Acked-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- include/net/regulatory.h | 2 + net/wireless/reg.c | 199 ++++++++++++++++++++++++++--------------------- 2 files changed, 111 insertions(+), 90 deletions(-) (limited to 'include/net') diff --git a/include/net/regulatory.h b/include/net/regulatory.h index 96b0f07cb85b..f17ed590d64a 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -36,6 +36,7 @@ enum environment_cap { /** * struct regulatory_request - used to keep track of regulatory requests * + * @rcu_head: RCU head struct used to free the request * @wiphy_idx: this is set if this request's initiator is * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This * can be used by the wireless core to deal with conflicts @@ -73,6 +74,7 @@ enum environment_cap { * @list: used to insert into the reg_requests_list linked list */ struct regulatory_request { + struct rcu_head rcu_head; int wiphy_idx; enum nl80211_reg_initiator initiator; enum nl80211_user_reg_hint_type user_reg_hint_type; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 9b64b201cdf1..2a7c3adf902f 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -82,7 +82,8 @@ static struct regulatory_request core_request_world = { }; /* Receipt of information from last regulatory request */ -static struct regulatory_request *last_request = &core_request_world; +static struct regulatory_request __rcu *last_request = + (void __rcu *)&core_request_world; /* To trigger userspace events */ static struct platform_device *reg_pdev; @@ -102,7 +103,7 @@ const struct ieee80211_regdomain __rcu *cfg80211_regdomain; * Protects static reg.c components: * - cfg80211_regdomain (if not used with RCU) * - cfg80211_world_regdom - * - last_request + * - last_request (if not used with RCU) * - reg_num_devs_support_basehint */ static DEFINE_MUTEX(reg_mutex); @@ -137,6 +138,12 @@ static void rcu_free_regdom(const struct ieee80211_regdomain *r) kfree_rcu((struct ieee80211_regdomain *)r, rcu_head); } +static struct regulatory_request *get_last_request(void) +{ + return rcu_dereference_protected(last_request, + lockdep_is_held(®_mutex)); +} + /* Used to queue up regulatory hints */ static LIST_HEAD(reg_requests_list); static spinlock_t reg_requests_lock; @@ -206,6 +213,7 @@ static void reset_regdomains(bool full_reset, const struct ieee80211_regdomain *new_regdom) { const struct ieee80211_regdomain *r; + struct regulatory_request *lr; assert_reg_lock(); @@ -228,9 +236,10 @@ static void reset_regdomains(bool full_reset, if (!full_reset) return; - if (last_request != &core_request_world) - kfree(last_request); - last_request = &core_request_world; + lr = get_last_request(); + if (lr != &core_request_world && lr) + kfree_rcu(lr, rcu_head); + rcu_assign_pointer(last_request, &core_request_world); } /* @@ -239,9 +248,11 @@ static void reset_regdomains(bool full_reset, */ static void update_world_regdomain(const struct ieee80211_regdomain *rd) { - WARN_ON(!last_request); + struct regulatory_request *lr; - assert_reg_lock(); + lr = get_last_request(); + + WARN_ON(!lr); reset_regdomains(false, rd); @@ -448,15 +459,12 @@ static int call_crda(const char *alpha2) static bool reg_is_valid_request(const char *alpha2) { - assert_reg_lock(); + struct regulatory_request *lr = get_last_request(); - if (!last_request) + if (!lr || lr->processed) return false; - if (last_request->processed) - return false; - - return alpha2_equal(last_request->alpha2, alpha2); + return alpha2_equal(lr->alpha2, alpha2); } /* Sanity check on a regulatory rule */ @@ -746,15 +754,14 @@ int freq_reg_info(struct wiphy *wiphy, u32 center_freq, const struct ieee80211_reg_rule **reg_rule) { const struct ieee80211_regdomain *regd; - - assert_reg_lock(); + struct regulatory_request *lr = get_last_request(); /* * Follow the driver's regulatory domain, if present, unless a country * IE has been processed or a user wants to help complaince further */ - if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && - last_request->initiator != NL80211_REGDOM_SET_BY_USER && + if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && + lr->initiator != NL80211_REGDOM_SET_BY_USER && wiphy->regd) regd = get_wiphy_regdom(wiphy); else @@ -828,8 +835,9 @@ static void handle_channel(struct wiphy *wiphy, const struct ieee80211_power_rule *power_rule = NULL; const struct ieee80211_freq_range *freq_range = NULL; struct wiphy *request_wiphy = NULL; + struct regulatory_request *lr = get_last_request(); - request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); + request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); flags = chan->orig_flags; @@ -862,7 +870,7 @@ static void handle_channel(struct wiphy *wiphy, if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) bw_flags = IEEE80211_CHAN_NO_HT40; - if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && + if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && request_wiphy && request_wiphy == wiphy && request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { /* @@ -927,7 +935,7 @@ bool reg_last_request_cell_base(void) bool val; mutex_lock(®_mutex); - val = reg_request_cell_base(last_request); + val = reg_request_cell_base(get_last_request()); mutex_unlock(®_mutex); return val; @@ -938,10 +946,12 @@ bool reg_last_request_cell_base(void) static enum reg_request_treatment reg_ignore_cell_hint(struct regulatory_request *pending_request) { + struct regulatory_request *lr = get_last_request(); + if (!reg_num_devs_support_basehint) return REG_REQ_IGNORE; - if (reg_request_cell_base(last_request) && + if (reg_request_cell_base(lr) && !regdom_changes(pending_request->alpha2)) return REG_REQ_ALREADY_SET; @@ -969,7 +979,9 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy) static bool ignore_reg_update(struct wiphy *wiphy, enum nl80211_reg_initiator initiator) { - if (!last_request) { + struct regulatory_request *lr = get_last_request(); + + if (!lr) { REG_DBG_PRINT("Ignoring regulatory request %s since last_request is not set\n", reg_initiator_name(initiator)); return true; @@ -988,13 +1000,13 @@ static bool ignore_reg_update(struct wiphy *wiphy, */ if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && - !is_world_regdom(last_request->alpha2)) { + !is_world_regdom(lr->alpha2)) { REG_DBG_PRINT("Ignoring regulatory request %s since the driver requires its own regulatory domain to be set first\n", reg_initiator_name(initiator)); return true; } - if (reg_request_cell_base(last_request)) + if (reg_request_cell_base(lr)) return reg_dev_ignore_cell_hint(wiphy); return false; @@ -1080,12 +1092,12 @@ static bool reg_is_world_roaming(struct wiphy *wiphy) { const struct ieee80211_regdomain *cr = get_cfg80211_regdom(); const struct ieee80211_regdomain *wr = get_wiphy_regdom(wiphy); + struct regulatory_request *lr = get_last_request(); if (is_world_regdom(cr->alpha2) || (wr && is_world_regdom(wr->alpha2))) return true; - if (last_request && - last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && + if (lr && lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) return true; @@ -1184,13 +1196,12 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, enum nl80211_reg_initiator initiator) { enum ieee80211_band band; - - assert_reg_lock(); + struct regulatory_request *lr = get_last_request(); if (ignore_reg_update(wiphy, initiator)) return; - last_request->dfs_region = get_cfg80211_regdom()->dfs_region; + lr->dfs_region = get_cfg80211_regdom()->dfs_region; for (band = 0; band < IEEE80211_NUM_BANDS; band++) handle_band(wiphy, initiator, wiphy->bands[band]); @@ -1199,7 +1210,7 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, reg_process_ht_flags(wiphy); if (wiphy->reg_notifier) - wiphy->reg_notifier(wiphy, last_request); + wiphy->reg_notifier(wiphy, lr); } static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) @@ -1220,7 +1231,7 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) if (initiator == NL80211_REGDOM_SET_BY_CORE && wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY && wiphy->reg_notifier) - wiphy->reg_notifier(wiphy, last_request); + wiphy->reg_notifier(wiphy, get_last_request()); } } @@ -1300,28 +1311,28 @@ 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 (!last_request) + if (!lr) return REG_REQ_OK; switch (pending_request->initiator) { case NL80211_REGDOM_SET_BY_CORE: return REG_REQ_OK; case NL80211_REGDOM_SET_BY_COUNTRY_IE: - if (reg_request_cell_base(last_request)) { + 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(last_request->wiphy_idx); + last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); if (unlikely(!is_an_alpha2(pending_request->alpha2))) return -EINVAL; - if (last_request->initiator == - NL80211_REGDOM_SET_BY_COUNTRY_IE) { + if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { if (last_wiphy != wiphy) { /* * Two cards with two APs claiming different @@ -1343,7 +1354,7 @@ get_reg_request_treatment(struct wiphy *wiphy, } return 0; case NL80211_REGDOM_SET_BY_DRIVER: - if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) { + if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) { if (regdom_changes(pending_request->alpha2)) return REG_REQ_OK; return REG_REQ_ALREADY_SET; @@ -1354,7 +1365,7 @@ get_reg_request_treatment(struct wiphy *wiphy, * back in or if you add a new device for which the previously * loaded card also agrees on the regulatory domain. */ - if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && + if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && !regdom_changes(pending_request->alpha2)) return REG_REQ_ALREADY_SET; @@ -1363,26 +1374,26 @@ get_reg_request_treatment(struct wiphy *wiphy, if (reg_request_cell_base(pending_request)) return reg_ignore_cell_hint(pending_request); - if (reg_request_cell_base(last_request)) + if (reg_request_cell_base(lr)) return REG_REQ_IGNORE; - if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) + if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) return REG_REQ_INTERSECT; /* * If the user knows better the user should set the regdom * to their country before the IE is picked up */ - if (last_request->initiator == NL80211_REGDOM_SET_BY_USER && - last_request->intersect) + if (lr->initiator == NL80211_REGDOM_SET_BY_USER && + lr->intersect) return REG_REQ_IGNORE; /* * Process user requests only after previous user/driver/core * requests have been processed */ - if ((last_request->initiator == NL80211_REGDOM_SET_BY_CORE || - last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER || - last_request->initiator == NL80211_REGDOM_SET_BY_USER) && - regdom_changes(last_request->alpha2)) + if ((lr->initiator == NL80211_REGDOM_SET_BY_CORE || + lr->initiator == NL80211_REGDOM_SET_BY_DRIVER || + lr->initiator == NL80211_REGDOM_SET_BY_USER) && + regdom_changes(lr->alpha2)) return REG_REQ_IGNORE; if (!regdom_changes(pending_request->alpha2)) @@ -1397,15 +1408,16 @@ get_reg_request_treatment(struct wiphy *wiphy, static void reg_set_request_processed(void) { bool need_more_processing = false; + struct regulatory_request *lr = get_last_request(); - last_request->processed = true; + lr->processed = true; spin_lock(®_requests_lock); if (!list_empty(®_requests_list)) need_more_processing = true; spin_unlock(®_requests_lock); - if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) + if (lr->initiator == NL80211_REGDOM_SET_BY_USER) cancel_delayed_work(®_timeout); if (need_more_processing) @@ -1432,6 +1444,7 @@ __regulatory_hint(struct wiphy *wiphy, 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); @@ -1472,18 +1485,20 @@ __regulatory_hint(struct wiphy *wiphy, } new_request: - if (last_request != &core_request_world) - kfree(last_request); + lr = get_last_request(); + if (lr != &core_request_world && lr) + kfree_rcu(lr, rcu_head); - last_request = pending_request; - last_request->intersect = intersect; - last_request->processed = false; + pending_request->intersect = intersect; + pending_request->processed = false; + rcu_assign_pointer(last_request, pending_request); + lr = pending_request; pending_request = NULL; - if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) { - user_alpha2[0] = last_request->alpha2[0]; - user_alpha2[1] = last_request->alpha2[1]; + 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 */ @@ -1494,13 +1509,13 @@ new_request: * inform userspace we have processed the request */ if (treatment == REG_REQ_ALREADY_SET) { - nl80211_send_reg_change_event(last_request); + nl80211_send_reg_change_event(lr); reg_set_request_processed(); } return treatment; } - if (call_crda(last_request->alpha2)) + if (call_crda(lr->alpha2)) return REG_REQ_IGNORE; return REG_REQ_OK; } @@ -1543,13 +1558,14 @@ static void reg_process_hint(struct regulatory_request *reg_request, */ static void reg_process_pending_hints(void) { - struct regulatory_request *reg_request; + struct regulatory_request *reg_request, *lr; mutex_lock(&cfg80211_mutex); mutex_lock(®_mutex); + lr = get_last_request(); /* When last_request->processed becomes true this will be rescheduled */ - if (last_request && !last_request->processed) { + if (lr && !lr->processed) { REG_DBG_PRINT("Pending regulatory request, waiting for it to be processed...\n"); goto out; } @@ -1702,11 +1718,12 @@ void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band, { char alpha2[2]; enum environment_cap env = ENVIRON_ANY; - struct regulatory_request *request; + struct regulatory_request *request, *lr; mutex_lock(®_mutex); + lr = get_last_request(); - if (unlikely(!last_request)) + if (unlikely(!lr)) goto out; /* IE len must be evenly divisible by 2 */ @@ -1729,8 +1746,8 @@ void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band, * We leave conflict resolution to the workqueue, where can hold * cfg80211_mutex. */ - if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && - last_request->wiphy_idx != WIPHY_IDX_INVALID) + if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && + lr->wiphy_idx != WIPHY_IDX_INVALID) goto out; request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); @@ -2021,13 +2038,12 @@ static void print_dfs_region(u8 dfs_region) static void print_regdomain(const struct ieee80211_regdomain *rd) { + struct regulatory_request *lr = get_last_request(); if (is_intersected_alpha2(rd->alpha2)) { - if (last_request->initiator == - NL80211_REGDOM_SET_BY_COUNTRY_IE) { + if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { struct cfg80211_registered_device *rdev; - rdev = cfg80211_rdev_by_wiphy_idx( - last_request->wiphy_idx); + rdev = cfg80211_rdev_by_wiphy_idx(lr->wiphy_idx); if (rdev) { pr_info("Current regulatory domain updated by AP to: %c%c\n", rdev->country_ie_alpha2[0], @@ -2042,7 +2058,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) if (is_unknown_alpha2(rd->alpha2)) pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n"); else { - if (reg_request_cell_base(last_request)) + if (reg_request_cell_base(lr)) pr_info("Regulatory domain changed to country: %c%c by Cell Station\n", rd->alpha2[0], rd->alpha2[1]); else @@ -2067,11 +2083,10 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) const struct ieee80211_regdomain *regd; const struct ieee80211_regdomain *intersected_rd = NULL; struct wiphy *request_wiphy; + struct regulatory_request *lr = get_last_request(); /* Some basic sanity checks first */ - assert_reg_lock(); - if (!reg_is_valid_request(rd->alpha2)) return -EINVAL; @@ -2089,7 +2104,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) * rd is non static (it means CRDA was present and was used last) * and the pending request came in from a country IE */ - if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { + if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { /* * If someone else asked us to change the rd lets only bother * checking if the alpha2 changes if CRDA was already called @@ -2111,16 +2126,16 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) return -EINVAL; } - request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); + request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); if (!request_wiphy && - (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER || - last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) { + (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER || + lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) { schedule_delayed_work(®_timeout, 0); return -ENODEV; } - if (!last_request->intersect) { - if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) { + if (!lr->intersect) { + if (lr->initiator != NL80211_REGDOM_SET_BY_DRIVER) { reset_regdomains(false, rd); return 0; } @@ -2148,7 +2163,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) /* Intersection requires a bit more work */ - if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { + if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { intersected_rd = regdom_intersect(rd, get_cfg80211_regdom()); if (!intersected_rd) return -EINVAL; @@ -2158,7 +2173,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) * However if a driver requested this specific regulatory * domain we keep it for its private use */ - if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) + if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER) rcu_assign_pointer(request_wiphy->regd, rd); else kfree(rd); @@ -2181,9 +2196,11 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) */ int set_regdom(const struct ieee80211_regdomain *rd) { + struct regulatory_request *lr; int r; mutex_lock(®_mutex); + lr = get_last_request(); /* Note that this doesn't update the wiphys, this is done below */ r = __set_regdom(rd); @@ -2196,18 +2213,17 @@ int set_regdom(const struct ieee80211_regdomain *rd) } /* This would make this whole thing pointless */ - if (WARN_ON(!last_request->intersect && - rd != get_cfg80211_regdom())) { + if (WARN_ON(!lr->intersect && rd != get_cfg80211_regdom())) { r = -EINVAL; goto out; } /* update all wiphys now with the new established regulatory domain */ - update_all_wiphy_regulatory(last_request->initiator); + update_all_wiphy_regulatory(lr->initiator); print_regdomain(get_cfg80211_regdom()); - nl80211_send_reg_change_event(last_request); + nl80211_send_reg_change_event(lr); reg_set_request_processed(); @@ -2220,10 +2236,11 @@ int set_regdom(const struct ieee80211_regdomain *rd) #ifdef CONFIG_HOTPLUG int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env) { - if (last_request && !last_request->processed) { + struct regulatory_request *lr = get_last_request(); + + if (lr && !lr->processed) { if (add_uevent_var(env, "COUNTRY=%c%c", - last_request->alpha2[0], - last_request->alpha2[1])) + lr->alpha2[0], lr->alpha2[1])) return -ENOMEM; } @@ -2252,8 +2269,10 @@ void wiphy_regulatory_register(struct wiphy *wiphy) void wiphy_regulatory_deregister(struct wiphy *wiphy) { struct wiphy *request_wiphy = NULL; + struct regulatory_request *lr; mutex_lock(®_mutex); + lr = get_last_request(); if (!reg_dev_ignore_cell_hint(wiphy)) reg_num_devs_support_basehint--; @@ -2261,14 +2280,14 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy) rcu_free_regdom(get_wiphy_regdom(wiphy)); rcu_assign_pointer(wiphy->regd, NULL); - if (last_request) - request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); + if (lr) + request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); if (!request_wiphy || request_wiphy != wiphy) goto out; - last_request->wiphy_idx = WIPHY_IDX_INVALID; - last_request->country_ie_env = ENVIRON_ANY; + lr->wiphy_idx = WIPHY_IDX_INVALID; + lr->country_ie_env = ENVIRON_ANY; out: mutex_unlock(®_mutex); } -- cgit v1.2.3-59-g8ed1b From 361c9c8b0eeeec7d881e018d5143bf883558c566 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 6 Dec 2012 15:57:14 +0100 Subject: regulatory: use IS_ERR macro family for freq_reg_info Instead of returning an error and filling a pointer return the pointer and an ERR_PTR value in error cases. Acked-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/regd.c | 16 ++++------ drivers/net/wireless/brcm80211/brcmsmac/channel.c | 7 ++--- drivers/net/wireless/rtlwifi/regd.c | 14 ++++----- include/net/cfg80211.h | 18 +++++------ net/wireless/reg.c | 38 ++++++++++------------- 5 files changed, 41 insertions(+), 52 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 8ae58c404c67..7a6c79e1f819 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -195,7 +195,6 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy, const struct ieee80211_reg_rule *reg_rule; struct ieee80211_channel *ch; unsigned int i; - int r; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { @@ -213,10 +212,8 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy, continue; if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { - r = freq_reg_info(wiphy, - ch->center_freq, - ®_rule); - if (r) + reg_rule = freq_reg_info(wiphy, ch->center_freq); + if (IS_ERR(reg_rule)) continue; /* * If 11d had a rule for this channel ensure @@ -252,7 +249,6 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy, struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; const struct ieee80211_reg_rule *reg_rule; - int r; sband = wiphy->bands[IEEE80211_BAND_2GHZ]; if (!sband) @@ -280,16 +276,16 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy, */ ch = &sband->channels[11]; /* CH 12 */ - r = freq_reg_info(wiphy, ch->center_freq, ®_rule); - if (!r) { + reg_rule = freq_reg_info(wiphy, ch->center_freq); + if (!IS_ERR(reg_rule)) { if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; } ch = &sband->channels[12]; /* CH 13 */ - r = freq_reg_info(wiphy, ch->center_freq, ®_rule); - if (!r) { + reg_rule = freq_reg_info(wiphy, ch->center_freq); + if (!IS_ERR(reg_rule)) { if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index 30272519d795..4eb3f0d52105 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -670,7 +670,7 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy, struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; const struct ieee80211_reg_rule *rule; - int band, i, ret; + int band, i; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { sband = wiphy->bands[band]; @@ -685,9 +685,8 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy, continue; if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { - ret = freq_reg_info(wiphy, ch->center_freq, - &rule); - if (ret) + rule = freq_reg_info(wiphy, ch->center_freq); + if (IS_ERR(rule)) continue; if (!(rule->flags & NL80211_RRF_NO_IBSS)) diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c index be55dc9167f0..7e3ead774fb9 100644 --- a/drivers/net/wireless/rtlwifi/regd.c +++ b/drivers/net/wireless/rtlwifi/regd.c @@ -158,7 +158,6 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy, const struct ieee80211_reg_rule *reg_rule; struct ieee80211_channel *ch; unsigned int i; - int r; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { @@ -173,8 +172,8 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy, (ch->flags & IEEE80211_CHAN_RADAR)) continue; if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { - r = freq_reg_info(wiphy, ch->center_freq, ®_rule); - if (r) + reg_rule = freq_reg_info(wiphy, ch->center_freq); + if (IS_ERR(reg_rule)) continue; /* @@ -209,7 +208,6 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; const struct ieee80211_reg_rule *reg_rule; - int r; if (!wiphy->bands[IEEE80211_BAND_2GHZ]) return; @@ -237,16 +235,16 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, */ ch = &sband->channels[11]; /* CH 12 */ - r = freq_reg_info(wiphy, ch->center_freq, ®_rule); - if (!r) { + reg_rule = freq_reg_info(wiphy, ch->center_freq); + if (!IS_ERR(reg_rule)) { if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; } ch = &sband->channels[12]; /* CH 13 */ - r = freq_reg_info(wiphy, ch->center_freq, ®_rule); - if (!r) { + reg_rule = freq_reg_info(wiphy, ch->center_freq); + if (!IS_ERR(reg_rule)) { if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f3be58a29642..1f74360b527c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2938,22 +2938,22 @@ extern void wiphy_apply_custom_regulatory( * freq_reg_info - get regulatory information for the given frequency * @wiphy: the wiphy for which we want to process this rule for * @center_freq: Frequency in KHz for which we want regulatory information for - * @reg_rule: the regulatory rule which we have for this frequency * * Use this function to get the regulatory rule for a specific frequency on * a given wireless device. If the device has a specific regulatory domain * it wants to follow we respect that unless a country IE has been received * and processed already. * - * Returns 0 if it was able to find a valid regulatory rule which does - * apply to the given center_freq otherwise it returns non-zero. It will - * also return -ERANGE if we determine the given center_freq does not even have - * a regulatory rule for a frequency range in the center_freq's band. See - * freq_in_rule_band() for our current definition of a band -- this is purely - * subjective and right now its 802.11 specific. + * When an error occurs, for example if no rule can be found, the return value + * is encoded using ERR_PTR(). Use IS_ERR() to check and PTR_ERR() to obtain + * the numeric return value. The numeric return value will be -ERANGE if we + * determine the given center_freq does not even have a regulatory rule for a + * frequency range in the center_freq's band. See freq_in_rule_band() for our + * current definition of a band -- this is purely subjective and right now it's + * 802.11 specific. */ -extern int freq_reg_info(struct wiphy *wiphy, u32 center_freq, - const struct ieee80211_reg_rule **reg_rule); +const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy, + u32 center_freq); /* * callbacks for asynchronous cfg80211 methods, notification diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2a7c3adf902f..fd53d975c0bc 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -710,16 +710,16 @@ static u32 map_regdom_flags(u32 rd_flags) return channel_flags; } -static int freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq, - const struct ieee80211_reg_rule **reg_rule, - const struct ieee80211_regdomain *regd) +static const struct ieee80211_reg_rule * +freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq, + const struct ieee80211_regdomain *regd) { int i; bool band_rule_found = false; bool bw_fits = false; if (!regd) - return -EINVAL; + return ERR_PTR(-EINVAL); for (i = 0; i < regd->n_reg_rules; i++) { const struct ieee80211_reg_rule *rr; @@ -738,20 +738,18 @@ static int freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq, bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(20)); - if (band_rule_found && bw_fits) { - *reg_rule = rr; - return 0; - } + if (band_rule_found && bw_fits) + return rr; } if (!band_rule_found) - return -ERANGE; + return ERR_PTR(-ERANGE); - return -EINVAL; + return ERR_PTR(-EINVAL); } -int freq_reg_info(struct wiphy *wiphy, u32 center_freq, - const struct ieee80211_reg_rule **reg_rule) +const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy, + u32 center_freq) { const struct ieee80211_regdomain *regd; struct regulatory_request *lr = get_last_request(); @@ -767,7 +765,7 @@ int freq_reg_info(struct wiphy *wiphy, u32 center_freq, else regd = get_cfg80211_regdom(); - return freq_reg_info_regd(wiphy, center_freq, reg_rule, regd); + return freq_reg_info_regd(wiphy, center_freq, regd); } EXPORT_SYMBOL(freq_reg_info); @@ -829,7 +827,6 @@ static void handle_channel(struct wiphy *wiphy, enum nl80211_reg_initiator initiator, struct ieee80211_channel *chan) { - int r; u32 flags, bw_flags = 0; const struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_power_rule *power_rule = NULL; @@ -841,8 +838,8 @@ static void handle_channel(struct wiphy *wiphy, flags = chan->orig_flags; - r = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq), ®_rule); - if (r) { + reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq)); + if (IS_ERR(reg_rule)) { /* * We will disable all channels that do not match our * received regulatory rule unless the hint is coming @@ -854,7 +851,7 @@ static void handle_channel(struct wiphy *wiphy, * while 5 GHz is still supported. */ if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && - r == -ERANGE) + PTR_ERR(reg_rule) == -ERANGE) return; REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq); @@ -1239,16 +1236,15 @@ static void handle_channel_custom(struct wiphy *wiphy, struct ieee80211_channel *chan, const struct ieee80211_regdomain *regd) { - int r; u32 bw_flags = 0; const struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_power_rule *power_rule = NULL; const struct ieee80211_freq_range *freq_range = NULL; - r = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq), - ®_rule, regd); + reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq), + regd); - if (r) { + if (IS_ERR(reg_rule)) { REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n", chan->center_freq); chan->flags = IEEE80211_CHAN_DISABLED; -- cgit v1.2.3-59-g8ed1b From 8a61af65c6d03781015315dbc43d0942a5b31db9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 13 Dec 2012 17:42:30 +0100 Subject: mac80211: fix channel context iteration During suspend/resume channel contexts might be iterated even if they haven't been re-added to the driver, keep track of this and skip them in iteration. Also use the new status for sanity checks. Also clarify the fact that during HW restart all contexts are iterated over (thanks Eliad.) Signed-off-by: Johannes Berg --- include/net/mac80211.h | 5 +++++ net/mac80211/chan.c | 3 ++- net/mac80211/driver-ops.h | 15 ++++++++++++--- net/mac80211/ieee80211_i.h | 1 + 4 files changed, 20 insertions(+), 4 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ee50c5eba50c..0978b0faa880 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3754,6 +3754,11 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw, * The iterator will not find a context that's being added (during * the driver callback to add it) but will find it while it's being * removed. + * + * Note that during hardware restart, all contexts that existed + * before the restart are considered already present so will be + * found while iterating, whether they've been re-added already + * or not. */ void ieee80211_iter_chan_contexts_atomic( struct ieee80211_hw *hw, diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 80e55527504b..1bfe0a8b19d2 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -381,7 +381,8 @@ void ieee80211_iter_chan_contexts_atomic( rcu_read_lock(); list_for_each_entry_rcu(ctx, &local->chanctx_list, list) - iter(hw, &ctx->conf, iter_data); + if (ctx->driver_present) + iter(hw, &ctx->conf, iter_data); rcu_read_unlock(); } EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 698dc7e6f309..608ced41548d 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -913,6 +913,8 @@ static inline int drv_add_chanctx(struct ieee80211_local *local, if (local->ops->add_chanctx) ret = local->ops->add_chanctx(&local->hw, &ctx->conf); trace_drv_return_int(local, ret); + if (!ret) + ctx->driver_present = true; return ret; } @@ -924,6 +926,7 @@ static inline void drv_remove_chanctx(struct ieee80211_local *local, if (local->ops->remove_chanctx) local->ops->remove_chanctx(&local->hw, &ctx->conf); trace_drv_return_void(local); + ctx->driver_present = false; } static inline void drv_change_chanctx(struct ieee80211_local *local, @@ -931,8 +934,10 @@ static inline void drv_change_chanctx(struct ieee80211_local *local, u32 changed) { trace_drv_change_chanctx(local, ctx, changed); - if (local->ops->change_chanctx) + if (local->ops->change_chanctx) { + WARN_ON_ONCE(!ctx->driver_present); local->ops->change_chanctx(&local->hw, &ctx->conf, changed); + } trace_drv_return_void(local); } @@ -945,10 +950,12 @@ static inline int drv_assign_vif_chanctx(struct ieee80211_local *local, check_sdata_in_driver(sdata); trace_drv_assign_vif_chanctx(local, sdata, ctx); - if (local->ops->assign_vif_chanctx) + if (local->ops->assign_vif_chanctx) { + WARN_ON_ONCE(!ctx->driver_present); ret = local->ops->assign_vif_chanctx(&local->hw, &sdata->vif, &ctx->conf); + } trace_drv_return_int(local, ret); return ret; @@ -961,10 +968,12 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local, check_sdata_in_driver(sdata); trace_drv_unassign_vif_chanctx(local, sdata, ctx); - if (local->ops->unassign_vif_chanctx) + if (local->ops->unassign_vif_chanctx) { + WARN_ON_ONCE(!ctx->driver_present); local->ops->unassign_vif_chanctx(&local->hw, &sdata->vif, &ctx->conf); + } trace_drv_return_void(local); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 38e7883cff23..23161189b173 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -685,6 +685,7 @@ struct ieee80211_chanctx { enum ieee80211_chanctx_mode mode; int refcount; + bool driver_present; struct ieee80211_chanctx_conf conf; }; -- cgit v1.2.3-59-g8ed1b From 18b559d5db47c86b10c14590aa2d26c0243c39e4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Jul 2012 13:51:25 +0200 Subject: mac80211: split TX aggregation stop action When TX aggregation is stopped, there are a few different cases: - connection with the peer was dropped - session stop was requested locally - session stop was requested by the peer - connection was dropped while a session is stopping The behaviour in these cases should be different, if the connection is dropped then the driver should drop all frames, otherwise the frames may continue to be transmitted, aggregated in the case of a locally requested session stop or unaggregated in the case of the peer requesting session stop. Split these different cases so that the driver can act accordingly; however, treat local and remote stop the same way and ask the driver to not send frames as aggregated packets any more. In the case of connection drop, the stop callback the driver is otherwise supposed to call is no longer required. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 4 ++- drivers/net/wireless/ath/ath9k/main.c | 4 ++- drivers/net/wireless/ath/carl9170/main.c | 4 ++- .../net/wireless/brcm80211/brcmsmac/mac80211_if.c | 4 ++- drivers/net/wireless/iwlegacy/4965-mac.c | 4 ++- drivers/net/wireless/iwlwifi/dvm/mac80211.c | 4 ++- drivers/net/wireless/mac80211_hwsim.c | 4 ++- drivers/net/wireless/mwl8k.c | 4 ++- drivers/net/wireless/rt2x00/rt2800lib.c | 4 ++- drivers/net/wireless/rtlwifi/core.c | 4 ++- drivers/net/wireless/ti/wlcore/main.c | 4 ++- include/net/mac80211.h | 22 +++++++++--- net/mac80211/agg-tx.c | 40 +++++++++++++++++++--- 13 files changed, 85 insertions(+), 21 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 9c07a8fa5134..a8016d70088a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1628,7 +1628,9 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, if (!ret) ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; - case IEEE80211_AMPDU_TX_STOP: + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index be30a9af1528..e1fa70596e61 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1610,7 +1610,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); ath9k_ps_restore(sc); break; - case IEEE80211_AMPDU_TX_STOP: + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: ath9k_ps_wakeup(sc); ath_tx_aggr_stop(sc, sta, tid); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 25a1e2f4f738..9d2051aeb782 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1394,7 +1394,9 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw, ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; - case IEEE80211_AMPDU_TX_STOP: + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: rcu_read_lock(); tid_info = rcu_dereference(sta_info->agg[tid]); if (tid_info) { diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 1fbd8ecbe2ea..f0fc8cd4d5df 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -668,7 +668,9 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw, ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; - case IEEE80211_AMPDU_TX_STOP: + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: spin_lock_bh(&wl->lock); brcms_c_ampdu_flush(wl->wlc, sta, tid); spin_unlock_bh(&wl->lock); diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index c3fbf6717564..6a86ed45835d 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -5968,7 +5968,9 @@ il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, D_HT("start Tx\n"); ret = il4965_tx_agg_start(il, vif, sta, tid, ssn); break; - case IEEE80211_AMPDU_TX_STOP: + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: D_HT("stop Tx\n"); ret = il4965_tx_agg_stop(il, vif, sta, tid); if (test_bit(S_EXIT_PENDING, &il->status)) diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 3163e0f38c25..02fdcea76b21 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -679,7 +679,9 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, IWL_DEBUG_HT(priv, "start Tx\n"); ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); break; - case IEEE80211_AMPDU_TX_STOP: + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: IWL_DEBUG_HT(priv, "stop Tx\n"); ret = iwlagn_tx_agg_stop(priv, vif, sta, tid); if ((ret == 0) && (priv->agg_tids_count > 0)) { diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 145498f8411f..d248a4cc6656 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1312,7 +1312,9 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_START: ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; - case IEEE80211_AMPDU_TX_STOP: + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index f221b95b90b3..19b46fdf9f0f 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -5170,7 +5170,9 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); break; - case IEEE80211_AMPDU_TX_STOP: + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: if (stream) { if (stream->state == AMPDU_STREAM_ACTIVE) { spin_unlock(&priv->stream_lock); diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 197b4466a5d2..12f93e42e160 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -5484,7 +5484,9 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, case IEEE80211_AMPDU_TX_START: ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; - case IEEE80211_AMPDU_TX_STOP: + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index be33aa14c8af..d3ce9fbef00e 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -879,7 +879,9 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw, "IEEE80211_AMPDU_TX_START: TID:%d\n", tid); return rtl_tx_agg_start(hw, sta, tid, ssn); break; - case IEEE80211_AMPDU_TX_STOP: + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, "IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid); return rtl_tx_agg_stop(hw, sta, tid); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index ea9d8e011bc9..d7de06359ae1 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -4575,7 +4575,9 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, * Falling break here on purpose for all TX APDU commands. */ case IEEE80211_AMPDU_TX_START: - case IEEE80211_AMPDU_TX_STOP: + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: case IEEE80211_AMPDU_TX_OPERATIONAL: ret = -EINVAL; break; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 0978b0faa880..a464f4fb36a0 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2033,17 +2033,29 @@ enum ieee80211_filter_flags { * calling ieee80211_start_tx_ba_cb_irqsafe, because the peer * might receive the addBA frame and send a delBA right away! * - * @IEEE80211_AMPDU_RX_START: start Rx aggregation - * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation - * @IEEE80211_AMPDU_TX_START: start Tx aggregation - * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation + * @IEEE80211_AMPDU_RX_START: start RX aggregation + * @IEEE80211_AMPDU_RX_STOP: stop RX aggregation + * @IEEE80211_AMPDU_TX_START: start TX aggregation * @IEEE80211_AMPDU_TX_OPERATIONAL: TX aggregation has become operational + * @IEEE80211_AMPDU_TX_STOP_CONT: stop TX aggregation but continue transmitting + * queued packets, now unaggregated. After all packets are transmitted the + * driver has to call ieee80211_stop_tx_ba_cb_irqsafe(). + * @IEEE80211_AMPDU_TX_STOP_FLUSH: stop TX aggregation and flush all packets, + * called when the station is removed. There's no need or reason to call + * ieee80211_stop_tx_ba_cb_irqsafe() in this case as mac80211 assumes the + * session is gone and removes the station. + * @IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: called when TX aggregation is stopped + * but the driver hasn't called ieee80211_stop_tx_ba_cb_irqsafe() yet and + * now the connection is dropped and the station will be removed. Drivers + * should clean up and drop remaining packets when this is called. */ enum ieee80211_ampdu_mlme_action { IEEE80211_AMPDU_RX_START, IEEE80211_AMPDU_RX_STOP, IEEE80211_AMPDU_TX_START, - IEEE80211_AMPDU_TX_STOP, + IEEE80211_AMPDU_TX_STOP_CONT, + IEEE80211_AMPDU_TX_STOP_FLUSH, + IEEE80211_AMPDU_TX_STOP_FLUSH_CONT, IEEE80211_AMPDU_TX_OPERATIONAL, }; diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index dda8d7df4b54..2f0ccbc5f13e 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -257,10 +257,25 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, { struct ieee80211_local *local = sta->local; struct tid_ampdu_tx *tid_tx; + enum ieee80211_ampdu_mlme_action action; int ret; lockdep_assert_held(&sta->ampdu_mlme.mtx); + switch (reason) { + case AGG_STOP_DECLINED: + case AGG_STOP_LOCAL_REQUEST: + case AGG_STOP_PEER_REQUEST: + action = IEEE80211_AMPDU_TX_STOP_CONT; + break; + case AGG_STOP_DESTROY_STA: + action = IEEE80211_AMPDU_TX_STOP_FLUSH; + break; + default: + WARN_ON_ONCE(1); + return -EINVAL; + } + spin_lock_bh(&sta->lock); tid_tx = rcu_dereference_protected_tid_tx(sta, tid); @@ -269,10 +284,19 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, return -ENOENT; } - /* if we're already stopping ignore any new requests to stop */ + /* + * if we're already stopping ignore any new requests to stop + * unless we're destroying it in which case notify the driver + */ if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { spin_unlock_bh(&sta->lock); - return -EALREADY; + if (reason != AGG_STOP_DESTROY_STA) + return -EALREADY; + ret = drv_ampdu_action(local, sta->sdata, + IEEE80211_AMPDU_TX_STOP_FLUSH_CONT, + &sta->sta, tid, NULL, 0); + WARN_ON_ONCE(ret); + goto remove_tid_tx; } if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { @@ -319,8 +343,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, WLAN_BACK_INITIATOR; tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST; - ret = drv_ampdu_action(local, sta->sdata, - IEEE80211_AMPDU_TX_STOP, + ret = drv_ampdu_action(local, sta->sdata, action, &sta->sta, tid, NULL, 0); /* HW shall not deny going back to legacy */ @@ -331,7 +354,14 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, */ } - return ret; + if (reason == AGG_STOP_DESTROY_STA) { + remove_tid_tx: + spin_lock_bh(&sta->lock); + ieee80211_remove_tid_tx(sta, tid); + spin_unlock_bh(&sta->lock); + } + + return 0; } /* -- cgit v1.2.3-59-g8ed1b From 1c06ef9831c78648f719a174e4598ae2600b0cf7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 28 Dec 2012 12:22:02 +0100 Subject: wireless: use __aligned Use __aligned(...) instead of __attribute__((aligned(...))) in mac80211 and cfg80211. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++-- include/net/mac80211.h | 6 +++--- net/wireless/core.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1f74360b527c..e5f085c89221 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1256,7 +1256,7 @@ struct cfg80211_bss { u8 bssid[ETH_ALEN]; - u8 priv[0] __attribute__((__aligned__(sizeof(void *)))); + u8 priv[0] __aligned(sizeof(void *)); }; /** @@ -2392,7 +2392,7 @@ struct wiphy { const struct iw_handler_def *wext; #endif - char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); + char priv[0] __aligned(NETDEV_ALIGN); }; static inline struct net *wiphy_net(struct wiphy *wiphy) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a464f4fb36a0..23daed3c78ed 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -173,7 +173,7 @@ struct ieee80211_chanctx_conf { u8 rx_chains_static, rx_chains_dynamic; - u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); + u8 drv_priv[0] __aligned(sizeof(void *)); }; /** @@ -1059,7 +1059,7 @@ struct ieee80211_vif { u32 driver_flags; /* must be last */ - u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); + u8 drv_priv[0] __aligned(sizeof(void *)); }; static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) @@ -1209,7 +1209,7 @@ struct ieee80211_sta { u8 max_sp; /* must be last */ - u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); + u8 drv_priv[0] __aligned(sizeof(void *)); }; /** diff --git a/net/wireless/core.h b/net/wireless/core.h index b8f4630c6ada..f342267e3620 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -89,7 +89,7 @@ struct cfg80211_registered_device { /* must be last because of the way we do wiphy_priv(), * and it should at least be aligned to NETDEV_ALIGN */ - struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); + struct wiphy wiphy __aligned(NETDEV_ALIGN); }; static inline -- cgit v1.2.3-59-g8ed1b From f0c9103813b3045bd5b43220b6a78c9908a45d24 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 26 Nov 2012 18:06:27 +0100 Subject: NFC: Fixed nfc core and hci unregistration and cleanup When an adapter is removed, it will unregister itself from hci and/or nfc core. In order to do that safely, work tasks must first be canceled and prevented to be scheduled again, before the hci or nfc device can be destroyed. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- include/net/nfc/hci.h | 2 ++ include/net/nfc/nfc.h | 2 ++ net/nfc/core.c | 47 ++++++++++++++++++++++------------------------- net/nfc/hci/core.c | 31 ++++++++++++++++++++++++------- net/nfc/hci/hcp.c | 7 +++++++ 5 files changed, 57 insertions(+), 32 deletions(-) (limited to 'include/net') diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index 671953e11575..e6224571e5e6 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -87,6 +87,8 @@ struct nfc_hci_dev { u32 max_data_link_payload; + bool shutting_down; + struct mutex msg_tx_mutex; struct list_head msg_tx_queue; diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index fce80b2f9be7..1665674e86b2 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -115,6 +115,8 @@ struct nfc_dev { struct timer_list check_pres_timer; struct work_struct check_pres_work; + bool shutting_down; + struct nfc_ops *ops; }; #define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev) diff --git a/net/nfc/core.c b/net/nfc/core.c index aa64ea441676..7d7b4ee34015 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -338,7 +338,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol) dev->active_target = target; dev->rf_mode = NFC_RF_INITIATOR; - if (dev->ops->check_presence) + if (dev->ops->check_presence && !dev->shutting_down) mod_timer(&dev->check_pres_timer, jiffies + msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); } @@ -429,7 +429,7 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb, rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb, cb_context); - if (!rc && dev->ops->check_presence) + if (!rc && dev->ops->check_presence && !dev->shutting_down) mod_timer(&dev->check_pres_timer, jiffies + msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); } else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) { @@ -684,11 +684,6 @@ static void nfc_release(struct device *d) pr_debug("dev_name=%s\n", dev_name(&dev->dev)); - if (dev->ops->check_presence) { - del_timer_sync(&dev->check_pres_timer); - cancel_work_sync(&dev->check_pres_work); - } - nfc_genl_data_exit(&dev->genl_data); kfree(dev->targets); kfree(dev); @@ -706,15 +701,16 @@ static void nfc_check_pres_work(struct work_struct *work) rc = dev->ops->check_presence(dev, dev->active_target); if (rc == -EOPNOTSUPP) goto exit; - if (!rc) { - mod_timer(&dev->check_pres_timer, jiffies + - msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); - } else { + if (rc) { u32 active_target_idx = dev->active_target->idx; device_unlock(&dev->dev); nfc_target_lost(dev, active_target_idx); return; } + + if (!dev->shutting_down) + mod_timer(&dev->check_pres_timer, jiffies + + msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); } exit: @@ -853,26 +849,27 @@ void nfc_unregister_device(struct nfc_dev *dev) id = dev->idx; - mutex_lock(&nfc_devlist_mutex); - nfc_devlist_generation++; - - /* lock to avoid unregistering a device while an operation - is in progress */ - device_lock(&dev->dev); - device_del(&dev->dev); - device_unlock(&dev->dev); + if (dev->ops->check_presence) { + device_lock(&dev->dev); + dev->shutting_down = true; + device_unlock(&dev->dev); + del_timer_sync(&dev->check_pres_timer); + cancel_work_sync(&dev->check_pres_work); + } - mutex_unlock(&nfc_devlist_mutex); + rc = nfc_genl_device_removed(dev); + if (rc) + pr_debug("The userspace won't be notified that the device %s " + "was removed\n", dev_name(&dev->dev)); nfc_llcp_unregister_device(dev); - rc = nfc_genl_device_removed(dev); - if (rc) - pr_debug("The userspace won't be notified that the device %s was removed\n", - dev_name(&dev->dev)); + mutex_lock(&nfc_devlist_mutex); + nfc_devlist_generation++; + device_del(&dev->dev); + mutex_unlock(&nfc_devlist_mutex); ida_simple_remove(&nfc_index_ida, id); - } EXPORT_SYMBOL(nfc_unregister_device); diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 7bea574d5934..b4b84268653d 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -57,6 +57,8 @@ static void nfc_hci_msg_tx_work(struct work_struct *work) int r = 0; mutex_lock(&hdev->msg_tx_mutex); + if (hdev->shutting_down) + goto exit; if (hdev->cmd_pending_msg) { if (timer_pending(&hdev->cmd_timer) == 0) { @@ -868,6 +870,28 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev) { struct hci_msg *msg, *n; + mutex_lock(&hdev->msg_tx_mutex); + + if (hdev->cmd_pending_msg) { + if (hdev->cmd_pending_msg->cb) + hdev->cmd_pending_msg->cb( + hdev->cmd_pending_msg->cb_context, + NULL, -ESHUTDOWN); + kfree(hdev->cmd_pending_msg); + hdev->cmd_pending_msg = NULL; + } + + hdev->shutting_down = true; + + mutex_unlock(&hdev->msg_tx_mutex); + + del_timer_sync(&hdev->cmd_timer); + cancel_work_sync(&hdev->msg_tx_work); + + cancel_work_sync(&hdev->msg_rx_work); + + nfc_unregister_device(hdev->ndev); + skb_queue_purge(&hdev->rx_hcp_frags); skb_queue_purge(&hdev->msg_rx_queue); @@ -876,13 +900,6 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev) skb_queue_purge(&msg->msg_frags); kfree(msg); } - - del_timer_sync(&hdev->cmd_timer); - - nfc_unregister_device(hdev->ndev); - - cancel_work_sync(&hdev->msg_tx_work); - cancel_work_sync(&hdev->msg_rx_work); } EXPORT_SYMBOL(nfc_hci_unregister_device); diff --git a/net/nfc/hci/hcp.c b/net/nfc/hci/hcp.c index bc308a7ca609..b6b4109f2343 100644 --- a/net/nfc/hci/hcp.c +++ b/net/nfc/hci/hcp.c @@ -105,6 +105,13 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, } mutex_lock(&hdev->msg_tx_mutex); + + if (hdev->shutting_down) { + err = -ESHUTDOWN; + mutex_unlock(&hdev->msg_tx_mutex); + goto out_skb_err; + } + list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue); mutex_unlock(&hdev->msg_tx_mutex); -- cgit v1.2.3-59-g8ed1b From 27c31191b3d7ff32c266a5dbea344b9aa96ebf14 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Wed, 28 Nov 2012 15:48:44 +0100 Subject: NFC: Added error handling in event_received hci ops There is no use to return an error if the caller doesn't get it. Signed-off-by: Samuel Ortiz --- drivers/nfc/pn544/pn544.c | 27 +++++++++++++-------------- include/net/nfc/hci.h | 4 ++-- net/nfc/hci/core.c | 8 +++++--- 3 files changed, 20 insertions(+), 19 deletions(-) (limited to 'include/net') diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c index cc666de3b8e5..4af70f9c01aa 100644 --- a/drivers/nfc/pn544/pn544.c +++ b/drivers/nfc/pn544/pn544.c @@ -714,8 +714,8 @@ static int pn544_hci_check_presence(struct nfc_hci_dev *hdev, return 0; } -static void pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, - u8 event, struct sk_buff *skb) +static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, u8 event, + struct sk_buff *skb) { struct sk_buff *rgb_skb = NULL; int r = 0; @@ -724,25 +724,23 @@ static void pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, switch (event) { case PN544_HCI_EVT_ACTIVATED: if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE) - nfc_hci_target_discovered(hdev, gate); + r = nfc_hci_target_discovered(hdev, gate); else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) { r = nfc_hci_get_param(hdev, gate, PN544_DEP_ATR_REQ, - &rgb_skb); - + &rgb_skb); if (r < 0) goto exit; - nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK, - NFC_COMM_PASSIVE, rgb_skb->data, - rgb_skb->len); + r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK, + NFC_COMM_PASSIVE, rgb_skb->data, + rgb_skb->len); kfree_skb(rgb_skb); } - break; case PN544_HCI_EVT_DEACTIVATED: - nfc_hci_send_event(hdev, gate, - NFC_HCI_EVT_END_OPERATION, NULL, 0); + r = nfc_hci_send_event(hdev, gate, NFC_HCI_EVT_END_OPERATION, + NULL, 0); break; case PN544_HCI_EVT_RCV_DATA: if (skb->len < 2) { @@ -757,15 +755,16 @@ static void pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, } skb_pull(skb, 2); - nfc_tm_data_received(hdev->ndev, skb); - - return; + return nfc_tm_data_received(hdev->ndev, skb); default: + pr_err("Discarded unknown event %x to gate %x\n", event, gate); break; } exit: kfree_skb(skb); + + return r; } static struct nfc_hci_ops pn544_hci_ops = { diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index e6224571e5e6..834e36481aff 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -57,8 +57,8 @@ struct nfc_hci_ops { int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb); int (*check_presence)(struct nfc_hci_dev *hdev, struct nfc_target *target); - void (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event, - struct sk_buff *skb); + int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event, + struct sk_buff *skb); }; /* Pipes */ diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index b4b84268653d..f30f6fe815b4 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -323,16 +323,18 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, break; default: if (hdev->ops->event_received) { - hdev->ops->event_received(hdev, gate, event, skb); - return; + r = hdev->ops->event_received(hdev, gate, event, skb); + goto exit_noskb; + } else { + r = -EINVAL; } - break; } exit: kfree_skb(skb); +exit_noskb: if (r) { /* TODO: There was an error dispatching the event, * how to propagate up to nfc core? -- cgit v1.2.3-59-g8ed1b From bf71ab8ba53081c28b960d48e0c4cd1c17588aa6 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Tue, 18 Dec 2012 14:15:49 +0100 Subject: NFC: Add HCI quirks to support driver (non)standard implementations Some chips diverge from the HCI spec in their implementation of standard features. This adds a new quirks parameter to nfc_hci_allocate_device() to let the driver indicate its divergence. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- drivers/nfc/pn544/pn544.c | 2 +- include/net/nfc/hci.h | 13 +++++++++++++ net/nfc/hci/command.c | 7 ++++++- net/nfc/hci/core.c | 3 +++ 4 files changed, 23 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c index cd8fb16f5416..ece834239852 100644 --- a/drivers/nfc/pn544/pn544.c +++ b/drivers/nfc/pn544/pn544.c @@ -833,7 +833,7 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, NFC_PROTO_ISO14443_B_MASK | NFC_PROTO_NFC_DEP_MASK; - info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, + info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, 0, protocols, llc_name, phy_headroom + PN544_CMDS_HEADROOM, phy_tailroom, phy_payload); diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index 834e36481aff..2ff71750c428 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -82,6 +82,16 @@ typedef int (*xmit) (struct sk_buff *skb, void *cb_data); #define NFC_HCI_MAX_GATES 256 +/* + * These values can be specified by a driver to indicate it requires some + * adaptation of the HCI standard. + * + * NFC_HCI_QUIRK_SHORT_CLEAR - send HCI_ADM_CLEAR_ALL_PIPE cmd with no params + */ +enum { + NFC_HCI_QUIRK_SHORT_CLEAR = 0, +}; + struct nfc_hci_dev { struct nfc_dev *ndev; @@ -131,11 +141,14 @@ struct nfc_hci_dev { u8 *gb; size_t gb_len; + + unsigned long quirks; }; /* hci device allocation */ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, struct nfc_hci_init_data *init_data, + unsigned long quirks, u32 protocols, const char *llc_name, int tx_headroom, diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 7d99410e6c1a..64f922be9281 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c @@ -280,14 +280,19 @@ static int nfc_hci_delete_pipe(struct nfc_hci_dev *hdev, u8 pipe) static int nfc_hci_clear_all_pipes(struct nfc_hci_dev *hdev) { u8 param[2]; + size_t param_len = 2; /* TODO: Find out what the identity reference data is * and fill param with it. HCI spec 6.1.3.5 */ pr_debug("\n"); + if (test_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &hdev->quirks)) + param_len = 0; + return nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE, - NFC_HCI_ADM_CLEAR_ALL_PIPE, param, 2, NULL); + NFC_HCI_ADM_CLEAR_ALL_PIPE, param, param_len, + NULL); } int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate) diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index d9190da4a403..755a6b9774ab 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -795,6 +795,7 @@ static struct nfc_ops hci_nfc_ops = { struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, struct nfc_hci_init_data *init_data, + unsigned long quirks, u32 protocols, const char *llc_name, int tx_headroom, @@ -838,6 +839,8 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, memset(hdev->gate2pipe, NFC_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe)); + hdev->quirks = quirks; + return hdev; } EXPORT_SYMBOL(nfc_hci_allocate_device); -- cgit v1.2.3-59-g8ed1b From 390a1bd8538132186ddb679cafe9e75b7ef7e2d2 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 19 Dec 2012 19:11:32 +0100 Subject: NFC: Initial Secure Element API Each NFC adapter can have several links to different secure elements and that property needs to be exported by the drivers. A secure element link can be enabled and disabled, and card emulation will be handled by the currently active one. Otherwise card emulation will be host implemented. Signed-off-by: Samuel Ortiz --- drivers/nfc/nfcwilink.c | 1 + drivers/nfc/pn533.c | 1 + drivers/nfc/pn544/pn544.c | 6 ++++-- include/net/nfc/hci.h | 3 +++ include/net/nfc/nci_core.h | 1 + include/net/nfc/nfc.h | 6 ++++++ include/uapi/linux/nfc.h | 14 ++++++++++++++ net/nfc/core.c | 3 +++ net/nfc/hci/core.c | 3 ++- net/nfc/nci/core.c | 2 ++ net/nfc/netlink.c | 1 + 11 files changed, 38 insertions(+), 3 deletions(-) (limited to 'include/net') diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c index c7c182d2b7df..3b731acbc408 100644 --- a/drivers/nfc/nfcwilink.c +++ b/drivers/nfc/nfcwilink.c @@ -542,6 +542,7 @@ static int nfcwilink_probe(struct platform_device *pdev) drv->ndev = nci_allocate_device(&nfcwilink_ops, protocols, + NFC_SE_NONE, NFCWILINK_HDR_LEN, 0); if (!drv->ndev) { diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index e8c083203b33..31a5b3b53b2a 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -2525,6 +2525,7 @@ static int pn533_probe(struct usb_interface *interface, dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols, + NFC_SE_NONE, dev->ops->tx_header_len + PN533_CMD_DATAEXCH_HEAD_LEN, dev->ops->tx_tail_len); diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c index d108c794008d..9c5f16e7baef 100644 --- a/drivers/nfc/pn544/pn544.c +++ b/drivers/nfc/pn544/pn544.c @@ -801,7 +801,7 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, struct nfc_hci_dev **hdev) { struct pn544_hci_info *info; - u32 protocols; + u32 protocols, se; struct nfc_hci_init_data init_data; int r; @@ -834,8 +834,10 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, NFC_PROTO_ISO14443_B_MASK | NFC_PROTO_NFC_DEP_MASK; + se = NFC_SE_UICC | NFC_SE_EMBEDDED; + info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, 0, - protocols, llc_name, + protocols, se, llc_name, phy_headroom + PN544_CMDS_HEADROOM, phy_tailroom, phy_payload); if (!info->hdev) { diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index 2ff71750c428..b87a1692b086 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -59,6 +59,8 @@ struct nfc_hci_ops { struct nfc_target *target); int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event, struct sk_buff *skb); + int (*enable_se)(struct nfc_dev *dev, u32 secure_element); + int (*disable_se)(struct nfc_dev *dev, u32 secure_element); }; /* Pipes */ @@ -150,6 +152,7 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, struct nfc_hci_init_data *init_data, unsigned long quirks, u32 protocols, + u32 supported_se, const char *llc_name, int tx_headroom, int tx_tailroom, diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h index d705d8674949..5bc0c460edc0 100644 --- a/include/net/nfc/nci_core.h +++ b/include/net/nfc/nci_core.h @@ -147,6 +147,7 @@ struct nci_dev { /* ----- NCI Devices ----- */ struct nci_dev *nci_allocate_device(struct nci_ops *ops, __u32 supported_protocols, + __u32 supported_se, int tx_headroom, int tx_tailroom); void nci_free_device(struct nci_dev *ndev); diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 1665674e86b2..87a6417fc934 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -68,6 +68,8 @@ struct nfc_ops { void *cb_context); int (*tm_send)(struct nfc_dev *dev, struct sk_buff *skb); int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target); + int (*enable_se)(struct nfc_dev *dev, u32 secure_element); + int (*disable_se)(struct nfc_dev *dev, u32 secure_element); }; #define NFC_TARGET_IDX_ANY -1 @@ -109,6 +111,9 @@ struct nfc_dev { struct nfc_genl_data genl_data; u32 supported_protocols; + u32 supported_se; + u32 active_se; + int tx_headroom; int tx_tailroom; @@ -125,6 +130,7 @@ extern struct class nfc_class; struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, u32 supported_protocols, + u32 supported_se, int tx_headroom, int tx_tailroom); diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h index 0e63cee8d810..80e4ecd8c04c 100644 --- a/include/uapi/linux/nfc.h +++ b/include/uapi/linux/nfc.h @@ -67,6 +67,11 @@ * subsequent CONNECT and CC messages. * If one of the passed parameters is wrong none is set and -EINVAL is * returned. + * @NFC_CMD_ENABLE_SE: Enable the physical link to a specific secure element. + * Once enabled a secure element will handle card emulation mode, i.e. + * starting a poll from a device which has a secure element enabled means + * we want to do SE based card emulation. + * @NFC_CMD_DISABLE_SE: Disable the physical link to a specific secure element. */ enum nfc_commands { NFC_CMD_UNSPEC, @@ -86,6 +91,8 @@ enum nfc_commands { NFC_EVENT_TM_DEACTIVATED, NFC_CMD_LLC_GET_PARAMS, NFC_CMD_LLC_SET_PARAMS, + NFC_CMD_ENABLE_SE, + NFC_CMD_DISABLE_SE, /* private: internal use only */ __NFC_CMD_AFTER_LAST }; @@ -114,6 +121,7 @@ enum nfc_commands { * @NFC_ATTR_LLC_PARAM_LTO: Link TimeOut parameter * @NFC_ATTR_LLC_PARAM_RW: Receive Window size parameter * @NFC_ATTR_LLC_PARAM_MIUX: MIU eXtension parameter + * @NFC_ATTR_SE: Available Secure Elements */ enum nfc_attrs { NFC_ATTR_UNSPEC, @@ -134,6 +142,7 @@ enum nfc_attrs { NFC_ATTR_LLC_PARAM_LTO, NFC_ATTR_LLC_PARAM_RW, NFC_ATTR_LLC_PARAM_MIUX, + NFC_ATTR_SE, /* private: internal use only */ __NFC_ATTR_AFTER_LAST }; @@ -172,6 +181,11 @@ enum nfc_attrs { #define NFC_PROTO_NFC_DEP_MASK (1 << NFC_PROTO_NFC_DEP) #define NFC_PROTO_ISO14443_B_MASK (1 << NFC_PROTO_ISO14443_B) +/* NFC Secure Elements */ +#define NFC_SE_NONE 0x0 +#define NFC_SE_UICC 0x1 +#define NFC_SE_EMBEDDED 0x2 + struct sockaddr_nfc { sa_family_t sa_family; __u32 dev_idx; diff --git a/net/nfc/core.c b/net/nfc/core.c index 7d7b4ee34015..25522e56d350 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -757,6 +757,7 @@ struct nfc_dev *nfc_get_device(unsigned int idx) */ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, u32 supported_protocols, + u32 supported_se, int tx_headroom, int tx_tailroom) { struct nfc_dev *dev; @@ -774,6 +775,8 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, dev->ops = ops; dev->supported_protocols = supported_protocols; + dev->supported_se = supported_se; + dev->active_se = NFC_SE_NONE; dev->tx_headroom = tx_headroom; dev->tx_tailroom = tx_tailroom; diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 755a6b9774ab..91020b210d87 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -797,6 +797,7 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, struct nfc_hci_init_data *init_data, unsigned long quirks, u32 protocols, + u32 supported_se, const char *llc_name, int tx_headroom, int tx_tailroom, @@ -822,7 +823,7 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, return NULL; } - hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols, + hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols, supported_se, tx_headroom + HCI_CMDS_HEADROOM, tx_tailroom); if (!hdev->ndev) { diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 5f98dc1bf039..48ada0ec749e 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -658,6 +658,7 @@ static struct nfc_ops nci_nfc_ops = { */ struct nci_dev *nci_allocate_device(struct nci_ops *ops, __u32 supported_protocols, + __u32 supported_se, int tx_headroom, int tx_tailroom) { struct nci_dev *ndev; @@ -680,6 +681,7 @@ struct nci_dev *nci_allocate_device(struct nci_ops *ops, ndev->nfc_dev = nfc_allocate_device(&nci_nfc_ops, supported_protocols, + supported_se, tx_headroom + NCI_DATA_HDR_SIZE, tx_tailroom); if (!ndev->nfc_dev) diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 3568ae16786d..504b883439f1 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -366,6 +366,7 @@ static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev, if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) || nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) || nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) || + nla_put_u32(msg, NFC_ATTR_SE, dev->supported_se) || nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up) || nla_put_u8(msg, NFC_ATTR_RF_MODE, dev->rf_mode)) goto nla_put_failure; -- cgit v1.2.3-59-g8ed1b From 0c0280bd0ba410326eecdaeb1b936696eda6381d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 11 Jan 2013 18:39:36 +0000 Subject: wireless: make the reg_notifier() void The reg_notifier()'s return value need not be checked as it is only supposed to do post regulatory work and that should never fail. Any behaviour to regulatory that needs to be considered before cfg80211 does work to a driver should be specified by using the already existing flags, the reg_notifier() just does post processing should it find it needs to. Also make lbs_reg_notifier static. Signed-off-by: Luis R. Rodriguez [move lbs_reg_notifier to not break compile] Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath5k/base.c | 5 ++-- drivers/net/wireless/ath/ath6kl/cfg80211.c | 16 ++++------- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 8 +++--- drivers/net/wireless/ath/ath9k/init.c | 9 +++---- drivers/net/wireless/ath/carl9170/main.c | 6 ++--- drivers/net/wireless/ath/regd.c | 18 ++++++------- drivers/net/wireless/ath/regd.h | 10 +++---- drivers/net/wireless/brcm80211/brcmsmac/channel.c | 6 ++--- drivers/net/wireless/libertas/cfg.c | 33 +++++++++++------------ drivers/net/wireless/libertas/cfg.h | 3 --- drivers/net/wireless/mwifiex/cfg80211.c | 6 ++--- drivers/net/wireless/rtlwifi/regd.c | 20 +++++++------- drivers/net/wireless/rtlwifi/regd.h | 6 ++--- drivers/net/wireless/ti/wlcore/main.c | 6 ++--- include/net/cfg80211.h | 4 +-- 15 files changed, 66 insertions(+), 90 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 30ca0a60a64c..1d264c0f5a9b 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -240,13 +240,14 @@ static const struct ath_ops ath5k_common_ops = { * Driver Initialization * \***********************/ -static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) +static void ath5k_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath5k_hw *ah = hw->priv; struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah); - return ath_reg_notifier_apply(wiphy, request, regulatory); + ath_reg_notifier_apply(wiphy, request, regulatory); } /********************\ diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 5516a8ccc3c6..4225cca0f198 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3492,8 +3492,8 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar) ath6kl_cfg80211_stop(vif); } -static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy, - struct regulatory_request *request) +static void ath6kl_cfg80211_reg_notify(struct wiphy *wiphy, + struct regulatory_request *request) { struct ath6kl *ar = wiphy_priv(wiphy); u32 rates[IEEE80211_NUM_BANDS]; @@ -3506,17 +3506,13 @@ static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy, request->processed ? " processed" : "", request->initiator, request->user_reg_hint_type); - /* - * As firmware is not able intersect regdoms, we can only listen to - * cellular hints. - */ if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE) - return -EOPNOTSUPP; + return; ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2); if (ret) { ath6kl_err("failed to set regdomain: %d\n", ret); - return ret; + return; } /* @@ -3536,10 +3532,8 @@ static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy, if (ret) { ath6kl_err("failed to start scan for a regdomain change: %d\n", ret); - return ret; + return; } - - return 0; } static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 05d5ba66cac3..e5d7958ab948 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -280,14 +280,14 @@ err: return ret; } -static int ath9k_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) +static void ath9k_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath9k_htc_priv *priv = hw->priv; - return ath_reg_notifier_apply(wiphy, request, - ath9k_hw_regulatory(priv->ah)); + ath_reg_notifier_apply(wiphy, request, + ath9k_hw_regulatory(priv->ah)); } static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index f69ef5d48c7b..315d6593e18e 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -302,16 +302,15 @@ static void setup_ht_cap(struct ath_softc *sc, ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; } -static int ath9k_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) +static void ath9k_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_regulatory *reg = ath9k_hw_regulatory(ah); - int ret; - ret = ath_reg_notifier_apply(wiphy, request, reg); + ath_reg_notifier_apply(wiphy, request, reg); /* Set tx power */ if (ah->curchan) { @@ -321,8 +320,6 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit; ath9k_ps_restore(sc); } - - return ret; } /* diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 9d2051aeb782..aaa2699e5a8c 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1918,13 +1918,13 @@ static int carl9170_parse_eeprom(struct ar9170 *ar) return 0; } -static int carl9170_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) +static void carl9170_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ar9170 *ar = hw->priv; - return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory); + ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory); } int carl9170_register(struct ar9170 *ar) diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 7a6c79e1f819..ccc4c718f124 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -356,9 +356,9 @@ static u16 ath_regd_find_country_by_name(char *alpha2) return -1; } -int ath_reg_notifier_apply(struct wiphy *wiphy, - struct regulatory_request *request, - struct ath_regulatory *reg) +void ath_reg_notifier_apply(struct wiphy *wiphy, + struct regulatory_request *request, + struct ath_regulatory *reg) { struct ath_common *common = container_of(reg, struct ath_common, regulatory); @@ -373,7 +373,7 @@ int ath_reg_notifier_apply(struct wiphy *wiphy, * any pending requests in the queue. */ if (!request) - return 0; + return; switch (request->initiator) { case NL80211_REGDOM_SET_BY_CORE: @@ -409,8 +409,6 @@ int ath_reg_notifier_apply(struct wiphy *wiphy, break; } - - return 0; } EXPORT_SYMBOL(ath_reg_notifier_apply); @@ -500,8 +498,8 @@ ath_get_regpair(int regdmn) static int ath_regd_init_wiphy(struct ath_regulatory *reg, struct wiphy *wiphy, - int (*reg_notifier)(struct wiphy *wiphy, - struct regulatory_request *request)) + void (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request)) { const struct ieee80211_regdomain *regd; @@ -621,8 +619,8 @@ static int __ath_regd_init(struct ath_regulatory *reg) int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy, - int (*reg_notifier)(struct wiphy *wiphy, - struct regulatory_request *request)) + void (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request)) { struct ath_common *common = container_of(reg, struct ath_common, regulatory); diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 03a8268ccf21..37f53bd8fcb1 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -252,12 +252,12 @@ enum CountryCode { bool ath_is_world_regd(struct ath_regulatory *reg); bool ath_is_49ghz_allowed(u16 redomain); int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy, - int (*reg_notifier)(struct wiphy *wiphy, - struct regulatory_request *request)); + void (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request)); u32 ath_regd_get_band_ctl(struct ath_regulatory *reg, enum ieee80211_band band); -int ath_reg_notifier_apply(struct wiphy *wiphy, - struct regulatory_request *request, - struct ath_regulatory *reg); +void ath_reg_notifier_apply(struct wiphy *wiphy, + struct regulatory_request *request, + struct ath_regulatory *reg); #endif diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index 4eb3f0d52105..cdb62b8ccc79 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -702,8 +702,8 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy, } } -static int brcms_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) +static void brcms_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct brcms_info *wl = hw->priv; @@ -744,8 +744,6 @@ static int brcms_reg_notifier(struct wiphy *wiphy, if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G) wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi, brcms_c_japan_ccode(request->alpha2)); - - return 0; } void brcms_c_regd_init(struct brcms_c_info *wlc) diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index ec6d5d6b452e..230f8ebbe289 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -2132,6 +2132,21 @@ static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv) lbs_deb_leave(LBS_DEB_CFG80211); } +static void lbs_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct lbs_private *priv = wiphy_priv(wiphy); + + lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain " + "callback for domain %c%c\n", request->alpha2[0], + request->alpha2[1]); + + memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2)); + if (lbs_iface_active(priv)) + lbs_set_11d_domain_info(priv); + + lbs_deb_leave(LBS_DEB_CFG80211); +} /* * This function get's called after lbs_setup_firmware() determined the @@ -2184,24 +2199,6 @@ int lbs_cfg_register(struct lbs_private *priv) return ret; } -int lbs_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) -{ - struct lbs_private *priv = wiphy_priv(wiphy); - int ret = 0; - - lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain " - "callback for domain %c%c\n", request->alpha2[0], - request->alpha2[1]); - - memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2)); - if (lbs_iface_active(priv)) - ret = lbs_set_11d_domain_info(priv); - - lbs_deb_leave(LBS_DEB_CFG80211); - return ret; -} - void lbs_scan_deinit(struct lbs_private *priv) { lbs_deb_enter(LBS_DEB_CFG80211); diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h index 558168ce634d..10995f59fe34 100644 --- a/drivers/net/wireless/libertas/cfg.h +++ b/drivers/net/wireless/libertas/cfg.h @@ -10,9 +10,6 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev); int lbs_cfg_register(struct lbs_private *priv); void lbs_cfg_free(struct lbs_private *priv); -int lbs_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request); - void lbs_send_disconnect_notification(struct lbs_private *priv); void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event); diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index a875499f8945..a838ddecd91a 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -519,8 +519,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) * - Set by user * - Set bt Country IE */ -static int mwifiex_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) +static void mwifiex_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); @@ -540,8 +540,6 @@ static int mwifiex_reg_notifier(struct wiphy *wiphy, break; } mwifiex_send_domain_info_cmd_fw(wiphy); - - return 0; } /* diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c index 7e3ead774fb9..d7d0d4948b01 100644 --- a/drivers/net/wireless/rtlwifi/regd.c +++ b/drivers/net/wireless/rtlwifi/regd.c @@ -298,9 +298,9 @@ static void _rtl_reg_apply_world_flags(struct wiphy *wiphy, return; } -static int _rtl_reg_notifier_apply(struct wiphy *wiphy, - struct regulatory_request *request, - struct rtl_regulatory *reg) +static void _rtl_reg_notifier_apply(struct wiphy *wiphy, + struct regulatory_request *request, + struct rtl_regulatory *reg) { /* We always apply this */ _rtl_reg_apply_radar_flags(wiphy); @@ -314,8 +314,6 @@ static int _rtl_reg_notifier_apply(struct wiphy *wiphy, _rtl_reg_apply_world_flags(wiphy, request->initiator, reg); break; } - - return 0; } static const struct ieee80211_regdomain *_rtl_regdomain_select( @@ -348,9 +346,9 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select( static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg, struct wiphy *wiphy, - int (*reg_notifier) (struct wiphy *wiphy, - struct regulatory_request * - request)) + void (*reg_notifier) (struct wiphy *wiphy, + struct regulatory_request * + request)) { const struct ieee80211_regdomain *regd; @@ -379,7 +377,7 @@ static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode) } int rtl_regd_init(struct ieee80211_hw *hw, - int (*reg_notifier) (struct wiphy *wiphy, + void (*reg_notifier) (struct wiphy *wiphy, struct regulatory_request *request)) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -421,12 +419,12 @@ int rtl_regd_init(struct ieee80211_hw *hw, return 0; } -int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) +void rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct rtl_priv *rtlpriv = rtl_priv(hw); RT_TRACE(rtlpriv, COMP_REGD, DBG_LOUD, "\n"); - return _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd); + _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd); } diff --git a/drivers/net/wireless/rtlwifi/regd.h b/drivers/net/wireless/rtlwifi/regd.h index 70ef2f418a44..4e1f4f00e6e9 100644 --- a/drivers/net/wireless/rtlwifi/regd.h +++ b/drivers/net/wireless/rtlwifi/regd.h @@ -55,7 +55,7 @@ enum country_code_type_t { }; int rtl_regd_init(struct ieee80211_hw *hw, - int (*reg_notifier) (struct wiphy *wiphy, - struct regulatory_request *request)); -int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); + void (*reg_notifier) (struct wiphy *wiphy, + struct regulatory_request *request)); +void rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); #endif diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index d7de06359ae1..ce6e62a37e14 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -89,8 +89,8 @@ static int wl12xx_set_authorized(struct wl1271 *wl, return 0; } -static int wl1271_reg_notify(struct wiphy *wiphy, - struct regulatory_request *request) +static void wl1271_reg_notify(struct wiphy *wiphy, + struct regulatory_request *request) { struct ieee80211_supported_band *band; struct ieee80211_channel *ch; @@ -107,8 +107,6 @@ static int wl1271_reg_notify(struct wiphy *wiphy, IEEE80211_CHAN_PASSIVE_SCAN; } - - return 0; } static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e5f085c89221..4275127da05a 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2364,8 +2364,8 @@ struct wiphy { struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS]; /* Lets us get back the wiphy on the callback */ - int (*reg_notifier)(struct wiphy *wiphy, - struct regulatory_request *request); + void (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request); /* fields below are read-only, assigned by cfg80211 */ -- cgit v1.2.3-59-g8ed1b From 0ae997dc75efb60d47f0c71890f1e972f7d462c1 Mon Sep 17 00:00:00 2001 From: Yacine Belkadi Date: Sat, 12 Jan 2013 13:54:14 +0100 Subject: {cfg,mac}80211.h: fix some kernel-doc warnings When building the 80211 DocBook, scripts/kernel-doc reports the following type of warnings: Warning(include/net/cfg80211.h:334): No description found for return value of 'cfg80211_get_chandef_type' These warnings are only reported when scripts/kernel-doc runs in verbose mode. To fix these use "Return:" to describe function return values. Signed-off-by: Yacine Belkadi [adjust for freq_reg_info() change] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 159 +++++++++++++++++++++++++++++-------------------- include/net/mac80211.h | 74 ++++++++++++++++++----- 2 files changed, 153 insertions(+), 80 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 4275127da05a..3d8717a0d3b2 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -326,7 +326,7 @@ struct cfg80211_chan_def { * cfg80211_get_chandef_type - return old channel type from chandef * @chandef: the channel definition * - * Returns the old channel type (NOHT, HT20, HT40+/-) from a given + * Return: The old channel type (NOHT, HT20, HT40+/-) from a given * chandef, which must have a bandwidth allowing this conversion. */ static inline enum nl80211_channel_type @@ -364,7 +364,7 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef, * @chandef1: first channel definition * @chandef2: second channel definition * - * Returns %true if the channels defined by the channel definitions are + * Return: %true if the channels defined by the channel definitions are * identical, %false otherwise. */ static inline bool @@ -382,7 +382,7 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1, * @chandef1: first channel definition * @chandef2: second channel definition * - * Returns %NULL if the given channel definitions are incompatible, + * Return: %NULL if the given channel definitions are incompatible, * chandef1 or chandef2 otherwise. */ const struct cfg80211_chan_def * @@ -392,6 +392,7 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1, /** * cfg80211_chandef_valid - check if a channel definition is valid * @chandef: the channel definition to check + * Return: %true if the channel definition is valid. %false otherwise. */ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef); @@ -399,7 +400,8 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef); * cfg80211_chandef_usable - check if secondary channels can be used * @wiphy: the wiphy to validate against * @chandef: the channel definition to check - * @prohibited_flags: the regulatory chanenl flags that must not be set + * @prohibited_flags: the regulatory channel flags that must not be set + * Return: %true if secondary channels are usable. %false otherwise. */ bool cfg80211_chandef_usable(struct wiphy *wiphy, const struct cfg80211_chan_def *chandef, @@ -1266,7 +1268,7 @@ struct cfg80211_bss { * * Note that the return value is an RCU-protected pointer, so * rcu_read_lock() must be held when calling this function. - * Returns %NULL if not found. + * Return: %NULL if not found. */ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie); @@ -2409,6 +2411,7 @@ static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net) * wiphy_priv - return priv from wiphy * * @wiphy: the wiphy whose priv pointer to return + * Return: The priv of @wiphy. */ static inline void *wiphy_priv(struct wiphy *wiphy) { @@ -2420,6 +2423,7 @@ static inline void *wiphy_priv(struct wiphy *wiphy) * priv_to_wiphy - return the wiphy containing the priv * * @priv: a pointer previously returned by wiphy_priv + * Return: The wiphy of @priv. */ static inline struct wiphy *priv_to_wiphy(void *priv) { @@ -2442,6 +2446,7 @@ static inline void set_wiphy_dev(struct wiphy *wiphy, struct device *dev) * wiphy_dev - get wiphy dev pointer * * @wiphy: The wiphy whose device struct to look up + * Return: The dev of @wiphy. */ static inline struct device *wiphy_dev(struct wiphy *wiphy) { @@ -2452,6 +2457,7 @@ static inline struct device *wiphy_dev(struct wiphy *wiphy) * wiphy_name - get wiphy name * * @wiphy: The wiphy whose name to return + * Return: The name of @wiphy. */ static inline const char *wiphy_name(const struct wiphy *wiphy) { @@ -2467,8 +2473,8 @@ static inline const char *wiphy_name(const struct wiphy *wiphy) * Create a new wiphy and associate the given operations with it. * @sizeof_priv bytes are allocated for private use. * - * The returned pointer must be assigned to each netdev's - * ieee80211_ptr for proper operation. + * Return: A pointer to the new wiphy. This pointer must be + * assigned to each netdev's ieee80211_ptr for proper operation. */ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv); @@ -2477,7 +2483,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv); * * @wiphy: The wiphy to register. * - * Returns a non-negative wiphy index or a negative error code. + * Return: A non-negative wiphy index or a negative error code. */ extern int wiphy_register(struct wiphy *wiphy); @@ -2626,6 +2632,7 @@ static inline u8 *wdev_address(struct wireless_dev *wdev) * wdev_priv - return wiphy priv from wireless_dev * * @wdev: The wireless device whose wiphy's priv pointer to return + * Return: The wiphy priv of @wdev. */ static inline void *wdev_priv(struct wireless_dev *wdev) { @@ -2643,12 +2650,14 @@ static inline void *wdev_priv(struct wireless_dev *wdev) * ieee80211_channel_to_frequency - convert channel number to frequency * @chan: channel number * @band: band, necessary due to channel number overlap + * Return: The corresponding frequency (in MHz), or 0 if the conversion failed. */ extern int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band); /** * ieee80211_frequency_to_channel - convert frequency to channel number * @freq: center frequency + * Return: The corresponding channel, or 0 if the conversion failed. */ extern int ieee80211_frequency_to_channel(int freq); @@ -2665,6 +2674,7 @@ extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy, * ieee80211_get_channel - get channel struct from wiphy for specified frequency * @wiphy: the struct wiphy to get the channel for * @freq: the center frequency of the channel + * Return: The channel struct from @wiphy at @freq. */ static inline struct ieee80211_channel * ieee80211_get_channel(struct wiphy *wiphy, int freq) @@ -2679,10 +2689,10 @@ ieee80211_get_channel(struct wiphy *wiphy, int freq) * @basic_rates: bitmap of basic rates * @bitrate: the bitrate for which to find the basic rate * - * This function returns the basic rate corresponding to a given - * bitrate, that is the next lower bitrate contained in the basic - * rate map, which is, for this function, given as a bitmap of - * indices of rates in the band's bitrate table. + * Return: The basic rate corresponding to a given bitrate, that + * is the next lower bitrate contained in the basic rate map, + * which is, for this function, given as a bitmap of indices of + * rates in the band's bitrate table. */ struct ieee80211_rate * ieee80211_get_response_rate(struct ieee80211_supported_band *sband, @@ -2775,18 +2785,21 @@ extern const unsigned char bridge_tunnel_header[6]; /** * ieee80211_get_hdrlen_from_skb - get header length from data * + * @skb: the frame + * * Given an skb with a raw 802.11 header at the data pointer this function - * returns the 802.11 header length in bytes (not including encryption - * headers). If the data in the sk_buff is too short to contain a valid 802.11 - * header the function returns 0. + * returns the 802.11 header length. * - * @skb: the frame + * Return: The 802.11 header length in bytes (not including encryption + * headers). Or 0 if the data in the sk_buff is too short to contain a valid + * 802.11 header. */ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); /** * ieee80211_hdrlen - get header length in bytes from frame control * @fc: frame control field in little-endian format + * Return: The header length in bytes. */ unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc); @@ -2794,7 +2807,7 @@ unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc); * ieee80211_get_mesh_hdrlen - get mesh extension header length * @meshhdr: the mesh extension header, only the flags field * (first byte) will be accessed - * Returns the length of the extension header, which is always at + * Return: The length of the extension header, which is always at * least 6 bytes and at most 18 if address 5 and 6 are present. */ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); @@ -2812,6 +2825,7 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); * @skb: the 802.11 data frame * @addr: the device MAC address * @iftype: the virtual interface type + * Return: 0 on success. Non-zero on error. */ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, enum nl80211_iftype iftype); @@ -2823,6 +2837,7 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, * @iftype: the virtual interface type * @bssid: the network bssid (used only for iftype STATION and ADHOC) * @qos: build 802.11 QoS data frame + * Return: 0 on success, or a negative error code. */ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, enum nl80211_iftype iftype, u8 *bssid, bool qos); @@ -2850,6 +2865,7 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, /** * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame * @skb: the data frame + * Return: The 802.1p/1d tag. */ unsigned int cfg80211_classify8021d(struct sk_buff *skb); @@ -2860,12 +2876,13 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb); * @ies: data consisting of IEs * @len: length of data * - * This function will return %NULL if the element ID could - * not be found or if the element is invalid (claims to be - * longer than the given data), or a pointer to the first byte - * of the requested element, that is the byte containing the - * element ID. There are no checks on the element length - * other than having to fit into the given data. + * Return: %NULL if the element ID could not be found or if + * the element is invalid (claims to be longer than the given + * data), or a pointer to the first byte of the requested + * element, that is the byte containing the element ID. + * + * Note: There are no checks on the element length other than + * having to fit into the given data. */ const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len); @@ -2877,12 +2894,13 @@ const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len); * @ies: data consisting of IEs * @len: length of data * - * This function will return %NULL if the vendor specific element ID - * could not be found or if the element is invalid (claims to be - * longer than the given data), or a pointer to the first byte - * of the requested element, that is the byte containing the - * element ID. There are no checks on the element length - * other than having to fit into the given data. + * Return: %NULL if the vendor specific element ID could not be found or if the + * element is invalid (claims to be longer than the given data), or a pointer to + * the first byte of the requested element, that is the byte containing the + * element ID. + * + * Note: There are no checks on the element length other than having to fit into + * the given data. */ const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type, const u8 *ies, int len); @@ -2915,6 +2933,8 @@ const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type, * * Drivers should check the return value, its possible you can get * an -ENOMEM. + * + * Return: 0 on success. -ENOMEM. */ extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2); @@ -2944,13 +2964,13 @@ extern void wiphy_apply_custom_regulatory( * it wants to follow we respect that unless a country IE has been received * and processed already. * - * When an error occurs, for example if no rule can be found, the return value - * is encoded using ERR_PTR(). Use IS_ERR() to check and PTR_ERR() to obtain - * the numeric return value. The numeric return value will be -ERANGE if we - * determine the given center_freq does not even have a regulatory rule for a - * frequency range in the center_freq's band. See freq_in_rule_band() for our - * current definition of a band -- this is purely subjective and right now it's - * 802.11 specific. + * Return: A valid pointer, or, when an error occurs, for example if no rule + * can be found, the return value is encoded using ERR_PTR(). Use IS_ERR() to + * check and PTR_ERR() to obtain the numeric return value. The numeric return + * value will be -ERANGE if we determine the given center_freq does not even + * have a regulatory rule for a frequency range in the center_freq's band. + * See freq_in_rule_band() for our current definition of a band -- this is + * purely subjective and right now it's 802.11 specific. */ const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy, u32 center_freq); @@ -3000,7 +3020,8 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy); * This informs cfg80211 that BSS information was found and * the BSS should be updated/added. * - * NOTE: Returns a referenced struct, must be released with cfg80211_put_bss()! + * Return: A referenced struct, must be released with cfg80211_put_bss()! + * Or %NULL on error. */ struct cfg80211_bss * __must_check cfg80211_inform_bss_frame(struct wiphy *wiphy, @@ -3025,7 +3046,8 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, * This informs cfg80211 that BSS information was found and * the BSS should be updated/added. * - * NOTE: Returns a referenced struct, must be released with cfg80211_put_bss()! + * Return: A referenced struct, must be released with cfg80211_put_bss()! + * Or %NULL on error. */ struct cfg80211_bss * __must_check cfg80211_inform_bss(struct wiphy *wiphy, @@ -3302,16 +3324,18 @@ void wiphy_rfkill_stop_polling(struct wiphy *wiphy); * the testmode command. Since it is intended for a reply, calling * it outside of the @testmode_cmd operation is invalid. * - * The returned skb (or %NULL if any errors happen) is pre-filled - * with the wiphy index and set up in a way that any data that is - * put into the skb (with skb_put(), nla_put() or similar) will end - * up being within the %NL80211_ATTR_TESTDATA attribute, so all that - * needs to be done with the skb is adding data for the corresponding - * userspace tool which can then read that data out of the testdata - * attribute. You must not modify the skb in any other way. + * The returned skb is pre-filled with the wiphy index and set up in + * a way that any data that is put into the skb (with skb_put(), + * nla_put() or similar) will end up being within the + * %NL80211_ATTR_TESTDATA attribute, so all that needs to be done + * with the skb is adding data for the corresponding userspace tool + * which can then read that data out of the testdata attribute. You + * must not modify the skb in any other way. * * When done, call cfg80211_testmode_reply() with the skb and return * its error code as the result of the @testmode_cmd operation. + * + * Return: An allocated and pre-filled skb. %NULL if any errors happen. */ struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, int approxlen); @@ -3321,11 +3345,12 @@ struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, * @skb: The skb, must have been allocated with * cfg80211_testmode_alloc_reply_skb() * - * Returns an error code or 0 on success, since calling this - * function will usually be the last thing before returning - * from the @testmode_cmd you should return the error code. - * Note that this function consumes the skb regardless of the - * return value. + * Since calling this function will usually be the last thing + * before returning from the @testmode_cmd you should return + * the error code. Note that this function consumes the skb + * regardless of the return value. + * + * Return: An error code or 0 on success. */ int cfg80211_testmode_reply(struct sk_buff *skb); @@ -3339,14 +3364,16 @@ int cfg80211_testmode_reply(struct sk_buff *skb); * This function allocates and pre-fills an skb for an event on the * testmode multicast group. * - * The returned skb (or %NULL if any errors happen) is set up in the - * same way as with cfg80211_testmode_alloc_reply_skb() but prepared - * for an event. As there, you should simply add data to it that will - * then end up in the %NL80211_ATTR_TESTDATA attribute. Again, you must - * not modify the skb in any other way. + * The returned skb is set up in the same way as with + * cfg80211_testmode_alloc_reply_skb() but prepared for an event. As + * there, you should simply add data to it that will then end up in the + * %NL80211_ATTR_TESTDATA attribute. Again, you must not modify the skb + * in any other way. * * When done filling the skb, call cfg80211_testmode_event() with the * skb to send the event. + * + * Return: An allocated and pre-filled skb. %NULL if any errors happen. */ struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp); @@ -3527,13 +3554,13 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, * @len: length of the frame data * @gfp: context flags * - * Returns %true if a user space application has registered for this frame. + * This function is called whenever an Action frame is received for a station + * mode interface, but is not processed in kernel. + * + * Return: %true if a user space application has registered for this frame. * For action frames, that makes it responsible for rejecting unrecognized * action frames; %false otherwise, in which case for action frames the * driver is responsible for rejecting the frame. - * - * This function is called whenever an Action frame is received for a station - * mode interface, but is not processed in kernel. */ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_dbm, const u8 *buf, size_t len, gfp_t gfp); @@ -3625,7 +3652,7 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, * This function is used in AP mode (only!) to inform userspace that * a spurious class 3 frame was received, to be able to deauth the * sender. - * Returns %true if the frame was passed to userspace (or this failed + * Return: %true if the frame was passed to userspace (or this failed * for a reason other than not having a subscription.) */ bool cfg80211_rx_spurious_frame(struct net_device *dev, @@ -3641,7 +3668,7 @@ bool cfg80211_rx_spurious_frame(struct net_device *dev, * an associated station sent a 4addr frame but that wasn't expected. * It is allowed and desirable to send this event only once for each * station to avoid event flooding. - * Returns %true if the frame was passed to userspace (or this failed + * Return: %true if the frame was passed to userspace (or this failed * for a reason other than not having a subscription.) */ bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, @@ -3679,8 +3706,8 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy, * @wiphy: the wiphy * @chandef: the channel definition * - * This function returns true if there is no secondary channel or the secondary - * channel(s) can be used for beaconing (i.e. is not a radar channel etc.) + * Return: %true if there is no secondary channel or the secondary channel(s) + * can be used for beaconing (i.e. is not a radar channel etc.) */ bool cfg80211_reg_can_beacon(struct wiphy *wiphy, struct cfg80211_chan_def *chandef); @@ -3750,9 +3777,9 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev); * The function finds a given P2P attribute in the (vendor) IEs and * copies its contents to the given buffer. * - * The return value is a negative error code (-%EILSEQ or -%ENOENT) if - * the data is malformed or the attribute can't be found (respectively), - * or the length of the found attribute (which can be zero). + * Return: A negative error code (-%EILSEQ or -%ENOENT) if the data is + * malformed or the attribute can't be found (respectively), or the + * length of the found attribute (which can be zero). */ int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, enum ieee80211_p2p_attr_id attr, diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 23daed3c78ed..79bc8709e83b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1522,6 +1522,8 @@ struct ieee80211_hw { * structure can then access it via hw->priv. Note that mac802111 drivers should * not use wiphy_priv() to try to get their private driver structure as this * is already used internally by mac80211. + * + * Return: The mac80211 driver hw struct of @wiphy. */ struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy); @@ -2673,6 +2675,8 @@ struct ieee80211_ops { * * @priv_data_len: length of private data * @ops: callbacks for this device + * + * Return: A pointer to the new hardware device, or %NULL on error. */ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops); @@ -2685,6 +2689,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, * need to fill the contained wiphy's information. * * @hw: the device to register as returned by ieee80211_alloc_hw() + * + * Return: 0 on success. An error code otherwise. */ int ieee80211_register_hw(struct ieee80211_hw *hw); @@ -2731,6 +2737,8 @@ extern char *__ieee80211_create_tpt_led_trigger( * of the trigger so you can automatically link the LED device. * * @hw: the hardware to get the LED trigger name for + * + * Return: The name of the LED trigger. %NULL if not configured for LEDs. */ static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw) { @@ -2750,6 +2758,8 @@ static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw) * of the trigger so you can automatically link the LED device. * * @hw: the hardware to get the LED trigger name for + * + * Return: The name of the LED trigger. %NULL if not configured for LEDs. */ static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw) { @@ -2769,6 +2779,8 @@ static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw) * of the trigger so you can automatically link the LED device. * * @hw: the hardware to get the LED trigger name for + * + * Return: The name of the LED trigger. %NULL if not configured for LEDs. */ static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) { @@ -2788,6 +2800,8 @@ static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) * of the trigger so you can automatically link the LED device. * * @hw: the hardware to get the LED trigger name for + * + * Return: The name of the LED trigger. %NULL if not configured for LEDs. */ static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw) { @@ -2805,9 +2819,10 @@ static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw) * @blink_table: the blink table -- needs to be ordered by throughput * @blink_table_len: size of the blink table * - * This function returns %NULL (in case of error, or if no LED - * triggers are configured) or the name of the new trigger. - * This function must be called before ieee80211_register_hw(). + * Return: %NULL (in case of error, or if no LED triggers are + * configured) or the name of the new trigger. + * + * Note: This function must be called before ieee80211_register_hw(). */ static inline char * ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw, unsigned int flags, @@ -2940,10 +2955,10 @@ static inline void ieee80211_rx_ni(struct ieee80211_hw *hw, * Calls to this function for a single hardware must be synchronized against * each other. * - * The function returns -EINVAL when the requested PS mode is already set. - * * @sta: currently connected sta * @start: start or stop PS + * + * Return: 0 on success. -EINVAL when the requested PS mode is already set. */ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start); @@ -2957,6 +2972,8 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start); * * @sta: currently connected sta * @start: start or stop PS + * + * Return: Like ieee80211_sta_ps_transition(). */ static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta, bool start) @@ -3094,6 +3111,8 @@ void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets); * according to the current DTIM parameters/TIM bitmap. * * The driver is responsible for freeing the returned skb. + * + * Return: The beacon template. %NULL on error. */ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -3105,6 +3124,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, * @vif: &struct ieee80211_vif pointer from the add_interface callback. * * See ieee80211_beacon_get_tim(). + * + * Return: See ieee80211_beacon_get_tim(). */ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif) @@ -3121,6 +3142,8 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, * hardware. The destination address should be set by the caller. * * Can only be called in AP mode. + * + * Return: The Probe Response template. %NULL on error. */ struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif); @@ -3136,6 +3159,8 @@ struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw, * * Note: Caller (or hardware) is responsible for setting the * &IEEE80211_FCTL_PM bit. + * + * Return: The PS Poll template. %NULL on error. */ struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif); @@ -3151,6 +3176,8 @@ struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, * * Note: Caller (or hardware) is responsible for setting the * &IEEE80211_FCTL_PM bit as well as Duration and Sequence Control fields. + * + * Return: The nullfunc template. %NULL on error. */ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif); @@ -3165,6 +3192,8 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, * * Creates a Probe Request template which can, for example, be uploaded to * hardware. + * + * Return: The Probe Request template. %NULL on error. */ struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -3200,6 +3229,8 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, * If the RTS is generated in firmware, but the host system must provide * the duration field, the low-level driver uses this function to receive * the duration field value in little-endian byteorder. + * + * Return: The duration. */ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, size_t frame_len, @@ -3235,6 +3266,8 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, * If the CTS-to-self is generated in firmware, but the host system must provide * the duration field, the low-level driver uses this function to receive * the duration field value in little-endian byteorder. + * + * Return: The duration. */ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -3251,6 +3284,8 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, * * Calculate the duration field of some generic frame, given its * length and transmission rate (in 100kbps). + * + * Return: The duration. */ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -3267,9 +3302,10 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, * hardware/firmware does not implement buffering of broadcast/multicast * frames when power saving is used, 802.11 code buffers them in the host * memory. The low-level driver uses this function to fetch next buffered - * frame. In most cases, this is used when generating beacon frame. This - * function returns a pointer to the next buffered skb or NULL if no more - * buffered frames are available. + * frame. In most cases, this is used when generating beacon frame. + * + * Return: A pointer to the next buffered skb or NULL if no more buffered + * frames are available. * * Note: buffered frames are returned only after DTIM beacon frame was * generated with ieee80211_beacon_get() and the low-level driver must thus @@ -3449,6 +3485,8 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue); * @queue: queue number (counted from zero). * * Drivers should use this function instead of netif_stop_queue. + * + * Return: %true if the queue is stopped. %false otherwise. */ int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue); @@ -3646,7 +3684,9 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, * @vif: virtual interface to look for station on * @addr: station's address * - * This function must be called under RCU lock and the + * Return: The station, if found. %NULL otherwise. + * + * Note: This function must be called under RCU lock and the * resulting pointer is only valid under RCU lock as well. */ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, @@ -3659,7 +3699,9 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, * @addr: remote station's address * @localaddr: local address (vif->sdata->vif.addr). Use NULL for 'any'. * - * This function must be called under RCU lock and the + * Return: The station, if found. %NULL otherwise. + * + * Note: This function must be called under RCU lock and the * resulting pointer is only valid under RCU lock as well. * * NOTE: You may pass NULL for localaddr, but then you will just get @@ -3789,7 +3831,9 @@ void ieee80211_iter_chan_contexts_atomic( * information. This function must only be called from within the * .bss_info_changed callback function and only in managed mode. The function * is only useful when the interface is associated, otherwise it will return - * NULL. + * %NULL. + * + * Return: The Probe Request template. %NULL on error. */ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif); @@ -4136,12 +4180,14 @@ void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif, void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif); /** - * ieee80211_ave_rssi - report the average rssi for the specified interface + * ieee80211_ave_rssi - report the average RSSI for the specified interface * * @vif: the specified virtual interface * - * This function return the average rssi value for the requested interface. - * It assumes that the given vif is valid. + * Note: This function assumes that the given vif is valid. + * + * Return: The average RSSI value for the requested interface, or 0 if not + * applicable. */ int ieee80211_ave_rssi(struct ieee80211_vif *vif); -- cgit v1.2.3-59-g8ed1b From 8f21b0adfe95907926da1bb0bcd3382b13d0143d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 11 Jan 2013 00:28:01 +0100 Subject: mac80211: call restart complete at wowlan resume time When the driver's resume function can't completely restore the configuration in the device, it returns 1 from the callback which will be treated like a HW restart request, but done directly. In this case, also call the driver's restart_complete() function so it can finish the reconfiguration there. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 5 ++++- net/mac80211/util.c | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 79bc8709e83b..3037f49e51c8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2488,7 +2488,10 @@ enum ieee80211_rate_control_changed { * * @restart_complete: Called after a call to ieee80211_restart_hw(), when the * reconfiguration has completed. This can help the driver implement the - * reconfiguration step. This callback may sleep. + * reconfiguration step. Also called when reconfiguring because the + * driver's resume function returned 1, as this is just like an "inline" + * hardware restart. This callback may sleep. + * */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0ad51e14f3c8..7519018ff71a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1358,9 +1358,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) struct ieee80211_chanctx *ctx; struct sta_info *sta; int res, i; -#ifdef CONFIG_PM bool reconfig_due_to_wowlan = false; +#ifdef CONFIG_PM if (local->suspended) local->resuming = true; @@ -1656,10 +1656,11 @@ int ieee80211_reconfig(struct ieee80211_local *local) * If this is for hw restart things are still running. * We may want to change that later, however. */ - if (!local->suspended) { + if (!local->suspended || reconfig_due_to_wowlan) drv_restart_complete(local); + + if (!local->suspended) return 0; - } #ifdef CONFIG_PM /* first set suspended false, then resuming */ -- cgit v1.2.3-59-g8ed1b From 9bdbf04db099c11bbbaea9dcea7465c508531fb8 Mon Sep 17 00:00:00 2001 From: Marco Porsch Date: Mon, 7 Jan 2013 16:04:51 +0100 Subject: {cfg,nl,mac}80211: set beacon interval and DTIM period on mesh join Move the default mesh beacon interval and DTIM period to cfg80211 and make them accessible to nl80211. This enables setting both values when joining an MBSS. Previously the DTIM parameter was not set by mac80211 so the driver's default value was used. Signed-off-by: Marco Porsch Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++++ net/mac80211/cfg.c | 3 +++ net/mac80211/mesh.c | 1 - net/mac80211/mesh.h | 2 -- net/wireless/mesh.c | 5 +++++ net/wireless/nl80211.c | 15 +++++++++++++++ 6 files changed, 27 insertions(+), 3 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 3d8717a0d3b2..516aded3697f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1036,6 +1036,8 @@ struct mesh_config { * @ie_len: length of vendor information elements * @is_authenticated: this mesh requires authentication * @is_secure: this mesh uses security + * @dtim_period: DTIM period to use + * @beacon_interval: beacon interval to use * @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a] * * These parameters are fixed when the mesh is created. @@ -1051,6 +1053,8 @@ struct mesh_setup { u8 ie_len; bool is_authenticated; bool is_secure; + u8 dtim_period; + u16 beacon_interval; int mcast_rate[IEEE80211_NUM_BANDS]; }; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8a91dd22d571..36aa65f495ff 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1666,6 +1666,9 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, memcpy(sdata->vif.bss_conf.mcast_rate, setup->mcast_rate, sizeof(setup->mcast_rate)); + sdata->vif.bss_conf.beacon_int = setup->beacon_interval; + sdata->vif.bss_conf.dtim_period = setup->dtim_period; + return 0; } diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 245885841c8d..694e27376afa 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -625,7 +625,6 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) ieee80211_queue_work(&local->hw, &sdata->work); sdata->vif.bss_conf.ht_operation_mode = ifmsh->mshcfg.ht_opmode; - sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; sdata->vif.bss_conf.enable_beacon = true; sdata->vif.bss_conf.basic_rates = ieee80211_mandatory_rates(local, band); diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index c07f6fc63dc6..aff301544c7f 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -191,8 +191,6 @@ struct mesh_rmc { #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) -#define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */ - #define MESH_PATH_EXPIRE (600 * HZ) /* Default maximum number of plinks per interface */ diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index f9d6ce5cfabb..0fe8ceb5444e 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -44,6 +44,9 @@ #define MESH_SYNC_NEIGHBOR_OFFSET_MAX 50 +#define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units (=TUs) */ +#define MESH_DEFAULT_DTIM_PERIOD 2 + const struct mesh_config default_mesh_config = { .dot11MeshRetryTimeout = MESH_RET_T, .dot11MeshConfirmTimeout = MESH_CONF_T, @@ -79,6 +82,8 @@ const struct mesh_setup default_mesh_setup = { .ie = NULL, .ie_len = 0, .is_secure = false, + .beacon_interval = MESH_DEFAULT_BEACON_INTERVAL, + .dtim_period = MESH_DEFAULT_DTIM_PERIOD, }; int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ceb27fda9ec5..d5842eb35aec 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6669,6 +6669,21 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]))) return -EINVAL; + if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { + setup.beacon_interval = + nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); + if (setup.beacon_interval < 10 || + setup.beacon_interval > 10000) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) { + setup.dtim_period = + nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); + if (setup.dtim_period < 1 || setup.dtim_period > 100) + return -EINVAL; + } + if (info->attrs[NL80211_ATTR_MESH_SETUP]) { /* parse additional setup parameters if given */ err = nl80211_parse_mesh_setup(info, &setup); -- cgit v1.2.3-59-g8ed1b From 3b1c5a5307fb5277f395efdcf330c064d79df07d Mon Sep 17 00:00:00 2001 From: Marco Porsch Date: Mon, 7 Jan 2013 16:04:52 +0100 Subject: {cfg,nl}80211: mesh power mode primitives and userspace access Add the nl80211_mesh_power_mode enumeration which holds possible values for the mesh power mode. These modes are unknown, active, light sleep and deep sleep. Add power_mode entry to the mesh config structure to hold the user-configured default mesh power mode. This value will be used for new peer links. Add the dot11MeshAwakeWindowDuration value to the mesh config. The awake window is a duration in TU describing how long the STA will stay awake after transmitting its beacon in PS mode. Add access routines to: - get/set local link-specific power mode (STA) - get remote STA's link-specific power mode (STA) - get remote STA's non-peer power mode (STA) - get/set default mesh power mode (mesh config) - get/set mesh awake window duration (mesh config) All config changes may be done at mesh runtime and take effect immediately. Signed-off-by: Marco Porsch Signed-off-by: Ivan Bezyazychnyy Signed-off-by: Mike Krinkin [fix commit message line length, error handling in set station] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 21 ++++++++++++++++++++ include/uapi/linux/nl80211.h | 47 ++++++++++++++++++++++++++++++++++++++++++++ net/wireless/mesh.c | 3 +++ net/wireless/nl80211.c | 43 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 113 insertions(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 516aded3697f..d9f08f65f7a5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -610,6 +610,8 @@ enum station_parameters_apply_mask { * @sta_modify_mask: bitmap indicating which parameters changed * (for those that don't have a natural "no change" value), * see &enum station_parameters_apply_mask + * @local_pm: local link-specific mesh power save mode (no change when set + * to unknown) */ struct station_parameters { u8 *supported_rates; @@ -625,6 +627,7 @@ struct station_parameters { struct ieee80211_vht_cap *vht_capa; u8 uapsd_queues; u8 max_sp; + enum nl80211_mesh_power_mode local_pm; }; /** @@ -655,6 +658,9 @@ struct station_parameters { * @STATION_INFO_STA_FLAGS: @sta_flags filled * @STATION_INFO_BEACON_LOSS_COUNT: @beacon_loss_count filled * @STATION_INFO_T_OFFSET: @t_offset filled + * @STATION_INFO_LOCAL_PM: @local_pm filled + * @STATION_INFO_PEER_PM: @peer_pm filled + * @STATION_INFO_NONPEER_PM: @nonpeer_pm filled */ enum station_info_flags { STATION_INFO_INACTIVE_TIME = 1<<0, @@ -678,6 +684,9 @@ enum station_info_flags { STATION_INFO_STA_FLAGS = 1<<18, STATION_INFO_BEACON_LOSS_COUNT = 1<<19, STATION_INFO_T_OFFSET = 1<<20, + STATION_INFO_LOCAL_PM = 1<<21, + STATION_INFO_PEER_PM = 1<<22, + STATION_INFO_NONPEER_PM = 1<<23, }; /** @@ -791,6 +800,9 @@ struct sta_bss_parameters { * @sta_flags: station flags mask & values * @beacon_loss_count: Number of times beacon loss event has triggered. * @t_offset: Time offset of the station relative to this host. + * @local_pm: local mesh STA power save mode + * @peer_pm: peer mesh STA power save mode + * @nonpeer_pm: non-peer mesh STA power save mode */ struct station_info { u32 filled; @@ -820,6 +832,9 @@ struct station_info { u32 beacon_loss_count; s64 t_offset; + enum nl80211_mesh_power_mode local_pm; + enum nl80211_mesh_power_mode peer_pm; + enum nl80211_mesh_power_mode nonpeer_pm; /* * Note: Add a new enum station_info_flags value for each new field and @@ -995,6 +1010,10 @@ struct bss_parameters { * @dot11MeshHWMPconfirmationInterval: The minimum interval of time (in TUs) * during which a mesh STA can send only one Action frame containing * a PREQ element for root path confirmation. + * @power_mode: The default mesh power save mode which will be the initial + * setting for new peer links. + * @dot11MeshAwakeWindowDuration: The duration in TUs the STA will remain awake + * after transmitting its beacon. */ struct mesh_config { u16 dot11MeshRetryTimeout; @@ -1022,6 +1041,8 @@ struct mesh_config { u32 dot11MeshHWMPactivePathToRootTimeout; u16 dot11MeshHWMProotInterval; u16 dot11MeshHWMPconfirmationInterval; + enum nl80211_mesh_power_mode power_mode; + u16 dot11MeshAwakeWindowDuration; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 547017100a30..6c4f703ae890 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1310,6 +1310,9 @@ enum nl80211_commands { * if not given in START_AP 0 is assumed, if not given in SET_BSS * no change is made. * + * @NL80211_ATTR_LOCAL_MESH_POWER_MODE: local mesh STA link-specific power mode + * defined in &enum nl80211_mesh_power_mode. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1580,6 +1583,8 @@ enum nl80211_attrs { NL80211_ATTR_P2P_CTWINDOW, NL80211_ATTR_P2P_OPPPS, + NL80211_ATTR_LOCAL_MESH_POWER_MODE, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1838,6 +1843,10 @@ enum nl80211_sta_bss_param { * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update. * @NL80211_STA_INFO_BEACON_LOSS: count of times beacon loss was detected (u32) * @NL80211_STA_INFO_T_OFFSET: timing offset with respect to this STA (s64) + * @NL80211_STA_INFO_LOCAL_PM: local mesh STA link-specific power mode + * @NL80211_STA_INFO_PEER_PM: peer mesh STA link-specific power mode + * @NL80211_STA_INFO_NONPEER_PM: neighbor mesh STA power save mode towards + * non-peer STA * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute */ @@ -1862,6 +1871,9 @@ enum nl80211_sta_info { NL80211_STA_INFO_STA_FLAGS, NL80211_STA_INFO_BEACON_LOSS, NL80211_STA_INFO_T_OFFSET, + NL80211_STA_INFO_LOCAL_PM, + NL80211_STA_INFO_PEER_PM, + NL80211_STA_INFO_NONPEER_PM, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, @@ -2252,6 +2264,34 @@ enum nl80211_mntr_flags { NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1 }; +/** + * enum nl80211_mesh_power_mode - mesh power save modes + * + * @NL80211_MESH_POWER_UNKNOWN: The mesh power mode of the mesh STA is + * not known or has not been set yet. + * @NL80211_MESH_POWER_ACTIVE: Active mesh power mode. The mesh STA is + * in Awake state all the time. + * @NL80211_MESH_POWER_LIGHT_SLEEP: Light sleep mode. The mesh STA will + * alternate between Active and Doze states, but will wake up for + * neighbor's beacons. + * @NL80211_MESH_POWER_DEEP_SLEEP: Deep sleep mode. The mesh STA will + * alternate between Active and Doze states, but may not wake up + * for neighbor's beacons. + * + * @__NL80211_MESH_POWER_AFTER_LAST - internal use + * @NL80211_MESH_POWER_MAX - highest possible power save level + */ + +enum nl80211_mesh_power_mode { + NL80211_MESH_POWER_UNKNOWN, + NL80211_MESH_POWER_ACTIVE, + NL80211_MESH_POWER_LIGHT_SLEEP, + NL80211_MESH_POWER_DEEP_SLEEP, + + __NL80211_MESH_POWER_AFTER_LAST, + NL80211_MESH_POWER_MAX = __NL80211_MESH_POWER_AFTER_LAST - 1 +}; + /** * enum nl80211_meshconf_params - mesh configuration parameters * @@ -2346,6 +2386,11 @@ enum nl80211_mntr_flags { * (in TUs) during which a mesh STA can send only one Action frame * containing a PREQ element for root path confirmation. * + * @NL80211_MESHCONF_POWER_MODE: Default mesh power mode for new peer links. + * type &enum nl80211_mesh_power_mode (u32) + * + * @NL80211_MESHCONF_AWAKE_WINDOW: awake window duration (in TUs) + * * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use */ enum nl80211_meshconf_params { @@ -2375,6 +2420,8 @@ enum nl80211_meshconf_params { NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, NL80211_MESHCONF_HWMP_ROOT_INTERVAL, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, + NL80211_MESHCONF_POWER_MODE, + NL80211_MESHCONF_AWAKE_WINDOW, /* keep last */ __NL80211_MESHCONF_ATTR_AFTER_LAST, diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 0fe8ceb5444e..55957a284f6c 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -46,6 +46,7 @@ #define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units (=TUs) */ #define MESH_DEFAULT_DTIM_PERIOD 2 +#define MESH_DEFAULT_AWAKE_WINDOW 10 /* in 1024 us units (=TUs) */ const struct mesh_config default_mesh_config = { .dot11MeshRetryTimeout = MESH_RET_T, @@ -72,6 +73,8 @@ const struct mesh_config default_mesh_config = { .dot11MeshHWMPactivePathToRootTimeout = MESH_PATH_TO_ROOT_TIMEOUT, .dot11MeshHWMProotInterval = MESH_ROOT_INTERVAL, .dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL, + .power_mode = NL80211_MESH_POWER_ACTIVE, + .dot11MeshAwakeWindowDuration = MESH_DEFAULT_AWAKE_WINDOW, }; const struct mesh_setup default_mesh_setup = { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d5842eb35aec..1a7a710fe9bf 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3001,6 +3001,18 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, nla_put_u32(msg, NL80211_STA_INFO_BEACON_LOSS, sinfo->beacon_loss_count)) goto nla_put_failure; + if ((sinfo->filled & STATION_INFO_LOCAL_PM) && + nla_put_u32(msg, NL80211_STA_INFO_LOCAL_PM, + sinfo->local_pm)) + goto nla_put_failure; + if ((sinfo->filled & STATION_INFO_PEER_PM) && + nla_put_u32(msg, NL80211_STA_INFO_PEER_PM, + sinfo->peer_pm)) + goto nla_put_failure; + if ((sinfo->filled & STATION_INFO_NONPEER_PM) && + nla_put_u32(msg, NL80211_STA_INFO_NONPEER_PM, + sinfo->nonpeer_pm)) + goto nla_put_failure; if (sinfo->filled & STATION_INFO_BSS_PARAM) { bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); if (!bss_param) @@ -3206,6 +3218,17 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) params.plink_state = nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); + if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) { + enum nl80211_mesh_power_mode pm = nla_get_u32( + info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]); + + if (pm <= NL80211_MESH_POWER_UNKNOWN || + pm > NL80211_MESH_POWER_MAX) + return -EINVAL; + + params.local_pm = pm; + } + switch (dev->ieee80211_ptr->iftype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: @@ -3213,6 +3236,8 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) /* disallow mesh-specific things */ if (params.plink_action) return -EINVAL; + if (params.local_pm) + return -EINVAL; /* TDLS can't be set, ... */ if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) @@ -3265,6 +3290,8 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) /* disallow things sta doesn't support */ if (params.plink_action) return -EINVAL; + if (params.local_pm) + return -EINVAL; /* reject any changes other than AUTHORIZED */ if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) return -EINVAL; @@ -3922,7 +3949,11 @@ static int nl80211_get_mesh_config(struct sk_buff *skb, nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL, cur_params.dot11MeshHWMProotInterval) || nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, - cur_params.dot11MeshHWMPconfirmationInterval)) + cur_params.dot11MeshHWMPconfirmationInterval) || + nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE, + cur_params.power_mode) || + nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW, + cur_params.dot11MeshAwakeWindowDuration)) goto nla_put_failure; nla_nest_end(msg, pinfoattr); genlmsg_end(msg, hdr); @@ -3961,6 +3992,8 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 }, [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 }, [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 }, + [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 }, + [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 }, }; static const struct nla_policy @@ -4088,6 +4121,14 @@ do { \ 1, 65535, mask, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode, + NL80211_MESH_POWER_ACTIVE, + NL80211_MESH_POWER_MAX, + mask, NL80211_MESHCONF_POWER_MODE, + nla_get_u32); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration, + 0, 65535, mask, + NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16); if (mask_out) *mask_out = mask; -- cgit v1.2.3-59-g8ed1b From 1c18f1452a772dfe884ed25677bddb3ecaf9c43a Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 8 Jan 2013 10:17:27 +0100 Subject: nl80211: allow user-space to set address for P2P_DEVICE As per email discussion Jouni Malinen pointed out that: "P2P message exchanges can be executed on the current operating channel of any operation (both P2P and non-P2P station). These can be on 5 GHz and even on 60 GHz (so yes, you _can_ do GO Negotiation on 60 GHz). As an example, it would be possible to receive a GO Negotiation Request frame on a 5 GHz only radio and then to complete GO Negotiation on that band. This can happen both when connected to a P2P group (through client discoverability mechanism) and when connected to a legacy AP (assuming the station receive Probe Request frame from full scan in the beginning of P2P device discovery)." This means that P2P messages can be sent over different radio devices. However, these should use the same P2P device address so it should be able to provision this from user-space. This patch adds a parameter for this to struct vif_params which should only be used during creation of the P2P device interface. Cc: Jouni Malinen Cc: Greg Goldman Cc: Jithu Jance Signed-off-by: Arend van Spriel [add error checking] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++++ net/wireless/nl80211.c | 7 +++++++ 2 files changed, 11 insertions(+) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d9f08f65f7a5..d81e730962cc 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -281,9 +281,13 @@ struct ieee80211_supported_band { /** * struct vif_params - describes virtual interface parameters * @use_4addr: use 4-address frames + * @macaddr: address to use for this virtual interface. This will only + * be used for non-netdevice interfaces. If this parameter is set + * to zero address the driver may determine the address as needed. */ struct vif_params { int use_4addr; + u8 macaddr[ETH_ALEN]; }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1a7a710fe9bf..d543cf152100 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2079,6 +2079,13 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) !(rdev->wiphy.interface_modes & (1 << type))) return -EOPNOTSUPP; + if (type == NL80211_IFTYPE_P2P_DEVICE && info->attrs[NL80211_ATTR_MAC]) { + nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC], + ETH_ALEN); + if (!is_valid_ether_addr(params.macaddr)) + return -EADDRNOTAVAIL; + } + if (info->attrs[NL80211_ATTR_4ADDR]) { params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); -- cgit v1.2.3-59-g8ed1b From cee00a959c0a86571e6f99cf42f0261d7e54d2ae Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 15 Jan 2013 17:15:57 +0200 Subject: cfg80211: Allow use_mfp to be specified with the connect command The NL80211_ATTR_USE_MFP attribute was originally added for NL80211_CMD_ASSOCIATE, but it is actually as useful (if not even more useful) with NL80211_CMD_CONNECT, so process that attribute with the connect command, too. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 ++ include/uapi/linux/nl80211.h | 6 +++--- net/wireless/nl80211.c | 9 +++++++++ net/wireless/sme.c | 3 ++- 4 files changed, 16 insertions(+), 4 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d81e730962cc..f1686d460e6b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1465,6 +1465,7 @@ struct cfg80211_ibss_params { * @ie: IEs for association request * @ie_len: Length of assoc_ie in octets * @privacy: indicates whether privacy-enabled APs should be used + * @mfp: indicate whether management frame protection is used * @crypto: crypto settings * @key_len: length of WEP key for shared key authentication * @key_idx: index of WEP key for shared key authentication @@ -1485,6 +1486,7 @@ struct cfg80211_connect_params { u8 *ie; size_t ie_len; bool privacy; + enum nl80211_mfp mfp; struct cfg80211_crypto_settings crypto; const u8 *key; u8 key_len, key_idx; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 6c4f703ae890..d01c16220dc5 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -374,8 +374,8 @@ * requests to connect to a specified network but without separating * auth and assoc steps. For this, you need to specify the SSID in a * %NL80211_ATTR_SSID attribute, and can optionally specify the association - * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC, - * %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, + * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP, + * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT. * Background scan period can optionally be @@ -958,7 +958,7 @@ enum nl80211_commands { * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is * used for the association (&enum nl80211_mfp, represented as a u32); * this attribute can be used - * with %NL80211_CMD_ASSOCIATE request + * with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests * * @NL80211_ATTR_STA_FLAGS2: Attribute containing a * &struct nl80211_sta_flag_update. diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d543cf152100..df82a5c9faee 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5932,6 +5932,15 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); } + if (info->attrs[NL80211_ATTR_USE_MFP]) { + connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); + if (connect.mfp != NL80211_MFP_REQUIRED && + connect.mfp != NL80211_MFP_NO) + return -EINVAL; + } else { + connect.mfp = NL80211_MFP_NO; + } + if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { connect.channel = ieee80211_get_channel(wiphy, diff --git a/net/wireless/sme.c b/net/wireless/sme.c index d2d26518cdd7..a825dfe12cf7 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -192,7 +192,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) prev_bssid, params->ssid, params->ssid_len, params->ie, params->ie_len, - false, ¶ms->crypto, + params->mfp != NL80211_MFP_NO, + ¶ms->crypto, params->flags, ¶ms->ht_capa, ¶ms->ht_capa_mask); if (err) -- cgit v1.2.3-59-g8ed1b From 11c4a075db2f8774d37544342c8cb9752b4db9e1 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Tue, 8 Jan 2013 14:04:07 +0100 Subject: cfg80211: check radar interface combinations To ease further DFS development regarding interface combinations, use the interface combinations structure to test for radar capabilities. Drivers can specify which channel widths they support, and in which modes. Right now only a single AP interface is allowed, but as the DFS code evolves other combinations can be enabled. Signed-off-by: Simon Wunderlich Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 ++ include/uapi/linux/nl80211.h | 3 +++ net/wireless/core.c | 12 ++++++++++-- net/wireless/core.h | 7 ++++--- net/wireless/nl80211.c | 3 +++ net/wireless/util.c | 41 ++++++++++++++++++++++++++++++++++++++--- 6 files changed, 60 insertions(+), 8 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f1686d460e6b..970da4420676 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2125,6 +2125,7 @@ struct ieee80211_iface_limit { * @beacon_int_infra_match: In this combination, the beacon intervals * between infrastructure and AP types must match. This is required * only in special cases. + * @radar_detect_widths: bitmap of channel widths supported for radar detection * * These examples can be expressed as follows: * @@ -2177,6 +2178,7 @@ struct ieee80211_iface_combination { u16 max_interfaces; u8 n_limits; bool beacon_int_infra_match; + u8 radar_detect_widths; }; struct mac_address { diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index d01c16220dc5..e6eeb4ba5dc5 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2984,6 +2984,8 @@ enum nl80211_iface_limit_attrs { * the infrastructure network's beacon interval. * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many * different channels may be used within this group. + * @NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS: u32 attribute containing the bitmap + * of supported channel widths for radar detection. * @NUM_NL80211_IFACE_COMB: number of attributes * @MAX_NL80211_IFACE_COMB: highest attribute number * @@ -3016,6 +3018,7 @@ enum nl80211_if_combination_attrs { NL80211_IFACE_COMB_MAXNUM, NL80211_IFACE_COMB_STA_AP_BI_MATCH, NL80211_IFACE_COMB_NUM_CHANNELS, + NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, /* keep last */ NUM_NL80211_IFACE_COMB, diff --git a/net/wireless/core.c b/net/wireless/core.c index 747dd9365a44..0e702cdc6043 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -382,8 +382,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) c = &wiphy->iface_combinations[i]; - /* Combinations with just one interface aren't real */ - if (WARN_ON(c->max_interfaces < 2)) + /* + * Combinations with just one interface aren't real, + * however we make an exception for DFS. + */ + if (WARN_ON((c->max_interfaces < 2) && !c->radar_detect_widths)) return -EINVAL; /* Need at least one channel */ @@ -398,6 +401,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) CFG80211_MAX_NUM_DIFFERENT_CHANNELS)) return -EINVAL; + /* DFS only works on one channel. */ + if (WARN_ON(c->radar_detect_widths && + (c->num_different_channels > 1))) + return -EINVAL; + if (WARN_ON(!c->n_limits)) return -EINVAL; diff --git a/net/wireless/core.h b/net/wireless/core.h index f342267e3620..8396f7671c8d 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -425,7 +425,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, enum nl80211_iftype iftype, struct ieee80211_channel *chan, - enum cfg80211_chan_mode chanmode); + enum cfg80211_chan_mode chanmode, + u8 radar_detect); static inline int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, @@ -433,7 +434,7 @@ cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, enum nl80211_iftype iftype) { return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL, - CHAN_MODE_UNDEFINED); + CHAN_MODE_UNDEFINED, 0); } static inline int @@ -450,7 +451,7 @@ cfg80211_can_use_chan(struct cfg80211_registered_device *rdev, enum cfg80211_chan_mode chanmode) { return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, - chan, chanmode); + chan, chanmode, 0); } void diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index df82a5c9faee..33de80364c5c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -856,6 +856,9 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy, nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM, c->max_interfaces)) goto nla_put_failure; + if (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, + c->radar_detect_widths)) + goto nla_put_failure; nla_nest_end(msg, nl_combi); } diff --git a/net/wireless/util.c b/net/wireless/util.c index 16d76a807c2f..1c2795d52db0 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1184,7 +1184,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, enum nl80211_iftype iftype, struct ieee80211_channel *chan, - enum cfg80211_chan_mode chanmode) + enum cfg80211_chan_mode chanmode, + u8 radar_detect) { struct wireless_dev *wdev_iter; u32 used_iftypes = BIT(iftype); @@ -1195,14 +1196,45 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, enum cfg80211_chan_mode chmode; int num_different_channels = 0; int total = 1; + bool radar_required; int i, j; ASSERT_RTNL(); lockdep_assert_held(&rdev->devlist_mtx); + if (WARN_ON(hweight32(radar_detect) > 1)) + return -EINVAL; + + switch (iftype) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_WDS: + radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR); + break; + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_MONITOR: + radar_required = false; + break; + case NL80211_IFTYPE_P2P_DEVICE: + case NUM_NL80211_IFTYPES: + case NL80211_IFTYPE_UNSPECIFIED: + default: + return -EINVAL; + } + + if (radar_required && !radar_detect) + return -EINVAL; + /* Always allow software iftypes */ - if (rdev->wiphy.software_iftypes & BIT(iftype)) + if (rdev->wiphy.software_iftypes & BIT(iftype)) { + if (radar_detect) + return -EINVAL; return 0; + } memset(num, 0, sizeof(num)); memset(used_channels, 0, sizeof(used_channels)); @@ -1275,7 +1307,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, used_iftypes |= BIT(wdev_iter->iftype); } - if (total == 1) + if (total == 1 && !radar_detect) return 0; for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { @@ -1308,6 +1340,9 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, } } + if (radar_detect && !(c->radar_detect_widths & radar_detect)) + goto cont; + /* * Finally check that all iftypes that we're currently * using are actually part of this combination. If they -- cgit v1.2.3-59-g8ed1b