diff mbox

{cfg,nl}80211: tx_mgmt: use current bss channel if omitted.

Message ID 1359738683-13499-1-git-send-email-cavallar@lri.fr (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Nicolas Cavallari Feb. 1, 2013, 5:11 p.m. UTC
Allow not specifying the channel when transmitting a management frame.
This allows user space code to not track the current channel.  This is
especially useful in IBSS mode, because userspace is not informed when
the channel changes because of a merge and requesting the current
channel before using it can introduce races.

Signed-off-by: Nicolas Cavallari <cavallar@lri.fr>
---
 net/wireless/mlme.c    |   14 ++++++++++++++
 net/wireless/nl80211.c |   13 ++++++++++---
 2 files changed, 24 insertions(+), 3 deletions(-)

Comments

Johannes Berg Feb. 4, 2013, 4:04 p.m. UTC | #1
On Fri, 2013-02-01 at 18:11 +0100, Nicolas Cavallari wrote:
> Allow not specifying the channel when transmitting a management frame.
> This allows user space code to not track the current channel.  This is
> especially useful in IBSS mode, because userspace is not informed when
> the channel changes because of a merge and requesting the current
> channel before using it can introduce races.


> @@ -836,10 +837,23 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
>  			err = -EOPNOTSUPP;
>  			break;
>  		}
> +		if (!err && chan == NULL) {
> +			cfg80211_get_chan_state(wdev, &chan, &chan_mode);

I'm not sure this is the best way of handling it. Is there a reason to
not pass NULL through to the driver(s) (and audit them) instead? This
channel access could be racy for channel changes still, etc.

johannes

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Nicolas Cavallari Feb. 4, 2013, 5:15 p.m. UTC | #2
On 04/02/2013 17:04, Johannes Berg wrote:
> On Fri, 2013-02-01 at 18:11 +0100, Nicolas Cavallari wrote:
>> Allow not specifying the channel when transmitting a management frame.
>> This allows user space code to not track the current channel.  This is
>> especially useful in IBSS mode, because userspace is not informed when
>> the channel changes because of a merge and requesting the current
>> channel before using it can introduce races.
> 
> 
>> @@ -836,10 +837,23 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
>>  			err = -EOPNOTSUPP;
>>  			break;
>>  		}
>> +		if (!err && chan == NULL) {
>> +			cfg80211_get_chan_state(wdev, &chan, &chan_mode);
> 
> I'm not sure this is the best way of handling it. Is there a reason to
> not pass NULL through to the driver(s) (and audit them) instead? This
> channel access could be racy for channel changes still, etc.

I couldn't understand how tracing would work with NULL arguments, and while most of the
drivers totally ignore the channel argument or does not read it when offchan is false, the
ath6kl driver actually uses the given channel and ignores the offchannel argument.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 461e692..8dc3f46 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -757,6 +757,7 @@  int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
 {
 	const struct ieee80211_mgmt *mgmt;
 	u16 stype;
+	enum cfg80211_chan_mode chan_mode;
 
 	if (!wdev->wiphy->mgmt_stypes)
 		return -EOPNOTSUPP;
@@ -836,10 +837,23 @@  int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
 			err = -EOPNOTSUPP;
 			break;
 		}
+		if (!err && chan == NULL) {
+			cfg80211_get_chan_state(wdev, &chan, &chan_mode);
+			if (!chan)
+				err = -ENOTCONN;
+		}
 		wdev_unlock(wdev);
 
 		if (err)
 			return err;
+	} else {
+		if (chan == NULL) {
+			wdev_lock(wdev);
+			cfg80211_get_chan_state(wdev, &chan, &chan_mode);
+			wdev_unlock(wdev);
+			if (!chan)
+				return -ENOTCONN;
+		}
 	}
 
 	if (!ether_addr_equal(mgmt->sa, wdev_address(wdev)))
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index b5978ab..f22c35e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6564,9 +6564,16 @@  static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
 
 	no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
 
-	err = nl80211_parse_chandef(rdev, info, &chandef);
-	if (err)
-		return err;
+	if (info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
+	    info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+		err = nl80211_parse_chandef(rdev, info, &chandef);
+		if (err)
+			return err;
+	} else {
+		if (offchan)
+			return -EINVAL;
+		chandef.chan = NULL;
+	}
 
 	if (!dont_wait_for_ack) {
 		msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);