These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / mac80211 / status.c
index 005fdbe..5bad05e 100644 (file)
@@ -67,7 +67,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
                       IEEE80211_TX_INTFL_RETRANSMISSION;
        info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
 
-       sta->tx_filtered_count++;
+       sta->status_stats.filtered++;
 
        /*
         * Clear more-data bit on filtered frames, it might be set
@@ -101,6 +101,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
         * when it wakes up for the next time.
         */
        set_sta_flag(sta, WLAN_STA_CLEAR_PS_FILT);
+       ieee80211_clear_fast_xmit(sta);
 
        /*
         * This code races in the following way:
@@ -181,8 +182,8 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
        struct ieee80211_local *local = sta->local;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
 
-       if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
-               sta->last_rx = jiffies;
+       if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
+               sta->rx_stats.last_rx = jiffies;
 
        if (ieee80211_is_data_qos(mgmt->frame_control)) {
                struct ieee80211_hdr *hdr = (void *) skb->data;
@@ -414,8 +415,7 @@ static void ieee80211_tdls_td_tx_handle(struct ieee80211_local *local,
 
        if (is_teardown) {
                /* This mechanism relies on being able to get ACKs */
-               WARN_ON(!(local->hw.flags &
-                         IEEE80211_HW_REPORTS_TX_ACK_STATUS));
+               WARN_ON(!ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS));
 
                /* Check if peer has ACKed */
                if (flags & IEEE80211_TX_STAT_ACK) {
@@ -429,6 +429,74 @@ static void ieee80211_tdls_td_tx_handle(struct ieee80211_local *local,
        }
 }
 
+static struct ieee80211_sub_if_data *
+ieee80211_sdata_from_skb(struct ieee80211_local *local, struct sk_buff *skb)
+{
+       struct ieee80211_sub_if_data *sdata;
+
+       if (skb->dev) {
+               list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+                       if (!sdata->dev)
+                               continue;
+
+                       if (skb->dev == sdata->dev)
+                               return sdata;
+               }
+
+               return NULL;
+       }
+
+       return rcu_dereference(local->p2p_sdata);
+}
+
+static void ieee80211_report_ack_skb(struct ieee80211_local *local,
+                                    struct ieee80211_tx_info *info,
+                                    bool acked, bool dropped)
+{
+       struct sk_buff *skb;
+       unsigned long flags;
+
+       spin_lock_irqsave(&local->ack_status_lock, flags);
+       skb = idr_find(&local->ack_status_frames, info->ack_frame_id);
+       if (skb)
+               idr_remove(&local->ack_status_frames, info->ack_frame_id);
+       spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+       if (!skb)
+               return;
+
+       if (dropped) {
+               dev_kfree_skb_any(skb);
+               return;
+       }
+
+       if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
+               u64 cookie = IEEE80211_SKB_CB(skb)->ack.cookie;
+               struct ieee80211_sub_if_data *sdata;
+               struct ieee80211_hdr *hdr = (void *)skb->data;
+
+               rcu_read_lock();
+               sdata = ieee80211_sdata_from_skb(local, skb);
+               if (sdata) {
+                       if (ieee80211_is_nullfunc(hdr->frame_control) ||
+                           ieee80211_is_qos_nullfunc(hdr->frame_control))
+                               cfg80211_probe_status(sdata->dev, hdr->addr1,
+                                                     cookie, acked,
+                                                     GFP_ATOMIC);
+                       else
+                               cfg80211_mgmt_tx_status(&sdata->wdev, cookie,
+                                                       skb->data, skb->len,
+                                                       acked, GFP_ATOMIC);
+               }
+               rcu_read_unlock();
+
+               dev_kfree_skb_any(skb);
+       } else {
+               /* consumes skb */
+               skb_complete_wifi_ack(skb, acked);
+       }
+}
+
 static void ieee80211_report_used_skb(struct ieee80211_local *local,
                                      struct sk_buff *skb, bool dropped)
 {
@@ -439,32 +507,16 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
        if (dropped)
                acked = false;
 
-       if (info->flags & (IEEE80211_TX_INTFL_NL80211_FRAME_TX |
-                          IEEE80211_TX_INTFL_MLME_CONN_TX)) {
-               struct ieee80211_sub_if_data *sdata = NULL;
-               struct ieee80211_sub_if_data *iter_sdata;
-               u64 cookie = (unsigned long)skb;
+       if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) {
+               struct ieee80211_sub_if_data *sdata;
 
                rcu_read_lock();
 
-               if (skb->dev) {
-                       list_for_each_entry_rcu(iter_sdata, &local->interfaces,
-                                               list) {
-                               if (!iter_sdata->dev)
-                                       continue;
-
-                               if (skb->dev == iter_sdata->dev) {
-                                       sdata = iter_sdata;
-                                       break;
-                               }
-                       }
-               } else {
-                       sdata = rcu_dereference(local->p2p_sdata);
-               }
+               sdata = ieee80211_sdata_from_skb(local, skb);
 
                if (!sdata) {
                        skb->dev = NULL;
-               } else if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) {
+               } else {
                        unsigned int hdr_size =
                                ieee80211_hdrlen(hdr->frame_control);
 
@@ -478,38 +530,11 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
                                ieee80211_mgd_conn_tx_status(sdata,
                                                             hdr->frame_control,
                                                             acked);
-               } else if (ieee80211_is_nullfunc(hdr->frame_control) ||
-                          ieee80211_is_qos_nullfunc(hdr->frame_control)) {
-                       cfg80211_probe_status(sdata->dev, hdr->addr1,
-                                             cookie, acked, GFP_ATOMIC);
-               } else {
-                       cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data,
-                                               skb->len, acked, GFP_ATOMIC);
                }
 
                rcu_read_unlock();
