diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 315cbf1ac5d..5a59c377f8c 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -34,6 +34,14 @@ #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12) +static void dhcp_lease_free(DHCPLease *lease) { + if (!lease) + return; + + free(lease->client_id.data); + free(lease); +} + /* configures the server's address and subnet, and optionally the pool's size and offset into the subnet * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address * moreover, the server's own address may be in the pool, and is in that case reserved in order not to @@ -47,7 +55,6 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres assert_return(address, -EINVAL); assert_return(address->s_addr != INADDR_ANY, -EINVAL); assert_return(prefixlen <= 32, -ERANGE); - assert_return(server->address == INADDR_ANY, -EBUSY); assert_se(in_addr_prefixlen_to_netmask(&netmask_addr, prefixlen)); netmask = netmask_addr.s_addr; @@ -78,19 +85,28 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres else size = size_max; - server->bound_leases = new0(DHCPLease*, size); - if (!server->bound_leases) - return -ENOMEM; + if (server->address != address->s_addr || server->netmask != netmask || server->pool_size != size || server->pool_offset != offset) { + DHCPLease *lease; - server->pool_offset = offset; - server->pool_size = size; + free(server->bound_leases); + server->bound_leases = new0(DHCPLease*, size); + if (!server->bound_leases) + return -ENOMEM; - server->address = address->s_addr; - server->netmask = netmask; - server->subnet = address->s_addr & netmask; + server->pool_offset = offset; + server->pool_size = size; - if (server_off >= offset && server_off - offset < size) - server->bound_leases[server_off - offset] = &server->invalid_lease; + server->address = address->s_addr; + server->netmask = netmask; + server->subnet = address->s_addr & netmask; + + if (server_off >= offset && server_off - offset < size) + server->bound_leases[server_off - offset] = &server->invalid_lease; + + /* Drop any leases associated with the old address range */ + while ((lease = hashmap_steal_first(server->leases_by_client_id))) + dhcp_lease_free(lease); + } return 0; } @@ -143,14 +159,6 @@ static const struct hash_ops client_id_hash_ops = { .compare = client_id_compare_func }; -static void dhcp_lease_free(DHCPLease *lease) { - if (!lease) - return; - - free(lease->client_id.data); - free(lease); -} - sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) { DHCPLease *lease; diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index e81c508c7ff..26f217835fb 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -63,7 +63,7 @@ static int test_basic(sd_event *event) { assert_se(sd_dhcp_server_configure_pool(server, &address_any, 28, 0, 0) == -EINVAL); assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 38, 0, 0) == -ERANGE); assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) >= 0); - assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) == -EBUSY); + assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) >= 0); test_pool(&address_any, 1, -EINVAL); test_pool(&address_lo, 1, 0); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 4af61df7ff3..4c57fa17938 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -3060,6 +3060,8 @@ static int link_carrier_lost(Link *link) { return r; } + (void) sd_dhcp_server_stop(link->dhcp_server); + r = link_drop_config(link); if (r < 0) return r;