net/mlx4_en: Fix mixed PFC and Global pause user control requests
[pandora-kernel.git] / net / mac80211 / rx.c
index fb123e2..0cfb95a 100644 (file)
@@ -421,10 +421,16 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
                return RX_CONTINUE;
 
        if (test_bit(SCAN_HW_SCANNING, &local->scanning) ||
-           test_bit(SCAN_SW_SCANNING, &local->scanning) ||
            local->sched_scanning)
                return ieee80211_scan_rx(rx->sdata, skb);
 
+       if (test_bit(SCAN_SW_SCANNING, &local->scanning)) {
+               /* drop all the other packets during a software scan anyway */
+               if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED)
+                       dev_kfree_skb(skb);
+               return RX_QUEUED;
+       }
+
        /* scanning finished during invoking of handlers */
        I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
        return RX_DROP_UNUSABLE;
@@ -509,6 +515,11 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 
                if (ieee80211_is_action(hdr->frame_control)) {
                        u8 category;
+
+                       /* make sure category field is present */
+                       if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
+                               return RX_DROP_MONITOR;
+
                        mgmt = (struct ieee80211_mgmt *)hdr;
                        category = mgmt->u.action.category;
                        if (category != WLAN_CATEGORY_MESH_ACTION &&
@@ -610,7 +621,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
        index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
                                                tid_agg_rx->buf_size;
        if (!tid_agg_rx->reorder_buf[index] &&
-           tid_agg_rx->stored_mpdu_num > 1) {
+           tid_agg_rx->stored_mpdu_num) {
                /*
                 * No buffers ready to be released, but check whether any
                 * frames in the reorder buffer have timed out.
@@ -659,9 +670,10 @@ 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] + 1 +
-                         HT_RX_REORDER_BUF_TIMEOUT);
+               if (!tid_agg_rx->removed)
+                       mod_timer(&tid_agg_rx->reorder_timer,
+                                 tid_agg_rx->reorder_time[j] + 1 +
+                                 HT_RX_REORDER_BUF_TIMEOUT);
        } else {
                del_timer(&tid_agg_rx->reorder_timer);
        }
@@ -753,7 +765,8 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
        u16 sc;
        int tid;
 
-       if (!ieee80211_is_data_qos(hdr->frame_control))
+       if (!ieee80211_is_data_qos(hdr->frame_control) ||
+           is_multicast_ether_addr(hdr->addr1))
                goto dont_reorder;
 
        /*
@@ -810,8 +823,14 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
 
-       /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
-       if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
+       /*
+        * Drop duplicate 802.11 retransmissions
+        * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
+        */
+       if (rx->skb->len >= 24 && rx->sta &&
+           !ieee80211_is_ctl(hdr->frame_control) &&
+           !ieee80211_is_qos_nullfunc(hdr->frame_control) &&
+           !is_multicast_ether_addr(hdr->addr1)) {
                if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
                             rx->sta->last_seq_ctrl[rx->seqno_idx] ==
                             hdr->seq_ctrl)) {
@@ -848,14 +867,16 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
                     (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
                if (rx->sta && rx->sta->dummy &&
                    ieee80211_is_data_present(hdr->frame_control)) {
-                       u16 ethertype;
-                       u8 *payload;
-
-                       payload = rx->skb->data +
-                               ieee80211_hdrlen(hdr->frame_control);
-                       ethertype = (payload[6] << 8) | payload[7];
-                       if (cpu_to_be16(ethertype) ==
-                           rx->sdata->control_port_protocol)
+                       unsigned int hdrlen;
+                       __be16 ethertype;
+
+                       hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+                       if (rx->skb->len < hdrlen + 8)
+                               return RX_DROP_MONITOR;
+
+                       skb_copy_bits(rx->skb, hdrlen + 6, &ethertype, 2);
+                       if (ethertype == rx->sdata->control_port_protocol)
                                return RX_CONTINUE;
                }
                return RX_DROP_MONITOR;
@@ -1443,15 +1464,21 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
 
        hdr = (struct ieee80211_hdr *)rx->skb->data;
        fc = hdr->frame_control;
+
+       if (ieee80211_is_ctl(fc))
+               return RX_CONTINUE;
+
        sc = le16_to_cpu(hdr->seq_ctrl);
        frag = sc & IEEE80211_SCTL_FRAG;
 
-       if (likely((!ieee80211_has_morefrags(fc) && frag == 0) ||
-                  (rx->skb)->len < 24 ||
-                  is_multicast_ether_addr(hdr->addr1))) {
-               /* not fragmented */
-               goto out;
+       if (is_multicast_ether_addr(hdr->addr1)) {
+               rx->local->dot11MulticastReceivedFrameCount++;
+               goto out_no_led;
        }
+
+       if (likely(!ieee80211_has_morefrags(fc) && frag == 0))
+               goto out;
+
        I802_DEBUG_INC(rx->local->rx_handlers_fragments);
 
        if (skb_linearize(rx->skb))
@@ -1542,12 +1569,10 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        status->rx_flags |= IEEE80211_RX_FRAGMENTED;
 
  out:
+       ieee80211_led_rx(rx->local);
+ out_no_led:
        if (rx->sta)
                rx->sta->rx_packets++;
-       if (is_multicast_ether_addr(hdr->addr1))
-               rx->local->dot11MulticastReceivedFrameCount++;
-       else
-               ieee80211_led_rx(rx->local);
        return RX_CONTINUE;
 }
 
@@ -1829,16 +1854,22 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        if (!(status->rx_flags & IEEE80211_RX_AMSDU))
                return RX_CONTINUE;
 
-       if (ieee80211_has_a4(hdr->frame_control) &&
-           rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
-           !rx->sdata->u.vlan.sta)
-               return RX_DROP_UNUSABLE;
+       if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
+               switch (rx->sdata->vif.type) {
+               case NL80211_IFTYPE_AP_VLAN:
+                       if (!rx->sdata->u.vlan.sta)
+                               return RX_DROP_UNUSABLE;
+                       break;
+               case NL80211_IFTYPE_STATION:
+                       if (!rx->sdata->u.mgd.use_4addr)
+                               return RX_DROP_UNUSABLE;
+                       break;
+               default:
+                       return RX_DROP_UNUSABLE;
+               }
+       }
 
-       if (is_multicast_ether_addr(hdr->addr1) &&
-           ((rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
-             rx->sdata->u.vlan.sta) ||
-            (rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
-             rx->sdata->u.mgd.use_4addr)))
+       if (is_multicast_ether_addr(hdr->addr1))
                return RX_DROP_UNUSABLE;
 
        skb->dev = dev;
@@ -1881,15 +1912,33 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 
        hdr = (struct ieee80211_hdr *) skb->data;
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+       /* make sure fixed part of mesh header is there, also checks skb len */
+       if (!pskb_may_pull(rx->skb, hdrlen + 6))
+               return RX_DROP_MONITOR;
+
        mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
 
+       /* make sure full mesh header is there, also checks skb len */
+       if (!pskb_may_pull(rx->skb,
+                          hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr)))
+               return RX_DROP_MONITOR;
+
+       /* reload pointers */
+       hdr = (struct ieee80211_hdr *) skb->data;
+       mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+
+       if (ieee80211_drop_unencrypted(rx, hdr->frame_control))
+               return RX_DROP_MONITOR;
+
        /* frame is in RMC, don't forward */
        if (ieee80211_is_data(hdr->frame_control) &&
            is_multicast_ether_addr(hdr->addr1) &&
            mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata))
                return RX_DROP_MONITOR;
 
-       if (!ieee80211_is_data(hdr->frame_control))
+       if (!ieee80211_is_data(hdr->frame_control) ||
+           !(status->rx_flags & IEEE80211_RX_RA_MATCH))
                return RX_CONTINUE;
 
        if (!mesh_hdr->ttl)
@@ -1910,9 +1959,13 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                if (is_multicast_ether_addr(hdr->addr1)) {
                        mpp_addr = hdr->addr3;
                        proxied_addr = mesh_hdr->eaddr1;
-               } else {
+               } else if ((mesh_hdr->flags & MESH_FLAGS_AE) ==
+                           MESH_FLAGS_AE_A5_A6) {
+                       /* has_a4 already checked in ieee80211_rx_mesh_check */
                        mpp_addr = hdr->addr4;
                        proxied_addr = mesh_hdr->eaddr2;
+               } else {
+                       return RX_DROP_MONITOR;
                }
 
                rcu_read_lock();
@@ -1935,7 +1988,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 
        mesh_hdr->ttl--;
 
-       if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
+       {
                if (!mesh_hdr->ttl)
                        IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh,
                                                     dropped_frames_ttl);
@@ -2289,6 +2342,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                }
                break;
        case WLAN_CATEGORY_SELF_PROTECTED:
