changeset 6:47aa3f1e5ce7 draft

Set the rfds correctly so we can get a reply after re-sending a request. Set the seconds elasped and maximum message size correctly in DHCP messages. Now compiles on Linux 2.4 kernels.
author Roy Marples <roy@marples.name>
date Fri, 01 Dec 2006 12:50:53 +0000
parents 154ec90943ef
children 57e17fb9cc78
files ChangeLog Makefile client.c dhcp.c dhcp.h interface.c interface.h socket.c socket.h
diffstat 9 files changed, 109 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Nov 30 15:58:45 2006 +0000
+++ b/ChangeLog	Fri Dec 01 12:50:53 2006 +0000
@@ -1,3 +1,6 @@
+Set the rfds correctly so we can get a reply after re-sending a request.
+Set the seconds elasped and maximum message size correctly in DHCP messages.
+Now compiles on Linux 2.4 kernels. 
 xmalloc dhcp objects so we can swap pointer around easily.
 
 dhcpcd-3.0.1
--- a/Makefile	Thu Nov 30 15:58:45 2006 +0000
+++ b/Makefile	Fri Dec 01 12:50:53 2006 +0000
@@ -1,6 +1,6 @@
 # Should work for both GNU make and BSD mke
 
-VERSION = 3.0.1
+VERSION = 3.0.2_pre1
 
 INSTALL ?= install
 CFLAGS ?= -Wall -O2 -pedantic -std=gnu99
--- a/client.c	Thu Nov 30 15:58:45 2006 +0000
+++ b/client.c	Fri Dec 01 12:50:53 2006 +0000
@@ -31,6 +31,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "arp.h"
@@ -64,15 +65,20 @@
 #define SOCKET_OPEN		1
 
 #define SOCKET_MODE(_mode) \
- if (iface->fd >= 0) close (iface->fd); \
-iface->fd = -1; \
-if (_mode == SOCKET_OPEN) \
-if (open_socket (iface, false) < 0) { retval = -1; goto eexit; } \
-mode = _mode;
+{ \
+  if (iface->fd >= 0) close (iface->fd); \
+  iface->fd = -1; \
+  if (_mode == SOCKET_OPEN) \
+  if (open_socket (iface, false) < 0) { retval = -1; goto eexit; } \
+  mode = _mode; \
+}
 
 #define SEND_MESSAGE(_type) \
