]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Implement support for RFC 3203, FORCERENEW message.
authorRoy Marples <roy@marples.name>
Fri, 31 Jan 2014 11:47:27 +0000 (11:47 +0000)
committerRoy Marples <roy@marples.name>
Fri, 31 Jan 2014 11:47:27 +0000 (11:47 +0000)
arp.c
arp.h
dhcp.c
dhcp.h
dhcpcd.8.in
dhcpcd.c
ipv4ll.c

diff --git a/arp.c b/arp.c
index 13779a480ada14541a6dc40362033c5b683d46ce..a2310180b6185bb7dbbab17ef0a93ce966f604f1 100644 (file)
--- a/arp.c
+++ b/arp.c
@@ -106,7 +106,6 @@ arp_failure(struct interface *ifp)
        unlink(state->leasefile);
        if (!state->lease.frominfo)
                dhcp_decline(ifp);
-       dhcp_close(ifp);
        eloop_timeout_delete(NULL, ifp);
        if (state->lease.frominfo)
                start_interface(ifp);
@@ -336,3 +335,19 @@ arp_start(struct interface *ifp)
        state->arping_index = 0;
        arp_probe(ifp);
 }
+
+void
+arp_close(struct interface *ifp)
+{
+       struct dhcp_state *state = D_STATE(ifp);
+
+       if (state == NULL)
+               return;
+
+       if (state->arp_fd != -1) {
+               eloop_event_delete(state->arp_fd);
+               close(state->arp_fd);
+               state->arp_fd = -1;
+       }
+}
+
diff --git a/arp.h b/arp.h
index c2d4fe51a8bf5e53630c4d4055ae2f1cda197818..2dac1bb754c10aa936282b749367684be3b58bee 100644 (file)
--- a/arp.h
+++ b/arp.h
@@ -45,4 +45,5 @@
 void arp_announce(void *);
 void arp_probe(void *);
 void arp_start(struct interface *);
+void arp_close(struct interface *);
 #endif
diff --git a/dhcp.c b/dhcp.c
index 3e9d2f80872e812327f656bfa80cc7aa86df545e..21b152a3c0639c929767b7c92df91dda5ae4b75b 100644 (file)
--- a/dhcp.c
+++ b/dhcp.c
@@ -1718,9 +1718,8 @@ dhcp_bind(void *arg)
        struct if_options *ifo = iface->options;
        struct dhcp_lease *lease = &state->lease;
        struct timeval tv;
+       uint8_t ipv4ll = 0;
 
-       /* We're binding an address now - ensure that sockets are closed */
-       dhcp_close(iface);
        state->reason = NULL;
        if (clock_monotonic)
                get_monotonic(&lease->boundtime);
@@ -1741,6 +1740,7 @@ dhcp_bind(void *arg)
                    iface->name, inet_ntoa(lease->addr));
                lease->leasetime = ~0U;
                state->reason = "IPV4LL";
+               ipv4ll = 1;
        } else if (ifo->options & DHCPCD_INFORM) {
                if (ifo->req_addr.s_addr != 0)
                        lease->addr.s_addr = ifo->req_addr.s_addr;
@@ -1822,6 +1822,8 @@ dhcp_bind(void *arg)
        }
        ipv4_applyaddr(iface);
        daemonise();
+       if (!ipv4ll)
+               arp_close(iface);
        state->state = DHS_BOUND;
        if (ifo->options & DHCPCD_ARP) {
                state->claims = 0;
@@ -2011,6 +2013,8 @@ dhcp_drop(struct interface *ifp, const char *reason)
        state = D_STATE(ifp);
        if (state == NULL)
                return;
+       dhcp_close(ifp);
+       arp_close(ifp);
        eloop_timeouts_delete(ifp, dhcp_expire, NULL);
        if (ifp->options->options & DHCPCD_RELEASE) {
                unlink(state->leasefile);
@@ -2164,6 +2168,49 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp,
                log_dhcp1(LOG_WARNING, "no authentication",
                    iface, dhcp, from, 0);
 
+       /* RFC 3203 */
+       if (type == DHCP_FORCERENEW) {
+               if (from->s_addr == INADDR_ANY ||
+                   from->s_addr == INADDR_BROADCAST)
+               {
+                       log_dhcp(LOG_ERR, "discarding Force Renew",
+                           iface, dhcp, from);
+                       return;
+               }
+               if (auth == NULL) {
+                       log_dhcp(LOG_ERR, "unauthenticated Force Renew",
+                           iface, dhcp, from);
+                       return;
+               }
+               if (state->state != DHS_BOUND) {
+                       log_dhcp(LOG_DEBUG, "not bound, ignoring Force Renew",
+                           iface, dhcp, from);
+                       return;
+               }
+               log_dhcp(LOG_ERR, "Force Renew from", iface, dhcp, from);
+               /* The rebind and expire timings are still the same, we just
+                * enter the renew state early */
+               eloop_timeout_delete(dhcp_renew, iface);
+               dhcp_renew(iface);
+               return;
+       }
+
+       if (state->state == DHS_BOUND) {
+               /* Before we supported FORCERENEW we closed off the raw
+                * port so we effectively ignored all messages.
+                * As such we'll not log by default here. */
+               //log_dhcp(LOG_DEBUG, "bound, ignoring", iface, dhcp, from);
+               return;
+       }
+
+       /* Ensure it's the right transaction */
+       if (state->xid != ntohl(dhcp->xid)) {
+               syslog(LOG_DEBUG,
+                   "%s: wrong xid 0x%x (expecting 0x%x) from %s",
+                   iface->name, ntohl(dhcp->xid), state->xid,
+                   inet_ntoa(*from));
+               return;
+       }
        /* reset the message counter */
        state->interval = 0;
 
@@ -2175,13 +2222,14 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp,
                        log_dhcp(LOG_WARNING, "reject NAK", iface, dhcp, from);
                        return;
                }
+
                /* We should restart on a NAK */
                log_dhcp(LOG_WARNING, "NAK:", iface, dhcp, from);
                if (!(options & DHCPCD_TEST)) {
                        dhcp_drop(iface, "NAK");
                        unlink(state->leasefile);
                }
-               dhcp_close(iface);
+
                /* If we constantly get NAKS then we should slowly back off */
                eloop_timeout_add_sec(state->nakoff, dhcp_discover, iface);
                if (state->nakoff == 0)
@@ -2291,11 +2339,6 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp,
        lease->frominfo = 0;
        eloop_timeout_delete(NULL, iface);
 
-       /* We now have an offer, so close the DHCP sockets.
-        * This allows us to safely ARP when broken DHCP servers send an ACK
-        * follows by an invalid NAK. */
-       dhcp_close(iface);
-
        if (ifo->options & DHCPCD_ARP &&
            state->addr.s_addr != state->offer->yiaddr)
        {
@@ -2441,14 +2484,6 @@ dhcp_handlepacket(void *arg)
                            iface->name, inet_ntoa(from));
                        continue;
                }
-               /* Ensure it's the right transaction */
-               if (state->xid != ntohl(dhcp->xid)) {
-                       syslog(LOG_DEBUG,
-                           "%s: wrong xid 0x%x (expecting 0x%x) from %s",
-                           iface->name, ntohl(dhcp->xid), state->xid,
-                           inet_ntoa(from));
-                       continue;
-               }
                /* Ensure packet is for us */
                if (iface->hwlen <= sizeof(dhcp->chaddr) &&
                    memcmp(dhcp->chaddr, iface->hwaddr, iface->hwlen))
@@ -2465,6 +2500,21 @@ dhcp_handlepacket(void *arg)
        free(dhcp);
 }
 
+static void
+dhcp_handleudp(void *arg)
+{
+       const struct interface *ifp;
+       const struct dhcp_state *state;
+       ssize_t bytes;
+       uint8_t buffer[sizeof(struct dhcp_message)];
+
+       ifp = arg;
+       state = D_CSTATE(ifp);
+       bytes = read(state->udp_fd, buffer, sizeof(buffer));
+       /* Just read what's in the UDP fd and discard it as we always read
+        * from the raw fd */
+}
+
 static int
 dhcp_open(struct interface *ifp)
 {
@@ -2491,15 +2541,13 @@ dhcp_open(struct interface *ifp)
                eloop_event_add(state->raw_fd, dhcp_handlepacket, ifp);
        }
        if (state->udp_fd == -1 &&
-           state->addr.s_addr != 0 &&
-           state->new != NULL &&
-           (state->new->cookie == htonl(MAGIC_COOKIE) ||
-           ifp->options->options & DHCPCD_INFORM))
+           ifp->options->options & DHCPCD_DHCP)
        {
                if (dhcp_openudp(ifp) == -1 && errno != EADDRINUSE) {
                        syslog(LOG_ERR, "%s: dhcp_openudp: %m", ifp->name);
                        return -1;
                }
+               eloop_event_add(state->udp_fd, dhcp_handleudp, ifp);
        }
        return 0;
 }
