diff options
Diffstat (limited to 'libdhcp/dhcp_client.c')
-rw-r--r-- | libdhcp/dhcp_client.c | 89 |
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"); |