Mercurial > hg > dhcpcd
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);
