Commit dca9ca2d authored by Markus Theil's avatar Markus Theil Committed by Johannes Berg
Browse files

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: default avatarMarkus 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: default avatarJohannes Berg <johannes.berg@intel.com>
parent 3c23215b
Loading
Loading
Loading
Loading
+19 −1
Original line number Diff line number Diff line
@@ -4069,7 +4069,8 @@ struct cfg80211_ops {
				   struct net_device *dev,
				   const u8 *buf, size_t len,
				   const u8 *dest, const __be16 proto,
				   const bool noencrypt);
				   const bool noencrypt,
				   u64 *cookie);

	int	(*get_ftm_responder_stats)(struct wiphy *wiphy,
				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,
			     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
+12 −0
Original line number Diff line number Diff line
@@ -1164,6 +1164,12 @@
 *	dropped because it did not include a valid MME MIC while beacon
 *	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_AFTER_LAST: internal use
 */
@@ -1392,6 +1398,8 @@ enum nl80211_commands {

	NL80211_CMD_UNPROT_BEACON,

	NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS,

	/* add new commands above here */

	/* 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
 *	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.
 * @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_BEACON_PROTECTION_CLIENT,
	NL80211_EXT_FEATURE_SCAN_FREQ_KHZ,
	NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS,

	/* add new features before the definition below */
	NUM_NL80211_EXT_FEATURES,
+2 −1
Original line number Diff line number Diff line
@@ -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);
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
			      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,
			      const u8 *buf, size_t len);

+2 −1
Original line number Diff line number Diff line
@@ -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,
			      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_local *local = sdata->local;
+33 −8
Original line number Diff line number Diff line
@@ -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)
{
	bool dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK];
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	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;
	u16 proto;
	bool noencrypt;
	u64 cookie = 0;
	int err;

	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 =
		nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]);

	return rdev_tx_control_port(rdev, dev, buf, len,
				    dest, cpu_to_be16(proto), noencrypt);

	err = rdev_tx_control_port(rdev, dev, buf, len,
				   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:
	wdev_unlock(wdev);
	return err;
@@ -16294,8 +16299,9 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
	return -ENOBUFS;
}

void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
			     const u8 *buf, size_t len, bool ack, gfp_t gfp)
static void nl80211_frame_tx_status(struct wireless_dev *wdev, u64 cookie,
				    const u8 *buf, size_t len, bool ack,
				    gfp_t gfp, enum nl80211_commands command)
{
	struct wiphy *wiphy = wdev->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;
	void *hdr;

	if (command == NL80211_CMD_FRAME_TX_STATUS)
		trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
	else
		trace_cfg80211_control_port_tx_status(wdev, cookie, ack);

	msg = nlmsg_new(100 + len, gfp);
	if (!msg)
		return;

	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS);
	hdr = nl80211hdr_put(msg, 0, 0, 0, command);
	if (!hdr) {
		nlmsg_free(msg);
		return;
@@ -16335,6 +16344,22 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
nla_put_failure:
	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);

static int __nl80211_rx_control_port(struct net_device *dev,
Loading