- // some cases are always conflicts
- if ((p.source_ip.s_addr == ip.s_addr)
- && (memcmp(&addr, &p.source_addr,
- ETH_ALEN) != 0)) {
-collision:
- VDBG("%s ARP conflict from %s\n", intf,
- ether_ntoa(&p.source_addr));
- if (ready) {
- time_t now = time(0);
-
- if ((defend + DEFEND_INTERVAL)
- < now) {
- defend = now;
- (void)arp(fd, &saddr,
- ARPOP_REQUEST,
- &addr, ip,
- &addr, ip);
- VDBG("%s defend\n", intf);
- timeout = -1;
- continue;
+ if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr)) == 0 &&
+ memcmp(ð_addr, &p.arp.arp_sha, ETH_ALEN) != 0) {
+ source_ip_conflict = 1;
+ }
+ if (memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0 &&
+ p.arp.arp_op == htons(ARPOP_REQUEST) &&
+ memcmp(ð_addr, &p.arp.arp_tha, ETH_ALEN) != 0) {
+ target_ip_conflict = 1;
+ }
+
+ VDBG("state = %d, source ip conflict = %d, target ip conflict = %d\n",
+ state, source_ip_conflict, target_ip_conflict);
+ switch (state) {
+ case PROBE:
+ case ANNOUNCE:
+ // When probing or announcing, check for source IP conflicts
+ // and other hosts doing ARP probes (target IP conflicts).
+ if (source_ip_conflict || target_ip_conflict) {
+ conflicts++;
+ if (conflicts >= MAX_CONFLICTS) {
+ VDBG("%s ratelimit\n", intf);
+ timeout = RATE_LIMIT_INTERVAL * 1000;
+ state = RATE_LIMIT_PROBE;