diff options
Diffstat (limited to 'net/mac80211')
41 files changed, 2231 insertions, 2017 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 8d249d70598..63af25458fd 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -107,6 +107,19 @@ config MAC80211_DEBUGFS  	  Say N unless you know you need this. +config MAC80211_MESSAGE_TRACING +	bool "Trace all mac80211 debug messages" +	depends on MAC80211 +	---help--- +	  Select this option to have mac80211 register the +	  mac80211_msg trace subsystem with tracepoints to +	  collect all debugging messages, independent of +	  printing them into the kernel log. + +	  The overhead in this option is that all the messages +	  need to be present in the binary and formatted at +	  runtime for tracing. +  menuconfig MAC80211_DEBUG_MENU  	bool "Select mac80211 debugging features"  	depends on MAC80211 @@ -140,26 +153,35 @@ config MAC80211_VERBOSE_DEBUG  	  Do not select this option. -config MAC80211_HT_DEBUG -	bool "Verbose HT debugging" +config MAC80211_MLME_DEBUG +	bool "Verbose managed MLME output"  	depends on MAC80211_DEBUG_MENU  	---help--- -	  This option enables 802.11n High Throughput features -	  debug tracing output. - -	  It should not be selected on production systems as some +	  Selecting this option causes mac80211 to print out +	  debugging messages for the managed-mode MLME. It +	  should not be selected on production systems as some  	  of the messages are remotely triggerable.  	  Do not select this option. -config MAC80211_TKIP_DEBUG -	bool "Verbose TKIP debugging" +config MAC80211_STA_DEBUG +	bool "Verbose station debugging"  	depends on MAC80211_DEBUG_MENU  	---help---  	  Selecting this option causes mac80211 to print out -	  very verbose TKIP debugging messages. It should not -	  be selected on production systems as those messages -	  are remotely triggerable. +	  debugging messages for station addition/removal. + +	  Do not select this option. + +config MAC80211_HT_DEBUG +	bool "Verbose HT debugging" +	depends on MAC80211_DEBUG_MENU +	---help--- +	  This option enables 802.11n High Throughput features +	  debug tracing output. + +	  It should not be selected on production systems as some +	  of the messages are remotely triggerable.  	  Do not select this option. @@ -174,7 +196,7 @@ config MAC80211_IBSS_DEBUG  	  Do not select this option. -config MAC80211_VERBOSE_PS_DEBUG +config MAC80211_PS_DEBUG  	bool "Verbose powersave mode debugging"  	depends on MAC80211_DEBUG_MENU  	---help--- @@ -186,7 +208,7 @@ config MAC80211_VERBOSE_PS_DEBUG  	  Do not select this option. -config MAC80211_VERBOSE_MPL_DEBUG +config MAC80211_MPL_DEBUG  	bool "Verbose mesh peer link debugging"  	depends on MAC80211_DEBUG_MENU  	depends on MAC80211_MESH @@ -199,7 +221,7 @@ config MAC80211_VERBOSE_MPL_DEBUG  	  Do not select this option. -config MAC80211_VERBOSE_MPATH_DEBUG +config MAC80211_MPATH_DEBUG  	bool "Verbose mesh path debugging"  	depends on MAC80211_DEBUG_MENU  	depends on MAC80211_MESH @@ -212,7 +234,7 @@ config MAC80211_VERBOSE_MPATH_DEBUG  	  Do not select this option. -config MAC80211_VERBOSE_MHWMP_DEBUG +config MAC80211_MHWMP_DEBUG  	bool "Verbose mesh HWMP routing debugging"  	depends on MAC80211_DEBUG_MENU  	depends on MAC80211_MESH @@ -225,7 +247,7 @@ config MAC80211_VERBOSE_MHWMP_DEBUG  	  Do not select this option. -config MAC80211_VERBOSE_MESH_SYNC_DEBUG +config MAC80211_MESH_SYNC_DEBUG  	bool "Verbose mesh mesh synchronization debugging"  	depends on MAC80211_DEBUG_MENU  	depends on MAC80211_MESH @@ -236,7 +258,7 @@ config MAC80211_VERBOSE_MESH_SYNC_DEBUG  	  Do not select this option. -config MAC80211_VERBOSE_TDLS_DEBUG +config MAC80211_TDLS_DEBUG  	bool "Verbose TDLS debugging"  	depends on MAC80211_DEBUG_MENU  	---help--- diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 3e9d931bba3..a7dd110faaf 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -9,7 +9,6 @@ mac80211-y := \  	scan.o offchannel.o \  	ht.o agg-tx.o agg-rx.o \  	ibss.o \ -	work.o \  	iface.o \  	rate.o \  	michael.o \ @@ -25,7 +24,7 @@ mac80211-y := \  	wme.o \  	event.o \  	chan.o \ -	driver-trace.o mlme.o +	trace.o mlme.o  mac80211-$(CONFIG_MAC80211_LEDS) += led.o  mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ @@ -43,7 +42,7 @@ mac80211-$(CONFIG_MAC80211_MESH) += \  mac80211-$(CONFIG_PM) += pm.o -CFLAGS_driver-trace.o := -I$(src) +CFLAGS_trace.o := -I$(src)  # objects for PID algorithm  rc80211_pid-y := rc80211_pid_algo.o @@ -59,4 +58,4 @@ mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y)  mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y)  mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y) -ccflags-y += -D__CHECK_ENDIAN__ +ccflags-y += -D__CHECK_ENDIAN__ -DDEBUG diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 26ddb699d69..186d9919b04 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -74,18 +74,17 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,  	RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL); -#ifdef CONFIG_MAC80211_HT_DEBUG -	printk(KERN_DEBUG +	ht_dbg(sta->sdata,  	       "Rx BA session stop requested for %pM tid %u %s reason: %d\n",  	       sta->sta.addr, tid,  	       initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator",  	       (int)reason); -#endif /* CONFIG_MAC80211_HT_DEBUG */  	if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,  			     &sta->sta, tid, NULL, 0)) -		printk(KERN_DEBUG "HW problem - can not stop rx " -				"aggregation for tid %d\n", tid); +		sdata_info(sta->sdata, +			   "HW problem - can not stop rx aggregation for tid %d\n", +			   tid);  	/* check if this is a self generated aggregation halt */  	if (initiator == WLAN_BACK_RECIPIENT && tx) @@ -145,19 +144,23 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)  	struct tid_ampdu_rx *tid_rx;  	unsigned long timeout; +	rcu_read_lock();  	tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[*ptid]); -	if (!tid_rx) +	if (!tid_rx) { +		rcu_read_unlock();  		return; +	}  	timeout = tid_rx->last_rx + TU_TO_JIFFIES(tid_rx->timeout);  	if (time_is_after_jiffies(timeout)) {  		mod_timer(&tid_rx->session_timer, timeout); +		rcu_read_unlock();  		return;  	} +	rcu_read_unlock(); + +	ht_dbg(sta->sdata, "rx session timer expired on tid %d\n", (u16)*ptid); -#ifdef CONFIG_MAC80211_HT_DEBUG -	printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); -#endif  	set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired);  	ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);  } @@ -244,10 +247,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,  	status = WLAN_STATUS_REQUEST_DECLINED;  	if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { -#ifdef CONFIG_MAC80211_HT_DEBUG -		printk(KERN_DEBUG "Suspend in progress. " -		       "Denying ADDBA request\n"); -#endif +		ht_dbg(sta->sdata, "Suspend in progress - Denying ADDBA request\n");  		goto end_no_lock;  	} @@ -259,10 +259,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,  	     (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) ||  	    (buf_size > IEEE80211_MAX_AMPDU_BUF)) {  		status = WLAN_STATUS_INVALID_QOS_PARAM; -#ifdef CONFIG_MAC80211_HT_DEBUG -		net_dbg_ratelimited("AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", -				    mgmt->sa, tid, ba_policy, buf_size); -#endif /* CONFIG_MAC80211_HT_DEBUG */ +		ht_dbg_ratelimited(sta->sdata, +				   "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", +				   mgmt->sa, tid, ba_policy, buf_size);  		goto end_no_lock;  	}  	/* determine default buffer size */ @@ -277,10 +276,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,  	mutex_lock(&sta->ampdu_mlme.mtx);  	if (sta->ampdu_mlme.tid_rx[tid]) { -#ifdef CONFIG_MAC80211_HT_DEBUG -		net_dbg_ratelimited("unexpected AddBA Req from %pM on tid %u\n", -				    mgmt->sa, tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ +		ht_dbg_ratelimited(sta->sdata, +				   "unexpected AddBA Req from %pM on tid %u\n", +				   mgmt->sa, tid);  		/* delete existing Rx BA session on the same tid */  		___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, @@ -319,10 +317,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,  	ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,  			       &sta->sta, tid, &start_seq_num, 0); -#ifdef CONFIG_MAC80211_HT_DEBUG -	printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - +	ht_dbg(sta->sdata, "Rx A-MPDU request on tid %d result %d\n", tid, ret);  	if (ret) {  		kfree(tid_agg_rx->reorder_buf);  		kfree(tid_agg_rx->reorder_time); diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 7cf07158805..d0deb3edae2 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -135,7 +135,8 @@ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)  	bar->control = cpu_to_le16(bar_control);  	bar->start_seq_num = cpu_to_le16(ssn); -	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; +	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | +					IEEE80211_TX_CTL_REQ_TX_STATUS;  	ieee80211_tx_skb_tid(sdata, skb, tid);  }  EXPORT_SYMBOL(ieee80211_send_bar); @@ -184,10 +185,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,  	spin_unlock_bh(&sta->lock); -#ifdef CONFIG_MAC80211_HT_DEBUG -	printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", +	ht_dbg(sta->sdata, "Tx BA session stop requested for %pM tid %u\n",  	       sta->sta.addr, tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */  	del_timer_sync(&tid_tx->addba_resp_timer);  	del_timer_sync(&tid_tx->session_timer); @@ -253,17 +252,13 @@ static void sta_addba_resp_timer_expired(unsigned long data)  	if (!tid_tx ||  	    test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {  		rcu_read_unlock(); -#ifdef CONFIG_MAC80211_HT_DEBUG -		printk(KERN_DEBUG "timer expired on tid %d but we are not " -				"(or no longer) expecting addBA response there\n", -			tid); -#endif +		ht_dbg(sta->sdata, +		       "timer expired on tid %d but we are not (or no longer) expecting addBA response there\n", +		       tid);  		return;  	} -#ifdef CONFIG_MAC80211_HT_DEBUG -	printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid); -#endif +	ht_dbg(sta->sdata, "addBA response timer expired on tid %d\n", tid);  	ieee80211_stop_tx_ba_session(&sta->sta, tid);  	rcu_read_unlock(); @@ -323,8 +318,9 @@ ieee80211_agg_splice_packets(struct ieee80211_sub_if_data *sdata,  	ieee80211_stop_queue_agg(sdata, tid); -	if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates" -			  " from the pending queue\n", tid)) +	if (WARN(!tid_tx, +		 "TID %d gone but expected when splicing aggregates from the pending queue\n", +		 tid))  		return;  	if (!skb_queue_empty(&tid_tx->pending)) { @@ -372,10 +368,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)  	ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,  			       &sta->sta, tid, &start_seq_num, 0);  	if (ret) { -#ifdef CONFIG_MAC80211_HT_DEBUG -		printk(KERN_DEBUG "BA request denied - HW unavailable for" -					" tid %d\n", tid); -#endif +		ht_dbg(sdata, +		       "BA request denied - HW unavailable for tid %d\n", tid);  		spin_lock_bh(&sta->lock);  		ieee80211_agg_splice_packets(sdata, tid_tx, tid);  		ieee80211_assign_tid_tx(sta, tid, NULL); @@ -388,9 +382,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)  	/* activate the timer for the recipient's addBA response */  	mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); -#ifdef CONFIG_MAC80211_HT_DEBUG -	printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); -#endif +	ht_dbg(sdata, "activated addBA response timer on tid %d\n", tid);  	spin_lock_bh(&sta->lock);  	sta->ampdu_mlme.last_addba_req_time[tid] = jiffies; @@ -437,9 +429,7 @@ static void sta_tx_agg_session_timer_expired(unsigned long data)  	rcu_read_unlock(); -#ifdef CONFIG_MAC80211_HT_DEBUG -	printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid); -#endif +	ht_dbg(sta->sdata, "tx session timer expired on tid %d\n", (u16)*ptid);  	ieee80211_stop_tx_ba_session(&sta->sta, *ptid);  } @@ -463,10 +453,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,  	    (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW))  		return -EINVAL; -#ifdef CONFIG_MAC80211_HT_DEBUG -	printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n", +	ht_dbg(sdata, "Open BA session requested for %pM tid %u\n",  	       pubsta->addr, tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */  	if (sdata->vif.type != NL80211_IFTYPE_STATION &&  	    sdata->vif.type != NL80211_IFTYPE_MESH_POINT && @@ -476,10 +464,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,  		return -EINVAL;  	if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { -#ifdef CONFIG_MAC80211_HT_DEBUG -		printk(KERN_DEBUG "BA sessions blocked. " -		       "Denying BA session request\n"); -#endif +		ht_dbg(sdata, +		       "BA sessions blocked - Denying BA session request\n");  		return -EINVAL;  	} @@ -497,10 +483,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,  	 */  	if (sta->sdata->vif.type == NL80211_IFTYPE_ADHOC &&  	    !sta->sta.ht_cap.ht_supported) { -#ifdef CONFIG_MAC80211_HT_DEBUG -		printk(KERN_DEBUG "BA request denied - IBSS STA %pM" -		       "does not advertise HT support\n", pubsta->addr); -#endif /* CONFIG_MAC80211_HT_DEBUG */ +		ht_dbg(sdata, +		       "BA request denied - IBSS STA %pM does not advertise HT support\n", +		       pubsta->addr);  		return -EINVAL;  	} @@ -520,12 +505,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,  	if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_BURST_RETRIES &&  	    time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] +  			HT_AGG_RETRIES_PERIOD)) { -#ifdef CONFIG_MAC80211_HT_DEBUG -		printk(KERN_DEBUG "BA request denied - " -		       "waiting a grace period after %d failed requests " -		       "on tid %u\n", +		ht_dbg(sdata, +		       "BA request denied - waiting a grace period after %d failed requests on tid %u\n",  		       sta->ampdu_mlme.addba_req_num[tid], tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */  		ret = -EBUSY;  		goto err_unlock_sta;  	} @@ -533,10 +515,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,  	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);  	/* check if the TID is not in aggregation flow already */  	if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { -#ifdef CONFIG_MAC80211_HT_DEBUG -		printk(KERN_DEBUG "BA request denied - session is not " -				 "idle on tid %u\n", tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ +		ht_dbg(sdata, +		       "BA request denied - session is not idle on tid %u\n", +		       tid);  		ret = -EAGAIN;  		goto err_unlock_sta;  	} @@ -591,9 +572,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,  	tid_tx = rcu_dereference_protected_tid_tx(sta, tid); -#ifdef CONFIG_MAC80211_HT_DEBUG -	printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); -#endif +	ht_dbg(sta->sdata, "Aggregation is on for tid %d\n", tid);  	drv_ampdu_action(local, sta->sdata,  			 IEEE80211_AMPDU_TX_OPERATIONAL, @@ -627,10 +606,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)  	trace_api_start_tx_ba_cb(sdata, ra, tid);  	if (tid >= STA_TID_NUM) { -#ifdef CONFIG_MAC80211_HT_DEBUG -		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", -				tid, STA_TID_NUM); -#endif +		ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", +		       tid, STA_TID_NUM);  		return;  	} @@ -638,9 +615,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)  	sta = sta_info_get_bss(sdata, ra);  	if (!sta) {  		mutex_unlock(&local->sta_mtx); -#ifdef CONFIG_MAC80211_HT_DEBUG -		printk(KERN_DEBUG "Could not find station: %pM\n", ra); -#endif +		ht_dbg(sdata, "Could not find station: %pM\n", ra);  		return;  	} @@ -648,9 +623,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)  	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);  	if (WARN_ON(!tid_tx)) { -#ifdef CONFIG_MAC80211_HT_DEBUG -		printk(KERN_DEBUG "addBA was not requested!\n"); -#endif +		ht_dbg(sdata, "addBA was not requested!\n");  		goto unlock;  	} @@ -750,25 +723,18 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)  	trace_api_stop_tx_ba_cb(sdata, ra, tid);  	if (tid >= STA_TID_NUM) { -#ifdef CONFIG_MAC80211_HT_DEBUG -		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", -				tid, STA_TID_NUM); -#endif +		ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", +		       tid, STA_TID_NUM);  		return;  	} -#ifdef CONFIG_MAC80211_HT_DEBUG -	printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n", -	       ra, tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ +	ht_dbg(sdata, "Stopping Tx BA session for %pM tid %d\n", ra, tid);  	mutex_lock(&local->sta_mtx);  	sta = sta_info_get_bss(sdata, ra);  	if (!sta) { -#ifdef CONFIG_MAC80211_HT_DEBUG -		printk(KERN_DEBUG "Could not find station: %pM\n", ra); -#endif +		ht_dbg(sdata, "Could not find station: %pM\n", ra);  		goto unlock;  	} @@ -777,9 +743,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)  	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);  	if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { -#ifdef CONFIG_MAC80211_HT_DEBUG -		printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); -#endif +		ht_dbg(sdata, "unexpected callback to A-MPDU stop\n");  		goto unlock_sta;  	} @@ -855,17 +819,13 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,  		goto out;  	if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) { -#ifdef CONFIG_MAC80211_HT_DEBUG -		printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); -#endif +		ht_dbg(sta->sdata, "wrong addBA response token, tid %d\n", tid);  		goto out;  	}  	del_timer_sync(&tid_tx->addba_resp_timer); -#ifdef CONFIG_MAC80211_HT_DEBUG -	printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); -#endif +	ht_dbg(sta->sdata, "switched off addBA timer for tid %d\n", tid);  	/*  	 * addba_resp_timer may have fired before we got here, and @@ -874,11 +834,9 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,  	 */  	if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||  	    test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { -#ifdef CONFIG_MAC80211_HT_DEBUG -		printk(KERN_DEBUG +		ht_dbg(sta->sdata,  		       "got addBA resp for tid %d but we already gave up\n",  		       tid); -#endif  		goto out;  	} diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 495831ee48f..d41974aacf5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -20,31 +20,31 @@  #include "rate.h"  #include "mesh.h" -static struct net_device *ieee80211_add_iface(struct wiphy *wiphy, char *name, -					      enum nl80211_iftype type, -					      u32 *flags, -					      struct vif_params *params) +static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, char *name, +						enum nl80211_iftype type, +						u32 *flags, +						struct vif_params *params)  {  	struct ieee80211_local *local = wiphy_priv(wiphy); -	struct net_device *dev; +	struct wireless_dev *wdev;  	struct ieee80211_sub_if_data *sdata;  	int err; -	err = ieee80211_if_add(local, name, &dev, type, params); +	err = ieee80211_if_add(local, name, &wdev, type, params);  	if (err)  		return ERR_PTR(err);  	if (type == NL80211_IFTYPE_MONITOR && flags) { -		sdata = IEEE80211_DEV_TO_SUB_IF(dev); +		sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);  		sdata->u.mntr_flags = *flags;  	} -	return dev; +	return wdev;  } -static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) +static int ieee80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)  { -	ieee80211_if_remove(IEEE80211_DEV_TO_SUB_IF(dev)); +	ieee80211_if_remove(IEEE80211_WDEV_TO_SUB_IF(wdev));  	return 0;  } @@ -353,6 +353,7 @@ void sta_set_rate_info_tx(struct sta_info *sta,  static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)  {  	struct ieee80211_sub_if_data *sdata = sta->sdata; +	struct ieee80211_local *local = sdata->local;  	struct timespec uptime;  	sinfo->generation = sdata->local->sta_generation; @@ -388,7 +389,9 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)  	if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ||  	    (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) {  		sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; -		sinfo->signal = (s8)sta->last_signal; +		if (!local->ops->get_rssi || +		    drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal)) +			sinfo->signal = (s8)sta->last_signal;  		sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);  	} @@ -517,7 +520,7 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,  	 * network device.  	 */ -	rcu_read_lock(); +	mutex_lock(&local->sta_mtx);  	if (sdata->vif.type == NL80211_IFTYPE_STATION) {  		sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); @@ -533,20 +536,20 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,  		sinfo.filled = 0;  		sta_set_sinfo(sta, &sinfo); -		if (sinfo.filled | STATION_INFO_TX_BITRATE) +		if (sinfo.filled & STATION_INFO_TX_BITRATE)  			data[i] = 100000 *  				cfg80211_calculate_bitrate(&sinfo.txrate);  		i++; -		if (sinfo.filled | STATION_INFO_RX_BITRATE) +		if (sinfo.filled & STATION_INFO_RX_BITRATE)  			data[i] = 100000 *  				cfg80211_calculate_bitrate(&sinfo.rxrate);  		i++; -		if (sinfo.filled | STATION_INFO_SIGNAL_AVG) +		if (sinfo.filled & STATION_INFO_SIGNAL_AVG)  			data[i] = (u8)sinfo.signal_avg;  		i++;  	} else { -		list_for_each_entry_rcu(sta, &local->sta_list, list) { +		list_for_each_entry(sta, &local->sta_list, list) {  			/* Make sure this station belongs to the proper dev */  			if (sta->sdata->dev != dev)  				continue; @@ -603,7 +606,7 @@ do_survey:  	else  		data[i++] = -1LL; -	rcu_read_unlock(); +	mutex_unlock(&local->sta_mtx);  	if (WARN_ON(i != STA_STATS_LEN))  		return; @@ -629,10 +632,11 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,  				 int idx, u8 *mac, struct station_info *sinfo)  {  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); +	struct ieee80211_local *local = sdata->local;  	struct sta_info *sta;  	int ret = -ENOENT; -	rcu_read_lock(); +	mutex_lock(&local->sta_mtx);  	sta = sta_info_get_by_idx(sdata, idx);  	if (sta) { @@ -641,7 +645,7 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,  		sta_set_sinfo(sta, sinfo);  	} -	rcu_read_unlock(); +	mutex_unlock(&local->sta_mtx);  	return ret;  } @@ -658,10 +662,11 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,  				 u8 *mac, struct station_info *sinfo)  {  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); +	struct ieee80211_local *local = sdata->local;  	struct sta_info *sta;  	int ret = -ENOENT; -	rcu_read_lock(); +	mutex_lock(&local->sta_mtx);  	sta = sta_info_get_bss(sdata, mac);  	if (sta) { @@ -669,11 +674,54 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,  		sta_set_sinfo(sta, sinfo);  	} -	rcu_read_unlock(); +	mutex_unlock(&local->sta_mtx);  	return ret;  } +static int ieee80211_set_channel(struct wiphy *wiphy, +				 struct net_device *netdev, +				 struct ieee80211_channel *chan, +				 enum nl80211_channel_type channel_type) +{ +	struct ieee80211_local *local = wiphy_priv(wiphy); +	struct ieee80211_sub_if_data *sdata = NULL; + +	if (netdev) +		sdata = IEEE80211_DEV_TO_SUB_IF(netdev); + +	switch (ieee80211_get_channel_mode(local, NULL)) { +	case CHAN_MODE_HOPPING: +		return -EBUSY; +	case CHAN_MODE_FIXED: +		if (local->oper_channel != chan || +		    (!sdata && local->_oper_channel_type != channel_type)) +			return -EBUSY; +		if (!sdata && local->_oper_channel_type == channel_type) +			return 0; +		break; +	case CHAN_MODE_UNDEFINED: +		break; +	} + +	if (!ieee80211_set_channel_type(local, sdata, channel_type)) +		return -EBUSY; + +	local->oper_channel = chan; + +	/* auto-detects changes */ +	ieee80211_hw_config(local, 0); + +	return 0; +} + +static int ieee80211_set_monitor_channel(struct wiphy *wiphy, +					 struct ieee80211_channel *chan, +					 enum nl80211_channel_type channel_type) +{ +	return ieee80211_set_channel(wiphy, NULL, chan, channel_type); +} +  static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,  				    const u8 *resp, size_t resp_len)  { @@ -788,6 +836,11 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,  	if (old)  		return -EALREADY; +	err = ieee80211_set_channel(wiphy, dev, params->channel, +				    params->channel_type); +	if (err) +		return err; +  	/*  	 * Apply control port protocol, this allows us to  	 * not encrypt dynamic WEP control frames. @@ -864,6 +917,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)  	kfree_rcu(old, rcu_head); +	sta_info_flush(sdata->local, sdata);  	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);  	return 0; @@ -1482,7 +1536,7 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,  	if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask))  		conf->dot11MeshTTL = nconf->dot11MeshTTL;  	if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask)) -		conf->dot11MeshTTL = nconf->element_ttl; +		conf->element_ttl = nconf->element_ttl;  	if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask))  		conf->auto_open_plinks = nconf->auto_open_plinks;  	if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask)) @@ -1517,17 +1571,16 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,  		 * announcements, so require this ifmsh to also be a root node  		 * */  		if (nconf->dot11MeshGateAnnouncementProtocol && -		    !conf->dot11MeshHWMPRootMode) { -			conf->dot11MeshHWMPRootMode = 1; +		    !(conf->dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)) { +			conf->dot11MeshHWMPRootMode = IEEE80211_PROACTIVE_RANN;  			ieee80211_mesh_root_setup(ifmsh);  		}  		conf->dot11MeshGateAnnouncementProtocol =  			nconf->dot11MeshGateAnnouncementProtocol;  	} -	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) { +	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask))  		conf->dot11MeshHWMPRannInterval =  			nconf->dot11MeshHWMPRannInterval; -	}  	if (_chg_mesh_attr(NL80211_MESHCONF_FORWARDING, mask))  		conf->dot11MeshForwarding = nconf->dot11MeshForwarding;  	if (_chg_mesh_attr(NL80211_MESHCONF_RSSI_THRESHOLD, mask)) { @@ -1543,6 +1596,15 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,  		sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode;  		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);  	} +	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, mask)) +		conf->dot11MeshHWMPactivePathToRootTimeout = +			nconf->dot11MeshHWMPactivePathToRootTimeout; +	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ROOT_INTERVAL, mask)) +		conf->dot11MeshHWMProotInterval = +			nconf->dot11MeshHWMProotInterval; +	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, mask)) +		conf->dot11MeshHWMPconfirmationInterval = +			nconf->dot11MeshHWMPconfirmationInterval;  	return 0;  } @@ -1558,6 +1620,12 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,  	err = copy_mesh_setup(ifmsh, setup);  	if (err)  		return err; + +	err = ieee80211_set_channel(wiphy, dev, setup->channel, +				    setup->channel_type); +	if (err) +		return err; +  	ieee80211_start_mesh(sdata);  	return 0; @@ -1674,54 +1742,7 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,  		return -EINVAL;  	} -	return 0; -} - -static int ieee80211_set_channel(struct wiphy *wiphy, -				 struct net_device *netdev, -				 struct ieee80211_channel *chan, -				 enum nl80211_channel_type channel_type) -{ -	struct ieee80211_local *local = wiphy_priv(wiphy); -	struct ieee80211_sub_if_data *sdata = NULL; -	struct ieee80211_channel *old_oper; -	enum nl80211_channel_type old_oper_type; -	enum nl80211_channel_type old_vif_oper_type= NL80211_CHAN_NO_HT; - -	if (netdev) -		sdata = IEEE80211_DEV_TO_SUB_IF(netdev); - -	switch (ieee80211_get_channel_mode(local, NULL)) { -	case CHAN_MODE_HOPPING: -		return -EBUSY; -	case CHAN_MODE_FIXED: -		if (local->oper_channel != chan) -			return -EBUSY; -		if (!sdata && local->_oper_channel_type == channel_type) -			return 0; -		break; -	case CHAN_MODE_UNDEFINED: -		break; -	} - -	if (sdata) -		old_vif_oper_type = sdata->vif.bss_conf.channel_type; -	old_oper_type = local->_oper_channel_type; - -	if (!ieee80211_set_channel_type(local, sdata, channel_type)) -		return -EBUSY; - -	old_oper = local->oper_channel; -	local->oper_channel = chan; - -	/* Update driver if changes were actually made. */ -	if ((old_oper != local->oper_channel) || -	    (old_oper_type != local->_oper_channel_type)) -		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - -	if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR && -	    old_vif_oper_type != sdata->vif.bss_conf.channel_type) -		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); +	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);  	return 0;  } @@ -1743,10 +1764,11 @@ static int ieee80211_resume(struct wiphy *wiphy)  #endif  static int ieee80211_scan(struct wiphy *wiphy, -			  struct net_device *dev,  			  struct cfg80211_scan_request *req)  { -	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); +	struct ieee80211_sub_if_data *sdata; + +	sdata = IEEE80211_WDEV_TO_SUB_IF(req->wdev);  	switch (ieee80211_vif_type_p2p(&sdata->vif)) {  	case NL80211_IFTYPE_STATION: @@ -2093,6 +2115,9 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,  	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);  	int i, ret; +	if (!ieee80211_sdata_running(sdata)) +		return -ENETDOWN; +  	if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) {  		ret = drv_set_bitrate_mask(local, sdata, mask);  		if (ret) @@ -2108,143 +2133,291 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,  	return 0;  } -static int ieee80211_remain_on_channel_hw(struct ieee80211_local *local, -					  struct net_device *dev, -					  struct ieee80211_channel *chan, -					  enum nl80211_channel_type chantype, -					  unsigned int duration, u64 *cookie) +static int ieee80211_start_roc_work(struct ieee80211_local *local, +				    struct ieee80211_sub_if_data *sdata, +				    struct ieee80211_channel *channel, +				    enum nl80211_channel_type channel_type, +				    unsigned int duration, u64 *cookie, +				    struct sk_buff *txskb)  { +	struct ieee80211_roc_work *roc, *tmp; +	bool queued = false;  	int ret; -	u32 random_cookie;  	lockdep_assert_held(&local->mtx); -	if (local->hw_roc_cookie) -		return -EBUSY; -	/* must be nonzero */ -	random_cookie = random32() | 1; +	roc = kzalloc(sizeof(*roc), GFP_KERNEL); +	if (!roc) +		return -ENOMEM; + +	roc->chan = channel; +	roc->chan_type = channel_type; +	roc->duration = duration; +	roc->req_duration = duration; +	roc->frame = txskb; +	roc->mgmt_tx_cookie = (unsigned long)txskb; +	roc->sdata = sdata; +	INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work); +	INIT_LIST_HEAD(&roc->dependents); + +	/* if there's one pending or we're scanning, queue this one */ +	if (!list_empty(&local->roc_list) || local->scanning) +		goto out_check_combine; + +	/* if not HW assist, just queue & schedule work */ +	if (!local->ops->remain_on_channel) { +		ieee80211_queue_delayed_work(&local->hw, &roc->work, 0); +		goto out_queue; +	} + +	/* otherwise actually kick it off here (for error handling) */ -	*cookie = random_cookie; -	local->hw_roc_dev = dev; -	local->hw_roc_cookie = random_cookie; -	local->hw_roc_channel = chan; -	local->hw_roc_channel_type = chantype; -	local->hw_roc_duration = duration; -	ret = drv_remain_on_channel(local, chan, chantype, duration); +	/* +	 * If the duration is zero, then the driver +	 * wouldn't actually do anything. Set it to +	 * 10 for now. +	 * +	 * TODO: cancel the off-channel operation +	 *       when we get the SKB's TX status and +	 *       the wait time was zero before. +	 */ +	if (!duration) +		duration = 10; + +	ret = drv_remain_on_channel(local, channel, channel_type, duration);  	if (ret) { -		local->hw_roc_channel = NULL; -		local->hw_roc_cookie = 0; +		kfree(roc); +		return ret;  	} -	return ret; +	roc->started = true; +	goto out_queue; + + out_check_combine: +	list_for_each_entry(tmp, &local->roc_list, list) { +		if (tmp->chan != channel || tmp->chan_type != channel_type) +			continue; + +		/* +		 * Extend this ROC if possible: +		 * +		 * If it hasn't started yet, just increase the duration +		 * and add the new one to the list of dependents. +		 */ +		if (!tmp->started) { +			list_add_tail(&roc->list, &tmp->dependents); +			tmp->duration = max(tmp->duration, roc->duration); +			queued = true; +			break; +		} + +		/* If it has already started, it's more difficult ... */ +		if (local->ops->remain_on_channel) { +			unsigned long j = jiffies; + +			/* +			 * In the offloaded ROC case, if it hasn't begun, add +			 * this new one to the dependent list to be handled +			 * when the the master one begins. If it has begun, +			 * check that there's still a minimum time left and +			 * if so, start this one, transmitting the frame, but +			 * add it to the list directly after this one with a +			 * a reduced time so we'll ask the driver to execute +			 * it right after finishing the previous one, in the +			 * hope that it'll also be executed right afterwards, +			 * effectively extending the old one. +			 * If there's no minimum time left, just add it to the +			 * normal list. +			 */ +			if (!tmp->hw_begun) { +				list_add_tail(&roc->list, &tmp->dependents); +				queued = true; +				break; +			} + +			if (time_before(j + IEEE80211_ROC_MIN_LEFT, +					tmp->hw_start_time + +					msecs_to_jiffies(tmp->duration))) { +				int new_dur; + +				ieee80211_handle_roc_started(roc); + +				new_dur = roc->duration - +					  jiffies_to_msecs(tmp->hw_start_time + +							   msecs_to_jiffies( +								tmp->duration) - +							   j); + +				if (new_dur > 0) { +					/* add right after tmp */ +					list_add(&roc->list, &tmp->list); +				} else { +					list_add_tail(&roc->list, +						      &tmp->dependents); +				} +				queued = true; +			} +		} else if (del_timer_sync(&tmp->work.timer)) { +			unsigned long new_end; + +			/* +			 * In the software ROC case, cancel the timer, if +			 * that fails then the finish work is already +			 * queued/pending and thus we queue the new ROC +			 * normally, if that succeeds then we can extend +			 * the timer duration and TX the frame (if any.) +			 */ + +			list_add_tail(&roc->list, &tmp->dependents); +			queued = true; + +			new_end = jiffies + msecs_to_jiffies(roc->duration); + +			/* ok, it was started & we canceled timer */ +			if (time_after(new_end, tmp->work.timer.expires)) +				mod_timer(&tmp->work.timer, new_end); +			else +				add_timer(&tmp->work.timer); + +			ieee80211_handle_roc_started(roc); +		} +		break; +	} + + out_queue: +	if (!queued) +		list_add_tail(&roc->list, &local->roc_list); + +	/* +	 * cookie is either the roc (for normal roc) +	 * or the SKB (for mgmt TX) +	 */ +	if (txskb) +		*cookie = (unsigned long)txskb; +	else +		*cookie = (unsigned long)roc; + +	return 0;  }  static int ieee80211_remain_on_channel(struct wiphy *wiphy, -				       struct net_device *dev, +				       struct wireless_dev *wdev,  				       struct ieee80211_channel *chan,  				       enum nl80211_channel_type channel_type,  				       unsigned int duration,  				       u64 *cookie)  { -	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); +	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);  	struct ieee80211_local *local = sdata->local; +	int ret; -	if (local->ops->remain_on_channel) { -		int ret; - -		mutex_lock(&local->mtx); -		ret = ieee80211_remain_on_channel_hw(local, dev, -						     chan, channel_type, -						     duration, cookie); -		local->hw_roc_for_tx = false; -		mutex_unlock(&local->mtx); - -		return ret; -	} +	mutex_lock(&local->mtx); +	ret = ieee80211_start_roc_work(local, sdata, chan, channel_type, +				       duration, cookie, NULL); +	mutex_unlock(&local->mtx); -	return ieee80211_wk_remain_on_channel(sdata, chan, channel_type, -					      duration, cookie); +	return ret;  } -static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local, -						 u64 cookie) +static int ieee80211_cancel_roc(struct ieee80211_local *local, +				u64 cookie, bool mgmt_tx)  { +	struct ieee80211_roc_work *roc, *tmp, *found = NULL;  	int ret; -	lockdep_assert_held(&local->mtx); +	mutex_lock(&local->mtx); +	list_for_each_entry_safe(roc, tmp, &local->roc_list, list) { +		struct ieee80211_roc_work *dep, *tmp2; -	if (local->hw_roc_cookie != cookie) -		return -ENOENT; +		list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) { +			if (!mgmt_tx && (unsigned long)dep != cookie) +				continue; +			else if (mgmt_tx && dep->mgmt_tx_cookie != cookie) +				continue; +			/* found dependent item -- just remove it */ +			list_del(&dep->list); +			mutex_unlock(&local->mtx); -	ret = drv_cancel_remain_on_channel(local); -	if (ret) -		return ret; +			ieee80211_roc_notify_destroy(dep); +			return 0; +		} -	local->hw_roc_cookie = 0; -	local->hw_roc_channel = NULL; +		if (!mgmt_tx && (unsigned long)roc != cookie) +			continue; +		else if (mgmt_tx && roc->mgmt_tx_cookie != cookie) +			continue; -	ieee80211_recalc_idle(local); +		found = roc; +		break; +	} -	return 0; -} +	if (!found) { +		mutex_unlock(&local->mtx); +		return -ENOENT; +	} -static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, -					      struct net_device *dev, -					      u64 cookie) -{ -	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); -	struct ieee80211_local *local = sdata->local; +	/* +	 * We found the item to cancel, so do that. Note that it +	 * may have dependents, which we also cancel (and send +	 * the expired signal for.) Not doing so would be quite +	 * tricky here, but we may need to fix it later. +	 */ + +	if (local->ops->remain_on_channel) { +		if (found->started) { +			ret = drv_cancel_remain_on_channel(local); +			if (WARN_ON_ONCE(ret)) { +				mutex_unlock(&local->mtx); +				return ret; +			} +		} -	if (local->ops->cancel_remain_on_channel) { -		int ret; +		list_del(&found->list); -		mutex_lock(&local->mtx); -		ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); +		if (found->started) +			ieee80211_start_next_roc(local);  		mutex_unlock(&local->mtx); -		return ret; +		ieee80211_roc_notify_destroy(found); +	} else { +		/* work may be pending so use it all the time */ +		found->abort = true; +		ieee80211_queue_delayed_work(&local->hw, &found->work, 0); + +		mutex_unlock(&local->mtx); + +		/* work will clean up etc */ +		flush_delayed_work(&found->work);  	} -	return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); +	return 0;  } -static enum work_done_result -ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb) +static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, +					      struct wireless_dev *wdev, +					      u64 cookie)  { -	/* -	 * Use the data embedded in the work struct for reporting -	 * here so if the driver mangled the SKB before dropping -	 * it (which is the only way we really should get here) -	 * then we don't report mangled data. -	 * -	 * If there was no wait time, then by the time we get here -	 * the driver will likely not have reported the status yet, -	 * so in that case userspace will have to deal with it. -	 */ - -	if (wk->offchan_tx.wait && !wk->offchan_tx.status) -		cfg80211_mgmt_tx_status(wk->sdata->dev, -					(unsigned long) wk->offchan_tx.frame, -					wk->data, wk->data_len, false, GFP_KERNEL); +	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); +	struct ieee80211_local *local = sdata->local; -	return WORK_DONE_DESTROY; +	return ieee80211_cancel_roc(local, cookie, false);  } -static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, +static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,  			     struct ieee80211_channel *chan, bool offchan,  			     enum nl80211_channel_type channel_type,  			     bool channel_type_valid, unsigned int wait,  			     const u8 *buf, size_t len, bool no_cck,  			     bool dont_wait_for_ack, u64 *cookie)  { -	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); +	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);  	struct ieee80211_local *local = sdata->local;  	struct sk_buff *skb;  	struct sta_info *sta; -	struct ieee80211_work *wk;  	const struct ieee80211_mgmt *mgmt = (void *)buf; +	bool need_offchan = false;  	u32 flags; -	bool is_offchan = false; +	int ret;  	if (dont_wait_for_ack)  		flags = IEEE80211_TX_CTL_NO_ACK; @@ -2252,33 +2425,28 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,  		flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |  			IEEE80211_TX_CTL_REQ_TX_STATUS; -	/* Check that we are on the requested channel for transmission */ -	if (chan != local->tmp_channel && -	    chan != local->oper_channel) -		is_offchan = true; -	if (channel_type_valid && -	    (channel_type != local->tmp_channel_type && -	     channel_type != local->_oper_channel_type)) -		is_offchan = true; - -	if (chan == local->hw_roc_channel) { -		/* TODO: check channel type? */ -		is_offchan = false; -		flags |= IEEE80211_TX_CTL_TX_OFFCHAN; -	} -  	if (no_cck)  		flags |= IEEE80211_TX_CTL_NO_CCK_RATE; -	if (is_offchan && !offchan) -		return -EBUSY; -  	switch (sdata->vif.type) {  	case NL80211_IFTYPE_ADHOC: +		if (!sdata->vif.bss_conf.ibss_joined) +			need_offchan = true; +		/* fall through */ +#ifdef CONFIG_MAC80211_MESH +	case NL80211_IFTYPE_MESH_POINT: +		if (ieee80211_vif_is_mesh(&sdata->vif) && +		    !sdata->u.mesh.mesh_id_len) +			need_offchan = true; +		/* fall through */ +#endif  	case NL80211_IFTYPE_AP:  	case NL80211_IFTYPE_AP_VLAN:  	case NL80211_IFTYPE_P2P_GO: -	case NL80211_IFTYPE_MESH_POINT: +		if (sdata->vif.type != NL80211_IFTYPE_ADHOC && +		    !ieee80211_vif_is_mesh(&sdata->vif) && +		    !rcu_access_pointer(sdata->bss->beacon)) +			need_offchan = true;  		if (!ieee80211_is_action(mgmt->frame_control) ||  		    mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)  			break; @@ -2290,167 +2458,101 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,  		break;  	case NL80211_IFTYPE_STATION:  	case NL80211_IFTYPE_P2P_CLIENT: +		if (!sdata->u.mgd.associated) +			need_offchan = true;  		break;  	default:  		return -EOPNOTSUPP;  	} +	mutex_lock(&local->mtx); + +	/* Check if the operating channel is the requested channel */ +	if (!need_offchan) { +		need_offchan = chan != local->oper_channel; +		if (channel_type_valid && +		    channel_type != local->_oper_channel_type) +			need_offchan = true; +	} + +	if (need_offchan && !offchan) { +		ret = -EBUSY; +		goto out_unlock; +	} +  	skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); -	if (!skb) -		return -ENOMEM; +	if (!skb) { +		ret = -ENOMEM; +		goto out_unlock; +	}  	skb_reserve(skb, local->hw.extra_tx_headroom);  	memcpy(skb_put(skb, len), buf, len);  	IEEE80211_SKB_CB(skb)->flags = flags; -	if (flags & IEEE80211_TX_CTL_TX_OFFCHAN) -		IEEE80211_SKB_CB(skb)->hw_queue = -			local->hw.offchannel_tx_hw_queue; -  	skb->dev = sdata->dev; -	*cookie = (unsigned long) skb; - -	if (is_offchan && local->ops->remain_on_channel) { -		unsigned int duration; -		int ret; - -		mutex_lock(&local->mtx); -		/* -		 * If the duration is zero, then the driver -		 * wouldn't actually do anything. Set it to -		 * 100 for now. -		 * -		 * TODO: cancel the off-channel operation -		 *       when we get the SKB's TX status and -		 *       the wait time was zero before. -		 */ -		duration = 100; -		if (wait) -			duration = wait; -		ret = ieee80211_remain_on_channel_hw(local, dev, chan, -						     channel_type, -						     duration, cookie); -		if (ret) { -			kfree_skb(skb); -			mutex_unlock(&local->mtx); -			return ret; -		} - -		local->hw_roc_for_tx = true; -		local->hw_roc_duration = wait; - -		/* -		 * queue up frame for transmission after -		 * ieee80211_ready_on_channel call -		 */ +	if (!need_offchan) { +		*cookie = (unsigned long) skb; +		ieee80211_tx_skb(sdata, skb); +		ret = 0; +		goto out_unlock; +	} -		/* modify cookie to prevent API mismatches */ -		*cookie ^= 2; -		IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN; +	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN; +	if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)  		IEEE80211_SKB_CB(skb)->hw_queue =  			local->hw.offchannel_tx_hw_queue; -		local->hw_roc_skb = skb; -		local->hw_roc_skb_for_status = skb; -		mutex_unlock(&local->mtx); - -		return 0; -	} - -	/* -	 * Can transmit right away if the channel was the -	 * right one and there's no wait involved... If a -	 * wait is involved, we might otherwise not be on -	 * the right channel for long enough! -	 */ -	if (!is_offchan && !wait && !sdata->vif.bss_conf.idle) { -		ieee80211_tx_skb(sdata, skb); -		return 0; -	} -	wk = kzalloc(sizeof(*wk) + len, GFP_KERNEL); -	if (!wk) { +	/* This will handle all kinds of coalescing and immediate TX */ +	ret = ieee80211_start_roc_work(local, sdata, chan, channel_type, +				       wait, cookie, skb); +	if (ret)  		kfree_skb(skb); -		return -ENOMEM; -	} - -	wk->type = IEEE80211_WORK_OFFCHANNEL_TX; -	wk->chan = chan; -	wk->chan_type = channel_type; -	wk->sdata = sdata; -	wk->done = ieee80211_offchan_tx_done; -	wk->offchan_tx.frame = skb; -	wk->offchan_tx.wait = wait; -	wk->data_len = len; -	memcpy(wk->data, buf, len); - -	ieee80211_add_work(wk); -	return 0; + out_unlock: +	mutex_unlock(&local->mtx); +	return ret;  }  static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, -					 struct net_device *dev, +					 struct wireless_dev *wdev,  					 u64 cookie)  { -	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); -	struct ieee80211_local *local = sdata->local; -	struct ieee80211_work *wk; -	int ret = -ENOENT; - -	mutex_lock(&local->mtx); - -	if (local->ops->cancel_remain_on_channel) { -		cookie ^= 2; -		ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); - -		if (ret == 0) { -			kfree_skb(local->hw_roc_skb); -			local->hw_roc_skb = NULL; -			local->hw_roc_skb_for_status = NULL; -		} - -		mutex_unlock(&local->mtx); - -		return ret; -	} - -	list_for_each_entry(wk, &local->work_list, list) { -		if (wk->sdata != sdata) -			continue; - -		if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX) -			continue; - -		if (cookie != (unsigned long) wk->offchan_tx.frame) -			continue; - -		wk->timeout = jiffies; - -		ieee80211_queue_work(&local->hw, &local->work_work); -		ret = 0; -		break; -	} -	mutex_unlock(&local->mtx); +	struct ieee80211_local *local = wiphy_priv(wiphy); -	return ret; +	return ieee80211_cancel_roc(local, cookie, true);  }  static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, -					  struct net_device *dev, +					  struct wireless_dev *wdev,  					  u16 frame_type, bool reg)  {  	struct ieee80211_local *local = wiphy_priv(wiphy); +	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); -	if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) -		return; +	switch (frame_type) { +	case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH: +		if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { +			struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; -	if (reg) -		local->probe_req_reg++; -	else -		local->probe_req_reg--; +			if (reg) +				ifibss->auth_frame_registrations++; +			else +				ifibss->auth_frame_registrations--; +		} +		break; +	case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ: +		if (reg) +			local->probe_req_reg++; +		else +			local->probe_req_reg--; -	ieee80211_queue_work(&local->hw, &local->reconfig_filter); +		ieee80211_queue_work(&local->hw, &local->reconfig_filter); +		break; +	default: +		break; +	}  }  static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) @@ -2570,8 +2672,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,  		tf->u.setup_req.capability =  			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); -		ieee80211_add_srates_ie(&sdata->vif, skb, false); -		ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); +		ieee80211_add_srates_ie(sdata, skb, false); +		ieee80211_add_ext_srates_ie(sdata, skb, false);  		ieee80211_tdls_add_ext_capab(skb);  		break;  	case WLAN_TDLS_SETUP_RESPONSE: @@ -2584,8 +2686,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,  		tf->u.setup_resp.capability =  			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); -		ieee80211_add_srates_ie(&sdata->vif, skb, false); -		ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); +		ieee80211_add_srates_ie(sdata, skb, false); +		ieee80211_add_ext_srates_ie(sdata, skb, false);  		ieee80211_tdls_add_ext_capab(skb);  		break;  	case WLAN_TDLS_SETUP_CONFIRM: @@ -2645,8 +2747,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,  		mgmt->u.action.u.tdls_discover_resp.capability =  			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); -		ieee80211_add_srates_ie(&sdata->vif, skb, false); -		ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); +		ieee80211_add_srates_ie(sdata, skb, false); +		ieee80211_add_ext_srates_ie(sdata, skb, false);  		ieee80211_tdls_add_ext_capab(skb);  		break;  	default: @@ -2676,9 +2778,8 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,  	    !sdata->u.mgd.associated)  		return -EINVAL; -#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG -	printk(KERN_DEBUG "TDLS mgmt action %d peer %pM\n", action_code, peer); -#endif +	tdls_dbg(sdata, "TDLS mgmt action %d peer %pM\n", +		 action_code, peer);  	skb = dev_alloc_skb(local->hw.extra_tx_headroom +  			    max(sizeof(struct ieee80211_mgmt), @@ -2787,9 +2888,7 @@ static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,  	if (sdata->vif.type != NL80211_IFTYPE_STATION)  		return -EINVAL; -#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG -	printk(KERN_DEBUG "TDLS oper %d peer %pM\n", oper, peer); -#endif +	tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);  	switch (oper) {  	case NL80211_TDLS_ENABLE_LINK: @@ -2886,8 +2985,8 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,  }  static struct ieee80211_channel * -ieee80211_wiphy_get_channel(struct wiphy *wiphy, -			    enum nl80211_channel_type *type) +ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, +			  enum nl80211_channel_type *type)  {  	struct ieee80211_local *local = wiphy_priv(wiphy); @@ -2933,7 +3032,7 @@ struct cfg80211_ops mac80211_config_ops = {  #endif  	.change_bss = ieee80211_change_bss,  	.set_txq_params = ieee80211_set_txq_params, -	.set_channel = ieee80211_set_channel, +	.set_monitor_channel = ieee80211_set_monitor_channel,  	.suspend = ieee80211_suspend,  	.resume = ieee80211_resume,  	.scan = ieee80211_scan, @@ -2968,7 +3067,6 @@ struct cfg80211_ops mac80211_config_ops = {  	.tdls_oper = ieee80211_tdls_oper,  	.tdls_mgmt = ieee80211_tdls_mgmt,  	.probe_client = ieee80211_probe_client, -	.get_channel = ieee80211_wiphy_get_channel,  	.set_noack_map = ieee80211_set_noack_map,  #ifdef CONFIG_PM  	.set_wakeup = ieee80211_set_wakeup, @@ -2976,4 +3074,5 @@ struct cfg80211_ops mac80211_config_ops = {  	.get_et_sset_count = ieee80211_get_et_sset_count,  	.get_et_stats = ieee80211_get_et_stats,  	.get_et_strings = ieee80211_get_et_strings, +	.get_channel = ieee80211_cfg_get_channel,  }; diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index c76cf7230c7..f0f87e5a1d3 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -41,6 +41,10 @@ __ieee80211_get_channel_mode(struct ieee80211_local *local,  			if (!sdata->u.ap.beacon)  				continue;  			break; +		case NL80211_IFTYPE_MESH_POINT: +			if (!sdata->wdev.mesh_id_len) +				continue; +			break;  		default:  			break;  		} diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h new file mode 100644 index 00000000000..8f383a57601 --- /dev/null +++ b/net/mac80211/debug.h @@ -0,0 +1,170 @@ +#ifndef __MAC80211_DEBUG_H +#define __MAC80211_DEBUG_H +#include <net/cfg80211.h> + +#ifdef CONFIG_MAC80211_IBSS_DEBUG +#define MAC80211_IBSS_DEBUG 1 +#else +#define MAC80211_IBSS_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_PS_DEBUG +#define MAC80211_PS_DEBUG 1 +#else +#define MAC80211_PS_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_HT_DEBUG +#define MAC80211_HT_DEBUG 1 +#else +#define MAC80211_HT_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MPL_DEBUG +#define MAC80211_MPL_DEBUG 1 +#else +#define MAC80211_MPL_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MPATH_DEBUG +#define MAC80211_MPATH_DEBUG 1 +#else +#define MAC80211_MPATH_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MHWMP_DEBUG +#define MAC80211_MHWMP_DEBUG 1 +#else +#define MAC80211_MHWMP_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MESH_SYNC_DEBUG +#define MAC80211_MESH_SYNC_DEBUG 1 +#else +#define MAC80211_MESH_SYNC_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_TDLS_DEBUG +#define MAC80211_TDLS_DEBUG 1 +#else +#define MAC80211_TDLS_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_STA_DEBUG +#define MAC80211_STA_DEBUG 1 +#else +#define MAC80211_STA_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MLME_DEBUG +#define MAC80211_MLME_DEBUG 1 +#else +#define MAC80211_MLME_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MESSAGE_TRACING +void __sdata_info(const char *fmt, ...) __printf(1, 2); +void __sdata_dbg(bool print, const char *fmt, ...) __printf(2, 3); +void __sdata_err(const char *fmt, ...) __printf(1, 2); +void __wiphy_dbg(struct wiphy *wiphy, bool print, const char *fmt, ...) +	__printf(3, 4); + +#define _sdata_info(sdata, fmt, ...)					\ +	__sdata_info("%s: " fmt, (sdata)->name, ##__VA_ARGS__) +#define _sdata_dbg(print, sdata, fmt, ...)				\ +	__sdata_dbg(print, "%s: " fmt, (sdata)->name, ##__VA_ARGS__) +#define _sdata_err(sdata, fmt, ...)					\ +	__sdata_err("%s: " fmt, (sdata)->name, ##__VA_ARGS__) +#define _wiphy_dbg(print, wiphy, fmt, ...)				\ +	__wiphy_dbg(wiphy, print, fmt, ##__VA_ARGS__) +#else +#define _sdata_info(sdata, fmt, ...)					\ +do {									\ +	pr_info("%s: " fmt,						\ +		(sdata)->name, ##__VA_ARGS__);				\ +} while (0) + +#define _sdata_dbg(print, sdata, fmt, ...)				\ +do {									\ +	if (print)							\ +		pr_debug("%s: " fmt,					\ +			 (sdata)->name, ##__VA_ARGS__);			\ +} while (0) + +#define _sdata_err(sdata, fmt, ...)					\ +do {									\ +	pr_err("%s: " fmt,						\ +	       (sdata)->name, ##__VA_ARGS__);				\ +} while (0) + +#define _wiphy_dbg(print, wiphy, fmt, ...)				\ +do {									\ +	if (print)							\ +		wiphy_dbg((wiphy), fmt, ##__VA_ARGS__);			\ +} while (0) +#endif + +#define sdata_info(sdata, fmt, ...)					\ +	_sdata_info(sdata, fmt, ##__VA_ARGS__) +#define sdata_err(sdata, fmt, ...)					\ +	_sdata_err(sdata, fmt, ##__VA_ARGS__) +#define sdata_dbg(sdata, fmt, ...)					\ +	_sdata_dbg(1, sdata, fmt, ##__VA_ARGS__) + +#define ht_dbg(sdata, fmt, ...)						\ +	_sdata_dbg(MAC80211_HT_DEBUG,					\ +		   sdata, fmt, ##__VA_ARGS__) + +#define ht_dbg_ratelimited(sdata, fmt, ...)				\ +	_sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(),		\ +		   sdata, fmt, ##__VA_ARGS__) + +#define ibss_dbg(sdata, fmt, ...)					\ +	_sdata_dbg(MAC80211_IBSS_DEBUG,					\ +		   sdata, fmt, ##__VA_ARGS__) + +#define ps_dbg(sdata, fmt, ...)						\ +	_sdata_dbg(MAC80211_PS_DEBUG,					\ +		   sdata, fmt, ##__VA_ARGS__) + +#define ps_dbg_hw(hw, fmt, ...)						\ +	_wiphy_dbg(MAC80211_PS_DEBUG,					\ +		   (hw)->wiphy, fmt, ##__VA_ARGS__) + +#define ps_dbg_ratelimited(sdata, fmt, ...)				\ +	_sdata_dbg(MAC80211_PS_DEBUG && net_ratelimit(),		\ +		   sdata, fmt, ##__VA_ARGS__) + +#define mpl_dbg(sdata, fmt, ...)					\ +	_sdata_dbg(MAC80211_MPL_DEBUG,					\ +		   sdata, fmt, ##__VA_ARGS__) + +#define mpath_dbg(sdata, fmt, ...)					\ +	_sdata_dbg(MAC80211_MPATH_DEBUG,				\ +		   sdata, fmt, ##__VA_ARGS__) + +#define mhwmp_dbg(sdata, fmt, ...)					\ +	_sdata_dbg(MAC80211_MHWMP_DEBUG,				\ +		   sdata, fmt, ##__VA_ARGS__) + +#define msync_dbg(sdata, fmt, ...)					\ +	_sdata_dbg(MAC80211_MESH_SYNC_DEBUG,				\ +		   sdata, fmt, ##__VA_ARGS__) + +#define tdls_dbg(sdata, fmt, ...)					\ +	_sdata_dbg(MAC80211_TDLS_DEBUG,					\ +		   sdata, fmt, ##__VA_ARGS__) + +#define sta_dbg(sdata, fmt, ...)					\ +	_sdata_dbg(MAC80211_STA_DEBUG,					\ +		   sdata, fmt, ##__VA_ARGS__) + +#define mlme_dbg(sdata, fmt, ...)					\ +	_sdata_dbg(MAC80211_MLME_DEBUG,					\ +		   sdata, fmt, ##__VA_ARGS__) + +#define mlme_dbg_ratelimited(sdata, fmt, ...)				\ +	_sdata_dbg(MAC80211_MLME_DEBUG && net_ratelimit(),		\ +		   sdata, fmt, ##__VA_ARGS__) + +#endif /* __MAC80211_DEBUG_H */ diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 778e5916d7c..b8dfb440c8e 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -325,8 +325,6 @@ void debugfs_hw_add(struct ieee80211_local *local)  		local->rx_handlers_drop_defrag);  	DEBUGFS_STATS_ADD(rx_handlers_drop_short,  		local->rx_handlers_drop_short); -	DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan, -		local->rx_handlers_drop_passive_scan);  	DEBUGFS_STATS_ADD(tx_expand_skb_head,  		local->tx_expand_skb_head);  	DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned, diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 7932767bb48..090d08ff22c 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -283,6 +283,11 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)  	lockdep_assert_held(&sdata->local->key_mtx); +	if (sdata->debugfs.default_unicast_key) { +		debugfs_remove(sdata->debugfs.default_unicast_key); +		sdata->debugfs.default_unicast_key = NULL; +	} +  	if (sdata->default_unicast_key) {  		key = key_mtx_dereference(sdata->local,  					  sdata->default_unicast_key); @@ -290,9 +295,11 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)  		sdata->debugfs.default_unicast_key =  			debugfs_create_symlink("default_unicast_key",  					       sdata->debugfs.dir, buf); -	} else { -		debugfs_remove(sdata->debugfs.default_unicast_key); -		sdata->debugfs.default_unicast_key = NULL; +	} + +	if (sdata->debugfs.default_multicast_key) { +		debugfs_remove(sdata->debugfs.default_multicast_key); +		sdata->debugfs.default_multicast_key = NULL;  	}  	if (sdata->default_multicast_key) { @@ -302,9 +309,6 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)  		sdata->debugfs.default_multicast_key =  			debugfs_create_symlink("default_multicast_key",  					       sdata->debugfs.dir, buf); -	} else { -		debugfs_remove(sdata->debugfs.default_multicast_key); -		sdata->debugfs.default_multicast_key = NULL;  	}  } diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 7ed433c66d6..6d5aec9418e 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -468,48 +468,54 @@ IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);  IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);  IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);  IEEE80211_IF_FILE(dropped_frames_congestion, -		u.mesh.mshstats.dropped_frames_congestion, DEC); +		  u.mesh.mshstats.dropped_frames_congestion, DEC);  IEEE80211_IF_FILE(dropped_frames_no_route, -		u.mesh.mshstats.dropped_frames_no_route, DEC); +		  u.mesh.mshstats.dropped_frames_no_route, DEC);  IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC);  /* Mesh parameters */  IEEE80211_IF_FILE(dot11MeshMaxRetries, -		u.mesh.mshcfg.dot11MeshMaxRetries, DEC); +		  u.mesh.mshcfg.dot11MeshMaxRetries, DEC);  IEEE80211_IF_FILE(dot11MeshRetryTimeout, -		u.mesh.mshcfg.dot11MeshRetryTimeout, DEC); +		  u.mesh.mshcfg.dot11MeshRetryTimeout, DEC);  IEEE80211_IF_FILE(dot11MeshConfirmTimeout, -		u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC); +		  u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC);  IEEE80211_IF_FILE(dot11MeshHoldingTimeout, -		u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC); +		  u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);  IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC);  IEEE80211_IF_FILE(element_ttl, u.mesh.mshcfg.element_ttl, DEC);  IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC);  IEEE80211_IF_FILE(dot11MeshMaxPeerLinks, -		u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC); +		  u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);  IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout, -		u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC); +		  u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);  IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval, -		u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC); +		  u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);  IEEE80211_IF_FILE(dot11MeshHWMPperrMinInterval, -		u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC); +		  u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC);  IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime, -		u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC); +		  u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);  IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries, -		u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC); +		  u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC);  IEEE80211_IF_FILE(path_refresh_time, -		u.mesh.mshcfg.path_refresh_time, DEC); +		  u.mesh.mshcfg.path_refresh_time, DEC);  IEEE80211_IF_FILE(min_discovery_timeout, -		u.mesh.mshcfg.min_discovery_timeout, DEC); +		  u.mesh.mshcfg.min_discovery_timeout, DEC);  IEEE80211_IF_FILE(dot11MeshHWMPRootMode, -		u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC); +		  u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);  IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol, -		u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC); +		  u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC);  IEEE80211_IF_FILE(dot11MeshHWMPRannInterval, -		u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC); +		  u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);  IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC);  IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC);  IEEE80211_IF_FILE(ht_opmode, u.mesh.mshcfg.ht_opmode, DEC); +IEEE80211_IF_FILE(dot11MeshHWMPactivePathToRootTimeout, +		  u.mesh.mshcfg.dot11MeshHWMPactivePathToRootTimeout, DEC); +IEEE80211_IF_FILE(dot11MeshHWMProotInterval, +		  u.mesh.mshcfg.dot11MeshHWMProotInterval, DEC); +IEEE80211_IF_FILE(dot11MeshHWMPconfirmationInterval, +		  u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval, DEC);  #endif  #define DEBUGFS_ADD_MODE(name, mode) \ @@ -607,9 +613,13 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)  	MESHPARAMS_ADD(min_discovery_timeout);  	MESHPARAMS_ADD(dot11MeshHWMPRootMode);  	MESHPARAMS_ADD(dot11MeshHWMPRannInterval); +	MESHPARAMS_ADD(dot11MeshForwarding);  	MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);  	MESHPARAMS_ADD(rssi_threshold);  	MESHPARAMS_ADD(ht_opmode); +	MESHPARAMS_ADD(dot11MeshHWMPactivePathToRootTimeout); +	MESHPARAMS_ADD(dot11MeshHWMProotInterval); +	MESHPARAMS_ADD(dot11MeshHWMPconfirmationInterval);  #undef MESHPARAMS_ADD  }  #endif @@ -685,6 +695,7 @@ void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)  	sprintf(buf, "netdev:%s", sdata->name);  	if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) -		printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " -		       "dir to %s\n", buf); +		sdata_err(sdata, +			  "debugfs: failed to rename debugfs dir to %s\n", +			  buf);  } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 6d33a0c743a..df920319910 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -3,7 +3,7 @@  #include <net/mac80211.h>  #include "ieee80211_i.h" -#include "driver-trace.h" +#include "trace.h"  static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata)  { @@ -27,14 +27,6 @@ static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb)  	local->ops->tx(&local->hw, skb);  } -static inline void drv_tx_frags(struct ieee80211_local *local, -				struct ieee80211_vif *vif, -				struct ieee80211_sta *sta, -				struct sk_buff_head *skbs) -{ -	local->ops->tx_frags(&local->hw, vif, sta, skbs); -} -  static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata,  				      u32 sset, u8 *data)  { @@ -845,4 +837,33 @@ drv_allow_buffered_frames(struct ieee80211_local *local,  						  more_data);  	trace_drv_return_void(local);  } + +static inline int drv_get_rssi(struct ieee80211_local *local, +				struct ieee80211_sub_if_data *sdata, +				struct ieee80211_sta *sta, +				s8 *rssi_dbm) +{ +	int ret; + +	might_sleep(); + +	ret = local->ops->get_rssi(&local->hw, &sdata->vif, sta, rssi_dbm); +	trace_drv_get_rssi(local, sta, *rssi_dbm, ret); + +	return ret; +} + +static inline void drv_mgd_prepare_tx(struct ieee80211_local *local, +				      struct ieee80211_sub_if_data *sdata) +{ +	might_sleep(); + +	check_sdata_in_driver(sdata); +	WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION); + +	trace_drv_mgd_prepare_tx(local, sdata); +	if (local->ops->mgd_prepare_tx) +		local->ops->mgd_prepare_tx(&local->hw, &sdata->vif); +	trace_drv_return_void(local); +}  #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/driver-trace.c b/net/mac80211/driver-trace.c deleted file mode 100644 index 8ed8711b1a6..00000000000 --- a/net/mac80211/driver-trace.c +++ /dev/null @@ -1,9 +0,0 @@ -/* bug in tracepoint.h, it should include this */ -#include <linux/module.h> - -/* sparse isn't too happy with all macros... */ -#ifndef __CHECKER__ -#include "driver-ops.h" -#define CREATE_TRACE_POINTS -#include "driver-trace.h" -#endif diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 6f8615c54b2..4b4538d6392 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -305,12 +305,10 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,  	tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;  	initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11; -#ifdef CONFIG_MAC80211_HT_DEBUG -	net_dbg_ratelimited("delba from %pM (%s) tid %d reason code %d\n", -			    mgmt->sa, initiator ? "initiator" : "recipient", -			    tid, -			    le16_to_cpu(mgmt->u.action.u.delba.reason_code)); -#endif /* CONFIG_MAC80211_HT_DEBUG */ +	ht_dbg_ratelimited(sdata, "delba from %pM (%s) tid %d reason code %d\n", +			   mgmt->sa, initiator ? "initiator" : "recipient", +			   tid, +			   le16_to_cpu(mgmt->u.action.u.delba.reason_code));  	if (initiator == WLAN_BACK_INITIATOR)  		__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0, diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 33d9d0c3e3d..5746d62faba 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -82,8 +82,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,  	local->oper_channel = chan;  	channel_type = ifibss->channel_type; -	if (channel_type > NL80211_CHAN_HT20 && -	    !cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type)) +	if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))  		channel_type = NL80211_CHAN_HT20;  	if (!ieee80211_set_channel_type(local, sdata, channel_type)) {  		/* can only fail due to HT40+/- mismatch */ @@ -262,11 +261,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,  	memcpy(addr, sta->sta.addr, ETH_ALEN); -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -	wiphy_debug(sdata->local->hw.wiphy, -		    "Adding new IBSS station %pM (dev=%s)\n", -		    addr, sdata->name); -#endif +	ibss_dbg(sdata, "Adding new IBSS station %pM\n", addr);  	sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);  	sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); @@ -280,12 +275,10 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,  	/* If it fails, maybe we raced another insertion? */  	if (sta_info_insert_rcu(sta))  		return sta_info_get(sdata, addr); -	if (auth) { -#ifdef CONFIG_MAC80211_IBSS_DEBUG -		printk(KERN_DEBUG "TX Auth SA=%pM DA=%pM BSSID=%pM" -		       "(auth_transaction=1)\n", sdata->vif.addr, -		       sdata->u.ibss.bssid, addr); -#endif +	if (auth && !sdata->u.ibss.auth_frame_registrations) { +		ibss_dbg(sdata, +			 "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", +			 sdata->vif.addr, sdata->u.ibss.bssid, addr);  		ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0,  				    addr, sdata->u.ibss.bssid, NULL, 0, 0);  	} @@ -308,7 +301,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,  	 * 	allow new one to be added.  	 */  	if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { -		net_dbg_ratelimited("%s: No room for a new IBSS STA entry %pM\n", +		net_info_ratelimited("%s: No room for a new IBSS STA entry %pM\n",  				    sdata->name, addr);  		rcu_read_lock();  		return NULL; @@ -355,11 +348,9 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,  	if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)  		return; -#ifdef CONFIG_MAC80211_IBSS_DEBUG -	printk(KERN_DEBUG "%s: RX Auth SA=%pM DA=%pM BSSID=%pM." -	       "(auth_transaction=%d)\n", -	       sdata->name, mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); -#endif +	ibss_dbg(sdata, +		 "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", +		 mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction);  	sta_info_destroy_addr(sdata, mgmt->sa);  	ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false);  	rcu_read_unlock(); @@ -422,15 +413,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,  					ieee80211_mandatory_rates(local, band);  				if (sta->sta.supp_rates[band] != prev_rates) { -#ifdef CONFIG_MAC80211_IBSS_DEBUG -					printk(KERN_DEBUG -						"%s: updated supp_rates set " -						"for %pM based on beacon" -						"/probe_resp (0x%x -> 0x%x)\n", -						sdata->name, sta->sta.addr, -						prev_rates, -						sta->sta.supp_rates[band]); -#endif +					ibss_dbg(sdata, +						 "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n", +						 sta->sta.addr, prev_rates, +						 sta->sta.supp_rates[band]);  					rates_updated = true;  				}  			} else { @@ -545,22 +531,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,  		rx_timestamp = drv_get_tsf(local, sdata);  	} -#ifdef CONFIG_MAC80211_IBSS_DEBUG -	printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" -	       "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", -	       mgmt->sa, mgmt->bssid, -	       (unsigned long long)rx_timestamp, -	       (unsigned long long)beacon_timestamp, -	       (unsigned long long)(rx_timestamp - beacon_timestamp), -	       jiffies); -#endif +	ibss_dbg(sdata, +		 "RX beacon SA=%pM BSSID=%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", +		 mgmt->sa, mgmt->bssid, +		 (unsigned long long)rx_timestamp, +		 (unsigned long long)beacon_timestamp, +		 (unsigned long long)(rx_timestamp - beacon_timestamp), +		 jiffies);  	if (beacon_timestamp > rx_timestamp) { -#ifdef CONFIG_MAC80211_IBSS_DEBUG -		printk(KERN_DEBUG "%s: beacon TSF higher than " -		       "local TSF - IBSS merge with BSSID %pM\n", -		       sdata->name, mgmt->bssid); -#endif +		ibss_dbg(sdata, +			 "beacon TSF higher than local TSF - IBSS merge with BSSID %pM\n", +			 mgmt->bssid);  		ieee80211_sta_join_ibss(sdata, bss);  		supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL);  		ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, @@ -586,7 +568,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,  	 * 	allow new one to be added.  	 */  	if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { -		net_dbg_ratelimited("%s: No room for a new IBSS STA entry %pM\n", +		net_info_ratelimited("%s: No room for a new IBSS STA entry %pM\n",  				    sdata->name, addr);  		return;  	} @@ -662,8 +644,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)  	if (ifibss->fixed_channel)  		return; -	printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " -	       "IBSS networks with same SSID (merge)\n", sdata->name); +	sdata_info(sdata, +		   "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n");  	ieee80211_request_internal_scan(sdata,  			ifibss->ssid, ifibss->ssid_len, NULL); @@ -691,8 +673,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)  		bssid[0] |= 0x02;  	} -	printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", -	       sdata->name, bssid); +	sdata_info(sdata, "Creating new IBSS network, BSSID %pM\n", bssid);  	capability = WLAN_CAPABILITY_IBSS; @@ -723,10 +704,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)  	lockdep_assert_held(&ifibss->mtx);  	active_ibss = ieee80211_sta_active_ibss(sdata); -#ifdef CONFIG_MAC80211_IBSS_DEBUG -	printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", -	       sdata->name, active_ibss); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ +	ibss_dbg(sdata, "sta_find_ibss (active_ibss=%d)\n", active_ibss);  	if (active_ibss)  		return; @@ -749,29 +727,24 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)  		struct ieee80211_bss *bss;  		bss = (void *)cbss->priv; -#ifdef CONFIG_MAC80211_IBSS_DEBUG -		printk(KERN_DEBUG "   sta_find_ibss: selected %pM current " -		       "%pM\n", cbss->bssid, ifibss->bssid); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ - -		printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" -		       " based on configured SSID\n", -		       sdata->name, cbss->bssid); +		ibss_dbg(sdata, +			 "sta_find_ibss: selected %pM current %pM\n", +			 cbss->bssid, ifibss->bssid); +		sdata_info(sdata, +			   "Selected IBSS BSSID %pM based on configured SSID\n", +			   cbss->bssid);  		ieee80211_sta_join_ibss(sdata, bss);  		ieee80211_rx_bss_put(local, bss);  		return;  	} -#ifdef CONFIG_MAC80211_IBSS_DEBUG -	printk(KERN_DEBUG "   did not try to join ibss\n"); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ +	ibss_dbg(sdata, "sta_find_ibss: did not try to join ibss\n");  	/* Selected IBSS not found in current scan results - try to scan */  	if (time_after(jiffies, ifibss->last_scan_completed +  					IEEE80211_SCAN_INTERVAL)) { -		printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " -		       "join\n", sdata->name); +		sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");  		ieee80211_request_internal_scan(sdata,  				ifibss->ssid, ifibss->ssid_len, @@ -785,9 +758,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)  				ieee80211_sta_create_ibss(sdata);  				return;  			} -			printk(KERN_DEBUG "%s: IBSS not allowed on" -			       " %d MHz\n", sdata->name, -			       local->hw.conf.channel->center_freq); +			sdata_info(sdata, "IBSS not allowed on %d MHz\n", +				   local->hw.conf.channel->center_freq);  			/* No IBSS found - decrease scan interval and continue  			 * scanning. */ @@ -822,12 +794,9 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,  	tx_last_beacon = drv_tx_last_beacon(local); -#ifdef CONFIG_MAC80211_IBSS_DEBUG -	printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" -	       " (tx_last_beacon=%d)\n", -	       sdata->name, mgmt->sa, mgmt->da, -	       mgmt->bssid, tx_last_beacon); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ +	ibss_dbg(sdata, +		 "RX ProbeReq SA=%pM DA=%pM BSSID=%pM (tx_last_beacon=%d)\n", +		 mgmt->sa, mgmt->da, mgmt->bssid, tx_last_beacon);  	if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da))  		return; @@ -840,11 +809,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,  	pos = mgmt->u.probe_req.variable;  	if (pos[0] != WLAN_EID_SSID ||  	    pos + 2 + pos[1] > end) { -#ifdef CONFIG_MAC80211_IBSS_DEBUG -		printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " -		       "from %pM\n", -		       sdata->name, mgmt->sa); -#endif +		ibss_dbg(sdata, "Invalid SSID IE in ProbeReq from %pM\n", +			 mgmt->sa);  		return;  	}  	if (pos[1] != 0 && @@ -861,10 +827,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,  	resp = (struct ieee80211_mgmt *) skb->data;  	memcpy(resp->da, mgmt->sa, ETH_ALEN); -#ifdef CONFIG_MAC80211_IBSS_DEBUG -	printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n", -	       sdata->name, resp->da); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ +	ibss_dbg(sdata, "Sending ProbeResp to %pM\n", resp->da);  	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;  	ieee80211_tx_skb(sdata, skb);  } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3f3cd50fff1..bb61f7718c4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -30,6 +30,7 @@  #include <net/mac80211.h>  #include "key.h"  #include "sta_info.h" +#include "debug.h"  struct ieee80211_local; @@ -55,11 +56,14 @@ struct ieee80211_local;  #define TU_TO_JIFFIES(x)	(usecs_to_jiffies((x) * 1024))  #define TU_TO_EXP_TIME(x)	(jiffies + TU_TO_JIFFIES(x)) +/* + * Some APs experience problems when working with U-APSD. Decrease the + * probability of that happening by using legacy mode for all ACs but VO. + * The AP that caused us trouble was a Cisco 4410N. It ignores our + * setting, and always treats non-VO ACs as legacy. + */  #define IEEE80211_DEFAULT_UAPSD_QUEUES \ -	(IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |	\ -	 IEEE80211_WMM_IE_STA_QOSINFO_AC_BE |	\ -	 IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |	\ -	 IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) +	IEEE80211_WMM_IE_STA_QOSINFO_AC_VO  #define IEEE80211_DEFAULT_MAX_SP_LEN		\  	IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL @@ -81,6 +85,8 @@ struct ieee80211_bss {  	size_t ssid_len;  	u8 ssid[IEEE80211_MAX_SSID_LEN]; +	u32 device_ts; +  	u8 dtim_period;  	bool wmm_used; @@ -203,7 +209,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result;   * enum ieee80211_packet_rx_flags - packet RX flags   * @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed   *	(incl. multicast frames) - * @IEEE80211_RX_IN_SCAN: received while scanning   * @IEEE80211_RX_FRAGMENTED: fragmented frame   * @IEEE80211_RX_AMSDU: a-MSDU packet   * @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed @@ -213,7 +218,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result;   * @rx_flags field of &struct ieee80211_rx_status.   */  enum ieee80211_packet_rx_flags { -	IEEE80211_RX_IN_SCAN			= BIT(0),  	IEEE80211_RX_RA_MATCH			= BIT(1),  	IEEE80211_RX_FRAGMENTED			= BIT(2),  	IEEE80211_RX_AMSDU			= BIT(3), @@ -317,55 +321,30 @@ struct mesh_preq_queue {  	u8 flags;  }; -enum ieee80211_work_type { -	IEEE80211_WORK_ABORT, -	IEEE80211_WORK_REMAIN_ON_CHANNEL, -	IEEE80211_WORK_OFFCHANNEL_TX, -}; - -/** - * enum work_done_result - indicates what to do after work was done - * - * @WORK_DONE_DESTROY: This work item is no longer needed, destroy. - * @WORK_DONE_REQUEUE: This work item was reset to be reused, and - *	should be requeued. - */ -enum work_done_result { -	WORK_DONE_DESTROY, -	WORK_DONE_REQUEUE, -}; +#if HZ/100 == 0 +#define IEEE80211_ROC_MIN_LEFT	1 +#else +#define IEEE80211_ROC_MIN_LEFT	(HZ/100) +#endif -struct ieee80211_work { +struct ieee80211_roc_work {  	struct list_head list; +	struct list_head dependents; -	struct rcu_head rcu_head; +	struct delayed_work work;  	struct ieee80211_sub_if_data *sdata; -	enum work_done_result (*done)(struct ieee80211_work *wk, -				      struct sk_buff *skb); -  	struct ieee80211_channel *chan;  	enum nl80211_channel_type chan_type; -	unsigned long timeout; -	enum ieee80211_work_type type; - -	bool started; +	bool started, abort, hw_begun, notified; -	union { -		struct { -			u32 duration; -		} remain; -		struct { -			struct sk_buff *frame; -			u32 wait; -			bool status; -		} offchan_tx; -	}; +	unsigned long hw_start_time; -	size_t data_len; -	u8 data[]; +	u32 duration, req_duration; +	struct sk_buff *frame; +	u64 mgmt_tx_cookie;  };  /* flags used in struct ieee80211_if_managed.flags */ @@ -399,7 +378,6 @@ struct ieee80211_mgd_auth_data {  struct ieee80211_mgd_assoc_data {  	struct cfg80211_bss *bss;  	const u8 *supp_rates; -	const u8 *ht_operation_ie;  	unsigned long timeout;  	int tries; @@ -414,6 +392,8 @@ struct ieee80211_mgd_assoc_data {  	bool sent_assoc;  	bool synced; +	u8 ap_ht_param; +  	size_t ie_len;  	u8 ie[];  }; @@ -532,6 +512,7 @@ struct ieee80211_if_ibss {  	bool privacy;  	bool control_port; +	unsigned int auth_frame_registrations;  	u8 bssid[ETH_ALEN] __aligned(2);  	u8 ssid[IEEE80211_MAX_SSID_LEN]; @@ -701,6 +682,9 @@ struct ieee80211_sub_if_data {  	/* TID bitmap for NoAck policy */  	u16 noack_map; +	/* bit field of ACM bits (BIT(802.1D tag)) */ +	u8 wmm_acm; +  	struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];  	struct ieee80211_key __rcu *default_unicast_key;  	struct ieee80211_key __rcu *default_multicast_key; @@ -847,13 +831,6 @@ struct ieee80211_local {  	const struct ieee80211_ops *ops;  	/* -	 * work stuff, potentially off-channel (in the future) -	 */ -	struct list_head work_list; -	struct timer_list work_timer; -	struct work_struct work_work; - -	/*  	 * private workqueue to mac80211. mac80211 makes this accessible  	 * via ieee80211_queue_work()  	 */ @@ -912,6 +889,9 @@ struct ieee80211_local {  	/* device is started */  	bool started; +	/* device is during a HW reconfig */ +	bool in_reconfig; +  	/* wowlan is enabled -- don't reconfig on resume */  	bool wowlan; @@ -985,14 +965,14 @@ struct ieee80211_local {  	int scan_channel_idx;  	int scan_ies_len; -	bool sched_scanning;  	struct ieee80211_sched_scan_ies sched_scan_ies;  	struct work_struct sched_scan_stopped_work; +	struct ieee80211_sub_if_data __rcu *sched_scan_sdata;  	unsigned long leave_oper_channel_time;  	enum mac80211_scan_state next_scan_state;  	struct delayed_work scan_work; -	struct ieee80211_sub_if_data *scan_sdata; +	struct ieee80211_sub_if_data __rcu *scan_sdata;  	enum nl80211_channel_type _oper_channel_type;  	struct ieee80211_channel *oper_channel, *csa_channel; @@ -1034,7 +1014,6 @@ struct ieee80211_local {  	unsigned int rx_handlers_drop_nullfunc;  	unsigned int rx_handlers_drop_defrag;  	unsigned int rx_handlers_drop_short; -	unsigned int rx_handlers_drop_passive_scan;  	unsigned int tx_expand_skb_head;  	unsigned int tx_expand_skb_head_cloned;  	unsigned int rx_expand_skb_head; @@ -1050,7 +1029,6 @@ struct ieee80211_local {  	int total_ps_buffered; /* total number of all buffered unicast and  				* multicast packets for power saving stations  				*/ -	unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */  	bool pspolling;  	bool offchannel_ps_enabled; @@ -1087,14 +1065,12 @@ struct ieee80211_local {  	} debugfs;  #endif -	struct ieee80211_channel *hw_roc_channel; -	struct net_device *hw_roc_dev; -	struct sk_buff *hw_roc_skb, *hw_roc_skb_for_status; +	/* +	 * Remain-on-channel support +	 */ +	struct list_head roc_list;  	struct work_struct hw_roc_start, hw_roc_done; -	enum nl80211_channel_type hw_roc_channel_type; -	unsigned int hw_roc_duration; -	u32 hw_roc_cookie; -	bool hw_roc_for_tx; +	unsigned long hw_roc_start_time;  	struct idr ack_status_frames;  	spinlock_t ack_status_lock; @@ -1114,6 +1090,12 @@ IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)  	return netdev_priv(dev);  } +static inline struct ieee80211_sub_if_data * +IEEE80211_WDEV_TO_SUB_IF(struct wireless_dev *wdev) +{ +	return container_of(wdev, struct ieee80211_sub_if_data, wdev); +} +  /* this struct represents 802.11n's RA/TID combination */  struct ieee80211_ra_tid {  	u8 ra[ETH_ALEN]; @@ -1264,8 +1246,7 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,  			   struct cfg80211_scan_request *req);  void ieee80211_scan_cancel(struct ieee80211_local *local);  void ieee80211_run_deferred_scan(struct ieee80211_local *local); -ieee80211_rx_result -ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); +void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb);  void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);  struct ieee80211_bss * @@ -1290,19 +1271,23 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,  				    bool offchannel_ps_enable);  void ieee80211_offchannel_return(struct ieee80211_local *local,  				 bool offchannel_ps_disable); -void ieee80211_hw_roc_setup(struct ieee80211_local *local); +void ieee80211_roc_setup(struct ieee80211_local *local); +void ieee80211_start_next_roc(struct ieee80211_local *local); +void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata); +void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc); +void ieee80211_sw_roc_work(struct work_struct *work); +void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);  /* interface handling */  int ieee80211_iface_init(void);  void ieee80211_iface_exit(void);  int ieee80211_if_add(struct ieee80211_local *local, const char *name, -		     struct net_device **new_dev, enum nl80211_iftype type, +		     struct wireless_dev **new_wdev, enum nl80211_iftype type,  		     struct vif_params *params);  int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,  			     enum nl80211_iftype type);  void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);  void ieee80211_remove_interfaces(struct ieee80211_local *local); -u32 __ieee80211_recalc_idle(struct ieee80211_local *local);  void ieee80211_recalc_idle(struct ieee80211_local *local);  void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,  				    const int offset); @@ -1499,18 +1484,12 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,  			       struct ieee80211_channel *channel,  			       enum nl80211_channel_type channel_type,  			       u16 prot_mode); - -/* internal work items */ -void ieee80211_work_init(struct ieee80211_local *local); -void ieee80211_add_work(struct ieee80211_work *wk); -void free_work(struct ieee80211_work *wk); -void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata); -int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, -				   struct ieee80211_channel *chan, -				   enum nl80211_channel_type channel_type, -				   unsigned int duration, u64 *cookie); -int ieee80211_wk_cancel_remain_on_channel( -	struct ieee80211_sub_if_data *sdata, u64 cookie); +u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, +			       u32 cap); +int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, +			    struct sk_buff *skb, bool need_basic); +int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, +				struct sk_buff *skb, bool need_basic);  /* channel management */  enum ieee80211_chan_mode { diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d4c19a7773d..bfb57dcc153 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -43,6 +43,128 @@   */ +static u32 ieee80211_idle_off(struct ieee80211_local *local, +			      const char *reason) +{ +	if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) +		return 0; + +	local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; +	return IEEE80211_CONF_CHANGE_IDLE; +} + +static u32 ieee80211_idle_on(struct ieee80211_local *local) +{ +	if (local->hw.conf.flags & IEEE80211_CONF_IDLE) +		return 0; + +	drv_flush(local, false); + +	local->hw.conf.flags |= IEEE80211_CONF_IDLE; +	return IEEE80211_CONF_CHANGE_IDLE; +} + +static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) +{ +	struct ieee80211_sub_if_data *sdata; +	int count = 0; +	bool working = false, scanning = false; +	unsigned int led_trig_start = 0, led_trig_stop = 0; +	struct ieee80211_roc_work *roc; + +#ifdef CONFIG_PROVE_LOCKING +	WARN_ON(debug_locks && !lockdep_rtnl_is_held() && +		!lockdep_is_held(&local->iflist_mtx)); +#endif +	lockdep_assert_held(&local->mtx); + +	list_for_each_entry(sdata, &local->interfaces, list) { +		if (!ieee80211_sdata_running(sdata)) { +			sdata->vif.bss_conf.idle = true; +			continue; +		} + +		sdata->old_idle = sdata->vif.bss_conf.idle; + +		/* do not count disabled managed interfaces */ +		if (sdata->vif.type == NL80211_IFTYPE_STATION && +		    !sdata->u.mgd.associated && +		    !sdata->u.mgd.auth_data && +		    !sdata->u.mgd.assoc_data) { +			sdata->vif.bss_conf.idle = true; +			continue; +		} +		/* do not count unused IBSS interfaces */ +		if (sdata->vif.type == NL80211_IFTYPE_ADHOC && +		    !sdata->u.ibss.ssid_len) { +			sdata->vif.bss_conf.idle = true; +			continue; +		} +		/* count everything else */ +		sdata->vif.bss_conf.idle = false; +		count++; +	} + +	if (!local->ops->remain_on_channel) { +		list_for_each_entry(roc, &local->roc_list, list) { +			working = true; +			roc->sdata->vif.bss_conf.idle = false; +		} +	} + +	sdata = rcu_dereference_protected(local->scan_sdata, +					  lockdep_is_held(&local->mtx)); +	if (sdata && !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { +		scanning = true; +		sdata->vif.bss_conf.idle = false; +	} + +	list_for_each_entry(sdata, &local->interfaces, list) { +		if (sdata->vif.type == NL80211_IFTYPE_MONITOR || +		    sdata->vif.type == NL80211_IFTYPE_AP_VLAN) +			continue; +		if (sdata->old_idle == sdata->vif.bss_conf.idle) +			continue; +		if (!ieee80211_sdata_running(sdata)) +			continue; +		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); +	} + +	if (working || scanning) +		led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; +	else +		led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; + +	if (count) +		led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; +	else +		led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; + +	ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); + +	if (working) +		return ieee80211_idle_off(local, "working"); +	if (scanning) +		return ieee80211_idle_off(local, "scanning"); +	if (!count) +		return ieee80211_idle_on(local); +	else +		return ieee80211_idle_off(local, "in use"); + +	return 0; +} + +void ieee80211_recalc_idle(struct ieee80211_local *local) +{ +	u32 chg; + +	mutex_lock(&local->iflist_mtx); +	chg = __ieee80211_recalc_idle(local); +	mutex_unlock(&local->iflist_mtx); +	if (chg) +		ieee80211_hw_config(local, chg); +} +  static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)  {  	int meshhdrlen; @@ -57,9 +179,6 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)  		return -EINVAL;  	} -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -	printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */  	dev->mtu = new_mtu;  	return 0;  } @@ -100,15 +219,12 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,  {  	struct ieee80211_local *local = sdata->local;  	struct ieee80211_sub_if_data *nsdata; -	struct net_device *dev = sdata->dev;  	ASSERT_RTNL();  	/* we hold the RTNL here so can safely walk the list */  	list_for_each_entry(nsdata, &local->interfaces, list) { -		struct net_device *ndev = nsdata->dev; - -		if (ndev != dev && ieee80211_sdata_running(nsdata)) { +		if (nsdata != sdata && ieee80211_sdata_running(nsdata)) {  			/*  			 * Allow only a single IBSS interface to be up at any  			 * time. This is restricted because beacon distribution @@ -127,7 +243,8 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,  			 * The remaining checks are only performed for interfaces  			 * with the same MAC address.  			 */ -			if (!ether_addr_equal(dev->dev_addr, ndev->dev_addr)) +			if (!ether_addr_equal(sdata->vif.addr, +					      nsdata->vif.addr))  				continue;  			/* @@ -217,17 +334,21 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)  static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)  {  	struct ieee80211_sub_if_data *sdata; -	int ret; +	int ret = 0;  	if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))  		return 0; +	mutex_lock(&local->iflist_mtx); +  	if (local->monitor_sdata) -		return 0; +		goto out_unlock;  	sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); -	if (!sdata) -		return -ENOMEM; +	if (!sdata) { +		ret = -ENOMEM; +		goto out_unlock; +	}  	/* set up data */  	sdata->local = local; @@ -241,18 +362,19 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)  	if (WARN_ON(ret)) {  		/* ok .. stupid driver, it asked for this! */  		kfree(sdata); -		return ret; +		goto out_unlock;  	}  	ret = ieee80211_check_queues(sdata);  	if (ret) {  		kfree(sdata); -		return ret; +		goto out_unlock;  	}  	rcu_assign_pointer(local->monitor_sdata, sdata); - -	return 0; + out_unlock: +	mutex_unlock(&local->iflist_mtx); +	return ret;  }  static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) @@ -262,10 +384,12 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)  	if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))  		return; -	sdata = rtnl_dereference(local->monitor_sdata); +	mutex_lock(&local->iflist_mtx); +	sdata = rcu_dereference_protected(local->monitor_sdata, +					  lockdep_is_held(&local->iflist_mtx));  	if (!sdata) -		return; +		goto out_unlock;  	rcu_assign_pointer(local->monitor_sdata, NULL);  	synchronize_net(); @@ -273,6 +397,8 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)  	drv_remove_interface(local, sdata);  	kfree(sdata); + out_unlock: +	mutex_unlock(&local->iflist_mtx);  }  /* @@ -520,7 +646,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,  	clear_bit(SDATA_STATE_RUNNING, &sdata->state); -	if (local->scan_sdata == sdata) +	if (rcu_access_pointer(local->scan_sdata) == sdata)  		ieee80211_scan_cancel(local);  	/* @@ -528,10 +654,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,  	 */  	netif_tx_stop_all_queues(sdata->dev); -	/* -	 * Purge work for this interface. -	 */ -	ieee80211_work_purge(sdata); +	ieee80211_roc_purge(sdata);  	/*  	 * Remove all stations associated with this interface. @@ -811,7 +934,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev,  	hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len)); -	return ieee80211_select_queue_80211(local, skb, hdr); +	return ieee80211_select_queue_80211(sdata, skb, hdr);  }  static const struct net_device_ops ieee80211_monitorif_ops = { @@ -1226,7 +1349,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,  		if (__ffs64(mask) + hweight64(mask) != fls64(mask)) {  			/* not a contiguous mask ... not handled now! */ -			printk(KERN_DEBUG "not contiguous\n"); +			pr_info("not contiguous\n");  			break;  		} @@ -1272,7 +1395,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,  }  int ieee80211_if_add(struct ieee80211_local *local, const char *name, -		     struct net_device **new_dev, enum nl80211_iftype type, +		     struct wireless_dev **new_wdev, enum nl80211_iftype type,  		     struct vif_params *params)  {  	struct net_device *ndev; @@ -1352,6 +1475,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,  			sdata->u.mgd.use_4addr = params->use_4addr;  	} +	ndev->features |= local->hw.netdev_features; +  	ret = register_netdevice(ndev);  	if (ret)  		goto fail; @@ -1360,8 +1485,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,  	list_add_tail_rcu(&sdata->list, &local->interfaces);  	mutex_unlock(&local->iflist_mtx); -	if (new_dev) -		*new_dev = ndev; +	if (new_wdev) +		*new_wdev = &sdata->wdev;  	return 0; @@ -1409,138 +1534,6 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)  	list_del(&unreg_list);  } -static u32 ieee80211_idle_off(struct ieee80211_local *local, -			      const char *reason) -{ -	if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) -		return 0; - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -	wiphy_debug(local->hw.wiphy, "device no longer idle - %s\n", reason); -#endif - -	local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; -	return IEEE80211_CONF_CHANGE_IDLE; -} - -static u32 ieee80211_idle_on(struct ieee80211_local *local) -{ -	if (local->hw.conf.flags & IEEE80211_CONF_IDLE) -		return 0; - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -	wiphy_debug(local->hw.wiphy, "device now idle\n"); -#endif - -	drv_flush(local, false); - -	local->hw.conf.flags |= IEEE80211_CONF_IDLE; -	return IEEE80211_CONF_CHANGE_IDLE; -} - -u32 __ieee80211_recalc_idle(struct ieee80211_local *local) -{ -	struct ieee80211_sub_if_data *sdata; -	int count = 0; -	bool working = false, scanning = false, hw_roc = false; -	struct ieee80211_work *wk; -	unsigned int led_trig_start = 0, led_trig_stop = 0; - -#ifdef CONFIG_PROVE_LOCKING -	WARN_ON(debug_locks && !lockdep_rtnl_is_held() && -		!lockdep_is_held(&local->iflist_mtx)); -#endif -	lockdep_assert_held(&local->mtx); - -	list_for_each_entry(sdata, &local->interfaces, list) { -		if (!ieee80211_sdata_running(sdata)) { -			sdata->vif.bss_conf.idle = true; -			continue; -		} - -		sdata->old_idle = sdata->vif.bss_conf.idle; - -		/* do not count disabled managed interfaces */ -		if (sdata->vif.type == NL80211_IFTYPE_STATION && -		    !sdata->u.mgd.associated && -		    !sdata->u.mgd.auth_data && -		    !sdata->u.mgd.assoc_data) { -			sdata->vif.bss_conf.idle = true; -			continue; -		} -		/* do not count unused IBSS interfaces */ -		if (sdata->vif.type == NL80211_IFTYPE_ADHOC && -		    !sdata->u.ibss.ssid_len) { -			sdata->vif.bss_conf.idle = true; -			continue; -		} -		/* count everything else */ -		sdata->vif.bss_conf.idle = false; -		count++; -	} - -	list_for_each_entry(wk, &local->work_list, list) { -		working = true; -		wk->sdata->vif.bss_conf.idle = false; -	} - -	if (local->scan_sdata && -	    !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { -		scanning = true; -		local->scan_sdata->vif.bss_conf.idle = false; -	} - -	if (local->hw_roc_channel) -		hw_roc = true; - -	list_for_each_entry(sdata, &local->interfaces, list) { -		if (sdata->vif.type == NL80211_IFTYPE_MONITOR || -		    sdata->vif.type == NL80211_IFTYPE_AP_VLAN) -			continue; -		if (sdata->old_idle == sdata->vif.bss_conf.idle) -			continue; -		if (!ieee80211_sdata_running(sdata)) -			continue; -		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); -	} - -	if (working || scanning || hw_roc) -		led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; -	else -		led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; - -	if (count) -		led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; -	else -		led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; - -	ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); - -	if (hw_roc) -		return ieee80211_idle_off(local, "hw remain-on-channel"); -	if (working) -		return ieee80211_idle_off(local, "working"); -	if (scanning) -		return ieee80211_idle_off(local, "scanning"); -	if (!count) -		return ieee80211_idle_on(local); -	else -		return ieee80211_idle_off(local, "in use"); - -	return 0; -} - -void ieee80211_recalc_idle(struct ieee80211_local *local) -{ -	u32 chg; - -	mutex_lock(&local->iflist_mtx); -	chg = __ieee80211_recalc_idle(local); -	mutex_unlock(&local->iflist_mtx); -	if (chg) -		ieee80211_hw_config(local, chg); -} -  static int netdev_notify(struct notifier_block *nb,  			 unsigned long state,  			 void *ndev) diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 5bb600d93d7..7ae678ba5d6 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -139,7 +139,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)  	}  	if (ret != -ENOSPC && ret != -EOPNOTSUPP) -		wiphy_err(key->local->hw.wiphy, +		sdata_err(sdata,  			  "failed to set key (%d, %pM) to hardware (%d)\n",  			  key->conf.keyidx,  			  sta ? sta->sta.addr : bcast_addr, ret); @@ -186,7 +186,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)  			  sta ? &sta->sta : NULL, &key->conf);  	if (ret) -		wiphy_err(key->local->hw.wiphy, +		sdata_err(sdata,  			  "failed to remove key (%d, %pM) from hardware (%d)\n",  			  key->conf.keyidx,  			  sta ? sta->sta.addr : bcast_addr, ret); @@ -194,26 +194,6 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)  	key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;  } -void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) -{ -	struct ieee80211_key *key; - -	key = container_of(key_conf, struct ieee80211_key, conf); - -	might_sleep(); -	assert_key_lock(key->local); - -	key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; - -	/* -	 * Flush TX path to avoid attempts to use this key -	 * after this function returns. Until then, drivers -	 * must be prepared to handle the key. -	 */ -	synchronize_rcu(); -} -EXPORT_SYMBOL_GPL(ieee80211_key_removed); -  static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,  					int idx, bool uni, bool multi)  { diff --git a/net/mac80211/main.c b/net/mac80211/main.c index f5548e95325..c26e231c733 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -322,7 +322,8 @@ static void ieee80211_restart_work(struct work_struct *work)  	mutex_lock(&local->mtx);  	WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) || -	     local->sched_scanning, +	     rcu_dereference_protected(local->sched_scan_sdata, +				       lockdep_is_held(&local->mtx)),  		"%s called with hardware scan in progress\n", __func__);  	mutex_unlock(&local->mtx); @@ -345,6 +346,13 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)  	ieee80211_stop_queues_by_reason(hw,  		IEEE80211_QUEUE_STOP_REASON_SUSPEND); +	/* +	 * Stop all Rx during the reconfig. We don't want state changes +	 * or driver callbacks while this is in progress. +	 */ +	local->in_reconfig = true; +	barrier(); +  	schedule_work(&local->restart_work);  }  EXPORT_SYMBOL(ieee80211_restart_hw); @@ -455,7 +463,9 @@ static const struct ieee80211_txrx_stypes  ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {  	[NL80211_IFTYPE_ADHOC] = {  		.tx = 0xffff, -		.rx = BIT(IEEE80211_STYPE_ACTION >> 4), +		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) | +			BIT(IEEE80211_STYPE_AUTH >> 4) | +			BIT(IEEE80211_STYPE_DEAUTH >> 4),  	},  	[NL80211_IFTYPE_STATION] = {  		.tx = 0xffff, @@ -578,7 +588,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,  	local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); -	BUG_ON(!ops->tx && !ops->tx_frags); +	BUG_ON(!ops->tx);  	BUG_ON(!ops->start);  	BUG_ON(!ops->stop);  	BUG_ON(!ops->config); @@ -625,8 +635,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,  	INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); -	ieee80211_work_init(local); -  	INIT_WORK(&local->restart_work, ieee80211_restart_work);  	INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); @@ -669,7 +677,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,  	ieee80211_led_names(local); -	ieee80211_hw_roc_setup(local); +	ieee80211_roc_setup(local);  	return &local->hw;  } @@ -681,7 +689,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  	int result, i;  	enum ieee80211_band band;  	int channels, max_bitrates; -	bool supp_ht; +	bool supp_ht, supp_vht; +	netdev_features_t feature_whitelist;  	static const u32 cipher_suites[] = {  		/* keep WEP first, it may be removed below */  		WLAN_CIPHER_SUITE_WEP40, @@ -698,16 +707,21 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  	     local->hw.offchannel_tx_hw_queue >= local->hw.queues))  		return -EINVAL; -	if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns)  #ifdef CONFIG_PM -	    && (!local->ops->suspend || !local->ops->resume) -#endif -	    ) +	if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) && +	    (!local->ops->suspend || !local->ops->resume))  		return -EINVAL; +#endif  	if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan)  		return -EINVAL; +	/* Only HW csum features are currently compatible with mac80211 */ +	feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | +			    NETIF_F_HW_CSUM; +	if (WARN_ON(hw->netdev_features & ~feature_whitelist)) +		return -EINVAL; +  	if (hw->max_report_rates == 0)  		hw->max_report_rates = hw->max_rates; @@ -719,6 +733,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  	channels = 0;  	max_bitrates = 0;  	supp_ht = false; +	supp_vht = false;  	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {  		struct ieee80211_supported_band *sband; @@ -736,6 +751,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  		if (max_bitrates < sband->n_bitrates)  			max_bitrates = sband->n_bitrates;  		supp_ht = supp_ht || sband->ht_cap.ht_supported; +		supp_vht = supp_vht || sband->vht_cap.vht_supported;  	}  	local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + @@ -811,6 +827,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  	if (supp_ht)  		local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); +	if (supp_vht) +		local->scan_ies_len += +			2 + sizeof(struct ieee80211_vht_capabilities); +  	if (!local->ops->hw_scan) {  		/* For hw_scan, driver needs to set these up. */  		local->hw.wiphy->max_scan_ssids = 4; @@ -1009,12 +1029,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)  	rtnl_unlock(); -	/* -	 * Now all work items will be gone, but the -	 * timer might still be armed, so delete it -	 */ -	del_timer_sync(&local->work_timer); -  	cancel_work_sync(&local->restart_work);  	cancel_work_sync(&local->reconfig_filter); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 2913113c583..6fac18c0423 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -133,7 +133,7 @@ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)  }  /** - * mesh_accept_plinks_update: update accepting_plink in local mesh beacons + * mesh_accept_plinks_update - update accepting_plink in local mesh beacons   *   * @sdata: mesh interface in which mesh beacons are going to be updated   */ @@ -443,7 +443,7 @@ static void ieee80211_mesh_path_root_timer(unsigned long data)  void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)  { -	if (ifmsh->mshcfg.dot11MeshHWMPRootMode) +	if (ifmsh->mshcfg.dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)  		set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);  	else {  		clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); @@ -523,11 +523,6 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,  {  	bool free_plinks; -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -	printk(KERN_DEBUG "%s: running mesh housekeeping\n", -	       sdata->name); -#endif -  	ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);  	mesh_path_expire(sdata); @@ -542,11 +537,17 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,  static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)  {  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; +	u32 interval;  	mesh_path_tx_root_frame(sdata); + +	if (ifmsh->mshcfg.dot11MeshHWMPRootMode == IEEE80211_PROACTIVE_RANN) +		interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval; +	else +		interval = ifmsh->mshcfg.dot11MeshHWMProotInterval; +  	mod_timer(&ifmsh->mesh_path_root_timer, -		  round_jiffies(TU_TO_EXP_TIME( -				  ifmsh->mshcfg.dot11MeshHWMPRannInterval))); +		  round_jiffies(TU_TO_EXP_TIME(interval)));  }  #ifdef CONFIG_PM diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index e3642756f8f..faaa39bcfd1 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -104,6 +104,7 @@ enum mesh_deferred_task_flags {   * an mpath to a hash bucket on a path table.   * @rann_snd_addr: the RANN sender address   * @rann_metric: the aggregated path metric towards the root node + * @last_preq_to_root: Timestamp of last PREQ sent to root   * @is_root: the destination station of this path is a root node   * @is_gate: the destination station of this path is a mesh gate   * @@ -131,6 +132,7 @@ struct mesh_path {  	spinlock_t state_lock;  	u8 rann_snd_addr[ETH_ALEN];  	u32 rann_metric; +	unsigned long last_preq_to_root;  	bool is_root;  	bool is_gate;  }; @@ -245,7 +247,7 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);  int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);  void ieee80211s_init(void);  void ieee80211s_update_metric(struct ieee80211_local *local, -		struct sta_info *stainfo, struct sk_buff *skb); +		struct sta_info *sta, struct sk_buff *skb);  void ieee80211s_stop(void);  void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);  void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 9b59658e865..494bc39f61a 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -13,13 +13,6 @@  #include "wme.h"  #include "mesh.h" -#ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG -#define mhwmp_dbg(fmt, args...) \ -	printk(KERN_DEBUG "Mesh HWMP (%s): " fmt "\n", sdata->name, ##args) -#else -#define mhwmp_dbg(fmt, args...)   do { (void)(0); } while (0) -#endif -  #define TEST_FRAME_LEN	8192  #define MAX_METRIC	0xffffffff  #define ARITH_SHIFT	8 @@ -98,6 +91,8 @@ static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae)  #define max_preq_retries(s) (s->u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries)  #define disc_timeout_jiff(s) \  	msecs_to_jiffies(sdata->u.mesh.mshcfg.min_discovery_timeout) +#define root_path_confirmation_jiffies(s) \ +	msecs_to_jiffies(sdata->u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval)  enum mpath_frame_type {  	MPATH_PREQ = 0, @@ -142,19 +137,19 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,  	switch (action) {  	case MPATH_PREQ: -		mhwmp_dbg("sending PREQ to %pM", target); +		mhwmp_dbg(sdata, "sending PREQ to %pM\n", target);  		ie_len = 37;  		pos = skb_put(skb, 2 + ie_len);  		*pos++ = WLAN_EID_PREQ;  		break;  	case MPATH_PREP: -		mhwmp_dbg("sending PREP to %pM", target); +		mhwmp_dbg(sdata, "sending PREP to %pM\n", target);  		ie_len = 31;  		pos = skb_put(skb, 2 + ie_len);  		*pos++ = WLAN_EID_PREP;  		break;  	case MPATH_RANN: -		mhwmp_dbg("sending RANN from %pM", orig_addr); +		mhwmp_dbg(sdata, "sending RANN from %pM\n", orig_addr);  		ie_len = sizeof(struct ieee80211_rann_ie);  		pos = skb_put(skb, 2 + ie_len);  		*pos++ = WLAN_EID_RANN; @@ -303,7 +298,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,  }  void ieee80211s_update_metric(struct ieee80211_local *local, -		struct sta_info *stainfo, struct sk_buff *skb) +		struct sta_info *sta, struct sk_buff *skb)  {  	struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -315,15 +310,14 @@ void ieee80211s_update_metric(struct ieee80211_local *local,  	failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK);  	/* moving average, scaled to 100 */ -	stainfo->fail_avg = ((80 * stainfo->fail_avg + 5) / 100 + 20 * failed); -	if (stainfo->fail_avg > 95) -		mesh_plink_broken(stainfo); +	sta->fail_avg = ((80 * sta->fail_avg + 5) / 100 + 20 * failed); +	if (sta->fail_avg > 95) +		mesh_plink_broken(sta);  }  static u32 airtime_link_metric_get(struct ieee80211_local *local,  				   struct sta_info *sta)  { -	struct ieee80211_supported_band *sband;  	struct rate_info rinfo;  	/* This should be adjusted for each device */  	int device_constant = 1 << ARITH_SHIFT; @@ -333,8 +327,6 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local,  	u32 tx_time, estimated_retx;  	u64 result; -	sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; -  	if (sta->fail_avg >= 100)  		return MAX_METRIC; @@ -519,10 +511,11 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,  	struct mesh_path *mpath = NULL;  	u8 *target_addr, *orig_addr;  	const u8 *da; -	u8 target_flags, ttl; -	u32 orig_sn, target_sn, lifetime; +	u8 target_flags, ttl, flags; +	u32 orig_sn, target_sn, lifetime, orig_metric;  	bool reply = false;  	bool forward = true; +	bool root_is_gate;  	/* Update target SN, if present */  	target_addr = PREQ_IE_TARGET_ADDR(preq_elem); @@ -530,11 +523,15 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,  	target_sn = PREQ_IE_TARGET_SN(preq_elem);  	orig_sn = PREQ_IE_ORIG_SN(preq_elem);  	target_flags = PREQ_IE_TARGET_F(preq_elem); +	orig_metric = metric; +	/* Proactive PREQ gate announcements */ +	flags = PREQ_IE_FLAGS(preq_elem); +	root_is_gate = !!(flags & RANN_FLAG_IS_GATE); -	mhwmp_dbg("received PREQ from %pM", orig_addr); +	mhwmp_dbg(sdata, "received PREQ from %pM\n", orig_addr);  	if (ether_addr_equal(target_addr, sdata->vif.addr)) { -		mhwmp_dbg("PREQ is for us"); +		mhwmp_dbg(sdata, "PREQ is for us\n");  		forward = false;  		reply = true;  		metric = 0; @@ -544,6 +541,22 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,  			target_sn = ++ifmsh->sn;  			ifmsh->last_sn_update = jiffies;  		} +	} else if (is_broadcast_ether_addr(target_addr) && +		   (target_flags & IEEE80211_PREQ_TO_FLAG)) { +		rcu_read_lock(); +		mpath = mesh_path_lookup(orig_addr, sdata); +		if (mpath) { +			if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) { +				reply = true; +				target_addr = sdata->vif.addr; +				target_sn = ++ifmsh->sn; +				metric = 0; +				ifmsh->last_sn_update = jiffies; +			} +			if (root_is_gate) +				mesh_path_add_gate(mpath); +		} +		rcu_read_unlock();  	} else {  		rcu_read_lock();  		mpath = mesh_path_lookup(target_addr, sdata); @@ -570,19 +583,20 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,  		lifetime = PREQ_IE_LIFETIME(preq_elem);  		ttl = ifmsh->mshcfg.element_ttl;  		if (ttl != 0) { -			mhwmp_dbg("replying to the PREQ"); +			mhwmp_dbg(sdata, "replying to the PREQ\n");  			mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr,  				cpu_to_le32(orig_sn), 0, target_addr,  				cpu_to_le32(target_sn), mgmt->sa, 0, ttl,  				cpu_to_le32(lifetime), cpu_to_le32(metric),  				0, sdata); -		} else +		} else {  			ifmsh->mshstats.dropped_frames_ttl++; +		}  	}  	if (forward && ifmsh->mshcfg.dot11MeshForwarding) {  		u32 preq_id; -		u8 hopcount, flags; +		u8 hopcount;  		ttl = PREQ_IE_TTL(preq_elem);  		lifetime = PREQ_IE_LIFETIME(preq_elem); @@ -590,13 +604,19 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,  			ifmsh->mshstats.dropped_frames_ttl++;  			return;  		} -		mhwmp_dbg("forwarding the PREQ from %pM", orig_addr); +		mhwmp_dbg(sdata, "forwarding the PREQ from %pM\n", orig_addr);  		--ttl; -		flags = PREQ_IE_FLAGS(preq_elem);  		preq_id = PREQ_IE_PREQ_ID(preq_elem);  		hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;  		da = (mpath && mpath->is_root) ?  			mpath->rann_snd_addr : broadcast_addr; + +		if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) { +			target_addr = PREQ_IE_TARGET_ADDR(preq_elem); +			target_sn = PREQ_IE_TARGET_SN(preq_elem); +			metric = orig_metric; +		} +  		mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,  				cpu_to_le32(orig_sn), target_flags, target_addr,  				cpu_to_le32(target_sn), da, @@ -631,7 +651,8 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,  	u8 next_hop[ETH_ALEN];  	u32 target_sn, orig_sn, lifetime; -	mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem)); +	mhwmp_dbg(sdata, "received PREP from %pM\n", +		  PREP_IE_ORIG_ADDR(prep_elem));  	orig_addr = PREP_IE_ORIG_ADDR(prep_elem);  	if (ether_addr_equal(orig_addr, sdata->vif.addr)) @@ -744,11 +765,6 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,  	bool root_is_gate;  	ttl = rann->rann_ttl; -	if (ttl <= 1) { -		ifmsh->mshstats.dropped_frames_ttl++; -		return; -	} -	ttl--;  	flags = rann->rann_flags;  	root_is_gate = !!(flags & RANN_FLAG_IS_GATE);  	orig_addr = rann->rann_addr; @@ -762,8 +778,9 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,  	if (ether_addr_equal(orig_addr, sdata->vif.addr))  		return; -	mhwmp_dbg("received RANN from %pM via neighbour %pM (is_gate=%d)", -			orig_addr, mgmt->sa, root_is_gate); +	mhwmp_dbg(sdata, +		  "received RANN from %pM via neighbour %pM (is_gate=%d)\n", +		  orig_addr, mgmt->sa, root_is_gate);  	rcu_read_lock();  	sta = sta_info_get(sdata, mgmt->sa); @@ -785,34 +802,50 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,  		}  	} +	if (!(SN_LT(mpath->sn, orig_sn)) && +	    !(mpath->sn == orig_sn && metric < mpath->rann_metric)) { +		rcu_read_unlock(); +		return; +	} +  	if ((!(mpath->flags & (MESH_PATH_ACTIVE | MESH_PATH_RESOLVING)) || -	     time_after(jiffies, mpath->exp_time - 1*HZ)) && -	     !(mpath->flags & MESH_PATH_FIXED)) { -		mhwmp_dbg("%s time to refresh root mpath %pM", sdata->name, -							       orig_addr); +	     (time_after(jiffies, mpath->last_preq_to_root + +				  root_path_confirmation_jiffies(sdata)) || +	     time_before(jiffies, mpath->last_preq_to_root))) && +	     !(mpath->flags & MESH_PATH_FIXED) && (ttl != 0)) { +		mhwmp_dbg(sdata, +			  "time to refresh root mpath %pM\n", +			  orig_addr);  		mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH); +		mpath->last_preq_to_root = jiffies;  	} -	if ((SN_LT(mpath->sn, orig_sn) || (mpath->sn == orig_sn && -	   metric < mpath->rann_metric)) && ifmsh->mshcfg.dot11MeshForwarding) { +	mpath->sn = orig_sn; +	mpath->rann_metric = metric + metric_txsta; +	mpath->is_root = true; +	/* Recording RANNs sender address to send individually +	 * addressed PREQs destined for root mesh STA */ +	memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN); + +	if (root_is_gate) +		mesh_path_add_gate(mpath); + +	if (ttl <= 1) { +		ifmsh->mshstats.dropped_frames_ttl++; +		rcu_read_unlock(); +		return; +	} +	ttl--; + +	if (ifmsh->mshcfg.dot11MeshForwarding) {  		mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,  				       cpu_to_le32(orig_sn),  				       0, NULL, 0, broadcast_addr,  				       hopcount, ttl, cpu_to_le32(interval),  				       cpu_to_le32(metric + metric_txsta),  				       0, sdata); -		mpath->sn = orig_sn; -		mpath->rann_metric = metric + metric_txsta; -		/* Recording RANNs sender address to send individually -		 * addressed PREQs destined for root mesh STA */ -		memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN);  	} -	mpath->is_root = true; - -	if (root_is_gate) -		mesh_path_add_gate(mpath); -  	rcu_read_unlock();  } @@ -889,7 +922,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)  	preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC);  	if (!preq_node) { -		mhwmp_dbg("could not allocate PREQ node"); +		mhwmp_dbg(sdata, "could not allocate PREQ node\n");  		return;  	} @@ -898,7 +931,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)  		spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);  		kfree(preq_node);  		if (printk_ratelimit()) -			mhwmp_dbg("PREQ node queue full"); +			mhwmp_dbg(sdata, "PREQ node queue full\n");  		return;  	} @@ -1021,12 +1054,15 @@ enddiscovery:  	kfree(preq_node);  } -/* mesh_nexthop_resolve - lookup next hop for given skb and start path - * discovery if no forwarding information is found. +/** + * mesh_nexthop_resolve - lookup next hop; conditionally start path discovery   *   * @skb: 802.11 frame to be sent   * @sdata: network subif the frame will be sent through   * + * Lookup next hop for given skb and start path discovery if no + * forwarding information is found. + *   * Returns: 0 if the next hop was found and -ENOENT if the frame was queued.   * skb is freeed here if no mpath could be allocated.   */ @@ -1146,7 +1182,7 @@ void mesh_path_timer(unsigned long data)  		if (!mpath->is_gate && mesh_gate_num(sdata) > 0) {  			ret = mesh_path_send_to_gates(mpath);  			if (ret) -				mhwmp_dbg("no gate was reachable"); +				mhwmp_dbg(sdata, "no gate was reachable\n");  		} else  			mesh_path_flush_pending(mpath);  	} @@ -1157,13 +1193,34 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)  {  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;  	u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval; -	u8 flags; +	u8 flags, target_flags = 0;  	flags = (ifmsh->mshcfg.dot11MeshGateAnnouncementProtocol)  			? RANN_FLAG_IS_GATE : 0; -	mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr, + +	switch (ifmsh->mshcfg.dot11MeshHWMPRootMode) { +	case IEEE80211_PROACTIVE_RANN: +		mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr,  			       cpu_to_le32(++ifmsh->sn),  			       0, NULL, 0, broadcast_addr, -			       0, sdata->u.mesh.mshcfg.element_ttl, +			       0, ifmsh->mshcfg.element_ttl,  			       cpu_to_le32(interval), 0, 0, sdata); +		break; +	case IEEE80211_PROACTIVE_PREQ_WITH_PREP: +		flags |= IEEE80211_PREQ_PROACTIVE_PREP_FLAG; +	case IEEE80211_PROACTIVE_PREQ_NO_PREP: +		interval = ifmsh->mshcfg.dot11MeshHWMPactivePathToRootTimeout; +		target_flags |= IEEE80211_PREQ_TO_FLAG | +				IEEE80211_PREQ_USN_FLAG; +		mesh_path_sel_frame_tx(MPATH_PREQ, flags, sdata->vif.addr, +				cpu_to_le32(++ifmsh->sn), target_flags, +				(u8 *) broadcast_addr, 0, broadcast_addr, +				0, ifmsh->mshcfg.element_ttl, +				cpu_to_le32(interval), +				0, cpu_to_le32(ifmsh->preq_id++), sdata); +		break; +	default: +		mhwmp_dbg(sdata, "Proactive mechanism not supported\n"); +		return; +	}  } diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index b39224d8255..075bc535c60 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -18,12 +18,6 @@  #include "ieee80211_i.h"  #include "mesh.h" -#ifdef CONFIG_MAC80211_VERBOSE_MPATH_DEBUG -#define mpath_dbg(fmt, args...)	printk(KERN_DEBUG fmt, ##args) -#else -#define mpath_dbg(fmt, args...)	do { (void)(0); } while (0) -#endif -  /* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */  #define INIT_PATHS_SIZE_ORDER	2 @@ -322,9 +316,8 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath,  	spin_lock_irqsave(&gate_mpath->frame_queue.lock, flags);  	skb_queue_splice(&gateq, &gate_mpath->frame_queue); -	mpath_dbg("Mpath queue for gate %pM has %d frames\n", -			gate_mpath->dst, -			skb_queue_len(&gate_mpath->frame_queue)); +	mpath_dbg(gate_mpath->sdata, "Mpath queue for gate %pM has %d frames\n", +		  gate_mpath->dst, skb_queue_len(&gate_mpath->frame_queue));  	spin_unlock_irqrestore(&gate_mpath->frame_queue.lock, flags);  	if (!copy) @@ -446,9 +439,9 @@ int mesh_path_add_gate(struct mesh_path *mpath)  	hlist_add_head_rcu(&new_gate->list, tbl->known_gates);  	spin_unlock_bh(&tbl->gates_lock);  	rcu_read_unlock(); -	mpath_dbg("Mesh path (%s): Recorded new gate: %pM. %d known gates\n", -		  mpath->sdata->name, mpath->dst, -		  mpath->sdata->u.mesh.num_gates); +	mpath_dbg(mpath->sdata, +		  "Mesh path: Recorded new gate: %pM. %d known gates\n", +		  mpath->dst, mpath->sdata->u.mesh.num_gates);  	return 0;  err_rcu:  	rcu_read_unlock(); @@ -477,8 +470,8 @@ static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)  			spin_unlock_bh(&tbl->gates_lock);  			mpath->sdata->u.mesh.num_gates--;  			mpath->is_gate = false; -			mpath_dbg("Mesh path (%s): Deleted gate: %pM. " -				  "%d known gates\n", mpath->sdata->name, +			mpath_dbg(mpath->sdata, +				  "Mesh path: Deleted gate: %pM. %d known gates\n",  				  mpath->dst, mpath->sdata->u.mesh.num_gates);  			break;  		} @@ -785,7 +778,7 @@ static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node)  /**   * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches   * - * @sta - mesh peer to match + * @sta: mesh peer to match   *   * RCU notes: this function is called when a mesh plink transitions from   * PLINK_ESTAB to any other state, since PLINK_ESTAB state is the only one that @@ -840,7 +833,7 @@ static void table_flush_by_iface(struct mesh_table *tbl,   *   * This function deletes both mesh paths as well as mesh portal paths.   * - * @sdata - interface data to match + * @sdata: interface data to match   *   */  void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata) @@ -946,19 +939,20 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)  			continue;  		if (gate->mpath->flags & MESH_PATH_ACTIVE) { -			mpath_dbg("Forwarding to %pM\n", gate->mpath->dst); +			mpath_dbg(sdata, "Forwarding to %pM\n", gate->mpath->dst);  			mesh_path_move_to_queue(gate->mpath, from_mpath, copy);  			from_mpath = gate->mpath;  			copy = true;  		} else { -			mpath_dbg("Not forwarding %p\n", gate->mpath); -			mpath_dbg("flags %x\n", gate->mpath->flags); +			mpath_dbg(sdata, +				  "Not forwarding %p (flags %#x)\n", +				  gate->mpath, gate->mpath->flags);  		}  	}  	hlist_for_each_entry_rcu(gate, n, known_gates, list)  		if (gate->mpath->sdata == sdata) { -			mpath_dbg("Sending to %pM\n", gate->mpath->dst); +			mpath_dbg(sdata, "Sending to %pM\n", gate->mpath->dst);  			mesh_path_tx_pending(gate->mpath);  		} diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 60ef235c9d9..af671b984df 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -13,12 +13,6 @@  #include "rate.h"  #include "mesh.h" -#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG -#define mpl_dbg(fmt, args...)	printk(KERN_DEBUG fmt, ##args) -#else -#define mpl_dbg(fmt, args...)	do { (void)(0); } while (0) -#endif -  #define PLINK_GET_LLID(p) (p + 2)  #define PLINK_GET_PLID(p) (p + 4) @@ -105,7 +99,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,  	return sta;  } -/* +/**   * mesh_set_ht_prot_mode - set correct HT protection mode   *   * Section 9.23.3.5 of IEEE 80211-2012 describes the protection rules for HT @@ -134,12 +128,14 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)  		switch (sta->ch_type) {  		case NL80211_CHAN_NO_HT: -			mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present", +			mpl_dbg(sdata, +				"mesh_plink %pM: nonHT sta (%pM) is present\n",  				sdata->vif.addr, sta->sta.addr);  			non_ht_sta = true;  			goto out;  		case NL80211_CHAN_HT20: -			mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present", +			mpl_dbg(sdata, +				"mesh_plink %pM: HT20 sta (%pM) is present\n",  				sdata->vif.addr, sta->sta.addr);  			ht20_sta = true;  		default: @@ -160,7 +156,8 @@ out:  		sdata->vif.bss_conf.ht_operation_mode = ht_opmode;  		sdata->u.mesh.mshcfg.ht_opmode = ht_opmode;  		changed = BSS_CHANGED_HT; -		mpl_dbg("mesh_plink %pM: protection mode changed to %d", +		mpl_dbg(sdata, +			"mesh_plink %pM: protection mode changed to %d\n",  			sdata->vif.addr, ht_opmode);  	} @@ -261,8 +258,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,  			pos = skb_put(skb, 2);  			memcpy(pos + 2, &plid, 2);  		} -		if (ieee80211_add_srates_ie(&sdata->vif, skb, true) || -		    ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) || +		if (ieee80211_add_srates_ie(sdata, skb, true) || +		    ieee80211_add_ext_srates_ie(sdata, skb, true) ||  		    mesh_add_rsn_ie(skb, sdata) ||  		    mesh_add_meshid_ie(skb, sdata) ||  		    mesh_add_meshconf_ie(skb, sdata)) @@ -323,7 +320,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,  	return 0;  } -/* mesh_peer_init - initialize new mesh peer and return resulting sta_info +/** + * mesh_peer_init - initialize new mesh peer and return resulting sta_info   *   * @sdata: local meshif   * @addr: peer's address @@ -437,7 +435,8 @@ static void mesh_plink_timer(unsigned long data)  		spin_unlock_bh(&sta->lock);  		return;  	} -	mpl_dbg("Mesh plink timer for %pM fired on state %d\n", +	mpl_dbg(sta->sdata, +		"Mesh plink timer for %pM fired on state %d\n",  		sta->sta.addr, sta->plink_state);  	reason = 0;  	llid = sta->llid; @@ -450,7 +449,8 @@ static void mesh_plink_timer(unsigned long data)  		/* retry timer */  		if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {  			u32 rand; -			mpl_dbg("Mesh plink for %pM (retry, timeout): %d %d\n", +			mpl_dbg(sta->sdata, +				"Mesh plink for %pM (retry, timeout): %d %d\n",  				sta->sta.addr, sta->plink_retries,  				sta->plink_timeout);  			get_random_bytes(&rand, sizeof(u32)); @@ -530,7 +530,8 @@ int mesh_plink_open(struct sta_info *sta)  	sta->plink_state = NL80211_PLINK_OPN_SNT;  	mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));  	spin_unlock_bh(&sta->lock); -	mpl_dbg("Mesh plink: starting establishment with %pM\n", +	mpl_dbg(sdata, +		"Mesh plink: starting establishment with %pM\n",  		sta->sta.addr);  	return mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, @@ -565,7 +566,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m  	u8 *baseaddr;  	u32 changed = 0;  	__le16 plid, llid, reason; -#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG  	static const char *mplstates[] = {  		[NL80211_PLINK_LISTEN] = "LISTEN",  		[NL80211_PLINK_OPN_SNT] = "OPN-SNT", @@ -575,14 +575,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m  		[NL80211_PLINK_HOLDING] = "HOLDING",  		[NL80211_PLINK_BLOCKED] = "BLOCKED"  	}; -#endif  	/* need action_code, aux */  	if (len < IEEE80211_MIN_ACTION_SIZE + 3)  		return;  	if (is_multicast_ether_addr(mgmt->da)) { -		mpl_dbg("Mesh plink: ignore frame from multicast address"); +		mpl_dbg(sdata, +			"Mesh plink: ignore frame from multicast address\n");  		return;  	} @@ -595,12 +595,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m  	}  	ieee802_11_parse_elems(baseaddr, len - baselen, &elems);  	if (!elems.peering) { -		mpl_dbg("Mesh plink: missing necessary peer link ie\n"); +		mpl_dbg(sdata, +			"Mesh plink: missing necessary peer link ie\n");  		return;  	}  	if (elems.rsn_len &&  			sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { -		mpl_dbg("Mesh plink: can't establish link with secure peer\n"); +		mpl_dbg(sdata, +			"Mesh plink: can't establish link with secure peer\n");  		return;  	} @@ -610,14 +612,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m  	    (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||  	    (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6  							&& ie_len != 8)) { -		mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n", -		    ftype, ie_len); +		mpl_dbg(sdata, +			"Mesh plink: incorrect plink ie length %d %d\n", +			ftype, ie_len);  		return;  	}  	if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&  				(!elems.mesh_id || !elems.mesh_config)) { -		mpl_dbg("Mesh plink: missing necessary ie\n"); +		mpl_dbg(sdata, "Mesh plink: missing necessary ie\n");  		return;  	}  	/* Note the lines below are correct, the llid in the frame is the plid @@ -632,21 +635,21 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m  	sta = sta_info_get(sdata, mgmt->sa);  	if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) { -		mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); +		mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");  		rcu_read_unlock();  		return;  	}  	if (ftype == WLAN_SP_MESH_PEERING_OPEN &&  	    !rssi_threshold_check(sta, sdata)) { -		mpl_dbg("Mesh plink: %pM does not meet rssi threshold\n", +		mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",  			mgmt->sa);  		rcu_read_unlock();  		return;  	}  	if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) { -		mpl_dbg("Mesh plink: Action frame from non-authed peer\n"); +		mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");  		rcu_read_unlock();  		return;  	} @@ -683,7 +686,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m  	} else if (!sta) {  		/* ftype == WLAN_SP_MESH_PEERING_OPEN */  		if (!mesh_plink_free_count(sdata)) { -			mpl_dbg("Mesh plink error: no more free plinks\n"); +			mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");  			rcu_read_unlock();  			return;  		} @@ -724,7 +727,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m  				event = CLS_ACPT;  			break;  		default: -			mpl_dbg("Mesh plink: unknown frame subtype\n"); +			mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");  			rcu_read_unlock();  			return;  		} @@ -734,13 +737,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m  		/* allocate sta entry if necessary and update info */  		sta = mesh_peer_init(sdata, mgmt->sa, &elems);  		if (!sta) { -			mpl_dbg("Mesh plink: failed to init peer!\n"); +			mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");  			rcu_read_unlock();  			return;  		}  	} -	mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n", +	mpl_dbg(sdata, +		"Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n",  		mgmt->sa, mplstates[sta->plink_state],  		le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),  		event); @@ -851,7 +855,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m  			mesh_plink_inc_estab_count(sdata);  			changed |= mesh_set_ht_prot_mode(sdata);  			changed |= BSS_CHANGED_BEACON; -			mpl_dbg("Mesh plink with %pM ESTABLISHED\n", +			mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",  				sta->sta.addr);  			break;  		default: @@ -887,7 +891,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m  			mesh_plink_inc_estab_count(sdata);  			changed |= mesh_set_ht_prot_mode(sdata);  			changed |= BSS_CHANGED_BEACON; -			mpl_dbg("Mesh plink with %pM ESTABLISHED\n", +			mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",  				sta->sta.addr);  			mesh_plink_frame_tx(sdata,  					    WLAN_SP_MESH_PEERING_CONFIRM, diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index 38d30e8ce6d..accfa00ffcd 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c @@ -12,13 +12,6 @@  #include "mesh.h"  #include "driver-ops.h" -#ifdef CONFIG_MAC80211_VERBOSE_MESH_SYNC_DEBUG -#define msync_dbg(fmt, args...) \ -	printk(KERN_DEBUG "Mesh sync (%s): " fmt "\n", sdata->name, ##args) -#else -#define msync_dbg(fmt, args...)   do { (void)(0); } while (0) -#endif -  /* This is not in the standard.  It represents a tolerable tbtt drift below   * which we do no TSF adjustment.   */ @@ -65,14 +58,14 @@ void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata)  	spin_lock_bh(&ifmsh->sync_offset_lock);  	if (ifmsh->sync_offset_clockdrift_max < beacon_int_fraction) { -		msync_dbg("TBTT : max clockdrift=%lld; adjusting", -			(long long) ifmsh->sync_offset_clockdrift_max); +		msync_dbg(sdata, "TBTT : max clockdrift=%lld; adjusting\n", +			  (long long) ifmsh->sync_offset_clockdrift_max);  		tsfdelta = -ifmsh->sync_offset_clockdrift_max;  		ifmsh->sync_offset_clockdrift_max = 0;  	} else { -		msync_dbg("TBTT : max clockdrift=%lld; adjusting by %llu", -			(long long) ifmsh->sync_offset_clockdrift_max, -			(unsigned long long) beacon_int_fraction); +		msync_dbg(sdata, "TBTT : max clockdrift=%lld; adjusting by %llu\n", +			  (long long) ifmsh->sync_offset_clockdrift_max, +			  (unsigned long long) beacon_int_fraction);  		tsfdelta = -beacon_int_fraction;  		ifmsh->sync_offset_clockdrift_max -= beacon_int_fraction;  	} @@ -120,7 +113,7 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,  	if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) {  		clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); -		msync_dbg("STA %pM : is adjusting TBTT", sta->sta.addr); +		msync_dbg(sdata, "STA %pM : is adjusting TBTT\n", sta->sta.addr);  		goto no_sync;  	} @@ -169,7 +162,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,  	if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {  		s64 t_clockdrift = sta->t_offset_setpoint  				   - sta->t_offset; -		msync_dbg("STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld", +		msync_dbg(sdata, +			  "STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld\n",  			  sta->sta.addr,  			  (long long) sta->t_offset,  			  (long long) @@ -178,7 +172,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,  		if (t_clockdrift > TOFFSET_MAXIMUM_ADJUSTMENT ||  			t_clockdrift < -TOFFSET_MAXIMUM_ADJUSTMENT) { -			msync_dbg("STA %pM : t_clockdrift=%lld too large, setpoint reset", +			msync_dbg(sdata, +				  "STA %pM : t_clockdrift=%lld too large, setpoint reset\n",  				  sta->sta.addr,  				  (long long) t_clockdrift);  			clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); @@ -197,8 +192,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,  	} else {  		sta->t_offset_setpoint = sta->t_offset - TOFFSET_SET_MARGIN;  		set_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); -		msync_dbg("STA %pM : offset was invalid, " -			  " sta->t_offset=%lld", +		msync_dbg(sdata, +			  "STA %pM : offset was invalid, sta->t_offset=%lld\n",  			  sta->sta.addr,  			  (long long) sta->t_offset);  		rcu_read_unlock(); @@ -226,17 +221,15 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata)  		 * to the driver tsf setter, we punt  		 * the tsf adjustment to the mesh tasklet  		 */ -		msync_dbg("TBTT : kicking off TBTT " -			  "adjustment with " -			  "clockdrift_max=%lld", -		  ifmsh->sync_offset_clockdrift_max); +		msync_dbg(sdata, +			  "TBTT : kicking off TBTT adjustment with clockdrift_max=%lld\n", +			  ifmsh->sync_offset_clockdrift_max);  		set_bit(MESH_WORK_DRIFT_ADJUST,  			&ifmsh->wrkq_flags);  	} else { -		msync_dbg("TBTT : max clockdrift=%lld; " -			  "too small to adjust", -			  (long long) -		       ifmsh->sync_offset_clockdrift_max); +		msync_dbg(sdata, +			  "TBTT : max clockdrift=%lld; too small to adjust\n", +			  (long long)ifmsh->sync_offset_clockdrift_max);  		ifmsh->sync_offset_clockdrift_max = 0;  	}  	spin_unlock_bh(&ifmsh->sync_offset_lock); @@ -268,7 +261,7 @@ static void mesh_sync_vendor_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,  	const u8 *oui;  	WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR); -	msync_dbg("called mesh_sync_vendor_rx_bcn_presp"); +	msync_dbg(sdata, "called mesh_sync_vendor_rx_bcn_presp\n");  	oui = mesh_get_vendor_oui(sdata);  	/*  here you would implement the vendor offset tracking for this oui */  } @@ -278,7 +271,7 @@ static void mesh_sync_vendor_adjust_tbtt(struct ieee80211_sub_if_data *sdata)  	const u8 *oui;  	WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR); -	msync_dbg("called mesh_sync_vendor_adjust_tbtt"); +	msync_dbg(sdata, "called mesh_sync_vendor_adjust_tbtt\n");  	oui = mesh_get_vendor_oui(sdata);  	/*  here you would implement the vendor tsf adjustment for this oui */  } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b3b3c264ff6..cef0c9e79ab 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -258,12 +258,11 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,  }  static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, -				struct sk_buff *skb, const u8 *ht_oper_ie, +				struct sk_buff *skb, u8 ap_ht_param,  				struct ieee80211_supported_band *sband,  				struct ieee80211_channel *channel,  				enum ieee80211_smps_mode smps)  { -	struct ieee80211_ht_operation *ht_oper;  	u8 *pos;  	u32 flags = channel->flags;  	u16 cap; @@ -271,21 +270,13 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,  	BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap)); -	if (!ht_oper_ie) -		return; - -	if (ht_oper_ie[1] < sizeof(struct ieee80211_ht_operation)) -		return; -  	memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));  	ieee80211_apply_htcap_overrides(sdata, &ht_cap); -	ht_oper = (struct ieee80211_ht_operation *)(ht_oper_ie + 2); -  	/* determine capability flags */  	cap = ht_cap.cap; -	switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { +	switch (ap_ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {  	case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:  		if (flags & IEEE80211_CHAN_NO_HT40PLUS) {  			cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; @@ -509,7 +500,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)  	}  	if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) -		ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_operation_ie, +		ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,  				    sband, local->oper_channel, ifmgd->ap_smps);  	/* if present, add any custom non-vendor IEs that go after HT */ @@ -550,6 +541,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)  		memcpy(pos, assoc_data->ie + offset, noffset - offset);  	} +	drv_mgd_prepare_tx(local, sdata); +  	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;  	ieee80211_tx_skb(sdata, skb);  } @@ -589,6 +582,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,  		if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))  			IEEE80211_SKB_CB(skb)->flags |=  				IEEE80211_TX_INTFL_DONT_ENCRYPT; + +		drv_mgd_prepare_tx(local, sdata); +  		ieee80211_tx_skb(sdata, skb);  	}  } @@ -911,9 +907,6 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)  	if (!mgd->associated)  		return false; -	if (!mgd->associated->beacon_ies) -		return false; -  	if (mgd->flags & (IEEE80211_STA_BEACON_POLL |  			  IEEE80211_STA_CONNECTION_POLL))  		return false; @@ -939,11 +932,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)  		return;  	} -	if (!list_empty(&local->work_list)) { -		local->ps_sdata = NULL; -		goto change; -	} -  	list_for_each_entry(sdata, &local->interfaces, list) {  		if (!ieee80211_sdata_running(sdata))  			continue; @@ -1016,7 +1004,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)  		local->ps_sdata = NULL;  	} - change:  	ieee80211_change_ps(local);  } @@ -1121,7 +1108,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data)  }  /* MLME */ -static void ieee80211_sta_wmm_params(struct ieee80211_local *local, +static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,  				     struct ieee80211_sub_if_data *sdata,  				     u8 *wmm_param, size_t wmm_param_len)  { @@ -1132,23 +1119,23 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,  	u8 *pos, uapsd_queues = 0;  	if (!local->ops->conf_tx) -		return; +		return false;  	if (local->hw.queues < IEEE80211_NUM_ACS) -		return; +		return false;  	if (!wmm_param) -		return; +		return false;  	if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) -		return; +		return false;  	if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)  		uapsd_queues = ifmgd->uapsd_queues;  	count = wmm_param[6] & 0x0f;  	if (count == ifmgd->wmm_last_param_set) -		return; +		return false;  	ifmgd->wmm_last_param_set = count;  	pos = wmm_param + 8; @@ -1156,7 +1143,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,  	memset(¶ms, 0, sizeof(params)); -	local->wmm_acm = 0; +	sdata->wmm_acm = 0;  	for (; left >= 4; left -= 4, pos += 4) {  		int aci = (pos[0] >> 5) & 0x03;  		int acm = (pos[0] >> 4) & 0x01; @@ -1167,21 +1154,21 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,  		case 1: /* AC_BK */  			queue = 3;  			if (acm) -				local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ +				sdata->wmm_acm |= BIT(1) | BIT(2); /* BK/- */  			if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)  				uapsd = true;  			break;  		case 2: /* AC_VI */  			queue = 1;  			if (acm) -				local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ +				sdata->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */  			if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)  				uapsd = true;  			break;  		case 3: /* AC_VO */  			queue = 0;  			if (acm) -				local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ +				sdata->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */  			if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)  				uapsd = true;  			break; @@ -1189,7 +1176,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,  		default:  			queue = 2;  			if (acm) -				local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ +				sdata->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */  			if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)  				uapsd = true;  			break; @@ -1201,23 +1188,37 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,  		params.txop = get_unaligned_le16(pos + 2);  		params.uapsd = uapsd; -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -		wiphy_debug(local->hw.wiphy, -			    "WMM queue=%d aci=%d acm=%d aifs=%d " -			    "cWmin=%d cWmax=%d txop=%d uapsd=%d\n", -			    queue, aci, acm, -			    params.aifs, params.cw_min, params.cw_max, -			    params.txop, params.uapsd); -#endif +		mlme_dbg(sdata, +			 "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d\n", +			 queue, aci, acm, +			 params.aifs, params.cw_min, params.cw_max, +			 params.txop, params.uapsd);  		sdata->tx_conf[queue] = params;  		if (drv_conf_tx(local, sdata, queue, ¶ms)) -			wiphy_debug(local->hw.wiphy, -				    "failed to set TX queue parameters for queue %d\n", -				    queue); +			sdata_err(sdata, +				  "failed to set TX queue parameters for queue %d\n", +				  queue);  	}  	/* enable WMM or activate new settings */  	sdata->vif.bss_conf.qos = true; +	return true; +} + +static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata) +{ +	lockdep_assert_held(&sdata->local->mtx); + +	sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | +				IEEE80211_STA_BEACON_POLL); +	ieee80211_run_deferred_scan(sdata->local); +} + +static void ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata) +{ +	mutex_lock(&sdata->local->mtx); +	__ieee80211_stop_poll(sdata); +	mutex_unlock(&sdata->local->mtx);  }  static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, @@ -1268,13 +1269,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,  	struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;  	bss_info_changed |= BSS_CHANGED_ASSOC; -	/* set timing information */ -	bss_conf->beacon_int = cbss->beacon_interval; -	bss_conf->last_tsf = cbss->tsf; - -	bss_info_changed |= BSS_CHANGED_BEACON_INT;  	bss_info_changed |= ieee80211_handle_bss_capability(sdata, -		cbss->capability, bss->has_erp_value, bss->erp_value); +		bss_conf->assoc_capability, bss->has_erp_value, bss->erp_value);  	sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec(  		IEEE80211_BEACON_LOSS_COUNT * bss_conf->beacon_int)); @@ -1285,8 +1281,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,  	sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;  	/* just to be sure */ -	sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | -				IEEE80211_STA_BEACON_POLL); +	ieee80211_stop_poll(sdata);  	ieee80211_led_assoc(local, 1); @@ -1327,7 +1322,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,  	struct ieee80211_local *local = sdata->local;  	struct sta_info *sta;  	u32 changed = 0; -	u8 bssid[ETH_ALEN];  	ASSERT_MGD_MTX(ifmgd); @@ -1337,10 +1331,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,  	if (WARN_ON(!ifmgd->associated))  		return; -	memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); +	ieee80211_stop_poll(sdata);  	ifmgd->associated = NULL; -	memset(ifmgd->bssid, 0, ETH_ALEN);  	/*  	 * we need to commit the associated = NULL change because the @@ -1360,22 +1353,40 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,  	netif_carrier_off(sdata->dev);  	mutex_lock(&local->sta_mtx); -	sta = sta_info_get(sdata, bssid); +	sta = sta_info_get(sdata, ifmgd->bssid);  	if (sta) {  		set_sta_flag(sta, WLAN_STA_BLOCK_BA);  		ieee80211_sta_tear_down_BA_sessions(sta, tx);  	}  	mutex_unlock(&local->sta_mtx); +	/* +	 * if we want to get out of ps before disassoc (why?) we have +	 * to do it before sending disassoc, as otherwise the null-packet +	 * won't be valid. +	 */ +	if (local->hw.conf.flags & IEEE80211_CONF_PS) { +		local->hw.conf.flags &= ~IEEE80211_CONF_PS; +		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); +	} +	local->ps_sdata = NULL; + +	/* flush out any pending frame (e.g. DELBA) before deauth/disassoc */ +	if (tx) +		drv_flush(local, false); +  	/* deauthenticate/disassociate now */  	if (tx || frame_buf) -		ieee80211_send_deauth_disassoc(sdata, bssid, stype, reason, -					       tx, frame_buf); +		ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype, +					       reason, tx, frame_buf);  	/* flush out frame */  	if (tx)  		drv_flush(local, false); +	/* clear bssid only after building the needed mgmt frames */ +	memset(ifmgd->bssid, 0, ETH_ALEN); +  	/* remove AP and TDLS peers */  	sta_info_flush(local, sdata); @@ -1395,12 +1406,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,  	del_timer_sync(&local->dynamic_ps_timer);  	cancel_work_sync(&local->dynamic_ps_enable_work); -	if (local->hw.conf.flags & IEEE80211_CONF_PS) { -		local->hw.conf.flags &= ~IEEE80211_CONF_PS; -		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); -	} -	local->ps_sdata = NULL; -  	/* Disable ARP filtering */  	if (sdata->vif.bss_conf.arp_filter_enabled) {  		sdata->vif.bss_conf.arp_filter_enabled = false; @@ -1456,8 +1461,7 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)  		return;  	} -	ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | -			  IEEE80211_STA_BEACON_POLL); +	__ieee80211_stop_poll(sdata);  	mutex_lock(&local->iflist_mtx);  	ieee80211_recalc_ps(local, -1); @@ -1477,7 +1481,6 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)  		  round_jiffies_up(jiffies +  				   IEEE80211_CONNECTION_IDLE_TIME));  out: -	ieee80211_run_deferred_scan(local);  	mutex_unlock(&local->mtx);  } @@ -1522,6 +1525,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)  	 * anymore. The timeout will be reset if the frame is ACKed by  	 * the AP.  	 */ +	ifmgd->probe_send_count++; +  	if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {  		ifmgd->nullfunc_failed = false;  		ieee80211_send_nullfunc(sdata->local, sdata, 0); @@ -1538,7 +1543,6 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)  					 0, (u32) -1, true, false);  	} -	ifmgd->probe_send_count++;  	ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);  	run_again(ifmgd, ifmgd->probe_timeout);  	if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) @@ -1566,11 +1570,12 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,  		goto out;  	} -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG  	if (beacon) -		net_dbg_ratelimited("%s: detected beacon loss from AP - sending probe request\n", -				    sdata->name); -#endif +		mlme_dbg_ratelimited(sdata, +				     "detected beacon loss from AP - sending probe request\n"); + +	ieee80211_cqm_rssi_notify(&sdata->vif, +		NL80211_CQM_RSSI_BEACON_LOSS_EVENT, GFP_KERNEL);  	/*  	 * The driver/our work has already reported this event or the @@ -1612,6 +1617,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,  {  	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);  	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; +	struct cfg80211_bss *cbss;  	struct sk_buff *skb;  	const u8 *ssid;  	int ssid_len; @@ -1621,16 +1627,22 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,  	ASSERT_MGD_MTX(ifmgd); -	if (!ifmgd->associated) +	if (ifmgd->associated) +		cbss = ifmgd->associated; +	else if (ifmgd->auth_data) +		cbss = ifmgd->auth_data->bss; +	else if (ifmgd->assoc_data) +		cbss = ifmgd->assoc_data->bss; +	else  		return NULL; -	ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); +	ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID);  	if (WARN_ON_ONCE(ssid == NULL))  		ssid_len = 0;  	else  		ssid_len = ssid[1]; -	skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, +	skb = ieee80211_build_probe_req(sdata, cbss->bssid,  					(u32) -1, ssid + 2, ssid_len,  					NULL, 0, true); @@ -1653,8 +1665,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)  	memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); -	printk(KERN_DEBUG "%s: Connection to AP %pM lost.\n", -	       sdata->name, bssid); +	sdata_info(sdata, "Connection to AP %pM lost\n", bssid);  	ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,  			       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, @@ -1750,6 +1761,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,  	if (!elems.challenge)  		return;  	auth_data->expected_transaction = 4; +	drv_mgd_prepare_tx(sdata->local, sdata);  	ieee80211_send_auth(sdata, 3, auth_data->algorithm,  			    elems.challenge - 2, elems.challenge_len + 2,  			    auth_data->bss->bssid, auth_data->bss->bssid, @@ -1788,9 +1800,10 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,  		return RX_MGMT_NONE;  	if (status_code != WLAN_STATUS_SUCCESS) { -		printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n", -		       sdata->name, mgmt->sa, status_code); -		goto out; +		sdata_info(sdata, "%pM denied authentication (status %d)\n", +			   mgmt->sa, status_code); +		ieee80211_destroy_auth_data(sdata, false); +		return RX_MGMT_CFG80211_RX_AUTH;  	}  	switch (ifmgd->auth_data->algorithm) { @@ -1811,8 +1824,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,  		return RX_MGMT_NONE;  	} -	printk(KERN_DEBUG "%s: authenticated\n", sdata->name); - out: +	sdata_info(sdata, "authenticated\n");  	ifmgd->auth_data->done = true;  	ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC;  	run_again(ifmgd, ifmgd->auth_data->timeout); @@ -1825,8 +1837,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,  		goto out_err;  	}  	if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) { -		printk(KERN_DEBUG "%s: failed moving %pM to auth\n", -		       sdata->name, bssid); +		sdata_info(sdata, "failed moving %pM to auth\n", bssid);  		goto out_err;  	}  	mutex_unlock(&sdata->local->sta_mtx); @@ -1860,8 +1871,8 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,  	reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); -	printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", -			sdata->name, bssid, reason_code); +	sdata_info(sdata, "deauthenticated from %pM (Reason: %u)\n", +		   bssid, reason_code);  	ieee80211_set_disassoc(sdata, 0, 0, false, NULL); @@ -1891,8 +1902,8 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,  	reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); -	printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", -			sdata->name, mgmt->sa, reason_code); +	sdata_info(sdata, "disassociated from %pM (Reason: %u)\n", +		   mgmt->sa, reason_code);  	ieee80211_set_disassoc(sdata, 0, 0, false, NULL); @@ -1984,17 +1995,15 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,  	capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);  	if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) -		printk(KERN_DEBUG -		       "%s: invalid AID value 0x%x; bits 15:14 not set\n", -		       sdata->name, aid); +		sdata_info(sdata, "invalid AID value 0x%x; bits 15:14 not set\n", +			   aid);  	aid &= ~(BIT(15) | BIT(14));  	ifmgd->broken_ap = false;  	if (aid == 0 || aid > IEEE80211_MAX_AID) { -		printk(KERN_DEBUG -		       "%s: invalid AID value %d (out of range), turn off PS\n", -		       sdata->name, aid); +		sdata_info(sdata, "invalid AID value %d (out of range), turn off PS\n", +			   aid);  		aid = 0;  		ifmgd->broken_ap = true;  	} @@ -2003,8 +2012,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,  	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);  	if (!elems.supp_rates) { -		printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", -		       sdata->name); +		sdata_info(sdata, "no SuppRates element in AssocResp\n");  		return false;  	} @@ -2044,9 +2052,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,  	if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))  		err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);  	if (err) { -		printk(KERN_DEBUG -		       "%s: failed to move station %pM to desired state\n", -		       sdata->name, sta->sta.addr); +		sdata_info(sdata, +			   "failed to move station %pM to desired state\n", +			   sta->sta.addr);  		WARN_ON(__sta_info_destroy(sta));  		mutex_unlock(&sdata->local->sta_mtx);  		return false; @@ -2129,10 +2137,10 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,  	status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);  	aid = le16_to_cpu(mgmt->u.assoc_resp.aid); -	printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " -	       "status=%d aid=%d)\n", -	       sdata->name, reassoc ? "Rea" : "A", mgmt->sa, -	       capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); +	sdata_info(sdata, +		   "RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n", +		   reassoc ? "Rea" : "A", mgmt->sa, +		   capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));  	pos = mgmt->u.assoc_resp.variable;  	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); @@ -2143,9 +2151,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,  		u32 tu, ms;  		tu = get_unaligned_le32(elems.timeout_int + 1);  		ms = tu * 1024 / 1000; -		printk(KERN_DEBUG "%s: %pM rejected association temporarily; " -		       "comeback duration %u TU (%u ms)\n", -		       sdata->name, mgmt->sa, tu, ms); +		sdata_info(sdata, +			   "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n", +			   mgmt->sa, tu, ms);  		assoc_data->timeout = jiffies + msecs_to_jiffies(ms);  		if (ms > IEEE80211_ASSOC_TIMEOUT)  			run_again(ifmgd, assoc_data->timeout); @@ -2155,19 +2163,17 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,  	*bss = assoc_data->bss;  	if (status_code != WLAN_STATUS_SUCCESS) { -		printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n", -		       sdata->name, mgmt->sa, status_code); +		sdata_info(sdata, "%pM denied association (code=%d)\n", +			   mgmt->sa, status_code);  		ieee80211_destroy_assoc_data(sdata, false);  	} else { -		printk(KERN_DEBUG "%s: associated\n", sdata->name); -  		if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {  			/* oops -- internal error -- send timeout for now */ -			ieee80211_destroy_assoc_data(sdata, true); -			sta_info_destroy_addr(sdata, mgmt->bssid); +			ieee80211_destroy_assoc_data(sdata, false);  			cfg80211_put_bss(*bss);  			return RX_MGMT_CFG80211_ASSOC_TIMEOUT;  		} +		sdata_info(sdata, "associated\n");  		/*  		 * destroy assoc_data afterwards, as otherwise an idle @@ -2267,7 +2273,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,  	if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies &&  	    ether_addr_equal(mgmt->bssid, ifmgd->auth_data->bss->bssid)) {  		/* got probe response, continue with auth */ -		printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name); +		sdata_info(sdata, "direct probe responded\n");  		ifmgd->auth_data->tries = 0;  		ifmgd->auth_data->timeout = jiffies;  		run_again(ifmgd, ifmgd->auth_data->timeout); @@ -2403,11 +2409,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,  	}  	if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -		net_dbg_ratelimited("%s: cancelling probereq poll due to a received beacon\n", -				    sdata->name); -#endif +		mlme_dbg_ratelimited(sdata, +				     "cancelling probereq poll due to a received beacon\n"); +		mutex_lock(&local->mtx);  		ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL; +		ieee80211_run_deferred_scan(local); +		mutex_unlock(&local->mtx); +  		mutex_lock(&local->iflist_mtx);  		ieee80211_recalc_ps(local, -1);  		mutex_unlock(&local->iflist_mtx); @@ -2428,14 +2436,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,  		directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len,  						   ifmgd->aid); -	if (ncrc != ifmgd->beacon_crc || !ifmgd->beacon_crc_valid) { -		ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, -				      true); - -		ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, -					 elems.wmm_param_len); -	} -  	if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {  		if (directed_tim) {  			if (local->hw.conf.dynamic_ps_timeout > 0) { @@ -2466,6 +2466,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,  	ifmgd->beacon_crc = ncrc;  	ifmgd->beacon_crc_valid = true; +	ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, +			      true); + +	if (ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, +				     elems.wmm_param_len)) +		changed |= BSS_CHANGED_QOS; +  	if (elems.erp_info && elems.erp_info_len >= 1) {  		erp_valid = true;  		erp_value = elems.erp_info[0]; @@ -2594,9 +2601,6 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,  	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;  	u8 frame_buf[DEAUTH_DISASSOC_LEN]; -	ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | -			  IEEE80211_STA_BEACON_POLL); -  	ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason,  			       false, frame_buf);  	mutex_unlock(&ifmgd->mtx); @@ -2628,8 +2632,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)  	auth_data->tries++;  	if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { -		printk(KERN_DEBUG "%s: authentication with %pM timed out\n", -		       sdata->name, auth_data->bss->bssid); +		sdata_info(sdata, "authentication with %pM timed out\n", +			   auth_data->bss->bssid);  		/*  		 * Most likely AP is not in the range so remove the @@ -2640,10 +2644,12 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)  		return -ETIMEDOUT;  	} +	drv_mgd_prepare_tx(local, sdata); +  	if (auth_data->bss->proberesp_ies) { -		printk(KERN_DEBUG "%s: send auth to %pM (try %d/%d)\n", -		       sdata->name, auth_data->bss->bssid, auth_data->tries, -		       IEEE80211_AUTH_MAX_TRIES); +		sdata_info(sdata, "send auth to %pM (try %d/%d)\n", +			   auth_data->bss->bssid, auth_data->tries, +			   IEEE80211_AUTH_MAX_TRIES);  		auth_data->expected_transaction = 2;  		ieee80211_send_auth(sdata, 1, auth_data->algorithm, @@ -2653,9 +2659,9 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)  	} else {  		const u8 *ssidie; -		printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n", -		       sdata->name, auth_data->bss->bssid, auth_data->tries, -		       IEEE80211_AUTH_MAX_TRIES); +		sdata_info(sdata, "direct probe to %pM (try %d/%i)\n", +			   auth_data->bss->bssid, auth_data->tries, +			   IEEE80211_AUTH_MAX_TRIES);  		ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID);  		if (!ssidie) @@ -2683,8 +2689,8 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)  	assoc_data->tries++;  	if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) { -		printk(KERN_DEBUG "%s: association with %pM timed out\n", -		       sdata->name, assoc_data->bss->bssid); +		sdata_info(sdata, "association with %pM timed out\n", +			   assoc_data->bss->bssid);  		/*  		 * Most likely AP is not in the range so remove the @@ -2695,9 +2701,9 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)  		return -ETIMEDOUT;  	} -	printk(KERN_DEBUG "%s: associate with %pM (try %d/%d)\n", -	       sdata->name, assoc_data->bss->bssid, assoc_data->tries, -	       IEEE80211_ASSOC_MAX_TRIES); +	sdata_info(sdata, "associate with %pM (try %d/%d)\n", +		   assoc_data->bss->bssid, assoc_data->tries, +		   IEEE80211_ASSOC_MAX_TRIES);  	ieee80211_send_assoc(sdata);  	assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; @@ -2770,45 +2776,31 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)  			ieee80211_reset_ap_probe(sdata);  		else if (ifmgd->nullfunc_failed) {  			if (ifmgd->probe_send_count < max_tries) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -				wiphy_debug(local->hw.wiphy, -					    "%s: No ack for nullfunc frame to" -					    " AP %pM, try %d/%i\n", -					    sdata->name, bssid, -					    ifmgd->probe_send_count, max_tries); -#endif +				mlme_dbg(sdata, +					 "No ack for nullfunc frame to AP %pM, try %d/%i\n", +					 bssid, ifmgd->probe_send_count, +					 max_tries);  				ieee80211_mgd_probe_ap_send(sdata);  			} else { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -				wiphy_debug(local->hw.wiphy, -					    "%s: No ack for nullfunc frame to" -					    " AP %pM, disconnecting.\n", -					    sdata->name, bssid); -#endif +				mlme_dbg(sdata, +					 "No ack for nullfunc frame to AP %pM, disconnecting.\n", +					 bssid);  				ieee80211_sta_connection_lost(sdata, bssid,  					WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);  			}  		} else if (time_is_after_jiffies(ifmgd->probe_timeout))  			run_again(ifmgd, ifmgd->probe_timeout);  		else if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -			wiphy_debug(local->hw.wiphy, -				    "%s: Failed to send nullfunc to AP %pM" -				    " after %dms, disconnecting.\n", -				    sdata->name, -				    bssid, probe_wait_ms); -#endif +			mlme_dbg(sdata, +				 "Failed to send nullfunc to AP %pM after %dms, disconnecting\n", +				 bssid, probe_wait_ms);  			ieee80211_sta_connection_lost(sdata, bssid,  				WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);  		} else if (ifmgd->probe_send_count < max_tries) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -			wiphy_debug(local->hw.wiphy, -				    "%s: No probe response from AP %pM" -				    " after %dms, try %d/%i\n", -				    sdata->name, -				    bssid, probe_wait_ms, -				    ifmgd->probe_send_count, max_tries); -#endif +			mlme_dbg(sdata, +				 "No probe response from AP %pM after %dms, try %d/%i\n", +				 bssid, probe_wait_ms, +				 ifmgd->probe_send_count, max_tries);  			ieee80211_mgd_probe_ap_send(sdata);  		} else {  			/* @@ -2873,8 +2865,7 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)  	u32 flags;  	if (sdata->vif.type == NL80211_IFTYPE_STATION) { -		sdata->u.mgd.flags &= ~(IEEE80211_STA_BEACON_POLL | -					IEEE80211_STA_CONNECTION_POLL); +		__ieee80211_stop_poll(sdata);  		/* let's probe the connection once */  		flags = sdata->local->hw.flags; @@ -2924,11 +2915,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)  		sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;  		mutex_lock(&ifmgd->mtx);  		if (ifmgd->associated) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -			wiphy_debug(sdata->local->hw.wiphy, -				    "%s: driver requested disconnect after resume.\n", -				    sdata->name); -#endif +			mlme_dbg(sdata, +				 "driver requested disconnect after resume\n");  			ieee80211_sta_connection_lost(sdata,  				ifmgd->associated->bssid,  				WLAN_REASON_UNSPECIFIED); @@ -2943,7 +2931,10 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)  	if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running))  		add_timer(&ifmgd->chswitch_timer);  	ieee80211_sta_reset_beacon_monitor(sdata); + +	mutex_lock(&sdata->local->mtx);  	ieee80211_restart_sta_timer(sdata); +	mutex_unlock(&sdata->local->mtx);  }  #endif @@ -2983,7 +2974,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)  /* scan finished notification */  void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)  { -	struct ieee80211_sub_if_data *sdata = local->scan_sdata; +	struct ieee80211_sub_if_data *sdata;  	/* Restart STA timers */  	rcu_read_lock(); @@ -3013,7 +3004,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,  	struct ieee80211_local *local = sdata->local;  	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;  	struct ieee80211_bss *bss = (void *)cbss->priv; -	struct sta_info *sta; +	struct sta_info *sta = NULL;  	bool have_sta = false;  	int err;  	int ht_cfreq; @@ -3066,13 +3057,11 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,  			 * since we look at probe response/beacon data here  			 * it should be OK.  			 */ -			printk(KERN_DEBUG -			       "%s: Wrong control channel: center-freq: %d" -			       " ht-cfreq: %d ht->primary_chan: %d" -			       " band: %d. Disabling HT.\n", -			       sdata->name, cbss->channel->center_freq, -			       ht_cfreq, ht_oper->primary_chan, -			       cbss->channel->band); +			sdata_info(sdata, +				   "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", +				   cbss->channel->center_freq, +				   ht_cfreq, ht_oper->primary_chan, +				   cbss->channel->band);  			ht_oper = NULL;  		}  	} @@ -3096,18 +3085,17 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,  	if (!ieee80211_set_channel_type(local, sdata, channel_type)) {  		/* can only fail due to HT40+/- mismatch */  		channel_type = NL80211_CHAN_HT20; -		printk(KERN_DEBUG -		       "%s: disabling 40 MHz due to multi-vif mismatch\n", -		       sdata->name); +		sdata_info(sdata, +			   "disabling 40 MHz due to multi-vif mismatch\n");  		ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;  		WARN_ON(!ieee80211_set_channel_type(local, sdata,  						    channel_type));  	}  	local->oper_channel = cbss->channel; -	ieee80211_hw_config(local, 0); +	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); -	if (!have_sta) { +	if (sta) {  		u32 rates = 0, basic_rates = 0;  		bool have_higher_than_11mbit;  		int min_rate = INT_MAX, min_rate_index = -1; @@ -3127,9 +3115,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,  		 * we can connect -- with a warning.  		 */  		if (!basic_rates && min_rate_index >= 0) { -			printk(KERN_DEBUG -			       "%s: No basic rates, using min rate instead.\n", -			       sdata->name); +			sdata_info(sdata, +				   "No basic rates, using min rate instead\n");  			basic_rates = BIT(min_rate_index);  		} @@ -3145,9 +3132,15 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,  		memcpy(ifmgd->bssid, cbss->bssid, ETH_ALEN); -		/* tell driver about BSSID and basic rates */ +		/* set timing information */ +		sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; +		sdata->vif.bss_conf.sync_tsf = cbss->tsf; +		sdata->vif.bss_conf.sync_device_ts = bss->device_ts; + +		/* tell driver about BSSID, basic rates and timing */  		ieee80211_bss_info_change_notify(sdata, -			BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES); +			BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES | +			BSS_CHANGED_BEACON_INT);  		if (assoc)  			sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); @@ -3155,9 +3148,9 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,  		err = sta_info_insert(sta);  		sta = NULL;  		if (err) { -			printk(KERN_DEBUG -			       "%s: failed to insert STA entry for the AP (error %d)\n", -			       sdata->name, err); +			sdata_info(sdata, +				   "failed to insert STA entry for the AP (error %d)\n", +				   err);  			return err;  		}  	} else @@ -3235,8 +3228,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,  	if (ifmgd->associated)  		ieee80211_set_disassoc(sdata, 0, 0, false, NULL); -	printk(KERN_DEBUG "%s: authenticate with %pM\n", -	       sdata->name, req->bss->bssid); +	sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);  	err = ieee80211_prep_connection(sdata, req->bss, false);  	if (err) @@ -3271,7 +3263,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,  	struct ieee80211_bss *bss = (void *)req->bss->priv;  	struct ieee80211_mgd_assoc_data *assoc_data;  	struct ieee80211_supported_band *sband; -	const u8 *ssidie; +	const u8 *ssidie, *ht_ie;  	int i, err;  	ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); @@ -3319,11 +3311,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,  	 * We can set this to true for non-11n hardware, that'll be checked  	 * separately along with the peer capabilities.  	 */ -	for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) +	for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) {  		if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||  		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || -		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) +		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) {  			ifmgd->flags |= IEEE80211_STA_DISABLE_11N; +			netdev_info(sdata->dev, +				    "disabling HT due to WEP/TKIP use\n"); +		} +	}  	if (req->flags & ASSOC_REQ_DISABLE_HT)  		ifmgd->flags |= IEEE80211_STA_DISABLE_11N; @@ -3331,8 +3327,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,  	/* Also disable HT if we don't support it or the AP doesn't use WMM */  	sband = local->hw.wiphy->bands[req->bss->channel->band];  	if (!sband->ht_cap.ht_supported || -	    local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) +	    local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) {  		ifmgd->flags |= IEEE80211_STA_DISABLE_11N; +		netdev_info(sdata->dev, +			    "disabling HT as WMM/QoS is not supported\n"); +	}  	memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));  	memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, @@ -3358,8 +3357,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,  			  (local->hw.queues >= IEEE80211_NUM_ACS);  	assoc_data->supp_rates = bss->supp_rates;  	assoc_data->supp_rates_len = bss->supp_rates_len; -	assoc_data->ht_operation_ie = -		ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION); + +	ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION); +	if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation)) +		assoc_data->ap_ht_param = +			((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param; +	else +		ifmgd->flags |= IEEE80211_STA_DISABLE_11N;  	if (bss->wmm_used && bss->uapsd_supported &&  	    (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { @@ -3406,8 +3410,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,  		 * Wait up to one beacon interval ...  		 * should this be more if we miss one?  		 */ -		printk(KERN_DEBUG "%s: waiting for beacon from %pM\n", -		       sdata->name, ifmgd->bssid); +		sdata_info(sdata, "waiting for beacon from %pM\n", +			   ifmgd->bssid);  		assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval);  	} else {  		assoc_data->have_beacon = true; @@ -3426,8 +3430,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,  				corrupt_type = "beacon";  		} else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP)  			corrupt_type = "probe response"; -		printk(KERN_DEBUG "%s: associating with AP with corrupt %s\n", -		       sdata->name, corrupt_type); +		sdata_info(sdata, "associating with AP with corrupt %s\n", +			   corrupt_type);  	}  	err = 0; @@ -3456,9 +3460,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,  		return 0;  	} -	printk(KERN_DEBUG -	       "%s: deauthenticating from %pM by local choice (reason=%d)\n", -	       sdata->name, req->bssid, req->reason_code); +	sdata_info(sdata, +		   "deauthenticating from %pM by local choice (reason=%d)\n", +		   req->bssid, req->reason_code);  	if (ifmgd->associated &&  	    ether_addr_equal(ifmgd->associated->bssid, req->bssid)) @@ -3500,8 +3504,9 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,  		return -ENOLINK;  	} -	printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n", -	       sdata->name, req->bss->bssid, req->reason_code); +	sdata_info(sdata, +		   "disassociating from %pM by local choice (reason=%d)\n", +		   req->bss->bssid, req->reason_code);  	memcpy(bssid, req->bss->bssid, ETH_ALEN);  	ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC, @@ -3542,10 +3547,3 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,  	cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);  }  EXPORT_SYMBOL(ieee80211_cqm_rssi_notify); - -unsigned char ieee80211_get_operstate(struct ieee80211_vif *vif) -{ -	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); -	return sdata->dev->operstate; -} -EXPORT_SYMBOL(ieee80211_get_operstate); diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index f054e94901a..635c3250c66 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -15,7 +15,7 @@  #include <linux/export.h>  #include <net/mac80211.h>  #include "ieee80211_i.h" -#include "driver-trace.h" +#include "driver-ops.h"  /*   * Tell our hardware to disable PS. @@ -24,8 +24,7 @@   * because we *may* be doing work on-operating channel, and want our   * hardware unconditionally awake, but still let the AP send us normal frames.   */ -static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata, -					   bool tell_ap) +static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)  {  	struct ieee80211_local *local = sdata->local;  	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -46,8 +45,8 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata,  		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);  	} -	if (tell_ap && (!local->offchannel_ps_enabled || -			!(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))) +	if (!local->offchannel_ps_enabled || +	    !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))  		/*  		 * If power save was enabled, no need to send a nullfunc  		 * frame because AP knows that we are sleeping. But if the @@ -132,7 +131,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,  			if (offchannel_ps_enable &&  			    (sdata->vif.type == NL80211_IFTYPE_STATION) &&  			    sdata->u.mgd.associated) -				ieee80211_offchannel_ps_enable(sdata, true); +				ieee80211_offchannel_ps_enable(sdata);  		}  	}  	mutex_unlock(&local->iflist_mtx); @@ -181,34 +180,58 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,  	mutex_unlock(&local->iflist_mtx);  } +void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) +{ +	if (roc->notified) +		return; + +	if (roc->mgmt_tx_cookie) { +		if (!WARN_ON(!roc->frame)) { +			ieee80211_tx_skb(roc->sdata, roc->frame); +			roc->frame = NULL; +		} +	} else { +		cfg80211_ready_on_channel(&roc->sdata->wdev, (unsigned long)roc, +					  roc->chan, roc->chan_type, +					  roc->req_duration, GFP_KERNEL); +	} + +	roc->notified = true; +} +  static void ieee80211_hw_roc_start(struct work_struct *work)  {  	struct ieee80211_local *local =  		container_of(work, struct ieee80211_local, hw_roc_start); -	struct ieee80211_sub_if_data *sdata; +	struct ieee80211_roc_work *roc, *dep, *tmp;  	mutex_lock(&local->mtx); -	if (!local->hw_roc_channel) { -		mutex_unlock(&local->mtx); -		return; -	} +	if (list_empty(&local->roc_list)) +		goto out_unlock; -	if (local->hw_roc_skb) { -		sdata = IEEE80211_DEV_TO_SUB_IF(local->hw_roc_dev); -		ieee80211_tx_skb(sdata, local->hw_roc_skb); -		local->hw_roc_skb = NULL; -	} else { -		cfg80211_ready_on_channel(local->hw_roc_dev, -					  local->hw_roc_cookie, -					  local->hw_roc_channel, -					  local->hw_roc_channel_type, -					  local->hw_roc_duration, -					  GFP_KERNEL); -	} +	roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work, +			       list); + +	if (!roc->started) +		goto out_unlock; + +	roc->hw_begun = true; +	roc->hw_start_time = local->hw_roc_start_time; -	ieee80211_recalc_idle(local); +	ieee80211_handle_roc_started(roc); +	list_for_each_entry_safe(dep, tmp, &roc->dependents, list) { +		ieee80211_handle_roc_started(dep); +		if (dep->duration > roc->duration) { +			u32 dur = dep->duration; +			dep->duration = dur - roc->duration; +			roc->duration = dur; +			list_del(&dep->list); +			list_add(&dep->list, &roc->list); +		} +	} + out_unlock:  	mutex_unlock(&local->mtx);  } @@ -216,36 +239,181 @@ void ieee80211_ready_on_channel(struct ieee80211_hw *hw)  {  	struct ieee80211_local *local = hw_to_local(hw); +	local->hw_roc_start_time = jiffies; +  	trace_api_ready_on_channel(local);  	ieee80211_queue_work(hw, &local->hw_roc_start);  }  EXPORT_SYMBOL_GPL(ieee80211_ready_on_channel); +void ieee80211_start_next_roc(struct ieee80211_local *local) +{ +	struct ieee80211_roc_work *roc; + +	lockdep_assert_held(&local->mtx); + +	if (list_empty(&local->roc_list)) { +		ieee80211_run_deferred_scan(local); +		return; +	} + +	roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work, +			       list); + +	if (WARN_ON_ONCE(roc->started)) +		return; + +	if (local->ops->remain_on_channel) { +		int ret, duration = roc->duration; + +		/* XXX: duplicated, see ieee80211_start_roc_work() */ +		if (!duration) +			duration = 10; + +		ret = drv_remain_on_channel(local, roc->chan, +					    roc->chan_type, +					    duration); + +		roc->started = true; + +		if (ret) { +			wiphy_warn(local->hw.wiphy, +				   "failed to start next HW ROC (%d)\n", ret); +			/* +			 * queue the work struct again to avoid recursion +			 * when multiple failures occur +			 */ +			ieee80211_remain_on_channel_expired(&local->hw); +		} +	} else { +		/* delay it a bit */ +		ieee80211_queue_delayed_work(&local->hw, &roc->work, +					     round_jiffies_relative(HZ/2)); +	} +} + +void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) +{ +	struct ieee80211_roc_work *dep, *tmp; + +	/* was never transmitted */ +	if (roc->frame) { +		cfg80211_mgmt_tx_status(&roc->sdata->wdev, +					(unsigned long)roc->frame, +					roc->frame->data, roc->frame->len, +					false, GFP_KERNEL); +		kfree_skb(roc->frame); +	} + +	if (!roc->mgmt_tx_cookie) +		cfg80211_remain_on_channel_expired(&roc->sdata->wdev, +						   (unsigned long)roc, +						   roc->chan, roc->chan_type, +						   GFP_KERNEL); + +	list_for_each_entry_safe(dep, tmp, &roc->dependents, list) +		ieee80211_roc_notify_destroy(dep); + +	kfree(roc); +} + +void ieee80211_sw_roc_work(struct work_struct *work) +{ +	struct ieee80211_roc_work *roc = +		container_of(work, struct ieee80211_roc_work, work.work); +	struct ieee80211_sub_if_data *sdata = roc->sdata; +	struct ieee80211_local *local = sdata->local; +	bool started; + +	mutex_lock(&local->mtx); + +	if (roc->abort) +		goto finish; + +	if (WARN_ON(list_empty(&local->roc_list))) +		goto out_unlock; + +	if (WARN_ON(roc != list_first_entry(&local->roc_list, +					    struct ieee80211_roc_work, +					    list))) +		goto out_unlock; + +	if (!roc->started) { +		struct ieee80211_roc_work *dep; + +		/* start this ROC */ + +		/* switch channel etc */ +		ieee80211_recalc_idle(local); + +		local->tmp_channel = roc->chan; +		local->tmp_channel_type = roc->chan_type; +		ieee80211_hw_config(local, 0); + +		/* tell userspace or send frame */ +		ieee80211_handle_roc_started(roc); +		list_for_each_entry(dep, &roc->dependents, list) +			ieee80211_handle_roc_started(dep); + +		/* if it was pure TX, just finish right away */ +		if (!roc->duration) +			goto finish; + +		roc->started = true; +		ieee80211_queue_delayed_work(&local->hw, &roc->work, +					     msecs_to_jiffies(roc->duration)); +	} else { +		/* finish this ROC */ + finish: +		list_del(&roc->list); +		started = roc->started; +		ieee80211_roc_notify_destroy(roc); + +		if (started) { +			drv_flush(local, false); + +			local->tmp_channel = NULL; +			ieee80211_hw_config(local, 0); + +			ieee80211_offchannel_return(local, true); +		} + +		ieee80211_recalc_idle(local); + +		if (started) +			ieee80211_start_next_roc(local); +	} + + out_unlock: +	mutex_unlock(&local->mtx); +} +  static void ieee80211_hw_roc_done(struct work_struct *work)  {  	struct ieee80211_local *local =  		container_of(work, struct ieee80211_local, hw_roc_done); +	struct ieee80211_roc_work *roc;  	mutex_lock(&local->mtx); -	if (!local->hw_roc_channel) { -		mutex_unlock(&local->mtx); -		return; -	} +	if (list_empty(&local->roc_list)) +		goto out_unlock; -	if (!local->hw_roc_for_tx) -		cfg80211_remain_on_channel_expired(local->hw_roc_dev, -						   local->hw_roc_cookie, -						   local->hw_roc_channel, -						   local->hw_roc_channel_type, -						   GFP_KERNEL); +	roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work, +			       list); + +	if (!roc->started) +		goto out_unlock; + +	list_del(&roc->list); -	local->hw_roc_channel = NULL; -	local->hw_roc_cookie = 0; +	ieee80211_roc_notify_destroy(roc); -	ieee80211_recalc_idle(local); +	/* if there's another roc, start it now */ +	ieee80211_start_next_roc(local); + out_unlock:  	mutex_unlock(&local->mtx);  } @@ -259,8 +427,47 @@ void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw)  }  EXPORT_SYMBOL_GPL(ieee80211_remain_on_channel_expired); -void ieee80211_hw_roc_setup(struct ieee80211_local *local) +void ieee80211_roc_setup(struct ieee80211_local *local)  {  	INIT_WORK(&local->hw_roc_start, ieee80211_hw_roc_start);  	INIT_WORK(&local->hw_roc_done, ieee80211_hw_roc_done); +	INIT_LIST_HEAD(&local->roc_list); +} + +void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata) +{ +	struct ieee80211_local *local = sdata->local; +	struct ieee80211_roc_work *roc, *tmp; +	LIST_HEAD(tmp_list); + +	mutex_lock(&local->mtx); +	list_for_each_entry_safe(roc, tmp, &local->roc_list, list) { +		if (roc->sdata != sdata) +			continue; + +		if (roc->started && local->ops->remain_on_channel) { +			/* can race, so ignore return value */ +			drv_cancel_remain_on_channel(local); +		} + +		list_move_tail(&roc->list, &tmp_list); +		roc->abort = true; +	} + +	ieee80211_start_next_roc(local); +	mutex_unlock(&local->mtx); + +	list_for_each_entry_safe(roc, tmp, &tmp_list, list) { +		if (local->ops->remain_on_channel) { +			list_del(&roc->list); +			ieee80211_roc_notify_destroy(roc); +		} else { +			ieee80211_queue_delayed_work(&local->hw, &roc->work, 0); + +			/* work will clean up etc */ +			flush_delayed_work(&roc->work); +		} +	} + +	WARN_ON_ONCE(!list_empty(&tmp_list));  } diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index af1c4e26e96..5c572e7a1a7 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -77,6 +77,17 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)  		int err = drv_suspend(local, wowlan);  		if (err < 0) {  			local->quiescing = false; +			local->wowlan = false; +			if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { +				mutex_lock(&local->sta_mtx); +				list_for_each_entry(sta, +						    &local->sta_list, list) { +					clear_sta_flag(sta, WLAN_STA_BLOCK_BA); +				} +				mutex_unlock(&local->sta_mtx); +			} +			ieee80211_wake_queues_by_reason(hw, +					IEEE80211_QUEUE_STOP_REASON_SUSPEND);  			return err;  		} else if (err > 0) {  			WARN_ON(err != 1); diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 2d1acc6c544..fb1d4aa65e8 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -626,8 +626,12 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,  #ifdef CONFIG_MAC80211_DEBUGFS  	/* use fixed index if set */ -	if (mp->fixed_rate_idx != -1) -		sample_idx = mp->fixed_rate_idx; +	if (mp->fixed_rate_idx != -1) { +		mi->max_tp_rate = mp->fixed_rate_idx; +		mi->max_tp_rate2 = mp->fixed_rate_idx; +		mi->max_prob_rate = mp->fixed_rate_idx; +		sample_idx = -1; +	}  #endif  	if (sample_idx >= 0) { @@ -809,7 +813,7 @@ minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)  			max_rates = sband->n_bitrates;  	} -	msp = kzalloc(sizeof(struct minstrel_ht_sta), gfp); +	msp = kzalloc(sizeof(*msp), gfp);  	if (!msp)  		return NULL; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7bcecf73aaf..0cb4edee6af 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -94,7 +94,7 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local,  	return len;  } -/* +/**   * ieee80211_add_rx_radiotap_header - add radiotap header   *   * add a radiotap header containing all the fields which the hardware provided. @@ -413,29 +413,6 @@ static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx)  /* rx handlers */ -static ieee80211_rx_result debug_noinline -ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) -{ -	struct ieee80211_local *local = rx->local; -	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); -	struct sk_buff *skb = rx->skb; - -	if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN) && -		   !local->sched_scanning)) -		return RX_CONTINUE; - -	if (test_bit(SCAN_HW_SCANNING, &local->scanning) || -	    test_bit(SCAN_SW_SCANNING, &local->scanning) || -	    test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || -	    local->sched_scanning) -		return ieee80211_scan_rx(rx->sdata, skb); - -	/* scanning finished during invoking of handlers */ -	I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); -	return RX_DROP_UNUSABLE; -} - -  static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb)  {  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -554,11 +531,11 @@ static inline u16 seq_sub(u16 sq1, u16 sq2)  } -static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, +static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,  					    struct tid_ampdu_rx *tid_agg_rx,  					    int index)  { -	struct ieee80211_local *local = hw_to_local(hw); +	struct ieee80211_local *local = sdata->local;  	struct sk_buff *skb = tid_agg_rx->reorder_buf[index];  	struct ieee80211_rx_status *status; @@ -578,7 +555,7 @@ no_frame:  	tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);  } -static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, +static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata,  					     struct tid_ampdu_rx *tid_agg_rx,  					     u16 head_seq_num)  { @@ -589,7 +566,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,  	while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {  		index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %  							tid_agg_rx->buf_size; -		ieee80211_release_reorder_frame(hw, tid_agg_rx, index); +		ieee80211_release_reorder_frame(sdata, tid_agg_rx, index);  	}  } @@ -604,7 +581,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,   */  #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) -static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, +static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,  					  struct tid_ampdu_rx *tid_agg_rx)  {  	int index, j; @@ -632,12 +609,9 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,  					HT_RX_REORDER_BUF_TIMEOUT))  				goto set_release_timer; -#ifdef CONFIG_MAC80211_HT_DEBUG -			if (net_ratelimit()) -				wiphy_debug(hw->wiphy, -					    "release an RX reorder frame due to timeout on earlier frames\n"); -#endif -			ieee80211_release_reorder_frame(hw, tid_agg_rx, j); +			ht_dbg_ratelimited(sdata, +					   "release an RX reorder frame due to timeout on earlier frames\n"); +			ieee80211_release_reorder_frame(sdata, tid_agg_rx, j);  			/*  			 * Increment the head seq# also for the skipped slots. @@ -647,7 +621,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,  			skipped = 0;  		}  	} else while (tid_agg_rx->reorder_buf[index]) { -		ieee80211_release_reorder_frame(hw, tid_agg_rx, index); +		ieee80211_release_reorder_frame(sdata, tid_agg_rx, index);  		index =	seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %  							tid_agg_rx->buf_size;  	} @@ -677,7 +651,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,   * rcu_read_lock protection. It returns false if the frame   * can be processed immediately, true if it was consumed.   */ -static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, +static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata,  					     struct tid_ampdu_rx *tid_agg_rx,  					     struct sk_buff *skb)  { @@ -706,7 +680,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,  	if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {  		head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));  		/* release stored frames up to new head to stack */ -		ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num); +		ieee80211_release_reorder_frames(sdata, tid_agg_rx, +						 head_seq_num);  	}  	/* Now the new frame is always in the range of the reordering buffer */ @@ -736,7 +711,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,  	tid_agg_rx->reorder_buf[index] = skb;  	tid_agg_rx->reorder_time[index] = jiffies;  	tid_agg_rx->stored_mpdu_num++; -	ieee80211_sta_reorder_release(hw, tid_agg_rx); +	ieee80211_sta_reorder_release(sdata, tid_agg_rx);   out:  	spin_unlock(&tid_agg_rx->reorder_lock); @@ -751,7 +726,6 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)  {  	struct sk_buff *skb = rx->skb;  	struct ieee80211_local *local = rx->local; -	struct ieee80211_hw *hw = &local->hw;  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;  	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);  	struct sta_info *sta = rx->sta; @@ -813,7 +787,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)  	 * sure that we cannot get to it any more before doing  	 * anything with it.  	 */ -	if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb)) +	if (ieee80211_sta_manage_reorder_buf(rx->sdata, tid_agg_rx, skb))  		return;   dont_reorder: @@ -1136,24 +1110,18 @@ static void ap_sta_ps_start(struct sta_info *sta)  	set_sta_flag(sta, WLAN_STA_PS_STA);  	if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))  		drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG -	printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", -	       sdata->name, sta->sta.addr, sta->sta.aid); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ +	ps_dbg(sdata, "STA %pM aid %d enters power save mode\n", +	       sta->sta.addr, sta->sta.aid);  }  static void ap_sta_ps_end(struct sta_info *sta)  { -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG -	printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n", -	       sta->sdata->name, sta->sta.addr, sta->sta.aid); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ +	ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n", +	       sta->sta.addr, sta->sta.aid);  	if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG -		printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n", -		       sta->sdata->name, sta->sta.addr, sta->sta.aid); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ +		ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n", +		       sta->sta.addr, sta->sta.aid);  		return;  	} @@ -1383,19 +1351,8 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,  	if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX)  		sdata->fragment_next = 0; -	if (!skb_queue_empty(&entry->skb_list)) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -		struct ieee80211_hdr *hdr = -			(struct ieee80211_hdr *) entry->skb_list.next->data; -		printk(KERN_DEBUG "%s: RX reassembly removed oldest " -		       "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " -		       "addr1=%pM addr2=%pM\n", -		       sdata->name, idx, -		       jiffies - entry->first_frag_time, entry->seq, -		       entry->last_frag, hdr->addr1, hdr->addr2); -#endif +	if (!skb_queue_empty(&entry->skb_list))  		__skb_queue_purge(&entry->skb_list); -	}  	__skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */  	*skb = NULL; @@ -1753,7 +1710,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)  			 */  			xmit_skb = skb_copy(skb, GFP_ATOMIC);  			if (!xmit_skb) -				net_dbg_ratelimited("%s: failed to clone multicast frame\n", +				net_info_ratelimited("%s: failed to clone multicast frame\n",  						    dev->name);  		} else {  			dsta = sta_info_get(sdata, skb->data); @@ -1937,7 +1894,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  	    ether_addr_equal(sdata->vif.addr, hdr->addr3))  		return RX_CONTINUE; -	q = ieee80211_select_queue_80211(local, skb, hdr); +	q = ieee80211_select_queue_80211(sdata, skb, hdr);  	if (ieee80211_queue_stopped(&local->hw, q)) {  		IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);  		return RX_DROP_MONITOR; @@ -1957,7 +1914,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  	fwd_skb = skb_copy(skb, GFP_ATOMIC);  	if (!fwd_skb) { -		net_dbg_ratelimited("%s: failed to clone mesh frame\n", +		net_info_ratelimited("%s: failed to clone mesh frame\n",  				    sdata->name);  		goto out;  	} @@ -2060,8 +2017,6 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)  static ieee80211_rx_result debug_noinline  ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)  { -	struct ieee80211_local *local = rx->local; -	struct ieee80211_hw *hw = &local->hw;  	struct sk_buff *skb = rx->skb;  	struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;  	struct tid_ampdu_rx *tid_agg_rx; @@ -2098,7 +2053,8 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)  		spin_lock(&tid_agg_rx->reorder_lock);  		/* release stored frames up to start of BAR */ -		ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num); +		ieee80211_release_reorder_frames(rx->sdata, tid_agg_rx, +						 start_seq_num);  		spin_unlock(&tid_agg_rx->reorder_lock);  		kfree_skb(skb); @@ -2425,7 +2381,7 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)  	if (rx->local->hw.flags & IEEE80211_HW_SIGNAL_DBM)  		sig = status->signal; -	if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq, sig, +	if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig,  			     rx->skb->data, rx->skb->len,  			     GFP_ATOMIC)) {  		if (rx->sta) @@ -2455,7 +2411,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)  	 * frames that we didn't handle, including returning unknown  	 * ones. For all other modes we will return them to the sender,  	 * setting the 0x80 bit in the action category, as required by -	 * 802.11-2007 7.3.1.11. +	 * 802.11-2012 9.24.4.  	 * Newer versions of hostapd shall also use the management frame  	 * registration mechanisms, but older ones still use cooked  	 * monitor interfaces so push all frames there. @@ -2465,6 +2421,9 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)  	     sdata->vif.type == NL80211_IFTYPE_AP_VLAN))  		return RX_DROP_MONITOR; +	if (is_multicast_ether_addr(mgmt->da)) +		return RX_DROP_MONITOR; +  	/* do not return rejected action frames */  	if (mgmt->u.action.category & 0x80)  		return RX_DROP_UNUSABLE; @@ -2713,7 +2672,6 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)  			goto rxh_next;  \  	} while (0); -	CALL_RXH(ieee80211_rx_h_passive_scan)  	CALL_RXH(ieee80211_rx_h_check)  	ieee80211_rx_reorder_ampdu(rx); @@ -2749,7 +2707,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)  		return;  	spin_lock(&tid_agg_rx->reorder_lock); -	ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx); +	ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx);  	spin_unlock(&tid_agg_rx->reorder_lock);  	ieee80211_rx_handlers(&rx); @@ -2783,11 +2741,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,  			return 0;  		if (ieee80211_is_beacon(hdr->frame_control)) {  			return 1; -		} -		else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { -			if (!(status->rx_flags & IEEE80211_RX_IN_SCAN)) -				return 0; -			status->rx_flags &= ~IEEE80211_RX_RA_MATCH; +		} else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { +			return 0;  		} else if (!multicast &&  			   !ether_addr_equal(sdata->vif.addr, hdr->addr1)) {  			if (!(sdata->dev->flags & IFF_PROMISC)) @@ -2825,11 +2780,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,  			 * and location updates. Note that mac80211  			 * itself never looks at these frames.  			 */ -			if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) && -			    ieee80211_is_public_action(hdr, skb->len)) +			if (ieee80211_is_public_action(hdr, skb->len))  				return 1; -			if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) && -			    !ieee80211_is_beacon(hdr->frame_control)) +			if (!ieee80211_is_beacon(hdr->frame_control))  				return 0;  			status->rx_flags &= ~IEEE80211_RX_RA_MATCH;  		} @@ -2895,7 +2848,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,  static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,  					 struct sk_buff *skb)  { -	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);  	struct ieee80211_local *local = hw_to_local(hw);  	struct ieee80211_sub_if_data *sdata;  	struct ieee80211_hdr *hdr; @@ -2913,11 +2865,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,  	if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))  		local->dot11ReceivedFragmentCount++; -	if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || -		     test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || -		     test_bit(SCAN_SW_SCANNING, &local->scanning))) -		status->rx_flags |= IEEE80211_RX_IN_SCAN; -  	if (ieee80211_is_mgmt(fc))  		err = skb_linearize(skb);  	else @@ -2932,6 +2879,10 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,  	ieee80211_parse_qos(&rx);  	ieee80211_verify_alignment(&rx); +	if (unlikely(ieee80211_is_probe_resp(hdr->frame_control) || +		     ieee80211_is_beacon(hdr->frame_control))) +		ieee80211_scan_rx(local, skb); +  	if (ieee80211_is_data(fc)) {  		prev_sta = NULL; @@ -3029,6 +2980,10 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)  	if (unlikely(local->quiescing || local->suspended))  		goto drop; +	/* We might be during a HW reconfig, prevent Rx for the same reason */ +	if (unlikely(local->in_reconfig)) +		goto drop; +  	/*  	 * The same happens when we're not even started,  	 * but that's worth a warning. diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 169da0742c8..bcaee5d1283 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -83,13 +83,14 @@ ieee80211_bss_info_update(struct ieee80211_local *local,  	cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel,  					 mgmt, len, signal, GFP_ATOMIC); -  	if (!cbss)  		return NULL;  	cbss->free_priv = ieee80211_rx_bss_free;  	bss = (void *)cbss->priv; +	bss->device_ts = rx_status->device_timestamp; +  	if (elems->parse_error) {  		if (beacon)  			bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON; @@ -114,8 +115,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,  	if (elems->tim && (!elems->parse_error ||  			   !(bss->valid_data & IEEE80211_BSS_VALID_DTIM))) { -		struct ieee80211_tim_ie *tim_ie = -			(struct ieee80211_tim_ie *)elems->tim; +		struct ieee80211_tim_ie *tim_ie = elems->tim;  		bss->dtim_period = tim_ie->dtim_period;  		if (!elems->parse_error)  				bss->valid_data |= IEEE80211_BSS_VALID_DTIM; @@ -165,52 +165,47 @@ ieee80211_bss_info_update(struct ieee80211_local *local,  	return bss;  } -ieee80211_rx_result -ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) +void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)  {  	struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); -	struct ieee80211_mgmt *mgmt; +	struct ieee80211_sub_if_data *sdata1, *sdata2; +	struct ieee80211_mgmt *mgmt = (void *)skb->data;  	struct ieee80211_bss *bss;  	u8 *elements;  	struct ieee80211_channel *channel;  	size_t baselen;  	int freq; -	__le16 fc; -	bool presp, beacon = false; +	bool beacon;  	struct ieee802_11_elems elems; -	if (skb->len < 2) -		return RX_DROP_UNUSABLE; - -	mgmt = (struct ieee80211_mgmt *) skb->data; -	fc = mgmt->frame_control; +	if (skb->len < 24 || +	    (!ieee80211_is_probe_resp(mgmt->frame_control) && +	     !ieee80211_is_beacon(mgmt->frame_control))) +		return; -	if (ieee80211_is_ctl(fc)) -		return RX_CONTINUE; +	sdata1 = rcu_dereference(local->scan_sdata); +	sdata2 = rcu_dereference(local->sched_scan_sdata); -	if (skb->len < 24) -		return RX_CONTINUE; +	if (likely(!sdata1 && !sdata2)) +		return; -	presp = ieee80211_is_probe_resp(fc); -	if (presp) { +	if (ieee80211_is_probe_resp(mgmt->frame_control)) {  		/* ignore ProbeResp to foreign address */ -		if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) -			return RX_DROP_MONITOR; +		if ((!sdata1 || !ether_addr_equal(mgmt->da, sdata1->vif.addr)) && +		    (!sdata2 || !ether_addr_equal(mgmt->da, sdata2->vif.addr))) +			return; -		presp = true;  		elements = mgmt->u.probe_resp.variable;  		baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); +		beacon = false;  	} else { -		beacon = ieee80211_is_beacon(fc);  		baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);  		elements = mgmt->u.beacon.variable; +		beacon = true;  	} -	if (!presp && !beacon) -		return RX_CONTINUE; -  	if (baselen > skb->len) -		return RX_DROP_MONITOR; +		return;  	ieee802_11_parse_elems(elements, skb->len - baselen, &elems); @@ -220,22 +215,16 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)  	else  		freq = rx_status->freq; -	channel = ieee80211_get_channel(sdata->local->hw.wiphy, freq); +	channel = ieee80211_get_channel(local->hw.wiphy, freq);  	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) -		return RX_DROP_MONITOR; +		return; -	bss = ieee80211_bss_info_update(sdata->local, rx_status, +	bss = ieee80211_bss_info_update(local, rx_status,  					mgmt, skb->len, &elems,  					channel, beacon);  	if (bss) -		ieee80211_rx_bss_put(sdata->local, bss); - -	if (channel == sdata->local->oper_channel) -		return RX_CONTINUE; - -	dev_kfree_skb(skb); -	return RX_QUEUED; +		ieee80211_rx_bss_put(local, bss);  }  /* return false if no more work */ @@ -293,7 +282,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,  		return;  	if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { -		int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req); +		int rc; + +		rc = drv_hw_scan(local, +			rcu_dereference_protected(local->scan_sdata, +						  lockdep_is_held(&local->mtx)), +			local->hw_scan_req); +  		if (rc == 0)  			return;  	} @@ -323,7 +318,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,  	ieee80211_mlme_notify_scan_completed(local);  	ieee80211_ibss_notify_scan_completed(local);  	ieee80211_mesh_notify_scan_completed(local); -	ieee80211_queue_work(&local->hw, &local->work_work); +	ieee80211_start_next_roc(local);  }  void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) @@ -376,7 +371,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)  static bool ieee80211_can_scan(struct ieee80211_local *local,  			       struct ieee80211_sub_if_data *sdata)  { -	if (!list_empty(&local->work_list)) +	if (!list_empty(&local->roc_list))  		return false;  	if (sdata->vif.type == NL80211_IFTYPE_STATION && @@ -394,7 +389,10 @@ void ieee80211_run_deferred_scan(struct ieee80211_local *local)  	if (!local->scan_req || local->scanning)  		return; -	if (!ieee80211_can_scan(local, local->scan_sdata)) +	if (!ieee80211_can_scan(local, +				rcu_dereference_protected( +					local->scan_sdata, +					lockdep_is_held(&local->mtx))))  		return;  	ieee80211_queue_delayed_work(&local->hw, &local->scan_work, @@ -405,9 +403,12 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,  					    unsigned long *next_delay)  {  	int i; -	struct ieee80211_sub_if_data *sdata = local->scan_sdata; +	struct ieee80211_sub_if_data *sdata;  	enum ieee80211_band band = local->hw.conf.channel->band; +	sdata = rcu_dereference_protected(local->scan_sdata, +					  lockdep_is_held(&local->mtx));; +  	for (i = 0; i < local->scan_req->n_ssids; i++)  		ieee80211_send_probe_req(  			sdata, NULL, @@ -439,7 +440,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,  	if (!ieee80211_can_scan(local, sdata)) {  		/* wait for the work to finish/time out */  		local->scan_req = req; -		local->scan_sdata = sdata; +		rcu_assign_pointer(local->scan_sdata, sdata);  		return 0;  	} @@ -473,7 +474,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,  	}  	local->scan_req = req; -	local->scan_sdata = sdata; +	rcu_assign_pointer(local->scan_sdata, sdata);  	if (local->ops->hw_scan) {  		__set_bit(SCAN_HW_SCANNING, &local->scanning); @@ -533,7 +534,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,  		ieee80211_recalc_idle(local);  		local->scan_req = NULL; -		local->scan_sdata = NULL; +		rcu_assign_pointer(local->scan_sdata, NULL);  	}  	return rc; @@ -720,7 +721,8 @@ void ieee80211_scan_work(struct work_struct *work)  	mutex_lock(&local->mtx); -	sdata = local->scan_sdata; +	sdata = rcu_dereference_protected(local->scan_sdata, +					  lockdep_is_held(&local->mtx));  	/* When scanning on-channel, the first-callback means completed. */  	if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { @@ -741,7 +743,7 @@ void ieee80211_scan_work(struct work_struct *work)  		int rc;  		local->scan_req = NULL; -		local->scan_sdata = NULL; +		rcu_assign_pointer(local->scan_sdata, NULL);  		rc = __ieee80211_start_scan(sdata, req);  		if (rc) { @@ -893,7 +895,9 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)  	if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {  		if (local->ops->cancel_hw_scan) -			drv_cancel_hw_scan(local, local->scan_sdata); +			drv_cancel_hw_scan(local, +				rcu_dereference_protected(local->scan_sdata, +						lockdep_is_held(&local->mtx)));  		goto out;  	} @@ -915,9 +919,9 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,  	struct ieee80211_local *local = sdata->local;  	int ret, i; -	mutex_lock(&sdata->local->mtx); +	mutex_lock(&local->mtx); -	if (local->sched_scanning) { +	if (rcu_access_pointer(local->sched_scan_sdata)) {  		ret = -EBUSY;  		goto out;  	} @@ -928,6 +932,9 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,  	}  	for (i = 0; i < IEEE80211_NUM_BANDS; i++) { +		if (!local->hw.wiphy->bands[i]) +			continue; +  		local->sched_scan_ies.ie[i] = kzalloc(2 +  						      IEEE80211_MAX_SSID_LEN +  						      local->scan_ies_len + @@ -948,7 +955,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,  	ret = drv_sched_scan_start(local, sdata, req,  				   &local->sched_scan_ies);  	if (ret == 0) { -		local->sched_scanning = true; +		rcu_assign_pointer(local->sched_scan_sdata, sdata);  		goto out;  	} @@ -956,7 +963,7 @@ out_free:  	while (i > 0)  		kfree(local->sched_scan_ies.ie[--i]);  out: -	mutex_unlock(&sdata->local->mtx); +	mutex_unlock(&local->mtx);  	return ret;  } @@ -965,22 +972,22 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)  	struct ieee80211_local *local = sdata->local;  	int ret = 0, i; -	mutex_lock(&sdata->local->mtx); +	mutex_lock(&local->mtx);  	if (!local->ops->sched_scan_stop) {  		ret = -ENOTSUPP;  		goto out;  	} -	if (local->sched_scanning) { +	if (rcu_access_pointer(local->sched_scan_sdata)) {  		for (i = 0; i < IEEE80211_NUM_BANDS; i++)  			kfree(local->sched_scan_ies.ie[i]);  		drv_sched_scan_stop(local, sdata); -		local->sched_scanning = false; +		rcu_assign_pointer(local->sched_scan_sdata, NULL);  	}  out: -	mutex_unlock(&sdata->local->mtx); +	mutex_unlock(&local->mtx);  	return ret;  } @@ -1004,7 +1011,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)  	mutex_lock(&local->mtx); -	if (!local->sched_scanning) { +	if (!rcu_access_pointer(local->sched_scan_sdata)) {  		mutex_unlock(&local->mtx);  		return;  	} @@ -1012,7 +1019,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)  	for (i = 0; i < IEEE80211_NUM_BANDS; i++)  		kfree(local->sched_scan_ies.ie[i]); -	local->sched_scanning = false; +	rcu_assign_pointer(local->sched_scan_sdata, NULL);  	mutex_unlock(&local->mtx); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f5b1638fbf8..06fa75ceb02 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -169,9 +169,7 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)  	if (sta->rate_ctrl)  		rate_control_free_sta(sta); -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -	wiphy_debug(local->hw.wiphy, "Destroyed STA %pM\n", sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ +	sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);  	kfree(sta);  } @@ -278,9 +276,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,  	for (i = 0; i < NUM_RX_DATA_QUEUES; i++)  		sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -	wiphy_debug(local->hw.wiphy, "Allocated STA %pM\n", sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ +	sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);  #ifdef CONFIG_MAC80211_MESH  	sta->plink_state = NL80211_PLINK_LISTEN; @@ -333,9 +329,9 @@ static int sta_info_insert_drv_state(struct ieee80211_local *local,  	}  	if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { -		printk(KERN_DEBUG -		       "%s: failed to move IBSS STA %pM to state %d (%d) - keeping it anyway.\n", -		       sdata->name, sta->sta.addr, state + 1, err); +		sdata_info(sdata, +			   "failed to move IBSS STA %pM to state %d (%d) - keeping it anyway\n", +			   sta->sta.addr, state + 1, err);  		err = 0;  	} @@ -378,7 +374,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)  	/* make the station visible */  	sta_info_hash_add(local, sta); -	list_add(&sta->list, &local->sta_list); +	list_add_rcu(&sta->list, &local->sta_list);  	set_sta_flag(sta, WLAN_STA_INSERTED); @@ -390,9 +386,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)  	sinfo.generation = local->sta_generation;  	cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -	wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ +	sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr);  	/* move reference to rcu-protected */  	rcu_read_lock(); @@ -618,10 +612,8 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local,  			break;  		local->total_ps_buffered--; -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG -		printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n", +		ps_dbg(sta->sdata, "Buffered frame expired (STA %pM)\n",  		       sta->sta.addr); -#endif  		dev_kfree_skb(skb);  	} @@ -688,7 +680,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)  	if (ret)  		return ret; -	list_del(&sta->list); +	list_del_rcu(&sta->list);  	mutex_lock(&local->key_mtx);  	for (i = 0; i < NUM_DEFAULT_KEYS; i++) @@ -747,9 +739,8 @@ int __must_check __sta_info_destroy(struct sta_info *sta)  		mesh_accept_plinks_update(sdata);  #endif -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -	wiphy_debug(local->hw.wiphy, "Removed STA %pM\n", sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ +	sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr); +  	cancel_work_sync(&sta->drv_unblock_wk);  	cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); @@ -889,10 +880,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,  			continue;  		if (time_after(jiffies, sta->last_rx + exp_time)) { -#ifdef CONFIG_MAC80211_IBSS_DEBUG -			printk(KERN_DEBUG "%s: expiring inactive STA %pM\n", -			       sdata->name, sta->sta.addr); -#endif +			ibss_dbg(sdata, "expiring inactive STA %pM\n", +				 sta->sta.addr);  			WARN_ON(__sta_info_destroy(sta));  		}  	} @@ -990,11 +979,9 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)  	sta_info_recalc_tim(sta); -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG -	printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " -	       "since STA not sleeping anymore\n", sdata->name, +	ps_dbg(sdata, +	       "STA %pM aid %d sending %d filtered/%d PS frames since STA not sleeping anymore\n",  	       sta->sta.addr, sta->sta.aid, filtered, buffered); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */  }  static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, @@ -1384,10 +1371,8 @@ int sta_info_move_state(struct sta_info *sta,  		return -EINVAL;  	} -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -	printk(KERN_DEBUG "%s: moving STA %pM to state %d\n", -		sta->sdata->name, sta->sta.addr, new_state); -#endif +	sta_dbg(sta->sdata, "moving STA %pM to state %d\n", +		sta->sta.addr, new_state);  	/*  	 * notify the driver before the actual changes so it can diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 3bb24a121c9..a470e1123a5 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -271,6 +271,9 @@ struct sta_ampdu_mlme {   * @plink_timer: peer link watch timer   * @plink_timer_was_running: used by suspend/resume to restore timers   * @t_offset: timing offset relative to this host + * @t_offset_setpoint: reference timing offset of this sta to be used when + * 	calculating clockdrift + * @ch_type: peer's channel type   * @debugfs: debug filesystem info   * @dead: set to true when sta is unlinked   * @uploaded: set to true when sta is uploaded to the driver @@ -278,6 +281,8 @@ struct sta_ampdu_mlme {   * @sta: station information we share with the driver   * @sta_state: duplicates information about station state (for debug)   * @beacon_loss_count: number of times beacon loss has triggered + * @supports_40mhz: tracks whether the station advertised 40 MHz support + *	as we overwrite its HT parameters with the currently used value   */  struct sta_info {  	/* General information, mostly static */ diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 28cfa981cfb..8cd72914cda 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -155,13 +155,10 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,  		return;  	} -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -	if (net_ratelimit()) -		wiphy_debug(local->hw.wiphy, -			    "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n", -			    skb_queue_len(&sta->tx_filtered[ac]), -			    !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies); -#endif +	ps_dbg_ratelimited(sta->sdata, +			   "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n", +			   skb_queue_len(&sta->tx_filtered[ac]), +			   !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies);  	dev_kfree_skb(skb);  } @@ -520,36 +517,21 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)  	if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {  		u64 cookie = (unsigned long)skb; +		acked = info->flags & IEEE80211_TX_STAT_ACK; -		if (ieee80211_is_nullfunc(hdr->frame_control) || -		    ieee80211_is_qos_nullfunc(hdr->frame_control)) { -			acked = info->flags & IEEE80211_TX_STAT_ACK; +		/* +		 * TODO: When we have non-netdev frame TX, +		 * we cannot use skb->dev->ieee80211_ptr +		 */ +		if (ieee80211_is_nullfunc(hdr->frame_control) || +		    ieee80211_is_qos_nullfunc(hdr->frame_control))  			cfg80211_probe_status(skb->dev, hdr->addr1,  					      cookie, acked, GFP_ATOMIC); -		} else { -			struct ieee80211_work *wk; - -			rcu_read_lock(); -			list_for_each_entry_rcu(wk, &local->work_list, list) { -				if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX) -					continue; -				if (wk->offchan_tx.frame != skb) -					continue; -				wk->offchan_tx.status = true; -				break; -			} -			rcu_read_unlock(); -			if (local->hw_roc_skb_for_status == skb) { -				cookie = local->hw_roc_cookie ^ 2; -				local->hw_roc_skb_for_status = NULL; -			} - +		else  			cfg80211_mgmt_tx_status( -				skb->dev, cookie, skb->data, skb->len, -				!!(info->flags & IEEE80211_TX_STAT_ACK), -				GFP_ATOMIC); -		} +				skb->dev->ieee80211_ptr, cookie, skb->data, +				skb->len, acked, GFP_ATOMIC);  	}  	if (unlikely(info->ack_frame_id)) { @@ -589,7 +571,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)  	/* send frame to monitor interfaces now */  	rtap_len = ieee80211_tx_radiotap_len(info);  	if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) { -		printk(KERN_ERR "ieee80211_tx_status: headroom too small\n"); +		pr_err("ieee80211_tx_status: headroom too small\n");  		dev_kfree_skb(skb);  		return;  	} diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 51077a956a8..57e14d59e12 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -260,17 +260,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,  	keyid = pos[3];  	iv32 = get_unaligned_le32(pos + 4);  	pos += 8; -#ifdef CONFIG_MAC80211_TKIP_DEBUG -	{ -		int i; -		printk(KERN_DEBUG "TKIP decrypt: data(len=%zd)", payload_len); -		for (i = 0; i < payload_len; i++) -			printk(" %02x", payload[i]); -		printk("\n"); -		printk(KERN_DEBUG "TKIP decrypt: iv16=%04x iv32=%08x\n", -		       iv16, iv32); -	} -#endif  	if (!(keyid & (1 << 5)))  		return TKIP_DECRYPT_NO_EXT_IV; @@ -281,16 +270,8 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,  	if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT &&  	    (iv32 < key->u.tkip.rx[queue].iv32 ||  	     (iv32 == key->u.tkip.rx[queue].iv32 && -	      iv16 <= key->u.tkip.rx[queue].iv16))) { -#ifdef CONFIG_MAC80211_TKIP_DEBUG -		printk(KERN_DEBUG "TKIP replay detected for RX frame from " -		       "%pM (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", -		       ta, -		       iv32, iv16, key->u.tkip.rx[queue].iv32, -		       key->u.tkip.rx[queue].iv16); -#endif +	      iv16 <= key->u.tkip.rx[queue].iv16)))  		return TKIP_DECRYPT_REPLAY; -	}  	if (only_iv) {  		res = TKIP_DECRYPT_OK; @@ -302,22 +283,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,  	    key->u.tkip.rx[queue].iv32 != iv32) {  		/* IV16 wrapped around - perform TKIP phase 1 */  		tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32); -#ifdef CONFIG_MAC80211_TKIP_DEBUG -		{ -			int i; -			u8 key_offset = NL80211_TKIP_DATA_OFFSET_ENCR_KEY; -			printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%pM" -			       " TK=", ta); -			for (i = 0; i < 16; i++) -				printk("%02x ", -				       key->conf.key[key_offset + i]); -			printk("\n"); -			printk(KERN_DEBUG "TKIP decrypt: P1K="); -			for (i = 0; i < 5; i++) -				printk("%04x ", key->u.tkip.rx[queue].p1k[i]); -			printk("\n"); -		} -#endif  	}  	if (key->local->ops->update_tkip_key &&  	    key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && @@ -333,15 +298,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,  	}  	tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key); -#ifdef CONFIG_MAC80211_TKIP_DEBUG -	{ -		int i; -		printk(KERN_DEBUG "TKIP decrypt: Phase2 rc4key="); -		for (i = 0; i < 16; i++) -			printk("%02x ", rc4key[i]); -		printk("\n"); -	} -#endif  	res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);   done: diff --git a/net/mac80211/trace.c b/net/mac80211/trace.c new file mode 100644 index 00000000000..386e45d8a95 --- /dev/null +++ b/net/mac80211/trace.c @@ -0,0 +1,75 @@ +/* bug in tracepoint.h, it should include this */ +#include <linux/module.h> + +/* sparse isn't too happy with all macros... */ +#ifndef __CHECKER__ +#include <net/cfg80211.h> +#include "driver-ops.h" +#include "debug.h" +#define CREATE_TRACE_POINTS +#include "trace.h" + +#ifdef CONFIG_MAC80211_MESSAGE_TRACING +void __sdata_info(const char *fmt, ...) +{ +	struct va_format vaf = { +		.fmt = fmt, +	}; +	va_list args; + +	va_start(args, fmt); +	vaf.va = &args; + +	pr_info("%pV", &vaf); +	trace_mac80211_info(&vaf); +	va_end(args); +} + +void __sdata_dbg(bool print, const char *fmt, ...) +{ +	struct va_format vaf = { +		.fmt = fmt, +	}; +	va_list args; + +	va_start(args, fmt); +	vaf.va = &args; + +	if (print) +		pr_debug("%pV", &vaf); +	trace_mac80211_dbg(&vaf); +	va_end(args); +} + +void __sdata_err(const char *fmt, ...) +{ +	struct va_format vaf = { +		.fmt = fmt, +	}; +	va_list args; + +	va_start(args, fmt); +	vaf.va = &args; + +	pr_err("%pV", &vaf); +	trace_mac80211_err(&vaf); +	va_end(args); +} + +void __wiphy_dbg(struct wiphy *wiphy, bool print, const char *fmt, ...) +{ +	struct va_format vaf = { +		.fmt = fmt, +	}; +	va_list args; + +	va_start(args, fmt); +	vaf.va = &args; + +	if (print) +		wiphy_dbg(wiphy, "%pV", &vaf); +	trace_mac80211_dbg(&vaf); +	va_end(args); +} +#endif +#endif diff --git a/net/mac80211/driver-trace.h b/net/mac80211/trace.h index 6de00b2c268..c6d33b55b2d 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/trace.h @@ -306,7 +306,8 @@ TRACE_EVENT(drv_bss_info_changed,  		__field(u8, dtimper)  		__field(u16, bcnint)  		__field(u16, assoc_cap) -		__field(u64, timestamp) +		__field(u64, sync_tsf) +		__field(u32, sync_device_ts)  		__field(u32, basic_rates)  		__field(u32, changed)  		__field(bool, enable_beacon) @@ -325,7 +326,8 @@ TRACE_EVENT(drv_bss_info_changed,  		__entry->dtimper = info->dtim_period;  		__entry->bcnint = info->beacon_int;  		__entry->assoc_cap = info->assoc_capability; -		__entry->timestamp = info->last_tsf; +		__entry->sync_tsf = info->sync_tsf; +		__entry->sync_device_ts = info->sync_device_ts;  		__entry->basic_rates = info->basic_rates;  		__entry->enable_beacon = info->enable_beacon;  		__entry->ht_operation_mode = info->ht_operation_mode; @@ -1218,6 +1220,39 @@ DEFINE_EVENT(release_evt, drv_allow_buffered_frames,  	TP_ARGS(local, sta, tids, num_frames, reason, more_data)  ); +TRACE_EVENT(drv_get_rssi, +	TP_PROTO(struct ieee80211_local *local, struct ieee80211_sta *sta, +		 s8 rssi, int ret), + +	TP_ARGS(local, sta, rssi, ret), + +	TP_STRUCT__entry( +		LOCAL_ENTRY +		STA_ENTRY +		__field(s8, rssi) +		__field(int, ret) +	), + +	TP_fast_assign( +		LOCAL_ASSIGN; +		STA_ASSIGN; +		__entry->rssi = rssi; +		__entry->ret = ret; +	), + +	TP_printk( +		LOCAL_PR_FMT STA_PR_FMT " rssi:%d ret:%d", +		LOCAL_PR_ARG, STA_PR_ARG, __entry->rssi, __entry->ret +	) +); + +DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx, +	TP_PROTO(struct ieee80211_local *local, +		 struct ieee80211_sub_if_data *sdata), + +	TP_ARGS(local, sdata) +); +  /*   * Tracing for API calls that drivers call.   */ @@ -1606,10 +1641,49 @@ TRACE_EVENT(stop_queue,  		LOCAL_PR_ARG, __entry->queue, __entry->reason  	)  ); + +#ifdef CONFIG_MAC80211_MESSAGE_TRACING +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mac80211_msg + +#define MAX_MSG_LEN	100 + +DECLARE_EVENT_CLASS(mac80211_msg_event, +	TP_PROTO(struct va_format *vaf), + +	TP_ARGS(vaf), + +	TP_STRUCT__entry( +		__dynamic_array(char, msg, MAX_MSG_LEN) +	), + +	TP_fast_assign( +		WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), +				       MAX_MSG_LEN, vaf->fmt, +				       *vaf->va) >= MAX_MSG_LEN); +	), + +	TP_printk("%s", __get_str(msg)) +); + +DEFINE_EVENT(mac80211_msg_event, mac80211_info, +	TP_PROTO(struct va_format *vaf), +	TP_ARGS(vaf) +); +DEFINE_EVENT(mac80211_msg_event, mac80211_dbg, +	TP_PROTO(struct va_format *vaf), +	TP_ARGS(vaf) +); +DEFINE_EVENT(mac80211_msg_event, mac80211_err, +	TP_PROTO(struct va_format *vaf), +	TP_ARGS(vaf) +); +#endif +  #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */  #undef TRACE_INCLUDE_PATH  #define TRACE_INCLUDE_PATH .  #undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE driver-trace +#define TRACE_INCLUDE_FILE trace  #include <trace/define_trace.h> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5f827a6b0d8..acf712ffb5e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -140,6 +140,8 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,  			if (r->flags & IEEE80211_RATE_MANDATORY_A)  				mrate = r->bitrate;  			break; +		case IEEE80211_BAND_60GHZ: +			/* TODO, for now fall through */  		case IEEE80211_NUM_BANDS:  			WARN_ON(1);  			break; @@ -153,7 +155,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,  	/* Don't calculate ACKs for QoS Frames with NoAck Policy set */  	if (ieee80211_is_data_qos(hdr->frame_control) && -	    *(ieee80211_get_qos_ctl(hdr)) | IEEE80211_QOS_CTL_ACK_POLICY_NOACK) +	    *(ieee80211_get_qos_ctl(hdr)) & IEEE80211_QOS_CTL_ACK_POLICY_NOACK)  		dur = 0;  	else  		/* Time needed to transmit ACK @@ -175,12 +177,6 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,  	return cpu_to_le16(dur);  } -static inline int is_ieee80211_device(struct ieee80211_local *local, -				      struct net_device *dev) -{ -	return local == wdev_priv(dev->ieee80211_ptr); -} -  /* tx handlers */  static ieee80211_tx_result debug_noinline  ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) @@ -297,10 +293,10 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)  		if (unlikely(!assoc &&  			     ieee80211_is_data(hdr->frame_control))) {  #ifdef CONFIG_MAC80211_VERBOSE_DEBUG -			printk(KERN_DEBUG "%s: dropped data frame to not " -			       "associated station %pM\n", -			       tx->sdata->name, hdr->addr1); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ +			sdata_info(tx->sdata, +				   "dropped data frame to not associated station %pM\n", +				   hdr->addr1); +#endif  			I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);  			return TX_DROP;  		} @@ -367,10 +363,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)  	rcu_read_unlock();  	local->total_ps_buffered = total; -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG -	wiphy_debug(local->hw.wiphy, "PS buffers full - purged %d frames\n", -		    purged); -#endif +	ps_dbg_hw(&local->hw, "PS buffers full - purged %d frames\n", purged);  }  static ieee80211_tx_result @@ -412,10 +405,8 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)  		purge_old_ps_buffers(tx->local);  	if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) { -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG -		net_dbg_ratelimited("%s: BC TX buffer full - dropping the oldest frame\n", -				    tx->sdata->name); -#endif +		ps_dbg(tx->sdata, +		       "BC TX buffer full - dropping the oldest frame\n");  		dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));  	} else  		tx->local->total_ps_buffered++; @@ -466,18 +457,15 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)  			return TX_CONTINUE;  		} -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG -		printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n", +		ps_dbg(sta->sdata, "STA %pM aid %d: PS buffer for AC %d\n",  		       sta->sta.addr, sta->sta.aid, ac); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */  		if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)  			purge_old_ps_buffers(tx->local);  		if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {  			struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]); -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG -			net_dbg_ratelimited("%s: STA %pM TX buffer for AC %d full - dropping oldest frame\n", -					    tx->sdata->name, sta->sta.addr, ac); -#endif +			ps_dbg(tx->sdata, +			       "STA %pM TX buffer for AC %d full - dropping oldest frame\n", +			       sta->sta.addr, ac);  			dev_kfree_skb(old);  		} else  			tx->local->total_ps_buffered++; @@ -499,14 +487,11 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)  		sta_info_recalc_tim(sta);  		return TX_QUEUED; +	} else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) { +		ps_dbg(tx->sdata, +		       "STA %pM in PS mode, but polling/in SP -> send frame\n", +		       sta->sta.addr);  	} -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG -	else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) { -		printk(KERN_DEBUG -		       "%s: STA %pM in PS mode, but polling/in SP -> send frame\n", -		       tx->sdata->name, sta->sta.addr); -	} -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */  	return TX_CONTINUE;  } @@ -538,7 +523,7 @@ ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx)  static ieee80211_tx_result debug_noinline  ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)  { -	struct ieee80211_key *key = NULL; +	struct ieee80211_key *key;  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; @@ -557,16 +542,23 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)  	else if (!is_multicast_ether_addr(hdr->addr1) &&  		 (key = rcu_dereference(tx->sdata->default_unicast_key)))  		tx->key = key; -	else if (tx->sdata->drop_unencrypted && -		 (tx->skb->protocol != tx->sdata->control_port_protocol) && -		 !(info->flags & IEEE80211_TX_CTL_INJECTED) && -		 (!ieee80211_is_robust_mgmt_frame(hdr) || -		  (ieee80211_is_action(hdr->frame_control) && -		   tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))) { +	else if (info->flags & IEEE80211_TX_CTL_INJECTED) +		tx->key = NULL; +	else if (!tx->sdata->drop_unencrypted) +		tx->key = NULL; +	else if (tx->skb->protocol == tx->sdata->control_port_protocol) +		tx->key = NULL; +	else if (ieee80211_is_robust_mgmt_frame(hdr) && +		 !(ieee80211_is_action(hdr->frame_control) && +		   tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP))) +		tx->key = NULL; +	else if (ieee80211_is_mgmt(hdr->frame_control) && +		 !ieee80211_is_robust_mgmt_frame(hdr)) +		tx->key = NULL; +	else {  		I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);  		return TX_DROP; -	} else -		tx->key = NULL; +	}  	if (tx->key) {  		bool skip_hw = false; @@ -974,8 +966,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)  			info->control.rates[1].idx = -1;  			info->control.rates[2].idx = -1;  			info->control.rates[3].idx = -1; -			info->control.rates[4].idx = -1; -			BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); +			BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 4);  			info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;  		} else {  			hdr->frame_control &= ~morefrags; @@ -1310,11 +1301,8 @@ static bool __ieee80211_tx(struct ieee80211_local *local,  		break;  	} -	if (local->ops->tx_frags) -		drv_tx_frags(local, vif, pubsta, skbs); -	else -		result = ieee80211_tx_frags(local, vif, pubsta, skbs, -					    txpending); +	result = ieee80211_tx_frags(local, vif, pubsta, skbs, +				    txpending);  	ieee80211_tpt_led_trig_tx(local, fc, led_len);  	ieee80211_led_tx(local, 1); @@ -1737,7 +1725,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,  	__le16 fc;  	struct ieee80211_hdr hdr;  	struct ieee80211s_hdr mesh_hdr __maybe_unused; -	struct mesh_path __maybe_unused *mppath = NULL; +	struct mesh_path __maybe_unused *mppath = NULL, *mpath = NULL;  	const u8 *encaps_data;  	int encaps_len, skip_header_bytes;  	int nh_pos, h_pos; @@ -1803,8 +1791,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,  			goto fail;  		}  		rcu_read_lock(); -		if (!is_multicast_ether_addr(skb->data)) -			mppath = mpp_path_lookup(skb->data, sdata); +		if (!is_multicast_ether_addr(skb->data)) { +			mpath = mesh_path_lookup(skb->data, sdata); +			if (!mpath) +				mppath = mpp_path_lookup(skb->data, sdata); +		}  		/*  		 * Use address extension if it is a packet from @@ -1833,6 +1824,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,  					/* RA TA mDA mSA AE:DA SA */  					mesh_da = mppath->mpp;  					is_mesh_mcast = 0; +				} else if (mpath) { +					mesh_da = mpath->dst; +					is_mesh_mcast = 0;  				} else {  					/* DA TA mSA AE:SA */  					mesh_da = bcast; @@ -1962,7 +1956,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,  		     (cpu_to_be16(ethertype) != sdata->control_port_protocol ||  		      !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) {  #ifdef CONFIG_MAC80211_VERBOSE_DEBUG -		net_dbg_ratelimited("%s: dropped frame to %pM (unauthorized port)\n", +		net_info_ratelimited("%s: dropped frame to %pM (unauthorized port)\n",  				    dev->name, hdr.addr1);  #endif @@ -2434,9 +2428,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,  		*pos++ = WLAN_EID_SSID;  		*pos++ = 0x0; -		if (ieee80211_add_srates_ie(&sdata->vif, skb, true) || +		if (ieee80211_add_srates_ie(sdata, skb, true) ||  		    mesh_add_ds_params_ie(skb, sdata) || -		    ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) || +		    ieee80211_add_ext_srates_ie(sdata, skb, true) ||  		    mesh_add_rsn_ie(skb, sdata) ||  		    mesh_add_ht_cap_ie(skb, sdata) ||  		    mesh_add_ht_oper_ie(skb, sdata) || @@ -2730,7 +2724,7 @@ EXPORT_SYMBOL(ieee80211_get_buffered_bc);  void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,  			  struct sk_buff *skb, int tid)  { -	int ac = ieee802_1d_to_ac[tid]; +	int ac = ieee802_1d_to_ac[tid & 7];  	skb_set_mac_header(skb, 0);  	skb_set_network_header(skb, 0); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 22f2216b397..39b82fee490 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -268,6 +268,10 @@ EXPORT_SYMBOL(ieee80211_ctstoself_duration);  void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)  {  	struct ieee80211_sub_if_data *sdata; +	int n_acs = IEEE80211_NUM_ACS; + +	if (local->hw.queues < IEEE80211_NUM_ACS) +		n_acs = 1;  	list_for_each_entry_rcu(sdata, &local->interfaces, list) {  		int ac; @@ -279,7 +283,7 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)  		    local->queue_stop_reasons[sdata->vif.cab_queue] != 0)  			continue; -		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { +		for (ac = 0; ac < n_acs; ac++) {  			int ac_queue = sdata->vif.hw_queue[ac];  			if (ac_queue == queue || @@ -341,6 +345,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,  {  	struct ieee80211_local *local = hw_to_local(hw);  	struct ieee80211_sub_if_data *sdata; +	int n_acs = IEEE80211_NUM_ACS;  	trace_stop_queue(local, queue, reason); @@ -352,11 +357,14 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,  	__set_bit(reason, &local->queue_stop_reasons[queue]); +	if (local->hw.queues < IEEE80211_NUM_ACS) +		n_acs = 1; +  	rcu_read_lock();  	list_for_each_entry_rcu(sdata, &local->interfaces, list) {  		int ac; -		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { +		for (ac = 0; ac < n_acs; ac++) {  			if (sdata->vif.hw_queue[ac] == queue ||  			    sdata->vif.cab_queue == queue)  				netif_stop_subqueue(sdata->dev, ac); @@ -521,6 +529,11 @@ void ieee80211_iterate_active_interfaces(  				 &sdata->vif);  	} +	sdata = rcu_dereference_protected(local->monitor_sdata, +					  lockdep_is_held(&local->iflist_mtx)); +	if (sdata) +		iterator(data, sdata->vif.addr, &sdata->vif); +  	mutex_unlock(&local->iflist_mtx);  }  EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); @@ -549,6 +562,10 @@ void ieee80211_iterate_active_interfaces_atomic(  				 &sdata->vif);  	} +	sdata = rcu_dereference(local->monitor_sdata); +	if (sdata) +		iterator(data, sdata->vif.addr, &sdata->vif); +  	rcu_read_unlock();  }  EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); @@ -804,7 +821,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,  	struct ieee80211_local *local = sdata->local;  	struct ieee80211_tx_queue_params qparam;  	int ac; -	bool use_11b; +	bool use_11b, enable_qos;  	int aCWmin, aCWmax;  	if (!local->ops->conf_tx) @@ -818,6 +835,13 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,  	use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&  		 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); +	/* +	 * By default disable QoS in STA mode for old access points, which do +	 * not support 802.11e. New APs will provide proper queue parameters, +	 * that we will configure later. +	 */ +	enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION); +  	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {  		/* Set defaults according to 802.11-2007 Table 7-37 */  		aCWmax = 1023; @@ -826,38 +850,47 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,  		else  			aCWmin = 15; -		switch (ac) { -		case IEEE80211_AC_BK: -			qparam.cw_max = aCWmax; -			qparam.cw_min = aCWmin; -			qparam.txop = 0; -			qparam.aifs = 7; -			break; -		default: /* never happens but let's not leave undefined */ -		case IEEE80211_AC_BE: +		if (enable_qos) { +			switch (ac) { +			case IEEE80211_AC_BK: +				qparam.cw_max = aCWmax; +				qparam.cw_min = aCWmin; +				qparam.txop = 0; +				qparam.aifs = 7; +				break; +			/* never happens but let's not leave undefined */ +			default: +			case IEEE80211_AC_BE: +				qparam.cw_max = aCWmax; +				qparam.cw_min = aCWmin; +				qparam.txop = 0; +				qparam.aifs = 3; +				break; +			case IEEE80211_AC_VI: +				qparam.cw_max = aCWmin; +				qparam.cw_min = (aCWmin + 1) / 2 - 1; +				if (use_11b) +					qparam.txop = 6016/32; +				else +					qparam.txop = 3008/32; +				qparam.aifs = 2; +				break; +			case IEEE80211_AC_VO: +				qparam.cw_max = (aCWmin + 1) / 2 - 1; +				qparam.cw_min = (aCWmin + 1) / 4 - 1; +				if (use_11b) +					qparam.txop = 3264/32; +				else +					qparam.txop = 1504/32; +				qparam.aifs = 2; +				break; +			} +		} else { +			/* Confiure old 802.11b/g medium access rules. */  			qparam.cw_max = aCWmax;  			qparam.cw_min = aCWmin;  			qparam.txop = 0; -			qparam.aifs = 3; -			break; -		case IEEE80211_AC_VI: -			qparam.cw_max = aCWmin; -			qparam.cw_min = (aCWmin + 1) / 2 - 1; -			if (use_11b) -				qparam.txop = 6016/32; -			else -				qparam.txop = 3008/32; -			qparam.aifs = 2; -			break; -		case IEEE80211_AC_VO: -			qparam.cw_max = (aCWmin + 1) / 2 - 1; -			qparam.cw_min = (aCWmin + 1) / 4 - 1; -			if (use_11b) -				qparam.txop = 3264/32; -			else -				qparam.txop = 1504/32;  			qparam.aifs = 2; -			break;  		}  		qparam.uapsd = false; @@ -866,12 +899,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,  		drv_conf_tx(local, sdata, ac, &qparam);  	} -	/* after reinitialize QoS TX queues setting to default, -	 * disable QoS at all */ -  	if (sdata->vif.type != NL80211_IFTYPE_MONITOR) { -		sdata->vif.bss_conf.qos = -			sdata->vif.type != NL80211_IFTYPE_STATION; +		sdata->vif.bss_conf.qos = enable_qos;  		if (bss_notify)  			ieee80211_bss_info_change_notify(sdata,  							 BSS_CHANGED_QOS); @@ -979,6 +1008,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,  	int ext_rates_len;  	sband = local->hw.wiphy->bands[band]; +	if (WARN_ON_ONCE(!sband)) +		return 0;  	pos = buffer; @@ -1060,6 +1091,10 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,  		pos += noffset - offset;  	} +	if (sband->vht_cap.vht_supported) +		pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, +						 sband->vht_cap.cap); +  	return pos - buffer;  } @@ -1267,14 +1302,19 @@ int ieee80211_reconfig(struct ieee80211_local *local)  	/* add STAs back */  	mutex_lock(&local->sta_mtx);  	list_for_each_entry(sta, &local->sta_list, list) { -		if (sta->uploaded) { -			enum ieee80211_sta_state state; +		enum ieee80211_sta_state state; -			for (state = IEEE80211_STA_NOTEXIST; -			     state < sta->sta_state - 1; state++) -				WARN_ON(drv_sta_state(local, sta->sdata, sta, -						      state, state + 1)); -		} +		if (!sta->uploaded) +			continue; + +		/* AP-mode stations will be added later */ +		if (sta->sdata->vif.type == NL80211_IFTYPE_AP) +			continue; + +		for (state = IEEE80211_STA_NOTEXIST; +		     state < sta->sta_state; state++) +			WARN_ON(drv_sta_state(local, sta->sdata, sta, state, +					      state + 1));  	}  	mutex_unlock(&local->sta_mtx); @@ -1371,6 +1411,33 @@ int ieee80211_reconfig(struct ieee80211_local *local)  		}  	} +	/* APs are now beaconing, add back stations */ +	mutex_lock(&local->sta_mtx); +	list_for_each_entry(sta, &local->sta_list, list) { +		enum ieee80211_sta_state state; + +		if (!sta->uploaded) +			continue; + +		if (sta->sdata->vif.type != NL80211_IFTYPE_AP) +			continue; + +		for (state = IEEE80211_STA_NOTEXIST; +		     state < sta->sta_state; state++) +			WARN_ON(drv_sta_state(local, sta->sdata, sta, state, +					      state + 1)); +	} +	mutex_unlock(&local->sta_mtx); + +	/* add back keys */ +	list_for_each_entry(sdata, &local->interfaces, list) +		if (ieee80211_sdata_running(sdata)) +			ieee80211_enable_keys(sdata); + + wake_up: +	local->in_reconfig = false; +	barrier(); +  	/*  	 * Clear the WLAN_STA_BLOCK_BA flag so new aggregation  	 * sessions can be established after a resume. @@ -1392,12 +1459,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)  		mutex_unlock(&local->sta_mtx);  	} -	/* add back keys */ -	list_for_each_entry(sdata, &local->interfaces, list) -		if (ieee80211_sdata_running(sdata)) -			ieee80211_enable_keys(sdata); - - wake_up:  	ieee80211_wake_queues_by_reason(hw,  			IEEE80211_QUEUE_STOP_REASON_SUSPEND); @@ -1661,6 +1722,27 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,  	return pos;  } +u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, +							   u32 cap) +{ +	__le32 tmp; + +	*pos++ = WLAN_EID_VHT_CAPABILITY; +	*pos++ = sizeof(struct ieee80211_vht_capabilities); +	memset(pos, 0, sizeof(struct ieee80211_vht_capabilities)); + +	/* capability flags */ +	tmp = cpu_to_le32(cap); +	memcpy(pos, &tmp, sizeof(u32)); +	pos += sizeof(u32); + +	/* VHT MCS set */ +	memcpy(pos, &vht_cap->vht_mcs, sizeof(vht_cap->vht_mcs)); +	pos += sizeof(vht_cap->vht_mcs); + +	return pos; +} +  u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,  			       struct ieee80211_channel *channel,  			       enum nl80211_channel_type channel_type, @@ -1726,15 +1808,14 @@ ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper)  	return channel_type;  } -int ieee80211_add_srates_ie(struct ieee80211_vif *vif, +int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,  			    struct sk_buff *skb, bool need_basic)  { -	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);  	struct ieee80211_local *local = sdata->local;  	struct ieee80211_supported_band *sband;  	int rate;  	u8 i, rates, *pos; -	u32 basic_rates = vif->bss_conf.basic_rates; +	u32 basic_rates = sdata->vif.bss_conf.basic_rates;  	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];  	rates = sband->n_bitrates; @@ -1758,15 +1839,14 @@ int ieee80211_add_srates_ie(struct ieee80211_vif *vif,  	return 0;  } -int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, +int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,  				struct sk_buff *skb, bool need_basic)  { -	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);  	struct ieee80211_local *local = sdata->local;  	struct ieee80211_supported_band *sband;  	int rate;  	u8 i, exrates, *pos; -	u32 basic_rates = vif->bss_conf.basic_rates; +	u32 basic_rates = sdata->vif.bss_conf.basic_rates;  	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];  	exrates = sband->n_bitrates; diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index c3d643a6536..cea06e9f26f 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -52,11 +52,11 @@ static int wme_downgrade_ac(struct sk_buff *skb)  	}  } -static u16 ieee80211_downgrade_queue(struct ieee80211_local *local, +static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata,  				     struct sk_buff *skb)  {  	/* in case we are a client verify acm is not set for this ac */ -	while (unlikely(local->wmm_acm & BIT(skb->priority))) { +	while (unlikely(sdata->wmm_acm & BIT(skb->priority))) {  		if (wme_downgrade_ac(skb)) {  			/*  			 * This should not really happen. The AP has marked all @@ -73,10 +73,11 @@ static u16 ieee80211_downgrade_queue(struct ieee80211_local *local,  }  /* Indicate which queue to use for this fully formed 802.11 frame */ -u16 ieee80211_select_queue_80211(struct ieee80211_local *local, +u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,  				 struct sk_buff *skb,  				 struct ieee80211_hdr *hdr)  { +	struct ieee80211_local *local = sdata->local;  	u8 *p;  	if (local->hw.queues < IEEE80211_NUM_ACS) @@ -94,7 +95,7 @@ u16 ieee80211_select_queue_80211(struct ieee80211_local *local,  	p = ieee80211_get_qos_ctl(hdr);  	skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; -	return ieee80211_downgrade_queue(local, skb); +	return ieee80211_downgrade_queue(sdata, skb);  }  /* Indicate which queue to use. */ @@ -156,7 +157,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,  	 * data frame has */  	skb->priority = cfg80211_classify8021d(skb); -	return ieee80211_downgrade_queue(local, skb); +	return ieee80211_downgrade_queue(sdata, skb);  }  void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index ca80818b7b6..7fea4bb8acb 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h @@ -15,7 +15,7 @@  extern const int ieee802_1d_to_ac[8]; -u16 ieee80211_select_queue_80211(struct ieee80211_local *local, +u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,  				 struct sk_buff *skb,  				 struct ieee80211_hdr *hdr);  u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/work.c b/net/mac80211/work.c deleted file mode 100644 index b2650a9d45f..00000000000 --- a/net/mac80211/work.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * mac80211 work implementation - * - * Copyright 2003-2008, Jouni Malinen <j@w1.fi> - * Copyright 2004, Instant802 Networks, Inc. - * Copyright 2005, Devicescape Software, Inc. - * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz> - * Copyright 2007, Michael Wu <flamingice@sourmilk.net> - * Copyright 2009, Johannes Berg <johannes@sipsolutions.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/delay.h> -#include <linux/if_ether.h> -#include <linux/skbuff.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/crc32.h> -#include <linux/slab.h> -#include <net/mac80211.h> -#include <asm/unaligned.h> - -#include "ieee80211_i.h" -#include "rate.h" -#include "driver-ops.h" - -enum work_action { -	WORK_ACT_NONE, -	WORK_ACT_TIMEOUT, -}; - - -/* utils */ -static inline void ASSERT_WORK_MTX(struct ieee80211_local *local) -{ -	lockdep_assert_held(&local->mtx); -} - -/* - * We can have multiple work items (and connection probing) - * scheduling this timer, but we need to take care to only - * reschedule it when it should fire _earlier_ than it was - * asked for before, or if it's not pending right now. This - * function ensures that. Note that it then is required to - * run this function for all timeouts after the first one - * has happened -- the work that runs from this timer will - * do that. - */ -static void run_again(struct ieee80211_local *local, -		      unsigned long timeout) -{ -	ASSERT_WORK_MTX(local); - -	if (!timer_pending(&local->work_timer) || -	    time_before(timeout, local->work_timer.expires)) -		mod_timer(&local->work_timer, timeout); -} - -void free_work(struct ieee80211_work *wk) -{ -	kfree_rcu(wk, rcu_head); -} - -static enum work_action __must_check -ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) -{ -	/* -	 * First time we run, do nothing -- the generic code will -	 * have switched to the right channel etc. -	 */ -	if (!wk->started) { -		wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration); - -		cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk, -					  wk->chan, wk->chan_type, -					  wk->remain.duration, GFP_KERNEL); - -		return WORK_ACT_NONE; -	} - -	return WORK_ACT_TIMEOUT; -} - -static enum work_action __must_check -ieee80211_offchannel_tx(struct ieee80211_work *wk) -{ -	if (!wk->started) { -		wk->timeout = jiffies + msecs_to_jiffies(wk->offchan_tx.wait); - -		/* -		 * After this, offchan_tx.frame remains but now is no -		 * longer a valid pointer -- we still need it as the -		 * cookie for canceling this work/status matching. -		 */ -		ieee80211_tx_skb(wk->sdata, wk->offchan_tx.frame); - -		return WORK_ACT_NONE; -	} - -	return WORK_ACT_TIMEOUT; -} - -static void ieee80211_work_timer(unsigned long data) -{ -	struct ieee80211_local *local = (void *) data; - -	if (local->quiescing) -		return; - -	ieee80211_queue_work(&local->hw, &local->work_work); -} - -static void ieee80211_work_work(struct work_struct *work) -{ -	struct ieee80211_local *local = -		container_of(work, struct ieee80211_local, work_work); -	struct ieee80211_work *wk, *tmp; -	LIST_HEAD(free_work); -	enum work_action rma; -	bool remain_off_channel = false; - -	/* -	 * ieee80211_queue_work() should have picked up most cases, -	 * here we'll pick the rest. -	 */ -	if (WARN(local->suspended, "work scheduled while going to suspend\n")) -		return; - -	mutex_lock(&local->mtx); - -	if (local->scanning) { -		mutex_unlock(&local->mtx); -		return; -	} - -	ieee80211_recalc_idle(local); - -	list_for_each_entry_safe(wk, tmp, &local->work_list, list) { -		bool started = wk->started; - -		/* mark work as started if it's on the current off-channel */ -		if (!started && local->tmp_channel && -		    wk->chan == local->tmp_channel && -		    wk->chan_type == local->tmp_channel_type) { -			started = true; -			wk->timeout = jiffies; -		} - -		if (!started && !local->tmp_channel) { -			ieee80211_offchannel_stop_vifs(local, true); - -			local->tmp_channel = wk->chan; -			local->tmp_channel_type = wk->chan_type; - -			ieee80211_hw_config(local, 0); - -			started = true; -			wk->timeout = jiffies; -		} - -		/* don't try to work with items that aren't started */ -		if (!started) -			continue; - -		if (time_is_after_jiffies(wk->timeout)) { -			/* -			 * This work item isn't supposed to be worked on -			 * right now, but take care to adjust the timer -			 * properly. -			 */ -			run_again(local, wk->timeout); -			continue; -		} - -		switch (wk->type) { -		default: -			WARN_ON(1); -			/* nothing */ -			rma = WORK_ACT_NONE; -			break; -		case IEEE80211_WORK_ABORT: -			rma = WORK_ACT_TIMEOUT; -			break; -		case IEEE80211_WORK_REMAIN_ON_CHANNEL: -			rma = ieee80211_remain_on_channel_timeout(wk); -			break; -		case IEEE80211_WORK_OFFCHANNEL_TX: -			rma = ieee80211_offchannel_tx(wk); -			break; -		} - -		wk->started = started; - -		switch (rma) { -		case WORK_ACT_NONE: -			/* might have changed the timeout */ -			run_again(local, wk->timeout); -			break; -		case WORK_ACT_TIMEOUT: -			list_del_rcu(&wk->list); -			synchronize_rcu(); -			list_add(&wk->list, &free_work); -			break; -		default: -			WARN(1, "unexpected: %d", rma); -		} -	} - -	list_for_each_entry(wk, &local->work_list, list) { -		if (!wk->started) -			continue; -		if (wk->chan != local->tmp_channel || -		    wk->chan_type != local->tmp_channel_type) -			continue; -		remain_off_channel = true; -	} - -	if (!remain_off_channel && local->tmp_channel) { -		local->tmp_channel = NULL; -		ieee80211_hw_config(local, 0); - -		ieee80211_offchannel_return(local, true); - -		/* give connection some time to breathe */ -		run_again(local, jiffies + HZ/2); -	} - -	ieee80211_recalc_idle(local); -	ieee80211_run_deferred_scan(local); - -	mutex_unlock(&local->mtx); - -	list_for_each_entry_safe(wk, tmp, &free_work, list) { -		wk->done(wk, NULL); -		list_del(&wk->list); -		kfree(wk); -	} -} - -void ieee80211_add_work(struct ieee80211_work *wk) -{ -	struct ieee80211_local *local; - -	if (WARN_ON(!wk->chan)) -		return; - -	if (WARN_ON(!wk->sdata)) -		return; - -	if (WARN_ON(!wk->done)) -		return; - -	if (WARN_ON(!ieee80211_sdata_running(wk->sdata))) -		return; - -	wk->started = false; - -	local = wk->sdata->local; -	mutex_lock(&local->mtx); -	list_add_tail(&wk->list, &local->work_list); -	mutex_unlock(&local->mtx); - -	ieee80211_queue_work(&local->hw, &local->work_work); -} - -void ieee80211_work_init(struct ieee80211_local *local) -{ -	INIT_LIST_HEAD(&local->work_list); -	setup_timer(&local->work_timer, ieee80211_work_timer, -		    (unsigned long)local); -	INIT_WORK(&local->work_work, ieee80211_work_work); -} - -void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) -{ -	struct ieee80211_local *local = sdata->local; -	struct ieee80211_work *wk; -	bool cleanup = false; - -	mutex_lock(&local->mtx); -	list_for_each_entry(wk, &local->work_list, list) { -		if (wk->sdata != sdata) -			continue; -		cleanup = true; -		wk->type = IEEE80211_WORK_ABORT; -		wk->started = true; -		wk->timeout = jiffies; -	} -	mutex_unlock(&local->mtx); - -	/* run cleanups etc. */ -	if (cleanup) -		ieee80211_work_work(&local->work_work); - -	mutex_lock(&local->mtx); -	list_for_each_entry(wk, &local->work_list, list) { -		if (wk->sdata != sdata) -			continue; -		WARN_ON(1); -		break; -	} -	mutex_unlock(&local->mtx); -} - -static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk, -						   struct sk_buff *skb) -{ -	/* -	 * We are done serving the remain-on-channel command. -	 */ -	cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk, -					   wk->chan, wk->chan_type, -					   GFP_KERNEL); - -	return WORK_DONE_DESTROY; -} - -int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, -				   struct ieee80211_channel *chan, -				   enum nl80211_channel_type channel_type, -				   unsigned int duration, u64 *cookie) -{ -	struct ieee80211_work *wk; - -	wk = kzalloc(sizeof(*wk), GFP_KERNEL); -	if (!wk) -		return -ENOMEM; - -	wk->type = IEEE80211_WORK_REMAIN_ON_CHANNEL; -	wk->chan = chan; -	wk->chan_type = channel_type; -	wk->sdata = sdata; -	wk->done = ieee80211_remain_done; - -	wk->remain.duration = duration; - -	*cookie = (unsigned long) wk; - -	ieee80211_add_work(wk); - -	return 0; -} - -int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata, -					  u64 cookie) -{ -	struct ieee80211_local *local = sdata->local; -	struct ieee80211_work *wk, *tmp; -	bool found = false; - -	mutex_lock(&local->mtx); -	list_for_each_entry_safe(wk, tmp, &local->work_list, list) { -		if ((unsigned long) wk == cookie) { -			wk->timeout = jiffies; -			found = true; -			break; -		} -	} -	mutex_unlock(&local->mtx); - -	if (!found) -		return -ENOENT; - -	ieee80211_queue_work(&local->hw, &local->work_work); - -	return 0; -}  |