summaryrefslogtreecommitdiff
path: root/libdhcp/dhcp_client.c
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-11-12 11:29:37 -0700
committerLuke T. Shumaker <lukeshu@lukeshu.com>2024-11-12 11:29:37 -0700
commit309b5776552282028908482badd9c45b82ecdaca (patch)
tree694d4f1ba2ada8a8335a4e89eb1a33959b1958bb /libdhcp/dhcp_client.c
parente9d1860b0a106e8088e365a9baa912acf98e0c2f (diff)
libdhcp: Reduce stack use
Diffstat (limited to 'libdhcp/dhcp_client.c')
-rw-r--r--libdhcp/dhcp_client.c129
1 files changed, 65 insertions, 64 deletions
diff --git a/libdhcp/dhcp_client.c b/libdhcp/dhcp_client.c
index bb21564..3728e19 100644
--- a/libdhcp/dhcp_client.c
+++ b/libdhcp/dhcp_client.c
@@ -248,7 +248,7 @@ static inline enum requirement dhcp_table5(typeof((struct dhcp_client){}.state)
* @return client->last_sent_msgtyp
* @return whether there was an error
*/
-static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const char *errstr) {
+static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const char *errstr, struct dhcp_msg *scratch_msg) {
/**********************************************************************\
* Preconditions *
\**********************************************************************/
@@ -290,17 +290,17 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const c
* Build the message *
\**********************************************************************/
- struct dhcp_msg msg = {0};
+ *scratch_msg = (struct dhcp_msg){0};
size_t optlen = 0;
/* Base structure.
* https://datatracker.ietf.org/doc/html/rfc2131#page-37 */
- msg.op = DHCP_OP_BOOTREQUEST;
- msg.htype = DHCP_HTYPE_ETHERNET;
- msg.hlen = sizeof(client->self_eth_addr);
- msg.hops = 0; /* relays increment this when they forward it along */
- msg.xid = uint32be_marshal(client->xid);
- msg.secs = uint16be_marshal( ({
+ scratch_msg->op = DHCP_OP_BOOTREQUEST;
+ scratch_msg->htype = DHCP_HTYPE_ETHERNET;
+ scratch_msg->hlen = sizeof(client->self_eth_addr);
+ scratch_msg->hops = 0; /* relays increment this when they forward it along */
+ scratch_msg->xid = uint32be_marshal(client->xid);
+ scratch_msg->secs = uint16be_marshal( ({
uint16_t secs;
switch (msgtyp) {
case DHCP_MSGTYP_DISCOVER: case DHCP_MSGTYP_INFORM:
@@ -335,42 +335,42 @@ 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:
- msg.flags = uint16be_marshal(server_broadcasts ? DHCP_FLAG_BROADCAST : 0);
+ scratch_msg->flags = uint16be_marshal(server_broadcasts ? DHCP_FLAG_BROADCAST : 0);
break;
case DHCP_MSGTYP_DECLINE: case DHCP_MSGTYP_RELEASE:
- msg.flags = uint16be_marshal(0);
+ scratch_msg->flags = uint16be_marshal(0);
break;
}
switch (msgtyp) {
- case DHCP_MSGTYP_DISCOVER: msg.ciaddr = net_ip4_addr_zero; break;
- case DHCP_MSGTYP_INFORM: msg.ciaddr = client->lease_client_addr; break;
+ case DHCP_MSGTYP_DISCOVER: scratch_msg->ciaddr = net_ip4_addr_zero; break;
+ case DHCP_MSGTYP_INFORM: scratch_msg->ciaddr = client->lease_client_addr; break;
case DHCP_MSGTYP_REQUEST: switch (client->state) {
case STATE_SELECTING: case STATE_INIT_REBOOT:
- msg.ciaddr = net_ip4_addr_zero; break;
+ scratch_msg->ciaddr = net_ip4_addr_zero; break;
case STATE_BOUND: case STATE_RENEWING: /* case STATE_REBINDING: */
/* RFC 2131 includes "REBINDING" here, but a
* DHCPREQUEST is never sent in the REBINDING
* state. */
- msg.ciaddr = client->lease_client_addr; break;
+ scratch_msg->ciaddr = client->lease_client_addr; break;
case IMPOSSIBLE_REQUEST_STATES:
assert_notreached("invalid client state for sending DHCPREQUEST");
- } break;
- case DHCP_MSGTYP_DECLINE: msg.ciaddr = net_ip4_addr_zero; break;
- case DHCP_MSGTYP_RELEASE: msg.ciaddr = client->lease_client_addr; break;
+ } break;
+ case DHCP_MSGTYP_DECLINE: scratch_msg->ciaddr = net_ip4_addr_zero; break;
+ case DHCP_MSGTYP_RELEASE: scratch_msg->ciaddr = client->lease_client_addr; break;
}
- msg.yiaddr = net_ip4_addr_zero; /* only set by servers */
- msg.siaddr = net_ip4_addr_zero; /* only set by servers */
- msg.giaddr = net_ip4_addr_zero; /* only set by relays */
- memcpy(msg.chaddr, client->self_eth_addr.octets, sizeof(client->self_eth_addr));
- /* msg.sname = "options, if indicated in 'sname/file' option'; otherwise unused"; */
- /* msg.file = "options, if indicated in 'sname/file' option'; otherwise unused"; */
+ scratch_msg->yiaddr = net_ip4_addr_zero; /* only set by servers */
+ scratch_msg->siaddr = net_ip4_addr_zero; /* only set by servers */
+ scratch_msg->giaddr = net_ip4_addr_zero; /* only set by relays */
+ memcpy(scratch_msg->chaddr, client->self_eth_addr.octets, sizeof(client->self_eth_addr));
+ /* scratch_msg->sname = "options, if indicated in 'sname/file' option'; otherwise unused"; */
+ /* scratch_msg->file = "options, if indicated in 'sname/file' option'; otherwise unused"; */
/* Magic cookie.
* https://datatracker.ietf.org/doc/html/rfc2131#section-4.1 */
- msg.options[optlen++] = dhcp_magic_cookie[0];
- msg.options[optlen++] = dhcp_magic_cookie[1];
- msg.options[optlen++] = dhcp_magic_cookie[2];
- msg.options[optlen++] = dhcp_magic_cookie[3];
+ scratch_msg->options[optlen++] = dhcp_magic_cookie[0];
+ scratch_msg->options[optlen++] = dhcp_magic_cookie[1];
+ scratch_msg->options[optlen++] = dhcp_magic_cookie[2];
+ scratch_msg->options[optlen++] = dhcp_magic_cookie[3];
/* Options. */
for (uint8_t opt = 1; opt < 255; opt++) {
@@ -415,7 +415,7 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const c
else {
_val16 = uint16be_marshal(20 /* IP header */ +
8 /* UDP header */ +
- sizeof(msg));
+ sizeof(*scratch_msg));
V_OBJ(_val16);
}
break;
@@ -437,9 +437,9 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const c
uint8_t len = val.len - done > UINT8_MAX
? UINT8_MAX
: val.len - done;
- msg.options[optlen++] = opt;
- msg.options[optlen++] = len;
- memcpy(&msg.options[optlen], &((char*)val.ptr)[done], len);
+ scratch_msg->options[optlen++] = opt;
+ scratch_msg->options[optlen++] = len;
+ memcpy(&scratch_msg->options[optlen], &((char*)val.ptr)[done], len);
optlen += len;
done += len;
}
@@ -449,13 +449,13 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const c
assert_notreached("bad table");
}
}
- msg.options[optlen++] = DHCP_OPT_END;
+ scratch_msg->options[optlen++] = DHCP_OPT_END;
assert(optlen <= CONFIG_DHCP_OPT_SIZE);
/**********************************************************************\
* Send *
\**********************************************************************/
- ssize_t r = VCALL(client->sock, sendto, &msg, DHCP_MSG_BASE_SIZE + optlen,
+ ssize_t r = VCALL(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);
@@ -741,16 +741,15 @@ static void dhcp_client_take_lease(struct dhcp_client *client, struct dhcp_recv_
static void dhcp_client_setstate(struct dhcp_client *client,
typeof((struct dhcp_client){}.state) newstate,
- uint8_t send_msgtyp, const char *errstr) {
+ uint8_t send_msgtyp, const char *errstr, struct dhcp_recv_msg *scratch_msg) {
if (send_msgtyp)
- (void)dhcp_client_send(client, send_msgtyp, errstr);
+ (void)dhcp_client_send(client, send_msgtyp, errstr, &scratch_msg->raw);
client->state = newstate;
}
-static __attribute__((noreturn)) void dhcp_client_run(struct dhcp_client *client) {
+static __attribute__((noreturn)) void dhcp_client_run(struct dhcp_client *client, struct dhcp_recv_msg *scratch_msg) {
assert(client);
- struct dhcp_recv_msg msg;
ssize_t r;
/* State transition diagram: https://datatracker.ietf.org/doc/html/rfc2131#page-35 */
@@ -759,24 +758,24 @@ static __attribute__((noreturn)) void dhcp_client_run(struct dhcp_client *client
case STATE_INIT:
client->xid = rand_uint63n(UINT32_MAX);
client->time_ns_init = VCALL(bootclock, get_time_ns);
- dhcp_client_setstate(client, STATE_SELECTING, DHCP_MSGTYP_DISCOVER, NULL);
+ 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);
- switch ((r = dhcp_client_recv(client, &msg))) {
+ switch ((r = dhcp_client_recv(client, scratch_msg))) {
case 0:
- switch (msg.options[DHCP_OPT_DHCP_MSG_TYPE].dat[0]) {
+ switch (scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].dat[0]) {
case DHCP_MSGTYP_OFFER:
/* Accept the first offer. */
- dhcp_client_take_lease(client, &msg, false);
- dhcp_client_setstate(client, STATE_REQUESTING, DHCP_MSGTYP_REQUEST, NULL);
+ dhcp_client_take_lease(client, scratch_msg, false);
+ dhcp_client_setstate(client, STATE_REQUESTING, DHCP_MSGTYP_REQUEST, NULL, scratch_msg);
break;
default:
/* ignore */
}
break;
case -NET_ETIMEDOUT:
- dhcp_client_setstate(client, STATE_INIT, 0, NULL);
+ dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg);
break;
default:
assert(r < 0);
@@ -785,18 +784,18 @@ static __attribute__((noreturn)) void dhcp_client_run(struct dhcp_client *client
break;
case STATE_REQUESTING:
VCALL(client->sock, set_read_deadline, 0);
- switch ((r = dhcp_client_recv(client, &msg))) {
+ switch ((r = dhcp_client_recv(client, scratch_msg))) {
case 0:
- switch (msg.options[DHCP_OPT_DHCP_MSG_TYPE].dat[0]) {
+ switch (scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].dat[0]) {
case DHCP_MSGTYP_NAK:
- dhcp_client_setstate(client, STATE_INIT, 0, NULL);
+ dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg);
break;
case DHCP_MSGTYP_ACK:
if (dhcp_check_conflict(client->sock, client->lease_client_addr)) {
- dhcp_client_setstate(client, STATE_INIT, DHCP_MSGTYP_DECLINE, "IP is already in use");
+ dhcp_client_setstate(client, STATE_INIT, DHCP_MSGTYP_DECLINE, "IP is already in use", scratch_msg);
} else {
- dhcp_client_take_lease(client, &msg, true);
- dhcp_client_setstate(client, STATE_BOUND, 0, NULL);
+ dhcp_client_take_lease(client, scratch_msg, true);
+ dhcp_client_setstate(client, STATE_BOUND, 0, NULL, scratch_msg);
}
break;
default:
@@ -810,12 +809,12 @@ static __attribute__((noreturn)) void dhcp_client_run(struct dhcp_client *client
break;
case STATE_BOUND:
VCALL(client->sock, set_read_deadline, client->lease_time_ns_t1);
- switch ((r = dhcp_client_recv(client, &msg))) {
+ switch ((r = dhcp_client_recv(client, scratch_msg))) {
case 0:
/* discard */
break;
case -NET_ETIMEDOUT:
- dhcp_client_setstate(client, STATE_RENEWING, DHCP_MSGTYP_REQUEST, NULL);
+ dhcp_client_setstate(client, STATE_RENEWING, DHCP_MSGTYP_REQUEST, NULL, scratch_msg);
break;
default:
assert(r < 0);
@@ -827,16 +826,16 @@ static __attribute__((noreturn)) void dhcp_client_run(struct dhcp_client *client
client->time_ns_init = VCALL(bootclock, get_time_ns);
VCALL(client->sock, set_read_deadline, client->lease_time_ns_t2);
- switch ((r = dhcp_client_recv(client, &msg))) {
+ switch ((r = dhcp_client_recv(client, scratch_msg))) {
case 0:
- switch (msg.options[DHCP_OPT_DHCP_MSG_TYPE].dat[0]) {
+ switch (scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].dat[0]) {
case DHCP_MSGTYP_NAK:
VCALL(client->iface, ifdown);
- dhcp_client_setstate(client, STATE_INIT, 0, NULL);
+ dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg);
break;
case DHCP_MSGTYP_ACK:
- dhcp_client_take_lease(client, &msg, true);
- dhcp_client_setstate(client, STATE_BOUND, 0, NULL);
+ dhcp_client_take_lease(client, scratch_msg, true);
+ dhcp_client_setstate(client, STATE_BOUND, 0, NULL, scratch_msg);
break;
default:
/* ignore */
@@ -844,7 +843,7 @@ static __attribute__((noreturn)) void dhcp_client_run(struct dhcp_client *client
break;
case -NET_ETIMEDOUT:
client->lease_server_id = net_ip4_addr_zero;
- dhcp_client_setstate(client, STATE_REBINDING, DHCP_MSGTYP_REQUEST, NULL);
+ dhcp_client_setstate(client, STATE_REBINDING, DHCP_MSGTYP_REQUEST, NULL, scratch_msg);
break;
default:
assert(r < 0);
@@ -853,16 +852,16 @@ static __attribute__((noreturn)) void dhcp_client_run(struct dhcp_client *client
break;
case STATE_REBINDING:
VCALL(client->sock, set_read_deadline, client->lease_time_ns_end);
- switch ((r = dhcp_client_recv(client, &msg))) {
+ switch ((r = dhcp_client_recv(client, scratch_msg))) {
case 0:
- switch (msg.options[DHCP_OPT_DHCP_MSG_TYPE].dat[0]) {
+ switch (scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].dat[0]) {
case DHCP_MSGTYP_NAK:
VCALL(client->iface, ifdown);
- dhcp_client_setstate(client, STATE_BOUND, 0, NULL);
+ dhcp_client_setstate(client, STATE_BOUND, 0, NULL, scratch_msg);
break;
case DHCP_MSGTYP_ACK:
- dhcp_client_take_lease(client, &msg, true);
- dhcp_client_setstate(client, STATE_BOUND, 0, NULL);
+ dhcp_client_take_lease(client, scratch_msg, true);
+ dhcp_client_setstate(client, STATE_BOUND, 0, NULL, scratch_msg);
break;
default:
/* ignore */
@@ -870,7 +869,7 @@ static __attribute__((noreturn)) void dhcp_client_run(struct dhcp_client *client
break;
case -NET_ETIMEDOUT:
VCALL(client->iface, ifdown);
- dhcp_client_setstate(client, STATE_BOUND, 0, NULL);
+ dhcp_client_setstate(client, STATE_BOUND, 0, NULL, scratch_msg);
break;
default:
assert(r < 0);
@@ -915,5 +914,7 @@ __attribute__((noreturn)) void dhcp_client_main(implements_net_iface *iface,
assert(client.sock);
- dhcp_client_run(&client);
+ struct dhcp_recv_msg scratch;
+
+ dhcp_client_run(&client, &scratch);
}