sctp: Fix regression introduced by new sctp_connectx api
[safe/jmp/linux-2.6] / net / mac80211 / rx.c
index 25a669c..7170bf4 100644 (file)
@@ -489,12 +489,21 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
+       char *dev_addr = rx->dev->dev_addr;
 
        if (ieee80211_is_data(hdr->frame_control)) {
-               if (!ieee80211_has_a4(hdr->frame_control))
-                       return RX_DROP_MONITOR;
-               if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0)
-                       return RX_DROP_MONITOR;
+               if (is_multicast_ether_addr(hdr->addr1)) {
+                       if (ieee80211_has_tods(hdr->frame_control) ||
+                               !ieee80211_has_fromds(hdr->frame_control))
+                               return RX_DROP_MONITOR;
+                       if (memcmp(hdr->addr3, dev_addr, ETH_ALEN) == 0)
+                               return RX_DROP_MONITOR;
+               } else {
+                       if (!ieee80211_has_a4(hdr->frame_control))
+                               return RX_DROP_MONITOR;
+                       if (memcmp(hdr->addr4, dev_addr, ETH_ALEN) == 0)
+                               return RX_DROP_MONITOR;
+               }
        }
 
        /* If there is not an established peer link and this is not a peer link
@@ -527,7 +536,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 
        if (ieee80211_is_data(hdr->frame_control) &&
            is_multicast_ether_addr(hdr->addr1) &&
-           mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->sdata))
+           mesh_rmc_check(hdr->addr3, msh_h_get(hdr, hdrlen), rx->sdata))
                return RX_DROP_MONITOR;
 #undef msh_h_get
 
@@ -1495,7 +1504,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                /* illegal frame */
                return RX_DROP_MONITOR;
 
-       if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){
+       if (!is_multicast_ether_addr(hdr->addr1) &&
+                       (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6)) {
                struct mesh_path *mppath;
 
                rcu_read_lock();
@@ -1512,7 +1522,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                rcu_read_unlock();
        }
 
-       if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0)
+       /* Frame has reached destination.  Don't forward */
+       if (!is_multicast_ether_addr(hdr->addr1) &&
+                       compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0)
                return RX_CONTINUE;
 
        mesh_hdr->ttl--;
@@ -1532,27 +1544,32 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                                                   rx->dev->name);
 
                        fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
-                       /*
-                        * Save TA to addr1 to send TA a path error if a
-                        * suitable next hop is not found
-                        */
-                       memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN);
                        memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN);
                        info = IEEE80211_SKB_CB(fwd_skb);
                        memset(info, 0, sizeof(*info));
                        info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                        info->control.vif = &rx->sdata->vif;
                        ieee80211_select_queue(local, fwd_skb);
-                       if (is_multicast_ether_addr(fwd_hdr->addr3))
-                               memcpy(fwd_hdr->addr1, fwd_hdr->addr3,
-                                               ETH_ALEN);
+                       if (is_multicast_ether_addr(fwd_hdr->addr1))
+                               IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+                                                               fwded_mcast);
                        else {
-                               int err = mesh_nexthop_lookup(fwd_skb, sdata);
+                               int err;
+                               /*
+                                * Save TA to addr1 to send TA a path error if a
+                                * suitable next hop is not found
+                                */
+                               memcpy(fwd_hdr->addr1, fwd_hdr->addr2,
+                                               ETH_ALEN);
+                               err = mesh_nexthop_lookup(fwd_skb, sdata);
                                /* Failed to immediately resolve next hop:
                                 * fwded frame was dropped or will be added
                                 * later to the pending skb queue.  */
                                if (err)
                                        return RX_DROP_MONITOR;
+
+                               IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+                                                               fwded_unicast);
                        }
                        IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
                                                     fwded_frames);
@@ -1560,7 +1577,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                }
        }
 
-       if (is_multicast_ether_addr(hdr->addr3) ||
+       if (is_multicast_ether_addr(hdr->addr1) ||
            rx->dev->flags & IFF_PROMISC)
                return RX_CONTINUE;
        else
@@ -2147,11 +2164,17 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 
        skb = rx.skb;
 
-       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+       if (rx.sdata && ieee80211_is_data(hdr->frame_control)) {
+               rx.flags |= IEEE80211_RX_RA_MATCH;
+               prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
+               if (prepares)
+                       prev = rx.sdata;
+       } else list_for_each_entry_rcu(sdata, &local->interfaces, list) {
                if (!netif_running(sdata->dev))
                        continue;
 
-               if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
+               if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+                   sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                        continue;
 
                rx.flags |= IEEE80211_RX_RA_MATCH;
@@ -2423,24 +2446,22 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
  * This is the receive path handler. It is called by a low level driver when an
  * 802.11 MPDU is received from the hardware.
  */
-void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
+void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_rate *rate = NULL;
        struct ieee80211_supported_band *sband;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 
-       if (status->band < 0 ||
-           status->band >= IEEE80211_NUM_BANDS) {
-               WARN_ON(1);
-               return;
-       }
+       WARN_ON_ONCE(softirq_count() == 0);
+
+       if (WARN_ON(status->band < 0 ||
+                   status->band >= IEEE80211_NUM_BANDS))
+               goto drop;
 
        sband = local->hw.wiphy->bands[status->band];
-       if (!sband) {
-               WARN_ON(1);
-               return;
-       }
+       if (WARN_ON(!sband))
+               goto drop;
 
        /*
         * If we're suspending, it is possible although not too likely
@@ -2449,16 +2470,21 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
         * that might, for example, cause stations to be added or other
         * driver callbacks be invoked.
         */
-       if (unlikely(local->quiescing || local->suspended)) {
-               kfree_skb(skb);
-               return;
-       }
+       if (unlikely(local->quiescing || local->suspended))
+               goto drop;
+
+       /*
+        * The same happens when we're not even started,
+        * but that's worth a warning.
+        */
+       if (WARN_ON(!local->started))
+               goto drop;
 
        if (status->flag & RX_FLAG_HT) {
                /* rate_idx is MCS index */
                if (WARN_ON(status->rate_idx < 0 ||
                            status->rate_idx >= 76))
-                       return;
+                       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
                 * MCS aware. */
@@ -2466,7 +2492,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
        } else {
                if (WARN_ON(status->rate_idx < 0 ||
                            status->rate_idx >= sband->n_bitrates))
-                       return;
+                       goto drop;
                rate = &sband->bitrates[status->rate_idx];
        }
 
@@ -2505,8 +2531,12 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
                __ieee80211_rx_handle_packet(hw, skb, rate);
 
        rcu_read_unlock();
+
+       return;
+ drop:
+       kfree_skb(skb);
 }
-EXPORT_SYMBOL(__ieee80211_rx);
+EXPORT_SYMBOL(ieee80211_rx);
 
 /* This is a version of the rx handler that can be called from hard irq
  * context. Post the skb on the queue and schedule the tasklet */