forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cfg80211: allow mgmt_frame_register callback to sleep
This callback is currently not allowed to sleep, which makes it more difficult to implement proper driver methods in mac80211 than it has to be. Instead of doing asynchronous work here in mac80211, make it possible for the callback to sleep by doing some asynchronous work in cfg80211. This also enables improvements to other drivers, like ath6kl, that would like to sleep in this callback. While at it, also fix the code to call the driver on the implicit unregistration when an interface is removed, and do that also when a P2P-Device wdev is destroyed (otherwise we leak the structs.) Signed-off-by: Johannes Berg <[email protected]>
- Loading branch information
1 parent
69f1322
commit 33d8783
Showing
5 changed files
with
73 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
* cfg80211 MLME SAP interface | ||
* | ||
* Copyright (c) 2009, Jouni Malinen <[email protected]> | ||
* Copyright (c) 2015 Intel Deutschland GmbH | ||
*/ | ||
|
||
#include <linux/kernel.h> | ||
|
@@ -389,6 +390,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |
|
||
struct cfg80211_mgmt_registration { | ||
struct list_head list; | ||
struct wireless_dev *wdev; | ||
|
||
u32 nlportid; | ||
|
||
|
@@ -399,6 +401,46 @@ struct cfg80211_mgmt_registration { | |
u8 match[]; | ||
}; | ||
|
||
static void | ||
cfg80211_process_mlme_unregistrations(struct cfg80211_registered_device *rdev) | ||
{ | ||
struct cfg80211_mgmt_registration *reg; | ||
|
||
ASSERT_RTNL(); | ||
|
||
spin_lock_bh(&rdev->mlme_unreg_lock); | ||
while ((reg = list_first_entry_or_null(&rdev->mlme_unreg, | ||
struct cfg80211_mgmt_registration, | ||
list))) { | ||
list_del(®->list); | ||
spin_unlock_bh(&rdev->mlme_unreg_lock); | ||
|
||
if (rdev->ops->mgmt_frame_register) { | ||
u16 frame_type = le16_to_cpu(reg->frame_type); | ||
|
||
rdev_mgmt_frame_register(rdev, reg->wdev, | ||
frame_type, false); | ||
} | ||
|
||
kfree(reg); | ||
|
||
spin_lock_bh(&rdev->mlme_unreg_lock); | ||
} | ||
spin_unlock_bh(&rdev->mlme_unreg_lock); | ||
} | ||
|
||
void cfg80211_mlme_unreg_wk(struct work_struct *wk) | ||
{ | ||
struct cfg80211_registered_device *rdev; | ||
|
||
rdev = container_of(wk, struct cfg80211_registered_device, | ||
mlme_unreg_wk); | ||
|
||
rtnl_lock(); | ||
cfg80211_process_mlme_unregistrations(rdev); | ||
rtnl_unlock(); | ||
} | ||
|
||
int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid, | ||
u16 frame_type, const u8 *match_data, | ||
int match_len) | ||
|
@@ -449,11 +491,18 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid, | |
nreg->match_len = match_len; | ||
nreg->nlportid = snd_portid; | ||
nreg->frame_type = cpu_to_le16(frame_type); | ||
nreg->wdev = wdev; | ||
list_add(&nreg->list, &wdev->mgmt_registrations); | ||
spin_unlock_bh(&wdev->mgmt_registrations_lock); | ||
|
||
/* process all unregistrations to avoid driver confusion */ | ||
cfg80211_process_mlme_unregistrations(rdev); | ||
|
||
if (rdev->ops->mgmt_frame_register) | ||
rdev_mgmt_frame_register(rdev, wdev, frame_type, true); | ||
|
||
return 0; | ||
|
||
out: | ||
spin_unlock_bh(&wdev->mgmt_registrations_lock); | ||
|
||
|
@@ -472,15 +521,12 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid) | |
if (reg->nlportid != nlportid) | ||
continue; | ||
|
||
if (rdev->ops->mgmt_frame_register) { | ||
u16 frame_type = le16_to_cpu(reg->frame_type); | ||
|
||
rdev_mgmt_frame_register(rdev, wdev, | ||
frame_type, false); | ||
} | ||
|
||
list_del(®->list); | ||
kfree(reg); | ||
spin_lock(&rdev->mlme_unreg_lock); | ||
list_add_tail(®->list, &rdev->mlme_unreg); | ||
spin_unlock(&rdev->mlme_unreg_lock); | ||
|
||
schedule_work(&rdev->mlme_unreg_wk); | ||
} | ||
|
||
spin_unlock_bh(&wdev->mgmt_registrations_lock); | ||
|
@@ -496,16 +542,15 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid) | |
|
||
void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) | ||
{ | ||
struct cfg80211_mgmt_registration *reg, *tmp; | ||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | ||
|
||
spin_lock_bh(&wdev->mgmt_registrations_lock); | ||
|
||
list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { | ||
list_del(®->list); | ||
kfree(reg); | ||
} | ||
|
||
spin_lock(&rdev->mlme_unreg_lock); | ||
list_splice_tail_init(&wdev->mgmt_registrations, &rdev->mlme_unreg); | ||
spin_unlock(&rdev->mlme_unreg_lock); | ||
spin_unlock_bh(&wdev->mgmt_registrations_lock); | ||
|
||
cfg80211_process_mlme_unregistrations(rdev); | ||
} | ||
|
||
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters