]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-ipv4ll.c
pkgconfig: define variables relative to ${prefix}/${rootprefix}/${sysconfdir}
[thirdparty/systemd.git] / src / network / networkd-ipv4ll.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <netinet/ether.h>
4 #include <linux/if.h>
5
6 #include "network-internal.h"
7 #include "networkd-address.h"
8 #include "networkd-manager.h"
9 #include "networkd-link.h"
10
11 static int ipv4ll_address_lost(Link *link) {
12 _cleanup_(address_freep) Address *address = NULL;
13 _cleanup_(route_freep) Route *route = NULL;
14 struct in_addr addr;
15 int r;
16
17 assert(link);
18
19 link->ipv4ll_route = false;
20 link->ipv4ll_address = false;
21
22 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
23 if (r < 0)
24 return 0;
25
26 log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr));
27
28 r = address_new(&address);
29 if (r < 0)
30 return log_link_error_errno(link, r, "Could not allocate address: %m");
31
32 address->family = AF_INET;
33 address->in_addr.in = addr;
34 address->prefixlen = 16;
35 address->scope = RT_SCOPE_LINK;
36
37 address_remove(address, link, link_address_remove_handler);
38
39 r = route_new(&route);
40 if (r < 0)
41 return log_link_error_errno(link, r, "Could not allocate route: %m");
42
43 route->family = AF_INET;
44 route->scope = RT_SCOPE_LINK;
45 route->priority = IPV4LL_ROUTE_METRIC;
46
47 route_remove(route, link, link_route_remove_handler);
48
49 link_check_ready(link);
50
51 return 0;
52 }
53
54 static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
55 Link *link = userdata;
56 int r;
57
58 assert(link);
59 assert(!link->ipv4ll_route);
60
61 r = sd_netlink_message_get_errno(m);
62 if (r < 0 && r != -EEXIST) {
63 log_link_error_errno(link, r, "could not set ipv4ll route: %m");
64 link_enter_failed(link);
65 }
66
67 link->ipv4ll_route = true;
68
69 if (link->ipv4ll_address == true)
70 link_check_ready(link);
71
72 return 1;
73 }
74
75 static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
76 Link *link = userdata;
77 int r;
78
79 assert(link);
80 assert(!link->ipv4ll_address);
81
82 r = sd_netlink_message_get_errno(m);
83 if (r < 0 && r != -EEXIST) {
84 log_link_error_errno(link, r, "could not set ipv4ll address: %m");
85 link_enter_failed(link);
86 } else if (r >= 0)
87 manager_rtnl_process_address(rtnl, m, link->manager);
88
89 link->ipv4ll_address = true;
90
91 if (link->ipv4ll_route)
92 link_check_ready(link);
93
94 return 1;
95 }
96
97 static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
98 _cleanup_(address_freep) Address *ll_addr = NULL;
99 _cleanup_(route_freep) Route *route = NULL;
100 struct in_addr address;
101 int r;
102
103 assert(ll);
104 assert(link);
105
106 r = sd_ipv4ll_get_address(ll, &address);
107 if (r == -ENOENT)
108 return 0;
109 else if (r < 0)
110 return r;
111
112 log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u",
113 ADDRESS_FMT_VAL(address));
114
115 r = address_new(&ll_addr);
116 if (r < 0)
117 return r;
118
119 ll_addr->family = AF_INET;
120 ll_addr->in_addr.in = address;
121 ll_addr->prefixlen = 16;
122 ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htobe32(0xfffffffflu >> ll_addr->prefixlen);
123 ll_addr->scope = RT_SCOPE_LINK;
124
125 r = address_configure(ll_addr, link, ipv4ll_address_handler, false);
126 if (r < 0)
127 return r;
128
129 link->ipv4ll_address = false;
130
131 r = route_new(&route);
132 if (r < 0)
133 return r;
134
135 route->family = AF_INET;
136 route->scope = RT_SCOPE_LINK;
137 route->protocol = RTPROT_STATIC;
138 route->priority = IPV4LL_ROUTE_METRIC;
139
140 r = route_configure(route, link, ipv4ll_route_handler);
141 if (r < 0)
142 return r;
143
144 link->ipv4ll_route = false;
145
146 return 0;
147 }
148
149 static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
150 Link *link = userdata;
151 int r;
152
153 assert(link);
154 assert(link->network);
155
156 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
157 return;
158
159 switch(event) {
160 case SD_IPV4LL_EVENT_STOP:
161 r = ipv4ll_address_lost(link);
162 if (r < 0) {
163 link_enter_failed(link);
164 return;
165 }
166 break;
167 case SD_IPV4LL_EVENT_CONFLICT:
168 r = ipv4ll_address_lost(link);
169 if (r < 0) {
170 link_enter_failed(link);
171 return;
172 }
173
174 r = sd_ipv4ll_restart(ll);
175 if (r < 0)
176 log_link_warning(link, "Could not acquire IPv4 link-local address");
177 break;
178 case SD_IPV4LL_EVENT_BIND:
179 r = ipv4ll_address_claimed(ll, link);
180 if (r < 0) {
181 link_enter_failed(link);
182 return;
183 }
184 break;
185 default:
186 log_link_warning(link, "IPv4 link-local unknown event: %d", event);
187 break;
188 }
189 }
190
191 int ipv4ll_configure(Link *link) {
192 uint64_t seed;
193 int r;
194
195 assert(link);
196 assert(link->network);
197 assert(link->network->link_local & ADDRESS_FAMILY_IPV4);
198
199 if (!link->ipv4ll) {
200 r = sd_ipv4ll_new(&link->ipv4ll);
201 if (r < 0)
202 return r;
203 }
204
205 if (link->sd_device &&
206 net_get_unique_predictable_data(link->sd_device, &seed) >= 0) {
207 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
208 if (r < 0)
209 return r;
210 }
211
212 r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
213 if (r < 0)
214 return r;
215
216 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
217 if (r < 0)
218 return r;
219
220 r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
221 if (r < 0)
222 return r;
223
224 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
225 if (r < 0)
226 return r;
227
228 return 0;
229 }