From 3d23e349d807177eaf519d444677cee86b1a04cf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 29 Sep 2009 23:27:28 +0200 Subject: wext: refactor Refactor wext to * split out iwpriv handling * split out iwspy handling * split out procfs support * allow cfg80211 to have wireless extensions compat code w/o CONFIG_WIRELESS_EXT After this, drivers need to - select WIRELESS_EXT - for wext support - select WEXT_PRIV - for iwpriv support - select WEXT_SPY - for iwspy support except cfg80211 -- which gets new hooks in wext-core.c and can then get wext handlers without CONFIG_WIRELESS_EXT. Wireless extensions procfs support is auto-selected based on PROC_FS and anything that requires the wext core (i.e. WIRELESS_EXT or CFG80211_WEXT). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/ibss.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net/wireless/ibss.c') diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index c88338911979..39b6d92e2828 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -15,7 +15,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_bss *bss; -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif @@ -44,7 +44,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, GFP_KERNEL); -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT memset(&wrqu, 0, sizeof(wrqu)); memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); @@ -96,7 +96,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, kfree(wdev->connect_keys); wdev->connect_keys = connkeys; -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT wdev->wext.ibss.channel = params->channel; #endif err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); @@ -154,7 +154,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) wdev->current_bss = NULL; wdev->ssid_len = 0; -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT if (!nowext) wdev->wext.ibss.ssid_len = 0; #endif @@ -203,7 +203,7 @@ int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, return err; } -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev) { -- cgit v1.2.3 From 98d3a7ca9232a436c067888936a0133e64ea126a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Nov 2009 13:03:43 +0100 Subject: 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 Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/core.h | 2 ++ net/wireless/ibss.c | 4 ++-- net/wireless/wext-compat.c | 49 +++++++++++++++++++++++++++++++++++++--------- 3 files changed, 44 insertions(+), 11 deletions(-) (limited to 'net/wireless/ibss.c') diff --git a/net/wireless/core.h b/net/wireless/core.h index 5aeebb9085f8..a9db9e6255bb 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -273,6 +273,8 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, struct cfg80211_ibss_params *params, struct cfg80211_cached_keys *connkeys); 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, struct net_device *dev, bool nowext); void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 39b6d92e2828..34dfc93fa713 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -169,8 +169,8 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext) wdev_unlock(wdev); } -static int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, - struct net_device *dev, bool nowext) +int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, bool nowext) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err; diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 41abcbdc5fb9..29091ac9f989 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -437,6 +437,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, { struct wireless_dev *wdev = dev->ieee80211_ptr; int err, i; + bool rejoin = false; if (!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) { 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); + } + /* + * 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 (!addr) { 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) wdev->wext.default_mgmt_key = -1; } - /* - * Applications using wireless extensions expect to be - * able to delete keys that don't exist, so allow that. - */ - if (err == -ENOENT) - return 0; + + if (!err && rejoin) + err = cfg80211_ibss_wext_join(rdev, wdev); return err; } @@ -511,11 +525,25 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 || params->cipher == WLAN_CIPHER_SUITE_WEP104) && (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, dev, idx); - if (!err) + } + if (!err) { wdev->wext.default_key = idx; + if (rejoin) + err = cfg80211_ibss_wext_join(rdev, wdev); + } return err; } @@ -539,10 +567,13 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, { int err; + /* devlist mutex needed for possible IBSS re-join */ + mutex_lock(&rdev->devlist_mtx); wdev_lock(dev->ieee80211_ptr); err = __cfg80211_set_encryption(rdev, dev, addr, remove, tx_key, idx, params); wdev_unlock(dev->ieee80211_ptr); + mutex_unlock(&rdev->devlist_mtx); return err; } -- cgit v1.2.3 From e60d7443e00a72a2c056950cdaab79c7b077f3d4 Mon Sep 17 00:00:00 2001 From: Alban Browaeys Date: Wed, 25 Nov 2009 15:13:00 +0100 Subject: wireless : use a dedicated workqueue for cfg80211. This patch moves the works cleanup, scan and events to a cfg80211 dedicated workqueue. Platform driver like eeepc-laptop ought to use works to rfkill (as new rfkill does lock in rfkill_unregister and the platform driver is called from rfkill_switch_all which also lock the same mutex). This raise a new issue in itself that the work scheduled by the platform driver to the global worqueue calls wiphy_unregister which flush_work scan and event works (which thus flush works on the global workqueue inside a work on the global workqueue) and also put on hold the wdev_cleanup_work (which prevents the dev_put on netdev thus indefinite Usage count error on wifi device). Signed-off-by: Johannes Berg Signed-off-by: Alban Browaeys Signed-off-by: John W. Linville --- net/wireless/core.c | 12 +++++++++++- net/wireless/core.h | 2 ++ net/wireless/ibss.c | 2 +- net/wireless/scan.c | 2 +- net/wireless/sme.c | 6 +++--- 5 files changed, 18 insertions(+), 6 deletions(-) (limited to 'net/wireless/ibss.c') diff --git a/net/wireless/core.c b/net/wireless/core.c index fe6f402a22af..c2a2c563d21a 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -45,6 +45,9 @@ DEFINE_MUTEX(cfg80211_mutex); /* for debugfs */ static struct dentry *ieee80211_debugfs_dir; +/* for the cleanup, scan and event works */ +struct workqueue_struct *cfg80211_wq; + /* requires cfg80211_mutex to be held! */ struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) { @@ -727,7 +730,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; case NETDEV_DOWN: dev_hold(dev); - schedule_work(&wdev->cleanup_work); + queue_work(cfg80211_wq, &wdev->cleanup_work); break; case NETDEV_UP: /* @@ -845,8 +848,14 @@ static int __init cfg80211_init(void) if (err) goto out_fail_reg; + cfg80211_wq = create_singlethread_workqueue("cfg80211"); + if (!cfg80211_wq) + goto out_fail_wq; + return 0; +out_fail_wq: + regulatory_exit(); out_fail_reg: debugfs_remove(ieee80211_debugfs_dir); out_fail_nl80211: @@ -868,5 +877,6 @@ static void cfg80211_exit(void) wiphy_sysfs_exit(); regulatory_exit(); unregister_pernet_device(&cfg80211_pernet_ops); + destroy_workqueue(cfg80211_wq); } module_exit(cfg80211_exit); diff --git a/net/wireless/core.h b/net/wireless/core.h index a9db9e6255bb..4ef3efc94106 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -91,6 +91,8 @@ bool wiphy_idx_valid(int wiphy_idx) return (wiphy_idx >= 0); } + +extern struct workqueue_struct *cfg80211_wq; extern struct mutex cfg80211_mutex; extern struct list_head cfg80211_rdev_list; extern int cfg80211_rdev_list_generation; diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 34dfc93fa713..6ef5a491fb4b 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -70,7 +70,7 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) spin_lock_irqsave(&wdev->event_lock, flags); list_add_tail(&ev->list, &wdev->event_list); spin_unlock_irqrestore(&wdev->event_lock, flags); - schedule_work(&rdev->event_work); + queue_work(cfg80211_wq, &rdev->event_work); } EXPORT_SYMBOL(cfg80211_ibss_joined); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 227d57b8dc41..df26228db1b3 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -88,7 +88,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); request->aborted = aborted; - schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk); + queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk); } EXPORT_SYMBOL(cfg80211_scan_done); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 0115d07d2c1a..2333d78187e4 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -488,7 +488,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, spin_lock_irqsave(&wdev->event_lock, flags); list_add_tail(&ev->list, &wdev->event_list); spin_unlock_irqrestore(&wdev->event_lock, flags); - schedule_work(&rdev->event_work); + queue_work(cfg80211_wq, &rdev->event_work); } EXPORT_SYMBOL(cfg80211_connect_result); @@ -583,7 +583,7 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, spin_lock_irqsave(&wdev->event_lock, flags); list_add_tail(&ev->list, &wdev->event_list); spin_unlock_irqrestore(&wdev->event_lock, flags); - schedule_work(&rdev->event_work); + queue_work(cfg80211_wq, &rdev->event_work); } EXPORT_SYMBOL(cfg80211_roamed); @@ -681,7 +681,7 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason, spin_lock_irqsave(&wdev->event_lock, flags); list_add_tail(&ev->list, &wdev->event_list); spin_unlock_irqrestore(&wdev->event_lock, flags); - schedule_work(&rdev->event_work); + queue_work(cfg80211_wq, &rdev->event_work); } EXPORT_SYMBOL(cfg80211_disconnected); -- cgit v1.2.3