sd-dhcp-server.c revision 5b34277c2015e32e51d10cfa076df2c7106b4537
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering This file is part of systemd.
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering Copyright (C) 2013 Intel Corporation. All rights reserved.
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering Copyright (C) 2014 Tom Gundersen
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering systemd is free software; you can redistribute it and/or modify it
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering under the terms of the GNU Lesser General Public License as published by
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering (at your option) any later version.
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering systemd is distributed in the hope that it will be useful, but
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering Lesser General Public License for more details.
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering You should have received a copy of the GNU Lesser General Public License
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringint sd_dhcp_server_set_lease_pool(sd_dhcp_server *server, struct in_addr *address,
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering assert_return(server->pool_start == htobe32(INADDR_ANY), -EBUSY);
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering assert_return(!server->pool_size, -EBUSY);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering assert_return(!server->bound_leases, -EBUSY);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering server->bound_leases = new0(DHCPLease*, size);
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poetteringint sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr *address) {
a1e58e8ee1c84b633d6d6d651d5328d4dd4eba5bLennart Poettering assert_return(server->address == htobe32(INADDR_ANY), -EBUSY);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringsd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering assert_se(REFCNT_INC(server->n_ref) >= 2);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringunsigned long client_id_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering siphash24((uint8_t*) &u, id->data, id->length, hash_key);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering return (unsigned long) u;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringint client_id_compare_func(const void *_a, const void *_b) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering return memcmp(a->data, b->data, a->length);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic void dhcp_lease_free(DHCPLease *lease) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart PoetteringDEFINE_TRIVIAL_CLEANUP_FUNC(DHCPLease*, dhcp_lease_free);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering#define _cleanup_dhcp_lease_free_ _cleanup_(dhcp_lease_freep)
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringsd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering if (server && REFCNT_DEC(server->n_ref) <= 0) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering HASHMAP_FOREACH(lease, server->leases_by_client_id, i) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering hashmap_remove(server->leases_by_client_id, lease);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering hashmap_free(server->leases_by_client_id);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringint sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering server->leases_by_client_id = hashmap_new(client_id_hash_func, client_id_compare_func);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringint sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int priority) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringint sd_dhcp_server_detach_event(sd_dhcp_server *server) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering server->event = sd_event_unref(server->event);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringsd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringint sd_dhcp_server_stop(sd_dhcp_server *server) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering sd_event_source_unref(server->receive_message);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering server->fd_raw = safe_close(server->fd_raw);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic int dhcp_server_send_unicast_raw(sd_dhcp_server *server, DHCPPacket *packet,
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering memcpy(&link.ll.sll_addr, &packet->dhcp.chaddr, ETH_ALEN);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER,
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering packet->dhcp.yiaddr, DHCP_PORT_CLIENT, len);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering .in.sin_port = htobe16(DHCP_PORT_CLIENT),
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))] = {};
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* we attach source interface and address info to the message
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering rather than binding the socket. This will be mostly useful
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering when we gain support for arbitrary number of server addresses
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering pktinfo->ipi_spec_dst.s_addr = server->address;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic bool requested_broadcast(DHCPRequest *req) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering return req->message->flags & htobe16(0x8000);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringint dhcp_server_send_packet(sd_dhcp_server *server,
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* RFC 2131 Section 4.1
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering If the ’giaddr’ field in a DHCP message from a client is non-zero,
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering the server sends any return messages to the ’DHCP server’ port on the
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering field is zero and the ’ciaddr’ field is nonzero, then the server
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering set, then the server broadcasts DHCPOFFER and DHCPACK messages to
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering messages to the client’s hardware address and ’yiaddr’ address. In
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering messages to 0xffffffff.
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering different subnet. The server MUST set the broadcast bit in the
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering client, because the client may not have a correct network address
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering or subnet mask, and the client may not be answering ARP requests.
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering } else if (req->message->ciaddr && type != DHCP_NAK)
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering if (destination || requested_broadcast(req) || type == DHCP_NAK)
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering return dhcp_server_send_udp(server, destination, &packet->dhcp,
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* we cannot send UDP packet to specific MAC address when the address is
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering not yet configured, so must fall back to raw packets */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering return dhcp_server_send_unicast_raw(server, packet,
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poetteringstatic int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering uint8_t type, size_t *_optoffset, DHCPRequest *req) {
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering _cleanup_free_ DHCPPacket *packet = NULL;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = dhcp_message_init(&packet->dhcp, BOOTREPLY, be32toh(req->message->xid),
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering packet->dhcp.flags = req->message->flags;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering packet->dhcp.giaddr = req->message->giaddr;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering memcpy(&packet->dhcp.chaddr, &req->message->chaddr, ETH_ALEN);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic int server_send_offer(sd_dhcp_server *server, DHCPRequest *req, be32_t address) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering _cleanup_free_ DHCPPacket *packet = NULL;
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering r = server_message_init(server, &packet, DHCP_OFFER, &offset, req);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, &lease_time);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset);
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poetteringstatic int server_send_ack(sd_dhcp_server *server, DHCPRequest *req, be32_t address) {
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering _cleanup_free_ DHCPPacket *packet = NULL;
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering r = server_message_init(server, &packet, DHCP_ACK, &offset, req);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, &lease_time);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = dhcp_server_send_packet(server, req, packet, DHCP_ACK, offset);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering _cleanup_free_ DHCPPacket *packet = NULL;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poetteringstatic int parse_request(uint8_t code, uint8_t len, const uint8_t *option,
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering req->lifetime = be32toh(*(be32_t*)option);
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering req->max_optlen = be16toh(*(be16_t*)option) -
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic void dhcp_request_free(DHCPRequest *req) {
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart PoetteringDEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering#define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poetteringstatic int ensure_sane_request(DHCPRequest *req, DHCPMessage *message) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* set client id based on mac address if client did not send an explicit one */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering memcpy(&req->client_id.data[1], &message->chaddr, ETH_ALEN);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poetteringstatic int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering if (be32toh(requested_ip) < be32toh(server->pool_start) ||
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering be32toh(requested_ip) >= be32toh(server->pool_start) +
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering return be32toh(requested_ip) - be32toh(server->pool_start);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringint dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering _cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering type = dhcp_option_parse(message, length, parse_request, req);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* this only fails on critical errors */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering existing_lease = hashmap_get(server->leases_by_client_id, &req->client_id);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_dhcp_server(server, "DISCOVER (0x%x)",
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* no pool allocated */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* for now pick a random free address from the pool */
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering for (i = 0; i < server->pool_size; i++) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering if (!server->bound_leases[server->next_offer]) {
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering address = htobe32(be32toh(server->pool_start) + server->next_offer);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering server->next_offer = (server->next_offer + 1) % server->pool_size;
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering /* no free addresses left */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = server_send_offer(server, req, address);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* this only fails on critical errors */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_dhcp_server(server, "could not send offer: %s",
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_dhcp_server(server, "DECLINE (0x%x)",
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering /* TODO: make sure we don't offer this address again */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* see RFC 2131, section 4.3.2 */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* SELECTING */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* client did not pick us */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* this MUST be zero */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* this must be filled in with the yiaddr
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering from the chosen OFFER */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* INIT-REBOOT */
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering /* this MUST be zero */
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering /* TODO: check more carefully if IP is correct */
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* REBINDING / RENEWING */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* this MUST be filled in with clients IP address */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering pool_offset = get_pool_offset(server, address);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* verify that the requested address is from the pool, and either
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering owned by the current client or free */
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering server->bound_leases[pool_offset] == existing_lease) {
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering lease->client_id.data = memdup(req->client_id.data,
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering lease->client_id.length = req->client_id.length;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = sd_event_now(server->event, CLOCK_MONOTONIC, &time_now);
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering lease->expiration = req->lifetime * USEC_PER_SEC + time_now;
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering r = server_send_ack(server, req, address);
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering /* this only fails on critical errors */
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering log_dhcp_server(server, "could not send ack: %s",
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering server->bound_leases[pool_offset] = lease;
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering hashmap_put(server->leases_by_client_id, &lease->client_id, lease);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* this only fails on critical errors */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_dhcp_server(server, "could not send nak: %s",
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic int server_receive_message(sd_event_source *s, int fd,
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering _cleanup_free_ DHCPMessage *message = NULL;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering else if ((size_t)len < sizeof(DHCPMessage))
0171da06ef8bb19c175c5aa8aff8cf95f3de7dc1Lennart Poettering for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
r = -errno;