Commit 959867fa authored by Johannes Berg's avatar Johannes Berg

cfg80211: require passing BSS struct back to cfg80211_assoc_timeout

Doing so will allow us to hold the BSS (not just ref it) over the
association process, thus ensuring that it doesn't time out and
gets invisible to the user (e.g. in 'iw wlan0 link'.)

This also fixes a leak in mac80211 where it doesn't always release
the BSS struct properly in all cases where calling this function.
This leak was reported by Ben Greear.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 86e8cf98
...@@ -1459,7 +1459,8 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie); ...@@ -1459,7 +1459,8 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
* This structure provides information needed to complete IEEE 802.11 * This structure provides information needed to complete IEEE 802.11
* authentication. * authentication.
* *
* @bss: The BSS to authenticate with. * @bss: The BSS to authenticate with, the callee must obtain a reference
* to it if it needs to keep it.
* @auth_type: Authentication type (algorithm) * @auth_type: Authentication type (algorithm)
* @ie: Extra IEs to add to Authentication frame or %NULL * @ie: Extra IEs to add to Authentication frame or %NULL
* @ie_len: Length of ie buffer in octets * @ie_len: Length of ie buffer in octets
...@@ -1497,11 +1498,10 @@ enum cfg80211_assoc_req_flags { ...@@ -1497,11 +1498,10 @@ enum cfg80211_assoc_req_flags {
* *
* This structure provides information needed to complete IEEE 802.11 * This structure provides information needed to complete IEEE 802.11
* (re)association. * (re)association.
* @bss: The BSS to associate with. If the call is successful the driver * @bss: The BSS to associate with. If the call is successful the driver is
* is given a reference that it must release, normally via a call to * given a reference that it must give back to cfg80211_send_rx_assoc()
* cfg80211_send_rx_assoc(), or, if association timed out, with a * or to cfg80211_assoc_timeout(). To ensure proper refcounting, new
* call to cfg80211_put_bss() (in addition to calling * association requests while already associating must be rejected.
* cfg80211_send_assoc_timeout())
* @ie: Extra IEs to add to (Re)Association Request frame or %NULL * @ie: Extra IEs to add to (Re)Association Request frame or %NULL
* @ie_len: Length of ie buffer in octets * @ie_len: Length of ie buffer in octets
* @use_mfp: Use management frame protection (IEEE 802.11w) in this association * @use_mfp: Use management frame protection (IEEE 802.11w) in this association
...@@ -3522,11 +3522,11 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, ...@@ -3522,11 +3522,11 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
/** /**
* cfg80211_assoc_timeout - notification of timed out association * cfg80211_assoc_timeout - notification of timed out association
* @dev: network device * @dev: network device
* @addr: The MAC address of the device with which the association timed out * @bss: The BSS entry with which association timed out.
* *
* This function may sleep. The caller must hold the corresponding wdev's mutex. * This function may sleep. The caller must hold the corresponding wdev's mutex.
*/ */
void cfg80211_assoc_timeout(struct net_device *dev, const u8 *addr); void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss);
/** /**
* cfg80211_tx_mlme_mgmt - notification of transmitted deauth/disassoc frame * cfg80211_tx_mlme_mgmt - notification of transmitted deauth/disassoc frame
......
...@@ -2795,8 +2795,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ...@@ -2795,8 +2795,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
if (!ieee80211_assoc_success(sdata, bss, mgmt, len)) { if (!ieee80211_assoc_success(sdata, bss, mgmt, len)) {
/* oops -- internal error -- send timeout for now */ /* oops -- internal error -- send timeout for now */
ieee80211_destroy_assoc_data(sdata, false); ieee80211_destroy_assoc_data(sdata, false);
cfg80211_put_bss(sdata->local->hw.wiphy, bss); cfg80211_assoc_timeout(sdata->dev, bss);
cfg80211_assoc_timeout(sdata->dev, mgmt->bssid);
return; return;
} }
sdata_info(sdata, "associated\n"); sdata_info(sdata, "associated\n");
...@@ -3513,13 +3512,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) ...@@ -3513,13 +3512,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
time_after(jiffies, ifmgd->assoc_data->timeout)) { time_after(jiffies, ifmgd->assoc_data->timeout)) {
if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) || if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) ||
ieee80211_do_assoc(sdata)) { ieee80211_do_assoc(sdata)) {
u8 bssid[ETH_ALEN]; struct cfg80211_bss *bss = ifmgd->assoc_data->bss;
memcpy(bssid, ifmgd->assoc_data->bss->bssid, ETH_ALEN);
ieee80211_destroy_assoc_data(sdata, false); ieee80211_destroy_assoc_data(sdata, false);
cfg80211_assoc_timeout(sdata->dev, bss);
cfg80211_assoc_timeout(sdata->dev, bssid);
} }
} else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started)
run_again(sdata, ifmgd->assoc_data->timeout); run_again(sdata, ifmgd->assoc_data->timeout);
...@@ -4445,8 +4441,11 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) ...@@ -4445,8 +4441,11 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
cancel_work_sync(&ifmgd->chswitch_work); cancel_work_sync(&ifmgd->chswitch_work);
sdata_lock(sdata); sdata_lock(sdata);
if (ifmgd->assoc_data) if (ifmgd->assoc_data) {
struct cfg80211_bss *bss = ifmgd->assoc_data->bss;
ieee80211_destroy_assoc_data(sdata, false); ieee80211_destroy_assoc_data(sdata, false);
cfg80211_assoc_timeout(sdata->dev, bss);
}
if (ifmgd->auth_data) if (ifmgd->auth_data)
ieee80211_destroy_auth_data(sdata, false); ieee80211_destroy_auth_data(sdata, false);
del_timer_sync(&ifmgd->timer); del_timer_sync(&ifmgd->timer);
......
...@@ -131,16 +131,18 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr) ...@@ -131,16 +131,18 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr)
} }
EXPORT_SYMBOL(cfg80211_auth_timeout); EXPORT_SYMBOL(cfg80211_auth_timeout);
void cfg80211_assoc_timeout(struct net_device *dev, const u8 *addr) void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy; struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_send_assoc_timeout(dev, addr); trace_cfg80211_send_assoc_timeout(dev, bss->bssid);
nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); nl80211_send_assoc_timeout(rdev, dev, bss->bssid, GFP_KERNEL);
cfg80211_sme_assoc_timeout(wdev); cfg80211_sme_assoc_timeout(wdev);
cfg80211_put_bss(wiphy, bss);
} }
EXPORT_SYMBOL(cfg80211_assoc_timeout); EXPORT_SYMBOL(cfg80211_assoc_timeout);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment