From 933b80fa645924c9bc6bb0c32209ca0865d6a4b8 Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Mon, 12 Oct 2020 22:18:33 +0200 Subject: Checkpoint: added start/finish v6only --- client/dhclient.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++ client/scripts/linux | 8 ++++++ includes/dhcpd.h | 10 +++++++- 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/client/dhclient.c b/client/dhclient.c index 7a7837cb..b989d1b7 100644 --- a/client/dhclient.c +++ b/client/dhclient.c @@ -1242,6 +1242,73 @@ void state_init (cpp) send_discover (client); } +/* v6only_timeout is called when the V6ONLY_WAIT timer expired. */ + +void finish_v6only(cpp) + void *cpp; +{ + struct client_state *client = cpp; + client->state = S_INIT; + state_init(cpp); +} + +/* + * state_v6only is called when a requested v6-only-preferred option was + * returned by the server. */ + +void start_v6only(packet, client) + struct packet *packet; + struct client_state *client; +{ + struct option_cache *oc; + struct data_string data; + uint32_t v6only_wait = 0; + struct timeval tv; + + /* Get the V6ONLY_WAIT timer. */ + oc = lookup_option(&dhcp_universe, packet->options, + DHO_V6_ONLY_PREFERRED); + if (!oc) { + /* Should not happen... */ + return; + } + + memset(&data, 0, sizeof(data)); + + if (evaluate_option_cache(&data, packet, (struct lease *)0, client, + packet->options, (struct option_state *)0, + &global_scope, oc, MDL)) { + if (data.len > 3) + v6only_wait = getULong(data.data); + data_string_forget(&data, MDL); + } + + if (v6only_wait < MIN_V6ONLY_WAIT) + v6only_wait = MIN_V6ONLY_WAIT; + + /* Enter V6ONLY state. */ + + client->state = S_V6ONLY; + + /* Run the client script. */ + script_init(client, "V6ONLY", NULL); + if (client->active) { + script_write_params(client, "old_", client->active); + destroy_client_lease(client->active); + client->active = NULL; + } + script_write_requested(client); + client_envadd(client, "", "v6-only-preferred", "%lu", + (long unsigned)v6only_wait); + script_go(client); + + /* Trigger finish_v6only after V6ONLY_WAIT seconds. */ + tv.tv_sec = cur_tv.tv_sec + v6only_wait; + tv.tv_usec = cur_tv.tv_usec; + + add_timeout(&tv, finish_v6only, client, 0, 0); +} + /* * state_selecting is called when one or more DHCPOFFER packets have been * received and a configurable period of time has passed. @@ -1650,6 +1717,7 @@ void state_stop (cpp) cancel_timeout(send_discover, client); cancel_timeout(send_request, client); cancel_timeout(state_bound, client); + cancel_timeout(finish_v6only, client); /* If we have an address, unconfigure it. */ if (client->active) { @@ -4623,6 +4691,7 @@ void client_location_changed () case S_REBINDING: case S_STOPPED: case S_DECLINING: + case S_V6ONLY: break; } client -> state = S_INIT; @@ -4701,6 +4770,7 @@ void do_release(client) cancel_timeout (state_init, client); cancel_timeout (send_request, client); cancel_timeout (state_reboot, client); + cancel_timeout (finish_v6only, client); client -> state = S_STOPPED; #if defined(DHCPv6) && defined(DHCP4o6) diff --git a/client/scripts/linux b/client/scripts/linux index 0c429697..63257bca 100755 --- a/client/scripts/linux +++ b/client/scripts/linux @@ -400,6 +400,14 @@ case "$reason" in ;; + V6ONLY) + if [ -n "$old_ip_address" ]; then + # flush leased IP + ${ip} -4 addr flush dev ${interface} label ${interface} + fi + + ;; + ### DHCPv6 Handlers # TODO handle prefix change: ?based on ${old_ip6_prefix} and ${new_ip6_prefix}? diff --git a/includes/dhcpd.h b/includes/dhcpd.h index b20dd240..caeeaeda 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -877,6 +877,10 @@ struct lease_state { # define DEFAULT_ABANDON_LEASE_TIME 86400 #endif +#if !defined (MIN_V6ONLY_WAIT) +# define MIN_V6ONLY_WAIT 300 +#endif + #define PLM_IGNORE 0 #define PLM_PREFER 1 #define PLM_EXACT 2 @@ -1204,7 +1208,8 @@ enum dhcp_state { S_RENEWING = 6, S_REBINDING = 7, S_DECLINING = 8, - S_STOPPED = 9 + S_STOPPED = 9, + S_V6ONLY = 10 }; /* Possible pending client operations. */ @@ -3003,6 +3008,9 @@ void state_bound (void *); void state_stop (void *); void state_panic (void *); +void start_v6only (struct packet *, struct client_state *); +void finish_v6only (void *); + void bind_lease (struct client_state *); void make_client_options (struct client_state *, -- cgit v1.2.1