Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
[linux-3.10.git] / net / mac80211 / tx.c
index 94de503..3392683 100644 (file)
@@ -35,6 +35,7 @@
 #define IEEE80211_TX_OK                0
 #define IEEE80211_TX_AGAIN     1
 #define IEEE80211_TX_FRAG_AGAIN        2
+#define IEEE80211_TX_PENDING   3
 
 /* misc utils */
 
@@ -330,6 +331,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,11 +426,17 @@ 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 &&
                 (tx->skb->protocol != cpu_to_be16(ETH_P_PAE)) &&
-                !(info->flags & IEEE80211_TX_CTL_INJECTED)) {
+                !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
+                (!ieee80211_is_robust_mgmt_frame(hdr) ||
+                 (ieee80211_is_action(hdr->frame_control) &&
+                  tx->sta && test_sta_flags(tx->sta, WLAN_STA_MFP)))) {
                I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
                return TX_DROP;
        } else
@@ -428,10 +451,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 +819,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 */
@@ -1052,8 +1086,7 @@ 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);
+                       return IEEE80211_TX_PENDING;
 
                ret = local->ops->tx(local_to_hw(local), skb);
                if (ret)
@@ -1179,8 +1212,9 @@ retry:
                 * queues, there's no reason for a driver to reject
                 * a frame there, warn and drop it.
                 */
-               if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
-                       goto drop;
+               if (ret != IEEE80211_TX_PENDING)
+                       if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
+                               goto drop;
 
                store = &local->pending_packet[queue];
 
@@ -1296,6 +1330,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;
@@ -1390,10 +1437,31 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
                                 struct net_device *dev)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_channel *chan = local->hw.conf.channel;
        struct ieee80211_radiotap_header *prthdr =
                (struct ieee80211_radiotap_header *)skb->data;
        u16 len_rthdr;
 
+       /*
+        * Frame injection is not allowed if beaconing is not allowed
+        * or if we need radar detection. Beaconing is usually not allowed when
+        * the mode or operation (Adhoc, AP, Mesh) does not support DFS.
+        * Passive scan is also used in world regulatory domains where
+        * your country is not known and as such it should be treated as
+        * NO TX unless the channel is explicitly allowed in which case
+        * your current regulatory domain would not have the passive scan
+        * flag.
+        *
+        * Since AP mode uses monitor interfaces to inject/TX management
+        * frames we can make AP mode the exception to this rule once it
+        * supports radar detection as its implementation can deal with
+        * radar detection by itself. We can do that later by adding a
+        * monitor flag interfaces used for AP support.
+        */
+       if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
+            IEEE80211_CHAN_PASSIVE_SCAN)))
+               goto fail;
+
        /* check for not even having the fixed radiotap header part */
        if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
                goto fail; /* too short to be possibly valid */
@@ -1477,19 +1545,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;