+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
#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
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));
+ assert_se(in4_addr_prefixlen_to_netmask(&netmask_addr, prefixlen));
netmask = netmask_addr.s_addr;
server_off = be32toh(address->s_addr & ~netmask);
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;
+
+ free(server->bound_leases);
+ server->bound_leases = new0(DHCPLease*, size);
+ if (!server->bound_leases)
+ return -ENOMEM;
+
+ server->pool_offset = offset;
+ server->pool_size = size;
- server->pool_offset = offset;
- server->pool_size = size;
+ server->address = address->s_addr;
+ server->netmask = netmask;
+ server->subnet = address->s_addr & netmask;
- 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;
- 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;
}
.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;
hashmap_free(server->leases_by_client_id);
free(server->bound_leases);
- free(server);
-
- return NULL;
+ return mfree(server);
}
int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
server->address = htobe32(INADDR_ANY);
server->netmask = htobe32(INADDR_ANY);
server->ifindex = ifindex;
+
server->leases_by_client_id = hashmap_new(&client_id_hash_ops);
+ if (!server->leases_by_client_id)
+ return -ENOMEM;
+
server->default_lease_time = DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC, USEC_PER_SEC);
server->max_lease_time = DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC, USEC_PER_SEC);
DHCPPacket *packet, size_t len) {
union sockaddr_union link = {
.ll.sll_family = AF_PACKET,
- .ll.sll_protocol = htons(ETH_P_IP),
+ .ll.sll_protocol = htobe16(ETH_P_IP),
.ll.sll_ifindex = server->ifindex,
.ll.sll_halen = ETH_ALEN,
};
if (!existing_lease) {
lease = new0(DHCPLease, 1);
- lease->address = req->requested_ip;
+ if (!lease)
+ return -ENOMEM;
+ lease->address = address;
lease->client_id.data = memdup(req->client_id.data,
req->client_id.length);
if (!lease->client_id.data) {
len = recvmsg(fd, &msg, 0);
if (len < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return -errno;
}
server->fd_raw = r;
- r = dhcp_network_bind_udp_socket(INADDR_ANY, DHCP_PORT_SERVER);
+ r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER);
if (r < 0) {
sd_dhcp_server_stop(server);
return r;