2013-06-25 07:02:54

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH v11 0/2] P2P find phase offload

Addressed input from Arend and Johannes:

- shorter comment for @flags for cfg80211_rx_mgmt()
- enum nl80211_rxmgmt_flags to define raw values, don't use BIT()

Actually, only patch 1/2 changed, but I am sending both to avoid any confusion

Vladimir Kondratiev (2):
cfg80211: add 'flags' to cfg80211_rx_mgmt()
cfg80211: P2P find phase offload

drivers/net/wireless/ath/ath6kl/wmi.c | 7 +-
drivers/net/wireless/ath/wil6210/wmi.c | 2 +-
drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 4 +-
drivers/net/wireless/mwifiex/util.c | 4 +-
include/net/cfg80211.h | 79 ++++++++++-
include/uapi/linux/nl80211.h | 29 ++++
net/mac80211/rx.c | 3 +-
net/wireless/mlme.c | 4 +-
net/wireless/nl80211.c | 187 +++++++++++++++++++++++++-
net/wireless/nl80211.h | 2 +-
net/wireless/rdev-ops.h | 19 +++
net/wireless/trace.h | 42 ++++++
12 files changed, 365 insertions(+), 17 deletions(-)

--
1.8.1.2



2013-06-25 07:03:00

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH v11 2/2] cfg80211: P2P find phase offload

Allow to implement P2P find phase in the driver/firmware.

Offload scheme designed as follows:

- Driver provide methods start_p2p_find and stop_p2p_find in the cfg80211_ops;
- Driver indicate firmware or driver responds to the probe requests by setting
feature NL80211_FEATURE_P2P_PROBE_RESP_OFFLOAD
- wpa_supplicant analyses methods supported to discover p2p offload support;
- wpa_supplicant analyses feature flags to discover p2p probe response
offload support;
to perform p2p scan, wpa_supplicant:
- perform legacy scan, through driver's cfg80211_ops 'scan' method
- configure rx management filter to get probe-request and probe-response frames
- start p2p find via driver's cfg80211_ops start_p2p_find method
- driver start p2p find with hardware and notify wpa_supplicant with
cfg80211_p2p_find_notify_start()
- driver/firmware toggle search/listen states. Received probe-request and
probe-response frames passed to the wpa_supplicant via cfg80211_rx_mgmt
- when wpa_supplicant wants to stop p2p find, it calls driver's
cfg80211_ops stop_p2p_find method. Alternatively, driver/firmware may decide
to stop p2p find. In all cases, driver notifies wpa_supplicant using
cfg80211_p2p_find_notify_end()

All driver to user space communication done through nl80211 layer.

Offloaded P2P find does not support variations like progressive scan.

Signed-off-by: Vladimir Kondratiev <[email protected]>
---
include/net/cfg80211.h | 76 ++++++++++++++++++
include/uapi/linux/nl80211.h | 16 ++++
net/wireless/nl80211.c | 181 +++++++++++++++++++++++++++++++++++++++++++
net/wireless/rdev-ops.h | 19 +++++
net/wireless/trace.h | 42 ++++++++++
5 files changed, 334 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 8347500..7ea551e 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1805,6 +1805,38 @@ struct cfg80211_update_ft_ies_params {
};

