diff options
author | David S. Miller <davem@davemloft.net> | 2011-05-05 14:09:28 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-05-05 14:09:28 -0700 |
commit | 90864fbc7639d7a2300c67a18c9fb9fbcf7d51d2 (patch) | |
tree | 6951c8d0e529dbfc7c4cec75d4cec63350e39b7c /net/mac80211 | |
parent | 228e548e602061b08ee8e8966f567c12aa079682 (diff) | |
parent | a70171dce9cd44cb06c7d299eba9fa87a8933045 (diff) | |
download | linux-90864fbc7639d7a2300c67a18c9fb9fbcf7d51d2.tar.bz2 |
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/aes_ccm.c | 6 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 15 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 18 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 27 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 7 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/key.c | 21 | ||||
-rw-r--r-- | net/mac80211/main.c | 18 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 3 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 4 | ||||
-rw-r--r-- | net/mac80211/pm.c | 16 | ||||
-rw-r--r-- | net/mac80211/rx.c | 49 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 2 | ||||
-rw-r--r-- | net/mac80211/status.c | 8 | ||||
-rw-r--r-- | net/mac80211/tx.c | 15 | ||||
-rw-r--r-- | net/mac80211/work.c | 6 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 62 |
17 files changed, 147 insertions, 133 deletions
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index 4bd6ef0be380..b9b595c08112 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c @@ -54,13 +54,12 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, u8 *cdata, u8 *mic) { int i, j, last_len, num_blocks; - u8 *pos, *cpos, *b, *s_0, *e, *b_0, *aad; + u8 *pos, *cpos, *b, *s_0, *e, *b_0; b = scratch; s_0 = scratch + AES_BLOCK_LEN; e = scratch + 2 * AES_BLOCK_LEN; b_0 = scratch + 3 * AES_BLOCK_LEN; - aad = scratch + 4 * AES_BLOCK_LEN; num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last_len = data_len % AES_BLOCK_LEN; @@ -94,13 +93,12 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, u8 *cdata, size_t data_len, u8 *mic, u8 *data) { int i, j, last_len, num_blocks; - u8 *pos, *cpos, *b, *s_0, *a, *b_0, *aad; + u8 *pos, *cpos, *b, *s_0, *a, *b_0; b = scratch; s_0 = scratch + AES_BLOCK_LEN; a = scratch + 2 * AES_BLOCK_LEN; b_0 = scratch + 3 * AES_BLOCK_LEN; - aad = scratch + 4 * AES_BLOCK_LEN; num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last_len = data_len % AES_BLOCK_LEN; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a9ddaf63ee14..12d52cec9515 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1633,16 +1633,13 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int i; - - /* - * This _could_ be supported by providing a hook for - * drivers for this function, but at this point it - * doesn't seem worth bothering. - */ - if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) - return -EOPNOTSUPP; + int i, ret; + if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) { + ret = drv_set_bitrate_mask(local, sdata, mask); + if (ret) + return ret; + } for (i = 0; i < IEEE80211_NUM_BANDS; i++) sdata->rc_rateidx_mask[i] = mask->control[i].legacy; diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 00a0685f2403..2ddb56e5b51f 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -565,4 +565,22 @@ static inline bool drv_tx_frames_pending(struct ieee80211_local *local) return ret; } + +static inline int drv_set_bitrate_mask(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + const struct cfg80211_bitrate_mask *mask) +{ + int ret = -EOPNOTSUPP; + + might_sleep(); + + trace_drv_set_bitrate_mask(local, sdata, mask); + if (local->ops->set_bitrate_mask) + ret = local->ops->set_bitrate_mask(&local->hw, + &sdata->vif, mask); + trace_drv_return_int(local, ret); + + return ret; +} + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index c8c934d48b7a..191e834ec46b 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -989,6 +989,33 @@ DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait, TP_ARGS(local) ); +TRACE_EVENT(drv_set_bitrate_mask, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + const struct cfg80211_bitrate_mask *mask), + + TP_ARGS(local, sdata, mask), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __field(u32, legacy_2g) + __field(u32, legacy_5g) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->legacy_2g = mask->control[IEEE80211_BAND_2GHZ].legacy; + __entry->legacy_5g = mask->control[IEEE80211_BAND_5GHZ].legacy; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " 2G Mask:0x%x 5G Mask:0x%x", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->legacy_2g, __entry->legacy_5g + ) +); + /* * Tracing for API calls that drivers call. */ diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 14883966374e..b81860c94698 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -40,7 +40,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) { - u16 auth_alg, auth_transaction, status_code; + u16 auth_alg, auth_transaction; lockdep_assert_held(&sdata->u.ibss.mtx); @@ -49,7 +49,6 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); - status_code = le16_to_cpu(mgmt->u.auth.status_code); /* * IEEE 802.11 standard does not require authentication in IBSS @@ -527,8 +526,6 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - struct ieee80211_local *local = sdata->local; - struct ieee80211_supported_band *sband; u8 bssid[ETH_ALEN]; u16 capability; int i; @@ -551,8 +548,6 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", sdata->name, bssid); - sband = local->hw.wiphy->bands[ifibss->channel->band]; - capability = WLAN_CAPABILITY_IBSS; if (ifibss->privacy) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a77849970914..027c0467d7a3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -766,6 +766,9 @@ struct ieee80211_local { int tx_headroom; /* required headroom for hardware/radiotap */ + /* count for keys needing tailroom space allocation */ + int crypto_tx_tailroom_needed_cnt; + /* Tasklet and skb queue to process calls from IRQ mode. All frames * added to skb_queue will be processed, but frames in * skb_queue_unreliable may be dropped if the total length of these diff --git a/net/mac80211/key.c b/net/mac80211/key.c index af3c56482c80..b510721e3b3d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -101,6 +101,11 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) if (!ret) { key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; + + if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || + (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))) + key->local->crypto_tx_tailroom_needed_cnt--; + return 0; } @@ -156,6 +161,10 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; + + if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || + (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))) + key->local->crypto_tx_tailroom_needed_cnt++; } void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) @@ -388,8 +397,10 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) ieee80211_aes_key_free(key->u.ccmp.tfm); if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); - if (key->local) + if (key->local) { ieee80211_debugfs_key_remove(key); + key->local->crypto_tx_tailroom_needed_cnt--; + } kfree(key); } @@ -451,6 +462,8 @@ int ieee80211_key_link(struct ieee80211_key *key, ieee80211_debugfs_key_add(key); + key->local->crypto_tx_tailroom_needed_cnt++; + ret = ieee80211_key_enable_hw_accel(key); mutex_unlock(&sdata->local->key_mtx); @@ -492,8 +505,12 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) mutex_lock(&sdata->local->key_mtx); - list_for_each_entry(key, &sdata->key_list, list) + sdata->local->crypto_tx_tailroom_needed_cnt = 0; + + list_for_each_entry(key, &sdata->key_list, list) { + sdata->local->crypto_tx_tailroom_needed_cnt++; ieee80211_key_enable_hw_accel(key); + } mutex_unlock(&sdata->local->key_mtx); } diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0ab2a8df312d..61877662e8f8 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -33,12 +33,6 @@ #include "cfg.h" #include "debugfs.h" - -static bool ieee80211_disable_40mhz_24ghz; -module_param(ieee80211_disable_40mhz_24ghz, bool, 0644); -MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz, - "Disable 40MHz support in the 2.4GHz band"); - static struct lock_class_key ieee80211_rx_skb_queue_class; void ieee80211_configure_filter(struct ieee80211_local *local) @@ -728,18 +722,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) } channels += sband->n_channels; - /* - * Since ieee80211_disable_40mhz_24ghz is global, we can - * modify the sband's ht data even if the driver uses a - * global structure for that. - */ - if (ieee80211_disable_40mhz_24ghz && - band == IEEE80211_BAND_2GHZ && - sband->ht_cap.ht_supported) { - sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; - } - if (max_bitrates < sband->n_bitrates) max_bitrates = sband->n_bitrates; supp_ht = supp_ht || sband->ht_cap.ht_supported; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 11207979e2e2..c1299e249541 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -613,12 +613,9 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { struct ieee80211_rx_status *rx_status; - struct ieee80211_if_mesh *ifmsh; struct ieee80211_mgmt *mgmt; u16 stype; - ifmsh = &sdata->u.mesh; - rx_status = IEEE80211_SKB_RXCB(skb); mgmt = (struct ieee80211_mgmt *) skb->data; stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 5bf64d7112b3..e57f2e728cfe 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -633,7 +633,6 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, struct mesh_path *mpath; u8 ttl; u8 *ta, *target_addr; - u8 target_flags; u32 target_sn; u16 target_rcode; @@ -644,7 +643,6 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, return; } ttl--; - target_flags = PERR_IE_TARGET_FLAGS(perr_elem); target_addr = PERR_IE_TARGET_ADDR(perr_elem); target_sn = PERR_IE_TARGET_SN(perr_elem); target_rcode = PERR_IE_TARGET_RCODE(perr_elem); @@ -675,12 +673,10 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_path *mpath; - u8 *ta; u8 ttl, flags, hopcount; u8 *orig_addr; u32 orig_sn, metric; - ta = mgmt->sa; ttl = rann->rann_ttl; if (ttl <= 1) { ifmsh->mshstats.dropped_frames_ttl++; diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index e37355193ed1..042461710880 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -14,12 +14,23 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) ieee80211_scan_cancel(local); + if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { + mutex_lock(&local->sta_mtx); + list_for_each_entry(sta, &local->sta_list, list) { + set_sta_flags(sta, WLAN_STA_BLOCK_BA); + ieee80211_sta_tear_down_BA_sessions(sta, true); + } + mutex_unlock(&local->sta_mtx); + } + ieee80211_stop_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); /* flush out all packets */ synchronize_net(); + drv_flush(local, false); + local->quiescing = true; /* make quiescing visible to timers everywhere */ mb(); @@ -43,11 +54,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) /* tear down aggregation sessions and remove STAs */ mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) { - if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { - set_sta_flags(sta, WLAN_STA_BLOCK_BA); - ieee80211_sta_tear_down_BA_sessions(sta, true); - } - if (sta->uploaded) { sdata = sta->sdata; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a864890e4d03..13a6697651ad 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -652,7 +652,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, set_release_timer: mod_timer(&tid_agg_rx->reorder_timer, - tid_agg_rx->reorder_time[j] + + tid_agg_rx->reorder_time[j] + 1 + HT_RX_REORDER_BUF_TIMEOUT); } else { del_timer(&tid_agg_rx->reorder_timer); @@ -2368,47 +2368,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) return RX_QUEUED; } -static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr, - struct ieee80211_rx_data *rx) -{ - int keyidx; - unsigned int hdrlen; - - hdrlen = ieee80211_hdrlen(hdr->frame_control); - if (rx->skb->len >= hdrlen + 4) - keyidx = rx->skb->data[hdrlen + 3] >> 6; - else - keyidx = -1; - - if (!rx->sta) { - /* - * Some hardware seem to generate incorrect Michael MIC - * reports; ignore them to avoid triggering countermeasures. - */ - return; - } - - if (!ieee80211_has_protected(hdr->frame_control)) - return; - - if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) { - /* - * APs with pairwise keys should never receive Michael MIC - * errors for non-zero keyidx because these are reserved for - * group keys and only the AP is sending real multicast - * frames in the BSS. - */ - return; - } - - if (!ieee80211_is_data(hdr->frame_control) && - !ieee80211_is_auth(hdr->frame_control)) - return; - - mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL, - GFP_ATOMIC); -} - /* TODO: use IEEE80211_RX_FRAGMENTED */ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, struct ieee80211_rate *rate) @@ -2752,12 +2711,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, if (!prepares) return false; - if (status->flag & RX_FLAG_MMIC_ERROR) { - if (status->rx_flags & IEEE80211_RX_RA_MATCH) - ieee80211_rx_michael_mic_report(hdr, rx); - return false; - } - if (!consume) { skb = skb_copy(skb, GFP_ATOMIC); if (!skb) { diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a03d8a312875..d9e6e81ff6b2 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -587,7 +587,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, { unsigned long flags; struct sk_buff *skb; - struct ieee80211_sub_if_data *sdata; if (skb_queue_empty(&sta->ps_tx_buf)) return false; @@ -604,7 +603,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, if (!skb) break; - sdata = sta->sdata; local->total_ps_buffered--; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n", diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 3ed3c835fbbf..1658efaa2e8e 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -446,3 +446,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) dev_kfree_skb(skb); } EXPORT_SYMBOL(ieee80211_tx_status); + +void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets) +{ + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr, + num_packets, GFP_ATOMIC); +} +EXPORT_SYMBOL(ieee80211_report_low_ack); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 17b10be31f55..e3e3aa173af0 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1036,14 +1036,11 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, struct ieee80211_radiotap_iterator iterator; struct ieee80211_radiotap_header *rthdr = (struct ieee80211_radiotap_header *) skb->data; - struct ieee80211_supported_band *sband; bool hw_frag; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, NULL); - sband = tx->local->hw.wiphy->bands[tx->channel->band]; - info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; tx->flags &= ~IEEE80211_TX_FRAGMENTED; @@ -1442,11 +1439,8 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, struct ieee80211_tx_data tx; ieee80211_tx_result res_prepare; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - u16 queue; bool result = true; - queue = skb_get_queue_mapping(skb); - if (unlikely(skb->len < 10)) { dev_kfree_skb(skb); return true; @@ -1482,12 +1476,7 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, { int tail_need = 0; - /* - * This could be optimised, devices that do full hardware - * crypto (including TKIP MMIC) need no tailroom... But we - * have no drivers for such devices currently. - */ - if (may_encrypt) { + if (may_encrypt && local->crypto_tx_tailroom_needed_cnt) { tail_need = IEEE80211_ENCRYPT_TAILROOM; tail_need -= skb_tailroom(skb); tail_need = max_t(int, tail_need, 0); @@ -2485,7 +2474,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, { struct ieee80211_local *local = hw_to_local(hw); struct sk_buff *skb = NULL; - struct sta_info *sta; struct ieee80211_tx_data tx; struct ieee80211_sub_if_data *sdata; struct ieee80211_if_ap *bss = NULL; @@ -2527,7 +2515,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, info = IEEE80211_SKB_CB(skb); - sta = tx.sta; tx.flags |= IEEE80211_TX_PS_BUFFERED; tx.channel = local->hw.conf.channel; info->band = tx.channel->band; diff --git a/net/mac80211/work.c b/net/mac80211/work.c index e73c8cae036b..a94b312dbfac 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -198,9 +198,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos, qos_info; - const u8 *ies; size_t offset = 0, noffset; - int i, len, count, rates_len, supp_rates_len; + int i, count, rates_len, supp_rates_len; u16 capab; struct ieee80211_supported_band *sband; u32 rates = 0; @@ -285,7 +284,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, } /* SSID */ - ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len); + pos = skb_put(skb, 2 + wk->assoc.ssid_len); *pos++ = WLAN_EID_SSID; *pos++ = wk->assoc.ssid_len; memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); @@ -295,7 +294,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, if (supp_rates_len > 8) supp_rates_len = 8; - len = sband->n_bitrates; pos = skb_put(skb, supp_rates_len + 2); *pos++ = WLAN_EID_SUPP_RATES; *pos++ = supp_rates_len; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index f1765de2f4bf..9dc3b5f26e80 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -87,42 +87,76 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - /* No way to verify the MIC if the hardware stripped it */ - if (status->flag & RX_FLAG_MMIC_STRIPPED) + /* + * it makes no sense to check for MIC errors on anything other + * than data frames. + */ + if (!ieee80211_is_data_present(hdr->frame_control)) + return RX_CONTINUE; + + /* + * No way to verify the MIC if the hardware stripped it or + * the IV with the key index. In this case we have solely rely + * on the driver to set RX_FLAG_MMIC_ERROR in the event of a + * MIC failure report. + */ + if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) { + if (status->flag & RX_FLAG_MMIC_ERROR) + goto mic_fail; + + if (!(status->flag & RX_FLAG_IV_STRIPPED)) + goto update_iv; + return RX_CONTINUE; + } + /* + * Some hardware seems to generate Michael MIC failure reports; even + * though, the frame was not encrypted with TKIP and therefore has no + * MIC. Ignore the flag them to avoid triggering countermeasures. + */ if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP || - !ieee80211_has_protected(hdr->frame_control) || - !ieee80211_is_data_present(hdr->frame_control)) + !(status->flag & RX_FLAG_DECRYPTED)) return RX_CONTINUE; + if (rx->sdata->vif.type == NL80211_IFTYPE_AP && rx->key->conf.keyidx) { + /* + * APs with pairwise keys should never receive Michael MIC + * errors for non-zero keyidx because these are reserved for + * group keys and only the AP is sending real multicast + * frames in the BSS. ( + */ + return RX_DROP_UNUSABLE; + } + + if (status->flag & RX_FLAG_MMIC_ERROR) + goto mic_fail; + hdrlen = ieee80211_hdrlen(hdr->frame_control); if (skb->len < hdrlen + MICHAEL_MIC_LEN) return RX_DROP_UNUSABLE; data = skb->data + hdrlen; data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; - key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; michael_mic(key, hdr, data, data_len, mic); - if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) { - if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) - return RX_DROP_UNUSABLE; - - mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, - (void *) skb->data, NULL, - GFP_ATOMIC); - return RX_DROP_UNUSABLE; - } + if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) + goto mic_fail; /* remove Michael MIC from payload */ skb_trim(skb, skb->len - MICHAEL_MIC_LEN); +update_iv: /* update IV in key information to be able to detect replays */ rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32; rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16; return RX_CONTINUE; + +mic_fail: + mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, + (void *) skb->data, NULL, GFP_ATOMIC); + return RX_DROP_UNUSABLE; } |