}
static void
-dhcp_renew(void *arg)
+dhcp_startrenew(void *arg)
{
struct interface *ifp = arg;
- struct dhcp_state *state = D_STATE(ifp);
- struct dhcp_lease *lease = &state->lease;
+ struct dhcp_state *state;
+ struct dhcp_lease *lease;
+
+ if ((state = D_STATE(ifp)) == NULL)
+ return;
+ /* Only renew in the bound or renew states */
+ if (state->state != DHS_BOUND &&
+ state->state != DHS_RENEW)
+ return;
+
+ /* Remove the timeout as the renew may have been forced. */
+ eloop_timeout_delete(ifp->ctx->eloop, dhcp_startrenew, ifp);
+
+ lease = &state->lease;
logger(ifp->ctx, LOG_DEBUG, "%s: renewing lease of %s",
ifp->name, inet_ntoa(lease->addr));
- logger(ifp->ctx, LOG_DEBUG, "%s: rebind in %"PRIu32" seconds,"
- " expire in %"PRIu32" seconds",
- ifp->name, lease->rebindtime - lease->renewaltime,
- lease->leasetime - lease->renewaltime);
state->state = DHS_RENEW;
state->xid = dhcp_xid(ifp);
+ state->interval = 0;
send_renew(ifp);
}
+void
+dhcp_renew(struct interface *ifp)
+{
+
+ dhcp_startrenew(ifp);
+}
+
static void
dhcp_arp_announced(struct arp_state *astate)
{
state->state = DHS_REBIND;
eloop_timeout_delete(ifp->ctx->eloop, send_renew, ifp);
state->lease.server.s_addr = 0;
+ state->interval = 0;
ifp->options->options &= ~(DHCPCD_CSR_WARNED |
DHCPCD_ROUTER_HOST_ROUTE_WARNED);
send_rebind(ifp);
lease->renewaltime = lease->rebindtime = lease->leasetime;
else {
eloop_timeout_add_sec(ifp->ctx->eloop,
- (time_t)lease->renewaltime, dhcp_renew, ifp);
+ (time_t)lease->renewaltime, dhcp_startrenew, ifp);
eloop_timeout_add_sec(ifp->ctx->eloop,
(time_t)lease->rebindtime, dhcp_rebind, ifp);
eloop_timeout_add_sec(ifp->ctx->eloop,
log_dhcp(LOG_ERR, "Force Renew from", ifp, dhcp, from);
/* The rebind and expire timings are still the same, we just
* enter the renew state early */
- if (state->state == DHS_BOUND) {
- eloop_timeout_delete(ifp->ctx->eloop,
- dhcp_renew, ifp);
+ if (state->state == DHS_BOUND)
dhcp_renew(ifp);
- } else {
+ else {
eloop_timeout_delete(ifp->ctx->eloop,
send_inform, ifp);
dhcp_inform(ifp);
void dhcp_abort(struct interface *);
void dhcp_discover(void *);
void dhcp_inform(struct interface *);
+void dhcp_renew(struct interface *);
void dhcp_bind(struct interface *);
void dhcp_reboot_newopts(struct interface *, unsigned long long);
void dhcp_close(struct interface *);
#define dhcp_drop(a, b) {}
#define dhcp_start(a) {}
#define dhcp_abort(a) {}
+#define dhcp_renew(a) {}
#define dhcp_reboot(a, b) (b = b)
#define dhcp_reboot_newopts(a, b) (b = b)
#define dhcp_close(a) {}
struct dhcp6_state *state;
ifp = arg;
- state = D6_STATE(ifp);
+ if ((state = D6_STATE(ifp)) == NULL)
+ return;
+
+ /* Only renew in the bound or renew states */
+ if (state->state != DH6S_BOUND &&
+ state->state != DH6S_RENEW)
+ return;
+
+ /* Remove the timeout as the renew may have been forced. */
+ eloop_timeout_delete(ifp->ctx->eloop, dhcp6_startrenew, ifp);
+
state->state = DH6S_RENEW;
state->RTC = 0;
state->IRT = REN_TIMEOUT;
dhcp6_sendrenew(ifp);
}
+void dhcp6_renew(struct interface *ifp)
+{
+
+ dhcp6_startrenew(ifp);
+}
+
int
dhcp6_dadcompleted(const struct interface *ifp)
{
ifp->name, op);
return;
}
- eloop_timeout_delete(ifp->ctx->eloop,
- dhcp6_startrenew, ifp);
dhcp6_startrenew(ifp);
break;
case DHCP6_INFORMATION_REQ:
int dhcp6_has_public_addr(const struct interface *);
int dhcp6_start(struct interface *, enum DH6S);
void dhcp6_reboot(struct interface *);
+void dhcp6_renew(struct interface *);
ssize_t dhcp6_env(char **, const char *, const struct interface *,
const struct dhcp6_message *, size_t);
void dhcp6_free(struct interface *);
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd September 30, 2015
+.Dd November 13, 2015
.Dt DHCPCD 8
.Os
.Sh NAME
.Nd a DHCP client
.Sh SYNOPSIS
.Nm
-.Op Fl 46ABbDdEGgHJKLMpqTV
+.Op Fl 46ABbDdEGgHJKLMNpqTV
.Op Fl C , Fl Fl nohook Ar hook
.Op Fl c , Fl Fl script Ar script
.Op Fl e , Fl Fl env Ar value
This may also cause
.Xr wpa_supplicant 8
to reload its configuration for each interface as well.
+.It Fl N , Fl Fl renew Op Ar interface
+Notifies
+.Nm
+to renew existing addresses on the specified
+.Ar interface .
+If no interface is specified then this applies to all interfaces.
+If
+.Nm
+is not running, then it starts up as normal.
+Unlike the
+.Fl n , Fl Fl rebind
+option above, the configuration for
+.Nm
+and
+.Xr wpa_supplicant 8
+is not reloaded.
.It Fl o , Fl Fl option Ar option
Request the DHCP
.Ar option
}
}
+static void
+dhcpcd_ifrenew(struct interface *ifp)
+{
+
+#define DHCPCD_RARENEW (DHCPCD_IPV6 | DHCPCD_IPV6RS)
+ if (ifp->options->options & DHCPCD_LINK &&
+ ifp->carrier != LINK_DOWN)
+ {
+ dhcp_renew(ifp);
+ if ((ifp->options->options & DHCPCD_RARENEW) == DHCPCD_RARENEW)
+ ipv6nd_startrs(ifp);
+ dhcp6_renew(ifp);
+ }
+}
+
+static void
+dhcpcd_renew(struct dhcpcd_ctx *ctx)
+{
+ struct interface *ifp;
+
+ TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+ dhcpcd_ifrenew(ifp);
+ }
+}
+
#ifdef USE_SIGNALS
#define sigmsg "received %s, %s"
static void
signal_cb(int sig, void *arg)
{
struct dhcpcd_ctx *ctx = arg;
- struct interface *ifp;
unsigned long long opts;
int exit_code;
ctx->argc - ctx->ifc);
return;
case SIGUSR1:
- logger(ctx, LOG_INFO, sigmsg, "SIGUSR1", "reconfiguring");
- TAILQ_FOREACH(ifp, ctx->ifaces, next) {
- ipv4_applyaddr(ifp);
- }
+ logger(ctx, LOG_INFO, sigmsg, "SIGUSR1", "renewing");
+ dhcpcd_renew(ctx);
return;
case SIGUSR2:
logger_close(ctx);
{
struct interface *ifp;
unsigned long long opts;
- int opt, oi, do_reboot;
+ int opt, oi, do_reboot, do_renew;
size_t len, l;
char *tmp, *p;
optind = 0;
oi = 0;
opts = 0;
- do_reboot = 0;
+ do_reboot = do_renew = 0;
while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
{
switch (opt) {
case 'x':
opts |= DHCPCD_EXITING;
break;
+ case 'N':
+ do_renew = 1;
+ break;
}
}
return 0;
}
+ if (do_renew) {
+ if (optind == argc) {
+ dhcpcd_renew(ctx);
+ return 0;
+ }
+ for (oi = optind; oi < argc; oi++) {
+ if ((ifp = if_find(ctx->ifaces, argv[oi])) == NULL)
+ continue;
+ dhcpcd_ifrenew(ifp);
+ }
+ return 0;
+ }
+
reload_config(ctx);
/* XXX: Respect initial commandline options? */
reconf_reboot(ctx, do_reboot, argc, argv, optind - 1);
sig = SIGTERM;
siga = "TERM";
break;
+ case 'N':
+ sig = SIGUSR1;
+ siga = "USR1";
+ break;
#endif
case 'T':
i = 1;
logger(&ctx, LOG_INFO, "sending signal %s to pid %d",
siga, pid);
if (pid == 0 || kill(pid, sig) != 0) {
- if (sig != SIGHUP && errno != EPERM)
+ if (sig != SIGHUP && sig != SIGUSR1 && errno != EPERM)
logger(&ctx, LOG_ERR, ""PACKAGE" not running");
if (pid != 0 && errno != ESRCH) {
logger(&ctx, LOG_ERR, "kill: %m");
goto exit_failure;
}
unlink(ctx.pidfile);
- if (sig != SIGHUP)
+ if (sig != SIGHUP && sig != SIGUSR1)
goto exit_failure;
} else {
struct timespec ts;
{"nolink", no_argument, NULL, 'K'},
{"noipv4ll", no_argument, NULL, 'L'},
{"master", no_argument, NULL, 'M'},
+ {"renew", no_argument, NULL, 'N'},
{"nooption", optional_argument, NULL, 'O'},
{"require", required_argument, NULL, 'Q'},
{"static", required_argument, NULL, 'S'},
case 'g': /* FALLTHROUGH */
case 'n': /* FALLTHROUGH */
case 'x': /* FALLTHROUGH */
+ case 'N': /* FALLTHROUGH */
case 'T': /* FALLTHROUGH */
case 'U': /* FALLTHROUGH */
case 'V': /* We need to handle non interface options */
/* Don't set any optional arguments here so we retain POSIX
* compatibility with getopt */
#define IF_OPTS "46bc:de:f:gh:i:j:kl:m:no:pqr:s:t:u:v:wxy:z:" \
- "ABC:DEF:GHI:JKLMO:Q:S:TUVW:X:Z:"
+ "ABC:DEF:GHI:JKLMNO:Q:S:TUVW:X:Z:"
#define DEFAULT_TIMEOUT 30
#define DEFAULT_REBOOT 5