1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 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>
26 #include "libudev-private.h"
29 int link_new(Manager *manager, struct udev_device *device, Link **ret) {
30 _cleanup_link_free_ Link *link = NULL;
32 struct ether_addr *mac_addr;
42 link->ifindex = udev_device_get_ifindex(device);
43 if (link->ifindex <= 0)
46 mac = udev_device_get_sysattr_value(device, "address");
50 mac_addr = ether_aton(mac);
54 memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
56 link->manager = manager;
57 link->state = _LINK_STATE_INVALID;
59 r = hashmap_put(manager->links, &link->ifindex, link);
69 void link_free(Link *link) {
73 assert(link->manager);
75 hashmap_remove(link->manager->links, &link->ifindex);
80 int link_add(Manager *m, struct udev_device *device) {
89 ifindex = udev_device_get_ifindex(device);
90 link = hashmap_get(m->links, &ifindex);
94 r = link_new(m, device, &link);
96 log_error("could not create link: %s", strerror(-r));
100 r = network_get(m, device, &network);
102 return r == -ENOENT ? 0 : r;
104 r = network_apply(m, network, link);
111 static int link_enter_configured(Link *link) {
112 log_info("Link configured successfully.");
114 link->state = LINK_STATE_CONFIGURED;
119 static int link_enter_failed(Link *link) {
120 log_warning("Could not configure link.");
122 link->state = LINK_STATE_FAILED;
127 static bool link_is_up(Link *link) {
128 return link->flags & IFF_UP;
131 static int link_enter_routes_set(Link *link) {
132 log_info("Routes set for link %u", (unsigned)link->ifindex);
134 if (link_is_up(link))
135 return link_enter_configured(link);
137 link->state = LINK_STATE_ROUTES_SET;
142 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
143 Link *link = userdata;
146 assert(link->rtnl_messages > 0);
147 assert(link->state == LINK_STATE_SET_ROUTES || link->state == LINK_STATE_FAILED);
149 link->rtnl_messages --;
151 if (link->state == LINK_STATE_FAILED)
154 r = sd_rtnl_message_get_errno(m);
155 if (r < 0 && r != -EEXIST) {
156 log_warning("Could not set route on interface %u: %s",
157 (unsigned)link->ifindex, strerror(-r));
158 return link_enter_failed(link);
161 if (link->rtnl_messages == 0)
162 return link_enter_routes_set(link);
167 static int link_enter_set_routes(Link *link) {
172 assert(link->network);
173 assert(link->rtnl_messages == 0);
174 assert(link->state == LINK_STATE_ADDRESSES_SET);
176 link->state = LINK_STATE_SET_ROUTES;
178 if (!link->network->routes)
179 return link_enter_routes_set(link);
181 LIST_FOREACH(routes, route, link->network->routes) {
182 r = route_configure(route, link, &route_handler);
184 link_enter_failed(link);
190 static int link_enter_addresses_set(Link *link) {
191 log_info("Addresses set for link %u", (unsigned)link->ifindex);
193 link->state = LINK_STATE_ADDRESSES_SET;
195 return link_enter_set_routes(link);
198 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
199 Link *link = userdata;
202 assert(link->rtnl_messages > 0);
203 assert(link->state == LINK_STATE_SET_ADDRESSES || link->state == LINK_STATE_FAILED);
205 link->rtnl_messages --;
207 if (link->state == LINK_STATE_FAILED)
210 r = sd_rtnl_message_get_errno(m);
211 if (r < 0 && r != -EEXIST) {
212 log_warning("Could not set address on interface %u: %s",
213 (unsigned)link->ifindex, strerror(-r));
214 link_enter_failed(link);
217 if (link->rtnl_messages == 0)
218 link_enter_addresses_set(link);
223 static int link_enter_set_addresses(Link *link) {
228 assert(link->network);
229 assert(link->rtnl_messages == 0);
231 if (!link->network->addresses)
232 return link_enter_addresses_set(link);
234 link->state = LINK_STATE_SET_ADDRESSES;
236 LIST_FOREACH(addresses, address, link->network->addresses) {
237 r = address_configure(address, link, &address_handler);
239 link_enter_failed(link);
245 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
246 Link *link = userdata;
249 r = sd_rtnl_message_get_errno(m);
251 log_warning("Could not bring up interface %u: %s",
252 (unsigned)link->ifindex, strerror(-r));
253 return link_enter_failed(link);
256 link->flags |= IFF_UP;
258 log_info("Link is UP.");
260 if (link->state == LINK_STATE_ROUTES_SET)
261 return link_enter_configured(link);
266 static int link_up(Link *link) {
267 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
271 assert(link->manager);
272 assert(link->manager->rtnl);
274 r = sd_rtnl_message_link_new(RTM_NEWLINK, link->ifindex, 0, IFF_UP, &req);
276 log_error("Could not allocate RTM_NEWLINK message");
280 r = sd_rtnl_call_async(link->manager->rtnl, req, link_handler, link, 0, NULL);
282 log_error("Could not send rtnetlink message: %s", strerror(-r));
289 int link_configure(Link *link) {
294 return link_enter_failed(link);
296 r = link_enter_set_addresses(link);
298 return link_enter_failed(link);