networkd-dhcp4.c revision b26fa1a2fbcfee7d03b0c8fd15ec3aa64ae70b9f
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen This file is part of systemd.
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen systemd is free software; you can redistribute it and/or modify it
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen under the terms of the GNU Lesser General Public License as published by
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen (at your option) any later version.
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen systemd is distributed in the hope that it will be useful, but
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen Lesser General Public License for more details.
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen You should have received a copy of the GNU Lesser General Public License
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
f5be560181d092c5f52a2b819aedcd48220f36abTom Gundersenstatic int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
5c1d3fc93d91384bbac29adf01074fa4375317eaUmut Tezduyar Lindskog _cleanup_link_unref_ Link *link = userdata;
06f021a8048583d66202e3ac5cd0a12386d33ac2Tom Gundersen if (r < 0 && r != -EEXIST) {
134e56dcc53970a20a858283650bb92cd5da1d17Lennart Poettering log_link_error_errno(link, r, "Could not set DHCPv4 route: %m");
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta _cleanup_free_ sd_dhcp_route **static_routes = NULL;
769d324c99aab129148bd25f5f663ef441287d86Lennart Poettering r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
769d324c99aab129148bd25f5f663ef441287d86Lennart Poettering if (r < 0 && r != -ENODATA)
cb9fc36a1211967e8c58b0502a26c42552ac8060Lennart Poettering return log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersen r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersen return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");
e331e24649213f2e093e16e4d3d64ee823dfc375Tom Gundersen return log_link_error_errno(link, r, "Could not allocate route: %m");
e331e24649213f2e093e16e4d3d64ee823dfc375Tom Gundersen return log_link_error_errno(link, r, "Could not allocate route: %m");
e331e24649213f2e093e16e4d3d64ee823dfc375Tom Gundersen /* The dhcp netmask may mask out the gateway. Add an explicit
e331e24649213f2e093e16e4d3d64ee823dfc375Tom Gundersen * route for the gw host so that we can route no matter the
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta * netmask or existing kernel route tables. */
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta route_gw->priority = link->network->dhcp_route_metric;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta r = route_configure(route_gw, link, &dhcp4_route_handler);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen return log_link_warning_errno(link, r, "Could not set host route: %m");
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen route->priority = link->network->dhcp_route_metric;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen r = route_configure(route, link, &dhcp4_route_handler);
edb85f0d8d0a84f27308a3728f3fde3c52b9dce2Susant Sahani log_link_warning_errno(link, r, "Could not set routes: %m");
1a436809498faf6486815baa0338fb6b8e5def07Tom Gundersen n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
bcb7a07e0a785bda1eed658e984ff6b4a11cba9aTom Gundersen return log_link_warning_errno(link, n, "DHCP error: could not get routes: %m");
1346b1f0388f4100bb3c2a2bb23bc881769c020cTom Gundersen for (i = 0; i < n; i++) {
e1ea665edac17d75fce01b72dadfa3211b60df2cEugene Yakubovich return log_link_error_errno(link, r, "Could not allocate route: %m");
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0);
dd43110f781a9245ec00531456fee68ed763a179Tom Gundersen assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0);
dd43110f781a9245ec00531456fee68ed763a179Tom Gundersen assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
e1853b00ef7cb56cafd908327dd44b3ab48b402cSusant Sahani route->priority = link->network->dhcp_route_metric;
769d324c99aab129148bd25f5f663ef441287d86Lennart Poettering r = route_configure(route, link, &dhcp4_route_handler);
5a8bcb674f71a20e95df55319b34c556638378ceLennart Poettering return log_link_warning_errno(link, r, "Could not set host route: %m");
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen _cleanup_address_free_ Address *address = NULL;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen for (i = 0; i < n; i++) {
5c1d3fc93d91384bbac29adf01074fa4375317eaUmut Tezduyar Lindskog _cleanup_route_free_ Route *route = NULL;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen if (r >= 0) {
aba496a58acf9d9c61314de71353550e579f85eeUmut Tezduyar Lindskog assert_se(sd_dhcp_route_get_gateway(routes[i], &route->gw.in) >= 0);
8cd11a0f0f4ca05199e1166f6a07472b296f7455Tom Gundersen assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0);
5d3de3fe9cc452f1bfe3c2dcafecbd7f904da4dcLennart Poettering assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);
16aa63a00b5b1db23a9c0b8de350ebf482d90cd0Tom Gundersen if (r >= 0) {
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
28cc555d8504c9429776aedbbe1fee7101258578Dan Williams if (r >= 0) {
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen if (r >= 0) {
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
9c0a72f961e00b0447767973e7117e131bea5b5dTom Gundersen prefixlen = in_addr_netmask_to_prefixlen(&netmask);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen address_remove(address, link, &link_address_remove_handler);
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen "DHCP error: could not reset MTU");
a97dcc12e486ecff531809802930a26c4da827f2Tom Gundersen (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen /* If a hostname was set due to the lease, then unset it now. */
45af44d47da6933b260c734ad9ff721f63f80a4dTom Gundersen log_link_warning_errno(link, r, "Failed to reset transient hostname: %m");
3bef724f7e7f7eaca69881548b06e221b77d7031Tom Gundersen link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
dbffab87f1504abc9f189dd253111693c99fbd9aTom Gundersen if (r < 0 && r != -EEXIST) {
505f8da7325591defe5f751f328bd26915267602Tom Gundersen log_link_error_errno(link, r, "Could not set DHCPv4 address: %m");
505f8da7325591defe5f751f328bd26915267602Tom Gundersen } else if (r >= 0)
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen manager_rtnl_process_address(rtnl, m, link->manager);
7951dea20911969287878e6897b3eca348721adeSusant Sahani prefixlen = in_addr_netmask_to_prefixlen(netmask);
7951dea20911969287878e6897b3eca348721adeSusant Sahani addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
7951dea20911969287878e6897b3eca348721adeSusant Sahani /* allow reusing an existing address and simply update its lifetime
7951dea20911969287878e6897b3eca348721adeSusant Sahani * in case it already exists */
7951dea20911969287878e6897b3eca348721adeSusant Sahani r = address_configure(addr, link, &dhcp4_address_handler, true);
85a8eeee36b57c1ab382b0225fa9a87525bbeee9Susant Sahanistatic int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
85a8eeee36b57c1ab382b0225fa9a87525bbeee9Susant Sahani uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
f048a16b464295a4e0a4f4c1210f06343ad31231Tom Gundersen return log_link_warning_errno(link, r, "DHCP error: no lease: %m");
5c1d3fc93d91384bbac29adf01074fa4375317eaUmut Tezduyar Lindskog link->dhcp_lease = sd_dhcp_lease_ref(lease);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen r = sd_dhcp_lease_get_address(lease, &address);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen return log_link_warning_errno(link, r, "DHCP error: no address: %m");
71a6151083d842b2f5bf04e50239f0bf85d34d2eTom Gundersen r = sd_dhcp_lease_get_netmask(lease, &netmask);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen return log_link_warning_errno(link, r, "DHCP error: no netmask: %m");
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
5d8e593dce074bff966fc0a46579c61b4f3bc33aSusant Sahani return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen r = dhcp4_update_address(link, &address, &netmask, lifetime);
f048a16b464295a4e0a4f4c1210f06343ad31231Tom Gundersen log_link_warning_errno(link, r, "Could not update IP address: %m");
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
71a6151083d842b2f5bf04e50239f0bf85d34d2eTom Gundersen uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen return log_link_error_errno(link, r, "DHCP error: No lease: %m");
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta return log_link_error_errno(link, r, "DHCP error: No address: %m");
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta return log_link_error_errno(link, r, "DHCP error: No netmask: %m");
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta prefixlen = in_addr_netmask_to_prefixlen(&netmask);
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta if (r < 0 && r != -ENODATA)
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m");
ed942a9eb22d50f667909ad6184b45015d28d054Tom Gundersen LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
ed942a9eb22d50f667909ad6184b45015d28d054Tom Gundersen "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersen "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway),
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersen LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u",
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering link->dhcp_lease = sd_dhcp_lease_ref(lease);
e331e24649213f2e093e16e4d3d64ee823dfc375Tom Gundersen log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
if (hostname) {
if (tz) {
switch (event) {
log_link_error(link, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
if (event < 0)
if (!hostname)
return -ENOMEM;
case DHCP_CLIENT_ID_DUID:
case DHCP_CLIENT_ID_MAC: