sd-dhcp6-client.c revision 7bd8e95d44977833d0de3fc4e893eb3bc84351d6
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye This file is part of systemd.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye Copyright (C) 2014-2015 Intel Corporation. All rights reserved.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye systemd is free software; you can redistribute it and/or modify it
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye under the terms of the GNU Lesser General Public License as published by
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye the Free Software Foundation; either version 2.1 of the License, or
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye (at your option) any later version.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye systemd is distributed in the hope that it will be useful, but
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye WITHOUT ANY WARRANTY; without even the implied warranty of
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye Lesser General Public License for more details.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye You should have received a copy of the GNU Lesser General Public License
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye along with systemd; If not, see <http://www.gnu.org/licenses/>.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbyeconst char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = {
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye [DHCP6_INFORMATION_REQUEST] = "INFORMATION-REQUEST",
c7eb123c8b2081a261deff3c401fbf92ddba1b58Jorgen AustvikDEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type, int);
1ed6b730409d4740e941142599767d5eac7e7d92Lubos Koscoconst char * dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik [DHCP6_STATUS_UNSPEC_FAIL] = "Unspecified failure",
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik [DHCP6_STATUS_NO_ADDRS_AVAIL] = "No addresses available",
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik [DHCP6_STATUS_NO_BINDING] = "Binding unavailable",
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik [DHCP6_STATUS_USE_MULTICAST] = "Use multicast",
c7eb123c8b2081a261deff3c401fbf92ddba1b58Jorgen AustvikDEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int);
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen AustvikDEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_client*, sd_dhcp6_client_unref);
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik#define _cleanup_dhcp6_client_unref_ _cleanup_(sd_dhcp6_client_unrefp)
49f592091468eac515dde6139fbc8efa26056b0aJorgen Austvik _cleanup_dhcp6_client_unref_ _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
49f592091468eac515dde6139fbc8efa26056b0aJorgen Austvikstatic int client_start(sd_dhcp6_client *client, enum DHCP6State state);
1ed6b730409d4740e941142599767d5eac7e7d92Lubos Koscoint sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
64b763950bf11e9357facbd2b5666631a895c085Trond Norbyeint sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index)
64b763950bf11e9357facbd2b5666631a895c085Trond Norbyeint sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye memcmp(&client->mac_addr, addr, addr_len) == 0)
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbyestatic int client_ensure_duid(sd_dhcp6_client *client)
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbyeint sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid,
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL);
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen if (duid_len != sizeof(client->duid.uuid))
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen /* accept unknown type in order to be forward compatible */
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen memcpy(&client->duid.raw.data, duid, duid_len);
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen client->duid_len = duid_len + sizeof(client->duid.type);
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlenint sd_dhcp6_client_set_information_request(sd_dhcp6_client *client,
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlenint sd_dhcp6_client_get_information_request(sd_dhcp6_client *client,
9661674ed58ba62a40e43d1a4b38d5e77c3c6545Knut Anders Hatlenint sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
9cf297d9a579835e9336d587eaee187ca0954767Knut Anders Hatlen assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
523201f786f6b12b7cf54091c6e5be167878cbeeTrond Norbye if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
0a0811923cbbd2976425db6f4c78eed811c2825bKnut Anders Hatlen client->req_opts[client->req_opts_len++] = htobe16(option);
0a0811923cbbd2976425db6f4c78eed811c2825bKnut Anders Hatlenint sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
a07b2874263e3c5f0cd2e83441719415d53059c2Knut Anders Hatlen *ret = sd_dhcp6_lease_ref(client->lease);
a07b2874263e3c5f0cd2e83441719415d53059c2Knut Anders Hatlenstatic void client_notify(sd_dhcp6_client *client, int event) {
a07b2874263e3c5f0cd2e83441719415d53059c2Knut Anders Hatlen client->cb(client, event, client->userdata);
a07b2874263e3c5f0cd2e83441719415d53059c2Knut Anders Hatlenstatic int client_reset(sd_dhcp6_client *client) {
a07b2874263e3c5f0cd2e83441719415d53059c2Knut Anders Hatlen dhcp6_lease_clear_timers(&client->lease->ia);
a07b2874263e3c5f0cd2e83441719415d53059c2Knut Anders Hatlen client->lease = sd_dhcp6_lease_unref(client->lease);
a07b2874263e3c5f0cd2e83441719415d53059c2Knut Anders Hatlen sd_event_source_unref(client->receive_message);
edcb01bf549171673fd0bb4239f2edfc7a810397Knut Anders Hatlen sd_event_source_unref(client->ia_na.timeout_t1);
edcb01bf549171673fd0bb4239f2edfc7a810397Knut Anders Hatlen sd_event_source_unref(client->ia_na.timeout_t2);
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik client->timeout_resend = sd_event_source_unref(client->timeout_resend);
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik sd_event_source_unref(client->timeout_resend_expire);
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvikstatic void client_stop(sd_dhcp6_client *client, int error) {
85e0595857351c6e22f75b8928967d14cb679ac5Jorgen Austvikstatic int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
85e0595857351c6e22f75b8928967d14cb679ac5Jorgen Austvik IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
1f17ba9e3c026d75f488227451416bd72a222afeTrond Norbye message->transaction_id = client->transaction_id;
49f592091468eac515dde6139fbc8efa26056b0aJorgen Austvik r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
49f592091468eac515dde6139fbc8efa26056b0aJorgen Austvik r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_SERVERID,
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
2e3c025fdd5908a27cc82eb1d5346368a8be4e0dJorgen Austvik r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ORO,
2e3c025fdd5908a27cc82eb1d5346368a8be4e0dJorgen Austvik r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID,
2e3c025fdd5908a27cc82eb1d5346368a8be4e0dJorgen Austvik elapsed_usec = time_now - client->transaction_start;
2e3c025fdd5908a27cc82eb1d5346368a8be4e0dJorgen Austvik if (elapsed_usec < 0xffff * USEC_PER_MSEC * 10)
2e3c025fdd5908a27cc82eb1d5346368a8be4e0dJorgen Austvik elapsed_time = htobe16(elapsed_usec / USEC_PER_MSEC / 10);
2e3c025fdd5908a27cc82eb1d5346368a8be4e0dJorgen Austvik r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ELAPSED_TIME,
void *userdata) {
void *userdata) {
void *userdata) {
assert(s);
void *userdata) {
assert(s);
case DHCP6_STATE_SOLICITATION:
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
case DHCP6_STATE_REBIND:
&expire);
case DHCP6_STATE_STOPPED:
case DHCP6_STATE_BOUND:
if (max_retransmit_count &&
goto error;
if (max_retransmit_time &&
client);
goto error;
goto error;
goto error;
goto error;
goto error;
goto error;
r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->ia_na.id);
bool clientid = false;
&optval)) >= 0) {
switch (optcode) {
case DHCP6_OPTION_CLIENTID:
if (clientid) {
return -EINVAL;
return -EINVAL;
clientid = true;
case DHCP6_OPTION_SERVERID:
if (r >= 0 && id) {
return -EINVAL;
case DHCP6_OPTION_PREFERENCE:
return -EINVAL;
case DHCP6_OPTION_STATUS_CODE:
return -EINVAL;
if (status) {
return -EINVAL;
case DHCP6_OPTION_IA_NA:
if (r < 0 && r != -ENOMSG)
return -EINVAL;
case DHCP6_OPTION_DNS_SERVERS:
if (r == -ENOMSG)
if (r < 0 || !clientid) {
return -EINVAL;
bool rapid_commit;
return -ENOMEM;
if (!rapid_commit)
return DHCP6_STATE_BOUND;
r = DHCP6_STATE_REQUEST;
void *userdata) {
assert(s);
if (r < 0 || buflen <= 0)
if (!message)
return -ENOMEM;
case DHCP6_SOLICIT:
case DHCP6_REQUEST:
case DHCP6_CONFIRM:
case DHCP6_RENEW:
case DHCP6_REBIND:
case DHCP6_RELEASE:
case DHCP6_DECLINE:
case DHCP6_RELAY_FORW:
case DHCP6_RELAY_REPL:
case DHCP6_ADVERTISE:
case DHCP6_REPLY:
case DHCP6_RECONFIGURE:
case DHCP6_STATE_SOLICITATION:
if (r == DHCP6_STATE_REQUEST) {
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
case DHCP6_STATE_REBIND:
if (r == DHCP6_STATE_BOUND) {
case DHCP6_STATE_BOUND:
case DHCP6_STATE_STOPPED:
switch (state) {
case DHCP6_STATE_STOPPED:
case DHCP6_STATE_SOLICITATION:
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
case DHCP6_STATE_REBIND:
case DHCP6_STATE_BOUND:
timeout, 0));
client);
timeout, 0));
client);
client);
client);
goto error;
goto error;
goto error;
int priority)
if (event)
if (!client)
return NULL;
if (client)
return client;
return NULL;
return client;
size_t t;
if (!client)
return -ENOMEM;
return -ENOMEM;