diff options
Diffstat (limited to '')
-rw-r--r-- | src/network/netdev/netdev-util.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/src/network/netdev/netdev-util.c b/src/network/netdev/netdev-util.c new file mode 100644 index 0000000..2350624 --- /dev/null +++ b/src/network/netdev/netdev-util.c @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "netdev-util.h" +#include "networkd-address.h" +#include "networkd-link.h" +#include "string-table.h" + +static const char * const netdev_local_address_type_table[_NETDEV_LOCAL_ADDRESS_TYPE_MAX] = { + [NETDEV_LOCAL_ADDRESS_IPV4LL] = "ipv4_link_local", + [NETDEV_LOCAL_ADDRESS_IPV6LL] = "ipv6_link_local", + [NETDEV_LOCAL_ADDRESS_DHCP4] = "dhcp4", + [NETDEV_LOCAL_ADDRESS_DHCP6] = "dhcp6", + [NETDEV_LOCAL_ADDRESS_SLAAC] = "slaac", +}; + +DEFINE_STRING_TABLE_LOOKUP(netdev_local_address_type, NetDevLocalAddressType); + +int link_get_local_address( + Link *link, + NetDevLocalAddressType type, + int family, + int *ret_family, + union in_addr_union *ret_address) { + + Address *a; + + assert(link); + + switch (type) { + case NETDEV_LOCAL_ADDRESS_IPV4LL: + assert(IN_SET(family, AF_UNSPEC, AF_INET)); + family = AF_INET; + break; + case NETDEV_LOCAL_ADDRESS_IPV6LL: + assert(IN_SET(family, AF_UNSPEC, AF_INET6)); + family = AF_INET6; + break; + case NETDEV_LOCAL_ADDRESS_DHCP4: + assert(IN_SET(family, AF_UNSPEC, AF_INET)); + family = AF_INET; + break; + case NETDEV_LOCAL_ADDRESS_DHCP6: + assert(IN_SET(family, AF_UNSPEC, AF_INET6)); + family = AF_INET6; + break; + case NETDEV_LOCAL_ADDRESS_SLAAC: + assert(IN_SET(family, AF_UNSPEC, AF_INET6)); + family = AF_INET6; + break; + default: + assert_not_reached(); + } + + if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false)) + return -EBUSY; + + SET_FOREACH(a, link->addresses) { + if (!address_is_ready(a)) + continue; + + if (a->family != family) + continue; + + if (in_addr_is_set(a->family, &a->in_addr_peer)) + continue; + + switch (type) { + case NETDEV_LOCAL_ADDRESS_IPV4LL: + if (a->source != NETWORK_CONFIG_SOURCE_IPV4LL) + continue; + break; + case NETDEV_LOCAL_ADDRESS_IPV6LL: + if (!in6_addr_is_link_local(&a->in_addr.in6)) + continue; + break; + case NETDEV_LOCAL_ADDRESS_DHCP4: + if (a->source != NETWORK_CONFIG_SOURCE_DHCP4) + continue; + break; + case NETDEV_LOCAL_ADDRESS_DHCP6: + if (a->source != NETWORK_CONFIG_SOURCE_DHCP6) + continue; + break; + case NETDEV_LOCAL_ADDRESS_SLAAC: + if (a->source != NETWORK_CONFIG_SOURCE_NDISC) + continue; + break; + default: + assert_not_reached(); + } + + if (ret_family) + *ret_family = a->family; + if (ret_address) + *ret_address = a->in_addr; + return 1; + } + + return -ENXIO; +} |