X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd-network%2Fsd-dhcp-client.c;h=5d8efbbd3f7c16c33b93fdc1873ecb0ccf4633df;hb=6236f49b230568ba3163df71fd7d386d354091de;hp=ce375dd0164b745856656a8343e1cea5287500e7;hpb=7bf2f4397255bc8f6cf20a0f2adab4c984ea7d14;p=elogind.git diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index ce375dd01..5d8efbbd3 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -46,7 +46,10 @@ struct sd_dhcp_client { size_t req_opts_allocated; size_t req_opts_size; be32_t last_addr; - struct ether_addr mac_addr; + struct { + uint8_t type; + struct ether_addr mac_addr; + } _packed_ client_id; uint32_t xid; usec_t start_time; uint16_t secs; @@ -152,7 +155,8 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, addr->ether_addr_octet[4], addr->ether_addr_octet[5]); - memcpy(&client->mac_addr, addr, ETH_ALEN); + memcpy(&client->client_id.mac_addr, addr, ETH_ALEN); + client->client_id.type = 0x01; return 0; } @@ -218,11 +222,14 @@ static int client_stop(sd_dhcp_client *client, int error) { } static int client_message_init(sd_dhcp_client *client, DHCPMessage *message, - uint8_t type, uint16_t secs, uint8_t **opt, - size_t *optlen) { + uint8_t type, uint8_t **opt, size_t *optlen) { int r; - assert(secs); + assert(client); + assert(client->secs); + assert(message); + assert(opt); + assert(optlen); r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, opt, optlen); @@ -231,9 +238,9 @@ static int client_message_init(sd_dhcp_client *client, DHCPMessage *message, /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers refuse to issue an DHCP lease if 'secs' is set to zero */ - message->secs = htobe16(secs); + message->secs = htobe16(client->secs); - memcpy(&message->chaddr, &client->mac_addr, ETH_ALEN); + memcpy(&message->chaddr, &client->client_id.mac_addr, ETH_ALEN); if (client->state == DHCP_STATE_RENEWING || client->state == DHCP_STATE_REBINDING) @@ -242,7 +249,7 @@ static int client_message_init(sd_dhcp_client *client, DHCPMessage *message, /* Some DHCP servers will refuse to issue an DHCP lease if the Client Identifier option is not set */ r = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER, - ETH_ALEN, &client->mac_addr); + sizeof(client->client_id), &client->client_id); if (r < 0) return r; @@ -280,51 +287,62 @@ static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet, packet, len); } -static int client_send_discover(sd_dhcp_client *client, uint16_t secs) { - int err = 0; +static int client_send_discover(sd_dhcp_client *client) { _cleanup_free_ DHCPPacket *discover; size_t optlen, len; uint8_t *opt; + usec_t time_now; + int r; + + assert(client); + + r = sd_event_get_now_monotonic(client->event, &time_now); + if (r < 0) + return r; + assert(time_now >= client->start_time); + + /* seconds between sending first and last DISCOVER + * must always be strictly positive to deal with broken servers */ + client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1; optlen = DHCP_MIN_OPTIONS_SIZE; len = sizeof(DHCPPacket) + optlen; discover = malloc0(len); - if (!discover) return -ENOMEM; - err = client_message_init(client, &discover->dhcp, DHCP_DISCOVER, - secs, &opt, &optlen); - if (err < 0) - return err; + r = client_message_init(client, &discover->dhcp, DHCP_DISCOVER, + &opt, &optlen); + if (r < 0) + return r; if (client->last_addr != INADDR_ANY) { - err = dhcp_option_append(&opt, &optlen, + r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_REQUESTED_IP_ADDRESS, 4, &client->last_addr); - if (err < 0) - return err; + if (r < 0) + return r; } - err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL); - if (err < 0) - return err; + r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL); + if (r < 0) + return r; - err = dhcp_client_send_raw(client, discover, len); - if (err < 0) - return err; + r = dhcp_client_send_raw(client, discover, len - optlen); + if (r < 0) + return r; log_dhcp_client(client, "DISCOVER"); return 0; } -static int client_send_request(sd_dhcp_client *client, uint16_t secs) { +static int client_send_request(sd_dhcp_client *client) { _cleanup_free_ DHCPPacket *request; size_t optlen, len; - int err; uint8_t *opt; + int r; optlen = DHCP_MIN_OPTIONS_SIZE; len = sizeof(DHCPPacket) + optlen; @@ -333,33 +351,33 @@ static int client_send_request(sd_dhcp_client *client, uint16_t secs) { if (!request) return -ENOMEM; - err = client_message_init(client, &request->dhcp, DHCP_REQUEST, secs, - &opt, &optlen); - if (err < 0) - return err; + r = client_message_init(client, &request->dhcp, DHCP_REQUEST, &opt, + &optlen); + if (r < 0) + return r; switch (client->state) { case DHCP_STATE_INIT_REBOOT: - err = dhcp_option_append(&opt, &optlen, + r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_REQUESTED_IP_ADDRESS, 4, &client->last_addr); - if (err < 0) - return err; + if (r < 0) + return r; break; case 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; + r = dhcp_option_append(&opt, &optlen, + DHCP_OPTION_REQUESTED_IP_ADDRESS, + 4, &client->lease->address); + if (r < 0) + return r; + + r = dhcp_option_append(&opt, &optlen, + DHCP_OPTION_SERVER_IDENTIFIER, + 4, &client->lease->server_address); + if (r < 0) + return r; break; case DHCP_STATE_INIT: @@ -372,34 +390,27 @@ static int client_send_request(sd_dhcp_client *client, uint16_t secs) { break; } - err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL); - if (err < 0) - return err; + r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL); + if (r < 0) + return r; 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); + r = dhcp_network_send_udp_socket(client->fd, + client->lease->server_address, + DHCP_PORT_SERVER, + &request->dhcp, + len - optlen - DHCP_IP_UDP_SIZE); } else { - err = dhcp_client_send_raw(client, request, len); + r = dhcp_client_send_raw(client, request, len - optlen); } - if (err < 0) - return err; + if (r < 0) + return r; log_dhcp_client(client, "REQUEST"); return 0; } -static uint16_t client_update_secs(sd_dhcp_client *client, usec_t time_now) -{ - client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1; - - return client->secs; -} - static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp_client *client = userdata; @@ -476,10 +487,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, switch (client->state) { case DHCP_STATE_INIT: - - client_update_secs(client, time_now); - - r = client_send_discover(client, client->secs); + r = client_send_discover(client); if (r >= 0) { client->state = DHCP_STATE_SELECTING; client->attempt = 1; @@ -491,9 +499,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, break; case DHCP_STATE_SELECTING: - client_update_secs(client, time_now); - - r = client_send_discover(client, client->secs); + r = client_send_discover(client); if (r < 0 && client->attempt >= 64) goto error; @@ -503,7 +509,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, case DHCP_STATE_REQUESTING: case DHCP_STATE_RENEWING: case DHCP_STATE_REBINDING: - r = client_send_request(client, client->secs); + r = client_send_request(client); if (r < 0 && client->attempt >= 64) goto error; @@ -852,8 +858,8 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, return 0; } - if (memcmp(&message->chaddr[0], &client->mac_addr.ether_addr_octet, - ETHER_ADDR_LEN)) { + if (memcmp(&message->chaddr[0], &client->client_id.mac_addr, + ETH_ALEN)) { log_dhcp_client(client, "received chaddr does not match " "expected: ignoring"); return 0;