diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2010-05-11 06:42:04 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-05-12 16:28:52 -0400 |
commit | b8d92c9c141ee3dc9b3537b1f0ffb4a54ea8d9b2 (patch) | |
tree | 9dee2ac8738e17242e2c891e8941dd43ca9c9189 /net | |
parent | 562db532760827f6ce30801a08e6b568848bc9f2 (diff) |
mac80211: don't process work item with wrong frame
When we process a frame, we currently just match it
to the work struct by the MAC addresses, and not by
the work type. This means that we can end up doing
the work for an association request item when (for
whatever reason) we receive another frame type, for
example a probe response. Processing the wrong type
of frame will lead to completely invalid data being
processed, and will lead to various problems like
thinking the association was successful even if the
AP never sent an assocation response.
Fix this by making each processing function check
that it is invoked for the right work struct type
only and continue processing otherwise (and drop
frames that we didn't expect).
This bug was uncovered during the debugging for
https://bugzilla.kernel.org/show_bug.cgi?id=15862
but doesn't seem to be the cause for any of the
various problems reported there.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/work.c | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 1e1ea3007b06..b0ba58589ca3 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #define IEEE80211_MAX_PROBE_TRIES 5 | 32 | #define IEEE80211_MAX_PROBE_TRIES 5 |
33 | 33 | ||
34 | enum work_action { | 34 | enum work_action { |
35 | WORK_ACT_MISMATCH, | ||
35 | WORK_ACT_NONE, | 36 | WORK_ACT_NONE, |
36 | WORK_ACT_TIMEOUT, | 37 | WORK_ACT_TIMEOUT, |
37 | WORK_ACT_DONE, | 38 | WORK_ACT_DONE, |
@@ -574,7 +575,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_work *wk, | |||
574 | u16 auth_alg, auth_transaction, status_code; | 575 | u16 auth_alg, auth_transaction, status_code; |
575 | 576 | ||
576 | if (wk->type != IEEE80211_WORK_AUTH) | 577 | if (wk->type != IEEE80211_WORK_AUTH) |
577 | return WORK_ACT_NONE; | 578 | return WORK_ACT_MISMATCH; |
578 | 579 | ||
579 | if (len < 24 + 6) | 580 | if (len < 24 + 6) |
580 | return WORK_ACT_NONE; | 581 | return WORK_ACT_NONE; |
@@ -625,6 +626,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk, | |||
625 | struct ieee802_11_elems elems; | 626 | struct ieee802_11_elems elems; |
626 | u8 *pos; | 627 | u8 *pos; |
627 | 628 | ||
629 | if (wk->type != IEEE80211_WORK_ASSOC) | ||
630 | return WORK_ACT_MISMATCH; | ||
631 | |||
628 | /* | 632 | /* |
629 | * AssocResp and ReassocResp have identical structure, so process both | 633 | * AssocResp and ReassocResp have identical structure, so process both |
630 | * of them in this function. | 634 | * of them in this function. |
@@ -680,6 +684,12 @@ ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk, | |||
680 | 684 | ||
681 | ASSERT_WORK_MTX(local); | 685 | ASSERT_WORK_MTX(local); |
682 | 686 | ||
687 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE) | ||
688 | return WORK_ACT_MISMATCH; | ||
689 | |||
690 | if (len < 24 + 12) | ||
691 | return WORK_ACT_NONE; | ||
692 | |||
683 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; | 693 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; |
684 | if (baselen > len) | 694 | if (baselen > len) |
685 | return WORK_ACT_NONE; | 695 | return WORK_ACT_NONE; |
@@ -694,7 +704,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, | |||
694 | struct ieee80211_rx_status *rx_status; | 704 | struct ieee80211_rx_status *rx_status; |
695 | struct ieee80211_mgmt *mgmt; | 705 | struct ieee80211_mgmt *mgmt; |
696 | struct ieee80211_work *wk; | 706 | struct ieee80211_work *wk; |
697 | enum work_action rma = WORK_ACT_NONE; | 707 | enum work_action rma; |
698 | u16 fc; | 708 | u16 fc; |
699 | 709 | ||
700 | rx_status = (struct ieee80211_rx_status *) skb->cb; | 710 | rx_status = (struct ieee80211_rx_status *) skb->cb; |
@@ -741,7 +751,17 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, | |||
741 | break; | 751 | break; |
742 | default: | 752 | default: |
743 | WARN_ON(1); | 753 | WARN_ON(1); |
754 | rma = WORK_ACT_NONE; | ||
744 | } | 755 | } |
756 | |||
757 | /* | ||
758 | * We've either received an unexpected frame, or we have | ||
759 | * multiple work items and need to match the frame to the | ||
760 | * right one. | ||
761 | */ | ||
762 | if (rma == WORK_ACT_MISMATCH) | ||
763 | continue; | ||
764 | |||
745 | /* | 765 | /* |
746 | * We've processed this frame for that work, so it can't | 766 | * We've processed this frame for that work, so it can't |
747 | * belong to another work struct. | 767 | * belong to another work struct. |
@@ -751,6 +771,9 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, | |||
751 | } | 771 | } |
752 | 772 | ||
753 | switch (rma) { | 773 | switch (rma) { |
774 | case WORK_ACT_MISMATCH: | ||
775 | /* ignore this unmatched frame */ | ||
776 | break; | ||
754 | case WORK_ACT_NONE: | 777 | case WORK_ACT_NONE: |
755 | break; | 778 | break; |
756 | case WORK_ACT_DONE: | 779 | case WORK_ACT_DONE: |