]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
Checkpoint: code done, need tests
authorFrancis Dupont <fdupont@isc.org>
Tue, 13 Oct 2020 08:15:00 +0000 (10:15 +0200)
committerFrancis Dupont <fdupont@isc.org>
Tue, 13 Oct 2020 08:15:00 +0000 (10:15 +0200)
client/dhclient.c
includes/dhcpd.h

index b989d1b79492d5afbce7d9f33858562ab9c86583..1a7ac85e8a91c8f807436808dd12b2a972c62625 100644 (file)
@@ -1242,49 +1242,79 @@ void state_init (cpp)
        send_discover (client);
 }
 
-/* v6only_timeout is called when the V6ONLY_WAIT timer expired. */
+/* check_v6only is called by dhcpoffer and dhcpack. It checks if a
+ * requested v6-only-preferred option is present and returned the
+ * V6ONLY_WAIT delay to suspend DHCPv4. */
 
-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)
+uint32_t check_v6only(packet, client)
        struct packet *packet;
        struct client_state *client;
 {
+       int i;
+       struct option **req;
+       isc_boolean_t found = ISC_FALSE;
        struct option_cache *oc;
        struct data_string data;
        uint32_t v6only_wait = 0;
-       struct timeval tv;
 
+       /* Check if the v6-only-preferred was requested. */
+       req = client->config->requested_options;
+
+       if (req == NULL)
+               return 0;
+
+       for (i = 0 ; req[i] != NULL ; i++) {
+               if ((req[i]->universe == &dhcp_universe) &&
+                   (req[i]->code == DHO_V6_ONLY_PREFERRED)) {
+                       found = ISC_TRUE;
+                       break;
+               }
+       }
+
+       if (found == ISC_FALSE)
+               return 0;
+       
        /* Get the V6ONLY_WAIT timer. */
        oc = lookup_option(&dhcp_universe, packet->options,
                           DHO_V6_ONLY_PREFERRED);
-       if (!oc) {
-               /* Should not happen... */
-               return;
-       }
+       if (!oc)
+               return 0;
 
        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)
+               if (data.len > 3) {
                        v6only_wait = getULong(data.data);
+                       if (v6only_wait < MIN_V6ONLY_WAIT)
+                               v6only_wait = MIN_V6ONLY_WAIT;
+               }
                data_string_forget(&data, MDL);
        }
 
-       if (v6only_wait < MIN_V6ONLY_WAIT)
-               v6only_wait = MIN_V6ONLY_WAIT;
+       return (v6only_wait);
+}
+
+/* finish_v6only 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);
+}
+
+/*
+ * start_v6only is called when a requested v6-only-preferred option was
+ * returned by the server. */
+
+void start_v6only(client, v6only_wait)
+       struct client_state *client;
+       uint32_t v6only_wait;
+{
+       struct timeval tv;
 
        /* Enter V6ONLY state. */
 
@@ -1404,6 +1434,7 @@ void dhcpack (packet)
 {
        struct interface_info *ip = packet -> interface;
        struct client_state *client;
+       uint32_t v6only_wait;
        struct client_lease *lease;
        struct option_cache *oc;
        struct data_string ds;
@@ -1439,6 +1470,15 @@ void dhcpack (packet)
                  inet_ntoa(packet->raw->yiaddr),
                  piaddr (packet->client_addr));
 
+       /* Check v6only first. */
+       v6only_wait = check_v6only(packet, client);
+       if (v6only_wait > 0) {
+               log_info("v6 only preferred for %lu.",
+                        (long unsigned)v6only_wait);
+               start_v6only(client, v6only_wait);
+               return;
+       }
+
        lease = packet_to_lease (packet, client);
        if (!lease) {
                log_info ("packet_to_lease failed.");
@@ -2077,6 +2117,7 @@ void dhcpoffer (packet)
 {
        struct interface_info *ip = packet -> interface;
        struct client_state *client;
+       uint32_t v6only_wait;
        struct client_lease *lease, *lp;
        struct option **req;
        int i;
@@ -2112,6 +2153,15 @@ void dhcpoffer (packet)
                 inet_ntoa(packet->raw->yiaddr),
                 piaddr(packet->client_addr));
 
+       /* Check v6only first. */
+       v6only_wait = check_v6only(packet, client);
+       if (v6only_wait > 0) {
+               log_info("%s: v6 only preferred for %lu.", obuf,
+                        (long unsigned)v6only_wait);
+               start_v6only(client, v6only_wait);
+               return;
+       }
+
        /* If this lease doesn't supply the minimum required DHCPv4 parameters,
         * ignore it.
         */
index caeeaeda1552d8b732eadad37c56e0a8da99555d..f9217ea8eca2fa05d0b0d7b56f4fe9445b7e59f5 100644 (file)
@@ -3008,7 +3008,8 @@ void state_bound (void *);
 void state_stop (void *);
 void state_panic (void *);
 
-void start_v6only (struct packet *, struct client_state *);
+uint32_t check_v6only (struct packet *, struct client_state *);
+void start_v6only (struct client_state *, uint32_t);
 void finish_v6only (void *);
 
 void bind_lease (struct client_state *);