mac80211: fix regression where EAPOL frames were sent in plaintext
[linux-2.6-microblaze.git] / net / mac80211 / status.c
index 0794396..6feb451 100644 (file)
@@ -66,8 +66,8 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
 
        info->control.jiffies = jiffies;
        info->control.vif = &sta->sdata->vif;
-       info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING |
-                      IEEE80211_TX_INTFL_RETRANSMISSION;
+       info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
+       info->flags |= IEEE80211_TX_INTFL_RETRANSMISSION;
        info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
 
        sta->status_stats.filtered++;
@@ -184,18 +184,6 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
        struct ieee80211_mgmt *mgmt = (void *) skb->data;
        struct ieee80211_local *local = sta->local;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
-       struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
-
-       if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
-               sta->status_stats.last_ack = jiffies;
-               if (txinfo->status.is_valid_ack_signal) {
-                       sta->status_stats.last_ack_signal =
-                                        (s8)txinfo->status.ack_signal;
-                       sta->status_stats.ack_signal_filled = true;
-                       ewma_avg_signal_add(&sta->status_stats.avg_ack_signal,
-                                           -txinfo->status.ack_signal);
-               }
-       }
 
        if (ieee80211_is_data_qos(mgmt->frame_control)) {
                struct ieee80211_hdr *hdr = (void *) skb->data;
@@ -890,7 +878,8 @@ void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb,
 }
 
 static void __ieee80211_tx_status(struct ieee80211_hw *hw,
-                                 struct ieee80211_tx_status *status)
+                                 struct ieee80211_tx_status *status,
+                                 int rates_idx, int retry_count)
 {
        struct sk_buff *skb = status->skb;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -899,17 +888,12 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
        struct sta_info *sta;
        __le16 fc;
        struct ieee80211_supported_band *sband;
-       int retry_count;
-       int rates_idx;
        bool send_to_cooked;
        bool acked;
        bool noack_success;
        struct ieee80211_bar *bar;
        int shift = 0;
        int tid = IEEE80211_NUM_TIDS;
-       u16 tx_time_est;
-
-       rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
 
        sband = local->hw.wiphy->bands[info->band];
        fc = hdr->frame_control;
@@ -987,62 +971,17 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
                if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
                        ieee80211_handle_filtered_frame(local, sta, skb);
                        return;
-               } else {
+               } else if (ieee80211_is_data_present(fc)) {
                        if (!acked && !noack_success)
-                               sta->status_stats.retry_failed++;
-                       sta->status_stats.retry_count += retry_count;
+                               sta->status_stats.msdu_failed[tid]++;
 
-                       if (ieee80211_is_data_present(fc)) {
-                               if (!acked && !noack_success)
-                                       sta->status_stats.msdu_failed[tid]++;
-
-                               sta->status_stats.msdu_retries[tid] +=
-                                       retry_count;
-                       }
+                       sta->status_stats.msdu_retries[tid] +=
+                               retry_count;
                }
 
-               rate_control_tx_status(local, sband, status);
-               if (ieee80211_vif_is_mesh(&sta->sdata->vif))
-                       ieee80211s_update_metric(local, sta, status);
-
                if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked)
                        ieee80211_frame_acked(sta, skb);
 
