Skip to content

Commit

Permalink
mac80211: move csa counters from sdata to beacon/presp
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Michal Kazior authored and Johannes Berg committed Jun 23, 2014
1 parent b493283 commit af296bd
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 75 deletions.
67 changes: 44 additions & 23 deletions net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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, &params->beacon);
err = ieee80211_assign_beacon(sdata, &params->beacon, NULL);
if (err < 0) {
ieee80211_vif_release_channel(sdata);
return err;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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));

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));
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;

err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
err = ieee80211_assign_beacon(sdata, &params->beacon_csa, &csa);
if (err < 0) {
kfree(sdata->u.ap.next_beacon);
return err;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion net/mac80211/ibss.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
16 changes: 13 additions & 3 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];
};

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion net/mac80211/mesh.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit af296bd

Please sign in to comment.