mac80211: move csa counters from sdata to beacon/presp
Having csa counters part of beacon and probe_resp structures makes it easier to get rid of possible races between setting a beacon and updating counters on SMP systems by guaranteeing counters are always consistent against given beacon struct. While at it relax WARN_ON into WARN_ON_ONCE to prevent spamming logs and racing. Signed-off-by: Michal Kazior <michal.kazior@tieto.com> [remove pointless array check] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
		
					parent
					
						
							
								b49328361b
							
						
					
				
			
			
				commit
				
					
						af296bdb8d
					
				
			
		
					 5 changed files with 115 additions and 75 deletions
				
			
		|  | @ -554,7 +554,8 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | ||||||
| 				    const u8 *resp, size_t resp_len) | 				    const u8 *resp, size_t resp_len, | ||||||
|  | 				    const struct ieee80211_csa_settings *csa) | ||||||
| { | { | ||||||
| 	struct probe_resp *new, *old; | 	struct probe_resp *new, *old; | ||||||
| 
 | 
 | ||||||
|  | @ -570,6 +571,11 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | ||||||
| 	new->len = resp_len; | 	new->len = resp_len; | ||||||
| 	memcpy(new->data, resp, resp_len); | 	memcpy(new->data, resp, resp_len); | ||||||
| 
 | 
 | ||||||
|  | 	if (csa) | ||||||
|  | 		memcpy(new->csa_counter_offsets, csa->counter_offsets_presp, | ||||||
|  | 		       csa->n_counter_offsets_presp * | ||||||
|  | 		       sizeof(new->csa_counter_offsets[0])); | ||||||
|  | 
 | ||||||
| 	rcu_assign_pointer(sdata->u.ap.probe_resp, new); | 	rcu_assign_pointer(sdata->u.ap.probe_resp, new); | ||||||
| 	if (old) | 	if (old) | ||||||
| 		kfree_rcu(old, rcu_head); | 		kfree_rcu(old, rcu_head); | ||||||
|  | @ -578,7 +584,8 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | ||||||
| 				   struct cfg80211_beacon_data *params) | 				   struct cfg80211_beacon_data *params, | ||||||
|  | 				   const struct ieee80211_csa_settings *csa) | ||||||
| { | { | ||||||
| 	struct beacon_data *new, *old; | 	struct beacon_data *new, *old; | ||||||
| 	int new_head_len, new_tail_len; | 	int new_head_len, new_tail_len; | ||||||
|  | @ -622,6 +629,13 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | ||||||
| 	new->head_len = new_head_len; | 	new->head_len = new_head_len; | ||||||
| 	new->tail_len = new_tail_len; | 	new->tail_len = new_tail_len; | ||||||
| 
 | 
 | ||||||
|  | 	if (csa) { | ||||||
|  | 		new->csa_current_counter = csa->count; | ||||||
|  | 		memcpy(new->csa_counter_offsets, csa->counter_offsets_beacon, | ||||||
|  | 		       csa->n_counter_offsets_beacon * | ||||||
|  | 		       sizeof(new->csa_counter_offsets[0])); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/* copy in head */ | 	/* copy in head */ | ||||||
| 	if (params->head) | 	if (params->head) | ||||||
| 		memcpy(new->head, params->head, new_head_len); | 		memcpy(new->head, params->head, new_head_len); | ||||||
|  | @ -636,7 +650,7 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | ||||||
| 			memcpy(new->tail, old->tail, new_tail_len); | 			memcpy(new->tail, old->tail, new_tail_len); | ||||||
| 
 | 
 | ||||||
| 	err = ieee80211_set_probe_resp(sdata, params->probe_resp, | 	err = ieee80211_set_probe_resp(sdata, params->probe_resp, | ||||||
| 				       params->probe_resp_len); | 				       params->probe_resp_len, csa); | ||||||
| 	if (err < 0) | 	if (err < 0) | ||||||
| 		return err; | 		return err; | ||||||
| 	if (err == 0) | 	if (err == 0) | ||||||
|  | @ -721,7 +735,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | ||||||
| 		sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |= | 		sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |= | ||||||
| 					IEEE80211_P2P_OPPPS_ENABLE_BIT; | 					IEEE80211_P2P_OPPPS_ENABLE_BIT; | ||||||
| 
 | 
 | ||||||
| 	err = ieee80211_assign_beacon(sdata, ¶ms->beacon); | 	err = ieee80211_assign_beacon(sdata, ¶ms->beacon, NULL); | ||||||
| 	if (err < 0) { | 	if (err < 0) { | ||||||
| 		ieee80211_vif_release_channel(sdata); | 		ieee80211_vif_release_channel(sdata); | ||||||
| 		return err; | 		return err; | ||||||
|  | @ -769,7 +783,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, | ||||||
| 	if (!old) | 	if (!old) | ||||||
| 		return -ENOENT; | 		return -ENOENT; | ||||||
| 
 | 
 | ||||||
| 	err = ieee80211_assign_beacon(sdata, params); | 	err = ieee80211_assign_beacon(sdata, params, NULL); | ||||||
| 	if (err < 0) | 	if (err < 0) | ||||||
| 		return err; | 		return err; | ||||||
| 	ieee80211_bss_info_change_notify(sdata, err); | 	ieee80211_bss_info_change_notify(sdata, err); | ||||||
|  | @ -2752,7 +2766,8 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata, | ||||||
| 
 | 
 | ||||||
| 	switch (sdata->vif.type) { | 	switch (sdata->vif.type) { | ||||||
| 	case NL80211_IFTYPE_AP: | 	case NL80211_IFTYPE_AP: | ||||||
| 		err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); | 		err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, | ||||||
|  | 					      NULL); | ||||||
| 		kfree(sdata->u.ap.next_beacon); | 		kfree(sdata->u.ap.next_beacon); | ||||||
| 		sdata->u.ap.next_beacon = NULL; | 		sdata->u.ap.next_beacon = NULL; | ||||||
| 
 | 
 | ||||||
|  | @ -2855,6 +2870,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, | ||||||
| 				    struct cfg80211_csa_settings *params, | 				    struct cfg80211_csa_settings *params, | ||||||
| 				    u32 *changed) | 				    u32 *changed) | ||||||
| { | { | ||||||
|  | 	struct ieee80211_csa_settings csa = {}; | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	switch (sdata->vif.type) { | 	switch (sdata->vif.type) { | ||||||
|  | @ -2889,20 +2905,13 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, | ||||||
| 		     IEEE80211_MAX_CSA_COUNTERS_NUM)) | 		     IEEE80211_MAX_CSA_COUNTERS_NUM)) | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 		/* make sure we don't have garbage in other counters */ | 		csa.counter_offsets_beacon = params->counter_offsets_beacon; | ||||||
| 		memset(sdata->csa_counter_offset_beacon, 0, | 		csa.counter_offsets_presp = params->counter_offsets_presp; | ||||||
| 		       sizeof(sdata->csa_counter_offset_beacon)); | 		csa.n_counter_offsets_beacon = params->n_counter_offsets_beacon; | ||||||
| 		memset(sdata->csa_counter_offset_presp, 0, | 		csa.n_counter_offsets_presp = params->n_counter_offsets_presp; | ||||||
| 		       sizeof(sdata->csa_counter_offset_presp)); | 		csa.count = params->count; | ||||||
| 
 | 
 | ||||||
| 		memcpy(sdata->csa_counter_offset_beacon, | 		err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa); | ||||||
| 		       params->counter_offsets_beacon, |  | ||||||
| 		       params->n_counter_offsets_beacon * sizeof(u16)); |  | ||||||
| 		memcpy(sdata->csa_counter_offset_presp, |  | ||||||
| 		       params->counter_offsets_presp, |  | ||||||
| 		       params->n_counter_offsets_presp * sizeof(u16)); |  | ||||||
| 
 |  | ||||||
| 		err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); |  | ||||||
| 		if (err < 0) { | 		if (err < 0) { | ||||||
| 			kfree(sdata->u.ap.next_beacon); | 			kfree(sdata->u.ap.next_beacon); | ||||||
| 			return err; | 			return err; | ||||||
|  | @ -3046,7 +3055,6 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | ||||||
| 	sdata->csa_radar_required = params->radar_required; | 	sdata->csa_radar_required = params->radar_required; | ||||||
| 	sdata->csa_chandef = params->chandef; | 	sdata->csa_chandef = params->chandef; | ||||||
| 	sdata->csa_block_tx = params->block_tx; | 	sdata->csa_block_tx = params->block_tx; | ||||||
| 	sdata->csa_current_counter = params->count; |  | ||||||
| 	sdata->vif.csa_active = true; | 	sdata->vif.csa_active = true; | ||||||
| 
 | 
 | ||||||
| 	if (sdata->csa_block_tx) | 	if (sdata->csa_block_tx) | ||||||
|  | @ -3194,10 +3202,23 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | ||||||
| 	     sdata->vif.type == NL80211_IFTYPE_ADHOC) && | 	     sdata->vif.type == NL80211_IFTYPE_ADHOC) && | ||||||
| 	    params->n_csa_offsets) { | 	    params->n_csa_offsets) { | ||||||
| 		int i; | 		int i; | ||||||
| 		u8 c = sdata->csa_current_counter; | 		struct beacon_data *beacon = NULL; | ||||||
| 
 | 
 | ||||||
|  | 		rcu_read_lock(); | ||||||
|  | 
 | ||||||
|  | 		if (sdata->vif.type == NL80211_IFTYPE_AP) | ||||||
|  | 			beacon = rcu_dereference(sdata->u.ap.beacon); | ||||||
|  | 		else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||||||
|  | 			beacon = rcu_dereference(sdata->u.ibss.presp); | ||||||
|  | 		else if (ieee80211_vif_is_mesh(&sdata->vif)) | ||||||
|  | 			beacon = rcu_dereference(sdata->u.mesh.beacon); | ||||||
|  | 
 | ||||||
|  | 		if (beacon) | ||||||
| 			for (i = 0; i < params->n_csa_offsets; i++) | 			for (i = 0; i < params->n_csa_offsets; i++) | ||||||
| 			data[params->csa_offsets[i]] = c; | 				data[params->csa_offsets[i]] = | ||||||
|  | 					beacon->csa_current_counter; | ||||||
|  | 
 | ||||||
|  | 		rcu_read_unlock(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	IEEE80211_SKB_CB(skb)->flags = flags; | 	IEEE80211_SKB_CB(skb)->flags = flags; | ||||||
|  |  | ||||||
|  | @ -143,7 +143,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, | ||||||
| 		*pos++ = csa_settings->block_tx ? 1 : 0; | 		*pos++ = csa_settings->block_tx ? 1 : 0; | ||||||
| 		*pos++ = ieee80211_frequency_to_channel( | 		*pos++ = ieee80211_frequency_to_channel( | ||||||
| 				csa_settings->chandef.chan->center_freq); | 				csa_settings->chandef.chan->center_freq); | ||||||
| 		sdata->csa_counter_offset_beacon[0] = (pos - presp->head); | 		presp->csa_counter_offsets[0] = (pos - presp->head); | ||||||
| 		*pos++ = csa_settings->count; | 		*pos++ = csa_settings->count; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -229,16 +229,29 @@ struct ieee80211_rx_data { | ||||||
| 	u16 tkip_iv16; | 	u16 tkip_iv16; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct ieee80211_csa_settings { | ||||||
|  | 	const u16 *counter_offsets_beacon; | ||||||
|  | 	const u16 *counter_offsets_presp; | ||||||
|  | 
 | ||||||
|  | 	int n_counter_offsets_beacon; | ||||||
|  | 	int n_counter_offsets_presp; | ||||||
|  | 
 | ||||||
|  | 	u8 count; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct beacon_data { | struct beacon_data { | ||||||
| 	u8 *head, *tail; | 	u8 *head, *tail; | ||||||
| 	int head_len, tail_len; | 	int head_len, tail_len; | ||||||
| 	struct ieee80211_meshconf_ie *meshconf; | 	struct ieee80211_meshconf_ie *meshconf; | ||||||
|  | 	u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM]; | ||||||
|  | 	u8 csa_current_counter; | ||||||
| 	struct rcu_head rcu_head; | 	struct rcu_head rcu_head; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct probe_resp { | struct probe_resp { | ||||||
| 	struct rcu_head rcu_head; | 	struct rcu_head rcu_head; | ||||||
| 	int len; | 	int len; | ||||||
|  | 	u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM]; | ||||||
| 	u8 data[0]; | 	u8 data[0]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -754,8 +767,6 @@ struct ieee80211_sub_if_data { | ||||||
| 	struct mac80211_qos_map __rcu *qos_map; | 	struct mac80211_qos_map __rcu *qos_map; | ||||||
| 
 | 
 | ||||||
| 	struct work_struct csa_finalize_work; | 	struct work_struct csa_finalize_work; | ||||||
| 	u16 csa_counter_offset_beacon[IEEE80211_MAX_CSA_COUNTERS_NUM]; |  | ||||||
| 	u16 csa_counter_offset_presp[IEEE80211_MAX_CSA_COUNTERS_NUM]; |  | ||||||
| 	bool csa_radar_required; | 	bool csa_radar_required; | ||||||
| 	bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ | 	bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ | ||||||
| 	struct cfg80211_chan_def csa_chandef; | 	struct cfg80211_chan_def csa_chandef; | ||||||
|  | @ -767,7 +778,6 @@ struct ieee80211_sub_if_data { | ||||||
| 	struct ieee80211_chanctx *reserved_chanctx; | 	struct ieee80211_chanctx *reserved_chanctx; | ||||||
| 	struct cfg80211_chan_def reserved_chandef; | 	struct cfg80211_chan_def reserved_chandef; | ||||||
| 	bool reserved_radar_required; | 	bool reserved_radar_required; | ||||||
| 	u8 csa_current_counter; |  | ||||||
| 
 | 
 | ||||||
| 	/* used to reconfigure hardware SM PS */ | 	/* used to reconfigure hardware SM PS */ | ||||||
| 	struct work_struct recalc_smps; | 	struct work_struct recalc_smps; | ||||||
|  |  | ||||||
|  | @ -679,7 +679,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | ||||||
| 		*pos++ = 0x0; | 		*pos++ = 0x0; | ||||||
| 		*pos++ = ieee80211_frequency_to_channel( | 		*pos++ = ieee80211_frequency_to_channel( | ||||||
| 				csa->settings.chandef.chan->center_freq); | 				csa->settings.chandef.chan->center_freq); | ||||||
| 		sdata->csa_counter_offset_beacon[0] = hdr_len + 6; | 		bcn->csa_counter_offsets[0] = hdr_len + 6; | ||||||
| 		*pos++ = csa->settings.count; | 		*pos++ = csa->settings.count; | ||||||
| 		*pos++ = WLAN_EID_CHAN_SWITCH_PARAM; | 		*pos++ = WLAN_EID_CHAN_SWITCH_PARAM; | ||||||
| 		*pos++ = 6; | 		*pos++ = 6; | ||||||
|  |  | ||||||
|  | @ -2426,7 +2426,7 @@ static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata, | ||||||
| 	u8 *beacon_data; | 	u8 *beacon_data; | ||||||
| 	size_t beacon_data_len; | 	size_t beacon_data_len; | ||||||
| 	int i; | 	int i; | ||||||
| 	u8 count = sdata->csa_current_counter; | 	u8 count = beacon->csa_current_counter; | ||||||
| 
 | 
 | ||||||
| 	switch (sdata->vif.type) { | 	switch (sdata->vif.type) { | ||||||
| 	case NL80211_IFTYPE_AP: | 	case NL80211_IFTYPE_AP: | ||||||
|  | @ -2445,46 +2445,53 @@ static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata, | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) { |  | ||||||
| 		u16 counter_offset_beacon = |  | ||||||
| 			sdata->csa_counter_offset_beacon[i]; |  | ||||||
| 		u16 counter_offset_presp = sdata->csa_counter_offset_presp[i]; |  | ||||||
| 
 |  | ||||||
| 		if (counter_offset_beacon) { |  | ||||||
| 			if (WARN_ON(counter_offset_beacon >= beacon_data_len)) |  | ||||||
| 				return; |  | ||||||
| 
 |  | ||||||
| 			beacon_data[counter_offset_beacon] = count; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (sdata->vif.type == NL80211_IFTYPE_AP && |  | ||||||
| 		    counter_offset_presp) { |  | ||||||
| 	rcu_read_lock(); | 	rcu_read_lock(); | ||||||
|  | 	for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) { | ||||||
| 		resp = rcu_dereference(sdata->u.ap.probe_resp); | 		resp = rcu_dereference(sdata->u.ap.probe_resp); | ||||||
| 
 | 
 | ||||||
| 			/* If nl80211 accepted the offset, this should
 | 		if (beacon->csa_counter_offsets[i]) { | ||||||
| 			 * not happen. | 			if (WARN_ON_ONCE(beacon->csa_counter_offsets[i] >= | ||||||
| 			 */ | 					 beacon_data_len)) { | ||||||
| 			if (WARN_ON(!resp)) { |  | ||||||
| 				rcu_read_unlock(); | 				rcu_read_unlock(); | ||||||
| 				return; | 				return; | ||||||
| 			} | 			} | ||||||
| 			resp->data[counter_offset_presp] = count; | 
 | ||||||
|  | 			beacon_data[beacon->csa_counter_offsets[i]] = count; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (sdata->vif.type == NL80211_IFTYPE_AP && resp) | ||||||
|  | 			resp->data[resp->csa_counter_offsets[i]] = count; | ||||||
|  | 	} | ||||||
| 	rcu_read_unlock(); | 	rcu_read_unlock(); | ||||||
| } | } | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif) | u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif) | ||||||
| { | { | ||||||
| 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||||||
|  | 	struct beacon_data *beacon = NULL; | ||||||
|  | 	u8 count = 0; | ||||||
| 
 | 
 | ||||||
| 	sdata->csa_current_counter--; | 	rcu_read_lock(); | ||||||
|  | 
 | ||||||
|  | 	if (sdata->vif.type == NL80211_IFTYPE_AP) | ||||||
|  | 		beacon = rcu_dereference(sdata->u.ap.beacon); | ||||||
|  | 	else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||||||
|  | 		beacon = rcu_dereference(sdata->u.ibss.presp); | ||||||
|  | 	else if (ieee80211_vif_is_mesh(&sdata->vif)) | ||||||
|  | 		beacon = rcu_dereference(sdata->u.mesh.beacon); | ||||||
|  | 
 | ||||||
|  | 	if (!beacon) | ||||||
|  | 		goto unlock; | ||||||
|  | 
 | ||||||
|  | 	beacon->csa_current_counter--; | ||||||
| 
 | 
 | ||||||
| 	/* the counter should never reach 0 */ | 	/* the counter should never reach 0 */ | ||||||
| 	WARN_ON(!sdata->csa_current_counter); | 	WARN_ON_ONCE(!beacon->csa_current_counter); | ||||||
|  | 	count = beacon->csa_current_counter; | ||||||
| 
 | 
 | ||||||
| 	return sdata->csa_current_counter; | unlock: | ||||||
|  | 	rcu_read_unlock(); | ||||||
|  | 	return count; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(ieee80211_csa_update_counter); | EXPORT_SYMBOL(ieee80211_csa_update_counter); | ||||||
| 
 | 
 | ||||||
|  | @ -2494,7 +2501,6 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) | ||||||
| 	struct beacon_data *beacon = NULL; | 	struct beacon_data *beacon = NULL; | ||||||
| 	u8 *beacon_data; | 	u8 *beacon_data; | ||||||
| 	size_t beacon_data_len; | 	size_t beacon_data_len; | ||||||
| 	int counter_beacon = sdata->csa_counter_offset_beacon[0]; |  | ||||||
| 	int ret = false; | 	int ret = false; | ||||||
| 
 | 
 | ||||||
| 	if (!ieee80211_sdata_running(sdata)) | 	if (!ieee80211_sdata_running(sdata)) | ||||||
|  | @ -2532,10 +2538,10 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (WARN_ON(counter_beacon > beacon_data_len)) | 	if (WARN_ON_ONCE(beacon->csa_counter_offsets[0] > beacon_data_len)) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	if (beacon_data[counter_beacon] == 1) | 	if (beacon_data[beacon->csa_counter_offsets[0]] == 1) | ||||||
| 		ret = true; | 		ret = true; | ||||||
|  out: |  out: | ||||||
| 	rcu_read_unlock(); | 	rcu_read_unlock(); | ||||||
|  | @ -2551,6 +2557,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | ||||||
| 		       bool is_template) | 		       bool is_template) | ||||||
| { | { | ||||||
| 	struct ieee80211_local *local = hw_to_local(hw); | 	struct ieee80211_local *local = hw_to_local(hw); | ||||||
|  | 	struct beacon_data *beacon = NULL; | ||||||
| 	struct sk_buff *skb = NULL; | 	struct sk_buff *skb = NULL; | ||||||
| 	struct ieee80211_tx_info *info; | 	struct ieee80211_tx_info *info; | ||||||
| 	struct ieee80211_sub_if_data *sdata = NULL; | 	struct ieee80211_sub_if_data *sdata = NULL; | ||||||
|  | @ -2572,8 +2579,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | ||||||
| 
 | 
 | ||||||
| 	if (sdata->vif.type == NL80211_IFTYPE_AP) { | 	if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||||||
| 		struct ieee80211_if_ap *ap = &sdata->u.ap; | 		struct ieee80211_if_ap *ap = &sdata->u.ap; | ||||||
| 		struct beacon_data *beacon = rcu_dereference(ap->beacon); |  | ||||||
| 
 | 
 | ||||||
|  | 		beacon = rcu_dereference(ap->beacon); | ||||||
| 		if (beacon) { | 		if (beacon) { | ||||||
| 			if (sdata->vif.csa_active) { | 			if (sdata->vif.csa_active) { | ||||||
| 				if (!is_template) | 				if (!is_template) | ||||||
|  | @ -2616,34 +2623,34 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | ||||||
| 	} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 	} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||||||
| 		struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 		struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||||||
| 		struct ieee80211_hdr *hdr; | 		struct ieee80211_hdr *hdr; | ||||||
| 		struct beacon_data *presp = rcu_dereference(ifibss->presp); |  | ||||||
| 
 | 
 | ||||||
| 		if (!presp) | 		beacon = rcu_dereference(ifibss->presp); | ||||||
|  | 		if (!beacon) | ||||||
| 			goto out; | 			goto out; | ||||||
| 
 | 
 | ||||||
| 		if (sdata->vif.csa_active) { | 		if (sdata->vif.csa_active) { | ||||||
| 			if (!is_template) | 			if (!is_template) | ||||||
| 				ieee80211_csa_update_counter(vif); | 				ieee80211_csa_update_counter(vif); | ||||||
| 
 | 
 | ||||||
| 			ieee80211_set_csa(sdata, presp); | 			ieee80211_set_csa(sdata, beacon); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		skb = dev_alloc_skb(local->tx_headroom + presp->head_len + | 		skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + | ||||||
| 				    local->hw.extra_beacon_tailroom); | 				    local->hw.extra_beacon_tailroom); | ||||||
| 		if (!skb) | 		if (!skb) | ||||||
| 			goto out; | 			goto out; | ||||||
| 		skb_reserve(skb, local->tx_headroom); | 		skb_reserve(skb, local->tx_headroom); | ||||||
| 		memcpy(skb_put(skb, presp->head_len), presp->head, | 		memcpy(skb_put(skb, beacon->head_len), beacon->head, | ||||||
| 		       presp->head_len); | 		       beacon->head_len); | ||||||
| 
 | 
 | ||||||
| 		hdr = (struct ieee80211_hdr *) skb->data; | 		hdr = (struct ieee80211_hdr *) skb->data; | ||||||
| 		hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 		hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||||||
| 						 IEEE80211_STYPE_BEACON); | 						 IEEE80211_STYPE_BEACON); | ||||||
| 	} else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 	} else if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||||||
| 		struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 		struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||||||
| 		struct beacon_data *bcn = rcu_dereference(ifmsh->beacon); |  | ||||||
| 
 | 
 | ||||||
| 		if (!bcn) | 		beacon = rcu_dereference(ifmsh->beacon); | ||||||
|  | 		if (!beacon) | ||||||
| 			goto out; | 			goto out; | ||||||
| 
 | 
 | ||||||
| 		if (sdata->vif.csa_active) { | 		if (sdata->vif.csa_active) { | ||||||
|  | @ -2655,40 +2662,42 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | ||||||
| 				 */ | 				 */ | ||||||
| 				ieee80211_csa_update_counter(vif); | 				ieee80211_csa_update_counter(vif); | ||||||
| 
 | 
 | ||||||
| 			ieee80211_set_csa(sdata, bcn); | 			ieee80211_set_csa(sdata, beacon); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (ifmsh->sync_ops) | 		if (ifmsh->sync_ops) | ||||||
| 			ifmsh->sync_ops->adjust_tbtt(sdata, bcn); | 			ifmsh->sync_ops->adjust_tbtt(sdata, beacon); | ||||||
| 
 | 
 | ||||||
| 		skb = dev_alloc_skb(local->tx_headroom + | 		skb = dev_alloc_skb(local->tx_headroom + | ||||||
| 				    bcn->head_len + | 				    beacon->head_len + | ||||||
| 				    256 + /* TIM IE */ | 				    256 + /* TIM IE */ | ||||||
| 				    bcn->tail_len + | 				    beacon->tail_len + | ||||||
| 				    local->hw.extra_beacon_tailroom); | 				    local->hw.extra_beacon_tailroom); | ||||||
| 		if (!skb) | 		if (!skb) | ||||||
| 			goto out; | 			goto out; | ||||||
| 		skb_reserve(skb, local->tx_headroom); | 		skb_reserve(skb, local->tx_headroom); | ||||||
| 		memcpy(skb_put(skb, bcn->head_len), bcn->head, bcn->head_len); | 		memcpy(skb_put(skb, beacon->head_len), beacon->head, | ||||||
|  | 		       beacon->head_len); | ||||||
| 		ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template); | 		ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template); | ||||||
| 
 | 
 | ||||||
| 		if (offs) { | 		if (offs) { | ||||||
| 			offs->tim_offset = bcn->head_len; | 			offs->tim_offset = beacon->head_len; | ||||||
| 			offs->tim_length = skb->len - bcn->head_len; | 			offs->tim_length = skb->len - beacon->head_len; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		memcpy(skb_put(skb, bcn->tail_len), bcn->tail, bcn->tail_len); | 		memcpy(skb_put(skb, beacon->tail_len), beacon->tail, | ||||||
|  | 		       beacon->tail_len); | ||||||
| 	} else { | 	} else { | ||||||
| 		WARN_ON(1); | 		WARN_ON(1); | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* CSA offsets */ | 	/* CSA offsets */ | ||||||
| 	if (offs) { | 	if (offs && beacon) { | ||||||
| 		int i; | 		int i; | ||||||
| 
 | 
 | ||||||
| 		for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; i++) { | 		for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; i++) { | ||||||
| 			u16 csa_off = sdata->csa_counter_offset_beacon[i]; | 			u16 csa_off = beacon->csa_counter_offsets[i]; | ||||||
| 
 | 
 | ||||||
| 			if (!csa_off) | 			if (!csa_off) | ||||||
| 				continue; | 				continue; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Michal Kazior
				Michal Kazior