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;
43 link->manager = manager;
44 link->state = _LINK_STATE_INVALID;
46 link->ifindex = udev_device_get_ifindex(device);
47 if (link->ifindex <= 0)
50 mac = udev_device_get_sysattr_value(device, "address");
52 mac_addr = ether_aton(mac);
54 memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
57 ifname = udev_device_get_sysname(device);
58 link->ifname = strdup(ifname);
60 r = hashmap_put(manager->links, &link->ifindex, link);
70 void link_free(Link *link) {
74 assert(link->manager);
77 sd_dhcp_client_free(link->dhcp);
79 route_free(link->dhcp_route);
80 link->dhcp_route = NULL;
82 address_free(link->dhcp_address);
83 link->dhcp_address = NULL;
85 hashmap_remove(link->manager->links, &link->ifindex);
92 int link_add(Manager *m, struct udev_device *device) {
102 ifindex = udev_device_get_ifindex(device);
103 link = hashmap_get(m->links, &ifindex);
107 r = link_new(m, device, &link);
109 log_error("Could not create link: %s", strerror(-r));
113 devtype = udev_device_get_devtype(device);
114 if (streq_ptr(devtype, "bridge")) {
115 r = bridge_set_link(m, link);
117 return r == -ENOENT ? 0 : r;
120 r = network_get(m, device, &network);
122 return r == -ENOENT ? 0 : r;
124 r = network_apply(m, network, link);
131 static int link_enter_configured(Link *link) {
133 assert(link->state == LINK_STATE_SETTING_ROUTES);
135 log_info("Link '%s' configured", link->ifname);
137 link->state = LINK_STATE_CONFIGURED;
142 static void link_enter_failed(Link *link) {
145 link->state = LINK_STATE_FAILED;
148 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
149 Link *link = userdata;
152 assert(link->route_messages > 0);
153 assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
154 link->state == LINK_STATE_SETTING_ROUTES ||
155 link->state == LINK_STATE_FAILED);
157 link->route_messages --;
159 if (link->state == LINK_STATE_FAILED)
162 r = sd_rtnl_message_get_errno(m);
163 if (r < 0 && r != -EEXIST)
164 log_warning("Could not set route on interface '%s': %s",
165 link->ifname, strerror(-r));
167 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
169 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
170 log_info("Routes set for link '%s'", link->ifname);
171 link_enter_configured(link);
177 static int link_enter_set_routes(Link *link) {
182 assert(link->network);
183 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
185 link->state = LINK_STATE_SETTING_ROUTES;
187 if (!link->network->static_routes && !link->dhcp_route)
188 return link_enter_configured(link);
190 LIST_FOREACH(static_routes, route, link->network->static_routes) {
191 r = route_configure(route, link, &route_handler);
193 log_warning("Could not set routes for link '%s'", link->ifname);
194 link_enter_failed(link);
198 link->route_messages ++;
201 if (link->dhcp_route) {
202 r = route_configure(link->dhcp_route, link, &route_handler);
204 log_warning("Could not set routes for link '%s'", link->ifname);
205 link_enter_failed(link);
209 link->route_messages ++;
215 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
216 Link *link = userdata;
221 assert(link->ifname);
222 assert(link->addr_messages > 0);
223 assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
225 link->addr_messages --;
227 if (link->state == LINK_STATE_FAILED)
230 r = sd_rtnl_message_get_errno(m);
231 if (r < 0 && r != -EEXIST)
232 log_warning("Could not set address on interface '%s': %s",
233 link->ifname, strerror(-r));
235 if (link->addr_messages == 0) {
236 log_info("Addresses set for link '%s'", link->ifname);
237 link_enter_set_routes(link);
243 static int link_enter_set_addresses(Link *link) {
248 assert(link->network);
249 assert(link->state != _LINK_STATE_INVALID);
251 link->state = LINK_STATE_SETTING_ADDRESSES;
253 if (!link->network->static_addresses && !link->dhcp_address)
254 return link_enter_set_routes(link);
256 LIST_FOREACH(static_addresses, address, link->network->static_addresses) {
257 r = address_configure(address, link, &address_handler);
259 log_warning("Could not set addresses for link '%s'", link->ifname);
260 link_enter_failed(link);
264 link->addr_messages ++;
267 if (link->dhcp_address) {
268 r = address_configure(link->dhcp_address, link, &address_handler);
270 log_warning("Could not set addresses for link '%s'", link->ifname);
271 link_enter_failed(link);
275 link->addr_messages ++;
281 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
282 Link *link = userdata;
285 r = sd_rtnl_message_get_errno(m);
287 log_warning("Could not bring up interface '%s': %s",
288 link->ifname, strerror(-r));
289 link_enter_failed(link);
295 static int link_up(Link *link) {
296 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
300 assert(link->manager);
301 assert(link->manager->rtnl);
303 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
305 log_error("Could not allocate RTM_SETLINK message");
309 r = sd_rtnl_message_link_set_flags(req, IFF_UP);
311 log_error("Could not set link flags");
315 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
317 log_error("Could not send rtnetlink message: %s", strerror(-r));
324 static int link_bridge_joined(Link *link) {
328 assert(link->state == LINK_STATE_JOINING_BRIDGE);
329 assert(link->network);
333 link_enter_failed(link);
337 if (!link->network->dhcp) {
338 r = link_enter_set_addresses(link);
340 link_enter_failed(link);
347 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
348 Link *link = userdata;
351 assert(link->state == LINK_STATE_JOINING_BRIDGE || link->state == LINK_STATE_FAILED);
352 assert(link->network);
354 if (link->state == LINK_STATE_FAILED)
357 r = sd_rtnl_message_get_errno(m);
359 log_warning("Could not join interface '%s' to bridge '%s': %s",
360 link->ifname, link->network->bridge->name, strerror(-r));
361 link_enter_failed(link);
364 log_info("Join interface '%s' to bridge: %s",
365 link->ifname, link->network->bridge->name);
367 link_bridge_joined(link);
372 static int link_enter_join_bridge(Link *link) {
376 assert(link->network);
377 assert(link->state == _LINK_STATE_INVALID);
379 link->state = LINK_STATE_JOINING_BRIDGE;
381 if (!link->network->bridge)
382 return link_bridge_joined(link);
384 r = bridge_join(link->network->bridge, link, &bridge_handler);
386 log_warning("Could not join link '%s' to bridge '%s'", link->ifname,
387 link->network->bridge->name);
388 link_enter_failed(link);
395 static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
396 Link *link = userdata;
399 r = sd_rtnl_message_get_errno(m);
401 log_warning("Could not get state of interface '%s': %s",
402 link->ifname, strerror(-r));
403 link_enter_failed(link);
406 link_update(link, m);
411 static int link_get(Link *link) {
412 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
416 assert(link->manager);
417 assert(link->manager->rtnl);
419 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
421 log_error("Could not allocate RTM_GETLINK message");
425 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
427 log_error("Could not send rtnetlink message: %s", strerror(-r));
434 int link_configure(Link *link) {
438 assert(link->network);
439 assert(link->state == _LINK_STATE_INVALID);
443 link_enter_failed(link);
447 r = link_enter_join_bridge(link);
454 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
455 Link *link = userdata;
460 assert(link->ifname);
462 if (link->state == LINK_STATE_FAILED)
465 r = sd_rtnl_message_get_errno(m);
466 if (r < 0 && r != -EEXIST)
467 log_warning("Could not drop address from interface '%s': %s",
468 link->ifname, strerror(-r));
473 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
474 Link *link = userdata;
475 struct in_addr address;
476 struct in_addr netmask;
477 struct in_addr gateway;
481 if (link->state == LINK_STATE_FAILED)
485 log_warning("DHCP error: %s", strerror(-event));
486 link_enter_failed(link);
490 if (event == DHCP_EVENT_NO_LEASE)
491 log_info("IP address in use.");
493 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_EXPIRED ||
494 event == DHCP_EVENT_STOP) {
495 address_drop(link->dhcp_address, link, address_drop_handler);
497 address_free(link->dhcp_address);
498 link->dhcp_address = NULL;
500 route_free(link->dhcp_route);
501 link->dhcp_route = NULL;
504 r = sd_dhcp_client_get_address(client, &address);
506 log_warning("DHCP error: no address");
507 link_enter_failed(link);
511 r = sd_dhcp_client_get_netmask(client, &netmask);
513 log_warning("DHCP error: no netmask");
514 link_enter_failed(link);
518 prefixlen = sd_dhcp_client_prefixlen(&netmask);
520 log_warning("DHCP error: no prefixlen");
521 link_enter_failed(link);
525 r = sd_dhcp_client_get_router(client, &gateway);
527 log_warning("DHCP error: no router");
528 link_enter_failed(link);
532 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_IP_ACQUIRE) {
533 _cleanup_address_free_ Address *addr = NULL;
534 _cleanup_route_free_ Route *rt = NULL;
536 log_info("Received config over DHCPv4");
538 r = address_new_dynamic(&addr);
540 log_error("Could not allocate address");
541 link_enter_failed(link);
545 addr->family = AF_INET;
546 addr->in_addr.in = address;
547 addr->prefixlen = prefixlen;
548 addr->netmask = netmask;
550 r = route_new_dynamic(&rt);
552 log_error("Could not allocate route");
553 link_enter_failed(link);
557 rt->family = AF_INET;
558 rt->in_addr.in = gateway;
560 link->dhcp_address = addr;
561 link->dhcp_route = rt;
565 link_enter_set_addresses(link);
571 static int link_acquire_conf(Link *link) {
575 assert(link->network);
576 assert(link->network->dhcp);
577 assert(link->manager);
578 assert(link->manager->event);
581 link->dhcp = sd_dhcp_client_new(link->manager->event);
585 r = sd_dhcp_client_set_index(link->dhcp, link->ifindex);
589 r = sd_dhcp_client_set_mac(link->dhcp, &link->mac);
593 r = sd_dhcp_client_set_callback(link->dhcp, dhcp_handler, link);
598 r = sd_dhcp_client_start(link->dhcp);
605 int link_update(Link *link, sd_rtnl_message *m) {
612 r = sd_rtnl_message_link_get_flags(m, &flags);
614 log_warning("Could not get link flags of '%s'", link->ifname);
618 if (link->flags & IFF_UP && !(flags & IFF_UP))
619 log_info("Interface '%s' is down", link->ifname);
620 else if (!(link->flags & IFF_UP) && flags & IFF_UP)
621 log_info("Interface '%s' is up", link->ifname);
623 if (link->flags & IFF_LOWER_UP && !(flags & IFF_LOWER_UP)) {
624 log_info("Interface '%s' is disconnected", link->ifname);
626 if (link->network->dhcp) {
627 r = sd_dhcp_client_stop(link->dhcp);
629 link_enter_failed(link);
633 } else if (!(link->flags & IFF_LOWER_UP) && flags & IFF_LOWER_UP) {
634 log_info("Interface '%s' is connected", link->ifname);
636 if (link->network && link->network->dhcp) {
637 r = link_acquire_conf(link);
639 link_enter_failed(link);