const u8 *anonce;
 };
 
+/**
+ * struct cfg80211_set_hw_timestamp - enable/disable HW timestamping
+ * @macaddr: peer MAC address. NULL to enable/disable HW timestamping for all
+ *     addresses.
+ * @enable: if set, enable HW timestamping for the specified MAC address.
+ *     Otherwise disable HW timestamping for the specified MAC address.
+ */
+struct cfg80211_set_hw_timestamp {
+       const u8 *macaddr;
+       bool enable;
+};
+
 /**
  * cfg80211_get_chandef_type - return old channel type from chandef
  * @chandef: the channel definition
  * @add_link_station: Add a link to a station.
  * @mod_link_station: Modify a link of a station.
  * @del_link_station: Remove a link of a station.
+ *
+ * @set_hw_timestamp: Enable/disable HW timestamping of TM/FTM frames.
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
                                    struct link_station_parameters *params);
        int     (*del_link_station)(struct wiphy *wiphy, struct net_device *dev,
                                    struct link_station_del_parameters *params);
+       int     (*set_hw_timestamp)(struct wiphy *wiphy, struct net_device *dev,
+                                   struct cfg80211_set_hw_timestamp *hwts);
 };
 
 /*
        int n_akm_suites;
 };
 
+#define CFG80211_HW_TIMESTAMP_ALL_PEERS        0xffff
+
 /**
  * struct wiphy - wireless hardware description
  * @mtx: mutex for the data (structures) of this device
  *     NL80211_MAX_NR_AKM_SUITES in order to avoid compatibility issues with
  *     legacy userspace and maximum allowed value is
  *     CFG80211_MAX_NUM_AKM_SUITES.
+ *
+ * @hw_timestamp_max_peers: maximum number of peers that the driver supports
+ *     enabling HW timestamping for concurrently. Setting this field to a
+ *     non-zero value indicates that the driver supports HW timestamping.
+ *     A value of %CFG80211_HW_TIMESTAMP_ALL_PEERS indicates the driver
+ *     supports enabling HW timestamping for all peers (i.e. no need to
+ *     specify a mac address).
  */
 struct wiphy {
        struct mutex mtx;
        u8 ema_max_profile_periodicity;
        u16 max_num_akm_suites;
 
+       u16 hw_timestamp_max_peers;
+
        char priv[] __aligned(NETDEV_ALIGN);
 };
 
 
  * @NL80211_CMD_MODIFY_LINK_STA: Modify a link of an MLD station
  * @NL80211_CMD_REMOVE_LINK_STA: Remove a link of an MLD station
  *
+ * @NL80211_CMD_SET_HW_TIMESTAMP: Enable/disable HW timestamping of Timing
+ *     measurement and Fine timing measurement frames. If %NL80211_ATTR_MAC
+ *     is included, enable/disable HW timestamping only for frames to/from the
+ *     specified MAC address. Otherwise enable/disable HW timestamping for
+ *     all TM/FTM frames (including ones that were enabled with specific MAC
+ *     address). If %NL80211_ATTR_HW_TIMESTAMP_ENABLED is not included, disable
+ *     HW timestamping.
+ *     The number of peers that HW timestamping can be enabled for concurrently
+ *     is indicated by %NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
        NL80211_CMD_MODIFY_LINK_STA,
        NL80211_CMD_REMOVE_LINK_STA,
 
+       NL80211_CMD_SET_HW_TIMESTAMP,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
  *     indicates that the sub-channel is punctured. Higher 16 bits are
  *     reserved.
  *
+ * @NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS: Maximum number of peers that HW
+ *     timestamping can be enabled for concurrently (u16), a wiphy attribute.
+ *     A value of 0xffff indicates setting for all peers (i.e. not specifying
+ *     an address with %NL80211_CMD_SET_HW_TIMESTAMP) is supported.
+ * @NL80211_ATTR_HW_TIMESTAMP_ENABLED: Indicates whether HW timestamping should
+ *     be enabled or not (flag attribute).
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
 
        NL80211_ATTR_PUNCT_BITMAP,
 
