ax25: Stop depending on arp_find
authorEric W. Biederman <ebiederm@xmission.com>
Mon, 2 Mar 2015 06:09:42 +0000 (00:09 -0600)
committerDavid S. Miller <davem@davemloft.net>
Mon, 2 Mar 2015 21:43:41 +0000 (16:43 -0500)
Have ax25_neigh_output perform ordinary arp resolution before calling
ax25_neigh_xmit.

Call dev_hard_header in ax25_neigh_output with a destination address so
it will not fail, and the destination mac address will not need to be
set in ax25_neigh_xmit.

Remove arp_find from ax25_neigh_xmit (the ordinary arp resolution added
to ax25_neigh_output removes the need for calling arp_find).

Document how close ax25_neigh_output is to neigh_resolve_output.

Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-hams@vger.kernel.org
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ax25/ax25_ip.c

index 08803e820f1d3090b8dbd7f144a6583d04b318ca..e030c64ebfb77bfc41ca6edf6b3211b1765485ff 100644 (file)
@@ -115,9 +115,6 @@ static int ax25_neigh_xmit(struct sk_buff *skb)
        dst = (ax25_address *)(bp + 1);
        src = (ax25_address *)(bp + 8);
 
-       if (arp_find(bp + 1, skb))
-               return 1;
-
        route = ax25_get_route(dst, NULL);
        if (route) {
                digipeat = route->digipeat;
@@ -218,16 +215,35 @@ put:
 
 static int ax25_neigh_output(struct neighbour *neigh, struct sk_buff *skb)
 {
-       struct net_device *dev = skb->dev;
-
-       __skb_pull(skb, skb_network_offset(skb));
-
-       if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
-                           skb->len) < 0 &&
-           ax25_neigh_xmit(skb));
-               return 0;
+       /* Except for calling ax25_neigh_xmit instead of
+        * dev_queue_xmit this is neigh_resolve_output.
+        */
+       int rc = 0;
+
+       if (!neigh_event_send(neigh, skb)) {
+               int err;
+               struct net_device *dev = neigh->dev;
+               unsigned int seq;
+
+               do {
+                       __skb_pull(skb, skb_network_offset(skb));
+                       seq = read_seqbegin(&neigh->ha_lock);
+                       err = dev_hard_header(skb, dev, ntohs(skb->protocol),
+                                             neigh->ha, NULL, skb->len);
+               } while (read_seqretry(&neigh->ha_lock, seq));
+
+               if (err >= 0) {
+                       ax25_neigh_xmit(skb);
+               } else
+                       goto out_kfree_skb;
+       }
+out:
+       return rc;
 
-       return dev_queue_xmit(skb);
+out_kfree_skb:
+       rc = -EINVAL;
+       kfree_skb(skb);
+       goto out;
 }
 
 int ax25_neigh_construct(struct neighbour *neigh)