void ni_dhcp4_fsm_fail_lease(ni_dhcp4_device_t *dev) { ni_debug_dhcp("%s: failing lease", dev->ifname); ni_dhcp4_fsm_restart(dev); ni_capture_free(dev->capture); dev->capture = NULL; ni_dhcp4_device_set_lease(dev, NULL); dev->notify = 1; dev->failed = 1; }
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_arp_socket_close(ni_arp_socket_t *arph) { ni_capture_free(arph->capture); free(arph); }
int ni_dhcp4_fsm_commit_lease(ni_dhcp4_device_t *dev, ni_addrconf_lease_t *lease) { ni_capture_free(dev->capture); dev->capture = NULL; if (lease) { ni_debug_dhcp("%s: committing lease", dev->ifname); if (dev->config->dry_run == NI_DHCP4_RUN_NORMAL) { ni_debug_dhcp("%s: schedule renewal of lease in %u seconds", dev->ifname, lease->dhcp4.renewal_time); ni_dhcp4_fsm_set_timeout(dev, lease->dhcp4.renewal_time); } /* If the user requested a specific route metric, apply it now */ if (dev->config) { ni_route_table_t *tab; ni_route_t *rp; unsigned int i; for (tab = lease->routes; tab; tab = tab->next) { for (i = 0; i < tab->routes.count; ++i) { if ((rp = tab->routes.data[i]) == NULL) continue; rp->protocol = RTPROT_DHCP; rp->priority = dev->config->route_priority; } } } ni_dhcp4_device_set_lease(dev, lease); dev->fsm.state = NI_DHCP4_STATE_BOUND; ni_note("%s: Committed DHCPv4 lease with address %s " "(lease time %u sec, renew in %u sec, rebind in %u sec)", dev->ifname, inet_ntoa(lease->dhcp4.address), lease->dhcp4.lease_time, lease->dhcp4.renewal_time, lease->dhcp4.rebind_time); /* Write the lease to lease cache */ if (dev->config->dry_run != NI_DHCP4_RUN_OFFER) { ni_addrconf_lease_file_write(dev->ifname, lease); } /* Notify anyone who cares that we've (re-)acquired the lease */ ni_dhcp4_send_event(NI_DHCP4_EVENT_ACQUIRED, dev, lease); if (dev->config->dry_run != NI_DHCP4_RUN_NORMAL) { ni_dhcp4_fsm_restart(dev); ni_dhcp4_device_stop(dev); } } else { /* Delete old lease file */ if ((lease = dev->lease) != NULL) { ni_note("%s: Dropped DHCPv4 lease with UUID %s", dev->ifname, ni_uuid_print(&lease->uuid)); lease->state = NI_ADDRCONF_STATE_RELEASED; ni_dhcp4_send_event(NI_DHCP4_EVENT_RELEASED, dev, lease); if (!dev->config || dev->config->dry_run != NI_DHCP4_RUN_OFFER) { ni_addrconf_lease_file_remove(dev->ifname, lease->type, lease->family); } ni_dhcp4_device_drop_lease(dev); } ni_dhcp4_fsm_restart(dev); } return 0; }
/* * Open a DHCP socket for send and receive */ int ni_dhcp_socket_open(ni_dhcp_device_t *dev) { ni_capture_protinfo_t prot_info; ni_capture_t *capture; /* We need to bind to a port, otherwise Linux will generate * ICMP_UNREACHABLE messages telling the server that there's * no DHCP client listening at all. * * We don't actually use this fd at all, instead using our packet * filter socket. * * (It would be nice if we did, at least in BOUND/RENEWING state * where good manners would dictate unicast requests anyway). */ if (dev->listen_fd == -1) { struct sockaddr_in sin; struct ifreq ifr; int on = 1; int fd; if ((fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { ni_error("socket: %m"); return -1; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) ni_error("SO_REUSEADDR: %m"); if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == -1) ni_error("SO_RCVBUF: %m"); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name)); if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1) ni_error("SO_SOBINDTODEVICE: %m"); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(DHCP_CLIENT_PORT); if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) == -1) { ni_error("bind: %m"); close(fd); } else { dev->listen_fd = fd; fcntl(fd, F_SETFD, FD_CLOEXEC); } } memset(&prot_info, 0, sizeof(prot_info)); prot_info.eth_protocol = ETHERTYPE_IP; prot_info.ip_protocol = IPPROTO_UDP; prot_info.ip_port = DHCP_CLIENT_PORT; if ((capture = dev->capture) != NULL) { if (ni_capture_is_valid(capture, ETHERTYPE_IP)) return 0; ni_capture_free(dev->capture); dev->capture = NULL; } dev->capture = ni_capture_open(&dev->system, &prot_info, ni_dhcp_socket_recv); if (!dev->capture) return -1; ni_capture_set_user_data(dev->capture, dev); return 0; }