-last_type = _type; \
-send_message (iface, dhcp, xid, _type, options);
+{ \
+  last_type = _type; \
+  last_send = uptime (); \
+  send_message (iface, dhcp, xid, _type, options); \
+}
 
 static int daemonise (char *pidfile)
 {
@@ -127,10 +133,11 @@
   int retval;
   dhcpmessage_t message;
   dhcp_t *dhcp;
-  int type;
-  int last_type = DHCP_REQUEST;
+  int type = DHCP_DISCOVER;
+  int last_type = DHCP_DISCOVER;
   bool daemonised = false;
   unsigned long start = 0;
+  unsigned long last_send = 0;
   int sig;
   unsigned char *buffer = NULL;
   int buffer_len = 0;
@@ -162,18 +169,23 @@
 
   while (1)
     {
-      maxfd = signal_fd_set (&rset, iface->fd);
-
       if (timeout > 0 || (options->timeout == 0 &&
 			  (state != STATE_INIT || xid)))
 	{
 	  if (options->timeout == 0 || dhcp->leasetime == -1)
 	    {
 	      logger (LOG_DEBUG, "waiting on select for infinity");
+	      maxfd = signal_fd_set (&rset, iface->fd);
 	      retval = select (maxfd + 1, &rset, NULL, NULL, NULL);
 	    }
 	  else
 	    {
+	      /* Resend our message if we're getting loads of packets
+		 that aren't for us. This mainly happens on Linux as it
+		 doesn't have a nice BPF filter. */
+	      if (iface->fd > -1 && uptime () - last_send >= TIMEOUT_MINI)
+		SEND_MESSAGE (last_type);
+
 	      logger (LOG_DEBUG, "waiting on select for %d seconds",
 		      timeout);
 	      /* If we're waiting for a reply, then we re-send the last
@@ -189,10 +201,11 @@
 		    tv.tv_sec = timeout;
 		  tv.tv_usec = 0;
 		  start = uptime ();
+		  maxfd = signal_fd_set (&rset, iface->fd);
 		  retval = select (maxfd + 1, &rset, NULL, NULL, &tv);
-		  if (retval == 0 && iface->fd != -1)
-		    send_message (iface, dhcp, xid, last_type, options);
 		  timeout -= uptime () - start;
+		  if (retval == 0 && iface->fd != -1 && timeout > 0)
+		    SEND_MESSAGE (last_type);
 		}
 	    }
 	}
@@ -297,6 +310,7 @@
 
 	      SOCKET_MODE (SOCKET_OPEN);
 	      timeout = options->timeout;
+	      iface->start_uptime = uptime ();
 	      if (dhcp->address.s_addr == 0)
 		{
 		  logger (LOG_INFO, "broadcasting for a lease");
@@ -316,6 +330,7 @@
 	      state = STATE_RENEWING;
 	      xid = random_xid ();
 	    case STATE_RENEWING:
+	      iface->start_uptime = uptime ();
 	      logger (LOG_INFO, "renewing lease of %s", inet_ntoa
 		      (dhcp->address));
 	      SOCKET_MODE (SOCKET_OPEN);
@@ -332,6 +347,9 @@
 	      break;
 	    case STATE_REQUESTING:
 	      logger (LOG_ERR, "timed out");
+	      if (! daemonised)
+		goto eexit;
+
 	      state = STATE_INIT;
 	      SOCKET_MODE (SOCKET_CLOSED);
 	      timeout = 0;
@@ -384,6 +402,7 @@
 	      if ((type = parse_dhcpmessage (new_dhcp, &message)) < 0)
 		{
 		  logger (LOG_ERR, "failed to parse packet");
+		  free_dhcp (new_dhcp);
 		  continue;
 		}
 
@@ -397,7 +416,6 @@
 	  /* No packets for us, so wait until we get one */
 	  if (! valid)
 	    {
-	      free_dhcp (new_dhcp);
 	      free (new_dhcp);
 	      continue;
 	    }
--- a/dhcp.c	Thu Nov 30 15:58:45 2006 +0000
+++ b/dhcp.c	Fri Dec 01 12:50:53 2006 +0000
@@ -27,6 +27,7 @@
 
 #include <limits.h>
 #include <math.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -54,6 +55,7 @@
 		     unsigned long xid, char type, options_t *options)
 {
   dhcpmessage_t message;
+  unsigned char *m = (unsigned char *) &message;
   unsigned char *p = (unsigned char *) &message.options;
   unsigned char *n_params = NULL;
   unsigned long l;
@@ -80,7 +82,11 @@
   message.op = DHCP_BOOTREQUEST;
   message.hwtype = ARPHRD_ETHER;
   message.hwlen = ETHER_ADDR_LEN;
-  message.secs = htons (10);
+  long up = uptime() - iface->start_uptime;
+  if (up < 0 || up > UINT16_MAX)
+    message.secs = htons (UINT16_MAX);
+  else
+    message.secs = htons (up);
   message.xid = xid;
   memcpy (&message.hwaddr, &iface->ethernet_address, ETHER_ADDR_LEN);
   message.cookie = htonl (MAGIC_COOKIE);
@@ -108,7 +114,7 @@
     {
       *p++ = DHCP_MAXMESSAGESIZE;
       *p++ = 2;
-      uint16_t sz = htons (sizeof (struct udp_dhcp_packet));
+      uint16_t sz = htons (sizeof (dhcpmessage_t));
       memcpy (p, &sz, 2);
       p += 2;
     }
@@ -217,9 +223,9 @@
       if (options->userclass)
 	{
 	  *p++ = DHCP_USERCLASS;
-	  *p++ = l = strlen (options->userclass);
-	  memcpy (p, options->userclass, l);
-	  p += l;
+	  *p++ = options->userclass_len;
+	  memcpy (p, &options->userclass, options->userclass_len);
+	  p += options->userclass_len;
 	}
       
       *p++ = DHCP_CLASSID;
@@ -245,15 +251,19 @@
       p += ETHER_ADDR_LEN;
     }
 
-  *p = DHCP_END;
+  *p++ = DHCP_END;
+
+  unsigned int message_length = p - m;
 
   struct udp_dhcp_packet packet;
   memset (&packet, 0, sizeof (struct udp_dhcp_packet));
-  make_dhcp_packet (&packet, (unsigned char *) &message, from, to);
+  make_dhcp_packet (&packet, (unsigned char *) &message, message_length,
+		    from, to);
 
   logger (LOG_DEBUG, "Sending %s with xid %d", dhcp_message[(int) type], xid);
   return send_packet (iface, ETHERTYPE_IP, (unsigned char *) &packet,
-		      sizeof (struct udp_dhcp_packet));
+		      message_length + sizeof (struct ip) +
+		      sizeof (struct udphdr));
 }
 
 static unsigned long getnetmask (unsigned long ip_in)
--- a/dhcp.h	Thu Nov 30 15:58:45 2006 +0000
+++ b/dhcp.h	Fri Dec 01 12:50:53 2006 +0000
@@ -31,6 +31,9 @@
 #include "dhcpcd.h"
 #include "interface.h"
 
+/* Max MTU - defines dhcp option length */
+#define MTU_MAX			1500
+
 /* UDP port numbers for DHCP */
 #define DHCP_SERVER_PORT 67
 #define DHCP_CLIENT_PORT 68
@@ -51,6 +54,7 @@
 #define	DHCP_RELEASE		7
 #define DHCP_INFORM		8
 
+
 /* DHCP options */
 enum DHCP_OPTIONS
 {
@@ -150,24 +154,37 @@
   char *rootpath;
 } dhcp_t;
 
+/* Sizes for DHCP options */
+#define HWADDR_LEN		16
+#define SERVERNAME_LEN		64
+#define BOOTFILE_LEN		128
+#define DHCP_UDP_LEN		(20 + 8)
+#define DHCP_BASE_LEN		(4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4)
+#define DHCP_RESERVE_LEN	(4 + 4 + 4 + 4 + 2)
+#define DHCP_FIXED_LEN		(DHCP_BASE_LEN + HWADDR_LEN + \
+				+ SERVERNAME_LEN + BOOTFILE_LEN)
+#define DHCP_OPTION_LEN		(MTU_MAX - DHCP_FIXED_LEN - DHCP_UDP_LEN \
+				 - DHCP_RESERVE_LEN)
+
+
 typedef struct dhcpmessage_t
 {
-  char op;		/* message type */
-  char hwtype;		/* hardware address type */
-  char hwlen;		/* hardware address length */
-  char hwopcount;	/* should be zero in client's message */
-  int32_t xid;		/* transaction id */
-  int16_t secs;		/* elapsed time in sec. from trying to boot */
+  unsigned char op;				/* message type */
+  unsigned char hwtype;				/* hardware address type */
+  unsigned char hwlen;				/* hardware address length */
+  unsigned char hwopcount;			/* should be zero in client's message */
+  int32_t xid;				/* transaction id */
+  int16_t secs;				/* elapsed time in sec. from trying to boot */
   int16_t flags;
-  int32_t ciaddr;		/* (previously allocated) client IP address */
-  int32_t yiaddr;		/* 'your' client IP address */
-  int32_t siaddr;		/* should be zero in client's messages */
-  int32_t giaddr;		/* should be zero in client's messages */
-  unsigned char hwaddr[16];	/* client's hardware address */
-  char servername[64];	/* server host name, null terminated string */
-  char bootfile[128];	/* boot file name, null terminated string */
+  int32_t ciaddr;			/* (previously allocated) client IP address */
+  int32_t yiaddr;			/* 'your' client IP address */
+  int32_t siaddr;			/* should be zero in client's messages */
+  int32_t giaddr;			/* should be zero in client's messages */
+  unsigned char hwaddr[HWADDR_LEN];	/* client's hardware address */
+  char servername[SERVERNAME_LEN];	/* server host name, null terminated string */
+  char bootfile[BOOTFILE_LEN];		/* boot file name, null terminated string */
   uint32_t cookie;
-  unsigned char options[308];	/* message options - cookie */
+  unsigned char options[DHCP_OPTION_LEN];	/* message options - cookie */
 } dhcpmessage_t;
 
 struct udp_dhcp_packet
