forked from mirrors/linux
		
	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,
 | 
			
		||||
				    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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -570,6 +571,11 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
 | 
			
		|||
	new->len = 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);
 | 
			
		||||
	if (old)
 | 
			
		||||
		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,
 | 
			
		||||
				   struct cfg80211_beacon_data *params)
 | 
			
		||||
				   struct cfg80211_beacon_data *params,
 | 
			
		||||
				   const struct ieee80211_csa_settings *csa)
 | 
			
		||||
{
 | 
			
		||||
	struct beacon_data *new, *old;
 | 
			
		||||
	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->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 */
 | 
			
		||||
	if (params->head)
 | 
			
		||||
		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);
 | 
			
		||||
 | 
			
		||||
	err = ieee80211_set_probe_resp(sdata, params->probe_resp,
 | 
			
		||||
				       params->probe_resp_len);
 | 
			
		||||
				       params->probe_resp_len, csa);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		return err;
 | 
			
		||||
	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 |=
 | 
			
		||||
					IEEE80211_P2P_OPPPS_ENABLE_BIT;
 | 
			
		||||
 | 
			
		||||
	err = ieee80211_assign_beacon(sdata, ¶ms->beacon);
 | 
			
		||||
	err = ieee80211_assign_beacon(sdata, ¶ms->beacon, NULL);
 | 
			
		||||
	if (err < 0) {
 | 
			
		||||
		ieee80211_vif_release_channel(sdata);
 | 
			
		||||
		return err;
 | 
			
		||||
| 
						 | 
				
			
			@ -769,7 +783,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
 | 
			
		|||
	if (!old)
 | 
			
		||||
		return -ENOENT;
 | 
			
		||||
 | 
			
		||||
	err = ieee80211_assign_beacon(sdata, params);
 | 
			
		||||
	err = ieee80211_assign_beacon(sdata, params, NULL);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		return 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) {
 | 
			
		||||
	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);
 | 
			
		||||
		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,
 | 
			
		||||
				    u32 *changed)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_csa_settings csa = {};
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	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))
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
 | 
			
		||||
		/* make sure we don't have garbage in other counters */
 | 
			
		||||
		memset(sdata->csa_counter_offset_beacon, 0,
 | 
			
		||||
		       sizeof(sdata->csa_counter_offset_beacon));
 | 
			
		||||
		memset(sdata->csa_counter_offset_presp, 0,
 | 
			
		||||
		       sizeof(sdata->csa_counter_offset_presp));
 | 
			
		||||
		csa.counter_offsets_beacon = params->counter_offsets_beacon;
 | 
			
		||||
		csa.counter_offsets_presp = params->counter_offsets_presp;
 | 
			
		||||
		csa.n_counter_offsets_beacon = params->n_counter_offsets_beacon;
 | 
			
		||||
		csa.n_counter_offsets_presp = params->n_counter_offsets_presp;
 | 
			
		||||
		csa.count = params->count;
 | 
			
		||||
 | 
			
		||||
		memcpy(sdata->csa_counter_offset_beacon,
 | 
			
		||||
		       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);
 | 
			
		||||
		err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa);
 | 
			
		||||
		if (err < 0) {
 | 
			
		||||
			kfree(sdata->u.ap.next_beacon);
 | 
			
		||||
			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_chandef = params->chandef;
 | 
			
		||||
	sdata->csa_block_tx = params->block_tx;
 | 
			
		||||
	sdata->csa_current_counter = params->count;
 | 
			
		||||
	sdata->vif.csa_active = true;
 | 
			
		||||
 | 
			
		||||
	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) &&
 | 
			
		||||
	    params->n_csa_offsets) {
 | 
			
		||||
		int i;
 | 
			
		||||
		u8 c = sdata->csa_current_counter;
 | 
			
		||||
		struct beacon_data *beacon = NULL;
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < params->n_csa_offsets; i++)
 | 
			
		||||
			data[params->csa_offsets[i]] = c;
 | 
			
		||||
		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++)
 | 
			
		||||
				data[params->csa_offsets[i]] =
 | 
			
		||||
					beacon->csa_current_counter;
 | 
			
		||||
 | 
			
		||||
		rcu_read_unlock();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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++ = ieee80211_frequency_to_channel(
 | 
			
		||||
				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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -229,16 +229,29 @@ struct ieee80211_rx_data {
 | 
			
		|||
	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 {
 | 
			
		||||
	u8 *head, *tail;
 | 
			
		||||
	int head_len, tail_len;
 | 
			
		||||
	struct ieee80211_meshconf_ie *meshconf;
 | 
			
		||||
	u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM];
 | 
			
		||||
	u8 csa_current_counter;
 | 
			
		||||
	struct rcu_head rcu_head;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct probe_resp {
 | 
			
		||||
	struct rcu_head rcu_head;
 | 
			
		||||
	int len;
 | 
			
		||||
	u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM];
 | 
			
		||||
	u8 data[0];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -754,8 +767,6 @@ struct ieee80211_sub_if_data {
 | 
			
		|||
	struct mac80211_qos_map __rcu *qos_map;
 | 
			
		||||
 | 
			
		||||
	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_block_tx; /* write-protected by sdata_lock and local->mtx */
 | 
			
		||||
	struct cfg80211_chan_def csa_chandef;
 | 
			
		||||
| 
						 | 
				
			
			@ -767,7 +778,6 @@ struct ieee80211_sub_if_data {
 | 
			
		|||
	struct ieee80211_chanctx *reserved_chanctx;
 | 
			
		||||
	struct cfg80211_chan_def reserved_chandef;
 | 
			
		||||
	bool reserved_radar_required;
 | 
			
		||||
	u8 csa_current_counter;
 | 
			
		||||
 | 
			
		||||
	/* used to reconfigure hardware SM PS */
 | 
			
		||||
	struct work_struct recalc_smps;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -679,7 +679,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
 | 
			
		|||
		*pos++ = 0x0;
 | 
			
		||||
		*pos++ = ieee80211_frequency_to_channel(
 | 
			
		||||
				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++ = WLAN_EID_CHAN_SWITCH_PARAM;
 | 
			
		||||
		*pos++ = 6;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2426,7 +2426,7 @@ static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata,
 | 
			
		|||
	u8 *beacon_data;
 | 
			
		||||
	size_t beacon_data_len;
 | 
			
		||||
	int i;
 | 
			
		||||
	u8 count = sdata->csa_current_counter;
 | 
			
		||||
	u8 count = beacon->csa_current_counter;
 | 
			
		||||
 | 
			
		||||
	switch (sdata->vif.type) {
 | 
			
		||||
	case NL80211_IFTYPE_AP:
 | 
			
		||||
| 
						 | 
				
			
			@ -2445,46 +2445,53 @@ static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata,
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	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];
 | 
			
		||||
		resp = rcu_dereference(sdata->u.ap.probe_resp);
 | 
			
		||||
 | 
			
		||||
		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();
 | 
			
		||||
			resp = rcu_dereference(sdata->u.ap.probe_resp);
 | 
			
		||||
 | 
			
		||||
			/* If nl80211 accepted the offset, this should
 | 
			
		||||
			 * not happen.
 | 
			
		||||
			 */
 | 
			
		||||
			if (WARN_ON(!resp)) {
 | 
			
		||||
		if (beacon->csa_counter_offsets[i]) {
 | 
			
		||||
			if (WARN_ON_ONCE(beacon->csa_counter_offsets[i] >=
 | 
			
		||||
					 beacon_data_len)) {
 | 
			
		||||
				rcu_read_unlock();
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			resp->data[counter_offset_presp] = count;
 | 
			
		||||
			rcu_read_unlock();
 | 
			
		||||
 | 
			
		||||
			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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u8 ieee80211_csa_update_counter(struct ieee80211_vif *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 */
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2494,7 +2501,6 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
 | 
			
		|||
	struct beacon_data *beacon = NULL;
 | 
			
		||||
	u8 *beacon_data;
 | 
			
		||||
	size_t beacon_data_len;
 | 
			
		||||
	int counter_beacon = sdata->csa_counter_offset_beacon[0];
 | 
			
		||||
	int ret = false;
 | 
			
		||||
 | 
			
		||||
	if (!ieee80211_sdata_running(sdata))
 | 
			
		||||
| 
						 | 
				
			
			@ -2532,10 +2538,10 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
 | 
			
		|||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON(counter_beacon > beacon_data_len))
 | 
			
		||||
	if (WARN_ON_ONCE(beacon->csa_counter_offsets[0] > beacon_data_len))
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	if (beacon_data[counter_beacon] == 1)
 | 
			
		||||
	if (beacon_data[beacon->csa_counter_offsets[0]] == 1)
 | 
			
		||||
		ret = true;
 | 
			
		||||
 out:
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
| 
						 | 
				
			
			@ -2551,6 +2557,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
 | 
			
		|||
		       bool is_template)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_local *local = hw_to_local(hw);
 | 
			
		||||
	struct beacon_data *beacon = NULL;
 | 
			
		||||
	struct sk_buff *skb = NULL;
 | 
			
		||||
	struct ieee80211_tx_info *info;
 | 
			
		||||
	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) {
 | 
			
		||||
		struct ieee80211_if_ap *ap = &sdata->u.ap;
 | 
			
		||||
		struct beacon_data *beacon = rcu_dereference(ap->beacon);
 | 
			
		||||
 | 
			
		||||
		beacon = rcu_dereference(ap->beacon);
 | 
			
		||||
		if (beacon) {
 | 
			
		||||
			if (sdata->vif.csa_active) {
 | 
			
		||||
				if (!is_template)
 | 
			
		||||
| 
						 | 
				
			
			@ -2616,34 +2623,34 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
 | 
			
		|||
	} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
 | 
			
		||||
		struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 | 
			
		||||
		struct ieee80211_hdr *hdr;
 | 
			
		||||
		struct beacon_data *presp = rcu_dereference(ifibss->presp);
 | 
			
		||||
 | 
			
		||||
		if (!presp)
 | 
			
		||||
		beacon = rcu_dereference(ifibss->presp);
 | 
			
		||||
		if (!beacon)
 | 
			
		||||
			goto out;
 | 
			
		||||
 | 
			
		||||
		if (sdata->vif.csa_active) {
 | 
			
		||||
			if (!is_template)
 | 
			
		||||
				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);
 | 
			
		||||
		if (!skb)
 | 
			
		||||
			goto out;
 | 
			
		||||
		skb_reserve(skb, local->tx_headroom);
 | 
			
		||||
		memcpy(skb_put(skb, presp->head_len), presp->head,
 | 
			
		||||
		       presp->head_len);
 | 
			
		||||
		memcpy(skb_put(skb, beacon->head_len), beacon->head,
 | 
			
		||||
		       beacon->head_len);
 | 
			
		||||
 | 
			
		||||
		hdr = (struct ieee80211_hdr *) skb->data;
 | 
			
		||||
		hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 | 
			
		||||
						 IEEE80211_STYPE_BEACON);
 | 
			
		||||
	} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
 | 
			
		||||
		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;
 | 
			
		||||
 | 
			
		||||
		if (sdata->vif.csa_active) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2655,40 +2662,42 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
 | 
			
		|||
				 */
 | 
			
		||||
				ieee80211_csa_update_counter(vif);
 | 
			
		||||
 | 
			
		||||
			ieee80211_set_csa(sdata, bcn);
 | 
			
		||||
			ieee80211_set_csa(sdata, beacon);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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 +
 | 
			
		||||
				    bcn->head_len +
 | 
			
		||||
				    beacon->head_len +
 | 
			
		||||
				    256 + /* TIM IE */
 | 
			
		||||
				    bcn->tail_len +
 | 
			
		||||
				    beacon->tail_len +
 | 
			
		||||
				    local->hw.extra_beacon_tailroom);
 | 
			
		||||
		if (!skb)
 | 
			
		||||
			goto out;
 | 
			
		||||
		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);
 | 
			
		||||
 | 
			
		||||
		if (offs) {
 | 
			
		||||
			offs->tim_offset = bcn->head_len;
 | 
			
		||||
			offs->tim_length = skb->len - bcn->head_len;
 | 
			
		||||
			offs->tim_offset = beacon->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 {
 | 
			
		||||
		WARN_ON(1);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* CSA offsets */
 | 
			
		||||
	if (offs) {
 | 
			
		||||
	if (offs && beacon) {
 | 
			
		||||
		int 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)
 | 
			
		||||
				continue;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue