This adds the necessary capabilities in nl80211 to allow drivers to assign a cookie to control port TX frames (returned via extack in the netlink ACK message of the command) and then later report the frame's status.
Unified · Split
| @@ -4069,7 +4069,8 @@ struct cfg80211_ops { · 4068 unmodified lines | |||
| 4069 | struct net_device *dev, | 4069 | struct net_device *dev, |
| 4070 | const u8 *buf, size_t len, | 4070 | const u8 *buf, size_t len, |
| 4071 | const u8 *dest, const __be16 proto, | 4071 | const u8 *dest, const __be16 proto, |
| 4072 | const bool noencrypt); | 4072 | const bool noencrypt, |
| 4073 | u64 *cookie); | ||
| 4073 | 4074 | ||
| 4074 | int (*get_ftm_responder_stats)(struct wiphy *wiphy, | 4075 | int (*get_ftm_responder_stats)(struct wiphy *wiphy, |
| 4075 | struct net_device *dev, | 4076 | struct net_device *dev, |
| @@ -7049,6 +7050,23 @@ static inline bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, · 2973 unmodified lines | |||
| 7049 | void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, | 7050 | void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, |
| 7050 | const u8 *buf, size_t len, bool ack, gfp_t gfp); | 7051 | const u8 *buf, size_t len, bool ack, gfp_t gfp); |
| 7051 | 7052 | ||
| 7053 | /** | ||
| 7054 | * cfg80211_control_port_tx_status - notification of TX status for control | ||
| 7055 | * port frames | ||
| 7056 | * @wdev: wireless device receiving the frame | ||
| 7057 | * @cookie: Cookie returned by cfg80211_ops::tx_control_port() | ||
| 7058 | * @buf: Data frame (header + body) | ||
| 7059 | * @len: length of the frame data | ||
| 7060 | * @ack: Whether frame was acknowledged | ||
| 7061 | * @gfp: context flags | ||
| 7062 | * | ||
| 7063 | * This function is called whenever a control port frame was requested to be | ||
| 7064 | * transmitted with cfg80211_ops::tx_control_port() to report the TX status of | ||
| 7065 | * the transmission attempt. | ||
| 7066 | */ | ||
| 7067 | void cfg80211_control_port_tx_status(struct wireless_dev *wdev, u64 cookie, | ||
| 7068 | const u8 *buf, size_t len, bool ack, | ||
| 7069 | gfp_t gfp); | ||
| 7052 | 7070 | ||
| 7053 | /** | 7071 | /** |
| 7054 | * cfg80211_rx_control_port - notification about a received control port frame | 7072 | * cfg80211_rx_control_port - notification about a received control port frame |
| @@ -1164,6 +1164,12 @@ · 1163 unmodified lines | |||
| 1164 | * dropped because it did not include a valid MME MIC while beacon | 1164 | * dropped because it did not include a valid MME MIC while beacon |
| 1165 | * protection was enabled (BIGTK configured in station mode). | 1165 | * protection was enabled (BIGTK configured in station mode). |
| 1166 | * | 1166 | * |
| 1167 | * @NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS: Report TX status of a control | ||
| 1168 | * port frame transmitted with %NL80211_CMD_CONTROL_PORT_FRAME. | ||
| 1169 | * %NL80211_ATTR_COOKIE identifies the TX command and %NL80211_ATTR_FRAME | ||
| 1170 | * includes the contents of the frame. %NL80211_ATTR_ACK flag is included | ||
| 1171 | * if the recipient acknowledged the frame. | ||
| 1172 | * | ||
| 1167 | * @NL80211_CMD_MAX: highest used command number | 1173 | * @NL80211_CMD_MAX: highest used command number |
| 1168 | * @__NL80211_CMD_AFTER_LAST: internal use | 1174 | * @__NL80211_CMD_AFTER_LAST: internal use |
| 1169 | */ | 1175 | */ |
| @@ -1392,6 +1398,8 @@ enum nl80211_commands { · 222 unmodified lines | |||
| 1392 | 1398 | ||
| 1393 | NL80211_CMD_UNPROT_BEACON, | 1399 | NL80211_CMD_UNPROT_BEACON, |
| 1394 | 1400 | ||
| 1401 | NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS, | ||
| 1402 | |||
| 1395 | /* add new commands above here */ | 1403 | /* add new commands above here */ |
| 1396 | 1404 | ||
| 1397 | /* used to define NL80211_CMD_MAX below */ | 1405 | /* used to define NL80211_CMD_MAX below */ |
| @@ -5729,6 +5737,9 @@ enum nl80211_feature_flags { · 4331 unmodified lines | |||
| 5729 | * report %NL80211_ATTR_SCAN_FREQ_KHZ, %NL80211_SCAN_FLAG_FREQ_KHZ must be | 5737 | * report %NL80211_ATTR_SCAN_FREQ_KHZ, %NL80211_SCAN_FLAG_FREQ_KHZ must be |
| 5730 | * included in the scan request. | 5738 | * included in the scan request. |
| 5731 | * | 5739 | * |
| 5740 | * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS: The driver | ||
| 5741 | * can report tx status for control port over nl80211 tx operations. | ||
| 5742 | * | ||
| 5732 | * @NUM_NL80211_EXT_FEATURES: number of extended features. | 5743 | * @NUM_NL80211_EXT_FEATURES: number of extended features. |
| 5733 | * @MAX_NL80211_EXT_FEATURES: highest extended feature index. | 5744 | * @MAX_NL80211_EXT_FEATURES: highest extended feature index. |
| 5734 | */ | 5745 | */ |
| @@ -5783,6 +5794,7 @@ enum nl80211_ext_feature_index { · 48 unmodified lines | |||
| 5783 | NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS, | 5794 | NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS, |
| 5784 | NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT, | 5795 | NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT, |
| 5785 | NL80211_EXT_FEATURE_SCAN_FREQ_KHZ, | 5796 | NL80211_EXT_FEATURE_SCAN_FREQ_KHZ, |
| 5797 | NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS, | ||
| 5786 | 5798 | ||
| 5787 | /* add new features before the definition below */ | 5799 | /* add new features before the definition below */ |
| 5788 | NUM_NL80211_EXT_FEATURES, | 5800 | NUM_NL80211_EXT_FEATURES, |
| @@ -1800,7 +1800,8 @@ void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata); · 1799 unmodified lines | |||
| 1800 | void ieee80211_clear_fast_xmit(struct sta_info *sta); | 1800 | void ieee80211_clear_fast_xmit(struct sta_info *sta); |
| 1801 | int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, | 1801 | int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, |
| 1802 | const u8 *buf, size_t len, | 1802 | const u8 *buf, size_t len, |
| 1803 | const u8 *dest, __be16 proto, bool unencrypted); | 1803 | const u8 *dest, __be16 proto, bool unencrypted, |
| 1804 | u64 *cookie); | ||
| 1804 | int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev, | 1805 | int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev, |
| 1805 | const u8 *buf, size_t len); | 1806 | const u8 *buf, size_t len); |
| 1806 | 1807 | ||
| @@ -5339,7 +5339,8 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, · 5338 unmodified lines | |||
| 5339 | 5339 | ||
| 5340 | int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, | 5340 | int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, |
| 5341 | const u8 *buf, size_t len, | 5341 | const u8 *buf, size_t len, |
| 5342 | const u8 *dest, __be16 proto, bool unencrypted) | 5342 | const u8 *dest, __be16 proto, bool unencrypted, |
| 5343 | u64 *cookie) | ||
| 5343 | { | 5344 | { |
| 5344 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 5345 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 5345 | struct ieee80211_local *local = sdata->local; | 5346 | struct ieee80211_local *local = sdata->local; |
| @@ -13866,6 +13866,7 @@ static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info) · 13865 unmodified lines | |||
| 13866 | 13866 | ||
| 13867 | static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info) | 13867 | static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info) |
| 13868 | { | 13868 | { |
| 13869 | bool dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK]; | ||
| 13869 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 13870 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| 13870 | struct net_device *dev = info->user_ptr[1]; | 13871 | struct net_device *dev = info->user_ptr[1]; |
| 13871 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 13872 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| @@ -13874,6 +13875,7 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info) · 2 unmodified lines | |||
| 13874 | u8 *dest; | 13875 | u8 *dest; |
| 13875 | u16 proto; | 13876 | u16 proto; |
| 13876 | bool noencrypt; | 13877 | bool noencrypt; |
| 13878 | u64 cookie = 0; | ||
| 13877 | int err; | 13879 | int err; |
| 13878 | 13880 | ||
| 13879 | if (!wiphy_ext_feature_isset(&rdev->wiphy, | 13881 | if (!wiphy_ext_feature_isset(&rdev->wiphy, |
| @@ -13918,9 +13920,12 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info) · 38 unmodified lines | |||
| 13918 | noencrypt = | 13920 | noencrypt = |
| 13919 | nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]); | 13921 | nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]); |
| 13920 | 13922 | ||
| 13921 | return rdev_tx_control_port(rdev, dev, buf, len, | 13923 | err = rdev_tx_control_port(rdev, dev, buf, len, |
| 13922 | dest, cpu_to_be16(proto), noencrypt); | 13924 | dest, cpu_to_be16(proto), noencrypt, |
| 13923 | 13925 | dont_wait_for_ack ? NULL : &cookie); | |
| 13926 | if (!err && !dont_wait_for_ack) | ||
| 13927 | nl_set_extack_cookie_u64(info->extack, cookie); | ||
| 13928 | return err; | ||
| 13924 | out: | 13929 | out: |
| 13925 | wdev_unlock(wdev); | 13930 | wdev_unlock(wdev); |
| 13926 | return err; | 13931 | return err; |
| @@ -16294,8 +16299,9 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, · 2367 unmodified lines | |||
| 16294 | return -ENOBUFS; | 16299 | return -ENOBUFS; |
| 16295 | } | 16300 | } |
| 16296 | 16301 | ||
| 16297 | void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, | 16302 | static void nl80211_frame_tx_status(struct wireless_dev *wdev, u64 cookie, |
| 16298 | const u8 *buf, size_t len, bool ack, gfp_t gfp) | 16303 | const u8 *buf, size_t len, bool ack, |
| 16304 | gfp_t gfp, enum nl80211_commands command) | ||
| 16299 | { | 16305 | { |
| 16300 | struct wiphy *wiphy = wdev->wiphy; | 16306 | struct wiphy *wiphy = wdev->wiphy; |
| 16301 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | 16307 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
| @@ -16303,13 +16309,16 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, · 1 unmodified line | |||
| 16303 | struct sk_buff *msg; | 16309 | struct sk_buff *msg; |
| 16304 | void *hdr; | 16310 | void *hdr; |
| 16305 | 16311 | ||
| 16306 | trace_cfg80211_mgmt_tx_status(wdev, cookie, ack); | 16312 | if (command == NL80211_CMD_FRAME_TX_STATUS) |
| 16313 | trace_cfg80211_mgmt_tx_status(wdev, cookie, ack); | ||
| 16314 | else | ||
| 16315 | trace_cfg80211_control_port_tx_status(wdev, cookie, ack); | ||
| 16307 | 16316 | ||
| 16308 | msg = nlmsg_new(100 + len, gfp); | 16317 | msg = nlmsg_new(100 + len, gfp); |
| 16309 | if (!msg) | 16318 | if (!msg) |
| 16310 | return; | 16319 | return; |
| 16311 | 16320 | ||
| 16312 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS); | 16321 | hdr = nl80211hdr_put(msg, 0, 0, 0, command); |
| 16313 | if (!hdr) { | 16322 | if (!hdr) { |
| 16314 | nlmsg_free(msg); | 16323 | nlmsg_free(msg); |
| 16315 | return; | 16324 | return; |
| @@ -16332,9 +16341,25 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, · 16 unmodified lines | |||
| 16332 | NL80211_MCGRP_MLME, gfp); | 16341 | NL80211_MCGRP_MLME, gfp); |
| 16333 | return; | 16342 | return; |
| 16334 | 16343 | ||
| 16335 | nla_put_failure: | 16344 | nla_put_failure: |
| 16336 | nlmsg_free(msg); | 16345 | nlmsg_free(msg); |
| 16337 | } | 16346 | } |
| 16347 | |||
| 16348 | void cfg80211_control_port_tx_status(struct wireless_dev *wdev, u64 cookie, | ||
| 16349 | const u8 *buf, size_t len, bool ack, | ||
| 16350 | gfp_t gfp) | ||
| 16351 | { | ||
| 16352 | nl80211_frame_tx_status(wdev, cookie, buf, len, ack, gfp, | ||
| 16353 | NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS); | ||
| 16354 | } | ||
| 16355 | EXPORT_SYMBOL(cfg80211_control_port_tx_status); | ||
| 16356 | |||
| 16357 | void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, | ||
| 16358 | const u8 *buf, size_t len, bool ack, gfp_t gfp) | ||
| 16359 | { | ||
| 16360 | nl80211_frame_tx_status(wdev, cookie, buf, len, ack, gfp, | ||
| 16361 | NL80211_CMD_FRAME_TX_STATUS); | ||
| 16362 | } | ||
| 16338 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); | 16363 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); |
| 16339 | 16364 | ||
| 16340 | static int __nl80211_rx_control_port(struct net_device *dev, | 16365 | static int __nl80211_rx_control_port(struct net_device *dev, |
| @@ -748,14 +748,17 @@ static inline int rdev_tx_control_port(struct cfg80211_registered_device *rdev, · 747 unmodified lines | |||
| 748 | struct net_device *dev, | 748 | struct net_device *dev, |
| 749 | const void *buf, size_t len, | 749 | const void *buf, size_t len, |
| 750 | const u8 *dest, __be16 proto, | 750 | const u8 *dest, __be16 proto, |
| 751 | const bool noencrypt) | 751 | const bool noencrypt, u64 *cookie) |
| 752 | { | 752 | { |
| 753 | int ret; | 753 | int ret; |
| 754 | trace_rdev_tx_control_port(&rdev->wiphy, dev, buf, len, | 754 | trace_rdev_tx_control_port(&rdev->wiphy, dev, buf, len, |
| 755 | dest, proto, noencrypt); | 755 | dest, proto, noencrypt); |
| 756 | ret = rdev->ops->tx_control_port(&rdev->wiphy, dev, buf, len, | 756 | ret = rdev->ops->tx_control_port(&rdev->wiphy, dev, buf, len, |
| 757 | dest, proto, noencrypt); | 757 | dest, proto, noencrypt, cookie); |
| 758 | trace_rdev_return_int(&rdev->wiphy, ret); | 758 | if (cookie) |
| 759 | trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); | ||
| 760 | else | ||
| 761 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
| 759 | return ret; | 762 | return ret; |
| 760 | } | 763 | } |
| 761 | 764 | ||
| @@ -2861,6 +2861,23 @@ TRACE_EVENT(cfg80211_mgmt_tx_status, · 2860 unmodified lines | |||
| 2861 | WDEV_PR_ARG, __entry->cookie, BOOL_TO_STR(__entry->ack)) | 2861 | WDEV_PR_ARG, __entry->cookie, BOOL_TO_STR(__entry->ack)) |
| 2862 | ); | 2862 | ); |
| 2863 | 2863 | ||
| 2864 | TRACE_EVENT(cfg80211_control_port_tx_status, | ||
| 2865 | TP_PROTO(struct wireless_dev *wdev, u64 cookie, bool ack), | ||
| 2866 | TP_ARGS(wdev, cookie, ack), | ||
| 2867 | TP_STRUCT__entry( | ||
| 2868 | WDEV_ENTRY | ||
| 2869 | __field(u64, cookie) | ||
| 2870 | __field(bool, ack) | ||
| 2871 | ), | ||
| 2872 | TP_fast_assign( | ||
| 2873 | WDEV_ASSIGN; | ||
| 2874 | __entry->cookie = cookie; | ||
| 2875 | __entry->ack = ack; | ||
| 2876 | ), | ||
| 2877 | TP_printk(WDEV_PR_FMT", cookie: %llu, ack: %s", | ||
| 2878 | WDEV_PR_ARG, __entry->cookie, BOOL_TO_STR(__entry->ack)) | ||
| 2879 | ); | ||
| 2880 | |||
| 2864 | TRACE_EVENT(cfg80211_rx_control_port, | 2881 | TRACE_EVENT(cfg80211_rx_control_port, |
| 2865 | TP_PROTO(struct net_device *netdev, struct sk_buff *skb, | 2882 | TP_PROTO(struct net_device *netdev, struct sk_buff *skb, |
| 2866 | bool unencrypted), | 2883 | bool unencrypted), |