diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 11:47:02 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 11:47:02 -0700 | 
| commit | 5f05647dd81c11a6a165ccc8f0c1370b16f3bcb0 (patch) | |
| tree | 7851ef1c93aa1aba7ef327ca4b75fd35e6d10f29 /net/mac80211/rx.c | |
| parent | 02f36038c568111ad4fc433f6fa760ff5e38fab4 (diff) | |
| parent | ec37a48d1d16c30b655ac5280209edf52a6775d4 (diff) | |
| download | olio-linux-3.10-5f05647dd81c11a6a165ccc8f0c1370b16f3bcb0.tar.xz olio-linux-3.10-5f05647dd81c11a6a165ccc8f0c1370b16f3bcb0.zip  | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1699 commits)
  bnx2/bnx2x: Unsupported Ethtool operations should return -EINVAL.
  vlan: Calling vlan_hwaccel_do_receive() is always valid.
  tproxy: use the interface primary IP address as a default value for --on-ip
  tproxy: added IPv6 support to the socket match
  cxgb3: function namespace cleanup
  tproxy: added IPv6 support to the TPROXY target
  tproxy: added IPv6 socket lookup function to nf_tproxy_core
  be2net: Changes to use only priority codes allowed by f/w
  tproxy: allow non-local binds of IPv6 sockets if IP_TRANSPARENT is enabled
  tproxy: added tproxy sockopt interface in the IPV6 layer
  tproxy: added udp6_lib_lookup function
  tproxy: added const specifiers to udp lookup functions
  tproxy: split off ipv6 defragmentation to a separate module
  l2tp: small cleanup
  nf_nat: restrict ICMP translation for embedded header
  can: mcp251x: fix generation of error frames
  can: mcp251x: fix endless loop in interrupt handler if CANINTF_MERRF is set
  can-raw: add msg_flags to distinguish local traffic
  9p: client code cleanup
  rds: make local functions/variables static
  ...
