]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/mac80211/rx.c
mac80211: fix race condition between assoc_done and first EAP packet
[mv-sheeva.git] / net / mac80211 / rx.c
index 7fa8c6be7bf02564cd5714033fbdb8761b30b03d..edd46193af6fa0a0d22ba2ed6718a74f028ce101 100644 (file)
@@ -331,15 +331,18 @@ static void ieee80211_parse_qos(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);
-       int tid;
+       int tid, seqno_idx, security_idx;
 
        /* does the frame have a qos control field? */
        if (ieee80211_is_data_qos(hdr->frame_control)) {
                u8 *qc = ieee80211_get_qos_ctl(hdr);
                /* frame has qos control */
                tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
-               if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
+               if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT)
                        status->rx_flags |= IEEE80211_RX_AMSDU;
+
+               seqno_idx = tid;
+               security_idx = tid;
        } else {
                /*
                 * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"):
@@ -352,10 +355,15 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
                 *
                 * We also use that counter for non-QoS STAs.
                 */
-               tid = NUM_RX_DATA_QUEUES - 1;
+               seqno_idx = NUM_RX_DATA_QUEUES;
+               security_idx = 0;
+               if (ieee80211_is_mgmt(hdr->frame_control))
+                       security_idx = NUM_RX_DATA_QUEUES;
+               tid = 0;
        }
 
-       rx->queue = tid;
+       rx->seqno_idx = seqno_idx;
+       rx->security_idx = security_idx;
        /* Set skb->priority to 1d tag if highest order bit of TID is not set.
         * For now, set skb->priority to 0 for other cases. */
        rx->skb->priority = (tid > 7) ? 0 : tid;
@@ -810,7 +818,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
        /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
        if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
                if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
-                            rx->sta->last_seq_ctrl[rx->queue] ==
+                            rx->sta->last_seq_ctrl[rx->seqno_idx] ==
                             hdr->seq_ctrl)) {
                        if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
                                rx->local->dot11FrameDuplicateCount++;
@@ -818,7 +826,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
                        }
                        return RX_DROP_UNUSABLE;
                } else
-                       rx->sta->last_seq_ctrl[rx->queue] = hdr->seq_ctrl;
+                       rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl;
        }
 
        if (unlikely(rx->skb->len < 16)) {
@@ -842,8 +850,21 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
                      ieee80211_is_pspoll(hdr->frame_control)) &&
                     rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
                     rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
-                    (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC))))
+                    (!rx->sta || !test_sta_flags(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)
+                               return RX_CONTINUE;
+               }
                return RX_DROP_MONITOR;
+       }
 
        return RX_CONTINUE;
 }
@@ -1011,6 +1032,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        }
 
        if (rx->key) {
+               if (unlikely(rx->key->flags & KEY_FLAG_TAINTED))
+                       return RX_DROP_MONITOR;
+
                rx->key->tx_rx_count++;
                /* TODO: add threshold stuff again */
        } else {
@@ -1374,11 +1398,10 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        if (frag == 0) {
                /* This is the first fragment of a new frame. */
                entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
-                                                rx->queue, &(rx->skb));
+                                                rx->seqno_idx, &(rx->skb));
                if (rx->key && rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP &&
                    ieee80211_has_protected(fc)) {
-                       int queue = ieee80211_is_mgmt(fc) ?
-                               NUM_RX_DATA_QUEUES : rx->queue;
+                       int queue = rx->security_idx;
                        /* Store CCMP PN so that we can verify that the next
                         * fragment has a sequential PN value. */
                        entry->ccmp = 1;
@@ -1392,7 +1415,8 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        /* This is a fragment for a frame that should already be pending in
         * fragment cache. Add this fragment to the end of the pending entry.
         */
-       entry = ieee80211_reassemble_find(rx->sdata, frag, seq, rx->queue, hdr);
+       entry = ieee80211_reassemble_find(rx->sdata, frag, seq,
+                                         rx->seqno_idx, hdr);
        if (!entry) {
                I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
                return RX_DROP_MONITOR;
@@ -1412,8 +1436,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
                        if (pn[i])
                                break;
                }
-               queue = ieee80211_is_mgmt(fc) ?
-                       NUM_RX_DATA_QUEUES : rx->queue;
+               queue = rx->security_idx;
                rpn = rx->key->u.ccmp.rx_pn[queue];
                if (memcmp(pn, rpn, CCMP_PN_LEN))
                        return RX_DROP_UNUSABLE;
@@ -2210,12 +2233,29 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                        goto handled;
                }
                break;
+       case WLAN_CATEGORY_SELF_PROTECTED:
+               switch (mgmt->u.action.u.self_prot.action_code) {
+               case WLAN_SP_MESH_PEERING_OPEN:
+               case WLAN_SP_MESH_PEERING_CLOSE:
+               case WLAN_SP_MESH_PEERING_CONFIRM:
+                       if (!ieee80211_vif_is_mesh(&sdata->vif))
+                               goto invalid;
+                       if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
+                               /* userspace handles this frame */
+                               break;
+                       goto queue;
+               case WLAN_SP_MGK_INFORM:
+               case WLAN_SP_MGK_ACK:
+                       if (!ieee80211_vif_is_mesh(&sdata->vif))
+                               goto invalid;
+                       break;
+               }
+               break;
        case WLAN_CATEGORY_MESH_ACTION:
                if (!ieee80211_vif_is_mesh(&sdata->vif))
                        break;
-               goto queue;
-       case WLAN_CATEGORY_MESH_PATH_SEL:
-               if (!mesh_path_sel_is_hwmp(sdata))
+               if (mesh_action_is_path_sel(mgmt) &&
+                 (!mesh_path_sel_is_hwmp(sdata)))
                        break;
                goto queue;
        }
@@ -2590,7 +2630,9 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
                .sta = sta,
                .sdata = sta->sdata,
                .local = sta->local,
-               .queue = tid,
+               /* This is OK -- must be QoS data frame */
+               .security_idx = tid,
+               .seqno_idx = tid,
                .flags = 0,
        };
        struct tid_ampdu_rx *tid_agg_rx;
@@ -2779,7 +2821,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        if (ieee80211_is_data(fc)) {
                prev_sta = NULL;
 
-               for_each_sta_info(local, hdr->addr2, sta, tmp) {
+               for_each_sta_info_rx(local, hdr->addr2, sta, tmp) {
                        if (!prev_sta) {
                                prev_sta = sta;
                                continue;
@@ -2823,7 +2865,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                        continue;
                }
 
-               rx.sta = sta_info_get_bss(prev, hdr->addr2);
+               rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
                rx.sdata = prev;
                ieee80211_prepare_and_rx_handle(&rx, skb, false);
 
@@ -2831,7 +2873,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        }
 
        if (prev) {
-               rx.sta = sta_info_get_bss(prev, hdr->addr2);
+               rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
                rx.sdata = prev;
 
                if (ieee80211_prepare_and_rx_handle(&rx, skb, true))