/**
+ * struct cfg80211_p2p_find_params - parameters for P2P find
+ * @probe_ie: extra IE's for probe frames
+ * @probe_ie_len: length, bytes, of @probe_ie
+ * @probe_resp_ie: extra IE's for probe response frames
+ * @probe_resp_ie_len: length, bytes, of @probe_resp_ie
+ * Driver/firmware may add additional IE's as well as modify
+ * provided ones; typical IE's to be added are
+ * WLAN_EID_EXT_SUPP_RATES, WLAN_EID_DS_PARAMS,
+ * WLAN_EID_HT_CAPABILITY.
+ * @min_discoverable_interval: and
+ * @max_discoverable_interval: min/max for random multiplier of 100TU's
+ * for the listen state duration
+ * @listen_channel: channels to listen on; not NULL
+ * @n_channels: number of channels to operate on
+ * @channels: channels to operate on
+ * may be NULL, in this case driver suppose to scan for all social
+ * channels; or channel set should be non-empty (n_channels > 0)
+ */
+struct cfg80211_p2p_find_params {
+ const u8 *probe_ie;
+ size_t probe_ie_len;
+ const u8 *probe_resp_ie;
+ size_t probe_resp_ie_len;
+ u32 min_discoverable_interval;
+ u32 max_discoverable_interval;
+ struct ieee80211_channel *listen_channel;
+
+ int n_channels;
+ struct ieee80211_channel **channels;
+};
+
+/**
* struct cfg80211_ops - backend description for wireless configuration
*
* This struct is registered by fullmac card drivers and/or wireless stacks
@@ -2043,6 +2075,24 @@ struct cfg80211_update_ft_ies_params {
* driver can take the most appropriate actions.
* @crit_proto_stop: Indicates critical protocol no longer needs increased link
* reliability. This operation can not fail.
+ *
+ * @start_p2p_find: start P2P find phase
+ * Parameters include IEs for probe/probe-resp frames;
+ * and channels to operate on.
+ * Parameters are not retained after call, driver need to copy data if
+ * it need it later.
+ * P2P find can't run concurrently with ROC or scan,
+ * conflict with scan detected by cfg80211 and -EBUSY returned;
+ * and driver should check for ROC and return -EBUSY to indicate conflict.
+ * While performing P2P discovery, driver should report received
+ * probe-request and probe-response frames via cfg80211_rx_mgmt
+ * accordingly to the rx mgmt filter, as set by mgmt_frame_register().
+ * If device indicates NL80211_FEATURE_P2P_PROBE_RESP_OFFLOAD, it may
+ * reply some matching probes and replied probes may be not reported to
+ * the upper layers; otherwise it must not reply any probe.
+ * @stop_p2p_find: stop P2P find phase
+ * After stopping p2p find, driver should call
+ * cfg80211_p2p_find_notify_end() to inform upper layers
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -2278,6 +2328,12 @@ struct cfg80211_ops {
u16 duration);
void (*crit_proto_stop)(struct wiphy *wiphy,
struct wireless_dev *wdev);
+
+ int (*start_p2p_find)(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct cfg80211_p2p_find_params *params);
+ void (*stop_p2p_find)(struct wiphy *wiphy,
+ struct wireless_dev *wdev);
};

/*
@@ -4177,6 +4233,26 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
*/
void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp);

+/**
+ * cfg80211_p2p_find_notify_start - report p2p find phase started
+ * @wdev: the wireless device reporting the event
+ * @gfp: allocation flags
+ */
+void cfg80211_p2p_find_notify_start(struct wireless_dev *wdev, gfp_t gfp);
+
+/**
+ * cfg80211_p2p_find_notify_end - report p2p find phase ended
+ * @wdev: the wireless device reporting the event
+ * @gfp: allocation flags
+ *
+ * p2p find phase may be ended either unsolicited or in response to
+ * ops->stop_p2p_find
+ *
+ * In any case, if @start_p2p_find from driver's struct cfg80211_ops called,
+ * @cfg80211_p2p_find_notify_end should be eventually called
+ */
+void cfg80211_p2p_find_notify_end(struct wireless_dev *wdev, gfp_t gfp);
+
/* Logging, debugging and troubleshooting/diagnostic helpers. */

/* wiphy_printk helpers, similar to dev_printk */
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index f125d2c..a4b14d4 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -810,6 +810,9 @@ enum nl80211_commands {
NL80211_CMD_CRIT_PROTOCOL_START,
NL80211_CMD_CRIT_PROTOCOL_STOP,

+ NL80211_CMD_START_P2P_FIND,
+ NL80211_CMD_STOP_P2P_FIND,
+
/* add new commands above here */

/* used to define NL80211_CMD_MAX below */
@@ -1438,6 +1441,11 @@ enum nl80211_commands {
*
* @NL80211_ATTR_RXMGMT_FLAGS: flags for cfg80211_rx_mgmt, u32
*
+ * @NL80211_ATTR_MIN_DISCOVERABLE_INTERVAL:
+ * @NL80211_ATTR_MAX_DISCOVERABLE_INTERVAL: min/max discoverable interval
+ * for the p2p find, multiple of 100 TUs, represented as u32
+ * @NL80211_ATTR_LISTEN_FREQ: Listen channel frequency, represented as u32
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1740,6 +1748,10 @@ enum nl80211_attrs {

NL80211_ATTR_RXMGMT_FLAGS,

+ NL80211_ATTR_MIN_DISCOVERABLE_INTERVAL,
+ NL80211_ATTR_MAX_DISCOVERABLE_INTERVAL,
+ NL80211_ATTR_LISTEN_FREQ,
+
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
@@ -3592,6 +3604,9 @@ enum nl80211_ap_sme_features {
* interface. An active monitor interface behaves like a normal monitor
* interface, but gets added to the driver. It ensures that incoming
* unicast packets directed at the configured interface address get ACKed.
+ * @NL80211_FEATURE_P2P_PROBE_RESP_OFFLOAD: When in P2P find phase,
+ * the device may respond to some probe-requests in hardware;
+ * replied probe-requests may be not reported to the upper layers.
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
@@ -3612,6 +3627,7 @@ enum nl80211_feature_flags {
NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15,
NL80211_FEATURE_USERSPACE_MPM = 1 << 16,
NL80211_FEATURE_ACTIVE_MONITOR = 1 << 17,
+ NL80211_FEATURE_P2P_PROBE_RESP_OFFLOAD = 1 << 18,
};

/**
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 65c5578..9acea1e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -349,6 +349,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
[NL80211_ATTR_PEER_AID] = { .type = NLA_U16 },
+ [NL80211_ATTR_MIN_DISCOVERABLE_INTERVAL] = { .type = NLA_U32 },
+ [NL80211_ATTR_MAX_DISCOVERABLE_INTERVAL] = { .type = NLA_U32 },
+ [NL80211_ATTR_LISTEN_FREQ] = { .type = NLA_U32 },
};

/* policy for the key attributes */
@@ -1387,6 +1390,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
if (split) {
CMD(crit_proto_start, CRIT_PROTOCOL_START);
CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
+ CMD(start_p2p_find, START_P2P_FIND);
+ CMD(stop_p2p_find, STOP_P2P_FIND);
}

#ifdef CONFIG_NL80211_TESTMODE
@@ -8306,6 +8311,129 @@ static int nl80211_crit_protocol_stop(struct sk_buff *skb,
return 0;
}

+static int nl80211_start_p2p_find(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct wireless_dev *wdev = info->user_ptr[1];
+ struct wiphy *wiphy = &rdev->wiphy;
+ /*
+ * Defaults, as defined in the spec
+ * Ref: Wi-Fi Peer-to-Peer (P2P) Technical Specification v1.1
+ * Clause: 3.1.2.1.3 Find Phase
+ */
+ struct cfg80211_p2p_find_params params = {
+ .min_discoverable_interval = 1,
+ .max_discoverable_interval = 3,
+ };
+ struct nlattr *attr_freq = info->attrs[NL80211_ATTR_SCAN_FREQUENCIES];
+ struct nlattr *attr_l_freq = info->attrs[NL80211_ATTR_LISTEN_FREQ];
+ struct nlattr *attr;
+ int err, tmp, n_channels, i = 0;
+ struct ieee80211_channel **channels = NULL;
+ struct ieee80211_channel *chan;
+
+ if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
+ return -EOPNOTSUPP;
+
+ if (!rdev->ops->start_p2p_find || !rdev->ops->stop_p2p_find)
+ return -EOPNOTSUPP;
+
+ if (!attr_l_freq)
+ return -EINVAL;
+
+ if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+ return -EINVAL;
+
+ if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_PROBE_RESP]))
+ return -EINVAL;
+
+ if (rdev->scan_req)
+ return -EBUSY;
+
+ chan = ieee80211_get_channel(wiphy, nla_get_u32(attr_l_freq));
+ if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED))
+ return -EINVAL;
+ params.listen_channel = chan;
+
+ if (attr_freq) {
+ n_channels = validate_scan_freqs(attr_freq);
+ if (!n_channels)
+ return -EINVAL;
+
+ channels = kzalloc(n_channels * sizeof(*channels), GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ /* user specified, bail out if channel not found */
+ nla_for_each_nested(attr, attr_freq, tmp) {
+ chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
+
+ if (!chan) {
+ err = -EINVAL;
+ goto out_free;
+ }
+
+ /* ignore disabled channels */
+ if (chan->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ params.channels[i] = chan;
+ i++;
+ }
+ if (!i) {
+ err = -EINVAL;
+ goto out_free;
+ }
+
+ params.n_channels = i;
+ params.channels = channels;
+ }
+
+
+ attr = info->attrs[NL80211_ATTR_IE];
+ if (attr) {
+ params.probe_ie_len = nla_len(attr);
+ params.probe_ie = nla_data(attr);
+ }
+
+ attr = info->attrs[NL80211_ATTR_IE_PROBE_RESP];
+ if (attr) {
+ params.probe_resp_ie_len = nla_len(attr);
+ params.probe_resp_ie = nla_data(attr);
+ }
+
+ attr = info->attrs[NL80211_ATTR_MIN_DISCOVERABLE_INTERVAL];
+ if (attr)
+ params.min_discoverable_interval = nla_get_u32(attr);
+
+ attr = info->attrs[NL80211_ATTR_MAX_DISCOVERABLE_INTERVAL];
+ if (attr)
+ params.max_discoverable_interval = nla_get_u32(attr);
+
+ err = rdev_start_p2p_find(rdev, wdev, &params);
+
+out_free:
+ kfree(channels);
+
+ return err;
+}
+
+static int nl80211_stop_p2p_find(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct wireless_dev *wdev = info->user_ptr[1];
+
+ if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
+ return -EOPNOTSUPP;
+
+ if (!rdev->ops->start_p2p_find || !rdev->ops->stop_p2p_find)
+ return -EOPNOTSUPP;
+
+ rdev_stop_p2p_find(rdev, wdev);
+
+ return 0;
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -8978,6 +9106,22 @@ static struct genl_ops nl80211_ops[] = {
NL80211_FLAG_NEED_RTNL,
},
{
+ .cmd = NL80211_CMD_START_P2P_FIND,
+ .doit = nl80211_start_p2p_find,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL80211_CMD_STOP_P2P_FIND,
+ .doit = nl80211_stop_p2p_find,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
.cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
.doit = nl80211_get_protocol_features,
.policy = nl80211_policy,
@@ -10645,6 +10789,43 @@ void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
}
EXPORT_SYMBOL(cfg80211_tdls_oper_request);

+static
+void cfg80211_p2p_find_notify(struct wireless_dev *wdev, int cmd, gfp_t gfp)
+{
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ struct sk_buff *msg;
+ void *hdr;
+
+ trace_cfg80211_p2p_find_notify(wdev, cmd);
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_end(msg, hdr);
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_scan_mcgrp.id, GFP_KERNEL);
+}
+
+void cfg80211_p2p_find_notify_start(struct wireless_dev *wdev, gfp_t gfp)
+{
+ cfg80211_p2p_find_notify(wdev, NL80211_CMD_START_P2P_FIND, gfp);
+}
+EXPORT_SYMBOL(cfg80211_p2p_find_notify_start);
+
+void cfg80211_p2p_find_notify_end(struct wireless_dev *wdev, gfp_t gfp)
+{
+ cfg80211_p2p_find_notify(wdev, NL80211_CMD_STOP_P2P_FIND, gfp);
+}
+EXPORT_SYMBOL(cfg80211_p2p_find_notify_end);
+
static int nl80211_netlink_notify(struct notifier_block * nb,
unsigned long state,
void *_notify)
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 9f15f0a..94ff98a 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -923,4 +923,23 @@ static inline void rdev_crit_proto_stop(struct cfg80211_registered_device *rdev,
trace_rdev_return_void(&rdev->wiphy);
}

+static inline int rdev_start_p2p_find(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ struct cfg80211_p2p_find_params *params)
+{
+ int ret;
+ trace_rdev_start_p2p_find(&rdev->wiphy, wdev, params);
+ ret = rdev->ops->start_p2p_find(&rdev->wiphy, wdev, params);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
+static inline void rdev_stop_p2p_find(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev)
+{
+ trace_rdev_stop_p2p_find(&rdev->wiphy, wdev);
+ rdev->ops->stop_p2p_find(&rdev->wiphy, wdev);
+ trace_rdev_return_void(&rdev->wiphy);
+}
+
#endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index e1534baf..0042ea2 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1841,6 +1841,34 @@ TRACE_EVENT(rdev_crit_proto_stop,
WIPHY_PR_ARG, WDEV_PR_ARG)
);

