md/raid0: apply base queue limits *before* disk_stack_limits
[firefly-linux-kernel-4.4.55.git] / net / mac80211 / rx.c
index 5dae166cb7f56b7cb9d9097496db9e8fa8d755ce..5bc0b88d9eb1331a0dd47aab05ffa01c7a0bc845 100644 (file)
@@ -42,6 +42,51 @@ static inline void ieee80211_rx_stats(struct net_device *dev, u32 len)
        u64_stats_update_end(&tstats->syncp);
 }
 
+static u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
+                              enum nl80211_iftype type)
+{
+       __le16 fc = hdr->frame_control;
+
+       if (ieee80211_is_data(fc)) {
+               if (len < 24) /* drop incorrect hdr len (data) */
+                       return NULL;
+
+               if (ieee80211_has_a4(fc))
+                       return NULL;
+               if (ieee80211_has_tods(fc))
+                       return hdr->addr1;
+               if (ieee80211_has_fromds(fc))
+                       return hdr->addr2;
+
+               return hdr->addr3;
+       }
+
+       if (ieee80211_is_mgmt(fc)) {
+               if (len < 24) /* drop incorrect hdr len (mgmt) */
+                       return NULL;
+               return hdr->addr3;
+       }
+
+       if (ieee80211_is_ctl(fc)) {
+               if (ieee80211_is_pspoll(fc))
+                       return hdr->addr1;
+
+               if (ieee80211_is_back_req(fc)) {
+                       switch (type) {
+                       case NL80211_IFTYPE_STATION:
+                               return hdr->addr2;
+                       case NL80211_IFTYPE_AP:
+                       case NL80211_IFTYPE_AP_VLAN:
+                               return hdr->addr1;
+                       default:
+                               break; /* fall through to the return */
+                       }
+               }
+       }
+
+       return NULL;
+}
+
 /*
  * monitor mode reception
  *
@@ -77,8 +122,7 @@ static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len,
        hdr = (void *)(skb->data + rtap_vendor_space);
 
        if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
-                           RX_FLAG_FAILED_PLCP_CRC |
-                           RX_FLAG_AMPDU_IS_ZEROLEN))
+                           RX_FLAG_FAILED_PLCP_CRC))
                return true;
 
        if (unlikely(skb->len < 16 + present_fcs_len + rtap_vendor_space))
@@ -346,10 +390,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                        cpu_to_le32(1 << IEEE80211_RADIOTAP_AMPDU_STATUS);
                put_unaligned_le32(status->ampdu_reference, pos);
                pos += 4;
-               if (status->flag & RX_FLAG_AMPDU_REPORT_ZEROLEN)
-                       flags |= IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN;
-               if (status->flag & RX_FLAG_AMPDU_IS_ZEROLEN)
-                       flags |= IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN;
                if (status->flag & RX_FLAG_AMPDU_LAST_KNOWN)
                        flags |= IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN;
                if (status->flag & RX_FLAG_AMPDU_IS_LAST)
@@ -1093,11 +1133,6 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
 
-       if (unlikely(rx->skb->len < 16)) {
-               I802_DEBUG_INC(rx->local->rx_handlers_drop_short);
-               return RX_DROP_MONITOR;
-       }
-
        /* Drop disallowed frame classes based on STA auth/assoc state;
         * IEEE 802.11, Chap 5.5.
         *
@@ -1240,22 +1275,22 @@ static void sta_ps_end(struct sta_info *sta)
        ieee80211_sta_ps_deliver_wakeup(sta);
 }
 
-int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)
+int ieee80211_sta_ps_transition(struct ieee80211_sta *pubsta, bool start)
 {
-       struct sta_info *sta_inf = container_of(sta, struct sta_info, sta);
+       struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
        bool in_ps;
 
-       WARN_ON(!ieee80211_hw_check(&sta_inf->local->hw, AP_LINK_PS));
+       WARN_ON(!ieee80211_hw_check(&sta->local->hw, AP_LINK_PS));
 
        /* Don't let the same PS state be set twice */
-       in_ps = test_sta_flag(sta_inf, WLAN_STA_PS_STA);
+       in_ps = test_sta_flag(sta, WLAN_STA_PS_STA);
        if ((start && in_ps) || (!start && !in_ps))
                return -EINVAL;
 
        if (start)
-               sta_ps_start(sta_inf);
+               sta_ps_start(sta);
        else
-               sta_ps_end(sta_inf);
+               sta_ps_end(sta);
 
        return 0;
 }
@@ -1393,7 +1428,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
        sta->rx_bytes += rx->skb->len;
        if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
                sta->last_signal = status->signal;
