X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-network%2Fsd-dhcp-client.c;h=2f94c160783279abf5b05cc2522eaf05127fa54b;hp=68bce5e45959c7a9ca0878ecffeff76ecf7b4ef3;hb=6ff8806e1d20a4d3cbc4b360326ea3786768f0ca;hpb=0af03ba57f43b973463e15949c2830cbd228f19d diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 68bce5e45..2f94c1607 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -59,6 +59,7 @@ struct sd_dhcp_client { } _packed_ client_id; char *hostname; char *vendor_class_identifier; + uint32_t mtu; uint32_t xid; usec_t start_time; uint16_t secs; @@ -227,6 +228,15 @@ int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, return 0; } +int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) { + assert_return(client, -EINVAL); + assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE); + + client->mtu = mtu; + + return 0; +} + int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { assert_return(client, -EINVAL); assert_return(ret, -EINVAL); @@ -366,9 +376,23 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, Note (from ConnMan): Some DHCP servers will send bigger DHCP packets than the defined default size unless the Maximum Messge Size option is explicitely set + + RFC3442 "Requirements to Avoid Sizing Constraints": + Because a full routing table can be quite large, the standard 576 + octet maximum size for a DHCP message may be too short to contain + some legitimate Classless Static Route options. Because of this, + clients implementing the Classless Static Route option SHOULD send a + Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP + stack is capable of receiving larger IP datagrams. In this case, the + client SHOULD set the value of this option to at least the MTU of the + interface that the client is configuring. The client MAY set the + value of this option higher, up to the size of the largest UDP packet + it is prepared to accept. (Note that the value specified in the + Maximum DHCP Message Size option is the total maximum packet size, + including IP and UDP headers.) */ max_size = htobe16(size); - r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, + r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0, DHCP_OPTION_MAXIMUM_MESSAGE_SIZE, 2, &max_size); if (r < 0) @@ -676,6 +700,11 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, if (r < 0) goto error; + r = sd_event_source_set_name(client->timeout_resend, + "dhcp4-resend-timer"); + if (r < 0) + goto error; + switch (client->state) { case DHCP_STATE_INIT: r = client_send_discover(client); @@ -749,6 +778,11 @@ static int client_initialize_io_events(sd_dhcp_client *client, if (r < 0) goto error; + r = sd_event_source_set_name(client->receive_message, + "dhcp4-receive-message"); + if (r < 0) + goto error; + error: if (r < 0) client_stop(client, r); @@ -775,6 +809,11 @@ static int client_initialize_time_events(sd_dhcp_client *client) { r = sd_event_source_set_priority(client->timeout_resend, client->event_priority); + r = sd_event_source_set_name(client->timeout_resend, + "dhcp4-resend-timer"); + if (r < 0) + goto error; + error: if (r < 0) client_stop(client, r); @@ -862,7 +901,6 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp_client *client = userdata; DHCP_CLIENT_DONT_DESTROY(client); - int r; client->state = DHCP_STATE_RENEWING; client->attempt = 1; @@ -881,7 +919,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease); if (r != DHCP_OFFER) { - log_dhcp_client(client, "receieved message was not an OFFER, ignoring"); + log_dhcp_client(client, "received message was not an OFFER, ignoring"); return -ENOMSG; } @@ -892,7 +930,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, if (lease->address == INADDR_ANY || lease->server_address == INADDR_ANY || lease->lifetime == 0) { - log_dhcp_client(client, "receieved lease lacks address, server " + log_dhcp_client(client, "received lease lacks address, server " "address or lease lifetime, ignoring"); return -ENOMSG; } @@ -900,7 +938,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, if (lease->subnet_mask == INADDR_ANY) { r = dhcp_lease_set_default_subnet_mask(lease); if (r < 0) { - log_dhcp_client(client, "receieved lease lacks subnet " + log_dhcp_client(client, "received lease lacks subnet " "mask, and a fallback one can not be " "generated, ignoring"); return -ENOMSG; @@ -916,6 +954,19 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, return 0; } +static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, + size_t len) { + int r; + + r = dhcp_option_parse(force, len, NULL, NULL); + if (r != DHCP_FORCERENEW) + return -ENOMSG; + + log_dhcp_client(client, "FORCERENEW"); + + return 0; +} + static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) { _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; @@ -932,7 +983,7 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, } if (r != DHCP_ACK) { - log_dhcp_client(client, "receieved message was not an ACK, ignoring"); + log_dhcp_client(client, "received message was not an ACK, ignoring"); return -ENOMSG; } @@ -943,7 +994,7 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, if (lease->address == INADDR_ANY || lease->server_address == INADDR_ANY || lease->lifetime == 0) { - log_dhcp_client(client, "receieved lease lacks address, server " + log_dhcp_client(client, "received lease lacks address, server " "address or lease lifetime, ignoring"); return -ENOMSG; } @@ -951,7 +1002,7 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, if (lease->subnet_mask == INADDR_ANY) { r = dhcp_lease_set_default_subnet_mask(lease); if (r < 0) { - log_dhcp_client(client, "receieved lease lacks subnet " + log_dhcp_client(client, "received lease lacks subnet " "mask, and a fallback one can not be " "generated, ignoring"); return -ENOMSG; @@ -1071,6 +1122,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { if (r < 0) return r; + r = sd_event_source_set_name(client->timeout_expire, + "dhcp4-lifetime"); + if (r < 0) + return r; + log_dhcp_client(client, "lease expires in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, 0)); @@ -1094,6 +1150,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { if (r < 0) return r; + r = sd_event_source_set_name(client->timeout_t2, + "dhcp4-t2-timeout"); + if (r < 0) + return r; + log_dhcp_client(client, "T2 expires in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, 0)); @@ -1116,6 +1177,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { if (r < 0) return r; + r = sd_event_source_set_name(client->timeout_t1, + "dhcp4-t1-timer"); + if (r < 0) + return r; + log_dhcp_client(client, "T1 expires in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, 0)); @@ -1156,6 +1222,11 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, client->event_priority); if (r < 0) goto error; + + r = sd_event_source_set_name(client->timeout_resend, + "dhcp4-resend-timer"); + if (r < 0) + goto error; } else if (r == -ENOMSG) /* invalid message, let's ignore it */ return 0; @@ -1226,9 +1297,20 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, break; + case DHCP_STATE_BOUND: + r = client_handle_forcerenew(client, message, len); + if (r >= 0) { + r = client_timeout_t1(NULL, 0, client); + if (r < 0) + goto error; + } else if (r == -ENOMSG) + /* invalid message, let's ignore it */ + return 0; + + break; + case DHCP_STATE_INIT: case DHCP_STATE_INIT_REBOOT: - case DHCP_STATE_BOUND: break; @@ -1285,13 +1367,6 @@ static int client_receive_message_udp(sd_event_source *s, int fd, 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 (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) { log_dhcp_client(client, "not an ethernet packet"); return 0; @@ -1304,6 +1379,16 @@ static int client_receive_message_udp(sd_event_source *s, int fd, return 0; } + if (client->state != DHCP_STATE_BOUND && + be32toh(message->xid) != client->xid) { + /* in BOUND state, we may receive FORCERENEW with xid set by server, + so ignore the xid in this case */ + log_dhcp_client(client, "received xid (%u) does not match " + "expected (%u): ignoring", + be32toh(message->xid), client->xid); + return 0; + } + return client_handle_message(client, message, len); } @@ -1370,6 +1455,7 @@ static int client_receive_message_raw(sd_event_source *s, int fd, } int sd_dhcp_client_start(sd_dhcp_client *client) { + char buffer[ETHER_ADDR_TO_STRING_MAX]; int r; assert_return(client, -EINVAL); @@ -1385,7 +1471,7 @@ int sd_dhcp_client_start(sd_dhcp_client *client) { if (r >= 0) log_dhcp_client(client, "STARTED on ifindex %u with address %s", client->index, - ether_ntoa(&client->client_id.mac_addr)); + ether_addr_to_string(&client->client_id.mac_addr, buffer)); return r; } @@ -1479,6 +1565,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret) { client->index = -1; client->fd = -1; client->attempt = 1; + client->mtu = DHCP_DEFAULT_MIN_SIZE; client->req_opts_size = ELEMENTSOF(default_req_opts);