+TRACE_EVENT(rdev_start_p2p_find,
+ TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+ struct cfg80211_p2p_find_params *params),
+ TP_ARGS(wiphy, wdev, params),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ WDEV_ENTRY
+ __field(u32, min_di)
+ __field(u32, max_di)
+ __field(int, n_channels)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ WDEV_ASSIGN;
+ __entry->min_di = params->min_discoverable_interval;
+ __entry->max_di = params->max_discoverable_interval;
+ __entry->n_channels = params->n_channels;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", disc. int. [%d..%d], n_channels %d",
+ WIPHY_PR_ARG, WDEV_PR_ARG, __entry->min_di, __entry->max_di,
+ __entry->n_channels)
+);
+
+DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_p2p_find,
+ TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
+ TP_ARGS(wiphy, wdev)
+);
+
/*************************************************************
* cfg80211 exported functions traces *
*************************************************************/
@@ -2520,6 +2548,20 @@ TRACE_EVENT(cfg80211_ft_event,
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap))
);

+TRACE_EVENT(cfg80211_p2p_find_notify,
+ TP_PROTO(struct wireless_dev *wdev, int cmd),
+ TP_ARGS(wdev, cmd),
+ TP_STRUCT__entry(
+ WDEV_ENTRY
+ __field(int, cmd)
+ ),
+ TP_fast_assign(
+ WDEV_ASSIGN;
+ __entry->cmd = cmd;
+ ),
+ TP_printk(WDEV_PR_FMT ", cmd: %d", WDEV_PR_ARG, __entry->cmd)
+);
+
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */

