#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
+#include <linux/if_arp.h>
#include <linux/if_infiniband.h>
#include "sd-dhcp6-client.h"
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
+#define IRT_DEFAULT 1 * USEC_PER_DAY
+#define IRT_MINIMUM 600 * USEC_PER_SEC
+
/* what to request from the server, addresses (IA_NA) and/or prefixes (IA_PD) */
enum {
DHCP6_REQUEST_IA_NA = 1,
void *userdata;
struct duid duid;
size_t duid_len;
+ usec_t information_request_time_usec;
+ usec_t information_refresh_time_usec;
};
static const uint16_t default_req_opts[] = {
uint32_t lt_t1 = ~0, lt_t2 = ~0;
bool clientid = false;
size_t pos = 0;
+ usec_t irt = IRT_DEFAULT;
int r;
assert(client);
return r;
break;
+
+ case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME:
+ irt = be32toh(*(be32_t *) optval) * USEC_PER_SEC;
+ break;
}
pos += offsetof(DHCP6Option, data) + optlen;
}
}
+ client->information_refresh_time_usec = MAX(irt, IRT_MINIMUM);
+
return 0;
}
assert(client->event);
buflen = next_datagram_size_fd(fd);
+ if (buflen == -ENETDOWN) {
+ /* the link is down. Don't return an error or the I/O event
+ source will be disconnected and we won't be able to receive
+ packets again when the link comes back. */
+ return 0;
+ }
if (buflen < 0)
return buflen;
len = recv(fd, message, buflen, 0);
if (len < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ /* see comment above for why we shouldn't error out on ENETDOWN. */
+ if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
return 0;
return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m");
client->fd = r;
}
- if (client->information_request)
+ if (client->information_request) {
+ usec_t t = now(CLOCK_MONOTONIC);
+
+ if (t < usec_add(client->information_request_time_usec, client->information_refresh_time_usec))
+ return 0;
+
+ client->information_request_time_usec = t;
state = DHCP6_STATE_INFORMATION_REQUEST;
+ }
log_dhcp6_client(client, "Started in %s mode",
client->information_request? "Information request":