+       NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS,
+       NL80211_ATTR_HW_TIMESTAMP_ENABLED,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
 
        [NL80211_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG },
        [NL80211_ATTR_MAX_NUM_AKM_SUITES] = { .type = NLA_REJECT },
        [NL80211_ATTR_PUNCT_BITMAP] = NLA_POLICY_RANGE(NLA_U8, 0, 0xffff),
+
+       [NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS] = { .type = NLA_U16 },
+       [NL80211_ATTR_HW_TIMESTAMP_ENABLED] = { .type = NLA_FLAG },
 };
 
 /* policy for the key attributes */
                if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_MLO)
                        nla_put_flag(msg, NL80211_ATTR_MLO_SUPPORT);
 
+               if (rdev->wiphy.hw_timestamp_max_peers &&
+                   nla_put_u16(msg, NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS,
+                               rdev->wiphy.hw_timestamp_max_peers))
+                       goto nla_put_failure;
+
                /* done */
                state->split_start = 0;
                break;
        return ret;
 }
 
+static int nl80211_set_hw_timestamp(struct sk_buff *skb,
+                                   struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       struct cfg80211_set_hw_timestamp hwts = {};
+
+       if (!rdev->wiphy.hw_timestamp_max_peers)
+               return -EOPNOTSUPP;
+
+       if (!info->attrs[NL80211_ATTR_MAC] &&
+           rdev->wiphy.hw_timestamp_max_peers != CFG80211_HW_TIMESTAMP_ALL_PEERS)
+               return -EOPNOTSUPP;
+
+       if (info->attrs[NL80211_ATTR_MAC])
+               hwts.macaddr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+       hwts.enable =
+               nla_get_flag(info->attrs[NL80211_ATTR_HW_TIMESTAMP_ENABLED]);
+
+       return rdev_set_hw_timestamp(rdev, dev, &hwts);
+}
+
 #define NL80211_FLAG_NEED_WIPHY                0x01
 #define NL80211_FLAG_NEED_NETDEV       0x02
 #define NL80211_FLAG_NEED_RTNL         0x04
                .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP |
                                         NL80211_FLAG_MLO_VALID_LINK_ID),
        },
+       {
+               .cmd = NL80211_CMD_SET_HW_TIMESTAMP,
+               .doit = nl80211_set_hw_timestamp,
+               .flags = GENL_UNS_ADMIN_PERM,
+               .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP),
+       },
 };
 
 static struct genl_family nl80211_fam __ro_after_init = {
 
        return ret;
 }
 
+static inline int
+rdev_set_hw_timestamp(struct cfg80211_registered_device *rdev,
+                     struct net_device *dev,
+                     struct cfg80211_set_hw_timestamp *hwts)
+{
+       struct wiphy *wiphy = &rdev->wiphy;
+       int ret;
+
+       if (!rdev->ops->set_hw_timestamp)
+               return -EOPNOTSUPP;
+
+       trace_rdev_set_hw_timestamp(wiphy, dev, hwts);
+       ret = rdev->ops->set_hw_timestamp(wiphy, dev, hwts);
+       trace_rdev_return_int(wiphy, ret);
+
+       return ret;
+}
 #endif /* __CFG80211_RDEV_OPS */
 
                  __entry->link_id)
 );
 
+TRACE_EVENT(rdev_set_hw_timestamp,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_set_hw_timestamp *hwts),
+
+       TP_ARGS(wiphy, netdev, hwts),
+
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(macaddr)
+               __field(bool, enable)
+       ),
+
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(macaddr, hwts->macaddr);
+               __entry->enable = hwts->enable;
+       ),
+
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", mac %pM, enable: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->macaddr,
+                 __entry->enable)
+);
+
 #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
 
 #undef TRACE_INCLUDE_PATH