From: Johannes Berg <johannes.berg@xxxxxxxxx> Allow drivers to specify that their mactime timestamp is at the beginning of the PLCP and adjust for that in mac80211. NOTE: This is incomplete, see ieee80211_plcp_duration!!! Signed-off-by: Johannes Berg <johannes.berg@xxxxxxxxx> --- include/net/cfg80211.h | 10 +++++ include/net/mac80211.h | 7 ++++ net/mac80211/ibss.c | 27 +-------------- net/mac80211/ieee80211_i.h | 11 ++++++ net/mac80211/rx.c | 8 ++-- net/mac80211/util.c | 76 +++++++++++++++++++++++++++++++++++++++++++++ net/wireless/core.h | 2 - net/wireless/util.c | 3 + 8 files changed, 114 insertions(+), 30 deletions(-) --- wireless-testing.orig/include/net/mac80211.h 2011-02-23 15:03:52.000000000 +0100 +++ wireless-testing/include/net/mac80211.h 2011-02-23 15:05:19.000000000 +0100 @@ -603,10 +603,15 @@ ieee80211_tx_info_clear_status(struct ie * field) is valid and contains the time the first symbol of the MPDU * was received. This is useful in monitor mode and for proper IBSS * merging. + * @RX_FLAG_MACTIME_PLCP: The timestamp passed in the RX status (@mactime + * field) is valid and contains the time when the PLCP of the frame + * started. mac80211 will automatically correct for the preamble time, + * for which the rate and preamble flags etc. MUST be set correctly. * @RX_FLAG_SHORTPRE: Short preamble was used for this frame * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index * @RX_FLAG_40MHZ: HT40 (40 MHz) was used * @RX_FLAG_SHORT_GI: Short guard interval was used + * @RX_FLAG_HT_GF: This frame was received in a HT-greenfield transmission */ enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = 1<<0, @@ -620,6 +625,8 @@ enum mac80211_rx_flags { RX_FLAG_HT = 1<<9, RX_FLAG_40MHZ = 1<<10, RX_FLAG_SHORT_GI = 1<<11, + RX_FLAG_MACTIME_PLCP = 1<<12, + RX_FLAG_HT_GF = 1<<13, }; /** --- wireless-testing.orig/include/net/cfg80211.h 2011-02-23 15:03:52.000000000 +0100 +++ wireless-testing/include/net/cfg80211.h 2011-02-23 15:05:19.000000000 +0100 @@ -471,6 +471,16 @@ struct rate_info { }; /** + * cfg80211_calculate_bitrate - calculate bitrate in 100kbit/s + * @rate: The rate information + * + * Calculates the net bitrate in units of 100kbit/s from the + * given rate/MCS information. + */ +u16 cfg80211_calculate_bitrate(struct rate_info *rate); + + +/** * struct station_info - station information * * Station information filled by driver for get_station() and dump_station. --- wireless-testing.orig/net/mac80211/ieee80211_i.h 2011-02-23 15:03:52.000000000 +0100 +++ wireless-testing/net/mac80211/ieee80211_i.h 2011-02-23 15:05:19.000000000 +0100 @@ -1347,6 +1347,17 @@ size_t ieee80211_ie_split(const u8 *ies, const u8 *ids, int n_ids, size_t offset); size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); +u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, + struct ieee80211_rx_status *status, + unsigned int mpdu_offset); + +static inline bool +ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status) +{ + return status->rx_flags & (RX_FLAG_MACTIME_MPDU | RX_FLAG_MACTIME_PLCP); +} + + /* internal work items */ void ieee80211_work_init(struct ieee80211_local *local); void ieee80211_add_work(struct ieee80211_work *wk); --- wireless-testing.orig/net/mac80211/util.c 2011-02-23 15:03:52.000000000 +0100 +++ wireless-testing/net/mac80211/util.c 2011-02-23 15:08:06.000000000 +0100 @@ -1418,3 +1418,79 @@ size_t ieee80211_ie_split_vendor(const u return pos; } + +static u64 ieee80211_plcp_duration(struct ieee80211_rx_status *status) +{ + if (status->rx_flags & RX_FLAG_HT_GF) { + /* HT-greenfield preamble */ + /* TODO */ + return 0; + } else if (status->rx_flags & RX_FLAG_HT) { + /* HT-mixed preamble */ + /* TODO */ + return 0; + } else switch (status->band) { + case IEEE80211_BAND_2GHZ: + if (status->rx_flags & RX_FLAG_SHORTPRE) + return 96; + return 192; + case IEEE80211_BAND_5GHZ: + /* This appears to be correct for iwlwifi, but is it really? */ + return 16; + case IEEE80211_NUM_BANDS: + break; + } + + WARN_ON_ONCE(1); + return 0; +} + +/** + * ieee80211_calculate_rx_timestamp - calculate timestamp in frame + * @status: RX status + * @mpdu_offset: offset into MPDU to calculate timestamp at + * + * This function calculates the RX timestamp at the given MPDU + * offset, taking into account what the RX timestamp was. + */ +u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, + struct ieee80211_rx_status *status, + unsigned int mpdu_offset) +{ + u64 ts = status->mactime; + struct rate_info ri; + u16 rate; + + if (WARN_ON(!ieee80211_have_rx_timestamp(status))) + return 0; + + /* Adjust for PLCP header */ + if (status->rx_flags & RX_FLAG_MACTIME_PLCP) + ts += ieee80211_plcp_duration(status); + + if (mpdu_offset == 0) + return ts; + + memset(&ri, 0, sizeof(ri)); + + /* Fill cfg80211 rate info */ + if (status->rx_flags & RX_FLAG_HT) { + ri.mcs = status->rate_idx; + ri.flags |= RATE_INFO_FLAGS_MCS; + if (status->rx_flags & RX_FLAG_40MHZ) + ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + if (status->rx_flags & RX_FLAG_SHORT_GI) + ri.flags |= RATE_INFO_FLAGS_SHORT_GI; + } else { + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[status->band]; + ri.legacy = sband->bitrates[status->rate_idx].bitrate; + } + + rate = cfg80211_calculate_bitrate(&ri); + + ts += mpdu_offset * 8 * 10 / rate; + + return ts; +} --- wireless-testing.orig/net/wireless/core.h 2011-02-23 15:03:52.000000000 +0100 +++ wireless-testing/net/wireless/core.h 2011-02-23 15:05:19.000000000 +0100 @@ -410,8 +410,6 @@ int cfg80211_set_freq(struct cfg80211_re struct wireless_dev *wdev, int freq, enum nl80211_channel_type channel_type); -u16 cfg80211_calculate_bitrate(struct rate_info *rate); - #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) #else --- wireless-testing.orig/net/wireless/util.c 2011-02-23 15:03:52.000000000 +0100 +++ wireless-testing/net/wireless/util.c 2011-02-23 15:05:19.000000000 +0100 @@ -872,7 +872,7 @@ u16 cfg80211_calculate_bitrate(struct ra return rate->legacy; /* the formula below does only work for MCS values smaller than 32 */ - if (rate->mcs >= 32) + if (WARN_ON_ONCE(rate->mcs >= 32)) return 0; modulation = rate->mcs & 7; @@ -896,3 +896,4 @@ u16 cfg80211_calculate_bitrate(struct ra /* do NOT round down here */ return (bitrate + 50000) / 100000; } +EXPORT_SYMBOL(cfg80211_calculate_bitrate); --- wireless-testing.orig/net/mac80211/ibss.c 2011-02-23 15:03:53.000000000 +0100 +++ wireless-testing/net/mac80211/ibss.c 2011-02-23 15:05:19.000000000 +0100 @@ -354,30 +354,9 @@ static void ieee80211_rx_bss_info(struct if (memcmp(cbss->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) goto put_bss; - if (rx_status->flag & RX_FLAG_MACTIME_MPDU) { - /* - * For correct IBSS merging we need mactime; since mactime is - * defined as the time the first data symbol of the frame hits - * the PHY, and the timestamp of the beacon is defined as "the - * time that the data symbol containing the first bit of the - * timestamp is transmitted to the PHY plus the transmitting - * STA's delays through its local PHY from the MAC-PHY - * interface to its interface with the WM" (802.11 11.1.2) - * - equals the time this bit arrives at the receiver - we have - * to take into account the offset between the two. - * - * E.g. at 1 MBit that means mactime is 192 usec earlier - * (=24 bytes * 8 usecs/byte) than the beacon timestamp. - */ - int rate; - - if (rx_status->flag & RX_FLAG_HT) - rate = 65; /* TODO: HT rates */ - else - rate = local->hw.wiphy->bands[band]-> - bitrates[rx_status->rate_idx].bitrate; - - rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); + if (ieee80211_have_rx_timestamp(rx_status)) { + rx_timestamp = + ieee80211_calculate_rx_timestamp(local, rx_status, 24); } else { /* * second best option: get current TSF --- wireless-testing.orig/net/mac80211/rx.c 2011-02-23 15:03:52.000000000 +0100 +++ wireless-testing/net/mac80211/rx.c 2011-02-23 15:05:19.000000000 +0100 @@ -77,7 +77,7 @@ ieee80211_rx_radiotap_len(struct ieee802 /* always present fields */ len = sizeof(struct ieee80211_radiotap_header) + 9; - if (status->flag & RX_FLAG_MACTIME_MPDU) + if (ieee80211_have_rx_timestamp(status)) len += 8; if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) len += 1; @@ -123,8 +123,10 @@ ieee80211_add_rx_radiotap_header(struct /* the order of the following fields is important */ /* IEEE80211_RADIOTAP_TSFT */ - if (status->flag & RX_FLAG_MACTIME_MPDU) { - put_unaligned_le64(status->mactime, pos); + if (ieee80211_have_rx_timestamp(status)) { + put_unaligned_le64( + ieee80211_calculate_rx_timestamp(local, status, 0), + pos); rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); pos += 8; -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html