X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-dhcp%2Fsd-dhcp-client.c;h=01397cff398be59c3a4e1a1fee05109bf28e7688;hp=d58755a603d664aa23fb3a218b3fdb84edc7b4b0;hb=0a1b6da82109c3b08b1f966a1625a77cc312135a;hpb=9fadd4cabf57285e58272ddb75147d8d52d4c5a9 diff --git a/src/libsystemd-dhcp/sd-dhcp-client.c b/src/libsystemd-dhcp/sd-dhcp-client.c index d58755a60..01397cff3 100644 --- a/src/libsystemd-dhcp/sd-dhcp-client.c +++ b/src/libsystemd-dhcp/sd-dhcp-client.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "util.h" #include "list.h" @@ -195,6 +196,8 @@ static int client_stop(sd_dhcp_client *client, int error) { if (client->lease) client->lease = sd_dhcp_lease_unref(client->lease); + log_dhcp_client(client, "STOPPED"); + return 0; } @@ -203,18 +206,24 @@ static int client_message_init(sd_dhcp_client *client, DHCPMessage *message, size_t *optlen) { int r; - r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, - secs, opt, optlen); + assert(secs); + + r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, opt, + optlen); if (r < 0) return r; + /* 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); + memcpy(&message->chaddr, &client->mac_addr, ETH_ALEN); if (client->state == DHCP_STATE_RENEWING || client->state == DHCP_STATE_REBINDING) message->ciaddr = client->lease->address; - /* Some DHCP servers will refuse to issue an DHCP lease if the Cliient + /* 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); @@ -277,11 +286,13 @@ static int client_send_discover(sd_dhcp_client *client, uint16_t secs) { if (err < 0) return err; - dhcp_packet_append_ip_headers(discover, BOOTREQUEST, len); + dhcp_packet_append_ip_headers(discover, len); err = dhcp_network_send_raw_socket(client->fd, &client->link, discover, len); + log_dhcp_client(client, "DISCOVER"); + return err; } @@ -328,12 +339,14 @@ static int client_send_request(sd_dhcp_client *client, uint16_t secs) { &request->dhcp, len - DHCP_IP_UDP_SIZE); } else { - dhcp_packet_append_ip_headers(request, BOOTREQUEST, len); + dhcp_packet_append_ip_headers(request, len); err = dhcp_network_send_raw_socket(client->fd, &client->link, request, len); } + log_dhcp_client(client, "REQUEST"); + return err; } @@ -392,10 +405,13 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, next_timeout += (random_u32() & 0x1fffff); - r = sd_event_add_monotonic(client->event, next_timeout, + client->timeout_resend = sd_event_source_unref(client->timeout_resend); + + r = sd_event_add_monotonic(client->event, + &client->timeout_resend, + next_timeout, 10 * USEC_PER_MSEC, - client_timeout_resend, client, - &client->timeout_resend); + client_timeout_resend, client); if (r < 0) goto error; @@ -465,8 +481,9 @@ static int client_initialize_events(sd_dhcp_client *client, assert(client); assert(client->event); - r = sd_event_add_io(client->event, client->fd, EPOLLIN, io_callback, - client, &client->receive_message); + r = sd_event_add_io(client->event, &client->receive_message, + client->fd, EPOLLIN, io_callback, + client); if (r < 0) goto error; @@ -475,9 +492,12 @@ static int client_initialize_events(sd_dhcp_client *client, if (r < 0) goto error; - r = sd_event_add_monotonic(client->event, usec, 0, - client_timeout_resend, client, - &client->timeout_resend); + client->timeout_resend = sd_event_source_unref(client->timeout_resend); + + r = sd_event_add_monotonic(client->event, + &client->timeout_resend, + usec, 0, + client_timeout_resend, client); if (r < 0) goto error; @@ -496,6 +516,8 @@ static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp_client *client = userdata; + log_dhcp_client(client, "EXPIRED"); + client_stop(client, DHCP_EVENT_EXPIRED); return 0; @@ -523,6 +545,8 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) client->fd = r; + log_dhcp_client(client, "TIMEOUT T2"); + return client_initialize_events(client, client_receive_message_raw, usec); } @@ -545,6 +569,8 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, client->fd = r; + log_dhcp_client(client, "TIMEOUT T1"); + return client_initialize_events(client, client_receive_message_udp, usec); } @@ -572,6 +598,8 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, client->lease = lease; lease = NULL; + log_dhcp_client(client, "OFFER"); + return 0; } @@ -585,8 +613,10 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, return r; r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease); - if (r == DHCP_NAK) + if (r == DHCP_NAK) { + log_dhcp_client(client, "NAK"); return DHCP_EVENT_NO_LEASE; + } if (r != DHCP_ACK) return -ENOMSG; @@ -612,6 +642,8 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, client->lease = lease; lease = NULL; + log_dhcp_client(client, "ACK"); + return r; } @@ -643,10 +675,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec) { if (next_timeout < usec) return -EINVAL; - r = sd_event_add_monotonic(client->event, next_timeout, + r = sd_event_add_monotonic(client->event, + &client->timeout_t1, + next_timeout, 10 * USEC_PER_MSEC, - client_timeout_t1, client, - &client->timeout_t1); + client_timeout_t1, client); if (r < 0) return r; @@ -669,10 +702,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec) { if (next_timeout < usec) return -EINVAL; - r = sd_event_add_monotonic(client->event, next_timeout, + r = sd_event_add_monotonic(client->event, + &client->timeout_t2, + next_timeout, 10 * USEC_PER_MSEC, - client_timeout_t2, client, - &client->timeout_t2); + client_timeout_t2, client); if (r < 0) return r; @@ -686,10 +720,10 @@ static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec) { if (next_timeout < usec) return -EINVAL; - r = sd_event_add_monotonic(client->event, next_timeout, + r = sd_event_add_monotonic(client->event, + &client->timeout_expire, next_timeout, 10 * USEC_PER_MSEC, - client_timeout_expire, client, - &client->timeout_expire); + client_timeout_expire, client); if (r < 0) return r; @@ -709,12 +743,30 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, assert(client->event); assert(message); - if (be32toh(message->xid) != client->xid) + if (len < DHCP_MESSAGE_SIZE) { + log_dhcp_client(client, "message too small (%d bytes): " + "ignoring", len); + return 0; + } + + if (message->op != BOOTREPLY) { + log_dhcp_client(client, "not a BOOTREPLY message: ignoring"); return 0; + } + + if (be32toh(message->xid) != client->xid) { + log_dhcp_client(client, "received xid (%u) does not match " + "expected (%u): ignoring", + be32toh(message->xid), client->xid); + return 0; + } if (memcmp(&message->chaddr[0], &client->mac_addr.ether_addr_octet, - ETHER_ADDR_LEN)) + ETHER_ADDR_LEN)) { + log_dhcp_client(client, "received chaddr does not match " + "expected: ignoring"); return 0; + } switch (client->state) { case DHCP_STATE_SELECTING: @@ -728,10 +780,11 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, client->state = DHCP_STATE_REQUESTING; client->attempt = 1; - r = sd_event_add_monotonic(client->event, time_now, 0, + r = sd_event_add_monotonic(client->event, + &client->timeout_resend, + time_now, 0, client_timeout_resend, - client, - &client->timeout_resend); + client); if (r < 0) goto error; @@ -798,19 +851,26 @@ error: return 0; } -static int client_receive_message_raw(sd_event_source *s, int fd, +static int client_receive_message_udp(sd_event_source *s, int fd, uint32_t revents, void *userdata) { sd_dhcp_client *client = userdata; - uint8_t buf[sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE]; - int buflen = sizeof(buf); - int len, r = 0; + _cleanup_free_ DHCPMessage *message = NULL; + int buflen = 0, len, r; usec_t time_now; assert(s); assert(client); assert(client->event); - len = read(fd, &buf, buflen); + r = ioctl(fd, FIONREAD, &buflen); + if (r < 0 || buflen <= 0) + buflen = sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE; + + message = malloc0(buflen); + if (!message) + return -ENOMEM; + + len = read(fd, message, buflen); if (len < 0) return 0; @@ -818,30 +878,34 @@ static int client_receive_message_raw(sd_event_source *s, int fd, if (r < 0) return client_stop(client, r); - return client_handle_message(client, (DHCPMessage *) buf, len, + return client_handle_message(client, message, len, time_now); } -static int client_receive_message_udp(sd_event_source *s, int fd, +static int client_receive_message_raw(sd_event_source *s, int fd, uint32_t revents, void *userdata) { sd_dhcp_client *client = userdata; - uint8_t buf[sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE]; - int buflen = sizeof(buf); - int len, r = 0; - DHCPPacket *packet; + _cleanup_free_ DHCPPacket *packet = NULL; + int buflen = 0, len, r; usec_t time_now; assert(s); assert(client); assert(client->event); - len = read(fd, &buf, buflen); + r = ioctl(fd, FIONREAD, &buflen); + if (r < 0 || buflen <= 0) + buflen = sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE; + + packet = malloc0(buflen); + if (!packet) + return -ENOMEM; + + len = read(fd, packet, buflen); if (len < 0) return 0; - packet = (DHCPPacket *) buf; - - r = dhcp_packet_verify_headers(packet, BOOTREPLY, len); + r = dhcp_packet_verify_headers(packet, len); if (r < 0) return 0; @@ -876,7 +940,9 @@ int sd_dhcp_client_start(sd_dhcp_client *client) { client->start_time = now(CLOCK_MONOTONIC); client->secs = 0; - return client_initialize_events(client, client_receive_message_udp, + log_dhcp_client(client, "STARTED"); + + return client_initialize_events(client, client_receive_message_raw, client->start_time); }