+               if (len < (IEEE80211_MIN_ACTION_SIZE +
+                          sizeof(mgmt->u.action.u.self_prot.action_code)))
+                       break;
+
                switch (mgmt->u.action.u.self_prot.action_code) {
                case WLAN_SP_MESH_PEERING_OPEN:
                case WLAN_SP_MESH_PEERING_CLOSE:
@@ -2307,6 +2364,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                }
                break;
        case WLAN_CATEGORY_MESH_ACTION:
+               if (len < (IEEE80211_MIN_ACTION_SIZE +
+                          sizeof(mgmt->u.action.u.mesh_action.action_code)))
+                       break;
+
                if (!ieee80211_vif_is_mesh(&sdata->vif))
                        break;
                if (mesh_action_is_path_sel(mgmt) &&
@@ -2383,7 +2444,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
         * frames that we didn't handle, including returning unknown
         * ones. For all other modes we will return them to the sender,
         * setting the 0x80 bit in the action category, as required by
-        * 802.11-2007 7.3.1.11.
+        * 802.11-2012 9.24.4.
         * Newer versions of hostapd shall also use the management frame
         * registration mechanisms, but older ones still use cooked
         * monitor interfaces so push all frames there.
@@ -2393,6 +2454,9 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
             sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
                return RX_DROP_MONITOR;
 
+       if (is_multicast_ether_addr(mgmt->da))
+               return RX_DROP_MONITOR;
+
        /* do not return rejected action frames */
        if (mgmt->u.action.category & 0x80)
                return RX_DROP_UNUSABLE;
@@ -2729,6 +2793,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
        case NL80211_IFTYPE_ADHOC:
                if (!bssid)
                        return 0;
+               if (compare_ether_addr(sdata->vif.addr, hdr->addr2) == 0 ||
+                   compare_ether_addr(sdata->u.ibss.bssid, hdr->addr2) == 0)
+                       return 0;
                if (ieee80211_is_beacon(hdr->frame_control)) {
                        return 1;
                }
@@ -2776,6 +2843,30 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
                              sdata->vif.p2p))
                                return 0;
                        status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