-       }
-
-       if (unlikely(info->ack_frame_id)) {
-               struct sk_buff *ack_skb;
-               unsigned long flags;
-
-               spin_lock_irqsave(&local->ack_status_lock, flags);
-               ack_skb = idr_find(&local->ack_status_frames,
-                                  info->ack_frame_id);
-               if (ack_skb)
-                       idr_remove(&local->ack_status_frames,
-                                  info->ack_frame_id);
-               spin_unlock_irqrestore(&local->ack_status_lock, flags);
-
-               if (ack_skb) {
-                       if (!dropped) {
-                               /* consumes ack_skb */
-                               skb_complete_wifi_ack(ack_skb, acked);
-                       } else {
-                               dev_kfree_skb_any(ack_skb);
-                       }
-               }
+       } else if (info->ack_frame_id) {
+               ieee80211_report_ack_skb(local, info, acked, dropped);
        }
 }
 
@@ -532,8 +557,9 @@ static void ieee80211_lost_packet(struct sta_info *sta,
            !(info->flags & IEEE80211_TX_STAT_AMPDU))
                return;
 
-       sta->lost_packets++;
-       if (!sta->sta.tdls && sta->lost_packets < STA_LOST_PKT_THRESHOLD)
+       sta->status_stats.lost_packets++;
+       if (!sta->sta.tdls &&
+           sta->status_stats.lost_packets < STA_LOST_PKT_THRESHOLD)
                return;
 
        /*
@@ -543,14 +569,15 @@ static void ieee80211_lost_packet(struct sta_info *sta,
         * mechanism.
         */
        if (sta->sta.tdls &&
-           (sta->lost_packets < STA_LOST_TDLS_PKT_THRESHOLD ||
+           (sta->status_stats.lost_packets < STA_LOST_TDLS_PKT_THRESHOLD ||
             time_before(jiffies,
-                        sta->last_tdls_pkt_time + STA_LOST_TDLS_PKT_TIME)))
+                        sta->status_stats.last_tdls_pkt_time +
+                        STA_LOST_TDLS_PKT_TIME)))
                return;
 
        cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
