/* 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 (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) 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; }