static int client_send_request(sd_dhcp_client *client, uint16_t secs) {
        _cleanup_free_ DHCPPacket *request;
        size_t optlen, len;
        int err;
        uint8_t *opt;

        optlen = DHCP_MIN_OPTIONS_SIZE;
        len = sizeof(DHCPPacket) + optlen;

        request = malloc0(len);
        if (!request)
                return -ENOMEM;

        err = client_message_init(client, &request->dhcp, DHCP_REQUEST, secs,
                                  &opt, &optlen);
        if (err < 0)
                return err;

        if (client->state == DHCP_STATE_REQUESTING) {
                err = dhcp_option_append(&opt, &optlen,
                                         DHCP_OPTION_REQUESTED_IP_ADDRESS,
                                         4, &client->lease->address);
                if (err < 0)
                        return err;

                err = dhcp_option_append(&opt, &optlen,
                                         DHCP_OPTION_SERVER_IDENTIFIER,
                                         4, &client->lease->server_address);
                if (err < 0)
                        return err;
        }

        err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
        if (err < 0)
                return err;

        if (client->state == DHCP_STATE_RENEWING) {
                err = dhcp_network_send_udp_socket(client->fd,
                                                   client->lease->server_address,
                                                   DHCP_PORT_SERVER,
                                                   &request->dhcp,
                                                   len - DHCP_IP_UDP_SIZE);
        } else {
                err = dhcp_client_send_raw(client, request, len);
        }
        if (err < 0)
                return err;

        log_dhcp_client(client, "REQUEST");

        return 0;
}
Example #2
0
static int client_send_request(sd_dhcp_client *client) {
        _cleanup_free_ DHCPPacket *request;
        size_t optlen, len;
        uint8_t *opt;
        int r;

        optlen = DHCP_MIN_OPTIONS_SIZE;
        len = sizeof(DHCPPacket) + optlen;

        request = malloc0(len);
        if (!request)
                return -ENOMEM;

        r = client_message_init(client, &request->dhcp, DHCP_REQUEST, &opt,
                                &optlen);
        if (r < 0)
                return r;

        switch (client->state) {
        /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
           SELECTING should be REQUESTING)
         */

        case DHCP_STATE_REQUESTING:
                /* Client inserts the address of the selected server in ’server
                   identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
                   filled in with the yiaddr value from the chosen DHCPOFFER.
                 */

                r = dhcp_option_append(&opt, &optlen,
                                       DHCP_OPTION_SERVER_IDENTIFIER,
                                       4, &client->lease->server_address);
                if (r < 0)
                        return r;

                r = dhcp_option_append(&opt, &optlen,
                                       DHCP_OPTION_REQUESTED_IP_ADDRESS,
                                       4, &client->lease->address);
                if (r < 0)
                        return r;

                break;

        case DHCP_STATE_INIT_REBOOT:
                /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
                   option MUST be filled in with client’s notion of its previously
                   assigned address. ’ciaddr’ MUST be zero.
                 */
                r = dhcp_option_append(&opt, &optlen,
                                       DHCP_OPTION_REQUESTED_IP_ADDRESS,
                                       4, &client->last_addr);
                if (r < 0)
                        return r;
                break;

        case DHCP_STATE_RENEWING:
                /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
                   option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
                   client’s IP address.
                */

                /* fall through */
        case DHCP_STATE_REBINDING:
                /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
                   option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
                   client’s IP address.

                   This message MUST be broadcast to the 0xffffffff IP broadcast address.
                 */
                request->dhcp.ciaddr = client->lease->address;

                break;

        case DHCP_STATE_INIT:
        case DHCP_STATE_SELECTING:
        case DHCP_STATE_REBOOTING:
        case DHCP_STATE_BOUND:
        case DHCP_STATE_STOPPED:
                return -EINVAL;
        }

        r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
        if (r < 0)
                return r;

        if (client->state == DHCP_STATE_RENEWING) {
                r = dhcp_network_send_udp_socket(client->fd,
                                                 client->lease->server_address,
                                                 DHCP_PORT_SERVER,
                                                 &request->dhcp,
                                                 len - optlen - DHCP_IP_UDP_SIZE);
        } else {
                r = dhcp_client_send_raw(client, request, len - optlen);
        }
        if (r < 0)
                return r;

        switch (client->state) {
        case DHCP_STATE_REQUESTING:
                log_dhcp_client(client, "REQUEST (requesting)");
                break;
        case DHCP_STATE_INIT_REBOOT:
                log_dhcp_client(client, "REQUEST (init-reboot)");
                break;
        case DHCP_STATE_RENEWING:
                log_dhcp_client(client, "REQUEST (renewing)");
                break;
        case DHCP_STATE_REBINDING:
                log_dhcp_client(client, "REQUEST (rebinding)");
                break;
        default:
                log_dhcp_client(client, "REQUEST (invalid)");
                break;
        }

        return 0;
}