 65835e0d5f
			
		
	
	65835e0d5f
	
	
	
		
			
			Refresh all patches. The removed patches were integrated upstream. This contains fixes for CVE-2020-3702 1. These patches (ath, ath9k, mac80211) were included in kernel versions since 4.14.245 and 4.19.205. They fix security vulnerability CVE-2020-3702 [1] similar to KrØØk, which was found by ESET [2]. Thank you Josef Schlehofer for reporting this problem. [1] https://nvd.nist.gov/vuln/detail/CVE-2020-3702 [2] https://www.welivesecurity.com/2020/08/06/beyond-kr00k-even-more-wifi-chips-vulnerable-eavesdropping/ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
		
			
				
	
	
		
			571 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			571 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From: Felix Fietkau <nbd@nbd.name>
 | |
| Date: Wed, 16 Dec 2020 21:34:03 +0100
 | |
| Subject: [PATCH] mac80211: add rx decapsulation offload support
 | |
| 
 | |
| This allows drivers to pass 802.3 frames to mac80211, with some restrictions:
 | |
| 
 | |
| - the skb must be passed with a valid sta
 | |
| - fast-rx needs to be active for the sta
 | |
| - monitor mode needs to be disabled
 | |
| 
 | |
| mac80211 will tell the driver when it is safe to enable rx decap offload for
 | |
| a particular station.
 | |
| 
 | |
| In order to implement support, a driver must:
 | |
| 
 | |
| - call ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD)
 | |
| - implement ops->sta_set_decap_offload
 | |
| - mark 802.3 frames with RX_FLAG_8023
 | |
| 
 | |
| If it doesn't want to enable offload for some vif types, it can mask out
 | |
| IEEE80211_OFFLOAD_DECAP_ENABLED in vif->offload_flags from within the
 | |
| .add_interface or .update_vif_offload driver ops
 | |
| 
 | |
| Signed-off-by: Felix Fietkau <nbd@nbd.name>
 | |
| ---
 | |
| 
 | |
| --- a/include/net/mac80211.h
 | |
| +++ b/include/net/mac80211.h
 | |