--- a/interface.c	Thu Nov 30 15:58:45 2006 +0000
+++ b/interface.c	Fri Dec 01 12:50:53 2006 +0000
@@ -28,6 +28,7 @@
 
 /* Netlink suff */
 #ifdef __linux__ 
+#include <asm/types.h> /* Needed for 2.4 kernels */
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 #include <netinet/ether.h>
@@ -157,16 +158,12 @@
       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)
     {
-      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;
-	}
+      logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", strerror (errno));
+      close (s);
+      return NULL;
     }
 
   close (s);
--- a/interface.h	Thu Nov 30 15:58:45 2006 +0000
+++ b/interface.h	Fri Dec 01 12:50:53 2006 +0000
@@ -61,6 +61,8 @@
 
   struct in_addr previous_address;
   route_t *previous_routes;
+
+  long start_uptime;
 } interface_t;
 
 void free_address (address_t *addresses);
--- a/socket.c	Thu Nov 30 15:58:45 2006 +0000
+++ b/socket.c	Fri Dec 01 12:50:53 2006 +0000
@@ -37,6 +37,7 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "dhcp.h"
@@ -66,7 +67,6 @@
       uint8_t a = 0;
       memcpy (&a, w, 1);
       sum += ntohs (a) << 8;
-      // sum += a;
     }
 
   sum = (sum >> 16) + (sum & 0xffff);
