diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2014-04-09 09:11:01 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2014-05-06 09:16:34 -0400 |
commit | f04c22033c25f71617ac62bcfe75698baa17a0b8 (patch) | |
tree | 468527116aa880a43f476dc020754b9b6c64982e | |
parent | 66199506fb91058a78b154b7fecb703ddaa27146 (diff) |
cfg80211: export interface stopping function
This exports a new cfg80211_stop_iface() function.
This is intended for driver internal interface
combination management and channel switching.
Due to locking issues (it re-enters driver) the
call is asynchronous and uses cfg80211 event
list/worker.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | include/net/cfg80211.h | 15 | ||||
-rw-r--r-- | net/wireless/ap.c | 4 | ||||
-rw-r--r-- | net/wireless/core.c | 43 | ||||
-rw-r--r-- | net/wireless/core.h | 7 | ||||
-rw-r--r-- | net/wireless/mesh.c | 4 | ||||
-rw-r--r-- | net/wireless/trace.h | 15 | ||||
-rw-r--r-- | net/wireless/util.c | 3 |
7 files changed, 80 insertions, 11 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7eae46ccec01..0631230b01eb 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -4756,6 +4756,21 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, | |||
4756 | void *data), | 4756 | void *data), |
4757 | void *data); | 4757 | void *data); |
4758 | 4758 | ||
4759 | /* | ||
4760 | * cfg80211_stop_iface - trigger interface disconnection | ||
4761 | * | ||
4762 | * @wiphy: the wiphy | ||
4763 | * @wdev: wireless device | ||
4764 | * @gfp: context flags | ||
4765 | * | ||
4766 | * Trigger interface to be stopped as if AP was stopped, IBSS/mesh left, STA | ||
4767 | * disconnected. | ||
4768 | * | ||
4769 | * Note: This doesn't need any locks and is asynchronous. | ||
4770 | */ | ||
4771 | void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
4772 | gfp_t gfp); | ||
4773 | |||
4759 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ | 4774 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ |
4760 | 4775 | ||
4761 | /* wiphy_printk helpers, similar to dev_printk */ | 4776 | /* wiphy_printk helpers, similar to dev_printk */ |
diff --git a/net/wireless/ap.c b/net/wireless/ap.c index 3e02ade508d8..bdad1f951561 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c | |||
@@ -6,8 +6,8 @@ | |||
6 | #include "rdev-ops.h" | 6 | #include "rdev-ops.h" |
7 | 7 | ||
8 | 8 | ||
9 | static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | 9 | int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, |
10 | struct net_device *dev, bool notify) | 10 | struct net_device *dev, bool notify) |
11 | { | 11 | { |
12 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 12 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
13 | int err; | 13 | int err; |
diff --git a/net/wireless/core.c b/net/wireless/core.c index f509da4d9be9..7e023b74f009 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -792,23 +792,23 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | |||
792 | rdev->num_running_monitor_ifaces += num; | 792 | rdev->num_running_monitor_ifaces += num; |
793 | } | 793 | } |
794 | 794 | ||
795 | void cfg80211_leave(struct cfg80211_registered_device *rdev, | 795 | void __cfg80211_leave(struct cfg80211_registered_device *rdev, |
796 | struct wireless_dev *wdev) | 796 | struct wireless_dev *wdev) |
797 | { | 797 | { |
798 | struct net_device *dev = wdev->netdev; | 798 | struct net_device *dev = wdev->netdev; |
799 | 799 | ||
800 | ASSERT_RTNL(); | 800 | ASSERT_RTNL(); |
801 | ASSERT_WDEV_LOCK(wdev); | ||
801 | 802 | ||
802 | switch (wdev->iftype) { | 803 | switch (wdev->iftype) { |
803 | case NL80211_IFTYPE_ADHOC: | 804 | case NL80211_IFTYPE_ADHOC: |
804 | cfg80211_leave_ibss(rdev, dev, true); | 805 | __cfg80211_leave_ibss(rdev, dev, true); |
805 | break; | 806 | break; |
806 | case NL80211_IFTYPE_P2P_CLIENT: | 807 | case NL80211_IFTYPE_P2P_CLIENT: |
807 | case NL80211_IFTYPE_STATION: | 808 | case NL80211_IFTYPE_STATION: |
808 | if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev) | 809 | if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev) |
809 | __cfg80211_stop_sched_scan(rdev, false); | 810 | __cfg80211_stop_sched_scan(rdev, false); |
810 | 811 | ||
811 | wdev_lock(wdev); | ||
812 | #ifdef CONFIG_CFG80211_WEXT | 812 | #ifdef CONFIG_CFG80211_WEXT |
813 | kfree(wdev->wext.ie); | 813 | kfree(wdev->wext.ie); |
814 | wdev->wext.ie = NULL; | 814 | wdev->wext.ie = NULL; |
@@ -817,20 +817,49 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
817 | #endif | 817 | #endif |
818 | cfg80211_disconnect(rdev, dev, | 818 | cfg80211_disconnect(rdev, dev, |
819 | WLAN_REASON_DEAUTH_LEAVING, true); | 819 | WLAN_REASON_DEAUTH_LEAVING, true); |
820 | wdev_unlock(wdev); | ||
821 | break; | 820 | break; |
822 | case NL80211_IFTYPE_MESH_POINT: | 821 | case NL80211_IFTYPE_MESH_POINT: |
823 | cfg80211_leave_mesh(rdev, dev); | 822 | __cfg80211_leave_mesh(rdev, dev); |
824 | break; | 823 | break; |
825 | case NL80211_IFTYPE_AP: | 824 | case NL80211_IFTYPE_AP: |
826 | case NL80211_IFTYPE_P2P_GO: | 825 | case NL80211_IFTYPE_P2P_GO: |
827 | cfg80211_stop_ap(rdev, dev, true); | 826 | __cfg80211_stop_ap(rdev, dev, true); |
828 | break; | 827 | break; |
829 | default: | 828 | default: |
830 | break; | 829 | break; |
831 | } | 830 | } |
832 | } | 831 | } |
833 | 832 | ||
833 | void cfg80211_leave(struct cfg80211_registered_device *rdev, | ||
834 | struct wireless_dev *wdev) | ||
835 | { | ||
836 | wdev_lock(wdev); | ||
837 | __cfg80211_leave(rdev, wdev); | ||
838 | wdev_unlock(wdev); | ||
839 | } | ||
840 | |||
841 | void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
842 | gfp_t gfp) | ||
843 | { | ||
844 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | ||
845 | struct cfg80211_event *ev; | ||
846 | unsigned long flags; | ||
847 | |||
848 | trace_cfg80211_stop_iface(wiphy, wdev); | ||
849 | |||
850 | ev = kzalloc(sizeof(*ev), gfp); | ||
851 | if (!ev) | ||
852 | return; | ||
853 | |||
854 | ev->type = EVENT_STOPPED; | ||
855 | |||
856 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
857 | list_add_tail(&ev->list, &wdev->event_list); | ||
858 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
859 | queue_work(cfg80211_wq, &rdev->event_work); | ||
860 | } | ||
861 | EXPORT_SYMBOL(cfg80211_stop_iface); | ||
862 | |||
834 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | 863 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, |
835 | unsigned long state, void *ptr) | 864 | unsigned long state, void *ptr) |
836 | { | 865 | { |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 681b8fa4355b..e9afbf10e756 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -185,6 +185,7 @@ enum cfg80211_event_type { | |||
185 | EVENT_ROAMED, | 185 | EVENT_ROAMED, |
186 | EVENT_DISCONNECTED, | 186 | EVENT_DISCONNECTED, |
187 | EVENT_IBSS_JOINED, | 187 | EVENT_IBSS_JOINED, |
188 | EVENT_STOPPED, | ||
188 | }; | 189 | }; |
189 | 190 | ||
190 | struct cfg80211_event { | 191 | struct cfg80211_event { |
@@ -281,6 +282,8 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
281 | struct net_device *dev, | 282 | struct net_device *dev, |
282 | struct mesh_setup *setup, | 283 | struct mesh_setup *setup, |
283 | const struct mesh_config *conf); | 284 | const struct mesh_config *conf); |
285 | int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | ||
286 | struct net_device *dev); | ||
284 | int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | 287 | int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, |
285 | struct net_device *dev); | 288 | struct net_device *dev); |
286 | int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, | 289 | int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, |
@@ -288,6 +291,8 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, | |||
288 | struct cfg80211_chan_def *chandef); | 291 | struct cfg80211_chan_def *chandef); |
289 | 292 | ||
290 | /* AP */ | 293 | /* AP */ |
294 | int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||
295 | struct net_device *dev, bool notify); | ||
291 | int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | 296 | int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, |
292 | struct net_device *dev, bool notify); | 297 | struct net_device *dev, bool notify); |
293 | 298 | ||
@@ -441,6 +446,8 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
441 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | 446 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, |
442 | enum nl80211_iftype iftype, int num); | 447 | enum nl80211_iftype iftype, int num); |
443 | 448 | ||
449 | void __cfg80211_leave(struct cfg80211_registered_device *rdev, | ||
450 | struct wireless_dev *wdev); | ||
444 | void cfg80211_leave(struct cfg80211_registered_device *rdev, | 451 | void cfg80211_leave(struct cfg80211_registered_device *rdev, |
445 | struct wireless_dev *wdev); | 452 | struct wireless_dev *wdev); |
446 | 453 | ||
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 3ddfb7cd335e..092300b30c37 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
@@ -238,8 +238,8 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, | |||
238 | return 0; | 238 | return 0; |
239 | } | 239 | } |
240 | 240 | ||
241 | static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | 241 | int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, |
242 | struct net_device *dev) | 242 | struct net_device *dev) |
243 | { | 243 | { |
244 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 244 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
245 | int err; | 245 | int err; |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index f3c13ff4d04c..cdfbb00e1b37 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -2636,6 +2636,21 @@ TRACE_EVENT(cfg80211_ft_event, | |||
2636 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap)) | 2636 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap)) |
2637 | ); | 2637 | ); |
2638 | 2638 | ||
2639 | TRACE_EVENT(cfg80211_stop_iface, | ||
2640 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), | ||
2641 | TP_ARGS(wiphy, wdev), | ||
2642 | TP_STRUCT__entry( | ||
2643 | WIPHY_ENTRY | ||
2644 | WDEV_ENTRY | ||
2645 | ), | ||
2646 | TP_fast_assign( | ||
2647 | WIPHY_ASSIGN; | ||
2648 | WDEV_ASSIGN; | ||
2649 | ), | ||
2650 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, | ||
2651 | WIPHY_PR_ARG, WDEV_PR_ARG) | ||
2652 | ); | ||
2653 | |||
2639 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ | 2654 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ |
2640 | 2655 | ||
2641 | #undef TRACE_INCLUDE_PATH | 2656 | #undef TRACE_INCLUDE_PATH |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 7c47fa07b276..a756429b3a0a 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -839,6 +839,9 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) | |||
839 | __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid, | 839 | __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid, |
840 | ev->ij.channel); | 840 | ev->ij.channel); |
841 | break; | 841 | break; |
842 | case EVENT_STOPPED: | ||
843 | __cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev); | ||
844 | break; | ||
842 | } | 845 | } |
843 | wdev_unlock(wdev); | 846 | wdev_unlock(wdev); |
844 | 847 | ||