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:
		
					parent
					
						
							
								0bc6b1871c
							
						
					
				
			
			
				commit
				
					
						98d3a7ca92
					
				
			
		
					 3 changed files with 44 additions and 11 deletions
				
			
		| 
						 | 
					@ -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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue