changeset 4:1405eec5277b draft

Quote all vars in the info file. -n and -G options now work as stated in the man page. Handle select loops with large timeouts and infinite lease times. Correctly set the broadcast flag. make_dhcp_packet already has byte ordered addresses, thanks to TGL for the fix. If we get a NAK then always re-enter the INIT state.
author Roy Marples <roy@marples.name>
date Thu, 30 Nov 2006 13:04:23 +0000
parents 8f7278d3d297
children 154ec90943ef
files ChangeLog Makefile client.c configure.c dhcp.c dhcp.h dhcpcd.8 dhcpcd.c dhcpcd.h interface.c socket.c
diffstat 11 files changed, 322 insertions(+), 268 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Nov 27 21:32:54 2006 +0000
+++ b/ChangeLog	Thu Nov 30 13:04:23 2006 +0000
@@ -1,3 +1,12 @@
+dhcpcd-3.0.1
+Quote all vars in the info file.
+-n and -G options now work as stated in the man page.
+Handle select loops with large timeouts and infinite lease times.
+Correctly set the broadcast flag.
+make_dhcp_packet already has byte ordered addresses, thanks to TGL
+for the fix.
+If we get a NAK then always re-enter the INIT state.
+
 dhcpcd-3.0.0
 A complete rewrite by Roy Marples <uberlord@gentoo.org>
 
--- a/Makefile	Mon Nov 27 21:32:54 2006 +0000
+++ b/Makefile	Thu Nov 30 13:04:23 2006 +0000
@@ -1,6 +1,6 @@
 # Should work for both GNU make and BSD mke
 
-VERSION = 3.0.0
+VERSION = 3.0.1
 
 INSTALL ?= install
 CFLAGS ?= -Wall -O2 -pedantic -std=gnu99
--- a/client.c	Mon Nov 27 21:32:54 2006 +0000
+++ b/client.c	Thu Nov 30 13:04:23 2006 +0000
@@ -43,6 +43,10 @@
 #include "signals.h"
 #include "socket.h"
 
+/* We need this for our maximum timeout as FreeBSD's select cannot handle
+   any higher than this. Is there a better way of working this out? */
+#define SELECT_MAX 100000000 
+
 /* This is out mini timeout.
    Basically we resend the last request every TIMEOUT_MINI seconds. */
 #define TIMEOUT_MINI 		3
@@ -73,22 +77,13 @@
 
 static int daemonise (char *pidfile)
 {
-  FILE *fp;
-
   if (daemon (0, 0) < 0)
     {
       logger (LOG_ERR, "unable to daemonise: %s", strerror (errno));
       return -1;
     }
 
-  if ((fp = fopen (pidfile, "w")) == NULL)
-    {
-      logger (LOG_ERR, "fopen `%s': %m", pidfile);
-      return -1;
-    }
-
-  fprintf (fp, "%u\n", getpid ());
-  fclose (fp);
+  make_pid (pidfile);
 
   return 0;
 }
@@ -127,7 +122,7 @@
   int state = STATE_INIT;
   struct timeval tv;
   int xid = 0;
-  unsigned long timeout = 0;
+  long timeout = 0;
   fd_set rset;
   int maxfd;
   int retval;
@@ -150,14 +145,12 @@
   /* Remove all existing addresses.
      After all, we ARE a DHCP client whose job it is to configure the
      interface. We only do this on start, so persistent addresses can be added
-     afterwards by the user if needed.
-     */
+     afterwards by the user if needed. */
   flush_addresses (iface->name);
 
   memset (&dhcp, 0, sizeof (dhcp_t));
   memset (&last_dhcp, 0, sizeof (dhcp_t));
 
-  dhcp.leasetime = options->leasetime;
   strcpy (dhcp.classid, options->classid);
   if (options->clientid[0])
     strcpy (dhcp.clientid, options->clientid);
@@ -165,22 +158,18 @@
     sprintf (dhcp.clientid, "%s", ether_ntoa (&iface->ethernet_address));
 
   if (options->requestaddress.s_addr != 0)
