+ if (link->state == LINK_STATE_FAILED)
+ return 0;
+
+ if (link->flags == flags) {
+ log_debug_link(link, "link status unchanged: %#.8x", flags);
+ return 0;
+ }
+
+ if ((link->flags & IFF_UP) != (flags & IFF_UP))
+ log_info_link(link,
+ "link is %s", flags & IFF_UP ? "up": "down");
+
+ if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
+ if (flags & IFF_LOWER_UP) {
+ log_info_link(link, "carrier on");
+
+ if (link->network->dhcp) {
+ r = link_acquire_conf(link);
+ if (r < 0) {
+ log_warning_link(link, "Could not acquire DHCPv4 lease: %s", strerror(-r));
+ link_enter_failed(link);
+ return r;
+ }
+ }
+ } else {
+ log_info_link(link, "carrier off");
+
+ if (link->network->dhcp) {
+ r = sd_dhcp_client_stop(link->dhcp);
+ if (r < 0) {
+ log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
+ link_enter_failed(link);
+ return r;
+ }
+ }
+ }
+ }
+
+ log_debug_link(link,
+ "link status updated: %#.8x -> %#.8x", link->flags, flags);
+
+ link->flags = flags;
+
+ return 0;
+}
+
+static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+ Link *link = userdata;
+ int r;
+
+ assert(link);
+
+ if (link->state == LINK_STATE_FAILED)
+ return 1;
+
+ r = sd_rtnl_message_get_errno(m);
+ if (r < 0) {
+ log_struct_link(LOG_ERR, link,
+ "MESSAGE=%s: could not bring up interface: %s",
+ link->ifname, strerror(-r),
+ "ERRNO=%d", -r,
+ NULL);
+ link_enter_failed(link);
+ return 1;
+ }
+
+ link_update_flags(link, link->flags | IFF_UP);
+
+ return 1;
+}
+
+static int link_up(Link *link) {
+ _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+ int r;
+
+ assert(link);
+ assert(link->manager);
+ assert(link->manager->rtnl);
+
+ log_debug_link(link, "bringing link up");
+
+ r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
+ if (r < 0) {
+ log_error_link(link, "Could not allocate RTM_SETLINK message");
+ return r;
+ }
+
+ r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
+ if (r < 0) {
+ log_error_link(link, "Could not set link flags: %s", strerror(-r));
+ return r;
+ }
+
+ r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);