| @@ -1297,6 +1297,8 @@ ieee80211_tx_info_clear_status(struct ie
 | |
|   *	the "0-length PSDU" field included there.  The value for it is
 | |
|   *	in &struct ieee80211_rx_status.  Note that if this value isn't
 | |
|   *	known the frame shouldn't be reported.
 | |
| + * @RX_FLAG_8023: the frame has an 802.3 header (decap offload performed by
 | |
| + *	hardware or driver)
 | |
|   */
 | |
|  enum mac80211_rx_flags {
 | |
|  	RX_FLAG_MMIC_ERROR		= BIT(0),
 | |
| @@ -1329,6 +1331,7 @@ enum mac80211_rx_flags {
 | |
|  	RX_FLAG_RADIOTAP_HE_MU		= BIT(27),
 | |
|  	RX_FLAG_RADIOTAP_LSIG		= BIT(28),
 | |
|  	RX_FLAG_NO_PSDU			= BIT(29),
 | |
| +	RX_FLAG_8023			= BIT(30),
 | |
|  };
 | |
|  
 | |
|  /**
 | |
| @@ -1650,11 +1653,15 @@ enum ieee80211_vif_flags {
 | |
|   *	The driver supports sending frames passed as 802.3 frames by mac80211.
 | |
|   *	It must also support sending 802.11 packets for the same interface.
 | |
|   * @IEEE80211_OFFLOAD_ENCAP_4ADDR: support 4-address mode encapsulation offload
 | |
| + * @IEEE80211_OFFLOAD_DECAP_ENABLED: rx encapsulation offload is enabled
 | |
| + *	The driver supports passing received 802.11 frames as 802.3 frames to
 | |
| + *	mac80211.
 | |
|   */
 | |
|  
 | |
|  enum ieee80211_offload_flags {
 | |
|  	IEEE80211_OFFLOAD_ENCAP_ENABLED		= BIT(0),
 | |
|  	IEEE80211_OFFLOAD_ENCAP_4ADDR		= BIT(1),
 | |
| +	IEEE80211_OFFLOAD_DECAP_ENABLED		= BIT(2),
 | |
|  };
 | |
|  
 | |
|  /**
 | |
| @@ -2390,6 +2397,9 @@ struct ieee80211_txq {
 | |
|   * @IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD: Hardware supports tx encapsulation
 | |
|   *	offload
 | |
|   *
 | |
| + * @IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD: Hardware supports rx decapsulation
 | |
| + *	offload
 | |
| + *
 | |
|   * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
 | |
|   */
 | |
|  enum ieee80211_hw_flags {
 | |
| @@ -2443,6 +2453,7 @@ enum ieee80211_hw_flags {
 | |
|  	IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
 | |
|  	IEEE80211_HW_AMPDU_KEYBORDER_SUPPORT,
 | |
|  	IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD,
 | |
| +	IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD,
 | |
|  
 | |
|  	/* keep last, obviously */
 | |
|  	NUM_IEEE80211_HW_FLAGS
 | |
| @@ -4196,6 +4207,9 @@ struct ieee80211_ops {
 | |
|  				   struct ieee80211_vif *vif);
 | |
|  	void (*sta_set_4addr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 | |
|  			      struct ieee80211_sta *sta, bool enabled);
 | |
| +	void (*sta_set_decap_offload)(struct ieee80211_hw *hw,
 | |
| +				      struct ieee80211_vif *vif,
 | |
| +				      struct ieee80211_sta *sta, bool enabled);
 | |
|  };
 | |
|  
 | |
|  /**
 | |
| --- a/net/mac80211/debugfs.c
 | |
| +++ b/net/mac80211/debugfs.c
 | |
| @@ -405,6 +405,7 @@ static const char *hw_flag_names[] = {
 | |
|  	FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
 | |
|  	FLAG(AMPDU_KEYBORDER_SUPPORT),
 | |
|  	FLAG(SUPPORTS_TX_ENCAP_OFFLOAD),
 | |
| +	FLAG(SUPPORTS_RX_DECAP_OFFLOAD),
 | |
|  #undef FLAG
 | |
|  };
 | |
|  
 | |
| --- a/net/mac80211/debugfs_sta.c
 | |
| +++ b/net/mac80211/debugfs_sta.c
 | |
| @@ -79,6 +79,7 @@ static const char * const sta_flag_names
 | |
|  	FLAG(MPSP_RECIPIENT),
 | |
|  	FLAG(PS_DELIVER),
 | |
|  	FLAG(USES_ENCRYPTION),
 | |
| +	FLAG(DECAP_OFFLOAD),
 | |
|  #undef FLAG
 | |
|  };
 | |
|  
 | |
| --- a/net/mac80211/driver-ops.h
 | |
| +++ b/net/mac80211/driver-ops.h
 | |
| @@ -1413,4 +1413,20 @@ static inline void drv_sta_set_4addr(str
 | |
|  	trace_drv_return_void(local);
 | |
|  }
 | |
|  
 | |
| +static inline void drv_sta_set_decap_offload(struct ieee80211_local *local,
 | |
| +					     struct ieee80211_sub_if_data *sdata,
 | |
| +					     struct ieee80211_sta *sta,
 | |
| +					     bool enabled)
 | |
| +{
 | |
| +	sdata = get_bss_sdata(sdata);
 | |
| +	if (!check_sdata_in_driver(sdata))
 | |
| +		return;
 | |
| +
 | |
| +	trace_drv_sta_set_decap_offload(local, sdata, sta, enabled);
 | |
| +	if (local->ops->sta_set_decap_offload)
 | |
| +		local->ops->sta_set_decap_offload(&local->hw, &sdata->vif, sta,
 | |
| +						  enabled);
 | |
| +	trace_drv_return_void(local);
 | |
| +}
 | |
| +
 | |
|  #endif /* __MAC80211_DRIVER_OPS */
 | |
| --- a/net/mac80211/iface.c
 | |
| +++ b/net/mac80211/iface.c
 | |
| @@ -856,7 +856,7 @@ static const struct net_device_ops ieee8
 | |
|  
 | |
|  };
 | |
|  
 | |
| -static bool ieee80211_iftype_supports_encap_offload(enum nl80211_iftype iftype)
 | |
| +static bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype)
 | |
|  {
 | |
|  	switch (iftype) {
 | |
|  	/* P2P GO and client are mapped to AP/STATION types */
 | |
| @@ -876,7 +876,7 @@ static bool ieee80211_set_sdata_offload_
 | |
|  	flags = sdata->vif.offload_flags;
 | |
|  
 | |
|  	if (ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) &&
 | |
| -	    ieee80211_iftype_supports_encap_offload(sdata->vif.type)) {
 | |
| +	    ieee80211_iftype_supports_hdr_offload(sdata->vif.type)) {
 | |
|  		flags |= IEEE80211_OFFLOAD_ENCAP_ENABLED;
 | |
|  
 | |
|  		if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
 | |
| @@ -889,10 +889,21 @@ static bool ieee80211_set_sdata_offload_
 | |
|  		flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
 | |
|  	}
 | |
|  
 | |
| +	if (ieee80211_hw_check(&local->hw, SUPPORTS_RX_DECAP_OFFLOAD) &&
 | |
| +	    ieee80211_iftype_supports_hdr_offload(sdata->vif.type)) {
 | |
| +		flags |= IEEE80211_OFFLOAD_DECAP_ENABLED;
 | |
| +
 | |
| +		if (local->monitors)
 | |
| +			flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED;
 | |
| +	} else {
 | |
| +		flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED;
 | |
| +	}
 | |
| +
 | |
|  	if (sdata->vif.offload_flags == flags)
 | |
|  		return false;
 | |
|  
 | |
|  	sdata->vif.offload_flags = flags;
 | |
| +	ieee80211_check_fast_rx_iface(sdata);
 | |
|  	return true;
 | |
|  }
 | |
|  
 | |
| @@ -910,7 +921,7 @@ static void ieee80211_set_vif_encap_ops(
 | |
|  	}
 | |
|  
 | |
|  	if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) ||
 | |
| -	    !ieee80211_iftype_supports_encap_offload(bss->vif.type))
 | |
| +	    !ieee80211_iftype_supports_hdr_offload(bss->vif.type))
 | |
|  		return;
 | |
|  
 | |
|  	enabled = bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED;
 | |
| --- a/net/mac80211/rx.c
 | |
| +++ b/net/mac80211/rx.c
 | |
| @@ -4195,7 +4195,9 @@ void ieee80211_check_fast_rx(struct sta_
 | |
|  		.vif_type = sdata->vif.type,
 | |
|  		.control_port_protocol = sdata->control_port_protocol,
 | |
|  	}, *old, *new = NULL;
 | |
| +	bool set_offload = false;
 | |
|  	bool assign = false;
 | |
| +	bool offload;
 | |
|  
 | |
|  	/* use sparse to check that we don't return without updating */
 | |
|  	__acquire(check_fast_rx);
 | |
| @@ -4308,6 +4310,17 @@ void ieee80211_check_fast_rx(struct sta_
 | |
|  	if (assign)
 | |
|  		new = kmemdup(&fastrx, sizeof(fastrx), GFP_KERNEL);
 | |
|  
 | |
| +	offload = assign &&
 | |
| +		  (sdata->vif.offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED);
 | |
| +
 | |
| +	if (offload)
 | |
| +		set_offload = !test_and_set_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD);
 | |
| +	else
 | |
| +		set_offload = test_and_clear_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD);
 | |
| +
 | |
| +	if (set_offload)
 | |
| +		drv_sta_set_decap_offload(local, sdata, &sta->sta, assign);
 | |
| +
 | |
|  	spin_lock_bh(&sta->lock);
 | |
|  	old = rcu_dereference_protected(sta->fast_rx, true);
 | |
|  	rcu_assign_pointer(sta->fast_rx, new);
 | |
| @@ -4354,6 +4367,108 @@ void ieee80211_check_fast_rx_iface(struc
 | |
|  	mutex_unlock(&local->sta_mtx);
 | |
|  }
 | |
|  
 | |
| +static void ieee80211_rx_8023(struct ieee80211_rx_data *rx,
 | |
| +			      struct ieee80211_fast_rx *fast_rx,
 | |
| +			      int orig_len)
 | |
