diff options
author | Eyal Shapira <eyal@wizery.com> | 2012-08-06 07:26:16 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-08-20 07:20:56 -0400 |
commit | aa7a00809cf6afe3cd6f5af2889110b47b798667 (patch) | |
tree | 4b2d537fdad3058f61ab0bb894b935afc75442b5 /net/mac80211/cfg.c | |
parent | f609a43dca2964a8a604ef554be92fa11c3b4c41 (diff) |
mac80211: avoid using synchronize_rcu in ieee80211_set_probe_resp
This could take a while (100ms+) and may delay sending assoc resp
in AP mode with WPS or P2P GO (as setting the probe resp takes place
there). We've encountered situations where the delay was big enough
to cause connection problems with devices like Galaxy Nexus.
Switch to using call_rcu with a free handler.
[Arik - rework to use plain buffer and instead of skb]
Signed-off-by: Eyal Shapira <eyal@wizery.com>
Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 16 |
1 files changed, 7 insertions, 9 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index df64b455821d..8052a7ad03a6 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -725,25 +725,23 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, | |||
725 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | 725 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, |
726 | const u8 *resp, size_t resp_len) | 726 | const u8 *resp, size_t resp_len) |
727 | { | 727 | { |
728 | struct sk_buff *new, *old; | 728 | struct probe_resp *new, *old; |
729 | 729 | ||
730 | if (!resp || !resp_len) | 730 | if (!resp || !resp_len) |
731 | return 1; | 731 | return -EINVAL; |
732 | 732 | ||
733 | old = rtnl_dereference(sdata->u.ap.probe_resp); | 733 | old = rtnl_dereference(sdata->u.ap.probe_resp); |
734 | 734 | ||
735 | new = dev_alloc_skb(resp_len); | 735 | new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL); |
736 | if (!new) | 736 | if (!new) |
737 | return -ENOMEM; | 737 | return -ENOMEM; |
738 | 738 | ||
739 | memcpy(skb_put(new, resp_len), resp, resp_len); | 739 | new->len = resp_len; |
740 | memcpy(new->data, resp, resp_len); | ||
740 | 741 | ||
741 | rcu_assign_pointer(sdata->u.ap.probe_resp, new); | 742 | rcu_assign_pointer(sdata->u.ap.probe_resp, new); |
742 | if (old) { | 743 | if (old) |
743 | /* TODO: use call_rcu() */ | 744 | kfree_rcu(old, rcu_head); |
744 | synchronize_rcu(); | ||
745 | dev_kfree_skb(old); | ||
746 | } | ||
747 | 745 | ||
748 | return 0; | 746 | return 0; |
749 | } | 747 | } |