nl80211: add ability to report TX status for control port TX
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. Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de> Link: https://lore.kernel.org/r/20200508144202.7678-2-markus.theil@tu-ilmenau.de [use extack cookie instead of explicit message, recombine patches] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:

committed by
Johannes Berg

parent
3c23215ba8
commit
dca9ca2d58
@@ -4069,7 +4069,8 @@ struct cfg80211_ops {
|
|||||||
struct net_device *dev,
|
struct net_device *dev,
|
||||||
const u8 *buf, size_t len,
|
const u8 *buf, size_t len,
|
||||||
const u8 *dest, const __be16 proto,
|
const u8 *dest, const __be16 proto,
|
||||||
const bool noencrypt);
|
const bool noencrypt,
|
||||||
|
u64 *cookie);
|
||||||
|
|
||||||
int (*get_ftm_responder_stats)(struct wiphy *wiphy,
|
int (*get_ftm_responder_stats)(struct wiphy *wiphy,
|
||||||
struct net_device *dev,
|
struct net_device *dev,
|
||||||
@@ -7049,6 +7050,23 @@ static inline bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq,
|
|||||||
void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
|
void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
|
||||||
const u8 *buf, size_t len, bool ack, gfp_t gfp);
|
const u8 *buf, size_t len, bool ack, gfp_t gfp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cfg80211_control_port_tx_status - notification of TX status for control
|
||||||
|
* port frames
|
||||||
|
* @wdev: wireless device receiving the frame
|
||||||
|
* @cookie: Cookie returned by cfg80211_ops::tx_control_port()
|
||||||
|
* @buf: Data frame (header + body)
|
||||||
|
* @len: length of the frame data
|
||||||
|
* @ack: Whether frame was acknowledged
|
||||||
|
* @gfp: context flags
|
||||||
|
*
|
||||||
|
* This function is called whenever a control port frame was requested to be
|
||||||
|
* transmitted with cfg80211_ops::tx_control_port() to report the TX status of
|
||||||
|
* the transmission attempt.
|
||||||
|
*/
|
||||||
|
void cfg80211_control_port_tx_status(struct wireless_dev *wdev, u64 cookie,
|
||||||
|
const u8 *buf, size_t len, bool ack,
|
||||||
|
gfp_t gfp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cfg80211_rx_control_port - notification about a received control port frame
|
* cfg80211_rx_control_port - notification about a received control port frame
|
||||||
|
@@ -1164,6 +1164,12 @@
|
|||||||
* dropped because it did not include a valid MME MIC while beacon
|
* dropped because it did not include a valid MME MIC while beacon
|
||||||
* protection was enabled (BIGTK configured in station mode).
|
* protection was enabled (BIGTK configured in station mode).
|
||||||
*
|
*
|
||||||
|
* @NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS: Report TX status of a control
|
||||||
|
* port frame transmitted with %NL80211_CMD_CONTROL_PORT_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.
|
||||||
|
*
|
||||||
* @NL80211_CMD_MAX: highest used command number
|
* @NL80211_CMD_MAX: highest used command number
|
||||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||||
*/
|
*/
|
||||||
@@ -1392,6 +1398,8 @@ enum nl80211_commands {
|
|||||||
|
|
||||||
NL80211_CMD_UNPROT_BEACON,
|
NL80211_CMD_UNPROT_BEACON,
|
||||||
|
|
||||||
|
NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS,
|
||||||
|
|
||||||
/* add new commands above here */
|
/* add new commands above here */
|
||||||
|
|
||||||
/* used to define NL80211_CMD_MAX below */
|
/* used to define NL80211_CMD_MAX below */
|
||||||
@@ -5729,6 +5737,9 @@ enum nl80211_feature_flags {
|
|||||||
* report %NL80211_ATTR_SCAN_FREQ_KHZ, %NL80211_SCAN_FLAG_FREQ_KHZ must be
|
* report %NL80211_ATTR_SCAN_FREQ_KHZ, %NL80211_SCAN_FLAG_FREQ_KHZ must be
|
||||||
* included in the scan request.
|
* included in the scan request.
|
||||||
*
|
*
|
||||||
|
* @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS: The driver
|
||||||
|
* can report tx status for control port over nl80211 tx operations.
|
||||||
|
*
|
||||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||||
*/
|
*/
|
||||||
@@ -5783,6 +5794,7 @@ enum nl80211_ext_feature_index {
|
|||||||
NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS,
|
NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS,
|
||||||
NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT,
|
NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT,
|
||||||
NL80211_EXT_FEATURE_SCAN_FREQ_KHZ,
|
NL80211_EXT_FEATURE_SCAN_FREQ_KHZ,
|
||||||
|
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS,
|
||||||
|
|
||||||
/* add new features before the definition below */
|
/* add new features before the definition below */
|
||||||
NUM_NL80211_EXT_FEATURES,
|
NUM_NL80211_EXT_FEATURES,
|
||||||
|
@@ -1800,7 +1800,8 @@ void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata);
|
|||||||
void ieee80211_clear_fast_xmit(struct sta_info *sta);
|
void ieee80211_clear_fast_xmit(struct sta_info *sta);
|
||||||
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
|
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
|
||||||
const u8 *buf, size_t len,
|
const u8 *buf, size_t len,
|
||||||
const u8 *dest, __be16 proto, bool unencrypted);
|
const u8 *dest, __be16 proto, bool unencrypted,
|
||||||
|
u64 *cookie);
|
||||||
int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
|
int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
|
||||||
const u8 *buf, size_t len);
|
const u8 *buf, size_t len);
|
||||||
|
|
||||||
|
@@ -5339,7 +5339,8 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
|
|||||||
|
|
||||||
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
|
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
|
||||||
const u8 *buf, size_t len,
|
const u8 *buf, size_t len,
|
||||||
const u8 *dest, __be16 proto, bool unencrypted)
|
const u8 *dest, __be16 proto, bool unencrypted,
|
||||||
|
u64 *cookie)
|
||||||
{
|
{
|
||||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||||
struct ieee80211_local *local = sdata->local;
|
struct ieee80211_local *local = sdata->local;
|
||||||
|
@@ -13866,6 +13866,7 @@ static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info)
|
|||||||
|
|
||||||
static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
|
static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
|
||||||
{
|
{
|
||||||
|
bool dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK];
|
||||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||||
struct net_device *dev = info->user_ptr[1];
|
struct net_device *dev = info->user_ptr[1];
|
||||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
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)
|
|||||||
u8 *dest;
|
u8 *dest;
|
||||||
u16 proto;
|
u16 proto;
|
||||||
bool noencrypt;
|
bool noencrypt;
|
||||||
|
u64 cookie = 0;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!wiphy_ext_feature_isset(&rdev->wiphy,
|
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)
|
|||||||
noencrypt =
|
noencrypt =
|
||||||
nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]);
|
nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]);
|
||||||
|
|
||||||
return rdev_tx_control_port(rdev, dev, buf, len,
|
err = rdev_tx_control_port(rdev, dev, buf, len,
|
||||||
dest, cpu_to_be16(proto), noencrypt);
|
dest, cpu_to_be16(proto), noencrypt,
|
||||||
|
dont_wait_for_ack ? NULL : &cookie);
|
||||||
|
if (!err && !dont_wait_for_ack)
|
||||||
|
nl_set_extack_cookie_u64(info->extack, cookie);
|
||||||
|
return err;
|
||||||
out:
|
out:
|
||||||
wdev_unlock(wdev);
|
wdev_unlock(wdev);
|
||||||
return err;
|
return err;
|
||||||
@@ -16294,8 +16299,9 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
|
|||||||
return -ENOBUFS;
|
return -ENOBUFS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
|
static void nl80211_frame_tx_status(struct wireless_dev *wdev, u64 cookie,
|
||||||
const u8 *buf, size_t len, bool ack, gfp_t gfp)
|
const u8 *buf, size_t len, bool ack,
|
||||||
|
gfp_t gfp, enum nl80211_commands command)
|
||||||
{
|
{
|
||||||
struct wiphy *wiphy = wdev->wiphy;
|
struct wiphy *wiphy = wdev->wiphy;
|
||||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||||
@@ -16303,13 +16309,16 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
|
|||||||
struct sk_buff *msg;
|
struct sk_buff *msg;
|
||||||
void *hdr;
|
void *hdr;
|
||||||
|
|
||||||
|
if (command == NL80211_CMD_FRAME_TX_STATUS)
|
||||||
trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
|
trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
|
||||||
|
else
|
||||||
|
trace_cfg80211_control_port_tx_status(wdev, cookie, ack);
|
||||||
|
|
||||||
msg = nlmsg_new(100 + len, gfp);
|
msg = nlmsg_new(100 + len, gfp);
|
||||||
if (!msg)
|
if (!msg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS);
|
hdr = nl80211hdr_put(msg, 0, 0, 0, command);
|
||||||
if (!hdr) {
|
if (!hdr) {
|
||||||
nlmsg_free(msg);
|
nlmsg_free(msg);
|
||||||
return;
|
return;
|
||||||
@@ -16332,9 +16341,25 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
|
|||||||
NL80211_MCGRP_MLME, gfp);
|
NL80211_MCGRP_MLME, gfp);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
nlmsg_free(msg);
|
nlmsg_free(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cfg80211_control_port_tx_status(struct wireless_dev *wdev, u64 cookie,
|
||||||
|
const u8 *buf, size_t len, bool ack,
|
||||||
|
gfp_t gfp)
|
||||||
|
{
|
||||||
|
nl80211_frame_tx_status(wdev, cookie, buf, len, ack, gfp,
|
||||||
|
NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(cfg80211_control_port_tx_status);
|
||||||
|
|
||||||
|
void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
|
||||||
|
const u8 *buf, size_t len, bool ack, gfp_t gfp)
|
||||||
|
{
|
||||||
|
nl80211_frame_tx_status(wdev, cookie, buf, len, ack, gfp,
|
||||||
|
NL80211_CMD_FRAME_TX_STATUS);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
|
EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
|
||||||
|
|
||||||
static int __nl80211_rx_control_port(struct net_device *dev,
|
static int __nl80211_rx_control_port(struct net_device *dev,
|
||||||
|
@@ -748,13 +748,16 @@ static inline int rdev_tx_control_port(struct cfg80211_registered_device *rdev,
|
|||||||
struct net_device *dev,
|
struct net_device *dev,
|
||||||
const void *buf, size_t len,
|
const void *buf, size_t len,
|
||||||
const u8 *dest, __be16 proto,
|
const u8 *dest, __be16 proto,
|
||||||
const bool noencrypt)
|
const bool noencrypt, u64 *cookie)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
trace_rdev_tx_control_port(&rdev->wiphy, dev, buf, len,
|
trace_rdev_tx_control_port(&rdev->wiphy, dev, buf, len,
|
||||||
dest, proto, noencrypt);
|
dest, proto, noencrypt);
|
||||||
ret = rdev->ops->tx_control_port(&rdev->wiphy, dev, buf, len,
|
ret = rdev->ops->tx_control_port(&rdev->wiphy, dev, buf, len,
|
||||||
dest, proto, noencrypt);
|
dest, proto, noencrypt, cookie);
|
||||||
|
if (cookie)
|
||||||
|
trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
|
||||||
|
else
|
||||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@@ -2861,6 +2861,23 @@ TRACE_EVENT(cfg80211_mgmt_tx_status,
|
|||||||
WDEV_PR_ARG, __entry->cookie, BOOL_TO_STR(__entry->ack))
|
WDEV_PR_ARG, __entry->cookie, BOOL_TO_STR(__entry->ack))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(cfg80211_control_port_tx_status,
|
||||||
|
TP_PROTO(struct wireless_dev *wdev, u64 cookie, bool ack),
|
||||||
|
TP_ARGS(wdev, cookie, ack),
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
WDEV_ENTRY
|
||||||
|
__field(u64, cookie)
|
||||||
|
__field(bool, ack)
|
||||||
|
),
|
||||||
|
TP_fast_assign(
|
||||||
|
WDEV_ASSIGN;
|
||||||
|
__entry->cookie = cookie;
|
||||||
|
__entry->ack = ack;
|
||||||
|
),
|
||||||
|
TP_printk(WDEV_PR_FMT", cookie: %llu, ack: %s",
|
||||||
|
WDEV_PR_ARG, __entry->cookie, BOOL_TO_STR(__entry->ack))
|
||||||
|
);
|
||||||
|
|
||||||
TRACE_EVENT(cfg80211_rx_control_port,
|
TRACE_EVENT(cfg80211_rx_control_port,
|
||||||
TP_PROTO(struct net_device *netdev, struct sk_buff *skb,
|
TP_PROTO(struct net_device *netdev, struct sk_buff *skb,
|
||||||
bool unencrypted),
|
bool unencrypted),
|
||||||
|
Reference in New Issue
Block a user