#undef TRACE_INCLUDE_PATH
--
1.8.1.2


2013-06-25 07:02:57

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH v11 1/2] cfg80211: add 'flags' to cfg80211_rx_mgmt()

Flags intended to report various auxiliary information.
Introduced flag NL80211_RXMGMT_FLAG_REPLIED to report
whether frame was replied by the device/driver.

Signed-off-by: Vladimir Kondratiev <[email protected]>
---
drivers/net/wireless/ath/ath6kl/wmi.c | 7 +++----
drivers/net/wireless/ath/wil6210/wmi.c | 2 +-
drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 4 ++--
drivers/net/wireless/mwifiex/util.c | 4 ++--
include/net/cfg80211.h | 3 ++-
include/uapi/linux/nl80211.h | 13 +++++++++++++
net/mac80211/rx.c | 3 +--
net/wireless/mlme.c | 4 ++--
net/wireless/nl80211.c | 6 ++++--
net/wireless/nl80211.h | 2 +-
10 files changed, 31 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 87aefb4..546d5da 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -568,8 +568,8 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len,
dlen, freq, vif->probe_req_report);

if (vif->probe_req_report || vif->nw_type == AP_NETWORK)
- cfg80211_rx_mgmt(&vif->wdev, freq, 0,
- ev->data, dlen, GFP_ATOMIC);
+ cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0,
+ GFP_ATOMIC);

return 0;
}
@@ -608,8 +608,7 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len,
return -EINVAL;
}
ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
- cfg80211_rx_mgmt(&vif->wdev, freq, 0,
- ev->data, dlen, GFP_ATOMIC);
+ cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0, GFP_ATOMIC);

return 0;
}
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index dc8059a..21c791e 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -339,7 +339,7 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
}
} else {
cfg80211_rx_mgmt(wil->wdev, freq, signal,
- (void *)rx_mgmt_frame, d_len, GFP_KERNEL);
+ (void *)rx_mgmt_frame, d_len, 0, GFP_KERNEL);
}
}

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
index 79555f0..d7a9745 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -1430,7 +1430,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
IEEE80211_BAND_5GHZ);

wdev = &ifp->vif->wdev;
- cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len,
+ cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0,
GFP_ATOMIC);

kfree(mgmt_frame);
@@ -1895,7 +1895,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
IEEE80211_BAND_2GHZ :
IEEE80211_BAND_5GHZ);

- cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len,
+ cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0,
GFP_ATOMIC);

brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index e57ac0d..5d9e150 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -171,8 +171,8 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
rx_pd->rx_pkt_length = cpu_to_le16(pkt_len);

cfg80211_rx_mgmt(priv->wdev, priv->roc_cfg.chan.center_freq,
- CAL_RSSI(rx_pd->snr, rx_pd->nf),
- skb->data, pkt_len, GFP_ATOMIC);
+ CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len,
+ 0, GFP_ATOMIC);

return 0;
}
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 6a43c34..8347500 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3856,6 +3856,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
* @sig_dbm: signal strength in mBm, or 0 if unknown
* @buf: Management frame (header + body)
* @len: length of the frame data
+ * @flags: flags, as defined in enum nl80211_rxmgmt_flags
* @gfp: context flags
*
* This function is called whenever an Action frame is received for a station
@@ -3867,7 +3868,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
* driver is responsible for rejecting the frame.
*/
bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_dbm,
- const u8 *buf, size_t len, gfp_t gfp);
+ const u8 *buf, size_t len, u32 flags, gfp_t gfp);

/**
* cfg80211_mgmt_tx_status - notification of TX status for management frame
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index ca6facf..f125d2c 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1436,6 +1436,8 @@ enum nl80211_commands {
* allowed to be used with the first @NL80211_CMD_SET_STATION command to
* update a TDLS peer STA entry.
*
+ * @NL80211_ATTR_RXMGMT_FLAGS: flags for cfg80211_rx_mgmt, u32
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1736,6 +1738,8 @@ enum nl80211_attrs {

NL80211_ATTR_PEER_AID,

+ NL80211_ATTR_RXMGMT_FLAGS,
+
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
@@ -3754,4 +3758,13 @@ enum nl80211_crit_proto_id {
/* maximum duration for critical protocol measures */
#define NL80211_CRIT_PROTO_MAX_DURATION 5000 /* msec */

+/**
+ * enum nl80211_rxmgmt_flags - flags for cfg80211_rx_mgmt
+ *
+ * @NL80211_RXMGMT_FLAG_REPLIED: frame was replied by device/driver.
+ */
+enum nl80211_rxmgmt_flags {
+ NL80211_RXMGMT_FLAG_REPLIED = (1 << 0),
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 23dbcfc..3f7fa49 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2635,8 +2635,7 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
sig = status->signal;

if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig,
- rx->skb->data, rx->skb->len,
- GFP_ATOMIC)) {
+ rx->skb->data, rx->skb->len, 0, GFP_ATOMIC)) {
if (rx->sta)
rx->sta->rx_packets++;
dev_kfree_skb(rx->skb);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index a61a44b..74b1856 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -615,7 +615,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
}

bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
- const u8 *buf, size_t len, gfp_t gfp)
+ const u8 *buf, size_t len, u32 flags, gfp_t gfp)
{
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
@@ -658,7 +658,7 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
/* Indicate the received Action frame to user space */
if (nl80211_send_mgmt(rdev, wdev, reg->nlportid,
freq, sig_mbm,
- buf, len, gfp))
+ buf, len, flags, gfp))
continue;

result = true;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 57be2f4..65c5578 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -9962,7 +9962,7 @@ EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u32 nlportid,
int freq, int sig_dbm,
- const u8 *buf, size_t len, gfp_t gfp)
+ const u8 *buf, size_t len, u32 flags, gfp_t gfp)
{
struct net_device *netdev = wdev->netdev;
struct sk_buff *msg;
@@ -9985,7 +9985,9 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
(sig_dbm &&
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
- nla_put(msg, NL80211_ATTR_FRAME, len, buf))
+ nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
+ (flags &&
+ nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags)))
goto nla_put_failure;

genlmsg_end(msg, hdr);
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index a4073e8..3b51a76 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -66,7 +66,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u32 nlpid,
int freq, int sig_dbm,
- const u8 *buf, size_t len, gfp_t gfp);
+ const u8 *buf, size_t len, u32 flags, gfp_t gfp);

void
nl80211_radar_notify(struct cfg80211_registered_device *rdev,
--
1.8.1.2