1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "sd-network.h"
4 
5 #include "alloc-util.h"
6 #include "hashmap.h"
7 #include "link.h"
8 #include "manager.h"
9 #include "string-util.h"
10 
link_new(Manager * m,Link ** ret,int ifindex,const char * ifname)11 int link_new(Manager *m, Link **ret, int ifindex, const char *ifname) {
12         _cleanup_(link_freep) Link *l = NULL;
13         _cleanup_free_ char *n = NULL;
14         int r;
15 
16         assert(m);
17         assert(ifindex > 0);
18         assert(ifname);
19 
20         n = strdup(ifname);
21         if (!n)
22                 return -ENOMEM;
23 
24         l = new(Link, 1);
25         if (!l)
26                 return -ENOMEM;
27 
28         *l = (Link) {
29                 .manager = m,
30                 .ifname = TAKE_PTR(n),
31                 .ifindex = ifindex,
32                 .required_operstate = LINK_OPERSTATE_RANGE_DEFAULT,
33         };
34 
35         r = hashmap_ensure_put(&m->links_by_index, NULL, INT_TO_PTR(ifindex), l);
36         if (r < 0)
37                 return r;
38 
39         r = hashmap_ensure_put(&m->links_by_name, &string_hash_ops, l->ifname, l);
40         if (r < 0)
41                 return r;
42 
43         if (ret)
44                 *ret = l;
45 
46         TAKE_PTR(l);
47         return 0;
48 }
49 
link_free(Link * l)50 Link *link_free(Link *l) {
51 
52         if (!l)
53                 return NULL;
54 
55         if (l->manager) {
56                 hashmap_remove(l->manager->links_by_index, INT_TO_PTR(l->ifindex));
57                 hashmap_remove(l->manager->links_by_name, l->ifname);
58         }
59 
60         free(l->state);
61         free(l->ifname);
62         return mfree(l);
63  }
64 
link_update_rtnl(Link * l,sd_netlink_message * m)65 int link_update_rtnl(Link *l, sd_netlink_message *m) {
66         const char *ifname;
67         int r;
68 
69         assert(l);
70         assert(l->manager);
71         assert(m);
72 
73         r = sd_rtnl_message_link_get_flags(m, &l->flags);
74         if (r < 0)
75                 return r;
76 
77         r = sd_netlink_message_read_string(m, IFLA_IFNAME, &ifname);
78         if (r < 0)
79                 return r;
80 
81         if (!streq(l->ifname, ifname)) {
82                 char *new_ifname;
83 
84                 new_ifname = strdup(ifname);
85                 if (!new_ifname)
86                         return -ENOMEM;
87 
88                 assert_se(hashmap_remove(l->manager->links_by_name, l->ifname) == l);
89                 free_and_replace(l->ifname, new_ifname);
90 
91                 r = hashmap_put(l->manager->links_by_name, l->ifname, l);
92                 if (r < 0)
93                         return r;
94         }
95 
96         return 0;
97 }
98 
link_update_monitor(Link * l)99 int link_update_monitor(Link *l) {
100         _cleanup_free_ char *required_operstate = NULL, *required_family = NULL,
101                 *ipv4_address_state = NULL, *ipv6_address_state = NULL, *state = NULL;
102         int r, ret = 0;
103 
104         assert(l);
105         assert(l->ifname);
106 
107         r = sd_network_link_get_required_for_online(l->ifindex);
108         if (r < 0)
109                 ret = log_link_debug_errno(l, r, "Failed to determine whether the link is required for online or not, "
110                                            "ignoring: %m");
111         else
112                 l->required_for_online = r > 0;
113 
114         r = sd_network_link_get_required_operstate_for_online(l->ifindex, &required_operstate);
115         if (r < 0)
116                 ret = log_link_debug_errno(l, r, "Failed to get required operational state, ignoring: %m");
117         else if (isempty(required_operstate))
118                 l->required_operstate = LINK_OPERSTATE_RANGE_DEFAULT;
119         else {
120                 r = parse_operational_state_range(required_operstate, &l->required_operstate);
121                 if (r < 0)
122                         ret = log_link_debug_errno(l, SYNTHETIC_ERRNO(EINVAL),
123                                                    "Failed to parse required operational state, ignoring: %m");
124         }
125 
126         r = network_link_get_operational_state(l->ifindex, &l->operational_state);
127         if (r < 0)
128                 ret = log_link_debug_errno(l, r, "Failed to get operational state, ignoring: %m");
129 
130         r = sd_network_link_get_required_family_for_online(l->ifindex, &required_family);
131         if (r < 0)
132                 ret = log_link_debug_errno(l, r, "Failed to get required address family, ignoring: %m");
133         else if (isempty(required_family))
134                 l->required_family = ADDRESS_FAMILY_NO;
135         else {
136                 AddressFamily f;
137 
138                 f = link_required_address_family_from_string(required_family);
139                 if (f < 0)
140                         ret = log_link_debug_errno(l, f, "Failed to parse required address family, ignoring: %m");
141                 else
142                         l->required_family = f;
143         }
144 
145         r = sd_network_link_get_ipv4_address_state(l->ifindex, &ipv4_address_state);
146         if (r < 0)
147                 ret = log_link_debug_errno(l, r, "Failed to get IPv4 address state, ignoring: %m");
148         else {
149                 LinkAddressState s;
150 
151                 s = link_address_state_from_string(ipv4_address_state);
152                 if (s < 0)
153                         ret = log_link_debug_errno(l, s, "Failed to parse IPv4 address state, ignoring: %m");
154                 else
155                         l->ipv4_address_state = s;
156         }
157 
158         r = sd_network_link_get_ipv6_address_state(l->ifindex, &ipv6_address_state);
159         if (r < 0)
160                 ret = log_link_debug_errno(l, r, "Failed to get IPv6 address state, ignoring: %m");
161         else {
162                 LinkAddressState s;
163 
164                 s = link_address_state_from_string(ipv6_address_state);
165                 if (s < 0)
166                         ret = log_link_debug_errno(l, s, "Failed to parse IPv6 address state, ignoring: %m");
167                 else
168                         l->ipv6_address_state = s;
169         }
170 
171         r = sd_network_link_get_setup_state(l->ifindex, &state);
172         if (r < 0)
173                 ret = log_link_debug_errno(l, r, "Failed to get setup state, ignoring: %m");
174         else
175                 free_and_replace(l->state, state);
176 
177         return ret;
178 }
179