summaryrefslogtreecommitdiff
path: root/libdhcp
diff options
context:
space:
mode:
Diffstat (limited to 'libdhcp')
-rw-r--r--libdhcp/CMakeLists.txt6
-rw-r--r--libdhcp/dhcp_client.c79
-rw-r--r--libdhcp/dhcp_common.h15
-rw-r--r--libdhcp/include/libdhcp/client.h4
4 files changed, 70 insertions, 34 deletions
diff --git a/libdhcp/CMakeLists.txt b/libdhcp/CMakeLists.txt
index 2ded1f4..dee7cb6 100644
--- a/libdhcp/CMakeLists.txt
+++ b/libdhcp/CMakeLists.txt
@@ -1,10 +1,10 @@
-# libdhcp/CMakeLists.txt - TODO
+# libdhcp/CMakeLists.txt - A DHCP client
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
add_library(libdhcp INTERFACE)
-target_include_directories(libdhcp SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_include_directories(libdhcp PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_sources(libdhcp INTERFACE
dhcp_client.c
)
diff --git a/libdhcp/dhcp_client.c b/libdhcp/dhcp_client.c
index c5da59b..8ec3647 100644
--- a/libdhcp/dhcp_client.c
+++ b/libdhcp/dhcp_client.c
@@ -1,6 +1,6 @@
/* libdhcp/dhcp_client.c - A DHCP client
*
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* -----------------------------------------------------------------------------
@@ -87,7 +87,6 @@
#include <string.h> /* for strlen(), memcpy(), memset() */
#include <libmisc/rand.h>
-#include <libmisc/vcall.h>
#include <libhw/generic/alarmclock.h>
#define LOG_NAME DHCP
@@ -125,8 +124,8 @@ enum requirement {
struct dhcp_client {
/* Static. */
- implements_net_iface *iface;
- implements_net_packet_conn *sock;
+ lo_interface net_iface iface;
+ lo_interface net_packet_conn sock;
struct net_eth_addr self_eth_addr;
char *self_hostname;
size_t self_id_len;
@@ -167,6 +166,18 @@ struct dhcp_client {
};
+static const char *state_strs[] = {
+ [STATE_INIT] = "INIT",
+ [STATE_SELECTING] = "SELECTING",
+ [STATE_REQUESTING] = "REQUESTING",
+ [STATE_BOUND] = "BOUND",
+ [STATE_RENEWING] = "RENEWING",
+ [STATE_REBINDING] = "REBINDING",
+
+ [STATE_INIT_REBOOT] = "INIT_REBOOT",
+ [STATE_REBOOTING] = "REBOOTING",
+};
+
/**
* For convenience in switch blocks, a list of the states that, when
* msgtyp==DHCP_MSGTYP_REQUEST, dhcp_client_send() has assert()ed the state is
@@ -301,7 +312,7 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const c
switch (msgtyp) {
case DHCP_MSGTYP_DISCOVER: case DHCP_MSGTYP_INFORM:
case DHCP_MSGTYP_REQUEST:
- secs = (VCALL(bootclock, get_time_ns) - client->time_ns_init)/NS_PER_S;
+ secs = (LO_CALL(bootclock, get_time_ns) - client->time_ns_init)/NS_PER_S;
if (!secs)
/* systemd's sd-dhcp-client.c asserts that some
* servers are broken and require .secs to be
@@ -449,7 +460,8 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const c
/**********************************************************************\
* Send *
\**********************************************************************/
- ssize_t r = VCALL(client->sock, sendto, scratch_msg, DHCP_MSG_BASE_SIZE + optlen,
+ debugf("state %s: sending DHCP %s", state_strs[client->state], dhcp_msgtyp_str(msgtyp));
+ ssize_t r = LO_CALL(client->sock, sendto, scratch_msg, DHCP_MSG_BASE_SIZE + optlen,
client_broadcasts ? net_ip4_addr_broadcast : client->lease_server_id, DHCP_PORT_SERVER);
if (r < 0) {
debugf("error: sendto: %zd", r);
@@ -566,7 +578,7 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg
assert(client);
ignore:
- msg_len = VCALL(client->sock, recvfrom, &ret->raw, sizeof(ret->raw), &srv_addr, &srv_port);
+ msg_len = LO_CALL(client->sock, recvfrom, &ret->raw, sizeof(ret->raw), &srv_addr, &srv_port);
if (msg_len < 0)
/* msg_len is -errno */
return msg_len;
@@ -689,10 +701,11 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg
}
/** @return true if there's a conflict, false if the addr appears to be unused */
-static bool dhcp_check_conflict(implements_net_packet_conn *sock, struct net_ip4_addr addr) {
- assert(sock);
- ssize_t v = VCALL(sock, sendto, "CHECK_IP_CONFLICT", 17, addr, 5000);
- return v != NET_EARP_TIMEOUT;
+static bool dhcp_check_conflict(lo_interface net_packet_conn sock, struct net_ip4_addr addr) {
+ assert(!LO_IS_NULL(sock));
+ ssize_t v = LO_CALL(sock, sendto, "CHECK_IP_CONFLICT", 17, addr, 5000);
+ debugf("check_ip_conflict => %zd", v);
+ return v != -NET_EARP_TIMEOUT;
}
static void dhcp_client_take_lease(struct dhcp_client *client, struct dhcp_recv_msg *msg, bool ifup) {
@@ -726,12 +739,17 @@ static void dhcp_client_take_lease(struct dhcp_client *client, struct dhcp_recv_
client->lease_time_ns_t2 = (dur_ns_t2 == DHCP_INFINITY * NS_PER_S) ? 0 : client->time_ns_init + dur_ns_t2;
client->lease_time_ns_end = (dur_ns_end == DHCP_INFINITY * NS_PER_S) ? 0 : client->time_ns_init + dur_ns_end;
- if (ifup)
- VCALL(client->iface, ifup, (struct net_iface_config){
+ if (ifup) {
+ infof("applying configuration to "PRI_net_eth_addr, ARG_net_eth_addr(client->self_eth_addr));
+ infof(":: addr = "PRI_net_ip4_addr, ARG_net_ip4_addr(client->lease_client_addr));
+ infof(":: gateway_addr = "PRI_net_ip4_addr, ARG_net_ip4_addr(client->lease_auxdata.gateway_addr));
+ infof(":: subnet_mask = "PRI_net_ip4_addr, ARG_net_ip4_addr(client->lease_auxdata.subnet_mask));
+ LO_CALL(client->iface, ifup, (struct net_iface_config){
.addr = client->lease_client_addr,
.gateway_addr = client->lease_auxdata.gateway_addr,
.subnet_mask = client->lease_auxdata.subnet_mask,
});
+ }
}
static void dhcp_client_setstate(struct dhcp_client *client,
@@ -749,14 +767,15 @@ static void dhcp_client_setstate(struct dhcp_client *client,
/* State transition diagram: https://datatracker.ietf.org/doc/html/rfc2131#page-35 */
for (;;) {
+ debugf("loop: state=%s", state_strs[client->state]);
switch (client->state) {
case STATE_INIT:
client->xid = rand_uint63n(UINT32_MAX);
- client->time_ns_init = VCALL(bootclock, get_time_ns);
+ client->time_ns_init = LO_CALL(bootclock, get_time_ns);
dhcp_client_setstate(client, STATE_SELECTING, DHCP_MSGTYP_DISCOVER, NULL, scratch_msg);
break;
case STATE_SELECTING:
- VCALL(client->sock, set_read_deadline, client->time_ns_init+CONFIG_DHCP_SELECTING_NS);
+ LO_CALL(client->sock, set_recv_deadline, client->time_ns_init+CONFIG_DHCP_SELECTING_NS);
switch ((r = dhcp_client_recv(client, scratch_msg))) {
case 0:
switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) {
@@ -778,7 +797,7 @@ static void dhcp_client_setstate(struct dhcp_client *client,
}
break;
case STATE_REQUESTING:
- VCALL(client->sock, set_read_deadline, 0);
+ LO_CALL(client->sock, set_recv_deadline, 0);
switch ((r = dhcp_client_recv(client, scratch_msg))) {
case 0:
switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) {
@@ -787,6 +806,8 @@ static void dhcp_client_setstate(struct dhcp_client *client,
break;
case DHCP_MSGTYP_ACK:
if (dhcp_check_conflict(client->sock, client->lease_client_addr)) {
+ debugf("IP "PRI_net_ip4_addr" is already in use",
+ ARG_net_ip4_addr(client->lease_client_addr));
dhcp_client_setstate(client, STATE_INIT, DHCP_MSGTYP_DECLINE, "IP is already in use", scratch_msg);
} else {
dhcp_client_take_lease(client, scratch_msg, true);
@@ -803,7 +824,7 @@ static void dhcp_client_setstate(struct dhcp_client *client,
}
break;
case STATE_BOUND:
- VCALL(client->sock, set_read_deadline, client->lease_time_ns_t1);
+ LO_CALL(client->sock, set_recv_deadline, client->lease_time_ns_t1);
switch ((r = dhcp_client_recv(client, scratch_msg))) {
case 0:
/* discard */
@@ -818,14 +839,14 @@ static void dhcp_client_setstate(struct dhcp_client *client,
break;
case STATE_RENEWING:
client->xid = rand_uint63n(UINT32_MAX);
- client->time_ns_init = VCALL(bootclock, get_time_ns);
+ client->time_ns_init = LO_CALL(bootclock, get_time_ns);
- VCALL(client->sock, set_read_deadline, client->lease_time_ns_t2);
+ LO_CALL(client->sock, set_recv_deadline, client->lease_time_ns_t2);
switch ((r = dhcp_client_recv(client, scratch_msg))) {
case 0:
switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) {
case DHCP_MSGTYP_NAK:
- VCALL(client->iface, ifdown);
+ LO_CALL(client->iface, ifdown);
dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg);
break;
case DHCP_MSGTYP_ACK:
@@ -846,12 +867,12 @@ static void dhcp_client_setstate(struct dhcp_client *client,
}
break;
case STATE_REBINDING:
- VCALL(client->sock, set_read_deadline, client->lease_time_ns_end);
+ LO_CALL(client->sock, set_recv_deadline, client->lease_time_ns_end);
switch ((r = dhcp_client_recv(client, scratch_msg))) {
case 0:
switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) {
case DHCP_MSGTYP_NAK:
- VCALL(client->iface, ifdown);
+ LO_CALL(client->iface, ifdown);
dhcp_client_setstate(client, STATE_BOUND, 0, NULL, scratch_msg);
break;
case DHCP_MSGTYP_ACK:
@@ -863,7 +884,7 @@ static void dhcp_client_setstate(struct dhcp_client *client,
}
break;
case -NET_ERECV_TIMEOUT:
- VCALL(client->iface, ifdown);
+ LO_CALL(client->iface, ifdown);
dhcp_client_setstate(client, STATE_BOUND, 0, NULL, scratch_msg);
break;
default:
@@ -880,9 +901,9 @@ static void dhcp_client_setstate(struct dhcp_client *client,
}
}
-[[noreturn]] void dhcp_client_main(implements_net_iface *iface,
+[[noreturn]] void dhcp_client_main(lo_interface net_iface iface,
char *self_hostname) {
- assert(iface);
+ assert(!LO_IS_NULL(iface));
/* Even though a client ID is optional and not meaningful for
* us (the best we can do is to duplicate .chaddr), systemd's
@@ -890,14 +911,14 @@ static void dhcp_client_setstate(struct dhcp_client *client,
* require it to be set. */
struct {uint8_t typ; struct net_eth_addr dat;} client_id = {
DHCP_HTYPE_ETHERNET,
- VCALL(iface, hwaddr),
+ LO_CALL(iface, hwaddr),
};
struct dhcp_client client = {
/* Static. */
.iface = iface,
- .sock = VCALL(iface, udp_conn, DHCP_PORT_CLIENT),
- .self_eth_addr = VCALL(iface, hwaddr),
+ .sock = LO_CALL(iface, udp_conn, DHCP_PORT_CLIENT),
+ .self_eth_addr = LO_CALL(iface, hwaddr),
.self_hostname = self_hostname,
.self_id_len = sizeof(client_id),
.self_id_dat = &client_id,
@@ -905,7 +926,7 @@ static void dhcp_client_setstate(struct dhcp_client *client,
/* Mutable. */
.state = STATE_INIT,
};
- assert(client.sock);
+ assert(!LO_IS_NULL(client.sock));
struct dhcp_recv_msg scratch;
diff --git a/libdhcp/dhcp_common.h b/libdhcp/dhcp_common.h
index b265df3..5b51ce2 100644
--- a/libdhcp/dhcp_common.h
+++ b/libdhcp/dhcp_common.h
@@ -68,6 +68,7 @@
#define _LIBDHCP_DHCP_COMMON_H_
#include <libmisc/endian.h>
+#include <libmisc/log.h> /* for const_byte_str() */
/* Config *********************************************************************/
@@ -302,4 +303,18 @@ static inline bool dhcp_opt_length_is_valid(uint8_t opt, uint16_t len) {
#define DHCP_MSGTYP_RELEASE ((uint8_t) 7) /* RFC2132, client->server */
#define DHCP_MSGTYP_INFORM ((uint8_t) 8) /* RFC2132, client->server */
+static const char *dhcp_msgtyp_str(uint8_t typ) {
+ switch (typ) {
+ case DHCP_MSGTYP_DISCOVER: return "DHCP_MSGTYP_DISCOVER";
+ case DHCP_MSGTYP_OFFER: return "DHCP_MSGTYP_OFFER";
+ case DHCP_MSGTYP_REQUEST: return "DHCP_MSGTYP_REQUEST";
+ case DHCP_MSGTYP_DECLINE: return "DHCP_MSGTYP_DECLINE";
+ case DHCP_MSGTYP_ACK: return "DHCP_MSGTYP_ACK";
+ case DHCP_MSGTYP_NAK: return "DHCP_MSGTYP_NAK";
+ case DHCP_MSGTYP_RELEASE: return "DHCP_MSGTYP_RELEASE";
+ case DHCP_MSGTYP_INFORM: return "DHCP_MSGTYP_INFORM";
+ default: return const_byte_str(typ);
+ }
+}
+
#endif /* _LIBDHCP_DHCP_COMMON_H_ */
diff --git a/libdhcp/include/libdhcp/client.h b/libdhcp/include/libdhcp/client.h
index c3cb76f..f81e9b1 100644
--- a/libdhcp/include/libdhcp/client.h
+++ b/libdhcp/include/libdhcp/client.h
@@ -1,6 +1,6 @@
/* libdhcp/client.h - A DHCP client
*
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* -----------------------------------------------------------------------------
@@ -69,7 +69,7 @@
#include <libhw/generic/net.h>
-[[noreturn]] void dhcp_client_main(implements_net_iface *iface,
+[[noreturn]] void dhcp_client_main(lo_interface net_iface iface,
char *self_hostname);
#endif /* _LIBDHCP_CLIENT_H_ */