diff options
Diffstat (limited to 'net/mac80211/rx.c')
| -rw-r--r-- | net/mac80211/rx.c | 199 | 
1 files changed, 141 insertions, 58 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index fe2c2a71779..b867bd55de7 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -476,7 +476,6 @@ static ieee80211_rx_result  ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)  {  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; -	unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);  	char *dev_addr = rx->sdata->vif.addr;  	if (ieee80211_is_data(hdr->frame_control)) { @@ -524,14 +523,6 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)  	} -#define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l)) - -	if (ieee80211_is_data(hdr->frame_control) && -	    is_multicast_ether_addr(hdr->addr1) && -	    mesh_rmc_check(hdr->addr3, msh_h_get(hdr, hdrlen), rx->sdata)) -		return RX_DROP_MONITOR; -#undef msh_h_get -  	return RX_CONTINUE;  } @@ -850,8 +841,21 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)  		      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)))) +		     (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) { +		if (rx->sta && rx->sta->dummy && +		    ieee80211_is_data_present(hdr->frame_control)) { +			u16 ethertype; +			u8 *payload; + +			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) +				return RX_CONTINUE; +		}  		return RX_DROP_MONITOR; +	}  	return RX_CONTINUE;  } @@ -1106,7 +1110,7 @@ static void ap_sta_ps_start(struct sta_info *sta)  	struct ieee80211_local *local = sdata->local;  	atomic_inc(&sdata->bss->num_sta_ps); -	set_sta_flags(sta, WLAN_STA_PS_STA); +	set_sta_flag(sta, WLAN_STA_PS_STA);  	if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))  		drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);  #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG @@ -1126,7 +1130,7 @@ static void ap_sta_ps_end(struct sta_info *sta)  	       sdata->name, sta->sta.addr, sta->sta.aid);  #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ -	if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) { +	if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {  #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG  		printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",  		       sdata->name, sta->sta.addr, sta->sta.aid); @@ -1145,7 +1149,7 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)  	WARN_ON(!(sta_inf->local->hw.flags & IEEE80211_HW_AP_LINK_PS));  	/* Don't let the same PS state be set twice */ -	in_ps = test_sta_flags(sta_inf, WLAN_STA_PS_STA); +	in_ps = test_sta_flag(sta_inf, WLAN_STA_PS_STA);  	if ((start && in_ps) || (!start && !in_ps))  		return -EINVAL; @@ -1159,6 +1163,81 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)  EXPORT_SYMBOL(ieee80211_sta_ps_transition);  static ieee80211_rx_result debug_noinline +ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx) +{ +	struct ieee80211_sub_if_data *sdata = rx->sdata; +	struct ieee80211_hdr *hdr = (void *)rx->skb->data; +	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); +	int tid, ac; + +	if (!rx->sta || !(status->rx_flags & IEEE80211_RX_RA_MATCH)) +		return RX_CONTINUE; + +	if (sdata->vif.type != NL80211_IFTYPE_AP && +	    sdata->vif.type != NL80211_IFTYPE_AP_VLAN) +		return RX_CONTINUE; + +	/* +	 * The device handles station powersave, so don't do anything about +	 * uAPSD and PS-Poll frames (the latter shouldn't even come up from +	 * it to mac80211 since they're handled.) +	 */ +	if (sdata->local->hw.flags & IEEE80211_HW_AP_LINK_PS) +		return RX_CONTINUE; + +	/* +	 * Don't do anything if the station isn't already asleep. In +	 * the uAPSD case, the station will probably be marked asleep, +	 * in the PS-Poll case the station must be confused ... +	 */ +	if (!test_sta_flag(rx->sta, WLAN_STA_PS_STA)) +		return RX_CONTINUE; + +	if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) { +		if (!test_sta_flag(rx->sta, WLAN_STA_SP)) { +			if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER)) +				ieee80211_sta_ps_deliver_poll_response(rx->sta); +			else +				set_sta_flag(rx->sta, WLAN_STA_PSPOLL); +		} + +		/* Free PS Poll skb here instead of returning RX_DROP that would +		 * count as an dropped frame. */ +		dev_kfree_skb(rx->skb); + +		return RX_QUEUED; +	} else if (!ieee80211_has_morefrags(hdr->frame_control) && +		   !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && +		   ieee80211_has_pm(hdr->frame_control) && +		   (ieee80211_is_data_qos(hdr->frame_control) || +		    ieee80211_is_qos_nullfunc(hdr->frame_control))) { +		tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; +		ac = ieee802_1d_to_ac[tid & 7]; + +		/* +		 * If this AC is not trigger-enabled do nothing. +		 * +		 * NB: This could/should check a separate bitmap of trigger- +		 * enabled queues, but for now we only implement uAPSD w/o +		 * TSPEC changes to the ACs, so they're always the same. +		 */ +		if (!(rx->sta->sta.uapsd_queues & BIT(ac))) +			return RX_CONTINUE; + +		/* if we are in a service period, do nothing */ +		if (test_sta_flag(rx->sta, WLAN_STA_SP)) +			return RX_CONTINUE; + +		if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER)) +			ieee80211_sta_ps_deliver_uapsd(rx->sta); +		else +			set_sta_flag(rx->sta, WLAN_STA_UAPSD); +	} + +	return RX_CONTINUE; +} + +static ieee80211_rx_result debug_noinline  ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)  {  	struct sta_info *sta = rx->sta; @@ -1216,7 +1295,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)  	    !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&  	    (rx->sdata->vif.type == NL80211_IFTYPE_AP ||  	     rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { -		if (test_sta_flags(sta, WLAN_STA_PS_STA)) { +		if (test_sta_flag(sta, WLAN_STA_PS_STA)) {  			/*  			 * Ignore doze->wake transitions that are  			 * indicated by non-data frames, the standard @@ -1469,33 +1548,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)  }  static ieee80211_rx_result debug_noinline -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) || -		   !(status->rx_flags & IEEE80211_RX_RA_MATCH))) -		return RX_CONTINUE; - -	if ((sdata->vif.type != NL80211_IFTYPE_AP) && -	    (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)) -		return RX_DROP_UNUSABLE; - -	if (!test_sta_flags(rx->sta, WLAN_STA_PS_DRIVER)) -		ieee80211_sta_ps_deliver_poll_response(rx->sta); -	else -		set_sta_flags(rx->sta, WLAN_STA_PSPOLL); - -	/* Free PS Poll skb here instead of returning RX_DROP that would -	 * count as an dropped frame. */ -	dev_kfree_skb(rx->skb); - -	return RX_QUEUED; -} - -static ieee80211_rx_result debug_noinline  ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx)  {  	u8 *data = rx->skb->data; @@ -1518,7 +1570,7 @@ static int  ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)  {  	if (unlikely(!rx->sta || -	    !test_sta_flags(rx->sta, WLAN_STA_AUTHORIZED))) +	    !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED)))  		return -EACCES;  	return 0; @@ -1561,7 +1613,7 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)  	if (status->flag & RX_FLAG_DECRYPTED)  		return 0; -	if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) { +	if (rx->sta && test_sta_flag(rx->sta, WLAN_STA_MFP)) {  		if (unlikely(!ieee80211_has_protected(fc) &&  			     ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&  			     rx->key)) { @@ -1827,6 +1879,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  	hdrlen = ieee80211_hdrlen(hdr->frame_control);  	mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); +	/* frame is in RMC, don't forward */ +	if (ieee80211_is_data(hdr->frame_control) && +	    is_multicast_ether_addr(hdr->addr1) && +	    mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata)) +		return RX_DROP_MONITOR; +  	if (!ieee80211_is_data(hdr->frame_control))  		return RX_CONTINUE; @@ -1834,6 +1892,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  		/* illegal frame */  		return RX_DROP_MONITOR; +	if (ieee80211_queue_stopped(&local->hw, skb_get_queue_mapping(skb))) { +		IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, +						dropped_frames_congestion); +		return RX_DROP_MONITOR; +	} +  	if (mesh_hdr->flags & MESH_FLAGS_AE) {  		struct mesh_path *mppath;  		char *proxied_addr; @@ -1889,13 +1953,13 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  			memset(info, 0, sizeof(*info));  			info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;  			info->control.vif = &rx->sdata->vif; -			skb_set_queue_mapping(skb, -				ieee80211_select_queue(rx->sdata, fwd_skb)); -			ieee80211_set_qos_hdr(local, skb); -			if (is_multicast_ether_addr(fwd_hdr->addr1)) +			if (is_multicast_ether_addr(fwd_hdr->addr1)) {  				IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,  								fwded_mcast); -			else { +				skb_set_queue_mapping(fwd_skb, +					ieee80211_select_queue(sdata, fwd_skb)); +				ieee80211_set_qos_hdr(sdata, fwd_skb); +			} else {  				int err;  				/*  				 * Save TA to addr1 to send TA a path error if a @@ -2220,12 +2284,29 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)  			goto handled;  		}  		break; +	case WLAN_CATEGORY_SELF_PROTECTED: +		switch (mgmt->u.action.u.self_prot.action_code) { +		case WLAN_SP_MESH_PEERING_OPEN: +		case WLAN_SP_MESH_PEERING_CLOSE: +		case WLAN_SP_MESH_PEERING_CONFIRM: +			if (!ieee80211_vif_is_mesh(&sdata->vif)) +				goto invalid; +			if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE) +				/* userspace handles this frame */ +				break; +			goto queue; +		case WLAN_SP_MGK_INFORM: +		case WLAN_SP_MGK_ACK: +			if (!ieee80211_vif_is_mesh(&sdata->vif)) +				goto invalid; +			break; +		} +		break;  	case WLAN_CATEGORY_MESH_ACTION:  		if (!ieee80211_vif_is_mesh(&sdata->vif))  			break; -		goto queue; -	case WLAN_CATEGORY_MESH_PATH_SEL: -		if (!mesh_path_sel_is_hwmp(sdata)) +		if (mesh_action_is_path_sel(mgmt) && +		  (!mesh_path_sel_is_hwmp(sdata)))  			break;  		goto queue;  	} @@ -2534,17 +2615,17 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx)  		CALL_RXH(ieee80211_rx_h_decrypt)  		CALL_RXH(ieee80211_rx_h_check_more_data) +		CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll)  		CALL_RXH(ieee80211_rx_h_sta_process)  		CALL_RXH(ieee80211_rx_h_defragment) -		CALL_RXH(ieee80211_rx_h_ps_poll)  		CALL_RXH(ieee80211_rx_h_michael_mic_verify)  		/* must be after MMIC verify so header is counted in MPDU mic */ -		CALL_RXH(ieee80211_rx_h_remove_qos_control) -		CALL_RXH(ieee80211_rx_h_amsdu)  #ifdef CONFIG_MAC80211_MESH  		if (ieee80211_vif_is_mesh(&rx->sdata->vif))  			CALL_RXH(ieee80211_rx_h_mesh_fwding);  #endif +		CALL_RXH(ieee80211_rx_h_remove_qos_control) +		CALL_RXH(ieee80211_rx_h_amsdu)  		CALL_RXH(ieee80211_rx_h_data)  		CALL_RXH(ieee80211_rx_h_ctrl);  		CALL_RXH(ieee80211_rx_h_mgmt_check) @@ -2686,7 +2767,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,  		} else if (!ieee80211_bssid_match(bssid,  					sdata->vif.addr)) {  			if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) && -			    !ieee80211_is_beacon(hdr->frame_control)) +			    !ieee80211_is_beacon(hdr->frame_control) && +			    !(ieee80211_is_action(hdr->frame_control) && +			      sdata->vif.p2p))  				return 0;  			status->rx_flags &= ~IEEE80211_RX_RA_MATCH;  		} @@ -2791,7 +2874,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,  	if (ieee80211_is_data(fc)) {  		prev_sta = NULL; -		for_each_sta_info(local, hdr->addr2, sta, tmp) { +		for_each_sta_info_rx(local, hdr->addr2, sta, tmp) {  			if (!prev_sta) {  				prev_sta = sta;  				continue; @@ -2835,7 +2918,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,  			continue;  		} -		rx.sta = sta_info_get_bss(prev, hdr->addr2); +		rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);  		rx.sdata = prev;  		ieee80211_prepare_and_rx_handle(&rx, skb, false); @@ -2843,7 +2926,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,  	}  	if (prev) { -		rx.sta = sta_info_get_bss(prev, hdr->addr2); +		rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);  		rx.sdata = prev;  		if (ieee80211_prepare_and_rx_handle(&rx, skb, true))  |