| +{
 | |
| +	struct ieee80211_sta_rx_stats *stats;
 | |
| +	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
 | |
| +	struct sta_info *sta = rx->sta;
 | |
| +	struct sk_buff *skb = rx->skb;
 | |
| +	void *sa = skb->data + ETH_ALEN;
 | |
| +	void *da = skb->data;
 | |
| +
 | |
| +	stats = &sta->rx_stats;
 | |
| +	if (fast_rx->uses_rss)
 | |
| +		stats = this_cpu_ptr(sta->pcpu_rx_stats);
 | |
| +
 | |
| +	/* statistics part of ieee80211_rx_h_sta_process() */
 | |
| +	if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
 | |
| +		stats->last_signal = status->signal;
 | |
| +		if (!fast_rx->uses_rss)
 | |
| +			ewma_signal_add(&sta->rx_stats_avg.signal,
 | |
| +					-status->signal);
 | |
| +	}
 | |
| +
 | |
| +	if (status->chains) {
 | |
| +		int i;
 | |
| +
 | |
| +		stats->chains = status->chains;
 | |
| +		for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) {
 | |
| +			int signal = status->chain_signal[i];
 | |
| +
 | |
| +			if (!(status->chains & BIT(i)))
 | |
| +				continue;
 | |
| +
 | |
| +			stats->chain_signal_last[i] = signal;
 | |
| +			if (!fast_rx->uses_rss)
 | |
| +				ewma_signal_add(&sta->rx_stats_avg.chain_signal[i],
 | |
| +						-signal);
 | |
| +		}
 | |
| +	}
 | |
| +	/* end of statistics */
 | |
| +
 | |
| +	stats->last_rx = jiffies;
 | |
| +	stats->last_rate = sta_stats_encode_rate(status);
 | |
| +
 | |
| +	stats->fragments++;
 | |
| +	stats->packets++;
 | |
| +
 | |
| +	skb->dev = fast_rx->dev;
 | |
| +
 | |
| +	ieee80211_rx_stats(fast_rx->dev, skb->len);
 | |
| +
 | |
| +	/* The seqno index has the same property as needed
 | |
| +	 * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
 | |
| +	 * for non-QoS-data frames. Here we know it's a data
 | |
| +	 * frame, so count MSDUs.
 | |
| +	 */
 | |
| +	u64_stats_update_begin(&stats->syncp);
 | |
| +	stats->msdu[rx->seqno_idx]++;
 | |
| +	stats->bytes += orig_len;
 | |
| +	u64_stats_update_end(&stats->syncp);
 | |
| +
 | |
| +	if (fast_rx->internal_forward) {
 | |
| +		struct sk_buff *xmit_skb = NULL;
 | |
| +		if (is_multicast_ether_addr(da)) {
 | |
| +			xmit_skb = skb_copy(skb, GFP_ATOMIC);
 | |
| +		} else if (!ether_addr_equal(da, sa) &&
 | |
| +			   sta_info_get(rx->sdata, da)) {
 | |
| +			xmit_skb = skb;
 | |
| +			skb = NULL;
 | |
| +		}
 | |
| +
 | |
| +		if (xmit_skb) {
 | |
| +			/*
 | |
| +			 * Send to wireless media and increase priority by 256
 | |
| +			 * to keep the received priority instead of
 | |
| +			 * reclassifying the frame (see cfg80211_classify8021d).
 | |
| +			 */
 | |
| +			xmit_skb->priority += 256;
 | |
| +			xmit_skb->protocol = htons(ETH_P_802_3);
 | |
| +			skb_reset_network_header(xmit_skb);
 | |
| +			skb_reset_mac_header(xmit_skb);
 | |
| +			dev_queue_xmit(xmit_skb);
 | |
| +		}
 | |
| +
 | |
| +		if (!skb)
 | |
| +			return;
 | |
| +	}
 | |
| +
 | |
| +	/* deliver to local stack */
 | |
| +	skb->protocol = eth_type_trans(skb, fast_rx->dev);
 | |
| +	memset(skb->cb, 0, sizeof(skb->cb));
 | |
| +	if (rx->list)
 | |
| +#if LINUX_VERSION_IS_GEQ(4,19,0)
 | |
| +		list_add_tail(&skb->list, rx->list);
 | |
| +#else
 | |
