usec_t transaction_start;
struct sd_dhcp6_lease *lease;
int fd;
+ bool information_request;
be16_t *req_opts;
size_t req_opts_allocated;
size_t req_opts_len;
return 0;
}
+int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client,
+ bool enabled) {
+ assert_return(client, -EINVAL);
+
+ client->information_request = enabled;
+
+ return 0;
+}
+
+int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client,
+ bool *enabled) {
+ assert_return(client, -EINVAL);
+ assert_return(enabled, -EINVAL);
+
+ *enabled = client->information_request;
+
+ return 0;
+}
+
int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
uint16_t option) {
size_t t;
message->transaction_id = client->transaction_id;
switch(client->state) {
+ case DHCP6_STATE_INFORMATION_REQUEST:
+ message->type = DHCP6_INFORMATION_REQUEST;
+
+ break;
+
case DHCP6_STATE_SOLICITATION:
message->type = DHCP6_SOLICIT;
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
switch (client->state) {
+ case DHCP6_STATE_INFORMATION_REQUEST:
+ init_retransmit_time = DHCP6_INF_TIMEOUT;
+ max_retransmit_time = DHCP6_INF_MAX_RT;
+
+ break;
+
case DHCP6_STATE_SOLICITATION:
if (client->retransmit_count && client->lease) {
break;
case DHCP6_OPTION_IA_NA:
+ if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
+ log_dhcp6_client(client, "Information request ignoring IA NA option");
+
+ break;
+ }
+
r = dhcp6_option_parse_ia(&optval, &optlen, optcode,
&lease->ia);
if (r < 0 && r != -ENOMSG)
return -EINVAL;
}
- r = dhcp6_lease_get_serverid(lease, &id, &id_len);
- if (r < 0)
- log_dhcp6_client(client, "%s has no server id",
- dhcp6_message_type_to_string(message->type));
+ if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
+ r = dhcp6_lease_get_serverid(lease, &id, &id_len);
+ if (r < 0)
+ log_dhcp6_client(client, "%s has no server id",
+ dhcp6_message_type_to_string(message->type));
+ }
return r;
}
return 0;
}
- if (client->lease)
+ if (client->lease) {
dhcp6_lease_clear_timers(&client->lease->ia);
+ client->lease = sd_dhcp6_lease_unref(client->lease);
+ }
- client->lease = sd_dhcp6_lease_unref(client->lease);
- client->lease = lease;
- lease = NULL;
+ if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
+ client->lease = lease;
+ lease = NULL;
+ }
return DHCP6_STATE_BOUND;
}
return r;
r = dhcp6_lease_get_preference(client->lease, &pref_lease);
- if (!client->lease || r < 0 || pref_advertise > pref_lease) {
+
+ if (r < 0 || pref_advertise > pref_lease) {
sd_dhcp6_lease_unref(client->lease);
client->lease = lease;
lease = NULL;
return 0;
switch (client->state) {
+ case DHCP6_STATE_INFORMATION_REQUEST:
+ r = client_receive_reply(client, message, len);
+ if (r < 0)
+ return 0;
+
+ client_notify(client, DHCP6_EVENT_INFORMATION_REQUEST);
+
+ client_start(client, DHCP6_STATE_STOPPED);
+
+ break;
+
case DHCP6_STATE_SOLICITATION:
r = client_receive_advertise(client, message, len);
assert_return(client->index > 0, -EINVAL);
assert_return(client->state != state, -EINVAL);
+ log_dhcp6_client(client, "client state %d new state %d", client->state, state);
client->timeout_resend_expire =
sd_event_source_unref(client->timeout_resend_expire);
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
switch (state) {
case DHCP6_STATE_STOPPED:
- case DHCP6_STATE_SOLICITATION:
+ if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
+ client->state = DHCP6_STATE_STOPPED;
- r = client_ensure_iaid(client);
- if (r < 0)
- return r;
-
- r = dhcp6_network_bind_udp_socket(client->index, NULL);
- if (r < 0)
- return r;
-
- client->fd = r;
-
- r = sd_event_add_io(client->event, &client->receive_message,
- client->fd, EPOLLIN, client_receive_message,
- client);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_priority(client->receive_message,
- client->event_priority);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_description(client->receive_message, "dhcp6-receive-message");
- if (r < 0)
- return r;
+ return 0;
+ }
+ /* fall through */
+ case DHCP6_STATE_SOLICITATION:
client->state = DHCP6_STATE_SOLICITATION;
break;
+ case DHCP6_STATE_INFORMATION_REQUEST:
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
case DHCP6_STATE_REBIND:
int sd_dhcp6_client_start(sd_dhcp6_client *client)
{
int r = 0;
+ enum DHCP6State state = DHCP6_STATE_SOLICITATION;
assert_return(client, -EINVAL);
assert_return(client->event, -EINVAL);
if (r < 0)
return r;
- return client_start(client, DHCP6_STATE_SOLICITATION);
+ r = client_ensure_iaid(client);
+ if (r < 0)
+ return r;
+
+ r = dhcp6_network_bind_udp_socket(client->index, NULL);
+ if (r < 0)
+ return r;
+
+ client->fd = r;
+
+ r = sd_event_add_io(client->event, &client->receive_message,
+ client->fd, EPOLLIN, client_receive_message,
+ client);
+ if (r < 0)
+ goto error;
+
+ r = sd_event_source_set_priority(client->receive_message,
+ client->event_priority);
+ if (r < 0)
+ goto error;
+
+ r = sd_event_source_set_description(client->receive_message,
+ "dhcp6-receive-message");
+ if (r < 0)
+ goto error;
+
+ if (client->information_request)
+ state = DHCP6_STATE_INFORMATION_REQUEST;
+
+ log_dhcp6_client(client, "Started in %s mode",
+ client->information_request? "Information request":
+ "Managed");
+
+ return client_start(client, state);
+
+error:
+ client_reset(client);
+ return r;
}
int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,