-    memcpy (&dhcp.address, &options->requestaddress, sizeof (struct in_addr));
+    dhcp.address.s_addr = options->requestaddress.s_addr;
 
   signal_setup ();
 
   while (1)
     {
-      int timeout_secs = timeout - uptime();
-      tv.tv_sec = timeout - uptime ();
-      tv.tv_usec = 0;
-
       maxfd = signal_fd_set (&rset, iface->fd);
 
-      if (timeout_secs > 0 || (options->timeout == 0 &&
-			       (state != STATE_INIT || xid)))
+      if (timeout > 0 || (options->timeout == 0 &&
+			  (state != STATE_INIT || xid)))
 	{
-	  if (options->timeout == 0)
+	  if (options->timeout == 0 || dhcp.leasetime == -1)
 	    {
 	      logger (LOG_DEBUG, "waiting on select for infinity");
 	      retval = select (maxfd + 1, &rset, NULL, NULL, NULL);
@@ -188,27 +177,24 @@
 	  else
 	    {
 	      logger (LOG_DEBUG, "waiting on select for %d seconds",
-		      timeout_secs);
+		      timeout);
 	      /* If we're waiting for a reply, then we re-send the last
 		 DHCP request periodically in-case of a bad line */
-	      if (iface->fd == -1)
-		{
-		  tv.tv_sec = timeout_secs;
-		  tv.tv_usec = 0;
-		  retval = select (maxfd + 1, &rset, NULL, NULL, &tv);
-		}
-	      else
+	      retval = 0;
+	      while (timeout > 0 && retval == 0)
 		{
-		  while (timeout_secs > 0)
-		    {
-		      tv.tv_sec = TIMEOUT_MINI;
-		      tv.tv_usec = 0;
-		      retval = select (maxfd + 1, &rset, NULL, NULL, &tv);
-		      if (retval != 0)
-			break;
-		      send_message (iface, &last_dhcp, xid, last_type, options);
-		      timeout_secs -= TIMEOUT_MINI;
-		    }
+		  if (iface->fd == -1)
+		    tv.tv_sec = SELECT_MAX;
+		  else
+		    tv.tv_sec = TIMEOUT_MINI;
+		  if (timeout < tv.tv_sec)
+		    tv.tv_sec = timeout;
+		  tv.tv_usec = 0;
+		  start = uptime ();
+		  retval = select (maxfd + 1, &rset, NULL, NULL, &tv);
+		  if (retval == 0 && iface->fd != -1)
+		    send_message (iface, &last_dhcp, xid, last_type, options);
+		  timeout -= uptime () - start;
 		}
 	    }
 	}
@@ -236,7 +222,6 @@
 	      switch (state)
 		{
 		case STATE_BOUND:
-		  SOCKET_MODE (SOCKET_OPEN);
 		case STATE_RENEWING:
 		case STATE_REBINDING:
 		  state = STATE_RENEW_REQUESTED;
@@ -313,51 +298,54 @@
 		    }
 		}
 
-	      timeout = uptime () + options->timeout;
+	      SOCKET_MODE (SOCKET_OPEN);
+	      timeout = options->timeout;
 	      if (dhcp.address.s_addr == 0)
-		logger (LOG_INFO, "broadcasting for lease");
+		{
+		  logger (LOG_INFO, "broadcasting for a lease");
+		  SEND_MESSAGE (DHCP_DISCOVER);
+		}
 	      else
-		logger (LOG_INFO, "broadcasting for lease of %s",
-			inet_ntoa (dhcp.address));
+		{
+		  logger (LOG_INFO, "broadcasting for a lease of %s",
+			  inet_ntoa (dhcp.address));
+		  SEND_MESSAGE (DHCP_REQUEST);
+		  state = STATE_REQUESTING;
+		}
 
-	      SOCKET_MODE (SOCKET_OPEN);
-	      SEND_MESSAGE (DHCP_DISCOVER);
 	      break;
 	    case STATE_BOUND:
+	    case STATE_RENEW_REQUESTED:
 	      state = STATE_RENEWING;
+	      xid = random_xid ();
 	    case STATE_RENEWING:
 	      logger (LOG_INFO, "renewing lease of %s", inet_ntoa
 		      (dhcp.address));
 	      SOCKET_MODE (SOCKET_OPEN);
-	      xid = random_xid ();
 	      SEND_MESSAGE (DHCP_REQUEST);
-	      timeout = uptime() + (dhcp.rebindtime - dhcp.renewaltime);
+	      timeout = dhcp.rebindtime - dhcp.renewaltime;
 	      state = STATE_REBINDING;
 	      break;
 	    case STATE_REBINDING:
 	      logger (LOG_ERR, "lost lease, attemping to rebind");
-	      xid = random_xid ();
+	      SOCKET_MODE (SOCKET_OPEN);
 	      SEND_MESSAGE (DHCP_DISCOVER);
-	      timeout = uptime() + (dhcp.leasetime - dhcp.rebindtime);
+	      timeout = dhcp.leasetime - dhcp.rebindtime;
 	      state = STATE_INIT;
 	      break;
 	    case STATE_REQUESTING:
-	    case STATE_RENEW_REQUESTED:
 	      logger (LOG_ERR, "timed out");
-	      if (! daemonised)
-		{
-		  retval = -1;
-		  goto eexit;
-		}
-
 	      state = STATE_INIT;
-	      timeout = uptime();
+	      SOCKET_MODE (SOCKET_CLOSED);
+	      timeout = 0;
 	      xid = 0;
-	      SOCKET_MODE (SOCKET_OPEN);
+	      free_dhcp (&dhcp);
+	      memset (&dhcp, 0, sizeof (dhcp_t));
+	      memset (&last_dhcp, 0, sizeof (dhcp_t));
 	      break;
 
 	    case STATE_RELEASED:
-	      timeout = 0x7fffffff;
+	      dhcp.leasetime = -1;
 	      break;
 	    }
 	}
