diff options
Diffstat (limited to 'libdhcp')
-rw-r--r-- | libdhcp/dhcp_client.c | 60 | ||||
-rw-r--r-- | libdhcp/tests/test_client.c | 6 |
2 files changed, 55 insertions, 11 deletions
diff --git a/libdhcp/dhcp_client.c b/libdhcp/dhcp_client.c index 359bd9f..208bc1c 100644 --- a/libdhcp/dhcp_client.c +++ b/libdhcp/dhcp_client.c @@ -461,10 +461,8 @@ static error dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const log_debugln("state ", state_strs[client->state], ": sending DHCP ", dhcp_msgtyp_str(msgtyp)); error err = 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 (!ERROR_IS_NULL(err)) { - log_debugln("error: sendto: ", (error, err)); + if (!ERROR_IS_NULL(err)) return err; - } client->last_sent_msgtyp = msgtyp; return ERROR_NULL; } @@ -573,7 +571,6 @@ static error dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg * ignore: size_t_or_error r = LO_CALL(client->sock, recvfrom, &ret->raw, sizeof(ret->raw), &srv_addr, &srv_port); if (r.is_err) - /* msg_len is -errno */ return r.err; msg_len = r.size_t; @@ -743,8 +740,15 @@ static void dhcp_client_setstate(struct dhcp_client *client, uint8_t send_msgtyp, const char *errstr, struct dhcp_recv_msg *scratch_msg) { if (send_msgtyp) { error err = dhcp_client_send(client, send_msgtyp, errstr, &scratch_msg->raw); + if (!ERROR_IS_NULL(err)) { + log_errorln("error: sendto: ", (error, err)); + if (err.num == E_POSIX_ENETDOWN) + newstate = STATE_INIT; + } error_cleanup(&err); } + if (newstate == STATE_INIT) + LO_CALL(client->iface, ifcfg, (struct net_iface_config){}); client->state = newstate; } @@ -757,6 +761,17 @@ static void dhcp_client_setstate(struct dhcp_client *client, log_debugln("loop: state=", state_strs[client->state]); switch (client->state) { case STATE_INIT: + log_debugln("state ", state_strs[client->state], ": wait for link up"); + uint64_t start = LO_CALL(bootclock, get_time_ns); + LO_CALL(client->iface, wait_for_link_up); + uint64_t end = LO_CALL(bootclock, get_time_ns); + log_debugln("state ", state_strs[client->state], ": link up after ", (duration, end-start)); + /* Just because we've processed link-up on our end + * doesn't mean the router has; 500ms now is better than + * the REQUEST packet getting dropped and us having to + * wait an entire CONFIG_DHCP_SELECTING_NS before + * realizing it. */ + sleep_for_ms(500); client->xid = rand_uint32(); client->time_ns_init = LO_CALL(bootclock, get_time_ns); dhcp_client_setstate(client, STATE_SELECTING, DHCP_MSGTYP_DISCOVER, NULL, scratch_msg); @@ -776,10 +791,15 @@ static void dhcp_client_setstate(struct dhcp_client *client, } break; case E_NET_ERECV_TIMEOUT: + log_errorln("error: recvfrom: ", (error, err), " (action: reset to state=INIT)"); + dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg); + break; + case E_POSIX_ENETDOWN: + log_errorln("error: recvfrom: ", (error, err), " (action: reset to state=INIT)"); dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg); break; default: - log_debugln("error: recvfrom: ", (error, err)); + log_errorln("error: recvfrom: ", (error, err), " (action: ignore)"); } break; case STATE_REQUESTING: @@ -803,8 +823,12 @@ static void dhcp_client_setstate(struct dhcp_client *client, /* ignore */ } break; + case E_POSIX_ENETDOWN: + log_errorln("error: recvfrom: ", (error, err), " (action: reset to state=INIT)"); + dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg); + break; default: - log_debugln("error: recvfrom: ", (error, err)); + log_errorln("error: recvfrom: ", (error, err), " (action: ignore)"); } break; case STATE_BOUND: @@ -814,10 +838,15 @@ static void dhcp_client_setstate(struct dhcp_client *client, /* discard */ break; case E_NET_ERECV_TIMEOUT: + /* Not logging the error here is intentional. */ dhcp_client_setstate(client, STATE_RENEWING, DHCP_MSGTYP_REQUEST, NULL, scratch_msg); break; + case E_POSIX_ENETDOWN: + log_errorln("error: recvfrom: ", (error, err), " (action: reset to state=INIT)"); + dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg); + break; default: - log_debugln("error: recvfrom: ", (error, err)); + log_errorln("error: recvfrom: ", (error, err), " (action: ignore)"); } break; case STATE_RENEWING: @@ -841,11 +870,16 @@ static void dhcp_client_setstate(struct dhcp_client *client, } break; case E_NET_ERECV_TIMEOUT: + log_errorln("error: recvfrom: ", (error, err), " (action: forget server, set state=REBINDING)"); client->lease_server_id = net_ip4_addr_zero; dhcp_client_setstate(client, STATE_REBINDING, DHCP_MSGTYP_REQUEST, NULL, scratch_msg); break; + case E_POSIX_ENETDOWN: + log_errorln("error: recvfrom: ", (error, err), " (action: reset to state=INIT)"); + dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg); + break; default: - log_debugln("error: recvfrom: ", (error, err)); + log_errorln("error: recvfrom: ", (error, err), " (action: ignore)"); } break; case STATE_REBINDING: @@ -866,11 +900,15 @@ static void dhcp_client_setstate(struct dhcp_client *client, } break; case E_NET_ERECV_TIMEOUT: - LO_CALL(client->iface, ifcfg, (struct net_iface_config){}); - dhcp_client_setstate(client, STATE_BOUND, 0, NULL, scratch_msg); + log_errorln("error: recvfrom: ", (error, err), " (action: reset to state=INIT)"); + dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg); + break; + case E_POSIX_ENETDOWN: + log_errorln("error: recvfrom: ", (error, err), " (action: reset to state=INIT)"); + dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg); break; default: - log_debugln("error: recvfrom: ", (error, err)); + log_errorln("error: recvfrom: ", (error, err), " (action: ignore)"); } break; case STATE_INIT_REBOOT: diff --git a/libdhcp/tests/test_client.c b/libdhcp/tests/test_client.c index 772d778..0112e76 100644 --- a/libdhcp/tests/test_client.c +++ b/libdhcp/tests/test_client.c @@ -99,6 +99,12 @@ static void test_ifcfg(struct test_iface *LM_UNUSED(self), struct net_iface_conf cr_exit(); } +static bool test_is_link_up(struct test_iface *LM_UNUSED(self)) { + return true; +} + +static void test_wait_for_link_up(struct test_iface *LM_UNUSED(self)) {} + static bool test_arp_ping(struct test_iface *LM_UNUSED(self), struct net_ip4_addr LM_UNUSED(addr)) { return false; } |