diff --git a/rules.d/81-net-dhcp.rules b/rules.d/81-net-dhcp.rules new file mode 100644 index 0000000000..2ef25ba060 --- /dev/null +++ b/rules.d/81-net-dhcp.rules @@ -0,0 +1,14 @@ +# do not edit this file, it will be overwritten on update + +ACTION=="remove", GOTO="net_dhcp_end" +SUBSYSTEM!="net", GOTO="net_dhcp_end" + +# Network interfaces requiring DHCPOFFER messages to be broadcast +# must set ID_NET_DHCP_BROADCAST to "1". This property will be +# checked by the networkd DHCP4 client to set the DHCP option + +# s390 ccwgroup interfaces in layer3 mode need broadcast DHCPOFFER +# using the link driver to detect this condition +ENV{ID_NET_DRIVER}=="qeth_l3", ENV{ID_NET_DHCP_BROADCAST}="1" + +LABEL="net_dhcp_end" diff --git a/rules.d/meson.build b/rules.d/meson.build index 42fa451c6b..4bbba09fd5 100644 --- a/rules.d/meson.build +++ b/rules.d/meson.build @@ -26,6 +26,7 @@ rules = files(''' 75-probe_mtd.rules 78-sound-card.rules 80-net-setup-link.rules + 81-net-dhcp.rules '''.split()) if conf.get('HAVE_KMOD') == 1 diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 6f06e2218d..64ecd9ceb5 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -1283,6 +1283,30 @@ static int dhcp4_set_request_address(Link *link) { return sd_dhcp_client_set_request_address(link->dhcp_client, &a->in_addr.in); } +static bool link_needs_dhcp_broadcast(Link *link) { + const char *val; + int r; + + assert(link); + assert(link->network); + + /* Return the setting in DHCP[4].RequestBroadcast if specified. Otherwise return the device property + * ID_NET_DHCP_BROADCAST setting, which may be set for interfaces requiring that the DHCPOFFER message + * is being broadcast because they can't handle unicast messages while not fully configured. + * If neither is set or a failure occurs, return false, which is the default for this flag. + */ + r = link->network->dhcp_broadcast; + if (r < 0 && link->sd_device && sd_device_get_property_value(link->sd_device, "ID_NET_DHCP_BROADCAST", &val) >= 0) { + r = parse_boolean(val); + if (r < 0) + log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m"); + else + log_link_debug(link, "DHCP4 CLIENT: Detected ID_NET_DHCP_BROADCAST='%d'.", r); + + } + return r == true; +} + int dhcp4_configure(Link *link) { sd_dhcp_option *send_option; void *request_options; @@ -1319,7 +1343,7 @@ int dhcp4_configure(Link *link) { if (r < 0) return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set callback: %m"); - r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, link->network->dhcp_broadcast); + r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, link_needs_dhcp_broadcast(link)); if (r < 0) return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for broadcast: %m"); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 6c37e32453..f50435b293 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -207,7 +207,7 @@ DHCPv4.RequestOptions, config_parse_dhcp_request_options, DHCPv4.Anonymize, config_parse_bool, 0, offsetof(Network, dhcp_anonymize) DHCPv4.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_send_hostname) DHCPv4.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname) -DHCPv4.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) +DHCPv4.RequestBroadcast, config_parse_tristate, 0, offsetof(Network, dhcp_broadcast) DHCPv4.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) DHCPv4.MUDURL, config_parse_dhcp_mud_url, 0, 0 DHCPv4.MaxAttempts, config_parse_dhcp_max_attempts, 0, 0 @@ -475,7 +475,7 @@ DHCP.UseRoutes, config_parse_bool, DHCP.Anonymize, config_parse_bool, 0, offsetof(Network, dhcp_anonymize) DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_send_hostname) DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname) -DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) +DHCP.RequestBroadcast, config_parse_tristate, 0, offsetof(Network, dhcp_broadcast) DHCP.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical) DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) DHCP.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET, offsetof(Network, dhcp_user_class) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 7f086ceae2..bd363b7bd6 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -368,6 +368,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi /* NOTE: from man: UseTimezone=... Defaults to "no".*/ .dhcp_use_timezone = false, .dhcp_ip_service_type = -1, + .dhcp_broadcast = -1, .dhcp6_use_address = true, .dhcp6_use_dns = true, diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index df77b42619..de5bd60a68 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -136,7 +136,7 @@ struct Network { int dhcp_ip_service_type; bool dhcp_anonymize; bool dhcp_send_hostname; - bool dhcp_broadcast; + int dhcp_broadcast; bool dhcp_use_dns; bool dhcp_use_dns_set; bool dhcp_routes_to_dns;