Commit e6e71054 authored by David S. Miller's avatar David S. Miller

Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless

John W. Linville says:

====================
This is a batch of fixes intended for the 3.7 stream.

Dan Carpenter brings a fix for a simple signedness bug that could
prevent the proper termination of a loop.

Felix Fietkau found a few more places that need to use
ieee80211_free_txskb for properly releasing SKBs used by mac80211.

Franky Lin offers a pair of brcmfmac fixes, both fixing simple state
reporting errors.

Hante Meuleman corrects an error reporting case that wasn't handling
all types of errors properly.

Johan Hedberg offers a fix for an issue discovered at the Bluetooth
UnPlug Fest.  Gustavo says "the patch fixes a failure to pair with
devices that support the LE Secure Connections feature."

Johannes Berg sends an iwlwifi fix to handle a message type that
is too large for the normal command mechanism.  He also provides a
mac80211 fix to use HT20 channels when HT40 channels are not permitted.

Jouni Malinen offers a mac80211 fix for a masking error that was
incorrectly marking some frames.

Piotr Haber provides a fix to make sure bcma devices are unregistered
properly.

Stanislav Yakovlev gives us a fix for a panic in the ipw2200 driver.

Stanislaw Gruszka sends a pair of fixes: one prevents a mismatch on
connection states between cfg80211 and mac80211; the other prevents
some frame corruption related to handling encryption.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9a4da2cd 06f40a41
...@@ -158,9 +158,10 @@ static int bcma_register_cores(struct bcma_bus *bus) ...@@ -158,9 +158,10 @@ static int bcma_register_cores(struct bcma_bus *bus)
static void bcma_unregister_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) if (core->dev_registered)
device_unregister(&core->dev); device_unregister(&core->dev);
} }
......
...@@ -1339,7 +1339,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo, ...@@ -1339,7 +1339,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,
} }
ret = brcmf_bus_start(dev); ret = brcmf_bus_start(dev);
if (ret == -ENOLINK) { if (ret) {
brcmf_dbg(ERROR, "dongle is not responding\n"); brcmf_dbg(ERROR, "dongle is not responding\n");
brcmf_detach(dev); brcmf_detach(dev);
goto fail; goto fail;
......
...@@ -3972,7 +3972,7 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg, ...@@ -3972,7 +3972,7 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg,
u8 *iovar_ie_buf; u8 *iovar_ie_buf;
u8 *curr_ie_buf; u8 *curr_ie_buf;
u8 *mgmt_ie_buf = NULL; u8 *mgmt_ie_buf = NULL;
u32 mgmt_ie_buf_len = 0; int mgmt_ie_buf_len;
u32 *mgmt_ie_len = 0; u32 *mgmt_ie_len = 0;
u32 del_add_ie_buf_len = 0; u32 del_add_ie_buf_len = 0;
u32 total_ie_buf_len = 0; u32 total_ie_buf_len = 0;
...@@ -3982,7 +3982,7 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg, ...@@ -3982,7 +3982,7 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg,
struct parsed_vndr_ie_info *vndrie_info; struct parsed_vndr_ie_info *vndrie_info;
s32 i; s32 i;
u8 *ptr; u8 *ptr;
u32 remained_buf_len; int remained_buf_len;
WL_TRACE("bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag); WL_TRACE("bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag);
iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
...@@ -4606,12 +4606,13 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, ...@@ -4606,12 +4606,13 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_profile *profile = cfg->profile; struct brcmf_cfg80211_profile *profile = cfg->profile;
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
struct wiphy *wiphy = cfg_to_wiphy(cfg); struct wiphy *wiphy = cfg_to_wiphy(cfg);
struct brcmf_channel_info_le channel_le; struct ieee80211_channel *notify_channel = NULL;
struct ieee80211_channel *notify_channel;
struct ieee80211_supported_band *band; struct ieee80211_supported_band *band;
struct brcmf_bss_info_le *bi;
u32 freq; u32 freq;
s32 err = 0; s32 err = 0;
u32 target_channel; u32 target_channel;
u8 *buf;
WL_TRACE("Enter\n"); WL_TRACE("Enter\n");
...@@ -4619,11 +4620,22 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, ...@@ -4619,11 +4620,22 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
memcpy(profile->bssid, e->addr, ETH_ALEN); memcpy(profile->bssid, e->addr, ETH_ALEN);
brcmf_update_bss_info(cfg); brcmf_update_bss_info(cfg);
brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_le, buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
sizeof(channel_le)); 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); bi = (struct brcmf_bss_info_le *)(buf + 4);
WL_CONN("Roamed to channel %d\n", target_channel); target_channel = bi->ctl_ch ? bi->ctl_ch :
CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
if (target_channel <= CH_MAX_2G_CHANNEL) if (target_channel <= CH_MAX_2G_CHANNEL)
band = wiphy->bands[IEEE80211_BAND_2GHZ]; band = wiphy->bands[IEEE80211_BAND_2GHZ];
...@@ -4633,6 +4645,8 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, ...@@ -4633,6 +4645,8 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
freq = ieee80211_channel_to_frequency(target_channel, band->band); freq = ieee80211_channel_to_frequency(target_channel, band->band);
notify_channel = ieee80211_get_channel(wiphy, freq); notify_channel = ieee80211_get_channel(wiphy, freq);
done:
kfree(buf);
cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid, cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
conn_info->req_ie, conn_info->req_ie_len, conn_info->req_ie, conn_info->req_ie_len,
conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
...@@ -5186,41 +5200,6 @@ brcmf_cfg80211_event(struct net_device *ndev, ...@@ -5186,41 +5200,6 @@ brcmf_cfg80211_event(struct net_device *ndev,
schedule_work(&cfg->event_work); 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) static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
{ {
/* Room for "event_msgs" + '\0' + bitvec */ /* Room for "event_msgs" + '\0' + bitvec */
...@@ -5439,7 +5418,8 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) ...@@ -5439,7 +5418,8 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
WL_BEACON_TIMEOUT); WL_BEACON_TIMEOUT);
if (err) if (err)
goto default_conf_out; 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) if (err && err != -EINPROGRESS)
goto default_conf_out; goto default_conf_out;
err = brcmf_dongle_probecap(cfg); err = brcmf_dongle_probecap(cfg);
......
...@@ -10472,7 +10472,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, ...@@ -10472,7 +10472,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
} else } else
len = src->len; 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) if (!dst)
continue; continue;
......
...@@ -518,7 +518,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, ...@@ -518,7 +518,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
* See iwlagn_mac_channel_switch. * See iwlagn_mac_channel_switch.
*/ */
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; 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; u32 switch_time_in_usec, ucode_switch_time;
u16 ch; u16 ch;
u32 tsf_low; u32 tsf_low;
...@@ -527,18 +527,25 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, ...@@ -527,18 +527,25 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
struct ieee80211_vif *vif = ctx->vif; struct ieee80211_vif *vif = ctx->vif;
struct iwl_host_cmd hcmd = { struct iwl_host_cmd hcmd = {
.id = REPLY_CHANNEL_SWITCH, .id = REPLY_CHANNEL_SWITCH,
.len = { sizeof(cmd), }, .len = { sizeof(*cmd), },
.flags = CMD_SYNC, .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; ch = ch_switch->channel->hw_value;
IWL_DEBUG_11H(priv, "channel switch from %u to %u\n", IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
ctx->active.channel, ch); ctx->active.channel, ch);
cmd.channel = cpu_to_le16(ch); cmd->channel = cpu_to_le16(ch);
cmd.rxon_flags = ctx->staging.flags; cmd->rxon_flags = ctx->staging.flags;
cmd.rxon_filter_flags = ctx->staging.filter_flags; cmd->rxon_filter_flags = ctx->staging.filter_flags;
switch_count = ch_switch->count; switch_count = ch_switch->count;
tsf_low = ch_switch->timestamp & 0x0ffffffff; tsf_low = ch_switch->timestamp & 0x0ffffffff;
/* /*
...@@ -554,23 +561,25 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, ...@@ -554,23 +561,25 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
switch_count = 0; switch_count = 0;
} }
if (switch_count <= 1) 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 { else {
switch_time_in_usec = switch_time_in_usec =
vif->bss_conf.beacon_int * switch_count * TIME_UNIT; vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
ucode_switch_time = iwl_usecs_to_beacons(priv, ucode_switch_time = iwl_usecs_to_beacons(priv,
switch_time_in_usec, switch_time_in_usec,
beacon_interval); beacon_interval);
cmd.switch_time = iwl_add_beacon_time(priv, cmd->switch_time = iwl_add_beacon_time(priv,
priv->ucode_beacon_time, priv->ucode_beacon_time,
ucode_switch_time, ucode_switch_time,
beacon_interval); beacon_interval);
} }
IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
cmd.switch_time); cmd->switch_time);
cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR; 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 = { struct iwl_lib_ops iwl6000_lib = {
......
...@@ -1218,6 +1218,7 @@ struct cfg80211_deauth_request { ...@@ -1218,6 +1218,7 @@ struct cfg80211_deauth_request {
const u8 *ie; const u8 *ie;
size_t ie_len; size_t ie_len;
u16 reason_code; u16 reason_code;
bool local_state_change;
}; };
/** /**
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#define SMP_TIMEOUT msecs_to_jiffies(30000) #define SMP_TIMEOUT msecs_to_jiffies(30000)
#define AUTH_REQ_MASK 0x07
static inline void swap128(u8 src[16], u8 dst[16]) static inline void swap128(u8 src[16], u8 dst[16])
{ {
int i; int i;
...@@ -230,7 +232,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, ...@@ -230,7 +232,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
req->max_key_size = SMP_MAX_ENC_KEY_SIZE; req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
req->init_key_dist = 0; req->init_key_dist = 0;
req->resp_key_dist = dist_keys; req->resp_key_dist = dist_keys;
req->auth_req = authreq; req->auth_req = (authreq & AUTH_REQ_MASK);
return; return;
} }
...@@ -239,7 +241,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, ...@@ -239,7 +241,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE; rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
rsp->init_key_dist = 0; rsp->init_key_dist = 0;
rsp->resp_key_dist = req->resp_key_dist & dist_keys; 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) static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
......
...@@ -853,7 +853,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ...@@ -853,7 +853,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (info->control.vif == &sdata->vif) { if (info->control.vif == &sdata->vif) {
__skb_unlink(skb, &local->pending[i]); __skb_unlink(skb, &local->pending[i]);
dev_kfree_skb_irq(skb); ieee80211_free_txskb(&local->hw, skb);
} }
} }
} }
......
...@@ -3099,22 +3099,32 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, ...@@ -3099,22 +3099,32 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
ht_cfreq, ht_oper->primary_chan, ht_cfreq, ht_oper->primary_chan,
cbss->channel->band); cbss->channel->band);
ht_oper = NULL; ht_oper = NULL;
} else {
channel_type = NL80211_CHAN_HT20;
} }
} }
if (ht_oper) { if (ht_oper && sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
channel_type = NL80211_CHAN_HT20; /*
* 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) {
switch (ht_oper->ht_param & case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { if (cbss->channel->flags & IEEE80211_CHAN_NO_HT40PLUS)
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
else
channel_type = NL80211_CHAN_HT40PLUS; channel_type = NL80211_CHAN_HT40PLUS;
break; break;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW: 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; channel_type = NL80211_CHAN_HT40MINUS;
break; break;
}
} }
} }
...@@ -3549,6 +3559,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, ...@@ -3549,6 +3559,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
{ {
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
bool tx = !req->local_state_change;
mutex_lock(&ifmgd->mtx); mutex_lock(&ifmgd->mtx);
...@@ -3565,12 +3576,12 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, ...@@ -3565,12 +3576,12 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
if (ifmgd->associated && if (ifmgd->associated &&
ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
req->reason_code, true, frame_buf); req->reason_code, tx, frame_buf);
} else { } else {
drv_mgd_prepare_tx(sdata->local, sdata); drv_mgd_prepare_tx(sdata->local, sdata);
ieee80211_send_deauth_disassoc(sdata, req->bssid, ieee80211_send_deauth_disassoc(sdata, req->bssid,
IEEE80211_STYPE_DEAUTH, IEEE80211_STYPE_DEAUTH,
req->reason_code, true, req->reason_code, tx,
frame_buf); frame_buf);
} }
......
...@@ -650,7 +650,7 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local, ...@@ -650,7 +650,7 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local,
*/ */
if (!skb) if (!skb)
break; 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, ...@@ -679,7 +679,7 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local,
local->total_ps_buffered--; local->total_ps_buffered--;
ps_dbg(sta->sdata, "Buffered frame expired (STA %pM)\n", ps_dbg(sta->sdata, "Buffered frame expired (STA %pM)\n",
sta->sta.addr); sta->sta.addr);
dev_kfree_skb(skb); ieee80211_free_txskb(&local->hw, skb);
} }
/* /*
......
...@@ -406,7 +406,7 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, ...@@ -406,7 +406,7 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
int queue = info->hw_queue; int queue = info->hw_queue;
if (WARN_ON(!info->control.vif)) { if (WARN_ON(!info->control.vif)) {
kfree_skb(skb); ieee80211_free_txskb(&local->hw, skb);
return; return;
} }
...@@ -431,7 +431,7 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, ...@@ -431,7 +431,7 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (WARN_ON(!info->control.vif)) { if (WARN_ON(!info->control.vif)) {
kfree_skb(skb); ieee80211_free_txskb(&local->hw, skb);
continue; continue;
} }
......
...@@ -106,7 +106,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) ...@@ -106,7 +106,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
if (status->flag & RX_FLAG_MMIC_ERROR) if (status->flag & RX_FLAG_MMIC_ERROR)
goto mic_fail; 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; goto update_iv;
return RX_CONTINUE; return RX_CONTINUE;
...@@ -545,14 +546,19 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) ...@@ -545,14 +546,19 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
static void bip_aad(struct sk_buff *skb, u8 *aad) 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 */ /* BIP AAD: FC(masked) || A1 || A2 || A3 */
/* FC type/subtype */ /* FC type/subtype */
aad[0] = skb->data[0];
/* Mask FC Retry, PwrMgt, MoreData flags to zero */ /* 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 */ /* A1 || A2 || A3 */
memcpy(aad + 2, skb->data + 4, 3 * ETH_ALEN); memcpy(aad + 2, &hdr->addr1, 3 * ETH_ALEN);
} }
......
...@@ -457,20 +457,14 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, ...@@ -457,20 +457,14 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
.reason_code = reason, .reason_code = reason,
.ie = ie, .ie = ie,
.ie_len = ie_len, .ie_len = ie_len,
.local_state_change = local_state_change,
}; };
ASSERT_WDEV_LOCK(wdev); ASSERT_WDEV_LOCK(wdev);
if (local_state_change) { if (local_state_change && (!wdev->current_bss ||
if (wdev->current_bss && !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
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;
}
return 0; return 0;
}
return rdev->ops->deauth(&rdev->wiphy, dev, &req); return rdev->ops->deauth(&rdev->wiphy, dev, &req);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment