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_debug_link(link, "IPv4 link-local release %u.%u.%u.%u",
44 ADDRESS_FMT_VAL(addr));
46 r = address_new_dynamic(&address);
48 log_error_link(link, "Could not allocate address: %s", strerror(-r));
52 address->family = AF_INET;
53 address->in_addr.in = addr;
54 address->prefixlen = 16;
55 address->scope = RT_SCOPE_LINK;
57 address_drop(address, link, &link_address_drop_handler);
59 r = route_new_dynamic(&route, RTPROT_UNSPEC);
61 log_error_link(link, "Could not allocate route: %s",
66 route->family = AF_INET;
67 route->scope = RT_SCOPE_LINK;
68 route->metrics = IPV4LL_ROUTE_METRIC;
70 route_drop(route, link, &link_route_drop_handler);
72 link_client_handler(link);
77 static int ipv4ll_route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
78 _cleanup_link_unref_ Link *link = userdata;
82 assert(!link->ipv4ll_route);
84 r = sd_rtnl_message_get_errno(m);
85 if (r < 0 && r != -EEXIST) {
86 log_error_link(link, "could not set ipv4ll route: %s", strerror(-r));
87 link_enter_failed(link);
90 link->ipv4ll_route = true;
92 if (link->ipv4ll_address == true)
93 link_client_handler(link);
98 static int ipv4ll_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
99 _cleanup_link_unref_ Link *link = userdata;
103 assert(!link->ipv4ll_address);
105 r = sd_rtnl_message_get_errno(m);
106 if (r < 0 && r != -EEXIST) {
107 log_error_link(link, "could not set ipv4ll address: %s", strerror(-r));
108 link_enter_failed(link);
110 /* calling handler directly so take a ref */
112 link_get_address_handler(rtnl, m, link);
115 link->ipv4ll_address = true;
117 if (link->ipv4ll_route == true)
118 link_client_handler(link);
123 static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
124 _cleanup_address_free_ Address *ll_addr = NULL;
125 _cleanup_route_free_ Route *route = NULL;
126 struct in_addr address;
132 r = sd_ipv4ll_get_address(ll, &address);
138 log_debug_link(link, "IPv4 link-local claim %u.%u.%u.%u",
139 ADDRESS_FMT_VAL(address));
141 r = address_new_dynamic(&ll_addr);
145 ll_addr->family = AF_INET;
146 ll_addr->in_addr.in = address;
147 ll_addr->prefixlen = 16;
148 ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen);
149 ll_addr->scope = RT_SCOPE_LINK;
151 r = address_configure(ll_addr, link, ipv4ll_address_handler);
155 link->ipv4ll_address = false;
157 r = route_new_dynamic(&route, RTPROT_STATIC);
161 route->family = AF_INET;
162 route->scope = RT_SCOPE_LINK;
163 route->metrics = IPV4LL_ROUTE_METRIC;
165 r = route_configure(route, link, ipv4ll_route_handler);
169 link->ipv4ll_route = false;
174 static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
175 Link *link = userdata;
179 assert(link->network);
180 assert(link->manager);
182 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
186 case IPV4LL_EVENT_STOP:
187 case IPV4LL_EVENT_CONFLICT:
188 r = ipv4ll_address_lost(link);
190 link_enter_failed(link);
194 case IPV4LL_EVENT_BIND:
195 r = ipv4ll_address_claimed(ll, link);
197 link_enter_failed(link);
203 log_warning_link(link, "IPv4 link-local error: %s", strerror(-event));
205 log_warning_link(link, "IPv4 link-local unknown event: %d", event);
210 int ipv4ll_configure(Link *link) {
215 assert(link->network);
216 assert(link->network->ipv4ll);
218 r = sd_ipv4ll_new(&link->ipv4ll);
222 if (link->udev_device) {
223 r = net_get_unique_predictable_data(link->udev_device, seed);
225 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
231 r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
235 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
239 r = sd_ipv4ll_set_index(link->ipv4ll, link->ifindex);
243 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);