if (error < 0)
log_dhcp_client(client, "STOPPED: %s", strerror(-error));
- else {
- switch(error) {
- case DHCP_EVENT_STOP:
- log_dhcp_client(client, "STOPPED");
- break;
- case DHCP_EVENT_NO_LEASE:
- log_dhcp_client(client, "STOPPED: No lease");
- break;
- default:
- log_dhcp_client(client, "STOPPED: Unknown reason");
- break;
- }
- }
+ else if (error == DHCP_EVENT_STOP)
+ log_dhcp_client(client, "STOPPED");
+ else
+ log_dhcp_client(client, "STOPPED: Unknown event");
client_notify(client, error);
return 0;
}
-static int client_initialize_events(sd_dhcp_client *client,
- sd_event_io_handler_t io_callback) {
+static int client_initialize_io_events(sd_dhcp_client *client,
+ sd_event_io_handler_t io_callback) {
int r;
assert(client);
if (r < 0)
goto error;
+error:
+ if (r < 0)
+ client_stop(client, r);
+
+ return 0;
+}
+
+static int client_initialize_time_events(sd_dhcp_client *client) {
+ int r;
+
+ assert(client);
+ assert(client->event);
+
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
r = sd_event_add_time(client->event,
}
+static int client_initialize_events(sd_dhcp_client *client,
+ sd_event_io_handler_t io_callback) {
+ client_initialize_io_events(client, io_callback);
+ client_initialize_time_events(client);
+
+ return 0;
+}
+
static int client_start(sd_dhcp_client *client) {
int r;
void *userdata) {
sd_dhcp_client *client = userdata;
DHCP_CLIENT_DONT_DESTROY(client);
- int r;
client->state = DHCP_STATE_RENEWING;
client->attempt = 1;
- r = dhcp_network_bind_udp_socket(client->lease->address,
- DHCP_PORT_CLIENT);
- if (r < 0) {
- log_dhcp_client(client, "could not bind UDP socket");
- return 0;
- }
-
- client->fd = r;
-
- return client_initialize_events(client, client_receive_message_udp);
+ return client_initialize_time_events(client);
}
static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
return 0;
}
+static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
+ size_t len) {
+ int r;
+
+ r = dhcp_option_parse(force, len, NULL, NULL);
+ if (r != DHCP_FORCERENEW)
+ return -ENOMSG;
+
+ log_dhcp_client(client, "FORCERENEW");
+
+ return 0;
+}
+
static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
size_t len) {
_cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
if (r == DHCP_NAK) {
log_dhcp_client(client, "NAK");
- return DHCP_EVENT_NO_LEASE;
+ return -EADDRNOTAVAIL;
}
if (r != DHCP_ACK) {
case DHCP_STATE_REBINDING:
r = client_handle_ack(client, message, len);
- if (r == DHCP_EVENT_NO_LEASE) {
-
- client->timeout_resend =
- sd_event_source_unref(client->timeout_resend);
-
- if (client->state == DHCP_STATE_REBOOTING) {
- r = client_initialize(client);
- if (r < 0)
- goto error;
-
- r = client_start(client);
- if (r < 0)
- goto error;
-
- log_dhcp_client(client, "REBOOTED");
- }
-
- goto error;
- } else if (r >= 0) {
+ if (r >= 0) {
client->timeout_resend =
sd_event_source_unref(client->timeout_resend);
if (r < 0)
goto error;
+ r = dhcp_network_bind_udp_socket(client->lease->address,
+ DHCP_PORT_CLIENT);
+ if (r < 0) {
+ log_dhcp_client(client, "could not bind UDP socket");
+ goto error;
+ }
+
+ client->fd = r;
+
+ client_initialize_io_events(client, client_receive_message_udp);
+
if (notify_event) {
client_notify(client, notify_event);
if (client->state == DHCP_STATE_STOPPED)
return 0;
}
- client->receive_message =
- sd_event_source_unref(client->receive_message);
- client->fd = asynchronous_close(client->fd);
+ } else if (r == -EADDRNOTAVAIL) {
+ /* got a NAK, let's restart the client */
+ client->timeout_resend =
+ sd_event_source_unref(client->timeout_resend);
+
+ r = client_initialize(client);
+ if (r < 0)
+ goto error;
+
+ r = client_start(client);
+ if (r < 0)
+ goto error;
+
+ log_dhcp_client(client, "REBOOTED");
+
+ return 0;
+ } else if (r == -ENOMSG)
+ /* invalid message, let's ignore it */
+ return 0;
+
+ break;
+
+ case DHCP_STATE_BOUND:
+ r = client_handle_forcerenew(client, message, len);
+ if (r >= 0) {
+ r = client_timeout_t1(NULL, 0, client);
+ if (r < 0)
+ goto error;
} else if (r == -ENOMSG)
/* invalid message, let's ignore it */
return 0;
case DHCP_STATE_INIT:
case DHCP_STATE_INIT_REBOOT:
- case DHCP_STATE_BOUND:
break;
}
error:
- if (r < 0 || r == DHCP_EVENT_NO_LEASE)
+ if (r < 0)
client_stop(client, r);
return r;
return 0;
}
- if (be32toh(message->xid) != client->xid) {
- log_dhcp_client(client, "received xid (%u) does not match "
- "expected (%u): ignoring",
- be32toh(message->xid), client->xid);
- return 0;
- }
-
if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
log_dhcp_client(client, "not an ethernet packet");
return 0;
return 0;
}
+ if (client->state != DHCP_STATE_BOUND &&
+ be32toh(message->xid) != client->xid) {
+ /* in BOUND state, we may receive FORCERENEW with xid set by server,
+ so ignore the xid in this case */
+ log_dhcp_client(client, "received xid (%u) does not match "
+ "expected (%u): ignoring",
+ be32toh(message->xid), client->xid);
+ return 0;
+ }
+
return client_handle_message(client, message, len);
}