chiark / gitweb /
sd-dhcp-client: split sd_dhcp_lease from sd_dhcp_client
[elogind.git] / src / network / networkd-link.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Tom Gundersen <teg@jklm.no>
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <netinet/ether.h>
23 #include <linux/if.h>
24
25 #include "networkd.h"
26 #include "libudev-private.h"
27 #include "util.h"
28 #include "bus-util.h"
29 #include "net-util.h"
30
31 int link_new(Manager *manager, struct udev_device *device, Link **ret) {
32         _cleanup_link_free_ Link *link = NULL;
33         const char *mac;
34         struct ether_addr *mac_addr;
35         const char *ifname;
36         int r;
37
38         assert(device);
39         assert(ret);
40
41         link = new0(Link, 1);
42         if (!link)
43                 return -ENOMEM;
44
45         link->manager = manager;
46         link->state = _LINK_STATE_INVALID;
47
48         link->ifindex = udev_device_get_ifindex(device);
49         if (link->ifindex <= 0)
50                 return -EINVAL;
51
52         mac = udev_device_get_sysattr_value(device, "address");
53         if (mac) {
54                 mac_addr = ether_aton(mac);
55                 if (mac_addr)
56                         memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
57         }
58
59         ifname = udev_device_get_sysname(device);
60         link->ifname = strdup(ifname);
61
62         r = hashmap_put(manager->links, &link->ifindex, link);
63         if (r < 0)
64                 return r;
65
66         *ret = link;
67         link = NULL;
68
69         return 0;
70 }
71
72 void link_free(Link *link) {
73         if (!link)
74                 return;
75
76         assert(link->manager);
77
78         sd_dhcp_client_free(link->dhcp_client);
79         sd_dhcp_lease_unref(link->dhcp_lease);
80
81         hashmap_remove(link->manager->links, &link->ifindex);
82
83         free(link->ifname);
84
85         free(link);
86 }
87
88 int link_add(Manager *m, struct udev_device *device, Link **ret) {
89         Link *link;
90         Network *network;
91         int r;
92         uint64_t ifindex;
93
94         assert(m);
95         assert(device);
96
97         ifindex = udev_device_get_ifindex(device);
98         link = hashmap_get(m->links, &ifindex);
99         if (link) {
100                 *ret = link;
101                 return -EEXIST;
102         }
103
104         r = link_new(m, device, &link);
105         if (r < 0)
106                 return r;
107
108         *ret = link;
109
110         r = network_get(m, device, &network);
111         if (r < 0)
112                 return r == -ENOENT ? 0 : r;
113
114         r = network_apply(m, network, link);
115         if (r < 0)
116                 return r;
117
118         return 0;
119 }
120
121 static int link_enter_configured(Link *link) {
122         assert(link);
123         assert(link->state == LINK_STATE_SETTING_ROUTES);
124
125         log_info_link(link, "link configured");
126
127         link->state = LINK_STATE_CONFIGURED;
128
129         return 0;
130 }
131
132 static void link_enter_failed(Link *link) {
133         assert(link);
134
135         log_warning_link(link, "failed");
136
137         link->state = LINK_STATE_FAILED;
138 }
139
140 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
141         Link *link = userdata;
142         int r;
143
144         assert(link->route_messages > 0);
145         assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
146                link->state == LINK_STATE_SETTING_ROUTES ||
147                link->state == LINK_STATE_FAILED);
148
149         link->route_messages --;
150
151         if (link->state == LINK_STATE_FAILED)
152                 return 1;
153
154         r = sd_rtnl_message_get_errno(m);
155         if (r < 0 && r != -EEXIST)
156                 log_struct_link(LOG_WARNING, link,
157                                 "MESSAGE=%s: could not set route: %s",
158                                 link->ifname, strerror(-r),
159                                 "ERRNO=%d", -r,
160                                 NULL);
161
162         /* we might have received an old reply after moving back to SETTING_ADDRESSES,
163          * ignore it */
164         if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
165                 log_debug_link(link, "routes set");
166                 link_enter_configured(link);
167         }
168
169         return 1;
170 }
171
172 static int link_enter_set_routes(Link *link) {
173         Route *rt;
174         int r;
175
176         assert(link);
177         assert(link->network);
178         assert(link->state == LINK_STATE_SETTING_ADDRESSES);
179
180         link->state = LINK_STATE_SETTING_ROUTES;
181
182         if (!link->network->static_routes && !link->dhcp_lease)
183                 return link_enter_configured(link);
184
185         log_debug_link(link, "setting routes");
186
187         LIST_FOREACH(static_routes, rt, link->network->static_routes) {
188                 r = route_configure(rt, link, &route_handler);
189                 if (r < 0) {
190                         log_warning_link(link,
191                                          "could not set routes: %s", strerror(-r));
192                         link_enter_failed(link);
193                         return r;
194                 }
195
196                 link->route_messages ++;
197         }
198
199         if (link->dhcp_lease) {
200                 _cleanup_route_free_ Route *route = NULL;
201                 struct in_addr gateway;
202
203                 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
204                 if (r < 0) {
205                         log_warning_link(link, "DHCP error: no router: %s",
206                                          strerror(-r));
207                         return r;
208                 }
209
210                 r = route_new_dynamic(&route);
211                 if (r < 0) {
212                         log_error_link(link, "Could not allocate route: %s",
213                                        strerror(-r));
214                         return r;
215                 }
216
217                 route->family = AF_INET;
218                 route->in_addr.in = gateway;
219
220                 r = route_configure(route, link, &route_handler);
221                 if (r < 0) {
222                         log_warning_link(link,
223                                          "could not set routes: %s", strerror(-r));
224                         link_enter_failed(link);
225                         return r;
226                 }
227
228                 link->route_messages ++;
229         }
230
231         return 0;
232 }
233
234 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
235         Link *link = userdata;
236         int r;
237
238         assert(m);
239         assert(link);
240         assert(link->ifname);
241         assert(link->addr_messages > 0);
242         assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
243
244         link->addr_messages --;
245
246         if (link->state == LINK_STATE_FAILED)
247                 return 1;
248
249         r = sd_rtnl_message_get_errno(m);
250         if (r < 0 && r != -EEXIST)
251                 log_struct_link(LOG_WARNING, link,
252                                 "MESSAGE=%s: could not set address: %s",
253                                 link->ifname, strerror(-r),
254                                 "ERRNO=%d", -r,
255                                 NULL);
256
257         if (link->addr_messages == 0) {
258                 log_debug_link(link, "addresses set");
259                 link_enter_set_routes(link);
260         }
261
262         return 1;
263 }
264
265 static int link_enter_set_addresses(Link *link) {
266         Address *ad;
267         int r;
268
269         assert(link);
270         assert(link->network);
271         assert(link->state != _LINK_STATE_INVALID);
272
273         link->state = LINK_STATE_SETTING_ADDRESSES;
274
275         if (!link->network->static_addresses && !link->dhcp_lease)
276                 return link_enter_set_routes(link);
277
278         log_debug_link(link, "setting addresses");
279
280         LIST_FOREACH(static_addresses, ad, link->network->static_addresses) {
281                 r = address_configure(ad, link, &address_handler);
282                 if (r < 0) {
283                         log_warning_link(link,
284                                          "could not set addresses: %s", strerror(-r));
285                         link_enter_failed(link);
286                         return r;
287                 }
288
289                 link->addr_messages ++;
290         }
291
292         if (link->dhcp_lease) {
293                 _cleanup_address_free_ Address *address = NULL;
294                 struct in_addr addr;
295                 struct in_addr netmask;
296                 unsigned prefixlen;
297
298                 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
299                 if (r < 0) {
300                         log_warning_link(link, "DHCP error: no address: %s",
301                                          strerror(-r));
302                         return r;
303                 }
304
305                 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
306                 if (r < 0) {
307                         log_warning_link(link, "DHCP error: no netmask: %s",
308                                          strerror(-r));
309                         return r;
310                 }
311
312                 prefixlen = net_netmask_to_prefixlen(&netmask);
313
314                 r = address_new_dynamic(&address);
315                 if (r < 0) {
316                         log_error_link(link, "Could not allocate address: %s",
317                                        strerror(-r));
318                         return r;
319                 }
320
321                 address->family = AF_INET;
322                 address->in_addr.in = addr;
323                 address->prefixlen = prefixlen;
324                 address->broadcast.s_addr = addr.s_addr | ~netmask.s_addr;
325
326                 r = address_configure(address, link, &address_handler);
327                 if (r < 0) {
328                         log_warning_link(link,
329                                          "could not set addresses: %s", strerror(-r));
330                         link_enter_failed(link);
331                         return r;
332                 }
333
334                 link->addr_messages ++;
335         }
336
337         return 0;
338 }
339
340 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
341         Link *link = userdata;
342         int r;
343
344         assert(m);
345         assert(link);
346         assert(link->ifname);
347
348         if (link->state == LINK_STATE_FAILED)
349                 return 1;
350
351         r = sd_rtnl_message_get_errno(m);
352         if (r < 0 && r != -ENOENT)
353                 log_struct_link(LOG_WARNING, link,
354                                 "MESSAGE=%s: could not drop address: %s",
355                                 link->ifname, strerror(-r),
356                                 "ERRNO=%d", -r,
357                                 NULL);
358
359         return 1;
360 }
361
362 static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
363         int r;
364
365         r = sd_bus_message_get_errno(m);
366         if (r < 0)
367                 log_warning("Could not set hostname: %s", strerror(-r));
368
369         return 1;
370 }
371
372 static int set_hostname(sd_bus *bus, const char *hostname) {
373         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
374         int r = 0;
375
376         assert(hostname);
377
378         log_debug("Setting transient hostname: '%s'", hostname);
379
380         if (!bus) { /* TODO: replace by assert when we can rely on kdbus */
381                 log_info("Not connected to system bus, ignoring transient hostname.");
382                 return 0;
383         }
384
385         r = sd_bus_message_new_method_call(
386                         bus,
387                         "org.freedesktop.hostname1",
388                         "/org/freedesktop/hostname1",
389                         "org.freedesktop.hostname1",
390                         "SetHostname",
391                         &m);
392         if (r < 0)
393                 return r;
394
395         r = sd_bus_message_append(m, "sb", hostname, false);
396         if (r < 0)
397                 return r;
398
399         r = sd_bus_call_async(bus, m, set_hostname_handler, NULL, 0, NULL);
400         if (r < 0)
401                 log_error("Could not set transient hostname: %s", strerror(-r));
402
403         return r;
404 }
405
406 static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
407         Link *link = userdata;
408         int r;
409
410         assert(m);
411         assert(link);
412         assert(link->ifname);
413
414         if (link->state == LINK_STATE_FAILED)
415                 return 1;
416
417         r = sd_rtnl_message_get_errno(m);
418         if (r < 0)
419                 log_struct_link(LOG_WARNING, link,
420                                 "MESSAGE=%s: could not set MTU: %s",
421                                 link->ifname, strerror(-r),
422                                 "ERRNO=%d", -r,
423                                 NULL);
424
425         return 1;
426 }
427
428 static int link_set_mtu(Link *link, uint32_t mtu) {
429         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
430         int r;
431
432         assert(link);
433         assert(link->manager);
434         assert(link->manager->rtnl);
435
436         log_debug_link(link, "setting MTU: %" PRIu32, mtu);
437
438         r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
439         if (r < 0) {
440                 log_error_link(link, "Could not allocate RTM_SETLINK message");
441                 return r;
442         }
443
444         r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
445         if (r < 0) {
446                 log_error_link(link, "Could not append MTU: %s", strerror(-r));
447                 return r;
448         }
449
450         r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
451         if (r < 0) {
452                 log_error_link(link,
453                                "Could not send rtnetlink message: %s", strerror(-r));
454                 return r;
455         }
456
457         return 0;
458 }
459
460 static int dhcp_lease_lost(Link *link) {
461         _cleanup_address_free_ Address *address = NULL;
462         struct in_addr addr;
463         struct in_addr netmask;
464         unsigned prefixlen;
465         int r;
466
467         assert(link);
468         assert(link->dhcp_lease);
469
470         r = address_new_dynamic(&address);
471         if (r >= 0) {
472                 sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
473                 sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
474                 prefixlen = net_netmask_to_prefixlen(&netmask);
475
476                 address->family = AF_INET;
477                 address->in_addr.in = addr;
478                 address->prefixlen = prefixlen;
479
480                 address_drop(address, link, address_drop_handler);
481         }
482
483         if (link->network->dhcp_mtu) {
484                 uint16_t mtu;
485
486                 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
487                 if (r >= 0 && link->original_mtu != mtu) {
488                         r = link_set_mtu(link, link->original_mtu);
489                         if (r < 0) {
490                                 log_warning_link(link, "DHCP error: could not reset MTU");
491                                 link_enter_failed(link);
492                                 return r;
493                         }
494                 }
495         }
496
497         if (link->network->dhcp_hostname) {
498                 r = set_hostname(link->manager->bus, "");
499                 if (r < 0)
500                         log_error("Failed to reset transient hostname");
501         }
502
503         link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
504
505         return 0;
506 }
507
508 static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
509         sd_dhcp_lease *lease;
510         struct in_addr address;
511         struct in_addr netmask;
512         struct in_addr gateway;
513         unsigned prefixlen;
514         _cleanup_address_free_ Address *addr = NULL;
515         _cleanup_route_free_ Route *rt = NULL;
516         struct in_addr *nameservers;
517         size_t nameservers_size;
518         int r;
519
520         assert(client);
521         assert(link);
522
523         r = sd_dhcp_client_get_lease(client, &lease);
524         if (r < 0) {
525                 log_warning_link(link, "DHCP error: no lease: %s",
526                                  strerror(-r));
527                 return r;
528         }
529
530         r = sd_dhcp_lease_get_address(lease, &address);
531         if (r < 0) {
532                 log_warning_link(link, "DHCP error: no address: %s",
533                                  strerror(-r));
534                 return r;
535         }
536
537         r = sd_dhcp_lease_get_netmask(lease, &netmask);
538         if (r < 0) {
539                 log_warning_link(link, "DHCP error: no netmask: %s",
540                                  strerror(-r));
541                 return r;
542         }
543
544         prefixlen = net_netmask_to_prefixlen(&netmask);
545
546         r = sd_dhcp_lease_get_router(lease, &gateway);
547         if (r < 0) {
548                 log_warning_link(link, "DHCP error: no router: %s",
549                                  strerror(-r));
550                 return r;
551         }
552
553         log_struct_link(LOG_INFO, link,
554                         "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
555                          link->ifname,
556                          ADDRESS_FMT_VAL(address),
557                          prefixlen,
558                          ADDRESS_FMT_VAL(gateway),
559                          "ADDRESS=%u.%u.%u.%u",
560                          ADDRESS_FMT_VAL(address),
561                          "PREFIXLEN=%u",
562                          prefixlen,
563                          "GATEWAY=%u.%u.%u.%u",
564                          ADDRESS_FMT_VAL(gateway),
565                          NULL);
566
567         if (link->network->dhcp_dns) {
568                 r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
569                 if (r >= 0) {
570                         r = manager_update_resolv_conf(link->manager);
571                         if (r < 0)
572                                 log_error("Failed to update resolv.conf");
573                 }
574         }
575
576         if (link->network->dhcp_mtu) {
577                 uint16_t mtu;
578
579                 r = sd_dhcp_lease_get_mtu(lease, &mtu);
580                 if (r >= 0) {
581                         r = link_set_mtu(link, mtu);
582                         if (r < 0)
583                                 log_error_link(link, "Failed to set MTU "
584                                                "to %" PRIu16, mtu);
585                 }
586         }
587
588         if (link->network->dhcp_hostname) {
589                 const char *hostname;
590
591                 r = sd_dhcp_lease_get_hostname(lease, &hostname);
592                 if (r >= 0) {
593                         r = set_hostname(link->manager->bus, hostname);
594                         if (r < 0)
595                                 log_error("Failed to set transient hostname "
596                                           "to '%s'", hostname);
597                 }
598         }
599
600         link->dhcp_lease = lease;
601
602         link_enter_set_addresses(link);
603
604         return 0;
605 }
606
607 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
608         Link *link = userdata;
609         int r;
610
611         assert(link);
612         assert(link->network);
613         assert(link->manager);
614
615         if (link->state == LINK_STATE_FAILED)
616                 return;
617
618         switch (event) {
619                 case DHCP_EVENT_NO_LEASE:
620                         log_debug_link(link, "IP address in use.");
621                         break;
622                 case DHCP_EVENT_EXPIRED:
623                 case DHCP_EVENT_STOP:
624                 case DHCP_EVENT_IP_CHANGE:
625                         if (link->network->dhcp_critical) {
626                                 log_error_link(link, "DHCPv4 connection considered system critical, "
627                                                "ignoring request to reconfigure it.");
628                                 return;
629                         }
630
631                         r = dhcp_lease_lost(link);
632                         if (r < 0) {
633                                 link_enter_failed(link);
634                                 return;
635                         }
636
637                         if (event == DHCP_EVENT_IP_CHANGE) {
638                                 r = dhcp_lease_acquired(client, link);
639                                 if (r < 0) {
640                                         link_enter_failed(link);
641                                         return;
642                                 }
643                         }
644
645                         break;
646                 case DHCP_EVENT_IP_ACQUIRE:
647                         r = dhcp_lease_acquired(client, link);
648                         if (r < 0) {
649                                 link_enter_failed(link);
650                                 return;
651                         }
652                         break;
653                 default:
654                         if (event < 0)
655                                 log_warning_link(link, "DHCP error: %s", strerror(-event));
656                         else
657                                 log_warning_link(link, "DHCP unknown event: %d", event);
658                         break;
659         }
660
661         return;
662 }
663
664 static int link_acquire_conf(Link *link) {
665         int r;
666
667         assert(link);
668         assert(link->network);
669         assert(link->network->dhcp);
670         assert(link->manager);
671         assert(link->manager->event);
672
673         if (!link->dhcp_client) {
674                 r = sd_dhcp_client_new(&link->dhcp_client);
675                 if (r < 0)
676                         return r;
677
678                 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
679                 if (r < 0)
680                         return r;
681
682                 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
683                 if (r < 0)
684                         return r;
685
686                 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
687                 if (r < 0)
688                         return r;
689
690                 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link);
691                 if (r < 0)
692                         return r;
693
694                 if (link->network->dhcp_mtu) {
695                         r = sd_dhcp_client_set_request_option(link->dhcp_client, 26);
696                         if (r < 0)
697                                 return r;
698                 }
699         }
700
701         log_debug_link(link, "acquiring DHCPv4 lease");
702
703         r = sd_dhcp_client_start(link->dhcp_client);
704         if (r < 0)
705                 return r;
706
707         return 0;
708 }
709
710 static int link_update_flags(Link *link, unsigned flags) {
711         int r;
712
713         assert(link);
714         assert(link->network);
715
716         if (link->state == LINK_STATE_FAILED)
717                 return 0;
718
719         if (link->flags == flags) {
720                 log_debug_link(link, "link status unchanged: %#.8x", flags);
721                 return 0;
722         }
723
724         if ((link->flags & IFF_UP) != (flags & IFF_UP))
725                 log_info_link(link,
726                               "link is %s", flags & IFF_UP ? "up": "down");
727
728         if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
729                 if (flags & IFF_LOWER_UP) {
730                         log_info_link(link, "carrier on");
731
732                         if (link->network->dhcp) {
733                                 r = link_acquire_conf(link);
734                                 if (r < 0) {
735                                         log_warning_link(link, "Could not acquire DHCPv4 lease: %s", strerror(-r));
736                                         link_enter_failed(link);
737                                         return r;
738                                 }
739                         }
740                 } else {
741                         log_info_link(link, "carrier off");
742
743                         if (link->network->dhcp) {
744                                 r = sd_dhcp_client_stop(link->dhcp_client);
745                                 if (r < 0) {
746                                         log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
747                                         link_enter_failed(link);
748                                         return r;
749                                 }
750                         }
751                 }
752         }
753
754         log_debug_link(link,
755                        "link status updated: %#.8x -> %#.8x", link->flags, flags);
756
757         link->flags = flags;
758
759         return 0;
760 }
761
762 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
763         Link *link = userdata;
764         int r;
765
766         assert(link);
767
768         if (link->state == LINK_STATE_FAILED)
769                 return 1;
770
771         r = sd_rtnl_message_get_errno(m);
772         if (r < 0) {
773                 log_struct_link(LOG_ERR, link,
774                                 "MESSAGE=%s: could not bring up interface: %s",
775                                 link->ifname, strerror(-r),
776                                 "ERRNO=%d", -r,
777                                 NULL);
778                 link_enter_failed(link);
779                 return 1;
780         }
781
782         link_update_flags(link, link->flags | IFF_UP);
783
784         return 1;
785 }
786
787 static int link_up(Link *link) {
788         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
789         int r;
790
791         assert(link);
792         assert(link->manager);
793         assert(link->manager->rtnl);
794
795         log_debug_link(link, "bringing link up");
796
797         r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
798         if (r < 0) {
799                 log_error_link(link, "Could not allocate RTM_SETLINK message");
800                 return r;
801         }
802
803         r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
804         if (r < 0) {
805                 log_error_link(link, "Could not set link flags: %s", strerror(-r));
806                 return r;
807         }
808
809         r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
810         if (r < 0) {
811                 log_error_link(link,
812                                "Could not send rtnetlink message: %s", strerror(-r));
813                 return r;
814         }
815
816         return 0;
817 }
818
819 static int link_enslaved(Link *link) {
820         int r;
821
822         assert(link);
823         assert(link->state == LINK_STATE_ENSLAVING);
824         assert(link->network);
825
826         r = link_up(link);
827         if (r < 0) {
828                 link_enter_failed(link);
829                 return r;
830         }
831
832         if (!link->network->dhcp)
833                 return link_enter_set_addresses(link);
834
835         return 0;
836 }
837
838 static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
839         Link *link = userdata;
840         int r;
841
842         assert(link);
843         assert(link->state == LINK_STATE_ENSLAVING || link->state == LINK_STATE_FAILED);
844         assert(link->network);
845
846         link->enslaving --;
847
848         if (link->state == LINK_STATE_FAILED)
849                 return 1;
850
851         r = sd_rtnl_message_get_errno(m);
852         if (r < 0) {
853                 log_struct_link(LOG_ERR, link,
854                                 "MESSAGE=%s: could not enslave: %s",
855                                 link->ifname, strerror(-r),
856                                 "ERRNO=%d", -r,
857                                 NULL);
858                 link_enter_failed(link);
859                 return 1;
860         }
861
862         log_debug_link(link, "enslaved");
863
864         if (link->enslaving == 0)
865                 link_enslaved(link);
866
867         return 1;
868 }
869
870 static int link_enter_enslave(Link *link) {
871         int r;
872
873         assert(link);
874         assert(link->network);
875         assert(link->state == _LINK_STATE_INVALID);
876
877         link->state = LINK_STATE_ENSLAVING;
878
879         if (!link->network->bridge && !link->network->bond && !link->network->vlan)
880                 return link_enslaved(link);
881
882         if (link->network->bridge) {
883                 log_struct_link(LOG_DEBUG, link,
884                                 "MESSAGE=%s: enslaving by '%s'",
885                                 link->ifname, link->network->bridge->name,
886                                 NETDEV(link->network->bridge),
887                                 NULL);
888
889                 r = netdev_enslave(link->network->bridge, link, &enslave_handler);
890                 if (r < 0) {
891                         log_struct_link(LOG_WARNING, link,
892                                         "MESSAGE=%s: could not enslave by '%s': %s",
893                                         link->ifname, link->network->bridge->name, strerror(-r),
894                                         NETDEV(link->network->bridge),
895                                         NULL);
896                         link_enter_failed(link);
897                         return r;
898                 }
899
900                 link->enslaving ++;
901         }
902
903         if (link->network->vlan) {
904                 log_struct_link(LOG_DEBUG, link,
905                                 "MESSAGE=%s: enslaving by '%s'",
906                                 link->ifname, link->network->vlan->name,
907                                 NETDEV(link->network->vlan),
908                                 NULL);
909
910                 r = netdev_enslave(link->network->vlan, link, &enslave_handler);
911                 if (r < 0) {
912                         log_struct_link(LOG_WARNING, link,
913                                         "MESSAGE=%s: could not enslave by '%s': %s",
914                                         link->ifname, link->network->vlan->name,
915                                         strerror(-r), NETDEV(link->network->vlan),
916                                         NULL);
917                         link_enter_failed(link);
918                         return r;
919                 }
920
921                 link->enslaving ++;
922         }
923
924         return 0;
925 }
926
927 static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
928         Link *link = userdata;
929         int r;
930
931         assert(link);
932
933         if (link->state == LINK_STATE_FAILED)
934                 return 1;
935
936         r = sd_rtnl_message_get_errno(m);
937         if (r < 0) {
938                 log_struct_link(LOG_ERR, link,
939                                 "MESSAGE=%s: could not get state: %s",
940                                 link->ifname, strerror(-r),
941                                 "ERRNO=%d", -r,
942                                 NULL);
943                 link_enter_failed(link);
944                 return 1;
945         }
946
947         log_debug_link(link, "got link state");
948
949         link_update(link, m);
950
951         return 1;
952 }
953
954 static int link_get(Link *link) {
955         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
956         int r;
957
958         assert(link);
959         assert(link->manager);
960         assert(link->manager->rtnl);
961
962         log_debug_link(link, "requesting link status");
963
964         r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
965         if (r < 0) {
966                 log_error_link(link, "Could not allocate RTM_GETLINK message");
967                 return r;
968         }
969
970         r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
971         if (r < 0) {
972                 log_error_link(link,
973                                "Could not send rtnetlink message: %s", strerror(-r));
974                 return r;
975         }
976
977         return 0;
978 }
979
980 int link_configure(Link *link) {
981         int r;
982
983         assert(link);
984         assert(link->network);
985         assert(link->state == _LINK_STATE_INVALID);
986
987         r = link_get(link);
988         if (r < 0) {
989                 link_enter_failed(link);
990                 return r;
991         }
992
993         return link_enter_enslave(link);
994 }
995
996 int link_update(Link *link, sd_rtnl_message *m) {
997         unsigned flags;
998         void *data;
999         uint16_t type;
1000         int r;
1001
1002         assert(link);
1003         assert(m);
1004
1005         if (link->state == LINK_STATE_FAILED)
1006                 return 0;
1007
1008         r = sd_rtnl_message_link_get_flags(m, &flags);
1009         if (r < 0) {
1010                 log_warning_link(link, "Could not get link flags");
1011                 return r;
1012         }
1013
1014         while (sd_rtnl_message_read(m, &type, &data) > 0) {
1015                 if (type == IFLA_MTU && link->network->dhcp &&
1016                     link->network->dhcp_mtu && !link->original_mtu) {
1017                         link->original_mtu = *(uint16_t *) data;
1018                         log_debug_link(link, "saved original MTU: %" PRIu16,
1019                                        link->original_mtu);
1020                 }
1021         }
1022
1023         return link_update_flags(link, flags);
1024 }