static uint32_t select_lease_time(struct dhcp_packet *packet) { uint32_t lease_time_sec = server_config.max_lease_sec; uint8_t *lease_time_opt = udhcp_get_option(packet, DHCP_LEASE_TIME); if (lease_time_opt) { move_from_unaligned32(lease_time_sec, lease_time_opt); lease_time_sec = ntohl(lease_time_sec); if (lease_time_sec > server_config.max_lease_sec) lease_time_sec = server_config.max_lease_sec; if (lease_time_sec < server_config.min_lease_sec) lease_time_sec = server_config.min_lease_sec; } return lease_time_sec; }
/* NOINLINE: limit stack usage in caller */ static NOINLINE void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease, uint8_t *requested_ip_opt, unsigned arpping_ms) { struct dhcp_packet packet; uint32_t lease_time_sec; struct in_addr addr; init_packet(&packet, oldpacket, DHCPOFFER); /* If it is a static lease, use its IP */ packet.yiaddr = static_lease_nip; /* Else: */ if (!static_lease_nip) { /* We have no static lease for client's chaddr */ uint32_t req_nip; const char *p_host_name; if (lease) { /* We have a dynamic lease for client's chaddr. * Reuse its IP (even if lease is expired). * Note that we ignore requested IP in this case. */ packet.yiaddr = lease->lease_nip; } /* Or: if client has requested an IP */ else if (requested_ip_opt != NULL /* (read IP) */ && (move_from_unaligned32(req_nip, requested_ip_opt), 1) /* and the IP is in the lease range */ && ntohl(req_nip) >= server_config.start_ip && ntohl(req_nip) <= server_config.end_ip /* and */ && ( !(lease = find_lease_by_nip(req_nip)) /* is not already taken */ || is_expired_lease(lease) /* or is taken, but expired */ ) ) { packet.yiaddr = req_nip; } else { /* Otherwise, find a free IP */ packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr, arpping_ms); } if (!packet.yiaddr) { bb_error_msg("no free IP addresses. OFFER abandoned"); return; } /* Reserve the IP for a short time hoping to get DHCPREQUEST soon */ p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME); lease = add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time, p_host_name, p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0 ); if (!lease) { bb_error_msg("no free IP addresses. OFFER abandoned"); return; } } lease_time_sec = select_lease_time(oldpacket); udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec)); add_server_options(&packet); addr.s_addr = packet.yiaddr; bb_info_msg("Sending OFFER of %s", inet_ntoa(addr)); /* send_packet emits error message itself if it detects failure */ send_packet(&packet, /*force_bcast:*/ 0); }