-               if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) &&
-                   ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
-                       ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data,
-                                               acked, info->status.tx_time);
-
-               if (info->status.tx_time &&
-                   wiphy_ext_feature_isset(local->hw.wiphy,
-                                           NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
-                       ieee80211_sta_register_airtime(&sta->sta, tid,
-                                                      info->status.tx_time, 0);
-
-               if ((tx_time_est = ieee80211_info_get_tx_time_est(info)) > 0) {
-                       /* Do this here to avoid the expensive lookup of the sta
-                        * in ieee80211_report_used_skb().
-                        */
-                       ieee80211_sta_update_pending_airtime(local, sta,
-                                                            skb_get_queue_mapping(skb),
-                                                            tx_time_est,
-                                                            true);
-                       ieee80211_info_set_tx_time_est(info, 0);
-               }
-
-               if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
-                       if (acked) {
-                               if (sta->status_stats.lost_packets)
-                                       sta->status_stats.lost_packets = 0;
-
-                               /* Track when last TDLS packet was ACKed */
-                               sta->status_stats.last_pkt_time = jiffies;
-                       } else if (noack_success) {
-                               /* nothing to do here, do not account as lost */
-                       } else {
-                               ieee80211_lost_packet(sta, info);
-                       }
-               }
        }
 
        /* SNMP counters
@@ -1101,7 +1040,10 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
         * with this test...
         */
        if (!local->monitors && (!send_to_cooked || !local->cooked_mntrs)) {
-               dev_kfree_skb(skb);
+               if (status->free_list)
+                       list_add_tail(&skb->list, status->free_list);
+               else
+                       dev_kfree_skb(skb);
                return;
        }
 
@@ -1126,7 +1068,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        if (sta)
                status.sta = &sta->sta;
 
-       __ieee80211_tx_status(hw, &status);
+       ieee80211_tx_status_ext(hw, &status);
        rcu_read_unlock();
 }
 EXPORT_SYMBOL(ieee80211_tx_status);
@@ -1137,10 +1079,12 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_tx_info *info = status->info;
        struct ieee80211_sta *pubsta = status->sta;
+       struct sk_buff *skb = status->skb;
        struct ieee80211_supported_band *sband;
-       struct sta_info *sta;
-       int retry_count;
+       struct sta_info *sta = NULL;
+       int rates_idx, retry_count;
        bool acked, noack_success;
+       u16 tx_time_est;
 
        if (pubsta) {
                sta = container_of(pubsta, struct sta_info, sta);
@@ -1149,13 +1093,22 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
                        sta->tx_stats.last_rate_info = *status->rate;
        }
 
-       if (status->skb)
-               return __ieee80211_tx_status(hw, status);
+       if (skb && (tx_time_est =
+                   ieee80211_info_get_tx_time_est(IEEE80211_SKB_CB(skb))) > 0) {
+               /* Do this here to avoid the expensive lookup of the sta
+                * in ieee80211_report_used_skb().
+                */
+               ieee80211_sta_update_pending_airtime(local, sta,
+                                                    skb_get_queue_mapping(skb),
+                                                    tx_time_est,
+                                                    true);
+               ieee80211_info_set_tx_time_est(IEEE80211_SKB_CB(skb), 0);
+       }
 
-       if (!status->sta)
-               return;
+       if (!status->info)
+               goto free;
 
-       ieee80211_tx_get_rates(hw, info, &retry_count);
+       rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
 
        sband = hw->wiphy->bands[info->band];
 
@@ -1163,24 +1116,46 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
        noack_success = !!(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED);
 
        if (pubsta) {
+               struct ieee80211_sub_if_data *sdata = sta->sdata;
+
                if (!acked && !noack_success)
                        sta->status_stats.retry_failed++;
                sta->status_stats.retry_count += retry_count;
 
-               if (acked) {
-                       sta->status_stats.last_ack = jiffies;
+               if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
+                       if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+                           skb && !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP))
+                               ieee80211_sta_tx_notify(sdata, (void *) skb->data,
+                                                       acked, info->status.tx_time);
 
-                       if (sta->status_stats.lost_packets)
-                               sta->status_stats.lost_packets = 0;
+                       if (acked) {
+                               sta->status_stats.last_ack = jiffies;
 
-                       /* Track when last packet was ACKed */
-                       sta->status_stats.last_pkt_time = jiffies;
-               } else if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
-                       return;
-               } else if (noack_success) {
-                       /* nothing to do here, do not account as lost */
-               } else {
-                       ieee80211_lost_packet(sta, info);
+                               if (sta->status_stats.lost_packets)
+                                       sta->status_stats.lost_packets = 0;
+
+                               /* Track when last packet was ACKed */
+                               sta->status_stats.last_pkt_time = jiffies;
+
+                               /* Reset connection monitor */
+                               if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+                                   unlikely(sdata->u.mgd.probe_send_count > 0))
+                                       sdata->u.mgd.probe_send_count = 0;
+
+                               if (info->status.is_valid_ack_signal) {
+                                       sta->status_stats.last_ack_signal =
+                                                        (s8)info->status.ack_signal;
+                                       sta->status_stats.ack_signal_filled = true;
+                                       ewma_avg_signal_add(&sta->status_stats.avg_ack_signal,
+                                                           -info->status.ack_signal);
+                               }
+                       } else if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
+                               return;
+                       } else if (noack_success) {
+                               /* nothing to do here, do not account as lost */
+                       } else {
+                               ieee80211_lost_packet(sta, info);
+                       }
                }
 
                rate_control_tx_status(local, sband, status);
