From: Luca Coelho <[email protected]>
Hi,
Here are some patches that implement time measurement timestamps in
cfg80211 and mac80211. Then there is an iwlwifi patch on top that
depends on them.
Since we have a single tree now, I sent the series with both cfg/mac
and iwlwifi patches. Let me know if you prefer to have them
separately.
As usual, I'm pushing this to a pending branch, for kbuild bot, and
I will report if there are any issues.
Please review.
Cheers,
Luca.
Avraham Stern (7):
nl80211: add RX and TX timestamp attributes
cfg80211: add a function for reporting TX status with hardware
timestamps
cfg80211/nl80211: move rx management data into a struct
cfg80211: add hardware timestamps to frame RX info
ieee80211: add helper functions for detecting TM/FTM frames
mac80211: add hardware timestamps for RX and TX
iwlwifi: mvm: report hardware timestamps in RX/TX status
.../wireless/intel/iwlwifi/fw/api/commands.h | 20 +-
.../wireless/intel/iwlwifi/fw/api/datapath.h | 126 ++++++++++++-
.../net/wireless/intel/iwlwifi/mvm/Makefile | 2 +-
.../net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 +
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 8 +
drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 12 ++
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 7 +-
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 6 +
.../wireless/intel/iwlwifi/mvm/time-sync.c | 172 ++++++++++++++++++
.../wireless/intel/iwlwifi/mvm/time-sync.h | 30 +++
drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 4 +-
include/linux/ieee80211.h | 54 ++++++
include/net/cfg80211.h | 111 ++++++++++-
include/net/mac80211.h | 30 ++-
include/uapi/linux/nl80211.h | 27 ++-
net/mac80211/rx.c | 32 +++-
net/mac80211/status.c | 40 +++-
net/wireless/mlme.c | 21 +--
net/wireless/nl80211.c | 69 ++++---
net/wireless/nl80211.h | 5 +-
net/wireless/trace.h | 8 +-
21 files changed, 713 insertions(+), 75 deletions(-)
create mode 100644 drivers/net/wireless/intel/iwlwifi/mvm/time-sync.c
create mode 100644 drivers/net/wireless/intel/iwlwifi/mvm/time-sync.h
--
2.35.1
From: Avraham Stern <[email protected]>
Add hardware timestamps to management frame RX info.
This shall be used by drivers that support hardware timestamping for
Timing measurement and Fine timing measurement action frames RX.
Signed-off-by: Avraham Stern <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
include/net/cfg80211.h | 4 ++++
net/wireless/nl80211.c | 10 +++++++++-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ae20256c3243..b113fb86151c 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -7537,6 +7537,8 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
* @buf: Management frame (header + body)
* @len: length of the frame data
* @flags: flags, as defined in enum nl80211_rxmgmt_flags
+ * @rx_tstamp: Hardware timestamp of frame RX in nanoseconds
+ * @ack_tstamp: Hardware timestamp of ack TX in nanoseconds
*/
struct cfg80211_rx_info {
int freq;
@@ -7544,6 +7546,8 @@ struct cfg80211_rx_info {
const u8 *buf;
size_t len;
u32 flags;
+ u64 rx_tstamp;
+ u64 ack_tstamp;
};
/**
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index fe4b62b4715f..6b78577aa590 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -17447,7 +17447,15 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, info->sig_dbm)) ||
nla_put(msg, NL80211_ATTR_FRAME, info->len, info->buf) ||
(info->flags &&
- nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, info->flags)))
+ nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, info->flags)) ||
+ (info->rx_tstamp && nla_put_u64_64bit(msg,
+ NL80211_ATTR_RX_HW_TIMESTAMP,
+ info->rx_tstamp,
+ NL80211_ATTR_PAD)) ||
+ (info->ack_tstamp && nla_put_u64_64bit(msg,
+ NL80211_ATTR_TX_HW_TIMESTAMP,
+ info->ack_tstamp,
+ NL80211_ATTR_PAD)))
goto nla_put_failure;
genlmsg_end(msg, hdr);
--
2.35.1
From: Avraham Stern <[email protected]>
The functions for reporting rx management take many arguments.
Collect all the arguments into a struct, which also make it easier
to add more arguments if needed.
Signed-off-by: Avraham Stern <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
include/net/cfg80211.h | 60 +++++++++++++++++++++++++++++++++++++++---
net/wireless/mlme.c | 21 +++++++--------
net/wireless/nl80211.c | 19 +++++++------
net/wireless/nl80211.h | 5 ++--
net/wireless/trace.h | 8 +++---
5 files changed, 81 insertions(+), 32 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 13c2ad88adb1..ae20256c3243 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -7529,6 +7529,39 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
enum nl80211_connect_failed_reason reason,
gfp_t gfp);
+/**
+ * struct cfg80211_rx_info - received management frame info
+ *
+ * @freq: Frequency on which the frame was received in kHz
+ * @sig_dbm: signal strength in dBm, or 0 if unknown
+ * @buf: Management frame (header + body)
+ * @len: length of the frame data
+ * @flags: flags, as defined in enum nl80211_rxmgmt_flags
+ */
+struct cfg80211_rx_info {
+ int freq;
+ int sig_dbm;
+ const u8 *buf;
+ size_t len;
+ u32 flags;
+};
+
+/**
+ * cfg80211_rx_mgmt_ext - management frame notification with extended info
+ * @wdev: wireless device receiving the frame
+ * @info: RX info as defined in struct cfg80211_rx_info
+ *
+ * This function is called whenever an Action frame is received for a station
+ * mode interface, but is not processed in kernel.
+ *
+ * Return: %true if a user space application has registered for this frame.
+ * For action frames, that makes it responsible for rejecting unrecognized
+ * action frames; %false otherwise, in which case for action frames the
+ * driver is responsible for rejecting the frame.
+ */
+bool cfg80211_rx_mgmt_ext(struct wireless_dev *wdev,
+ struct cfg80211_rx_info *info);
+
/**
* cfg80211_rx_mgmt_khz - notification of received, unprocessed management frame
* @wdev: wireless device receiving the frame
@@ -7546,8 +7579,20 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
* action frames; %false otherwise, in which case for action frames the
* driver is responsible for rejecting the frame.
*/
-bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm,
- const u8 *buf, size_t len, u32 flags);
+static inline bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq,
+ int sig_dbm, const u8 *buf, size_t len,
+ u32 flags)
+{
+ struct cfg80211_rx_info info = {
+ .freq = freq,
+ .sig_dbm = sig_dbm,
+ .buf = buf,
+ .len = len,
+ .flags = flags
+ };
+
+ return cfg80211_rx_mgmt_ext(wdev, &info);
+}
/**
* cfg80211_rx_mgmt - notification of received, unprocessed management frame
@@ -7570,8 +7615,15 @@ static inline bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq,
int sig_dbm, const u8 *buf, size_t len,
u32 flags)
{
- return cfg80211_rx_mgmt_khz(wdev, MHZ_TO_KHZ(freq), sig_dbm, buf, len,
- flags);
+ struct cfg80211_rx_info info = {
+ .freq = MHZ_TO_KHZ(freq),
+ .sig_dbm = sig_dbm,
+ .buf = buf,
+ .len = len,
+ .flags = flags
+ };
+
+ return cfg80211_rx_mgmt_ext(wdev, &info);
}
/**
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index c8155a483ec2..f3492c5fb3d3 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -4,7 +4,7 @@
*
* Copyright (c) 2009, Jouni Malinen <[email protected]>
* Copyright (c) 2015 Intel Deutschland GmbH
- * Copyright (C) 2019-2020 Intel Corporation
+ * Copyright (C) 2019-2020, 2022 Intel Corporation
*/
#include <linux/kernel.h>
@@ -759,15 +759,15 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
return rdev_mgmt_tx(rdev, wdev, params, cookie);
}
-bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm,
- const u8 *buf, size_t len, u32 flags)
+bool cfg80211_rx_mgmt_ext(struct wireless_dev *wdev,
+ struct cfg80211_rx_info *info)
{
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct cfg80211_mgmt_registration *reg;
const struct ieee80211_txrx_stypes *stypes =
&wiphy->mgmt_stypes[wdev->iftype];
- struct ieee80211_mgmt *mgmt = (void *)buf;
+ struct ieee80211_mgmt *mgmt = (void *)info->buf;
const u8 *data;
int data_len;
bool result = false;
@@ -775,7 +775,7 @@ bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm,
cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE);
u16 stype;
- trace_cfg80211_rx_mgmt(wdev, freq, sig_dbm);
+ trace_cfg80211_rx_mgmt(wdev, info);
stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4;
if (!(stypes->rx & BIT(stype))) {
@@ -783,8 +783,8 @@ bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm,
return false;
}
- data = buf + ieee80211_hdrlen(mgmt->frame_control);
- data_len = len - ieee80211_hdrlen(mgmt->frame_control);
+ data = info->buf + ieee80211_hdrlen(mgmt->frame_control);
+ data_len = info->len - ieee80211_hdrlen(mgmt->frame_control);
spin_lock_bh(&rdev->mgmt_registrations_lock);
@@ -801,9 +801,8 @@ bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm,
/* found match! */
/* Indicate the received Action frame to user space */
- if (nl80211_send_mgmt(rdev, wdev, reg->nlportid,
- freq, sig_dbm,
- buf, len, flags, GFP_ATOMIC))
+ if (nl80211_send_mgmt(rdev, wdev, reg->nlportid, info,
+ GFP_ATOMIC))
continue;
result = true;
@@ -815,7 +814,7 @@ bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm,
trace_cfg80211_return_bool(result);
return result;
}
-EXPORT_SYMBOL(cfg80211_rx_mgmt_khz);
+EXPORT_SYMBOL(cfg80211_rx_mgmt_ext);
void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev)
{
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index bc9818dd2f9a..fe4b62b4715f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -17420,14 +17420,13 @@ EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u32 nlportid,
- int freq, int sig_dbm,
- const u8 *buf, size_t len, u32 flags, gfp_t gfp)
+ struct cfg80211_rx_info *info, gfp_t gfp)
{
struct net_device *netdev = wdev->netdev;
struct sk_buff *msg;
void *hdr;
- msg = nlmsg_new(100 + len, gfp);
+ msg = nlmsg_new(100 + info->len, gfp);
if (!msg)
return -ENOMEM;
@@ -17442,13 +17441,13 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
netdev->ifindex)) ||
nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
NL80211_ATTR_PAD) ||
- nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, KHZ_TO_MHZ(freq)) ||
- nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET, freq % 1000) ||
- (sig_dbm &&
- nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
- nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
- (flags &&
- nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags)))
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, KHZ_TO_MHZ(info->freq)) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET, info->freq % 1000) ||
+ (info->sig_dbm &&
+ nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, info->sig_dbm)) ||
+ nla_put(msg, NL80211_ATTR_FRAME, info->len, info->buf) ||
+ (info->flags &&
+ nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, info->flags)))
goto nla_put_failure;
genlmsg_end(msg, hdr);
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index d642e3be4ee7..88824b357a7d 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Portions of this file
- * Copyright (C) 2018, 2020-2021 Intel Corporation
+ * Copyright (C) 2018, 2020-2022 Intel Corporation
*/
#ifndef __NET_WIRELESS_NL80211_H
#define __NET_WIRELESS_NL80211_H
@@ -107,8 +107,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u32 nlpid,
- int freq, int sig_dbm,
- const u8 *buf, size_t len, u32 flags, gfp_t gfp);
+ struct cfg80211_rx_info *info, gfp_t gfp);
void
nl80211_radar_notify(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 228079d7690a..288ee19e1eb6 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2892,8 +2892,8 @@ DEFINE_EVENT(cfg80211_netdev_mac_evt, cfg80211_del_sta,
);
TRACE_EVENT(cfg80211_rx_mgmt,
- TP_PROTO(struct wireless_dev *wdev, int freq, int sig_dbm),
- TP_ARGS(wdev, freq, sig_dbm),
+ TP_PROTO(struct wireless_dev *wdev, struct cfg80211_rx_info *info),
+ TP_ARGS(wdev, info),
TP_STRUCT__entry(
WDEV_ENTRY
__field(int, freq)
@@ -2901,8 +2901,8 @@ TRACE_EVENT(cfg80211_rx_mgmt,
),
TP_fast_assign(
WDEV_ASSIGN;
- __entry->freq = freq;
- __entry->sig_dbm = sig_dbm;
+ __entry->freq = info->freq;
+ __entry->sig_dbm = info->sig_dbm;
),
TP_printk(WDEV_PR_FMT ", freq: "KHZ_F", sig dbm: %d",
WDEV_PR_ARG, PR_KHZ(__entry->freq), __entry->sig_dbm)
--
2.35.1
From: Avraham Stern <[email protected]>
Add attributes for reporting hardware timestamps for management frames
RX and TX. These attributes will be used for reporting hardware
timestamps for Timing measurement and Fine timing measurement action
frames, which will allow userspace applications to measure the path
delay between devices and sync clocks.
For TX, these attributes are used for reporting the frame RX time and
the ack TX time. For TX, they are used for reporting the frame TX time
and the ack RX time.
Signed-off-by: Avraham Stern <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
include/uapi/linux/nl80211.h | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 0568a79097b8..1554854c03e3 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -753,6 +753,9 @@
* %NL80211_ATTR_CSA_C_OFFSETS_TX is an array of offsets to CSA
* counters which will be updated to the current value. This attribute
* is used during CSA period.
+ * For RX notification, %NL80211_ATTR_RX_HW_TIMESTAMP may be included to
+ * indicate the frame RX timestamp and %NL80211_ATTR_TX_HW_TIMESTAMP may
+ * be included to indicate the ack TX timestamp.
* @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
* command may be used with the corresponding cookie to cancel the wait
* time if it is known that it is no longer necessary. This command is
@@ -763,7 +766,9 @@
* transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies
* the TX command and %NL80211_ATTR_FRAME includes the contents of the
* frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
- * the frame.
+ * the frame. %NL80211_ATTR_TX_HW_TIMESTAMP may be included to indicate the
+ * tx timestamp and %NL80211_ATTR_RX_HW_TIMESTAMP may be included to
+ * indicate the ack RX timestamp.
* @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for
* backward compatibility.
*
@@ -2663,6 +2668,18 @@ enum nl80211_commands {
* association request when used with NL80211_CMD_NEW_STATION). Can be set
* only if %NL80211_STA_FLAG_WME is set.
*
+ * @NL80211_ATTR_TX_HW_TIMESTAMP: Hardware timestamp for TX operation in
+ * nanoseconds (u64). This is the device clock timestamp so it will
+ * probably reset when the device is stopped or the firmware is reset.
+ * When used with %NL80211_CMD_FRAME_TX_STATUS, indicates the frame TX
+ * timestamp. When used with %NL80211_CMD_FRAME RX notification, indicates
+ * the ack TX timestamp.
+ * @NL80211_ATTR_RX_HW_TIMESTAMP: Hardware timestamp for RX operation in
+ * nanoseconds (u64). This is the device clock timestamp so it will
+ * probably reset when the device is stopped or the firmware is reset.
+ * When used with %NL80211_CMD_FRAME_TX_STATUS, indicates the ack RX
+ * timestamp. When used with %NL80211_CMD_FRAME RX notification, indicates
+ * the incoming frame RX timestamp.
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3175,6 +3192,9 @@ enum nl80211_attrs {
NL80211_ATTR_EHT_CAPABILITY,
+ NL80211_ATTR_TX_HW_TIMESTAMP,
+ NL80211_ATTR_RX_HW_TIMESTAMP,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -6172,6 +6192,10 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_RADAR_BACKGROUND: Device supports background radar/CAC
* detection.
*
+ * @NL80211_EXT_FEATURE_HW_TIMESTAMP: Device supports timestamping timing
+ * measurement and fine timing measurement action frames and their acks
+ * on TX and RX.
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -6239,6 +6263,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_BSS_COLOR,
NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD,
NL80211_EXT_FEATURE_RADAR_BACKGROUND,
+ NL80211_EXT_FEATURE_HW_TIMESTAMP,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
--
2.35.1
From: Avraham Stern <[email protected]>
Signed-off-by: Avraham Stern <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
include/linux/ieee80211.h | 54 +++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 75d40acb60c1..313aabb2d511 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1301,6 +1301,15 @@ struct ieee80211_mgmt {
u8 action_code;
u8 variable[];
} __packed s1g;
+ struct {
+ u8 action_code;
+ u8 dialog_token;
+ u8 follow_up;
+ u32 tod;
+ u32 toa;
+ u8 max_tod_error;
+ u8 max_toa_error;
+ } __packed wnm_timing_msr;
} u;
} __packed action;
} u;
@@ -3464,6 +3473,17 @@ enum ieee80211_mesh_actioncode {
WLAN_MESH_ACTION_TBTT_ADJUSTMENT_RESPONSE,
};
+/* Unprotected WNM action codes */
+enum ieee80211_unprotected_wnm_actioncode {
+ WLAN_UNPROTECTED_WNM_ACTION_TIM = 0,
+ WLAN_UNPROTECTED_WNM_ACTION_TIMING_MEASUREMENT_RESPONSE = 1,
+};
+
+/* Public action codes */
+enum ieee80211_public_actioncode {
+ WLAN_PUBLIC_ACTION_FTM_RESPONSE = 33,
+};
+
/* Security key length */
enum ieee80211_key_len {
WLAN_KEY_LEN_WEP40 = 5,
@@ -4252,6 +4272,40 @@ static inline bool ieee80211_action_contains_tpc(struct sk_buff *skb)
return true;
}
+static inline bool ieee80211_is_timing_measurement(struct sk_buff *skb)
+{
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+
+ if (!ieee80211_is_action(mgmt->frame_control))
+ return false;
+
+ if (skb->len < IEEE80211_MIN_ACTION_SIZE)
+ return false;
+
+ if (mgmt->u.action.category == WLAN_CATEGORY_WNM_UNPROTECTED &&
+ mgmt->u.action.u.wnm_timing_msr.action_code ==
+ WLAN_UNPROTECTED_WNM_ACTION_TIMING_MEASUREMENT_RESPONSE &&
+ skb->len >= offsetofend(typeof(*mgmt), u.action.u.wnm_timing_msr))
+ return true;
+
+ return false;
+}
+
+static inline bool ieee80211_is_ftm(struct sk_buff *skb)
+{
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+
+ if (!ieee80211_is_public_action((void *)mgmt, skb->len))
+ return false;
+
+ if (mgmt->u.action.u.ftm.action_code ==
+ WLAN_PUBLIC_ACTION_FTM_RESPONSE &&
+ skb->len >= offsetofend(typeof(*mgmt), u.action.u.ftm))
+ return true;
+
+ return false;
+}
+
struct element {
u8 id;
u8 datalen;
--
2.35.1
From: Avraham Stern <[email protected]>
When the low level driver reports hardware timestamps for frame
TX status or frame RX, pass the timestamps to cfg80211.
Signed-off-by: Avraham Stern <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
include/net/mac80211.h | 30 +++++++++++++++++++++++++++++-
net/mac80211/rx.c | 32 ++++++++++++++++++++++++--------
net/mac80211/status.c | 40 ++++++++++++++++++++++++++++++----------
3 files changed, 83 insertions(+), 19 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 382ebb862ea8..1d18c005a4e9 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -125,6 +125,22 @@
* via the usual ieee80211_tx_dequeue).
*/
+/**
+ * DOC: HW timestamping
+ *
+ * Timing Measurement and Fine Timing Measurement require accurate timestamps
+ * of the action frames TX/RX and their respective acks.
+ *
+ * To report hardware timestamps for Timing Measurement or Fine Timing
+ * Measurement frame RX, the low level driver should set the SKB's hwtstamp
+ * field to the frame RX timestamp and report the ack TX timestamp in the
+ * ieee80211_rx_status struct.
+ *
+ * Similarly, To report hardware timestamps for Timing Measurement or Fine
+ * Timing Measurement frame TX, the driver should set the SKB's hwtstamp field
+ * to the frame TX timestamp and report the ack RX timestamp in the
+ * ieee80211_tx_status struct.
+ */
struct device;
/**
@@ -1151,6 +1167,10 @@ ieee80211_info_get_tx_time_est(struct ieee80211_tx_info *info)
* @info: Basic tx status information
* @skb: Packet skb (can be NULL if not provided by the driver)
* @rate: The TX rate that was used when sending the packet
+ * @ack_hwtstamp: Hardware timestamp of the received ack in nanoseconds
+ * Only needed for Timing measurement and Fine timing measurement action
+ * frames. Only reported by devices that have the
+ * %NL80211_EXT_FEATURE_HW_TIMESTAMP capability.
* @free_list: list where processed skbs are stored to be free'd by the driver
*/
struct ieee80211_tx_status {
@@ -1158,6 +1178,7 @@ struct ieee80211_tx_status {
struct ieee80211_tx_info *info;
struct sk_buff *skb;
struct rate_info *rate;
+ ktime_t ack_hwtstamp;
struct list_head *free_list;
};
@@ -1393,6 +1414,10 @@ enum mac80211_rx_encoding {
* (TSF) timer when the first data symbol (MPDU) arrived at the hardware.
* @boottime_ns: CLOCK_BOOTTIME timestamp the frame was received at, this is
* needed only for beacons and probe responses that update the scan cache.
+ * @ack_tx_hwtstamp: Hardware timestamp for the ack TX in nanoseconds. Only
+ * needed for Timing measurement and Fine timing measurement action frames.
+ * Only reported by devices that have the %NL80211_EXT_FEATURE_HW_TIMESTAMP
+ * capability.
* @device_timestamp: arbitrary timestamp for the device, mac80211 doesn't use
* it but can store it and pass it back to the driver for synchronisation
* @band: the active band when this frame was received
@@ -1426,7 +1451,10 @@ enum mac80211_rx_encoding {
*/
struct ieee80211_rx_status {
u64 mactime;
- u64 boottime_ns;
+ union {
+ u64 boottime_ns;
+ ktime_t ack_tx_hwtstamp;
+ };
u32 device_timestamp;
u32 ampdu_reference;
u32 flag;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index beb6b92eb780..2d9c2a3370b2 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3586,7 +3586,11 @@ static ieee80211_rx_result debug_noinline
ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
{
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
- int sig = 0;
+ struct cfg80211_rx_info info = {
+ .freq = ieee80211_rx_status_to_khz(status),
+ .buf = rx->skb->data,
+ .len = rx->skb->len
+ };
/* skip known-bad action frames and return them in the next handler */
if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM)
@@ -3601,11 +3605,17 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) &&
!(status->flag & RX_FLAG_NO_SIGNAL_VAL))
- sig = status->signal;
+ info.sig_dbm = status->signal;
+
+ if (wiphy_ext_feature_isset(rx->local->hw.wiphy,
+ NL80211_EXT_FEATURE_HW_TIMESTAMP) &&
+ (ieee80211_is_timing_measurement(rx->skb) ||
+ ieee80211_is_ftm(rx->skb))) {
+ info.rx_tstamp = ktime_to_ns(skb_hwtstamps(rx->skb)->hwtstamp);
+ info.ack_tstamp = ktime_to_ns(status->ack_tx_hwtstamp);
+ }
- if (cfg80211_rx_mgmt_khz(&rx->sdata->wdev,
- ieee80211_rx_status_to_khz(status), sig,
- rx->skb->data, rx->skb->len, 0)) {
+ if (cfg80211_rx_mgmt_ext(&rx->sdata->wdev, &info)) {
if (rx->sta)
rx->sta->rx_stats.packets++;
dev_kfree_skb(rx->skb);
@@ -4677,8 +4687,10 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
return false;
if (!consume) {
- skb = skb_copy(skb, GFP_ATOMIC);
- if (!skb) {
+ struct skb_shared_hwtstamps *shwt;
+
+ rx->skb = skb_copy(skb, GFP_ATOMIC);
+ if (!rx->skb) {
if (net_ratelimit())
wiphy_debug(local->hw.wiphy,
"failed to copy skb for %s\n",
@@ -4686,7 +4698,11 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
return true;
}
- rx->skb = skb;
+ /* skb_copy() does not copy the hw timestamps, so copy it
+ * explicitly
+ */
+ shwt = skb_hwtstamps(rx->skb);
+ shwt->hwtstamp = skb_hwtstamps(skb)->hwtstamp;
}
ieee80211_invoke_rx_handlers(rx);
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index e81e8a5bb774..eb3c75a435f7 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -612,9 +612,11 @@ ieee80211_sdata_from_skb(struct ieee80211_local *local, struct sk_buff *skb)
}
static void ieee80211_report_ack_skb(struct ieee80211_local *local,
- struct ieee80211_tx_info *info,
- bool acked, bool dropped)
+ struct sk_buff *orig_skb,
+ bool acked, bool dropped,
+ ktime_t ack_hwtstamp)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(orig_skb);
struct sk_buff *skb;
unsigned long flags;
@@ -631,6 +633,21 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local,
struct ieee80211_hdr *hdr = (void *)skb->data;
bool is_valid_ack_signal =
!!(info->status.flags & IEEE80211_TX_STATUS_ACK_SIGNAL_VALID);
+ struct cfg80211_tx_status status = {
+ .cookie = cookie,
+ .buf = skb->data,
+ .len = skb->len,
+ .ack = acked,
+ };
+
+ if (wiphy_ext_feature_isset(local->hw.wiphy,
+ NL80211_EXT_FEATURE_HW_TIMESTAMP) &&
+ (ieee80211_is_timing_measurement(orig_skb) ||
+ ieee80211_is_ftm(orig_skb))) {
+ status.tx_tstamp =
+ ktime_to_ns(skb_hwtstamps(orig_skb)->hwtstamp);
+ status.ack_tstamp = ktime_to_ns(ack_hwtstamp);
+ }
rcu_read_lock();
sdata = ieee80211_sdata_from_skb(local, skb);
@@ -650,9 +667,9 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local,
is_valid_ack_signal,
GFP_ATOMIC);
else if (ieee80211_is_mgmt(hdr->frame_control))
- cfg80211_mgmt_tx_status(&sdata->wdev, cookie,
- skb->data, skb->len,
- acked, GFP_ATOMIC);
+ cfg80211_mgmt_tx_status_ext(&sdata->wdev,
+ &status,
+ GFP_ATOMIC);
else
pr_warn("Unknown status report in ack skb\n");
@@ -669,7 +686,8 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local,
}
static void ieee80211_report_used_skb(struct ieee80211_local *local,
- struct sk_buff *skb, bool dropped)
+ struct sk_buff *skb, bool dropped,
+ ktime_t ack_hwtstamp)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u16 tx_time_est = ieee80211_info_get_tx_time_est(info);
@@ -732,7 +750,8 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
rcu_read_unlock();
} else if (info->ack_frame_id) {
- ieee80211_report_ack_skb(local, info, acked, dropped);
+ ieee80211_report_ack_skb(local, skb, acked, dropped,
+ ack_hwtstamp);
}
if (!dropped && skb->destructor) {
@@ -1047,7 +1066,7 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
jiffies + msecs_to_jiffies(10));
}
- ieee80211_report_used_skb(local, skb, false);
+ ieee80211_report_used_skb(local, skb, false, status->ack_hwtstamp);
/* this was a transmitted frame, but now we want to reuse it */
skb_orphan(skb);
@@ -1212,7 +1231,7 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
if (!skb)
return;
- ieee80211_report_used_skb(local, skb, false);
+ ieee80211_report_used_skb(local, skb, false, status->ack_hwtstamp);
if (status->free_list)
list_add_tail(&skb->list, status->free_list);
else
@@ -1274,8 +1293,9 @@ EXPORT_SYMBOL(ieee80211_report_low_ack);
void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ieee80211_local *local = hw_to_local(hw);
+ ktime_t kt = ktime_set(0, 0);
- ieee80211_report_used_skb(local, skb, true);
+ ieee80211_report_used_skb(local, skb, true, kt);
dev_kfree_skb_any(skb);
}
EXPORT_SYMBOL(ieee80211_free_txskb);
--
2.35.1
On 4/6/2022 5:09 AM, Luca Coelho wrote:
[...snip...]
> +/**
> + * cfg80211_rx_mgmt_ext - management frame notification with extended info
> + * @wdev: wireless device receiving the frame
> + * @info: RX info as defined in struct cfg80211_rx_info
> + *
> + * This function is called whenever an Action frame is received for a station
> + * mode interface, but is not processed in kernel.
> + *
> + * Return: %true if a user space application has registered for this frame.
> + * For action frames, that makes it responsible for rejecting unrecognized
> + * action frames; %false otherwise, in which case for action frames the
> + * driver is responsible for rejecting the frame.
> + */
> +bool cfg80211_rx_mgmt_ext(struct wireless_dev *wdev,
> + struct cfg80211_rx_info *info);
can/should info be const?
/jeff
Luca Coelho <[email protected]> writes:
> From: Avraham Stern <[email protected]>
>
> Add attributes for reporting hardware timestamps for management frames
> RX and TX.
Here you talk about management frames...
> + * @NL80211_EXT_FEATURE_HW_TIMESTAMP: Device supports timestamping timing
> + * measurement and fine timing measurement action frames and their acks
> + * on TX and RX.
.... but here you talk about action frames and their acks. Why the difference?
> For TX, these attributes are used for reporting the frame RX time and
> the ack TX time. For TX, they are used for reporting the frame TX time
> and the ack RX time.
You have "For TX" twice so I can't understand what you mean.
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
Luca Coelho <[email protected]> writes:
> From: Avraham Stern <[email protected]>
>
> When the low level driver reports hardware timestamps for frame
> TX status or frame RX, pass the timestamps to cfg80211.
So the driver is supposed to set timestamps for all frames, not just
management frames?
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches