Android-x86
Fork
Spenden

  • R/O
  • HTTP
  • SSH
  • HTTPS

external-dhcpcd: Commit

external/dhcpcd


Commit MetaInfo

Revision4c5a5fb53bccceff331bae70f748bf9b4609fe0a (tree)
Zeit2008-12-18 11:04:11
AutorThe Android Open Source Project <initial-contribution@andr...>
CommiterThe Android Open Source Project

Log Message

Code drop from //branches/cupcake/...@124589

Ändern Zusammenfassung

Diff

--- a/Android.mk
+++ b/Android.mk
@@ -10,13 +10,20 @@ include $(CLEAR_VARS)
1010 LOCAL_SRC_FILES := common.c dhcp.c dhcpcd.c logger.c net.c \
1111 signals.c configure.c client.c if-linux.c lpf.c
1212 LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
13-LOCAL_CFLAGS := -DDISABLE_ARP
14-LOCAL_SHARED_LIBRARIES := libc
13+LOCAL_SHARED_LIBRARIES := libc libcutils
1514 LOCAL_MODULE = dhcpcd
1615 LOCAL_MODULE_TAGS := user development
1716 include $(BUILD_EXECUTABLE)
1817
1918 include $(CLEAR_VARS)
19+LOCAL_SRC_FILES := showlease.c
20+LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
21+LOCAL_SHARED_LIBRARIES := libc
22+LOCAL_MODULE = showlease
23+LOCAL_MODULE_TAGS := user development
24+include $(BUILD_EXECUTABLE)
25+
26+include $(CLEAR_VARS)
2027 LOCAL_MODULE := dhcpcd.conf
2128 LOCAL_MODULE_TAGS := user development
2229 LOCAL_MODULE_CLASS := ETC
--- a/Makefile
+++ b/Makefile
@@ -46,6 +46,6 @@ SED_SYS= -e 's:@SYSCONFDIR@:${SYSCONFDIR}:g'
4646 ${SED} ${SED_HOOKDIR} ${SED_SCRIPT} ${SED_SYS} $< > $@
4747
4848 MK= mk
49-include ${MK}/os.mk
5049 include ${MK}/sys.mk
50+include ${MK}/os.mk
5151 include ${MK}/prog.mk
--- a/README
+++ b/README
@@ -15,12 +15,10 @@ If you're cross compiling you may need to set the below knobs to avoid
1515 automatic tests.
1616 OS=BSD | Linux
1717
18-If size is your thing, you can remove all non-essential userland options
19-by adding -DMINIMAL to your CPPFLAGS. This currently shaves off around 6k.
20-You can save a futher 600 bytes or so by using the small make target.
21-
22-If you're building for a NOMMU system where fork() does not work, you should
23-add -DTHERE_IS_NO_FORK to your CPPFLAGS.
18+If you're building for an MMU-less system where fork() does not work, you
19+should add -DTHERE_IS_NO_FORK to your CPPFLAGS.
20+This also puts the --no-background flag on and stops the --background flag
21+from working.
2422
2523 You can change the default dir with these knobs.
2624 For example, to satisfy FHS compliance you would do this:-
@@ -66,4 +64,4 @@ ChangeLog
6664 ---------
6765 We no longer supply a ChangeLog.
6866 However, you're more than welcome to read the git commit comments at
69-http://git.marples.name/?p=dhcpcd/.git;a=summary
67+http://git.marples.name/?p=dhcpcd.git;a=summary
--- a/bpf-filter.h
+++ b/bpf-filter.h
@@ -36,14 +36,14 @@ static const struct bpf_insn const arp_bpf_filter [] = {
3636 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
3737 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 0, 3),
3838 #endif
39-
40- /* Make sure this is an ARP REPLY... */
39+ /* Make sure this is an ARP REQUEST... */
40+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20 + BPF_ETHCOOK),
41+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0),
42+ /* or ARP REPLY... */
4143 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20 + BPF_ETHCOOK),
4244 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 0, 1),
43-
4445 /* If we passed all the tests, ask for the whole packet. */
4546 BPF_STMT(BPF_RET + BPF_K, BPF_WHOLEPACKET),
46-
4747 /* Otherwise, drop it. */
4848 BPF_STMT(BPF_RET + BPF_K, 0),
4949 };
@@ -81,25 +81,19 @@ static const struct bpf_insn const dhcp_bpf_filter [] = {
8181 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
8282 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
8383 #endif
84-
8584 /* Make sure it's a UDP packet... */
8685 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23 + BPF_ETHCOOK),
8786 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
88-
8987 /* Make sure this isn't a fragment... */
9088 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20 + BPF_ETHCOOK),
9189 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
92-
9390 /* Get the IP header length... */
9491 BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14 + BPF_ETHCOOK),
95-
9692 /* Make sure it's to the right port... */
9793 BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16 + BPF_ETHCOOK),
9894 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_CLIENT_PORT, 0, 1),
99-
10095 /* If we passed all the tests, ask for the whole packet. */
10196 BPF_STMT(BPF_RET + BPF_K, BPF_WHOLEPACKET),
102-
10397 /* Otherwise, drop it. */
10498 BPF_STMT(BPF_RET + BPF_K, 0),
10599 };
--- a/bpf.c
+++ b/bpf.c
@@ -108,15 +108,13 @@ open_socket(struct interface *iface, int protocol)
108108
109109 /* Install the DHCP filter */
110110 if (protocol == ETHERTYPE_ARP) {
111-#ifdef ENABLE_ARP
112111 pf.bf_insns = UNCONST(arp_bpf_filter);
113112 pf.bf_len = arp_bpf_filter_len;
114113 fdp = &iface->arp_fd;
115-#endif
116114 } else {
117115 pf.bf_insns = UNCONST(dhcp_bpf_filter);
118116 pf.bf_len = dhcp_bpf_filter_len;
119- fdp = &iface->fd;
117+ fdp = &iface->raw_fd;
120118 }
121119 if (ioctl(fd, BIOCSETF, &pf) == -1)
122120 goto eexit;
@@ -142,6 +140,7 @@ send_raw_packet(const struct interface *iface, int protocol,
142140 {
143141 struct iovec iov[2];
144142 struct ether_header hw;
143+ int fd;
145144
146145 memset(&hw, 0, ETHER_HDR_LEN);
147146 memset(&hw.ether_dhost, 0xff, ETHER_ADDR_LEN);
@@ -150,7 +149,11 @@ send_raw_packet(const struct interface *iface, int protocol,
150149 iov[0].iov_len = ETHER_HDR_LEN;
151150 iov[1].iov_base = UNCONST(data);
152151 iov[1].iov_len = len;
153- return writev(iface->fd, iov, 2);
152+ if (protocol == ETHERTYPE_ARP)
153+ fd = iface->arp_fd;
154+ else
155+ fd = iface->raw_fd;
156+ return writev(fd, iov, 2);
154157 }
155158
156159 /* BPF requires that we read the entire buffer.
@@ -164,12 +167,10 @@ get_raw_packet(struct interface *iface, int protocol,
164167 ssize_t bytes;
165168 const unsigned char *payload;
166169
167- if (protocol == ETHERTYPE_ARP) {
168-#ifdef ENABLE_ARP
170+ if (protocol == ETHERTYPE_ARP)
169171 fd = iface->arp_fd;
170-#endif
171- } else
172- fd = iface->fd;
172+ else
173+ fd = iface->raw_fd;
173174
174175 for (;;) {
175176 if (iface->buffer_len == 0) {
--- a/client.c
+++ b/client.c
@@ -53,12 +53,7 @@
5353 #include "logger.h"
5454 #include "signals.h"
5555
56-#ifdef ENABLE_IPV4LL
57-# ifndef ENABLE_ARP
58- # error "IPv4LL requires ENABLE_ARP to work"
59-# endif
60-# define IPV4LL_LEASETIME 2
61-#endif
56+#define IPV4LL_LEASETIME 2
6257
6358 /* Some platforms don't define INFTIM */
6459 #ifndef INFTIM
@@ -73,17 +68,18 @@
7368 #define STATE_REBINDING 5
7469 #define STATE_REBOOT 6
7570 #define STATE_RENEW_REQUESTED 7
76-#define STATE_PROBING 8
77-#define STATE_ANNOUNCING 9
71+#define STATE_INIT_IPV4LL 8
72+#define STATE_PROBING 9
73+#define STATE_ANNOUNCING 10
7874
79-/* Constants taken from RFC 2131.
80- * We multiply some numbers by 1000 so they are suitable for use in poll(). */
75+/* Constants taken from RFC 2131. */
8176 #define T1 0.5
8277 #define T2 0.875
83-#define DHCP_BASE 4 * 1000
84-#define DHCP_RAND_MIN -1 * 1000
85-#define DHCP_RAND_MAX 1 * 1000
86-#define DHCP_MAX 64 * 1000
78+#define DHCP_BASE 4
79+#define DHCP_MAX 64
80+#define DHCP_RAND_MIN -1
81+#define DHCP_RAND_MAX 1
82+#define DHCP_ARP_FAIL 10
8783
8884 /* We should define a maximum for the NAK exponential backoff */
8985 #define NAKOFF_MAX 60
@@ -91,24 +87,44 @@
9187 #define SOCKET_CLOSED 0
9288 #define SOCKET_OPEN 1
9389
94-/* Indexes for pollfds */
95-#define POLLFD_SIGNAL 0
96-#define POLLFD_IFACE 1
97-#define POLLFD_ARP 2
98-
99-/* These are really for IPV4LL, RFC 3927.
100- * We multiply some numbers by 1000 so they are suitable for use in poll(). */
101-#define PROBE_WAIT 1 * 1000
90+/* These are for IPV4LL, RFC 3927. */
91+#define PROBE_WAIT 1
10292 #define PROBE_NUM 3
103-#define PROBE_MIN 1 * 1000
104-#define PROBE_MAX 2 * 1000
105-#define ANNOUNCE_WAIT 2 * 1000
106-#define ANNOUNCE_NUM 2
107-#define ANNOUNCE_INTERVAL 2 * 1000
93+#define PROBE_MIN 1
94+#define PROBE_MAX 2
95+#define ANNOUNCE_WAIT 2
96+/* BSD systems always do a grauitous ARP when assigning an address,
97+ * so we can do one less announce. */
98+#ifdef BSD
99+# define ANNOUNCE_NUM 1
100+#else
101+# define ANNOUNCE_NUM 2
102+#endif
103+#define ANNOUNCE_INTERVAL 2
108104 #define MAX_CONFLICTS 10
109105 #define RATE_LIMIT_INTERVAL 60
110106 #define DEFEND_INTERVAL 10
111107
108+
109+/* number of usecs in a second. */
110+#define USECS_SECOND 1000000
111+/* As we use timevals, we should use the usec part for
112+ * greater randomisation. */
113+#define DHCP_RAND_MIN_U DHCP_RAND_MIN * USECS_SECOND
114+#define DHCP_RAND_MAX_U DHCP_RAND_MAX * USECS_SECOND
115+#define PROBE_MIN_U PROBE_MIN * USECS_SECOND
116+#define PROBE_MAX_U PROBE_MAX * USECS_SECOND
117+
118+#define timernorm(tvp) \
119+ do { \
120+ while ((tvp)->tv_usec >= 1000000) { \
121+ (tvp)->tv_sec++; \
122+ (tvp)->tv_usec -= 1000000; \
123+ } \
124+ } while (0 /* CONSTCOND */);
125+
126+#define timerneg(tvp) ((tvp)->tv_sec < 0 || (tvp)->tv_usec < 0)
127+
112128 struct if_state {
113129 int options;
114130 struct interface *interface;
@@ -116,25 +132,28 @@ struct if_state {
116132 struct dhcp_message *new;
117133 struct dhcp_message *old;
118134 struct dhcp_lease lease;
119- struct timeval start;
135+ struct timeval timeout;
120136 struct timeval stop;
137+ struct timeval exit;
121138 int state;
122139 int messages;
123- long timeout;
124140 time_t nakoff;
125141 uint32_t xid;
126142 int socket;
127143 int *pid_fd;
128144 int signal_fd;
129-#ifdef ENABLE_ARP
145+ int carrier;
130146 int probes;
131147 int claims;
132148 int conflicts;
133149 time_t defend;
134150 struct in_addr fail;
135-#endif
136151 };
137152
153+#define LINK_UP 1
154+#define LINK_UNKNOWN 0
155+#define LINK_DOWN -1
156+
138157 struct dhcp_op {
139158 uint8_t value;
140159 const char *name;
@@ -163,19 +182,17 @@ get_dhcp_op(uint8_t type)
163182 return NULL;
164183 }
165184
185+#ifdef THERE_IS_NO_FORK
186+#define daemonise(a,b) 0
187+#else
166188 static int
167189 daemonise(struct if_state *state, const struct options *options)
168190 {
169191 pid_t pid;
170192 sigset_t full;
171193 sigset_t old;
172-#ifdef THERE_IS_NO_FORK
173- char **argv;
174- int i;
175-#else
176194 char buf = '\0';
177195 int sidpipe[2];
178-#endif
179196
180197 if (state->options & DHCPCD_DAEMONISED ||
181198 !(options->options & DHCPCD_DAEMONISE))
@@ -184,7 +201,6 @@ daemonise(struct if_state *state, const struct options *options)
184201 sigfillset(&full);
185202 sigprocmask(SIG_SETMASK, &full, &old);
186203
187-#ifndef THERE_IS_NO_FORK
188204 /* Setup a signal pipe so parent knows when to exit. */
189205 if (pipe(sidpipe) == -1) {
190206 logger(LOG_ERR,"pipe: %s", strerror(errno));
@@ -214,36 +230,6 @@ daemonise(struct if_state *state, const struct options *options)
214230 close(sidpipe[0]);
215231 break;
216232 }
217-#else
218- logger(LOG_INFO, "forking to background");
219-
220- /* We need to add --daemonise to our options */
221- argv = xmalloc(sizeof(char *) * (dhcpcd_argc + 4));
222- argv[0] = dhcpcd;
223- for (i = 1; i < dhcpcd_argc; i++)
224- argv[i] = dhcpcd_argv[i];
225- argv[i] = (char *)"--daemonised";
226- if (dhcpcd_skiproutes) {
227- argv[++i] = (char *)"--skiproutes";
228- argv[++i] = dhcpcd_skiproutes;
229- }
230- argv[i + 1] = NULL;
231-
232- switch (pid = vfork()) {
233- case -1:
234- logger(LOG_ERR, "vfork: %s", strerror(errno));
235- _exit(EXIT_FAILURE);
236- case 0:
237- signal_reset();
238- sigprocmask(SIG_SETMASK, &old, NULL);
239- execvp(dhcpcd, argv);
240- /* Must not use stdio here. */
241- write(STDERR_FILENO, "exec failed\n", 12);
242- _exit(EXIT_FAILURE);
243- }
244-
245- free(argv);
246-#endif
247233
248234 /* Done with the fd now */
249235 if (pid != 0) {
@@ -253,18 +239,16 @@ daemonise(struct if_state *state, const struct options *options)
253239 }
254240
255241 sigprocmask(SIG_SETMASK, &old, NULL);
256-
257- state->state = STATE_BOUND;
258242 if (pid == 0) {
259243 state->options |= DHCPCD_DAEMONISED;
244+ timerclear(&state->exit);
260245 return 0;
261246 }
262-
263247 state->options |= DHCPCD_PERSISTENT | DHCPCD_FORKED;
264248 return -1;
265249 }
250+#endif
266251
267-#ifndef MINIMAL
268252 #define THIRTY_YEARS_IN_SECONDS 946707779
269253 static size_t
270254 get_duid(unsigned char *duid, const struct interface *iface)
@@ -333,9 +317,7 @@ get_duid(unsigned char *duid, const struct interface *iface)
333317 }
334318 return len;
335319 }
336-#endif
337320
338-#ifdef ENABLE_IPV4LL
339321 static struct dhcp_message*
340322 ipv4ll_get_dhcp(uint32_t old_addr)
341323 {
@@ -346,42 +328,58 @@ ipv4ll_get_dhcp(uint32_t old_addr)
346328 dhcp = xzalloc(sizeof(*dhcp));
347329 /* Put some LL options in */
348330 p = dhcp->options;
349- *p++ = DHCP_SUBNETMASK;
350- *p += sizeof(u32);
351- u32 = LINKLOCAL_MASK;
331+ *p++ = DHO_SUBNETMASK;
332+ *p++ = sizeof(u32);
333+ u32 = htonl(LINKLOCAL_MASK);
352334 memcpy(p, &u32, sizeof(u32));
353335 p += sizeof(u32);
354- *p++ = DHCP_BROADCAST;
355- *p += sizeof(u32);
356- u32 = LINKLOCAL_BRDC;
336+ *p++ = DHO_BROADCAST;
337+ *p++ = sizeof(u32);
338+ u32 = htonl(LINKLOCAL_BRDC);
357339 memcpy(p, &u32, sizeof(u32));
358340 p += sizeof(u32);
359- *p++ = DHCP_END;
341+ *p++ = DHO_END;
360342
361343 for (;;) {
362344 dhcp->yiaddr = htonl(LINKLOCAL_ADDR |
363345 (((uint32_t)abs((int)arc4random())
364346 % 0xFD00) + 0x0100));
365- if (dhcp->yiaddr != old_addr)
347+ if (dhcp->yiaddr != old_addr &&
348+ IN_LINKLOCAL(ntohl(dhcp->yiaddr)))
366349 break;
367350 }
368351 return dhcp;
369352 }
370-#endif
353+
354+static double
355+timeval_to_double(struct timeval *tv)
356+{
357+ return tv->tv_sec * 1.0 + tv->tv_usec * 1.0e-6;
358+}
371359
372360 static void
373361 get_lease(struct dhcp_lease *lease, const struct dhcp_message *dhcp)
374362 {
363+ time_t t;
364+
375365 lease->frominfo = 0;
376366 lease->addr.s_addr = dhcp->yiaddr;
377367
378- if (get_option_addr(&lease->net.s_addr, dhcp, DHCP_SUBNETMASK) == -1)
368+ if (get_option_addr(&lease->net.s_addr, dhcp, DHO_SUBNETMASK) == -1)
379369 lease->net.s_addr = get_netmask(dhcp->yiaddr);
380- if (get_option_uint32(&lease->leasetime, dhcp, DHCP_LEASETIME) != 0)
370+ if (get_option_uint32(&lease->leasetime, dhcp, DHO_LEASETIME) == 0) {
371+ /* Ensure that we can use the lease */
372+ t = 0;
373+ if (t + (time_t)lease->leasetime < t) {
374+ logger(LOG_WARNING, "lease of %u would overflow, "
375+ "treating as infinite", lease->leasetime);
376+ lease->leasetime = ~0U; /* Infinite lease */
377+ }
378+ } else
381379 lease->leasetime = DEFAULT_LEASETIME;
382- if (get_option_uint32(&lease->renewaltime, dhcp, DHCP_RENEWALTIME) != 0)
380+ if (get_option_uint32(&lease->renewaltime, dhcp, DHO_RENEWALTIME) != 0)
383381 lease->renewaltime = 0;
384- if (get_option_uint32(&lease->rebindtime, dhcp, DHCP_REBINDTIME) != 0)
382+ if (get_option_uint32(&lease->rebindtime, dhcp, DHO_REBINDTIME) != 0)
385383 lease->rebindtime = 0;
386384 }
387385
@@ -390,21 +388,21 @@ get_old_lease(struct if_state *state)
390388 {
391389 struct interface *iface = state->interface;
392390 struct dhcp_lease *lease = &state->lease;
393- struct dhcp_message *dhcp;
391+ struct dhcp_message *dhcp = NULL;
394392 struct timeval tv;
395393 unsigned int offset = 0;
396394 struct stat sb;
397395
396+ if (stat(iface->leasefile, &sb) == -1) {
397+ if (errno != ENOENT)
398+ logger(LOG_ERR, "stat: %s", strerror(errno));
399+ goto eexit;
400+ }
398401 if (!IN_LINKLOCAL(ntohl(iface->addr.s_addr)))
399402 logger(LOG_INFO, "trying to use old lease in `%s'",
400403 iface->leasefile);
401404 if ((dhcp = read_lease(iface)) == NULL) {
402- if (errno != ENOENT)
403- logger(LOG_INFO, "read_lease: %s", strerror(errno));
404- goto eexit;
405- }
406- if (stat(iface->leasefile, &sb) == -1) {
407- logger(LOG_ERR, "stat: %s", strerror(errno));
405+ logger(LOG_INFO, "read_lease: %s", strerror(errno));
408406 goto eexit;
409407 }
410408 get_lease(&state->lease, dhcp);
@@ -416,10 +414,8 @@ get_old_lease(struct if_state *state)
416414 dhcp->servername[0] = '\0';
417415
418416 if (!IN_LINKLOCAL(ntohl(dhcp->yiaddr))) {
419-#ifndef THERE_IS_NO_FORK
420417 if (!(state->options & DHCPCD_LASTLEASE))
421418 goto eexit;
422-#endif
423419
424420 /* Ensure that we can still use the lease */
425421 if (gettimeofday(&tv, NULL) == -1) {
@@ -429,7 +425,7 @@ get_old_lease(struct if_state *state)
429425
430426 offset = tv.tv_sec - lease->leasedfrom;
431427 if (lease->leasedfrom &&
432- tv.tv_sec - lease->leasedfrom > lease->leasetime)
428+ tv.tv_sec - lease->leasedfrom > (time_t)lease->leasetime)
433429 {
434430 logger(LOG_ERR, "lease expired %u seconds ago",
435431 offset + lease->leasetime);
@@ -445,8 +441,8 @@ get_old_lease(struct if_state *state)
445441
446442 if (lease->leasedfrom == 0)
447443 offset = 0;
448- state->timeout = lease->renewaltime - offset;
449444 iface->start_uptime = uptime();
445+ state->timeout.tv_sec = lease->renewaltime - offset;
450446 free(state->old);
451447 state->old = state->new;
452448 state->new = NULL;
@@ -465,24 +461,25 @@ client_setup(struct if_state *state, const struct options *options)
465461 struct interface *iface = state->interface;
466462 struct dhcp_lease *lease = &state->lease;
467463 struct in_addr addr;
468-#ifndef MINIMAL
464+ struct timeval tv;
469465 size_t len = 0;
470466 unsigned char *duid = NULL;
471467 uint32_t ul;
472-#endif
473468
474469 state->state = STATE_INIT;
475470 state->nakoff = 1;
476471 state->options = options->options;
472+ timerclear(&tv);
477473
478474 if (options->request_address.s_addr == 0 &&
479475 (options->options & DHCPCD_INFORM ||
480476 options->options & DHCPCD_REQUEST ||
481- options->options & DHCPCD_DAEMONISED))
477+ (options->options & DHCPCD_DAEMONISED &&
478+ !(options->options & DHCPCD_BACKGROUND))))
482479 {
483480 if (get_old_lease(state) != 0)
484481 return -1;
485- state->timeout = 0;
482+ timerclear(&state->timeout);
486483
487484 if (!(options->options & DHCPCD_DAEMONISED) &&
488485 IN_LINKLOCAL(ntohl(lease->addr.s_addr)))
@@ -490,21 +487,21 @@ client_setup(struct if_state *state, const struct options *options)
490487 logger(LOG_ERR, "cannot request a link local address");
491488 return -1;
492489 }
493-#ifdef THERE_IS_NO_FORK
494- if (options->options & DHCPCD_DAEMONISED) {
495- state->state = STATE_BOUND;
496- state->timeout = state->lease.renewaltime;
497- iface->addr.s_addr = lease->addr.s_addr;
498- iface->net.s_addr = lease->net.s_addr;
499- get_option_addr(&lease->server.s_addr,
500- state->offer, DHCP_SERVERID);
501- }
502-#endif
503490 } else {
504491 lease->addr.s_addr = options->request_address.s_addr;
505492 lease->net.s_addr = options->request_netmask.s_addr;
506493 }
507494
495+ if (options->options & DHCPCD_REQUEST &&
496+ state->options & DHCPCD_ARP &&
497+ !state->offer)
498+ {
499+ state->offer = xzalloc(sizeof(*state->offer));
500+ state->offer->yiaddr = options->request_address.s_addr;
501+ state->state = STATE_PROBING;
502+ state->xid = arc4random();
503+ }
504+
508505 /* If INFORMing, ensure the interface has the address */
509506 if (state->options & DHCPCD_INFORM &&
510507 has_address(iface->name, &lease->addr, &lease->net) < 1)
@@ -522,7 +519,6 @@ client_setup(struct if_state *state, const struct options *options)
522519 iface->net.s_addr = lease->net.s_addr;
523520 }
524521
525-#ifndef MINIMAL
526522 if (*options->clientid) {
527523 iface->clientid = xmalloc(options->clientid[0] + 1);
528524 memcpy(iface->clientid,
@@ -536,7 +532,7 @@ client_setup(struct if_state *state, const struct options *options)
536532 }
537533
538534 if (len > 0) {
539- logger(LOG_INFO, "DUID = %s",
535+ logger(LOG_DEBUG, "DUID = %s",
540536 hwaddr_ntoa(duid, len));
541537
542538 iface->clientid = xmalloc(len + 6);
@@ -568,34 +564,64 @@ client_setup(struct if_state *state, const struct options *options)
568564 memcpy(iface->clientid + 2, iface->hwaddr, iface->hwlen);
569565 }
570566 }
571-#endif
572567
568+ if (state->options & DHCPCD_LINK) {
569+ open_link_socket(iface);
570+ switch (carrier_status(iface->name)) {
571+ case 0:
572+ state->carrier = LINK_DOWN;
573+ break;
574+ case 1:
575+ state->carrier = LINK_UP;
576+ break;
577+ default:
578+ state->carrier = LINK_UNKNOWN;
579+ }
580+ }
581+
582+ if (options->timeout > 0 &&
583+ !(state->options & DHCPCD_DAEMONISED))
584+ {
585+ if (state->options & DHCPCD_IPV4LL) {
586+ state->stop.tv_sec = options->timeout;
587+ if (!(state->options & DHCPCD_BACKGROUND))
588+ state->exit.tv_sec = state->stop.tv_sec + 10;
589+ } else if (!(state->options & DHCPCD_BACKGROUND))
590+ state->exit.tv_sec = options->timeout;
591+ }
573592 return 0;
574593 }
575594
576595 static int
577596 do_socket(struct if_state *state, int mode)
578597 {
579- if (state->interface->fd >= 0) {
580- close(state->interface->fd);
581- state->interface->fd = -1;
598+ if (state->interface->raw_fd != -1) {
599+ close(state->interface->raw_fd);
600+ state->interface->raw_fd = -1;
582601 }
583- if (mode == SOCKET_CLOSED && state->interface->udp_fd >= 0) {
584- close(state->interface->udp_fd);
585- state->interface->udp_fd = -1;
602+ if (mode == SOCKET_CLOSED) {
603+ if (state->interface->udp_fd != -1) {
604+ close(state->interface->udp_fd);
605+ state->interface->udp_fd = -1;
606+ }
607+ if (state->interface->arp_fd != -1) {
608+ close(state->interface->arp_fd);
609+ state->interface->arp_fd = -1;
610+ }
586611 }
587612
588- /* We need to bind to a port, otherwise we generate ICMP messages
589- * that cannot connect the port when we have an address.
590- * We don't actually use this fd at all, instead using our packet
591- * filter socket. */
613+ /* Always have the UDP socket open to avoid the kernel sending
614+ * ICMP unreachable messages. */
615+ /* For systems without SO_BINDTODEVICE, (ie BSD ones) we may get an
616+ * error or EADDRINUSE when binding to INADDR_ANY as another dhcpcd
617+ * instance could be running.
618+ * Oddly enough, we don't care about this as the socket is there
619+ * just to please the kernel - we don't care for reading from it. */
592620 if (mode == SOCKET_OPEN &&
593621 state->interface->udp_fd == -1 &&
594- state->lease.addr.s_addr != 0)
595- if (open_udp_socket(state->interface) == -1) {
596- logger(LOG_ERR, "open_udp_socket: %s", strerror(errno));
597- return -1;
598- }
622+ open_udp_socket(state->interface) == -1 &&
623+ (errno != EADDRINUSE || state->interface->addr.s_addr != 0))
624+ logger(LOG_ERR, "open_udp_socket: %s", strerror(errno));
599625
600626 if (mode == SOCKET_OPEN)
601627 if (open_socket(state->interface, ETHERTYPE_IP) == -1) {
@@ -611,107 +637,211 @@ send_message(struct if_state *state, int type, const struct options *options)
611637 {
612638 struct dhcp_message *dhcp;
613639 uint8_t *udp;
614- ssize_t len;
615- ssize_t r;
616- struct in_addr from;
617- struct in_addr to;
640+ ssize_t len, r;
641+ struct in_addr from, to;
642+ in_addr_t a = 0;
618643
619- logger(LOG_DEBUG, "sending %s with xid 0x%x",
620- get_dhcp_op(type), state->xid);
644+ if (state->carrier == LINK_DOWN)
645+ return 0;
646+ if (type == DHCP_RELEASE)
647+ logger(LOG_DEBUG, "sending %s with xid 0x%x",
648+ get_dhcp_op(type), state->xid);
649+ else
650+ logger(LOG_DEBUG,
651+ "sending %s with xid 0x%x, next in %0.2f seconds",
652+ get_dhcp_op(type), state->xid,
653+ timeval_to_double(&state->timeout));
621654 state->messages++;
655+ if (state->messages < 0)
656+ state->messages = INT_MAX;
657+ /* If we couldn't open a UDP port for our IP address
658+ * then we cannot renew.
659+ * This could happen if our IP was pulled out from underneath us. */
660+ if (state->interface->udp_fd == -1) {
661+ a = state->interface->addr.s_addr;
662+ state->interface->addr.s_addr = 0;
663+ }
622664 len = make_message(&dhcp, state->interface, &state->lease, state->xid,
623665 type, options);
666+ if (state->interface->udp_fd == -1)
667+ state->interface->addr.s_addr = a;
624668 from.s_addr = dhcp->ciaddr;
625669 if (from.s_addr)
626670 to.s_addr = state->lease.server.s_addr;
627671 else
628672 to.s_addr = 0;
629- if (to.s_addr) {
673+ if (to.s_addr && to.s_addr != INADDR_BROADCAST) {
630674 r = send_packet(state->interface, to, (uint8_t *)dhcp, len);
631675 if (r == -1)
632676 logger(LOG_ERR, "send_packet: %s", strerror(errno));
633677 } else {
634678 len = make_udp_packet(&udp, (uint8_t *)dhcp, len, from, to);
635- free(dhcp);
636679 r = send_raw_packet(state->interface, ETHERTYPE_IP, udp, len);
680+ free(udp);
637681 if (r == -1)
638682 logger(LOG_ERR, "send_raw_packet: %s", strerror(errno));
639- free(udp);
683+ }
684+ free(dhcp);
685+ /* Failed to send the packet? Return to the init state */
686+ if (r == -1) {
687+ state->state = STATE_INIT;
688+ timerclear(&state->timeout);
689+ timerclear(&state->stop);
690+ do_socket(state, SOCKET_CLOSED);
640691 }
641692 return r;
642693 }
643694
644695 static void
645-drop_config(struct if_state *state, const char *reason, const struct options *options)
696+drop_config(struct if_state *state, const char *reason,
697+ const struct options *options)
646698 {
647- configure(state->interface, reason, NULL, state->new,
648- &state->lease, options, 0);
649- free(state->old);
650- state->old = NULL;
651- free(state->new);
652- state->new = NULL;
653-
699+ if (state->new || strcmp(reason, "FAIL") == 0) {
700+ configure(state->interface, reason, NULL, state->new,
701+ &state->lease, options, 0);
702+ free(state->old);
703+ state->old = NULL;
704+ free(state->new);
705+ state->new = NULL;
706+ }
654707 state->lease.addr.s_addr = 0;
655708 }
656709
710+static void
711+reduce_timers(struct if_state *state, const struct timeval *tv)
712+{
713+ if (timerisset(&state->exit)) {
714+ timersub(&state->exit, tv, &state->exit);
715+ if (!timerisset(&state->exit))
716+ state->exit.tv_sec = -1;
717+ }
718+ if (timerisset(&state->stop)) {
719+ timersub(&state->stop, tv, &state->stop);
720+ if (!timerisset(&state->stop))
721+ state->stop.tv_sec = -1;
722+ }
723+ if (timerisset(&state->timeout)) {
724+ timersub(&state->timeout, tv, &state->timeout);
725+ if (!timerisset(&state->timeout))
726+ state->timeout.tv_sec = -1;
727+ }
728+}
729+
730+static struct timeval *
731+get_lowest_timer(struct if_state *state)
732+{
733+ struct timeval *ref = NULL;
734+
735+ if (timerisset(&state->exit))
736+ ref = &state->exit;
737+ if (timerisset(&state->stop)) {
738+ if (!ref || timercmp(&state->stop, ref, <))
739+ ref = &state->stop;
740+ }
741+ if (timerisset(&state->timeout)) {
742+ if (!ref || timercmp(&state->timeout, ref, <))
743+ ref = &state->timeout;
744+ }
745+ return ref;
746+}
747+
657748 static int
658-wait_for_packet(struct if_state *state)
749+wait_for_fd(struct if_state *state, int *fd)
659750 {
660- struct pollfd fds[3]; /* iface, arp, signal */
661- int retval, timeout, nfds = 0;
662- time_t start;
663- struct timeval now, d;
751+ struct pollfd fds[4]; /* signal, link, raw, arp */
752+ struct interface *iface = state->interface;
753+ int i, r, nfds = 0, msecs = -1;
754+ struct timeval start, stop, diff, *ref;
755+ static int lastinf = 0;
756+
757+ /* Ensure that we haven't already timed out */
758+ ref = get_lowest_timer(state);
759+ if (ref && timerneg(ref))
760+ return 0;
664761
665762 /* We always listen to signals */
666763 fds[nfds].fd = state->signal_fd;
667764 fds[nfds].events = POLLIN;
668765 nfds++;
766+ /* And links */
767+ if (iface->link_fd != -1) {
768+ fds[nfds].fd = iface->link_fd;
769+ fds[nfds].events = POLLIN;
770+ nfds++;
771+ }
669772
670- if (state->lease.leasetime == ~0U && state->state == STATE_BOUND) {
671- logger(LOG_DEBUG, "waiting for infinity");
672- timeout = INFTIM;
673- } else {
674- timeout = state->timeout;
675- if (timerisset(&state->stop)) {
676- get_time(&now);
677- if (timercmp(&state->stop, &now, >)) {
678- timersub(&state->stop, &now, &d);
679- retval = d.tv_sec * 1000 + (d.tv_usec + 999) / 1000;
680- if (retval < timeout)
681- timeout = retval;
682- }
773+ if (state->lease.leasetime == ~0U &&
774+ state->state == STATE_BOUND)
775+ {
776+ if (!lastinf) {
777+ logger(LOG_DEBUG, "waiting for infinity");
778+ lastinf = 1;
683779 }
684- if (timeout <= 0)
685- return 0;
686- if (state->interface->fd != -1) {
687- fds[nfds].fd = state->interface->fd;
780+ ref = NULL;
781+ } else if (state->carrier == LINK_DOWN && !ref) {
782+ if (!lastinf) {
783+ logger(LOG_DEBUG, "waiting for carrier");
784+ lastinf = 1;
785+ }
786+ if (timerisset(&state->exit))
787+ ref = &state->exit;
788+ else
789+ ref = NULL;
790+ } else {
791+ if (iface->raw_fd != -1) {
792+ fds[nfds].fd = iface->raw_fd;
688793 fds[nfds].events = POLLIN;
689794 nfds++;
690795 }
691-#ifdef ENABLE_ARP
692- if (state->interface->arp_fd != -1) {
693- fds[nfds].fd = state->interface->arp_fd;
796+ if (iface->arp_fd != -1) {
797+ fds[nfds].fd = iface->arp_fd;
694798 fds[nfds].events = POLLIN;
695799 nfds++;
696800 }
697-#endif
698- logger(LOG_DEBUG, "waiting for %0.3f seconds",
699- (float)timeout / 1000);
700801 }
701802
702- start = uptime();
703- retval = poll(fds, nfds, timeout);
704- if (timeout != INFTIM) {
705- state->timeout -= uptime() - start;
706- if (state->timeout < 0)
707- state->timeout = 0;
708- }
709- if (retval == -1) {
710- if (errno == EINTR)
803+ /* Wait and then reduce the timers.
804+ * If we reduce a timer to zero, set it negative to indicate timeout.
805+ * We cannot reliably use select as there is no guarantee we will
806+ * actually wait the whole time if greater than 31 days according
807+ * to POSIX. So we loop on poll if needed as it's limitation of
808+ * INT_MAX milliseconds is known. */
809+ for (;;) {
810+ get_monotonic(&start);
811+ if (ref) {
812+ lastinf = 0;
813+ if (ref->tv_sec > INT_MAX / 1000 ||
814+ (ref->tv_sec == INT_MAX / 1000 &&
815+ (ref->tv_usec + 999) / 1000 > INT_MAX % 1000))
816+ msecs = INT_MAX;
817+ else
818+ msecs = ref->tv_sec * 1000 +
819+ (ref->tv_usec + 999) / 1000;
820+ } else
821+ msecs = -1;
822+ r = poll(fds, nfds, msecs);
823+ get_monotonic(&stop);
824+ timersub(&stop, &start, &diff);
825+ reduce_timers(state, &diff);
826+ if (r == -1) {
827+ if (errno != EINTR)
828+ logger(LOG_ERR, "poll: %s", strerror(errno));
829+ return -1;
830+ }
831+ if (r)
832+ break;
833+ /* We should not have an infinite timeout if we get here */
834+ if (timerneg(ref))
711835 return 0;
712- logger(LOG_ERR, "poll: %s", strerror(errno));
713836 }
714- return retval;
837+
838+ /* We configured our array in the order we should deal with them */
839+ for (i = 0; i < nfds; i++)
840+ if (fds[i].revents & POLLIN) {
841+ *fd = fds[i].fd;
842+ return r;
843+ }
844+ return r;
715845 }
716846
717847 static int
@@ -730,37 +860,18 @@ handle_signal(int sig, struct if_state *state, const struct options *options)
730860 if (!(state->options & DHCPCD_PERSISTENT))
731861 drop_config(state, "STOP", options);
732862 return -1;
733-
734863 case SIGALRM:
735- logger (LOG_INFO, "received SIGALRM, renewing lease");
736- switch (state->state) {
737- case STATE_BOUND:
738- case STATE_RENEWING:
739- case STATE_REBINDING:
740- case STATE_ANNOUNCING:
741- state->state = STATE_RENEW_REQUESTED;
742- break;
743- case STATE_RENEW_REQUESTED:
744- case STATE_REQUESTING:
745- state->state = STATE_INIT;
746- break;
747- }
864+ logger(LOG_INFO, "received SIGALRM, renewing lease");
865+ do_socket(state, SOCKET_CLOSED);
866+ state->state = STATE_RENEW_REQUESTED;
867+ timerclear(&state->timeout);
748868 timerclear(&state->stop);
749- state->timeout = 0;
750- return 0;
751-
869+ return 1;
752870 case SIGHUP:
753- if (state->state != STATE_BOUND &&
754- state->state != STATE_RENEWING &&
755- state->state != STATE_REBINDING)
871+ logger(LOG_INFO, "received SIGHUP, releasing lease");
872+ if (lease->addr.s_addr &&
873+ !IN_LINKLOCAL(ntohl(lease->addr.s_addr)))
756874 {
757- logger(LOG_ERR,
758- "received SIGHUP, but no lease to release");
759- return -1;
760- }
761-
762- logger (LOG_INFO, "received SIGHUP, releasing lease");
763- if (!IN_LINKLOCAL(ntohl(lease->addr.s_addr))) {
764875 do_socket(state, SOCKET_OPEN);
765876 state->xid = arc4random();
766877 send_message(state, DHCP_RELEASE, options);
@@ -768,14 +879,13 @@ handle_signal(int sig, struct if_state *state, const struct options *options)
768879 }
769880 drop_config(state, "RELEASE", options);
770881 return -1;
771-
772882 default:
773883 logger (LOG_ERR,
774884 "received signal %d, but don't know what to do with it",
775885 sig);
776886 }
777887
778- return -1;
888+ return 0;
779889 }
780890
781891 static int bind_dhcp(struct if_state *state, const struct options *options)
@@ -783,17 +893,19 @@ static int bind_dhcp(struct if_state *state, const struct options *options)
783893 struct interface *iface = state->interface;
784894 struct dhcp_lease *lease = &state->lease;
785895 const char *reason = NULL;
786- struct timeval tv;
896+ struct timeval start, stop, diff;
787897 int retval;
788898
789899 free(state->old);
790900 state->old = state->new;
791901 state->new = state->offer;
792902 state->offer = NULL;
793-#ifdef ENABLE_ARP
903+ state->messages = 0;
794904 state->conflicts = 0;
795905 state->defend = 0;
796-#endif
906+ timerclear(&state->exit);
907+ if (clock_monotonic)
908+ get_monotonic(&lease->boundtime);
797909
798910 if (options->options & DHCPCD_INFORM) {
799911 if (options->request_address.s_addr != 0)
@@ -804,17 +916,18 @@ static int bind_dhcp(struct if_state *state, const struct options *options)
804916 inet_ntoa(lease->addr));
805917 state->state = STATE_BOUND;
806918 state->lease.leasetime = ~0U;
919+ timerclear(&state->stop);
807920 reason = "INFORM";
808921 } else if (IN_LINKLOCAL(htonl(state->new->yiaddr))) {
809922 get_lease(lease, state->new);
810923 logger(LOG_INFO, "using IPv4LL address %s",
811924 inet_ntoa(lease->addr));
812925 state->state = STATE_INIT;
813- state->timeout = 0;
926+ timerclear(&state->timeout);
814927 reason = "IPV4LL";
815928 } else {
816- if (gettimeofday(&tv, NULL) == 0)
817- lease->leasedfrom = tv.tv_sec;
929+ if (gettimeofday(&start, NULL) == 0)
930+ lease->leasedfrom = start.tv_sec;
818931
819932 get_lease(lease, state->new);
820933 if (lease->frominfo)
@@ -822,55 +935,40 @@ static int bind_dhcp(struct if_state *state, const struct options *options)
822935
823936 if (lease->leasetime == ~0U) {
824937 lease->renewaltime = lease->rebindtime = lease->leasetime;
825- state->timeout = 1; /* So we wait for infinity */
826938 logger(LOG_INFO, "leased %s for infinity",
827939 inet_ntoa(lease->addr));
828940 state->state = STATE_BOUND;
941+ timerclear(&state->stop);
829942 } else {
830- logger(LOG_INFO, "leased %s for %u seconds",
831- inet_ntoa(lease->addr), lease->leasetime);
832-
833943 if (lease->rebindtime >= lease->leasetime) {
834- lease->rebindtime = (lease->leasetime * T2);
944+ lease->rebindtime = lease->leasetime * T2;
835945 logger(LOG_ERR,
836946 "rebind time greater than lease "
837947 "time, forcing to %u seconds",
838948 lease->rebindtime);
839949 }
840-
841950 if (lease->renewaltime > lease->rebindtime) {
842- lease->renewaltime = (lease->leasetime * T1);
951+ lease->renewaltime = lease->leasetime * T1;
843952 logger(LOG_ERR,
844953 "renewal time greater than rebind time, "
845954 "forcing to %u seconds",
846955 lease->renewaltime);
847956 }
848-
849- if (!lease->renewaltime) {
850- lease->renewaltime = (lease->leasetime * T1);
851- logger(LOG_INFO,
852- "no renewal time supplied, assuming %d seconds",
853- lease->renewaltime);
854- } else
855- logger(LOG_DEBUG, "renew in %u seconds",
856- lease->renewaltime);
857-
858- if (!lease->rebindtime) {
859- lease->rebindtime = (lease->leasetime * T2);
860- logger(LOG_INFO,
861- "no rebind time supplied, assuming %d seconds",
862- lease->rebindtime);
863- } else
864- logger(LOG_DEBUG, "rebind in %u seconds",
865- lease->rebindtime);
866-
867- state->timeout = lease->renewaltime * 1000;
957+ if (!lease->renewaltime)
958+ lease->renewaltime = lease->leasetime * T1;
959+ if (!lease->rebindtime)
960+ lease->rebindtime = lease->leasetime * T2;
961+ logger(LOG_INFO,
962+ "leased %s for %u seconds",
963+ inet_ntoa(lease->addr), lease->leasetime);
964+ state->stop.tv_sec = lease->renewaltime;
965+ state->stop.tv_usec = 0;
868966 }
869967 state->state = STATE_BOUND;
870968 }
871969
872970 state->xid = 0;
873- timerclear(&state->stop);
971+ timerclear(&state->timeout);
874972 if (!reason) {
875973 if (state->old) {
876974 if (state->old->yiaddr == state->new->yiaddr &&
@@ -881,8 +979,18 @@ static int bind_dhcp(struct if_state *state, const struct options *options)
881979 } else
882980 reason = "BOUND";
883981 }
982+ /* If we have a monotonic clock we can safely substract the
983+ * script execution time from our timers.
984+ * Otherwise we can't as the script may update the real time. */
985+ if (clock_monotonic)
986+ get_monotonic(&start);
884987 retval = configure(iface, reason, state->new, state->old,
885988 &state->lease, options, 1);
989+ if (clock_monotonic) {
990+ get_monotonic(&stop);
991+ timersub(&stop, &start, &diff);
992+ reduce_timers(state, &diff);
993+ }
886994 if (retval != 0)
887995 return -1;
888996 return daemonise(state, options);
@@ -895,18 +1003,15 @@ handle_timeout_fail(struct if_state *state, const struct options *options)
8951003 struct interface *iface = state->interface;
8961004 int gotlease = -1;
8971005 const char *reason = NULL;
898- struct timeval tv;
8991006
900- timerclear(&tv);
901- /* Clear our timers and counters as we've failed.
902- * We'll either abort or move to another state with new timers */
9031007 timerclear(&state->stop);
904- state->messages = 0;
905- state->timeout = 0;
1008+ timerclear(&state->exit);
1009+ if (state->state != STATE_DISCOVERING)
1010+ state->messages = 0;
9061011
9071012 switch (state->state) {
908- case STATE_DISCOVERING:
909- /* FALLTHROUGH */
1013+ case STATE_INIT: /* FALLTHROUGH */
1014+ case STATE_DISCOVERING: /* FALLTHROUGH */
9101015 case STATE_REQUESTING:
9111016 if (IN_LINKLOCAL(ntohl(iface->addr.s_addr))) {
9121017 if (!(state->options & DHCPCD_DAEMONISED))
@@ -915,7 +1020,8 @@ handle_timeout_fail(struct if_state *state, const struct options *options)
9151020 if (iface->addr.s_addr != 0 &&
9161021 !(state->options & DHCPCD_INFORM))
9171022 logger(LOG_ERR, "lost lease");
918- else
1023+ else if (state->carrier != LINK_DOWN ||
1024+ !(state->options & DHCPCD_DAEMONISED))
9191025 logger(LOG_ERR, "timed out");
9201026 }
9211027 do_socket(state, SOCKET_CLOSED);
@@ -923,64 +1029,81 @@ handle_timeout_fail(struct if_state *state, const struct options *options)
9231029 state->options & DHCPCD_TEST)
9241030 return -1;
9251031
926- if (state->options & DHCPCD_IPV4LL ||
927- state->options & DHCPCD_LASTLEASE)
1032+ if (state->carrier != LINK_DOWN &&
1033+ (state->options & DHCPCD_IPV4LL ||
1034+ state->options & DHCPCD_LASTLEASE))
9281035 gotlease = get_old_lease(state);
9291036
930-#ifdef ENABLE_IPV4LL
931- if (state->options & DHCPCD_IPV4LL && gotlease != 0) {
1037+ if (state->carrier != LINK_DOWN &&
1038+ state->options & DHCPCD_IPV4LL &&
1039+ gotlease != 0)
1040+ {
9321041 logger(LOG_INFO, "probing for an IPV4LL address");
9331042 free(state->offer);
9341043 state->offer = ipv4ll_get_dhcp(0);
9351044 gotlease = 0;
9361045 }
937-#endif
9381046
939-#ifdef ENABLE_ARP
9401047 if (gotlease == 0 &&
9411048 state->offer->yiaddr != iface->addr.s_addr)
9421049 {
9431050 state->state = STATE_PROBING;
9441051 state->claims = 0;
9451052 state->probes = 0;
946- state->conflicts = 0;
947- return 0;
1053+ if (iface->addr.s_addr)
1054+ state->conflicts = 0;
1055+ return 1;
9481056 }
949-#endif
9501057
9511058 if (gotlease == 0)
9521059 return bind_dhcp(state, options);
9531060
954- reason = "FAIL";
1061+ if (iface->addr.s_addr)
1062+ reason = "EXPIRE";
1063+ else
1064+ reason = "FAIL";
9551065 drop_config(state, reason, options);
9561066 if (!(state->options & DHCPCD_DAEMONISED) &&
9571067 (state->options & DHCPCD_DAEMONISE))
9581068 return -1;
959- state->state = STATE_INIT;
1069+ state->state = STATE_RENEW_REQUESTED;
1070+ return 1;
1071+ case STATE_BOUND:
1072+ logger(LOG_INFO, "renewing lease of %s",inet_ntoa(lease->addr));
1073+ if (state->carrier != LINK_DOWN)
1074+ do_socket(state, SOCKET_OPEN);
1075+ state->xid = arc4random();
1076+ state->state = STATE_RENEWING;
1077+ state->stop.tv_sec = lease->rebindtime - lease->renewaltime;
9601078 break;
9611079 case STATE_RENEWING:
9621080 logger(LOG_ERR, "failed to renew, attempting to rebind");
963- lease->addr.s_addr = 0;
9641081 state->state = STATE_REBINDING;
965- tv.tv_sec = lease->rebindtime - lease->renewaltime;
1082+ if (lease->server.s_addr == 0)
1083+ state->stop.tv_sec = options->timeout;
1084+ else
1085+ state->stop.tv_sec = lease->rebindtime - \
1086+ lease->renewaltime;
1087+ lease->server.s_addr = 0;
9661088 break;
9671089 case STATE_REBINDING:
968- logger(LOG_ERR, "failed to rebind, attempting to discover");
1090+ logger(LOG_ERR, "failed to rebind");
9691091 reason = "EXPIRE";
9701092 drop_config(state, reason, options);
9711093 state->state = STATE_INIT;
9721094 break;
1095+ case STATE_PROBING: /* FALLTHROUGH */
1096+ case STATE_ANNOUNCING:
1097+ /* We should have lost carrier here and exit timer went */
1098+ logger(LOG_ERR, "timed out");
1099+ return -1;
9731100 default:
9741101 logger(LOG_DEBUG, "handle_timeout_failed: invalid state %d",
9751102 state->state);
9761103 }
9771104
978- get_time(&state->start);
979- if (timerisset(&tv))
980- timeradd(&state->start, &tv, &state->stop);
981-
9821105 /* This effectively falls through into the handle_timeout funtion */
983- return 0;
1106+ return 1;
9841107 }
9851108
9861109 static int
@@ -988,14 +1111,32 @@ handle_timeout(struct if_state *state, const struct options *options)
9881111 {
9891112 struct dhcp_lease *lease = &state->lease;
9901113 struct interface *iface = state->interface;
991- int i;
992- struct timeval tv;
1114+ int i = 0;
9931115 struct in_addr addr;
1116+ struct timeval tv;
1117+
1118+ timerclear(&state->timeout);
1119+ if (timerneg(&state->exit))
1120+ return handle_timeout_fail(state, options);
9941121
995-#ifdef ENABLE_ARP
1122+ if (state->state == STATE_RENEW_REQUESTED &&
1123+ IN_LINKLOCAL(ntohl(lease->addr.s_addr)))
1124+ {
1125+ state->state = STATE_PROBING;
1126+ free(state->offer);
1127+ state->offer = read_lease(state->interface);
1128+ state->probes = 0;
1129+ state->claims = 0;
1130+ }
9961131 switch (state->state) {
1132+ case STATE_INIT_IPV4LL:
1133+ state->state = STATE_PROBING;
1134+ free(state->offer);
1135+ state->offer = ipv4ll_get_dhcp(0);
1136+ state->probes = 0;
1137+ state->claims = 0;
1138+ /* FALLTHROUGH */
9971139 case STATE_PROBING:
998- timerclear(&state->stop);
9991140 if (iface->arp_fd == -1)
10001141 open_socket(iface, ETHERTYPE_ARP);
10011142 if (state->probes < PROBE_NUM) {
@@ -1006,79 +1147,130 @@ handle_timeout(struct if_state *state, const struct options *options)
10061147 inet_ntoa(addr));
10071148 }
10081149 state->probes++;
1009- logger(LOG_DEBUG, "sending ARP probe #%d",
1010- state->probes);
1011- if (state->probes < PROBE_NUM)
1012- state->timeout = (arc4random() %
1013- (PROBE_MAX - PROBE_MIN)) + PROBE_MIN;
1014- else
1015- state->timeout = ANNOUNCE_WAIT;
1016- send_arp(iface, ARPOP_REQUEST, 0, state->offer->yiaddr);
1150+ if (state->probes < PROBE_NUM) {
1151+ state->timeout.tv_sec = PROBE_MIN;
1152+ state->timeout.tv_usec = arc4random() %
1153+ (PROBE_MAX_U - PROBE_MIN_U);
1154+ timernorm(&state->timeout);
1155+ } else {
1156+ state->timeout.tv_sec = ANNOUNCE_WAIT;
1157+ state->timeout.tv_usec = 0;
1158+ }
1159+ logger(LOG_DEBUG,
1160+ "sending ARP probe (%d of %d), next in %0.2f seconds",
1161+ state->probes, PROBE_NUM,
1162+ timeval_to_double(&state->timeout));
1163+ if (send_arp(iface, ARPOP_REQUEST, 0,
1164+ state->offer->yiaddr) == -1)
1165+ {
1166+ logger(LOG_ERR, "send_arp: %s", strerror(errno));
1167+ return -1;
1168+ }
10171169 return 0;
10181170 } else {
10191171 /* We've waited for ANNOUNCE_WAIT after the final probe
10201172 * so the address is now ours */
1021- i = bind_dhcp(state, options);
1022- state->state = STATE_ANNOUNCING;
1023- state->timeout = ANNOUNCE_INTERVAL;
1024- return i;
1173+ if (IN_LINKLOCAL(htonl(state->offer->yiaddr))) {
1174+ i = bind_dhcp(state, options);
1175+ state->state = STATE_ANNOUNCING;
1176+ state->timeout.tv_sec = ANNOUNCE_INTERVAL;
1177+ state->timeout.tv_usec = 0;
1178+ return i;
1179+ }
1180+ state->state = STATE_REQUESTING;
10251181 }
1182+ break;
10261183 case STATE_ANNOUNCING:
1027- timerclear(&state->stop);
1184+ if (iface->arp_fd == -1)
1185+ open_socket(iface, ETHERTYPE_ARP);
10281186 if (state->claims < ANNOUNCE_NUM) {
10291187 state->claims++;
1030- logger(LOG_DEBUG, "sending ARP announce #%d",
1031- state->claims);
1032- send_arp(iface, ARPOP_REQUEST,
1033- state->new->yiaddr, state->new->yiaddr);
1034- if (state->claims < ANNOUNCE_NUM)
1035- state->timeout = ANNOUNCE_INTERVAL;
1036- else if (IN_LINKLOCAL(htonl(lease->addr.s_addr))) {
1037- state->state = STATE_INIT;
1038- state->timeout = 0;
1039- } else {
1040- state->state = STATE_BOUND;
1041- state->timeout = lease->renewaltime * 1000 -
1042- (ANNOUNCE_INTERVAL * ANNOUNCE_NUM);
1043- close(iface->arp_fd);
1044- iface->arp_fd = -1;
1188+ if (state->claims < ANNOUNCE_NUM) {
1189+ state->timeout.tv_sec = ANNOUNCE_INTERVAL;
1190+ state->timeout.tv_usec = 0;
1191+ logger(LOG_DEBUG,
1192+ "sending ARP announce (%d of %d),"
1193+ " next in %0.2f seconds",
1194+ state->claims, ANNOUNCE_NUM,
1195+ timeval_to_double(&state->timeout));
1196+ } else
1197+ logger(LOG_DEBUG,
1198+ "sending ARP announce (%d of %d)",
1199+ state->claims, ANNOUNCE_NUM);
1200+ i = send_arp(iface, ARPOP_REQUEST,
1201+ state->new->yiaddr, state->new->yiaddr);
1202+ if (i == -1) {
1203+ logger(LOG_ERR, "send_arp: %s", strerror(errno));
1204+ return -1;
1205+ }
1206+ }
1207+ if (state->claims < ANNOUNCE_NUM)
1208+ return 0;
1209+ if (IN_LINKLOCAL(htonl(state->new->yiaddr))) {
1210+ /* We should pretend to be at the end
1211+ * of the DHCP negotation cycle */
1212+ state->state = STATE_INIT;
1213+ state->messages = DHCP_MAX / DHCP_BASE;
1214+ state->probes = 0;
1215+ state->claims = 0;
1216+ timerclear(&state->stop);
1217+ goto dhcp_timeout;
1218+ } else {
1219+ state->state = STATE_BOUND;
1220+ close(iface->arp_fd);
1221+ iface->arp_fd = -1;
1222+ if (lease->leasetime != ~0U) {
1223+ state->stop.tv_sec = lease->renewaltime;
1224+ state->stop.tv_usec = 0;
1225+ if (clock_monotonic) {
1226+ get_monotonic(&tv);
1227+ timersub(&tv, &lease->boundtime, &tv);
1228+ timersub(&state->stop, &tv, &state->stop);
1229+ } else {
1230+ state->stop.tv_sec -=
1231+ (ANNOUNCE_INTERVAL * ANNOUNCE_NUM);
1232+ }
1233+ logger(LOG_DEBUG, "renew in %ld seconds",
1234+ (long int)state->stop.tv_sec);
10451235 }
10461236 }
10471237 return 0;
10481238 }
1049-#endif
10501239
1051- if (timerisset(&state->stop)) {
1052- get_time(&tv);
1053- if (timercmp(&tv, &state->stop, >))
1054- return handle_timeout_fail(state, options);
1055- }
1056- timerclear(&tv);
1240+ if (timerneg(&state->stop))
1241+ return handle_timeout_fail(state, options);
10571242
10581243 switch (state->state) {
1059- case STATE_INIT: /* FALLTHROUGH */
10601244 case STATE_BOUND: /* FALLTHROUGH */
10611245 case STATE_RENEW_REQUESTED:
1246+ timerclear(&state->stop);
1247+ /* FALLTHROUGH */
1248+ case STATE_INIT:
10621249 do_socket(state, SOCKET_OPEN);
10631250 state->xid = arc4random();
1064- state->messages = 0;
1065- state->nakoff = 1;
10661251 iface->start_uptime = uptime();
1067- get_time(&state->start);
1068- timerclear(&state->stop);
1252+ break;
10691253 }
10701254
10711255 switch(state->state) {
1072- case STATE_INIT:
1073- /* 21Jul08 - was && DHCPCD_DAEMONISED */
1074- if (!(state->state & DHCPCD_DAEMONISED) &&
1075- options->timeout &&
1076- !IN_LINKLOCAL(htonl(iface->addr.s_addr)))
1077- {
1078- get_time(&state->start);
1079- tv.tv_sec = options->timeout;
1080- timeradd(&state->start, &tv, &state->stop);
1256+ case STATE_RENEW_REQUESTED:
1257+ /* If a renew was requested (ie, didn't timeout) we actually
1258+ * enter the REBIND state so that we broadcast to all servers.
1259+ * We need to do this for when we change networks. */
1260+ lease->server.s_addr = 0;
1261+ state->messages = 0;
1262+ if (lease->addr.s_addr && !(state->options & DHCPCD_INFORM)) {
1263+ logger(LOG_INFO, "rebinding lease of %s",
1264+ inet_ntoa(lease->addr));
1265+ state->state = STATE_REBINDING;
1266+ state->stop.tv_sec = options->timeout;
1267+ state->stop.tv_usec = 0;
1268+ break;
10811269 }
1270+ /* FALLTHROUGH */
1271+ case STATE_INIT:
1272+ if (state->carrier == LINK_DOWN)
1273+ return 0;
10821274 if (lease->addr.s_addr == 0 ||
10831275 IN_LINKLOCAL(ntohl(iface->addr.s_addr)))
10841276 {
@@ -1093,20 +1285,33 @@ handle_timeout(struct if_state *state, const struct options *options)
10931285 inet_ntoa(lease->addr));
10941286 state->state = STATE_REQUESTING;
10951287 }
1288+ if (!lease->addr.s_addr && !timerisset(&state->stop)) {
1289+ state->stop.tv_sec = DHCP_MAX + DHCP_RAND_MIN;
1290+ state->stop.tv_usec = arc4random() % (DHCP_RAND_MAX_U - DHCP_RAND_MIN_U);
1291+ timernorm(&state->stop);
1292+ }
10961293 break;
1097- case STATE_RENEW_REQUESTED:
1098- case STATE_BOUND:
1099- if (IN_LINKLOCAL(ntohl(lease->addr.s_addr))) {
1100- lease->addr.s_addr = 0;
1101- state->state = STATE_INIT;
1102- state->timeout = 0;
1294+ }
1295+
1296+dhcp_timeout:
1297+ if (state->carrier == LINK_DOWN) {
1298+ timerclear(&state->timeout);
1299+ return 0;
1300+ }
1301+ state->timeout.tv_sec = DHCP_BASE;
1302+ for (i = 0; i < state->messages; i++) {
1303+ state->timeout.tv_sec *= 2;
1304+ if (state->timeout.tv_sec > DHCP_MAX) {
1305+ state->timeout.tv_sec = DHCP_MAX;
11031306 break;
11041307 }
1105- logger(LOG_INFO, "renewing lease of %s",inet_ntoa(lease->addr));
1106- state->state = STATE_RENEWING;
1107- break;
11081308 }
1309+ state->timeout.tv_sec += DHCP_RAND_MIN;
1310+ state->timeout.tv_usec = arc4random() %
1311+ (DHCP_RAND_MAX_U - DHCP_RAND_MIN_U);
1312+ timernorm(&state->timeout);
11091313
1314+ /* We send the message here so that the timeout is reported */
11101315 switch (state->state) {
11111316 case STATE_DISCOVERING:
11121317 send_message(state, DHCP_DISCOVER, options);
@@ -1119,111 +1324,155 @@ handle_timeout(struct if_state *state, const struct options *options)
11191324 /* FALLTHROUGH */
11201325 case STATE_RENEWING: /* FALLTHROUGH */
11211326 case STATE_REBINDING:
1327+ if (iface->raw_fd == -1)
1328+ do_socket(state, SOCKET_OPEN);
11221329 send_message(state, DHCP_REQUEST, options);
11231330 break;
11241331 }
11251332
1126- state->timeout = DHCP_BASE;
1127- for (i = 1; i < state->messages; i++) {
1128- state->timeout *= 2;
1129- if (state->timeout > DHCP_MAX) {
1130- state->timeout = DHCP_MAX;
1131- break;
1132- }
1133- }
1134- state->timeout += (arc4random() % (DHCP_RAND_MAX - DHCP_RAND_MIN)) +
1135- DHCP_RAND_MIN;
11361333 return 0;
11371334 }
11381335
1336+static void
1337+log_dhcp(int lvl, const char *msg, const struct dhcp_message *dhcp)
1338+{
1339+ char *a;
1340+ struct in_addr addr;
1341+ int r;
1342+
1343+ if (strcmp(msg, "NAK:") == 0)
1344+ a = get_option_string(dhcp, DHO_MESSAGE);
1345+ else {
1346+ addr.s_addr = dhcp->yiaddr;
1347+ a = xstrdup(inet_ntoa(addr));
1348+ }
1349+ r = get_option_addr(&addr.s_addr, dhcp, DHO_SERVERID);
1350+ if (dhcp->servername[0] && r == 0)
1351+ logger(lvl, "%s %s from %s `%s'", msg, a,
1352+ inet_ntoa(addr), dhcp->servername);
1353+ else if (r == 0)
1354+ logger(lvl, "%s %s from %s", msg, a, inet_ntoa(addr));
1355+ else
1356+ logger(lvl, "%s %s", msg, a);
1357+ free(a);
1358+}
1359+
11391360 static int
11401361 handle_dhcp(struct if_state *state, struct dhcp_message **dhcpp,
11411362 const struct options *options)
11421363 {
1143- struct timespec ts;
11441364 struct dhcp_message *dhcp = *dhcpp;
11451365 struct interface *iface = state->interface;
11461366 struct dhcp_lease *lease = &state->lease;
1147- char *addr;
1148- struct in_addr saddr;
1149- uint8_t type;
1367+ uint8_t type, tmp;
1368+ struct in_addr addr;
1369+ size_t i;
11501370 int r;
11511371
1152- if (get_option_uint8(&type, dhcp, DHCP_MESSAGETYPE) == -1) {
1153- logger(LOG_ERR, "no DHCP type in message");
1154- return -1;
1155- }
1156-
11571372 /* reset the message counter */
11581373 state->messages = 0;
11591374
1375+ /* We have to have DHCP type to work */
1376+ if (get_option_uint8(&type, dhcp, DHO_MESSAGETYPE) == -1) {
1377+ log_dhcp(LOG_ERR, "no DHCP type in", dhcp);
1378+ return 0;
1379+ }
1380+
1381+ /* Ensure that it's not from a blacklisted server.
1382+ * We should expand this to check IP and/or hardware address
1383+ * at the packet level. */
1384+ if (options->blacklist_len != 0 &&
1385+ get_option_addr(&addr.s_addr, dhcp, DHO_SERVERID) == 0)
1386+ {
1387+ for (i = 0; i < options->blacklist_len; i++) {
1388+ if (options->blacklist[i] != addr.s_addr)
1389+ continue;
1390+ if (dhcp->servername[0])
1391+ logger(LOG_WARNING,
1392+ "ignoring blacklisted server %s `%s'",
1393+ inet_ntoa(addr), dhcp->servername);
1394+ else
1395+ logger(LOG_WARNING,
1396+ "ignoring blacklisted server %s",
1397+ inet_ntoa(addr));
1398+ return 0;
1399+ }
1400+ }
1401+
11601402 /* We should restart on a NAK */
11611403 if (type == DHCP_NAK) {
1162- addr = get_option_string(dhcp, DHCP_MESSAGE);
1163- logger(LOG_WARNING, "received NAK: %s", addr);
1164- free(addr);
1404+ log_dhcp(LOG_WARNING, "NAK:", dhcp);
1405+ drop_config(state, "EXPIRE", options);
1406+ do_socket(state, SOCKET_CLOSED);
11651407 state->state = STATE_INIT;
1166- state->timeout = 0;
1167- lease->addr.s_addr = 0;
1168- timerclear(&state->stop);
1169-
11701408 /* If we constantly get NAKS then we should slowly back off */
1171- if (state->nakoff > 0) {
1172- logger(LOG_DEBUG, "sleeping for %lu seconds",
1173- (unsigned long)state->nakoff);
1174- ts.tv_sec = state->nakoff;
1175- ts.tv_nsec = 0;
1409+ if (state->nakoff == 0) {
1410+ state->nakoff = 1;
1411+ timerclear(&state->timeout);
1412+ } else {
1413+ state->timeout.tv_sec = state->nakoff;
1414+ state->timeout.tv_usec = 0;
11761415 state->nakoff *= 2;
11771416 if (state->nakoff > NAKOFF_MAX)
11781417 state->nakoff = NAKOFF_MAX;
1179- nanosleep(&ts, NULL);
1180- }
1181-
1418+ }
11821419 return 0;
11831420 }
11841421
11851422 /* No NAK, so reset the backoff */
11861423 state->nakoff = 1;
11871424
1425+ /* Ensure that all required options are present */
1426+ for (i = 1; i < 255; i++) {
1427+ if (has_option_mask(options->requiremask, i) &&
1428+ get_option_uint8(&tmp, dhcp, i) != 0)
1429+ {
1430+ log_dhcp(LOG_WARNING, "reject", dhcp);
1431+ return 0;
1432+ }
1433+ }
1434+
11881435 if (type == DHCP_OFFER && state->state == STATE_DISCOVERING) {
11891436 lease->addr.s_addr = dhcp->yiaddr;
1190- addr = xstrdup(inet_ntoa(lease->addr));
1191- r = get_option_addr(&lease->server.s_addr, dhcp, DHCP_SERVERID);
1192- if (dhcp->servername[0] && r == 0)
1193- logger(LOG_INFO, "offered %s from %s `%s'",
1194- addr, inet_ntoa(lease->server),
1195- dhcp->servername);
1196- else if (r == 0)
1197- logger(LOG_INFO, "offered %s from %s",
1198- addr, inet_ntoa(lease->server));
1199- else
1200- logger(LOG_INFO, "offered %s", addr);
1201- free(addr);
1202-
1437+ get_option_addr(&lease->server.s_addr, dhcp, DHO_SERVERID);
1438+ log_dhcp(LOG_INFO, "offered", dhcp);
12031439 if (state->options & DHCPCD_TEST) {
1204- exec_script(options, iface->name, "TEST", dhcp, NULL);
1205- free(dhcp);
1206- return 0;
1440+ run_script(options, iface->name, "TEST", dhcp, NULL);
1441+ /* Fake the fact we forked so we return 0 to userland */
1442+ state->options |= DHCPCD_FORKED;
1443+ return -1;
1444+ }
1445+ free(state->offer);
1446+ state->offer = dhcp;
1447+ *dhcpp = NULL;
1448+ timerclear(&state->timeout);
1449+ if (state->options & DHCPCD_ARP &&
1450+ iface->addr.s_addr != state->offer->yiaddr)
1451+ {
1452+ /* If the interface already has the address configured
1453+ * then we can't ARP for duplicate detection. */
1454+ addr.s_addr = state->offer->yiaddr;
1455+ if (!has_address(iface->name, &addr, NULL)) {
1456+ state->state = STATE_PROBING;
1457+ state->claims = 0;
1458+ state->probes = 0;
1459+ state->conflicts = 0;
1460+ timerclear(&state->stop);
1461+ return 1;
1462+ }
12071463 }
1208-
1209- free(dhcp);
12101464 state->state = STATE_REQUESTING;
1211- state->timeout = 0;
1212- return 0;
1465+ return 1;
12131466 }
12141467
12151468 if (type == DHCP_OFFER) {
1216- saddr.s_addr = dhcp->yiaddr;
1217- logger(LOG_INFO, "got subsequent offer of %s, ignoring ",
1218- inet_ntoa(saddr));
1219- free(dhcp);
1469+ log_dhcp(LOG_INFO, "ignoring offer of", dhcp);
12201470 return 0;
12211471 }
12221472
12231473 /* We should only be dealing with acks */
12241474 if (type != DHCP_ACK) {
1225- logger(LOG_ERR, "%d not an ACK or OFFER", type);
1226- free(dhcp);
1475+ log_dhcp(LOG_ERR, "not ACK or OFFER", dhcp);
12271476 return 0;
12281477 }
12291478
@@ -1233,35 +1482,30 @@ handle_dhcp(struct if_state *state, struct dhcp_message **dhcpp,
12331482 case STATE_RENEWING:
12341483 case STATE_REBINDING:
12351484 if (!(state->options & DHCPCD_INFORM)) {
1236- saddr.s_addr = dhcp->yiaddr;
1237- logger(LOG_INFO, "lease of %s acknowledged",
1238- inet_ntoa(saddr));
1485+ get_option_addr(&lease->server.s_addr,
1486+ dhcp, DHO_SERVERID);
1487+ log_dhcp(LOG_INFO, "acknowledged", dhcp);
12391488 }
1489+ free(state->offer);
1490+ state->offer = dhcp;
1491+ *dhcpp = NULL;
12401492 break;
12411493 default:
12421494 logger(LOG_ERR, "wrong state %d", state->state);
12431495 }
12441496
12451497 do_socket(state, SOCKET_CLOSED);
1246- free(state->offer);
1247- state->offer = dhcp;
1248- *dhcpp = NULL;
1249-
1250-#ifdef ENABLE_ARP
1251- if (state->options & DHCPCD_ARP &&
1252- iface->addr.s_addr != state->offer->yiaddr)
1253- {
1254- state->state = STATE_PROBING;
1255- state->timeout = 0;
1256- state->claims = 0;
1257- state->probes = 0;
1258- state->conflicts = 0;
1259- timerclear(&state->stop);
1260- return 0;
1498+ r = bind_dhcp(state, options);
1499+ if (!(state->options & DHCPCD_ARP)) {
1500+ if (!(state->options & DHCPCD_INFORM))
1501+ logger(LOG_DEBUG, "renew in %ld seconds",
1502+ (long int)state->stop.tv_sec);
1503+ return r;
12611504 }
1262-#endif
1263-
1264- return bind_dhcp(state, options);
1505+ state->state = STATE_ANNOUNCING;
1506+ if (state->options & DHCPCD_FORKED)
1507+ return r;
1508+ return 1;
12651509 }
12661510
12671511 static int
@@ -1269,7 +1513,7 @@ handle_dhcp_packet(struct if_state *state, const struct options *options)
12691513 {
12701514 uint8_t *packet;
12711515 struct interface *iface = state->interface;
1272- struct dhcp_message *dhcp;
1516+ struct dhcp_message *dhcp = NULL;
12731517 const uint8_t *pp;
12741518 uint8_t *p;
12751519 ssize_t bytes;
@@ -1279,7 +1523,6 @@ handle_dhcp_packet(struct if_state *state, const struct options *options)
12791523 * The benefit is that if we get >1 DHCP packet in our buffer and
12801524 * the first one fails for any reason, we can use the next. */
12811525 packet = xmalloc(udp_dhcp_len);
1282- dhcp = xmalloc(sizeof(*dhcp));
12831526 for(;;) {
12841527 bytes = get_raw_packet(iface, ETHERTYPE_IP,
12851528 packet, udp_dhcp_len);
@@ -1296,11 +1539,14 @@ handle_dhcp_packet(struct if_state *state, const struct options *options)
12961539 logger(LOG_ERR, "packet greater than DHCP size");
12971540 continue;
12981541 }
1542+ if (!dhcp)
1543+ dhcp = xmalloc(sizeof(*dhcp));
12991544 memcpy(dhcp, pp, bytes);
13001545 if (dhcp->cookie != htonl(MAGIC_COOKIE)) {
13011546 logger(LOG_DEBUG, "bogus cookie, ignoring");
13021547 continue;
13031548 }
1549+ /* Ensure it's the right transaction */
13041550 if (state->xid != dhcp->xid) {
13051551 logger(LOG_DEBUG,
13061552 "ignoring packet with xid 0x%x as"
@@ -1308,25 +1554,28 @@ handle_dhcp_packet(struct if_state *state, const struct options *options)
13081554 dhcp->xid, state->xid);
13091555 continue;
13101556 }
1557+ /* Ensure packet is for us */
1558+ if (iface->hwlen <= sizeof(dhcp->chaddr) &&
1559+ memcmp(dhcp->chaddr, iface->hwaddr, iface->hwlen))
1560+ {
1561+ logger(LOG_DEBUG, "xid 0x%x is not for our hwaddr %s",
1562+ dhcp->xid,
1563+ hwaddr_ntoa(dhcp->chaddr, sizeof(dhcp->chaddr)));
1564+ continue;
1565+ }
13111566 /* We should ensure that the packet is terminated correctly
13121567 * if we have space for the terminator */
13131568 if ((size_t)bytes < sizeof(struct dhcp_message)) {
13141569 p = (uint8_t *)dhcp + bytes - 1;
1315- while (p > dhcp->options && *p == DHCP_PAD)
1570+ while (p > dhcp->options && *p == DHO_PAD)
13161571 p--;
1317- if (*p != DHCP_END)
1318- *++p = DHCP_END;
1572+ if (*p != DHO_END)
1573+ *++p = DHO_END;
13191574 }
1320- free(packet);
1321- if (handle_dhcp(state, &dhcp, options) == 0) {
1322- /* Fake the fact we forked so we return 0 to userland */
1323- if (state->options & DHCPCD_TEST)
1324- state->options |= DHCPCD_FORKED;
1325- else
1326- return 0;
1327- }
1328- if (state->options & DHCPCD_FORKED)
1329- return -1;
1575+ retval = handle_dhcp(state, &dhcp, options);
1576+ if (retval == 0 && state->options & DHCPCD_TEST)
1577+ state->options |= DHCPCD_FORKED;
1578+ break;
13301579 }
13311580
13321581 free(packet);
@@ -1334,7 +1583,6 @@ handle_dhcp_packet(struct if_state *state, const struct options *options)
13341583 return retval;
13351584 }
13361585
1337-#ifdef ENABLE_ARP
13381586 static int
13391587 handle_arp_packet(struct if_state *state)
13401588 {
@@ -1347,7 +1595,6 @@ handle_arp_packet(struct if_state *state)
13471595 struct interface *iface = state->interface;
13481596
13491597 state->fail.s_addr = 0;
1350-
13511598 for(;;) {
13521599 bytes = get_raw_packet(iface, ETHERTYPE_ARP,
13531600 arp_reply, sizeof(arp_reply));
@@ -1373,6 +1620,10 @@ handle_arp_packet(struct if_state *state)
13731620 /* Ensure we got all the data */
13741621 if ((hw_t + reply.ar_hln + reply.ar_pln) - arp_reply > bytes)
13751622 continue;
1623+ /* Ignore messages from ourself */
1624+ if (reply.ar_hln == iface->hwlen &&
1625+ memcmp(hw_s, iface->hwaddr, iface->hwlen) == 0)
1626+ continue;
13761627 /* Copy out the IP addresses */
13771628 memcpy(&reply_s, hw_s + reply.ar_hln, reply.ar_pln);
13781629 memcpy(&reply_t, hw_t + reply.ar_hln, reply.ar_pln);
@@ -1380,19 +1631,13 @@ handle_arp_packet(struct if_state *state)
13801631 /* Check for conflict */
13811632 if (state->offer &&
13821633 (reply_s == state->offer->yiaddr ||
1383- (reply_t == state->offer->yiaddr &&
1384- reply.ar_op == htons(ARPOP_REQUEST) &&
1385- (iface->hwlen != reply.ar_hln ||
1386- memcmp(hw_s, iface->hwaddr, iface->hwlen) != 0))))
1634+ (reply_s == 0 && reply_t == state->offer->yiaddr)))
13871635 state->fail.s_addr = state->offer->yiaddr;
13881636
13891637 /* Handle IPv4LL conflicts */
13901638 if (IN_LINKLOCAL(htonl(iface->addr.s_addr)) &&
13911639 (reply_s == iface->addr.s_addr ||
1392- (reply_t == iface->addr.s_addr &&
1393- reply.ar_op == htons(ARPOP_REQUEST) &&
1394- (iface->hwlen != reply.ar_hln ||
1395- memcmp(hw_s, iface->hwaddr, iface->hwlen) != 0))))
1640+ (reply_s == 0 && reply_t == iface->addr.s_addr)))
13961641 state->fail.s_addr = iface->addr.s_addr;
13971642
13981643 if (state->fail.s_addr) {
@@ -1409,78 +1654,118 @@ handle_arp_packet(struct if_state *state)
14091654 static int
14101655 handle_arp_fail(struct if_state *state, const struct options *options)
14111656 {
1412- struct timespec ts;
14131657 time_t up;
1658+ int cookie = state->offer->cookie;
14141659
1415- if (IN_LINKLOCAL(htonl(state->fail.s_addr))) {
1416- if (state->fail.s_addr == state->interface->addr.s_addr) {
1660+ if (!IN_LINKLOCAL(htonl(state->fail.s_addr))) {
1661+ state->state = STATE_INIT;
1662+ free(state->offer);
1663+ state->offer = NULL;
1664+ state->lease.addr.s_addr = 0;
1665+ if (!cookie)
1666+ return 1;
1667+ state->timeout.tv_sec = DHCP_ARP_FAIL;
1668+ state->timeout.tv_usec = 0;
1669+ do_socket(state, SOCKET_OPEN);
1670+ send_message(state, DHCP_DECLINE, options);
1671+ do_socket(state, SOCKET_CLOSED);
1672+ return 0;
1673+ }
1674+
1675+ if (state->fail.s_addr == state->interface->addr.s_addr) {
1676+ if (state->state == STATE_PROBING)
1677+ /* This should only happen when SIGALRM or
1678+ * link when down/up and we have a conflict. */
1679+ drop_config(state, "EXPIRE", options);
1680+ else {
14171681 up = uptime();
14181682 if (state->defend + DEFEND_INTERVAL > up) {
1419- drop_config(state, "FAIL", options);
1420- state->state = STATE_PROBING;
1421- state->timeout = 0;
1422- state->claims = 0;
1423- state->probes = 0;
1424- state->conflicts = 0;
1425- timerclear(&state->stop);
1426- } else
1683+ drop_config(state, "EXPIRE", options);
1684+ state->conflicts = -1;
1685+ /* drop through to set conflicts to 0 */
1686+ } else {
14271687 state->defend = up;
1428- return 0;
1688+ return 0;
1689+ }
14291690 }
1691+ }
1692+ do_socket(state, SOCKET_CLOSED);
1693+ state->conflicts++;
1694+ timerclear(&state->stop);
1695+ if (state->conflicts > MAX_CONFLICTS) {
1696+ logger(LOG_ERR, "failed to obtain an IPv4LL address");
1697+ state->state = STATE_INIT;
1698+ timerclear(&state->timeout);
1699+ if (!(state->options & DHCPCD_DAEMONISED) &&
1700+ (state->options & DHCPCD_DAEMONISE))
1701+ return -1;
1702+ return 1;
1703+ }
1704+ state->state = STATE_INIT_IPV4LL;
1705+ state->timeout.tv_sec = PROBE_WAIT;
1706+ state->timeout.tv_usec = 0;
1707+ return 0;
1708+}
14301709
1431- timerclear(&state->stop);
1432- state->conflicts++;
1433- state->timeout = 0;
1434- state->claims = 0;
1435- state->probes = 0;
1436- state->state = STATE_PROBING;
1437- free(state->offer);
1438- if (state->conflicts > MAX_CONFLICTS) {
1439- /* RFC 3927 says we should rate limit */
1440- logger(LOG_INFO, "sleeping for %d seconds",
1441- RATE_LIMIT_INTERVAL);
1442- ts.tv_sec = RATE_LIMIT_INTERVAL;
1443- ts.tv_nsec = 0;
1444- nanosleep(&ts, NULL);
1445- }
1446- state->offer = ipv4ll_get_dhcp(0);
1447- return 0;
1710+static int
1711+handle_link(struct if_state *state)
1712+{
1713+ int retval;
1714+
1715+ retval = link_changed(state->interface);
1716+ if (retval == -1) {
1717+ logger(LOG_ERR, "link_changed: %s", strerror(errno));
1718+ return -1;
14481719 }
1720+ if (retval == 0)
1721+ return 0;
14491722
1450- do_socket(state, SOCKET_OPEN);
1451- send_message(state, DHCP_DECLINE, options);
1452- state->timeout = 0;
1453- state->state = STATE_INIT;
1454- /* RFC 2131 says that we should wait for 10 seconds
1455- * before doing anything else */
1456- logger(LOG_INFO, "sleeping for 10 seconds");
1457- ts.tv_sec = 10;
1458- ts.tv_nsec = 0;
1459- nanosleep(&ts, NULL);
1723+ timerclear(&state->timeout);
1724+ switch (carrier_status(state->interface->name)) {
1725+ case -1:
1726+ logger(LOG_ERR, "carrier_status: %s", strerror(errno));
1727+ return -1;
1728+ case 0:
1729+ if (state->carrier != LINK_DOWN) {
1730+ logger(LOG_INFO, "carrier lost");
1731+ state->carrier = LINK_DOWN;
1732+ do_socket(state, SOCKET_CLOSED);
1733+ if (state->state != STATE_BOUND)
1734+ timerclear(&state->stop);
1735+ }
1736+ break;
1737+ default:
1738+ if (state->carrier != LINK_UP) {
1739+ logger(LOG_INFO, "carrier acquired");
1740+ state->state = STATE_RENEW_REQUESTED;
1741+ state->carrier = LINK_UP;
1742+ timerclear(&state->stop);
1743+ return 1;
1744+ }
1745+ break;
1746+ }
14601747 return 0;
14611748 }
1462-#endif
14631749
14641750 int
14651751 dhcp_run(const struct options *options, int *pid_fd)
14661752 {
14671753 struct interface *iface;
14681754 struct if_state *state = NULL;
1469- int retval = -1;
1470- int sig;
1755+ int fd = -1, r = 0, sig;
14711756
14721757 iface = read_interface(options->interface, options->metric);
14731758 if (!iface) {
14741759 logger(LOG_ERR, "read_interface: %s", strerror(errno));
14751760 goto eexit;
14761761 }
1477-
1478- logger(LOG_INFO, "hardware address = %s",
1762+ logger(LOG_DEBUG, "hardware address = %s",
14791763 hwaddr_ntoa(iface->hwaddr, iface->hwlen));
1480-
14811764 state = xzalloc(sizeof(*state));
14821765 state->pid_fd = pid_fd;
14831766 state->interface = iface;
1767+ if (!(options->options & DHCPCD_TEST))
1768+ run_script(options, iface->name, "PREINIT", NULL, NULL);
14841769
14851770 if (client_setup(state, options) == -1)
14861771 goto eexit;
@@ -1488,42 +1773,51 @@ dhcp_run(const struct options *options, int *pid_fd)
14881773 goto eexit;
14891774 if (signal_setup() == -1)
14901775 goto eexit;
1491-
14921776 state->signal_fd = signal_fd();
14931777
1778+ if (state->options & DHCPCD_BACKGROUND &&
1779+ !(state->options & DHCPCD_DAEMONISED))
1780+ if (daemonise(state, options) == -1)
1781+ goto eexit;
1782+
1783+ if (state->carrier == LINK_DOWN)
1784+ logger(LOG_INFO, "waiting for carrier");
1785+
14941786 for (;;) {
1495- retval = wait_for_packet(state);
1496-
1497- /* We should always handle our signals first */
1498- if ((sig = (signal_read(state->signal_fd))) != -1) {
1499- retval = handle_signal(sig, state, options);
1500- } else if (retval == 0)
1501- retval = handle_timeout(state, options);
1502- else if (retval == -1) {
1503- if (errno == EINTR)
1504- /* The interupt will be handled above */
1505- retval = 0;
1506- } else if (retval > 0) {
1507- if (fd_hasdata(state->interface->fd) == 1)
1508- retval = handle_dhcp_packet(state, options);
1509-#ifdef ENABLE_ARP
1510- else if (fd_hasdata(state->interface->arp_fd) == 1) {
1511- retval = handle_arp_packet(state);
1512- if (retval == -1)
1513- retval = handle_arp_fail(state, options);
1514- }
1515-#endif
1516- else
1517- retval = 0;
1787+ if (r == 0)
1788+ r = handle_timeout(state, options);
1789+ else if (r > 0) {
1790+ if (fd == state->signal_fd) {
1791+ if ((sig = signal_read()) != -1)
1792+ r = handle_signal(sig, state, options);
1793+ } else if (fd == iface->link_fd)
1794+ r = handle_link(state);
1795+ else if (fd == iface->raw_fd)
1796+ r = handle_dhcp_packet(state, options);
1797+ else if (fd == iface->arp_fd) {
1798+ if ((r = handle_arp_packet(state)) == -1)
1799+ r = handle_arp_fail(state, options);
1800+ } else
1801+ r = 0;
15181802 }
1519-
1520- if (retval != 0)
1803+ if (r == -1)
15211804 break;
1805+ if (r == 0) {
1806+ fd = -1;
1807+ r = wait_for_fd(state, &fd);
1808+ if (r == -1 && errno == EINTR) {
1809+ r = 1;
1810+ fd = state->signal_fd;
1811+ }
1812+ } else
1813+ r = 0;
15221814 }
15231815
15241816 eexit:
15251817 if (iface) {
15261818 do_socket(state, SOCKET_CLOSED);
1819+ if (iface->link_fd != -1)
1820+ close(iface->link_fd);
15271821 free_routes(iface->routes);
15281822 free(iface->clientid);
15291823 free(iface->buffer);
@@ -1532,7 +1826,7 @@ eexit:
15321826
15331827 if (state) {
15341828 if (state->options & DHCPCD_FORKED)
1535- retval = 0;
1829+ r = 0;
15361830 if (state->options & DHCPCD_DAEMONISED)
15371831 unlink(options->pidfile);
15381832 free(state->offer);
@@ -1541,5 +1835,5 @@ eexit:
15411835 free(state);
15421836 }
15431837
1544- return retval;
1838+ return r;
15451839 }
--- a/common.c
+++ b/common.c
@@ -25,6 +25,11 @@
2525 * SUCH DAMAGE.
2626 */
2727
28+#ifdef __APPLE__
29+# include <mach/mach_time.h>
30+# include <mach/kern_return.h>
31+#endif
32+
2833 #include <sys/param.h>
2934 #include <sys/time.h>
3035
@@ -33,7 +38,6 @@
3338 #ifdef BSD
3439 # include <paths.h>
3540 #endif
36-#include <poll.h>
3741 #include <stdint.h>
3842 #include <stdio.h>
3943 #include <stdlib.h>
@@ -48,6 +52,8 @@
4852 # define _PATH_DEVNULL "/dev/null"
4953 #endif
5054
55+int clock_monotonic = 0;
56+
5157 /* Handy routine to read very long lines in text files.
5258 * This means we read the whole line and avoid any nasty buffer overflows. */
5359 ssize_t
@@ -151,25 +157,6 @@ close_fds(void)
151157 }
152158
153159 int
154-fd_hasdata(int fd)
155-{
156- struct pollfd fds;
157- int retval;
158-
159- if (fd == -1)
160- return -1;
161- fds.fd = fd;
162- fds.events = POLLIN;
163- fds.revents = 0;
164- retval = poll(&fds, 1, 0);
165- if (retval == -1)
166- return -1;
167- if (retval > 0 && fds.revents & POLLIN)
168- return retval;
169- return 0;
170-}
171-
172-int
173160 set_cloexec(int fd)
174161 {
175162 int flags;
@@ -202,41 +189,77 @@ set_nonblock(int fd)
202189 * Which is why we use CLOCK_MONOTONIC, but it is not available on all
203190 * platforms.
204191 */
192+#define NO_MONOTONIC "host does not support a monotonic clock - timing can skew"
205193 int
206-get_time(struct timeval *tp)
194+get_monotonic(struct timeval *tp)
207195 {
196+ static int posix_clock_set = 0;
208197 #if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC)
209198 struct timespec ts;
210199 static clockid_t posix_clock;
211- static int posix_clock_set = 0;
212200
213- if (!posix_clock_set) {
214- if (sysconf(_SC_MONOTONIC_CLOCK) >= 0)
201+ if (posix_clock_set == 0) {
202+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
215203 posix_clock = CLOCK_MONOTONIC;
216- else
217- posix_clock = CLOCK_REALTIME;
204+ clock_monotonic = 1;
205+ }
218206 posix_clock_set = 1;
219207 }
220208
221- if (clock_gettime(posix_clock, &ts) == -1)
222- return -1;
209+ if (clock_monotonic) {
210+ if (clock_gettime(posix_clock, &ts) == 0) {
211+ tp->tv_sec = ts.tv_sec;
212+ tp->tv_usec = ts.tv_nsec / 1000;
213+ return 0;
214+ }
215+ }
216+#elif defined(__APPLE__)
217+#define NSEC_PER_SEC 1000000000
218+ /* We can use mach kernel functions here.
219+ * This is crap though - why can't they implement clock_gettime?*/
220+ static struct mach_timebase_info info = { 0, 0 };
221+ static double factor = 0.0;
222+ uint64_t nano;
223+ long rem;
224+
225+ if (posix_clock_set == 0) {
226+ if (mach_timebase_info(&info) == KERN_SUCCESS) {
227+ factor = (double)info.numer / (double)info.denom;
228+ clock_monotonic = 1;
229+ }
230+ posix_clock_set = 1;
231+ }
232+ if (clock_monotonic) {
233+ nano = mach_absolute_time();
234+ if ((info.denom != 1 || info.numer != 1) && factor != 0.0)
235+ nano *= factor;
236+ tp->tv_sec = nano / NSEC_PER_SEC;
237+ rem = nano % NSEC_PER_SEC;
238+ if (rem < 0) {
239+ tp->tv_sec--;
240+ rem += NSEC_PER_SEC;
241+ }
242+ tp->tv_usec = rem / 1000;
243+ return 0;
244+ }
245+#endif
223246
224- tp->tv_sec = ts.tv_sec;
225- tp->tv_usec = ts.tv_nsec / 1000;
226- return 0;
227-#else
247+ /* Something above failed, so fall back to gettimeofday */
248+ if (!posix_clock_set) {
249+ logger(LOG_WARNING, NO_MONOTONIC);
250+ posix_clock_set = 1;
251+ }
228252 return gettimeofday(tp, NULL);
229-#endif
230253 }
231254
232255 time_t
233256 uptime(void)
234257 {
235- struct timeval tp;
258+ struct timeval tv;
236259
237- if (get_time(&tp) == -1)
260+ if (get_monotonic(&tv) == -1)
238261 return -1;
239- return tp.tv_sec;
262+ return tv.tv_sec;
240263 }
241264
242265 int
@@ -247,7 +270,7 @@ writepid(int fd, pid_t pid)
247270
248271 if (ftruncate(fd, (off_t)0) == -1)
249272 return -1;
250- snprintf(spid, sizeof(spid), "%u", pid);
273+ snprintf(spid, sizeof(spid), "%u\n", pid);
251274 len = pwrite(fd, spid, strlen(spid), (off_t)0);
252275 if (len != (ssize_t)strlen(spid))
253276 return -1;
--- a/common.h
+++ b/common.h
@@ -63,19 +63,20 @@ size_t strlcpy(char *, const char *, size_t);
6363 #endif
6464
6565 #ifndef HAVE_CLOSEFROM
66-#define HAVE_CLOSEFROM 1
66+# if defined(__NetBSD__) || defined(__OpenBSD__)
67+# define HAVE_CLOSEFROM 1
68+# endif
6769 #endif
68-#if defined(__linux__) || defined(__FreeBSD__)
69-# undef HAVE_CLOSEFROM
70+#ifndef HAVE_CLOSEFROM
7071 int closefrom(int);
7172 #endif
7273
7374 int close_fds(void);
7475 int set_cloexec(int);
7576 int set_nonblock(int);
76-int fd_hasdata(int);
7777 ssize_t get_line(char **, size_t *, FILE *);
78-int get_time(struct timeval *);
78+extern int clock_monotonic;
79+int get_monotonic(struct timeval *);
7980 time_t uptime(void);
8081 int writepid(int, pid_t);
8182 void *xrealloc(void *, size_t);
--- a/config.h
+++ b/config.h
@@ -28,34 +28,7 @@
2828 #define CONFIG_H
2929
3030 #define PACKAGE "dhcpcd"
31-#define VERSION "4.0.0-beta9"
32-
33-/* You can enable/disable various chunks of optional code here.
34- * You would only do this to try and shrink the end binary if dhcpcd
35- * was running on a low memory device */
36-
37-/* Disable everything we possibly can. */
38-#ifdef MINIMAL
39-# ifndef DISABLE_ARP
40-# define DISABLE_ARP
41-# endif
42-# ifndef DISABLE_IPV4LL
43-# define DISABLE_IPV4LL
44-# endif
45-#endif
46-
47-/* Enable ARP by default. */
48-#ifndef DISABLE_ARP
49-# define ENABLE_ARP
50-#endif
51-
52-/* IPV4LL, aka ZeroConf, aka APIPA, aka RFC 3927.
53- * Needs ARP. */
54-#ifndef DISABLE_IPV4LL
55-# ifdef ENABLE_ARP
56-# define ENABLE_IPV4LL
57-# endif
58-#endif
31+#define VERSION "4.0.1"
5932
6033 /*
6134 * By default we don't add a local link route if we got a routeable address.
@@ -64,7 +37,7 @@
6437 * Ideally the host network scripts should add the link local route for us.
6538 * If not, you can define this to get dhcpcd to always add the link local route.
6639 */
67-// #define ENABLE_IPV4LL_ALWAYSROUTE
40+// #define IPV4LL_ALWAYSROUTE
6841
6942 /* Some systems do not have a working fork. */
7043 /* #define THERE_IS_NO_FORK */
--- a/configure.c
+++ b/configure.c
@@ -48,22 +48,50 @@
4848
4949 #define DEFAULT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin"
5050
51+
52+static int
53+exec_script(char *const *argv, char *const *env)
54+{
55+ pid_t pid;
56+ sigset_t full;
57+ sigset_t old;
58+
59+ /* OK, we need to block signals */
60+ sigfillset(&full);
61+ sigprocmask(SIG_SETMASK, &full, &old);
62+ signal_reset();
63+
64+ switch (pid = vfork()) {
65+ case -1:
66+ logger(LOG_ERR, "vfork: %s", strerror(errno));
67+ break;
68+ case 0:
69+ sigprocmask(SIG_SETMASK, &old, NULL);
70+ execve(argv[0], argv, env);
71+ logger(LOG_ERR, "%s: %s", argv[0], strerror(errno));
72+ _exit(127);
73+ /* NOTREACHED */
74+ }
75+
76+ /* Restore our signals */
77+ signal_setup();
78+ sigprocmask(SIG_SETMASK, &old, NULL);
79+ return pid;
80+}
81+
5182 int
52-exec_script(const struct options *options, const char *iface,
53- const char *reason,
54- const struct dhcp_message *dhcpn, const struct dhcp_message *dhcpo)
83+run_script(const struct options *options, const char *iface,
84+ const char *reason,
85+ const struct dhcp_message *dhcpn, const struct dhcp_message *dhcpo)
5586 {
5687 char *const argv[2] = { UNCONST(options->script), NULL };
5788 char **env = NULL, **ep;
5889 char *path;
5990 ssize_t e, elen;
60- int ret = 0;
6191 pid_t pid;
6292 int status = 0;
63- sigset_t full;
64- sigset_t old;
6593
66- logger(LOG_DEBUG, "executing `%s'", options->script);
94+ logger(LOG_DEBUG, "executing `%s', reason %s", options->script, reason);
6795
6896 /* Make our env */
6997 elen = 5;
@@ -115,50 +143,17 @@ exec_script(const struct options *options, const char *iface,
115143 }
116144 env[elen] = '\0';
117145
118- /* OK, we need to block signals */
119- sigfillset(&full);
120- sigprocmask(SIG_SETMASK, &full, &old);
121-
122-#ifdef THERE_IS_NO_FORK
123- signal_reset();
124- pid = vfork();
125-#else
126- pid = fork();
127-#endif
128-
129- switch (pid) {
130- case -1:
131-#ifdef THERE_IS_NO_FORK
132- logger(LOG_ERR, "vfork: %s", strerror(errno));
133-#else
134- logger(LOG_ERR, "fork: %s", strerror(errno));
135-#endif
136- ret = -1;
137- break;
138- case 0:
139-#ifndef THERE_IS_NO_FORK
140- signal_reset();
141-#endif
142- sigprocmask(SIG_SETMASK, &old, NULL);
143- execve(options->script, argv, env);
144- logger(LOG_ERR, "%s: %s", options->script, strerror(errno));
145- _exit(111);
146- /* NOTREACHED */
147- }
148-
149-#ifdef THERE_IS_NO_FORK
150- signal_setup();
151-#endif
152-
153- /* Restore our signals */
154- sigprocmask(SIG_SETMASK, &old, NULL);
155-
156- /* Wait for the script to finish */
157- while (waitpid(pid, &status, 0) == -1) {
158- if (errno != EINTR) {
159- logger(LOG_ERR, "waitpid: %s", strerror(errno));
160- status = -1;
161- break;
146+ pid = exec_script(argv, env);
147+ if (pid == -1)
148+ status = -1;
149+ else if (pid != 0) {
150+ /* Wait for the script to finish */
151+ while (waitpid(pid, &status, 0) == -1) {
152+ if (errno != EINTR) {
153+ logger(LOG_ERR, "waitpid: %s", strerror(errno));
154+ status = -1;
155+ break;
156+ }
162157 }
163158 }
164159
@@ -167,7 +162,6 @@ exec_script(const struct options *options, const char *iface,
167162 while (*ep)
168163 free(*ep++);
169164 free(env);
170-
171165 return status;
172166 }
173167
@@ -193,14 +187,13 @@ delete_route(const char *iface, struct rt *rt, int metric)
193187 int retval;
194188
195189 addr = xstrdup(inet_ntoa(rt->dest));
196- logger(LOG_DEBUG, "removing route %s/%d via %s",
197- addr, inet_ntocidr(rt->net), inet_ntoa(rt->gate));
190+ logger(LOG_DEBUG, "deleting route %s/%d via %s",
191+ addr, inet_ntocidr(rt->net), inet_ntoa(rt->gate));
198192 free(addr);
199193 retval = del_route(iface, &rt->dest, &rt->net, &rt->gate, metric);
200- if (retval != 0)
194+ if (retval != 0 && errno != ENOENT && errno != ESRCH)
201195 logger(LOG_ERR," del_route: %s", strerror(errno));
202196 return retval;
203-
204197 }
205198
206199 static int
@@ -245,22 +238,9 @@ configure_routes(struct interface *iface, const struct dhcp_message *dhcp,
245238 int retval = 0;
246239 char *addr;
247240
248-#ifdef THERE_IS_NO_FORK
249- char *skipp;
250- size_t skiplen;
251- int skip = 0;
252-
253- free(dhcpcd_skiproutes);
254- /* We can never have more than 255 routes. So we need space
255- * for 255 3 digit numbers and commas */
256- skiplen = 255 * 4 + 1;
257- skipp = dhcpcd_skiproutes = xmalloc(sizeof(char) * skiplen);
258- *skipp = '\0';
259-#endif
260-
261241 ort = get_option_routes(dhcp);
262242
263-#ifdef ENABLE_IPV4LL_ALWAYSROUTE
243+#ifdef IPV4LL_ALWAYSROUTE
264244 if (options->options & DHCPCD_IPV4LL &&
265245 IN_PRIVATE(ntohl(dhcp->yiaddr)))
266246 {
@@ -287,43 +267,6 @@ configure_routes(struct interface *iface, const struct dhcp_message *dhcp,
287267 }
288268 #endif
289269
290-#ifdef THERE_IS_NO_FORK
291- if (dhcpcd_skiproutes) {
292- int i = -1;
293- char *sk, *skp, *token;
294- free_routes(iface->routes);
295- for (rt = ort; rt; rt = rt->next) {
296- i++;
297- /* Check that we did add this route or not */
298- sk = skp = xstrdup(dhcpcd_skiproutes);
299- while ((token = strsep(&skp, ","))) {
300- if (isdigit((unsigned char)*token) &&
301- atoi(token) == i)
302- break;
303- }
304- free(sk);
305- if (token)
306- continue;
307- if (nr) {
308- rtn->next = xmalloc(sizeof(*rtn));
309- rtn = rtn->next;
310- } else {
311- nr = rtn = xmalloc(sizeof(*rtn));
312- }
313- rtn->dest.s_addr = rt->dest.s_addr;
314- rtn->net.s_addr = rt->net.s_addr;
315- rtn->gate.s_addr = rt->gate.s_addr;
316- rtn->next = NULL;
317- }
318- iface->routes = nr;
319- nr = NULL;
320-
321- /* We no longer need this */
322- free(dhcpcd_skiproutes);
323- dhcpcd_skiproutes = NULL;
324- }
325-#endif
326-
327270 /* Now remove old routes we no longer use.
328271 * We should do this in reverse order. */
329272 iface->routes = reverse_routes(iface->routes);
@@ -370,37 +313,25 @@ configure_routes(struct interface *iface, const struct dhcp_message *dhcp,
370313 rtn->gate.s_addr = rt->gate.s_addr;
371314 rtn->next = NULL;
372315 }
373-#ifdef THERE_IS_NO_FORK
374- /* If we have daemonised yet we need to record which routes
375- * we failed to add so we can skip them */
376- else if (!(options->options & DHCPCD_DAEMONISED)) {
377- /* We can never have more than 255 / 4 routes,
378- * so 3 chars is plently */
379- printf("foo\n");
380- if (*skipp)
381- *skipp++ = ',';
382- skipp += snprintf(skipp,
383- dhcpcd_skiproutes + skiplen - skipp,
384- "%d", skip);
385- }
386- skip++;
387-#endif
388316 }
389317 free_routes(ort);
390318 free_routes(iface->routes);
391319 iface->routes = nr;
320+ return retval;
321+}
392322
393-#ifdef THERE_IS_NO_FORK
394- if (dhcpcd_skiproutes) {
395- if (*dhcpcd_skiproutes)
396- *skipp = '\0';
397- else {
398- free(dhcpcd_skiproutes);
399- dhcpcd_skiproutes = NULL;
400- }
401- }
402-#endif
403-
323+static int
324+delete_address(struct interface *iface)
325+{
326+ int retval;
327+ logger(LOG_DEBUG, "deleting IP address %s/%d",
328+ inet_ntoa(iface->addr),
329+ inet_ntocidr(iface->net));
330+ retval = del_address(iface->name, &iface->addr, &iface->net);
331+ if (retval == -1 && errno != EADDRNOTAVAIL)
332+ logger(LOG_ERR, "del_address: %s", strerror(errno));
333+ iface->addr.s_addr = 0;
334+ iface->net.s_addr = 0;
404335 return retval;
405336 }
406337
@@ -419,14 +350,16 @@ configure(struct interface *iface, const char *reason,
419350 #endif
420351
421352 /* Grab our IP config */
422- if (dhcp == NULL || dhcp->yiaddr == 0)
353+ if (dhcp == NULL)
423354 up = 0;
424355 else {
425356 addr.s_addr = dhcp->yiaddr;
357+ if (addr.s_addr == 0)
358+ addr.s_addr = lease->addr.s_addr;
426359 /* Ensure we have all the needed values */
427- if (get_option_addr(&net.s_addr, dhcp, DHCP_SUBNETMASK) == -1)
360+ if (get_option_addr(&net.s_addr, dhcp, DHO_SUBNETMASK) == -1)
428361 net.s_addr = get_netmask(addr.s_addr);
429- if (get_option_addr(&brd.s_addr, dhcp, DHCP_BROADCAST) == -1)
362+ if (get_option_addr(&brd.s_addr, dhcp, DHO_BROADCAST) == -1)
430363 brd.s_addr = addr.s_addr | ~net.s_addr;
431364 }
432365
@@ -435,19 +368,10 @@ configure(struct interface *iface, const char *reason,
435368 /* Only reset things if we had set them before */
436369 if (iface->addr.s_addr != 0) {
437370 delete_routes(iface, options->metric);
438- logger(LOG_DEBUG, "deleting IP address %s/%d",
439- inet_ntoa(iface->addr),
440- inet_ntocidr(iface->net));
441- if (del_address(iface->name, &iface->addr,
442- &iface->net) == -1 &&
443- errno != ENOENT)
444- logger(LOG_ERR, "del_address: %s",
445- strerror(errno));
446- iface->addr.s_addr = 0;
447- iface->net.s_addr = 0;
371+ delete_address(iface);
448372 }
449373
450- exec_script(options, iface->name, reason, NULL, old);
374+ run_script(options, iface->name, reason, NULL, old);
451375 return 0;
452376 }
453377
@@ -466,8 +390,8 @@ configure(struct interface *iface, const char *reason,
466390
467391 /* Now delete the old address if different */
468392 if (iface->addr.s_addr != addr.s_addr &&
469- iface->addr.s_addr != 0)
470- del_address(iface->name, &iface->addr, &iface->net);
393+ iface->addr.s_addr != 0)
394+ delete_address(iface);
471395
472396 #ifdef __linux__
473397 /* On linux, we need to change the subnet route to have our metric. */
@@ -491,6 +415,6 @@ configure(struct interface *iface, const char *reason,
491415 if (write_lease(iface, dhcp) == -1)
492416 logger(LOG_ERR, "write_lease: %s", strerror(errno));
493417
494- exec_script(options, iface->name, reason, dhcp, old);
418+ run_script(options, iface->name, reason, dhcp, old);
495419 return 0;
496420 }
--- a/configure.h
+++ b/configure.h
@@ -32,8 +32,8 @@
3232 #include "dhcp.h"
3333 #include "net.h"
3434
35-int exec_script(const struct options *, const char *, const char *,
36- const struct dhcp_message *, const struct dhcp_message *);
35+int run_script(const struct options *, const char *, const char *,
36+ const struct dhcp_message *, const struct dhcp_message *);
3737 int configure(struct interface *, const char *,
3838 const struct dhcp_message *, const struct dhcp_message *,
3939 const struct dhcp_lease *, const struct options *, int);
--- a/dhcp.c
+++ b/dhcp.c
@@ -137,6 +137,7 @@ static const struct dhcp_opt const dhcp_opts[] = {
137137 { 75, IPV4 | ARRAY, "streettalk_server" },
138138 { 76, IPV4 | ARRAY, "streettalk_directory_assistance_server" },
139139 { 77, STRING, "user_class" },
140+ { 81, STRING | RFC3397, "fqdn_name" },
140141 { 85, IPV4 | ARRAY, "nds_servers" },
141142 { 86, STRING, "nds_tree_name" },
142143 { 87, STRING, "nds_context" },
@@ -151,7 +152,7 @@ static const struct dhcp_opt const dhcp_opts[] = {
151152 { 118, IPV4, "subnet_selection" },
152153 { 119, STRING | RFC3397, "domain_search" },
153154 { 121, RFC3442 | REQUEST, "classless_static_routes" },
154- { 249, RFC3442, "ms-classless_static_routes" },
155+ { 249, RFC3442, "ms_classless_static_routes" },
155156 { 0, 0, NULL }
156157 };
157158
@@ -165,11 +166,11 @@ print_options(void)
165166 printf("%03d %s\n", opt->option, opt->var);
166167 }
167168
168-int make_reqmask(uint8_t *mask, char **opts, int add)
169+int make_option_mask(uint8_t *mask, char **opts, int add)
169170 {
170- char *token;
171- char *p = *opts;
171+ char *token, *p = *opts, *t;
172172 const struct dhcp_opt *opt;
173+ int match, n;
173174
174175 while ((token = strsep(&p, ", "))) {
175176 if (*token == '\0')
@@ -177,13 +178,23 @@ int make_reqmask(uint8_t *mask, char **opts, int add)
177178 for (opt = dhcp_opts; opt->option; opt++) {
178179 if (!opt->var)
179180 continue;
180- if (strcmp(opt->var, token) == 0) {
181+ match = 0;
182+ if (strcmp(opt->var, token) == 0)
183+ match = 1;
184+ else {
185+ errno = 0;
186+ n = strtol(token, &t, 0);
187+ if (errno == 0 && !*t)
188+ if (opt->option == n)
189+ match = 1;
190+ }
191+ if (match) {
181192 if (add == 1)
182- add_reqmask(mask,
183- opt->option);
193+ add_option_mask(mask,
194+ opt->option);
184195 else
185- del_reqmask(mask,
186- opt->option);
196+ del_option_mask(mask,
197+ opt->option);
187198 break;
188199 }
189200 }
@@ -268,9 +279,9 @@ get_option(const struct dhcp_message *dhcp, uint8_t opt, int *len, int *type)
268279 bl += ol;
269280 }
270281 switch (o) {
271- case DHCP_PAD:
282+ case DHO_PAD:
272283 continue;
273- case DHCP_END:
284+ case DHO_END:
274285 if (overl & 1) {
275286 /* bit 1 set means parse boot file */
276287 overl &= ~1;
@@ -284,7 +295,7 @@ get_option(const struct dhcp_message *dhcp, uint8_t opt, int *len, int *type)
284295 } else
285296 goto exit;
286297 break;
287- case DHCP_OPTIONSOVERLOADED:
298+ case DHO_OPTIONSOVERLOADED:
288299 /* Ensure we only get this option once */
289300 if (!overl)
290301 overl = p[1];
@@ -295,7 +306,7 @@ get_option(const struct dhcp_message *dhcp, uint8_t opt, int *len, int *type)
295306 }
296307
297308 exit:
298- if (valid_length(o, bl, type) == -1) {
309+ if (valid_length(opt, bl, type) == -1) {
299310 errno = EINVAL;
300311 return NULL;
301312 }
@@ -372,7 +383,9 @@ decode_rfc3397(char *out, ssize_t len, int pl, const uint8_t *p)
372383 while (q - p < pl) {
373384 r = NULL;
374385 hops = 0;
375- while ((l = *q++)) {
386+ /* We check we are inside our length again incase
387+ * the data is NOT terminated correctly. */
388+ while ((l = *q++) && q - p < pl) {
376389 ltype = l & 0xc0;
377390 if (ltype == 0x80 || ltype == 0x40)
378391 return 0;
@@ -583,7 +596,7 @@ decode_rfc3361(int dl, const uint8_t *data)
583596 char *
584597 get_option_string(const struct dhcp_message *dhcp, uint8_t option)
585598 {
586- int type;
599+ int type = 0;
587600 int len;
588601 const uint8_t *p;
589602 char *s;
@@ -654,10 +667,10 @@ get_option_routes(const struct dhcp_message *dhcp)
654667 int len;
655668
656669 /* If we have CSR's then we MUST use these only */
657- p = get_option(dhcp, DHCP_CSR, &len, NULL);
670+ p = get_option(dhcp, DHO_CSR, &len, NULL);
658671 /* Check for crappy MS option */
659672 if (!p)
660- p = get_option(dhcp, DHCP_MSCSR, &len, NULL);
673+ p = get_option(dhcp, DHO_MSCSR, &len, NULL);
661674 if (p) {
662675 routes = decode_rfc3442_rt(len, p);
663676 if (routes)
@@ -665,7 +678,7 @@ get_option_routes(const struct dhcp_message *dhcp)
665678 }
666679
667680 /* OK, get our static routes first. */
668- p = get_option(dhcp, DHCP_STATICROUTE, &len, NULL);
681+ p = get_option(dhcp, DHO_STATICROUTE, &len, NULL);
669682 if (p) {
670683 e = p + len;
671684 while (p < e) {
@@ -684,7 +697,7 @@ get_option_routes(const struct dhcp_message *dhcp)
684697 }
685698
686699 /* Now grab our routers */
687- p = get_option(dhcp, DHCP_ROUTER, &len, NULL);
700+ p = get_option(dhcp, DHO_ROUTER, &len, NULL);
688701 if (p) {
689702 e = p + len;
690703 while (p < e) {
@@ -701,26 +714,51 @@ get_option_routes(const struct dhcp_message *dhcp)
701714 return routes;
702715 }
703716
717+static size_t
718+encode_rfc1035(const char *src, uint8_t *dst, size_t len)
719+{
720+ const char *c = src;
721+ uint8_t *p = dst;
722+ uint8_t *lp = p++;
723+
724+ if (len == 0)
725+ return 0;
726+ while (c < src + len) {
727+ if (*c == '\0')
728+ break;
729+ if (*c == '.') {
730+ /* Skip the trailing . */
731+ if (c == src + len - 1)
732+ break;
733+ *lp = p - lp - 1;
734+ if (*lp == '\0')
735+ return p - dst;
736+ lp = p++;
737+ } else
738+ *p++ = (uint8_t) *c;
739+ c++;
740+ }
741+ *lp = p - lp - 1;
742+ *p++ = '\0';
743+ return p - dst;
744+}
745+
704746 ssize_t
705747 make_message(struct dhcp_message **message,
706748 const struct interface *iface, const struct dhcp_lease *lease,
707749 uint32_t xid, uint8_t type, const struct options *options)
708750 {
709751 struct dhcp_message *dhcp;
710- uint8_t *m, *p;
752+ uint8_t *m, *lp, *p;
711753 uint8_t *n_params = NULL;
712754 time_t up = uptime() - iface->start_uptime;
713755 uint32_t ul;
714756 uint16_t sz;
715757 const struct dhcp_opt *opt;
716-#ifndef MINIMAL
717- uint8_t *d;
718- const char *c;
719-#endif
720758
721759 dhcp = xzalloc(sizeof (*dhcp));
722760 m = (uint8_t *)dhcp;
723- p = (uint8_t *)&dhcp->options;
761+ p = dhcp->options;
724762
725763 if ((type == DHCP_INFORM ||
726764 type == DHCP_RELEASE ||
@@ -760,12 +798,12 @@ make_message(struct dhcp_message **message,
760798 dhcp->xid = xid;
761799 dhcp->cookie = htonl(MAGIC_COOKIE);
762800
763- *p++ = DHCP_MESSAGETYPE;
801+ *p++ = DHO_MESSAGETYPE;
764802 *p++ = 1;
765803 *p++ = type;
766804
767805 if (type == DHCP_REQUEST) {
768- *p++ = DHCP_MAXMESSAGESIZE;
806+ *p++ = DHO_MAXMESSAGESIZE;
769807 *p++ = 2;
770808 sz = get_mtu(iface->name);
771809 if (sz < MTU_MIN) {
@@ -777,27 +815,26 @@ make_message(struct dhcp_message **message,
777815 p += 2;
778816 }
779817
780-#ifndef MINIMAL
781818 if (iface->clientid) {
782- *p++ = DHCP_CLIENTID;
819+ *p++ = DHO_CLIENTID;
783820 memcpy(p, iface->clientid, iface->clientid[0] + 1);
784821 p += iface->clientid[0] + 1;
785822 }
786823
787824 if (type != DHCP_DECLINE && type != DHCP_RELEASE) {
788825 if (options->userclass[0]) {
789- *p++ = DHCP_USERCLASS;
826+ *p++ = DHO_USERCLASS;
790827 memcpy(p, options->userclass, options->userclass[0] + 1);
791828 p += options->userclass[0] + 1;
792829 }
793830
794- if (options->classid[0]) {
795- *p++ = DHCP_CLASSID;
796- memcpy(p, options->classid, options->classid[0] + 1);
797- p += options->classid[0] + 1;
831+ if (options->vendorclassid[0]) {
832+ *p++ = DHO_VENDORCLASSID;
833+ memcpy(p, options->vendorclassid,
834+ options->vendorclassid[0] + 1);
835+ p += options->vendorclassid[0] + 1;
798836 }
799837 }
800-#endif
801838
802839 if (type == DHCP_DISCOVER || type == DHCP_REQUEST) {
803840 #define PUTADDR(_type, _val) \
@@ -811,14 +848,14 @@ make_message(struct dhcp_message **message,
811848 lease->addr.s_addr != iface->addr.s_addr &&
812849 !IN_LINKLOCAL(ntohl(lease->addr.s_addr)))
813850 {
814- PUTADDR(DHCP_IPADDRESS, lease->addr);
851+ PUTADDR(DHO_IPADDRESS, lease->addr);
815852 if (lease->server.s_addr)
816- PUTADDR(DHCP_SERVERID, lease->server);
853+ PUTADDR(DHO_SERVERID, lease->server);
817854 }
818855 #undef PUTADDR
819856
820857 if (options->leasetime != 0) {
821- *p++ = DHCP_LEASETIME;
858+ *p++ = DHO_LEASETIME;
822859 *p++ = 4;
823860 ul = htonl(options->leasetime);
824861 memcpy(p, &ul, 4);
@@ -830,61 +867,52 @@ make_message(struct dhcp_message **message,
830867 type == DHCP_INFORM ||
831868 type == DHCP_REQUEST)
832869 {
833-#ifndef MINIMAL
834870 if (options->hostname[0]) {
835- if (options->fqdn == FQDN_DISABLE) {
836- *p++ = DHCP_HOSTNAME;
837- memcpy(p, options->hostname, options->hostname[0] + 1);
838- p += options->hostname[0] + 1;
839- } else {
840- /* Draft IETF DHC-FQDN option (81) */
841- *p++ = DHCP_FQDN;
842- *p++ = options->hostname[0] + 4;
843- /*
844- * Flags: 0000NEOS
845- * S: 1 => Client requests Server to update
846- * a RR in DNS as well as PTR
847- * O: 1 => Server indicates to client that
848- * DNS has been updated
849- * E: 1 => Name data is DNS format
850- * N: 1 => Client requests Server to not
851- * update DNS
852- */
853- *p++ = (options->fqdn & 0x9) | 0x4;
854- *p++ = 0; /* from server for PTR RR */
855- *p++ = 0; /* from server for A RR if S=1 */
856- c = options->hostname + 1;
857- d = p++;
858- while (*c) {
859- if (*c == '.') {
860- *d = p - d - 1;
861- d = p++;
862- } else
863- *p++ = (uint8_t) *c;
864- c++;
865- }
866- *p ++ = 0;
867- }
871+ *p++ = DHO_HOSTNAME;
872+ memcpy(p, options->hostname, options->hostname[0] + 1);
873+ p += options->hostname[0] + 1;
874+ }
875+ if (options->fqdn != FQDN_DISABLE) {
876+ /* IETF DHC-FQDN option (81), RFC4702 */
877+ *p++ = DHO_FQDN;
878+ lp = p;
879+ *p++ = 3;
880+ /*
881+ * Flags: 0000NEOS
882+ * S: 1 => Client requests Server to update
883+ * a RR in DNS as well as PTR
884+ * O: 1 => Server indicates to client that
885+ * DNS has been updated
886+ * E: 1 => Name data is DNS format
887+ * N: 1 => Client requests Server to not
888+ * update DNS
889+ */
890+ *p++ = (options->fqdn & 0x09) | 0x04;
891+ *p++ = 0; /* from server for PTR RR */
892+ *p++ = 0; /* from server for A RR if S=1 */
893+ ul = encode_rfc1035(options->hostname + 1, p,
894+ options->hostname[0]);
895+ *lp += ul;
896+ p += ul;
868897 }
869898
870899 /* vendor is already encoded correctly, so just add it */
871900 if (options->vendor[0]) {
872- *p++ = DHCP_VENDOR;
901+ *p++ = DHO_VENDOR;
873902 memcpy(p, options->vendor, options->vendor[0] + 1);
874903 p += options->vendor[0] + 1;
875904 }
876-#endif
877905
878- *p++ = DHCP_PARAMETERREQUESTLIST;
906+ *p++ = DHO_PARAMETERREQUESTLIST;
879907 n_params = p;
880908 *p++ = 0;
881909 for (opt = dhcp_opts; opt->option; opt++) {
882910 if (!(opt->type & REQUEST ||
883- has_reqmask(options->reqmask, opt->option)))
911+ has_option_mask(options->requestmask, opt->option)))
884912 continue;
885913 switch (opt->option) {
886- case DHCP_RENEWALTIME: /* FALLTHROUGH */
887- case DHCP_REBINDTIME:
914+ case DHO_RENEWALTIME: /* FALLTHROUGH */
915+ case DHO_REBINDTIME:
888916 if (type == DHCP_INFORM)
889917 continue;
890918 break;
@@ -893,14 +921,14 @@ make_message(struct dhcp_message **message,
893921 }
894922 *n_params = p - n_params - 1;
895923 }
896- *p++ = DHCP_END;
924+ *p++ = DHO_END;
897925
898926 #ifdef BOOTP_MESSAGE_LENTH_MIN
899927 /* Some crappy DHCP servers think they have to obey the BOOTP minimum
900928 * message length.
901929 * They are wrong, but we should still cater for them. */
902930 while (p - m < BOOTP_MESSAGE_LENTH_MIN)
903- *p++ = DHCP_PAD;
931+ *p++ = DHO_PAD;
904932 #endif
905933
906934 *message = dhcp;
@@ -931,12 +959,12 @@ write_lease(const struct interface *iface, const struct dhcp_message *dhcp)
931959 /* Only write as much as we need */
932960 while (p < e) {
933961 o = *p;
934- if (o == DHCP_END) {
962+ if (o == DHO_END) {
935963 bytes = p - (const uint8_t *)dhcp;
936964 break;
937965 }
938966 p++;
939- if (o != DHCP_PAD) {
967+ if (o != DHO_PAD) {
940968 l = *p++;
941969 p += l;
942970 }
@@ -1149,13 +1177,13 @@ configure_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
11491177 char cidr[4];
11501178 uint8_t overl = 0;
11511179
1152- get_option_uint8(&overl, dhcp, DHCP_OPTIONSOVERLOADED);
1180+ get_option_uint8(&overl, dhcp, DHO_OPTIONSOVERLOADED);
11531181
11541182 if (!env) {
11551183 for (opt = dhcp_opts; opt->option; opt++) {
11561184 if (!opt->var)
11571185 continue;
1158- if (has_reqmask(options->nomask, opt->option))
1186+ if (has_option_mask(options->nomask, opt->option))
11591187 continue;
11601188 if (get_option_raw(dhcp, opt->option))
11611189 e++;
@@ -1175,14 +1203,14 @@ configure_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
11751203 * message but are not necessarily in the options */
11761204 addr.s_addr = dhcp->yiaddr;
11771205 setvar(&ep, prefix, "ip_address", inet_ntoa(addr));
1178- if (get_option_addr(&net.s_addr, dhcp, DHCP_SUBNETMASK) == -1) {
1206+ if (get_option_addr(&net.s_addr, dhcp, DHO_SUBNETMASK) == -1) {
11791207 net.s_addr = get_netmask(addr.s_addr);
11801208 setvar(&ep, prefix, "subnet_mask", inet_ntoa(net));
11811209 }
11821210 i = inet_ntocidr(net);
11831211 snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net));
11841212 setvar(&ep, prefix, "subnet_cidr", cidr);
1185- if (get_option_addr(&brd.s_addr, dhcp, DHCP_BROADCAST) == -1) {
1213+ if (get_option_addr(&brd.s_addr, dhcp, DHO_BROADCAST) == -1) {
11861214 brd.s_addr = addr.s_addr | ~net.s_addr;
11871215 setvar(&ep, prefix, "broadcast_address", inet_ntoa(net));
11881216 }
@@ -1198,12 +1226,17 @@ configure_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
11981226 for (opt = dhcp_opts; opt->option; opt++) {
11991227 if (!opt->var)
12001228 continue;
1201- if (has_reqmask(options->nomask, opt->option))
1229+ if (has_option_mask(options->nomask, opt->option))
12021230 continue;
12031231 val = NULL;
12041232 p = get_option(dhcp, opt->option, &pl, NULL);
12051233 if (!p)
12061234 continue;
1235+ /* We only want the FQDN name */
1236+ if (opt->option == DHO_FQDN) {
1237+ p += 3;
1238+ pl -= 3;
1239+ }
12071240 len = print_option(NULL, 0, opt->type, pl, p);
12081241 if (len < 0)
12091242 return -1;
--- a/dhcp.h
+++ b/dhcp.h
@@ -62,60 +62,52 @@
6262 #define DHCP_INFORM 8
6363
6464 /* DHCP options */
65-enum DHCP_OPTIONS
65+enum DHO
6666 {
67- DHCP_PAD = 0,
68- DHCP_SUBNETMASK = 1,
69- DHCP_ROUTER = 3,
70- DHCP_DNSSERVER = 6,
71- DHCP_HOSTNAME = 12,
72- DHCP_DNSDOMAIN = 15,
73- DHCP_MTU = 26,
74- DHCP_BROADCAST = 28,
75- DHCP_STATICROUTE = 33,
76- DHCP_NISDOMAIN = 40,
77- DHCP_NISSERVER = 41,
78- DHCP_NTPSERVER = 42,
79- DHCP_VENDOR = 43,
80- DHCP_IPADDRESS = 50,
81- DHCP_LEASETIME = 51,
82- DHCP_OPTIONSOVERLOADED = 52,
83- DHCP_MESSAGETYPE = 53,
84- DHCP_SERVERID = 54,
85- DHCP_PARAMETERREQUESTLIST = 55,
86- DHCP_MESSAGE = 56,
87- DHCP_MAXMESSAGESIZE = 57,
88- DHCP_RENEWALTIME = 58,
89- DHCP_REBINDTIME = 59,
90- DHCP_CLASSID = 60,
91- DHCP_CLIENTID = 61,
92- DHCP_USERCLASS = 77, /* RFC 3004 */
93- DHCP_FQDN = 81,
94- DHCP_DNSSEARCH = 119, /* RFC 3397 */
95- DHCP_CSR = 121, /* RFC 3442 */
96- DHCP_MSCSR = 249, /* MS code for RFC 3442 */
97- DHCP_END = 255
67+ DHO_PAD = 0,
68+ DHO_SUBNETMASK = 1,
69+ DHO_ROUTER = 3,
70+ DHO_DNSSERVER = 6,
71+ DHO_HOSTNAME = 12,
72+ DHO_DNSDOMAIN = 15,
73+ DHO_MTU = 26,
74+ DHO_BROADCAST = 28,
75+ DHO_STATICROUTE = 33,
76+ DHO_NISDOMAIN = 40,
77+ DHO_NISSERVER = 41,
78+ DHO_NTPSERVER = 42,
79+ DHO_VENDOR = 43,
80+ DHO_IPADDRESS = 50,
81+ DHO_LEASETIME = 51,
82+ DHO_OPTIONSOVERLOADED = 52,
83+ DHO_MESSAGETYPE = 53,
84+ DHO_SERVERID = 54,
85+ DHO_PARAMETERREQUESTLIST = 55,
86+ DHO_MESSAGE = 56,
87+ DHO_MAXMESSAGESIZE = 57,
88+ DHO_RENEWALTIME = 58,
89+ DHO_REBINDTIME = 59,
90+ DHO_VENDORCLASSID = 60,
91+ DHO_CLIENTID = 61,
92+ DHO_USERCLASS = 77, /* RFC 3004 */
93+ DHO_FQDN = 81,
94+ DHO_DNSSEARCH = 119, /* RFC 3397 */
95+ DHO_CSR = 121, /* RFC 3442 */
96+ DHO_MSCSR = 249, /* MS code for RFC 3442 */
97+ DHO_END = 255
9898 };
9999
100-/* SetFQDNHostName values - lsnybble used in flags
101- * byte (see buildmsg.c), hsnybble to create order
100+/* FQDN values - lsnybble used in flags
101+ * hsnybble to create order
102102 * and to allow 0x00 to mean disable
103103 */
104-enum FQQN {
104+enum FQDN {
105105 FQDN_DISABLE = 0x00,
106106 FQDN_NONE = 0x18,
107107 FQDN_PTR = 0x20,
108108 FQDN_BOTH = 0x31
109109 };
110110
111-struct fqdn
112-{
113- uint8_t flags;
114- uint8_t r1;
115- uint8_t r2;
116- char *name;
117-};
118-
119111 /* Sizes for DHCP options */
120112 #define DHCP_CHADDR_LEN 16
121113 #define SERVERNAME_LEN 64
@@ -157,14 +149,15 @@ struct dhcp_lease {
157149 uint32_t renewaltime;
158150 uint32_t rebindtime;
159151 struct in_addr server;
160- uint32_t leasedfrom;
152+ time_t leasedfrom;
153+ struct timeval boundtime;
161154 uint8_t frominfo;
162155 };
163156
164-#define add_reqmask(var, val) (var[val >> 3] |= 1 << (val & 7))
165-#define del_reqmask(var, val) (var[val >> 3] &= ~(1 << (val & 7)))
166-#define has_reqmask(var, val) (var[val >> 3] & (1 << (val & 7)))
167-int make_reqmask(uint8_t *, char **, int);
157+#define add_option_mask(var, val) (var[val >> 3] |= 1 << (val & 7))
158+#define del_option_mask(var, val) (var[val >> 3] &= ~(1 << (val & 7)))
159+#define has_option_mask(var, val) (var[val >> 3] & (1 << (val & 7)))
160+int make_option_mask(uint8_t *, char **, int);
168161 void print_options(void);
169162 char *get_option_string(const struct dhcp_message *, uint8_t);
170163 int get_option_addr(uint32_t *, const struct dhcp_message *, uint8_t);
--- a/dhcpcd-hooks/01-test
+++ b/dhcpcd-hooks/01-test
@@ -3,5 +3,5 @@
33 case ${reason} in
44 TEST) set | grep "^\(interface\|metric\|pid\|reason\|skip_hooks\)=" | sort
55 set | grep "^\(new_\|old_\)" | sort
6- ;;
6+ ;;
77 esac
--- a/dhcpcd-hooks/20-resolv.conf
+++ b/dhcpcd-hooks/20-resolv.conf
@@ -1,14 +1,71 @@
11 # Generate /etc/resolv.conf
22 # Support resolvconf(8) if available
3+# We can merge other dhcpcd resolv.conf files into one like resolvconf,
4+# but resolvconf is preferred as other applications like VPN clients
5+# can readily hook into it.
6+# Also, resolvconf can configure local nameservers such as bind
7+# or dnsmasq. This is important as the libc resolver isn't that powerful.
38
4-make_resolv_conf()
9+resolv_conf_dir="${state_dir}/resolv.conf"
10+
11+build_resolv_conf()
12+{
13+ local cf="/etc/resolv.conf.${interface}"
14+ local interfaces= header= search= srvs= servers= x=
15+
16+ # Build a list of interfaces
17+ interfaces=$(list_interfaces "${resolv_conf_dir}")
18+
19+ # Build the resolv.conf
20+ if [ -n "${interfaces}" ]; then
21+ # Build the header
22+ for x in ${interfaces}; do
23+ header="${header}${header:+, }${x}"
24+ done
25+
26+ # Build the search list
27+ search=$(cd "${resolv_conf_dir}"; \
28+ key_get_value "search " ${interfaces})
29+ [ -n "${search}" ] && search="search $(uniqify ${search})\n"
30+
31+ # Build the nameserver list
32+ srvs=$(cd "${resolv_conf_dir}"; \
33+ key_get_value "nameserver " ${interfaces})
34+ for x in $(uniqify ${srvs}); do
35+ servers="${servers}nameserver ${x}\n"
36+ done
37+ fi
38+ header="${signature_base}${header:+ ${from} }${header}"
39+
40+ # Assemble resolv.conf using our head and tail files
41+ [ -f "${cf}" ] && rm -f "${cf}"
42+ echo "${header}" > "${cf}"
43+ if [ -f /etc/resolv.conf.head ]; then
44+ cat /etc/resolv.conf.head >> "${cf}"
45+ else
46+ echo "# /etc/resolv.conf.head can replace this line" >> "${cf}"
47+ fi
48+ printf "${search}${servers}" >> "${cf}"
49+ if [ -f /etc/resolv.conf.tail ]; then
50+ cat /etc/resolv.conf.tail >> "${cf}"
51+ else
52+ echo "# /etc/resolv.conf.tail can replace this line" >> "${cf}"
53+ fi
54+ mv -f "${cf}" /etc/resolv.conf
55+}
56+
57+add_resolv_conf()
558 {
59+ local x= conf="${signature}\n"
60+
61+ # If we don't have any configuration, remove it
662 if [ -z "${new_domain_name_servers}" -a \
763 -z "${new_domain_name}" -a \
864 -z "${new_domain_search}" ]; then
9- return 0
65+ remove_resolv_conf
66+ return $?
1067 fi
11- local x= conf="${signature}\n"
68+
1269 if [ -n "${new_domain_search}" ]; then
1370 conf="${conf}search ${new_domain_search}\n"
1471 elif [ -n "${new_domain_name}" ]; then
@@ -19,22 +76,32 @@ make_resolv_conf()
1976 done
2077 if type resolvconf >/dev/null 2>&1; then
2178 printf "${conf}" | resolvconf -a "${interface}"
22- else
23- save_conf /etc/resolv.conf
24- printf "${conf}" > /etc/resolv.conf
79+ return $?
80+ fi
81+
82+ if [ -e "${resolv_conf_dir}/${interface}" ]; then
83+ rm -f "${resolv_conf_dir}/${interface}"
84+ fi
85+ if [ ! -d "${resolv_conf_dir}" ]; then
86+ mkdir -p "${resolv_conf_dir}"
2587 fi
88+ printf "${conf}" > "${resolv_conf_dir}/${interface}"
89+ build_resolv_conf
2690 }
2791
28-restore_resolv_conf()
92+remove_resolv_conf()
2993 {
3094 if type resolvconf >/dev/null 2>&1; then
3195 resolvconf -d "${interface}" -f
3296 else
33- restore_conf /etc/resolv.conf || return 0
97+ if [ -e "${resolv_conf_dir}/${interface}" ]; then
98+ rm -f "${resolv_conf_dir}/${interface}"
99+ fi
100+ build_resolv_conf
34101 fi
35102 }
36103
37104 case "${reason}" in
38-BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT) make_resolv_conf;;
39-EXPIRE|FAIL|IPV4LL|RELEASE|STOP) restore_resolv_conf;;
105+BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT) add_resolv_conf;;
106+PREINIT|EXPIRE|FAIL|IPV4LL|RELEASE|STOP) remove_resolv_conf;;
40107 esac
--- a/dhcpcd-hooks/29-lookup-hostname
+++ b/dhcpcd-hooks/29-lookup-hostname
@@ -2,6 +2,7 @@
22
33 lookup_hostname()
44 {
5+ [ -z "${new_ip_address}" ] && return 1
56 local h=
67 # Silly ISC programs love to send error text to stdout
78 if type dig >/dev/null 2>&1; then
@@ -23,7 +24,7 @@ lookup_hostname()
2324
2425 set_hostname()
2526 {
26- if [ -z "${new_host_name}" ]; then
27+ if [ -z "${new_host_name}" -a -z "${new_fqdn_name}" ]; then
2728 export new_host_name="$(lookup_hostname)"
2829 fi
2930 }
--- a/dhcpcd-hooks/30-hostname
+++ b/dhcpcd-hooks/30-hostname
@@ -3,16 +3,23 @@
33 need_hostname()
44 {
55 case "$(hostname)" in
6- ""|"(none)"|localhost) [ -n "${new_host_name}" ];;
7- "${old_host_name}") true;;
8- *) false;;
6+ ""|"(none)"|localhost|localhost.localdomain)
7+ [ -n "${new_host_name}" -o -n "${new_fqdn_name}" ];;
8+ "${old_host_name}"|"${old_fqdn_name}")
9+ true;;
10+ *)
11+ false;;
912 esac
1013 }
1114
1215 set_hostname()
1316 {
1417 if need_hostname; then
15- hostname "${new_host_name}"
18+ if [ -n "${new_host_name}" ]; then
19+ hostname "${new_host_name}"
20+ else
21+ hostname "${new_fqdn_name}"
22+ fi
1623 fi
1724 }
1825
--- a/dhcpcd-hooks/50-ntp.conf
+++ b/dhcpcd-hooks/50-ntp.conf
@@ -1,4 +1,6 @@
11 # Sample dhcpcd hook script for ntp
2+# Like our resolv.conf hook script, we store a database of ntp.conf files
3+# and merge into /etc/ntp.conf
24
35 # Detect OpenRC or BSD rc
46 # Distributions may want to just have their command here instead of this
@@ -10,42 +12,71 @@ elif [ -x /usr/local/etc/rc.d/ntpd ]; then
1012 ntpd_restart_cmd="/usr/local/etc/rc.d/ntpd restart"
1113 fi
1214
13-make_ntp_conf()
15+ntp_conf_dir="${state_dir}/ntp.conf"
16+
17+build_ntp_conf()
1418 {
15- [ -z "${new_ntp_servers}" ] && return 0
16- local cf=/etc/ntp.conf."${interface}" x=
17- echo "${signature}" > "${cf}"
18- echo "restrict default noquery notrust nomodify" >> "${cf}"
19- echo "restrict 127.0.0.1" >> "${cf}"
20- for x in ${new_ntp_servers}; do
21- echo "restrict ${x} nomodify notrap noquery" >> "${cf}"
22- echo "server ${x}" >> "${cf}"
23- done
24- if [ ! -e /etc/ntp.conf ]; then
25- false
26- elif type cmp >/dev/null 2>&1; then
27- cmp -s /etc/ntp.conf "${cf}"
28- elif type diff >/dev/null 2>&1; then
29- diff -q /etc/ntp.conf "${cf}" >/dev/null
30- else
31- false
19+ local cf="/etc/ntp.conf.${interface}"
20+ local interfaces= header= srvs= servers= x=
21+
22+ # Build a list of interfaces
23+ interfaces=$(list_interfaces "${ntp_conf_dir}")
24+
25+ if [ -n "${interfaces}" ]; then
26+ # Build the header
27+ for x in ${interfaces}; do
28+ header="${header}${header:+, }${x}"
29+ done
30+
31+ # Build a server list
32+ srvs=$(cd "${ntp_conf_dir}";
33+ key_get_value "server " ${interfaces})
34+ if [ -n "${srvs}" ]; then
35+ for x in $(uniqify ${srvs}); do
36+ servers="${servers}server ${x}\n"
37+ done
38+ fi
3239 fi
33- if [ $? = 0 ]; then
34- rm -f "${cf}"
35- else
36- save_conf /etc/ntp.conf
37- mv -f "${cf}" /etc/ntp.conf
40+
41+ # Merge our config into ntp.conf
42+ [ -e "${cf}" ] && rm -f "${cf}"
43+ remove_markers "${signature_base}" "${signature_base_end}" \
44+ /etc/ntp.conf > "${cf}"
45+ if [ -n "${servers}" ]; then
46+ echo "${signature_base}${header:+ ${from} }${header}" >> "${cf}"
47+ printf "${search}${servers}" >> "${cf}"
48+ echo "${signature_base_end}${header:+ ${from} }${header}" >> "${cf}"
49+ fi
50+
51+ # If we changed anything, restart ntpd
52+ if change_file /etc/ntp.conf "${cf}"; then
3853 [ -n "${ntpd_restart_cmd}" ] && ${ntpd_restart_cmd}
3954 fi
4055 }
4156
42-restore_ntp_conf()
57+add_ntp_conf()
4358 {
44- restore_conf /etc/ntp.conf || return 0
45- [ -n "${ntpd_restart_cmd}" ] && ${ntpd_restart_cmd}
59+ local cf="${ntp_conf_dir}/${interface}" x=
60+
61+ [ -e "${cf}" ] && rm "${cf}"
62+ [ -d "${ntp_conf_dir}" ] || mkdir -p "${ntp_conf_dir}"
63+ if [ -n "${new_ntp_servers}" ]; then
64+ for x in ${new_ntp_servers}; do
65+ echo "server ${x}" >> "${cf}"
66+ done
67+ fi
68+ build_ntp_conf
69+}
70+
71+remove_ntp_conf()
72+{
73+ if [ -e "${ntp_conf_dir}/${interface}" ]; then
74+ rm "${ntp_conf_dir}/${interface}"
75+ fi
76+ build_ntp_conf
4677 }
4778
4879 case "${reason}" in
49-BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT) make_ntp_conf;;
50-EXPIRE|FAIL|IPV4LL|RELEASE|STOP) restore_ntp_conf;;
80+BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT) add_ntp_conf add;;
81+PREINIT|EXPIRE|FAIL|IPV4LL|RELEASE|STOP) remove_ntp_conf del;;
5182 esac
--- a/dhcpcd-hooks/50-yp.conf
+++ b/dhcpcd-hooks/50-yp.conf
@@ -10,6 +10,7 @@ make_yp_conf()
1010 {
1111 [ -z "${new_nis_domain}" -a -z "${new_nis_servers}" ] && return 0
1212 local cf=/etc/yp.conf."${interface}" prefix= x= pid=
13+ rm -f "${cf}"
1314 echo "${signature}" > "${cf}"
1415 if [ -n "${new_nis_domain}" ]; then
1516 domainname "${new_nis_domain}"
--- a/dhcpcd-hooks/90-NetworkManager
+++ b/dhcpcd-hooks/90-NetworkManager
@@ -1,7 +1,8 @@
1-# Hook for NetworkManager, relies on D-Bus
1+# Hook for NetworkManager-0.7.0
2+# NOTE: NetworkManager will override the script dhcpcd calls, so this hook
3+# only makes sense if NetworkManager is patched NOT to override the
4+# script dhcpcd would call.
25
3-if type dbus-send >/dev/null 2>&1; then
4- dbus-send --system --dest=com.redhat.dhcp \
5- --type=method_call /com/redhat/dhcp/"${interface}" \
6- com.redhat.dhcp.set 'string:'"`env`"
6+if [ -x /usr/libexec/nm-dhcp-client.action ]; then
7+ /usr/libexec/nm-dhcp-client.action
78 fi
--- a/dhcpcd-hooks/95-configured
+++ b/dhcpcd-hooks/95-configured
@@ -16,7 +16,11 @@ BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT)
1616 setprop dhcp.${interface}.result "ok"
1717 ;;
1818
19-EXPIRE|FAIL|IPV4LL|RELEASE|STOP)
19+EXPIRE|FAIL|IPV4LL|STOP)
2020 setprop dhcp.${interface}.result "failed"
2121 ;;
22+
23+RELEASE)
24+ setprop dhcp.${interface}.result "released"
25+ ;;
2226 esac
--- a/dhcpcd-hooks/Makefile
+++ b/dhcpcd-hooks/Makefile
@@ -1,9 +1,11 @@
1-LIBEXECDIR= ${PREFIX}/libexec
1+LIBEXECDIR?= ${PREFIX}/libexec
22 HOOKDIR= ${LIBEXECDIR}/dhcpcd-hooks
33 SYSTEMSCRIPTS= 01-test 10-mtu 20-resolv.conf 30-hostname
44 FILES= ${SYSTEMSCRIPTS} ${HOOKSCRIPTS}
55 FILESDIR= ${HOOKDIR}
66
7+all:
8+
79 MK= ../mk
810 include ${MK}/os.mk
911 include ${MK}/sys.mk
--- a/dhcpcd-run-hooks
+++ b/dhcpcd-run-hooks
@@ -1,29 +1,22 @@
11 #!/system/bin/sh
22 # dhcpcd client configuration script
33
4-# Handy functions for our hooks to use
5-signature="# Generated by dhcpcd for ${interface}"
6-save_conf()
7-{
8- if ls "$1" >/dev/null 2>&1; then
9- rm -f "$1"-pre."${interface}"
10- mv -f "$1" "$1"-pre."${interface}"
11- fi
12-}
13-restore_conf()
14-{
15- ls "$1"-pre."${interface}" >/dev/null 2>&1 || return 1
16- rm -f "$1"
17- mv -f "$1"-pre."${interface}" "$1"
18-}
4+# Handy variables and functions for our hooks to use
5+from="from"
6+signature_base="# Generated by dhcpcd"
7+signature="${signature_base} ${from} ${interface}"
8+signature_base_end="# End of dhcpcd"
9+signature_end="${signature_base_end} ${from} ${interface}"
10+state_dir="/data/misc/dhcpcd"
1911
2012 # We source each script into this one so that scripts run earlier can
2113 # remove variables from the environment so later scripts don't see them.
22-# Thus, the user can create their dhcpcd.hook script to configure
14+# Thus, the user can create their dhcpcd.enter/exit-hook script to configure
2315 # /etc/resolv.conf how they want and stop the system scripts ever updating it.
2416 for hook in \
25- /system/etc/dhcpcd/dhcpcd.hook \
26- /system/etc/dhcpcd/dhcpcd-hooks/*
17+ /system/etc/dhcpcd/dhcpcd.enter-hook \
18+ /system/etc/dhcpcd/dhcpcd-hooks/* \
19+ /system/etc/dhcpcd/dhcpcd.exit-hook
2720 do
2821 for skip in ${skip_hooks}; do
2922 case "${hook}" in
--- a/dhcpcd-run-hooks.8
+++ b/dhcpcd-run-hooks.8
@@ -22,7 +22,7 @@
2222 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2323 .\" SUCH DAMAGE.
2424 .\"
25-.Dd May 21, 2008
25+.Dd August 14, 2008
2626 .Dt DHCPCD.SH 8 SMM
2727 .Sh NAME
2828 .Nm dhcpcd-run-hooks
@@ -31,11 +31,13 @@
3131 .Nm
3232 is used by
3333 .Xr dhcpcd 8
34-to run any system or user defined hook scripts.
34+to run any system and user defined hook scripts.
3535 System hook scripts are found in
3636 .Pa /system/etc/dhcpcd/dhcpcd-hooks
37-and the user defined hook is
38-.Pa /system/etc/dhcpcd/dhcpcd.hook .
37+and the user defined hooks are
38+.Pa /system/etc/dhcpcd/dhcpcd.enter-hook .
39+and
40+.Pa /system/etc/dhcpcd/dhcpcd.exit-hook .
3941 The default install supplies hook scripts for configuring
4042 .Pa /etc/resolv.conf
4143 and the hostname.
@@ -67,6 +69,11 @@ Here's a list of reasons why
6769 .Nm
6870 could be invoked:
6971 .Bl -tag -width indent
72+.It Dv PREINIT
73+dhcpcd is starting up and any pre-initialisation should be done.
74+.It Dv INFORM
75+dhcpcd informed a DHCP server about it's address and obtained other
76+configuration details.
7077 .It Dv BOUND
7178 dhcpcd obtained a new lease from a DHCP server.
7279 .It Dv RENEW
@@ -93,10 +100,11 @@ script to process them.
93100 When
94101 .Nm
95102 runs, it loads
96-.Pa /system/etc/dhcpcd/dhcpcd.hook
103+.Pa /system/etc/dhcpcd/dhcpcd.enter-hook
97104 and any scripts found in
98105 .Pa /system/etc/dhcpcd/dhcpcd-hooks
99-in a lexical order.
106+in a lexical order and then finally
107+.Pa /system/etc/dhcpcd/dhcpcd.exit-hook
100108 .Sh SEE ALSO
101109 .Xr dhcpcd 8
102110 .Sh AUTHORS
--- a/dhcpcd-run-hooks.8.in
+++ b/dhcpcd-run-hooks.8.in
@@ -22,7 +22,7 @@
2222 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2323 .\" SUCH DAMAGE.
2424 .\"
25-.Dd May 21, 2008
25+.Dd August 14, 2008
2626 .Dt DHCPCD.SH 8 SMM
2727 .Sh NAME
2828 .Nm dhcpcd-run-hooks
@@ -31,11 +31,13 @@
3131 .Nm
3232 is used by
3333 .Xr dhcpcd 8
34-to run any system or user defined hook scripts.
34+to run any system and user defined hook scripts.
3535 System hook scripts are found in
3636 .Pa @HOOKDIR@
37-and the user defined hook is
38-.Pa @SYSCONFDIR@/dhcpcd.hook .
37+and the user defined hooks are
38+.Pa @SYSCONFDIR@/dhcpcd.enter-hook .
39+and
40+.Pa @SYSCONFDIR@/dhcpcd.exit-hook .
3941 The default install supplies hook scripts for configuring
4042 .Pa /etc/resolv.conf
4143 and the hostname.
@@ -67,6 +69,11 @@ Here's a list of reasons why
6769 .Nm
6870 could be invoked:
6971 .Bl -tag -width indent
72+.It Dv PREINIT
73+dhcpcd is starting up and any pre-initialisation should be done.
74+.It Dv INFORM
75+dhcpcd informed a DHCP server about it's address and obtained other
76+configuration details.
7077 .It Dv BOUND
7178 dhcpcd obtained a new lease from a DHCP server.
7279 .It Dv RENEW
@@ -93,10 +100,11 @@ script to process them.
93100 When
94101 .Nm
95102 runs, it loads
96-.Pa @SYSCONFDIR@/dhcpcd.hook
103+.Pa @SYSCONFDIR@/dhcpcd.enter-hook
97104 and any scripts found in
98105 .Pa @HOOKDIR@
99-in a lexical order.
106+in a lexical order and then finally
107+.Pa @SYSCONFDIR@/dhcpcd.exit-hook
100108 .Sh SEE ALSO
101109 .Xr dhcpcd 8
102110 .Sh AUTHORS
--- a/dhcpcd-run-hooks.in
+++ b/dhcpcd-run-hooks.in
@@ -1,8 +1,104 @@
11 #!/bin/sh
22 # dhcpcd client configuration script
33
4-# Handy functions for our hooks to use
5-signature="# Generated by dhcpcd for ${interface}"
4+# Handy variables and functions for our hooks to use
5+from="from"
6+signature_base="# Generated by dhcpcd"
7+signature="${signature_base} ${from} ${interface}"
8+signature_base_end="# End of dhcpcd"
9+signature_end="${signature_base_end} ${from} ${interface}"
10+state_dir="/var/run/dhcpcd"
11+
12+# Ensure that all arguments are unique
13+uniqify()
14+{
15+ local result=
16+
17+ while [ -n "$1" ]; do
18+ case " ${result} " in
19+ *" $1 "*);;
20+ *) result="${result}${result:+ }$1";;
21+ esac
22+ shift
23+ done
24+ echo "${result}"
25+}
26+
27+# List interface config files in a dir
28+# We may wish to control the order at some point rather than just lexical
29+list_interfaces()
30+{
31+ local x= interfaces=
32+ for x in "$1"/*; do
33+ [ -e "${x}" ] || continue
34+ interfaces="${interfaces}${interfaces:+ }${x##*/}"
35+ done
36+ echo "${interfaces}"
37+}
38+
39+# We normally use sed to extract values using a key from a list of files
40+# but sed may not always be available at the time.
41+key_get_value()
42+{
43+ local key="$1" value= x= line=
44+
45+ shift
46+ if type sed >/dev/null 2>&1; then
47+ sed -n "s/^${key}//p" $@
48+ else
49+ for x; do
50+ while read line; do
51+ case "${line}" in
52+ "${key}"*) echo "${line##${key}}";;
53+ esac
54+ done < "${x}"
55+ done
56+ fi
57+}
58+
59+# We normally use sed to remove markers from a configuration file
60+# but sed may not always be available at the time.
61+remove_markers()
62+{
63+ local m1="$1" m2="$2" x= line= in_marker=0
64+
65+ shift; shift
66+ if type sed >/dev/null 2>&1; then
67+ sed "/^${m1}/,/^${m2}/d" $@
68+ else
69+ for x; do
70+ while read line; do
71+ case "${line}" in
72+ "${m1}"*) in_marker=1;;
73+ "${m2}"*) in_marker=0;;
74+ *) [ ${in_marker} = 0 ] && echo "${line}";;
75+ esac
76+ done < "${x}"
77+ done
78+ fi
79+}
80+
81+# Compare two files
82+# It different, replace first with second otherwise remove second
83+change_file()
84+{
85+ if type cmp >/dev/null 2>&1; then
86+ cmp -s "$1" "$2"
87+ elif type diff >/dev/null 2>&1; then
88+ diff -q "$1" "$2" >/dev/null
89+ else
90+ # Hopefully we're only working on small text files ...
91+ [ "$(cat "$1")" = "$(cat "$2")" ]
92+ fi
93+ if [ $? -eq 0 ]; then
94+ rm -f "$2"
95+ return 1
96+ fi
97+ mv -f "$2" "$1"
98+ return 0
99+}
100+
101+# Save a config file
6102 save_conf()
7103 {
8104 if [ -f "$1" ]; then
@@ -10,6 +106,8 @@ save_conf()
10106 mv -f "$1" "$1"-pre."${interface}"
11107 fi
12108 }
109+
110+# Restore a config file
13111 restore_conf()
14112 {
15113 [ -f "$1"-pre."${interface}" ] || return 1
@@ -17,13 +115,15 @@ restore_conf()
17115 mv -f "$1"-pre."${interface}" "$1"
18116 }
19117
118+
20119 # We source each script into this one so that scripts run earlier can
21120 # remove variables from the environment so later scripts don't see them.
22-# Thus, the user can create their dhcpcd.hook script to configure
121+# Thus, the user can create their dhcpcd.enter/exit-hook script to configure
23122 # /etc/resolv.conf how they want and stop the system scripts ever updating it.
24123 for hook in \
25- @SYSCONFDIR@/dhcpcd.hook \
26- @HOOKDIR@/*
124+ @SYSCONFDIR@/dhcpcd.enter-hook \
125+ @HOOKDIR@/* \
126+ @SYSCONFDIR@/dhcpcd.exit-hook
27127 do
28128 for skip in ${skip_hooks}; do
29129 case "${hook}" in
--- a/dhcpcd.8
+++ b/dhcpcd.8
@@ -22,18 +22,18 @@
2222 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2323 .\" SUCH DAMAGE.
2424 .\"
25-.Dd Jul 08, 2008
25+.Dd August 20, 2008
2626 .Dt DHCPCD 8 SMM
2727 .Sh NAME
2828 .Nm dhcpcd
2929 .Nd an RFC 2131 compliant DHCP client
3030 .Sh SYNOPSIS
3131 .Nm
32-.Op Fl dknpqADEGLSTXV
32+.Op Fl bdknpqABDEGKLSTV
3333 .Op Fl c , -script Ar script
3434 .Op Fl f , -config Ar file
3535 .Op Fl h , -hostname Ar hostname
36-.Op Fl i , -classid Ar classid
36+.Op Fl i , -vendorclassid Ar vendorclassid
3737 .Op Fl l , -leasetime Ar seconds
3838 .Op Fl m , -metric Ar metric
3939 .Op Fl o , -option Ar option
@@ -46,6 +46,8 @@
4646 .Op Fl F , -fqdn Ar FQDN
4747 .Op Fl I , -clientid Ar clientid
4848 .Op Fl O , -nooption Ar option
49+.Op Fl Q , -require Ar option
50+.Op Fl X , -blacklist Ar address
4951 .Ar interface
5052 .Nm
5153 .Fl k , -release
@@ -56,9 +58,7 @@
5658 .Sh DESCRIPTION
5759 .Nm
5860 is an implementation of the DHCP client specified in
59-.Rs
60-.%T "RFC 2131"
61-.Re
61+.Li RFC 2131 .
6262 .Nm
6363 gets the host information
6464 .Po
@@ -69,40 +69,42 @@ from a DHCP server and configures the network
6969 of the
7070 machine on which it is running.
7171 .Nm
72-will then write DNS information to
72+then runs the configuration script which writes DNS information to
7373 .Xr resolvconf 8 ,
7474 if available, otherwise directly to
7575 .Pa /etc/resolv.conf .
7676 If the hostname is currenly blank, (null) or localhost then
7777 .Nm
78-will set the hostname to the one supplied by the DHCP server.
78+sets the hostname to the one supplied by the DHCP server.
7979 .Nm
8080 then daemonises and waits for the lease renewal time to lapse.
8181 Then it attempts to renew its lease and reconfigure if the new lease changes.
8282 .Ss Local Link configuration
8383 If
8484 .Nm
85-failed to obtain a lease, it will probe for a valid IPv4LL address
85+failed to obtain a lease, it probes for a valid IPv4LL address
8686 .Po
87-aka Zeroconf, aka APIPA
87+aka ZeroConf, aka APIPA
8888 .Pc .
89-Once obtained it will restart the process of looking for a DHCP server to get a
89+Once obtained it restarts the process of looking for a DHCP server to get a
9090 proper address.
9191 .Pp
9292 When using IPv4LL,
9393 .Nm
94-will always succeed and return a 0 exit code. To disable this behaviour, you
95-can use the
94+nearly always succeeds and returns an exit code of 0.
95+In the rare case it fails, it normally means that there is a reverse ARP proxy
96+installed which always defeats IPv4LL probing.
97+To disable this behaviour, you can use the
9698 .Fl L , -noipv4ll
9799 option.
98100 .Ss Hooking into DHCP events
99101 .Nm
100-will run
102+runs
101103 .Pa /system/etc/dhcpcd/dhcpcd-run-hooks ,
102104 or the script specified by the
103105 .Fl c , -script
104106 option.
105-This script will run each script found in
107+This script runs each script found in
106108 .Pa /system/etc/dhcpcd/dhcpcd-hooks
107109 in a lexical order.
108110 The default installation supplies the scripts
@@ -124,6 +126,10 @@ You can fine tune the behaviour of
124126 .Nm
125127 with the following options:
126128 .Bl -tag -width indent
129+.It Fl b , -background
130+Background immediately.
131+This is useful for startup scripts which don't disable link messages for
132+carrier status.
127133 .It Fl c , -script Ar script
128134 Use this
129135 .Ar script
@@ -142,16 +148,16 @@ always processes the config file before any command line options.
142148 .It Fl h , -hostname Ar hostname
143149 By default,
144150 .Nm
145-will send the current hostname to the DHCP server so it can register in DNS.
151+sends the current hostname to the DHCP server so it can register in DNS.
146152 You can use this option to specify the
147153 .Ar hostname
148154 sent, or an empty string to
149155 stop any
150156 .Ar hostname
151157 from being sent.
152-.It Fl i , -classid Ar classid
158+.It Fl i , -vendorclassid Ar vendorclassid
153159 Override the
154-.Ar classid
160+.Ar vendorclassid
155161 field sent. The default is
156162 dhcpcd <version>.
157163 If not set then none is sent.
@@ -163,6 +169,8 @@ process running on the
163169 to release its lease, deconfigure the
164170 .Ar interface
165171 and then exit.
172+.Nm
173+then waits until this process has exited.
166174 .It Fl l , -leasetime Ar seconds
167175 Request a specific lease time in
168176 .Ar seconds .
@@ -184,14 +192,27 @@ Request the DHCP
184192 .Ar option
185193 variable for use in
186194 .Pa /system/etc/dhcpcd/dhcpcd-run-hooks .
187-.It Fl n , -renew
195+.It Fl n , -rebind
188196 Notifies an existing
189197 .Nm
190198 process running on the
191199 .Ar interface
192-to renew it's lease. If
200+to rebind it's lease.
201+.Nm
202+will not re-configure itself or use any other command line arguments.
203+.Nm
204+will timeout the rebind after 30 seconds at which point the lease will be
205+expired and
206+.Nm
207+will enter the discovery state to obtain a new lease.
208+Use the
209+.Fl t , -timeout
210+option to change this.
211+If
193212 .Nm
194213 is not running, then it starts up as normal.
214+This option used to be renew, but rebind is more accurate as we need to
215+broadcast the request instead of unicasting.
195216 .It Fl p , -persistent
196217 .Nm
197218 normally deconfigures the
@@ -201,28 +222,31 @@ Sometimes, this isn't desirable if for example you have root mounted over NFS.
201222 You can use this option to stop this from happening.
202223 .It Fl r , -request Op Ar address
203224 .Nm
204-normally sends a DHCP Broadcast to find servers to offer an address.
225+normally sends a DHCP DISCOVER to find servers to offer an address.
205226 .Nm
206-will then request the address used.
207-You can use this option to skip the broadcast step and just request an
227+then requests the address used.
228+You can use this option to skip the BROADCAST step and just request the
208229 .Ar address .
209230 The downside is if you request an
210231 .Ar address
211232 the DHCP server does not know about or the DHCP server is not
212233 authorative, it will remain silent.
213-In this situation, we go back to the init state and broadcast again.
234+In this situation, we go back to the init state and DISCOVER again.
214235 If no
215236 .Ar address
216237 is given then the first address currently assigned to the
217238 .Ar interface
218239 is used.
219240 .It Fl s , -inform Op Ar address Ns Op Ar /cidr
220-Behaves exactly like
241+Behaves like
221242 .Fl r , -request
222243 as above, but sends a DHCP INFORM instead of a REQUEST.
223244 This does not get a lease as such, just notifies the DHCP server of the
224245 .Ar address
225246 in use.
247+You should also include the optional
248+.Ar cidr
249+network number in-case the address is not already configured on the interface.
226250 .Nm
227251 remains running and pretends it has an infinite lease.
228252 .Nm
@@ -243,7 +267,7 @@ to wait forever to get a lease.
243267 .It Fl u , -userclass Ar class
244268 Tags the DHCP message with the userclass
245269 .Ar class .
246-DHCP servers use this give memebers of the class DHCP options other than the
270+DHCP servers use this give members of the class DHCP options other than the
247271 default, without having to know things like hardware address or hostname.
248272 .It Fl v , -vendor Ar code , Ns Ar value
249273 Add an enscapulated vendor option.
@@ -252,30 +276,31 @@ should be between 1 and 254 inclusive.
252276 Examples.
253277 .Pp
254278 Set the vendor option 01 with an IP address.
255-.D1 dhcpcd -v 01,192.168.0.2 eth0
279+.D1 dhcpcd \-v 01,192.168.0.2 eth0
256280 Set the vendor option 02 with a hex code.
257-.D1 dhcpcd -v 02,01:02:03:04:05 eth0
281+.D1 dhcpcd \-v 02,01:02:03:04:05 eth0
258282 Do the above and set a third option with a string and not an IP address.
259-.D1 dhcpcd -v 01,192.168.0.2 -v 02,01:02:03:04:05 -v 03,\e"192.168.0.2\e" eth0
283+.D1 dhcpcd \-v 01,192.168.0.2 \-v 02,01:02:03:04:05 \-v 03,\e"192.168.0.2\e" eth0
260284 .It Fl x , -exit
261-This causes an existing
285+This will signal an existing
262286 .Nm
263287 process running on the
264288 .Ar interface
265289 to deconfigure the
266290 .Ar interface
267291 and exit.
292+.Nm
293+then waits until this process has exited.
268294 .It Fl D , -duid
269295 Generate an
270-.Rs
271-.%T "RFC 4361"
272-.Re
296+.Li RFC 4361
273297 compliant clientid.
274298 This requires persistent storage and not all DHCP servers work with it so it's
275299 not enabled by default.
276-The DUID generated will be held in
300+.Nm
301+generates the DUID and stores in it
277302 .Pa /system/etc/dhcpcd/dhcpcd.duid
278-and should not be copied to other hosts.
303+This file should not be copied to other hosts.
279304 .It Fl E , -lastlease
280305 If
281306 .Nm
@@ -289,12 +314,15 @@ Requests that the DHCP server updates DNS using FQDN instead of just a
289314 hostname.
290315 Valid values for
291316 .Ar fqdn
292-are none, ptr and both.
317+are disable, none, ptr and both.
293318 The current hostname or the hostname specified using the
294319 .Fl h , -hostname
295320 option must be a FQDN.
296321 .Nm
297322 itself never does any DNS updates.
323+.Nm
324+encodes the FQDN hostname as specified in
325+.Li RFC1035 .
298326 .It Fl I , -clientid Ar clientid
299327 Change the default clientid sent from the interface hardware address.
300328 If the string is of the format 01:02:03 then it is encoded as hex.
@@ -311,12 +339,14 @@ Here are some options that deal with turning these bits off.
311339 Quiet
312340 .Nm
313341 on the command line, only warnings and errors will be displayed.
314-The messagea are still logged though.
342+The messages are still logged though.
315343 .It Fl A , -noarp
316344 Don't request or claim the address by ARP.
317345 This also disables IPv4LL.
318-.It Fl G , -nogateway
319-Don't set any default routes.
346+.It Fl B , -nobackground
347+Don't run in the background when we acquire a lease.
348+This is mainly useful for running under the control of another process, such
349+as a debugger or a network manager.
320350 .It Fl C , -nohook Ar script
321351 Don't run this hook script.
322352 Matches full name, or prefixed with 2 numbers optionally ending with
@@ -324,19 +354,23 @@ Matches full name, or prefixed with 2 numbers optionally ending with
324354 .Pp
325355 So to stop dhcpcd from touching your DNS or MTU settings you would do:-
326356 .D1 dhcpcd -C resolv.conf -C mtu eth0
327-.It Fl X , -nodaemonise
328-Don't daemonise when we acquire a lease.
329-This disables the
330-.Fl t, -timeout
331-option.
332-This is mainly useful for running under the control of another process, such
333-as a debugger or a network manager.
357+.It Fl G , -nogateway
358+Don't set any default routes.
359+.It Fl K , -nolink
360+Don't receive link messages for carrier status.
361+You should only have to use this with buggy device drivers or running
362+.Nm
363+through a network manager.
334364 .It Fl L , -noipv4ll
335-Don't use IPv4LL at all.
365+Don't use IPv4LL (aka APIPA, aka Bonjour, aka ZeroConf).
336366 .It Fl O , -nooption Ar option
337367 Don't request the specified option.
338368 If no option given, then don't request any options other than those to
339369 configure the interface and routing.
370+.It Fl Q , -require Ar option
371+Requires the
372+.Ar option
373+to be present in all DHCP messages, otherwise the message is ignored.
340374 .It Fl T, -test
341375 On receipt of OFFER messages just call
342376 .Pa /system/etc/dhcpcd/dhcpcd-run-hooks
@@ -347,6 +381,13 @@ files.
347381 .It Fl V, -variables
348382 Display a list of option codes and the associated variable for use in
349383 .Xr dhcpcd-run-hooks 8 .
384+.It Fl X, -blacklist Ar address
385+Ignores all DHCP messages which have this
386+.Ar address
387+as the server ID.
388+This may be expanded in future releases to ignore all packets
389+matching either the IP or hardware
390+.Ar address .
350391 .El
351392 .Sh NOTES
352393 .Nm
@@ -369,6 +410,11 @@ option described above.
369410 .It Pa /data/misc/dhcp/dhcpcd\- Ns Ar interface Ns .lease
370411 The actual DHCP message send by the server. We use this when reading the last
371412 lease and use the files mtime as when it was issued.
413+.It Pa /var/run/dhcpcd\- Ns Ar interface Ns .pid
414+Stores the PID of
415+.Nm
416+running on the
417+.Ar interface .
372418 .El
373419 .Sh SEE ALSO
374420 .Xr dhcpcd.conf 5 ,
--- a/dhcpcd.8.in
+++ b/dhcpcd.8.in
@@ -22,18 +22,18 @@
2222 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2323 .\" SUCH DAMAGE.
2424 .\"
25-.Dd Jul 08, 2008
25+.Dd August 20, 2008
2626 .Dt DHCPCD 8 SMM
2727 .Sh NAME
2828 .Nm dhcpcd
2929 .Nd an RFC 2131 compliant DHCP client
3030 .Sh SYNOPSIS
3131 .Nm
32-.Op Fl dknpqADEGLSTXV
32+.Op Fl bdknpqABDEGKLSTV
3333 .Op Fl c , -script Ar script
3434 .Op Fl f , -config Ar file
3535 .Op Fl h , -hostname Ar hostname
36-.Op Fl i , -classid Ar classid
36+.Op Fl i , -vendorclassid Ar vendorclassid
3737 .Op Fl l , -leasetime Ar seconds
3838 .Op Fl m , -metric Ar metric
3939 .Op Fl o , -option Ar option
@@ -46,6 +46,8 @@
4646 .Op Fl F , -fqdn Ar FQDN
4747 .Op Fl I , -clientid Ar clientid
4848 .Op Fl O , -nooption Ar option
49+.Op Fl Q , -require Ar option
50+.Op Fl X , -blacklist Ar address
4951 .Ar interface
5052 .Nm
5153 .Fl k , -release
@@ -56,9 +58,7 @@
5658 .Sh DESCRIPTION
5759 .Nm
5860 is an implementation of the DHCP client specified in
59-.Rs
60-.%T "RFC 2131"
61-.Re
61+.Li RFC 2131 .
6262 .Nm
6363 gets the host information
6464 .Po
@@ -69,40 +69,42 @@ from a DHCP server and configures the network
6969 of the
7070 machine on which it is running.
7171 .Nm
72-will then write DNS information to
72+then runs the configuration script which writes DNS information to
7373 .Xr resolvconf 8 ,
7474 if available, otherwise directly to
7575 .Pa /etc/resolv.conf .
7676 If the hostname is currenly blank, (null) or localhost then
7777 .Nm
78-will set the hostname to the one supplied by the DHCP server.
78+sets the hostname to the one supplied by the DHCP server.
7979 .Nm
8080 then daemonises and waits for the lease renewal time to lapse.
8181 Then it attempts to renew its lease and reconfigure if the new lease changes.
8282 .Ss Local Link configuration
8383 If
8484 .Nm
85-failed to obtain a lease, it will probe for a valid IPv4LL address
85+failed to obtain a lease, it probes for a valid IPv4LL address
8686 .Po
87-aka Zeroconf, aka APIPA
87+aka ZeroConf, aka APIPA
8888 .Pc .
89-Once obtained it will restart the process of looking for a DHCP server to get a
89+Once obtained it restarts the process of looking for a DHCP server to get a
9090 proper address.
9191 .Pp
9292 When using IPv4LL,
9393 .Nm
94-will always succeed and return a 0 exit code. To disable this behaviour, you
95-can use the
94+nearly always succeeds and returns an exit code of 0.
95+In the rare case it fails, it normally means that there is a reverse ARP proxy
96+installed which always defeats IPv4LL probing.
97+To disable this behaviour, you can use the
9698 .Fl L , -noipv4ll
9799 option.
98100 .Ss Hooking into DHCP events
99101 .Nm
100-will run
102+runs
101103 .Pa @SCRIPT@ ,
102104 or the script specified by the
103105 .Fl c , -script
104106 option.
105-This script will run each script found in
107+This script runs each script found in
106108 .Pa @HOOKDIR@
107109 in a lexical order.
108110 The default installation supplies the scripts
@@ -124,6 +126,10 @@ You can fine tune the behaviour of
124126 .Nm
125127 with the following options:
126128 .Bl -tag -width indent
129+.It Fl b , -background
130+Background immediately.
131+This is useful for startup scripts which don't disable link messages for
132+carrier status.
127133 .It Fl c , -script Ar script
128134 Use this
129135 .Ar script
@@ -142,16 +148,16 @@ always processes the config file before any command line options.
142148 .It Fl h , -hostname Ar hostname
143149 By default,
144150 .Nm
145-will send the current hostname to the DHCP server so it can register in DNS.
151+sends the current hostname to the DHCP server so it can register in DNS.
146152 You can use this option to specify the
147153 .Ar hostname
148154 sent, or an empty string to
149155 stop any
150156 .Ar hostname
151157 from being sent.
152-.It Fl i , -classid Ar classid
158+.It Fl i , -vendorclassid Ar vendorclassid
153159 Override the
154-.Ar classid
160+.Ar vendorclassid
155161 field sent. The default is
156162 dhcpcd <version>.
157163 If not set then none is sent.
@@ -163,6 +169,8 @@ process running on the
163169 to release its lease, deconfigure the
164170 .Ar interface
165171 and then exit.
172+.Nm
173+then waits until this process has exited.
166174 .It Fl l , -leasetime Ar seconds
167175 Request a specific lease time in
168176 .Ar seconds .
@@ -184,14 +192,27 @@ Request the DHCP
184192 .Ar option
185193 variable for use in
186194 .Pa @SCRIPT@ .
187-.It Fl n , -renew
195+.It Fl n , -rebind
188196 Notifies an existing
189197 .Nm
190198 process running on the
191199 .Ar interface
192-to renew it's lease. If
200+to rebind it's lease.
201+.Nm
202+will not re-configure itself or use any other command line arguments.
203+.Nm
204+will timeout the rebind after 30 seconds at which point the lease will be
205+expired and
206+.Nm
207+will enter the discovery state to obtain a new lease.
208+Use the
209+.Fl t , -timeout
210+option to change this.
211+If
193212 .Nm
194213 is not running, then it starts up as normal.
214+This option used to be renew, but rebind is more accurate as we need to
215+broadcast the request instead of unicasting.
195216 .It Fl p , -persistent
196217 .Nm
197218 normally deconfigures the
@@ -201,28 +222,31 @@ Sometimes, this isn't desirable if for example you have root mounted over NFS.
201222 You can use this option to stop this from happening.
202223 .It Fl r , -request Op Ar address
203224 .Nm
204-normally sends a DHCP Broadcast to find servers to offer an address.
225+normally sends a DHCP DISCOVER to find servers to offer an address.
205226 .Nm
206-will then request the address used.
207-You can use this option to skip the broadcast step and just request an
227+then requests the address used.
228+You can use this option to skip the BROADCAST step and just request the
208229 .Ar address .
209230 The downside is if you request an
210231 .Ar address
211232 the DHCP server does not know about or the DHCP server is not
212233 authorative, it will remain silent.
213-In this situation, we go back to the init state and broadcast again.
234+In this situation, we go back to the init state and DISCOVER again.
214235 If no
215236 .Ar address
216237 is given then the first address currently assigned to the
217238 .Ar interface
218239 is used.
219240 .It Fl s , -inform Op Ar address Ns Op Ar /cidr
220-Behaves exactly like
241+Behaves like
221242 .Fl r , -request
222243 as above, but sends a DHCP INFORM instead of a REQUEST.
223244 This does not get a lease as such, just notifies the DHCP server of the
224245 .Ar address
225246 in use.
247+You should also include the optional
248+.Ar cidr
249+network number in-case the address is not already configured on the interface.
226250 .Nm
227251 remains running and pretends it has an infinite lease.
228252 .Nm
@@ -243,7 +267,7 @@ to wait forever to get a lease.
243267 .It Fl u , -userclass Ar class
244268 Tags the DHCP message with the userclass
245269 .Ar class .
246-DHCP servers use this give memebers of the class DHCP options other than the
270+DHCP servers use this give members of the class DHCP options other than the
247271 default, without having to know things like hardware address or hostname.
248272 .It Fl v , -vendor Ar code , Ns Ar value
249273 Add an enscapulated vendor option.
@@ -252,30 +276,31 @@ should be between 1 and 254 inclusive.
252276 Examples.
253277 .Pp
254278 Set the vendor option 01 with an IP address.
255-.D1 dhcpcd -v 01,192.168.0.2 eth0
279+.D1 dhcpcd \-v 01,192.168.0.2 eth0
256280 Set the vendor option 02 with a hex code.
257-.D1 dhcpcd -v 02,01:02:03:04:05 eth0
281+.D1 dhcpcd \-v 02,01:02:03:04:05 eth0
258282 Do the above and set a third option with a string and not an IP address.
259-.D1 dhcpcd -v 01,192.168.0.2 -v 02,01:02:03:04:05 -v 03,\e"192.168.0.2\e" eth0
283+.D1 dhcpcd \-v 01,192.168.0.2 \-v 02,01:02:03:04:05 \-v 03,\e"192.168.0.2\e" eth0
260284 .It Fl x , -exit
261-This causes an existing
285+This will signal an existing
262286 .Nm
263287 process running on the
264288 .Ar interface
265289 to deconfigure the
266290 .Ar interface
267291 and exit.
292+.Nm
293+then waits until this process has exited.
268294 .It Fl D , -duid
269295 Generate an
270-.Rs
271-.%T "RFC 4361"
272-.Re
296+.Li RFC 4361
273297 compliant clientid.
274298 This requires persistent storage and not all DHCP servers work with it so it's
275299 not enabled by default.
276-The DUID generated will be held in
300+.Nm
301+generates the DUID and stores in it
277302 .Pa @SYSCONFDIR@/dhcpcd.duid
278-and should not be copied to other hosts.
303+This file should not be copied to other hosts.
279304 .It Fl E , -lastlease
280305 If
281306 .Nm
@@ -289,12 +314,15 @@ Requests that the DHCP server updates DNS using FQDN instead of just a
289314 hostname.
290315 Valid values for
291316 .Ar fqdn
292-are none, ptr and both.
317+are disable, none, ptr and both.
293318 The current hostname or the hostname specified using the
294319 .Fl h , -hostname
295320 option must be a FQDN.
296321 .Nm
297322 itself never does any DNS updates.
323+.Nm
324+encodes the FQDN hostname as specified in
325+.Li RFC1035 .
298326 .It Fl I , -clientid Ar clientid
299327 Change the default clientid sent from the interface hardware address.
300328 If the string is of the format 01:02:03 then it is encoded as hex.
@@ -311,12 +339,14 @@ Here are some options that deal with turning these bits off.
311339 Quiet
312340 .Nm
313341 on the command line, only warnings and errors will be displayed.
314-The messagea are still logged though.
342+The messages are still logged though.
315343 .It Fl A , -noarp
316344 Don't request or claim the address by ARP.
317345 This also disables IPv4LL.
318-.It Fl G , -nogateway
319-Don't set any default routes.
346+.It Fl B , -nobackground
347+Don't run in the background when we acquire a lease.
348+This is mainly useful for running under the control of another process, such
349+as a debugger or a network manager.
320350 .It Fl C , -nohook Ar script
321351 Don't run this hook script.
322352 Matches full name, or prefixed with 2 numbers optionally ending with
@@ -324,19 +354,23 @@ Matches full name, or prefixed with 2 numbers optionally ending with
324354 .Pp
325355 So to stop dhcpcd from touching your DNS or MTU settings you would do:-
326356 .D1 dhcpcd -C resolv.conf -C mtu eth0
327-.It Fl X , -nodaemonise
328-Don't daemonise when we acquire a lease.
329-This disables the
330-.Fl t, -timeout
331-option.
332-This is mainly useful for running under the control of another process, such
333-as a debugger or a network manager.
357+.It Fl G , -nogateway
358+Don't set any default routes.
359+.It Fl K , -nolink
360+Don't receive link messages for carrier status.
361+You should only have to use this with buggy device drivers or running
362+.Nm
363+through a network manager.
334364 .It Fl L , -noipv4ll
335-Don't use IPv4LL at all.
365+Don't use IPv4LL (aka APIPA, aka Bonjour, aka ZeroConf).
336366 .It Fl O , -nooption Ar option
337367 Don't request the specified option.
338368 If no option given, then don't request any options other than those to
339369 configure the interface and routing.
370+.It Fl Q , -require Ar option
371+Requires the
372+.Ar option
373+to be present in all DHCP messages, otherwise the message is ignored.
340374 .It Fl T, -test
341375 On receipt of OFFER messages just call
342376 .Pa @SCRIPT@
@@ -347,6 +381,13 @@ files.
347381 .It Fl V, -variables
348382 Display a list of option codes and the associated variable for use in
349383 .Xr dhcpcd-run-hooks 8 .
384+.It Fl X, -blacklist Ar address
385+Ignores all DHCP messages which have this
386+.Ar address
387+as the server ID.
388+This may be expanded in future releases to ignore all packets
389+matching either the IP or hardware
390+.Ar address .
350391 .El
351392 .Sh NOTES
352393 .Nm
@@ -369,6 +410,11 @@ option described above.
369410 .It Pa @DBDIR@/dhcpcd\- Ns Ar interface Ns .lease
370411 The actual DHCP message send by the server. We use this when reading the last
371412 lease and use the files mtime as when it was issued.
413+.It Pa /var/run/dhcpcd\- Ns Ar interface Ns .pid
414+Stores the PID of
415+.Nm
416+running on the
417+.Ar interface .
372418 .El
373419 .Sh SEE ALSO
374420 .Xr dhcpcd.conf 5 ,
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -42,6 +42,7 @@ const char copyright[] = "Copyright (c) 2006-2008 Roy Marples";
4242 #include <stdlib.h>
4343 #include <string.h>
4444 #include <unistd.h>
45+#include <time.h>
4546
4647 #include "config.h"
4748 #include "client.h"
@@ -53,71 +54,66 @@ const char copyright[] = "Copyright (c) 2006-2008 Roy Marples";
5354 #ifdef ANDROID
5455 #include <linux/capability.h>
5556 #include <linux/prctl.h>
57+#include <cutils/properties.h>
5658 #include <private/android_filesystem_config.h>
5759 #endif
5860
5961 /* Don't set any optional arguments here so we retain POSIX
6062 * compatibility with getopt */
61-#define OPTS "c:df:h:i:kl:m:no:pqr:s:t:u:v:xAC:DEF:GI:LO:TVX"
63+#define OPTS "bc:df:h:i:kl:m:no:pqr:s:t:u:v:xABC:DEF:GI:KLO:Q:TVX:"
6264
6365 static int doversion = 0;
6466 static int dohelp = 0;
6567 static const struct option longopts[] = {
66- {"script", required_argument, NULL, 'c'},
67- {"debug", no_argument, NULL, 'd'},
68- {"config", required_argument, NULL, 'f'},
69- {"hostname", optional_argument, NULL, 'h'},
70- {"classid", optional_argument, NULL, 'i'},
71- {"release", no_argument, NULL, 'k'},
72- {"leasetime", required_argument, NULL, 'l'},
73- {"metric", required_argument, NULL, 'm'},
74- {"renew", no_argument, NULL, 'n'},
75- {"option", required_argument, NULL, 'o'},
76- {"persistent", no_argument, NULL, 'p'},
77- {"quiet", no_argument, NULL, 'q'},
78- {"inform", optional_argument, NULL, 's'},
79- {"request", optional_argument, NULL, 'r'},
80- {"timeout", required_argument, NULL, 't'},
81- {"userclass", required_argument, NULL, 'u'},
82- {"vendor", required_argument, NULL, 'v'},
83- {"exit", no_argument, NULL, 'x'},
84- {"noarp", no_argument, NULL, 'A'},
85- {"nohook", required_argument, NULL, 'C'},
86- {"duid", no_argument, NULL, 'D'},
87- {"lastlease", no_argument, NULL, 'E'},
88- {"fqdn", optional_argument, NULL, 'F'},
89- {"nogateway", no_argument, NULL, 'G'},
90- {"clientid", optional_argument, NULL, 'I'},
91- {"noipv4ll", no_argument, NULL, 'L'},
92- {"nooption", optional_argument, NULL, 'O'},
93- {"test", no_argument, NULL, 'T'},
94- {"variables", no_argument, NULL, 'V'},
95- {"nodaemonise", no_argument, NULL, 'X'},
96- {"help", no_argument, &dohelp, 1},
97- {"version", no_argument, &doversion, 1},
98-#ifdef THERE_IS_NO_FORK
99- {"daemonised", no_argument, NULL, 'z'},
100- {"skiproutes", required_argument, NULL, 'Z'},
101-#endif
68+ {"background", no_argument, NULL, 'b'},
69+ {"script", required_argument, NULL, 'c'},
70+ {"debug", no_argument, NULL, 'd'},
71+ {"config", required_argument, NULL, 'f'},
72+ {"hostname", optional_argument, NULL, 'h'},
73+ {"vendorclassid", optional_argument, NULL, 'i'},
74+ {"release", no_argument, NULL, 'k'},
75+ {"leasetime", required_argument, NULL, 'l'},
76+ {"metric", required_argument, NULL, 'm'},
77+ {"rebind", no_argument, NULL, 'n'},
78+ {"option", required_argument, NULL, 'o'},
79+ {"persistent", no_argument, NULL, 'p'},
80+ {"quiet", no_argument, NULL, 'q'},
81+ {"request", optional_argument, NULL, 'r'},
82+ {"inform", optional_argument, NULL, 's'},
83+ {"timeout", required_argument, NULL, 't'},
84+ {"userclass", required_argument, NULL, 'u'},
85+ {"vendor", required_argument, NULL, 'v'},
86+ {"exit", no_argument, NULL, 'x'},
87+ {"noarp", no_argument, NULL, 'A'},
88+ {"nobackground", no_argument, NULL, 'B'},
89+ {"nohook", required_argument, NULL, 'C'},
90+ {"duid", no_argument, NULL, 'D'},
91+ {"lastlease", no_argument, NULL, 'E'},
92+ {"fqdn", optional_argument, NULL, 'F'},
93+ {"nogateway", no_argument, NULL, 'G'},
94+ {"clientid", optional_argument, NULL, 'I'},
95+ {"nolink", no_argument, NULL, 'K'},
96+ {"noipv4ll", no_argument, NULL, 'L'},
97+ {"nooption", optional_argument, NULL, 'O'},
98+ {"require", required_argument, NULL, 'Q'},
99+ {"test", no_argument, NULL, 'T'},
100+ {"variables", no_argument, NULL, 'V'},
101+ {"blacklist", required_argument, NULL, 'X'},
102+ {"help", no_argument, &dohelp, 1},
103+ {"version", no_argument, &doversion, 1},
102104 #ifdef CMDLINE_COMPAT
103- {"nohostname", no_argument, NULL, 'H'},
104- {"nomtu", no_argument, NULL, 'M'},
105- {"nontp", no_argument, NULL, 'N'},
106- {"nodns", no_argument, NULL, 'R'},
107- {"msscr", no_argument, NULL, 'S'},
108- {"nonis", no_argument, NULL, 'Y'},
105+ {"classid", optional_argument, NULL, 'i'},
106+ {"renew", no_argument, NULL, 'n'},
107+ {"nohostname", no_argument, NULL, 'H'},
108+ {"nomtu", no_argument, NULL, 'M'},
109+ {"nontp", no_argument, NULL, 'N'},
110+ {"nodns", no_argument, NULL, 'R'},
111+ {"msscr", no_argument, NULL, 'S'},
112+ {"nonis", no_argument, NULL, 'Y'},
109113 #endif
110114 {NULL, 0, NULL, '\0'}
111115 };
112116
113-#ifdef THERE_IS_NO_FORK
114-char dhcpcd[PATH_MAX];
115-char **dhcpcd_argv = NULL;
116-int dhcpcd_argc = 0;
117-char *dhcpcd_skiproutes = NULL;
118-#define EXTRA_OPTS "zZ:"
119-#endif
120-
121117 #ifdef CMDLINE_COMPAT
122118 # define EXTRA_OPTS "HMNRSY"
123119 #endif
@@ -164,12 +160,10 @@ read_pid(const char *pidfile)
164160 static void
165161 usage(void)
166162 {
167-#ifndef MINIMAL
168163 printf("usage: "PACKAGE" [-dknpqxADEGHKLOTV] [-c script] [-f file ] [-h hostname]\n"
169164 " [-i classID ] [-l leasetime] [-m metric] [-o option] [-r ipaddr]\n"
170165 " [-s ipaddr] [-t timeout] [-u userclass] [-F none|ptr|both]\n"
171- " [-I clientID] [-C hookscript] <interface>\n");
172-#endif
166+ " [-I clientID] [-C hookscript] [-Q option] [-X ipaddr] <interface>\n");
173167 }
174168
175169 static char *
@@ -214,7 +208,6 @@ add_environ(struct options *options, const char *value, int uniq)
214208 return newlist[i];
215209 }
216210
217-#ifndef MINIMAL
218211 #define parse_string(buf, len, arg) parse_string_hwaddr(buf, len, arg, 0)
219212 static ssize_t
220213 parse_string_hwaddr(char *sbuf, ssize_t slen, char *str, int clid)
@@ -312,7 +305,6 @@ parse_string_hwaddr(char *sbuf, ssize_t slen, char *str, int clid)
312305 }
313306 return l;
314307 }
315-#endif
316308
317309 static int
318310 parse_option(int opt, char *oarg, struct options *options)
@@ -320,44 +312,44 @@ parse_option(int opt, char *oarg, struct options *options)
320312 int i;
321313 char *p;
322314 ssize_t s;
323-#ifndef MINIMAL
324315 struct in_addr addr;
325-#endif
326316
327317 switch(opt) {
318+ case 'b':
319+ options->options |= DHCPCD_BACKGROUND;
320+ break;
328321 case 'c':
329322 strlcpy(options->script, oarg, sizeof(options->script));
330323 break;
331324 case 'h':
332-#ifndef MINIMAL
333325 if (oarg)
334326 s = parse_string(options->hostname + 1,
335- MAXHOSTNAMELEN, oarg);
327+ HOSTNAME_MAX_LEN, oarg);
336328 else
337329 s = 0;
338330 if (s == -1) {
339331 logger(LOG_ERR, "hostname: %s", strerror(errno));
340332 return -1;
341333 }
334+ if (s != 0 && options->hostname[1] == '.') {
335+ logger(LOG_ERR, "hostname cannot begin with a .");
336+ return -1;
337+ }
342338 options->hostname[0] = (uint8_t)s;
343-#endif
344339 break;
345340 case 'i':
346-#ifndef MINIMAL
347341 if (oarg)
348- s = parse_string((char *)options->classid + 1,
349- CLASSID_MAX_LEN, oarg);
342+ s = parse_string((char *)options->vendorclassid + 1,
343+ VENDORCLASSID_MAX_LEN, oarg);
350344 else
351345 s = 0;
352346 if (s == -1) {
353- logger(LOG_ERR, "classid: %s", strerror(errno));
347+ logger(LOG_ERR, "vendorclassid: %s", strerror(errno));
354348 return -1;
355349 }
356- *options->classid = (uint8_t)s;
357-#endif
350+ *options->vendorclassid = (uint8_t)s;
358351 break;
359352 case 'l':
360-#ifndef MINIMAL
361353 if (*oarg == '-') {
362354 logger(LOG_ERR,
363355 "leasetime must be a positive value");
@@ -369,7 +361,6 @@ parse_option(int opt, char *oarg, struct options *options)
369361 logger(LOG_ERR, "`%s' out of range", oarg);
370362 return -1;
371363 }
372-#endif
373364 break;
374365 case 'm':
375366 options->metric = atoint(oarg);
@@ -379,7 +370,7 @@ parse_option(int opt, char *oarg, struct options *options)
379370 }
380371 break;
381372 case 'o':
382- if (make_reqmask(options->reqmask, &oarg, 1) != 0) {
373+ if (make_option_mask(options->requestmask, &oarg, 1) != 0) {
383374 logger(LOG_ERR, "unknown option `%s'", oarg);
384375 return -1;
385376 }
@@ -416,7 +407,7 @@ parse_option(int opt, char *oarg, struct options *options)
416407 case 'r':
417408 if (!(options->options & DHCPCD_INFORM))
418409 options->options |= DHCPCD_REQUEST;
419- if (*oarg && !inet_aton(oarg, &options->request_address)) {
410+ if (oarg && !inet_aton(oarg, &options->request_address)) {
420411 logger(LOG_ERR, "`%s' is not a valid IP address",
421412 oarg);
422413 return -1;
@@ -430,7 +421,6 @@ parse_option(int opt, char *oarg, struct options *options)
430421 }
431422 break;
432423 case 'u':
433-#ifndef MINIMAL
434424 s = USERCLASS_MAX_LEN - options->userclass[0] - 1;
435425 s = parse_string((char *)options->userclass + options->userclass[0] + 2,
436426 s, oarg);
@@ -442,10 +432,8 @@ parse_option(int opt, char *oarg, struct options *options)
442432 options->userclass[options->userclass[0] + 1] = s;
443433 options->userclass[0] += s + 1;
444434 }
445-#endif
446435 break;
447436 case 'v':
448-#ifndef MINIMAL
449437 p = strchr(oarg, ',');
450438 if (!p || !p[1]) {
451439 logger(LOG_ERR, "invalid vendor format");
@@ -480,13 +468,15 @@ parse_option(int opt, char *oarg, struct options *options)
480468 options->vendor[options->vendor[0] + 2] = s;
481469 options->vendor[0] += s + 2;
482470 }
483-#endif
484471 break;
485472 case 'A':
486473 options->options &= ~DHCPCD_ARP;
487474 /* IPv4LL requires ARP */
488475 options->options &= ~DHCPCD_IPV4LL;
489476 break;
477+ case 'B':
478+ options->options &= ~DHCPCD_DAEMONISE;
479+ break;
490480 case 'C':
491481 /* Commas to spaces for shell */
492482 while ((p = strchr(oarg, ',')))
@@ -504,7 +494,6 @@ parse_option(int opt, char *oarg, struct options *options)
504494 options->options |= DHCPCD_LASTLEASE;
505495 break;
506496 case 'F':
507-#ifndef MINIMAL
508497 if (!oarg) {
509498 options->fqdn = FQDN_BOTH;
510499 break;
@@ -515,20 +504,20 @@ parse_option(int opt, char *oarg, struct options *options)
515504 options->fqdn = FQDN_PTR;
516505 else if (strcmp(oarg, "both") == 0)
517506 options->fqdn = FQDN_BOTH;
507+ else if (strcmp(oarg, "disable") == 0)
508+ options->fqdn = FQDN_DISABLE;
518509 else {
519510 logger(LOG_ERR, "invalid value `%s' for FQDN",
520511 oarg);
521512 return -1;
522513 }
523-#endif
524514 break;
525515 case 'G':
526516 options->options &= ~DHCPCD_GATEWAY;
527517 break;
528518 case 'I':
529-#ifndef MINIMAL
530519 /* Strings have a type of 0 */;
531- options->classid[1] = 0;
520+ options->clientid[1] = 0;
532521 if (oarg)
533522 s = parse_string_hwaddr((char *)options->clientid + 1,
534523 CLIENTID_MAX_LEN, oarg, 1);
@@ -543,21 +532,40 @@ parse_option(int opt, char *oarg, struct options *options)
543532 options->options &= ~DHCPCD_DUID;
544533 options->options &= ~DHCPCD_CLIENTID;
545534 }
546-#endif
535+ break;
536+ case 'K':
537+ options->options &= ~DHCPCD_LINK;
547538 break;
548539 case 'L':
549540 options->options &= ~DHCPCD_IPV4LL;
550541 break;
551542 case 'O':
552- if (make_reqmask(options->reqmask, &optarg, -1) != 0 ||
553- make_reqmask(options->nomask, &optarg, 1) != 0)
543+ if (make_option_mask(options->requestmask, &oarg, -1) != 0 ||
544+ make_option_mask(options->requiremask, &oarg, -1) != 0 ||
545+ make_option_mask(options->nomask, &oarg, 1) != 0)
546+ {
547+ logger(LOG_ERR, "unknown option `%s'", oarg);
548+ return -1;
549+ }
550+ break;
551+ case 'Q':
552+ if (make_option_mask(options->requiremask, &oarg, 1) != 0 ||
553+ make_option_mask(options->requestmask, &oarg, 1) != 0)
554554 {
555- logger(LOG_ERR, "unknown option `%s'", optarg);
555+ logger(LOG_ERR, "unknown option `%s'", oarg);
556556 return -1;
557557 }
558558 break;
559559 case 'X':
560- options->options &= ~DHCPCD_DAEMONISE;
560+ if (!inet_aton(oarg, &addr)) {
561+ logger(LOG_ERR, "`%s' is not a valid IP address",
562+ oarg);
563+ return -1;
564+ }
565+ options->blacklist = xrealloc(options->blacklist,
566+ sizeof(in_addr_t) * (options->blacklist_len + 1));
567+ options->blacklist[options->blacklist_len] = addr.s_addr;
568+ options->blacklist_len++;
561569 break;
562570 default:
563571 return 0;
@@ -630,38 +638,34 @@ main(int argc, char **argv)
630638 FILE *f;
631639 char *cf = NULL;
632640 char *intf = NULL;
641+ struct timespec ts;
633642
634643 #ifdef ANDROID
635644 switchUser();
636645 #endif
637-
638646 closefrom(3);
647+ /* Saves calling fflush(stream) in the logger */
648+ setlinebuf(stdout);
639649 openlog(PACKAGE, LOG_PID, LOG_LOCAL0);
650+ setlogprefix(PACKAGE ": ");
640651
641652 options = xzalloc(sizeof(*options));
642- options->options |= DHCPCD_GATEWAY | DHCPCD_DAEMONISE;
653+ options->options |= DHCPCD_CLIENTID | DHCPCD_GATEWAY | DHCPCD_DAEMONISE;
654+ options->options |= DHCPCD_ARP | DHCPCD_IPV4LL | DHCPCD_LINK;
643655 options->timeout = DEFAULT_TIMEOUT;
644656 strlcpy(options->script, SCRIPT, sizeof(options->script));
645657
646-#ifndef MINIMAL
647- options->options |= DHCPCD_CLIENTID;
648- options->classid[0] = snprintf((char *)options->classid + 1, CLASSID_MAX_LEN,
649- "%s %s", PACKAGE, VERSION);
650-#endif
651-#ifdef ENABLE_ARP
652- options->options |= DHCPCD_ARP;
653- #ifdef ENABLE_IPV4LL
654- options->options |= DHCPCD_IPV4LL;
655- #endif
656-#endif
658+ options->vendorclassid[0] = snprintf((char *)options->vendorclassid + 1,
659+ VENDORCLASSID_MAX_LEN,
660+ "%s %s", PACKAGE, VERSION);
657661
658662 #ifdef CMDLINE_COMPAT
659- add_reqmask(options->reqmask, DHCP_DNSSERVER);
660- add_reqmask(options->reqmask, DHCP_DNSDOMAIN);
661- add_reqmask(options->reqmask, DHCP_DNSSEARCH);
662- add_reqmask(options->reqmask, DHCP_NISSERVER);
663- add_reqmask(options->reqmask, DHCP_NISDOMAIN);
664- add_reqmask(options->reqmask, DHCP_NTPSERVER);
663+ add_option_mask(options->requestmask, DHO_DNSSERVER);
664+ add_option_mask(options->requestmask, DHO_DNSDOMAIN);
665+ add_option_mask(options->requestmask, DHO_DNSSEARCH);
666+ add_option_mask(options->requestmask, DHO_NISSERVER);
667+ add_option_mask(options->requestmask, DHO_NISDOMAIN);
668+ add_option_mask(options->requestmask, DHO_NTPSERVER);
665669
666670 /* If the duid file exists, then enable duid by default
667671 * This means we don't break existing clients that easily :) */
@@ -671,23 +675,11 @@ main(int argc, char **argv)
671675 }
672676 #endif
673677
674-#ifdef THERE_IS_NO_FORK
675- dhcpcd_argv = argv;
676- dhcpcd_argc = argc;
677- if (!realpath(argv[0], dhcpcd)) {
678- fprintf(stderr, "unable to resolve the path `%s': %s",
679- argv[0], strerror(errno));
680- goto abort;
681- }
682-#endif
683-
684-#ifndef MINIMAL
685678 gethostname(options->hostname + 1, sizeof(options->hostname));
686679 if (strcmp(options->hostname + 1, "(none)") == 0 ||
687680 strcmp(options->hostname + 1, "localhost") == 0)
688681 options->hostname[1] = '\0';
689682 *options->hostname = strlen(options->hostname + 1);
690-#endif
691683
692684 while ((opt = getopt_long(argc, argv, OPTS EXTRA_OPTS,
693685 longopts, &option_index)) != -1)
@@ -711,23 +703,8 @@ main(int argc, char **argv)
711703 }
712704 }
713705
714- if (doversion) {
706+ if (doversion)
715707 printf(""PACKAGE" "VERSION"\n%s\n", copyright);
716- printf("Compile time options:"
717-#ifdef ENABLE_ARP
718- " ARP"
719-#endif
720-#ifdef ENABLE_IPV4LL
721- " IPV4LL"
722-#endif
723-#ifdef MINIMAL
724- " MINIMAL"
725-#endif
726-#ifdef THERE_IS_NO_FORK
727- " THERE_IS_NO_FORK"
728-#endif
729- "\n");
730- }
731708
732709 if (dohelp)
733710 usage();
@@ -822,15 +799,6 @@ main(int argc, char **argv)
822799 break;
823800 case 'f':
824801 break;
825-#ifdef THERE_IS_NO_FORK
826- case 'z':
827- options->options |= DHCPCD_DAEMONISED;
828- close_fds();
829- break;
830- case 'Z':
831- dhcpcd_skiproutes = xstrdup(optarg);
832- break;
833-#endif
834802 case 'k':
835803 sig = SIGHUP;
836804 break;
@@ -846,22 +814,22 @@ main(int argc, char **argv)
846814 #ifdef CMDLINE_COMPAT
847815 case 'H': /* FALLTHROUGH */
848816 case 'M':
849- del_reqmask(options->reqmask, DHCP_MTU);
817+ del_option_mask(options->requestmask, DHO_MTU);
850818 break;
851819 case 'N':
852- del_reqmask(options->reqmask, DHCP_NTPSERVER);
820+ del_option_mask(options->requestmask, DHO_NTPSERVER);
853821 break;
854822 case 'R':
855- del_reqmask(options->reqmask, DHCP_DNSSERVER);
856- del_reqmask(options->reqmask, DHCP_DNSDOMAIN);
857- del_reqmask(options->reqmask, DHCP_DNSSEARCH);
823+ del_option_mask(options->requestmask, DHO_DNSSERVER);
824+ del_option_mask(options->requestmask, DHO_DNSDOMAIN);
825+ del_option_mask(options->requestmask, DHO_DNSSEARCH);
858826 break;
859827 case 'S':
860- add_reqmask(options->reqmask, DHCP_MSCSR);
828+ add_option_mask(options->requestmask, DHO_MSCSR);
861829 break;
862830 case 'Y':
863- del_reqmask(options->reqmask, DHCP_NISSERVER);
864- del_reqmask(options->reqmask, DHCP_NISDOMAIN);
831+ del_option_mask(options->requestmask, DHO_NISSERVER);
832+ del_option_mask(options->requestmask, DHO_NISDOMAIN);
865833 break;
866834 #endif
867835 default:
@@ -874,60 +842,17 @@ main(int argc, char **argv)
874842 }
875843 }
876844
877-#ifndef MINIMAL
878- if ((p = strchr(options->hostname, '.'))) {
879- if (options->fqdn == FQDN_DISABLE)
880- *p = '\0';
881- } else {
882- if (options->fqdn != FQDN_DISABLE) {
883- logger(LOG_WARNING, "hostname `%s' is not a FQDN",
884- options->hostname);
885- options->fqdn = FQDN_DISABLE;
886- }
887- }
888- if (options->fqdn != FQDN_DISABLE)
889- del_reqmask(options->reqmask, DHCP_HOSTNAME);
845+#ifdef THERE_IS_NO_FORK
846+ options->options &= ~DHCPCD_DAEMONISE;
890847 #endif
891848
892- if (options->request_address.s_addr == 0 &&
893- (options->options & DHCPCD_INFORM ||
894- options->options & DHCPCD_REQUEST))
895- {
896- if (get_address(options->interface,
897- &options->request_address,
898- &options->request_netmask) != 1)
899- {
900- logger(LOG_ERR, "no existing address");
901- goto abort;
902- }
903- }
904-
905- if (!(options->options & DHCPCD_DAEMONISE))
906- options->timeout = 0;
907-
908- if (IN_LINKLOCAL(ntohl(options->request_address.s_addr))) {
909- logger(LOG_ERR,
910- "you are not allowed to request a link local address");
911- goto abort;
912- }
913-
914-/* android runs us as user "dhcp" */
915849 #ifndef ANDROID
850+ /* android runs us as user "dhcp" */
916851 if (geteuid())
917852 logger(LOG_WARNING, PACKAGE " will not work correctly unless"
918853 " run as root");
919854 #endif
920855
921- prefix = xmalloc(sizeof(char) * (IF_NAMESIZE + 3));
922- snprintf(prefix, IF_NAMESIZE, "%s: ", options->interface);
923- setlogprefix(prefix);
924- snprintf(options->pidfile, sizeof(options->pidfile), PIDFILE,
925- options->interface);
926- free(prefix);
927-
928- chdir("/");
929- umask(022);
930-
931856 if (options->options & DHCPCD_TEST) {
932857 if (options->options & DHCPCD_REQUEST ||
933858 options->options & DHCPCD_INFORM) {
@@ -948,32 +873,100 @@ main(int argc, char **argv)
948873 }
949874 }
950875
876+ prefix = xmalloc(sizeof(char) * (IF_NAMESIZE + 3));
877+ snprintf(prefix, IF_NAMESIZE, "%s: ", options->interface);
878+ setlogprefix(prefix);
879+ snprintf(options->pidfile, sizeof(options->pidfile), PIDFILE,
880+ options->interface);
881+ free(prefix);
882+
883+ if (options->request_address.s_addr == 0 &&
884+ (options->options & DHCPCD_INFORM ||
885+ options->options & DHCPCD_REQUEST))
886+ {
887+ errno = 0;
888+ if (get_address(options->interface,
889+ &options->request_address,
890+ &options->request_netmask) != 1)
891+ {
892+ if (errno)
893+ logger(LOG_ERR, "get_address: %s",
894+ strerror(errno));
895+ else
896+ logger(LOG_ERR, "no existing address");
897+ goto abort;
898+ }
899+ }
900+ if (IN_LINKLOCAL(ntohl(options->request_address.s_addr))) {
901+ logger(LOG_ERR,
902+ "you are not allowed to request a link local address");
903+ goto abort;
904+ }
905+
906+ chdir("/");
907+ umask(022);
908+
951909 if (sig != 0 && !(options->options & DHCPCD_DAEMONISED)) {
910+#ifdef ANDROID
911+ char pidpropname[PROPERTY_KEY_MAX];
912+ char pidpropval[PROPERTY_VALUE_MAX];
913+
914+ i = -1;
915+ if (snprintf(pidpropname,
916+ sizeof(pidpropname),
917+ "dhcp.%s.pid", options->interface) >= PROPERTY_KEY_MAX) {
918+ goto abort;
919+ }
920+ property_get(pidpropname, pidpropval, NULL);
921+ if (strlen(pidpropval) == 0) {
922+ goto abort;
923+ }
924+ pid = atoi(pidpropval);
925+#else
952926 i = -1;
953927 pid = read_pid(options->pidfile);
928+#endif
954929 if (pid != 0)
955930 logger(LOG_INFO, "sending signal %d to pid %d",
956931 sig, pid);
957932
958- if (!pid || (i = kill(pid, sig)))
959- logger(sig == SIGALRM ? LOG_INFO : LOG_ERR,
960- ""PACKAGE" not running");
961-
962- if (pid != 0 && (sig != SIGALRM || i != 0))
933+ if (!pid || (i = kill(pid, sig))) {
934+ if (sig != SIGALRM)
935+ logger(LOG_ERR, ""PACKAGE" not running");
963936 unlink(options->pidfile);
964-
937+ }
965938 if (i == 0) {
966- retval = EXIT_SUCCESS;
939+ if (sig == SIGALRM) {
940+ retval = EXIT_SUCCESS;
941+ goto abort;
942+ }
943+ /* Spin until it exits */
944+ logger(LOG_INFO, "waiting for pid %d to exit", pid);
945+ ts.tv_sec = 0;
946+ ts.tv_nsec = 100000000; /* 10th of a second */
947+ for(i = 0; i < 100; i++) {
948+ nanosleep(&ts, NULL);
949+ if (read_pid(options->pidfile) == 0) {
950+ retval = EXIT_SUCCESS;
951+ break;
952+ }
953+ }
954+ if (retval != EXIT_SUCCESS)
955+ logger(LOG_ERR, "pid %d failed to exit", pid);
967956 goto abort;
968957 }
969-
970958 if (sig != SIGALRM)
971959 goto abort;
972960 }
973-#ifndef ANDROID
961+
974962 if (!(options->options & DHCPCD_TEST) &&
975963 !(options->options & DHCPCD_DAEMONISED))
976964 {
965+#ifdef ANDROID
966+ char pidpropname[PROPERTY_KEY_MAX];
967+ char pidpropval[PROPERTY_VALUE_MAX];
968+#endif
969+#ifndef ANDROID
977970 if ((pid = read_pid(options->pidfile)) > 0 &&
978971 kill(pid, 0) == 0)
979972 {
@@ -982,7 +975,7 @@ main(int argc, char **argv)
982975 pid, options->pidfile);
983976 goto abort;
984977 }
985-
978+#endif
986979 pid_fd = open(options->pidfile,
987980 O_WRONLY | O_CREAT | O_NONBLOCK, 0664);
988981 if (pid_fd == -1) {
@@ -1001,17 +994,27 @@ main(int argc, char **argv)
1001994
1002995 if (set_cloexec(pid_fd) == -1)
1003996 goto abort;
997+#ifdef ANDROID
998+ if (snprintf(pidpropname,
999+ sizeof(pidpropname),
1000+ "dhcp.%s.pid", options->interface) >= PROPERTY_KEY_MAX) {
1001+ goto abort;
1002+ }
1003+ if (snprintf(pidpropval, sizeof(pidpropval), "%d", getpid()) >= PROPERTY_VALUE_MAX) {
1004+ goto abort;
1005+ }
1006+ property_set(pidpropname, pidpropval);
1007+#else
10041008 writepid(pid_fd, getpid());
1009+#endif
10051010 logger(LOG_INFO, PACKAGE " " VERSION " starting");
10061011 }
1007-#endif /* ANDROID */
1008-#ifndef MINIMAL
1012+
10091013 /* Terminate the encapsulated options */
10101014 if (options->vendor[0]) {
10111015 options->vendor[0]++;
1012- options->vendor[options->vendor[0]] = DHCP_END;
1016+ options->vendor[options->vendor[0]] = DHO_END;
10131017 }
1014-#endif
10151018
10161019 if (dhcp_run(options, &pid_fd) == 0)
10171020 retval = EXIT_SUCCESS;
@@ -1028,14 +1031,8 @@ abort:
10281031 free(options->environ[len++]);
10291032 free(options->environ);
10301033 }
1034+ free(options->blacklist);
10311035 free(options);
1032-
1033-#ifdef THERE_IS_NO_FORK
1034- /* There may have been an error before the dhcp_run function
1035- * clears this, so just do it here to be safe */
1036- free(dhcpcd_skiproutes);
1037-#endif
1038-
10391036 exit(retval);
10401037 /* NOTREACHED */
10411038 }
--- a/dhcpcd.conf.5
+++ b/dhcpcd.conf.5
@@ -22,7 +22,7 @@
2222 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2323 .\" SUCH DAMAGE.
2424 .\"
25-.Dd Jun 30, 2008
25+.Dd August 18, 2008
2626 .Dt DHCPCD.CONF 5 SMM
2727 .Sh NAME
2828 .Nm dhcpcd.conf
@@ -43,9 +43,10 @@ Blank lines and lines starting with # are ignored.
4343 .Pp
4444 Here's a list of available options:
4545 .Bl -tag -width indent
46-.It Ic classid Ar string
47-Change the default classid sent from dhcpcd-version.
48-If not set then none is sent.
46+.It Ic background
47+Background immediately.
48+This is useful for startup scripts which don't disable link messages for
49+carrier status.
4950 .It Ic clientid Ar string
5051 Change the default clientid sent from the interface hardware address.
5152 If the string is of the format 01:02:03 then it is encoded as hex.
@@ -71,10 +72,13 @@ if a FQDN (ie, contains a .) then it will be encoded as such.
7172 none disables FQDN encoding, ptr just asks the DHCP server to update the PTR
7273 record of the host in DNS whereas both also updates the A record.
7374 The current hostname or the hostname specified using the
74-.Fl h , -hostname
75+.Ic hostname
7576 option must be a FQDN.
7677 .Nm dhcpcd
7778 itself never does any DNS updates.
79+.Nm dhcpcd
80+encodes the FQDN hostname as specified in
81+.Li RFC1035 .
7882 .It Ic interface Ar interface
7983 Subsequent options are only parsed for this
8084 .Ar interface .
@@ -96,14 +100,25 @@ See
96100 .Rs
97101 .%T "RFC 3927"
98102 .Re
99-.It Ic option Ar dhcp-option
103+.It Ic nolink
104+Don't receive link messages about carrier status.
105+You should only set this for buggy interface drivers.
106+.It Ic option Ar option
100107 Requests the
101-.Ar dhcp-option
108+.Ar option
102109 from the server.
103110 It can be a variable to be used in
104111 .Xr dhcpcd-run-hooks 8
105112 or the numerical value.
106-You can specify more seperated by commas, spaces or more option lines.
113+You can specify more options seperated by commas, spaces or more option lines.
114+.It Ic require Ar option
115+Requires the
116+.Ar option
117+to be present in all DHCP messages, otherwise the message is ignored.
118+It can be a variable to be used in
119+.Xr dhcpcd-run-hooks 8
120+or the numerical value.
121+You can specify more options seperated by commas, spaces or more require lines.
107122 .It Ic script Ar script
108123 Use
109124 .Ar script
@@ -115,7 +130,7 @@ be too long or too short and can be changed here.
115130 .It Ic userclass Ar string
116131 Tag the DHCP messages with the userclass.
117132 You can specify more than one.
118-.It vendor Ar code , Ns Ar value
133+.It Ic vendor Ar code , Ns Ar value
119134 Add an enscapulated vendor option.
120135 .Ar code
121136 should be between 1 and 254 inclusive.
@@ -127,6 +142,9 @@ Set the vendor option 02 with a hex code.
127142 .D1 vendor 02,01:02:03:04:05
128143 Set the vendor option 03 with an IP address as a string.
129144 .D1 vendor 03,\e"192.168.0.2\e"
145+.It Ic vendorclassid Ar string
146+Change the default vendorclassid sent from dhcpcd-version.
147+If not set then none is sent.
130148 .El
131149 .Sh SEE ALSO
132150 .Xr dhcpcd-run-hooks 8 ,
--- a/dhcpcd.conf.5.in
+++ b/dhcpcd.conf.5.in
@@ -22,7 +22,7 @@
2222 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2323 .\" SUCH DAMAGE.
2424 .\"
25-.Dd Jun 30, 2008
25+.Dd August 18, 2008
2626 .Dt DHCPCD.CONF 5 SMM
2727 .Sh NAME
2828 .Nm dhcpcd.conf
@@ -43,9 +43,10 @@ Blank lines and lines starting with # are ignored.
4343 .Pp
4444 Here's a list of available options:
4545 .Bl -tag -width indent
46-.It Ic classid Ar string
47-Change the default classid sent from dhcpcd-version.
48-If not set then none is sent.
46+.It Ic background
47+Background immediately.
48+This is useful for startup scripts which don't disable link messages for
49+carrier status.
4950 .It Ic clientid Ar string
5051 Change the default clientid sent from the interface hardware address.
5152 If the string is of the format 01:02:03 then it is encoded as hex.
@@ -71,10 +72,13 @@ if a FQDN (ie, contains a .) then it will be encoded as such.
7172 none disables FQDN encoding, ptr just asks the DHCP server to update the PTR
7273 record of the host in DNS whereas both also updates the A record.
7374 The current hostname or the hostname specified using the
74-.Fl h , -hostname
75+.Ic hostname
7576 option must be a FQDN.
7677 .Nm dhcpcd
7778 itself never does any DNS updates.
79+.Nm dhcpcd
80+encodes the FQDN hostname as specified in
81+.Li RFC1035 .
7882 .It Ic interface Ar interface
7983 Subsequent options are only parsed for this
8084 .Ar interface .
@@ -96,14 +100,25 @@ See
96100 .Rs
97101 .%T "RFC 3927"
98102 .Re
99-.It Ic option Ar dhcp-option
103+.It Ic nolink
104+Don't receive link messages about carrier status.
105+You should only set this for buggy interface drivers.
106+.It Ic option Ar option
100107 Requests the
101-.Ar dhcp-option
108+.Ar option
102109 from the server.
103110 It can be a variable to be used in
104111 .Xr dhcpcd-run-hooks 8
105112 or the numerical value.
106-You can specify more seperated by commas, spaces or more option lines.
113+You can specify more options seperated by commas, spaces or more option lines.
114+.It Ic require Ar option
115+Requires the
116+.Ar option
117+to be present in all DHCP messages, otherwise the message is ignored.
118+It can be a variable to be used in
119+.Xr dhcpcd-run-hooks 8
120+or the numerical value.
121+You can specify more options seperated by commas, spaces or more require lines.
107122 .It Ic script Ar script
108123 Use
109124 .Ar script
@@ -115,7 +130,7 @@ be too long or too short and can be changed here.
115130 .It Ic userclass Ar string
116131 Tag the DHCP messages with the userclass.
117132 You can specify more than one.
118-.It vendor Ar code , Ns Ar value
133+.It Ic vendor Ar code , Ns Ar value
119134 Add an enscapulated vendor option.
120135 .Ar code
121136 should be between 1 and 254 inclusive.
@@ -127,6 +142,9 @@ Set the vendor option 02 with a hex code.
127142 .D1 vendor 02,01:02:03:04:05
128143 Set the vendor option 03 with an IP address as a string.
129144 .D1 vendor 03,\e"192.168.0.2\e"
145+.It Ic vendorclassid Ar string
146+Change the default vendorclassid sent from dhcpcd-version.
147+If not set then none is sent.
130148 .El
131149 .Sh SEE ALSO
132150 .Xr dhcpcd-run-hooks 8 ,
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -41,18 +41,12 @@
4141 #define DEFAULT_TIMEOUT 30
4242 #define DEFAULT_LEASETIME 3600 /* 1 hour */
4343
44-#define CLASSID_MAX_LEN 48
44+#define HOSTNAME_MAX_LEN 250 /* 255 - 3 (FQDN) - 2 (DNS enc) */
45+#define VENDORCLASSID_MAX_LEN 48
4546 #define CLIENTID_MAX_LEN 48
4647 #define USERCLASS_MAX_LEN 255
4748 #define VENDOR_MAX_LEN 255
4849
49-#ifdef THERE_IS_NO_FORK
50-extern char dhcpcd[PATH_MAX];
51-extern char **dhcpcd_argv;
52-extern int dhcpcd_argc;
53-extern char *dhcpcd_skiproutes;
54-#endif
55-
5650 #define DHCPCD_ARP (1 << 0)
5751 #define DHCPCD_DOMAIN (1 << 2)
5852 #define DHCPCD_GATEWAY (1 << 3)
@@ -68,11 +62,14 @@ extern char *dhcpcd_skiproutes;
6862 #define DHCPCD_FORKED (1 << 17)
6963 #define DHCPCD_HOSTNAME (1 << 18)
7064 #define DHCPCD_CLIENTID (1 << 19)
65+#define DHCPCD_LINK (1 << 20)
66+#define DHCPCD_BACKGROUND (1 << 21)
7167
7268 struct options {
7369 char interface[IF_NAMESIZE];
7470 int metric;
75- uint8_t reqmask[256 / 8];
71+ uint8_t requestmask[256 / 8];
72+ uint8_t requiremask[256 / 8];
7673 uint8_t nomask[256 / 8];
7774 uint32_t leasetime;
7875 time_t timeout;
@@ -85,14 +82,14 @@ struct options {
8582 char script[PATH_MAX];
8683 char pidfile[PATH_MAX];
8784
88-#ifndef MINIMAL
89- char hostname[MAXHOSTNAMELEN];
85+ char hostname[HOSTNAME_MAX_LEN + 1];
9086 int fqdn;
91- uint8_t classid[CLASSID_MAX_LEN + 1];
87+ uint8_t vendorclassid[VENDORCLASSID_MAX_LEN + 1];
9288 char clientid[CLIENTID_MAX_LEN + 1];
9389 uint8_t userclass[USERCLASS_MAX_LEN + 1];
9490 uint8_t vendor[VENDOR_MAX_LEN + 1];
95-#endif
96-};
9791
92+ size_t blacklist_len;
93+ in_addr_t *blacklist;
94+};
9895 #endif
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -185,3 +185,57 @@ if_route(const char *ifname, const struct in_addr *destination,
185185 close(s);
186186 return retval;
187187 }
188+
189+int
190+open_link_socket(struct interface *iface)
191+{
192+ int fd;
193+
194+ fd = socket(PF_ROUTE, SOCK_RAW, 0);
195+ if (fd == -1)
196+ return -1;
197+ set_cloexec(fd);
198+ if (iface->link_fd != -1)
199+ close(iface->link_fd);
200+ iface->link_fd = fd;
201+ return 0;
202+}
203+
204+#define BUFFER_LEN 2048
205+int
206+link_changed(struct interface *iface)
207+{
208+ char buffer[2048], *p;
209+ ssize_t bytes;
210+ struct rt_msghdr *rtm;
211+ struct if_msghdr *ifm;
212+ int i;
213+
214+ if ((i = if_nametoindex(iface->name)) == -1)
215+ return -1;
216+ for (;;) {
217+ bytes = recv(iface->link_fd, buffer, BUFFER_LEN, MSG_DONTWAIT);
218+ if (bytes == -1) {
219+ if (errno == EAGAIN)
220+ return 0;
221+ if (errno == EINTR)
222+ continue;
223+ return -1;
224+ }
225+ for (p = buffer; bytes > 0;
226+ bytes -= ((struct rt_msghdr *)p)->rtm_msglen,
227+ p += ((struct rt_msghdr *)p)->rtm_msglen)
228+ {
229+ rtm = (struct rt_msghdr *)p;
230+ if (rtm->rtm_type != RTM_IFINFO)
231+ continue;
232+ ifm = (struct if_msghdr *)p;
233+ if (ifm->ifm_index != i)
234+ continue;
235+
236+ /* Link changed */
237+ return 1;
238+ }
239+ }
240+ return 0;
241+}
--- a/if-linux.c
+++ b/if-linux.c
@@ -46,128 +46,178 @@
4646 #include <string.h>
4747 #include <unistd.h>
4848
49+/* Support older kernels */
50+#ifndef IFLA_WIRELESS
51+# define IFLA_WIRELSSS (IFLFA_MASTER + 1)
52+#endif
53+
4954 #include "config.h"
5055 #include "common.h"
5156 #include "dhcp.h"
5257 #include "net.h"
5358
54-/* This netlink stuff is overly compex IMO.
55- * The BSD implementation is much cleaner and a lot less code.
56- * send_netlink handles the actual transmission so we can work out
57- * if there was an error or not. */
5859 #define BUFFERLEN 256
59-static int
60-send_netlink(struct nlmsghdr *hdr)
60+
61+int
62+open_link_socket(struct interface *iface)
6163 {
62- int s;
63- pid_t mypid = getpid ();
64+ int fd;
6465 struct sockaddr_nl nl;
65- struct iovec iov;
66- struct msghdr msg;
67- static unsigned int seq;
68- char *buffer = NULL;
69- ssize_t bytes;
70- union
71- {
72- char *buffer;
73- struct nlmsghdr *nlm;
74- } h;
75- int len, l;
76- struct nlmsgerr *err;
7766
78- if ((s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
67+ if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
7968 return -1;
80-
8169 memset(&nl, 0, sizeof(nl));
8270 nl.nl_family = AF_NETLINK;
83- if (bind(s, (struct sockaddr *)&nl, sizeof(nl)) == -1)
84- goto eexit;
85-
86- memset(&iov, 0, sizeof(iov));
87- iov.iov_base = hdr;
88- iov.iov_len = hdr->nlmsg_len;
89-
90- memset(&msg, 0, sizeof(msg));
91- msg.msg_name = &nl;
92- msg.msg_namelen = sizeof(nl);
93- msg.msg_iov = &iov;
94- msg.msg_iovlen = 1;
95-
96- /* Request a reply */
97- hdr->nlmsg_flags |= NLM_F_ACK;
98- hdr->nlmsg_seq = ++seq;
71+ nl.nl_groups = RTMGRP_LINK;
72+ if (bind(fd, (struct sockaddr *)&nl, sizeof(nl)) == -1)
73+ return -1;
74+ set_cloexec(fd);
75+ if (iface->link_fd != -1)
76+ close(iface->link_fd);
77+ iface->link_fd = fd;
78+ return 0;
79+}
9980
100- if (sendmsg(s, &msg, 0) == -1)
101- goto eexit;
81+static int
82+get_netlink(int fd, int flags,
83+ int (*callback)(struct nlmsghdr *, const char *),
84+ const char *ifname)
85+{
86+ char *buffer = NULL;
87+ ssize_t bytes;
88+ struct nlmsghdr *nlm;
89+ int r = -1;
10290
10391 buffer = xzalloc(sizeof(char) * BUFFERLEN);
104- iov.iov_base = buffer;
105-
10692 for (;;) {
107- iov.iov_len = BUFFERLEN;
108- bytes = recvmsg(s, &msg, 0);
109-
93+ bytes = recv(fd, buffer, BUFFERLEN, flags);
11094 if (bytes == -1) {
95+ if (errno == EAGAIN) {
96+ r = 0;
97+ goto eexit;
98+ }
11199 if (errno == EINTR)
112100 continue;
113101 goto eexit;
114102 }
115-
116- if (bytes == 0) {
117- errno = ENODATA;
118- goto eexit;
103+ for (nlm = (struct nlmsghdr *)buffer;
104+ NLMSG_OK(nlm, (size_t)bytes);
105+ nlm = NLMSG_NEXT(nlm, bytes))
106+ {
107+ r = callback(nlm, ifname);
108+ if (r != 0)
109+ goto eexit;
119110 }
111+ }
120112
121- if (msg.msg_namelen != sizeof(nl)) {
122- errno = EBADMSG;
123- goto eexit;
124- }
113+eexit:
114+ free(buffer);
115+ return r;
116+}
125117
126- for (h.buffer = buffer; bytes >= (signed) sizeof(*h.nlm); ) {
127- len = h.nlm->nlmsg_len;
128- l = len - sizeof(*h.nlm);
129- err = (struct nlmsgerr *)NLMSG_DATA(h.nlm);
118+static int
119+err_netlink(struct nlmsghdr *nlm, _unused const char *ifname)
120+{
121+ struct nlmsgerr *err;
122+ int l;
130123
131- if (l < 0 || len > bytes) {
132- errno = EBADMSG;
133- goto eexit;
134- }
124+ if (nlm->nlmsg_type != NLMSG_ERROR)
125+ return 0;
126+ l = nlm->nlmsg_len - sizeof(*nlm);
127+ if ((size_t)l < sizeof(*err)) {
128+ errno = EBADMSG;
129+ return -1;
130+ }
131+ err = (struct nlmsgerr *)NLMSG_DATA(nlm);
132+ if (err->error == 0)
133+ return l;
134+ errno = -err->error;
135+ return -1;
136+}
135137
136- /* Ensure it's our message */
137- if (nl.nl_pid != 0 ||
138- (pid_t)h.nlm->nlmsg_pid != mypid ||
139- h.nlm->nlmsg_seq != seq)
140- {
141- /* Next Message */
142- bytes -= NLMSG_ALIGN(len);
143- h.buffer += NLMSG_ALIGN(len);
144- continue;
145- }
138+static int
139+link_netlink(struct nlmsghdr *nlm, const char *ifname)
140+{
141+ int len;
142+ struct rtattr *rta;
143+ struct ifinfomsg *ifi;
144+ char ifn[IF_NAMESIZE + 1];
145+
146+ if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK)
147+ return 0;
148+ len = nlm->nlmsg_len - sizeof(*nlm);
149+ if ((size_t)len < sizeof(*ifi)) {
150+ errno = EBADMSG;
151+ return -1;
152+ }
153+ ifi = NLMSG_DATA(nlm);
154+ if (ifi->ifi_flags & IFF_LOOPBACK)
155+ return 0;
156+ rta = (struct rtattr *) ((char *)ifi + NLMSG_ALIGN(sizeof(*ifi)));
157+ len = NLMSG_PAYLOAD(nlm, sizeof(*ifi));
158+ *ifn = '\0';
159+ while (RTA_OK(rta, len)) {
160+ switch (rta->rta_type) {
161+ case IFLA_WIRELESS:
162+ /* Ignore wireless messages */
163+ if (nlm->nlmsg_type == RTM_NEWLINK &&
164+ ifi->ifi_change == 0)
165+ return 0;
166+ break;
167+ case IFLA_IFNAME:
168+ strlcpy(ifn, RTA_DATA(rta), sizeof(ifn));
169+ break;
170+ }
171+ rta = RTA_NEXT(rta, len);
172+ }
146173
147- /* We get an NLMSG_ERROR back with a code of zero for success */
148- if (h.nlm->nlmsg_type != NLMSG_ERROR)
149- continue;
174+ if (strncmp(ifname, ifn, sizeof(ifn)) == 0)
175+ return 1;
176+ return 0;
177+}
150178
151- if ((unsigned)l < sizeof(*err)) {
152- errno = EBADMSG;
153- goto eexit;
154- }
179+int
180+link_changed(struct interface *iface)
181+{
182+ return get_netlink(iface->link_fd, MSG_DONTWAIT,
183+ &link_netlink, iface->name);
184+}
155185
156- if (err->error == 0) {
157- close(s);
158- free(buffer);
159- return l;
160- }
186+static int
187+send_netlink(struct nlmsghdr *hdr)
188+{
189+ int fd, r;
190+ struct sockaddr_nl nl;
191+ struct iovec iov;
192+ struct msghdr msg;
193+ static unsigned int seq;
161194
162- errno = -err->error;
163- goto eexit;
164- }
195+ if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
196+ return -1;
197+ memset(&nl, 0, sizeof(nl));
198+ nl.nl_family = AF_NETLINK;
199+ if (bind(fd, (struct sockaddr *)&nl, sizeof(nl)) == -1) {
200+ close(fd);
201+ return -1;
165202 }
203+ memset(&iov, 0, sizeof(iov));
204+ iov.iov_base = hdr;
205+ iov.iov_len = hdr->nlmsg_len;
206+ memset(&msg, 0, sizeof(msg));
207+ msg.msg_name = &nl;
208+ msg.msg_namelen = sizeof(nl);
209+ msg.msg_iov = &iov;
210+ msg.msg_iovlen = 1;
211+ /* Request a reply */
212+ hdr->nlmsg_flags |= NLM_F_ACK;
213+ hdr->nlmsg_seq = ++seq;
166214
167-eexit:
168- close(s);
169- free(buffer);
170- return -1;
215+ if (sendmsg(fd, &msg, 0) != -1)
216+ r = get_netlink(fd, 0, &err_netlink, NULL);
217+ else
218+ r = -1;
219+ close(fd);
220+ return r;
171221 }
172222
173223 #define NLMSG_TAIL(nmsg) \
@@ -285,15 +335,16 @@ if_route(const char *ifname,
285335 nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
286336 nlm->hdr.nlmsg_type = RTM_NEWROUTE;
287337 if (action == 0)
288- nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
338+ nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
289339 else if (action > 0)
290340 /*
291- * commented out NLM_F_EXCL here and
292- * below. We sometimes keep one interface up while
293- * we are configuring the other one, and this flag
341+ * ers@google:
342+ * commented out NLM_F_EXCL here and below. We
343+ * sometimes keep one interface up while we are
344+ * configuring the other one, and this flag
294345 * causes route addition to fail.
295346 */
296- nlm->hdr.nlmsg_flags = NLM_F_CREATE /* | NLM_F_EXCL*/;
347+ nlm->hdr.nlmsg_flags = NLM_F_CREATE /* | NLM_F_EXCL */;
297348 else
298349 nlm->hdr.nlmsg_type = RTM_DELROUTE;
299350 nlm->hdr.nlmsg_flags |= NLM_F_REQUEST;
--- a/logger.c
+++ b/logger.c
@@ -38,31 +38,6 @@
3838 static int loglevel = LOG_INFO;
3939 static char logprefix[12] = {0};
4040
41-struct logname {
42- int level;
43- const char *name;
44-};
45-static const struct logname const lognames[] = {
46- { LOG_DEBUG, "debug" },
47- { LOG_INFO, "info" },
48- { LOG_WARNING, "warning" },
49- { LOG_ERR, "error" },
50- { -1, NULL }
51-};
52-
53-int
54-logtolevel(const char *priority)
55-{
56- const struct logname *lt;
57-
58- if (isdigit((unsigned char)*priority))
59- return atoi(priority);
60- for (lt = lognames; lt->name; lt++)
61- if (!strcasecmp(priority, lt->name))
62- return lt->level;
63- return -1;
64-}
65-
6641 void
6742 setloglevel(int level)
6843 {
@@ -90,10 +65,6 @@ logger(int level, const char *fmt, ...)
9065 fprintf(f, "%s", logprefix);
9166 vfprintf(f, fmt, p);
9267 fputc('\n', f);
93-
94- /* stdout, stderr may be re-directed to some kind of buffer.
95- * So we always flush to ensure it's written. */
96- fflush(f);
9768 }
9869
9970 if (level < LOG_DEBUG || level <= loglevel) {
--- a/logger.h
+++ b/logger.h
@@ -36,7 +36,6 @@
3636
3737 #include <syslog.h>
3838
39-int logtolevel(const char *);
4039 void setloglevel(int);
4140 void setlogprefix(const char *);
4241 void logger(int, const char *, ...) _PRINTF_LIKE (2, 3);
--- a/lpf.c
+++ b/lpf.c
@@ -89,13 +89,10 @@ open_socket(struct interface *iface, int protocol)
8989 }
9090 /* Install the DHCP filter */
9191 memset(&pf, 0, sizeof(pf));
92-#ifdef ENABLE_ARP
9392 if (protocol == ETHERTYPE_ARP) {
9493 pf.filter = UNCONST(arp_bpf_filter);
9594 pf.len = arp_bpf_filter_len;
96- } else
97-#endif
98- {
95+ } else {
9996 pf.filter = UNCONST(dhcp_bpf_filter);
10097 pf.len = dhcp_bpf_filter_len;
10198 }
@@ -107,12 +104,10 @@ open_socket(struct interface *iface, int protocol)
107104 goto eexit;
108105 if (bind(s, &su.sa, sizeof(su)) == -1)
109106 goto eexit;
110-#ifdef ENABLE_ARP
111107 if (protocol == ETHERTYPE_ARP)
112108 fd = &iface->arp_fd;
113109 else
114-#endif
115- fd = &iface->fd;
110+ fd = &iface->raw_fd;
116111 if (*fd != -1)
117112 close(*fd);
118113 *fd = s;
@@ -148,12 +143,10 @@ send_raw_packet(const struct interface *iface, int protocol,
148143 &ipv4_bcast_addr, sizeof(ipv4_bcast_addr));
149144 else
150145 memset(&su.sll.sll_addr, 0xff, iface->hwlen);
151-#ifdef ENABLE_ARP
152146 if (protocol == ETHERTYPE_ARP)
153147 fd = iface->arp_fd;
154148 else
155-#endif
156- fd = iface->fd;
149+ fd = iface->raw_fd;
157150
158151 return sendto(fd, data, len, 0, &su.sa, sizeof(su));
159152 }
@@ -164,12 +157,10 @@ get_raw_packet(struct interface *iface, int protocol, void *data, ssize_t len)
164157 ssize_t bytes;
165158 int fd = -1;
166159
167- if (protocol == ETHERTYPE_ARP) {
168-#ifdef ENABLE_ARP
160+ if (protocol == ETHERTYPE_ARP)
169161 fd = iface->arp_fd;
170-#endif
171- } else
172- fd = iface->fd;
162+ else
163+ fd = iface->raw_fd;
173164 bytes = read(fd, data, len);
174165 if (bytes == -1)
175166 return errno == EAGAIN ? 0 : -1;
--- /dev/null
+++ b/mk/os-Darwin.mk
@@ -0,0 +1,5 @@
1+# Setup OS specific variables
2+# Copyright 2008 Roy Marples <roy@marples.name>
3+
4+include ${MK}/os-BSD.mk
5+LINK_RPATH= --rpath
--- a/mk/os-Linux.mk
+++ b/mk/os-Linux.mk
@@ -6,23 +6,3 @@ SRC_IF= if-linux.c
66
77 CPPFLAGS+= -D_BSD_SOURCE -D_XOPEN_SOURCE=600
88 LIBRT= -lrt
9-
10-# Work out if our fork() works or not.
11-# If cross-compiling, you'll need to set HAVE_FORK to yes or no depending
12-# on your target arch.
13-_HAVE_FORK_SH= if test "${HAVE_FORK}" = "yes"; then \
14- echo ""; \
15- elif test -n "${HAVE_FORK}"; then \
16- echo "-DTHERE_IS_NO_FORK"; \
17- else \
18- printf '\#include <stdlib.h>\n\#include <unistd.h>\nint main (void) { pid_t pid = fork(); if (pid == -1) exit (-1); exit (0); }\n' > .fork.c; \
19- ${CC} .fork.c -o .fork >/dev/null 2>&1; \
20- if ./.fork; then \
21- echo ""; \
22- else \
23- echo "-DTHERE_IS_NO_FORK"; \
24- fi; \
25- rm -f .fork.c .fork; \
26- fi;
27-_HAVE_FORK!= ${_HAVE_FORK_SH}
28-CPPFLAGS+= ${_HAVE_FORK}$(shell ${_HAVE_FORK_SH})
--- a/mk/os.mk
+++ b/mk/os.mk
@@ -1,7 +1,7 @@
11 # Setup OS specific variables
22 # Copyright 2008 Roy Marples <roy@marples.name>
33
4-_OS_SH= case `uname -s` in Linux) echo "Linux";; *) echo "BSD";; esac
4+_OS_SH= case `uname -s` in Linux) echo "Linux";; Darwin) echo "Darwin";; *) echo "BSD";; esac
55 _OS!= ${_OS_SH}
66 OS= ${_OS}$(shell ${_OS_SH})
77 include ${MK}/os-${OS}.mk
--- a/mk/prog.mk
+++ b/mk/prog.mk
@@ -7,18 +7,19 @@ include ${MK}/cc.mk
77
88 OBJS+= ${SRCS:.c=.o}
99
10-# This is for NetBSD which has a different libc in /lib which we need
11-# to link to if installing in /
10+# If building for /, ensure we use the libc in / if different from
11+# the default one in /usr/lib
12+LINK_RPATH?= -Wl,-rpath
1213 _RPATH_SH= if test "${PREFIX}" = "" -o "${PREIX}" = "/"; then \
13- echo "-Wl,-rpath=${PREFIX}/${LIBNAME}"; \
14+ echo "${LINK_RPATH}=${PREFIX}/${LIBNAME}"; \
1415 else \
1516 echo ""; \
1617 fi
1718 _RPATH!= ${_RPATH_SH}
1819 LDFLAGS+= ${_RPATH}$(shell ${_RPATH_SH})
1920
20-# This is for NetBSD which has different dynamic linker in /lib which we need
21-# to use to if installing in /
21+# If building for /, ensure we use the linker in /libexec if different from
22+# the default one in /usr/libexec
2223 _DYNLINK_SH= if test "${PREFIX}" = "" -o "${PREFIX}" = "/" && test -e /libexec/ld.elf_so; then \
2324 echo "-Wl,-dynamic-linker=/libexec/ld.elf_so"; \
2425 else \
--- a/net.c
+++ b/net.c
@@ -43,6 +43,9 @@
4343 #define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */
4444 #include <netinet/udp.h>
4545 #undef __FAVOR_BSD
46+#ifdef SIOCGIFMEDIA
47+#include <net/if_media.h>
48+#endif
4649 #include <arpa/inet.h>
4750 #ifdef AF_LINK
4851 # include <net/if_dl.h>
@@ -50,7 +53,6 @@
5053
5154 #include <ctype.h>
5255 #include <errno.h>
53-#include <poll.h>
5456 #include <stddef.h>
5557 #include <stdio.h>
5658 #include <stdlib.h>
@@ -79,7 +81,7 @@ inet_ntocidr(struct in_addr address)
7981 }
8082
8183 int
82-inet_cidrtoaddr (int cidr, struct in_addr *addr)
84+inet_cidrtoaddr(int cidr, struct in_addr *addr)
8385 {
8486 int ocets;
8587
@@ -181,7 +183,7 @@ do_interface(const char *ifname,
181183 {
182184 int s;
183185 struct ifconf ifc;
184- int retval = 0;
186+ int retval = 0, found = 0;
185187 int len = 10 * sizeof(struct ifreq);
186188 int lastlen = 0;
187189 char *p;
@@ -192,9 +194,8 @@ do_interface(const char *ifname,
192194 struct sockaddr_in address;
193195 struct ifreq *ifr;
194196 struct sockaddr_in netmask;
195-
196197 #ifdef AF_LINK
197- struct sockaddr_dl sdl;
198+ struct sockaddr_dl *sdl;
198199 #endif
199200
200201 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
@@ -239,12 +240,15 @@ do_interface(const char *ifname,
239240 if (strcmp(ifname, ifr->ifr_name) != 0)
240241 continue;
241242
243+ found = 1;
244+
242245 #ifdef AF_LINK
243246 if (hwaddr && hwlen && ifr->ifr_addr.sa_family == AF_LINK) {
244- memcpy(&sdl, &ifr->ifr_addr, sizeof(sdl));
245- *hwlen = sdl.sdl_alen;
246- memcpy(hwaddr, sdl.sdl_data + sdl.sdl_nlen,
247- (size_t)sdl.sdl_alen);
247+ sdl = xmalloc(ifr->ifr_addr.sa_len);
248+ memcpy(sdl, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
249+ *hwlen = sdl->sdl_alen;
250+ memcpy(hwaddr, LLADDR(sdl), *hwlen);
251+ free(sdl);
248252 retval = 1;
249253 break;
250254 }
@@ -273,11 +277,90 @@ do_interface(const char *ifname,
273277
274278 }
275279
280+ if (!found)
281+ errno = ENXIO;
276282 close(s);
277283 free(ifc.ifc_buf);
278284 return retval;
279285 }
280286
287+int
288+up_interface(const char *ifname)
289+{
290+ int s;
291+ struct ifreq ifr;
292+ int retval = -1;
293+#ifdef __linux__
294+ char *p;
295+#endif
296+
297+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
298+ return -1;
299+ memset(&ifr, 0, sizeof(ifr));
300+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
301+#ifdef __linux__
302+ /* We can only bring the real interface up */
303+ if ((p = strchr(ifr.ifr_name, ':')))
304+ *p = '\0';
305+#endif
306+ if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0) {
307+ if ((ifr.ifr_flags & IFF_UP))
308+ retval = 0;
309+ else {
310+ ifr.ifr_flags |= IFF_UP;
311+ if (ioctl(s, SIOCSIFFLAGS, &ifr) == 0)
312+ retval = 0;
313+ }
314+ }
315+ close(s);
316+ return retval;
317+}
318+
319+int
320+carrier_status(const char *ifname)
321+{
322+ int s;
323+ struct ifreq ifr;
324+ int retval = -1;
325+#ifdef SIOCGIFMEDIA
326+ struct ifmediareq ifmr;
327+#endif
328+#ifdef __linux__
329+ char *p;
330+#endif
331+
332+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
333+ return -1;
334+ memset(&ifr, 0, sizeof(ifr));
335+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
336+#ifdef __linux__
337+ /* We can only test the real interface up */
338+ if ((p = strchr(ifr.ifr_name, ':')))
339+ *p = '\0';
340+#endif
341+ if ((retval = ioctl(s, SIOCGIFFLAGS, &ifr)) == 0) {
342+ if (ifr.ifr_flags & IFF_UP && ifr.ifr_flags & IFF_RUNNING)
343+ retval = 1;
344+ else
345+ retval = 0;
346+ }
347+
348+#ifdef SIOCGIFMEDIA
349+ if (retval == 1) {
350+ memset(&ifmr, 0, sizeof(ifmr));
351+ strncpy(ifmr.ifm_name, ifr.ifr_name, sizeof(ifmr.ifm_name));
352+ if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1 &&
353+ ifmr.ifm_status & IFM_AVALID)
354+ {
355+ if (!(ifmr.ifm_status & IFM_ACTIVE))
356+ retval = 0;
357+ }
358+ }
359+#endif
360+ close(s);
361+ return retval;
362+}
363+
281364 struct interface *
282365 read_interface(const char *ifname, _unused int metric)
283366 {
@@ -287,9 +370,6 @@ read_interface(const char *ifname, _unused int metric)
287370 unsigned char *hwaddr = NULL;
288371 size_t hwlen = 0;
289372 sa_family_t family = 0;
290-#ifdef __linux__
291- char *p;
292-#endif
293373
294374 memset(&ifr, 0, sizeof(ifr));
295375 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
@@ -342,20 +422,8 @@ read_interface(const char *ifname, _unused int metric)
342422 goto eexit;
343423 }
344424
345- /* Bring the interface up if it's down */
346- strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
347-#ifdef __linux__
348- /* We can only bring the real interface up */
349- if ((p = strchr(ifr.ifr_name, ':')))
350- *p = '\0';
351-#endif
352- if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1)
425+ if (up_interface(ifname) != 0)
353426 goto eexit;
354- if (!(ifr.ifr_flags & IFF_UP)) {
355- ifr.ifr_flags |= IFF_UP;
356- if (ioctl(s, SIOCSIFFLAGS, &ifr) != 0)
357- goto eexit;
358- }
359427
360428 iface = xzalloc(sizeof(*iface));
361429 strlcpy(iface->name, ifname, IF_NAMESIZE);
@@ -367,11 +435,10 @@ read_interface(const char *ifname, _unused int metric)
367435 iface->arpable = !(ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK));
368436
369437 /* 0 is a valid fd, so init to -1 */
370- iface->fd = -1;
438+ iface->raw_fd = -1;
371439 iface->udp_fd = -1;
372-#ifdef ENABLE_ARP
373440 iface->arp_fd = -1;
374-#endif
441+ iface->link_fd = -1;
375442
376443 eexit:
377444 close(s);
@@ -419,21 +486,32 @@ open_udp_socket(struct interface *iface)
419486 struct sockaddr sa;
420487 struct sockaddr_in sin;
421488 } su;
422- int n = 1;
489+ int n;
490+#ifdef SO_BINDTODEVICE
491+ struct ifreq ifr;
492+#endif
423493
424494 if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
425495 return -1;
426496
427- memset(&su, 0, sizeof(su));
428- su.sin.sin_family = AF_INET;
429- su.sin.sin_port = htons(DHCP_CLIENT_PORT);
430- su.sin.sin_addr.s_addr = iface->addr.s_addr;
497+ n = 1;
431498 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
432499 goto eexit;
433- /* As we don't actually use this socket for anything, set
434- * the receiver buffer to 1 */
500+#ifdef SO_BINDTODEVICE
501+ memset(&ifr, 0, sizeof(ifr));
502+ strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
503+ if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
504+ goto eexit;
505+#endif
506+ /* As we don't use this socket for receiving, set the
507+ * receive buffer to 1 */
508+ n = 1;
435509 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)
436510 goto eexit;
511+ memset(&su, 0, sizeof(su));
512+ su.sin.sin_family = AF_INET;
513+ su.sin.sin_port = htons(DHCP_CLIENT_PORT);
514+ su.sin.sin_addr.s_addr = iface->addr.s_addr;
437515 if (bind(s, &su.sa, sizeof(su)) == -1)
438516 goto eexit;
439517
@@ -596,38 +674,34 @@ valid_udp_packet(const uint8_t *data)
596674 return retval;
597675 }
598676
599-#ifdef ENABLE_ARP
600677 int
601678 send_arp(const struct interface *iface, int op, in_addr_t sip, in_addr_t tip)
602679 {
603680 struct arphdr *arp;
604681 size_t arpsize;
605- unsigned char *p;
682+ uint8_t *p;
606683 int retval;
607684
608- arpsize = sizeof(*arp) + 2 * iface->hwlen + 2 *sizeof(sip);
609-
685+ arpsize = sizeof(*arp) + 2 * iface->hwlen + 2 * sizeof(sip);
610686 arp = xmalloc(arpsize);
611687 arp->ar_hrd = htons(iface->family);
612688 arp->ar_pro = htons(ETHERTYPE_IP);
613689 arp->ar_hln = iface->hwlen;
614690 arp->ar_pln = sizeof(sip);
615691 arp->ar_op = htons(op);
616- p = (unsigned char *)arp;
692+ p = (uint8_t *)arp;
617693 p += sizeof(*arp);
618694 memcpy(p, iface->hwaddr, iface->hwlen);
619695 p += iface->hwlen;
620696 memcpy(p, &sip, sizeof(sip));
621697 p += sizeof(sip);
622- /* ARP requests should ignore this, but we fill with 0xff
623- * for broadcast. */
624- memset(p, 0xff, iface->hwlen);
625- p += iface->hwlen;
698+ /* ARP requests should ignore this */
699+ retval = iface->hwlen;
700+ while (retval--)
701+ *p++ = '\0';
626702 memcpy(p, &tip, sizeof(tip));
627-
703+ p += sizeof(tip);
628704 retval = send_raw_packet(iface, ETHERTYPE_ARP, arp, arpsize);
629705 free(arp);
630706 return retval;
631707 }
632-#endif
633-
--- a/net.h
+++ b/net.h
@@ -71,8 +71,8 @@
7171 #endif
7272
7373 #define LINKLOCAL_ADDR 0xa9fe0000
74-#define LINKLOCAL_MASK 0xffff0000
75-#define LINKLOCAL_BRDC 0xa9feffff
74+#define LINKLOCAL_MASK IN_CLASSB_NET
75+#define LINKLOCAL_BRDC (LINKLOCAL_ADDR | ~LINKLOCAL_MASK)
7676
7777 #ifndef IN_LINKLOCAL
7878 # define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR)
@@ -101,13 +101,12 @@ struct interface
101101 size_t hwlen;
102102 int arpable;
103103
104- int fd;
104+ int raw_fd;
105105 int udp_fd;
106+ int arp_fd;
107+ int link_fd;
106108 size_t buffer_size, buffer_len, buffer_pos;
107109 unsigned char *buffer;
108-#ifdef ENABLE_ARP
109- int arp_fd;
110-#endif
111110
112111 struct in_addr addr;
113112 struct in_addr net;
@@ -131,6 +130,7 @@ int do_mtu(const char *, short int);
131130 int inet_ntocidr(struct in_addr);
132131 int inet_cidrtoaddr(int, struct in_addr *);
133132
133+int up_interface(const char *);
134134 int do_interface(const char *, unsigned char *, size_t *,
135135 struct in_addr *, struct in_addr *, int);
136136 int if_address(const char *, const struct in_addr *, const struct in_addr *,
@@ -148,6 +148,8 @@ int if_route(const char *, const struct in_addr *, const struct in_addr *,
148148 const struct in_addr *, int, int);
149149 #define add_route(ifname, dest, mask, gate, metric) \
150150 if_route(ifname, dest, mask, gate, metric, 1)
151+#define change_route(ifname, dest, mask, gate, metric) \
152+ if_route(ifname, dest, mask, gate, metric, 0)
151153 #define del_route(ifname, dest, mask, gate, metric) \
152154 if_route(ifname, dest, mask, gate, metric, -1)
153155 void free_routes(struct rt *);
@@ -166,7 +168,9 @@ ssize_t send_raw_packet(const struct interface *, int,
166168 const void *, ssize_t);
167169 ssize_t get_raw_packet(struct interface *, int, void *, ssize_t);
168170
169-#ifdef ENABLE_ARP
170171 int send_arp(const struct interface *, int, in_addr_t, in_addr_t);
171-#endif
172+
173+int open_link_socket(struct interface *);
174+int link_changed(struct interface *);
175+int carrier_status(const char *);
172176 #endif
--- /dev/null
+++ b/showlease.c
@@ -0,0 +1,349 @@
1+#include <stdio.h>
2+#include <stdlib.h>
3+#include <errno.h>
4+#include <fcntl.h>
5+
6+#include "dhcp.h"
7+#include "config.h"
8+
9+#define REQUEST (1 << 0)
10+#define UINT8 (1 << 1)
11+#define UINT16 (1 << 2)
12+#define SINT16 (1 << 3)
13+#define UINT32 (1 << 4)
14+#define SINT32 (1 << 5)
15+#define IPV4 (1 << 6)
16+#define STRING (1 << 7)
17+#define PAIR (1 << 8)
18+#define ARRAY (1 << 9)
19+#define RFC3361 (1 << 10)
20+#define RFC3397 (1 << 11)
21+#define RFC3442 (1 << 12)
22+
23+struct dhcp_opt {
24+ uint8_t option;
25+ int type;
26+ const char *var;
27+};
28+
29+static const struct dhcp_opt const dhcp_opts[] = {
30+ { 1, IPV4 | REQUEST, "subnet_mask" },
31+ { 2, UINT32, "time_offset" },
32+ { 3, IPV4 | ARRAY | REQUEST, "routers" },
33+ { 4, IPV4 | ARRAY, "time_servers" },
34+ { 5, IPV4 | ARRAY, "ien116_name_servers" },
35+ { 6, IPV4 | ARRAY, "domain_name_servers" },
36+ { 7, IPV4 | ARRAY, "log_servers" },
37+ { 8, IPV4 | ARRAY, "cookie_servers" },
38+ { 9, IPV4 | ARRAY, "lpr_servers" },
39+ { 10, IPV4 | ARRAY, "impress_servers" },
40+ { 11, IPV4 | ARRAY, "resource_location_servers" },
41+ { 12, STRING, "host_name" },
42+ { 13, UINT16, "boot_size" },
43+ { 14, STRING, "merit_dump" },
44+ { 15, STRING, "domain_name" },
45+ { 16, IPV4, "swap_server" },
46+ { 17, STRING, "root_path" },
47+ { 18, STRING, "extensions_path" },
48+ { 19, UINT8, "ip_forwarding" },
49+ { 20, UINT8, "non_local_source_routing" },
50+ { 21, IPV4 | ARRAY, "policy_filter" },
51+ { 22, SINT16, "max_dgram_reassembly" },
52+ { 23, UINT16, "default_ip_ttl" },
53+ { 24, UINT32, "path_mtu_aging_timeout" },
54+ { 25, UINT16 | ARRAY, "path_mtu_plateau_table" },
55+ { 26, UINT16, "interface_mtu" },
56+ { 27, UINT8, "all_subnets_local" },
57+ { 28, IPV4 | REQUEST, "broadcast_address" },
58+ { 29, UINT8, "perform_mask_discovery" },
59+ { 30, UINT8, "mask_supplier" },
60+ { 31, UINT8, "router_discovery" },
61+ { 32, IPV4, "router_solicitation_address" },
62+ { 33, IPV4 | ARRAY | REQUEST, "static_routes" },
63+ { 34, UINT8, "trailer_encapsulation" },
64+ { 35, UINT32, "arp_cache_timeout" },
65+ { 36, UINT16, "ieee802_3_encapsulation" },
66+ { 37, UINT8, "default_tcp_ttl" },
67+ { 38, UINT32, "tcp_keepalive_interval" },
68+ { 39, UINT8, "tcp_keepalive_garbage" },
69+ { 40, STRING, "nis_domain" },
70+ { 41, IPV4 | ARRAY, "nis_servers" },
71+ { 42, IPV4 | ARRAY, "ntp_servers" },
72+ { 43, STRING, "vendor_encapsulated_options" },
73+ { 44, IPV4 | ARRAY, "netbios_name_servers" },
74+ { 45, IPV4, "netbios_dd_server" },
75+ { 46, UINT8, "netbios_node_type" },
76+ { 47, STRING, "netbios_scope" },
77+ { 48, IPV4 | ARRAY, "font_servers" },
78+ { 49, IPV4 | ARRAY, "x_display_manager" },
79+ { 50, IPV4, "dhcp_requested_address" },
80+ { 51, UINT32 | REQUEST, "dhcp_lease_time" },
81+ { 52, UINT8, "dhcp_option_overload" },
82+ { 53, UINT8, "dhcp_message_type" },
83+ { 54, IPV4, "dhcp_server_identifier" },
84+ { 55, UINT8 | ARRAY, "dhcp_parameter_request_list" },
85+ { 56, STRING, "dhcp_message" },
86+ { 57, UINT16, "dhcp_max_message_size" },
87+ { 58, UINT32 | REQUEST, "dhcp_renewal_time" },
88+ { 59, UINT32 | REQUEST, "dhcp_rebinding_time" },
89+ { 64, STRING, "nisplus_domain" },
90+ { 65, IPV4 | ARRAY, "nisplus_servers" },
91+ { 66, STRING, "tftp_server_name" },
92+ { 67, STRING, "bootfile_name" },
93+ { 68, IPV4 | ARRAY, "mobile_ip_home_agent" },
94+ { 69, IPV4 | ARRAY, "smtp_server" },
95+ { 70, IPV4 | ARRAY, "pop_server" },
96+ { 71, IPV4 | ARRAY, "nntp_server" },
97+ { 72, IPV4 | ARRAY, "www_server" },
98+ { 73, IPV4 | ARRAY, "finger_server" },
99+ { 74, IPV4 | ARRAY, "irc_server" },
100+ { 75, IPV4 | ARRAY, "streettalk_server" },
101+ { 76, IPV4 | ARRAY, "streettalk_directory_assistance_server" },
102+ { 77, STRING, "user_class" },
103+ { 85, IPV4 | ARRAY, "nds_servers" },
104+ { 86, STRING, "nds_tree_name" },
105+ { 87, STRING, "nds_context" },
106+ { 88, STRING | RFC3397, "bcms_controller_names" },
107+ { 89, IPV4 | ARRAY, "bcms_controller_address" },
108+ { 91, UINT32, "client_last_transaction_time" },
109+ { 92, IPV4 | ARRAY, "associated_ip" },
110+ { 98, STRING, "uap_servers" },
111+ { 112, IPV4 | ARRAY, "netinfo_server_address" },
112+ { 113, STRING, "netinfo_server_tag" },
113+ { 114, STRING, "default_url" },
114+ { 118, IPV4, "subnet_selection" },
115+ { 119, STRING | RFC3397, "domain_search" },
116+ { 121, RFC3442 | REQUEST, "classless_static_routes" },
117+ { 249, RFC3442, "ms-classless_static_routes" },
118+ { 0, 0, NULL }
119+};
120+
121+struct dhcp_message *
122+get_lease(const char *leasefile)
123+{
124+ int fd;
125+ struct dhcp_message *dhcp;
126+ ssize_t bytes;
127+
128+ fd = open(leasefile, O_RDONLY);
129+ if (fd == -1)
130+ return NULL;
131+ dhcp = malloc(sizeof(*dhcp));
132+ memset(dhcp, 0, sizeof(*dhcp));
133+ bytes = read(fd, dhcp, sizeof(*dhcp));
134+ close(fd);
135+ if (bytes < 0) {
136+ free(dhcp);
137+ dhcp = NULL;
138+ }
139+ return dhcp;
140+}
141+
142+static uint8_t *dhcp_opt_buffer = NULL;
143+
144+static int
145+valid_length(uint8_t option, int dl, int *type)
146+{
147+ const struct dhcp_opt *opt;
148+ ssize_t sz;
149+
150+ if (dl == 0)
151+ return -1;
152+
153+ for (opt = dhcp_opts; opt->option; opt++) {
154+ if (opt->option != option)
155+ continue;
156+
157+ if (type)
158+ *type = opt->type;
159+
160+ if (opt->type == 0 || opt->type & STRING || opt->type & RFC3442)
161+ return 0;
162+
163+ sz = 0;
164+ if (opt->type & UINT32 || opt->type & IPV4)
165+ sz = sizeof(uint32_t);
166+ if (opt->type & UINT16)
167+ sz = sizeof(uint16_t);
168+ if (opt->type & UINT8)
169+ sz = sizeof(uint8_t);
170+ if (opt->type & IPV4 || opt->type & ARRAY)
171+ return dl % sz;
172+ return (dl == sz ? 0 : -1);
173+ }
174+
175+ /* unknown option, so let it pass */
176+ return 0;
177+}
178+
179+static void
180+free_option_buffer(void)
181+{
182+ free(dhcp_opt_buffer);
183+}
184+
185+
186+#define get_option_raw(dhcp, opt) get_option(dhcp, opt, NULL, NULL)
187+static const uint8_t *
188+get_option(const struct dhcp_message *dhcp, uint8_t opt, int *len, int *type)
189+{
190+ const uint8_t *p = dhcp->options;
191+ const uint8_t *e = p + sizeof(dhcp->options);
192+ uint8_t l, ol = 0;
193+ uint8_t o = 0;
194+ uint8_t overl = 0;
195+ uint8_t *bp = NULL;
196+ const uint8_t *op = NULL;
197+ int bl = 0;
198+
199+ while (p < e) {
200+ o = *p++;
201+ if (o == opt) {
202+ if (op) {
203+ if (!dhcp_opt_buffer) {
204+ dhcp_opt_buffer = malloc(sizeof(struct dhcp_message));
205+ atexit(free_option_buffer);
206+ }
207+ if (!bp)
208+ bp = dhcp_opt_buffer;
209+ memcpy(bp, op, ol);
210+ bp += ol;
211+ }
212+ ol = *p;
213+ op = p + 1;
214+ bl += ol;
215+ }
216+ switch (o) {
217+ case DHO_PAD:
218+ continue;
219+ case DHO_END:
220+ if (overl & 1) {
221+ /* bit 1 set means parse boot file */
222+ overl &= ~1;
223+ p = dhcp->bootfile;
224+ e = p + sizeof(dhcp->bootfile);
225+ } else if (overl & 2) {
226+ /* bit 2 set means parse server name */
227+ overl &= ~2;
228+ p = dhcp->servername;
229+ e = p + sizeof(dhcp->servername);
230+ } else
231+ goto exit;
232+ break;
233+ case DHO_OPTIONSOVERLOADED:
234+ /* Ensure we only get this option once */
235+ if (!overl)
236+ overl = p[1];
237+ break;
238+ }
239+ l = *p++;
240+ p += l;
241+ }
242+
243+exit:
244+ if (valid_length(o, bl, type) == -1) {
245+ errno = EINVAL;
246+ return NULL;
247+ }
248+ if (len)
249+ *len = bl;
250+ if (bp) {
251+ memcpy(bp, op, ol);
252+ return (const uint8_t *)&dhcp_opt_buffer;
253+ }
254+ if (op)
255+ return op;
256+ errno = ENOENT;
257+ return NULL;
258+}
259+
260+int
261+get_option_addr(uint32_t *a, const struct dhcp_message *dhcp, uint8_t option)
262+{
263+ const uint8_t *p = get_option_raw(dhcp, option);
264+
265+ if (!p)
266+ return -1;
267+ memcpy(a, p, sizeof(*a));
268+ return 0;
269+}
270+
271+int
272+get_option_uint32(uint32_t *i, const struct dhcp_message *dhcp, uint8_t option)
273+{
274+ uint32_t a;
275+
276+ if (get_option_addr(&a, dhcp, option) == -1)
277+ return -1;
278+
279+ *i = ntohl(a);
280+ return 0;
281+}
282+
283+uint32_t
284+get_netmask(uint32_t addr)
285+{
286+ uint32_t dst;
287+
288+ if (addr == 0)
289+ return 0;
290+
291+ dst = htonl(addr);
292+ if (IN_CLASSA(dst))
293+ return ntohl(IN_CLASSA_NET);
294+ if (IN_CLASSB (dst))
295+ return ntohl(IN_CLASSB_NET);
296+ if (IN_CLASSC (dst))
297+ return ntohl(IN_CLASSC_NET);
298+
299+ return 0;
300+}
301+
302+void showlease(struct dhcp_lease *lease)
303+{
304+ printf("addr: %s\n", inet_ntoa(lease->addr));
305+ printf("net: %s\n", inet_ntoa(lease->net));
306+ printf("leasetime: %d\n", lease->leasetime);
307+ printf("renew: %d\n", lease->renewaltime);
308+ printf("rebind: %d\n", lease->rebindtime);
309+ printf("server: %s\n", inet_ntoa(lease->server));
310+}
311+#define MAX_LEASETIME 2147460
312+
313+int
314+main(int argc, char *argv[])
315+{
316+ struct dhcp_message *dhcp;
317+ struct dhcp_lease *lease;
318+ char leasefile[PATH_MAX];
319+
320+ if (argc < 2) {
321+ fprintf(stderr, "Usage: %s <interface>\n", argv[0]);
322+ exit(1);
323+ }
324+ snprintf(leasefile, PATH_MAX, LEASEFILE, argv[1]);
325+ if ((dhcp = get_lease(leasefile)) == NULL) {
326+ fprintf(stderr, "Couldn't read lease file: %s\n", strerror(errno));
327+ exit(1);
328+ }
329+ lease = malloc(sizeof(*lease));
330+ lease->frominfo = 0;
331+ lease->addr.s_addr = dhcp->yiaddr;
332+
333+ if (get_option_addr(&lease->net.s_addr, dhcp, DHO_SUBNETMASK) == -1)
334+ lease->net.s_addr = get_netmask(dhcp->yiaddr);
335+ if (get_option_uint32(&lease->leasetime, dhcp, DHO_LEASETIME) != 0)
336+ lease->leasetime = DEFAULT_LEASETIME;
337+ get_option_addr(&lease->server.s_addr, dhcp, DHO_SERVERID);
338+ /* Dm: limit lease time value to avoid negative numbers when
339+ converting to milliseconds */
340+ if ((lease->leasetime != ~0U) && (lease->leasetime > MAX_LEASETIME))
341+ lease->leasetime = MAX_LEASETIME;
342+ if (get_option_uint32(&lease->renewaltime, dhcp, DHO_RENEWALTIME) != 0)
343+ lease->renewaltime = 0;
344+ if (get_option_uint32(&lease->rebindtime, dhcp, DHO_REBINDTIME) != 0)
345+ lease->rebindtime = 0;
346+ showlease(lease);
347+ free(lease);
348+ return 0;
349+}
--- a/signals.c
+++ b/signals.c
@@ -29,7 +29,6 @@
2929 #include <sys/socket.h>
3030
3131 #include <errno.h>
32-#include <poll.h>
3332 #include <signal.h>
3433 #include <string.h>
3534 #include <unistd.h>
@@ -62,31 +61,20 @@ signal_fd(void)
6261 return (signal_pipe[0]);
6362 }
6463
65-/* Check if we have a signal or not */
66-int
67-signal_exists(int fd)
68-{
69- if (fd_hasdata(fd) == 1)
70- return 0;
71- return -1;
72-}
73-
7464 /* Read a signal from the signal pipe. Returns 0 if there is
7565 * no signal, -1 on error (and sets errno appropriately), and
7666 * your signal on success */
7767 int
78-signal_read(int fd)
68+signal_read(void)
7969 {
8070 int sig = -1;
8171 char buf[16];
8272 size_t bytes;
8373
84- if (fd_hasdata(fd) == 1) {
85- memset(buf, 0, sizeof(buf));
86- bytes = read(signal_pipe[0], buf, sizeof(buf));
87- if (bytes >= sizeof(sig))
88- memcpy(&sig, buf, sizeof(sig));
89- }
74+ memset(buf, 0, sizeof(buf));
75+ bytes = read(signal_pipe[0], buf, sizeof(buf));
76+ if (bytes >= sizeof(sig))
77+ memcpy(&sig, buf, sizeof(sig));
9078 return sig;
9179 }
9280
--- a/signals.h
+++ b/signals.h
@@ -28,13 +28,10 @@
2828 #ifndef SIGNAL_H
2929 #define SIGNAL_H
3030
31-#include <poll.h>
32-
3331 int signal_init(void);
3432 int signal_setup(void);
3533 int signal_reset(void);
3634 int signal_fd(void);
37-int signal_exists(int fd);
38-int signal_read(int fd);
35+int signal_read(void);
3936
4037 #endif
Show on old repository browser