summaryrefslogtreecommitdiff
path: root/libdhcp
diff options
context:
space:
mode:
Diffstat (limited to 'libdhcp')
-rw-r--r--libdhcp/dhcp_client.c89
1 files changed, 40 insertions, 49 deletions
diff --git a/libdhcp/dhcp_client.c b/libdhcp/dhcp_client.c
index 1b4bf61..e5f3232 100644
--- a/libdhcp/dhcp_client.c
+++ b/libdhcp/dhcp_client.c
@@ -182,7 +182,7 @@ struct dhcp_client {
* @return client->last_sent_msgtyp
* @return whether there was an error
*/
-static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, char *errstr) {
+static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const char *errstr) {
/**********************************************************************\
* Preconditions *
\**********************************************************************/
@@ -295,7 +295,7 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, char *e
bool have_cols;
enum requirement cols[5];
size_t val_len;
- void *val_ptr;
+ const void *val_ptr;
} options[0x100] = {
#define V(x) sizeof(x), &(x)
#define NONE 0, NULL
@@ -667,65 +667,66 @@ 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) {
+ if (send_msgtyp)
+ (void)dhcp_client_send(client, send_msgtyp, errstr);
+ client->state = newstate;
+}
+
static __attribute__((noreturn)) void dhcp_client_run(struct dhcp_client *client) {
assert(client);
+ struct dhcp_recv_msg msg;
+ ssize_t r;
+
/* State transition diagram: https://datatracker.ietf.org/doc/html/rfc2131#page-35 */
for (;;) {
switch (client->state) {
- case STATE_INIT: {
+ case STATE_INIT:
client->xid = rand_uint63n(UINT32_MAX);
client->time_ns_init = VCALL(bootclock, get_time_ns);
-
- if (dhcp_client_send(client, DHCP_MSGTYP_DISCOVER, NULL))
- break;
- client->state = STATE_SELECTING;
+ dhcp_client_setstate(client, STATE_SELECTING, DHCP_MSGTYP_DISCOVER, NULL);
break;
- }
- case STATE_SELECTING: {
+ case STATE_SELECTING:
VCALL(client->sock, set_read_deadline, client->time_ns_init+CONFIG_DHCP_SELECTING_NS);
- struct dhcp_recv_msg msg;
- ssize_t r = dhcp_client_recv(client, &msg);
- switch (r) {
+ switch ((r = dhcp_client_recv(client, &msg))) {
case 0:
switch (msg.options[DHCP_OPT_DHCP_MSG_TYPE].dat[0]) {
case DHCP_MSGTYP_OFFER:
/* Accept the first offer. */
dhcp_client_take_lease(client, &msg, false);
- if (dhcp_client_send(client, DHCP_MSGTYP_REQUEST, NULL))
- break;
- client->state = STATE_REQUESTING;
+ dhcp_client_setstate(client, STATE_REQUESTING, DHCP_MSGTYP_REQUEST, NULL);
break;
default:
/* ignore */
}
break;
case -NET_ETIMEDOUT:
- client->state = STATE_INIT;
+ dhcp_client_setstate(client, STATE_INIT, 0, NULL);
break;
default:
assert(r < 0);
debugf("error: recvfrom: %d", r);
}
break;
- }
- case STATE_REQUESTING: {
+ case STATE_REQUESTING:
VCALL(client->sock, set_read_deadline, 0);
- struct dhcp_recv_msg msg;
- ssize_t r = dhcp_client_recv(client, &msg);
- switch (r) {
+ switch ((r = dhcp_client_recv(client, &msg))) {
case 0:
switch (msg.options[DHCP_OPT_DHCP_MSG_TYPE].dat[0]) {
case DHCP_MSGTYP_NAK:
- client->state = STATE_INIT;
+ dhcp_client_setstate(client, STATE_INIT, 0, NULL);
break;
case DHCP_MSGTYP_ACK:
if (dhcp_check_conflict(client->sock, client->lease_client_addr)) {
- (void)dhcp_client_send(client, DHCP_MSGTYP_DECLINE, "IP is already in use");
- client->state = STATE_INIT;
+ dhcp_client_setstate(client, STATE_INIT, DHCP_MSGTYP_DECLINE, "IP is already in use");
} else {
dhcp_client_take_lease(client, &msg, true);
+ dhcp_client_setstate(client, STATE_BOUND, 0, NULL);
}
+ break;
default:
/* ignore */
}
@@ -735,85 +736,75 @@ static __attribute__((noreturn)) void dhcp_client_run(struct dhcp_client *client
debugf("error: recvfrom: %d", r);
}
break;
- }
- case STATE_BOUND: {
+ case STATE_BOUND:
VCALL(client->sock, set_read_deadline, client->lease_time_ns_t1);
- struct dhcp_recv_msg msg;
- ssize_t r = dhcp_client_recv(client, &msg);
- switch (r) {
+ switch ((r = dhcp_client_recv(client, &msg))) {
case 0:
/* discard */
break;
case -NET_ETIMEDOUT:
- if (dhcp_client_send(client, DHCP_MSGTYP_REQUEST, NULL))
- break;
- client->state = STATE_RENEWING;
+ dhcp_client_setstate(client, STATE_RENEWING, DHCP_MSGTYP_REQUEST, NULL);
break;
default:
assert(r < 0);
debugf("error: recvfrom: %d", r);
}
break;
- }
- case STATE_RENEWING: {
+ case STATE_RENEWING:
client->xid = rand_uint63n(UINT32_MAX);
client->time_ns_init = VCALL(bootclock, get_time_ns);
VCALL(client->sock, set_read_deadline, client->lease_time_ns_t2);
- struct dhcp_recv_msg msg;
- ssize_t r = dhcp_client_recv(client, &msg);
- switch (r) {
+ switch ((r = dhcp_client_recv(client, &msg))) {
case 0:
switch (msg.options[DHCP_OPT_DHCP_MSG_TYPE].dat[0]) {
case DHCP_MSGTYP_NAK:
VCALL(client->iface, ifdown);
- client->state = STATE_INIT;
+ dhcp_client_setstate(client, STATE_INIT, 0, NULL);
break;
case DHCP_MSGTYP_ACK:
dhcp_client_take_lease(client, &msg, true);
+ dhcp_client_setstate(client, STATE_BOUND, 0, NULL);
+ break;
default:
/* ignore */
}
break;
case -NET_ETIMEDOUT:
- if (dhcp_client_send(client, DHCP_MSGTYP_REQUEST, NULL))
- break;
client->lease_server_id = net_ip4_addr_zero;
- client->state = STATE_REBINDING;
+ dhcp_client_setstate(client, STATE_REBINDING, DHCP_MSGTYP_REQUEST, NULL);
break;
default:
assert(r < 0);
debugf("error: recvfrom: %d", r);
}
break;
- }
- case STATE_REBINDING: {
+ case STATE_REBINDING:
VCALL(client->sock, set_read_deadline, client->lease_time_ns_end);
- struct dhcp_recv_msg msg;
- ssize_t r = dhcp_client_recv(client, &msg);
- switch (r) {
+ switch ((r = dhcp_client_recv(client, &msg))) {
case 0:
switch (msg.options[DHCP_OPT_DHCP_MSG_TYPE].dat[0]) {
case DHCP_MSGTYP_NAK:
VCALL(client->iface, ifdown);
- client->state = STATE_INIT;
+ dhcp_client_setstate(client, STATE_BOUND, 0, NULL);
break;
case DHCP_MSGTYP_ACK:
dhcp_client_take_lease(client, &msg, true);
+ dhcp_client_setstate(client, STATE_BOUND, 0, NULL);
+ break;
default:
/* ignore */
}
break;
case -NET_ETIMEDOUT:
VCALL(client->iface, ifdown);
- client->state = STATE_INIT;
+ dhcp_client_setstate(client, STATE_BOUND, 0, NULL);
break;
default:
assert(r < 0);
debugf("error: recvfrom: %d", r);
}
break;
- }
case STATE_INIT_REBOOT:
case STATE_REBOOTING:
assert_notreached("initialization with known network address is not supported");