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); }
static void ni_dhcp4_device_close(ni_dhcp4_device_t *dev) { ni_capture_free(dev->capture); dev->capture = NULL; if (dev->listen_fd >= 0) close(dev->listen_fd); dev->listen_fd = -1; if (dev->fsm.timer) { ni_warn("%s: timer active for %s", __func__, dev->ifname); ni_timer_cancel(dev->fsm.timer); dev->fsm.timer = NULL; } ni_dhcp4_device_arp_close(dev); }
void ni_dhcp4_fsm_link_down(ni_dhcp4_device_t *dev) { if (dev->config == NULL) return; switch (dev->fsm.state) { case NI_DHCP4_STATE_INIT: case NI_DHCP4_STATE_SELECTING: case NI_DHCP4_STATE_REQUESTING: case NI_DHCP4_STATE_VALIDATING: ni_dhcp4_device_arp_close(dev); ni_dhcp4_device_drop_lease(dev); ni_dhcp4_fsm_restart(dev); break; default: ; } }
int ni_dhcp4_fsm_arp_validate(ni_dhcp4_device_t *dev) { struct in_addr null = { 0 }; struct in_addr claim; if (!dev || !dev->lease) return -1; claim = dev->lease->dhcp4.address; if (dev->arp.handle == NULL) { dev->arp.handle = ni_arp_socket_open(&dev->system, ni_dhcp4_fsm_process_arp_packet, dev); if (!dev->arp.handle->user_data) { ni_error("%s: unable to create ARP handle", dev->ifname); return -1; } } if (dev->arp.nprobes) { ni_debug_dhcp("%s: arp validate: probing for %s", dev->ifname, inet_ntoa(claim)); ni_arp_send_request(dev->arp.handle, null, claim); dev->arp.nprobes--; } else if (dev->arp.nclaims) { ni_debug_dhcp("%s: arp validate: claiming %s", dev->ifname, inet_ntoa(claim)); ni_arp_send_grat_request(dev->arp.handle, claim); dev->arp.nclaims--; } else { /* Wow, we're done! */ ni_info("%s: Successfully validated DHCPv4 address %s", dev->ifname, inet_ntoa(claim)); ni_dhcp4_fsm_commit_lease(dev, dev->lease); ni_dhcp4_device_arp_close(dev); return 0; } ni_dhcp4_fsm_set_timeout_msec(dev, NI_DHCP4_ARP_TIMEOUT); return 0; }