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);
409 static int link_get(Link *link) {
410 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
414 assert(link->manager);
415 assert(link->manager->rtnl);
417 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
419 log_error("Could not allocate RTM_GETLINK message");
423 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
425 log_error("Could not send rtnetlink message: %s", strerror(-r));
432 int link_configure(Link *link) {
436 assert(link->network);
437 assert(link->state == _LINK_STATE_INVALID);
441 link_enter_failed(link);
445 r = link_enter_join_bridge(link);
452 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
453 Link *link = userdata;
458 assert(link->ifname);
460 if (link->state == LINK_STATE_FAILED)
463 r = sd_rtnl_message_get_errno(m);
464 if (r < 0 && r != -EEXIST)
465 log_warning("Could not drop address from interface '%s': %s",
466 link->ifname, strerror(-r));
471 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
472 Link *link = userdata;
473 struct in_addr address;
474 struct in_addr netmask;
475 struct in_addr gateway;
479 if (link->state == LINK_STATE_FAILED)
483 log_warning("DHCP error: %s", strerror(-event));
484 link_enter_failed(link);
488 if (event == DHCP_EVENT_NO_LEASE)
489 log_info("IP address in use.");
491 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_EXPIRED ||
492 event == DHCP_EVENT_STOP) {
493 address_drop(link->dhcp_address, link, address_drop_handler);
495 address_free(link->dhcp_address);
496 link->dhcp_address = NULL;
498 route_free(link->dhcp_route);
499 link->dhcp_route = NULL;
502 r = sd_dhcp_client_get_address(client, &address);
504 log_warning("DHCP error: no address");
505 link_enter_failed(link);
509 r = sd_dhcp_client_get_netmask(client, &netmask);
511 log_warning("DHCP error: no netmask");
512 link_enter_failed(link);
516 prefixlen = sd_dhcp_client_prefixlen(&netmask);
518 log_warning("DHCP error: no prefixlen");
519 link_enter_failed(link);
523 r = sd_dhcp_client_get_router(client, &gateway);
525 log_warning("DHCP error: no router");
526 link_enter_failed(link);
530 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_IP_ACQUIRE) {
531 _cleanup_address_free_ Address *addr = NULL;
532 _cleanup_route_free_ Route *rt = NULL;
534 log_info("Received config over DHCPv4");
536 r = address_new_dynamic(&addr);
538 log_error("Could not allocate address");
539 link_enter_failed(link);
543 addr->family = AF_INET;
544 addr->in_addr.in = address;
545 addr->prefixlen = prefixlen;
546 addr->netmask = netmask;
548 r = route_new_dynamic(&rt);
550 log_error("Could not allocate route");
551 link_enter_failed(link);
555 rt->family = AF_INET;
556 rt->in_addr.in = gateway;
558 link->dhcp_address = addr;
559 link->dhcp_route = rt;
563 link_enter_set_addresses(link);
569 static int link_acquire_conf(Link *link) {
573 assert(link->network);
574 assert(link->network->dhcp);
575 assert(link->manager);
576 assert(link->manager->event);
579 link->dhcp = sd_dhcp_client_new(link->manager->event);
583 r = sd_dhcp_client_set_index(link->dhcp, link->ifindex);
587 r = sd_dhcp_client_set_mac(link->dhcp, &link->mac);
591 r = sd_dhcp_client_set_callback(link->dhcp, dhcp_handler, link);
596 r = sd_dhcp_client_start(link->dhcp);
603 int link_update(Link *link, sd_rtnl_message *m) {
610 r = sd_rtnl_message_link_get_flags(m, &flags);
612 log_warning("Could not get link flags of '%s'", link->ifname);
616 if (link->flags & IFF_UP && !(flags & IFF_UP))
617 log_info("Interface '%s' is down", link->ifname);
618 else if (!(link->flags & IFF_UP) && flags & IFF_UP)
619 log_info("Interface '%s' is up", link->ifname);
621 if (link->flags & IFF_LOWER_UP && !(flags & IFF_LOWER_UP)) {
622 log_info("Interface '%s' is disconnected", link->ifname);
624 if (link->network->dhcp) {
625 r = sd_dhcp_client_stop(link->dhcp);
627 link_enter_failed(link);
631 } else if (!(link->flags & IFF_LOWER_UP) && flags & IFF_LOWER_UP) {
632 log_info("Interface '%s' is connected", link->ifname);
634 if (link->network->dhcp) {
635 r = link_acquire_conf(link);
637 link_enter_failed(link);