]> err.no Git - linux-2.6/blobdiff - net/mac80211/rx.c
[MAC80211]: ignore key index on pairwise key (WEP only)
[linux-2.6] / net / mac80211 / rx.c
index 976b646a40decebc13f03db55be670bfb12f7833..28b8b6af4c42cca3c92082551d28ed588b3f8664 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/rcupdate.h>
 #include <net/mac80211.h>
 #include <net/ieee80211_radiotap.h>
 
@@ -93,8 +94,6 @@ ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx)
         * 1 usec = 1/8 * (1080 / 10) = 13.5 */
 
        if (mode->mode == MODE_IEEE80211A ||
-           mode->mode == MODE_ATHEROS_TURBO ||
-           mode->mode == MODE_ATHEROS_TURBOG ||
            (mode->mode == MODE_IEEE80211G &&
             rate->flags & IEEE80211_RATE_ERP))
                hdrtime = CHAN_UTIL_HDR_SHORT;
@@ -311,6 +310,7 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
        int keyidx;
        int hdrlen;
+       struct ieee80211_key *stakey = NULL;
 
        /*
         * Key selection 101
@@ -327,8 +327,15 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
         * frames can also use key indizes like GTKs. Hence, if we don't
         * have a PTK/STK we check the key index for a WEP key.
         *
+        * Note that in a regular BSS, multicast frames are sent by the
+        * AP only, associated stations unicast the frame to the AP first
+        * which then multicasts it on their behalf.
+        *
         * There is also a slight problem in IBSS mode: GTKs are negotiated
         * with each station, that is something we don't currently handle.
+        * The spec seems to expect that one negotiates the same key with
+        * every station but there's no such requirement; VLANs could be
+        * possible.
         */
 
        if (!(rx->fc & IEEE80211_FCTL_PROTECTED))
@@ -341,8 +348,11 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
        if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
                return TXRX_CONTINUE;
 
-       if (!is_multicast_ether_addr(hdr->addr1) && rx->sta && rx->sta->key) {
-               rx->key = rx->sta->key;
+       if (rx->sta)
+               stakey = rcu_dereference(rx->sta->key);
+
+       if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
+               rx->key = stakey;
        } else {
                /*
                 * The device doesn't give us the IV so we won't be
@@ -353,7 +363,8 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
                 * we somehow allow the driver to tell us which key
                 * the hardware used if this flag is set?
                 */
-               if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV))
+               if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
+                   (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED))
                        return TXRX_CONTINUE;
 
                hdrlen = ieee80211_get_hdrlen(rx->fc);
@@ -367,7 +378,7 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
                 */
                keyidx = rx->skb->data[hdrlen + 3] >> 6;
 
-               rx->key = rx->sdata->keys[keyidx];
+               rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
 
                /*
                 * RSNA-protected unicast frames should always be sent with
@@ -485,12 +496,9 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
 
        sta->rx_fragments++;
        sta->rx_bytes += rx->skb->len;
-       sta->last_rssi = (sta->last_rssi * 15 +
-                         rx->u.rx.status->ssi) / 16;
-       sta->last_signal = (sta->last_signal * 15 +
-                           rx->u.rx.status->signal) / 16;
-       sta->last_noise = (sta->last_noise * 15 +
-                          rx->u.rx.status->noise) / 16;
+       sta->last_rssi = rx->u.rx.status->ssi;
+       sta->last_signal = rx->u.rx.status->signal;
+       sta->last_noise = rx->u.rx.status->noise;
 
        if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) {
                /* Change STA power saving mode only in the end of a frame
@@ -527,8 +535,8 @@ ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx)
                return TXRX_CONTINUE;
 
        /* Check for weak IVs, if hwaccel did not remove IV from the frame */
-       if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) ||
-           (rx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT))
+       if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) ||
+           !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED))
                if (ieee80211_wep_is_weak_iv(rx->skb, rx->key))
                        rx->sta->wep_weak_iv_count++;
 
@@ -552,15 +560,14 @@ ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx)
                return TXRX_DROP;
        }
 
-       if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED) ||
-           (rx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) {
+       if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
                if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) {
                        if (net_ratelimit())
                                printk(KERN_DEBUG "%s: RX WEP frame, decrypt "
                                       "failed\n", rx->dev->name);
                        return TXRX_DROP;
                }
-       } else if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) {
+       } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) {
                ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
                /* remove ICV */
                skb_trim(rx->skb, rx->skb->len - 4);
@@ -891,14 +898,10 @@ static ieee80211_txrx_result
 ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx)
 {
        /*
-        * Pass through unencrypted frames if the hardware might have
-        * decrypted them already without telling us, but that can only
-        * be true if we either didn't find a key or the found key is
-        * uploaded to the hardware.
+        * Pass through unencrypted frames if the hardware has
+        * decrypted them already.
         */
-       if ((rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) &&
-           (!rx->key ||
-            !(rx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)))
+       if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED)
                return TXRX_CONTINUE;
 
        /* Drop unencrypted frames if key is set. */
@@ -992,9 +995,10 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                memcpy(dst, hdr->addr1, ETH_ALEN);
                memcpy(src, hdr->addr3, ETH_ALEN);
 
-               if (sdata->type != IEEE80211_IF_TYPE_STA) {
+               if (sdata->type != IEEE80211_IF_TYPE_STA ||
+                   (is_multicast_ether_addr(dst) &&
+                    !compare_ether_addr(src, dev->dev_addr)))
                        return TXRX_DROP;
-               }
                break;
        case 0:
                /* DA SA BSSID */
@@ -1205,8 +1209,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
                goto ignore;
        }
 
-       if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) &&
-           rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) {
+       if (rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) {
                /* AP with Pairwise keys support should never receive Michael
                 * MIC errors for non-zero keyidx because these are reserved
                 * for group keys and only the AP is sending real multicast
@@ -1360,6 +1363,12 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
                skb_pull(skb, radiotap_len);
        }
 
+       /*
+        * key references are protected using RCU and this requires that
+        * we are in a read-site RCU section during receive processing
+        */
+       rcu_read_lock();
+
        hdr = (struct ieee80211_hdr *) skb->data;
        memset(&rx, 0, sizeof(rx));
        rx.skb = skb;
@@ -1394,12 +1403,13 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
        skb = rx.skb;
 
        skb_push(skb, radiotap_len);
-       if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) &&
+       if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) &&
            !local->iff_promiscs && !is_multicast_ether_addr(hdr->addr1)) {
                rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
                ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
                                             rx.sta);
                sta_info_put(sta);
+               rcu_read_unlock();
                return;
        }
 
@@ -1461,6 +1471,8 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
        read_unlock(&local->sub_if_lock);
 
  end:
+       rcu_read_unlock();
+
        if (sta)
                sta_info_put(sta);
 }