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