aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2014-04-09 09:11:01 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-05-06 09:16:34 -0400
commitf04c22033c25f71617ac62bcfe75698baa17a0b8 (patch)
tree468527116aa880a43f476dc020754b9b6c64982e
parent66199506fb91058a78b154b7fecb703ddaa27146 (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.h15
-rw-r--r--net/wireless/ap.c4
-rw-r--r--net/wireless/core.c43
-rw-r--r--net/wireless/core.h7
-rw-r--r--net/wireless/mesh.c4
-rw-r--r--net/wireless/trace.h15
-rw-r--r--net/wireless/util.c3
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 */
4771void 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
9static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, 9int __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
795void cfg80211_leave(struct cfg80211_registered_device *rdev, 795void __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
833void 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
841void 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}
861EXPORT_SYMBOL(cfg80211_stop_iface);
862
834static int cfg80211_netdev_notifier_call(struct notifier_block *nb, 863static 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
190struct cfg80211_event { 191struct 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);
285int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
286 struct net_device *dev);
284int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, 287int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
285 struct net_device *dev); 288 struct net_device *dev);
286int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, 289int 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 */
294int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
295 struct net_device *dev, bool notify);
291int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, 296int 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,
441void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, 446void 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
449void __cfg80211_leave(struct cfg80211_registered_device *rdev,
450 struct wireless_dev *wdev);
444void cfg80211_leave(struct cfg80211_registered_device *rdev, 451void 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
241static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, 241int __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
2639TRACE_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