@@ -146,12 +146,38 @@ Address *address_free(Address *address) {
146146static bool address_may_have_broadcast (const Address * a ) {
147147 assert (a );
148148
149+ if (a -> family != AF_INET )
150+ return false;
151+
152+ if (in4_addr_is_set (& a -> in_addr_peer .in ))
153+ return false;
154+
149155 /* A /31 or /32 IPv4 address does not have a broadcast address.
150156 * See https://tools.ietf.org/html/rfc3021 */
157+ if (a -> prefixlen > 30 )
158+ return false;
159+
160+ if (a -> set_broadcast >= 0 )
161+ return a -> set_broadcast ;
162+
163+ return true; /* Defaults to true. */
164+ }
165+
166+ void address_set_broadcast (Address * a ) {
167+ assert (a );
168+
169+ if (!address_may_have_broadcast (a ))
170+ return ;
151171
152- return a -> family == AF_INET &&
153- in4_addr_is_null (& a -> in_addr_peer .in ) &&
154- a -> prefixlen <= 30 ;
172+ /* If explicitly configured, do not update the address. */
173+ if (in4_addr_is_set (& a -> broadcast ))
174+ return ;
175+
176+ /* If Address= is 0.0.0.0, then the broadcast address will be set later in address_acquire(). */
177+ if (in4_addr_is_null (& a -> in_addr .in ))
178+ return ;
179+
180+ a -> broadcast .s_addr = a -> in_addr .in .s_addr | htobe32 (UINT32_C (0xffffffff ) >> a -> prefixlen );
155181}
156182
157183static bool address_may_set_broadcast (const Address * a , const Link * link ) {
@@ -161,9 +187,6 @@ static bool address_may_set_broadcast(const Address *a, const Link *link) {
161187 if (!address_may_have_broadcast (a ))
162188 return false;
163189
164- if (a -> set_broadcast >= 0 )
165- return a -> set_broadcast ;
166-
167190 /* Typical configuration for wireguard does not set broadcast. */
168191 return !streq_ptr (link -> kind , "wireguard" );
169192}
@@ -466,7 +489,7 @@ int address_get(Link *link, const Address *in, Address **ret) {
466489 return - ENOENT ;
467490}
468491
469- int link_has_ipv6_address (Link * link , const struct in6_addr * address ) {
492+ int link_get_ipv6_address (Link * link , const struct in6_addr * address , Address * * ret ) {
470493 _cleanup_ (address_freep ) Address * a = NULL ;
471494 int r ;
472495
@@ -482,10 +505,10 @@ int link_has_ipv6_address(Link *link, const struct in6_addr *address) {
482505 a -> family = AF_INET6 ;
483506 a -> in_addr .in6 = * address ;
484507
485- return address_get (link , a , NULL ) >= 0 ;
508+ return address_get (link , a , ret ) ;
486509}
487510
488- static int link_get_ipv4_address (Set * addresses , const struct in_addr * address , Address * * ret ) {
511+ static int addresses_get_ipv4_address (Set * addresses , const struct in_addr * address , Address * * ret ) {
489512 Address * a ;
490513
491514 assert (address );
@@ -506,26 +529,48 @@ static int link_get_ipv4_address(Set *addresses, const struct in_addr *address,
506529 return - ENOENT ;
507530}
508531
532+ int link_get_ipv4_address (Link * link , const struct in_addr * address , unsigned char prefixlen , Address * * ret ) {
533+ int r ;
534+
535+ assert (link );
536+ assert (address );
537+
538+ if (prefixlen != 0 ) {
539+ _cleanup_ (address_freep ) Address * a = NULL ;
540+
541+ /* If prefixlen is set, then we can use address_get(). */
542+
543+ r = address_new (& a );
544+ if (r < 0 )
545+ return r ;
546+
547+ a -> family = AF_INET ;
548+ a -> in_addr .in = * address ;
549+ a -> prefixlen = prefixlen ;
550+
551+ return address_get (link , a , ret );
552+ }
553+
554+ if (addresses_get_ipv4_address (link -> addresses , address , ret ) >= 0 )
555+ return 0 ;
556+ return addresses_get_ipv4_address (link -> addresses_foreign , address , ret );
557+ }
558+
509559int manager_has_address (Manager * manager , int family , const union in_addr_union * address , bool check_ready ) {
560+ Address * a ;
510561 Link * link ;
511562 int r ;
512563
513564 assert (manager );
514565 assert (IN_SET (family , AF_INET , AF_INET6 ));
515566 assert (address );
516567
517- if (family == AF_INET )
518- HASHMAP_FOREACH (link , manager -> links ) {
519- Address * a ;
520-
521- if (link_get_ipv4_address (link -> addresses , & address -> in , & a ) >= 0 )
522- return !check_ready || address_is_ready (a );
523- if (link_get_ipv4_address (link -> addresses_foreign , & address -> in , & a ) >= 0 )
568+ if (family == AF_INET ) {
569+ HASHMAP_FOREACH (link , manager -> links )
570+ if (link_get_ipv4_address (link , & address -> in , 0 , & a ) >= 0 )
524571 return !check_ready || address_is_ready (a );
525- }
526- else {
572+ } else {
527573 _cleanup_ (address_freep ) Address * tmp = NULL ;
528- Address * a ;
529574
530575 r = address_new (& tmp );
531576 if (r < 0 )
@@ -825,7 +870,6 @@ int link_drop_addresses(Link *link) {
825870
826871static int address_acquire (Link * link , const Address * original , Address * * ret ) {
827872 union in_addr_union in_addr = IN_ADDR_NULL ;
828- struct in_addr broadcast = {};
829873 _cleanup_ (address_freep ) Address * na = NULL ;
830874 int r ;
831875
@@ -847,16 +891,10 @@ static int address_acquire(Link *link, const Address *original, Address **ret) {
847891 if (r == 0 )
848892 return - EBUSY ;
849893
850- if ( original -> family == AF_INET ) {
851- /* Pick first address in range for ourselves ... */
894+ /* Pick first address in range for ourselves. */
895+ if ( original -> family == AF_INET )
852896 in_addr .in .s_addr = in_addr .in .s_addr | htobe32 (1 );
853-
854- /* .. and use last as broadcast address */
855- if (original -> prefixlen > 30 )
856- broadcast .s_addr = 0 ;
857- else
858- broadcast .s_addr = in_addr .in .s_addr | htobe32 (0xFFFFFFFFUL >> original -> prefixlen );
859- } else if (original -> family == AF_INET6 )
897+ else if (original -> family == AF_INET6 )
860898 in_addr .in6 .s6_addr [15 ] |= 1 ;
861899
862900 r = address_new (& na );
@@ -867,8 +905,8 @@ static int address_acquire(Link *link, const Address *original, Address **ret) {
867905 if (r < 0 )
868906 return r ;
869907
870- na -> broadcast = broadcast ;
871908 na -> in_addr = in_addr ;
909+ address_set_broadcast (na );
872910
873911 r = set_ensure_put (& link -> pool_addresses , & address_hash_ops , na );
874912 if (r < 0 )
@@ -1119,6 +1157,32 @@ int link_request_static_addresses(Link *link) {
11191157 req -> after_configure = static_address_after_configure ;
11201158 }
11211159
1160+ if (in4_addr_is_set (& link -> network -> dhcp_server_address )) {
1161+ _cleanup_ (address_freep ) Address * address = NULL ;
1162+
1163+ r = address_new (& address );
1164+ if (r < 0 )
1165+ return log_oom ();
1166+
1167+ address -> family = AF_INET ;
1168+ address -> in_addr .in = link -> network -> dhcp_server_address ;
1169+ address -> prefixlen = link -> network -> dhcp_server_address_prefixlen ;
1170+ address_set_broadcast (address );
1171+
1172+ /* The same address may be explicitly configured in [Address] or [Network] section.
1173+ * Configure the DHCP server address only when it is not. */
1174+ if (!link_is_static_address_configured (link , address )) {
1175+ Request * req ;
1176+
1177+ r = link_request_address (link , TAKE_PTR (address ), true, & link -> static_address_messages ,
1178+ static_address_handler , & req );
1179+ if (r < 0 )
1180+ return r ;
1181+
1182+ req -> after_configure = static_address_after_configure ;
1183+ }
1184+ }
1185+
11221186 if (link -> static_address_messages == 0 ) {
11231187 link -> static_addresses_configured = true;
11241188 link_check_ready (link );
@@ -1960,10 +2024,9 @@ static int address_section_verify(Address *address) {
19602024 address -> section -> filename , address -> section -> line );
19612025 }
19622026
1963- if (address_may_have_broadcast (address )) {
1964- if (address -> broadcast .s_addr == 0 && address -> set_broadcast != 0 )
1965- address -> broadcast .s_addr = address -> in_addr .in .s_addr | htobe32 (0xfffffffflu >> address -> prefixlen );
1966- } else if (address -> broadcast .s_addr != 0 ) {
2027+ if (address_may_have_broadcast (address ))
2028+ address_set_broadcast (address );
2029+ else if (address -> broadcast .s_addr != 0 ) {
19672030 log_warning ("%s: broadcast address is set for IPv6 address or IPv4 address with prefixlength larger than 30. "
19682031 "Ignoring Broadcast= setting in the [Address] section from line %u." ,
19692032 address -> section -> filename , address -> section -> line );
0 commit comments