@@ -1188,6 +1163,10 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
                        ieee80211s_update_metric(local, sta, status);
        }
 
+       if (skb && !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP))
+               return __ieee80211_tx_status(hw, status, rates_idx,
+                                            retry_count);
+
        if (acked || noack_success) {
                I802_DEBUG_INC(local->dot11TransmittedFrameCount);
                if (!pubsta)
@@ -1199,6 +1178,16 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
        } else {
                I802_DEBUG_INC(local->dot11FailedCount);
        }
+
+free:
+       if (!skb)
+               return;
+
+       ieee80211_report_used_skb(local, skb, false);
+       if (status->free_list)
+               list_add_tail(&skb->list, status->free_list);
+       else
+               dev_kfree_skb(skb);
 }
 EXPORT_SYMBOL(ieee80211_tx_status_ext);
 
@@ -1225,69 +1214,23 @@ void ieee80211_tx_status_8023(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif,
                              struct sk_buff *skb)
 {
-       struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_tx_status status = {
+               .skb = skb,
+               .info = IEEE80211_SKB_CB(skb),
+       };
        struct sta_info *sta;
-       int retry_count;
-       int rates_idx;
-       bool acked;
 
        sdata = vif_to_sdata(vif);
 
-       acked = info->flags & IEEE80211_TX_STAT_ACK;
-       rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
-
        rcu_read_lock();
 
-       if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
-               goto counters_update;
-
-       if (IS_ERR(sta))
-               goto counters_update;
-
-       if (!acked)
-               sta->status_stats.retry_failed++;
-
-       if (rates_idx != -1)
-               sta->tx_stats.last_rate = info->status.rates[rates_idx];
-
-       sta->status_stats.retry_count += retry_count;
-
-       if (ieee80211_hw_check(hw, REPORTS_TX_ACK_STATUS)) {
-               if (acked && vif->type == NL80211_IFTYPE_STATION)
-                       ieee80211_sta_reset_conn_monitor(sdata);
-
-               sta->status_stats.last_ack = jiffies;
-               if (info->flags & IEEE80211_TX_STAT_ACK) {
-                       if (sta->status_stats.lost_packets)
-                               sta->status_stats.lost_packets = 0;
+       if (!ieee80211_lookup_ra_sta(sdata, skb, &sta) && !IS_ERR(sta))
+               status.sta = &sta->sta;
 
-                       sta->status_stats.last_pkt_time = jiffies;
-               } else {
-                       ieee80211_lost_packet(sta, info);
-               }
-       }
+       ieee80211_tx_status_ext(hw, &status);
 
-counters_update:
        rcu_read_unlock();
-       ieee80211_led_tx(local);
-
-       if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
-           !(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED))
-               goto skip_stats_update;
-
-       I802_DEBUG_INC(local->dot11TransmittedFrameCount);
-       if (is_multicast_ether_addr(skb->data))
-               I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
-       if (retry_count > 0)
-               I802_DEBUG_INC(local->dot11RetryCount);
-       if (retry_count > 1)
-               I802_DEBUG_INC(local->dot11MultipleRetryCount);
-
-skip_stats_update:
-       ieee80211_report_used_skb(local, skb, false);
-       dev_kfree_skb(skb);
 }
 EXPORT_SYMBOL(ieee80211_tx_status_8023);