#include <linux/if.h>
#include "alloc-util.h"
-#include "dhcp-lease-internal.h"
#include "hostname-util.h"
#include "parse-util.h"
-#include "netdev/vrf.h"
#include "network-internal.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "string-util.h"
#include "sysctl-util.h"
-static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
- void *userdata) {
- _cleanup_(link_unrefp) Link *link = userdata;
+static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
static int link_set_dhcp_routes(Link *link) {
_cleanup_free_ sd_dhcp_route **static_routes = NULL;
bool classless_route = false, static_route = false;
- struct in_addr gateway, address;
+ const struct in_addr *router;
+ struct in_addr address;
int r, n, i;
uint32_t table;
if (!link->network->dhcp_use_routes)
return 0;
- /* When the interface is part of an VRF use the VRFs routing table, unless
- * there is a another table specified. */
- table = link->network->dhcp_route_table;
- if (!link->network->dhcp_route_table_set && link->network->vrf != NULL)
- table = VRF(link->network->vrf)->table;
+ table = link_get_dhcp_route_table(link);
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
if (r < 0)
log_link_debug_errno(link, n, "DHCP error: could not get routes: %m");
for (i = 0; i < n; i++) {
- if (static_routes[i]->option == SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE)
+ switch (sd_dhcp_route_get_option(static_routes[i])) {
+ case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
classless_route = true;
-
- if (static_routes[i]->option == SD_DHCP_OPTION_STATIC_ROUTE)
+ break;
+ case SD_DHCP_OPTION_STATIC_ROUTE:
static_route = true;
+ break;
+ }
}
for (i = 0; i < n; i++) {
/* if the DHCP server returns both a Classless Static Routes option and a Static Routes option,
the DHCP client MUST ignore the Static Routes option. */
- if (classless_route && static_routes[i]->option == SD_DHCP_OPTION_STATIC_ROUTE)
+ if (classless_route &&
+ sd_dhcp_route_get_option(static_routes[i]) != SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE)
continue;
r = route_new(&route);
link->dhcp4_messages++;
}
- r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
- if (r == -ENODATA)
- log_link_info_errno(link, r, "DHCP: No gateway received from DHCP server: %m");
+ r = sd_dhcp_lease_get_router(link->dhcp_lease, &router);
+ if (IN_SET(r, 0, -ENODATA))
+ log_link_info(link, "DHCP: No gateway received from DHCP server.");
else if (r < 0)
log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");
+ else if (in4_addr_is_null(&router[0]))
+ log_link_info(link, "DHCP: Received gateway is null.");
/* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
a Router option, the DHCP client MUST ignore the Router option. */
if (classless_route && static_route)
log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option and router option");
- if (r >= 0 && !classless_route) {
- _cleanup_(route_freep) Route *route = NULL;
- _cleanup_(route_freep) Route *route_gw = NULL;
-
- r = route_new(&route);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not allocate route: %m");
-
- route->protocol = RTPROT_DHCP;
+ if (r > 0 && !classless_route && !in4_addr_is_null(&router[0])) {
+ _cleanup_(route_freep) Route *route = NULL, *route_gw = NULL;
r = route_new(&route_gw);
if (r < 0)
* route for the gw host so that we can route no matter the
* netmask or existing kernel route tables. */
route_gw->family = AF_INET;
- route_gw->dst.in = gateway;
+ route_gw->dst.in = router[0];
route_gw->dst_prefixlen = 32;
route_gw->prefsrc.in = address;
route_gw->scope = RT_SCOPE_LINK;
link->dhcp4_messages++;
+ r = route_new(&route);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not allocate route: %m");
+
route->family = AF_INET;
- route->gw.in = gateway;
+ route->gw.in = router[0];
route->prefsrc.in = address;
+ route->protocol = RTPROT_DHCP;
route->priority = link->network->dhcp_route_metric;
route->table = table;
static int dhcp_lease_lost(Link *link) {
_cleanup_(address_freep) Address *address = NULL;
+ const struct in_addr *router;
struct in_addr addr;
struct in_addr netmask;
- struct in_addr gateway;
unsigned prefixlen = 0;
int r;
assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0);
assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);
- route_remove(route, link,
- link_route_remove_handler);
+ route_remove(route, link, NULL);
}
}
}
r = address_new(&address);
if (r >= 0) {
- r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
- if (r >= 0) {
+ r = sd_dhcp_lease_get_router(link->dhcp_lease, &router);
+ if (r > 0 && !in4_addr_is_null(&router[0])) {
_cleanup_(route_freep) Route *route_gw = NULL;
_cleanup_(route_freep) Route *route = NULL;
r = route_new(&route_gw);
if (r >= 0) {
route_gw->family = AF_INET;
- route_gw->dst.in = gateway;
+ route_gw->dst.in = router[0];
route_gw->dst_prefixlen = 32;
route_gw->scope = RT_SCOPE_LINK;
- route_remove(route_gw, link,
- link_route_remove_handler);
+ route_remove(route_gw, link, NULL);
}
r = route_new(&route);
if (r >= 0) {
route->family = AF_INET;
- route->gw.in = gateway;
+ route->gw.in = router[0];
- route_remove(route, link,
- link_route_remove_handler);
+ route_remove(route, link, NULL);
}
}
address->in_addr.in = addr;
address->prefixlen = prefixlen;
- address_remove(address, link, link_address_remove_handler);
+ address_remove(address, link, NULL);
}
}
return 0;
}
-static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
- void *userdata) {
- _cleanup_(link_unrefp) Link *link = userdata;
+static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
}
static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
+ const struct in_addr *router;
sd_dhcp_lease *lease;
struct in_addr address;
struct in_addr netmask;
- struct in_addr gateway;
unsigned prefixlen;
uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
int r;
prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
- r = sd_dhcp_lease_get_router(lease, &gateway);
+ r = sd_dhcp_lease_get_router(lease, &router);
if (r < 0 && r != -ENODATA)
return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m");
- if (r >= 0)
+ if (r > 0 && !in4_addr_is_null(&router[0]))
log_struct(LOG_INFO,
LOG_LINK_INTERFACE(link),
LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
ADDRESS_FMT_VAL(address),
prefixlen,
- ADDRESS_FMT_VAL(gateway)),
+ ADDRESS_FMT_VAL(router[0])),
"ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
"PREFIXLEN=%u", prefixlen,
- "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway));
+ "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(router[0]));
else
log_struct(LOG_INFO,
LOG_LINK_INTERFACE(link),
return 0;
}
+int dhcp4_set_client_identifier(Link *link) {
+ int r;
+
+ assert(link);
+ assert(link->network);
+ assert(link->dhcp_client);
+
+ switch (link->network->dhcp_client_identifier) {
+ case DHCP_CLIENT_ID_DUID: {
+ /* If configured, apply user specified DUID and IAID */
+ const DUID *duid = link_get_duid(link);
+
+ if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0)
+ r = sd_dhcp_client_set_iaid_duid_llt(link->dhcp_client,
+ link->network->iaid_set,
+ link->network->iaid,
+ duid->llt_time);
+ else
+ r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
+ link->network->iaid_set,
+ link->network->iaid,
+ duid->type,
+ duid->raw_data_len > 0 ? duid->raw_data : NULL,
+ duid->raw_data_len);
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set IAID+DUID: %m");
+ break;
+ }
+ case DHCP_CLIENT_ID_DUID_ONLY: {
+ /* If configured, apply user specified DUID */
+ const DUID *duid = link_get_duid(link);
+
+ if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0)
+ r = sd_dhcp_client_set_duid_llt(link->dhcp_client,
+ duid->llt_time);
+ else
+ r = sd_dhcp_client_set_duid(link->dhcp_client,
+ duid->type,
+ duid->raw_data_len > 0 ? duid->raw_data : NULL,
+ duid->raw_data_len);
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m");
+ break;
+ }
+ case DHCP_CLIENT_ID_MAC:
+ r = sd_dhcp_client_set_client_id(link->dhcp_client,
+ ARPHRD_ETHER,
+ (const uint8_t *) &link->mac,
+ sizeof(link->mac));
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m");
+ break;
+ default:
+ assert_not_reached("Unknown client identifier type.");
+ }
+
+ return 0;
+}
+
int dhcp4_configure(Link *link) {
int r;
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m");
}
- switch (link->network->dhcp_client_identifier) {
- case DHCP_CLIENT_ID_DUID: {
- /* If configured, apply user specified DUID and/or IAID */
- const DUID *duid = link_duid(link);
-
- r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
- link->network->iaid,
- duid->type,
- duid->raw_data_len > 0 ? duid->raw_data : NULL,
- duid->raw_data_len);
- if (r < 0)
- return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m");
- break;
- }
- case DHCP_CLIENT_ID_DUID_ONLY: {
- /* If configured, apply user specified DUID */
- const DUID *duid = link_duid(link);
-
- r = sd_dhcp_client_set_duid(link->dhcp_client,
- duid->type,
- duid->raw_data_len > 0 ? duid->raw_data : NULL,
- duid->raw_data_len);
- if (r < 0)
- return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m");
- break;
- }
- case DHCP_CLIENT_ID_MAC:
- r = sd_dhcp_client_set_client_id(link->dhcp_client,
- ARPHRD_ETHER,
- (const uint8_t *) &link->mac,
- sizeof(link->mac));
- if (r < 0)
- return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m");
- break;
- default:
- assert_not_reached("Unknown client identifier type.");
- }
-
- return 0;
+ return dhcp4_set_client_identifier(link);
}