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:
Родитель
b49328361b
Коммит
af296bdb8d
|
@ -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;
|
||||||
|
|
||||||
for (i = 0; i < params->n_csa_offsets; i++)
|
rcu_read_lock();
|
||||||
data[params->csa_offsets[i]] = c;
|
|
||||||
|
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;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) {
|
for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) {
|
||||||
u16 counter_offset_beacon =
|
resp = rcu_dereference(sdata->u.ap.probe_resp);
|
||||||
sdata->csa_counter_offset_beacon[i];
|
|
||||||
u16 counter_offset_presp = sdata->csa_counter_offset_presp[i];
|
|
||||||
|
|
||||||
if (counter_offset_beacon) {
|
if (beacon->csa_counter_offsets[i]) {
|
||||||
if (WARN_ON(counter_offset_beacon >= beacon_data_len))
|
if (WARN_ON_ONCE(beacon->csa_counter_offsets[i] >=
|
||||||
return;
|
beacon_data_len)) {
|
||||||
|
|
||||||
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)) {
|
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return;
|
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)
|
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;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче