diff options
Diffstat (limited to 'net/mac80211/rx.c')
| -rw-r--r-- | net/mac80211/rx.c | 77 | 
1 files changed, 23 insertions, 54 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c5d4530d828..13a6697651a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -143,7 +143,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,  	if (status->flag & RX_FLAG_HT) {  		/*  		 * MCS information is a separate field in radiotap, -		 * added below. +		 * added below. The byte here is needed as padding +		 * for the channel though, so initialise it to 0.  		 */  		*pos = 0;  	} else { @@ -502,7 +503,8 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)  		if (ieee80211_is_probe_req(hdr->frame_control) ||  		    ieee80211_is_probe_resp(hdr->frame_control) || -		    ieee80211_is_beacon(hdr->frame_control)) +		    ieee80211_is_beacon(hdr->frame_control) || +		    ieee80211_is_auth(hdr->frame_control))  			return RX_CONTINUE;  		return RX_DROP_MONITOR; @@ -650,7 +652,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,   set_release_timer:  		mod_timer(&tid_agg_rx->reorder_timer, -			  tid_agg_rx->reorder_time[j] + +			  tid_agg_rx->reorder_time[j] + 1 +  			  HT_RX_REORDER_BUF_TIMEOUT);  	} else {  		del_timer(&tid_agg_rx->reorder_timer); @@ -707,6 +709,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,  	/*  	 * If the current MPDU is in the right order and nothing else  	 * is stored we can process it directly, no need to buffer it. +	 * If it is first but there's something stored, we may be able +	 * to release frames after this one.  	 */  	if (mpdu_seq_num == tid_agg_rx->head_seq_num &&  	    tid_agg_rx->stored_mpdu_num == 0) { @@ -1583,7 +1587,7 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)  }  static int -__ieee80211_data_to_8023(struct ieee80211_rx_data *rx) +__ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control)  {  	struct ieee80211_sub_if_data *sdata = rx->sdata;  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; @@ -1591,6 +1595,7 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)  	struct ethhdr *ehdr;  	int ret; +	*port_control = false;  	if (ieee80211_has_a4(hdr->frame_control) &&  	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)  		return -1; @@ -1609,11 +1614,13 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)  		return -1;  	ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type); -	if (ret < 0 || !check_port_control) +	if (ret < 0)  		return ret;  	ehdr = (struct ethhdr *) rx->skb->data; -	if (ehdr->h_proto != rx->sdata->control_port_protocol) +	if (ehdr->h_proto == rx->sdata->control_port_protocol) +		*port_control = true; +	else if (check_port_control)  		return -1;  	return 0; @@ -1914,6 +1921,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)  	struct net_device *dev = sdata->dev;  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;  	__le16 fc = hdr->frame_control; +	bool port_control;  	int err;  	if (unlikely(!ieee80211_is_data(hdr->frame_control))) @@ -1930,13 +1938,21 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)  	    sdata->vif.type == NL80211_IFTYPE_AP)  		return RX_DROP_MONITOR; -	err = __ieee80211_data_to_8023(rx); +	err = __ieee80211_data_to_8023(rx, &port_control);  	if (unlikely(err))  		return RX_DROP_UNUSABLE;  	if (!ieee80211_frame_allowed(rx, fc))  		return RX_DROP_MONITOR; +	if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && +	    unlikely(port_control) && sdata->bss) { +		sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, +				     u.ap); +		dev = sdata->dev; +		rx->sdata = sdata; +	} +  	rx->skb->dev = dev;  	dev->stats.rx_packets++; @@ -2352,47 +2368,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)  	return RX_QUEUED;  } -static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr, -					    struct ieee80211_rx_data *rx) -{ -	int keyidx; -	unsigned int hdrlen; - -	hdrlen = ieee80211_hdrlen(hdr->frame_control); -	if (rx->skb->len >= hdrlen + 4) -		keyidx = rx->skb->data[hdrlen + 3] >> 6; -	else -		keyidx = -1; - -	if (!rx->sta) { -		/* -		 * Some hardware seem to generate incorrect Michael MIC -		 * reports; ignore them to avoid triggering countermeasures. -		 */ -		return; -	} - -	if (!ieee80211_has_protected(hdr->frame_control)) -		return; - -	if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) { -		/* -		 * APs with pairwise keys should never receive Michael MIC -		 * errors for non-zero keyidx because these are reserved for -		 * group keys and only the AP is sending real multicast -		 * frames in the BSS. -		 */ -		return; -	} - -	if (!ieee80211_is_data(hdr->frame_control) && -	    !ieee80211_is_auth(hdr->frame_control)) -		return; - -	mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL, -					GFP_ATOMIC); -} -  /* TODO: use IEEE80211_RX_FRAGMENTED */  static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,  					struct ieee80211_rate *rate) @@ -2736,12 +2711,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,  	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) {  |