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