139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt This file is part of systemd.
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt Copyright (C) 2014-2015 Intel Corporation. All rights reserved.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt systemd is free software; you can redistribute it and/or modify it
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt under the terms of the GNU Lesser General Public License as published by
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt the Free Software Foundation; either version 2.1 of the License, or
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt (at your option) any later version.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt systemd is distributed in the hope that it will be useful, but
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt WITHOUT ANY WARRANTY; without even the implied warranty of
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt Lesser General Public License for more details.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt You should have received a copy of the GNU Lesser General Public License
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt along with systemd; If not, see <http://www.gnu.org/licenses/>.
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktconst char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt [DHCP6_INFORMATION_REQUEST] = "INFORMATION-REQUEST",
a9aff3615b430f86bd0a824214d95f634efaf894Patrik FlyktDEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type, int);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktconst char * dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt [DHCP6_STATUS_UNSPEC_FAIL] = "Unspecified failure",
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt [DHCP6_STATUS_NO_ADDRS_AVAIL] = "No addresses available",
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt [DHCP6_STATUS_NO_BINDING] = "Binding unavailable",
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt [DHCP6_STATUS_USE_MULTICAST] = "Use multicast",
631bbe71298ec892f77f44f94feb612646fe6853Patrik FlyktDEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int);
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_dhcp6_client_unrefp) _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flyktstatic int client_start(sd_dhcp6_client *client, enum DHCP6State state);
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poetteringint sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_cb_t cb, void *userdata) {
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poetteringint sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) {
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
c601ebf79f0c54be14d3c16f0f484c0335cdeec4Tom Gundersenint sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address) {
c601ebf79f0c54be14d3c16f0f484c0335cdeec4Tom Gundersen assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0, -EINVAL);
c601ebf79f0c54be14d3c16f0f484c0335cdeec4Tom Gundersen assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams memcmp(&client->mac_addr, addr, addr_len) == 0)
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poetteringstatic int client_ensure_duid(sd_dhcp6_client *client) {
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL);
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen /* accept unknown type in order to be forward compatible */
ebe207d4acf38165adbc45298662982eecdb9e9fTom Gundersen memcpy(&client->duid.raw.data, duid, duid_len);
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersen client->duid_len = duid_len + sizeof(client->duid.type);
04c0136989b7eb896bfb0fb176e11233d69e1453Lennart Poetteringint sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled) {
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
04c0136989b7eb896bfb0fb176e11233d69e1453Lennart Poetteringint sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled) {
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poetteringint sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) {
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt client->req_opts[client->req_opts_len++] = htobe16(option);
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flyktint sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flyktstatic void client_notify(sd_dhcp6_client *client, int event) {
f89087272b5561c9a3fc9d6a4e2a09f75f688fa7Thomas Hallerstatic void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) {
f89087272b5561c9a3fc9d6a4e2a09f75f688fa7Thomas Hallerstatic int client_reset(sd_dhcp6_client *client) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt sd_event_source_unref(client->receive_message);
c806ffb9592fa9a2b13a1f9f9be4c77cd5b211aaZbigniew Jędrzejewski-Szmek client->fd = safe_close(client->fd);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt sd_event_source_unref(client->ia_na.timeout_t1);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt sd_event_source_unref(client->ia_na.timeout_t2);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt client->timeout_resend = sd_event_source_unref(client->timeout_resend);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt sd_event_source_unref(client->timeout_resend_expire);
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flyktstatic void client_stop(sd_dhcp6_client *client, int error) {
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flyktstatic int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt message->transaction_id = client->transaction_id;
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
2c1ab8ca9b5dec48c66eb25dd8af71731e70e517Beniamino Galvani r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_SERVERID,
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
2c1ab8ca9b5dec48c66eb25dd8af71731e70e517Beniamino Galvani r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ORO,
2c1ab8ca9b5dec48c66eb25dd8af71731e70e517Beniamino Galvani r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_CLIENTID,
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt elapsed_usec = time_now - client->transaction_start;
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt if (elapsed_usec < 0xffff * USEC_PER_MSEC * 10)
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt elapsed_time = htobe16(elapsed_usec / USEC_PER_MSEC / 10);
2c1ab8ca9b5dec48c66eb25dd8af71731e70e517Beniamino Galvani r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ELAPSED_TIME,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flyktstatic int client_timeout_t2(sd_event_source *s, uint64_t usec,
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt sd_event_source_unref(client->lease->ia.timeout_t2);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flyktstatic int client_timeout_t1(sd_event_source *s, uint64_t usec,
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt sd_event_source_unref(client->lease->ia.timeout_t1);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic int client_timeout_resend_expire(sd_event_source *s, uint64_t usec,
10c9ce615d98e125bc520efa94aebaef250a4061David Herrmann client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt /* RFC 3315, section 18.1.4., says that "...the client may choose to
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt use a Solicit message to locate a new DHCP server..." */
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt client_start(client, DHCP6_STATE_SOLICITATION);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic usec_t client_timeout_compute_random(usec_t val) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt (random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic int client_timeout_resend(sd_event_source *s, uint64_t usec,
4b4923e65423e60d755841b5b264730e8f3deab3Tom Gundersen usec_t time_now, init_retransmit_time = 0, max_retransmit_time = 0;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt client->timeout_resend = sd_event_source_unref(client->timeout_resend);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt if (client->retransmit_count && client->lease) {
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt /* RFC 3315, section 18.1.3. says max retransmit duration will
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt be the remaining time until T2. Instead of setting MRD,
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt wait for T2 to trigger with the same end result */
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt r = dhcp6_lease_ia_rebind_expire(&client->lease->ia,
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt if (r < 0) {
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt max_retransmit_duration = expire * USEC_PER_SEC;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt client->retransmit_count >= max_retransmit_count) {
10c9ce615d98e125bc520efa94aebaef250a4061David Herrmann client_stop(client, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX);
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt client_timeout_compute_random(init_retransmit_time);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt client->retransmit_time += init_retransmit_time / 10;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt client->retransmit_time > max_retransmit_time / 2)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt client->retransmit_time += client_timeout_compute_random(client->retransmit_time);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_dhcp6_client(client, "Next retransmission in %s",
ed19c567e5fcdcec1a2b6dbac63787e001ad5d55Tom Gundersen format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC));
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = sd_event_add_time(client->event, &client->timeout_resend,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = sd_event_source_set_priority(client->timeout_resend,
356779df90a2ecab5da2cb310ad0f8ebc9ca9f46Lennart Poettering r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timer");
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (max_retransmit_duration && !client->timeout_resend_expire) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = sd_event_source_set_priority(client->timeout_resend_expire,
356779df90a2ecab5da2cb310ad0f8ebc9ca9f46Lennart Poettering r = sd_event_source_set_description(client->timeout_resend_expire, "dhcp6-resend-expire-timer");
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flyktstatic int client_ensure_iaid(sd_dhcp6_client *client) {
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->ia_na.id);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic int client_parse_message(sd_dhcp6_client *client,
44481a8b537839cd9ffead4d261491641f5b5260Zbigniew Jędrzejewski-Szmek uint8_t *optval, *option, *id = NULL;
44481a8b537839cd9ffead4d261491641f5b5260Zbigniew Jędrzejewski-Szmek option = (uint8_t *)message + sizeof(DHCP6Message);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_dhcp6_client(client, "%s contains multiple clientids",
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_dhcp6_client(client, "%s DUID does not match",
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = dhcp6_lease_get_serverid(lease, &id, &id_len);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r >= 0 && id) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_dhcp6_client(client, "%s contains multiple serverids",
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = dhcp6_lease_set_serverid(lease, optval, optlen);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = dhcp6_lease_set_preference(lease, *optval);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt log_dhcp6_client(client, "Information request ignoring IA NA option");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = dhcp6_option_parse_ia(&optval, &optlen, optcode,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r < 0 && r != -ENOMSG)
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt r = dhcp6_lease_set_dns(lease, optval, optlen);
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt r = dhcp6_lease_set_domains(lease, optval, optlen);
6599680e2d33597f0f11a99e1c3c957b42418568Patrik Flykt r = dhcp6_lease_set_ntp(lease, optval, optlen);
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt r = dhcp6_lease_set_sntp(lease, optval, optlen);
c47e8936a43ce546e8a74fa569e9fbfae6c64be7Patrik Flykt if (r < 0 || !clientid) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_dhcp6_client(client, "%s has incomplete options",
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt r = dhcp6_lease_get_serverid(lease, &id, &id_len);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt log_dhcp6_client(client, "%s has no server id",
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poetteringstatic int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt r = client_parse_message(client, reply, len, lease);
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt if (client->state == DHCP6_STATE_SOLICITATION) {
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt r = dhcp6_lease_get_rapid_commit(lease, &rapid_commit);
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poetteringstatic int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = client_parse_message(client, advertise, len, lease);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = dhcp6_lease_get_preference(lease, &pref_advertise);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = dhcp6_lease_get_preference(client->lease, &pref_lease);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt if (pref_advertise == 255 || client->retransmit_count > 1)
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poetteringstatic int client_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
0d43d2fcb7ac5264c739dc2f67f93ed0985a418aTom Gundersen else if (buflen < 0)
0d43d2fcb7ac5264c739dc2f67f93ed0985a418aTom Gundersen /* This really should not happen */
0d43d2fcb7ac5264c739dc2f67f93ed0985a418aTom Gundersen log_dhcp6_client(client, "Could not receive message from UDP socket: %m");
0d43d2fcb7ac5264c739dc2f67f93ed0985a418aTom Gundersen } else if ((size_t)len < sizeof(DHCP6Message))
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_dhcp6_client(client, "unknown message type %d",
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (client->transaction_id != (message->transaction_id &
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt r = client_receive_reply(client, message, len);
10c9ce615d98e125bc520efa94aebaef250a4061David Herrmann client_notify(client, SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = client_receive_advertise(client, message, len);
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt /* fall through for Soliciation Rapid Commit option check */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt r = client_receive_reply(client, message, len);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (r < 0) {
10c9ce615d98e125bc520efa94aebaef250a4061David Herrmann client_notify(client, SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r >= 0) {
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poetteringstatic int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt assert_return(client->state != state, -EINVAL);
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt sd_event_source_unref(client->timeout_resend_expire);
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt client->timeout_resend = sd_event_source_unref(client->timeout_resend);
38a03f06a7393d2721c23f23f0589d2f6d0904afLennart Poettering r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt /* fall through */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (client->lease->ia.lifetime_t1 == 0xffffffff ||
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt log_dhcp6_client(client, "infinite T1 0x%08x or T2 0x%08x",
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC);
ed19c567e5fcdcec1a2b6dbac63787e001ad5d55Tom Gundersen format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen clock_boottime_or_monotonic(), time_now + timeout,
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt r = sd_event_source_set_priority(client->lease->ia.timeout_t1,
356779df90a2ecab5da2cb310ad0f8ebc9ca9f46Lennart Poettering r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout");
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC);
ed19c567e5fcdcec1a2b6dbac63787e001ad5d55Tom Gundersen format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen clock_boottime_or_monotonic(), time_now + timeout,
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt r = sd_event_source_set_priority(client->lease->ia.timeout_t2,
356779df90a2ecab5da2cb310ad0f8ebc9ca9f46Lennart Poettering r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout");
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt client->transaction_id = random_u32() & htobe32(0x00ffffff);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = sd_event_add_time(client->event, &client->timeout_resend,
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen clock_boottime_or_monotonic(), 0, 0, client_timeout_resend,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = sd_event_source_set_priority(client->timeout_resend,
356779df90a2ecab5da2cb310ad0f8ebc9ca9f46Lennart Poettering r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timeout");
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poetteringint sd_dhcp6_client_stop(sd_dhcp6_client *client) {
10c9ce615d98e125bc520efa94aebaef250a4061David Herrmann client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
f667c150a9116022f348cb6d8f2a553dce2386c3Tom Gundersenint sd_dhcp6_client_is_running(sd_dhcp6_client *client) {
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poetteringint sd_dhcp6_client_start(sd_dhcp6_client *client) {
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt enum DHCP6State state = DHCP6_STATE_SOLICITATION;
c601ebf79f0c54be14d3c16f0f484c0335cdeec4Tom Gundersen assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0, -EINVAL);
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
c601ebf79f0c54be14d3c16f0f484c0335cdeec4Tom Gundersen r = dhcp6_network_bind_udp_socket(client->index, &client->local_address);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt r = sd_event_add_io(client->event, &client->receive_message,
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt r = sd_event_source_set_priority(client->receive_message,
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt r = sd_event_source_set_description(client->receive_message,
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt "dhcp6-receive-message");
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt client->information_request? "Information request":
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poetteringint sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int priority) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktint sd_dhcp6_client_detach_event(sd_dhcp6_client *client) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktsd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktsd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktsd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poetteringint sd_dhcp6_client_new(sd_dhcp6_client **ret) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
2c1ab8ca9b5dec48c66eb25dd8af71731e70e517Beniamino Galvani client->ia_na.type = SD_DHCP6_OPTION_IA_NA;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt client->req_opts_len = ELEMENTSOF(default_req_opts);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt client->req_opts = new0(be16_t, client->req_opts_len);