2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/param.h>
43 #include "configure.h"
46 #include "if-options.h"
51 # define _PATH_DEVNULL "/dev/null"
54 /* We do things after aquiring the lease, so ensure we have enough time for them */
55 #define DHCP_MIN_LEASE 20
57 #ifndef THERE_IS_NO_FORK
67 if (options
& DHCPCD_DAEMONISED
|| !(options
& DHCPCD_DAEMONISE
))
70 sigprocmask(SIG_SETMASK
, &full
, &old
);
71 /* Setup a signal pipe so parent knows when to exit. */
72 if (pipe(sidpipe
) == -1) {
73 syslog(LOG_ERR
, "pipe: %m");
76 syslog(LOG_INFO
, "forking to background");
77 switch (pid
= fork()) {
79 syslog(LOG_ERR
, "fork: %m");
84 /* Notify parent it's safe to exit as we've detached. */
86 if (write(sidpipe
[1], &buf
, 1) == -1)
87 syslog(LOG_ERR
, "failed to notify parent: %m");
89 if ((fd
= open(_PATH_DEVNULL
, O_RDWR
, 0)) != -1) {
90 dup2(fd
, STDIN_FILENO
);
91 dup2(fd
, STDOUT_FILENO
);
92 dup2(fd
, STDERR_FILENO
);
93 if (fd
> STDERR_FILENO
)
99 /* Wait for child to detach */
101 if (read(sidpipe
[0], &buf
, 1) == -1)
102 syslog(LOG_ERR
, "failed to read child: %m");
106 /* Done with the fd now */
108 writepid(pidfd
, pid
);
113 options
|= DHCPCD_DAEMONISED
;
114 sigprocmask(SIG_SETMASK
, &old
, NULL
);
120 bind_interface(void *arg
)
122 struct interface
*iface
= arg
;
123 struct if_state
*state
= iface
->state
;
124 struct if_options
*ifo
= state
->options
;
125 struct dhcp_lease
*lease
= &state
->lease
;
128 /* We're binding an address now - ensure that sockets are closed */
129 close_sockets(iface
);
130 state
->reason
= NULL
;
131 delete_timeout(handle_exit_timeout
, NULL
);
133 get_monotonic(&lease
->boundtime
);
136 state
->old
= state
->new;
137 state
->new = state
->offer
;
139 get_lease(lease
, state
->new);
140 if (ifo
->options
& DHCPCD_STATIC
) {
141 syslog(LOG_INFO
, "%s: using static address %s",
142 iface
->name
, inet_ntoa(lease
->addr
));
143 lease
->leasetime
= ~0U;
144 lease
->net
.s_addr
= ifo
->req_mask
.s_addr
;
145 state
->reason
= "STATIC";
146 } else if (IN_LINKLOCAL(htonl(state
->new->yiaddr
))) {
147 syslog(LOG_INFO
, "%s: using IPv4LL address %s",
148 iface
->name
, inet_ntoa(lease
->addr
));
149 lease
->leasetime
= ~0U;
150 state
->reason
= "IPV4LL";
151 } else if (ifo
->options
& DHCPCD_INFORM
) {
152 if (ifo
->req_addr
.s_addr
!= 0)
153 lease
->addr
.s_addr
= ifo
->req_addr
.s_addr
;
155 lease
->addr
.s_addr
= iface
->addr
.s_addr
;
156 syslog(LOG_INFO
, "%s: received approval for %s", iface
->name
,
157 inet_ntoa(lease
->addr
));
158 lease
->leasetime
= ~0U;
159 state
->reason
= "INFORM";
161 if (gettimeofday(&tv
, NULL
) == 0)
162 lease
->leasedfrom
= tv
.tv_sec
;
163 else if (lease
->frominfo
)
164 state
->reason
= "TIMEOUT";
165 if (lease
->leasetime
== ~0U) {
169 syslog(LOG_INFO
, "%s: leased %s for infinity",
170 iface
->name
, inet_ntoa(lease
->addr
));
172 if (lease
->leasetime
< DHCP_MIN_LEASE
) {
174 "%s: minimum lease is %d seconds",
175 iface
->name
, DHCP_MIN_LEASE
);
176 lease
->leasetime
= DHCP_MIN_LEASE
;
178 if (lease
->rebindtime
== 0)
179 lease
->rebindtime
= lease
->leasetime
* T2
;
180 else if (lease
->rebindtime
>= lease
->leasetime
) {
181 lease
->rebindtime
= lease
->leasetime
* T2
;
183 "%s: rebind time greater than lease "
184 "time, forcing to %u seconds",
185 iface
->name
, lease
->rebindtime
);
187 if (lease
->renewaltime
== 0)
188 lease
->renewaltime
= lease
->leasetime
* T1
;
189 else if (lease
->renewaltime
> lease
->rebindtime
) {
190 lease
->renewaltime
= lease
->leasetime
* T1
;
192 "%s: renewal time greater than rebind "
193 "time, forcing to %u seconds",
194 iface
->name
, lease
->renewaltime
);
197 "%s: leased %s for %u seconds", iface
->name
,
198 inet_ntoa(lease
->addr
), lease
->leasetime
);
201 if (options
& DHCPCD_TEST
) {
202 state
->reason
= "TEST";
206 if (state
->reason
== NULL
) {
208 if (state
->old
->yiaddr
== state
->new->yiaddr
&&
209 lease
->server
.s_addr
)
210 state
->reason
= "RENEW";
212 state
->reason
= "REBIND";
213 } else if (state
->state
== DHS_REBOOT
)
214 state
->reason
= "REBOOT";
216 state
->reason
= "BOUND";
218 if (lease
->leasetime
== ~0U)
219 lease
->renewaltime
= lease
->rebindtime
= lease
->leasetime
;
221 add_timeout_sec(lease
->renewaltime
, start_renew
, iface
);
222 add_timeout_sec(lease
->rebindtime
, start_rebind
, iface
);
223 add_timeout_sec(lease
->leasetime
, start_expire
, iface
);
225 ifo
->options
&= ~ DHCPCD_CSR_WARNED
;
228 state
->state
= DHS_BOUND
;
229 if (ifo
->options
& DHCPCD_ARP
) {
231 send_arp_announce(iface
);