diff options
-rw-r--r-- | src/libsystemd-network/sd-dhcp-lease.c | 24 | ||||
-rw-r--r-- | src/shared/in-addr-util.c | 43 | ||||
-rw-r--r-- | src/shared/in-addr-util.h | 2 |
3 files changed, 54 insertions, 15 deletions
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index 6680d06736..4fb01c0729 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -30,6 +30,7 @@ #include "list.h" #include "mkdir.h" #include "fileio.h" +#include "in-addr-util.h" #include "dhcp-protocol.h" #include "dhcp-internal.h" @@ -803,27 +804,20 @@ int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) { } int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) { - uint32_t address; + struct in_addr address; + struct in_addr mask; + int r; assert(lease); - assert(lease->address != INADDR_ANY); - address = be32toh(lease->address); + address.s_addr = lease->address; /* fall back to the default subnet masks based on address class */ + r = in_addr_default_subnet_mask(&address, &mask); + if (r < 0) + return r; - if ((address >> 31) == 0x0) - /* class A, leading bits: 0 */ - lease->subnet_mask = htobe32(0xff000000); - else if ((address >> 30) == 0x2) - /* class B, leading bits 10 */ - lease->subnet_mask = htobe32(0xffff0000); - else if ((address >> 29) == 0x6) - /* class C, leading bits 110 */ - lease->subnet_mask = htobe32(0xffffff00); - else - /* class D or E, no default mask. give up */ - return -ERANGE; + lease->subnet_mask = mask.s_addr; return 0; } diff --git a/src/shared/in-addr-util.c b/src/shared/in-addr-util.c index 457eedd6d8..5fbee6caf2 100644 --- a/src/shared/in-addr-util.c +++ b/src/shared/in-addr-util.c @@ -248,3 +248,46 @@ unsigned in_addr_netmask_to_prefixlen(const struct in_addr *addr) { return 32 - u32ctz(be32toh(addr->s_addr)); } + +int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) { + uint32_t address; + + assert(addr); + assert(addr->s_addr != INADDR_ANY); + assert(prefixlen); + + address = be32toh(addr->s_addr); + + if ((address >> 31) == 0x0) + /* class A, leading bits: 0 */ + *prefixlen = 8; + else if ((address >> 30) == 0x2) + /* class B, leading bits 10 */ + *prefixlen = 16; + else if ((address >> 29) == 0x6) + /* class C, leading bits 110 */ + *prefixlen = 24; + else + /* class D or E, no default prefixlen */ + return -ERANGE; + + return 0; +} + +int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) { + unsigned char prefixlen; + int r; + + assert(addr); + assert(mask); + + r = in_addr_default_prefixlen(addr, &prefixlen); + if (r < 0) + return r; + + assert(prefixlen > 0 && prefixlen < 32); + + mask->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff); + + return 0; +} diff --git a/src/shared/in-addr-util.h b/src/shared/in-addr-util.h index 0036acee22..8da030ceb6 100644 --- a/src/shared/in-addr-util.h +++ b/src/shared/in-addr-util.h @@ -40,6 +40,8 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret); int in_addr_from_string(int family, const char *s, union in_addr_union *ret); int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret); unsigned in_addr_netmask_to_prefixlen(const struct in_addr *addr); +int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen); +int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask); static inline size_t FAMILY_ADDRESS_SIZE(int family) { assert(family == AF_INET || family == AF_INET6); |