diff options
Diffstat (limited to 'net/mac80211')
| -rw-r--r-- | net/mac80211/cfg.c | 3 | ||||
| -rw-r--r-- | net/mac80211/ibss.c | 10 | ||||
| -rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
| -rw-r--r-- | net/mac80211/iface.c | 2 | ||||
| -rw-r--r-- | net/mac80211/main.c | 6 | ||||
| -rw-r--r-- | net/mac80211/mlme.c | 35 | ||||
| -rw-r--r-- | net/mac80211/rx.c | 72 | ||||
| -rw-r--r-- | net/mac80211/scan.c | 2 | ||||
| -rw-r--r-- | net/mac80211/sta_info.c | 15 | ||||
| -rw-r--r-- | net/mac80211/status.c | 9 | ||||
| -rw-r--r-- | net/mac80211/tx.c | 9 | ||||
| -rw-r--r-- | net/mac80211/util.c | 48 | ||||
| -rw-r--r-- | net/mac80211/wpa.c | 14 | 
13 files changed, 168 insertions, 59 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 05f3a313db8..7371f676cf4 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2594,6 +2594,9 @@ static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,  		else  			local->probe_req_reg--; +		if (!local->open_count) +			break; +  		ieee80211_queue_work(&local->hw, &local->reconfig_filter);  		break;  	default: diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 5f3620f0bc0..c21e33d1abd 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1108,7 +1108,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,  	sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH;  	sdata->u.ibss.ibss_join_req = jiffies; -	memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN); +	memcpy(sdata->u.ibss.ssid, params->ssid, params->ssid_len);  	sdata->u.ibss.ssid_len = params->ssid_len;  	mutex_unlock(&sdata->u.ibss.mtx); @@ -1151,10 +1151,6 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)  	mutex_lock(&sdata->u.ibss.mtx); -	sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH; -	memset(sdata->u.ibss.bssid, 0, ETH_ALEN); -	sdata->u.ibss.ssid_len = 0; -  	active_ibss = ieee80211_sta_active_ibss(sdata);  	if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) { @@ -1175,6 +1171,10 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)  		}  	} +	ifibss->state = IEEE80211_IBSS_MLME_SEARCH; +	memset(ifibss->bssid, 0, ETH_ALEN); +	ifibss->ssid_len = 0; +  	sta_info_flush(sdata->local, sdata);  	spin_lock_bh(&ifibss->incomplete_lock); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8c804550465..156e5835e37 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1314,6 +1314,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,  					 struct net_device *dev);  netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,  				       struct net_device *dev); +void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, +			      struct sk_buff_head *skbs);  /* HT */  void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 6f8a73c64fb..7de7717ad67 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -853,7 +853,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,  			struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);  			if (info->control.vif == &sdata->vif) {  				__skb_unlink(skb, &local->pending[i]); -				dev_kfree_skb_irq(skb); +				ieee80211_free_txskb(&local->hw, skb);  			}  		}  	} diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c80c4490351..f57f597972f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -871,8 +871,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  				local->hw.wiphy->cipher_suites,  				sizeof(u32) * local->hw.wiphy->n_cipher_suites,  				GFP_KERNEL); -			if (!suites) -				return -ENOMEM; +			if (!suites) { +				result = -ENOMEM; +				goto fail_wiphy_register; +			}  			for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {  				u32 suite = local->hw.wiphy->cipher_suites[r];  				if (suite == WLAN_CIPHER_SUITE_WEP40 || diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e714ed8bb19..1b7eed252fe 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3099,22 +3099,32 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,  				   ht_cfreq, ht_oper->primary_chan,  				   cbss->channel->band);  			ht_oper = NULL; +		} else { +			channel_type = NL80211_CHAN_HT20;  		}  	} -	if (ht_oper) { -		channel_type = NL80211_CHAN_HT20; +	if (ht_oper && sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { +		/* +		 * cfg80211 already verified that the channel itself can +		 * be used, but it didn't check that we can do the right +		 * HT type, so do that here as well. If HT40 isn't allowed +		 * on this channel, disable 40 MHz operation. +		 */ -		if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { -			switch (ht_oper->ht_param & -					IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { -			case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: +		switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { +		case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: +			if (cbss->channel->flags & IEEE80211_CHAN_NO_HT40PLUS) +				ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ; +			else  				channel_type = NL80211_CHAN_HT40PLUS; -				break; -			case IEEE80211_HT_PARAM_CHA_SEC_BELOW: +			break; +		case IEEE80211_HT_PARAM_CHA_SEC_BELOW: +			if (cbss->channel->flags & IEEE80211_CHAN_NO_HT40MINUS) +				ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ; +			else  				channel_type = NL80211_CHAN_HT40MINUS; -				break; -			} +			break;  		}  	} @@ -3549,6 +3559,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,  {  	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;  	u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; +	bool tx = !req->local_state_change;  	mutex_lock(&ifmgd->mtx); @@ -3565,12 +3576,12 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,  	if (ifmgd->associated &&  	    ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {  		ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, -				       req->reason_code, true, frame_buf); +				       req->reason_code, tx, frame_buf);  	} else {  		drv_mgd_prepare_tx(sdata->local, sdata);  		ieee80211_send_deauth_disassoc(sdata, req->bssid,  					       IEEE80211_STYPE_DEAUTH, -					       req->reason_code, true, +					       req->reason_code, tx,  					       frame_buf);  	} diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 61c621e9273..00ade7feb2e 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -531,6 +531,11 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)  		if (ieee80211_is_action(hdr->frame_control)) {  			u8 category; + +			/* make sure category field is present */ +			if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE) +				return RX_DROP_MONITOR; +  			mgmt = (struct ieee80211_mgmt *)hdr;  			category = mgmt->u.action.category;  			if (category != WLAN_CATEGORY_MESH_ACTION && @@ -883,14 +888,16 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)  		 */  		if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION &&  		    ieee80211_is_data_present(hdr->frame_control)) { -			u16 ethertype; -			u8 *payload; +			unsigned int hdrlen; +			__be16 ethertype; -			payload = rx->skb->data + -				ieee80211_hdrlen(hdr->frame_control); -			ethertype = (payload[6] << 8) | payload[7]; -			if (cpu_to_be16(ethertype) == -			    rx->sdata->control_port_protocol) +			hdrlen = ieee80211_hdrlen(hdr->frame_control); + +			if (rx->skb->len < hdrlen + 8) +				return RX_DROP_MONITOR; + +			skb_copy_bits(rx->skb, hdrlen + 6, ðertype, 2); +			if (ethertype == rx->sdata->control_port_protocol)  				return RX_CONTINUE;  		} @@ -1462,11 +1469,14 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)  	hdr = (struct ieee80211_hdr *)rx->skb->data;  	fc = hdr->frame_control; + +	if (ieee80211_is_ctl(fc)) +		return RX_CONTINUE; +  	sc = le16_to_cpu(hdr->seq_ctrl);  	frag = sc & IEEE80211_SCTL_FRAG;  	if (likely((!ieee80211_has_morefrags(fc) && frag == 0) || -		   (rx->skb)->len < 24 ||  		   is_multicast_ether_addr(hdr->addr1))) {  		/* not fragmented */  		goto out; @@ -1889,6 +1899,20 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  	hdr = (struct ieee80211_hdr *) skb->data;  	hdrlen = ieee80211_hdrlen(hdr->frame_control); + +	/* make sure fixed part of mesh header is there, also checks skb len */ +	if (!pskb_may_pull(rx->skb, hdrlen + 6)) +		return RX_DROP_MONITOR; + +	mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); + +	/* make sure full mesh header is there, also checks skb len */ +	if (!pskb_may_pull(rx->skb, +			   hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr))) +		return RX_DROP_MONITOR; + +	/* reload pointers */ +	hdr = (struct ieee80211_hdr *) skb->data;  	mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);  	/* frame is in RMC, don't forward */ @@ -1897,7 +1921,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  	    mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata))  		return RX_DROP_MONITOR; -	if (!ieee80211_is_data(hdr->frame_control)) +	if (!ieee80211_is_data(hdr->frame_control) || +	    !(status->rx_flags & IEEE80211_RX_RA_MATCH))  		return RX_CONTINUE;  	if (!mesh_hdr->ttl) @@ -1911,9 +1936,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  		if (is_multicast_ether_addr(hdr->addr1)) {  			mpp_addr = hdr->addr3;  			proxied_addr = mesh_hdr->eaddr1; -		} else { +		} else if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6) { +			/* has_a4 already checked in ieee80211_rx_mesh_check */  			mpp_addr = hdr->addr4;  			proxied_addr = mesh_hdr->eaddr2; +		} else { +			return RX_DROP_MONITOR;  		}  		rcu_read_lock(); @@ -1941,12 +1969,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  	}  	skb_set_queue_mapping(skb, q); -	if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) -		goto out; -  	if (!--mesh_hdr->ttl) {  		IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl); -		return RX_DROP_MONITOR; +		goto out;  	}  	if (!ifmsh->mshcfg.dot11MeshForwarding) @@ -2353,6 +2378,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)  		}  		break;  	case WLAN_CATEGORY_SELF_PROTECTED: +		if (len < (IEEE80211_MIN_ACTION_SIZE + +			   sizeof(mgmt->u.action.u.self_prot.action_code))) +			break; +  		switch (mgmt->u.action.u.self_prot.action_code) {  		case WLAN_SP_MESH_PEERING_OPEN:  		case WLAN_SP_MESH_PEERING_CLOSE: @@ -2371,6 +2400,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)  		}  		break;  	case WLAN_CATEGORY_MESH_ACTION: +		if (len < (IEEE80211_MIN_ACTION_SIZE + +			   sizeof(mgmt->u.action.u.mesh_action.action_code))) +			break; +  		if (!ieee80211_vif_is_mesh(&sdata->vif))  			break;  		if (mesh_action_is_path_sel(mgmt) && @@ -2913,10 +2946,15 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,  	if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))  		local->dot11ReceivedFragmentCount++; -	if (ieee80211_is_mgmt(fc)) -		err = skb_linearize(skb); -	else +	if (ieee80211_is_mgmt(fc)) { +		/* drop frame if too short for header */ +		if (skb->len < ieee80211_hdrlen(fc)) +			err = -ENOBUFS; +		else +			err = skb_linearize(skb); +	} else {  		err = !pskb_may_pull(skb, ieee80211_hdrlen(fc)); +	}  	if (err) {  		dev_kfree_skb(skb); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index c4cdbde24fd..43e60b5a754 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -917,7 +917,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,  				       struct cfg80211_sched_scan_request *req)  {  	struct ieee80211_local *local = sdata->local; -	struct ieee80211_sched_scan_ies sched_scan_ies; +	struct ieee80211_sched_scan_ies sched_scan_ies = {};  	int ret, i;  	mutex_lock(&local->mtx); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 797dd36a220..d2eb64e1235 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -117,8 +117,8 @@ static void free_sta_work(struct work_struct *wk)  	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {  		local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]); -		__skb_queue_purge(&sta->ps_tx_buf[ac]); -		__skb_queue_purge(&sta->tx_filtered[ac]); +		ieee80211_purge_tx_queue(&local->hw, &sta->ps_tx_buf[ac]); +		ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]);  	}  #ifdef CONFIG_MAC80211_MESH @@ -141,7 +141,7 @@ static void free_sta_work(struct work_struct *wk)  		tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);  		if (!tid_tx)  			continue; -		__skb_queue_purge(&tid_tx->pending); +		ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);  		kfree(tid_tx);  	} @@ -650,7 +650,7 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local,  		 */  		if (!skb)  			break; -		dev_kfree_skb(skb); +		ieee80211_free_txskb(&local->hw, skb);  	}  	/* @@ -679,7 +679,7 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local,  		local->total_ps_buffered--;  		ps_dbg(sta->sdata, "Buffered frame expired (STA %pM)\n",  		       sta->sta.addr); -		dev_kfree_skb(skb); +		ieee80211_free_txskb(&local->hw, skb);  	}  	/* @@ -961,6 +961,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)  	struct ieee80211_local *local = sdata->local;  	struct sk_buff_head pending;  	int filtered = 0, buffered = 0, ac; +	unsigned long flags;  	clear_sta_flag(sta, WLAN_STA_SP); @@ -976,12 +977,16 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)  	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {  		int count = skb_queue_len(&pending), tmp; +		spin_lock_irqsave(&sta->tx_filtered[ac].lock, flags);  		skb_queue_splice_tail_init(&sta->tx_filtered[ac], &pending); +		spin_unlock_irqrestore(&sta->tx_filtered[ac].lock, flags);  		tmp = skb_queue_len(&pending);  		filtered += tmp - count;  		count = tmp; +		spin_lock_irqsave(&sta->ps_tx_buf[ac].lock, flags);  		skb_queue_splice_tail_init(&sta->ps_tx_buf[ac], &pending); +		spin_unlock_irqrestore(&sta->ps_tx_buf[ac].lock, flags);  		tmp = skb_queue_len(&pending);  		buffered += tmp - count;  	} diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 3af0cc4130f..101eb88a2b7 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -668,3 +668,12 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)  	dev_kfree_skb_any(skb);  }  EXPORT_SYMBOL(ieee80211_free_txskb); + +void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, +			      struct sk_buff_head *skbs) +{ +	struct sk_buff *skb; + +	while ((skb = __skb_dequeue(skbs))) +		ieee80211_free_txskb(hw, skb); +} diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c9bf83f3665..b858ebe41fd 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1358,7 +1358,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)  		if (tx->skb)  			ieee80211_free_txskb(&tx->local->hw, tx->skb);  		else -			__skb_queue_purge(&tx->skbs); +			ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);  		return -1;  	} else if (unlikely(res == TX_QUEUED)) {  		I802_DEBUG_INC(tx->local->tx_handlers_queued); @@ -2120,10 +2120,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,   */  void ieee80211_clear_tx_pending(struct ieee80211_local *local)  { +	struct sk_buff *skb;  	int i; -	for (i = 0; i < local->hw.queues; i++) -		skb_queue_purge(&local->pending[i]); +	for (i = 0; i < local->hw.queues; i++) { +		while ((skb = skb_dequeue(&local->pending[i])) != NULL) +			ieee80211_free_txskb(&local->hw, skb); +	}  }  /* diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 22ca35054dd..0151ae33c4c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -406,7 +406,7 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,  	int queue = info->hw_queue;  	if (WARN_ON(!info->control.vif)) { -		kfree_skb(skb); +		ieee80211_free_txskb(&local->hw, skb);  		return;  	} @@ -431,7 +431,7 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,  		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);  		if (WARN_ON(!info->control.vif)) { -			kfree_skb(skb); +			ieee80211_free_txskb(&local->hw, skb);  			continue;  		} @@ -643,13 +643,41 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,  			break;  		} -		if (id != WLAN_EID_VENDOR_SPECIFIC && -		    id != WLAN_EID_QUIET && -		    test_bit(id, seen_elems)) { -			elems->parse_error = true; -			left -= elen; -			pos += elen; -			continue; +		switch (id) { +		case WLAN_EID_SSID: +		case WLAN_EID_SUPP_RATES: +		case WLAN_EID_FH_PARAMS: +		case WLAN_EID_DS_PARAMS: +		case WLAN_EID_CF_PARAMS: +		case WLAN_EID_TIM: +		case WLAN_EID_IBSS_PARAMS: +		case WLAN_EID_CHALLENGE: +		case WLAN_EID_RSN: +		case WLAN_EID_ERP_INFO: +		case WLAN_EID_EXT_SUPP_RATES: +		case WLAN_EID_HT_CAPABILITY: +		case WLAN_EID_HT_OPERATION: +		case WLAN_EID_VHT_CAPABILITY: +		case WLAN_EID_VHT_OPERATION: +		case WLAN_EID_MESH_ID: +		case WLAN_EID_MESH_CONFIG: +		case WLAN_EID_PEER_MGMT: +		case WLAN_EID_PREQ: +		case WLAN_EID_PREP: +		case WLAN_EID_PERR: +		case WLAN_EID_RANN: +		case WLAN_EID_CHANNEL_SWITCH: +		case WLAN_EID_EXT_CHANSWITCH_ANN: +		case WLAN_EID_COUNTRY: +		case WLAN_EID_PWR_CONSTRAINT: +		case WLAN_EID_TIMEOUT_INTERVAL: +			if (test_bit(id, seen_elems)) { +				elems->parse_error = true; +				left -= elen; +				pos += elen; +				continue; +			} +			break;  		}  		if (calc_crc && id < 64 && (filter & (1ULL << id))) @@ -1463,6 +1491,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)  		list_for_each_entry(sdata, &local->interfaces, list) {  			if (sdata->vif.type != NL80211_IFTYPE_STATION)  				continue; +			if (!sdata->u.mgd.associated) +				continue;  			ieee80211_send_nullfunc(local, sdata, 0);  		} diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index bdb53aba888..8bd2f5c6a56 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -106,7 +106,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)  		if (status->flag & RX_FLAG_MMIC_ERROR)  			goto mic_fail; -		if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key) +		if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key && +		    rx->key->conf.cipher == WLAN_CIPHER_SUITE_TKIP)  			goto update_iv;  		return RX_CONTINUE; @@ -545,14 +546,19 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)  static void bip_aad(struct sk_buff *skb, u8 *aad)  { +	__le16 mask_fc; +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; +  	/* BIP AAD: FC(masked) || A1 || A2 || A3 */  	/* FC type/subtype */ -	aad[0] = skb->data[0];  	/* Mask FC Retry, PwrMgt, MoreData flags to zero */ -	aad[1] = skb->data[1] & ~(BIT(4) | BIT(5) | BIT(6)); +	mask_fc = hdr->frame_control; +	mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY | IEEE80211_FCTL_PM | +				IEEE80211_FCTL_MOREDATA); +	put_unaligned(mask_fc, (__le16 *) &aad[0]);  	/* A1 || A2 || A3 */ -	memcpy(aad + 2, skb->data + 4, 3 * ETH_ALEN); +	memcpy(aad + 2, &hdr->addr1, 3 * ETH_ALEN);  }  |