diff options
author | Jouni Malinen <jouni@qca.qualcomm.com> | 2011-10-27 09:00:13 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2011-11-11 05:58:55 -0500 |
commit | 1052261e4bba9879c1d7d519c8e8606c5d4264d5 (patch) | |
tree | 386a1c7c51e25021156174632fed554d870b2d68 /drivers | |
parent | f7830202c3ae934e2b978b750656626b203decb4 (diff) |
ath6kl: Report unique remain-on-channel cookie values
Even though only a single concurrent remain-on-channel operation is
supported, there may be two pending remain-on-channel events (one to
indicate end of a canceled operation and another to indicate start of a
new operation). User space won't be able to distinguish these events
unless unique cookies are used.
The previous behavior resulted in wpa_supplicant getting quite
confused about the driver's offchannel state in various sequences
and this made the P2P state machine behave incorrectly. Use of
more than a single remain-on-channel cookie value fixes this.
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/core.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/wmi.c | 13 |
3 files changed, 22 insertions, 4 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index a563fdf891da..940aeb69d20c 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -1932,10 +1932,16 @@ static int ath6kl_remain_on_channel(struct wiphy *wiphy, | |||
1932 | { | 1932 | { |
1933 | struct ath6kl *ar = ath6kl_priv(dev); | 1933 | struct ath6kl *ar = ath6kl_priv(dev); |
1934 | struct ath6kl_vif *vif = netdev_priv(dev); | 1934 | struct ath6kl_vif *vif = netdev_priv(dev); |
1935 | u32 id; | ||
1935 | 1936 | ||
1936 | /* TODO: if already pending or ongoing remain-on-channel, | 1937 | /* TODO: if already pending or ongoing remain-on-channel, |
1937 | * return -EBUSY */ | 1938 | * return -EBUSY */ |
1938 | *cookie = 1; /* only a single pending request is supported */ | 1939 | id = ++vif->last_roc_id; |
1940 | if (id == 0) { | ||
1941 | /* Do not use 0 as the cookie value */ | ||
1942 | id = ++vif->last_roc_id; | ||
1943 | } | ||
1944 | *cookie = id; | ||
1939 | 1945 | ||
1940 | return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx, | 1946 | return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx, |
1941 | chan->center_freq, duration); | 1947 | chan->center_freq, duration); |
@@ -1948,8 +1954,9 @@ static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy, | |||
1948 | struct ath6kl *ar = ath6kl_priv(dev); | 1954 | struct ath6kl *ar = ath6kl_priv(dev); |
1949 | struct ath6kl_vif *vif = netdev_priv(dev); | 1955 | struct ath6kl_vif *vif = netdev_priv(dev); |
1950 | 1956 | ||
1951 | if (cookie != 1) | 1957 | if (cookie != vif->last_roc_id) |
1952 | return -ENOENT; | 1958 | return -ENOENT; |
1959 | vif->last_cancel_roc_id = cookie; | ||
1953 | 1960 | ||
1954 | return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx); | 1961 | return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx); |
1955 | } | 1962 | } |
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 97d7f11d425d..5ac415ee9243 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h | |||
@@ -427,6 +427,8 @@ struct ath6kl_vif { | |||
427 | struct cfg80211_scan_request *scan_req; | 427 | struct cfg80211_scan_request *scan_req; |
428 | enum sme_state sme_state; | 428 | enum sme_state sme_state; |
429 | int reconnect_flag; | 429 | int reconnect_flag; |
430 | u32 last_roc_id; | ||
431 | u32 last_cancel_roc_id; | ||
430 | u32 send_action_id; | 432 | u32 send_action_id; |
431 | bool probe_req_report; | 433 | bool probe_req_report; |
432 | u16 next_chan; | 434 | u16 next_chan; |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index e6b0960ef430..ddefc8e4a66b 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c | |||
@@ -443,6 +443,7 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap, | |||
443 | u32 dur; | 443 | u32 dur; |
444 | struct ieee80211_channel *chan; | 444 | struct ieee80211_channel *chan; |
445 | struct ath6kl *ar = wmi->parent_dev; | 445 | struct ath6kl *ar = wmi->parent_dev; |
446 | u32 id; | ||
446 | 447 | ||
447 | if (len < sizeof(*ev)) | 448 | if (len < sizeof(*ev)) |
448 | return -EINVAL; | 449 | return -EINVAL; |
@@ -458,7 +459,8 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap, | |||
458 | "(freq=%u)\n", freq); | 459 | "(freq=%u)\n", freq); |
459 | return -EINVAL; | 460 | return -EINVAL; |
460 | } | 461 | } |
461 | cfg80211_ready_on_channel(vif->ndev, 1, chan, NL80211_CHAN_NO_HT, | 462 | id = vif->last_roc_id; |
463 | cfg80211_ready_on_channel(vif->ndev, id, chan, NL80211_CHAN_NO_HT, | ||
462 | dur, GFP_ATOMIC); | 464 | dur, GFP_ATOMIC); |
463 | 465 | ||
464 | return 0; | 466 | return 0; |
@@ -473,6 +475,7 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi, | |||
473 | u32 dur; | 475 | u32 dur; |
474 | struct ieee80211_channel *chan; | 476 | struct ieee80211_channel *chan; |
475 | struct ath6kl *ar = wmi->parent_dev; | 477 | struct ath6kl *ar = wmi->parent_dev; |
478 | u32 id; | ||
476 | 479 | ||
477 | if (len < sizeof(*ev)) | 480 | if (len < sizeof(*ev)) |
478 | return -EINVAL; | 481 | return -EINVAL; |
@@ -488,7 +491,13 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi, | |||
488 | "channel (freq=%u)\n", freq); | 491 | "channel (freq=%u)\n", freq); |
489 | return -EINVAL; | 492 | return -EINVAL; |
490 | } | 493 | } |
491 | cfg80211_remain_on_channel_expired(vif->ndev, 1, chan, | 494 | if (vif->last_cancel_roc_id && |
495 | vif->last_cancel_roc_id + 1 == vif->last_roc_id) | ||
496 | id = vif->last_cancel_roc_id; /* event for cancel command */ | ||
497 | else | ||
498 | id = vif->last_roc_id; /* timeout on uncanceled r-o-c */ | ||
499 | vif->last_cancel_roc_id = 0; | ||
500 | cfg80211_remain_on_channel_expired(vif->ndev, id, chan, | ||
492 | NL80211_CHAN_NO_HT, GFP_ATOMIC); | 501 | NL80211_CHAN_NO_HT, GFP_ATOMIC); |
493 | 502 | ||
494 | return 0; | 503 | return 0; |