-                                   sta->lost_packets, GFP_ATOMIC);
-       sta->lost_packets = 0;
+                                   sta->status_stats.lost_packets, GFP_ATOMIC);
+       sta->status_stats.lost_packets = 0;
 }
 
 static int ieee80211_tx_get_rates(struct ieee80211_hw *hw,
@@ -611,18 +638,18 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
                sta = container_of(pubsta, struct sta_info, sta);
 
                if (!acked)
-                       sta->tx_retry_failed++;
-               sta->tx_retry_count += retry_count;
+                       sta->status_stats.retry_failed++;
+               sta->status_stats.retry_count += retry_count;
 
                if (acked) {
-                       sta->last_rx = jiffies;
+                       sta->rx_stats.last_rx = jiffies;
 
-                       if (sta->lost_packets)
-                               sta->lost_packets = 0;
+                       if (sta->status_stats.lost_packets)
+                               sta->status_stats.lost_packets = 0;
 
                        /* Track when last TDLS packet was ACKed */
                        if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
-                               sta->last_tdls_pkt_time = jiffies;
+                               sta->status_stats.last_tdls_pkt_time = jiffies;
                } else {
                        ieee80211_lost_packet(sta, info);
                }
@@ -631,29 +658,83 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
        }
 
        if (acked || noack_success) {
-                   local->dot11TransmittedFrameCount++;
-                   if (!pubsta)
-                           local->dot11MulticastTransmittedFrameCount++;
-                   if (retry_count > 0)
-                           local->dot11RetryCount++;
-                   if (retry_count > 1)
-                           local->dot11MultipleRetryCount++;
+               I802_DEBUG_INC(local->dot11TransmittedFrameCount);
+               if (!pubsta)
+                       I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
+               if (retry_count > 0)
+                       I802_DEBUG_INC(local->dot11RetryCount);
+               if (retry_count > 1)
+                       I802_DEBUG_INC(local->dot11MultipleRetryCount);
        } else {
-               local->dot11FailedCount++;
+               I802_DEBUG_INC(local->dot11FailedCount);
        }
 }
 EXPORT_SYMBOL(ieee80211_tx_status_noskb);
 
-void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb,
+                         struct ieee80211_supported_band *sband,
+                         int retry_count, int shift, bool send_to_cooked)
 {
        struct sk_buff *skb2;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_sub_if_data *sdata;
+       struct net_device *prev_dev = NULL;
+       int rtap_len;
+
+       /* send frame to monitor interfaces now */
+       rtap_len = ieee80211_tx_radiotap_len(info);
+       if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
+               pr_err("ieee80211_tx_status: headroom too small\n");
+               dev_kfree_skb(skb);
+               return;
+       }
+       ieee80211_add_tx_radiotap_header(local, sband, skb, retry_count,
+                                        rtap_len, shift);
+
+       /* XXX: is this sufficient for BPF? */
+       skb_set_mac_header(skb, 0);
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+       skb->pkt_type = PACKET_OTHERHOST;
+       skb->protocol = htons(ETH_P_802_2);
+       memset(skb->cb, 0, sizeof(skb->cb));
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+                       if (!ieee80211_sdata_running(sdata))
+                               continue;
+
+                       if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) &&
+                           !send_to_cooked)
+                               continue;
+
+                       if (prev_dev) {
+                               skb2 = skb_clone(skb, GFP_ATOMIC);
+                               if (skb2) {
+                                       skb2->dev = prev_dev;
+                                       netif_rx(skb2);
+                               }
+                       }
+
+                       prev_dev = sdata->dev;
+               }
+       }
+       if (prev_dev) {
+               skb->dev = prev_dev;
+               netif_rx(skb);
+               skb = NULL;
+       }
+       rcu_read_unlock();
+       dev_kfree_skb(skb);
+}
+
+void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        __le16 fc;
        struct ieee80211_supported_band *sband;
-       struct ieee80211_sub_if_data *sdata;
-       struct net_device *prev_dev = NULL;
        struct sta_info *sta;
        struct rhash_head *tmp;
        int retry_count;
@@ -661,7 +742,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        bool send_to_cooked;
        bool acked;
        struct ieee80211_bar *bar;
-       int rtap_len;
        int shift = 0;
        int tid = IEEE80211_NUM_TIDS;
        const struct bucket_table *tbl;
@@ -703,10 +783,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                                        ieee80211_get_qos_ctl(hdr),
                                        sta, true, acked);
 
-               if ((local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) &&
+               if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL) &&
                    (ieee80211_is_data(hdr->frame_control)) &&
                    (rates_idx != -1))
-                       sta->last_tx_rate = info->status.rates[rates_idx];
+                       sta->tx_stats.last_rate =
+                               info->status.rates[rates_idx];
 
                if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
                    (ieee80211_is_data_qos(fc))) {
@@ -752,13 +833,15 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                        return;
                } else {
                        if (!acked)
-                               sta->tx_retry_failed++;
-                       sta->tx_retry_count += retry_count;
+                               sta->status_stats.retry_failed++;
+                       sta->status_stats.retry_count += retry_count;
 
                        if (ieee80211_is_data_present(fc)) {
                                if (!acked)
-                                       sta->tx_msdu_failed[tid]++;
-                               sta->tx_msdu_retries[tid] += retry_count;
+                                       sta->status_stats.msdu_failed[tid]++;
+
+                               sta->status_stats.msdu_retries[tid] +=
+                                       retry_count;
                        }
                }
 
