Set the seconds elasped and maximum message size correctly in DHCP messages.
Now compiles on Linux 2.4 kernels.
+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
# 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
#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)
{
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;
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
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);
}
}
}
SOCKET_MODE (SOCKET_OPEN);
timeout = options->timeout;
+ iface->start_uptime = uptime ();
if (dhcp->address.s_addr == 0)
{
logger (LOG_INFO, "broadcasting for a lease");
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);
break;
case STATE_REQUESTING:
logger (LOG_ERR, "timed out");
+ if (! daemonised)
+ goto eexit;
+
state = STATE_INIT;
SOCKET_MODE (SOCKET_CLOSED);
timeout = 0;
if ((type = parse_dhcpmessage (new_dhcp, &message)) < 0)
{
logger (LOG_ERR, "failed to parse packet");
+ free_dhcp (new_dhcp);
continue;
}
/* No packets for us, so wait until we get one */
if (! valid)
{
- free_dhcp (new_dhcp);
free (new_dhcp);
continue;
}
#include <limits.h>
#include <math.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
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;
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);
{
*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;
}
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;
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)
#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
#define DHCP_RELEASE 7
#define DHCP_INFORM 8
+
/* DHCP options */
enum DHCP_OPTIONS
{
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
/* 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>
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);
struct in_addr previous_address;
route_t *previous_routes;
+
+ long start_uptime;
} interface_t;
void free_address (address_t *addresses);
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
#include "dhcp.h"
uint8_t a = 0;
memcpy (&a, w, 1);
sum += ntohs (a) << 8;
- // sum += a;
}
sum = (sum >> 16) + (sum & 0xffff);
}
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;
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;
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));
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;
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;
}
}
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;
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)
{
close (fd);
return -1;
}
-
+
if (iface->fd > -1)
close (iface->fd);
iface->fd = fd;
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;
}
#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);