static void send_offer(GDHCPServer *dhcp_server, struct dhcp_packet *client_packet, struct dhcp_lease *lease, uint32_t requested_nip) { struct dhcp_packet packet; struct in_addr addr; init_packet(dhcp_server, &packet, client_packet, DHCPOFFER); if (lease) packet.yiaddr = htonl(lease->lease_nip); else if (check_requested_nip(dhcp_server, requested_nip)) packet.yiaddr = htonl(requested_nip); else packet.yiaddr = htonl(find_free_or_expired_nip( dhcp_server, client_packet->chaddr)); debug(dhcp_server, "find yiaddr %u", packet.yiaddr); if (!packet.yiaddr) { debug(dhcp_server, "Err: Can not found lease and send offer"); return; } lease = add_lease(dhcp_server, OFFER_TIME, packet.chaddr, packet.yiaddr); if (!lease) { debug(dhcp_server, "Err: No free IP addresses. OFFER abandoned"); return; } dhcp_add_option_uint32(&packet, DHCP_LEASE_TIME, dhcp_server->lease_seconds); add_server_options(dhcp_server, &packet); addr.s_addr = packet.yiaddr; debug(dhcp_server, "Sending OFFER of %s", inet_ntoa(addr)); send_packet_to_client(dhcp_server, &packet); }
/* 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); }