]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Set the rfds correctly so we can get a reply after re-sending a request.
authorRoy Marples <roy@marples.name>
Fri, 1 Dec 2006 12:50:53 +0000 (12:50 +0000)
committerRoy Marples <roy@marples.name>
Fri, 1 Dec 2006 12:50:53 +0000 (12:50 +0000)
Set the seconds elasped and maximum message size correctly in DHCP messages.
Now compiles on Linux 2.4 kernels.

ChangeLog
Makefile
client.c
dhcp.c
dhcp.h
interface.c
interface.h
socket.c
socket.h

index 76d8b3d1c1785678944b8d8d9cfe5a41928c6d47..dbfa1edd94f89884f10260ae4e3e705e3c1b26a7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
index bf03a21bf6590972c571da8ef5cd5846ed29d710..1c1992c9f15731d53cd95852b686139494e7ff2e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -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
index 655262815c0e0274f9158546d45546fd52d61b46..8a6530b8f84615881a682c7d91dc053d42df4772 100644 (file)
--- a/client.c
+++ b/client.c
@@ -31,6 +31,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "arp.h"
 #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 dhcp_run (options_t *options)
   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 @@ int dhcp_run (options_t *options)
 
   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 @@ int dhcp_run (options_t *options)
                    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 @@ int dhcp_run (options_t *options)
 
              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 @@ int dhcp_run (options_t *options)
              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 @@ int dhcp_run (options_t *options)
              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 @@ int dhcp_run (options_t *options)
              if ((type = parse_dhcpmessage (new_dhcp, &message)) < 0)
                {
                  logger (LOG_ERR, "failed to parse packet");
+                 free_dhcp (new_dhcp);
                  continue;
                }
 
@@ -397,7 +416,6 @@ int dhcp_run (options_t *options)
          /* No packets for us, so wait until we get one */
          if (! valid)
            {
-             free_dhcp (new_dhcp);
              free (new_dhcp);
              continue;
            }
diff --git a/dhcp.c b/dhcp.c
index 0e012908c918b6c94d1c9d56b2cd4172e00840f0..5f85947a853597c97502173bf3914a649e8634e5 100644 (file)
--- a/dhcp.c
+++ b/dhcp.c
@@ -27,6 +27,7 @@
 
 #include <limits.h>
 #include <math.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -54,6 +55,7 @@ size_t send_message (interface_t *iface, dhcp_t *dhcp,
                     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 @@ size_t send_message (interface_t *iface, dhcp_t *dhcp,
   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 @@ size_t send_message (interface_t *iface, dhcp_t *dhcp,
     {
       *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 @@ size_t send_message (interface_t *iface, dhcp_t *dhcp,
       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 @@ size_t send_message (interface_t *iface, dhcp_t *dhcp,
       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)
diff --git a/dhcp.h b/dhcp.h
index b5076b388eb4d15f69c897a060a70403f06face2..10104318d5218e28a43c945c59d3f0c4ffd86062 100644 (file)
--- a/dhcp.h
+++ b/dhcp.h
@@ -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 @@ typedef struct dhcp_t
   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
index dacc7a1f27666f2a65372f3800950b6811fb21a3..7631fafbc92416235729a781ce0e1bb10e406a09 100644 (file)
@@ -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 @@ interface_t *read_interface (const char *ifname, int metric)
       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);
index f118dc1e1658aef1340e46b732468ee00498446d..8b855459f44c0c0eb836aafc1b33305184e4892f 100644 (file)
@@ -61,6 +61,8 @@ typedef struct interface_t
 
   struct in_addr previous_address;
   route_t *previous_routes;
+
+  long start_uptime;
 } interface_t;
 
 void free_address (address_t *addresses);
index 5c33ba601bab8befec7fe3c3a29583a9fca46199..fb5864d3648df5deb33ff33c011015c7d590db48 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -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 @@ static uint16_t checksum (unsigned char *addr, uint16_t len)
       uint8_t a = 0;
       memcpy (&a, w, 1);
       sum += ntohs (a) << 8;
-      // sum += a;
     }
 
   sum = (sum >> 16) + (sum & 0xffff);
@@ -76,7 +76,7 @@ static uint16_t checksum (unsigned char *addr, uint16_t len)
 }
 
 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 @@ void make_dhcp_packet(struct udp_dhcp_packet *packet,
      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 @@ void make_dhcp_packet(struct udp_dhcp_packet *packet,
 
   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 @@ void make_dhcp_packet(struct udp_dhcp_packet *packet,
   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 @@ int get_packet (interface_t *iface, unsigned char *data,
       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 open_socket (interface_t *iface, bool arp)
   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 @@ int open_socket (interface_t *iface, bool arp)
   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 @@ int open_socket (interface_t *iface, bool arp)
       close (fd);
       return -1;
     }
-
+  
   if (iface->fd > -1)
     close (iface->fd);
   iface->fd = fd;
@@ -475,6 +477,10 @@ size_t get_packet (interface_t *iface, unsigned char *data,
   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;
     }
 
index 023b862d3c0716f54cd0994dc5aeee876220bb2e..a35f5b563f6bfc469973f206a3d1744e8438e928 100644 (file)
--- a/socket.h
+++ b/socket.h
@@ -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);