| +		__skb_queue_tail(rx->list, skb);
 | |
| +#endif
 | |
| +	else
 | |
| +		netif_receive_skb(skb);
 | |
| +
 | |
| +}
 | |
| +
 | |
|  static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
 | |
|  				     struct ieee80211_fast_rx *fast_rx)
 | |
|  {
 | |
| @@ -4374,9 +4489,6 @@ static bool ieee80211_invoke_fast_rx(str
 | |
|  	} addrs __aligned(2);
 | |
|  	struct ieee80211_sta_rx_stats *stats = &sta->rx_stats;
 | |
|  
 | |
| -	if (fast_rx->uses_rss)
 | |
| -		stats = this_cpu_ptr(sta->pcpu_rx_stats);
 | |
| -
 | |
|  	/* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write
 | |
|  	 * to a common data structure; drivers can implement that per queue
 | |
|  	 * but we don't have that information in mac80211
 | |
| @@ -4450,32 +4562,6 @@ static bool ieee80211_invoke_fast_rx(str
 | |
|  	    pskb_trim(skb, skb->len - fast_rx->icv_len))
 | |
|  		goto drop;
 | |
|  
 | |
| -	/* statistics part of ieee80211_rx_h_sta_process() */
 | |
| -	if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
 | |
| -		stats->last_signal = status->signal;
 | |
| -		if (!fast_rx->uses_rss)
 | |
| -			ewma_signal_add(&sta->rx_stats_avg.signal,
 | |
| -					-status->signal);
 | |
| -	}
 | |
| -
 | |
| -	if (status->chains) {
 | |
| -		int i;
 | |
| -
 | |
| -		stats->chains = status->chains;
 | |
| -		for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) {
 | |
| -			int signal = status->chain_signal[i];
 | |
| -
 | |
| -			if (!(status->chains & BIT(i)))
 | |
| -				continue;
 | |
| -
 | |
| -			stats->chain_signal_last[i] = signal;
 | |
| -			if (!fast_rx->uses_rss)
 | |
| -				ewma_signal_add(&sta->rx_stats_avg.chain_signal[i],
 | |
| -						-signal);
 | |
| -		}
 | |
| -	}
 | |
| -	/* end of statistics */
 | |
| -
 | |
|  	if (rx->key && !ieee80211_has_protected(hdr->frame_control))
 | |
|  		goto drop;
 | |
|  
 | |
| @@ -4487,12 +4573,6 @@ static bool ieee80211_invoke_fast_rx(str
 | |
|  		return true;
 | |
|  	}
 | |
|  
 | |
| -	stats->last_rx = jiffies;
 | |
| -	stats->last_rate = sta_stats_encode_rate(status);
 | |
| -
 | |
| -	stats->fragments++;
 | |
| -	stats->packets++;
 | |
| -
 | |
|  	/* do the header conversion - first grab the addresses */
 | |
|  	ether_addr_copy(addrs.da, skb->data + fast_rx->da_offs);
 | |
|  	ether_addr_copy(addrs.sa, skb->data + fast_rx->sa_offs);
 | |
| @@ -4501,62 +4581,14 @@ static bool ieee80211_invoke_fast_rx(str
 | |
|  	/* push the addresses in front */
 | |
|  	memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs));
 | |
|  
 | |
| -	skb->dev = fast_rx->dev;
 | |
| -
 | |
| -	ieee80211_rx_stats(fast_rx->dev, skb->len);
 | |
| -
 | |
| -	/* The seqno index has the same property as needed
 | |
| -	 * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
 | |
| -	 * for non-QoS-data frames. Here we know it's a data
 | |
| -	 * frame, so count MSDUs.
 | |
| -	 */
 | |
| -	u64_stats_update_begin(&stats->syncp);
 | |
| -	stats->msdu[rx->seqno_idx]++;
 | |
| -	stats->bytes += orig_len;
 | |
| -	u64_stats_update_end(&stats->syncp);
 | |
| -
 | |
