]> Pileus Git - ~andy/linux/blobdiff - net/core/neighbour.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw
[~andy/linux] / net / core / neighbour.c
index a793af9af1505c4a919d15b603c4f1936d2d9bd9..117afaf512689b4de570ddb0c32869a4c5532918 100644 (file)
@@ -1201,10 +1201,23 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
                        write_unlock_bh(&neigh->lock);
 
                        rcu_read_lock();
-                       /* On shaper/eql skb->dst->neighbour != neigh :( */
-                       if (dst && (n2 = dst_get_neighbour_noref(dst)) != NULL)
-                               n1 = n2;
+
+                       /* Why not just use 'neigh' as-is?  The problem is that
+                        * things such as shaper, eql, and sch_teql can end up
+                        * using alternative, different, neigh objects to output
+                        * the packet in the output path.  So what we need to do
+                        * here is re-lookup the top-level neigh in the path so
+                        * we can reinject the packet there.
+                        */
+                       n2 = NULL;
+                       if (dst) {
+                               n2 = dst_neigh_lookup_skb(dst, skb);
+                               if (n2)
+                                       n1 = n2;
+                       }
                        n1->output(n1, skb);
+                       if (n2)
+                               neigh_release(n2);
                        rcu_read_unlock();
 
                        write_lock_bh(&neigh->lock);