diff options
Diffstat (limited to 'net/ipv4/arp.c')
-rw-r--r-- | net/ipv4/arp.c | 39 |
1 files changed, 25 insertions, 14 deletions
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 30409b75e925..f03db8b7abee 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c | |||
@@ -113,6 +113,8 @@ | |||
113 | #include <net/arp.h> | 113 | #include <net/arp.h> |
114 | #include <net/ax25.h> | 114 | #include <net/ax25.h> |
115 | #include <net/netrom.h> | 115 | #include <net/netrom.h> |
116 | #include <net/dst_metadata.h> | ||
117 | #include <net/ip_tunnels.h> | ||
116 | 118 | ||
117 | #include <linux/uaccess.h> | 119 | #include <linux/uaccess.h> |
118 | 120 | ||
@@ -296,7 +298,8 @@ static void arp_send_dst(int type, int ptype, __be32 dest_ip, | |||
296 | struct net_device *dev, __be32 src_ip, | 298 | struct net_device *dev, __be32 src_ip, |
297 | const unsigned char *dest_hw, | 299 | const unsigned char *dest_hw, |
298 | const unsigned char *src_hw, | 300 | const unsigned char *src_hw, |
299 | const unsigned char *target_hw, struct sk_buff *oskb) | 301 | const unsigned char *target_hw, |
302 | struct dst_entry *dst) | ||
300 | { | 303 | { |
301 | struct sk_buff *skb; | 304 | struct sk_buff *skb; |
302 | 305 | ||
@@ -309,9 +312,7 @@ static void arp_send_dst(int type, int ptype, __be32 dest_ip, | |||
309 | if (!skb) | 312 | if (!skb) |
310 | return; | 313 | return; |
311 | 314 | ||
312 | if (oskb) | 315 | skb_dst_set(skb, dst); |
313 | skb_dst_copy(skb, oskb); | ||
314 | |||
315 | arp_xmit(skb); | 316 | arp_xmit(skb); |
316 | } | 317 | } |
317 | 318 | ||
@@ -333,6 +334,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
333 | __be32 target = *(__be32 *)neigh->primary_key; | 334 | __be32 target = *(__be32 *)neigh->primary_key; |
334 | int probes = atomic_read(&neigh->probes); | 335 | int probes = atomic_read(&neigh->probes); |
335 | struct in_device *in_dev; | 336 | struct in_device *in_dev; |
337 | struct dst_entry *dst = NULL; | ||
336 | 338 | ||
337 | rcu_read_lock(); | 339 | rcu_read_lock(); |
338 | in_dev = __in_dev_get_rcu(dev); | 340 | in_dev = __in_dev_get_rcu(dev); |
@@ -381,9 +383,10 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
381 | } | 383 | } |
382 | } | 384 | } |
383 | 385 | ||
386 | if (skb && !(dev->priv_flags & IFF_XMIT_DST_RELEASE)) | ||
387 | dst = dst_clone(skb_dst(skb)); | ||
384 | arp_send_dst(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr, | 388 | arp_send_dst(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr, |
385 | dst_hw, dev->dev_addr, NULL, | 389 | dst_hw, dev->dev_addr, NULL, dst); |
386 | dev->priv_flags & IFF_XMIT_DST_RELEASE ? NULL : skb); | ||
387 | } | 390 | } |
388 | 391 | ||
389 | static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) | 392 | static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) |
@@ -649,6 +652,7 @@ static int arp_process(struct sock *sk, struct sk_buff *skb) | |||
649 | int addr_type; | 652 | int addr_type; |
650 | struct neighbour *n; | 653 | struct neighbour *n; |
651 | struct net *net = dev_net(dev); | 654 | struct net *net = dev_net(dev); |
655 | struct dst_entry *reply_dst = NULL; | ||
652 | bool is_garp = false; | 656 | bool is_garp = false; |
653 | 657 | ||
654 | /* arp_rcv below verifies the ARP header and verifies the device | 658 | /* arp_rcv below verifies the ARP header and verifies the device |
@@ -749,13 +753,18 @@ static int arp_process(struct sock *sk, struct sk_buff *skb) | |||
749 | * cache. | 753 | * cache. |
750 | */ | 754 | */ |
751 | 755 | ||
756 | if (arp->ar_op == htons(ARPOP_REQUEST) && skb_metadata_dst(skb)) | ||
757 | reply_dst = (struct dst_entry *) | ||
758 | iptunnel_metadata_reply(skb_metadata_dst(skb), | ||
759 | GFP_ATOMIC); | ||
760 | |||
752 | /* Special case: IPv4 duplicate address detection packet (RFC2131) */ | 761 | /* Special case: IPv4 duplicate address detection packet (RFC2131) */ |
753 | if (sip == 0) { | 762 | if (sip == 0) { |
754 | if (arp->ar_op == htons(ARPOP_REQUEST) && | 763 | if (arp->ar_op == htons(ARPOP_REQUEST) && |
755 | inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL && | 764 | inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL && |
756 | !arp_ignore(in_dev, sip, tip)) | 765 | !arp_ignore(in_dev, sip, tip)) |
757 | arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, | 766 | arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, |
758 | dev->dev_addr, sha); | 767 | sha, dev->dev_addr, sha, reply_dst); |
759 | goto out; | 768 | goto out; |
760 | } | 769 | } |
761 | 770 | ||
@@ -774,9 +783,10 @@ static int arp_process(struct sock *sk, struct sk_buff *skb) | |||
774 | if (!dont_send) { | 783 | if (!dont_send) { |
775 | n = neigh_event_ns(&arp_tbl, sha, &sip, dev); | 784 | n = neigh_event_ns(&arp_tbl, sha, &sip, dev); |
776 | if (n) { | 785 | if (n) { |
777 | arp_send(ARPOP_REPLY, ETH_P_ARP, sip, | 786 | arp_send_dst(ARPOP_REPLY, ETH_P_ARP, |
778 | dev, tip, sha, dev->dev_addr, | 787 | sip, dev, tip, sha, |
779 | sha); | 788 | dev->dev_addr, sha, |
789 | reply_dst); | ||
780 | neigh_release(n); | 790 | neigh_release(n); |
781 | } | 791 | } |
782 | } | 792 | } |
@@ -794,9 +804,10 @@ static int arp_process(struct sock *sk, struct sk_buff *skb) | |||
794 | if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED || | 804 | if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED || |
795 | skb->pkt_type == PACKET_HOST || | 805 | skb->pkt_type == PACKET_HOST || |
796 | NEIGH_VAR(in_dev->arp_parms, PROXY_DELAY) == 0) { | 806 | NEIGH_VAR(in_dev->arp_parms, PROXY_DELAY) == 0) { |
797 | arp_send(ARPOP_REPLY, ETH_P_ARP, sip, | 807 | arp_send_dst(ARPOP_REPLY, ETH_P_ARP, |
798 | dev, tip, sha, dev->dev_addr, | 808 | sip, dev, tip, sha, |
799 | sha); | 809 | dev->dev_addr, sha, |
810 | reply_dst); | ||
800 | } else { | 811 | } else { |
801 | pneigh_enqueue(&arp_tbl, | 812 | pneigh_enqueue(&arp_tbl, |
802 | in_dev->arp_parms, skb); | 813 | in_dev->arp_parms, skb); |