From a66b98db570a638afd909459e1e6bfa272344bd3 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 23 Jun 2011 00:00:24 +0300 Subject: mac80211: fix rx->key NULL dereference during mic failure Sometimes when reporting a MIC failure rx->key may be unset. This code path is hit when receiving a packet meant for a multicast address, and decryption is performed in HW. Fortunately, the failing key_idx is not used for anything up to (and including) usermode, so we allow ourselves to drop it on the way up when a key cannot be retrieved. Signed-off-by: Arik Nemtsov Cc: stable@kernel.org Signed-off-by: John W. Linville --- net/mac80211/wpa.c | 8 +++++++- net/wireless/nl80211.c | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 9dc3b5f26e8..d91c1a26630 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -154,7 +154,13 @@ update_iv: return RX_CONTINUE; mic_fail: - mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, + /* + * In some cases the key can be unset - e.g. a multicast packet, in + * a driver that supports HW encryption. Send up the key idx only if + * the key is set. + */ + mac80211_ev_michael_mic_failure(rx->sdata, + rx->key ? rx->key->conf.keyidx : -1, (void *) skb->data, NULL, GFP_ATOMIC); return RX_DROP_UNUSABLE; } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 98fa8eb6cc4..f07602d7bf6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6463,7 +6463,8 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, if (addr) NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type); - NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); + if (key_id != -1) + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); if (tsc) NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); -- cgit v1.2.3-18-g5258 From 04b7dcf979d71e870683c804802e44287a802760 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Jun 2011 10:06:59 +0200 Subject: wireless: unify QoS control field definitions Move all that mac80211 has into the generic ieee80211.h header file and use them. At the same time move them from mask+shift to just bits and rename them for consistent names. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 2 +- net/mac80211/wme.c | 3 +-- net/mac80211/wme.h | 5 ----- 3 files changed, 2 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7fa8c6be7bf..b5493ecd1e9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -338,7 +338,7 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) u8 *qc = ieee80211_get_qos_ctl(hdr); /* frame has qos control */ tid = *qc & IEEE80211_QOS_CTL_TID_MASK; - if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) + if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT) status->rx_flags |= IEEE80211_RX_AMSDU; } else { /* diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 28bc084dbfb..7a49532f14c 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -151,8 +151,7 @@ void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb) tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; if (unlikely(local->wifi_wme_noack_test)) - ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK << - QOS_CONTROL_ACK_POLICY_SHIFT; + ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK; /* qos header is 2 bytes, second reserved */ *p++ = ack_policy | tid; *p = 0; diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index 6053b1c9fee..faead6d0202 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h @@ -13,11 +13,6 @@ #include #include "ieee80211_i.h" -#define QOS_CONTROL_ACK_POLICY_NORMAL 0 -#define QOS_CONTROL_ACK_POLICY_NOACK 1 - -#define QOS_CONTROL_ACK_POLICY_SHIFT 5 - extern const int ieee802_1d_to_ac[8]; u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, -- cgit v1.2.3-18-g5258 From 8ee3108075c9e9e2701493a245a754b8b0db8e57 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Jun 2011 16:43:48 +0200 Subject: mac80211: restrict advertised HW scan rates Advertise only user-requested bitrates in a HW scan. Note that the hw_scan API doesn't currently have a way of asking for a specific probe request bitrate, so we might end up using a bitrate that we don't advertise as supported. I'll fix that later. Also add a hexdump printk to hwsim to verify this. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/scan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 1758b463c58..6403722da60 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -228,6 +228,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) { struct cfg80211_scan_request *req = local->scan_req; + struct ieee80211_sub_if_data *sdata = local->scan_sdata; enum ieee80211_band band; int i, ielen, n_chans; @@ -251,8 +252,8 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) local->hw_scan_req->n_channels = n_chans; ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, - req->ie, req->ie_len, band, (u32) -1, - 0); + req->ie, req->ie_len, band, + sdata->rc_rateidx_mask[band], 0); local->hw_scan_req->ie_len = ielen; return true; -- cgit v1.2.3-18-g5258 From daf4ce85cd5221a3609e68419d01730170975e94 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 22 Jun 2011 10:08:11 -0700 Subject: bluetooth: uses crypto interfaces, select CRYPTO Recent changes to hci_core.c use crypto interfaces, so select CRYPTO to make sure that those interfaces are present. Fixes these build errors when CRYPTO is not enabled: net/built-in.o: In function `hci_register_dev': (.text+0x4cf86): undefined reference to `crypto_alloc_base' net/built-in.o: In function `hci_unregister_dev': (.text+0x4f912): undefined reference to `crypto_destroy_tfm' Signed-off-by: Randy Dunlap Signed-off-by: John W. Linville --- net/bluetooth/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index f495dea741e..bfb3dc03c9d 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -6,6 +6,7 @@ menuconfig BT tristate "Bluetooth subsystem support" depends on NET && !S390 depends on RFKILL || !RFKILL + select CRYPTO help Bluetooth is low-cost, low-power, short-range wireless technology. It was designed as a replacement for cables and other short-range -- cgit v1.2.3-18-g5258 From 15b4d843ab66bc0ac2cd46baa20a3ce9638604e6 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 23 Jun 2011 01:15:27 +0300 Subject: mac80211: reestablish mis-configured existing Rx BA sessions When forming a Rx BA session, sometimes the ADDBA response gets lost. This leads to a situation where the session is configured locally, but doesn't exist on the remote side. Subsequent ADDBA requests are declined by mac80211. Fix this by assuming the session state of the initiator is the correct one. When receiving an unexpected ADDBA request on a TID with an active Rx BA session, delete the existing one and establish a new session. Signed-off-by: Arik Nemtsov Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/agg-rx.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 89b0b2ca6db..ebadb9ac9a7 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -262,7 +262,11 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, "%pM on tid %u\n", mgmt->sa, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - goto end; + + /* delete existing Rx BA session on the same tid */ + ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, + WLAN_STATUS_UNSPECIFIED_QOS, + false); } /* prepare A-MPDU MLME for Rx aggregation */ -- cgit v1.2.3-18-g5258 From a806c558e01747b499201d2667818f03d79ef1e3 Mon Sep 17 00:00:00 2001 From: Paul Stewart Date: Thu, 23 Jun 2011 09:00:11 -0800 Subject: mac80211: Drop DS Channel PARAM in directed probe Do not send DS Channel parameter for directed probe requests in order to maximize the chance that we get a response. Some badly-behaved APs don't respond when this parameter is included. Signed-off-by: Paul Stewart Reviewed-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 6 ++++-- net/mac80211/mlme.c | 5 +++-- net/mac80211/scan.c | 3 ++- net/mac80211/util.c | 21 ++++++++++++++++----- net/mac80211/work.c | 2 +- 5 files changed, 26 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 090b0ec1e05..25c15cc6331 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1350,10 +1350,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len); + const u8 *ie, size_t ie_len, + bool directed); void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len); + const u8 *ie, size_t ie_len, + bool directed); void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, const size_t supp_rates_len, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index faca5033f06..0f6052faeb4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1204,7 +1204,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) ieee80211_send_nullfunc(sdata->local, sdata, 0); } else { ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); - ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); + ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0, + true); } ifmgd->probe_send_count++; @@ -1289,7 +1290,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, - ssid + 2, ssid[1], NULL, 0); + ssid + 2, ssid[1], NULL, 0, true); return skb; } diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 6403722da60..e5a6ea4a94e 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -659,7 +659,8 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, sdata, NULL, local->scan_req->ssids[i].ssid, local->scan_req->ssids[i].ssid_len, - local->scan_req->ie, local->scan_req->ie_len); + local->scan_req->ie, local->scan_req->ie_len, + false); /* * After sending probe requests, wait for probe responses diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 05e3fb889d7..652e5695225 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1018,7 +1018,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len) + const u8 *ie, size_t ie_len, + bool directed) { struct ieee80211_local *local = sdata->local; struct sk_buff *skb; @@ -1035,8 +1036,16 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, return NULL; } - chan = ieee80211_frequency_to_channel( - local->hw.conf.channel->center_freq); + /* + * Do not send DS Channel parameter for directed probe requests + * in order to maximize the chance that we get a response. Some + * badly-behaved APs don't respond when this parameter is included. + */ + if (directed) + chan = 0; + else + chan = ieee80211_frequency_to_channel( + local->hw.conf.channel->center_freq); buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, local->hw.conf.channel->band, @@ -1062,11 +1071,13 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len) + const u8 *ie, size_t ie_len, + bool directed) { struct sk_buff *skb; - skb = ieee80211_build_probe_req(sdata, dst, ssid, ssid_len, ie, ie_len); + skb = ieee80211_build_probe_req(sdata, dst, ssid, ssid_len, ie, ie_len, + directed); if (skb) ieee80211_tx_skb(sdata, skb); } diff --git a/net/mac80211/work.c b/net/mac80211/work.c index d2e7f0e8667..edf8583280c 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -450,7 +450,7 @@ ieee80211_direct_probe(struct ieee80211_work *wk) * will not answer to direct packet in unassociated state. */ ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid, - wk->probe_auth.ssid_len, NULL, 0); + wk->probe_auth.ssid_len, NULL, 0, true); wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; run_again(local, wk->timeout); -- cgit v1.2.3-18-g5258 From 77b7023afe93b5e3bdcf2c0faaa5e5caafb6ef44 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 26 Jun 2011 12:06:54 +0300 Subject: mac80211: dynamic PS - don't enter PS when TX frames are pending Use the tx_frames_pending() driver callback to determine if Tx frames are pending for its internal queues. If so postpone the dynamic PS timeout to avoid interrupting Tx traffic. The commit e8306f989483e4b97a8b37dd268de6c8c6f35e75 enabled this behavior for drivers with IEEE80211_HW_PS_NULLFUNC_STACK. We enable this for all drivers supporting dynamic PS. This patch helps improve performance in noisy environments. Signed-off-by: Arik Nemtsov Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0f6052faeb4..b87420088c3 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -760,23 +760,34 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) if (local->hw.conf.flags & IEEE80211_CONF_PS) return; - /* - * transmission can be stopped by others which leads to - * dynamic_ps_timer expiry. Postpond the ps timer if it - * is not the actual idle state. - */ - spin_lock_irqsave(&local->queue_stop_reason_lock, flags); - for (q = 0; q < local->hw.queues; q++) { - if (local->queue_stop_reasons[q]) { - spin_unlock_irqrestore(&local->queue_stop_reason_lock, - flags); + if (!local->disable_dynamic_ps && + local->hw.conf.dynamic_ps_timeout > 0) { + /* don't enter PS if TX frames are pending */ + if (drv_tx_frames_pending(local)) { mod_timer(&local->dynamic_ps_timer, jiffies + msecs_to_jiffies( local->hw.conf.dynamic_ps_timeout)); return; } + + /* + * transmission can be stopped by others which leads to + * dynamic_ps_timer expiry. Postpone the ps timer if it + * is not the actual idle state. + */ + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + for (q = 0; q < local->hw.queues; q++) { + if (local->queue_stop_reasons[q]) { + spin_unlock_irqrestore(&local->queue_stop_reason_lock, + flags); + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies( + local->hw.conf.dynamic_ps_timeout)); + return; + } + } + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); } - spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { @@ -801,7 +812,8 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); } - netif_tx_wake_all_queues(sdata->dev); + if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) + netif_tx_wake_all_queues(sdata->dev); } void ieee80211_dynamic_ps_timer(unsigned long data) -- cgit v1.2.3-18-g5258 From 39df600aa6ac027b53c4ce3089cba57467a960df Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 27 Jun 2011 23:58:45 +0300 Subject: mac80211: propagate information about STA WME support down Add a memeber to the ieee80211_sta structure to indicate whether the STA supports WME. Signed-off-by: Arik Nemtsov Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6e56c6ee7cc..9fe22cc393c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -674,8 +674,11 @@ static void sta_apply_parameters(struct ieee80211_local *local, if (mask & BIT(NL80211_STA_FLAG_WME)) { sta->flags &= ~WLAN_STA_WME; - if (set & BIT(NL80211_STA_FLAG_WME)) + sta->sta.wme = false; + if (set & BIT(NL80211_STA_FLAG_WME)) { sta->flags |= WLAN_STA_WME; + sta->sta.wme = true; + } } if (mask & BIT(NL80211_STA_FLAG_MFP)) { -- cgit v1.2.3-18-g5258