Fix up conflicts in net/core/dev.c, drivers/net/pcmcia/smc91c92_cs.c and
drivers/net/wireless/ath/ath9k/debug.c as per David
Diffstat (limited to 'net/mac80211/rx.c')
| -rw-r--r-- | net/mac80211/rx.c | 819 | 
1 files changed, 520 insertions, 299 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 28624282c5f..902b03ee8f6 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -315,6 +315,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,  static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)  {  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; +	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);  	int tid;  	/* does the frame have a qos control field? */ @@ -323,9 +324,7 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)  		/* frame has qos control */  		tid = *qc & IEEE80211_QOS_CTL_TID_MASK;  		if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) -			rx->flags |= IEEE80211_RX_AMSDU; -		else -			rx->flags &= ~IEEE80211_RX_AMSDU; +			status->rx_flags |= IEEE80211_RX_AMSDU;  	} else {  		/*  		 * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"): @@ -387,26 +386,25 @@ 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 (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning))) +	if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN))) +		return RX_CONTINUE; + +	if (test_bit(SCAN_HW_SCANNING, &local->scanning))  		return ieee80211_scan_rx(rx->sdata, skb); -	if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning) && -		     (rx->flags & IEEE80211_RX_IN_SCAN))) { +	if (test_bit(SCAN_SW_SCANNING, &local->scanning)) {  		/* drop all the other packets during a software scan anyway */  		if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED)  			dev_kfree_skb(skb);  		return RX_QUEUED;  	} -	if (unlikely(rx->flags & IEEE80211_RX_IN_SCAN)) { -		/* scanning finished during invoking of handlers */ -		I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); -		return RX_DROP_UNUSABLE; -	} - -	return RX_CONTINUE; +	/* scanning finished during invoking of handlers */ +	I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); +	return RX_DROP_UNUSABLE;  } @@ -538,20 +536,12 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,  					    int index,  					    struct sk_buff_head *frames)  { -	struct ieee80211_supported_band *sband; -	struct ieee80211_rate *rate = NULL;  	struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; -	struct ieee80211_rx_status *status;  	if (!skb)  		goto no_frame; -	status = IEEE80211_SKB_RXCB(skb); - -	/* release the reordered frames to stack */ -	sband = hw->wiphy->bands[status->band]; -	if (!(status->flag & RX_FLAG_HT)) -		rate = &sband->bitrates[status->rate_idx]; +	/* release the frame from the reorder ring buffer */  	tid_agg_rx->stored_mpdu_num--;  	tid_agg_rx->reorder_buf[index] = NULL;  	__skb_queue_tail(frames, skb); @@ -580,9 +570,102 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,   * frames that have not yet been received are assumed to be lost and the skb   * can be released for processing. This may also release other skb's from the   * reorder buffer if there are no additional gaps between the frames. + * + * Callers must hold tid_agg_rx->reorder_lock.   */  #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) +static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, +					  struct tid_ampdu_rx *tid_agg_rx, +					  struct sk_buff_head *frames) +{ +	int index, j; + +	/* release the buffer until next missing frame */ +	index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % +						tid_agg_rx->buf_size; +	if (!tid_agg_rx->reorder_buf[index] && +	    tid_agg_rx->stored_mpdu_num > 1) { +		/* +		 * No buffers ready to be released, but check whether any +		 * frames in the reorder buffer have timed out. +		 */ +		int skipped = 1; +		for (j = (index + 1) % tid_agg_rx->buf_size; j != index; +		     j = (j + 1) % tid_agg_rx->buf_size) { +			if (!tid_agg_rx->reorder_buf[j]) { +				skipped++; +				continue; +			} +			if (!time_after(jiffies, tid_agg_rx->reorder_time[j] + +					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, frames); + +			/* +			 * Increment the head seq# also for the skipped slots. +			 */ +			tid_agg_rx->head_seq_num = +				(tid_agg_rx->head_seq_num + skipped) & SEQ_MASK; +			skipped = 0; +		} +	} else while (tid_agg_rx->reorder_buf[index]) { +		ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames); +		index =	seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % +							tid_agg_rx->buf_size; +	} + +	/* +	 * Disable the reorder release timer for now. +	 * +	 * The current implementation lacks a proper locking scheme +	 * which would protect vital statistic and debug counters +	 * from being updated by two different but concurrent BHs. +	 * +	 * More information about the topic is available from: +	 * - thread: http://marc.info/?t=128635927000001 +	 * +	 * What was wrong: +	 * =>  http://marc.info/?l=linux-wireless&m=128636170811964 +	 * "Basically the thing is that until your patch, the data +	 *  in the struct didn't actually need locking because it +	 *  was accessed by the RX path only which is not concurrent." +	 * +	 * List of what needs to be fixed: +	 * => http://marc.info/?l=linux-wireless&m=128656352920957 +	 * + +	if (tid_agg_rx->stored_mpdu_num) { +		j = index = seq_sub(tid_agg_rx->head_seq_num, +				    tid_agg_rx->ssn) % tid_agg_rx->buf_size; + +		for (; j != (index - 1) % tid_agg_rx->buf_size; +		     j = (j + 1) % tid_agg_rx->buf_size) { +			if (tid_agg_rx->reorder_buf[j]) +				break; +		} + + set_release_timer: + +		mod_timer(&tid_agg_rx->reorder_timer, +			  tid_agg_rx->reorder_time[j] + +			  HT_RX_REORDER_BUF_TIMEOUT); +	} else { +		del_timer(&tid_agg_rx->reorder_timer); +	} +	*/ + +set_release_timer: +	return; +} +  /*   * As this function belongs to the RX path it must be under   * rcu_read_lock protection. It returns false if the frame @@ -598,14 +681,16 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,  	u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;  	u16 head_seq_num, buf_size;  	int index; +	bool ret = true;  	buf_size = tid_agg_rx->buf_size;  	head_seq_num = tid_agg_rx->head_seq_num; +	spin_lock(&tid_agg_rx->reorder_lock);  	/* frame with out of date sequence number */  	if (seq_less(mpdu_seq_num, head_seq_num)) {  		dev_kfree_skb(skb); -		return true; +		goto out;  	}  	/* @@ -626,7 +711,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,  	/* check if we already stored this frame */  	if (tid_agg_rx->reorder_buf[index]) {  		dev_kfree_skb(skb); -		return true; +		goto out;  	}  	/* @@ -636,58 +721,19 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,  	if (mpdu_seq_num == tid_agg_rx->head_seq_num &&  	    tid_agg_rx->stored_mpdu_num == 0) {  		tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); -		return false; +		ret = false; +		goto out;  	}  	/* put the frame in the reordering buffer */  	tid_agg_rx->reorder_buf[index] = skb;  	tid_agg_rx->reorder_time[index] = jiffies;  	tid_agg_rx->stored_mpdu_num++; -	/* release the buffer until next missing frame */ -	index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % -						tid_agg_rx->buf_size; -	if (!tid_agg_rx->reorder_buf[index] && -	    tid_agg_rx->stored_mpdu_num > 1) { -		/* -		 * No buffers ready to be released, but check whether any -		 * frames in the reorder buffer have timed out. -		 */ -		int j; -		int skipped = 1; -		for (j = (index + 1) % tid_agg_rx->buf_size; j != index; -		     j = (j + 1) % tid_agg_rx->buf_size) { -			if (!tid_agg_rx->reorder_buf[j]) { -				skipped++; -				continue; -			} -			if (!time_after(jiffies, tid_agg_rx->reorder_time[j] + -					HT_RX_REORDER_BUF_TIMEOUT)) -				break; - -#ifdef CONFIG_MAC80211_HT_DEBUG -			if (net_ratelimit()) -				printk(KERN_DEBUG "%s: release an RX reorder " -				       "frame due to timeout on earlier " -				       "frames\n", -				       wiphy_name(hw->wiphy)); -#endif -			ieee80211_release_reorder_frame(hw, tid_agg_rx, -							j, frames); +	ieee80211_sta_reorder_release(hw, tid_agg_rx, frames); -			/* -			 * Increment the head seq# also for the skipped slots. -			 */ -			tid_agg_rx->head_seq_num = -				(tid_agg_rx->head_seq_num + skipped) & SEQ_MASK; -			skipped = 0; -		} -	} else while (tid_agg_rx->reorder_buf[index]) { -		ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames); -		index =	seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % -							tid_agg_rx->buf_size; -	} - -	return true; + out: +	spin_unlock(&tid_agg_rx->reorder_lock); +	return ret;  }  /* @@ -761,13 +807,14 @@ static ieee80211_rx_result debug_noinline  ieee80211_rx_h_check(struct ieee80211_rx_data *rx)  {  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; +	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);  	/* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */  	if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {  		if (unlikely(ieee80211_has_retry(hdr->frame_control) &&  			     rx->sta->last_seq_ctrl[rx->queue] ==  			     hdr->seq_ctrl)) { -			if (rx->flags & IEEE80211_RX_RA_MATCH) { +			if (status->rx_flags & IEEE80211_RX_RA_MATCH) {  				rx->local->dot11FrameDuplicateCount++;  				rx->sta->num_duplicates++;  			} @@ -796,11 +843,12 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)  	if (unlikely((ieee80211_is_data(hdr->frame_control) ||  		      ieee80211_is_pspoll(hdr->frame_control)) &&  		     rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && +		     rx->sdata->vif.type != NL80211_IFTYPE_WDS &&  		     (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) {  		if ((!ieee80211_has_fromds(hdr->frame_control) &&  		     !ieee80211_has_tods(hdr->frame_control) &&  		     ieee80211_is_data(hdr->frame_control)) || -		    !(rx->flags & IEEE80211_RX_RA_MATCH)) { +		    !(status->rx_flags & IEEE80211_RX_RA_MATCH)) {  			/* Drop IBSS frames and frames for other hosts  			 * silently. */  			return RX_DROP_MONITOR; @@ -822,7 +870,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)  	int keyidx;  	int hdrlen;  	ieee80211_rx_result result = RX_DROP_UNUSABLE; -	struct ieee80211_key *stakey = NULL; +	struct ieee80211_key *sta_ptk = NULL;  	int mmie_keyidx = -1;  	__le16 fc; @@ -857,22 +905,25 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)  	 * No point in finding a key and decrypting if the frame is neither  	 * addressed to us nor a multicast frame.  	 */ -	if (!(rx->flags & IEEE80211_RX_RA_MATCH)) +	if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))  		return RX_CONTINUE;  	/* start without a key */  	rx->key = NULL;  	if (rx->sta) -		stakey = rcu_dereference(rx->sta->key); +		sta_ptk = rcu_dereference(rx->sta->ptk);  	fc = hdr->frame_control;  	if (!ieee80211_has_protected(fc))  		mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); -	if (!is_multicast_ether_addr(hdr->addr1) && stakey) { -		rx->key = stakey; +	if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) { +		rx->key = sta_ptk; +		if ((status->flag & RX_FLAG_DECRYPTED) && +		    (status->flag & RX_FLAG_IV_STRIPPED)) +			return RX_CONTINUE;  		/* Skip decryption if the frame is not protected. */  		if (!ieee80211_has_protected(fc))  			return RX_CONTINUE; @@ -885,7 +936,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)  		if (mmie_keyidx < NUM_DEFAULT_KEYS ||  		    mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)  			return RX_DROP_MONITOR; /* unexpected BIP keyidx */ -		rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]); +		if (rx->sta) +			rx->key = rcu_dereference(rx->sta->gtk[mmie_keyidx]); +		if (!rx->key) +			rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);  	} else if (!ieee80211_has_protected(fc)) {  		/*  		 * The frame was not protected, so skip decryption. However, we @@ -928,16 +982,25 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)  		skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);  		keyidx = keyid >> 6; -		rx->key = rcu_dereference(rx->sdata->keys[keyidx]); +		/* check per-station GTK first, if multicast packet */ +		if (is_multicast_ether_addr(hdr->addr1) && rx->sta) +			rx->key = rcu_dereference(rx->sta->gtk[keyidx]); -		/* -		 * RSNA-protected unicast frames should always be sent with -		 * pairwise or station-to-station keys, but for WEP we allow -		 * using a key index as well. -		 */ -		if (rx->key && rx->key->conf.alg != ALG_WEP && -		    !is_multicast_ether_addr(hdr->addr1)) -			rx->key = NULL; +		/* if not found, try default key */ +		if (!rx->key) { +			rx->key = rcu_dereference(rx->sdata->keys[keyidx]); + +			/* +			 * RSNA-protected unicast frames should always be +			 * sent with pairwise or station-to-station keys, +			 * but for WEP we allow using a key index as well. +			 */ +			if (rx->key && +			    rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 && +			    rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 && +			    !is_multicast_ether_addr(hdr->addr1)) +				rx->key = NULL; +		}  	}  	if (rx->key) { @@ -951,8 +1014,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)  		return RX_DROP_UNUSABLE;  	/* the hdr variable is invalid now! */ -	switch (rx->key->conf.alg) { -	case ALG_WEP: +	switch (rx->key->conf.cipher) { +	case WLAN_CIPHER_SUITE_WEP40: +	case WLAN_CIPHER_SUITE_WEP104:  		/* Check for weak IVs if possible */  		if (rx->sta && ieee80211_is_data(fc) &&  		    (!(status->flag & RX_FLAG_IV_STRIPPED) || @@ -962,15 +1026,21 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)  		result = ieee80211_crypto_wep_decrypt(rx);  		break; -	case ALG_TKIP: +	case WLAN_CIPHER_SUITE_TKIP:  		result = ieee80211_crypto_tkip_decrypt(rx);  		break; -	case ALG_CCMP: +	case WLAN_CIPHER_SUITE_CCMP:  		result = ieee80211_crypto_ccmp_decrypt(rx);  		break; -	case ALG_AES_CMAC: +	case WLAN_CIPHER_SUITE_AES_CMAC:  		result = ieee80211_crypto_aes_cmac_decrypt(rx);  		break; +	default: +		/* +		 * We can reach here only with HW-only algorithms +		 * but why didn't it decrypt the frame?! +		 */ +		return RX_DROP_UNUSABLE;  	}  	/* either the frame has been decrypted or will be dropped */ @@ -1079,7 +1149,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)  		sta->last_rx = jiffies;  	} -	if (!(rx->flags & IEEE80211_RX_RA_MATCH)) +	if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))  		return RX_CONTINUE;  	if (rx->sdata->vif.type == NL80211_IFTYPE_STATION) @@ -1236,6 +1306,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)  	unsigned int frag, seq;  	struct ieee80211_fragment_entry *entry;  	struct sk_buff *skb; +	struct ieee80211_rx_status *status;  	hdr = (struct ieee80211_hdr *)rx->skb->data;  	fc = hdr->frame_control; @@ -1265,7 +1336,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)  		/* This is the first fragment of a new frame. */  		entry = ieee80211_reassemble_add(rx->sdata, frag, seq,  						 rx->queue, &(rx->skb)); -		if (rx->key && rx->key->conf.alg == ALG_CCMP && +		if (rx->key && rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP &&  		    ieee80211_has_protected(fc)) {  			int queue = ieee80211_is_mgmt(fc) ?  				NUM_RX_DATA_QUEUES : rx->queue; @@ -1294,7 +1365,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)  		int i;  		u8 pn[CCMP_PN_LEN], *rpn;  		int queue; -		if (!rx->key || rx->key->conf.alg != ALG_CCMP) +		if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP)  			return RX_DROP_UNUSABLE;  		memcpy(pn, entry->last_pn, CCMP_PN_LEN);  		for (i = CCMP_PN_LEN - 1; i >= 0; i--) { @@ -1335,7 +1406,8 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)  	}  	/* Complete frame has been reassembled - process it now */ -	rx->flags |= IEEE80211_RX_FRAGMENTED; +	status = IEEE80211_SKB_RXCB(rx->skb); +	status->rx_flags |= IEEE80211_RX_FRAGMENTED;   out:  	if (rx->sta) @@ -1352,9 +1424,10 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)  {  	struct ieee80211_sub_if_data *sdata = rx->sdata;  	__le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control; +	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);  	if (likely(!rx->sta || !ieee80211_is_pspoll(fc) || -		   !(rx->flags & IEEE80211_RX_RA_MATCH))) +		   !(status->rx_flags & IEEE80211_RX_RA_MATCH)))  		return RX_CONTINUE;  	if ((sdata->vif.type != NL80211_IFTYPE_AP) && @@ -1492,7 +1565,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)  	 * Allow EAPOL frames to us/the PAE group address regardless  	 * of whether the frame was encrypted or not.  	 */ -	if (ehdr->h_proto == htons(ETH_P_PAE) && +	if (ehdr->h_proto == rx->sdata->control_port_protocol &&  	    (compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 ||  	     compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))  		return true; @@ -1515,6 +1588,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)  	struct sk_buff *skb, *xmit_skb;  	struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;  	struct sta_info *dsta; +	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);  	skb = rx->skb;  	xmit_skb = NULL; @@ -1522,7 +1596,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)  	if ((sdata->vif.type == NL80211_IFTYPE_AP ||  	     sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&  	    !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && -	    (rx->flags & IEEE80211_RX_RA_MATCH) && +	    (status->rx_flags & IEEE80211_RX_RA_MATCH) &&  	    (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {  		if (is_multicast_ether_addr(ehdr->h_dest)) {  			/* @@ -1599,6 +1673,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;  	__le16 fc = hdr->frame_control;  	struct sk_buff_head frame_list; +	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);  	if (unlikely(!ieee80211_is_data(fc)))  		return RX_CONTINUE; @@ -1606,7 +1681,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)  	if (unlikely(!ieee80211_is_data_present(fc)))  		return RX_DROP_MONITOR; -	if (!(rx->flags & IEEE80211_RX_AMSDU)) +	if (!(status->rx_flags & IEEE80211_RX_AMSDU))  		return RX_CONTINUE;  	if (ieee80211_has_a4(hdr->frame_control) && @@ -1657,6 +1732,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  	struct sk_buff *skb = rx->skb, *fwd_skb;  	struct ieee80211_local *local = rx->local;  	struct ieee80211_sub_if_data *sdata = rx->sdata; +	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);  	hdr = (struct ieee80211_hdr *) skb->data;  	hdrlen = ieee80211_hdrlen(hdr->frame_control); @@ -1702,7 +1778,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  	mesh_hdr->ttl--; -	if (rx->flags & IEEE80211_RX_RA_MATCH) { +	if (status->rx_flags & IEEE80211_RX_RA_MATCH) {  		if (!mesh_hdr->ttl)  			IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh,  						     dropped_frames_ttl); @@ -1909,13 +1985,38 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,  }  static ieee80211_rx_result debug_noinline +ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) +{ +	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; +	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); + +	/* +	 * From here on, look only at management frames. +	 * Data and control frames are already handled, +	 * and unknown (reserved) frames are useless. +	 */ +	if (rx->skb->len < 24) +		return RX_DROP_MONITOR; + +	if (!ieee80211_is_mgmt(mgmt->frame_control)) +		return RX_DROP_MONITOR; + +	if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) +		return RX_DROP_MONITOR; + +	if (ieee80211_drop_unencrypted_mgmt(rx)) +		return RX_DROP_UNUSABLE; + +	return RX_CONTINUE; +} + +static ieee80211_rx_result debug_noinline  ieee80211_rx_h_action(struct ieee80211_rx_data *rx)  {  	struct ieee80211_local *local = rx->local;  	struct ieee80211_sub_if_data *sdata = rx->sdata;  	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; -	struct sk_buff *nskb; -	struct ieee80211_rx_status *status; +	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);  	int len = rx->skb->len;  	if (!ieee80211_is_action(mgmt->frame_control)) @@ -1928,10 +2029,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)  	if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)  		return RX_DROP_UNUSABLE; -	if (!(rx->flags & IEEE80211_RX_RA_MATCH)) -		return RX_DROP_UNUSABLE; - -	if (ieee80211_drop_unencrypted_mgmt(rx)) +	if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))  		return RX_DROP_UNUSABLE;  	switch (mgmt->u.action.category) { @@ -2024,17 +2122,36 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)  		goto queue;  	} +	return RX_CONTINUE; +   invalid: -	/* -	 * For AP mode, hostapd is responsible for handling any action -	 * 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. -	 */ -	if (sdata->vif.type == NL80211_IFTYPE_AP || -	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN) -		return RX_DROP_MONITOR; +	status->rx_flags |= IEEE80211_RX_MALFORMED_ACTION_FRM; +	/* will return in the next handlers */ +	return RX_CONTINUE; + + handled: +	if (rx->sta) +		rx->sta->rx_packets++; +	dev_kfree_skb(rx->skb); +	return RX_QUEUED; + + queue: +	rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME; +	skb_queue_tail(&sdata->skb_queue, rx->skb); +	ieee80211_queue_work(&local->hw, &sdata->work); +	if (rx->sta) +		rx->sta->rx_packets++; +	return RX_QUEUED; +} + +static ieee80211_rx_result debug_noinline +ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) +{ +	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); + +	/* skip known-bad action frames and return them in the next handler */ +	if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) +		return RX_CONTINUE;  	/*  	 * Getting here means the kernel doesn't know how to handle @@ -2042,12 +2159,46 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)  	 * so userspace can register for those to know whether ones  	 * it transmitted were processed or returned.  	 */ -	status = IEEE80211_SKB_RXCB(rx->skb); -	if (cfg80211_rx_action(rx->sdata->dev, status->freq, -			       rx->skb->data, rx->skb->len, -			       GFP_ATOMIC)) -		goto handled; +	if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq, +			     rx->skb->data, rx->skb->len, +			     GFP_ATOMIC)) { +		if (rx->sta) +			rx->sta->rx_packets++; +		dev_kfree_skb(rx->skb); +		return RX_QUEUED; +	} + + +	return RX_CONTINUE; +} + +static ieee80211_rx_result debug_noinline +ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) +{ +	struct ieee80211_local *local = rx->local; +	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; +	struct sk_buff *nskb; +	struct ieee80211_sub_if_data *sdata = rx->sdata; +	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); + +	if (!ieee80211_is_action(mgmt->frame_control)) +		return RX_CONTINUE; + +	/* +	 * For AP mode, hostapd is responsible for handling any action +	 * 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. +	 * 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. +	 */ +	if (!(status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) && +	    (sdata->vif.type == NL80211_IFTYPE_AP || +	     sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) +		return RX_DROP_MONITOR;  	/* do not return rejected action frames */  	if (mgmt->u.action.category & 0x80) @@ -2066,20 +2217,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)  		ieee80211_tx_skb(rx->sdata, nskb);  	} - - handled: -	if (rx->sta) -		rx->sta->rx_packets++;  	dev_kfree_skb(rx->skb);  	return RX_QUEUED; - - queue: -	rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME; -	skb_queue_tail(&sdata->skb_queue, rx->skb); -	ieee80211_queue_work(&local->hw, &sdata->work); -	if (rx->sta) -		rx->sta->rx_packets++; -	return RX_QUEUED;  }  static ieee80211_rx_result debug_noinline @@ -2090,15 +2229,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)  	struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;  	__le16 stype; -	if (!(rx->flags & IEEE80211_RX_RA_MATCH)) -		return RX_DROP_MONITOR; - -	if (rx->skb->len < 24) -		return RX_DROP_MONITOR; - -	if (ieee80211_drop_unencrypted_mgmt(rx)) -		return RX_DROP_UNUSABLE; -  	rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb);  	if (rxs != RX_CONTINUE)  		return rxs; @@ -2199,6 +2329,14 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,  	struct net_device *prev_dev = NULL;  	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); +	/* +	 * If cooked monitor has been processed already, then +	 * don't do it again. If not, set the flag. +	 */ +	if (rx->flags & IEEE80211_RX_CMNTR) +		goto out_free_skb; +	rx->flags |= IEEE80211_RX_CMNTR; +  	if (skb_headroom(skb) < sizeof(*rthdr) &&  	    pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))  		goto out_free_skb; @@ -2253,29 +2391,53 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,  	if (prev_dev) {  		skb->dev = prev_dev;  		netif_receive_skb(skb); -		skb = NULL; -	} else -		goto out_free_skb; - -	return; +		return; +	}   out_free_skb:  	dev_kfree_skb(skb);  } - -static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, -					 struct ieee80211_rx_data *rx, -					 struct sk_buff *skb, -					 struct ieee80211_rate *rate) +static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx, +					 ieee80211_rx_result res)  { -	struct sk_buff_head reorder_release; -	ieee80211_rx_result res = RX_DROP_MONITOR; +	switch (res) { +	case RX_DROP_MONITOR: +		I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop); +		if (rx->sta) +			rx->sta->rx_dropped++; +		/* fall through */ +	case RX_CONTINUE: { +		struct ieee80211_rate *rate = NULL; +		struct ieee80211_supported_band *sband; +		struct ieee80211_rx_status *status; -	__skb_queue_head_init(&reorder_release); +		status = IEEE80211_SKB_RXCB((rx->skb)); -	rx->skb = skb; -	rx->sdata = sdata; +		sband = rx->local->hw.wiphy->bands[status->band]; +		if (!(status->flag & RX_FLAG_HT)) +			rate = &sband->bitrates[status->rate_idx]; + +		ieee80211_rx_cooked_monitor(rx, rate); +		break; +		} +	case RX_DROP_UNUSABLE: +		I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop); +		if (rx->sta) +			rx->sta->rx_dropped++; +		dev_kfree_skb(rx->skb); +		break; +	case RX_QUEUED: +		I802_DEBUG_INC(rx->sdata->local->rx_handlers_queued); +		break; +	} +} + +static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, +				  struct sk_buff_head *frames) +{ +	ieee80211_rx_result res = RX_DROP_MONITOR; +	struct sk_buff *skb;  #define CALL_RXH(rxh)			\  	do {				\ @@ -2284,23 +2446,14 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,  			goto rxh_next;  \  	} while (0); -	/* -	 * NB: the rxh_next label works even if we jump -	 *     to it from here because then the list will -	 *     be empty, which is a trivial check -	 */ -	CALL_RXH(ieee80211_rx_h_passive_scan) -	CALL_RXH(ieee80211_rx_h_check) - -	ieee80211_rx_reorder_ampdu(rx, &reorder_release); - -	while ((skb = __skb_dequeue(&reorder_release))) { +	while ((skb = __skb_dequeue(frames))) {  		/*  		 * all the other fields are valid across frames  		 * that belong to an aMPDU since they are on the  		 * same TID from the same station  		 */  		rx->skb = skb; +		rx->flags = 0;  		CALL_RXH(ieee80211_rx_h_decrypt)  		CALL_RXH(ieee80211_rx_h_check_more_data) @@ -2312,50 +2465,92 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,  		CALL_RXH(ieee80211_rx_h_remove_qos_control)  		CALL_RXH(ieee80211_rx_h_amsdu)  #ifdef CONFIG_MAC80211_MESH -		if (ieee80211_vif_is_mesh(&sdata->vif)) +		if (ieee80211_vif_is_mesh(&rx->sdata->vif))  			CALL_RXH(ieee80211_rx_h_mesh_fwding);  #endif  		CALL_RXH(ieee80211_rx_h_data)  		/* special treatment -- needs the queue */ -		res = ieee80211_rx_h_ctrl(rx, &reorder_release); +		res = ieee80211_rx_h_ctrl(rx, frames);  		if (res != RX_CONTINUE)  			goto rxh_next; +		CALL_RXH(ieee80211_rx_h_mgmt_check)  		CALL_RXH(ieee80211_rx_h_action) +		CALL_RXH(ieee80211_rx_h_userspace_mgmt) +		CALL_RXH(ieee80211_rx_h_action_return)  		CALL_RXH(ieee80211_rx_h_mgmt) + rxh_next: +		ieee80211_rx_handlers_result(rx, res); +  #undef CALL_RXH +	} +} + +static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) +{ +	struct sk_buff_head reorder_release; +	ieee80211_rx_result res = RX_DROP_MONITOR; + +	__skb_queue_head_init(&reorder_release); + +#define CALL_RXH(rxh)			\ +	do {				\ +		res = rxh(rx);		\ +		if (res != RX_CONTINUE)	\ +			goto rxh_next;  \ +	} while (0); + +	CALL_RXH(ieee80211_rx_h_passive_scan) +	CALL_RXH(ieee80211_rx_h_check) + +	ieee80211_rx_reorder_ampdu(rx, &reorder_release); + +	ieee80211_rx_handlers(rx, &reorder_release); +	return;   rxh_next: -		switch (res) { -		case RX_DROP_MONITOR: -			I802_DEBUG_INC(sdata->local->rx_handlers_drop); -			if (rx->sta) -				rx->sta->rx_dropped++; -			/* fall through */ -		case RX_CONTINUE: -			ieee80211_rx_cooked_monitor(rx, rate); -			break; -		case RX_DROP_UNUSABLE: -			I802_DEBUG_INC(sdata->local->rx_handlers_drop); -			if (rx->sta) -				rx->sta->rx_dropped++; -			dev_kfree_skb(rx->skb); -			break; -		case RX_QUEUED: -			I802_DEBUG_INC(sdata->local->rx_handlers_queued); -			break; -		} -	} +	ieee80211_rx_handlers_result(rx, res); + +#undef CALL_RXH +} + +/* + * This function makes calls into the RX path. Therefore the + * caller must hold the sta_info->lock and everything has to + * be under rcu_read_lock protection as well. + */ +void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) +{ +	struct sk_buff_head frames; +	struct ieee80211_rx_data rx = { +		.sta = sta, +		.sdata = sta->sdata, +		.local = sta->local, +		.queue = tid, +	}; +	struct tid_ampdu_rx *tid_agg_rx; + +	tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); +	if (!tid_agg_rx) +		return; + +	__skb_queue_head_init(&frames); + +	spin_lock(&tid_agg_rx->reorder_lock); +	ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx, &frames); +	spin_unlock(&tid_agg_rx->reorder_lock); + +	ieee80211_rx_handlers(&rx, &frames);  }  /* main receive path */ -static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, -				struct ieee80211_rx_data *rx, +static int prepare_for_handlers(struct ieee80211_rx_data *rx,  				struct ieee80211_hdr *hdr)  { +	struct ieee80211_sub_if_data *sdata = rx->sdata;  	struct sk_buff *skb = rx->skb;  	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);  	u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type); @@ -2369,7 +2564,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,  		    compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) {  			if (!(sdata->dev->flags & IFF_PROMISC))  				return 0; -			rx->flags &= ~IEEE80211_RX_RA_MATCH; +			status->rx_flags &= ~IEEE80211_RX_RA_MATCH;  		}  		break;  	case NL80211_IFTYPE_ADHOC: @@ -2379,15 +2574,15 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,  			return 1;  		}  		else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { -			if (!(rx->flags & IEEE80211_RX_IN_SCAN)) +			if (!(status->rx_flags & IEEE80211_RX_IN_SCAN))  				return 0; -			rx->flags &= ~IEEE80211_RX_RA_MATCH; +			status->rx_flags &= ~IEEE80211_RX_RA_MATCH;  		} else if (!multicast &&  			   compare_ether_addr(sdata->vif.addr,  					      hdr->addr1) != 0) {  			if (!(sdata->dev->flags & IFF_PROMISC))  				return 0; -			rx->flags &= ~IEEE80211_RX_RA_MATCH; +			status->rx_flags &= ~IEEE80211_RX_RA_MATCH;  		} else if (!rx->sta) {  			int rate_idx;  			if (status->flag & RX_FLAG_HT) @@ -2405,7 +2600,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,  			if (!(sdata->dev->flags & IFF_PROMISC))  				return 0; -			rx->flags &= ~IEEE80211_RX_RA_MATCH; +			status->rx_flags &= ~IEEE80211_RX_RA_MATCH;  		}  		break;  	case NL80211_IFTYPE_AP_VLAN: @@ -2416,9 +2611,9 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,  				return 0;  		} else if (!ieee80211_bssid_match(bssid,  					sdata->vif.addr)) { -			if (!(rx->flags & IEEE80211_RX_IN_SCAN)) +			if (!(status->rx_flags & IEEE80211_RX_IN_SCAN))  				return 0; -			rx->flags &= ~IEEE80211_RX_RA_MATCH; +			status->rx_flags &= ~IEEE80211_RX_RA_MATCH;  		}  		break;  	case NL80211_IFTYPE_WDS: @@ -2427,9 +2622,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,  		if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))  			return 0;  		break; -	case NL80211_IFTYPE_MONITOR: -	case NL80211_IFTYPE_UNSPECIFIED: -	case __NL80211_IFTYPE_AFTER_LAST: +	default:  		/* should never get here */  		WARN_ON(1);  		break; @@ -2439,12 +2632,56 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,  }  /* + * This function returns whether or not the SKB + * was destined for RX processing or not, which, + * if consume is true, is equivalent to whether + * or not the skb was consumed. + */ +static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, +					    struct sk_buff *skb, bool consume) +{ +	struct ieee80211_local *local = rx->local; +	struct ieee80211_sub_if_data *sdata = rx->sdata; +	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); +	struct ieee80211_hdr *hdr = (void *)skb->data; +	int prepares; + +	rx->skb = skb; +	status->rx_flags |= IEEE80211_RX_RA_MATCH; +	prepares = prepare_for_handlers(rx, hdr); + +	if (!prepares) +		return false; + +	if (status->flag & RX_FLAG_MMIC_ERROR) { +		if (status->rx_flags & IEEE80211_RX_RA_MATCH) +			ieee80211_rx_michael_mic_report(hdr, rx); +		return false; +	} + +	if (!consume) { +		skb = skb_copy(skb, GFP_ATOMIC); +		if (!skb) { +			if (net_ratelimit()) +				wiphy_debug(local->hw.wiphy, +					"failed to copy multicast frame for %s\n", +					sdata->name); +			return true; +		} + +		rx->skb = skb; +	} + +	ieee80211_invoke_rx_handlers(rx); +	return true; +} + +/*   * This is the actual Rx frames handler. as it blongs to Rx path it must   * be called with rcu_read_lock protection.   */  static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, -					 struct sk_buff *skb, -					 struct ieee80211_rate *rate) +					 struct sk_buff *skb)  {  	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);  	struct ieee80211_local *local = hw_to_local(hw); @@ -2452,11 +2689,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,  	struct ieee80211_hdr *hdr;  	__le16 fc;  	struct ieee80211_rx_data rx; -	int prepares; -	struct ieee80211_sub_if_data *prev = NULL; -	struct sk_buff *skb_new; -	struct sta_info *sta, *tmp; -	bool found_sta = false; +	struct ieee80211_sub_if_data *prev; +	struct sta_info *sta, *tmp, *prev_sta;  	int err = 0;  	fc = ((struct ieee80211_hdr *)skb->data)->frame_control; @@ -2469,7 +2703,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,  	if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||  		     test_bit(SCAN_OFF_CHANNEL, &local->scanning))) -		rx.flags |= IEEE80211_RX_IN_SCAN; +		status->rx_flags |= IEEE80211_RX_IN_SCAN;  	if (ieee80211_is_mgmt(fc))  		err = skb_linearize(skb); @@ -2486,91 +2720,67 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,  	ieee80211_verify_alignment(&rx);  	if (ieee80211_is_data(fc)) { -		for_each_sta_info(local, hdr->addr2, sta, tmp) { -			rx.sta = sta; -			found_sta = true; -			rx.sdata = sta->sdata; +		prev_sta = NULL; -			rx.flags |= IEEE80211_RX_RA_MATCH; -			prepares = prepare_for_handlers(rx.sdata, &rx, hdr); -			if (prepares) { -				if (status->flag & RX_FLAG_MMIC_ERROR) { -					if (rx.flags & IEEE80211_RX_RA_MATCH) -						ieee80211_rx_michael_mic_report(hdr, &rx); -				} else -					prev = rx.sdata; -			} -		} -	} -	if (!found_sta) { -		list_for_each_entry_rcu(sdata, &local->interfaces, list) { -			if (!ieee80211_sdata_running(sdata)) +		for_each_sta_info(local, hdr->addr2, sta, tmp) { +			if (!prev_sta) { +				prev_sta = sta;  				continue; +			} -			if (sdata->vif.type == NL80211_IFTYPE_MONITOR || -			    sdata->vif.type == NL80211_IFTYPE_AP_VLAN) -				continue; +			rx.sta = prev_sta; +			rx.sdata = prev_sta->sdata; +			ieee80211_prepare_and_rx_handle(&rx, skb, false); -			/* -			 * frame is destined for this interface, but if it's -			 * not also for the previous one we handle that after -			 * the loop to avoid copying the SKB once too much -			 */ +			prev_sta = sta; +		} -			if (!prev) { -				prev = sdata; -				continue; -			} +		if (prev_sta) { +			rx.sta = prev_sta; +			rx.sdata = prev_sta->sdata; -			rx.sta = sta_info_get_bss(prev, hdr->addr2); +			if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) +				return; +		} +	} -			rx.flags |= IEEE80211_RX_RA_MATCH; -			prepares = prepare_for_handlers(prev, &rx, hdr); +	prev = NULL; -			if (!prepares) -				goto next; +	list_for_each_entry_rcu(sdata, &local->interfaces, list) { +		if (!ieee80211_sdata_running(sdata)) +			continue; -			if (status->flag & RX_FLAG_MMIC_ERROR) { -				rx.sdata = prev; -				if (rx.flags & IEEE80211_RX_RA_MATCH) -					ieee80211_rx_michael_mic_report(hdr, -									&rx); -				goto next; -			} +		if (sdata->vif.type == NL80211_IFTYPE_MONITOR || +		    sdata->vif.type == NL80211_IFTYPE_AP_VLAN) +			continue; -			/* -			 * frame was destined for the previous interface -			 * so invoke RX handlers for it -			 */ +		/* +		 * frame is destined for this interface, but if it's +		 * not also for the previous one we handle that after +		 * the loop to avoid copying the SKB once too much +		 */ -			skb_new = skb_copy(skb, GFP_ATOMIC); -			if (!skb_new) { -				if (net_ratelimit()) -					printk(KERN_DEBUG "%s: failed to copy " -					       "multicast frame for %s\n", -					       wiphy_name(local->hw.wiphy), -					       prev->name); -				goto next; -			} -			ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate); -next: +		if (!prev) {  			prev = sdata; +			continue;  		} -		if (prev) { -			rx.sta = sta_info_get_bss(prev, hdr->addr2); +		rx.sta = sta_info_get_bss(prev, hdr->addr2); +		rx.sdata = prev; +		ieee80211_prepare_and_rx_handle(&rx, skb, false); -			rx.flags |= IEEE80211_RX_RA_MATCH; -			prepares = prepare_for_handlers(prev, &rx, hdr); +		prev = sdata; +	} -			if (!prepares) -				prev = NULL; -		} +	if (prev) { +		rx.sta = sta_info_get_bss(prev, hdr->addr2); +		rx.sdata = prev; + +		if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) +			return;  	} -	if (prev) -		ieee80211_invoke_rx_handlers(prev, &rx, skb, rate); -	else -		dev_kfree_skb(skb); + +	dev_kfree_skb(skb);  }  /* @@ -2611,30 +2821,41 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)  	if (WARN_ON(!local->started))  		goto drop; -	if (status->flag & RX_FLAG_HT) { +	if (likely(!(status->flag & RX_FLAG_FAILED_PLCP_CRC))) {  		/* -		 * rate_idx is MCS index, which can be [0-76] as documented on: -		 * -		 * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n -		 * -		 * Anything else would be some sort of driver or hardware error. -		 * The driver should catch hardware errors. +		 * Validate the rate, unless a PLCP error means that +		 * we probably can't have a valid rate here anyway.  		 */ -		if (WARN((status->rate_idx < 0 || -			 status->rate_idx > 76), -			 "Rate marked as an HT rate but passed " -			 "status->rate_idx is not " -			 "an MCS index [0-76]: %d (0x%02x)\n", -			 status->rate_idx, -			 status->rate_idx)) -			goto drop; -	} else { -		if (WARN_ON(status->rate_idx < 0 || -			    status->rate_idx >= sband->n_bitrates)) -			goto drop; -		rate = &sband->bitrates[status->rate_idx]; + +		if (status->flag & RX_FLAG_HT) { +			/* +			 * rate_idx is MCS index, which can be [0-76] +			 * as documented on: +			 * +			 * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n +			 * +			 * Anything else would be some sort of driver or +			 * hardware error. The driver should catch hardware +			 * errors. +			 */ +			if (WARN((status->rate_idx < 0 || +				 status->rate_idx > 76), +				 "Rate marked as an HT rate but passed " +				 "status->rate_idx is not " +				 "an MCS index [0-76]: %d (0x%02x)\n", +				 status->rate_idx, +				 status->rate_idx)) +				goto drop; +		} else { +			if (WARN_ON(status->rate_idx < 0 || +				    status->rate_idx >= sband->n_bitrates)) +				goto drop; +			rate = &sband->bitrates[status->rate_idx]; +		}  	} +	status->rx_flags = 0; +  	/*  	 * key references and virtual interfaces are protected using RCU  	 * and this requires that we are in a read-side RCU section during @@ -2654,7 +2875,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)  		return;  	} -	__ieee80211_rx_handle_packet(hw, skb, rate); +	__ieee80211_rx_handle_packet(hw, skb);  	rcu_read_unlock();  |