@@ -770,25 +853,23 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                        ieee80211_frame_acked(sta, skb);
 
                if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) &&
-                   (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS))
+                   ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
                        ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data,
                                                acked, info->status.tx_time);
 
-               if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {
+               if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
                        if (info->flags & IEEE80211_TX_STAT_ACK) {
-                               if (sta->lost_packets)
-                                       sta->lost_packets = 0;
+                               if (sta->status_stats.lost_packets)
+                                       sta->status_stats.lost_packets = 0;
 
                                /* Track when last TDLS packet was ACKed */
                                if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
-                                       sta->last_tdls_pkt_time = jiffies;
+                                       sta->status_stats.last_tdls_pkt_time =
+                                               jiffies;
                        } else {
                                ieee80211_lost_packet(sta, info);
                        }
                }
-
-               if (acked)
-                       sta->last_ack_signal = info->status.ack_signal;
        }
 
        rcu_read_unlock();
@@ -802,13 +883,13 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        if ((info->flags & IEEE80211_TX_STAT_ACK) ||
            (info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED)) {
                if (ieee80211_is_first_frag(hdr->seq_ctrl)) {
-                       local->dot11TransmittedFrameCount++;
+                       I802_DEBUG_INC(local->dot11TransmittedFrameCount);
                        if (is_multicast_ether_addr(ieee80211_get_DA(hdr)))
-                               local->dot11MulticastTransmittedFrameCount++;
+                               I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
                        if (retry_count > 0)
-                               local->dot11RetryCount++;
+                               I802_DEBUG_INC(local->dot11RetryCount);
                        if (retry_count > 1)
-                               local->dot11MultipleRetryCount++;
+                               I802_DEBUG_INC(local->dot11MultipleRetryCount);
                }
 
                /* This counter shall be incremented for an acknowledged MPDU
@@ -818,14 +899,14 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                if (!is_multicast_ether_addr(hdr->addr1) ||
                    ieee80211_is_data(fc) ||
                    ieee80211_is_mgmt(fc))
-                       local->dot11TransmittedFragmentCount++;
+                       I802_DEBUG_INC(local->dot11TransmittedFragmentCount);
        } else {
                if (ieee80211_is_first_frag(hdr->seq_ctrl))
-                       local->dot11FailedCount++;
+                       I802_DEBUG_INC(local->dot11FailedCount);
        }
 
        if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc) &&
-           (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) &&
+           ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS) &&
            !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
            local->ps_sdata && !(local->scanning)) {
                if (info->flags & IEEE80211_TX_STAT_ACK) {
@@ -854,51 +935,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                return;
        }
 
-       /* send frame to monitor interfaces now */
-       rtap_len = ieee80211_tx_radiotap_len(info);
-       if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
-               pr_err("ieee80211_tx_status: headroom too small\n");
-               dev_kfree_skb(skb);
-               return;
-       }
-       ieee80211_add_tx_radiotap_header(local, sband, skb, retry_count,
-                                        rtap_len, shift);
-
-       /* XXX: is this sufficient for BPF? */
-       skb_set_mac_header(skb, 0);
-       skb->ip_summed = CHECKSUM_UNNECESSARY;
-       skb->pkt_type = PACKET_OTHERHOST;
-       skb->protocol = htons(ETH_P_802_2);
-       memset(skb->cb, 0, sizeof(skb->cb));
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-               if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
-                       if (!ieee80211_sdata_running(sdata))
-                               continue;
-
-                       if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) &&
-                           !send_to_cooked)
-                               continue;
-
-                       if (prev_dev) {
-                               skb2 = skb_clone(skb, GFP_ATOMIC);
-                               if (skb2) {
-                                       skb2->dev = prev_dev;
-                                       netif_rx(skb2);
-                               }
-                       }
-
-                       prev_dev = sdata->dev;
-               }
-       }
-       if (prev_dev) {
-               skb->dev = prev_dev;
-               netif_rx(skb);
-               skb = NULL;
-       }
-       rcu_read_unlock();
-       dev_kfree_skb(skb);
+       /* send to monitor interfaces */
+       ieee80211_tx_monitor(local, skb, sband, retry_count, shift, send_to_cooked);
 }
 EXPORT_SYMBOL(ieee80211_tx_status);