@@ -76,7 +76,7 @@
 }
 
 void make_dhcp_packet(struct udp_dhcp_packet *packet,
-		      unsigned char *data,
+		      unsigned char *data, unsigned int length,
 		      struct in_addr source, struct in_addr dest)
 {
   struct ip *ip = &packet->ip;
@@ -91,7 +91,7 @@
      If we don't do the ordering like so then the udp checksum will be
      broken, so find another way of doing it! */
 
-  memcpy (&packet->dhcp, data, sizeof (dhcpmessage_t));
+  memcpy (&packet->dhcp, data, length);
 
   ip->ip_p = IPPROTO_UDP;
   ip->ip_src.s_addr = source.s_addr;
@@ -102,7 +102,7 @@
 
   udp->uh_sport = htons (DHCP_CLIENT_PORT);
   udp->uh_dport = htons (DHCP_SERVER_PORT);
-  udp->uh_ulen = htons (sizeof (struct udphdr) + sizeof (struct dhcpmessage_t));
+  udp->uh_ulen = htons (sizeof (struct udphdr) + length);
   ip->ip_len = udp->uh_ulen;
   udp->uh_sum = checksum ((unsigned char *) packet,
 			  sizeof (struct udp_dhcp_packet));
@@ -112,7 +112,7 @@
   ip->ip_id = 0;
   ip->ip_tos = IPTOS_LOWDELAY;
   ip->ip_len = htons (sizeof (struct ip) + sizeof (struct udphdr) +
-		      sizeof (struct dhcpmessage_t));
+		      length);
   ip->ip_id = 0;
   ip->ip_off = 0;
   ip->ip_ttl = IPDEFTTL;
@@ -334,6 +334,10 @@
       if (*buffer_len < 1)
 	{
 	  logger (LOG_ERR, "read: %s", strerror (errno));
+	  struct timespec tv;
+	  tv.tv_sec = 5;
+	  tv.tv_nsec = 0;
+	  nanosleep (&tv, NULL);
 	  return -1;
 	}
     }
@@ -397,7 +401,7 @@
   int flags;
   struct sockaddr_ll sll;
 
-  if ((fd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_IP))) == -1)
+  if ((fd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_IP))) < 0)
     {
       logger (LOG_ERR, "socket: %s", strerror (errno));
       return -1;
@@ -418,8 +422,6 @@
   else
     sll.sll_protocol = htons (ETH_P_IP);
   sll.sll_ifindex = if_nametoindex (iface->name);
-  sll.sll_halen = ETHER_ADDR_LEN;
-  memset(sll.sll_addr, 0xff, sizeof (sll.sll_addr));
 
   if (bind(fd, (struct sockaddr *) &sll, sizeof (struct sockaddr_ll)) == -1)
     {
@@ -427,7 +429,7 @@
       close (fd);
       return -1;
     }
-
+  
   if (iface->fd > -1)
     close (iface->fd);
   iface->fd = fd;
@@ -475,6 +477,10 @@
   if (bytes < 0)
     {
       logger (LOG_ERR, "read: %s", strerror (errno));
+      struct timespec tv;
+      tv.tv_sec = 5;
+      tv.tv_nsec = 0;
+      nanosleep (&tv, NULL);
       return -1;
     }
 
--- a/socket.h	Thu Nov 30 15:58:45 2006 +0000
+++ b/socket.h	Fri Dec 01 12:50:53 2006 +0000
@@ -29,7 +29,7 @@
 #include "interface.h"
 
 void make_dhcp_packet(struct udp_dhcp_packet *packet,
-		      unsigned char *data,
+		      unsigned char *data, unsigned int length,
 		      struct in_addr source, struct in_addr dest);
 
 int open_socket (interface_t *iface, bool arp);