void ni_dhcp4_fsm_process_arp_packet(ni_arp_socket_t *arph, const ni_arp_packet_t *pkt, void *user_data) { ni_dhcp4_device_t *dev = user_data; ni_netconfig_t *nc = ni_global_state_handle(0); const ni_netdev_t *ifp; ni_bool_t false_alarm = FALSE; ni_bool_t found_addr = FALSE; if (!pkt || pkt->op != ARPOP_REPLY || !dev || !dev->lease) return; /* Is it about the address we're validating at all? */ if (pkt->sip.s_addr != dev->lease->dhcp4.address.s_addr) return; /* Ignore any ARP replies that seem to come from our own * MAC address. Some helpful switches seem to generate * these. */ if (ni_link_address_equal(&dev->system.hwaddr, &pkt->sha)) return; /* As well as ARP replies that seem to come from our own * host: dup if same address, not a dup if there are two * interfaces connected to the same broadcast domain. */ for (ifp = ni_netconfig_devlist(nc); ifp; ifp = ifp->next) { if (ifp->link.ifindex == dev->link.ifindex) continue; if (!ni_netdev_link_is_up(ifp)) continue; if (!ni_link_address_equal(&ifp->link.hwaddr, &pkt->sha)) continue; /* OK, we have an interface matching the hwaddr, * which will answer arp requests when it is on * the same broadcast domain and causes a false * alarm, except it really has the IP assigned. */ false_alarm = TRUE; if (__ni_dhcp4_address_on_device(ifp, pkt->sip)) found_addr = TRUE; } if (false_alarm && !found_addr) return; ni_debug_dhcp("%s: address %s already in use by %s", dev->ifname, inet_ntoa(pkt->sip), ni_link_address_print(&pkt->sha)); ni_dhcp4_device_arp_close(dev); ni_dhcp4_fsm_decline(dev); }
/* * Helper functions for matching naming attributes */ static ni_bool_t __match_hwaddr(const ni_hwaddr_t *hwaddr, const char *string) { ni_hwaddr_t match; if (!string) return FALSE; if (ni_link_address_parse(&match, hwaddr->type, string) < 0) return FALSE; return ni_link_address_equal(hwaddr, &match); }
/* * Find interface by its LL address */ ni_netdev_t * ni_netdev_by_hwaddr(ni_netconfig_t *nc, const ni_hwaddr_t *lla) { ni_netdev_t *dev; if (!lla || !lla->len) return NULL; for (dev = nc->interfaces; dev; dev = dev->next) { if (ni_link_address_equal(&dev->link.hwaddr, lla)) return dev; } return NULL; }
ni_compat_netdev_t * ni_compat_netdev_by_hwaddr(ni_compat_netdev_array_t *array, const ni_hwaddr_t *hwaddr) { unsigned int i; if (array == NULL || hwaddr == NULL || hwaddr->type == 0) return NULL; for (i = 0; i < array->count; ++i) { ni_compat_netdev_t *compat = array->data[i]; if (ni_link_address_equal(hwaddr, &compat->identify.hwaddr)) return compat; } return NULL; }
static void __do_arp_validate_process(ni_arp_socket_t *sock, const ni_arp_packet_t *pkt, void *user_data) { struct arp_handle *handle = user_data; ni_netconfig_t *nc = ni_global_state_handle(0); const ni_netdev_t *ifp; ni_bool_t false_alarm = FALSE; ni_bool_t found_addr = FALSE; const ni_address_t *ap; ni_sockaddr_t addr; if (!pkt || pkt->op != ARPOP_REPLY || !handle->replies) return; /* Is it about the address we're validating at all? */ if (pkt->sip.s_addr != handle->ipaddr.sin.sin_addr.s_addr) { ni_debug_application("%s: report about different address", handle->ifname); return; } /* Ignore any ARP replies that seem to come from our own * MAC address. Some helpful switches seem to generate * these. */ if (ni_link_address_equal(&sock->dev_info.hwaddr, &pkt->sha)) { ni_debug_application("%s: adress in use by ourself", handle->ifname); return; } /* As well as ARP replies that seem to come from our own * host: dup if same address, not a dup if there are two * interfaces connected to the same broadcast domain. */ ni_sockaddr_set_ipv4(&addr, pkt->sip, 0); for (ifp = ni_netconfig_devlist(nc); ifp; ifp = ifp->next) { if (ifp->link.ifindex == sock->dev_info.ifindex) continue; if (!ni_netdev_link_is_up(ifp)) continue; if (!ni_link_address_equal(&ifp->link.hwaddr, &pkt->sha)) continue; /* OK, we have an interface matching the hwaddr, * which will answer arp requests when it is on * the same broadcast domain and causes a false * alarm, except it really has the IP assigned. */ false_alarm = TRUE; for (ap = ifp->addrs; !found_addr && ap; ap = ap->next) { if (ap->family != AF_INET) continue; if (ni_sockaddr_equal(&ap->local_addr, &addr)) found_addr = TRUE; } } if (false_alarm && !found_addr) { ni_debug_application("%s: reply from one of our interfaces", handle->ifname); return; } ni_info("%s: adress %s in use by %s reported", handle->ifname, inet_ntoa(pkt->sip), ni_link_address_print(&pkt->sha)); handle->hwaddr = pkt->sha; }