diff --git a/Makefile.am b/Makefile.am index 8af29d160e..4f5e036990 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2345,6 +2345,8 @@ noinst_LTLIBRARIES += \ libsystemd_dhcp_la_SOURCES = \ src/systemd/sd-dhcp-client.h \ src/libsystemd-dhcp/sd-dhcp-client.c \ + src/libsystemd-dhcp/dhcp-lease.h \ + src/libsystemd-dhcp/dhcp-lease.c \ src/libsystemd-dhcp/dhcp-network.c \ src/libsystemd-dhcp/dhcp-option.c \ src/libsystemd-dhcp/dhcp-internal.h \ diff --git a/src/libsystemd-dhcp/dhcp-lease.c b/src/libsystemd-dhcp/dhcp-lease.c new file mode 100644 index 0000000000..c1f76aa561 --- /dev/null +++ b/src/libsystemd-dhcp/dhcp-lease.c @@ -0,0 +1,244 @@ +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + Copyright (C) 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "list.h" + +#include "dhcp-protocol.h" +#include "dhcp-internal.h" +#include "dhcp-lease.h" +#include "sd-dhcp-client.h" + +int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + addr->s_addr = lease->address; + + return 0; +} + +int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) { + assert_return(lease, -EINVAL); + assert_return(mtu, -EINVAL); + + if (lease->mtu) + *mtu = lease->mtu; + else + return -ENOENT; + + return 0; +} + +int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, struct in_addr **addr, size_t *addr_size) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + assert_return(addr_size, -EINVAL); + + if (lease->dns_size) { + *addr_size = lease->dns_size; + *addr = lease->dns; + } else + return -ENOENT; + + return 0; +} + +int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) { + assert_return(lease, -EINVAL); + assert_return(domainname, -EINVAL); + + if (lease->domainname) + *domainname = lease->domainname; + else + return -ENOENT; + + return 0; +} + +int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) { + assert_return(lease, -EINVAL); + assert_return(hostname, -EINVAL); + + if (lease->hostname) + *hostname = lease->hostname; + else + return -ENOENT; + + return 0; +} + +int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + addr->s_addr = lease->router; + + return 0; +} + +int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + addr->s_addr = lease->subnet_mask; + + return 0; +} + +sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) { + if (lease) + assert_se(REFCNT_INC(lease->n_ref) >= 2); + + return lease; +} + +sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) { + if (lease && REFCNT_DEC(lease->n_ref) <= 0) { + free(lease->hostname); + free(lease->domainname); + free(lease->dns); + free(lease); + } + + return NULL; +} + +int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option, + void *user_data) { + sd_dhcp_lease *lease = user_data; + be32_t val; + + switch(code) { + + case DHCP_OPTION_IP_ADDRESS_LEASE_TIME: + if (len == 4) { + memcpy(&val, option, 4); + lease->lifetime = be32toh(val); + } + + break; + + case DHCP_OPTION_SERVER_IDENTIFIER: + if (len >= 4) + memcpy(&lease->server_address, option, 4); + + break; + + case DHCP_OPTION_SUBNET_MASK: + if (len >= 4) + memcpy(&lease->subnet_mask, option, 4); + + break; + + case DHCP_OPTION_ROUTER: + if (len >= 4) + memcpy(&lease->router, option, 4); + + break; + + case DHCP_OPTION_DOMAIN_NAME_SERVER: + if (len && !(len % 4)) { + unsigned i; + + lease->dns_size = len / 4; + + free(lease->dns); + lease->dns = new0(struct in_addr, lease->dns_size); + if (!lease->dns) + return -ENOMEM; + + for (i = 0; i < lease->dns_size; i++) { + memcpy(&lease->dns[i].s_addr, option + 4 * i, 4); + } + } + + break; + + case DHCP_OPTION_INTERFACE_MTU: + if (len >= 2) { + be16_t mtu; + + memcpy(&mtu, option, 2); + lease->mtu = be16toh(mtu); + + if (lease->mtu < 68) + lease->mtu = 0; + } + + break; + + case DHCP_OPTION_DOMAIN_NAME: + if (len >= 1) { + free(lease->domainname); + lease->domainname = strndup((const char *)option, len); + } + + break; + + case DHCP_OPTION_HOST_NAME: + if (len >= 1) { + free(lease->hostname); + lease->hostname = strndup((const char *)option, len); + } + + break; + + case DHCP_OPTION_RENEWAL_T1_TIME: + if (len == 4) { + memcpy(&val, option, 4); + lease->t1 = be32toh(val); + } + + break; + + case DHCP_OPTION_REBINDING_T2_TIME: + if (len == 4) { + memcpy(&val, option, 4); + lease->t2 = be32toh(val); + } + + break; + } + + return 0; +} + +int dhcp_lease_new(sd_dhcp_lease **ret) { + _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; + + lease = new0(sd_dhcp_lease, 1); + if (!lease) + return -ENOMEM; + + lease->n_ref = REFCNT_INIT; + + *ret = lease; + lease = NULL; + + return 0; +} diff --git a/src/libsystemd-dhcp/dhcp-lease.h b/src/libsystemd-dhcp/dhcp-lease.h new file mode 100644 index 0000000000..87323dcb37 --- /dev/null +++ b/src/libsystemd-dhcp/dhcp-lease.h @@ -0,0 +1,57 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + Copyright (C) 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "socket-util.h" +#include "refcnt.h" + +#include "dhcp-protocol.h" + +#include "sd-dhcp-client.h" + +struct sd_dhcp_lease { + RefCount n_ref; + + uint32_t t1; + uint32_t t2; + uint32_t lifetime; + be32_t address; + be32_t server_address; + be32_t subnet_mask; + be32_t router; + struct in_addr *dns; + size_t dns_size; + uint16_t mtu; + char *domainname; + char *hostname; +}; + +int dhcp_lease_new(sd_dhcp_lease **ret); +int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option, + void *user_data); + +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_lease*, sd_dhcp_lease_unref); +#define _cleanup_dhcp_lease_unref_ _cleanup_(sd_dhcp_lease_unrefp) diff --git a/src/libsystemd-dhcp/sd-dhcp-client.c b/src/libsystemd-dhcp/sd-dhcp-client.c index 3b3785809e..72998bc6cb 100644 --- a/src/libsystemd-dhcp/sd-dhcp-client.c +++ b/src/libsystemd-dhcp/sd-dhcp-client.c @@ -28,37 +28,12 @@ #include "list.h" #include "dhcp-protocol.h" +#include "dhcp-lease.h" #include "dhcp-internal.h" #include "sd-dhcp-client.h" #define DHCP_CLIENT_MIN_OPTIONS_SIZE 312 -#define client_state_machine_check(s, r) \ - do { \ - if (s != DHCP_STATE_BOUND && \ - s != DHCP_STATE_RENEWING && \ - s != DHCP_STATE_REBINDING) { \ - return (r); \ - } \ - } while (false) - -struct DHCPLease { - uint32_t t1; - uint32_t t2; - uint32_t lifetime; - be32_t address; - be32_t server_address; - be32_t subnet_mask; - be32_t router; - struct in_addr *dns; - size_t dns_size; - uint16_t mtu; - char *domainname; - char *hostname; -}; - -typedef struct DHCPLease DHCPLease; - struct sd_dhcp_client { DHCPState state; sd_event *event; @@ -83,7 +58,7 @@ struct sd_dhcp_client { sd_event_source *timeout_expire; sd_dhcp_client_cb_t cb; void *userdata; - DHCPLease *lease; + sd_dhcp_lease *lease; }; static const uint8_t default_req_opts[] = { @@ -172,93 +147,16 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, return 0; } -int sd_dhcp_client_get_address(sd_dhcp_client *client, struct in_addr *addr) { +int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { assert_return(client, -EINVAL); - assert_return(addr, -EINVAL); + assert_return(ret, -EINVAL); - client_state_machine_check (client->state, -EADDRNOTAVAIL); + if (client->state != DHCP_STATE_BOUND && + client->state != DHCP_STATE_RENEWING && + client->state != DHCP_STATE_REBINDING) + return -EADDRNOTAVAIL; - addr->s_addr = client->lease->address; - - return 0; -} - -int sd_dhcp_client_get_mtu(sd_dhcp_client *client, uint16_t *mtu) { - assert_return(client, -EINVAL); - assert_return(mtu, -EINVAL); - - client_state_machine_check (client->state, -EADDRNOTAVAIL); - - if (client->lease->mtu) - *mtu = client->lease->mtu; - else - return -ENOENT; - - return 0; -} - -int sd_dhcp_client_get_dns(sd_dhcp_client *client, struct in_addr **addr, size_t *addr_size) { - assert_return(client, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(addr_size, -EINVAL); - - client_state_machine_check (client->state, -EADDRNOTAVAIL); - - if (client->lease->dns_size) { - *addr_size = client->lease->dns_size; - *addr = client->lease->dns; - } else - return -ENOENT; - - return 0; -} - -int sd_dhcp_client_get_domainname(sd_dhcp_client *client, const char **domainname) { - assert_return(client, -EINVAL); - assert_return(domainname, -EINVAL); - - client_state_machine_check (client->state, -EADDRNOTAVAIL); - - if (client->lease->domainname) - *domainname = client->lease->domainname; - else - return -ENOENT; - - return 0; -} - -int sd_dhcp_client_get_hostname(sd_dhcp_client *client, const char **hostname) { - assert_return(client, -EINVAL); - assert_return(hostname, -EINVAL); - - client_state_machine_check (client->state, -EADDRNOTAVAIL); - - if (client->lease->hostname) - *hostname = client->lease->hostname; - else - return -ENOENT; - - return 0; -} - -int sd_dhcp_client_get_router(sd_dhcp_client *client, struct in_addr *addr) { - assert_return(client, -EINVAL); - assert_return(addr, -EINVAL); - - client_state_machine_check (client->state, -EADDRNOTAVAIL); - - addr->s_addr = client->lease->router; - - return 0; -} - -int sd_dhcp_client_get_netmask(sd_dhcp_client *client, struct in_addr *addr) { - assert_return(client, -EINVAL); - assert_return(addr, -EINVAL); - - client_state_machine_check (client->state, -EADDRNOTAVAIL); - - addr->s_addr = client->lease->subnet_mask; + *ret = sd_dhcp_lease_ref(client->lease); return 0; } @@ -270,19 +168,6 @@ static int client_notify(sd_dhcp_client *client, int event) { return 0; } -static void lease_free(DHCPLease *lease) { - if (!lease) - return; - - free(lease->hostname); - free(lease->domainname); - free(lease->dns); - free(lease); -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPLease*, lease_free); -#define _cleanup_lease_free_ _cleanup_(lease_freep) - static int client_stop(sd_dhcp_client *client, int error) { assert_return(client, -EINVAL); @@ -307,10 +192,8 @@ static int client_stop(sd_dhcp_client *client, int error) { client->secs = 0; client->state = DHCP_STATE_INIT; - if (client->lease) { - lease_free(client->lease); - client->lease = NULL; - } + if (client->lease) + client->lease = sd_dhcp_lease_unref(client->lease); return 0; } @@ -721,106 +604,6 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) return client_initialize_events(client, usec); } -static int client_parse_options(uint8_t code, uint8_t len, const uint8_t *option, - void *user_data) { - DHCPLease *lease = user_data; - be32_t val; - - switch(code) { - - case DHCP_OPTION_IP_ADDRESS_LEASE_TIME: - if (len == 4) { - memcpy(&val, option, 4); - lease->lifetime = be32toh(val); - } - - break; - - case DHCP_OPTION_SERVER_IDENTIFIER: - if (len >= 4) - memcpy(&lease->server_address, option, 4); - - break; - - case DHCP_OPTION_SUBNET_MASK: - if (len >= 4) - memcpy(&lease->subnet_mask, option, 4); - - break; - - case DHCP_OPTION_ROUTER: - if (len >= 4) - memcpy(&lease->router, option, 4); - - break; - - case DHCP_OPTION_DOMAIN_NAME_SERVER: - if (len && !(len % 4)) { - unsigned i; - - lease->dns_size = len / 4; - - free(lease->dns); - lease->dns = new0(struct in_addr, lease->dns_size); - if (!lease->dns) - return -ENOMEM; - - for (i = 0; i < lease->dns_size; i++) { - memcpy(&lease->dns[i].s_addr, option + 4 * i, 4); - } - } - - break; - - case DHCP_OPTION_INTERFACE_MTU: - if (len >= 2) { - be16_t mtu; - - memcpy(&mtu, option, 2); - lease->mtu = be16toh(mtu); - - if (lease->mtu < 68) - lease->mtu = 0; - } - - break; - - case DHCP_OPTION_DOMAIN_NAME: - if (len >= 1) { - free(lease->domainname); - lease->domainname = strndup((const char *)option, len); - } - - break; - - case DHCP_OPTION_HOST_NAME: - if (len >= 1) { - free(lease->hostname); - lease->hostname = strndup((const char *)option, len); - } - - break; - - case DHCP_OPTION_RENEWAL_T1_TIME: - if (len == 4) { - memcpy(&val, option, 4); - lease->t1 = be32toh(val); - } - - break; - - case DHCP_OPTION_REBINDING_T2_TIME: - if (len == 4) { - memcpy(&val, option, 4); - lease->t2 = be32toh(val); - } - - break; - } - - return 0; -} - static int client_verify_headers(sd_dhcp_client *client, DHCPPacket *message, size_t len) { size_t hdrlen; @@ -864,19 +647,19 @@ static int client_verify_headers(sd_dhcp_client *client, DHCPPacket *message, static int client_receive_offer(sd_dhcp_client *client, DHCPPacket *offer, size_t len) { - _cleanup_lease_free_ DHCPLease *lease = NULL; + _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; int r; r = client_verify_headers(client, offer, len); if (r < 0) return r; - lease = new0(DHCPLease, 1); - if (!lease) - return -ENOMEM; + r = dhcp_lease_new(&lease); + if (r < 0) + return r; len = len - DHCP_IP_UDP_SIZE; - r = dhcp_option_parse(&offer->dhcp, len, client_parse_options, + r = dhcp_option_parse(&offer->dhcp, len, dhcp_lease_parse_options, lease); if (r != DHCP_OFFER) return -ENOMSG; @@ -899,7 +682,7 @@ static int client_receive_ack(sd_dhcp_client *client, const uint8_t *buf, size_t len) { DHCPPacket *ack; DHCPMessage *dhcp; - _cleanup_lease_free_ DHCPLease *lease = NULL; + _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; int r; if (client->state == DHCP_STATE_RENEWING) { @@ -915,11 +698,11 @@ static int client_receive_ack(sd_dhcp_client *client, const uint8_t *buf, len -= DHCP_IP_UDP_SIZE; } - lease = new0(DHCPLease, 1); - if (!lease) - return -ENOMEM; + r = dhcp_lease_new(&lease); + if (r < 0) + return r; - r = dhcp_option_parse(dhcp, len, client_parse_options, lease); + r = dhcp_option_parse(dhcp, len, dhcp_lease_parse_options, lease); if (r == DHCP_NAK) return DHCP_EVENT_NO_LEASE; @@ -941,7 +724,7 @@ static int client_receive_ack(sd_dhcp_client *client, const uint8_t *buf, r = DHCP_EVENT_IP_CHANGE; } - lease_free(client->lease); + client->lease = sd_dhcp_lease_unref(client->lease); } client->lease = lease; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 563eab9887..2883f195da 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -75,14 +75,8 @@ void link_free(Link *link) { assert(link->manager); - if (link->dhcp) - sd_dhcp_client_free(link->dhcp); - - route_free(link->dhcp_route); - link->dhcp_route = NULL; - - address_free(link->dhcp_address); - link->dhcp_address = NULL; + sd_dhcp_client_free(link->dhcp_client); + sd_dhcp_lease_unref(link->dhcp_lease); hashmap_remove(link->manager->links, &link->ifindex); @@ -176,7 +170,7 @@ static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { } static int link_enter_set_routes(Link *link) { - Route *route; + Route *rt; int r; assert(link); @@ -185,13 +179,13 @@ static int link_enter_set_routes(Link *link) { link->state = LINK_STATE_SETTING_ROUTES; - if (!link->network->static_routes && !link->dhcp_route) + if (!link->network->static_routes && !link->dhcp_lease) return link_enter_configured(link); log_debug_link(link, "setting routes"); - LIST_FOREACH(static_routes, route, link->network->static_routes) { - r = route_configure(route, link, &route_handler); + LIST_FOREACH(static_routes, rt, link->network->static_routes) { + r = route_configure(rt, link, &route_handler); if (r < 0) { log_warning_link(link, "could not set routes: %s", strerror(-r)); @@ -202,8 +196,28 @@ static int link_enter_set_routes(Link *link) { link->route_messages ++; } - if (link->dhcp_route) { - r = route_configure(link->dhcp_route, link, &route_handler); + if (link->dhcp_lease) { + _cleanup_route_free_ Route *route = NULL; + struct in_addr gateway; + + r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); + if (r < 0) { + log_warning_link(link, "DHCP error: no router: %s", + strerror(-r)); + return r; + } + + r = route_new_dynamic(&route); + if (r < 0) { + log_error_link(link, "Could not allocate route: %s", + strerror(-r)); + return r; + } + + route->family = AF_INET; + route->in_addr.in = gateway; + + r = route_configure(route, link, &route_handler); if (r < 0) { log_warning_link(link, "could not set routes: %s", strerror(-r)); @@ -249,7 +263,7 @@ static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { } static int link_enter_set_addresses(Link *link) { - Address *address; + Address *ad; int r; assert(link); @@ -258,13 +272,13 @@ static int link_enter_set_addresses(Link *link) { link->state = LINK_STATE_SETTING_ADDRESSES; - if (!link->network->static_addresses && !link->dhcp_address) + if (!link->network->static_addresses && !link->dhcp_lease) return link_enter_set_routes(link); log_debug_link(link, "setting addresses"); - LIST_FOREACH(static_addresses, address, link->network->static_addresses) { - r = address_configure(address, link, &address_handler); + LIST_FOREACH(static_addresses, ad, link->network->static_addresses) { + r = address_configure(ad, link, &address_handler); if (r < 0) { log_warning_link(link, "could not set addresses: %s", strerror(-r)); @@ -275,8 +289,41 @@ static int link_enter_set_addresses(Link *link) { link->addr_messages ++; } - if (link->dhcp_address) { - r = address_configure(link->dhcp_address, link, &address_handler); + if (link->dhcp_lease) { + _cleanup_address_free_ Address *address = NULL; + struct in_addr addr; + struct in_addr netmask; + unsigned prefixlen; + + r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr); + if (r < 0) { + log_warning_link(link, "DHCP error: no address: %s", + strerror(-r)); + return r; + } + + r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask); + if (r < 0) { + log_warning_link(link, "DHCP error: no netmask: %s", + strerror(-r)); + return r; + } + + prefixlen = net_netmask_to_prefixlen(&netmask); + + r = address_new_dynamic(&address); + if (r < 0) { + log_error_link(link, "Could not allocate address: %s", + strerror(-r)); + return r; + } + + address->family = AF_INET; + address->in_addr.in = addr; + address->prefixlen = prefixlen; + address->broadcast.s_addr = addr.s_addr | ~netmask.s_addr; + + r = address_configure(address, link, &address_handler); if (r < 0) { log_warning_link(link, "could not set addresses: %s", strerror(-r)); @@ -410,28 +457,33 @@ static int link_set_mtu(Link *link, uint32_t mtu) { return 0; } -static int dhcp_lease_lost(sd_dhcp_client *client, Link *link) { +static int dhcp_lease_lost(Link *link) { + _cleanup_address_free_ Address *address = NULL; + struct in_addr addr; + struct in_addr netmask; + unsigned prefixlen; int r; - assert(client); assert(link); + assert(link->dhcp_lease); - if (link->dhcp_address) { - address_drop(link->dhcp_address, link, address_drop_handler); + r = address_new_dynamic(&address); + if (r >= 0) { + sd_dhcp_lease_get_address(link->dhcp_lease, &addr); + sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask); + prefixlen = net_netmask_to_prefixlen(&netmask); - address_free(link->dhcp_address); - link->dhcp_address = NULL; - } + address->family = AF_INET; + address->in_addr.in = addr; + address->prefixlen = prefixlen; - if (link->dhcp_route) { - route_free(link->dhcp_route); - link->dhcp_route = NULL; + address_drop(address, link, address_drop_handler); } if (link->network->dhcp_mtu) { uint16_t mtu; - r = sd_dhcp_client_get_mtu(client, &mtu); + r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu); if (r >= 0 && link->original_mtu != mtu) { r = link_set_mtu(link, link->original_mtu); if (r < 0) { @@ -448,10 +500,13 @@ static int dhcp_lease_lost(sd_dhcp_client *client, Link *link) { log_error("Failed to reset transient hostname"); } + link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease); + return 0; } static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { + sd_dhcp_lease *lease; struct in_addr address; struct in_addr netmask; struct in_addr gateway; @@ -465,14 +520,21 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { assert(client); assert(link); - r = sd_dhcp_client_get_address(client, &address); + r = sd_dhcp_client_get_lease(client, &lease); + if (r < 0) { + log_warning_link(link, "DHCP error: no lease: %s", + strerror(-r)); + return r; + } + + r = sd_dhcp_lease_get_address(lease, &address); if (r < 0) { log_warning_link(link, "DHCP error: no address: %s", strerror(-r)); return r; } - r = sd_dhcp_client_get_netmask(client, &netmask); + r = sd_dhcp_lease_get_netmask(lease, &netmask); if (r < 0) { log_warning_link(link, "DHCP error: no netmask: %s", strerror(-r)); @@ -481,14 +543,13 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { prefixlen = net_netmask_to_prefixlen(&netmask); - r = sd_dhcp_client_get_router(client, &gateway); + r = sd_dhcp_lease_get_router(lease, &gateway); if (r < 0) { log_warning_link(link, "DHCP error: no router: %s", strerror(-r)); return r; } - log_struct_link(LOG_INFO, link, "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u", link->ifname, @@ -503,35 +564,8 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { ADDRESS_FMT_VAL(gateway), NULL); - r = address_new_dynamic(&addr); - if (r < 0) { - log_error_link(link, "Could not allocate address: %s", - strerror(-r)); - return r; - } - - addr->family = AF_INET; - addr->in_addr.in = address; - addr->prefixlen = prefixlen; - addr->broadcast.s_addr = address.s_addr | ~netmask.s_addr; - - r = route_new_dynamic(&rt); - if (r < 0) { - log_error_link(link, "Could not allocate route: %s", - strerror(-r)); - return r; - } - - rt->family = AF_INET; - rt->in_addr.in = gateway; - - link->dhcp_address = addr; - link->dhcp_route = rt; - addr = NULL; - rt = NULL; - if (link->network->dhcp_dns) { - r = sd_dhcp_client_get_dns(client, &nameservers, &nameservers_size); + r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size); if (r >= 0) { r = manager_update_resolv_conf(link->manager); if (r < 0) @@ -542,7 +576,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { if (link->network->dhcp_mtu) { uint16_t mtu; - r = sd_dhcp_client_get_mtu(client, &mtu); + r = sd_dhcp_lease_get_mtu(lease, &mtu); if (r >= 0) { r = link_set_mtu(link, mtu); if (r < 0) @@ -554,7 +588,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { if (link->network->dhcp_hostname) { const char *hostname; - r = sd_dhcp_client_get_hostname(client, &hostname); + r = sd_dhcp_lease_get_hostname(lease, &hostname); if (r >= 0) { r = set_hostname(link->manager->bus, hostname); if (r < 0) @@ -563,6 +597,8 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { } } + link->dhcp_lease = lease; + link_enter_set_addresses(link); return 0; @@ -592,7 +628,7 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) { return; } - r = dhcp_lease_lost(client, link); + r = dhcp_lease_lost(link); if (r < 0) { link_enter_failed(link); return; @@ -634,29 +670,29 @@ static int link_acquire_conf(Link *link) { assert(link->manager); assert(link->manager->event); - if (!link->dhcp) { - r = sd_dhcp_client_new(&link->dhcp); + if (!link->dhcp_client) { + r = sd_dhcp_client_new(&link->dhcp_client); if (r < 0) return r; - r = sd_dhcp_client_attach_event(link->dhcp, NULL, 0); + r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0); if (r < 0) return r; - r = sd_dhcp_client_set_index(link->dhcp, link->ifindex); + r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex); if (r < 0) return r; - r = sd_dhcp_client_set_mac(link->dhcp, &link->mac); + r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac); if (r < 0) return r; - r = sd_dhcp_client_set_callback(link->dhcp, dhcp_handler, link); + r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link); if (r < 0) return r; if (link->network->dhcp_mtu) { - r = sd_dhcp_client_set_request_option(link->dhcp, 26); + r = sd_dhcp_client_set_request_option(link->dhcp_client, 26); if (r < 0) return r; } @@ -664,7 +700,7 @@ static int link_acquire_conf(Link *link) { log_debug_link(link, "acquiring DHCPv4 lease"); - r = sd_dhcp_client_start(link->dhcp); + r = sd_dhcp_client_start(link->dhcp_client); if (r < 0) return r; @@ -705,7 +741,7 @@ static int link_update_flags(Link *link, unsigned flags) { log_info_link(link, "carrier off"); if (link->network->dhcp) { - r = sd_dhcp_client_stop(link->dhcp); + r = sd_dhcp_client_stop(link->dhcp_client); if (r < 0) { log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r)); link_enter_failed(link); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index a007b0485f..1b3e71ab0e 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -364,12 +364,12 @@ int manager_update_resolv_conf(Manager *m) { "# static file or a different symlink.\n\n", f); HASHMAP_FOREACH(link, m->links, i) { - if (link->dhcp) { + if (link->dhcp_lease) { struct in_addr *nameservers; size_t nameservers_size; if (link->network->dhcp_dns) { - r = sd_dhcp_client_get_dns(link->dhcp, &nameservers, &nameservers_size); + r = sd_dhcp_lease_get_dns(link->dhcp_lease, &nameservers, &nameservers_size); if (r >= 0) { unsigned j; @@ -379,7 +379,7 @@ int manager_update_resolv_conf(Manager *m) { } if (link->network->dhcp_domainname && !domainname) { - r = sd_dhcp_client_get_domainname(link->dhcp, &domainname); + r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname); if (r >= 0) fprintf(f, "domain %s\n", domainname); } diff --git a/src/network/networkd.h b/src/network/networkd.h index 831a9cbdd9..e9ca38f597 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -174,18 +174,15 @@ struct Link { Network *network; - Route *dhcp_route; - Address *dhcp_address; - Address *dns; - uint16_t original_mtu; - LinkState state; unsigned addr_messages; unsigned route_messages; unsigned enslaving; - sd_dhcp_client *dhcp; + sd_dhcp_client *dhcp_client; + sd_dhcp_lease *dhcp_lease; + uint16_t original_mtu; }; struct Manager { diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index e66361193f..87f5adb597 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -36,6 +36,7 @@ enum { }; typedef struct sd_dhcp_client sd_dhcp_client; +typedef struct sd_dhcp_lease sd_dhcp_lease; typedef void (*sd_dhcp_client_cb_t)(sd_dhcp_client *client, int event, void *userdata); @@ -49,14 +50,17 @@ int sd_dhcp_client_set_request_address(sd_dhcp_client *client, int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index); int sd_dhcp_client_set_mac(sd_dhcp_client *client, const struct ether_addr *addr); +int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret); -int sd_dhcp_client_get_address(sd_dhcp_client *client, struct in_addr *addr); -int sd_dhcp_client_get_netmask(sd_dhcp_client *client, struct in_addr *addr); -int sd_dhcp_client_get_router(sd_dhcp_client *client, struct in_addr *addr); -int sd_dhcp_client_get_dns(sd_dhcp_client *client, struct in_addr **addr, size_t *addr_size); -int sd_dhcp_client_get_mtu(sd_dhcp_client *client, uint16_t *mtu); -int sd_dhcp_client_get_domainname(sd_dhcp_client *client, const char **domainname); -int sd_dhcp_client_get_hostname(sd_dhcp_client *client, const char **hostname); +sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease); +sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease); +int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr); +int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr); +int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr); +int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, struct in_addr **addr, size_t *addr_size); +int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu); +int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname); +int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname); int sd_dhcp_client_stop(sd_dhcp_client *client); int sd_dhcp_client_start(sd_dhcp_client *client);