@@ -386,15 +374,16 @@
 
 	      if (xid != message.xid)
 		{
-		  logger (LOG_ERR, "ignoring transaction %d as it's not ours (%d)",
+		  logger (LOG_ERR,
+			  "ignoring packet with xid %d as it's not ours (%d)",
 			  message.xid, xid);
 		  continue;
 		}
 
-	      logger (LOG_DEBUG, "got packet with transaction %d", message.xid);
+	      logger (LOG_DEBUG, "got a packet with xid %d", message.xid);
 	      if ((type = parse_dhcpmessage (&dhcp, &message)) < 0)
 		{
-		  logger (LOG_ERR, "failed to parse message");
+		  logger (LOG_ERR, "failed to parse packet");
 		  continue;
 		}
 
@@ -409,6 +398,20 @@
 	  if (! valid)
 	    continue;
 
+	  /* We should restart on a NAK */
+	  if (type == DHCP_NAK)
+	    {
+	      logger (LOG_INFO, "received NAK: %s", dhcp.message);
+	      state = STATE_INIT;
+	      timeout = 0;
+	      xid = 0;
+	      free_dhcp (&dhcp);
+	      memset (&dhcp, 0, sizeof (dhcp_t));
+	      memset (&last_dhcp, 0, sizeof (dhcp_t));
+	      configure (options, iface, &dhcp);
+	      continue;
+	    }
+
 	  switch (state)
 	    {
 	    case STATE_INIT:
@@ -474,11 +477,16 @@
 			      dhcp.rebindtime);
 		    }
 
-		  logger (LOG_INFO, "leased %s for %d seconds",
-			  inet_ntoa (dhcp.address), dhcp.leasetime);
+		  if (dhcp.leasetime == -1)
+		    logger (LOG_INFO, "leased %s for infinity",
+			    inet_ntoa (dhcp.address));
+		  else
+		    logger (LOG_INFO, "leased %s for %u seconds",
+			    inet_ntoa (dhcp.address),
+			    dhcp.leasetime, dhcp.renewaltime);
+
 		  state = STATE_BOUND;
-		  start = uptime ();
-		  timeout = start + dhcp.renewaltime;
+		  timeout = dhcp.renewaltime;
 		  xid = 0;
 
 		  if (configure (options, iface, &dhcp) < 0 && ! daemonised)
@@ -497,8 +505,6 @@
 		      daemonised = true;
 		    }
 		}
-	      else if (type == DHCP_NAK)
-		logger (LOG_INFO, "received NAK: %s", dhcp.message);
 	      else if (type == DHCP_OFFER)
 		logger (LOG_INFO, "got subsequent offer of %s, ignoring ",
 			inet_ntoa (dhcp.address));
@@ -511,12 +517,14 @@
 	}
       else if (retval == -1 && errno == EINTR)
 	{
-	  /* Signal interupt will be handled above */
+	  /* The interupt will be handled above */
 	}
       else 
 	{
-	  /* An error occured */
+	  /* An error occured. As we heavily depend on select, we abort. */
 	  logger (LOG_ERR, "error on select: %s", strerror (errno));
+	  retval = -1;
+	  goto eexit;
 	}
     }
 
@@ -524,15 +532,10 @@
   SOCKET_MODE (SOCKET_CLOSED);
 
   /* Remove our config if we need to */
-  if (dhcp.address.s_addr != 0 && ! options->persistent && daemonised)
-    {
-      dhcp.address.s_addr = 0;
-      dhcp.netmask.s_addr = 0;
-      dhcp.broadcast.s_addr = 0;
+  free_dhcp (&dhcp);
+  memset (&dhcp, 0, sizeof (dhcp_t));
+  if (iface->previous_address.s_addr != 0 && ! options->persistent && daemonised)
       configure (options, iface, &dhcp);
-    }
-
-  free_dhcp (&dhcp);
 
   if (iface)
     {
--- a/configure.c	Mon Nov 27 21:32:54 2006 +0000
+++ b/configure.c	Thu Nov 30 13:04:23 2006 +0000
@@ -252,11 +252,11 @@
       return -1;
     }
 
-  fprintf (f, "IPADDR=%s\n", inet_ntoa (dhcp->address));
-  fprintf (f, "NETMASK=%s\n", inet_ntoa (dhcp->netmask));
-  fprintf (f, "BROADCAST=%s\n", inet_ntoa (dhcp->broadcast));
+  fprintf (f, "IPADDR='%s'\n", inet_ntoa (dhcp->address));
+  fprintf (f, "NETMASK='%s'\n", inet_ntoa (dhcp->netmask));
+  fprintf (f, "BROADCAST='%s'\n", inet_ntoa (dhcp->broadcast));
   if (dhcp->mtu > 0)
-    fprintf (f, "MTU=%d\n", dhcp->mtu);
+    fprintf (f, "MTU='%d'\n", dhcp->mtu);
   
   if (dhcp->routes)
     {
@@ -295,9 +295,9 @@
 
   if (dhcp->fqdn)
     {
-      fprintf (f, "FQDNFLAGS=%u\n", dhcp->fqdn->flags);
-      fprintf (f, "FQDNRCODE1=%u\n", dhcp->fqdn->r1);
-      fprintf (f, "FQDNRCODE2=%u\n", dhcp->fqdn->r2);
+      fprintf (f, "FQDNFLAGS='%u'\n", dhcp->fqdn->flags);
+      fprintf (f, "FQDNRCODE1='%u'\n", dhcp->fqdn->r1);
+      fprintf (f, "FQDNRCODE2='%u'\n", dhcp->fqdn->r2);
       fprintf (f, "FQDNHOSTNAME='%s'\n", dhcp->fqdn->name);
     }
 
@@ -331,12 +331,12 @@
   if (dhcp->rootpath)
     fprintf (f, "ROOTPATH='%s'\n", cleanmetas (dhcp->rootpath));
 
-  fprintf (f, "DHCPSID=%s\n", inet_ntoa (dhcp->serveraddress));
-  fprintf (f, "DHCPCHADDR=%s\n", ether_ntoa (&iface->ethernet_address));
+  fprintf (f, "DHCPSID='%s'\n", inet_ntoa (dhcp->serveraddress));
+  fprintf (f, "DHCPCHADDR='%s'\n", ether_ntoa (&iface->ethernet_address));
   fprintf (f, "DHCPSNAME='%s'\n", cleanmetas (dhcp->servername));
-  fprintf (f, "LEASETIME=%u\n", dhcp->leasetime);
-  fprintf (f, "RENEWALTIME=%u\n", dhcp->renewaltime);
-  fprintf (f, "REBINDTIME=%u\n", dhcp->rebindtime);
+  fprintf (f, "LEASETIME='%u'\n", dhcp->leasetime);
+  fprintf (f, "RENEWALTIME='%u'\n", dhcp->renewaltime);
+  fprintf (f, "REBINDTIME='%u'\n", dhcp->rebindtime);
   fprintf (f, "INTERFACE='%s'\n", iface->name);
   fprintf (f, "CLASSID='%s'\n", cleanmetas (dhcp->classid));
   fprintf (f, "CLIENTID='%s'\n", cleanmetas (dhcp->clientid));
@@ -392,14 +392,17 @@
 	  iface->previous_routes = NULL;
 	}
 
+      /* Only reset things if we had set them before */
       if (iface->previous_address.s_addr != 0)
-	del_address (iface->name, iface->previous_address);
-      memset (&iface->previous_address, 0, sizeof (struct in_addr));
+	{
+	  del_address (iface->name, iface->previous_address);
+	  memset (&iface->previous_address, 0, sizeof (struct in_addr));
 
-      restore_resolv (iface->name);
-      
-      /* We currently don't have a resolvconf style programs for ntp/nis */
-      exec_script (options->script, iface->infofile, "down");
+	  restore_resolv (iface->name);
+
+	  /* we currently don't have a resolvconf style programs for ntp/nis */
+	  exec_script (options->script, iface->infofile, "down");
+	}
       return 0;
     }
 
