diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-11-12 11:29:37 -0700 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-11-12 11:29:37 -0700 |
commit | 309b5776552282028908482badd9c45b82ecdaca (patch) | |
tree | 694d4f1ba2ada8a8335a4e89eb1a33959b1958bb /libdhcp/dhcp_client.c | |
parent | e9d1860b0a106e8088e365a9baa912acf98e0c2f (diff) |
libdhcp: Reduce stack use
Diffstat (limited to 'libdhcp/dhcp_client.c')
-rw-r--r-- | libdhcp/dhcp_client.c | 129 |
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); } |