sd-dhcp-client.c revision 0374814250e0ccc4699214422999cb5b35a1afae
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering This file is part of systemd.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering Copyright (C) 2013 Intel Corporation. All rights reserved.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering systemd is free software; you can redistribute it and/or modify it
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering under the terms of the GNU Lesser General Public License as published by
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering (at your option) any later version.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering systemd is distributed in the hope that it will be useful, but
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering Lesser General Public License for more details.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering You should have received a copy of the GNU Lesser General Public License
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering /* 0: Generic (non-LL) (RFC 2132) */
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering /* 1: Ethernet Link-Layer (RFC 2132) */
c30a0c62fdbf6f11902be9db64ade99fb508adfdLennart Poettering /* 2 - 254: ARP/Link-Layer (RFC 2132) */
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering /* 255: Node-specific (RFC 4361) */
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsiefferstatic int client_receive_message_raw(sd_event_source *s, int fd,
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsiefferstatic int client_receive_message_udp(sd_event_source *s, int fd,
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poetteringstatic void client_stop(sd_dhcp_client *client, int error);
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poetteringint sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringint sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poetteringint sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering assert_return (IN_SET(client->state, DHCP_STATE_INIT,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering for (i = 0; i < client->req_opts_size; i++)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek client->req_opts[client->req_opts_size++] = option;
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poetteringint sd_dhcp_client_set_request_address(sd_dhcp_client *client,
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering assert_return (IN_SET(client->state, DHCP_STATE_INIT,
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poetteringint sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poettering assert_return (IN_SET(client->state, DHCP_STATE_INIT,
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering assert_return(interface_index > 0, -EINVAL);
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poetteringint sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
e2cc6eca73cd1df8be552d7c23f9ff3d69c06f1eLennart Poettering assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering assert_return(addr_len == ETH_ALEN, -EINVAL);
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
e2cc6eca73cd1df8be552d7c23f9ff3d69c06f1eLennart Poettering memcmp(&client->mac_addr, addr, addr_len) == 0)
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
65b5116220a8ebf8a260716152409aa05377aaccLennart Poettering log_dhcp_client(client, "Changing MAC address on running DHCP "
65b5116220a8ebf8a260716152409aa05377aaccLennart Poettering "client, restarting");
65b5116220a8ebf8a260716152409aa05377aaccLennart Poettering client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
e2cc6eca73cd1df8be552d7c23f9ff3d69c06f1eLennart Poettering memcpy(&client->mac_addr, addr, addr_len);
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering if (need_restart && client->state != DHCP_STATE_STOPPED)
e2cc6eca73cd1df8be552d7c23f9ff3d69c06f1eLennart Poetteringint sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type,
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering const uint8_t **data, size_t *data_len) {
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering *data_len = client->client_id_len - sizeof(client->client_id.type);
cc3773810855956bad92337cee8fa193584ab62eLennart Poetteringint sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (client->client_id_len == data_len + sizeof(client->client_id.type) &&
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering memcmp(&client->client_id.raw.data, data, data_len) == 0)
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering log_dhcp_client(client, "Changing client ID on running DHCP "
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering "client, restarting");
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering memcpy(&client->client_id.raw.data, data, data_len);
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering client->client_id_len = data_len + sizeof (client->client_id.type);
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering if (need_restart && client->state != DHCP_STATE_STOPPED)
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poetteringint sd_dhcp_client_set_hostname(sd_dhcp_client *client,
if (hostname) {
if (!new_hostname)
return -ENOMEM;
const char *vci) {
if (!new_vci)
return -ENOMEM;
return -EADDRNOTAVAIL;
if (error < 0)
if (!packet)
return -ENOMEM;
r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid);
client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len;
case DHCP_STATE_REQUESTING:
case DHCP_STATE_INIT_REBOOT:
case DHCP_STATE_RENEWING:
case DHCP_STATE_REBINDING:
case DHCP_STATE_INIT:
case DHCP_STATE_SELECTING:
case DHCP_STATE_REBOOTING:
case DHCP_STATE_BOUND:
case DHCP_STATE_STOPPED:
return -EINVAL;
case DHCP_STATE_REQUESTING:
case DHCP_STATE_INIT_REBOOT:
case DHCP_STATE_RENEWING:
case DHCP_STATE_REBINDING:
void *userdata) {
assert(s);
goto error;
case DHCP_STATE_RENEWING:
case DHCP_STATE_REBINDING:
case DHCP_STATE_REBOOTING:
goto error;
goto error;
case DHCP_STATE_INIT:
case DHCP_STATE_INIT_REBOOT:
case DHCP_STATE_SELECTING:
case DHCP_STATE_REQUESTING:
case DHCP_STATE_BOUND:
case DHCP_STATE_STOPPED:
r = -EINVAL;
goto error;
goto error;
goto error;
goto error;
case DHCP_STATE_INIT:
goto error;
case DHCP_STATE_SELECTING:
goto error;
case DHCP_STATE_INIT_REBOOT:
case DHCP_STATE_REQUESTING:
case DHCP_STATE_RENEWING:
case DHCP_STATE_REBINDING:
goto error;
case DHCP_STATE_REBOOTING:
case DHCP_STATE_BOUND:
case DHCP_STATE_STOPPED:
r = -EINVAL;
goto error;
client);
goto error;
goto error;
goto error;
goto error;
goto error;
goto error;
void *userdata) {
void *userdata) {
if (r != DHCP_OFFER) {
return -ENOMSG;
log_dhcp_client(client, "received lease lacks address, server address or lease lifetime, ignoring");
return -ENOMSG;
return -ENOMSG;
if (r != DHCP_FORCERENEW)
return -ENOMSG;
if (r == DHCP_NAK) {
return -EADDRNOTAVAIL;
if (r != DHCP_ACK) {
return -ENOMSG;
return -ENOMSG;
return -ENOMSG;
lifetime = 0;
int len) {
int r = 0, notify_event = 0;
case DHCP_STATE_SELECTING:
goto error;
goto error;
goto error;
} else if (r == -ENOMSG)
case DHCP_STATE_REBOOTING:
case DHCP_STATE_REQUESTING:
case DHCP_STATE_RENEWING:
case DHCP_STATE_REBINDING:
else if (r != SD_DHCP_CLIENT_EVENT_IP_ACQUIRE)
notify_event = r;
goto error;
goto error;
if (notify_event) {
} else if (r == -EADDRNOTAVAIL) {
goto error;
goto error;
} else if (r == -ENOMSG)
case DHCP_STATE_BOUND:
goto error;
} else if (r == -ENOMSG)
case DHCP_STATE_INIT:
case DHCP_STATE_INIT_REBOOT:
case DHCP_STATE_STOPPED:
r = -EINVAL;
goto error;
assert(s);
if (buflen < 0)
return -EIO;
if (!message)
return -ENOMEM;
if (len < 0) {
expected_hlen = 0;
bool checksum = true;
assert(s);
if (buflen < 0)
return -EIO;
if (!packet)
return -ENOMEM;
if (len < 0) {
int priority) {
if (event)
if (!client)
return NULL;
if (!client)
return NULL;
return client;
if (!client)
return NULL;
return NULL;
return NULL;
if (!client)
return -ENOMEM;
return -ENOMEM;