Commit e247bd90 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

cfg80211/mac80211: allow management TX to not wait for ACK

For probe responses it can be useful to not wait for ACK to
avoid retransmissions if the station that sent the probe is
already on the next channel, so allow userspace to request
not caring about the ACK with a new nl80211 flag.

Since mac80211 needs to be updated for the new function
prototype anyway implement it right away -- it's just a
few lines of code.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e7f4a940
...@@ -1732,7 +1732,8 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, ...@@ -1732,7 +1732,8 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan, bool offchan, struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait, bool channel_type_valid, unsigned int wait,
const u8 *buf, size_t len, bool no_cck, u64 *cookie) const u8 *buf, size_t len, bool no_cck,
bool dont_wait_for_ack, u64 *cookie)
{ {
struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl *ar = ath6kl_priv(dev);
u32 id; u32 id;
......
...@@ -1151,6 +1151,11 @@ enum nl80211_commands { ...@@ -1151,6 +1151,11 @@ enum nl80211_commands {
* with support for the features listed in this attribute, see * with support for the features listed in this attribute, see
* &enum nl80211_ap_sme_features. * &enum nl80211_ap_sme_features.
* *
* @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells
* the driver to not wait for an acknowledgement. Note that due to this,
* it will also not give a status callback nor return a cookie. This is
* mostly useful for probe responses to save airtime.
*
* @NL80211_ATTR_MAX: highest attribute number currently defined * @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use * @__NL80211_ATTR_AFTER_LAST: internal use
*/ */
...@@ -1381,6 +1386,8 @@ enum nl80211_attrs { ...@@ -1381,6 +1386,8 @@ enum nl80211_attrs {
NL80211_ATTR_DEVICE_AP_SME, NL80211_ATTR_DEVICE_AP_SME,
NL80211_ATTR_DONT_WAIT_FOR_ACK,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,
......
...@@ -1588,7 +1588,7 @@ struct cfg80211_ops { ...@@ -1588,7 +1588,7 @@ struct cfg80211_ops {
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait, bool channel_type_valid, unsigned int wait,
const u8 *buf, size_t len, bool no_cck, const u8 *buf, size_t len, bool no_cck,
u64 *cookie); bool dont_wait_for_ack, u64 *cookie);
int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy, int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
u64 cookie); u64 cookie);
......
...@@ -1936,7 +1936,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, ...@@ -1936,7 +1936,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait, bool channel_type_valid, unsigned int wait,
const u8 *buf, size_t len, bool no_cck, const u8 *buf, size_t len, bool no_cck,
u64 *cookie) bool dont_wait_for_ack, 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;
...@@ -1944,10 +1944,15 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, ...@@ -1944,10 +1944,15 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
struct sta_info *sta; struct sta_info *sta;
struct ieee80211_work *wk; struct ieee80211_work *wk;
const struct ieee80211_mgmt *mgmt = (void *)buf; const struct ieee80211_mgmt *mgmt = (void *)buf;
u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | u32 flags;
IEEE80211_TX_CTL_REQ_TX_STATUS;
bool is_offchan = false; bool is_offchan = false;
if (dont_wait_for_ack)
flags = IEEE80211_TX_CTL_NO_ACK;
else
flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
IEEE80211_TX_CTL_REQ_TX_STATUS;
/* Check that we are on the requested channel for transmission */ /* Check that we are on the requested channel for transmission */
if (chan != local->tmp_channel && if (chan != local->tmp_channel &&
chan != local->oper_channel) chan != local->oper_channel)
......
...@@ -378,7 +378,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, ...@@ -378,7 +378,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait, bool channel_type_valid, unsigned int wait,
const u8 *buf, size_t len, bool no_cck, const u8 *buf, size_t len, bool no_cck,
u64 *cookie); bool dont_wait_for_ack, u64 *cookie);
/* SME */ /* SME */
int __cfg80211_connect(struct cfg80211_registered_device *rdev, int __cfg80211_connect(struct cfg80211_registered_device *rdev,
......
...@@ -904,7 +904,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, ...@@ -904,7 +904,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait, bool channel_type_valid, unsigned int wait,
const u8 *buf, size_t len, bool no_cck, const u8 *buf, size_t len, bool no_cck,
u64 *cookie) bool dont_wait_for_ack, u64 *cookie)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
const struct ieee80211_mgmt *mgmt; const struct ieee80211_mgmt *mgmt;
...@@ -995,7 +995,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, ...@@ -995,7 +995,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
/* Transmit the Action frame as requested by user space */ /* Transmit the Action frame as requested by user space */
return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan, return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan,
channel_type, channel_type_valid, channel_type, channel_type_valid,
wait, buf, len, no_cck, cookie); wait, buf, len, no_cck, dont_wait_for_ack,
cookie);
} }
bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
......
...@@ -196,6 +196,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { ...@@ -196,6 +196,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 }, [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
[NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG }, [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
[NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG }, [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
[NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
}; };
/* policy for the key attributes */ /* policy for the key attributes */
...@@ -5282,10 +5283,11 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) ...@@ -5282,10 +5283,11 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
int err; int err;
void *hdr; void *hdr;
u64 cookie; u64 cookie;
struct sk_buff *msg; struct sk_buff *msg = NULL;
unsigned int wait = 0; unsigned int wait = 0;
bool offchan; bool offchan, no_cck, dont_wait_for_ack;
bool no_cck;
dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK];
if (!info->attrs[NL80211_ATTR_FRAME] || if (!info->attrs[NL80211_ATTR_FRAME] ||
!info->attrs[NL80211_ATTR_WIPHY_FREQ]) !info->attrs[NL80211_ATTR_WIPHY_FREQ])
...@@ -5329,29 +5331,36 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) ...@@ -5329,29 +5331,36 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
if (chan == NULL) if (chan == NULL)
return -EINVAL; return -EINVAL;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!dont_wait_for_ack) {
if (!msg) msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
return -ENOMEM; if (!msg)
return -ENOMEM;
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
NL80211_CMD_FRAME); NL80211_CMD_FRAME);
if (IS_ERR(hdr)) { if (IS_ERR(hdr)) {
err = PTR_ERR(hdr); err = PTR_ERR(hdr);
goto free_msg; goto free_msg;
}
} }
err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type, err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type,
channel_type_valid, wait, channel_type_valid, wait,
nla_data(info->attrs[NL80211_ATTR_FRAME]), nla_data(info->attrs[NL80211_ATTR_FRAME]),
nla_len(info->attrs[NL80211_ATTR_FRAME]), nla_len(info->attrs[NL80211_ATTR_FRAME]),
no_cck, &cookie); no_cck, dont_wait_for_ack, &cookie);
if (err) if (err)
goto free_msg; goto free_msg;
NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); if (msg) {
NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
genlmsg_end(msg, hdr); genlmsg_end(msg, hdr);
return genlmsg_reply(msg, info); return genlmsg_reply(msg, info);
}
return 0;
nla_put_failure: nla_put_failure:
err = -ENOBUFS; err = -ENOBUFS;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment