1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
22 #include <netinet/ether.h>
25 #include "networkd-link.h"
26 #include "network-internal.h"
28 static int ipv4ll_address_lost(Link *link) {
29 _cleanup_address_free_ Address *address = NULL;
30 _cleanup_route_free_ Route *route = NULL;
36 link->ipv4ll_route = false;
37 link->ipv4ll_address = false;
39 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
43 log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr));
45 r = address_new_dynamic(&address);
47 log_link_error(link, "Could not allocate address: %s", strerror(-r));
51 address->family = AF_INET;
52 address->in_addr.in = addr;
53 address->prefixlen = 16;
54 address->scope = RT_SCOPE_LINK;
56 address_drop(address, link, &link_address_drop_handler);
58 r = route_new_dynamic(&route, RTPROT_UNSPEC);
60 log_link_error(link, "Could not allocate route: %s",
65 route->family = AF_INET;
66 route->scope = RT_SCOPE_LINK;
67 route->metrics = IPV4LL_ROUTE_METRIC;
69 route_drop(route, link, &link_route_drop_handler);
71 link_client_handler(link);
76 static int ipv4ll_route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
77 _cleanup_link_unref_ Link *link = userdata;
81 assert(!link->ipv4ll_route);
83 r = sd_rtnl_message_get_errno(m);
84 if (r < 0 && r != -EEXIST) {
85 log_link_error(link, "could not set ipv4ll route: %s", strerror(-r));
86 link_enter_failed(link);
89 link->ipv4ll_route = true;
91 if (link->ipv4ll_address == true)
92 link_client_handler(link);
97 static int ipv4ll_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
98 _cleanup_link_unref_ Link *link = userdata;
102 assert(!link->ipv4ll_address);
104 r = sd_rtnl_message_get_errno(m);
105 if (r < 0 && r != -EEXIST) {
106 log_link_error(link, "could not set ipv4ll address: %s", strerror(-r));
107 link_enter_failed(link);
109 link_rtnl_process_address(rtnl, m, link->manager);
111 link->ipv4ll_address = true;
113 if (link->ipv4ll_route == true)
114 link_client_handler(link);
119 static 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;
128 r = sd_ipv4ll_get_address(ll, &address);
134 log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u",
135 ADDRESS_FMT_VAL(address));
137 r = address_new_dynamic(&ll_addr);
141 ll_addr->family = AF_INET;
142 ll_addr->in_addr.in = address;
143 ll_addr->prefixlen = 16;
144 ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen);
145 ll_addr->scope = RT_SCOPE_LINK;
147 r = address_configure(ll_addr, link, ipv4ll_address_handler);
151 link->ipv4ll_address = false;
153 r = route_new_dynamic(&route, RTPROT_STATIC);
157 route->family = AF_INET;
158 route->scope = RT_SCOPE_LINK;
159 route->metrics = IPV4LL_ROUTE_METRIC;
161 r = route_configure(route, link, ipv4ll_route_handler);
165 link->ipv4ll_route = false;
170 static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
171 Link *link = userdata;
175 assert(link->network);
176 assert(link->manager);
178 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
182 case IPV4LL_EVENT_STOP:
183 case IPV4LL_EVENT_CONFLICT:
184 r = ipv4ll_address_lost(link);
186 link_enter_failed(link);
190 case IPV4LL_EVENT_BIND:
191 r = ipv4ll_address_claimed(ll, link);
193 link_enter_failed(link);
199 log_link_warning(link, "IPv4 link-local error: %s", strerror(-event));
201 log_link_warning(link, "IPv4 link-local unknown event: %d", event);
206 int ipv4ll_configure(Link *link) {
211 assert(link->network);
212 assert(link->network->ipv4ll);
214 r = sd_ipv4ll_new(&link->ipv4ll);
218 if (link->udev_device) {
219 r = net_get_unique_predictable_data(link->udev_device, seed);
221 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
227 r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
231 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
235 r = sd_ipv4ll_set_index(link->ipv4ll, link->ifindex);
239 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);