mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 08:44:41 +00:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									66199506fb
								
							
						
					
					
						commit
						f04c22033c
					
				
					 7 changed files with 80 additions and 11 deletions
				
			
		|  | @ -4756,6 +4756,21 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, | |||
| 					    void *data), | ||||
| 			       void *data); | ||||
| 
 | ||||
| /*
 | ||||
|  * cfg80211_stop_iface - trigger interface disconnection | ||||
|  * | ||||
|  * @wiphy: the wiphy | ||||
|  * @wdev: wireless device | ||||
|  * @gfp: context flags | ||||
|  * | ||||
|  * Trigger interface to be stopped as if AP was stopped, IBSS/mesh left, STA | ||||
|  * disconnected. | ||||
|  * | ||||
|  * Note: This doesn't need any locks and is asynchronous. | ||||
|  */ | ||||
| void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev, | ||||
| 			 gfp_t gfp); | ||||
| 
 | ||||
| /* Logging, debugging and troubleshooting/diagnostic helpers. */ | ||||
| 
 | ||||
| /* wiphy_printk helpers, similar to dev_printk */ | ||||
|  |  | |||
|  | @ -6,8 +6,8 @@ | |||
| #include "rdev-ops.h" | ||||
| 
 | ||||
| 
 | ||||
| static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||||
| 			      struct net_device *dev, bool notify) | ||||
| int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||||
| 		       struct net_device *dev, bool notify) | ||||
| { | ||||
| 	struct wireless_dev *wdev = dev->ieee80211_ptr; | ||||
| 	int err; | ||||
|  |  | |||
|  | @ -792,23 +792,23 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | |||
| 		rdev->num_running_monitor_ifaces += num; | ||||
| } | ||||
| 
 | ||||
| void cfg80211_leave(struct cfg80211_registered_device *rdev, | ||||
| 		    struct wireless_dev *wdev) | ||||
| void __cfg80211_leave(struct cfg80211_registered_device *rdev, | ||||
| 		      struct wireless_dev *wdev) | ||||
| { | ||||
| 	struct net_device *dev = wdev->netdev; | ||||
| 
 | ||||
| 	ASSERT_RTNL(); | ||||
| 	ASSERT_WDEV_LOCK(wdev); | ||||
| 
 | ||||
| 	switch (wdev->iftype) { | ||||
| 	case NL80211_IFTYPE_ADHOC: | ||||
| 		cfg80211_leave_ibss(rdev, dev, true); | ||||
| 		__cfg80211_leave_ibss(rdev, dev, true); | ||||
| 		break; | ||||
| 	case NL80211_IFTYPE_P2P_CLIENT: | ||||
| 	case NL80211_IFTYPE_STATION: | ||||
| 		if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev) | ||||
| 			__cfg80211_stop_sched_scan(rdev, false); | ||||
| 
 | ||||
| 		wdev_lock(wdev); | ||||
| #ifdef CONFIG_CFG80211_WEXT | ||||
| 		kfree(wdev->wext.ie); | ||||
| 		wdev->wext.ie = NULL; | ||||
|  | @ -817,20 +817,49 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
| #endif | ||||
| 		cfg80211_disconnect(rdev, dev, | ||||
| 				    WLAN_REASON_DEAUTH_LEAVING, true); | ||||
| 		wdev_unlock(wdev); | ||||
| 		break; | ||||
| 	case NL80211_IFTYPE_MESH_POINT: | ||||
| 		cfg80211_leave_mesh(rdev, dev); | ||||
| 		__cfg80211_leave_mesh(rdev, dev); | ||||
| 		break; | ||||
| 	case NL80211_IFTYPE_AP: | ||||
| 	case NL80211_IFTYPE_P2P_GO: | ||||
| 		cfg80211_stop_ap(rdev, dev, true); | ||||
| 		__cfg80211_stop_ap(rdev, dev, true); | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void cfg80211_leave(struct cfg80211_registered_device *rdev, | ||||
| 		    struct wireless_dev *wdev) | ||||
| { | ||||
| 	wdev_lock(wdev); | ||||
| 	__cfg80211_leave(rdev, wdev); | ||||
| 	wdev_unlock(wdev); | ||||
| } | ||||
| 
 | ||||
| void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev, | ||||
| 			 gfp_t gfp) | ||||
| { | ||||
| 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | ||||
| 	struct cfg80211_event *ev; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	trace_cfg80211_stop_iface(wiphy, wdev); | ||||
| 
 | ||||
| 	ev = kzalloc(sizeof(*ev), gfp); | ||||
| 	if (!ev) | ||||
| 		return; | ||||
| 
 | ||||
| 	ev->type = EVENT_STOPPED; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&wdev->event_lock, flags); | ||||
| 	list_add_tail(&ev->list, &wdev->event_list); | ||||
| 	spin_unlock_irqrestore(&wdev->event_lock, flags); | ||||
| 	queue_work(cfg80211_wq, &rdev->event_work); | ||||
| } | ||||
| EXPORT_SYMBOL(cfg80211_stop_iface); | ||||
| 
 | ||||
