]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-ipv4ll.c
scsi_id: use _cleanup_free_ on buffer allocated by get_file_options
[thirdparty/systemd.git] / src / network / networkd-ipv4ll.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
6 ***/
7
8 #include <netinet/ether.h>
9 #include <linux/if.h>
10
11 #include "network-internal.h"
12 #include "networkd-address.h"
13 #include "networkd-manager.h"
14 #include "networkd-link.h"
15
16 static int ipv4ll_address_lost(Link *link) {
17 _cleanup_(address_freep) Address *address = NULL;
18 _cleanup_(route_freep) Route *route = NULL;
19 struct in_addr addr;
20 int r;
21
22 assert(link);
23
24 link->ipv4ll_route = false;
25 link->ipv4ll_address = false;
26
27 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
28 if (r < 0)
29 return 0;
30
31 log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr));
32
33 r = address_new(&address);
34 if (r < 0) {
35 log_link_error_errno(link, r, "Could not allocate address: %m");
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
44 address_remove(address, link, link_address_remove_handler);
45
46 r = route_new(&route);
47 if (r < 0) {
48 log_link_error_errno(link, r, "Could not allocate route: %m");
49 return r;
50 }
51
52 route->family = AF_INET;
53 route->scope = RT_SCOPE_LINK;
54 route->priority = IPV4LL_ROUTE_METRIC;
55
56 route_remove(route, link, link_route_remove_handler);
57
58 link_check_ready(link);
59
60 return 0;
61 }
62
63 static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
64 _cleanup_(link_unrefp) Link *link = userdata;
65 int r;
66
67 assert(link);
68 assert(!link->ipv4ll_route);
69
70 r = sd_netlink_message_get_errno(m);
71 if (r < 0 && r != -EEXIST) {
72 log_link_error_errno(link, r, "could not set ipv4ll route: %m");
73 link_enter_failed(link);
74 }
75
76 link->ipv4ll_route = true;
77
78 if (link->ipv4ll_address == true)
79 link_check_ready(link);
80
81 return 1;
82 }
83
84 static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
85 _cleanup_(link_unrefp) Link *link = userdata;
86 int r;
87
88 assert(link);
89 assert(!link->ipv4ll_address);
90
91 r = sd_netlink_message_get_errno(m);
92 if (r < 0 && r != -EEXIST) {
93 log_link_error_errno(link, r, "could not set ipv4ll address: %m");
94 link_enter_failed(link);
95 } else if (r >= 0)
96 manager_rtnl_process_address(rtnl, m, link->manager);
97
98 link->ipv4ll_address = true;
99
100 if (link->ipv4ll_route)
101 link_check_ready(link);
102
103 return 1;
104 }
105
106 static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
107 _cleanup_(address_freep) Address *ll_addr = NULL;
108 _cleanup_(route_freep) Route *route = NULL;
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
121 log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u",
122 ADDRESS_FMT_VAL(address));
123
124 r = address_new(&ll_addr);
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;
131 ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htobe32(0xfffffffflu >> ll_addr->prefixlen);
132 ll_addr->scope = RT_SCOPE_LINK;
133
134 r = address_configure(ll_addr, link, ipv4ll_address_handler, false);
135 if (r < 0)
136 return r;
137
138 link->ipv4ll_address = false;
139
140 r = route_new(&route);
141 if (r < 0)
142 return r;
143
144 route->family = AF_INET;
145 route->scope = RT_SCOPE_LINK;
146 route->protocol = RTPROT_STATIC;
147 route->priority = IPV4LL_ROUTE_METRIC;
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
158 static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
159 Link *link = userdata;
160 int r;
161
162 assert(link);
163 assert(link->network);
164
165 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
166 return;
167
168 switch(event) {
169 case SD_IPV4LL_EVENT_STOP:
170 r = ipv4ll_address_lost(link);
171 if (r < 0) {
172 link_enter_failed(link);
173 return;
174 }
175 break;
176 case SD_IPV4LL_EVENT_CONFLICT:
177 r = ipv4ll_address_lost(link);
178 if (r < 0) {
179 link_enter_failed(link);
180 return;
181 }
182
183 r = sd_ipv4ll_restart(ll);
184 if (r < 0)
185 log_link_warning(link, "Could not acquire IPv4 link-local address");
186 break;
187 case SD_IPV4LL_EVENT_BIND:
188 r = ipv4ll_address_claimed(ll, link);
189 if (r < 0) {
190 link_enter_failed(link);
191 return;
192 }
193 break;
194 default:
195 log_link_warning(link, "IPv4 link-local unknown event: %d", event);
196 break;
197 }
198 }
199
200 int ipv4ll_configure(Link *link) {
201 uint64_t seed;
202 int r;
203
204 assert(link);
205 assert(link->network);
206 assert(link->network->link_local & ADDRESS_FAMILY_IPV4);
207
208 if (!link->ipv4ll) {
209 r = sd_ipv4ll_new(&link->ipv4ll);
210 if (r < 0)
211 return r;
212 }
213
214 if (link->udev_device) {
215 r = net_get_unique_predictable_data(link->udev_device, &seed);
216 if (r >= 0) {
217 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
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
231 r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
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 }