-               ewma_add(&sta->avg_signal, -status->signal);
+               ewma_signal_add(&sta->avg_signal, -status->signal);
        }
 
        if (status->chains) {
@@ -1405,7 +1440,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                                continue;
 
                        sta->chain_signal_last[i] = signal;
-                       ewma_add(&sta->chain_signal_avg[i], -signal);
+                       ewma_signal_add(&sta->chain_signal_avg[i], -signal);
                }
        }
 
@@ -1647,7 +1682,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                if (unlikely(rx->key->flags & KEY_FLAG_TAINTED))
                        return RX_DROP_MONITOR;
 
-               rx->key->tx_rx_count++;
                /* TODO: add threshold stuff again */
        } else {
                return RX_DROP_MONITOR;
@@ -1883,7 +1917,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
 
        /* Complete frame has been reassembled - process it now */
        status = IEEE80211_SKB_RXCB(rx->skb);
-       status->rx_flags |= IEEE80211_RX_FRAGMENTED;
 
  out:
        ieee80211_led_rx(rx->local);
@@ -2108,9 +2141,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
                /* deliver to local stack */
                skb->protocol = eth_type_trans(skb, dev);
                memset(skb->cb, 0, sizeof(skb->cb));
-               if (!(rx->flags & IEEE80211_RX_REORDER_TIMER) &&
-                   rx->local->napi)
-                       napi_gro_receive(rx->local->napi, skb);
+               if (rx->napi)
+                       napi_gro_receive(rx->napi, skb);
                else
                        netif_receive_skb(skb);
        }
@@ -2378,9 +2410,8 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
                    tf->category == WLAN_CATEGORY_TDLS &&
                    (tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST ||
                     tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE)) {
-                       rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TDLS_CHSW;
-                       skb_queue_tail(&sdata->skb_queue, rx->skb);
-                       ieee80211_queue_work(&rx->local->hw, &sdata->work);
+                       skb_queue_tail(&local->skb_queue_tdls_chsw, rx->skb);
+                       schedule_work(&local->tdls_chsw_work);
                        if (rx->sta)
                                rx->sta->rx_packets++;
 
@@ -3004,7 +3035,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
        return RX_QUEUED;
 }
 
-/* TODO: use IEEE80211_RX_FRAGMENTED */
 static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
                                        struct ieee80211_rate *rate)
 {
@@ -3216,7 +3246,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
                /* This is OK -- must be QoS data frame */
                .security_idx = tid,
                .seqno_idx = tid,
-               .flags = IEEE80211_RX_REORDER_TIMER,
+               .napi = NULL, /* must be NULL to not have races */
        };
        struct tid_ampdu_rx *tid_agg_rx;
 
@@ -3286,7 +3316,7 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
        case NL80211_IFTYPE_OCB:
                if (!bssid)
                        return false;
-               if (ieee80211_is_beacon(hdr->frame_control))
+               if (!ieee80211_is_data_present(hdr->frame_control))
                        return false;
                if (!is_broadcast_ether_addr(bssid))
                        return false;
@@ -3393,7 +3423,8 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
  * be called with rcu_read_lock protection.
  */
 static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
-                                        struct sk_buff *skb)
+                                        struct sk_buff *skb,
+                                        struct napi_struct *napi)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata;
@@ -3409,6 +3440,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        memset(&rx, 0, sizeof(rx));
        rx.skb = skb;
        rx.local = local;
+       rx.napi = napi;
 
        if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
                I802_DEBUG_INC(local->dot11ReceivedFragmentCount);
@@ -3510,7 +3542,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
  * This is the receive path handler. It is called by a low level driver when an
  * 802.11 MPDU is received from the hardware.
  */
-void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
+void ieee80211_rx_napi(struct ieee80211_hw *hw, struct sk_buff *skb,
+                      struct napi_struct *napi)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_rate *rate = NULL;
@@ -3609,7 +3642,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
        ieee80211_tpt_led_trig_rx(local,
                        ((struct ieee80211_hdr *)skb->data)->frame_control,
                        skb->len);
-       __ieee80211_rx_handle_packet(hw, skb);
+       __ieee80211_rx_handle_packet(hw, skb, napi);
 
        rcu_read_unlock();
 
@@ -3617,7 +3650,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
  drop:
        kfree_skb(skb);
 }
-EXPORT_SYMBOL(ieee80211_rx);
+EXPORT_SYMBOL(ieee80211_rx_napi);
 
 /* This is a version of the rx handler that can be called from hard irq
  * context. Post the skb on the queue and schedule the tasklet */