| -	if (fast_rx->internal_forward) {
 | |
| -		struct sk_buff *xmit_skb = NULL;
 | |
| -		if (is_multicast_ether_addr(addrs.da)) {
 | |
| -			xmit_skb = skb_copy(skb, GFP_ATOMIC);
 | |
| -		} else if (!ether_addr_equal(addrs.da, addrs.sa) &&
 | |
| -			   sta_info_get(rx->sdata, addrs.da)) {
 | |
| -			xmit_skb = skb;
 | |
| -			skb = NULL;
 | |
| -		}
 | |
| -
 | |
| -		if (xmit_skb) {
 | |
| -			/*
 | |
| -			 * Send to wireless media and increase priority by 256
 | |
| -			 * to keep the received priority instead of
 | |
| -			 * reclassifying the frame (see cfg80211_classify8021d).
 | |
| -			 */
 | |
| -			xmit_skb->priority += 256;
 | |
| -			xmit_skb->protocol = htons(ETH_P_802_3);
 | |
| -			skb_reset_network_header(xmit_skb);
 | |
| -			skb_reset_mac_header(xmit_skb);
 | |
| -			dev_queue_xmit(xmit_skb);
 | |
| -		}
 | |
| -
 | |
| -		if (!skb)
 | |
| -			return true;
 | |
| -	}
 | |
| -
 | |
| -	/* deliver to local stack */
 | |
| -	skb->protocol = eth_type_trans(skb, fast_rx->dev);
 | |
| -	memset(skb->cb, 0, sizeof(skb->cb));
 | |
| -	if (rx->list)
 | |
| -#if LINUX_VERSION_IS_GEQ(4,19,0)
 | |
| -		list_add_tail(&skb->list, rx->list);
 | |
| -#else
 | |
| -		__skb_queue_tail(rx->list, skb);
 | |
| -#endif
 | |
| -	else
 | |
| -		netif_receive_skb(skb);
 | |
| +	ieee80211_rx_8023(rx, fast_rx, orig_len);
 | |
|  
 | |
|  	return true;
 | |
|   drop:
 | |
|  	dev_kfree_skb(skb);
 | |
| +	if (fast_rx->uses_rss)
 | |
| +		stats = this_cpu_ptr(sta->pcpu_rx_stats);
 | |
| +
 | |
|  	stats->dropped++;
 | |
|  	return true;
 | |
|  }
 | |
| @@ -4610,6 +4642,47 @@ static bool ieee80211_prepare_and_rx_han
 | |
|  	return true;
 | |
|  }
 | |
|  
 | |
| +static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw,
 | |
| +				       struct ieee80211_sta *pubsta,
 | |
| +				       struct sk_buff *skb,
 | |
| +#if LINUX_VERSION_IS_GEQ(4,19,0)
 | |
| +				       struct list_head *list)
 | |
| +#else
 | |
| +				       struct sk_buff_head *list)
 | |
| +#endif
 | |
| +{
 | |
| +	struct ieee80211_local *local = hw_to_local(hw);
 | |
| +	struct ieee80211_fast_rx *fast_rx;
 | |
| +	struct ieee80211_rx_data rx;
 | |
| +
 | |
| +	memset(&rx, 0, sizeof(rx));
 | |
| +	rx.skb = skb;
 | |
| +	rx.local = local;
 | |
| +	rx.list = list;
 | |
| +
 | |
| +	I802_DEBUG_INC(local->dot11ReceivedFragmentCount);
 | |
| +
 | |
| +	/* drop frame if too short for header */
 | |
| +	if (skb->len < sizeof(struct ethhdr))
 | |
| +		goto drop;
 | |
| +
 | |
| +	if (!pubsta)
 | |
| +		goto drop;
 | |
| +
 | |
| +	rx.sta = container_of(pubsta, struct sta_info, sta);
 | |
| +	rx.sdata = rx.sta->sdata;
 | |
| +
 | |
| +	fast_rx = rcu_dereference(rx.sta->fast_rx);
 | |
| +	if (!fast_rx)
 | |
| +		goto drop;
 | |
| +
 | |
| +	ieee80211_rx_8023(&rx, fast_rx, skb->len);
 | |
| +	return;
 | |
| +
 | |
| +drop:
 | |
| +	dev_kfree_skb(skb);
 | |
| +}
 | |
| +
 | |
