diff options
author | Tom Gundersen <teg@jklm.no> | 2014-02-04 23:13:52 +0100 |
---|---|---|
committer | Tom Gundersen <teg@jklm.no> | 2014-02-07 15:48:35 +0100 |
commit | a6cc569e33a05b07550c6c7b4d67d83d868f8bc1 (patch) | |
tree | 5b8754fa594896f79ba4cb62772f6b1b49be4325 | |
parent | d72143bad46b51fc0bbedf01ff92aea8b07afac6 (diff) |
sd-dhcp-client: split sd_dhcp_lease from sd_dhcp_client
This allows us users of the library to keep copies of old leases. This is
used by networkd to know what addresses to drop (if any) when the lease
expires.
In the future this may be used by DNAv4 and sd-dhcp-server.
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | src/libsystemd-dhcp/dhcp-lease.c | 244 | ||||
-rw-r--r-- | src/libsystemd-dhcp/dhcp-lease.h | 57 | ||||
-rw-r--r-- | src/libsystemd-dhcp/sd-dhcp-client.c | 261 | ||||
-rw-r--r-- | src/network/networkd-link.c | 186 | ||||
-rw-r--r-- | src/network/networkd-manager.c | 6 | ||||
-rw-r--r-- | src/network/networkd.h | 9 | ||||
-rw-r--r-- | src/systemd/sd-dhcp-client.h | 20 |
8 files changed, 454 insertions, 331 deletions
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 <http://www.gnu.org/licenses/>. +***/ + +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <net/ethernet.h> +#include <sys/param.h> + +#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 <http://www.gnu.org/licenses/>. +***/ + +#include <stdint.h> +#include <linux/if_packet.h> + +#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) { - assert_return(client, -EINVAL); - assert_return(addr, -EINVAL); - - client_state_machine_check (client->state, -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) { +int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { 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); + 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->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_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); +int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret); + +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); |