diff options
Diffstat (limited to 'net/mac80211/util.c')
| -rw-r--r-- | net/mac80211/util.c | 107 | 
1 files changed, 87 insertions, 20 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index f11e8c540db..0f38f43ac62 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -739,11 +739,7 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,  				if (calc_crc)  					crc = crc32_be(crc, pos - 2, elen + 2); -				if (pos[3] == 1) { -					/* OUI Type 1 - WPA IE */ -					elems->wpa = pos; -					elems->wpa_len = elen; -				} else if (elen >= 5 && pos[3] == 2) { +				if (elen >= 5 && pos[3] == 2) {  					/* OUI Type 2 - WMM IE */  					if (pos[4] == 0) {  						elems->wmm_info = pos; @@ -791,6 +787,12 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,  			else  				elem_parse_failed = true;  			break; +		case WLAN_EID_OPMODE_NOTIF: +			if (elen > 0) +				elems->opmode_notif = pos; +			else +				elem_parse_failed = true; +			break;  		case WLAN_EID_MESH_ID:  			elems->mesh_id = pos;  			elems->mesh_id_len = elen; @@ -805,6 +807,10 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,  			elems->peering = pos;  			elems->peering_len = elen;  			break; +		case WLAN_EID_MESH_AWAKE_WINDOW: +			if (elen >= 2) +				elems->awake_window = (void *)pos; +			break;  		case WLAN_EID_PREQ:  			elems->preq = pos;  			elems->preq_len = elen; @@ -1029,8 +1035,9 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local,  void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,  			 u16 transaction, u16 auth_alg, u16 status, -			 u8 *extra, size_t extra_len, const u8 *da, -			 const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx) +			 const u8 *extra, size_t extra_len, const u8 *da, +			 const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx, +			 u32 tx_flags)  {  	struct ieee80211_local *local = sdata->local;  	struct sk_buff *skb; @@ -1063,7 +1070,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,  		WARN_ON(err);  	} -	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; +	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | +					tx_flags;  	ieee80211_tx_skb(sdata, skb);  } @@ -1277,7 +1285,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,  void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,  			      const u8 *ssid, size_t ssid_len,  			      const u8 *ie, size_t ie_len, -			      u32 ratemask, bool directed, bool no_cck, +			      u32 ratemask, bool directed, u32 tx_flags,  			      struct ieee80211_channel *channel, bool scan)  {  	struct sk_buff *skb; @@ -1286,9 +1294,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,  					ssid, ssid_len,  					ie, ie_len, directed);  	if (skb) { -		if (no_cck) -			IEEE80211_SKB_CB(skb)->flags |= -				IEEE80211_TX_CTL_NO_CCK_RATE; +		IEEE80211_SKB_CB(skb)->flags |= tx_flags;  		if (scan)  			ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band);  		else @@ -1358,6 +1364,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)  	struct ieee80211_chanctx *ctx;  	struct sta_info *sta;  	int res, i; +	bool reconfig_due_to_wowlan = false;  #ifdef CONFIG_PM  	if (local->suspended) @@ -1377,6 +1384,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)  		 * res is 1, which means the driver requested  		 * to go through a regular reset on wakeup.  		 */ +		reconfig_due_to_wowlan = true;  	}  #endif  	/* everything else happens only if HW was up & running */ @@ -1526,11 +1534,20 @@ int ieee80211_reconfig(struct ieee80211_local *local)  			  BSS_CHANGED_IDLE |  			  BSS_CHANGED_TXPOWER; +#ifdef CONFIG_PM +		if (local->resuming && !reconfig_due_to_wowlan) +			sdata->vif.bss_conf = sdata->suspend_bss_conf; +#endif +  		switch (sdata->vif.type) {  		case NL80211_IFTYPE_STATION:  			changed |= BSS_CHANGED_ASSOC |  				   BSS_CHANGED_ARP_FILTER |  				   BSS_CHANGED_PS; + +			if (sdata->u.mgd.dtim_period) +				changed |= BSS_CHANGED_DTIM_PERIOD; +  			mutex_lock(&sdata->u.mgd.mtx);  			ieee80211_bss_info_change_notify(sdata, changed);  			mutex_unlock(&sdata->u.mgd.mtx); @@ -1550,9 +1567,11 @@ int ieee80211_reconfig(struct ieee80211_local *local)  			/* fall through */  		case NL80211_IFTYPE_MESH_POINT: -			changed |= BSS_CHANGED_BEACON | -				   BSS_CHANGED_BEACON_ENABLED; -			ieee80211_bss_info_change_notify(sdata, changed); +			if (sdata->vif.bss_conf.enable_beacon) { +				changed |= BSS_CHANGED_BEACON | +					   BSS_CHANGED_BEACON_ENABLED; +				ieee80211_bss_info_change_notify(sdata, changed); +			}  			break;  		case NL80211_IFTYPE_WDS:  			break; @@ -1632,7 +1651,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)  		mutex_lock(&local->sta_mtx);  		list_for_each_entry(sta, &local->sta_list, list) { -			ieee80211_sta_tear_down_BA_sessions(sta, true); +			ieee80211_sta_tear_down_BA_sessions( +					sta, AGG_STOP_LOCAL_REQUEST);  			clear_sta_flag(sta, WLAN_STA_BLOCK_BA);  		} @@ -1646,10 +1666,11 @@ int ieee80211_reconfig(struct ieee80211_local *local)  	 * If this is for hw restart things are still running.  	 * We may want to change that later, however.  	 */ -	if (!local->suspended) { +	if (!local->suspended || reconfig_due_to_wowlan)  		drv_restart_complete(local); + +	if (!local->suspended)  		return 0; -	}  #ifdef CONFIG_PM  	/* first set suspended false, then resuming */ @@ -1864,7 +1885,7 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,  }  u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, -							   u32 cap) +			       u32 cap)  {  	__le32 tmp; @@ -1926,7 +1947,7 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,  }  void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, -				  struct ieee80211_ht_operation *ht_oper, +				  const struct ieee80211_ht_operation *ht_oper,  				  struct cfg80211_chan_def *chandef)  {  	enum nl80211_channel_type channel_type; @@ -2114,3 +2135,49 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,  	return ts;  } + +void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) +{ +	struct ieee80211_sub_if_data *sdata; + +	mutex_lock(&local->iflist_mtx); +	list_for_each_entry(sdata, &local->interfaces, list) { +		cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); + +		if (sdata->wdev.cac_started) { +			ieee80211_vif_release_channel(sdata); +			cfg80211_cac_event(sdata->dev, +					   NL80211_RADAR_CAC_ABORTED, +					   GFP_KERNEL); +		} +	} +	mutex_unlock(&local->iflist_mtx); +} + +void ieee80211_dfs_radar_detected_work(struct work_struct *work) +{ +	struct ieee80211_local *local = +		container_of(work, struct ieee80211_local, radar_detected_work); +	struct cfg80211_chan_def chandef; + +	ieee80211_dfs_cac_cancel(local); + +	if (local->use_chanctx) +		/* currently not handled */ +		WARN_ON(1); +	else { +		cfg80211_chandef_create(&chandef, local->hw.conf.channel, +					local->hw.conf.channel_type); +		cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL); +	} +} + +void ieee80211_radar_detected(struct ieee80211_hw *hw) +{ +	struct ieee80211_local *local = hw_to_local(hw); + +	trace_api_radar_detected(local); + +	ieee80211_queue_work(hw, &local->radar_detected_work); +} +EXPORT_SYMBOL(ieee80211_radar_detected);  |