mac80211: Fix regression in mesh forwarding path.
authorJavier Cardona <javier@cozybit.com>
Tue, 7 Jul 2009 17:55:03 +0000 (10:55 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 24 Jul 2009 19:05:31 +0000 (15:05 -0400)
The removal of the master netdev broke the mesh forwarding path.  This patch
fixes it by using the new internal 'pending' queue.

As a result of this change, mesh forwarding no longer does the inefficient
802.11 -> 802.3 -> 802.11 conversion that was done before.

[Changes since v1]
Suggested by Johannes:
 - Select queue before adding to mpath queue
 - ieee80211_add_pending_skb -> ieee80211_add_pending_skbs
 - Remove unnecessary header wme.h

Signed-off-by: Javier Cardona <javier@cozybit.com>
Signed-off-by: Andrey Yurovsky <andrey@cozybit.com>
Reviewed-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/rx.c
net/mac80211/tx.c

index 8e86e91..e93c37e 100644 (file)
@@ -784,7 +784,6 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
                mesh_path_add(dst_addr, sdata);
                mpath = mesh_path_lookup(dst_addr, sdata);
                if (!mpath) {
-                       dev_kfree_skb(skb);
                        sdata->u.mesh.mshstats.dropped_frames_no_route++;
                        err = -ENOSPC;
                        goto endlookup;
@@ -804,6 +803,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
                memcpy(hdr->addr1, mpath->next_hop->sta.addr,
                                ETH_ALEN);
        } else {
+               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
                if (!(mpath->flags & MESH_PATH_RESOLVING)) {
                        /* Start discovery only if it is not running yet */
                        mesh_queue_preq(mpath, PREQ_Q_F_START);
@@ -815,6 +815,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
                        skb_unlink(skb_to_free, &mpath->frame_queue);
                }
 
+               info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                skb_queue_tail(&mpath->frame_queue, skb);
                if (skb_to_free)
                        mesh_path_discard_frame(skb_to_free, sdata);
index f0304bf..04b9e4d 100644 (file)
@@ -499,11 +499,9 @@ enddel:
  */
 void mesh_path_tx_pending(struct mesh_path *mpath)
 {
-       struct sk_buff *skb;
-
-       while ((skb = skb_dequeue(&mpath->frame_queue)) &&
-                       (mpath->flags & MESH_PATH_ACTIVE))
-               dev_queue_xmit(skb);
+       if (mpath->flags & MESH_PATH_ACTIVE)
+               ieee80211_add_pending_skbs(mpath->sdata->local,
+                               &mpath->frame_queue);
 }
 
 /**
index 7f33f77..66c797c 100644 (file)
@@ -1479,10 +1479,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        unsigned int hdrlen;
        struct sk_buff *skb = rx->skb, *fwd_skb;
        struct ieee80211_local *local = rx->local;
+       struct ieee80211_sub_if_data *sdata;
 
        hdr = (struct ieee80211_hdr *) skb->data;
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
        mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+       sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 
        if (!ieee80211_is_data(hdr->frame_control))
                return RX_CONTINUE;
@@ -1492,10 +1494,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                return RX_DROP_MONITOR;
 
        if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){
-               struct ieee80211_sub_if_data *sdata;
                struct mesh_path *mppath;
 
-               sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
                rcu_read_lock();
                mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata);
                if (!mppath) {
@@ -1541,6 +1541,19 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                        info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                        fwd_skb->iif = rx->dev->ifindex;
                        ieee80211_select_queue(local, fwd_skb);
+                       if (is_multicast_ether_addr(fwd_hdr->addr3))
+                               memcpy(fwd_hdr->addr1, fwd_hdr->addr3,
+                                               ETH_ALEN);
+                       else {
+                               int 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_frames);
                        ieee80211_add_pending_skb(local, fwd_skb);
                }
        }
index a204092..2572509 100644 (file)
@@ -1419,9 +1419,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
                                dev_put(sdata->dev);
                                return;
                        }
-               if (memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) != 0)
-                       IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
-                                                    fwded_frames);
        } else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
                int hdrlen;
                u16 len_rthdr;