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