cfg80211: re-join IBSS when privacy changes

When going from/to a WEP protected IBSS, we need to
leave this one and join a new one to take care of
the changed capability.

Cc: Hong Zhang <henryzhang62@yahoo.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Johannes Berg 2009-11-18 13:03:43 +01:00 committed by John W. Linville
parent 0bc6b1871c
commit 98d3a7ca92
3 changed files with 44 additions and 11 deletions

View File

@ -273,6 +273,8 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
struct cfg80211_ibss_params *params, struct cfg80211_ibss_params *params,
struct cfg80211_cached_keys *connkeys); struct cfg80211_cached_keys *connkeys);
void cfg80211_clear_ibss(struct net_device *dev, bool nowext); void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
struct net_device *dev, bool nowext);
int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
struct net_device *dev, bool nowext); struct net_device *dev, bool nowext);
void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid);

View File

@ -169,7 +169,7 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
wdev_unlock(wdev); wdev_unlock(wdev);
} }
static int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
struct net_device *dev, bool nowext) struct net_device *dev, bool nowext)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;

View File

@ -437,6 +437,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
int err, i; int err, i;
bool rejoin = false;
if (!wdev->wext.keys) { if (!wdev->wext.keys) {
wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
@ -466,8 +467,24 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
if (remove) { if (remove) {
err = 0; err = 0;
if (wdev->current_bss) if (wdev->current_bss) {
/*
* If removing the current TX key, we will need to
* join a new IBSS without the privacy bit clear.
*/
if (idx == wdev->wext.default_key &&
wdev->iftype == NL80211_IFTYPE_ADHOC) {
__cfg80211_leave_ibss(rdev, wdev->netdev, true);
rejoin = true;
}
err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
}
/*
* Applications using wireless extensions expect to be
* able to delete keys that don't exist, so allow that.
*/
if (err == -ENOENT)
err = 0;
if (!err) { if (!err) {
if (!addr) { if (!addr) {
wdev->wext.keys->params[idx].key_len = 0; wdev->wext.keys->params[idx].key_len = 0;
@ -478,12 +495,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
else if (idx == wdev->wext.default_mgmt_key) else if (idx == wdev->wext.default_mgmt_key)
wdev->wext.default_mgmt_key = -1; wdev->wext.default_mgmt_key = -1;
} }
/*
* Applications using wireless extensions expect to be if (!err && rejoin)
* able to delete keys that don't exist, so allow that. err = cfg80211_ibss_wext_join(rdev, wdev);
*/
if (err == -ENOENT)
return 0;
return err; return err;
} }
@ -511,11 +525,25 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 || if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
params->cipher == WLAN_CIPHER_SUITE_WEP104) && params->cipher == WLAN_CIPHER_SUITE_WEP104) &&
(tx_key || (!addr && wdev->wext.default_key == -1))) { (tx_key || (!addr && wdev->wext.default_key == -1))) {
if (wdev->current_bss) if (wdev->current_bss) {
/*
* If we are getting a new TX key from not having
* had one before we need to join a new IBSS with
* the privacy bit set.
*/
if (wdev->iftype == NL80211_IFTYPE_ADHOC &&
wdev->wext.default_key == -1) {
__cfg80211_leave_ibss(rdev, wdev->netdev, true);
rejoin = true;
}
err = rdev->ops->set_default_key(&rdev->wiphy, err = rdev->ops->set_default_key(&rdev->wiphy,
dev, idx); dev, idx);
if (!err) }
if (!err) {
wdev->wext.default_key = idx; wdev->wext.default_key = idx;
if (rejoin)
err = cfg80211_ibss_wext_join(rdev, wdev);
}
return err; return err;
} }
@ -539,10 +567,13 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
{ {
int err; int err;
/* devlist mutex needed for possible IBSS re-join */
mutex_lock(&rdev->devlist_mtx);
wdev_lock(dev->ieee80211_ptr); wdev_lock(dev->ieee80211_ptr);
err = __cfg80211_set_encryption(rdev, dev, addr, remove, err = __cfg80211_set_encryption(rdev, dev, addr, remove,
tx_key, idx, params); tx_key, idx, params);
wdev_unlock(dev->ieee80211_ptr); wdev_unlock(dev->ieee80211_ptr);
mutex_unlock(&rdev->devlist_mtx);
return err; return err;
} }