static int link_enter_set_addresses(Link *link) {
        Address *ad;
        int r;

        assert(link);
        assert(link->network);
        assert(link->state != _LINK_STATE_INVALID);

        link_set_state(link, LINK_STATE_SETTING_ADDRESSES);

        LIST_FOREACH(addresses, ad, link->network->static_addresses) {
                r = address_configure(ad, link, &address_handler, false);
                if (r < 0) {
                        log_link_warning_errno(link, r, "Could not set addresses: %m");
                        link_enter_failed(link);
                        return r;
                }

                link->link_messages ++;
        }

        /* now that we can figure out a default address for the dhcp server,
           start it */
        if (link_dhcp4_server_enabled(link)) {
                Address *address;
                Link *uplink = NULL;
                bool acquired_uplink = false;

                address = link_find_dhcp_server_address(link);
                if (!address) {
                        log_link_warning(link, "Failed to find suitable address for DHCPv4 server instance.");
                        link_enter_failed(link);
                        return 0;
                }

                /* use the server address' subnet as the pool */
                r = sd_dhcp_server_configure_pool(link->dhcp_server, &address->in_addr.in, address->prefixlen,
                                                  link->network->dhcp_server_pool_offset, link->network->dhcp_server_pool_size);
                if (r < 0)
                        return r;

                /* TODO:
                r = sd_dhcp_server_set_router(link->dhcp_server,
                                              &main_address->in_addr.in);
                if (r < 0)
                        return r;
                */

                if (link->network->dhcp_server_max_lease_time_usec > 0) {
                        r = sd_dhcp_server_set_max_lease_time(
                                        link->dhcp_server,
                                        DIV_ROUND_UP(link->network->dhcp_server_max_lease_time_usec, USEC_PER_SEC));
                        if (r < 0)
                                return r;
                }

                if (link->network->dhcp_server_default_lease_time_usec > 0) {
                        r = sd_dhcp_server_set_default_lease_time(
                                        link->dhcp_server,
                                        DIV_ROUND_UP(link->network->dhcp_server_default_lease_time_usec, USEC_PER_SEC));
                        if (r < 0)
                                return r;
                }

                if (link->network->dhcp_server_emit_dns) {

                        if (link->network->n_dhcp_server_dns > 0)
                                r = sd_dhcp_server_set_dns(link->dhcp_server, link->network->dhcp_server_dns, link->network->n_dhcp_server_dns);
                        else {
                                uplink = manager_find_uplink(link->manager, link);
                                acquired_uplink = true;

                                if (!uplink) {
                                        log_link_debug(link, "Not emitting DNS server information on link, couldn't find suitable uplink.");
                                        r = 0;
                                } else
                                        r = link_push_dns_to_dhcp_server(uplink, link->dhcp_server);
                        }
                        if (r < 0)
                                log_link_warning_errno(link, r, "Failed to set DNS server for DHCP server, ignoring: %m");
                }


                if (link->network->dhcp_server_emit_ntp) {

                        if (link->network->n_dhcp_server_ntp > 0)
                                r = sd_dhcp_server_set_ntp(link->dhcp_server, link->network->dhcp_server_ntp, link->network->n_dhcp_server_ntp);
                        else {
                                if (!acquired_uplink)
                                        uplink = manager_find_uplink(link->manager, link);

                                if (!uplink) {
                                        log_link_debug(link, "Not emitting NTP server information on link, couldn't find suitable uplink.");
                                        r = 0;
                                } else
                                        r = link_push_ntp_to_dhcp_server(uplink, link->dhcp_server);

                        }
                        if (r < 0)
                                log_link_warning_errno(link, r, "Failed to set NTP server for DHCP server, ignoring: %m");
                }

                if (link->network->dhcp_server_emit_timezone) {
                        _cleanup_free_ char *buffer = NULL;
                        const char *tz = NULL;

                        if (link->network->dhcp_server_timezone)
                                tz = link->network->dhcp_server_timezone;
                        else {
                                r = get_timezone(&buffer);
                                if (r < 0)
                                        log_warning_errno(r, "Failed to determine timezone: %m");
                                else
                                        tz = buffer;
                        }

                        if (tz) {
                                r = sd_dhcp_server_set_timezone(link->dhcp_server, tz);
                                if (r < 0)
                                        return r;
                        }
                }

                r = sd_dhcp_server_start(link->dhcp_server);
                if (r < 0) {
                        log_link_warning_errno(link, r, "Could not start DHCPv4 server instance: %m");

                        link_enter_failed(link);

                        return 0;
                }

                log_link_debug(link, "Offering DHCPv4 leases");
        }

        if (link->link_messages == 0)
                link_enter_set_routes(link);
        else
                log_link_debug(link, "Setting addresses");

        return 0;
}