]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-ipv4ll.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / network / networkd-ipv4ll.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
b22d8a00
TG
2/***
3 This file is part of systemd.
4
5 Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <netinet/ether.h>
22#include <linux/if.h>
23
b22d8a00 24#include "network-internal.h"
23f53b99
TG
25#include "networkd-address.h"
26#include "networkd-manager.h"
27#include "networkd-link.h"
b22d8a00
TG
28
29static int ipv4ll_address_lost(Link *link) {
30 _cleanup_address_free_ Address *address = NULL;
31 _cleanup_route_free_ Route *route = NULL;
32 struct in_addr addr;
33 int r;
34
35 assert(link);
36
37 link->ipv4ll_route = false;
920b52e4 38 link->ipv4ll_address = false;
b22d8a00
TG
39
40 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
41 if (r < 0)
42 return 0;
43
79008bdd 44 log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr));
b22d8a00 45
f0213e37 46 r = address_new(&address);
b22d8a00 47 if (r < 0) {
e53fc357 48 log_link_error_errno(link, r, "Could not allocate address: %m");
b22d8a00
TG
49 return r;
50 }
51
52 address->family = AF_INET;
53 address->in_addr.in = addr;
54 address->prefixlen = 16;
55 address->scope = RT_SCOPE_LINK;
56
483d099e 57 address_remove(address, link, link_address_remove_handler);
b22d8a00 58
ed9e361a 59 r = route_new(&route);
b22d8a00 60 if (r < 0) {
e53fc357 61 log_link_error_errno(link, r, "Could not allocate route: %m");
b22d8a00
TG
62 return r;
63 }
64
65 route->family = AF_INET;
66 route->scope = RT_SCOPE_LINK;
86655331 67 route->priority = IPV4LL_ROUTE_METRIC;
b22d8a00 68
483d099e 69 route_remove(route, link, link_route_remove_handler);
b22d8a00 70
8012cd39 71 link_check_ready(link);
b22d8a00
TG
72
73 return 0;
74}
75
1c4baffc 76static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
b22d8a00
TG
77 _cleanup_link_unref_ Link *link = userdata;
78 int r;
79
80 assert(link);
81 assert(!link->ipv4ll_route);
82
1c4baffc 83 r = sd_netlink_message_get_errno(m);
b22d8a00 84 if (r < 0 && r != -EEXIST) {
e53fc357 85 log_link_error_errno(link, r, "could not set ipv4ll route: %m");
b22d8a00
TG
86 link_enter_failed(link);
87 }
88
89 link->ipv4ll_route = true;
90
91 if (link->ipv4ll_address == true)
8012cd39 92 link_check_ready(link);
b22d8a00
TG
93
94 return 1;
95}
96
1c4baffc 97static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
b22d8a00
TG
98 _cleanup_link_unref_ Link *link = userdata;
99 int r;
100
101 assert(link);
102 assert(!link->ipv4ll_address);
103
1c4baffc 104 r = sd_netlink_message_get_errno(m);
b22d8a00 105 if (r < 0 && r != -EEXIST) {
e53fc357 106 log_link_error_errno(link, r, "could not set ipv4ll address: %m");
b22d8a00 107 link_enter_failed(link);
45af44d4 108 } else if (r >= 0)
200a0868 109 manager_rtnl_process_address(rtnl, m, link->manager);
b22d8a00
TG
110
111 link->ipv4ll_address = true;
112
c1db1a80 113 if (link->ipv4ll_route)
8012cd39 114 link_check_ready(link);
b22d8a00
TG
115
116 return 1;
117}
118
119static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
120 _cleanup_address_free_ Address *ll_addr = NULL;
121 _cleanup_route_free_ Route *route = NULL;
122 struct in_addr address;
123 int r;
124
125 assert(ll);
126 assert(link);
127
128 r = sd_ipv4ll_get_address(ll, &address);
129 if (r == -ENOENT)
130 return 0;
131 else if (r < 0)
132 return r;
133
79008bdd 134 log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u",
b22d8a00
TG
135 ADDRESS_FMT_VAL(address));
136
f0213e37 137 r = address_new(&ll_addr);
b22d8a00
TG
138 if (r < 0)
139 return r;
140
141 ll_addr->family = AF_INET;
142 ll_addr->in_addr.in = address;
143 ll_addr->prefixlen = 16;
8e38570e 144 ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htobe32(0xfffffffflu >> ll_addr->prefixlen);
b22d8a00
TG
145 ll_addr->scope = RT_SCOPE_LINK;
146
66669078 147 r = address_configure(ll_addr, link, ipv4ll_address_handler, false);
b22d8a00
TG
148 if (r < 0)
149 return r;
150
151 link->ipv4ll_address = false;
152
ed9e361a 153 r = route_new(&route);
b22d8a00
TG
154 if (r < 0)
155 return r;
156
157 route->family = AF_INET;
158 route->scope = RT_SCOPE_LINK;
ed9e361a 159 route->protocol = RTPROT_STATIC;
86655331 160 route->priority = IPV4LL_ROUTE_METRIC;
b22d8a00
TG
161
162 r = route_configure(route, link, ipv4ll_route_handler);
163 if (r < 0)
164 return r;
165
166 link->ipv4ll_route = false;
167
168 return 0;
169}
170
9ed794a3 171static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
b22d8a00
TG
172 Link *link = userdata;
173 int r;
174
175 assert(link);
176 assert(link->network);
b22d8a00
TG
177
178 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
179 return;
180
181 switch(event) {
be19c5b5 182 case SD_IPV4LL_EVENT_STOP:
0698ff41
JR
183 r = ipv4ll_address_lost(link);
184 if (r < 0) {
185 link_enter_failed(link);
186 return;
187 }
188 break;
be19c5b5 189 case SD_IPV4LL_EVENT_CONFLICT:
b22d8a00
TG
190 r = ipv4ll_address_lost(link);
191 if (r < 0) {
192 link_enter_failed(link);
193 return;
194 }
0698ff41
JR
195
196 r = sd_ipv4ll_restart(ll);
197 if (r < 0)
198 log_link_warning(link, "Could not acquire IPv4 link-local address");
b22d8a00 199 break;
be19c5b5 200 case SD_IPV4LL_EVENT_BIND:
b22d8a00
TG
201 r = ipv4ll_address_claimed(ll, link);
202 if (r < 0) {
203 link_enter_failed(link);
204 return;
205 }
206 break;
207 default:
b45e4eb6 208 log_link_warning(link, "IPv4 link-local unknown event: %d", event);
b22d8a00
TG
209 break;
210 }
211}
212
213int ipv4ll_configure(Link *link) {
dbe81cbd 214 uint64_t seed;
b22d8a00
TG
215 int r;
216
217 assert(link);
218 assert(link->network);
e0ee46f2 219 assert(link->network->link_local & ADDRESS_FAMILY_IPV4);
b22d8a00 220
0bc70f1d
TG
221 if (!link->ipv4ll) {
222 r = sd_ipv4ll_new(&link->ipv4ll);
223 if (r < 0)
224 return r;
225 }
b22d8a00
TG
226
227 if (link->udev_device) {
dbe81cbd 228 r = net_get_unique_predictable_data(link->udev_device, &seed);
b22d8a00 229 if (r >= 0) {
38958cd6 230 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
b22d8a00
TG
231 if (r < 0)
232 return r;
233 }
234 }
235
236 r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
237 if (r < 0)
238 return r;
239
240 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
241 if (r < 0)
242 return r;
243
2f8e7633 244 r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
b22d8a00
TG
245 if (r < 0)
246 return r;
247
248 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
249 if (r < 0)
250 return r;
251
252 return 0;
253}