-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.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>
# 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
#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
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;
}
int state = STATE_INIT;
struct timeval tv;
int xid = 0;
- unsigned long timeout = 0;
+ long timeout = 0;
fd_set rset;
int maxfd;
int retval;
/* 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);
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);
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)
+ retval = 0;
+ while (timeout > 0 && retval == 0)
{
- tv.tv_sec = timeout_secs;
+ 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);
- }
- else
- {
- 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 (retval == 0 && iface->fd != -1)
+ send_message (iface, &last_dhcp, xid, last_type, options);
+ timeout -= uptime () - start;
}
}
}
switch (state)
{
case STATE_BOUND:
- SOCKET_MODE (SOCKET_OPEN);
case STATE_RENEWING:
case STATE_REBINDING:
state = STATE_RENEW_REQUESTED;
}
}
- 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;
}
}
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;
}
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:
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)
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));
}
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;
}
}
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;
- configure (options, iface, &dhcp);
- }
-
free_dhcp (&dhcp);
+ memset (&dhcp, 0, sizeof (dhcp_t));
+ if (iface->previous_address.s_addr != 0 && ! options->persistent && daemonised)
+ configure (options, iface, &dhcp);
if (iface)
{
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)
{
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);
}
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));
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;
}
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);
#include "logger.h"
#include "socket.h"
+#define BROADCAST_FLAG 0x8000
+
static char *dhcp_message[] = {
[DHCP_DISCOVER] = "DHCP_DISCOVER",
[DHCP_OFFER] = "DHCP_OFFER",
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;
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);
+
+ /* 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 &&
- iface->previous_address.s_addr == dhcp->address.s_addr)
- message.ciaddr = iface->previous_address.s_addr;
+ 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;
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; */
- }
- 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;
+ *p++ = DHCP_PARAMETERREQUESTLIST;
+ n_params = p;
+ *p++ = 0;
- *n_params = p - n_params - 1;
+ /* 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;
+ }
if (type == DHCP_REQUEST)
{
}
}
- 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])
{
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,
{
memset (route, 0, sizeof (route_t));
- cidr = (int) *q++;
+ cidr = *q++;
if (cidr == 0)
ocets = 0;
else if (cidr < 9)
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;
-
+#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:
- if (dhcp->hostname)
- free (dhcp->hostname);
- dhcp->hostname = xmalloc (length + 1);
- memcpy (dhcp->hostname, p, length);
- dhcp->hostname[length] = '\0';
+ 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:
- if (dhcp->nisdomain)
- free (dhcp->nisdomain);
- dhcp->nisdomain = xmalloc (length + 1);
- memcpy (dhcp->nisdomain, p, length);
- dhcp->nisdomain[length] = '\0';
+ GETSTR (dhcp->nisdomain);
break;
+#undef GETSTR
+#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)
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
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;
.\" $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
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
_int = (int) _number; \
}
-static pid_t readpid(char *pidfile)
+static pid_t read_pid(const char *pidfile)
{
FILE *fp;
pid_t pid;
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 ()
options.interface);
if (options.signal != 0)
- exit (kill_pid (options.pidfile, options.signal));
-
- umask (022);
-
- if (readpid (options.pidfile))
{
- logger (LOG_ERR, ""PACKAGE" already running (%s)", options.pidfile);
- exit (EXIT_FAILURE);
+ 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 (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);
}
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);
char pidfile[PATH_MAX];
} options_t;
+void make_pid (const char *pidfile);
+
#endif
#include "logger.h"
#include "pathnames.h"
-#ifndef IFF_NOTRAILERS
-#define IFF_NOTRAILERS 0
-#endif
-
void free_address (address_t *addresses)
{
if (!addresses)
struct ifaddrs *ifap;
struct ifaddrs *p;
- unsigned int flags;
if (getifaddrs (&ifap) != 0)
return NULL;
return NULL;
}
- flags = p->ifa_flags;
#ifdef __linux__
memcpy (hwaddr, sll->sll_addr, ETHER_ADDR_LEN);
#else
return NULL;
}
- if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
+#ifndef __linux__
+ ifr.ifr_metric = metric;
+ if (ioctl(s, SIOCSIFMETRIC, &ifr) < 0)
{
- logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno));
+ logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno));
close (s);
return NULL;
}
+#endif
- ifr.ifr_flags |= IFF_UP | IFF_BROADCAST | IFF_NOTRAILERS | IFF_RUNNING;
- if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
+ if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
{
- logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", strerror (errno));
+ logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno));
close (s);
return NULL;
}
-#ifndef __linux__
- ifr.ifr_metric = metric;
- if (ioctl(s, SIOCSIFMETRIC, &ifr) < 0)
+ /* Bring the interface up if we need to */
+ if (! (ifr.ifr_flags & IFF_UP))
{
- logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno));
- close (s);
- return NULL;
+ 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;
+ }
}
-#endif
close (s);
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);