]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-ipv4ll.c
log: add an "error" parameter to all low-level logging calls and intrdouce log_error_...
[thirdparty/systemd.git] / src / network / networkd-ipv4ll.c
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
28 static 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;
37 link->ipv4ll_address = false;
38
39 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
40 if (r < 0)
41 return 0;
42
43 log_debug_link(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr));
44
45 r = address_new_dynamic(&address);
46 if (r < 0) {
47 log_error_link(link, "Could not allocate address: %s", strerror(-r));
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
56 address_drop(address, link, &link_address_drop_handler);
57
58 r = route_new_dynamic(&route, RTPROT_UNSPEC);
59 if (r < 0) {
60 log_error_link(link, "Could not allocate route: %s",
61 strerror(-r));
62 return r;
63 }
64
65 route->family = AF_INET;
66 route->scope = RT_SCOPE_LINK;
67 route->metrics = IPV4LL_ROUTE_METRIC;
68
69 route_drop(route, link, &link_route_drop_handler);
70
71 link_client_handler(link);
72
73 return 0;
74 }
75
76 static int ipv4ll_route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
77 _cleanup_link_unref_ Link *link = userdata;
78 int r;
79
80 assert(link);
81 assert(!link->ipv4ll_route);
82
83 r = sd_rtnl_message_get_errno(m);
84 if (r < 0 && r != -EEXIST) {
85 log_error_link(link, "could not set ipv4ll route: %s", strerror(-r));
86 link_enter_failed(link);
87 }
88
89 link->ipv4ll_route = true;
90
91 if (link->ipv4ll_address == true)
92 link_client_handler(link);
93
94 return 1;
95 }
96
97 static int ipv4ll_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
98 _cleanup_link_unref_ Link *link = userdata;
99 int r;
100
101 assert(link);
102 assert(!link->ipv4ll_address);
103
104 r = sd_rtnl_message_get_errno(m);
105 if (r < 0 && r != -EEXIST) {
106 log_error_link(link, "could not set ipv4ll address: %s", strerror(-r));
107 link_enter_failed(link);
108 } else if (r >= 0) {
109 /* calling handler directly so take a ref */
110 link_ref(link);
111 link_get_address_handler(rtnl, m, link);
112 }
113
114 link->ipv4ll_address = true;
115
116 if (link->ipv4ll_route == true)
117 link_client_handler(link);
118
119 return 1;
120 }
121
122 static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
123 _cleanup_address_free_ Address *ll_addr = NULL;
124 _cleanup_route_free_ Route *route = NULL;
125 struct in_addr address;
126 int r;
127
128 assert(ll);
129 assert(link);
130
131 r = sd_ipv4ll_get_address(ll, &address);
132 if (r == -ENOENT)
133 return 0;
134 else if (r < 0)
135 return r;
136
137 log_debug_link(link, "IPv4 link-local claim %u.%u.%u.%u",
138 ADDRESS_FMT_VAL(address));
139
140 r = address_new_dynamic(&ll_addr);
141 if (r < 0)
142 return r;
143
144 ll_addr->family = AF_INET;
145 ll_addr->in_addr.in = address;
146 ll_addr->prefixlen = 16;
147 ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen);
148 ll_addr->scope = RT_SCOPE_LINK;
149
150 r = address_configure(ll_addr, link, ipv4ll_address_handler);
151 if (r < 0)
152 return r;
153
154 link->ipv4ll_address = false;
155
156 r = route_new_dynamic(&route, RTPROT_STATIC);
157 if (r < 0)
158 return r;
159
160 route->family = AF_INET;
161 route->scope = RT_SCOPE_LINK;
162 route->metrics = IPV4LL_ROUTE_METRIC;
163
164 r = route_configure(route, link, ipv4ll_route_handler);
165 if (r < 0)
166 return r;
167
168 link->ipv4ll_route = false;
169
170 return 0;
171 }
172
173 static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
174 Link *link = userdata;
175 int r;
176
177 assert(link);
178 assert(link->network);
179 assert(link->manager);
180
181 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
182 return;
183
184 switch(event) {
185 case IPV4LL_EVENT_STOP:
186 case IPV4LL_EVENT_CONFLICT:
187 r = ipv4ll_address_lost(link);
188 if (r < 0) {
189 link_enter_failed(link);
190 return;
191 }
192 break;
193 case IPV4LL_EVENT_BIND:
194 r = ipv4ll_address_claimed(ll, link);
195 if (r < 0) {
196 link_enter_failed(link);
197 return;
198 }
199 break;
200 default:
201 if (event < 0)
202 log_warning_link(link, "IPv4 link-local error: %s", strerror(-event));
203 else
204 log_warning_link(link, "IPv4 link-local unknown event: %d", event);
205 break;
206 }
207 }
208
209 int ipv4ll_configure(Link *link) {
210 uint8_t seed[8];
211 int r;
212
213 assert(link);
214 assert(link->network);
215 assert(link->network->ipv4ll);
216
217 r = sd_ipv4ll_new(&link->ipv4ll);
218 if (r < 0)
219 return r;
220
221 if (link->udev_device) {
222 r = net_get_unique_predictable_data(link->udev_device, seed);
223 if (r >= 0) {
224 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
225 if (r < 0)
226 return r;
227 }
228 }
229
230 r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
231 if (r < 0)
232 return r;
233
234 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
235 if (r < 0)
236 return r;
237
238 r = sd_ipv4ll_set_index(link->ipv4ll, link->ifindex);
239 if (r < 0)
240 return r;
241
242 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
243 if (r < 0)
244 return r;
245
246 return 0;
247 }