mirror of
https://github.com/rsmarples/dhcpcd.git
synced 2024-11-24 10:35:03 +08:00
Replace timeval with timespec.
This commit is contained in:
parent
3a8b97eed2
commit
573d048785
12
arp.c
12
arp.c
@ -253,24 +253,24 @@ arp_probe1(void *arg)
|
||||
{
|
||||
struct arp_state *astate = arg;
|
||||
struct interface *ifp = astate->iface;
|
||||
struct timeval tv;
|
||||
struct timespec tv;
|
||||
|
||||
if (++astate->probes < PROBE_NUM) {
|
||||
tv.tv_sec = PROBE_MIN;
|
||||
tv.tv_usec = (suseconds_t)arc4random_uniform(
|
||||
(PROBE_MAX - PROBE_MIN) * 1000000);
|
||||
timernorm(&tv);
|
||||
tv.tv_nsec = (suseconds_t)arc4random_uniform(
|
||||
(PROBE_MAX - PROBE_MIN) * NSEC_PER_SEC);
|
||||
timespecnorm(&tv);
|
||||
eloop_timeout_add_tv(ifp->ctx->eloop, &tv, arp_probe1, astate);
|
||||
} else {
|
||||
tv.tv_sec = ANNOUNCE_WAIT;
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_nsec = 0;
|
||||
eloop_timeout_add_tv(ifp->ctx->eloop, &tv, arp_probed, astate);
|
||||
}
|
||||
syslog(LOG_DEBUG,
|
||||
"%s: ARP probing %s (%d of %d), next in %0.1f seconds",
|
||||
ifp->name, inet_ntoa(astate->addr),
|
||||
astate->probes ? astate->probes : PROBE_NUM, PROBE_NUM,
|
||||
timeval_to_double(&tv));
|
||||
timespec_to_double(&tv));
|
||||
if (arp_send(ifp, ARPOP_REQUEST, 0, astate->addr.s_addr) == -1)
|
||||
syslog(LOG_ERR, "send_arp: %m");
|
||||
}
|
||||
|
34
common.c
34
common.c
@ -89,18 +89,13 @@ get_hostname(char *buf, size_t buflen, int short_hostname)
|
||||
*/
|
||||
#define NO_MONOTONIC "host does not support a monotonic clock - timing can skew"
|
||||
int
|
||||
get_monotonic(struct timeval *tp)
|
||||
get_monotonic(struct timespec *ts)
|
||||
{
|
||||
#if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC)
|
||||
struct timespec ts;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
|
||||
tp->tv_sec = ts.tv_sec;
|
||||
tp->tv_usec = (suseconds_t)(ts.tv_nsec / 1000);
|
||||
#if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC)
|
||||
return clock_gettime(CLOCK_MONOTONIC, ts);
|
||||
return 0;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
#define NSEC_PER_SEC 1000000000
|
||||
/* We can use mach kernel functions here.
|
||||
* This is crap though - why can't they implement clock_gettime?*/
|
||||
static struct mach_timebase_info info = { 0, 0 };
|
||||
@ -118,13 +113,12 @@ get_monotonic(struct timeval *tp)
|
||||
nano = mach_absolute_time();
|
||||
if ((info.denom != 1 || info.numer != 1) && factor != 0.0)
|
||||
nano *= factor;
|
||||
tp->tv_sec = nano / NSEC_PER_SEC;
|
||||
rem = nano % NSEC_PER_SEC;
|
||||
if (rem < 0) {
|
||||
tp->tv_sec--;
|
||||
rem += NSEC_PER_SEC;
|
||||
ts->tv_sec = nano / NSEC_PER_SEC;
|
||||
ts->tv_nsec = nano % NSEC_PER_SEC;
|
||||
if (ts->tv_nsec < 0) {
|
||||
ts->tv_sec--;
|
||||
ts->tv_nsec += NSEC_PER_SEC;
|
||||
}
|
||||
tp->tv_usec = rem / 1000;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@ -136,7 +130,15 @@ get_monotonic(struct timeval *tp)
|
||||
posix_clock_set = 1;
|
||||
}
|
||||
#endif
|
||||
return gettimeofday(tp, NULL);
|
||||
{
|
||||
struct timeval tv;
|
||||
if (gettimeofday(&tv, NULL) == 0) {
|
||||
TIMEVAL_TO_TIMESPEC(&tv, ts);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
@ -172,7 +174,7 @@ setvard(char ***e, const char *prefix, const char *var, size_t value)
|
||||
time_t
|
||||
uptime(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct timespec tv;
|
||||
|
||||
if (get_monotonic(&tv) == -1)
|
||||
return -1;
|
||||
|
38
common.h
38
common.h
@ -48,28 +48,34 @@
|
||||
#define STRINGIFY(a) #a
|
||||
#define TOSTRING(a) STRINGIFY(a)
|
||||
|
||||
#define USECINSEC 1000000
|
||||
#define timeval_to_double(tv) \
|
||||
((double)(tv)->tv_sec + (double)((tv)->tv_usec) * 1.0e-6)
|
||||
#define timernorm(tv) do { \
|
||||
while ((tv)->tv_usec >= USECINSEC) { \
|
||||
(tv)->tv_sec++; \
|
||||
(tv)->tv_usec -= USECINSEC; \
|
||||
} \
|
||||
#define USEC_PER_SEC 1000000L
|
||||
#define USEC_PER_NSEC 1000L
|
||||
#define NSEC_PER_SEC 1000000000L
|
||||
#define MSEC_PER_SEC 1000L
|
||||
#define MSEC_PER_NSEC 1000000L
|
||||
|
||||
#define timespec_to_double(tv) \
|
||||
((double)(tv)->tv_sec + (double)((tv)->tv_nsec) / 1000000000.0)
|
||||
#define timespecnorm(tv) do { \
|
||||
while ((tv)->tv_nsec >= NSEC_PER_SEC) { \
|
||||
(tv)->tv_sec++; \
|
||||
(tv)->tv_nsec -= NSEC_PER_SEC; \
|
||||
} \
|
||||
} while (0 /* CONSTCOND */);
|
||||
#define tv_to_ms(ms, tv) do { \
|
||||
ms = (tv)->tv_sec * 1000; \
|
||||
ms += (tv)->tv_usec / 1000; \
|
||||
#define ts_to_ms(ms, tv) do { \
|
||||
ms = (tv)->tv_sec * MSEC_PER_SEC; \
|
||||
ms += (tv)->tv_nsec / MSEC_PER_NSEC; \
|
||||
} while (0 /* CONSTCOND */);
|
||||
#define ms_to_tv(tv, ms) do { \
|
||||
(tv)->tv_sec = ms / 1000; \
|
||||
(tv)->tv_usec = (suseconds_t)(ms - ((tv)->tv_sec * 1000)) * 1000; \
|
||||
#define ms_to_ts(tv, ms) do { \
|
||||
(tv)->tv_sec = ms / MSEC_PER_SEC; \
|
||||
(tv)->tv_nsec = (suseconds_t)(ms - ((tv)->tv_sec * MSEC_PER_SEC)) \
|
||||
* MSEC_PER_NSEC; \
|
||||
} while (0 /* CONSTCOND */);
|
||||
|
||||
#ifndef TIMEVAL_TO_TIMESPEC
|
||||
#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
|
||||
(ts)->tv_sec = (tv)->tv_sec; \
|
||||
(ts)->tv_nsec = (tv)->tv_usec * 1000; \
|
||||
(ts)->tv_nsec = (tv)->tv_usec * USEC_PER_NSEC; \
|
||||
} while (0 /* CONSTCOND */)
|
||||
#endif
|
||||
|
||||
@ -110,7 +116,7 @@
|
||||
void get_line_free(void);
|
||||
const char *get_hostname(char *, size_t, int);
|
||||
extern int clock_monotonic;
|
||||
int get_monotonic(struct timeval *);
|
||||
int get_monotonic(struct timespec *);
|
||||
ssize_t setvar(char ***, const char *, const char *, const char *);
|
||||
ssize_t setvard(char ***, const char *, const char *, size_t);
|
||||
time_t uptime(void);
|
||||
|
36
dhcp.c
36
dhcp.c
@ -1569,7 +1569,7 @@ send_message(struct interface *iface, uint8_t type,
|
||||
ssize_t r;
|
||||
struct in_addr from, to;
|
||||
in_addr_t a = INADDR_ANY;
|
||||
struct timeval tv;
|
||||
struct timespec tv;
|
||||
int s;
|
||||
|
||||
if (!callback)
|
||||
@ -1584,13 +1584,13 @@ send_message(struct interface *iface, uint8_t type,
|
||||
state->interval = 64;
|
||||
}
|
||||
tv.tv_sec = state->interval + DHCP_RAND_MIN;
|
||||
tv.tv_usec = (suseconds_t)arc4random_uniform(
|
||||
(DHCP_RAND_MAX - DHCP_RAND_MIN) * 1000000);
|
||||
timernorm(&tv);
|
||||
tv.tv_nsec = (suseconds_t)arc4random_uniform(
|
||||
(DHCP_RAND_MAX - DHCP_RAND_MIN) * NSEC_PER_SEC);
|
||||
timespecnorm(&tv);
|
||||
syslog(LOG_DEBUG,
|
||||
"%s: sending %s (xid 0x%x), next in %0.1f seconds",
|
||||
iface->name, get_dhcp_op(type), state->xid,
|
||||
timeval_to_double(&tv));
|
||||
timespec_to_double(&tv));
|
||||
}
|
||||
|
||||
if (dhcp_open(iface) == -1)
|
||||
@ -1829,7 +1829,6 @@ dhcp_bind(struct interface *ifp, struct arp_state *astate)
|
||||
struct dhcp_state *state = D_STATE(ifp);
|
||||
struct if_options *ifo = ifp->options;
|
||||
struct dhcp_lease *lease = &state->lease;
|
||||
struct timeval tv;
|
||||
uint8_t ipv4ll = 0;
|
||||
|
||||
if (state->state == DHS_BOUND)
|
||||
@ -1862,9 +1861,7 @@ dhcp_bind(struct interface *ifp, struct arp_state *astate)
|
||||
lease->leasetime = ~0U;
|
||||
state->reason = "INFORM";
|
||||
} else {
|
||||
if (gettimeofday(&tv, NULL) == 0)
|
||||
lease->leasedfrom = tv.tv_sec;
|
||||
else if (lease->frominfo)
|
||||
if (lease->frominfo)
|
||||
state->reason = "TIMEOUT";
|
||||
if (lease->leasetime == ~0U) {
|
||||
lease->renewaltime =
|
||||
@ -3071,7 +3068,6 @@ dhcp_start1(void *arg)
|
||||
struct if_options *ifo = ifp->options;
|
||||
struct dhcp_state *state;
|
||||
struct stat st;
|
||||
struct timeval now;
|
||||
uint32_t l;
|
||||
int nolease;
|
||||
|
||||
@ -3167,10 +3163,12 @@ dhcp_start1(void *arg)
|
||||
} else if (state->lease.leasetime != ~0U &&
|
||||
stat(state->leasefile, &st) == 0)
|
||||
{
|
||||
time_t now;
|
||||
|
||||
/* Offset lease times and check expiry */
|
||||
gettimeofday(&now, NULL);
|
||||
if ((time_t)state->lease.leasetime <
|
||||
now.tv_sec - st.st_mtime)
|
||||
now = time(NULL);
|
||||
if (now == -1 ||
|
||||
(time_t)state->lease.leasetime < now - st.st_mtime)
|
||||
{
|
||||
syslog(LOG_DEBUG,
|
||||
"%s: discarding expired lease",
|
||||
@ -3195,7 +3193,7 @@ dhcp_start1(void *arg)
|
||||
dhcp_drop(ifp, "EXPIRE");
|
||||
#endif
|
||||
} else {
|
||||
l = (uint32_t)(now.tv_sec - st.st_mtime);
|
||||
l = (uint32_t)(now - st.st_mtime);
|
||||
state->lease.leasetime -= l;
|
||||
state->lease.renewaltime -= l;
|
||||
state->lease.rebindtime -= l;
|
||||
@ -3223,19 +3221,19 @@ dhcp_start1(void *arg)
|
||||
void
|
||||
dhcp_start(struct interface *ifp)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct timespec tv;
|
||||
|
||||
if (!(ifp->options->options & DHCPCD_IPV4))
|
||||
return;
|
||||
|
||||
/* No point in delaying a static configuration */
|
||||
tv.tv_sec = DHCP_MIN_DELAY;
|
||||
tv.tv_usec = (suseconds_t)arc4random_uniform(
|
||||
(DHCP_MAX_DELAY - DHCP_MIN_DELAY) * 1000000);
|
||||
timernorm(&tv);
|
||||
tv.tv_nsec = (suseconds_t)arc4random_uniform(
|
||||
(DHCP_MAX_DELAY - DHCP_MIN_DELAY) * NSEC_PER_SEC);
|
||||
timespecnorm(&tv);
|
||||
syslog(LOG_DEBUG,
|
||||
"%s: delaying IPv4 for %0.1f seconds",
|
||||
ifp->name, timeval_to_double(&tv));
|
||||
ifp->name, timespec_to_double(&tv));
|
||||
|
||||
eloop_timeout_add_tv(ifp->ctx->eloop, &tv, dhcp_start1, ifp);
|
||||
}
|
||||
|
1
dhcp.h
1
dhcp.h
@ -181,7 +181,6 @@ struct dhcp_lease {
|
||||
uint32_t renewaltime;
|
||||
uint32_t rebindtime;
|
||||
struct in_addr server;
|
||||
time_t leasedfrom;
|
||||
uint8_t frominfo;
|
||||
uint32_t cookie;
|
||||
};
|
||||
|
62
dhcp6.c
62
dhcp6.c
@ -990,7 +990,7 @@ dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
|
||||
struct sockaddr_in6 dst;
|
||||
struct cmsghdr *cm;
|
||||
struct in6_pktinfo pi;
|
||||
struct timeval RTprev;
|
||||
struct timespec RTprev;
|
||||
double rnd;
|
||||
time_t ms;
|
||||
uint8_t neg;
|
||||
@ -1037,49 +1037,49 @@ dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
|
||||
state->RT.tv_sec = 1;
|
||||
else
|
||||
state->RT.tv_sec = 0;
|
||||
state->RT.tv_usec = (suseconds_t)arc4random_uniform(
|
||||
state->IMD * 1000000);
|
||||
timernorm(&state->RT);
|
||||
state->RT.tv_nsec = (suseconds_t)arc4random_uniform(
|
||||
state->IMD * NSEC_PER_SEC);
|
||||
timespecnorm(&state->RT);
|
||||
broad_uni = "delaying";
|
||||
goto logsend;
|
||||
}
|
||||
if (state->RTC == 0) {
|
||||
RTprev.tv_sec = state->IRT;
|
||||
RTprev.tv_usec = 0;
|
||||
RTprev.tv_nsec = 0;
|
||||
state->RT.tv_sec = RTprev.tv_sec;
|
||||
state->RT.tv_usec = 0;
|
||||
state->RT.tv_nsec = 0;
|
||||
} else {
|
||||
RTprev = state->RT;
|
||||
timeradd(&state->RT, &state->RT, &state->RT);
|
||||
timespecadd(&state->RT, &state->RT, &state->RT);
|
||||
}
|
||||
|
||||
rnd = DHCP6_RAND_MIN;
|
||||
rnd += (suseconds_t)arc4random_uniform(
|
||||
DHCP6_RAND_MAX - DHCP6_RAND_MIN);
|
||||
rnd /= 1000;
|
||||
rnd /= MSEC_PER_SEC;
|
||||
neg = (rnd < 0.0);
|
||||
if (neg)
|
||||
rnd = -rnd;
|
||||
tv_to_ms(ms, &RTprev);
|
||||
ts_to_ms(ms, &RTprev);
|
||||
ms *= rnd;
|
||||
ms_to_tv(&RTprev, ms);
|
||||
ms_to_ts(&RTprev, ms);
|
||||
if (neg)
|
||||
timersub(&state->RT, &RTprev, &state->RT);
|
||||
timespecsub(&state->RT, &RTprev, &state->RT);
|
||||
else
|
||||
timeradd(&state->RT, &RTprev, &state->RT);
|
||||
timespecadd(&state->RT, &RTprev, &state->RT);
|
||||
|
||||
if (state->RT.tv_sec > state->MRT) {
|
||||
RTprev.tv_sec = state->MRT;
|
||||
RTprev.tv_usec = 0;
|
||||
RTprev.tv_nsec = 0;
|
||||
state->RT.tv_sec = state->MRT;
|
||||
state->RT.tv_usec = 0;
|
||||
tv_to_ms(ms, &RTprev);
|
||||
state->RT.tv_nsec = 0;
|
||||
ts_to_ms(ms, &RTprev);
|
||||
ms *= rnd;
|
||||
ms_to_tv(&RTprev, ms);
|
||||
ms_to_ts(&RTprev, ms);
|
||||
if (neg)
|
||||
timersub(&state->RT, &RTprev, &state->RT);
|
||||
timespecsub(&state->RT, &RTprev, &state->RT);
|
||||
else
|
||||
timeradd(&state->RT, &RTprev, &state->RT);
|
||||
timespecadd(&state->RT, &RTprev, &state->RT);
|
||||
}
|
||||
|
||||
logsend:
|
||||
@ -1092,7 +1092,7 @@ logsend:
|
||||
state->send->xid[0],
|
||||
state->send->xid[1],
|
||||
state->send->xid[2],
|
||||
timeval_to_double(&state->RT));
|
||||
timespec_to_double(&state->RT));
|
||||
|
||||
/* Wait the initial delay */
|
||||
if (state->IMD) {
|
||||
@ -1695,7 +1695,7 @@ dhcp6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr,
|
||||
|
||||
static int
|
||||
dhcp6_findna(struct interface *ifp, uint16_t ot, const uint8_t *iaid,
|
||||
const uint8_t *d, size_t l, const struct timeval *acquired)
|
||||
const uint8_t *d, size_t l, const struct timespec *acquired)
|
||||
{
|
||||
struct dhcp6_state *state;
|
||||
const struct dhcp6_option *o;
|
||||
@ -1776,7 +1776,7 @@ dhcp6_findna(struct interface *ifp, uint16_t ot, const uint8_t *iaid,
|
||||
|
||||
static int
|
||||
dhcp6_findpd(struct interface *ifp, const uint8_t *iaid,
|
||||
const uint8_t *d, size_t l, const struct timeval *acquired)
|
||||
const uint8_t *d, size_t l, const struct timespec *acquired)
|
||||
{
|
||||
struct dhcp6_state *state;
|
||||
const struct dhcp6_option *o, *ex;
|
||||
@ -1902,7 +1902,7 @@ dhcp6_findpd(struct interface *ifp, const uint8_t *iaid,
|
||||
|
||||
static int
|
||||
dhcp6_findia(struct interface *ifp, const struct dhcp6_message *m, size_t l,
|
||||
const char *sfrom, const struct timeval *acquired)
|
||||
const char *sfrom, const struct timespec *acquired)
|
||||
{
|
||||
struct dhcp6_state *state;
|
||||
const struct if_options *ifo;
|
||||
@ -2051,11 +2051,11 @@ dhcp6_findia(struct interface *ifp, const struct dhcp6_message *m, size_t l,
|
||||
static int
|
||||
dhcp6_validatelease(struct interface *ifp,
|
||||
const struct dhcp6_message *m, size_t len,
|
||||
const char *sfrom, const struct timeval *acquired)
|
||||
const char *sfrom, const struct timespec *acquired)
|
||||
{
|
||||
struct dhcp6_state *state;
|
||||
int nia;
|
||||
struct timeval aq;
|
||||
struct timespec aq;
|
||||
|
||||
if (len <= sizeof(*m)) {
|
||||
syslog(LOG_ERR, "%s: DHCPv6 lease truncated", ifp->name);
|
||||
@ -2109,9 +2109,9 @@ dhcp6_readlease(struct interface *ifp)
|
||||
struct stat st;
|
||||
int fd;
|
||||
ssize_t bytes;
|
||||
struct timeval now;
|
||||
const struct dhcp6_option *o;
|
||||
struct timeval acquired;
|
||||
struct timespec acquired;
|
||||
time_t now;
|
||||
|
||||
state = D6_STATE(ifp);
|
||||
if (stat(state->leasefile, &st) == -1) {
|
||||
@ -2145,9 +2145,13 @@ dhcp6_readlease(struct interface *ifp)
|
||||
goto ex;
|
||||
}
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
if ((now = time(NULL)) == -1) {
|
||||
syslog(LOG_ERR, "%s: time: %m", __func__);
|
||||
goto ex;
|
||||
}
|
||||
|
||||
get_monotonic(&acquired);
|
||||
acquired.tv_sec -= now.tv_sec - st.st_mtime;
|
||||
acquired.tv_sec -= now - st.st_mtime;
|
||||
|
||||
/* Check to see if the lease is still valid */
|
||||
fd = dhcp6_validatelease(ifp, state->new, state->new_len, NULL,
|
||||
@ -2158,7 +2162,7 @@ dhcp6_readlease(struct interface *ifp)
|
||||
if (!(ifp->ctx->options & DHCPCD_DUMPLEASE) &&
|
||||
state->expire != ND6_INFINITE_LIFETIME)
|
||||
{
|
||||
if ((time_t)state->expire < now.tv_sec - st.st_mtime) {
|
||||
if ((time_t)state->expire < now - st.st_mtime) {
|
||||
syslog(LOG_DEBUG,"%s: discarding expired lease",
|
||||
ifp->name);
|
||||
goto ex;
|
||||
|
2
dhcp6.h
2
dhcp6.h
@ -172,7 +172,7 @@ struct dhcp6_state {
|
||||
time_t start_uptime;
|
||||
|
||||
/* Message retransmission timings */
|
||||
struct timeval RT;
|
||||
struct timespec RT;
|
||||
unsigned int IMD;
|
||||
unsigned int RTC;
|
||||
time_t IRT;
|
||||
|
10
dhcpcd.c
10
dhcpcd.c
@ -550,10 +550,10 @@ dhcpcd_pollup(void *arg)
|
||||
|
||||
carrier = if_carrier(ifp); /* will set ifp->flags */
|
||||
if (carrier == LINK_UP && !(ifp->flags & IFF_UP)) {
|
||||
struct timeval tv;
|
||||
struct timespec tv;
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = IF_POLL_UP * 1000;
|
||||
tv.tv_nsec = IF_POLL_UP * MSEC_PER_NSEC;
|
||||
eloop_timeout_add_tv(ifp->ctx->eloop, &tv, dhcpcd_pollup, ifp);
|
||||
return;
|
||||
}
|
||||
@ -681,7 +681,7 @@ dhcpcd_startinterface(void *arg)
|
||||
size_t i;
|
||||
char buf[DUID_LEN * 3];
|
||||
int carrier;
|
||||
struct timeval tv;
|
||||
struct timespec tv;
|
||||
|
||||
if (ifo->options & DHCPCD_LINK) {
|
||||
switch (ifp->carrier) {
|
||||
@ -695,7 +695,7 @@ dhcpcd_startinterface(void *arg)
|
||||
* Loop until both IFF_UP and IFF_RUNNING are set */
|
||||
if ((carrier = if_carrier(ifp)) == LINK_UNKNOWN) {
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = IF_POLL_UP * 1000;
|
||||
tv.tv_nsec = IF_POLL_UP * MSEC_PER_NSEC;
|
||||
eloop_timeout_add_tv(ifp->ctx->eloop,
|
||||
&tv, dhcpcd_startinterface, ifp);
|
||||
} else
|
||||
@ -1508,7 +1508,7 @@ main(int argc, char **argv)
|
||||
* eloop removals as well, so init here. */
|
||||
ctx.eloop = eloop_init();
|
||||
if (ctx.eloop == NULL) {
|
||||
syslog(LOG_ERR, "%s: %m", __func__);
|
||||
syslog(LOG_ERR, "%s: eloop_init: %m", __func__);
|
||||
goto exit_failure;
|
||||
}
|
||||
|
||||
|
32
eloop.c
32
eloop.c
@ -153,16 +153,15 @@ eloop_event_delete(struct eloop_ctx *ctx, int fd, int write_only)
|
||||
|
||||
int
|
||||
eloop_q_timeout_add_tv(struct eloop_ctx *ctx, int queue,
|
||||
const struct timeval *when, void (*callback)(void *), void *arg)
|
||||
const struct timespec *when, void (*callback)(void *), void *arg)
|
||||
{
|
||||
struct timeval now;
|
||||
struct timeval w;
|
||||
struct timespec now, w;
|
||||
struct eloop_timeout *t, *tt = NULL;
|
||||
|
||||
get_monotonic(&now);
|
||||
timeradd(&now, when, &w);
|
||||
timespecadd(&now, when, &w);
|
||||
/* Check for time_t overflow. */
|
||||
if (timercmp(&w, &now, <)) {
|
||||
if (timespeccmp(&w, &now, <)) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
@ -188,8 +187,7 @@ eloop_q_timeout_add_tv(struct eloop_ctx *ctx, int queue,
|
||||
}
|
||||
}
|
||||
|
||||
t->when.tv_sec = w.tv_sec;
|
||||
t->when.tv_usec = w.tv_usec;
|
||||
t->when = w;
|
||||
t->callback = callback;
|
||||
t->arg = arg;
|
||||
t->queue = queue;
|
||||
@ -197,7 +195,7 @@ eloop_q_timeout_add_tv(struct eloop_ctx *ctx, int queue,
|
||||
/* The timeout list should be in chronological order,
|
||||
* soonest first. */
|
||||
TAILQ_FOREACH(tt, &ctx->timeouts, next) {
|
||||
if (timercmp(&t->when, &tt->when, <)) {
|
||||
if (timespeccmp(&t->when, &tt->when, <)) {
|
||||
TAILQ_INSERT_BEFORE(tt, t, next);
|
||||
return 0;
|
||||
}
|
||||
@ -210,10 +208,10 @@ int
|
||||
eloop_q_timeout_add_sec(struct eloop_ctx *ctx, int queue, time_t when,
|
||||
void (*callback)(void *), void *arg)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct timespec tv;
|
||||
|
||||
tv.tv_sec = when;
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_nsec = 0;
|
||||
return eloop_q_timeout_add_tv(ctx, queue, &tv, callback, arg);
|
||||
}
|
||||
|
||||
@ -261,6 +259,11 @@ struct eloop_ctx *
|
||||
eloop_init(void)
|
||||
{
|
||||
struct eloop_ctx *ctx;
|
||||
struct timespec now;
|
||||
|
||||
/* Check we have a working monotonic clock. */
|
||||
if (get_monotonic(&now) == -1)
|
||||
return NULL;
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (ctx) {
|
||||
@ -306,12 +309,10 @@ int
|
||||
eloop_start(struct dhcpcd_ctx *dctx)
|
||||
{
|
||||
struct eloop_ctx *ctx;
|
||||
struct timeval now;
|
||||
int n;
|
||||
struct eloop_event *e;
|
||||
struct eloop_timeout *t;
|
||||
struct timeval tv;
|
||||
struct timespec ts, *tsp;
|
||||
struct timespec now, ts, *tsp;
|
||||
void (*t0)(void *);
|
||||
#ifndef USE_SIGNALS
|
||||
int timeout;
|
||||
@ -331,14 +332,13 @@ eloop_start(struct dhcpcd_ctx *dctx)
|
||||
}
|
||||
if ((t = TAILQ_FIRST(&ctx->timeouts))) {
|
||||
get_monotonic(&now);
|
||||
if (timercmp(&now, &t->when, >)) {
|
||||
if (timespeccmp(&now, &t->when, >)) {
|
||||
TAILQ_REMOVE(&ctx->timeouts, t, next);
|
||||
t->callback(t->arg);
|
||||
TAILQ_INSERT_TAIL(&ctx->free_timeouts, t, next);
|
||||
continue;
|
||||
}
|
||||
timersub(&t->when, &now, &tv);
|
||||
TIMEVAL_TO_TIMESPEC(&tv, &ts);
|
||||
timespecsub(&t->when, &now, &ts);
|
||||
tsp = &ts;
|
||||
} else
|
||||
/* No timeouts, so wait forever */
|
||||
|
4
eloop.h
4
eloop.h
@ -50,7 +50,7 @@ struct eloop_event {
|
||||
|
||||
struct eloop_timeout {
|
||||
TAILQ_ENTRY(eloop_timeout) next;
|
||||
struct timeval when;
|
||||
struct timespec when;
|
||||
void (*callback)(void *);
|
||||
void *arg;
|
||||
int queue;
|
||||
@ -88,7 +88,7 @@ void eloop_event_delete(struct eloop_ctx *, int, int);
|
||||
int eloop_q_timeout_add_sec(struct eloop_ctx *, int queue,
|
||||
time_t, void (*)(void *), void *);
|
||||
int eloop_q_timeout_add_tv(struct eloop_ctx *, int queue,
|
||||
const struct timeval *, void (*)(void *), void *);
|
||||
const struct timespec *, void (*)(void *), void *);
|
||||
int eloop_timeout_add_now(struct eloop_ctx *, void (*)(void *), void *);
|
||||
void eloop_q_timeout_delete(struct eloop_ctx *, int, void (*)(void *), void *);
|
||||
struct eloop_ctx * eloop_init(void);
|
||||
|
6
if-bsd.c
6
if-bsd.c
@ -599,6 +599,9 @@ if_route(unsigned char cmd, const struct rt *rt, struct rt *srt)
|
||||
else {
|
||||
#ifdef RTF_CLONING
|
||||
rtm.hdr.rtm_flags |= RTF_CLONING;
|
||||
#endif
|
||||
#ifdef RTP_CONNECTED
|
||||
rtm.hdr.rtm_priority = RTP_CONNECTED;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -952,6 +955,9 @@ if_route6(unsigned char cmd, const struct rt6 *rt, struct rt6 *srt)
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&rt->gate)) {
|
||||
#ifdef RTF_CLONING
|
||||
rtm.hdr.rtm_flags |= RTF_CLONING;
|
||||
#endif
|
||||
#ifdef RTP_CONNECTED
|
||||
rtm.hdr.rtm_priority = RTP_CONNECTED;
|
||||
#endif
|
||||
} else
|
||||
rtm.hdr.rtm_flags |= RTF_GATEWAY | RTF_STATIC;
|
||||
|
40
ipv6.c
40
ipv6.c
@ -594,9 +594,9 @@ ipv6_checkaddrflags(void *arg)
|
||||
ap->iface->ctx->ifaces, ap->iface->name,
|
||||
&ap->addr, ap->prefix_len, ifa_flags);
|
||||
} else {
|
||||
struct timeval tv;
|
||||
struct timespec tv;
|
||||
|
||||
ms_to_tv(&tv, RETRANS_TIMER / 2);
|
||||
ms_to_ts(&tv, RETRANS_TIMER / 2);
|
||||
eloop_timeout_add_tv(ap->iface->ctx->eloop, &tv,
|
||||
ipv6_checkaddrflags, ap);
|
||||
}
|
||||
@ -627,7 +627,7 @@ ipv6_deleteaddr(struct ipv6_addr *addr)
|
||||
}
|
||||
|
||||
int
|
||||
ipv6_addaddr(struct ipv6_addr *ap, const struct timeval *now)
|
||||
ipv6_addaddr(struct ipv6_addr *ap, const struct timespec *now)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct ipv6_state *state;
|
||||
@ -676,17 +676,17 @@ ipv6_addaddr(struct ipv6_addr *ap, const struct timeval *now)
|
||||
/* Adjust plftime and vltime based on acquired time */
|
||||
pltime = ap->prefix_pltime;
|
||||
vltime = ap->prefix_vltime;
|
||||
if (timerisset(&ap->acquired) &&
|
||||
if (timespecisset(&ap->acquired) &&
|
||||
(ap->prefix_pltime != ND6_INFINITE_LIFETIME ||
|
||||
ap->prefix_vltime != ND6_INFINITE_LIFETIME))
|
||||
{
|
||||
struct timeval n;
|
||||
struct timespec n;
|
||||
|
||||
if (now == NULL) {
|
||||
get_monotonic(&n);
|
||||
now = &n;
|
||||
}
|
||||
timersub(now, &ap->acquired, &n);
|
||||
timespecsub(now, &ap->acquired, &n);
|
||||
if (ap->prefix_pltime != ND6_INFINITE_LIFETIME)
|
||||
ap->prefix_pltime -= (uint32_t)n.tv_sec;
|
||||
if (ap->prefix_vltime != ND6_INFINITE_LIFETIME)
|
||||
@ -732,9 +732,9 @@ ipv6_addaddr(struct ipv6_addr *ap, const struct timeval *now)
|
||||
eloop_timeout_delete(ap->iface->ctx->eloop,
|
||||
ipv6_checkaddrflags, ap);
|
||||
if (!(ap->flags & IPV6_AF_DADCOMPLETED)) {
|
||||
struct timeval tv;
|
||||
struct timespec tv;
|
||||
|
||||
ms_to_tv(&tv, RETRANS_TIMER / 2);
|
||||
ms_to_ts(&tv, RETRANS_TIMER / 2);
|
||||
eloop_timeout_add_tv(ap->iface->ctx->eloop,
|
||||
&tv, ipv6_checkaddrflags, ap);
|
||||
}
|
||||
@ -766,10 +766,10 @@ ipv6_addaddrs(struct ipv6_addrhead *addrs)
|
||||
{
|
||||
struct ipv6_addr *ap, *apn, *apf;
|
||||
ssize_t i;
|
||||
struct timeval now;
|
||||
struct timespec now;
|
||||
|
||||
i = 0;
|
||||
timerclear(&now);
|
||||
timespecclear(&now);
|
||||
TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
|
||||
if (ap->prefix_vltime == 0) {
|
||||
if (ap->flags & IPV6_AF_ADDED) {
|
||||
@ -814,7 +814,7 @@ ipv6_addaddrs(struct ipv6_addrhead *addrs)
|
||||
apf->flags &= ~IPV6_AF_ADDED;
|
||||
if (ap->flags & IPV6_AF_NEW)
|
||||
i++;
|
||||
if (!timerisset(&now))
|
||||
if (!timespecisset(&now))
|
||||
get_monotonic(&now);
|
||||
ipv6_addaddr(ap, &now);
|
||||
}
|
||||
@ -836,9 +836,9 @@ ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop,
|
||||
const struct interface *ifd)
|
||||
{
|
||||
struct ipv6_addr *ap, *apn, *apf;
|
||||
struct timeval now;
|
||||
struct timespec now;
|
||||
|
||||
timerclear(&now);
|
||||
timespecclear(&now);
|
||||
TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
|
||||
if (ifd && ap->delegating_iface != ifd)
|
||||
continue;
|
||||
@ -860,7 +860,7 @@ ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop,
|
||||
if (!(ap->iface->options->options &
|
||||
DHCPCD_EXITING) && apf)
|
||||
{
|
||||
if (!timerisset(&now))
|
||||
if (!timespecisset(&now))
|
||||
get_monotonic(&now);
|
||||
ipv6_addaddr(apf, &now);
|
||||
}
|
||||
@ -997,9 +997,9 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&ap->addr)) {
|
||||
#ifdef IPV6_POLLADDRFLAG
|
||||
if (ap->addr_flags & IN6_IFF_TENTATIVE) {
|
||||
struct timeval tv;
|
||||
struct timespec tv;
|
||||
|
||||
ms_to_tv(&tv, RETRANS_TIMER / 2);
|
||||
ms_to_ts(&tv, RETRANS_TIMER / 2);
|
||||
eloop_timeout_add_tv(
|
||||
ap->iface->ctx->eloop,
|
||||
&tv, ipv6_checkaddrflags, ap);
|
||||
@ -1437,7 +1437,7 @@ ipv6_tempdadcallback(void *arg)
|
||||
|
||||
if (ia->flags & IPV6_AF_DUPLICATED) {
|
||||
struct ipv6_addr *ia1;
|
||||
struct timeval tv;
|
||||
struct timespec tv;
|
||||
|
||||
if (++ia->dadcounter == TEMP_IDGEN_RETRIES) {
|
||||
syslog(LOG_ERR,
|
||||
@ -1457,7 +1457,7 @@ ipv6_tempdadcallback(void *arg)
|
||||
}
|
||||
|
||||
struct ipv6_addr *
|
||||
ipv6_createtempaddr(struct ipv6_addr *ia0, const struct timeval *now)
|
||||
ipv6_createtempaddr(struct ipv6_addr *ia0, const struct timespec *now)
|
||||
{
|
||||
struct ipv6_state *state;
|
||||
const struct ipv6_state *cstate;
|
||||
@ -1649,7 +1649,7 @@ valid:
|
||||
}
|
||||
|
||||
void
|
||||
ipv6_addtempaddrs(struct interface *ifp, const struct timeval *now)
|
||||
ipv6_addtempaddrs(struct interface *ifp, const struct timespec *now)
|
||||
{
|
||||
struct ipv6_state *state;
|
||||
struct ipv6_addr *ia;
|
||||
@ -1666,7 +1666,7 @@ static void
|
||||
ipv6_regentempaddr(void *arg)
|
||||
{
|
||||
struct ipv6_addr *ia = arg, *ia1;
|
||||
struct timeval tv;
|
||||
struct timespec tv;
|
||||
|
||||
syslog(LOG_DEBUG, "%s: regen temp addr %s",
|
||||
ia->iface->name, ia->saddr);
|
||||
|
10
ipv6.h
10
ipv6.h
@ -104,8 +104,8 @@ struct ipv6_addr {
|
||||
uint8_t prefix_len;
|
||||
uint32_t prefix_vltime;
|
||||
uint32_t prefix_pltime;
|
||||
struct timeval created;
|
||||
struct timeval acquired;
|
||||
struct timespec created;
|
||||
struct timespec acquired;
|
||||
struct in6_addr addr;
|
||||
int addr_flags;
|
||||
short flags;
|
||||
@ -238,7 +238,7 @@ uint8_t ipv6_prefixlen(const struct in6_addr *);
|
||||
int ipv6_userprefix( const struct in6_addr *, short prefix_len,
|
||||
uint64_t user_number, struct in6_addr *result, short result_len);
|
||||
void ipv6_checkaddrflags(void *);
|
||||
int ipv6_addaddr(struct ipv6_addr *, const struct timeval *);
|
||||
int ipv6_addaddr(struct ipv6_addr *, const struct timespec *);
|
||||
ssize_t ipv6_addaddrs(struct ipv6_addrhead *addrs);
|
||||
void ipv6_freedrop_addrs(struct ipv6_addrhead *, int,
|
||||
const struct interface *);
|
||||
@ -261,9 +261,9 @@ void ipv6_freedrop(struct interface *, int);
|
||||
void ipv6_gentempifid(struct interface *);
|
||||
void ipv6_settempstale(struct interface *);
|
||||
struct ipv6_addr *ipv6_createtempaddr(struct ipv6_addr *,
|
||||
const struct timeval *);
|
||||
const struct timespec *);
|
||||
struct ipv6_addr *ipv6_settemptime(struct ipv6_addr *, int);
|
||||
void ipv6_addtempaddrs(struct interface *, const struct timeval *);
|
||||
void ipv6_addtempaddrs(struct interface *, const struct timespec *);
|
||||
#else
|
||||
#define ipv6_gentempifid(a) {}
|
||||
#define ipv6_settempstale(a) {}
|
||||
|
55
ipv6nd.c
55
ipv6nd.c
@ -519,7 +519,7 @@ ipv6nd_scriptrun(struct ra *rap)
|
||||
TAILQ_FOREACH(rao, &rap->options, next) {
|
||||
if (rao->type == ND_OPT_RDNSS &&
|
||||
rao->option &&
|
||||
timerisset(&rao->expire))
|
||||
timespecisset(&rao->expire))
|
||||
{
|
||||
hasdns = 1;
|
||||
break;
|
||||
@ -578,7 +578,7 @@ ipv6nd_dadcallback(void *arg)
|
||||
struct interface *ifp;
|
||||
struct ra *rap;
|
||||
int wascompleted, found;
|
||||
struct timeval tv;
|
||||
struct timespec tv;
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
const char *p;
|
||||
int dadcounter;
|
||||
@ -630,9 +630,9 @@ ipv6nd_dadcallback(void *arg)
|
||||
else
|
||||
ap->saddr[0] = '\0';
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = (suseconds_t)arc4random_uniform(
|
||||
IDGEN_DELAY * USECINSEC);
|
||||
timernorm(&tv);
|
||||
tv.tv_nsec = (suseconds_t)
|
||||
arc4random_uniform(IDGEN_DELAY * NSEC_PER_SEC);
|
||||
timespecnorm(&tv);
|
||||
eloop_timeout_add_tv(ifp->ctx->eloop, &tv,
|
||||
ipv6nd_addaddr, ap);
|
||||
return;
|
||||
@ -690,7 +690,7 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
|
||||
struct ra_opt *rao;
|
||||
struct ipv6_addr *ap;
|
||||
char *opt, *opt2, *tmp;
|
||||
struct timeval expire;
|
||||
struct timespec expire;
|
||||
uint8_t new_rap, new_data;
|
||||
#ifdef IPV6_MANAGETEMPADDR
|
||||
uint8_t new_ap;
|
||||
@ -1094,11 +1094,11 @@ extra_opt:
|
||||
} else
|
||||
free(opt);
|
||||
if (lifetime == ~0U)
|
||||
timerclear(&rao->expire);
|
||||
timespecclear(&rao->expire);
|
||||
else {
|
||||
expire.tv_sec = (time_t)lifetime;
|
||||
expire.tv_usec = 0;
|
||||
timeradd(&rap->received, &expire, &rao->expire);
|
||||
expire.tv_nsec = 0;
|
||||
timespecadd(&rap->received, &expire, &rao->expire);
|
||||
}
|
||||
if (rao && rao->type == ND_OPT_PREFIX_INFORMATION && opt2) {
|
||||
n = _ND_OPT_PREFIX_ADDR;
|
||||
@ -1316,13 +1316,13 @@ ipv6nd_expirera(void *arg)
|
||||
struct interface *ifp;
|
||||
struct ra *rap, *ran;
|
||||
struct ra_opt *rao, *raon;
|
||||
struct timeval now, lt, expire, next;
|
||||
struct timespec now, lt, expire, next;
|
||||
int expired, valid;
|
||||
|
||||
ifp = arg;
|
||||
get_monotonic(&now);
|
||||
expired = 0;
|
||||
timerclear(&next);
|
||||
timespecclear(&next);
|
||||
|
||||
TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
|
||||
if (rap->iface != ifp)
|
||||
@ -1330,9 +1330,10 @@ ipv6nd_expirera(void *arg)
|
||||
valid = 0;
|
||||
if (rap->lifetime) {
|
||||
lt.tv_sec = (time_t)rap->lifetime;
|
||||
lt.tv_usec = 0;
|
||||
timeradd(&rap->received, <, &expire);
|
||||
if (rap->lifetime == 0 || timercmp(&now, &expire, >)) {
|
||||
lt.tv_nsec = 0;
|
||||
timespecadd(&rap->received, <, &expire);
|
||||
if (rap->lifetime == 0 || timespeccmp(&now, &expire, >))
|
||||
{
|
||||
if (!rap->expired) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s: %s: router expired",
|
||||
@ -1341,9 +1342,9 @@ ipv6nd_expirera(void *arg)
|
||||
}
|
||||
} else {
|
||||
valid = 1;
|
||||
timersub(&expire, &now, <);
|
||||
if (!timerisset(&next) ||
|
||||
timercmp(&next, <, >))
|
||||
timespecsub(&expire, &now, <);
|
||||
if (!timespecisset(&next) ||
|
||||
timespeccmp(&next, <, >))
|
||||
next = lt;
|
||||
}
|
||||
}
|
||||
@ -1366,9 +1367,9 @@ ipv6nd_expirera(void *arg)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!timerisset(&rao->expire))
|
||||
if (!timespecisset(&rao->expire))
|
||||
continue;
|
||||
if (timercmp(&now, &rao->expire, >)) {
|
||||
if (timespeccmp(&now, &rao->expire, >)) {
|
||||
/* Expired prefixes are logged above */
|
||||
if (rao->type != ND_OPT_PREFIX_INFORMATION)
|
||||
syslog(LOG_WARNING,
|
||||
@ -1381,8 +1382,8 @@ ipv6nd_expirera(void *arg)
|
||||
continue;
|
||||
}
|
||||
valid = 1;
|
||||
timersub(&rao->expire, &now, <);
|
||||
if (!timerisset(&next) || timercmp(&next, <, >))
|
||||
timespecsub(&rao->expire, &now, <);
|
||||
if (!timespecisset(&next) || timespeccmp(&next, <, >))
|
||||
next = lt;
|
||||
}
|
||||
|
||||
@ -1392,7 +1393,7 @@ ipv6nd_expirera(void *arg)
|
||||
ipv6nd_free_ra(rap);
|
||||
}
|
||||
|
||||
if (timerisset(&next))
|
||||
if (timespecisset(&next))
|
||||
eloop_timeout_add_tv(ifp->ctx->eloop,
|
||||
&next, ipv6nd_expirera, ifp);
|
||||
if (expired) {
|
||||
@ -1624,16 +1625,16 @@ ipv6nd_startrs1(void *arg)
|
||||
void
|
||||
ipv6nd_startrs(struct interface *ifp)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct timespec tv;
|
||||
|
||||
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = (suseconds_t)arc4random_uniform(
|
||||
MAX_RTR_SOLICITATION_DELAY * 1000000);
|
||||
timernorm(&tv);
|
||||
tv.tv_nsec = (suseconds_t)arc4random_uniform(
|
||||
MAX_RTR_SOLICITATION_DELAY * NSEC_PER_SEC);
|
||||
timespecnorm(&tv);
|
||||
syslog(LOG_DEBUG,
|
||||
"%s: delaying IPv6 router solicitation for %0.1f seconds",
|
||||
ifp->name, timeval_to_double(&tv));
|
||||
ifp->name, timespec_to_double(&tv));
|
||||
eloop_timeout_add_tv(ifp->ctx->eloop, &tv, ipv6nd_startrs1, ifp);
|
||||
return;
|
||||
}
|
||||
|
4
ipv6nd.h
4
ipv6nd.h
@ -37,7 +37,7 @@
|
||||
struct ra_opt {
|
||||
TAILQ_ENTRY(ra_opt) next;
|
||||
uint16_t type;
|
||||
struct timeval expire;
|
||||
struct timespec expire;
|
||||
char *option;
|
||||
};
|
||||
|
||||
@ -48,7 +48,7 @@ struct ra {
|
||||
char sfrom[INET6_ADDRSTRLEN];
|
||||
unsigned char *data;
|
||||
size_t data_len;
|
||||
struct timeval received;
|
||||
struct timespec received;
|
||||
unsigned char flags;
|
||||
uint32_t lifetime;
|
||||
uint32_t reachable;
|
||||
|
Loading…
Reference in New Issue
Block a user