Commit 8cef2c9d authored by Johannes Berg's avatar Johannes Berg

cfg80211: move TSF into IEs

While technically the TSF isn't an IE, it can be
necessary to distinguish between the TSF from a
beacon and a probe response, in particular in
order to know the next DTIM TBTT, as not all APs
are spec compliant wrt. TSF==0 being a DTIM TBTT
and thus the DTIM count needs to be taken into
account as well.

To allow this, move the TSF into the IE struct
so it can be known whence it came.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 83c7aa1a
...@@ -164,6 +164,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, ...@@ -164,6 +164,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
ies = rcu_dereference(bss->ies); ies = rcu_dereference(bss->ies);
beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC); beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC);
beacon_ie_len = ies->len; beacon_ie_len = ies->len;
bss_desc->timestamp = ies->tsf;
rcu_read_unlock(); rcu_read_unlock();
if (!beacon_ie) { if (!beacon_ie) {
...@@ -179,7 +180,6 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, ...@@ -179,7 +180,6 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
bss_desc->cap_info_bitmap = bss->capability; bss_desc->cap_info_bitmap = bss->capability;
bss_desc->bss_band = bss_priv->band; bss_desc->bss_band = bss_priv->band;
bss_desc->fw_tsf = bss_priv->fw_tsf; bss_desc->fw_tsf = bss_priv->fw_tsf;
bss_desc->timestamp = bss->tsf;
if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n"); dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n");
bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
......
...@@ -1266,11 +1266,13 @@ enum cfg80211_signal_type { ...@@ -1266,11 +1266,13 @@ enum cfg80211_signal_type {
/** /**
* struct cfg80211_bss_ie_data - BSS entry IE data * struct cfg80211_bss_ie_data - BSS entry IE data
* @tsf: TSF contained in the frame that carried these IEs
* @rcu_head: internal use, for freeing * @rcu_head: internal use, for freeing
* @len: length of the IEs * @len: length of the IEs
* @data: IE data * @data: IE data
*/ */
struct cfg80211_bss_ies { struct cfg80211_bss_ies {
u64 tsf;
struct rcu_head rcu_head; struct rcu_head rcu_head;
int len; int len;
u8 data[]; u8 data[];
...@@ -1284,7 +1286,6 @@ struct cfg80211_bss_ies { ...@@ -1284,7 +1286,6 @@ struct cfg80211_bss_ies {
* *
* @channel: channel this BSS is on * @channel: channel this BSS is on
* @bssid: BSSID of the BSS * @bssid: BSSID of the BSS
* @tsf: timestamp of last received update
* @beacon_interval: the beacon interval as from the frame * @beacon_interval: the beacon interval as from the frame
* @capability: the capability field in host byte order * @capability: the capability field in host byte order
* @ies: the information elements (Note that there is no guarantee that these * @ies: the information elements (Note that there is no guarantee that these
...@@ -1304,8 +1305,6 @@ struct cfg80211_bss_ies { ...@@ -1304,8 +1305,6 @@ struct cfg80211_bss_ies {
* @priv: private area for driver use, has at least wiphy->bss_priv_size bytes * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
*/ */
struct cfg80211_bss { struct cfg80211_bss {
u64 tsf;
struct ieee80211_channel *channel; struct ieee80211_channel *channel;
const struct cfg80211_bss_ies __rcu *ies; const struct cfg80211_bss_ies __rcu *ies;
......
...@@ -242,6 +242,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, ...@@ -242,6 +242,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
u32 basic_rates; u32 basic_rates;
int i, j; int i, j;
u16 beacon_int = cbss->beacon_interval; u16 beacon_int = cbss->beacon_interval;
const struct cfg80211_bss_ies *ies;
u64 tsf;
lockdep_assert_held(&sdata->u.ibss.mtx); lockdep_assert_held(&sdata->u.ibss.mtx);
...@@ -265,13 +267,17 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, ...@@ -265,13 +267,17 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
} }
} }
rcu_read_lock();
ies = rcu_dereference(cbss->ies);
tsf = ies->tsf;
rcu_read_unlock();
__ieee80211_sta_join_ibss(sdata, cbss->bssid, __ieee80211_sta_join_ibss(sdata, cbss->bssid,
beacon_int, beacon_int,
cbss->channel, cbss->channel,
basic_rates, basic_rates,
cbss->capability, cbss->capability,
cbss->tsf, tsf, false);
false);
} }
static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
...@@ -535,8 +541,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, ...@@ -535,8 +541,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
cbss = container_of((void *)bss, struct cfg80211_bss, priv); cbss = container_of((void *)bss, struct cfg80211_bss, priv);
/* was just updated in ieee80211_bss_info_update */ /* same for beacon and probe response */
beacon_timestamp = cbss->tsf; beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
/* check if we need to merge IBSS */ /* check if we need to merge IBSS */
......
...@@ -3667,6 +3667,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, ...@@ -3667,6 +3667,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
bool have_higher_than_11mbit; bool have_higher_than_11mbit;
int min_rate = INT_MAX, min_rate_index = -1; int min_rate = INT_MAX, min_rate_index = -1;
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
const struct cfg80211_bss_ies *ies;
sband = local->hw.wiphy->bands[cbss->channel->band]; sband = local->hw.wiphy->bands[cbss->channel->band];
...@@ -3710,7 +3711,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, ...@@ -3710,7 +3711,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
/* set timing information */ /* set timing information */
sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
sdata->vif.bss_conf.sync_tsf = cbss->tsf; rcu_read_lock();
ies = rcu_dereference(cbss->ies);
sdata->vif.bss_conf.sync_tsf = ies->tsf;
rcu_read_unlock();
sdata->vif.bss_conf.sync_device_ts = bss->device_ts; sdata->vif.bss_conf.sync_device_ts = bss->device_ts;
/* tell driver about BSSID, basic rates and timing */ /* tell driver about BSSID, basic rates and timing */
......
...@@ -4997,6 +4997,7 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, ...@@ -4997,6 +4997,7 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
const struct cfg80211_bss_ies *ies; const struct cfg80211_bss_ies *ies;
void *hdr; void *hdr;
struct nlattr *bss; struct nlattr *bss;
bool tsf = false;
ASSERT_WDEV_LOCK(wdev); ASSERT_WDEV_LOCK(wdev);
...@@ -5020,22 +5021,24 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, ...@@ -5020,22 +5021,24 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
rcu_read_lock(); rcu_read_lock();
ies = rcu_dereference(res->ies); ies = rcu_dereference(res->ies);
if (ies && ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS, if (ies) {
ies->len, ies->data)) { if (nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf))
rcu_read_unlock(); goto fail_unlock_rcu;
goto nla_put_failure; tsf = true;
if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
ies->len, ies->data))
goto fail_unlock_rcu;
} }
ies = rcu_dereference(res->beacon_ies); ies = rcu_dereference(res->beacon_ies);
if (ies && ies->len && nla_put(msg, NL80211_BSS_BEACON_IES, if (ies) {
ies->len, ies->data)) { if (!tsf && nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf))
rcu_read_unlock(); goto fail_unlock_rcu;
goto nla_put_failure; if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
ies->len, ies->data))
goto fail_unlock_rcu;
} }
rcu_read_unlock(); rcu_read_unlock();
if (res->tsf &&
nla_put_u64(msg, NL80211_BSS_TSF, res->tsf))
goto nla_put_failure;
if (res->beacon_interval && if (res->beacon_interval &&
nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval)) nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval))
goto nla_put_failure; goto nla_put_failure;
...@@ -5080,6 +5083,8 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, ...@@ -5080,6 +5083,8 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
return genlmsg_end(msg, hdr); return genlmsg_end(msg, hdr);
fail_unlock_rcu:
rcu_read_unlock();
nla_put_failure: nla_put_failure:
genlmsg_cancel(msg, hdr); genlmsg_cancel(msg, hdr);
return -EMSGSIZE; return -EMSGSIZE;
......
...@@ -695,7 +695,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, ...@@ -695,7 +695,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
if (found) { if (found) {
found->pub.beacon_interval = tmp->pub.beacon_interval; found->pub.beacon_interval = tmp->pub.beacon_interval;
found->pub.tsf = tmp->pub.tsf;
found->pub.signal = tmp->pub.signal; found->pub.signal = tmp->pub.signal;
found->pub.capability = tmp->pub.capability; found->pub.capability = tmp->pub.capability;
found->ts = tmp->ts; found->ts = tmp->ts;
...@@ -880,7 +879,6 @@ cfg80211_inform_bss(struct wiphy *wiphy, ...@@ -880,7 +879,6 @@ cfg80211_inform_bss(struct wiphy *wiphy,
memcpy(tmp.pub.bssid, bssid, ETH_ALEN); memcpy(tmp.pub.bssid, bssid, ETH_ALEN);
tmp.pub.channel = channel; tmp.pub.channel = channel;
tmp.pub.signal = signal; tmp.pub.signal = signal;
tmp.pub.tsf = tsf;
tmp.pub.beacon_interval = beacon_interval; tmp.pub.beacon_interval = beacon_interval;
tmp.pub.capability = capability; tmp.pub.capability = capability;
/* /*
...@@ -895,6 +893,7 @@ cfg80211_inform_bss(struct wiphy *wiphy, ...@@ -895,6 +893,7 @@ cfg80211_inform_bss(struct wiphy *wiphy,
if (!ies) if (!ies)
return NULL; return NULL;
ies->len = ielen; ies->len = ielen;
ies->tsf = tsf;
memcpy(ies->data, ie, ielen); memcpy(ies->data, ie, ielen);
rcu_assign_pointer(tmp.pub.beacon_ies, ies); rcu_assign_pointer(tmp.pub.beacon_ies, ies);
...@@ -951,6 +950,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, ...@@ -951,6 +950,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
if (!ies) if (!ies)
return NULL; return NULL;
ies->len = ielen; ies->len = ielen;
ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
memcpy(ies->data, mgmt->u.probe_resp.variable, ielen); memcpy(ies->data, mgmt->u.probe_resp.variable, ielen);
if (ieee80211_is_probe_resp(mgmt->frame_control)) if (ieee80211_is_probe_resp(mgmt->frame_control))
...@@ -962,7 +962,6 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, ...@@ -962,7 +962,6 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN); memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
tmp.pub.channel = channel; tmp.pub.channel = channel;
tmp.pub.signal = signal; tmp.pub.signal = signal;
tmp.pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
...@@ -1409,7 +1408,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, ...@@ -1409,7 +1408,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
if (buf) { if (buf) {
memset(&iwe, 0, sizeof(iwe)); memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVCUSTOM; iwe.cmd = IWEVCUSTOM;
sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->pub.tsf)); sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf));
iwe.u.data.length = strlen(buf); iwe.u.data.length = strlen(buf);
current_ev = iwe_stream_add_point(info, current_ev, end_buf, current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, buf); &iwe, buf);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment