mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-30 21:44:27 -04:00 
			
		
		
		
	3.18.12 backported 61ada528dea028331e99e8ceaed87c683ad25de2 ("sched/wait:
Provide infrastructure to deal with nested blocking") from 3.19, causing
the following error on load:
[   13.588000] compat: exports duplicate symbol woken_wake_function (owned by kernel)
Fix this by guarding it with a check for 3.18.11 or earlier instead of
3.19.
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
SVN-Revision: 45710
		
	
			
		
			
				
	
	
		
			268 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			268 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From: Johannes Berg <johannes.berg@intel.com>
 | |
| Date: Fri, 20 Mar 2015 14:18:27 +0100
 | |
| Subject: [PATCH] mac80211: avoid duplicate TX path station lookup
 | |
| 
 | |
| Instead of looking up the destination station twice in the TX path
 | |
| (first to build the header, and then for control processing), save
 | |
| it when building the header and use it later in the TX path.
 | |
| 
 | |
| To avoid having to look up the station in the many callers, allow
 | |
| those to pass %NULL which keeps the existing lookup.
 | |
| 
 | |
| Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 | |
| ---
 | |
| 
 | |
| --- a/net/mac80211/cfg.c
 | |
| +++ b/net/mac80211/cfg.c
 | |
| @@ -3565,7 +3565,7 @@ static int ieee80211_probe_client(struct
 | |
|  		nullfunc->qos_ctrl = cpu_to_le16(7);
 | |
|  
 | |
|  	local_bh_disable();
 | |
| -	ieee80211_xmit(sdata, skb);
 | |
| +	ieee80211_xmit(sdata, sta, skb);
 | |
|  	local_bh_enable();
 | |
|  	rcu_read_unlock();
 | |
|  
 | |
| --- a/net/mac80211/ieee80211_i.h
 | |
| +++ b/net/mac80211/ieee80211_i.h
 | |
| @@ -1775,7 +1775,8 @@ void mac80211_ev_michael_mic_failure(str
 | |
|  				     gfp_t gfp);
 | |
|  void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
 | |
|  			       bool bss_notify);
 | |
| -void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
 | |
| +void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 | |
| +		    struct sta_info *sta, struct sk_buff *skb);
 | |
|  
 | |
|  void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
 | |
|  				 struct sk_buff *skb, int tid,
 | |
| --- a/net/mac80211/sta_info.c
 | |
| +++ b/net/mac80211/sta_info.c
 | |
| @@ -1279,7 +1279,7 @@ static void ieee80211_send_null_response
 | |
|  	}
 | |
|  
 | |
|  	info->band = chanctx_conf->def.chan->band;
 | |
| -	ieee80211_xmit(sdata, skb);
 | |
| +	ieee80211_xmit(sdata, sta, skb);
 | |
|  	rcu_read_unlock();
 | |
|  }
 | |
|  
 | |
| --- a/net/mac80211/tx.c
 | |
| +++ b/net/mac80211/tx.c
 | |
| @@ -1110,11 +1110,13 @@ static bool ieee80211_tx_prep_agg(struct
 | |
|  
 | |
|  /*
 | |
|   * initialises @tx
 | |
| + * pass %NULL for the station if unknown, a valid pointer if known
 | |
| + * or an ERR_PTR() if the station is known not to exist
 | |
|   */
 | |
|  static ieee80211_tx_result
 | |
|  ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 | |
|  		     struct ieee80211_tx_data *tx,
 | |
| -		     struct sk_buff *skb)
 | |
| +		     struct sta_info *sta, struct sk_buff *skb)
 | |
|  {
 | |
|  	struct ieee80211_local *local = sdata->local;
 | |
|  	struct ieee80211_hdr *hdr;
 | |
| @@ -1137,17 +1139,22 @@ ieee80211_tx_prepare(struct ieee80211_su
 | |
|  
 | |
|  	hdr = (struct ieee80211_hdr *) skb->data;
 | |
|  
 | |
| -	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
 | |
| -		tx->sta = rcu_dereference(sdata->u.vlan.sta);
 | |
| -		if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr)
 | |
| -			return TX_DROP;
 | |
| -	} else if (info->flags & (IEEE80211_TX_CTL_INJECTED |
 | |
| -				  IEEE80211_TX_INTFL_NL80211_FRAME_TX) ||
 | |
| -		   tx->sdata->control_port_protocol == tx->skb->protocol) {
 | |
| -		tx->sta = sta_info_get_bss(sdata, hdr->addr1);
 | |
| +	if (likely(sta)) {
 | |
| +		if (!IS_ERR(sta))
 | |
| +			tx->sta = sta;
 | |
| +	} else {
 | |
| +		if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
 | |
| +			tx->sta = rcu_dereference(sdata->u.vlan.sta);
 | |
| +			if (!tx->sta && sdata->wdev.use_4addr)
 | |
| +				return TX_DROP;
 | |
| +		} else if (info->flags & (IEEE80211_TX_INTFL_NL80211_FRAME_TX |
 | |
| +					  IEEE80211_TX_CTL_INJECTED) ||
 | |
| +			   tx->sdata->control_port_protocol == tx->skb->protocol) {
 | |
| +			tx->sta = sta_info_get_bss(sdata, hdr->addr1);
 | |
| +		}
 | |
| +		if (!tx->sta && !is_multicast_ether_addr(hdr->addr1))
 | |
| +			tx->sta = sta_info_get(sdata, hdr->addr1);
 | |
|  	}
 | |
| -	if (!tx->sta && !is_multicast_ether_addr(hdr->addr1))
 | |
| -		tx->sta = sta_info_get(sdata, hdr->addr1);
 | |
|  
 | |
|  	if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
 | |
|  	    !ieee80211_is_qos_nullfunc(hdr->frame_control) &&
 | |
| @@ -1485,7 +1492,7 @@ bool ieee80211_tx_prepare_skb(struct iee
 | |
|  	struct ieee80211_tx_data tx;
 | |
|  	struct sk_buff *skb2;
 | |
|  
 | |
| -	if (ieee80211_tx_prepare(sdata, &tx, skb) == TX_DROP)
 | |
| +	if (ieee80211_tx_prepare(sdata, &tx, NULL, skb) == TX_DROP)
 | |
|  		return false;
 | |
|  
 | |
|  	info->band = band;
 | |
| @@ -1518,7 +1525,8 @@ EXPORT_SYMBOL(ieee80211_tx_prepare_skb);
 | |
|   * Returns false if the frame couldn't be transmitted but was queued instead.
 | |
|   */
 | |
|  static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
 | |
| -			 struct sk_buff *skb, bool txpending)
 | |
| +			 struct sta_info *sta, struct sk_buff *skb,
 | |
| +			 bool txpending)
 | |
|  {
 | |
|  	struct ieee80211_local *local = sdata->local;
 | |
|  	struct ieee80211_tx_data tx;
 | |
| @@ -1534,7 +1542,7 @@ static bool ieee80211_tx(struct ieee8021
 | |
|  
 | |
|  	/* initialises tx */
 | |
|  	led_len = skb->len;
 | |
| -	res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
 | |
| +	res_prepare = ieee80211_tx_prepare(sdata, &tx, sta, skb);
 | |
|  
 | |
|  	if (unlikely(res_prepare == TX_DROP)) {
 | |
|  		ieee80211_free_txskb(&local->hw, skb);
 | |
| @@ -1590,7 +1598,8 @@ static int ieee80211_skb_resize(struct i
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
| -void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
 | |
| +void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 | |
| +		    struct sta_info *sta, struct sk_buff *skb)
 | |
|  {
 | |
|  	struct ieee80211_local *local = sdata->local;
 | |
|  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 | |
| @@ -1625,7 +1634,7 @@ void ieee80211_xmit(struct ieee80211_sub
 | |
|  	}
 | |
|  
 | |
|  	ieee80211_set_qos_hdr(sdata, skb);
 | |
| -	ieee80211_tx(sdata, skb, false);
 | |
| +	ieee80211_tx(sdata, sta, skb, false);
 | |
|  }
 | |
|  
 | |
|  static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
 | |
| @@ -1846,7 +1855,7 @@ netdev_tx_t ieee80211_monitor_start_xmit
 | |
|  		goto fail_rcu;
 | |
|  
 | |
|  	info->band = chandef->chan->band;
 | |
| -	ieee80211_xmit(sdata, skb);
 | |
| +	ieee80211_xmit(sdata, NULL, skb);
 | |
|  	rcu_read_unlock();
 | |
|  
 | |
|  	return NETDEV_TX_OK;
 | |
| @@ -1877,7 +1886,8 @@ fail:
 | |
|   * Returns: the (possibly reallocated) skb or an ERR_PTR() code
 | |
|   */
 | |
|  static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
 | |
| -					   struct sk_buff *skb, u32 info_flags)
 | |
| +					   struct sk_buff *skb, u32 info_flags,
 | |
| +					   struct sta_info **sta_out)
 | |
|  {
 | |
|  	struct ieee80211_local *local = sdata->local;
 | |
|  	struct ieee80211_tx_info *info;
 | |
| @@ -1920,6 +1930,7 @@ static struct sk_buff *ieee80211_build_h
 | |
|  			authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
 | |
|  			wme_sta = sta->sta.wme;
 | |
|  			have_station = true;
 | |
| +			*sta_out = sta;
 | |
|  		} else if (sdata->wdev.use_4addr) {
 | |
|  			ret = -ENOLINK;
 | |
|  			goto free;
 | |
| @@ -2073,6 +2084,7 @@ static struct sk_buff *ieee80211_build_h
 | |
|  			have_station = true;
 | |
|  			authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
 | |
|  			wme_sta = sta->sta.wme;
 | |
| +			*sta_out = sta;
 | |
|  		}  else if (sdata->u.mgd.use_4addr &&
 | |
|  			    cpu_to_be16(ethertype) != sdata->control_port_protocol) {
 | |
|  			fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
 | |
| @@ -2136,13 +2148,18 @@ static struct sk_buff *ieee80211_build_h
 | |
|  	 * and mesh mode checks authorization later.
 | |
|  	 */
 | |
|  	multicast = is_multicast_ether_addr(hdr.addr1);
 | |
| -	if (!multicast && !have_station &&
 | |
| -	    !ieee80211_vif_is_mesh(&sdata->vif)) {
 | |
| -		sta = sta_info_get(sdata, hdr.addr1);
 | |
| +	if (multicast) {
 | |
| +		*sta_out = ERR_PTR(-ENOENT);
 | |
| +	} else if (!have_station && !ieee80211_vif_is_mesh(&sdata->vif)) {
 | |
| +		if (sdata->control_port_protocol == skb->protocol)
 | |
| +			sta = sta_info_get_bss(sdata, hdr.addr1);
 | |
| +		else
 | |
| +			sta = sta_info_get(sdata, hdr.addr1);
 | |
|  		if (sta) {
 | |
|  			authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
 | |
|  			wme_sta = sta->sta.wme;
 | |
|  		}
 | |
| +		*sta_out = sta ?: ERR_PTR(-ENOENT);
 | |
|  	}
 | |
|  
 | |
|  	/* For mesh, the use of the QoS header is mandatory */
 | |
| @@ -2320,6 +2337,7 @@ void __ieee80211_subif_start_xmit(struct
 | |
|  				  u32 info_flags)
 | |
|  {
 | |
|  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 | |
| +	struct sta_info *sta = NULL;
 | |
|  
 | |
|  	if (unlikely(skb->len < ETH_HLEN)) {
 | |
|  		kfree_skb(skb);
 | |
| @@ -2328,7 +2346,7 @@ void __ieee80211_subif_start_xmit(struct
 | |
|  
 | |
|  	rcu_read_lock();
 | |
|  
 | |
| -	skb = ieee80211_build_hdr(sdata, skb, info_flags);
 | |
| +	skb = ieee80211_build_hdr(sdata, skb, info_flags, &sta);
 | |
|  	if (IS_ERR(skb))
 | |
|  		goto out;
 | |
|  
 | |
| @@ -2336,7 +2354,7 @@ void __ieee80211_subif_start_xmit(struct
 | |
|  	dev->stats.tx_bytes += skb->len;
 | |
|  	dev->trans_start = jiffies;
 | |
|  
 | |
| -	ieee80211_xmit(sdata, skb);
 | |
| +	ieee80211_xmit(sdata, sta, skb);
 | |
|   out:
 | |
|  	rcu_read_unlock();
 | |
|  }
 | |
| @@ -2364,10 +2382,11 @@ ieee80211_build_data_template(struct iee
 | |
|  		.local = sdata->local,
 | |
|  		.sdata = sdata,
 | |
|  	};
 | |
| +	struct sta_info *sta_ignore;
 | |
|  
 | |
|  	rcu_read_lock();
 | |
|  
 | |
| -	skb = ieee80211_build_hdr(sdata, skb, info_flags);
 | |
| +	skb = ieee80211_build_hdr(sdata, skb, info_flags, &sta_ignore);
 | |
|  	if (IS_ERR(skb))
 | |
|  		goto out;
 | |
|  
 | |
| @@ -2425,7 +2444,7 @@ static bool ieee80211_tx_pending_skb(str
 | |
|  			return true;
 | |
|  		}
 | |
|  		info->band = chanctx_conf->def.chan->band;
 | |
| -		result = ieee80211_tx(sdata, skb, true);
 | |
| +		result = ieee80211_tx(sdata, NULL, skb, true);
 | |
|  	} else {
 | |
|  		struct sk_buff_head skbs;
 | |
|  
 | |
| @@ -3163,7 +3182,7 @@ ieee80211_get_buffered_bc(struct ieee802
 | |
|  
 | |
|  		if (sdata->vif.type == NL80211_IFTYPE_AP)
 | |
|  			sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
 | |
| -		if (!ieee80211_tx_prepare(sdata, &tx, skb))
 | |
| +		if (!ieee80211_tx_prepare(sdata, &tx, NULL, skb))
 | |
|  			break;
 | |
|  		dev_kfree_skb_any(skb);
 | |
|  	}
 | |
| @@ -3295,6 +3314,6 @@ void __ieee80211_tx_skb_tid_band(struct
 | |
|  	 */
 | |
|  	local_bh_disable();
 | |
|  	IEEE80211_SKB_CB(skb)->band = band;
 | |
| -	ieee80211_xmit(sdata, skb);
 | |
| +	ieee80211_xmit(sdata, NULL, skb);
 | |
|  	local_bh_enable();
 | |
|  }
 |