1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <netinet/in.h>
4 #include <linux/if.h>
5 
6 #include "netif-util.h"
7 #include "networkd-address.h"
8 #include "networkd-ipv4ll.h"
9 #include "networkd-link.h"
10 #include "networkd-manager.h"
11 #include "networkd-queue.h"
12 #include "parse-util.h"
13 
address_new_from_ipv4ll(Link * link,Address ** ret)14 static int address_new_from_ipv4ll(Link *link, Address **ret) {
15         _cleanup_(address_freep) Address *address = NULL;
16         struct in_addr addr;
17         int r;
18 
19         assert(link);
20         assert(link->ipv4ll);
21         assert(ret);
22 
23         r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
24         if (r < 0)
25                 return r;
26 
27         r = address_new(&address);
28         if (r < 0)
29                 return -ENOMEM;
30 
31         address->source = NETWORK_CONFIG_SOURCE_IPV4LL;
32         address->family = AF_INET;
33         address->in_addr.in = addr;
34         address->prefixlen = 16;
35         address->scope = RT_SCOPE_LINK;
36         address->route_metric = IPV4LL_ROUTE_METRIC;
37         address_set_broadcast(address, link);
38 
39         *ret = TAKE_PTR(address);
40         return 0;
41 }
42 
ipv4ll_address_lost(Link * link)43 static int ipv4ll_address_lost(Link *link) {
44         _cleanup_(address_freep) Address *address = NULL;
45         Address *existing;
46         int r;
47 
48         assert(link);
49 
50         link->ipv4ll_address_configured = false;
51 
52         r = address_new_from_ipv4ll(link, &address);
53         if (r == -ENOENT)
54                 return 0;
55         if (r < 0)
56                 return r;
57 
58         if (address_get(link, address, &existing) < 0)
59                 return 0;
60 
61         if (existing->source != NETWORK_CONFIG_SOURCE_IPV4LL)
62                 return 0;
63 
64         if (!address_exists(existing))
65                 return 0;
66 
67         log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR,
68                        IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
69 
70         return address_remove(existing);
71 }
72 
ipv4ll_address_handler(sd_netlink * rtnl,sd_netlink_message * m,Request * req,Link * link,Address * address)73 static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
74         int r;
75 
76         assert(link);
77         assert(!link->ipv4ll_address_configured);
78 
79         r = address_configure_handler_internal(rtnl, m, link, "Could not set ipv4ll address");
80         if (r <= 0)
81                 return r;
82 
83         link->ipv4ll_address_configured = true;
84         link_check_ready(link);
85 
86         return 1;
87 }
88 
ipv4ll_address_claimed(sd_ipv4ll * ll,Link * link)89 static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
90         _cleanup_(address_freep) Address *address = NULL;
91         int r;
92 
93         assert(ll);
94         assert(link);
95 
96         link->ipv4ll_address_configured = false;
97 
98         r = address_new_from_ipv4ll(link, &address);
99         if (r == -ENOENT)
100                 return 0;
101         if (r < 0)
102                 return r;
103 
104         log_link_debug(link, "IPv4 link-local claim "IPV4_ADDRESS_FMT_STR,
105                        IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
106 
107         return link_request_address(link, TAKE_PTR(address), true, NULL, ipv4ll_address_handler, NULL);
108 }
109 
ipv4ll_handler(sd_ipv4ll * ll,int event,void * userdata)110 static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
111         Link *link = userdata;
112         int r;
113 
114         assert(link);
115         assert(link->network);
116 
117         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
118                 return;
119 
120         switch (event) {
121                 case SD_IPV4LL_EVENT_STOP:
122                         r = ipv4ll_address_lost(link);
123                         if (r < 0) {
124                                 link_enter_failed(link);
125                                 return;
126                         }
127                         break;
128                 case SD_IPV4LL_EVENT_CONFLICT:
129                         r = ipv4ll_address_lost(link);
130                         if (r < 0) {
131                                 link_enter_failed(link);
132                                 return;
133                         }
134 
135                         r = sd_ipv4ll_restart(ll);
136                         if (r < 0) {
137                                 log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
138                                 link_enter_failed(link);
139                         }
140                         break;
141                 case SD_IPV4LL_EVENT_BIND:
142                         r = ipv4ll_address_claimed(ll, link);
143                         if (r < 0) {
144                                 log_link_error(link, "Failed to configure ipv4ll address: %m");
145                                 link_enter_failed(link);
146                                 return;
147                         }
148                         break;
149                 default:
150                         log_link_warning(link, "IPv4 link-local unknown event: %d", event);
151                         break;
152         }
153 }
154 
ipv4ll_check_mac(sd_ipv4ll * ll,const struct ether_addr * mac,void * userdata)155 static int ipv4ll_check_mac(sd_ipv4ll *ll, const struct ether_addr *mac, void *userdata) {
156         Manager *m = userdata;
157         struct hw_addr_data hw_addr;
158 
159         assert(m);
160         assert(mac);
161 
162         hw_addr = (struct hw_addr_data) {
163                 .length = ETH_ALEN,
164                 .ether = *mac,
165         };
166 
167         return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0;
168 }
169 
ipv4ll_configure(Link * link)170 int ipv4ll_configure(Link *link) {
171         uint64_t seed;
172         int r;
173 
174         assert(link);
175 
176         if (!link_ipv4ll_enabled(link))
177                 return 0;
178 
179         if (link->ipv4ll)
180                 return -EBUSY;
181 
182         r = sd_ipv4ll_new(&link->ipv4ll);
183         if (r < 0)
184                 return r;
185 
186         r = sd_ipv4ll_attach_event(link->ipv4ll, link->manager->event, 0);
187         if (r < 0)
188                 return r;
189 
190         if (link->sd_device &&
191             net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) {
192                 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
193                 if (r < 0)
194                         return r;
195         }
196 
197         r = sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.ether);
198         if (r < 0)
199                 return r;
200 
201         r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
202         if (r < 0)
203                 return r;
204 
205         r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
206         if (r < 0)
207                 return r;
208 
209         return sd_ipv4ll_set_check_mac_callback(link->ipv4ll, ipv4ll_check_mac, link->manager);
210 }
211 
ipv4ll_update_mac(Link * link)212 int ipv4ll_update_mac(Link *link) {
213         assert(link);
214 
215         if (link->hw_addr.length != ETH_ALEN)
216                 return 0;
217         if (ether_addr_is_null(&link->hw_addr.ether))
218                 return 0;
219         if (!link->ipv4ll)
220                 return 0;
221 
222         return sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.ether);
223 }
224 
config_parse_ipv4ll(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)225 int config_parse_ipv4ll(
226                 const char* unit,
227                 const char *filename,
228                 unsigned line,
229                 const char *section,
230                 unsigned section_line,
231                 const char *lvalue,
232                 int ltype,
233                 const char *rvalue,
234                 void *data,
235                 void *userdata) {
236 
237         AddressFamily *link_local = data;
238         int r;
239 
240         assert(filename);
241         assert(lvalue);
242         assert(rvalue);
243         assert(data);
244 
245         /* Note that this is mostly like
246          * config_parse_address_family(), except that it
247          * applies only to IPv4 */
248 
249         r = parse_boolean(rvalue);
250         if (r < 0) {
251                 log_syntax(unit, LOG_WARNING, filename, line, r,
252                            "Failed to parse %s=%s, ignoring assignment. "
253                            "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.",
254                            lvalue, rvalue, lvalue);
255                 return 0;
256         }
257 
258         SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, r);
259 
260         log_syntax(unit, LOG_WARNING, filename, line, 0,
261                    "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.",
262                    lvalue, rvalue, address_family_to_string(*link_local));
263 
264         return 0;
265 }
266