|  /*
 | |
|   * This is the actual Rx frames handler. as it belongs to Rx path it must
 | |
|   * be called with rcu_read_lock protection.
 | |
| @@ -4847,15 +4920,20 @@ void ieee80211_rx_list(struct ieee80211_
 | |
|  	 * if it was previously present.
 | |
|  	 * Also, frames with less than 16 bytes are dropped.
 | |
|  	 */
 | |
| -	skb = ieee80211_rx_monitor(local, skb, rate);
 | |
| -	if (!skb)
 | |
| -		return;
 | |
| +	if (!(status->flag & RX_FLAG_8023)) {
 | |
| +		skb = ieee80211_rx_monitor(local, skb, rate);
 | |
| +		if (!skb)
 | |
| +			return;
 | |
| +	}
 | |
|  
 | |
|  	ieee80211_tpt_led_trig_rx(local,
 | |
|  			((struct ieee80211_hdr *)skb->data)->frame_control,
 | |
|  			skb->len);
 | |
|  
 | |
| -	__ieee80211_rx_handle_packet(hw, pubsta, skb, list);
 | |
| +	if (status->flag & RX_FLAG_8023)
 | |
| +		__ieee80211_rx_handle_8023(hw, pubsta, skb, list);
 | |
| +	else
 | |
| +		__ieee80211_rx_handle_packet(hw, pubsta, skb, list);
 | |
|  
 | |
|  	return;
 | |
|   drop:
 | |
| --- a/net/mac80211/sta_info.h
 | |
| +++ b/net/mac80211/sta_info.h
 | |
| @@ -71,6 +71,7 @@
 | |
|   *	until pending frames are delivered
 | |
|   * @WLAN_STA_USES_ENCRYPTION: This station was configured for encryption,
 | |
|   *	so drop all packets without a key later.
 | |
| + * @WLAN_STA_DECAP_OFFLOAD: This station uses rx decap offload
 | |
|   *
 | |
|   * @NUM_WLAN_STA_FLAGS: number of defined flags
 | |
|   */
 | |
| @@ -102,6 +103,7 @@ enum ieee80211_sta_info_flags {
 | |
|  	WLAN_STA_MPSP_RECIPIENT,
 | |
|  	WLAN_STA_PS_DELIVER,
 | |
|  	WLAN_STA_USES_ENCRYPTION,
 | |
| +	WLAN_STA_DECAP_OFFLOAD,
 | |
|  
 | |
|  	NUM_WLAN_STA_FLAGS,
 | |
|  };
 | |
| --- a/net/mac80211/trace.h
 | |
| +++ b/net/mac80211/trace.h
 | |
| @@ -2761,7 +2761,7 @@ DEFINE_EVENT(local_sdata_addr_evt, drv_u
 | |
|  	TP_ARGS(local, sdata)
 | |
|  );
 | |
|  
 | |
| -TRACE_EVENT(drv_sta_set_4addr,
 | |
| +DECLARE_EVENT_CLASS(sta_flag_evt,
 | |
|  	TP_PROTO(struct ieee80211_local *local,
 | |
|  		 struct ieee80211_sub_if_data *sdata,
 | |
|  		 struct ieee80211_sta *sta, bool enabled),
 | |
| @@ -2788,6 +2788,22 @@ TRACE_EVENT(drv_sta_set_4addr,
 | |
|  	)
 | |
|  );
 | |
|  
 | |
| +DEFINE_EVENT(sta_flag_evt, drv_sta_set_4addr,
 | |
| +	TP_PROTO(struct ieee80211_local *local,
 | |
| +		 struct ieee80211_sub_if_data *sdata,
 | |
| +		 struct ieee80211_sta *sta, bool enabled),
 | |
| +
 | |
| +	TP_ARGS(local, sdata, sta, enabled)
 | |
| +);
 | |
| +
 | |
| +DEFINE_EVENT(sta_flag_evt, drv_sta_set_decap_offload,
 | |
| +	TP_PROTO(struct ieee80211_local *local,
 | |
| +		 struct ieee80211_sub_if_data *sdata,
 | |
| +		 struct ieee80211_sta *sta, bool enabled),
 | |
| +
 | |
| +	TP_ARGS(local, sdata, sta, enabled)
 | |
| +);
 | |
| +
 | |
|  #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
 | |
|  
 | |
|  #undef TRACE_INCLUDE_PATH
 |