1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "netdev-util.h"
4 #include "networkd-address.h"
5 #include "networkd-link.h"
6 #include "string-table.h"
7 
8 static const char * const netdev_local_address_type_table[_NETDEV_LOCAL_ADDRESS_TYPE_MAX] = {
9         [NETDEV_LOCAL_ADDRESS_IPV4LL]  = "ipv4_link_local",
10         [NETDEV_LOCAL_ADDRESS_IPV6LL]  = "ipv6_link_local",
11         [NETDEV_LOCAL_ADDRESS_DHCP4]   = "dhcp4",
12         [NETDEV_LOCAL_ADDRESS_DHCP6]   = "dhcp6",
13         [NETDEV_LOCAL_ADDRESS_SLAAC]   = "slaac",
14 };
15 
16 DEFINE_STRING_TABLE_LOOKUP(netdev_local_address_type, NetDevLocalAddressType);
17 
link_get_local_address(Link * link,NetDevLocalAddressType type,int family,int * ret_family,union in_addr_union * ret_address)18 int link_get_local_address(
19                 Link *link,
20                 NetDevLocalAddressType type,
21                 int family,
22                 int *ret_family,
23                 union in_addr_union *ret_address) {
24 
25         Address *a;
26 
27         assert(link);
28 
29         switch (type) {
30         case NETDEV_LOCAL_ADDRESS_IPV4LL:
31                 assert(IN_SET(family, AF_UNSPEC, AF_INET));
32                 family = AF_INET;
33                 break;
34         case NETDEV_LOCAL_ADDRESS_IPV6LL:
35                 assert(IN_SET(family, AF_UNSPEC, AF_INET6));
36                 family = AF_INET6;
37                 break;
38         case NETDEV_LOCAL_ADDRESS_DHCP4:
39                 assert(IN_SET(family, AF_UNSPEC, AF_INET));
40                 family = AF_INET;
41                 break;
42         case NETDEV_LOCAL_ADDRESS_DHCP6:
43                 assert(IN_SET(family, AF_UNSPEC, AF_INET6));
44                 family = AF_INET6;
45                 break;
46         case NETDEV_LOCAL_ADDRESS_SLAAC:
47                 assert(IN_SET(family, AF_UNSPEC, AF_INET6));
48                 family = AF_INET6;
49                 break;
50         default:
51                 assert_not_reached();
52         }
53 
54         if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
55                 return -EBUSY;
56 
57         SET_FOREACH(a, link->addresses) {
58                 if (!address_is_ready(a))
59                         continue;
60 
61                 if (a->family != family)
62                         continue;
63 
64                 if (in_addr_is_set(a->family, &a->in_addr_peer))
65                         continue;
66 
67                 switch (type) {
68                 case NETDEV_LOCAL_ADDRESS_IPV4LL:
69                         if (a->source != NETWORK_CONFIG_SOURCE_IPV4LL)
70                                 continue;
71                         break;
72                 case NETDEV_LOCAL_ADDRESS_IPV6LL:
73                         if (!in6_addr_is_link_local(&a->in_addr.in6))
74                                 continue;
75                         break;
76                 case NETDEV_LOCAL_ADDRESS_DHCP4:
77                         if (a->source != NETWORK_CONFIG_SOURCE_DHCP4)
78                                 continue;
79                         break;
80                 case NETDEV_LOCAL_ADDRESS_DHCP6:
81                         if (a->source != NETWORK_CONFIG_SOURCE_DHCP6)
82                                 continue;
83                         break;
84                 case NETDEV_LOCAL_ADDRESS_SLAAC:
85                         if (a->source != NETWORK_CONFIG_SOURCE_NDISC)
86                                 continue;
87                         break;
88                 default:
89                         assert_not_reached();
90                 }
91 
92                 if (ret_family)
93                         *ret_family = a->family;
94                 if (ret_address)
95                         *ret_address = a->in_addr;
96                 return 1;
97         }
98 
99         return -ENXIO;
100 }
101