+               } else {
+                       /*
+                        * 802.11-2016 Table 9-26 says that for data frames,
+                        * A1 must be the BSSID - we've checked that already
+                        * but may have accepted the wildcard
+                        * (ff:ff:ff:ff:ff:ff).
+                        *
+                        * It also says:
+                        *      The BSSID of the Data frame is determined as
+                        *      follows:
+                        *      a) If the STA is contained within an AP or is
+                        *         associated with an AP, the BSSID is the
+                        *         address currently in use by the STA
+                        *         contained in the AP.
+                        *
+                        * So we should not accept data frames with an address
+                        * that's multicast.
+                        *
+                        * Accepting it also opens a security problem because
+                        * stations could encrypt it with the GTK and inject
+                        * traffic that way.
+                        */
+                       if (ieee80211_is_data(hdr->frame_control) && multicast)
+                               return 0;
                }
                break;
        case NL80211_IFTYPE_WDS:
@@ -2858,13 +2949,18 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                local->dot11ReceivedFragmentCount++;
 
        if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
-                    test_bit(SCAN_SW_SCANNING, &local->scanning)))
+                    test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
                status->rx_flags |= IEEE80211_RX_IN_SCAN;
 
-       if (ieee80211_is_mgmt(fc))
-               err = skb_linearize(skb);
-       else
+       if (ieee80211_is_mgmt(fc)) {
+               /* drop frame if too short for header */
+               if (skb->len < ieee80211_hdrlen(fc))
+                       err = -ENOBUFS;
+               else
+                       err = skb_linearize(skb);
+       } else {
                err = !pskb_may_pull(skb, ieee80211_hdrlen(fc));
+       }
 
        if (err) {
                dev_kfree_skb(skb);