diff options
Diffstat (limited to 'net/ipv4/arp.c')
-rw-r--r-- | net/ipv4/arp.c | 48 |
1 files changed, 41 insertions, 7 deletions
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 0937b34c27ca..e9f3386a528b 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c | |||
@@ -641,6 +641,32 @@ void arp_xmit(struct sk_buff *skb) | |||
641 | } | 641 | } |
642 | EXPORT_SYMBOL(arp_xmit); | 642 | EXPORT_SYMBOL(arp_xmit); |
643 | 643 | ||
644 | static bool arp_is_garp(struct net *net, struct net_device *dev, | ||
645 | int *addr_type, __be16 ar_op, | ||
646 | __be32 sip, __be32 tip, | ||
647 | unsigned char *sha, unsigned char *tha) | ||
648 | { | ||
649 | bool is_garp = tip == sip; | ||
650 | |||
651 | /* Gratuitous ARP _replies_ also require target hwaddr to be | ||
652 | * the same as source. | ||
653 | */ | ||
654 | if (is_garp && ar_op == htons(ARPOP_REPLY)) | ||
655 | is_garp = | ||
656 | /* IPv4 over IEEE 1394 doesn't provide target | ||
657 | * hardware address field in its ARP payload. | ||
658 | */ | ||
659 | tha && | ||
660 | !memcmp(tha, sha, dev->addr_len); | ||
661 | |||
662 | if (is_garp) { | ||
663 | *addr_type = inet_addr_type_dev_table(net, dev, sip); | ||
664 | if (*addr_type != RTN_UNICAST) | ||
665 | is_garp = false; | ||
666 | } | ||
667 | return is_garp; | ||
668 | } | ||
669 | |||
644 | /* | 670 | /* |
645 | * Process an arp request. | 671 | * Process an arp request. |
646 | */ | 672 | */ |
@@ -653,6 +679,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) | |||
653 | unsigned char *arp_ptr; | 679 | unsigned char *arp_ptr; |
654 | struct rtable *rt; | 680 | struct rtable *rt; |
655 | unsigned char *sha; | 681 | unsigned char *sha; |
682 | unsigned char *tha = NULL; | ||
656 | __be32 sip, tip; | 683 | __be32 sip, tip; |
657 | u16 dev_type = dev->type; | 684 | u16 dev_type = dev->type; |
658 | int addr_type; | 685 | int addr_type; |
@@ -724,6 +751,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) | |||
724 | break; | 751 | break; |
725 | #endif | 752 | #endif |
726 | default: | 753 | default: |
754 | tha = arp_ptr; | ||
727 | arp_ptr += dev->addr_len; | 755 | arp_ptr += dev->addr_len; |
728 | } | 756 | } |
729 | memcpy(&tip, arp_ptr, 4); | 757 | memcpy(&tip, arp_ptr, 4); |
@@ -835,19 +863,25 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) | |||
835 | 863 | ||
836 | n = __neigh_lookup(&arp_tbl, &sip, dev, 0); | 864 | n = __neigh_lookup(&arp_tbl, &sip, dev, 0); |
837 | 865 | ||
838 | if (IN_DEV_ARP_ACCEPT(in_dev)) { | 866 | addr_type = -1; |
839 | unsigned int addr_type = inet_addr_type_dev_table(net, dev, sip); | 867 | if (n || IN_DEV_ARP_ACCEPT(in_dev)) { |
868 | is_garp = arp_is_garp(net, dev, &addr_type, arp->ar_op, | ||
869 | sip, tip, sha, tha); | ||
870 | } | ||
840 | 871 | ||
872 | if (IN_DEV_ARP_ACCEPT(in_dev)) { | ||
841 | /* Unsolicited ARP is not accepted by default. | 873 | /* Unsolicited ARP is not accepted by default. |
842 | It is possible, that this option should be enabled for some | 874 | It is possible, that this option should be enabled for some |
843 | devices (strip is candidate) | 875 | devices (strip is candidate) |
844 | */ | 876 | */ |
845 | is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip && | ||
846 | addr_type == RTN_UNICAST; | ||
847 | |||
848 | if (!n && | 877 | if (!n && |
849 | ((arp->ar_op == htons(ARPOP_REPLY) && | 878 | (is_garp || |
850 | addr_type == RTN_UNICAST) || is_garp)) | 879 | (arp->ar_op == htons(ARPOP_REPLY) && |
880 | (addr_type == RTN_UNICAST || | ||
881 | (addr_type < 0 && | ||
882 | /* postpone calculation to as late as possible */ | ||
883 | inet_addr_type_dev_table(net, dev, sip) == | ||
884 | RTN_UNICAST))))) | ||
851 | n = __neigh_lookup(&arp_tbl, &sip, dev, 1); | 885 | n = __neigh_lookup(&arp_tbl, &sip, dev, 1); |
852 | } | 886 | } |
853 | 887 | ||