From 33766368f6532313571534f9112b1796d6651bbe Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 30 Sep 2012 19:47:40 +0300 Subject: mac80211: Fix FC masking in BIP AAD generation The bits used in the mask were off-by-one and ended up masking PwrMgt, MoreData, Protected fields instead of Retry, PwrMgt, MoreData. Fix this and to mask the correct fields. While doing so, convert the code to mask the full FC using IEEE80211_FCTL_* defines similarly to how CCMP AAD is built. Since BIP is used only with broadcast/multicast management frames, the Retry field is always 0 in these frames. The Protected field is also zero to maintain backwards compatibility. As such, the incorrect mask here does not really cause any problems for valid frames. In theory, an invalid BIP frame with Retry or Protected field set to 1 could be rejected because of BIP validation. However, no such frame should show up with standard compliant implementations, so this does not cause problems in normal BIP use. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- net/mac80211/wpa.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index bdb53aba888e..e58bf3fe3ed9 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -545,14 +545,19 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) static void bip_aad(struct sk_buff *skb, u8 *aad) { + __le16 mask_fc; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + /* BIP AAD: FC(masked) || A1 || A2 || A3 */ /* FC type/subtype */ - aad[0] = skb->data[0]; /* Mask FC Retry, PwrMgt, MoreData flags to zero */ - aad[1] = skb->data[1] & ~(BIT(4) | BIT(5) | BIT(6)); + mask_fc = hdr->frame_control; + mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY | IEEE80211_FCTL_PM | + IEEE80211_FCTL_MOREDATA); + put_unaligned(mask_fc, (__le16 *) &aad[0]); /* A1 || A2 || A3 */ - memcpy(aad + 2, skb->data + 4, 3 * ETH_ALEN); + memcpy(aad + 2, &hdr->addr1, 3 * ETH_ALEN); } -- cgit v1.2.3 From 065a13e2cc665f6547dc7e8a9d6b6565badf940a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 11 Oct 2012 16:26:06 +0200 Subject: Bluetooth: SMP: Fix setting unknown auth_req bits When sending a pairing request or response we should not just blindly copy the value that the remote device sent. Instead we should at least make sure to mask out any unknown bits. This is particularly critical from the upcoming LE Secure Connections feature perspective as incorrectly indicating support for it (by copying the remote value) would cause a failure to pair with devices that support it. Signed-off-by: Johan Hedberg Cc: stable@kernel.org Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/smp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 8c225ef349cd..2ac8d50861e0 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -32,6 +32,8 @@ #define SMP_TIMEOUT msecs_to_jiffies(30000) +#define AUTH_REQ_MASK 0x07 + static inline void swap128(u8 src[16], u8 dst[16]) { int i; @@ -230,7 +232,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, req->max_key_size = SMP_MAX_ENC_KEY_SIZE; req->init_key_dist = 0; req->resp_key_dist = dist_keys; - req->auth_req = authreq; + req->auth_req = (authreq & AUTH_REQ_MASK); return; } @@ -239,7 +241,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE; rsp->init_key_dist = 0; rsp->resp_key_dist = req->resp_key_dist & dist_keys; - rsp->auth_req = authreq; + rsp->auth_req = (authreq & AUTH_REQ_MASK); } static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) -- cgit v1.2.3 From 6863255bd0e48bc41ae5a066d5c771801e92735a Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 15 Oct 2012 14:52:41 +0200 Subject: cfg80211/mac80211: avoid state mishmash on deauth Avoid situation when we are on associate state in mac80211 and on disassociate state in cfg80211. This can results on crash during modules unload (like showed on this thread: http://marc.info/?t=134373976300001&r=1&w=2) and possibly other problems. Reported-by: Pedro Francisco Cc: stable@vger.kernel.org Signed-off-by: Stanislaw Gruszka Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 1 + net/mac80211/mlme.c | 5 +++-- net/wireless/mlme.c | 12 +++--------- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1b4989082244..f8cd4cf3fad8 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1218,6 +1218,7 @@ struct cfg80211_deauth_request { const u8 *ie; size_t ie_len; u16 reason_code; + bool local_state_change; }; /** diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e714ed8bb198..e510a33fec76 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3549,6 +3549,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; + bool tx = !req->local_state_change; mutex_lock(&ifmgd->mtx); @@ -3565,12 +3566,12 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, if (ifmgd->associated && ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, - req->reason_code, true, frame_buf); + req->reason_code, tx, frame_buf); } else { drv_mgd_prepare_tx(sdata->local, sdata); ieee80211_send_deauth_disassoc(sdata, req->bssid, IEEE80211_STYPE_DEAUTH, - req->reason_code, true, + req->reason_code, tx, frame_buf); } diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 8016fee0752b..904a7f368325 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -457,20 +457,14 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, .reason_code = reason, .ie = ie, .ie_len = ie_len, + .local_state_change = local_state_change, }; ASSERT_WDEV_LOCK(wdev); - if (local_state_change) { - if (wdev->current_bss && - ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) { - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(&wdev->current_bss->pub); - wdev->current_bss = NULL; - } - + if (local_state_change && (!wdev->current_bss || + !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) return 0; - } return rdev->ops->deauth(&rdev->wiphy, dev, &req); } -- cgit v1.2.3 From 4045f72bcf3c293c7c5932ef001742d8bb5ded76 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 2 Oct 2012 21:34:23 +0200 Subject: mac80211: check if key has TKIP type before updating IV This patch fix corruption which can manifest itself by following crash when switching on rfkill switch with rt2x00 driver: https://bugzilla.redhat.com/attachment.cgi?id=615362 Pointer key->u.ccmp.tfm of group key get corrupted in: ieee80211_rx_h_michael_mic_verify(): /* update IV in key information to be able to detect replays */ rx->key->u.tkip.rx[rx->security_idx].iv32 = rx->tkip_iv32; rx->key->u.tkip.rx[rx->security_idx].iv16 = rx->tkip_iv16; because rt2x00 always set RX_FLAG_MMIC_STRIPPED, even if key is not TKIP. We already check type of the key in different path in ieee80211_rx_h_michael_mic_verify() function, so adding additional check here is reasonable. Cc: stable@vger.kernel.org # 3.0+ Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- net/mac80211/wpa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index bdb53aba888e..e72562a18bad 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -106,7 +106,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) if (status->flag & RX_FLAG_MMIC_ERROR) goto mic_fail; - if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key) + if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key && + rx->key->conf.cipher == WLAN_CIPHER_SUITE_TKIP) goto update_iv; return RX_CONTINUE; -- cgit v1.2.3 From e270b302e4771cde91e713ae17da31c1afc9a135 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 10 Oct 2012 11:13:06 -0700 Subject: brcmfmac: handle all exceptions as an error. in brcmf_usb_probe_cb only return code ENOLINK was seen as an error. This is wrong, all error codes should be returned to usb subsystem. Reviewed-by: Arend Van Spriel Signed-off-by: Hante Meuleman Signed-off-by: Franky Lin Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index a2b4b1e71017..7a6dfdc67b6c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -1339,7 +1339,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo, } ret = brcmf_bus_start(dev); - if (ret == -ENOLINK) { + if (ret) { brcmf_dbg(ERROR, "dongle is not responding\n"); brcmf_detach(dev); goto fail; -- cgit v1.2.3 From a180b83bb1f036c587bdb93ac6171b94ff49133c Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Wed, 10 Oct 2012 11:13:09 -0700 Subject: brcmfmac: use control channel in roamed status reporting Channel reported in scan results passed to cfg80211 is control channel. But chanspec is reported while notifying cfg80211 about roamed update. Cfg80211 complains because it could not find the bss in the list. Report control channel while calling cfg80211_roamed. Signed-off-by: Franky Lin Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 26 +++++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index c1abaa6db59e..48f08ae9062c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -4606,12 +4606,13 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, struct brcmf_cfg80211_profile *profile = cfg->profile; struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); struct wiphy *wiphy = cfg_to_wiphy(cfg); - struct brcmf_channel_info_le channel_le; - struct ieee80211_channel *notify_channel; + struct ieee80211_channel *notify_channel = NULL; struct ieee80211_supported_band *band; + struct brcmf_bss_info_le *bi; u32 freq; s32 err = 0; u32 target_channel; + u8 *buf; WL_TRACE("Enter\n"); @@ -4619,11 +4620,22 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, memcpy(profile->bssid, e->addr, ETH_ALEN); brcmf_update_bss_info(cfg); - brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_le, - sizeof(channel_le)); + buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); + if (buf == NULL) { + err = -ENOMEM; + goto done; + } + + /* data sent to dongle has to be little endian */ + *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX); + err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX); + + if (err) + goto done; - target_channel = le32_to_cpu(channel_le.target_channel); - WL_CONN("Roamed to channel %d\n", target_channel); + bi = (struct brcmf_bss_info_le *)(buf + 4); + target_channel = bi->ctl_ch ? bi->ctl_ch : + CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); if (target_channel <= CH_MAX_2G_CHANNEL) band = wiphy->bands[IEEE80211_BAND_2GHZ]; @@ -4633,6 +4645,8 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, freq = ieee80211_channel_to_frequency(target_channel, band->band); notify_channel = ieee80211_get_channel(wiphy, freq); +done: + kfree(buf); cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid, conn_info->req_ie, conn_info->req_ie_len, conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); -- cgit v1.2.3 From 5dd161ff7b46029c9da4f4ef8b214b8ba4316445 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Wed, 10 Oct 2012 11:13:10 -0700 Subject: brcmfmac: set dongle mode accordingly when interface up The mode of WiFi dongle should be initialized in brcmf_cfg80211_up which get called when network interface is brought up. Otherwise brcmf_cfg80211_get_station would return error. Signed-off-by: Franky Lin Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 38 ++-------------------- 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 48f08ae9062c..2c66bae77b37 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -5200,41 +5200,6 @@ brcmf_cfg80211_event(struct net_device *ndev, schedule_work(&cfg->event_work); } -static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype) -{ - s32 infra = 0; - s32 err = 0; - - switch (iftype) { - case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_WDS: - WL_ERR("type (%d) : currently we do not support this mode\n", - iftype); - err = -EINVAL; - return err; - case NL80211_IFTYPE_ADHOC: - infra = 0; - break; - case NL80211_IFTYPE_STATION: - infra = 1; - break; - case NL80211_IFTYPE_AP: - infra = 1; - break; - default: - err = -EINVAL; - WL_ERR("invalid type (%d)\n", iftype); - return err; - } - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra); - if (err) { - WL_ERR("WLC_SET_INFRA error (%d)\n", err); - return err; - } - - return 0; -} - static s32 brcmf_dongle_eventmsg(struct net_device *ndev) { /* Room for "event_msgs" + '\0' + bitvec */ @@ -5453,7 +5418,8 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) WL_BEACON_TIMEOUT); if (err) goto default_conf_out; - err = brcmf_dongle_mode(ndev, wdev->iftype); + err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype, + NULL, NULL); if (err && err != -EINPROGRESS) goto default_conf_out; err = brcmf_dongle_probecap(cfg); -- cgit v1.2.3 From 3e4f319dacc60c1b4537b85329d393ad18bf7501 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 10 Oct 2012 11:13:12 -0700 Subject: brcmfmac: fix end of loop check (signedness bug) The problem here is that we loop until "remained_buf_len" is less than zero, but since it is unsigned, it never is. "remained_buf_len" has to be large enough to hold the value from "mgmt_ie_buf_len". That variable is type u32, but it only holds small values so I have changed to both variables to int. Also I removed the bogus initialization from "mgmt_ie_buf_len" so that GCC can detect if it is used unitialized. I moved the declaration of "remained_buf_len" closer to where it is used so it's easier to read. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Dan Carpenter Signed-off-by: Franky Lin Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 2c66bae77b37..411dfe7c7ff0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -3972,7 +3972,7 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg, u8 *iovar_ie_buf; u8 *curr_ie_buf; u8 *mgmt_ie_buf = NULL; - u32 mgmt_ie_buf_len = 0; + int mgmt_ie_buf_len; u32 *mgmt_ie_len = 0; u32 del_add_ie_buf_len = 0; u32 total_ie_buf_len = 0; @@ -3982,7 +3982,7 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg, struct parsed_vndr_ie_info *vndrie_info; s32 i; u8 *ptr; - u32 remained_buf_len; + int remained_buf_len; WL_TRACE("bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag); iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); -- cgit v1.2.3 From d4fa14cd62bd078c8e3ef39283b9f237e5b2ff0f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 10 Oct 2012 22:40:23 +0200 Subject: mac80211: use ieee80211_free_txskb in a few more places Free tx status skbs when draining power save buffers, pending frames, or when tearing down a vif. Fixes remaining conditions that can lead to hostapd/wpa_supplicant hangs when running out of socket write memory. Signed-off-by: Felix Fietkau Cc: stable@vger.kernel.org Signed-off-by: John W. Linville --- net/mac80211/iface.c | 2 +- net/mac80211/sta_info.c | 4 ++-- net/mac80211/util.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 6f8a73c64fb3..7de7717ad67d 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -853,7 +853,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (info->control.vif == &sdata->vif) { __skb_unlink(skb, &local->pending[i]); - dev_kfree_skb_irq(skb); + ieee80211_free_txskb(&local->hw, skb); } } } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 797dd36a220d..0a4e4c04db89 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -650,7 +650,7 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local, */ if (!skb) break; - dev_kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); } /* @@ -679,7 +679,7 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local, local->total_ps_buffered--; ps_dbg(sta->sdata, "Buffered frame expired (STA %pM)\n", sta->sta.addr); - dev_kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); } /* diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 22ca35054dd0..94e586873979 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -406,7 +406,7 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, int queue = info->hw_queue; if (WARN_ON(!info->control.vif)) { - kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); return; } @@ -431,7 +431,7 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (WARN_ON(!info->control.vif)) { - kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); continue; } -- cgit v1.2.3 From 1fffa905adffbf0d3767fc978ef09afb830275eb Mon Sep 17 00:00:00 2001 From: Piotr Haber Date: Thu, 11 Oct 2012 14:05:15 +0200 Subject: bcma: fix unregistration of cores When cores are unregistered, entries need to be removed from cores list in a safe manner. Reported-by: Stanislaw Gruszka Reviewed-by: Arend Van Spriel Signed-off-by: Piotr Haber Cc: stable@vger.kernel.org Signed-off-by: John W. Linville --- drivers/bcma/main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 432aeeedfd5e..d865470bc951 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -158,9 +158,10 @@ static int bcma_register_cores(struct bcma_bus *bus) static void bcma_unregister_cores(struct bcma_bus *bus) { - struct bcma_device *core; + struct bcma_device *core, *tmp; - list_for_each_entry(core, &bus->cores, list) { + list_for_each_entry_safe(core, tmp, &bus->cores, list) { + list_del(&core->list); if (core->dev_registered) device_unregister(&core->dev); } -- cgit v1.2.3 From bf11315eeda510ea4fc1a2bf972d8155d31d89b4 Mon Sep 17 00:00:00 2001 From: Stanislav Yakovlev Date: Mon, 15 Oct 2012 14:14:32 +0000 Subject: net/wireless: ipw2200: Fix panic occurring in ipw_handle_promiscuous_tx() The driver does not count space of radiotap fields when allocating skb for radiotap packet. This leads to kernel panic with the following call trace: ... [67607.676067] [] error_code+0x67/0x6c [67607.676067] [] ? skb_put+0x91/0xa0 [67607.676067] [] ? ipw_handle_promiscuous_tx+0x16b/0x2d0 [ipw2200] [67607.676067] [] ipw_handle_promiscuous_tx+0x16b/0x2d0 [ipw2200] [67607.676067] [] ipw_net_hard_start_xmit+0x8b/0x90 [ipw2200] [67607.676067] [] libipw_xmit+0x55a/0x980 [libipw] [67607.676067] [] dev_hard_start_xmit+0x218/0x4d0 ... This bug was found by VittGam. https://bugzilla.kernel.org/show_bug.cgi?id=43255 Cc: stable@kernel.org Signed-off-by: Stanislav Yakovlev Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 935120fc8c93..768bf612533e 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -10472,7 +10472,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, } else len = src->len; - dst = alloc_skb(len + sizeof(*rt_hdr), GFP_ATOMIC); + dst = alloc_skb(len + sizeof(*rt_hdr) + sizeof(u16)*2, GFP_ATOMIC); if (!dst) continue; -- cgit v1.2.3 From 8f7b8db6e0557c8437adf9371e020cd89a7e85dc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 25 Sep 2012 16:40:12 +0200 Subject: iwlwifi: fix 6000 series channel switch command The channel switch command for 6000 series devices is larger than the maximum inline command size of 320 bytes. The command is therefore refused with a warning. Fix this by allocating the command and using the NOCOPY mechanism. Cc: stable@kernel.org Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/devices.c | 39 ++++++++++++++++++------------ 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/devices.c b/drivers/net/wireless/iwlwifi/dvm/devices.c index 349c205d5f62..da5862064195 100644 --- a/drivers/net/wireless/iwlwifi/dvm/devices.c +++ b/drivers/net/wireless/iwlwifi/dvm/devices.c @@ -518,7 +518,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, * See iwlagn_mac_channel_switch. */ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - struct iwl6000_channel_switch_cmd cmd; + struct iwl6000_channel_switch_cmd *cmd; u32 switch_time_in_usec, ucode_switch_time; u16 ch; u32 tsf_low; @@ -527,18 +527,25 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, struct ieee80211_vif *vif = ctx->vif; struct iwl_host_cmd hcmd = { .id = REPLY_CHANNEL_SWITCH, - .len = { sizeof(cmd), }, + .len = { sizeof(*cmd), }, .flags = CMD_SYNC, - .data = { &cmd, }, + .dataflags[0] = IWL_HCMD_DFL_NOCOPY, }; + int err; - cmd.band = priv->band == IEEE80211_BAND_2GHZ; + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + hcmd.data[0] = cmd; + + cmd->band = priv->band == IEEE80211_BAND_2GHZ; ch = ch_switch->channel->hw_value; IWL_DEBUG_11H(priv, "channel switch from %u to %u\n", ctx->active.channel, ch); - cmd.channel = cpu_to_le16(ch); - cmd.rxon_flags = ctx->staging.flags; - cmd.rxon_filter_flags = ctx->staging.filter_flags; + cmd->channel = cpu_to_le16(ch); + cmd->rxon_flags = ctx->staging.flags; + cmd->rxon_filter_flags = ctx->staging.filter_flags; switch_count = ch_switch->count; tsf_low = ch_switch->timestamp & 0x0ffffffff; /* @@ -554,23 +561,25 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, switch_count = 0; } if (switch_count <= 1) - cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); + cmd->switch_time = cpu_to_le32(priv->ucode_beacon_time); else { switch_time_in_usec = vif->bss_conf.beacon_int * switch_count * TIME_UNIT; ucode_switch_time = iwl_usecs_to_beacons(priv, switch_time_in_usec, beacon_interval); - cmd.switch_time = iwl_add_beacon_time(priv, - priv->ucode_beacon_time, - ucode_switch_time, - beacon_interval); + cmd->switch_time = iwl_add_beacon_time(priv, + priv->ucode_beacon_time, + ucode_switch_time, + beacon_interval); } IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", - cmd.switch_time); - cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR; + cmd->switch_time); + cmd->expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR; - return iwl_dvm_send_cmd(priv, &hcmd); + err = iwl_dvm_send_cmd(priv, &hcmd); + kfree(cmd); + return err; } struct iwl_lib_ops iwl6000_lib = { -- cgit v1.2.3 From 3a40414f826a8f1096d9b94c4a53ef91b25ba28d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 1 Oct 2012 15:52:00 +0200 Subject: mac80211: connect with HT20 if HT40 is not permitted Some changes to fix issues with HT40 APs in Korea and follow-up changes to allow using HT40 even if the local regulatory database disallows it caused issues with iwlwifi (and could cause issues with other devices); iwlwifi firmware would assert if you tried to connect to an AP that has an invalid configuration (e.g. using HT40- on channel 140.) Fix this, while avoiding the "Korean AP" issue by disabling HT40 and advertising HT20 to the AP when connecting. Cc: stable@vger.kernel.org [3.6] Reported-by: Florian Reitmeir Tested-by: Florian Reitmeir Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e510a33fec76..1b7eed252fe9 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3099,22 +3099,32 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, ht_cfreq, ht_oper->primary_chan, cbss->channel->band); ht_oper = NULL; + } else { + channel_type = NL80211_CHAN_HT20; } } - if (ht_oper) { - channel_type = NL80211_CHAN_HT20; + if (ht_oper && sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { + /* + * cfg80211 already verified that the channel itself can + * be used, but it didn't check that we can do the right + * HT type, so do that here as well. If HT40 isn't allowed + * on this channel, disable 40 MHz operation. + */ - if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { - switch (ht_oper->ht_param & - IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + if (cbss->channel->flags & IEEE80211_CHAN_NO_HT40PLUS) + ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ; + else channel_type = NL80211_CHAN_HT40PLUS; - break; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + if (cbss->channel->flags & IEEE80211_CHAN_NO_HT40MINUS) + ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ; + else channel_type = NL80211_CHAN_HT40MINUS; - break; - } + break; } } -- cgit v1.2.3