aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/work.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/work.c')
-rw-r--r--net/mac80211/work.c62
1 files changed, 50 insertions, 12 deletions
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index 15e1ba931b8..be3d4a69869 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -33,6 +33,7 @@
33#define IEEE80211_MAX_PROBE_TRIES 5 33#define IEEE80211_MAX_PROBE_TRIES 5
34 34
35enum work_action { 35enum work_action {
36 WORK_ACT_MISMATCH,
36 WORK_ACT_NONE, 37 WORK_ACT_NONE,
37 WORK_ACT_TIMEOUT, 38 WORK_ACT_TIMEOUT,
38 WORK_ACT_DONE, 39 WORK_ACT_DONE,
@@ -213,15 +214,25 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
213 214
214 sband = local->hw.wiphy->bands[wk->chan->band]; 215 sband = local->hw.wiphy->bands[wk->chan->band];
215 216
216 /* 217 if (wk->assoc.supp_rates_len) {
217 * Get all rates supported by the device and the AP as 218 /*
218 * some APs don't like getting a superset of their rates 219 * Get all rates supported by the device and the AP as
219 * in the association request (e.g. D-Link DAP 1353 in 220 * some APs don't like getting a superset of their rates
220 * b-only mode)... 221 * in the association request (e.g. D-Link DAP 1353 in
221 */ 222 * b-only mode)...
222 rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates, 223 */
223 wk->assoc.supp_rates_len, 224 rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates,
224 sband, &rates); 225 wk->assoc.supp_rates_len,
226 sband, &rates);
227 } else {
228 /*
229 * In case AP not provide any supported rates information
230 * before association, we send information element(s) with
231 * all rates that we support.
232 */
233 rates = ~0;
234 rates_len = sband->n_bitrates;
235 }
225 236
226 skb = alloc_skb(local->hw.extra_tx_headroom + 237 skb = alloc_skb(local->hw.extra_tx_headroom +
227 sizeof(*mgmt) + /* bit too much but doesn't matter */ 238 sizeof(*mgmt) + /* bit too much but doesn't matter */
@@ -575,7 +586,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_work *wk,
575 u16 auth_alg, auth_transaction, status_code; 586 u16 auth_alg, auth_transaction, status_code;
576 587
577 if (wk->type != IEEE80211_WORK_AUTH) 588 if (wk->type != IEEE80211_WORK_AUTH)
578 return WORK_ACT_NONE; 589 return WORK_ACT_MISMATCH;
579 590
580 if (len < 24 + 6) 591 if (len < 24 + 6)
581 return WORK_ACT_NONE; 592 return WORK_ACT_NONE;
@@ -626,6 +637,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk,
626 struct ieee802_11_elems elems; 637 struct ieee802_11_elems elems;
627 u8 *pos; 638 u8 *pos;
628 639
640 if (wk->type != IEEE80211_WORK_ASSOC)
641 return WORK_ACT_MISMATCH;
642
629 /* 643 /*
630 * AssocResp and ReassocResp have identical structure, so process both 644 * AssocResp and ReassocResp have identical structure, so process both
631 * of them in this function. 645 * of them in this function.
@@ -681,6 +695,12 @@ ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk,
681 695
682 ASSERT_WORK_MTX(local); 696 ASSERT_WORK_MTX(local);
683 697
698 if (wk->type != IEEE80211_WORK_DIRECT_PROBE)
699 return WORK_ACT_MISMATCH;
700
701 if (len < 24 + 12)
702 return WORK_ACT_NONE;
703
684 baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; 704 baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
685 if (baselen > len) 705 if (baselen > len)
686 return WORK_ACT_NONE; 706 return WORK_ACT_NONE;
@@ -695,7 +715,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
695 struct ieee80211_rx_status *rx_status; 715 struct ieee80211_rx_status *rx_status;
696 struct ieee80211_mgmt *mgmt; 716 struct ieee80211_mgmt *mgmt;
697 struct ieee80211_work *wk; 717 struct ieee80211_work *wk;
698 enum work_action rma = WORK_ACT_NONE; 718 enum work_action rma;
699 u16 fc; 719 u16 fc;
700 720
701 rx_status = (struct ieee80211_rx_status *) skb->cb; 721 rx_status = (struct ieee80211_rx_status *) skb->cb;
@@ -742,7 +762,17 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
742 break; 762 break;
743 default: 763 default:
744 WARN_ON(1); 764 WARN_ON(1);
765 rma = WORK_ACT_NONE;
745 } 766 }
767
768 /*
769 * We've either received an unexpected frame, or we have
770 * multiple work items and need to match the frame to the
771 * right one.
772 */
773 if (rma == WORK_ACT_MISMATCH)
774 continue;
775
746 /* 776 /*
747 * We've processed this frame for that work, so it can't 777 * We've processed this frame for that work, so it can't
748 * belong to another work struct. 778 * belong to another work struct.
@@ -752,6 +782,9 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
752 } 782 }
753 783
754 switch (rma) { 784 switch (rma) {
785 case WORK_ACT_MISMATCH:
786 /* ignore this unmatched frame */
787 break;
755 case WORK_ACT_NONE: 788 case WORK_ACT_NONE:
756 break; 789 break;
757 case WORK_ACT_DONE: 790 case WORK_ACT_DONE:
@@ -920,11 +953,16 @@ static void ieee80211_work_work(struct work_struct *work)
920 run_again(local, jiffies + HZ/2); 953 run_again(local, jiffies + HZ/2);
921 } 954 }
922 955
923 if (list_empty(&local->work_list) && local->scan_req) 956 mutex_lock(&local->scan_mtx);
957
958 if (list_empty(&local->work_list) && local->scan_req &&
959 !local->scanning)
924 ieee80211_queue_delayed_work(&local->hw, 960 ieee80211_queue_delayed_work(&local->hw,
925 &local->scan_work, 961 &local->scan_work,
926 round_jiffies_relative(0)); 962 round_jiffies_relative(0));
927 963
964 mutex_unlock(&local->scan_mtx);
965
928 mutex_unlock(&local->work_mtx); 966 mutex_unlock(&local->work_mtx);
929 967
930 ieee80211_recalc_idle(local); 968 ieee80211_recalc_idle(local);