mac80211: Fix radiotap header it_present on big endian CPUs
[safe/jmp/linux-2.6] / net / mac80211 / tx.c
index 4278e54..ad53ea9 100644 (file)
@@ -330,6 +330,22 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
        return TX_CONTINUE;
 }
 
+static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta,
+                            struct sk_buff *skb)
+{
+       if (!ieee80211_is_mgmt(fc))
+               return 0;
+
+       if (sta == NULL || !test_sta_flags(sta, WLAN_STA_MFP))
+               return 0;
+
+       if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *)
+                                           skb->data))
+               return 0;
+
+       return 1;
+}
+
 static ieee80211_tx_result
 ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 {
@@ -409,6 +425,9 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                tx->key = NULL;
        else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
                tx->key = key;
+       else if (ieee80211_is_mgmt(hdr->frame_control) &&
+                (key = rcu_dereference(tx->sdata->default_mgmt_key)))
+               tx->key = key;
        else if ((key = rcu_dereference(tx->sdata->default_key)))
                tx->key = key;
        else if (tx->sdata->drop_unencrypted &&
@@ -428,10 +447,19 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                        if (ieee80211_is_auth(hdr->frame_control))
                                break;
                case ALG_TKIP:
-               case ALG_CCMP:
                        if (!ieee80211_is_data_present(hdr->frame_control))
                                tx->key = NULL;
                        break;
+               case ALG_CCMP:
+                       if (!ieee80211_is_data_present(hdr->frame_control) &&
+                           !ieee80211_use_mfp(hdr->frame_control, tx->sta,
+                                              tx->skb))
+                               tx->key = NULL;
+                       break;
+               case ALG_AES_CMAC:
+                       if (!ieee80211_is_mgmt(hdr->frame_control))
+                               tx->key = NULL;
+                       break;
                }
        }
 
@@ -787,6 +815,8 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
                return ieee80211_crypto_tkip_encrypt(tx);
        case ALG_CCMP:
                return ieee80211_crypto_ccmp_encrypt(tx);
+       case ALG_AES_CMAC:
+               return ieee80211_crypto_aes_cmac_encrypt(tx);
        }
 
        /* not reached */
@@ -1053,7 +1083,6 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
        if (skb) {
                if (netif_subqueue_stopped(local->mdev, skb))
                        return IEEE80211_TX_AGAIN;
-               info =  IEEE80211_SKB_CB(skb);
 
                ret = local->ops->tx(local_to_hw(local), skb);
                if (ret)
@@ -1296,6 +1325,19 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
                return 0;
        }
 
+       if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
+           local->hw.conf.dynamic_ps_timeout > 0) {
+               if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+                       ieee80211_stop_queues_by_reason(&local->hw,
+                                       IEEE80211_QUEUE_STOP_REASON_PS);
+                       queue_work(local->hw.workqueue,
+                                       &local->dynamic_ps_disable_work);
+               }
+
+               mod_timer(&local->dynamic_ps_timer, jiffies +
+                       msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
+       }
+
        memset(info, 0, sizeof(*info));
 
        info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
@@ -1475,19 +1517,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
                goto fail;
        }
 
-       if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) &&
-           local->dynamic_ps_timeout > 0) {
-               if (local->hw.conf.flags & IEEE80211_CONF_PS) {
-                       ieee80211_stop_queues_by_reason(&local->hw,
-                                                       IEEE80211_QUEUE_STOP_REASON_PS);
-                       queue_work(local->hw.workqueue,
-                                  &local->dynamic_ps_disable_work);
-               }
-
-               mod_timer(&local->dynamic_ps_timer, jiffies +
-                         msecs_to_jiffies(local->dynamic_ps_timeout));
-       }
-
        nh_pos = skb_network_header(skb) - skb->data;
        h_pos = skb_transport_header(skb) - skb->data;