1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <netinet/in.h>
4 #include <linux/if_arp.h>
7 #include "dhcp-identifier.h"
8 #include "dhcp-internal.h"
9 #include "dhcp6-internal.h"
11 #include "hexdecoct.h"
12 #include "in-addr-util.h"
13 #include "networkd-dhcp-common.h"
14 #include "networkd-link.h"
15 #include "networkd-manager.h"
16 #include "networkd-network.h"
17 #include "parse-util.h"
18 #include "socket-util.h"
19 #include "string-table.h"
22 bool link_dhcp_enabled(Link
*link
, int family
) {
24 assert(IN_SET(family
, AF_INET
, AF_INET6
));
26 if (family
== AF_INET6
&& !socket_ipv6_is_supported())
29 if (link
->flags
& IFF_LOOPBACK
)
32 if (link
->iftype
== ARPHRD_CAN
)
38 return link
->network
->dhcp
& (family
== AF_INET
? ADDRESS_FAMILY_IPV4
: ADDRESS_FAMILY_IPV6
);
41 void network_adjust_dhcp(Network
*network
) {
43 assert(network
->dhcp
>= 0);
45 if (network
->dhcp
== ADDRESS_FAMILY_NO
)
48 /* Bonding slave does not support addressing. */
50 log_warning("%s: Cannot enable DHCP= when Bond= is specified, disabling DHCP=.",
52 network
->dhcp
= ADDRESS_FAMILY_NO
;
56 if (!FLAGS_SET(network
->link_local
, ADDRESS_FAMILY_IPV6
) &&
57 FLAGS_SET(network
->dhcp
, ADDRESS_FAMILY_IPV6
)) {
58 log_warning("%s: DHCPv6 client is enabled but IPv6 link local addressing is disabled. "
59 "Disabling DHCPv6 client.", network
->filename
);
60 SET_FLAG(network
->dhcp
, ADDRESS_FAMILY_IPV6
, false);
63 network_adjust_dhcp4(network
);
66 static bool duid_needs_product_uuid(const DUID
*duid
) {
69 return duid
->type
== DUID_TYPE_UUID
&& duid
->raw_data_len
== 0;
72 static const struct DUID fallback_duid
= { .type
= DUID_TYPE_EN
};
74 const DUID
*link_get_duid(Link
*link
, int family
) {
78 assert(IN_SET(family
, AF_INET
, AF_INET6
));
81 duid
= family
== AF_INET
? &link
->network
->dhcp_duid
: &link
->network
->dhcp6_duid
;
82 if (duid
->type
!= _DUID_TYPE_INVALID
) {
83 if (duid_needs_product_uuid(duid
))
84 return &link
->manager
->duid_product_uuid
;
90 duid
= family
== AF_INET
? &link
->manager
->dhcp_duid
: &link
->manager
->dhcp6_duid
;
91 if (link
->hw_addr
.length
== 0 && IN_SET(duid
->type
, DUID_TYPE_LLT
, DUID_TYPE_LL
))
92 /* Fallback to DUID that works without MAC address.
93 * This is useful for tunnel devices without MAC address. */
94 return &fallback_duid
;
99 static int link_configure_and_start_dhcp_delayed(Link
*link
) {
104 if (!IN_SET(link
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
107 if (!link
->dhcp_client
) {
108 r
= dhcp4_configure(link
);
113 if (!link
->dhcp6_client
) {
114 r
= dhcp6_configure(link
);
119 if (link
->set_flags_messages
> 0)
122 if (!link_has_carrier(link
))
125 r
= dhcp4_start(link
);
127 return log_link_warning_errno(link
, r
, "Failed to start DHCPv4 client: %m");
129 r
= ndisc_start(link
);
131 return log_link_warning_errno(link
, r
, "Failed to start IPv6 Router Discovery: %m");
133 r
= dhcp6_start(link
);
135 return log_link_warning_errno(link
, r
, "Failed to start DHCPv6 client: %m");
140 static int get_product_uuid_handler(sd_bus_message
*m
, void *userdata
, sd_bus_error
*ret_error
) {
141 Manager
*manager
= userdata
;
142 const sd_bus_error
*e
;
151 e
= sd_bus_message_get_error(m
);
153 r
= sd_bus_error_get_errno(e
);
154 log_warning_errno(r
, "Could not get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %s",
155 bus_error_message(e
, r
));
159 r
= sd_bus_message_read_array(m
, 'y', &a
, &sz
);
161 log_warning_errno(r
, "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
165 if (sz
!= sizeof(sd_id128_t
)) {
166 log_warning("Invalid product UUID. Falling back to use machine-app-specific ID as DUID-UUID.");
170 memcpy(&manager
->duid_product_uuid
.raw_data
, a
, sz
);
171 manager
->duid_product_uuid
.raw_data_len
= sz
;
174 /* To avoid calling GetProductUUID() bus method so frequently, set the flag below
175 * even if the method fails. */
176 manager
->has_product_uuid
= true;
178 while ((link
= set_steal_first(manager
->links_requesting_uuid
))) {
179 r
= link_configure_and_start_dhcp_delayed(link
);
181 link_enter_failed(link
);
186 manager
->links_requesting_uuid
= set_free(manager
->links_requesting_uuid
);
191 int manager_request_product_uuid(Manager
*m
) {
196 if (m
->product_uuid_requested
)
199 log_debug("Requesting product UUID");
201 if (sd_bus_is_ready(m
->bus
) <= 0) {
202 log_debug("Not connected to system bus, requesting product UUID later.");
206 r
= sd_bus_call_method_async(
209 "org.freedesktop.hostname1",
210 "/org/freedesktop/hostname1",
211 "org.freedesktop.hostname1",
213 get_product_uuid_handler
,
218 return log_warning_errno(r
, "Failed to get product UUID: %m");
220 m
->product_uuid_requested
= true;
225 int dhcp_configure_duid(Link
*link
, const DUID
*duid
) {
230 assert(link
->manager
);
235 if (!duid_needs_product_uuid(duid
))
238 if (m
->has_product_uuid
)
241 r
= manager_request_product_uuid(m
);
243 log_link_warning_errno(link
, r
,
244 "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
248 r
= set_ensure_put(&m
->links_requesting_uuid
, NULL
, link
);
257 int config_parse_dhcp(
259 const char *filename
,
262 unsigned section_line
,
269 AddressFamily
*dhcp
= data
, s
;
276 /* Note that this is mostly like
277 * config_parse_address_family(), except that it
278 * understands some old names for the enum values */
280 s
= address_family_from_string(rvalue
);
283 /* Previously, we had a slightly different enum here,
284 * support its values for compatibility. */
286 s
= dhcp_deprecated_address_family_from_string(rvalue
);
288 log_syntax(unit
, LOG_WARNING
, filename
, line
, s
,
289 "Failed to parse DHCP option, ignoring: %s", rvalue
);
293 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
294 "DHCP=%s is deprecated, please use DHCP=%s instead.",
295 rvalue
, address_family_to_string(s
));
302 int config_parse_dhcp_route_metric(
304 const char *filename
,
307 unsigned section_line
,
314 Network
*network
= userdata
;
323 r
= safe_atou32(rvalue
, &metric
);
325 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
326 "Failed to parse RouteMetric=%s, ignoring assignment: %m", rvalue
);
330 if (streq_ptr(section
, "DHCPv4")) {
331 network
->dhcp_route_metric
= metric
;
332 network
->dhcp_route_metric_set
= true;
333 } else if (STRPTR_IN_SET(section
, "DHCPv6", "IPv6AcceptRA")) {
334 network
->ipv6_accept_ra_route_metric
= metric
;
335 network
->ipv6_accept_ra_route_metric_set
= true;
336 } else { /* [DHCP] section */
337 if (!network
->dhcp_route_metric_set
)
338 network
->dhcp_route_metric
= metric
;
339 if (!network
->ipv6_accept_ra_route_metric_set
)
340 network
->ipv6_accept_ra_route_metric
= metric
;
346 int config_parse_dhcp_use_dns(
348 const char *filename
,
351 unsigned section_line
,
358 Network
*network
= userdata
;
366 r
= parse_boolean(rvalue
);
368 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
369 "Failed to parse UseDNS=%s, ignoring assignment: %m", rvalue
);
373 if (streq_ptr(section
, "DHCPv4")) {
374 network
->dhcp_use_dns
= r
;
375 network
->dhcp_use_dns_set
= true;
376 } else if (streq_ptr(section
, "DHCPv6")) {
377 network
->dhcp6_use_dns
= r
;
378 network
->dhcp6_use_dns_set
= true;
379 } else { /* [DHCP] section */
380 if (!network
->dhcp_use_dns_set
)
381 network
->dhcp_use_dns
= r
;
382 if (!network
->dhcp6_use_dns_set
)
383 network
->dhcp6_use_dns
= r
;
389 int config_parse_dhcp_use_domains(
391 const char *filename
,
394 unsigned section_line
,
401 Network
*network
= userdata
;
409 d
= dhcp_use_domains_from_string(rvalue
);
411 log_syntax(unit
, LOG_WARNING
, filename
, line
, d
,
412 "Failed to parse %s=%s, ignoring assignment: %m", lvalue
, rvalue
);
416 if (streq_ptr(section
, "DHCPv4")) {
417 network
->dhcp_use_domains
= d
;
418 network
->dhcp_use_domains_set
= true;
419 } else if (streq_ptr(section
, "DHCPv6")) {
420 network
->dhcp6_use_domains
= d
;
421 network
->dhcp6_use_domains_set
= true;
422 } else { /* [DHCP] section */
423 if (!network
->dhcp_use_domains_set
)
424 network
->dhcp_use_domains
= d
;
425 if (!network
->dhcp6_use_domains_set
)
426 network
->dhcp6_use_domains
= d
;
432 int config_parse_dhcp_use_ntp(
434 const char *filename
,
437 unsigned section_line
,
444 Network
*network
= userdata
;
452 r
= parse_boolean(rvalue
);
454 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
455 "Failed to parse UseNTP=%s, ignoring assignment: %m", rvalue
);
459 if (streq_ptr(section
, "DHCPv4")) {
460 network
->dhcp_use_ntp
= r
;
461 network
->dhcp_use_ntp_set
= true;
462 } else if (streq_ptr(section
, "DHCPv6")) {
463 network
->dhcp6_use_ntp
= r
;
464 network
->dhcp6_use_ntp_set
= true;
465 } else { /* [DHCP] section */
466 if (!network
->dhcp_use_ntp_set
)
467 network
->dhcp_use_ntp
= r
;
468 if (!network
->dhcp6_use_ntp_set
)
469 network
->dhcp6_use_ntp
= r
;
475 int config_parse_section_route_table(
477 const char *filename
,
480 unsigned section_line
,
487 Network
*network
= userdata
;
496 r
= safe_atou32(rvalue
, &rt
);
498 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
499 "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue
);
503 if (STRPTR_IN_SET(section
, "DHCP", "DHCPv4")) {
504 network
->dhcp_route_table
= rt
;
505 network
->dhcp_route_table_set
= true;
506 } else { /* section is IPv6AcceptRA */
507 network
->ipv6_accept_ra_route_table
= rt
;
508 network
->ipv6_accept_ra_route_table_set
= true;
514 int config_parse_iaid(const char *unit
,
515 const char *filename
,
518 unsigned section_line
,
525 Network
*network
= userdata
;
533 assert(IN_SET(ltype
, AF_INET
, AF_INET6
));
535 r
= safe_atou32(rvalue
, &iaid
);
537 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
538 "Unable to read IAID, ignoring assignment: %s", rvalue
);
542 if (ltype
== AF_INET
) {
543 network
->dhcp_iaid
= iaid
;
544 network
->dhcp_iaid_set
= true;
545 if (!network
->dhcp6_iaid_set_explicitly
) {
546 /* Backward compatibility. Previously, IAID is shared by DHCP4 and DHCP6.
547 * If DHCP6 IAID is not specified explicitly, then use DHCP4 IAID for DHCP6. */
548 network
->dhcp6_iaid
= iaid
;
549 network
->dhcp6_iaid_set
= true;
552 assert(ltype
== AF_INET6
);
553 network
->dhcp6_iaid
= iaid
;
554 network
->dhcp6_iaid_set
= true;
555 network
->dhcp6_iaid_set_explicitly
= true;
561 int config_parse_dhcp_user_or_vendor_class(
563 const char *filename
,
566 unsigned section_line
,
579 assert(IN_SET(ltype
, AF_INET
, AF_INET6
));
581 if (isempty(rvalue
)) {
586 for (const char *p
= rvalue
;;) {
587 _cleanup_free_
char *w
= NULL
;
590 r
= extract_first_word(&p
, &w
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_UNQUOTE
);
594 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
595 "Failed to split user classes option, ignoring: %s", rvalue
);
602 if (ltype
== AF_INET
) {
603 if (len
> UINT8_MAX
|| len
== 0) {
604 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
605 "%s length is not in the range 1…255, ignoring.", w
);
609 if (len
> UINT16_MAX
|| len
== 0) {
610 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
611 "%s length is not in the range 1…65535, ignoring.", w
);
616 r
= strv_consume(l
, TAKE_PTR(w
));
622 int config_parse_dhcp_send_option(
624 const char *filename
,
627 unsigned section_line
,
634 _cleanup_(sd_dhcp_option_unrefp
) sd_dhcp_option
*opt4
= NULL
, *old4
= NULL
;
635 _cleanup_(sd_dhcp6_option_unrefp
) sd_dhcp6_option
*opt6
= NULL
, *old6
= NULL
;
636 uint32_t uint32_data
, enterprise_identifier
= 0;
637 _cleanup_free_
char *word
= NULL
, *q
= NULL
;
638 OrderedHashmap
**options
= data
;
639 uint16_t u16
, uint16_data
;
640 union in_addr_union addr
;
641 DHCPOptionDataType type
;
642 uint8_t u8
, uint8_data
;
653 if (isempty(rvalue
)) {
654 *options
= ordered_hashmap_free(*options
);
659 if (ltype
== AF_INET6
&& streq(lvalue
, "SendVendorOption")) {
660 r
= extract_first_word(&p
, &word
, ":", 0);
663 if (r
<= 0 || isempty(p
)) {
664 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
665 "Invalid DHCP option, ignoring assignment: %s", rvalue
);
669 r
= safe_atou32(word
, &enterprise_identifier
);
671 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
672 "Failed to parse DHCPv6 enterprise identifier data, ignoring assignment: %s", p
);
678 r
= extract_first_word(&p
, &word
, ":", 0);
681 if (r
<= 0 || isempty(p
)) {
682 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
683 "Invalid DHCP option, ignoring assignment: %s", rvalue
);
687 if (ltype
== AF_INET6
) {
688 r
= safe_atou16(word
, &u16
);
690 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
691 "Invalid DHCP option, ignoring assignment: %s", rvalue
);
694 if (u16
< 1 || u16
>= UINT16_MAX
) {
695 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
696 "Invalid DHCP option, valid range is 1-65535, ignoring assignment: %s", rvalue
);
700 r
= safe_atou8(word
, &u8
);
702 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
703 "Invalid DHCP option, ignoring assignment: %s", rvalue
);
706 if (u8
< 1 || u8
>= UINT8_MAX
) {
707 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
708 "Invalid DHCP option, valid range is 1-254, ignoring assignment: %s", rvalue
);
714 r
= extract_first_word(&p
, &word
, ":", 0);
717 if (r
<= 0 || isempty(p
)) {
718 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
719 "Invalid DHCP option, ignoring assignment: %s", rvalue
);
723 type
= dhcp_option_data_type_from_string(word
);
725 log_syntax(unit
, LOG_WARNING
, filename
, line
, type
,
726 "Invalid DHCP option data type, ignoring assignment: %s", p
);
731 case DHCP_OPTION_DATA_UINT8
:{
732 r
= safe_atou8(p
, &uint8_data
);
734 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
735 "Failed to parse DHCP uint8 data, ignoring assignment: %s", p
);
740 sz
= sizeof(uint8_t);
743 case DHCP_OPTION_DATA_UINT16
:{
746 r
= safe_atou16(p
, &k
);
748 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
749 "Failed to parse DHCP uint16 data, ignoring assignment: %s", p
);
753 uint16_data
= htobe16(k
);
754 udata
= &uint16_data
;
755 sz
= sizeof(uint16_t);
758 case DHCP_OPTION_DATA_UINT32
: {
761 r
= safe_atou32(p
, &k
);
763 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
764 "Failed to parse DHCP uint32 data, ignoring assignment: %s", p
);
768 uint32_data
= htobe32(k
);
769 udata
= &uint32_data
;
770 sz
= sizeof(uint32_t);
774 case DHCP_OPTION_DATA_IPV4ADDRESS
: {
775 r
= in_addr_from_string(AF_INET
, p
, &addr
);
777 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
778 "Failed to parse DHCP ipv4address data, ignoring assignment: %s", p
);
783 sz
= sizeof(addr
.in
.s_addr
);
786 case DHCP_OPTION_DATA_IPV6ADDRESS
: {
787 r
= in_addr_from_string(AF_INET6
, p
, &addr
);
789 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
790 "Failed to parse DHCP ipv6address data, ignoring assignment: %s", p
);
795 sz
= sizeof(addr
.in6
.s6_addr
);
798 case DHCP_OPTION_DATA_STRING
:
799 sz
= cunescape(p
, UNESCAPE_ACCEPT_NUL
, &q
);
801 log_syntax(unit
, LOG_WARNING
, filename
, line
, sz
,
802 "Failed to decode DHCP option data, ignoring assignment: %s", p
);
810 if (ltype
== AF_INET6
) {
811 r
= sd_dhcp6_option_new(u16
, udata
, sz
, enterprise_identifier
, &opt6
);
813 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
814 "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue
);
818 r
= ordered_hashmap_ensure_allocated(options
, &dhcp6_option_hash_ops
);
822 /* Overwrite existing option */
823 old6
= ordered_hashmap_get(*options
, UINT_TO_PTR(u16
));
824 r
= ordered_hashmap_replace(*options
, UINT_TO_PTR(u16
), opt6
);
826 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
827 "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue
);
832 r
= sd_dhcp_option_new(u8
, udata
, sz
, &opt4
);
834 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
835 "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue
);
839 r
= ordered_hashmap_ensure_allocated(options
, &dhcp_option_hash_ops
);
843 /* Overwrite existing option */
844 old4
= ordered_hashmap_get(*options
, UINT_TO_PTR(u8
));
845 r
= ordered_hashmap_replace(*options
, UINT_TO_PTR(u8
), opt4
);
847 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
848 "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue
);
856 int config_parse_dhcp_request_options(
858 const char *filename
,
861 unsigned section_line
,
868 Network
*network
= userdata
;
876 if (isempty(rvalue
)) {
877 if (ltype
== AF_INET
)
878 network
->dhcp_request_options
= set_free(network
->dhcp_request_options
);
880 network
->dhcp6_request_options
= set_free(network
->dhcp6_request_options
);
885 for (const char *p
= rvalue
;;) {
886 _cleanup_free_
char *n
= NULL
;
889 r
= extract_first_word(&p
, &n
, NULL
, 0);
893 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
894 "Failed to parse DHCP request option, ignoring assignment: %s",
901 r
= safe_atou32(n
, &i
);
903 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
904 "DHCP request option is invalid, ignoring assignment: %s", n
);
908 if (i
< 1 || i
>= UINT8_MAX
) {
909 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
910 "DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n
);
914 r
= set_ensure_put(ltype
== AF_INET
? &network
->dhcp_request_options
: &network
->dhcp6_request_options
,
915 NULL
, UINT32_TO_PTR(i
));
917 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
918 "Failed to store DHCP request option '%s', ignoring assignment: %m", n
);
922 static const char* const dhcp_use_domains_table
[_DHCP_USE_DOMAINS_MAX
] = {
923 [DHCP_USE_DOMAINS_NO
] = "no",
924 [DHCP_USE_DOMAINS_ROUTE
] = "route",
925 [DHCP_USE_DOMAINS_YES
] = "yes",
928 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains
, DHCPUseDomains
, DHCP_USE_DOMAINS_YES
);
930 static const char * const dhcp_option_data_type_table
[_DHCP_OPTION_DATA_MAX
] = {
931 [DHCP_OPTION_DATA_UINT8
] = "uint8",
932 [DHCP_OPTION_DATA_UINT16
] = "uint16",
933 [DHCP_OPTION_DATA_UINT32
] = "uint32",
934 [DHCP_OPTION_DATA_STRING
] = "string",
935 [DHCP_OPTION_DATA_IPV4ADDRESS
] = "ipv4address",
936 [DHCP_OPTION_DATA_IPV6ADDRESS
] = "ipv6address",
939 DEFINE_STRING_TABLE_LOOKUP(dhcp_option_data_type
, DHCPOptionDataType
);
941 static const char* const duid_type_table
[_DUID_TYPE_MAX
] = {
942 [DUID_TYPE_LLT
] = "link-layer-time",
943 [DUID_TYPE_EN
] = "vendor",
944 [DUID_TYPE_LL
] = "link-layer",
945 [DUID_TYPE_UUID
] = "uuid",
947 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type
, DUIDType
);
949 int config_parse_duid_type(
951 const char *filename
,
954 unsigned section_line
,
961 _cleanup_free_
char *type_string
= NULL
;
962 const char *p
= rvalue
;
973 if (!force
&& duid
->set
)
976 r
= extract_first_word(&p
, &type_string
, ":", 0);
980 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
981 "Invalid syntax, ignoring: %s", rvalue
);
985 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
986 "Failed to extract DUID type from '%s', ignoring.", rvalue
);
990 type
= duid_type_from_string(type_string
);
992 log_syntax(unit
, LOG_WARNING
, filename
, line
, type
,
993 "Failed to parse DUID type '%s', ignoring.", type_string
);
1000 if (type
!= DUID_TYPE_LLT
) {
1001 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1002 "Invalid syntax, ignoring: %s", rvalue
);
1006 r
= parse_timestamp(p
, &u
);
1008 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1009 "Failed to parse timestamp, ignoring: %s", p
);
1022 int config_parse_manager_duid_type(
1024 const char *filename
,
1026 const char *section
,
1027 unsigned section_line
,
1034 Manager
*manager
= userdata
;
1039 /* For backward compatibility. Setting both DHCP4 and DHCP6 DUID if they are not specified explicitly. */
1041 r
= config_parse_duid_type(unit
, filename
, line
, section
, section_line
, lvalue
, false, rvalue
, &manager
->dhcp_duid
, manager
);
1045 return config_parse_duid_type(unit
, filename
, line
, section
, section_line
, lvalue
, false, rvalue
, &manager
->dhcp6_duid
, manager
);
1048 int config_parse_network_duid_type(
1050 const char *filename
,
1052 const char *section
,
1053 unsigned section_line
,
1060 Network
*network
= userdata
;
1065 r
= config_parse_duid_type(unit
, filename
, line
, section
, section_line
, lvalue
, true, rvalue
, &network
->dhcp_duid
, network
);
1069 /* For backward compatibility, also set DHCP6 DUID if not specified explicitly. */
1070 return config_parse_duid_type(unit
, filename
, line
, section
, section_line
, lvalue
, false, rvalue
, &network
->dhcp6_duid
, network
);
1073 int config_parse_duid_rawdata(
1075 const char *filename
,
1077 const char *section
,
1078 unsigned section_line
,
1085 uint8_t raw_data
[MAX_DUID_LEN
];
1095 if (!force
&& duid
->set
)
1098 /* RawData contains DUID in format "NN:NN:NN..." */
1099 for (const char *p
= rvalue
;;) {
1102 _cleanup_free_
char *cbyte
= NULL
;
1104 r
= extract_first_word(&p
, &cbyte
, ":", 0);
1108 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to read DUID, ignoring assignment: %s.", rvalue
);
1114 if (count
>= MAX_DUID_LEN
) {
1115 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Max DUID length exceeded, ignoring assignment: %s.", rvalue
);
1119 len
= strlen(cbyte
);
1120 if (!IN_SET(len
, 1, 2)) {
1121 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid length - DUID byte: %s, ignoring assignment: %s.", cbyte
, rvalue
);
1124 n1
= unhexchar(cbyte
[0]);
1126 n2
= unhexchar(cbyte
[1]);
1130 if (n1
< 0 || n2
< 0) {
1131 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid DUID byte: %s. Ignoring assignment: %s.", cbyte
, rvalue
);
1135 byte
= ((uint8_t) n1
<< (4 * (len
-1))) | (uint8_t) n2
;
1136 raw_data
[count
++] = byte
;
1139 assert_cc(sizeof(raw_data
) == sizeof(duid
->raw_data
));
1140 memcpy(duid
->raw_data
, raw_data
, count
);
1141 duid
->raw_data_len
= count
;
1147 int config_parse_manager_duid_rawdata(
1149 const char *filename
,
1151 const char *section
,
1152 unsigned section_line
,
1159 Manager
*manager
= userdata
;
1164 /* For backward compatibility. Setting both DHCP4 and DHCP6 DUID if they are not specified explicitly. */
1166 r
= config_parse_duid_rawdata(unit
, filename
, line
, section
, section_line
, lvalue
, false, rvalue
, &manager
->dhcp_duid
, manager
);
1170 return config_parse_duid_rawdata(unit
, filename
, line
, section
, section_line
, lvalue
, false, rvalue
, &manager
->dhcp6_duid
, manager
);
1173 int config_parse_network_duid_rawdata(
1175 const char *filename
,
1177 const char *section
,
1178 unsigned section_line
,
1185 Network
*network
= userdata
;
1190 r
= config_parse_duid_rawdata(unit
, filename
, line
, section
, section_line
, lvalue
, true, rvalue
, &network
->dhcp_duid
, network
);
1194 /* For backward compatibility, also set DHCP6 DUID if not specified explicitly. */
1195 return config_parse_duid_rawdata(unit
, filename
, line
, section
, section_line
, lvalue
, false, rvalue
, &network
->dhcp6_duid
, network
);