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->manager = manager;
43 link->state = _LINK_STATE_INVALID;
45 link->ifindex = udev_device_get_ifindex(device);
46 if (link->ifindex <= 0)
49 mac = udev_device_get_sysattr_value(device, "address");
51 mac_addr = ether_aton(mac);
53 memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
56 r = hashmap_put(manager->links, &link->ifindex, link);
66 void link_free(Link *link) {
70 assert(link->manager);
72 hashmap_remove(link->manager->links, &link->ifindex);
77 int link_add(Manager *m, struct udev_device *device) {
86 ifindex = udev_device_get_ifindex(device);
87 link = hashmap_get(m->links, &ifindex);
91 r = link_new(m, device, &link);
93 log_error("could not create link: %s", strerror(-r));
97 r = network_get(m, device, &network);
99 return r == -ENOENT ? 0 : r;
101 r = network_apply(m, network, link);
108 static int link_enter_configured(Link *link) {
109 log_info("Link configured successfully.");
111 link->state = LINK_STATE_CONFIGURED;
116 static int link_enter_failed(Link *link) {
117 log_warning("Could not configure link.");
119 link->state = LINK_STATE_FAILED;
124 static bool link_is_up(Link *link) {
125 return link->flags & IFF_UP;
128 static int link_enter_routes_set(Link *link) {
129 log_info("Routes set for link %u", (unsigned)link->ifindex);
131 if (link_is_up(link))
132 return link_enter_configured(link);
134 link->state = LINK_STATE_ROUTES_SET;
139 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
140 Link *link = userdata;
143 assert(link->rtnl_messages > 0);
144 assert(link->state == LINK_STATE_SET_ROUTES || link->state == LINK_STATE_FAILED);
146 link->rtnl_messages --;
148 if (link->state == LINK_STATE_FAILED)
151 r = sd_rtnl_message_get_errno(m);
152 if (r < 0 && r != -EEXIST) {
153 log_warning("Could not set route on interface %u: %s",
154 (unsigned)link->ifindex, strerror(-r));
155 return link_enter_failed(link);
158 if (link->rtnl_messages == 0)
159 return link_enter_routes_set(link);
164 static int link_enter_set_routes(Link *link) {
169 assert(link->network);
170 assert(link->rtnl_messages == 0);
171 assert(link->state == LINK_STATE_ADDRESSES_SET);
173 link->state = LINK_STATE_SET_ROUTES;
175 if (!link->network->routes)
176 return link_enter_routes_set(link);
178 LIST_FOREACH(routes, route, link->network->routes) {
179 r = route_configure(route, link, &route_handler);
181 link_enter_failed(link);
187 static int link_enter_addresses_set(Link *link) {
188 log_info("Addresses set for link %u", (unsigned)link->ifindex);
190 link->state = LINK_STATE_ADDRESSES_SET;
192 return link_enter_set_routes(link);
195 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
196 Link *link = userdata;
199 assert(link->rtnl_messages > 0);
200 assert(link->state == LINK_STATE_SET_ADDRESSES || link->state == LINK_STATE_FAILED);
202 link->rtnl_messages --;
204 if (link->state == LINK_STATE_FAILED)
207 r = sd_rtnl_message_get_errno(m);
208 if (r < 0 && r != -EEXIST) {
209 log_warning("Could not set address on interface %u: %s",
210 (unsigned)link->ifindex, strerror(-r));
211 link_enter_failed(link);
214 if (link->rtnl_messages == 0)
215 link_enter_addresses_set(link);
220 static int link_enter_set_addresses(Link *link) {
225 assert(link->network);
226 assert(link->rtnl_messages == 0);
228 if (!link->network->addresses)
229 return link_enter_addresses_set(link);
231 link->state = LINK_STATE_SET_ADDRESSES;
233 LIST_FOREACH(addresses, address, link->network->addresses) {
234 r = address_configure(address, link, &address_handler);
236 link_enter_failed(link);
242 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
243 Link *link = userdata;
246 r = sd_rtnl_message_get_errno(m);
248 log_warning("Could not bring up interface %u: %s",
249 (unsigned)link->ifindex, strerror(-r));
250 return link_enter_failed(link);
253 link->flags |= IFF_UP;
255 log_info("Link is UP.");
257 if (link->state == LINK_STATE_ROUTES_SET)
258 return link_enter_configured(link);
263 static int link_up(Link *link) {
264 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
268 assert(link->manager);
269 assert(link->manager->rtnl);
271 r = sd_rtnl_message_link_new(RTM_NEWLINK, link->ifindex, 0, IFF_UP, &req);
273 log_error("Could not allocate RTM_NEWLINK message");
277 r = sd_rtnl_call_async(link->manager->rtnl, req, link_handler, link, 0, NULL);
279 log_error("Could not send rtnetlink message: %s", strerror(-r));
286 int link_configure(Link *link) {
291 return link_enter_failed(link);
293 r = link_enter_set_addresses(link);
295 return link_enter_failed(link);