| static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | ||||
| 					 unsigned long state, void *ptr) | ||||
| { | ||||
|  |  | |||
|  | @ -185,6 +185,7 @@ enum cfg80211_event_type { | |||
| 	EVENT_ROAMED, | ||||
| 	EVENT_DISCONNECTED, | ||||
| 	EVENT_IBSS_JOINED, | ||||
| 	EVENT_STOPPED, | ||||
| }; | ||||
| 
 | ||||
| struct cfg80211_event { | ||||
|  | @ -281,6 +282,8 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
| 		       struct net_device *dev, | ||||
| 		       struct mesh_setup *setup, | ||||
| 		       const struct mesh_config *conf); | ||||
| int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | ||||
| 			  struct net_device *dev); | ||||
| int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | ||||
| 			struct net_device *dev); | ||||
| int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, | ||||
|  | @ -288,6 +291,8 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, | |||
| 			      struct cfg80211_chan_def *chandef); | ||||
| 
 | ||||
| /* AP */ | ||||
| int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||||
| 		       struct net_device *dev, bool notify); | ||||
| int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||||
| 		     struct net_device *dev, bool notify); | ||||
| 
 | ||||
|  | @ -441,6 +446,8 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
| void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | ||||
| 			       enum nl80211_iftype iftype, int num); | ||||
| 
 | ||||
| void __cfg80211_leave(struct cfg80211_registered_device *rdev, | ||||
| 		      struct wireless_dev *wdev); | ||||
| void cfg80211_leave(struct cfg80211_registered_device *rdev, | ||||
| 		    struct wireless_dev *wdev); | ||||
| 
 | ||||
|  |  | |||
|  | @ -238,8 +238,8 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | ||||
| 				 struct net_device *dev) | ||||
| int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | ||||
| 			  struct net_device *dev) | ||||
| { | ||||
| 	struct wireless_dev *wdev = dev->ieee80211_ptr; | ||||
| 	int err; | ||||
|  |  | |||
|  | @ -2636,6 +2636,21 @@ TRACE_EVENT(cfg80211_ft_event, | |||
| 		  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap)) | ||||
| ); | ||||
| 
 | ||||
| TRACE_EVENT(cfg80211_stop_iface, | ||||
| 	TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), | ||||
| 	TP_ARGS(wiphy, wdev), | ||||
| 	TP_STRUCT__entry( | ||||
| 		WIPHY_ENTRY | ||||
| 		WDEV_ENTRY | ||||
| 	), | ||||
| 	TP_fast_assign( | ||||
| 		WIPHY_ASSIGN; | ||||
| 		WDEV_ASSIGN; | ||||
| 	), | ||||
| 	TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, | ||||
| 		  WIPHY_PR_ARG, WDEV_PR_ARG) | ||||
| ); | ||||
| 
 | ||||
| #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ | ||||
| 
 | ||||
| #undef TRACE_INCLUDE_PATH | ||||
|  |  | |||
|  | @ -839,6 +839,9 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) | |||
| 			__cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid, | ||||
| 					       ev->ij.channel); | ||||
| 			break; | ||||
| 		case EVENT_STOPPED: | ||||
| 			__cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev); | ||||
| 			break; | ||||
| 		} | ||||
| 		wdev_unlock(wdev); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Michal Kazior
						Michal Kazior