chiark / gitweb /
sd-lldp: minor header cleanup
[elogind.git] / src / libsystemd-network / sd-dhcp6-client.c
index cc5b74416ffdb6dcffe02be90f0e63da783318d5..017371e8371e21d00f37a214c0fad6dfb445e759 100644 (file)
@@ -62,6 +62,7 @@ struct sd_dhcp6_client {
         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;
@@ -227,6 +228,25 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du
         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;
@@ -333,6 +353,11 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
         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;
 
@@ -494,6 +519,12 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
         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) {
@@ -744,6 +775,12 @@ static int client_parse_message(sd_dhcp6_client *client,
                         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)
@@ -779,10 +816,12 @@ static int client_parse_message(sd_dhcp6_client *client,
                 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;
 }
@@ -814,12 +853,15 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply,
                         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;
 }
@@ -846,7 +888,8 @@ static int client_receive_advertise(sd_dhcp6_client *client,
                 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;
@@ -913,6 +956,17 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
                 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);
 
@@ -971,6 +1025,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
         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);
@@ -988,37 +1043,19 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
 
         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:
@@ -1123,6 +1160,7 @@ int sd_dhcp6_client_stop(sd_dhcp6_client *client)
 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);
@@ -1132,7 +1170,44 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client)
         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,