} _packed_ client_id;
char *hostname;
char *vendor_class_identifier;
+ uint32_t mtu;
uint32_t xid;
usec_t start_time;
uint16_t secs;
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);
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)
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);
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);
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);
void *userdata) {
sd_dhcp_client *client = userdata;
DHCP_CLIENT_DONT_DESTROY(client);
- int r;
client->state = DHCP_STATE_RENEWING;
client->attempt = 1;
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;
}
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;
}
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;
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;
}
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;
}
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;
}
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;
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));
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));
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));
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;
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;
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;
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);
}
}
int sd_dhcp_client_start(sd_dhcp_client *client) {
+ char buffer[ETHER_ADDR_TO_STRING_MAX];
int r;
assert_return(client, -EINVAL);
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;
}
client->index = -1;
client->fd = -1;
client->attempt = 1;
+ client->mtu = DHCP_DEFAULT_MIN_SIZE;
client->req_opts_size = ELEMENTSOF(default_req_opts);