@@ -434,6 +437,11 @@
       
       for (route = dhcp->routes; route; route = route->next)
 	{
+	  /* Don't set default routes if not asked to */
+	  if (route->destination.s_addr == 0 && route->netmask.s_addr == 0
+	      && ! options->dogateway)
+	    continue;
+
 	  int remember = add_route (iface->name, route->destination,
 				    route->netmask,  route->gateway,
 				    options->metric);
--- a/dhcp.c	Mon Nov 27 21:32:54 2006 +0000
+++ b/dhcp.c	Thu Nov 30 13:04:23 2006 +0000
@@ -36,6 +36,8 @@
 #include "logger.h"
 #include "socket.h"
 
+#define BROADCAST_FLAG 0x8000
+
 static char *dhcp_message[] = {
   [DHCP_DISCOVER] 	= "DHCP_DISCOVER",
   [DHCP_OFFER]		= "DHCP_OFFER",
@@ -55,10 +57,24 @@
   unsigned char *p = (unsigned char *) &message.options;
   unsigned char *n_params = NULL;
   unsigned long l;
+  struct in_addr from;
+  struct in_addr to;
 
   if (!iface || !options || !dhcp)
     return -1;
 
+  if (type == DHCP_RELEASE || type == DHCP_INFORM ||
+      (type == DHCP_REQUEST &&
+       iface->previous_address.s_addr == dhcp->address.s_addr))
+    from.s_addr = dhcp->address.s_addr;
+  else
+    from.s_addr = 0;
+
+  if (type == DHCP_RELEASE)
+    to.s_addr = dhcp->serveraddress.s_addr;
+  else
+    to.s_addr = 0;
+
   memset (&message, 0, sizeof (dhcpmessage_t));
 
   message.op = DHCP_BOOTREQUEST;
@@ -67,11 +83,22 @@
   message.secs = htons (10);
   message.xid = xid;
   memcpy (&message.hwaddr, &iface->ethernet_address, ETHER_ADDR_LEN);
-  message.cookie = htonl(MAGIC_COOKIE);
+  message.cookie = htonl (MAGIC_COOKIE);
 
-  if (iface->previous_address.s_addr != 0 &&
-      iface->previous_address.s_addr == dhcp->address.s_addr)
-    message.ciaddr = iface->previous_address.s_addr; 
+  /* This logic should be improved so that we don't need to set the 0
+     flag as it's done in the above memset statement */
+  if (type == DHCP_REQUEST
+      && dhcp->address.s_addr == iface->previous_address.s_addr
+      && iface->previous_address.s_addr != 0)
+    message.flags = 0;
+  else
+    message.flags = htons (BROADCAST_FLAG);
+
+  if (iface->previous_address.s_addr != 0
+      && (type == DHCP_INFORM || type == DHCP_RELEASE
+	  || (type == DHCP_REQUEST
+	      && iface->previous_address.s_addr == dhcp->address.s_addr)))
+    message.ciaddr = iface->previous_address.s_addr;
 
   *p++ = DHCP_MESSAGETYPE; 
   *p++ = 1;
@@ -86,72 +113,73 @@
       p += 2;
     }
 
-  if (dhcp->address.s_addr != 0 && iface->previous_address.s_addr == 0)
-    {
-      *p++ = DHCP_ADDRESS;
-      *p++ = 4;
-      memcpy (p, &dhcp->address.s_addr, 4);
-      p += 4;
+#define PUTADDR(_type, _val) \
+    { \
+      *p++ = _type; \
+      *p++ = 4; \
+      memcpy (p, &_val.s_addr, 4); \
+      p += 4; \
     }
+  if (dhcp->address.s_addr != 0 && iface->previous_address.s_addr == 0
+      && type != DHCP_RELEASE)
+    PUTADDR (DHCP_ADDRESS, dhcp->address);
 
   if (dhcp->serveraddress.s_addr != 0 && dhcp->address.s_addr !=0 &&
-      iface->previous_address.s_addr == 0)
-    {
-      *p++ = DHCP_SERVERIDENTIFIER;
-      *p++ = 4;
-      memcpy (p, &dhcp->serveraddress.s_addr, 4);
-      p += 4;
-
-      /* Blank out the server address so we broadcast */
-      if (type == DHCP_REQUEST) dhcp->serveraddress.s_addr = 0;
-    }
+      (iface->previous_address.s_addr == 0 || type == DHCP_RELEASE))
+    PUTADDR (DHCP_SERVERIDENTIFIER, dhcp->serveraddress);
+#undef PUTADDR
 
   if (type == DHCP_REQUEST || type == DHCP_DISCOVER)
     {
-      if (dhcp->leasetime > 0)
+      if (options->leasetime != 0)
 	{
 	  *p++ = DHCP_LEASETIME;
 	  *p++ = 4;
-	  uint32_t ul = htonl (dhcp->leasetime);
+	  uint32_t ul = htonl (options->leasetime);
 	  memcpy (p, &ul, 4);
 	  p += 4;
 	}
     }
 
-  *p++ = DHCP_PARAMETERREQUESTLIST;
-  n_params = p;
-  *p++ = 0;
-
-  if (type == DHCP_REQUEST)
+  if (type == DHCP_DISCOVER || type == DHCP_INFORM || type == DHCP_REQUEST)
     {
-      *p++ = DHCP_RENEWALTIME;
-      *p++ = DHCP_REBINDTIME;
-      *p++ = DHCP_NETMASK;
-      *p++ = DHCP_BROADCAST;
-      *p++ = DHCP_CSR;
-      /* RFC 3442 states classless static routes should be before routers
-       * and static routes as classless static routes override them both */
-      *p++ = DHCP_ROUTERS;
-      *p++ = DHCP_STATICROUTE;
-      *p++ = DHCP_HOSTNAME;
-      *p++ = DHCP_DNSSEARCH;
-      *p++ = DHCP_DNSDOMAIN;
-      *p++ = DHCP_DNSSERVER;
-      *p++ = DHCP_NISDOMAIN;
-      *p++ = DHCP_NISSERVER;
-      *p++ = DHCP_NTPSERVER;
-      /* These parameters were requested by dhcpcd-2.0 and earlier
-	 but we never did anything with them */
-      /*    *p++ = DHCP_DEFAULTIPTTL;
-       *p++ = DHCP_MASKDISCOVERY;
-       *p++ = DHCP_ROUTERDISCOVERY; */
+      *p++ = DHCP_PARAMETERREQUESTLIST;
+      n_params = p;
+      *p++ = 0;
+
+      /* If we don't request one item, then we get defaults back which
+	 we don't want */
+      if (type == DHCP_DISCOVER)
+	{
+	  *p++ = DHCP_DNSSERVER;
+	}
+      else
+	{
+	  *p++ = DHCP_RENEWALTIME;
+	  *p++ = DHCP_REBINDTIME;
+	  *p++ = DHCP_NETMASK;
+	  *p++ = DHCP_BROADCAST;
+	  *p++ = DHCP_CSR;
+	  /* RFC 3442 states classless static routes should be before routers
+	   * and static routes as classless static routes override them both */
+	  *p++ = DHCP_ROUTERS;
+	  *p++ = DHCP_STATICROUTE;
+	  *p++ = DHCP_HOSTNAME;
+	  *p++ = DHCP_DNSSEARCH;
+	  *p++ = DHCP_DNSDOMAIN;
+	  *p++ = DHCP_DNSSERVER;
+	  *p++ = DHCP_NISDOMAIN;
+	  *p++ = DHCP_NISSERVER;
+	  *p++ = DHCP_NTPSERVER;
+	  /* These parameters were requested by dhcpcd-2.0 and earlier
+	     but we never did anything with them */
+	  /*    *p++ = DHCP_DEFAULTIPTTL;
+	   *p++ = DHCP_MASKDISCOVERY;
+	   *p++ = DHCP_ROUTERDISCOVERY; */
+	}
+
+      *n_params = p - n_params - 1;
     }
-  else
-    /* Always request one parameter so we don't get the server default
-       when we don't actally need any at this time */
-    *p++ = DHCP_DNSSERVER;
-
-  *n_params = p - n_params - 1;
 
   if (type == DHCP_REQUEST)
     {
@@ -184,19 +212,22 @@
 	}
     }
 
