Merge tag 'char-misc-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[firefly-linux-kernel-4.4.55.git] / net / mac80211 / status.c
index 461594966b65ed1f356522336346add77e0835f7..45628f37c083aa72575fcc0a0241b1aefc0cb5ad 100644 (file)
@@ -181,7 +181,7 @@ 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)
+       if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
                sta->last_rx = jiffies;
 
        if (ieee80211_is_data_qos(mgmt->frame_control)) {
@@ -414,8 +414,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 +428,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,28 +506,12 @@ 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;
@@ -478,38 +529,14 @@ 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);
+                       /* we assign ack frame ID for the others */
+                       WARN_ON(1);
                }
 
                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);
        }
 }
 
@@ -703,7 +730,7 @@ 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];
@@ -770,11 +797,11 @@ 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;
@@ -825,7 +852,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        }
 
        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) {