mac80211: fix max HT rate processing on mac80211
[safe/jmp/linux-2.6] / net / mac80211 / rx.c
index 51cb8bc..006cf89 100644 (file)
@@ -507,7 +507,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 
                if (ieee80211_is_action(hdr->frame_control)) {
                        mgmt = (struct ieee80211_mgmt *)hdr;
-                       if (mgmt->u.action.category != PLINK_CATEGORY)
+                       if (mgmt->u.action.category != MESH_PLINK_CATEGORY)
                                return RX_DROP_MONITOR;
                        return RX_CONTINUE;
                }
@@ -781,7 +781,7 @@ static void ap_sta_ps_start(struct sta_info *sta)
        struct ieee80211_local *local = sdata->local;
 
        atomic_inc(&sdata->bss->num_sta_ps);
-       set_sta_flags(sta, WLAN_STA_PS);
+       set_sta_flags(sta, WLAN_STA_PS_STA);
        drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta);
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
@@ -789,38 +789,28 @@ static void ap_sta_ps_start(struct sta_info *sta)
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 }
 
-static int ap_sta_ps_end(struct sta_info *sta)
+static void ap_sta_ps_end(struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
-       struct ieee80211_local *local = sdata->local;
-       int sent, buffered;
 
        atomic_dec(&sdata->bss->num_sta_ps);
 
-       clear_sta_flags(sta, WLAN_STA_PS);
-       drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta);
-
-       if (!skb_queue_empty(&sta->ps_tx_buf))
-               sta_info_clear_tim_bit(sta);
+       clear_sta_flags(sta, WLAN_STA_PS_STA);
 
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n",
               sdata->dev->name, sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
-       /* Send all buffered frames to the station */
-       sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered);
-       buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf);
-       sent += buffered;
-       local->total_ps_buffered -= buffered;
-
+       if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) {
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
-              "since STA not sleeping anymore\n", sdata->dev->name,
-              sta->sta.addr, sta->sta.aid, sent - buffered, buffered);
+               printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
+                      sdata->dev->name, sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+               return;
+       }
 
-       return sent;
+       ieee80211_sta_ps_deliver_wakeup(sta);
 }
 
 static ieee80211_rx_result debug_noinline
@@ -868,7 +858,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
        if (!ieee80211_has_morefrags(hdr->frame_control) &&
            (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
             rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
-               if (test_sta_flags(sta, WLAN_STA_PS)) {
+               if (test_sta_flags(sta, WLAN_STA_PS_STA)) {
                        /*
                         * Ignore doze->wake transitions that are
                         * indicated by non-data frames, the standard
@@ -879,7 +869,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                         */
                        if (ieee80211_is_data(hdr->frame_control) &&
                            !ieee80211_has_pm(hdr->frame_control))
-                               rx->sent_ps_buffered += ap_sta_ps_end(sta);
+                               ap_sta_ps_end(sta);
                } else {
                        if (ieee80211_has_pm(hdr->frame_control))
                                ap_sta_ps_start(sta);
@@ -1096,9 +1086,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
-       struct sk_buff *skb;
-       int no_pending_pkts;
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
        __le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control;
 
        if (likely(!rx->sta || !ieee80211_is_pspoll(fc) ||
@@ -1109,56 +1097,10 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
            (sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
                return RX_DROP_UNUSABLE;
 
-       skb = skb_dequeue(&rx->sta->tx_filtered);
-       if (!skb) {
-               skb = skb_dequeue(&rx->sta->ps_tx_buf);
-               if (skb)
-                       rx->local->total_ps_buffered--;
-       }
-       no_pending_pkts = skb_queue_empty(&rx->sta->tx_filtered) &&
-               skb_queue_empty(&rx->sta->ps_tx_buf);
-
-       if (skb) {
-               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-               struct ieee80211_hdr *hdr =
-                       (struct ieee80211_hdr *) skb->data;
-
-               /*
-                * Tell TX path to send this frame even though the STA may
-                * still remain is PS mode after this frame exchange.
-                */
-               info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE;
-
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n",
-                      rx->sta->sta.addr, rx->sta->sta.aid,
-                      skb_queue_len(&rx->sta->ps_tx_buf));
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-
-               /* Use MoreData flag to indicate whether there are more
-                * buffered frames for this STA */
-               if (no_pending_pkts)
-                       hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
-               else
-                       hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
-
-               ieee80211_add_pending_skb(rx->local, skb);
-
-               if (no_pending_pkts)
-                       sta_info_clear_tim_bit(rx->sta);
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       } else if (!rx->sent_ps_buffered) {
-               /*
-                * FIXME: This can be the result of a race condition between
-                *        us expiring a frame and the station polling for it.
-                *        Should we send it a null-func frame indicating we
-                *        have nothing buffered for it?
-                */
-               printk(KERN_DEBUG "%s: STA %pM sent PS Poll even "
-                      "though there are no buffered frames for it\n",
-                      rx->dev->name, rx->sta->sta.addr);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-       }
+       if (!test_sta_flags(rx->sta, WLAN_STA_PS_DRIVER))
+               ieee80211_sta_ps_deliver_poll_response(rx->sta);
+       else
+               set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
 
        /* Free PS Poll skb here instead of returning RX_DROP that would
         * count as an dropped frame. */
@@ -1239,6 +1181,13 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
 {
        struct net_device *dev = rx->dev;
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->use_4addr &&
+           ieee80211_has_a4(hdr->frame_control))
+               return -1;
+       if (sdata->use_4addr && is_multicast_ether_addr(hdr->addr1))
+               return -1;
 
        return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type);
 }
@@ -1592,6 +1541,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
 {
        struct net_device *dev = rx->dev;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        __le16 fc = hdr->frame_control;
        int err;
 
@@ -1601,6 +1551,14 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
        if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
                return RX_DROP_MONITOR;
 
+       /*
+        * Allow the cooked monitor interface of an AP to see 4-addr frames so
+        * that a 4-addr station can be detected and moved into a separate VLAN
+        */
+       if (ieee80211_has_a4(hdr->frame_control) &&
+           sdata->vif.type == NL80211_IFTYPE_AP)
+               return RX_DROP_MONITOR;
+
        err = __ieee80211_data_to_8023(rx);
        if (unlikely(err))
                return RX_DROP_UNUSABLE;
@@ -2041,7 +1999,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_STATION:
-               if (!bssid)
+               if (!bssid && !sdata->use_4addr)
                        return 0;
                if (!multicast &&
                    compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
@@ -2483,9 +2441,21 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
                goto drop;
 
        if (status->flag & RX_FLAG_HT) {
-               /* rate_idx is MCS index */
-               if (WARN_ON(status->rate_idx < 0 ||
-                           status->rate_idx >= 76))
+               /*
+                * rate_idx is MCS index, which can be [0-76] as documented on:
+                *
+                * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n
+                *
+                * Anything else would be some sort of driver or hardware error.
+                * The driver should catch hardware errors.
+                */
+               if (WARN((status->rate_idx < 0 ||
+                        status->rate_idx > 76),
+                        "Rate marked as an HT rate but passed "
+                        "status->rate_idx is not "
+                        "an MCS index [0-76]: %d (0x%02x)\n",
+                        status->rate_idx,
+                        status->rate_idx))
                        goto drop;
                /* HT rates are not in the table - use the highest legacy rate
                 * for now since other parts of mac80211 may not yet be fully