-  if (options->userclass)
+  if (type != DHCP_DECLINE && type != DHCP_RELEASE)
     {
-      *p++ = DHCP_USERCLASS;
-      *p++ = l = strlen (options->userclass);
-      memcpy (p, options->userclass, l);
+      if (options->userclass)
+	{
+	  *p++ = DHCP_USERCLASS;
+	  *p++ = l = strlen (options->userclass);
+	  memcpy (p, options->userclass, l);
+	  p += l;
+	}
+      
+      *p++ = DHCP_CLASSID;
+      *p++ = l = strlen (options->classid);
+      memcpy (p, options->classid, l);
       p += l;
     }
 
-  *p++ = DHCP_CLASSID;
-  *p++ = l = strlen (options->classid);
-  memcpy (p, options->classid, l);
-  p += l;
-
   *p++ = DHCP_CLIENTID;
   if (options->clientid[0])
     {
@@ -218,8 +249,7 @@
 
   struct udp_dhcp_packet packet;
   memset (&packet, 0, sizeof (struct udp_dhcp_packet));
-  make_dhcp_packet (&packet, (unsigned char *) &message,
-		    dhcp->address, dhcp->serveraddress);
+  make_dhcp_packet (&packet, (unsigned char *) &message, from, to);
 
   logger (LOG_DEBUG, "Sending %s with xid %d", dhcp_message[(int) type], xid);
   return send_packet (iface, ETHERTYPE_IP, (unsigned char *) &packet,
@@ -330,7 +360,7 @@
     {
       memset (route, 0, sizeof (route_t));
 
-      cidr = (int) *q++;
+      cidr = *q++;
       if (cidr == 0)
 	ocets = 0;
       else if (cidr < 9)
@@ -475,94 +505,77 @@
 	case DHCP_MESSAGETYPE:
 	  retval = (int) *p;
 	  break;
-
+#define GET_UINT32(_val) \
+	  memcpy (&_val, p, sizeof (uint32_t));
+#define GET_UINT32_H(_val) \
+	  GET_UINT32 (_val); \
+	  _val = ntohl (_val);
 	case DHCP_ADDRESS:
-	  memcpy (&dhcp->address.s_addr, p, 4);
+	  GET_UINT32 (dhcp->address.s_addr);
 	  break;
 	case DHCP_NETMASK:
-	  memcpy (&dhcp->netmask.s_addr, p, 4);
+	  GET_UINT32 (dhcp->netmask.s_addr);
 	  break;
 	case DHCP_BROADCAST:
-	  memcpy (&dhcp->broadcast.s_addr, p, 4);
+	  GET_UINT32 (dhcp->broadcast.s_addr);
 	  break;
 	case DHCP_SERVERIDENTIFIER:
-	  memcpy (&dhcp->serveraddress.s_addr, p, 4);
+	  GET_UINT32 (dhcp->serveraddress.s_addr);
 	  break;
-
 	case DHCP_LEASETIME:
-	  dhcp->leasetime = ntohl (* (uint32_t *) p);
+	  GET_UINT32_H (dhcp->leasetime);
 	  break;
 	case DHCP_RENEWALTIME:
-	  dhcp->renewaltime = ntohl (* (uint32_t *) p);
+	  GET_UINT32_H (dhcp->renewaltime);
 	  break;
 	case DHCP_REBINDTIME:
-	  dhcp->rebindtime = ntohl (* (uint32_t *) p);
+	  GET_UINT32_H (dhcp->rebindtime);
 	  break;
 	case DHCP_MTU:
-	  dhcp->mtu = ntohs (* (uint16_t *) p);
+	  GET_UINT32_H (dhcp->mtu);
 	  /* Minimum legal mtu is 68 */
 	  if (dhcp->mtu > 0 && dhcp->mtu < 68)
 	    dhcp->mtu = 68;
 	  break;
-
-	case DHCP_HOSTNAME:
-	  if (dhcp->hostname)
-	    free (dhcp->hostname);
-	  dhcp->hostname = xmalloc (length + 1);
-	  memcpy (dhcp->hostname, p, length);
-	  dhcp->hostname[length] = '\0';
-	  break;
+#undef GET_UINT32_H
+#undef GET_UINT32
 
+#define GETSTR(_var) \
+	  if (_var) free (_var); \
+	  _var = xmalloc (length + 1); \
+	  memcpy (_var, p, length); \
+	  memset (_var + length, 0, 1);
+	case DHCP_HOSTNAME:
+	  GETSTR (dhcp->hostname);
+	  break;
 	case DHCP_DNSDOMAIN:
-	  if (dhcp->dnsdomain)
-	    free (dhcp->dnsdomain);
-	  dhcp->dnsdomain = xmalloc (length + 1);
-	  memcpy (dhcp->dnsdomain, p, length);
-	  dhcp->dnsdomain[length] = '\0';
+	  GETSTR (dhcp->dnsdomain);
 	  break;
-
 	case DHCP_MESSAGE:
-	  if (dhcp->message)
-	    free (dhcp->message);
-	  dhcp->message = xmalloc (length + 1);
-	  memcpy (dhcp->message, p, length);
-	  dhcp->message[length] = '\0';
+	  GETSTR (dhcp->message);
 	  break;
-
 	case DHCP_ROOTPATH:
-	  if (dhcp->rootpath)
-	    free (dhcp->rootpath);
-	  dhcp->rootpath = xmalloc (length + 1);
-	  memcpy (dhcp->rootpath, p, length);
-	  dhcp->rootpath[length] = '\0';
+	  GETSTR (dhcp->rootpath);
+	  break;
+	case DHCP_NISDOMAIN:
+	  GETSTR (dhcp->nisdomain);
 	  break;
+#undef GETSTR
 
-	case DHCP_NISDOMAIN:
-	  if (dhcp->nisdomain)
-	    free (dhcp->nisdomain);
-	  dhcp->nisdomain = xmalloc (length + 1);
-	  memcpy (dhcp->nisdomain, p, length);
-	  dhcp->nisdomain[length] = '\0';
-	  break;
-
+#define GETADDR(_var) \
+	  if (_var) free (_var); \
+	  _var = xmalloc (sizeof (address_t)); \
+	  dhcp_add_address (_var, p, length);
 	case DHCP_DNSSERVER:
-	  if (dhcp->dnsservers)
-	    free_address (dhcp->dnsservers);
-	  dhcp->dnsservers = xmalloc (sizeof (address_t));
-	  dhcp_add_address (dhcp->dnsservers, p, length);
+	  GETADDR (dhcp->dnsservers);
 	  break;
 	case DHCP_NTPSERVER:
-	  if (dhcp->ntpservers)
-	    free_address (dhcp->ntpservers);
-	  dhcp->ntpservers = xmalloc (sizeof (address_t));
-	  dhcp_add_address (dhcp->ntpservers, p, length);
+	  GETADDR (dhcp->ntpservers);
 	  break;
 	case DHCP_NISSERVER:
-	  if (dhcp->nisservers)
-	    free_address (dhcp->nisservers);
-	  dhcp->nisservers = xmalloc (sizeof (address_t));
-	  dhcp_add_address (dhcp->nisservers, p, length);
+	  GETADDR (dhcp->nisservers);
 	  break;
+#undef GETADDR
 
 	case DHCP_DNSSEARCH:
 	  if (dhcp->dnssearch)
@@ -612,9 +625,9 @@
 
 eexit:
   /* Fill in any missing fields */
-  if (!dhcp->netmask.s_addr)
+  if (! dhcp->netmask.s_addr)
     dhcp->netmask.s_addr = getnetmask (dhcp->address.s_addr);
-  if (!dhcp->broadcast.s_addr)
+  if (! dhcp->broadcast.s_addr)
     dhcp->broadcast.s_addr = dhcp->address.s_addr | ~dhcp->netmask.s_addr;
 
   /* If we have classess static routes then we discard
--- a/dhcp.h	Mon Nov 27 21:32:54 2006 +0000
+++ b/dhcp.h	Thu Nov 30 13:04:23 2006 +0000
@@ -128,9 +128,9 @@
   struct in_addr broadcast;
   unsigned short mtu;
 
-  unsigned leasetime;
-  unsigned renewaltime;
-  unsigned rebindtime;
+  unsigned int leasetime;
+  unsigned int renewaltime;
+  unsigned int rebindtime;
   
   route_t *routes;
 
--- a/dhcpcd.8	Mon Nov 27 21:32:54 2006 +0000
+++ b/dhcpcd.8	Thu Nov 30 13:04:23 2006 +0000
@@ -1,6 +1,6 @@
 .\" $Id$
 .\"
-.TH dhcpcd 8 "15 August 2006" "dhcpcd 3.0"
+.TH dhcpcd 8 "30 November 2006" "dhcpcd 3.0"
 
 .SH NAME
 dhcpcd \- DHCP client daemon
@@ -144,9 +144,11 @@
 lease period when the lease is not renewed.
 .TP
 .BI \-s \ ipaddr
-Sends DHCP_DISCOVER message to DHCP server requesting to lease ip address
-ipaddr.
+Sends DHCP_REQUEST message requesting to lease IP address ipaddr.
 The ipaddr parameter must be in the form xxx.xxx.xxx.xxx.
+This effectively doubles the timeout period, as if we fail to get
+this IP address then we enter the INIT state and try to get any
+IP address.
 .TP
 .BI \-t \ timeout
 Specifies (in seconds ) for how long
--- a/dhcpcd.c	Mon Nov 27 21:32:54 2006 +0000
+++ b/dhcpcd.c	Thu Nov 30 13:04:23 2006 +0000
@@ -56,7 +56,7 @@
   _int = (int) _number; \
 }
 
-static pid_t readpid(char *pidfile)
+static pid_t read_pid(const char *pidfile)
 {
   FILE *fp;
   pid_t pid;
@@ -73,18 +73,18 @@
   return pid;
 }
 
-static int kill_pid (char *pidfile, int sig)
+void make_pid (const char *pidfile)
 {
-  pid_t pid = readpid (pidfile);
-  int r = 0;
+  FILE *fp;
 
-  if (!pid || (r = kill (pid, sig)))
+  if ((fp = fopen (pidfile, "w")) == NULL)
     {
-      logger (LOG_ERR, ""PACKAGE" not running");
-      unlink (pidfile);
+      logger (LOG_ERR, "fopen `%s': %s", pidfile, strerror (errno));
+      return;
     }
 
-  return r;
+  fprintf (fp, "%u\n", getpid ());
+  fclose (fp);
 }
 
 static void usage ()
@@ -330,20 +330,31 @@
 	    options.interface);
 
   if (options.signal != 0)
-    exit (kill_pid (options.pidfile, options.signal));
+    {
+      pid_t pid = read_pid (options.pidfile);
+      if (pid != 0)
+        logger (LOG_INFO, "sending signal %d to pid %d", options.signal, pid);
+     
+      int killed = -1;
+      if (! pid || (killed = kill (pid, options.signal)))
+	logger (options.signal == SIGALRM ? LOG_INFO : LOG_ERR, ""PACKAGE" not running");
+
+      if (pid != 0 && (options.signal != SIGALRM || killed != 0))
+	unlink (options.pidfile);
+
+      if (killed == 0)
+	exit (EXIT_SUCCESS);
+
+      if (options.signal != SIGALRM)
+	exit (EXIT_FAILURE);
+    }
 
   umask (022);
 
-  if (readpid (options.pidfile))
-    {
-      logger (LOG_ERR, ""PACKAGE" already running (%s)", options.pidfile);
-      exit (EXIT_FAILURE);
-    }
-
   if (mkdir (CONFIGDIR, S_IRUSR |S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP
 	     | S_IROTH | S_IXOTH) && errno != EEXIST )
     {
-      logger( LOG_ERR, "mkdir(\"%s\",0): %m\n", CONFIGDIR);
+      logger (LOG_ERR, "mkdir(\"%s\",0): %m\n", CONFIGDIR);
       exit (EXIT_FAILURE);
     }
 
@@ -354,6 +365,14 @@
       exit (EXIT_FAILURE);
     }
 
+  if (read_pid (options.pidfile))
+    {
+      logger (LOG_ERR, ""PACKAGE" already running (%s)", options.pidfile);
+      exit (EXIT_FAILURE);
+    }
+
+  make_pid (options.pidfile);
+
   logger (LOG_INFO, PACKAGE " " VERSION " starting");
   if (dhcp_run (&options))
     exit (EXIT_FAILURE);
--- a/dhcpcd.h	Mon Nov 27 21:32:54 2006 +0000
+++ b/dhcpcd.h	Thu Nov 30 13:04:23 2006 +0000
@@ -64,4 +64,6 @@
   char pidfile[PATH_MAX];
 } options_t;
 
+void make_pid (const char *pidfile);
+
 #endif
--- a/interface.c	Mon Nov 27 21:32:54 2006 +0000
+++ b/interface.c	Thu Nov 30 13:04:23 2006 +0000
@@ -51,10 +51,6 @@
 #include "logger.h"
 #include "pathnames.h"
 
-#ifndef IFF_NOTRAILERS
-#define	IFF_NOTRAILERS 0
-#endif
-
 void free_address (address_t *addresses)
 {
   if (!addresses)
@@ -99,7 +95,6 @@
 
   struct ifaddrs *ifap;
   struct ifaddrs *p;
-  unsigned int flags;
 
   if (getifaddrs (&ifap) != 0)
     return NULL;
@@ -122,7 +117,6 @@
 	  return NULL;
 	}
 
-      flags = p->ifa_flags;
 #ifdef __linux__
       memcpy (hwaddr, sll->sll_addr, ETHER_ADDR_LEN);
 #else
@@ -146,21 +140,6 @@
       return NULL;
     }
 
-  if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
-    {
-      logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno));
-      close (s);
-      return NULL;
-    }
-
-  ifr.ifr_flags |= IFF_UP | IFF_BROADCAST | IFF_NOTRAILERS | IFF_RUNNING;
-  if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
-    {
-      logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", strerror (errno));
-      close (s);
-      return NULL;
-    }
-
 #ifndef __linux__
   ifr.ifr_metric = metric;
   if (ioctl(s, SIOCSIFMETRIC, &ifr) < 0)
@@ -171,6 +150,25 @@
     }
 #endif
 
+  if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
+    {
+      logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno));
+      close (s);
+      return NULL;
+    }
+
+  /* Bring the interface up if we need to */
+  if (! (ifr.ifr_flags & IFF_UP))
+    {
+      ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+      if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
+	{
+	  logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", strerror (errno));
+	  close (s);
+	  return NULL;
+	}
+    }
+
   close (s);
 
   iface = xmalloc (sizeof (interface_t));
--- a/socket.c	Mon Nov 27 21:32:54 2006 +0000
+++ b/socket.c	Thu Nov 30 13:04:23 2006 +0000
@@ -94,11 +94,11 @@
   memcpy (&packet->dhcp, data, sizeof (dhcpmessage_t));
 
   ip->ip_p = IPPROTO_UDP;
-  ip->ip_src.s_addr = htonl (source.s_addr);
+  ip->ip_src.s_addr = source.s_addr;
   if (dest.s_addr == 0)
-    ip->ip_dst.s_addr = htonl (INADDR_BROADCAST);
+    ip->ip_dst.s_addr = INADDR_BROADCAST;
   else
-    ip->ip_dst.s_addr = htonl (dest.s_addr);
+    ip->ip_dst.s_addr = dest.s_addr;
 
   udp->uh_sport = htons (DHCP_CLIENT_PORT);
   udp->uh_dport = htons (DHCP_SERVER_PORT);