diff -ru linux-2.4.5-pre4.orig/net/ipv4/arp.c linux-2.4.5-pre4/net/ipv4/arp.c --- linux-2.4.5-pre4.orig/net/ipv4/arp.c Sun May 20 20:54:17 2001 +++ linux-2.4.5-pre4/net/ipv4/arp.c Tue May 22 09:58:24 2001 @@ -321,11 +321,24 @@ struct net_device *dev = neigh->dev; u32 target = *(u32*)neigh->primary_key; int probes = atomic_read(&neigh->probes); + struct rtable *rt; - if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL) - saddr = skb->nh.iph->saddr; - else - saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); + /* Determine source IP for the probing packet. */ + saddr = 0; + if (skb != NULL) { + rt = (struct rtable*)skb->dst; + if (!rt->rt_iif) + saddr = rt->rt_src; + } + if (!saddr) { + if (ip_route_output(&rt, target, 0, 0, dev->ifindex) < 0) + /* Never send probes with 0 source as we used to. */ + return; + saddr = rt->rt_src; + ip_rt_put(rt); + } + if (!saddr) + return; if ((probes -= neigh->parms->ucast_probes) < 0) { if (!(neigh->nud_state&NUD_VALID)) @@ -345,20 +358,35 @@ read_unlock_bh(&neigh->lock); } -static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev) +static int arp_filter(struct sk_buff *skb, __u32 sip, __u32 tip, + struct in_device *in_dev) { struct rtable *rt; int flag = 0; - /*unsigned long now; */ + if (!IN_DEV_ARPFILTER(in_dev)) + return 0; + + /* Always answer direct queries. */ + if (skb->pkt_type == PACKET_HOST) + return 0; + + /* Then check routes: + * primarily, this check is used to not to answer to some requests if + * several interfaces are connected to the same segment. + * This check also may be used for manual control of who sees IP + * addresses at which link-level addresses by installing prohibiting + * routes. -- 2001/05/20 SAW + */ if (ip_route_output(&rt, sip, tip, 0, 0) < 0) return 1; - if (rt->u.dst.dev != dev) { + if (rt->u.dst.dev != in_dev->dev) { NET_INC_STATS_BH(ArpFilter); flag = 1; } ip_rt_put(rt); - return flag; + + return flag; } /* OBSOLETE FUNCTIONS */ @@ -757,10 +785,7 @@ if (addr_type == RTN_LOCAL) { n = neigh_event_ns(&arp_tbl, sha, &sip, dev); if (n) { - int dont_send = 0; - if (IN_DEV_ARPFILTER(in_dev)) - dont_send |= arp_filter(sip,tip,dev); - if (!dont_send) + if (!arp_filter(skb, sip, tip, in_dev)) arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha); neigh_release(n);