@@ -2686,7 +2734,6 @@ dhcp_start(struct interface *ifp)
                syslog(LOG_WARNING, "%s: needs a clientid to configure",
                    ifp->name);
                dhcp_drop(ifp, "FAIL");
-               dhcp_close(ifp);
                eloop_timeout_delete(NULL, ifp);
                return;
        }
diff --git a/dhcp.h b/dhcp.h
index b1777f85620ffbabc3f91a439c03ca638d14fc01..92e8bd2cc52a2637a04228635b820cac4608fe2f 100644 (file)
--- a/dhcp.h
+++ b/dhcp.h
@@ -57,6 +57,7 @@
 #define DHCP_NAK            6
 #define DHCP_RELEASE        7
 #define DHCP_INFORM         8
+#define DHCP_FORCERENEW     9
 
 /* Constants taken from RFC 2131. */
 #define T1                     0.5
index df49ab8b4544b3dfb7a018ab27e0d462e2f2a334..770d23a05442f8136719e0a36c1021ca378a10e1 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd January 30, 2014
+.Dd January 31, 2014
 .Dt DHCPCD 8
 .Os
 .Sh NAME
@@ -98,7 +98,8 @@ sets the hostname to the one supplied by the DHCP server.
 .Nm
 then daemonises and waits for the lease renewal time to lapse.
 It will then attempt to renew its lease and reconfigure if the new lease
-changes.
+changes when the lease beings to expire or the DHCP server sends message
+to renew early.
 .Pp
 .Nm
 is also an implementation of the BOOTP client specified in
@@ -652,10 +653,10 @@ running on the
 .Xr resolvconf 8
 .Sh STANDARDS
 RFC\ 951, RFC\ 1534, RFC\ 2104, RFC\ 2131, RFC\ 2132, RFC\ 2855, RFC\ 3004,
-RFC\ 3118, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396, RFC\ 3397, RFC\ 3442,
-RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075, RFC\ 4242, RFC\ 4361,
-RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833, RFC\ 5227, RFC\ 5942,
-RFC\ 5969, RFC\ 6106.
+RFC\ 3118, RFC\ 3203, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396, RFC\ 3397,
+RFC\ 3442, RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075, RFC\ 4242,
+RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833, RFC\ 5227,
+RFC\ 5942, RFC\ 5969, RFC\ 6106.
 .Sh AUTHORS
 .An Roy Marples Aq Mt roy@marples.name
 .Sh BUGS
index 70210f118fcd7294c3494e6d639809b613726438..16b8e8afcd40d9b9202febeda3ac81a6a184a2aa 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -328,7 +328,6 @@ stop_interface(struct interface *ifp)
        dhcp6_drop(ifp, NULL);
        ipv6nd_drop(ifp);
        dhcp_drop(ifp, "STOP");
-       dhcp_close(ifp);
        eloop_timeout_delete(NULL, ifp);
        if (ifp->options->options & DHCPCD_DEPARTED)
                script_runreason(ifp, "DEPARTED");
@@ -526,7 +525,6 @@ handle_carrier(int carrier, int flags, const char *ifname)
                        if (ifp->carrier == LINK_UP)
                                syslog(LOG_INFO, "%s: carrier lost", ifp->name);
                        ifp->carrier = LINK_DOWN;
-                       dhcp_close(ifp);
                        dhcp6_drop(ifp, "EXPIRE6");
                        ipv6nd_drop(ifp);
                        /* Don't blindly delete our knowledge of LL addresses.
index 731a6f4bc3c1f250953f06629b6fe145f29db75d..b32b9f693d093e654de3c28b89755ed9db488fc5 100644 (file)
--- a/ipv4ll.c
+++ b/ipv4ll.c
@@ -151,7 +151,6 @@ ipv4ll_handle_failure(void *arg)
                }
        }
 
-       dhcp_close(ifp);
        free(state->offer);
        state->offer = NULL;
        eloop_timeout_delete(NULL, ifp);