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 | 4069 | struct net_device *dev, |
| 4070 | 4070 | const u8 *buf, size_t len, |
| 4071 | 4071 | const u8 *dest, const __be16 proto, |
| 4072 | − const bool noencrypt); | |
| 4072 | + const bool noencrypt, | |
| 4073 | + u64 *cookie); | |
| 4073 | 4074 | |
| 4074 | 4075 | int (*get_ftm_responder_stats)(struct wiphy *wiphy, |
| 4075 | 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 | 7050 | void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, |
| 7050 | 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 | 7072 | * cfg80211_rx_control_port - notification about a received control port frame |
| @@ -1164,6 +1164,12 @@ · 1163 unmodified lines | ||
| 1164 | 1164 | * dropped because it did not include a valid MME MIC while beacon |
| 1165 | 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 | 1173 | * @NL80211_CMD_MAX: highest used command number |
| 1168 | 1174 | * @__NL80211_CMD_AFTER_LAST: internal use |
| 1169 | 1175 | */ |
| @@ -1392,6 +1398,8 @@ enum nl80211_commands { · 222 unmodified lines | ||
| 1392 | 1398 | |
| 1393 | 1399 | NL80211_CMD_UNPROT_BEACON, |
| 1394 | 1400 | |
| 1401 | + NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS, | |
| 1402 | + | |
| 1395 | 1403 | /* add new commands above here */ |
| 1396 | 1404 | |
| 1397 | 1405 | /* used to define NL80211_CMD_MAX below */ |
| @@ -5729,6 +5737,9 @@ enum nl80211_feature_flags { · 4331 unmodified lines | ||
| 5729 | 5737 | * report %NL80211_ATTR_SCAN_FREQ_KHZ, %NL80211_SCAN_FLAG_FREQ_KHZ must be |
| 5730 | 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 | 5743 | * @NUM_NL80211_EXT_FEATURES: number of extended features. |
| 5733 | 5744 | * @MAX_NL80211_EXT_FEATURES: highest extended feature index. |
| 5734 | 5745 | */ |
| @@ -5783,6 +5794,7 @@ enum nl80211_ext_feature_index { · 48 unmodified lines | ||
| 5783 | 5794 | NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS, |
| 5784 | 5795 | NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT, |
| 5785 | 5796 | NL80211_EXT_FEATURE_SCAN_FREQ_KHZ, |
| 5797 | + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS, | |
| 5786 | 5798 | |
| 5787 | 5799 | /* add new features before the definition below */ |
| 5788 | 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 | 1800 | void ieee80211_clear_fast_xmit(struct sta_info *sta); |
| 1801 | 1801 | int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, |
| 1802 | 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 | 1805 | int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev, |
| 1805 | 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 | 5340 | int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, |
| 5341 | 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 | 5345 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 5345 | 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 | 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 | 13870 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| 13870 | 13871 | struct net_device *dev = info->user_ptr[1]; |
| 13871 | 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 | 13875 | u8 *dest; |
| 13875 | 13876 | u16 proto; |
| 13876 | 13877 | bool noencrypt; |
| 13878 | + u64 cookie = 0; | |
| 13877 | 13879 | int err; |
| 13878 | 13880 | |
| 13879 | 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 | 13920 | noencrypt = |
| 13919 | 13921 | nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]); |
| 13920 | 13922 | |
| 13921 | − return rdev_tx_control_port(rdev, dev, buf, len, | |
| 13922 | − dest, cpu_to_be16(proto), noencrypt); | |
| 13923 | − | |
| 13923 | + err = rdev_tx_control_port(rdev, dev, buf, len, | |
| 13924 | + dest, cpu_to_be16(proto), noencrypt, | |
| 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 | 13929 | out: |
| 13925 | 13930 | wdev_unlock(wdev); |
| 13926 | 13931 | return err; |
| @@ -16294,8 +16299,9 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, · 2367 unmodified lines | ||
| 16294 | 16299 | return -ENOBUFS; |
| 16295 | 16300 | } |
| 16296 | 16301 | |
| 16297 | −void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, | |
| 16298 | − const u8 *buf, size_t len, bool ack, gfp_t gfp) | |
| 16302 | +static void nl80211_frame_tx_status(struct wireless_dev *wdev, u64 cookie, | |
| 16303 | + const u8 *buf, size_t len, bool ack, | |
| 16304 | + gfp_t gfp, enum nl80211_commands command) | |
| 16299 | 16305 | { |
| 16300 | 16306 | struct wiphy *wiphy = wdev->wiphy; |
| 16301 | 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 | 16309 | struct sk_buff *msg; |
| 16304 | 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 | 16317 | msg = nlmsg_new(100 + len, gfp); |
| 16309 | 16318 | if (!msg) |
| 16310 | 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 | 16322 | if (!hdr) { |
| 16314 | 16323 | nlmsg_free(msg); |
| 16315 | 16324 | return; |
| @@ -16332,9 +16341,25 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, · 16 unmodified lines | ||
| 16332 | 16341 | NL80211_MCGRP_MLME, gfp); |
| 16333 | 16342 | return; |
| 16334 | 16343 | |
| 16335 | − nla_put_failure: | |
| 16344 | +nla_put_failure: | |
| 16336 | 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 | 16363 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); |
| 16339 | 16364 | |
| 16340 | 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 | 748 | struct net_device *dev, |
| 749 | 749 | const void *buf, size_t len, |
| 750 | 750 | const u8 *dest, __be16 proto, |
| 751 | − const bool noencrypt) | |
| 751 | + const bool noencrypt, u64 *cookie) | |
| 752 | 752 | { |
| 753 | 753 | int ret; |
| 754 | 754 | trace_rdev_tx_control_port(&rdev->wiphy, dev, buf, len, |
| 755 | 755 | dest, proto, noencrypt); |
| 756 | 756 | ret = rdev->ops->tx_control_port(&rdev->wiphy, dev, buf, len, |
| 757 | − dest, proto, noencrypt); | |
| 758 | − trace_rdev_return_int(&rdev->wiphy, ret); | |
| 757 | + dest, proto, noencrypt, cookie); | |
| 758 | + if (cookie) | |
| 759 | + trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); | |
| 760 | + else | |
| 761 | + trace_rdev_return_int(&rdev->wiphy, ret); | |
| 759 | 762 | return ret; |
| 760 | 763 | } |
| 761 | 764 | |
| @@ -2861,6 +2861,23 @@ TRACE_EVENT(cfg80211_mgmt_tx_status, · 2860 unmodified lines | ||
| 2861 | 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 | 2881 | TRACE_EVENT(cfg80211_rx_control_port, |
| 2865 | 2882 | TP_PROTO(struct net_device *netdev, struct sk_buff *skb, |
| 2866 | 2883 | bool unencrypted), |