blob: dc10386d5f3389c7da363b71a96ecf19f0d7437f [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Mike Frysinger7031f622006-05-08 03:20:50 +00002/* dhcpc.c
3 *
4 * udhcp DHCP client
5 *
6 * Russ Dill <Russ.Dill@asu.edu> July 2001
7 *
8 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
9 */
10
Mike Frysinger7031f622006-05-08 03:20:50 +000011#include <getopt.h>
Denis Vlasenkoaf1c8432007-03-26 13:22:35 +000012#include <syslog.h>
Mike Frysinger7031f622006-05-08 03:20:50 +000013
14#include "common.h"
15#include "dhcpd.h"
16#include "dhcpc.h"
17#include "options.h"
Denis Vlasenko5a3395b2006-11-18 19:51:32 +000018
Mike Frysinger7031f622006-05-08 03:20:50 +000019
20static int state;
Denis Vlasenko239369b2006-09-07 17:05:44 +000021/* Something is definitely wrong here. IPv4 addresses
22 * in variables of type long?? BTW, we use inet_ntoa()
23 * in the code. Manpage says that struct in_addr has a member of type long (!)
24 * which holds IPv4 address, and the struct is passed by value (!!)
25 */
Mike Frysinger7031f622006-05-08 03:20:50 +000026static unsigned long requested_ip; /* = 0 */
Denis Vlasenko74c9d232007-01-18 15:42:00 +000027static uint32_t server_addr;
Mike Frysinger7031f622006-05-08 03:20:50 +000028static unsigned long timeout;
29static int packet_num; /* = 0 */
30static int fd = -1;
31
32#define LISTEN_NONE 0
33#define LISTEN_KERNEL 1
34#define LISTEN_RAW 2
35static int listen_mode;
36
Denis Vlasenkoe2d3ded2006-11-27 23:43:28 +000037struct client_config_t client_config;
38
Mike Frysinger7031f622006-05-08 03:20:50 +000039
Mike Frysinger7031f622006-05-08 03:20:50 +000040/* just a little helper */
41static void change_mode(int new_mode)
42{
Denis Vlasenko3538b9a2006-09-06 18:36:50 +000043 DEBUG("entering %s listen mode",
Mike Frysinger7031f622006-05-08 03:20:50 +000044 new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
45 if (fd >= 0) close(fd);
46 fd = -1;
47 listen_mode = new_mode;
48}
49
50
51/* perform a renew */
52static void perform_renew(void)
53{
Denis Vlasenko3538b9a2006-09-06 18:36:50 +000054 bb_info_msg("Performing a DHCP renew");
Mike Frysinger7031f622006-05-08 03:20:50 +000055 switch (state) {
56 case BOUND:
57 change_mode(LISTEN_KERNEL);
58 case RENEWING:
59 case REBINDING:
60 state = RENEW_REQUESTED;
61 break;
62 case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
Rob Landley3f785612006-05-28 01:06:36 +000063 udhcp_run_script(NULL, "deconfig");
Mike Frysinger7031f622006-05-08 03:20:50 +000064 case REQUESTING:
65 case RELEASED:
66 change_mode(LISTEN_RAW);
67 state = INIT_SELECTING;
68 break;
69 case INIT_SELECTING:
70 break;
71 }
72
73 /* start things over */
74 packet_num = 0;
75
76 /* Kill any timeouts because the user wants this to hurry along */
77 timeout = 0;
78}
79
80
81/* perform a release */
82static void perform_release(void)
83{
84 char buffer[16];
85 struct in_addr temp_addr;
86
87 /* send release packet */
88 if (state == BOUND || state == RENEWING || state == REBINDING) {
89 temp_addr.s_addr = server_addr;
90 sprintf(buffer, "%s", inet_ntoa(temp_addr));
91 temp_addr.s_addr = requested_ip;
Denis Vlasenko3538b9a2006-09-06 18:36:50 +000092 bb_info_msg("Unicasting a release of %s to %s",
Mike Frysinger7031f622006-05-08 03:20:50 +000093 inet_ntoa(temp_addr), buffer);
94 send_release(server_addr, requested_ip); /* unicast */
Rob Landley3f785612006-05-28 01:06:36 +000095 udhcp_run_script(NULL, "deconfig");
Mike Frysinger7031f622006-05-08 03:20:50 +000096 }
Denis Vlasenko3538b9a2006-09-06 18:36:50 +000097 bb_info_msg("Entering released state");
Mike Frysinger7031f622006-05-08 03:20:50 +000098
99 change_mode(LISTEN_NONE);
100 state = RELEASED;
101 timeout = 0x7fffffff;
102}
103
104
105static void client_background(void)
106{
Denis Vlasenkoaf1c8432007-03-26 13:22:35 +0000107#ifdef __uClinux__
108 bb_error_msg("cannot background in uclinux (yet)");
109/* ... mainly because udhcpc calls client_background()
110 * in _the _middle _of _udhcpc _run_, not at the start!
111 * If that will be properly disabled for NOMMU, client_background()
112 * will work on NOMMU too */
113#else
114 bb_daemonize(DAEMON_CHDIR_ROOT);
115 logmode &= ~LOGMODE_STDIO;
116#endif
Mike Frysinger7031f622006-05-08 03:20:50 +0000117 client_config.foreground = 1; /* Do not fork again. */
118 client_config.background_if_no_lease = 0;
119}
120
121
Denis Vlasenkoe2d3ded2006-11-27 23:43:28 +0000122static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
123{
124 uint8_t *storage;
125 int len = strlen(str);
126 if (len > 255) len = 255;
127 storage = xzalloc(len + extra + OPT_DATA);
128 storage[OPT_CODE] = code;
129 storage[OPT_LEN] = len + extra;
130 memcpy(storage + extra + OPT_DATA, str, len);
131 return storage;
132}
133
134
Denis Vlasenko06af2162007-02-03 17:28:39 +0000135int udhcpc_main(int argc, char *argv[]);
Mike Frysinger7031f622006-05-08 03:20:50 +0000136int udhcpc_main(int argc, char *argv[])
Mike Frysinger7031f622006-05-08 03:20:50 +0000137{
138 uint8_t *temp, *message;
Denis Vlasenkoe2d3ded2006-11-27 23:43:28 +0000139 char *str_c, *str_V, *str_h, *str_F, *str_r, *str_T, *str_t;
Mike Frysinger7031f622006-05-08 03:20:50 +0000140 unsigned long t1 = 0, t2 = 0, xid = 0;
Rob Landley49ea4662006-09-11 01:34:21 +0000141 unsigned long start = 0, lease = 0;
Mike Frysinger7031f622006-05-08 03:20:50 +0000142 long now;
Denis Vlasenkoe2d3ded2006-11-27 23:43:28 +0000143 unsigned opt;
Mike Frysinger7031f622006-05-08 03:20:50 +0000144 int max_fd;
145 int sig;
Denis Vlasenkoe2d3ded2006-11-27 23:43:28 +0000146 int retval;
147 int len;
Mike Frysinger7031f622006-05-08 03:20:50 +0000148 int no_clientid = 0;
Denis Vlasenkoe2d3ded2006-11-27 23:43:28 +0000149 fd_set rfds;
150 struct timeval tv;
151 struct dhcpMessage packet;
152 struct in_addr temp_addr;
Mike Frysinger7031f622006-05-08 03:20:50 +0000153
Denis Vlasenkoe2d3ded2006-11-27 23:43:28 +0000154 enum {
155 OPT_c = 1 << 0,
156 OPT_C = 1 << 1,
157 OPT_V = 1 << 2,
158 OPT_f = 1 << 3,
159 OPT_b = 1 << 4,
160 OPT_H = 1 << 5,
161 OPT_h = 1 << 6,
162 OPT_F = 1 << 7,
163 OPT_i = 1 << 8,
164 OPT_n = 1 << 9,
165 OPT_p = 1 << 10,
166 OPT_q = 1 << 11,
167 OPT_R = 1 << 12,
168 OPT_r = 1 << 13,
169 OPT_s = 1 << 14,
170 OPT_T = 1 << 15,
171 OPT_t = 1 << 16,
172 OPT_v = 1 << 17,
173 };
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000174#if ENABLE_GETOPT_LONG
Mike Frysinger7031f622006-05-08 03:20:50 +0000175 static const struct option arg_options[] = {
Denis Vlasenkoe2d3ded2006-11-27 23:43:28 +0000176 { "clientid", required_argument, 0, 'c' },
177 { "clientid-none", no_argument, 0, 'C' },
178 { "vendorclass", required_argument, 0, 'V' },
179 { "foreground", no_argument, 0, 'f' },
180 { "background", no_argument, 0, 'b' },
181 { "hostname", required_argument, 0, 'H' },
182 { "hostname", required_argument, 0, 'h' },
183 { "fqdn", required_argument, 0, 'F' },
184 { "interface", required_argument, 0, 'i' },
185 { "now", no_argument, 0, 'n' },
186 { "pidfile", required_argument, 0, 'p' },
187 { "quit", no_argument, 0, 'q' },
188 { "release", no_argument, 0, 'R' },
189 { "request", required_argument, 0, 'r' },
190 { "script", required_argument, 0, 's' },
191 { "timeout", required_argument, 0, 'T' },
192 { "version", no_argument, 0, 'v' },
193 { "retries", required_argument, 0, 't' },
194 { 0, 0, 0, 0 }
Mike Frysinger7031f622006-05-08 03:20:50 +0000195 };
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000196#endif
Denis Vlasenkoe2d3ded2006-11-27 23:43:28 +0000197 /* Default options. */
198 client_config.interface = "eth0";
199 client_config.script = DEFAULT_SCRIPT;
200 client_config.retries = 3;
201 client_config.timeout = 3;
Mike Frysinger7031f622006-05-08 03:20:50 +0000202
Denis Vlasenkoe2d3ded2006-11-27 23:43:28 +0000203 /* Parse command line */
204 opt_complementary = "?:c--C:C--c" // mutually exclusive
205 ":hH:Hh"; // -h and -H are the same
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000206#if ENABLE_GETOPT_LONG
Denis Vlasenkoe2d3ded2006-11-27 23:43:28 +0000207 applet_long_options = arg_options;
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000208#endif
Denis Vlasenkoe2d3ded2006-11-27 23:43:28 +0000209 opt = getopt32(argc, argv, "c:CV:fbH:h:F:i:np:qRr:s:T:t:v",
210 &str_c, &str_V, &str_h, &str_h, &str_F,
211 &client_config.interface, &client_config.pidfile, &str_r,
212 &client_config.script, &str_T, &str_t
213 );
214
215 if (opt & OPT_c)
216 client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0);
217 if (opt & OPT_C)
218 no_clientid = 1;
219 if (opt & OPT_V)
220 client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0);
221 if (opt & OPT_f)
222 client_config.foreground = 1;
223 if (opt & OPT_b)
224 client_config.background_if_no_lease = 1;
225 if (opt & OPT_h)
226 client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0);
227 if (opt & OPT_F) {
228 client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3);
229 /* Flags: 0000NEOS
230 S: 1 => Client requests Server to update A RR in DNS as well as PTR
231 O: 1 => Server indicates to client that DNS has been updated regardless
232 E: 1 => Name data is DNS format, i.e. <4>host<6>domain<4>com<0> not "host.domain.com"
233 N: 1 => Client requests Server to not update DNS
234 */
235 client_config.fqdn[OPT_DATA + 0] = 0x1;
236 /* client_config.fqdn[OPT_DATA + 1] = 0; - redundant */
237 /* client_config.fqdn[OPT_DATA + 2] = 0; - redundant */
238 }
239 // if (opt & OPT_i) client_config.interface = ...
240 if (opt & OPT_n)
241 client_config.abort_if_no_lease = 1;
242 // if (opt & OPT_p) client_config.pidfile = ...
243 if (opt & OPT_q)
244 client_config.quit_after_lease = 1;
245 if (opt & OPT_R)
246 client_config.release_on_quit = 1;
247 if (opt & OPT_r)
248 requested_ip = inet_addr(str_r);
249 // if (opt & OPT_s) client_config.script = ...
250 if (opt & OPT_T)
251 client_config.timeout = xatoi_u(str_T);
252 if (opt & OPT_t)
253 client_config.retries = xatoi_u(str_t);
254 if (opt & OPT_v) {
255 printf("version %s\n\n", BB_VER);
256 return 0;
Mike Frysinger7031f622006-05-08 03:20:50 +0000257 }
258
Denis Vlasenkoaf1c8432007-03-26 13:22:35 +0000259 if (ENABLE_FEATURE_UDHCP_SYSLOG) {
260 openlog(applet_name, LOG_PID, LOG_LOCAL0);
261 logmode |= LOGMODE_SYSLOG;
262 }
Mike Frysinger7031f622006-05-08 03:20:50 +0000263
264 if (read_interface(client_config.interface, &client_config.ifindex,
265 NULL, client_config.arp) < 0)
266 return 1;
267
Denis Vlasenkoaf1c8432007-03-26 13:22:35 +0000268 /* Sanitize fd's and write pidfile */
269 udhcp_make_pidfile(client_config.pidfile);
270
Mike Frysinger7031f622006-05-08 03:20:50 +0000271 /* if not set, and not suppressed, setup the default client ID */
272 if (!client_config.clientid && !no_clientid) {
Denis Vlasenkoe2d3ded2006-11-27 23:43:28 +0000273 client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);
Mike Frysinger7031f622006-05-08 03:20:50 +0000274 client_config.clientid[OPT_DATA] = 1;
Denis Vlasenkoe2d3ded2006-11-27 23:43:28 +0000275 memcpy(client_config.clientid + OPT_DATA+1, client_config.arp, 6);
Mike Frysinger7031f622006-05-08 03:20:50 +0000276 }
277
Denis Vlasenkoe2d3ded2006-11-27 23:43:28 +0000278 if (!client_config.vendorclass)
279 client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, "udhcp "BB_VER, 0);
Mike Frysinger7031f622006-05-08 03:20:50 +0000280
281 /* setup the signal pipe */
282 udhcp_sp_setup();
283
284 state = INIT_SELECTING;
Rob Landley3f785612006-05-28 01:06:36 +0000285 udhcp_run_script(NULL, "deconfig");
Mike Frysinger7031f622006-05-08 03:20:50 +0000286 change_mode(LISTEN_RAW);
287
288 for (;;) {
Mike Frysinger7031f622006-05-08 03:20:50 +0000289 tv.tv_sec = timeout - uptime();
290 tv.tv_usec = 0;
291
292 if (listen_mode != LISTEN_NONE && fd < 0) {
293 if (listen_mode == LISTEN_KERNEL)
294 fd = listen_socket(INADDR_ANY, CLIENT_PORT, client_config.interface);
295 else
296 fd = raw_socket(client_config.ifindex);
Mike Frysinger7031f622006-05-08 03:20:50 +0000297 }
298 max_fd = udhcp_sp_fd_set(&rfds, fd);
299
300 if (tv.tv_sec > 0) {
Denis Vlasenko3538b9a2006-09-06 18:36:50 +0000301 DEBUG("Waiting on select...");
Mike Frysinger7031f622006-05-08 03:20:50 +0000302 retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
303 } else retval = 0; /* If we already timed out, fall through */
304
305 now = uptime();
306 if (retval == 0) {
307 /* timeout dropped to zero */
308 switch (state) {
309 case INIT_SELECTING:
310 if (packet_num < client_config.retries) {
311 if (packet_num == 0)
312 xid = random_xid();
313
314 /* send discover packet */
315 send_discover(xid, requested_ip); /* broadcast */
316
317 timeout = now + client_config.timeout;
318 packet_num++;
319 } else {
Rob Landley3f785612006-05-28 01:06:36 +0000320 udhcp_run_script(NULL, "leasefail");
Mike Frysinger7031f622006-05-08 03:20:50 +0000321 if (client_config.background_if_no_lease) {
Denis Vlasenko3538b9a2006-09-06 18:36:50 +0000322 bb_info_msg("No lease, forking to background");
Mike Frysinger7031f622006-05-08 03:20:50 +0000323 client_background();
324 } else if (client_config.abort_if_no_lease) {
Denis Vlasenko3538b9a2006-09-06 18:36:50 +0000325 bb_info_msg("No lease, failing");
Mike Frysinger7031f622006-05-08 03:20:50 +0000326 return 1;
327 }
328 /* wait to try again */
329 packet_num = 0;
330 timeout = now + 60;
331 }
332 break;
333 case RENEW_REQUESTED:
334 case REQUESTING:
335 if (packet_num < client_config.retries) {
336 /* send request packet */
337 if (state == RENEW_REQUESTED)
338 send_renew(xid, server_addr, requested_ip); /* unicast */
339 else send_selecting(xid, server_addr, requested_ip); /* broadcast */
340
341 timeout = now + ((packet_num == 2) ? 10 : 2);
342 packet_num++;
343 } else {
344 /* timed out, go back to init state */
Rob Landley3f785612006-05-28 01:06:36 +0000345 if (state == RENEW_REQUESTED) udhcp_run_script(NULL, "deconfig");
Mike Frysinger7031f622006-05-08 03:20:50 +0000346 state = INIT_SELECTING;
347 timeout = now;
348 packet_num = 0;
349 change_mode(LISTEN_RAW);
350 }
351 break;
352 case BOUND:
353 /* Lease is starting to run out, time to enter renewing state */
354 state = RENEWING;
355 change_mode(LISTEN_KERNEL);
Denis Vlasenko3538b9a2006-09-06 18:36:50 +0000356 DEBUG("Entering renew state");
Mike Frysinger7031f622006-05-08 03:20:50 +0000357 /* fall right through */
358 case RENEWING:
359 /* Either set a new T1, or enter REBINDING state */
360 if ((t2 - t1) <= (lease / 14400 + 1)) {
361 /* timed out, enter rebinding state */
362 state = REBINDING;
363 timeout = now + (t2 - t1);
Denis Vlasenko3538b9a2006-09-06 18:36:50 +0000364 DEBUG("Entering rebinding state");
Mike Frysinger7031f622006-05-08 03:20:50 +0000365 } else {
366 /* send a request packet */
367 send_renew(xid, server_addr, requested_ip); /* unicast */
368
369 t1 = (t2 - t1) / 2 + t1;
370 timeout = t1 + start;
371 }
372 break;
373 case REBINDING:
374 /* Either set a new T2, or enter INIT state */
375 if ((lease - t2) <= (lease / 14400 + 1)) {
376 /* timed out, enter init state */
377 state = INIT_SELECTING;
Denis Vlasenko3538b9a2006-09-06 18:36:50 +0000378 bb_info_msg("Lease lost, entering init state");
Rob Landley3f785612006-05-28 01:06:36 +0000379 udhcp_run_script(NULL, "deconfig");
Mike Frysinger7031f622006-05-08 03:20:50 +0000380 timeout = now;
381 packet_num = 0;
382 change_mode(LISTEN_RAW);
383 } else {
384 /* send a request packet */
385 send_renew(xid, 0, requested_ip); /* broadcast */
386
387 t2 = (lease - t2) / 2 + t2;
388 timeout = t2 + start;
389 }
390 break;
391 case RELEASED:
392 /* yah, I know, *you* say it would never happen */
393 timeout = 0x7fffffff;
394 break;
395 }
396 } else if (retval > 0 && listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds)) {
397 /* a packet is ready, read it */
398
399 if (listen_mode == LISTEN_KERNEL)
Rob Landley3f785612006-05-28 01:06:36 +0000400 len = udhcp_get_packet(&packet, fd);
Mike Frysinger7031f622006-05-08 03:20:50 +0000401 else len = get_raw_packet(&packet, fd);
402
403 if (len == -1 && errno != EINTR) {
Denis Vlasenko3538b9a2006-09-06 18:36:50 +0000404 DEBUG("error on read, %s, reopening socket", strerror(errno));
Mike Frysinger7031f622006-05-08 03:20:50 +0000405 change_mode(listen_mode); /* just close and reopen */
406 }
407 if (len < 0) continue;
408
409 if (packet.xid != xid) {
Denis Vlasenko3538b9a2006-09-06 18:36:50 +0000410 DEBUG("Ignoring XID %lx (our xid is %lx)",
Mike Frysinger7031f622006-05-08 03:20:50 +0000411 (unsigned long) packet.xid, xid);
412 continue;
413 }
414
415 /* Ignore packets that aren't for us */
416 if (memcmp(packet.chaddr, client_config.arp, 6)) {
Denis Vlasenko3538b9a2006-09-06 18:36:50 +0000417 DEBUG("Packet does not have our chaddr - ignoring");
Mike Frysinger7031f622006-05-08 03:20:50 +0000418 continue;
419 }
420
421 if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
Denis Vlasenkoa6dbb082006-10-12 19:29:44 +0000422 bb_error_msg("cannot get option from packet - ignoring");
Mike Frysinger7031f622006-05-08 03:20:50 +0000423 continue;
424 }
425
426 switch (state) {
427 case INIT_SELECTING:
428 /* Must be a DHCPOFFER to one of our xid's */
429 if (*message == DHCPOFFER) {
Denis Vlasenko239369b2006-09-07 17:05:44 +0000430 temp = get_option(&packet, DHCP_SERVER_ID);
431 if (temp) {
Denis Vlasenko74c9d232007-01-18 15:42:00 +0000432 /* can be misaligned, thus memcpy */
433 memcpy(&server_addr, temp, 4);
Mike Frysinger7031f622006-05-08 03:20:50 +0000434 xid = packet.xid;
435 requested_ip = packet.yiaddr;
436
437 /* enter requesting state */
438 state = REQUESTING;
439 timeout = now;
440 packet_num = 0;
441 } else {
Denis Vlasenkoa6dbb082006-10-12 19:29:44 +0000442 bb_error_msg("no server ID in message");
Mike Frysinger7031f622006-05-08 03:20:50 +0000443 }
444 }
445 break;
446 case RENEW_REQUESTED:
447 case REQUESTING:
448 case RENEWING:
449 case REBINDING:
450 if (*message == DHCPACK) {
Denis Vlasenko239369b2006-09-07 17:05:44 +0000451 temp = get_option(&packet, DHCP_LEASE_TIME);
452 if (!temp) {
Denis Vlasenkoa6dbb082006-10-12 19:29:44 +0000453 bb_error_msg("no lease time with ACK, using 1 hour lease");
Mike Frysinger7031f622006-05-08 03:20:50 +0000454 lease = 60 * 60;
455 } else {
Denis Vlasenko74c9d232007-01-18 15:42:00 +0000456 /* can be misaligned, thus memcpy */
457 memcpy(&lease, temp, 4);
458 lease = ntohl(lease);
Mike Frysinger7031f622006-05-08 03:20:50 +0000459 }
460
461 /* enter bound state */
462 t1 = lease / 2;
463
464 /* little fixed point for n * .875 */
465 t2 = (lease * 0x7) >> 3;
466 temp_addr.s_addr = packet.yiaddr;
Denis Vlasenko3538b9a2006-09-06 18:36:50 +0000467 bb_info_msg("Lease of %s obtained, lease time %ld",
Mike Frysinger7031f622006-05-08 03:20:50 +0000468 inet_ntoa(temp_addr), lease);
469 start = now;
470 timeout = t1 + start;
471 requested_ip = packet.yiaddr;
Rob Landley3f785612006-05-28 01:06:36 +0000472 udhcp_run_script(&packet,
Mike Frysinger7031f622006-05-08 03:20:50 +0000473 ((state == RENEWING || state == REBINDING) ? "renew" : "bound"));
474
475 state = BOUND;
476 change_mode(LISTEN_NONE);
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000477 if (client_config.quit_after_lease) {
478 if (client_config.release_on_quit)
479 perform_release();
Mike Frysinger7031f622006-05-08 03:20:50 +0000480 return 0;
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000481 }
Mike Frysinger7031f622006-05-08 03:20:50 +0000482 if (!client_config.foreground)
483 client_background();
484
485 } else if (*message == DHCPNAK) {
486 /* return to init state */
Denis Vlasenko3538b9a2006-09-06 18:36:50 +0000487 bb_info_msg("Received DHCP NAK");
Rob Landley3f785612006-05-28 01:06:36 +0000488 udhcp_run_script(&packet, "nak");
Mike Frysinger7031f622006-05-08 03:20:50 +0000489 if (state != REQUESTING)
Rob Landley3f785612006-05-28 01:06:36 +0000490 udhcp_run_script(NULL, "deconfig");
Mike Frysinger7031f622006-05-08 03:20:50 +0000491 state = INIT_SELECTING;
492 timeout = now;
493 requested_ip = 0;
494 packet_num = 0;
495 change_mode(LISTEN_RAW);
496 sleep(3); /* avoid excessive network traffic */
497 }
498 break;
499 /* case BOUND, RELEASED: - ignore all packets */
500 }
501 } else if (retval > 0 && (sig = udhcp_sp_read(&rfds))) {
502 switch (sig) {
503 case SIGUSR1:
504 perform_renew();
505 break;
506 case SIGUSR2:
507 perform_release();
508 break;
509 case SIGTERM:
Denis Vlasenko3538b9a2006-09-06 18:36:50 +0000510 bb_info_msg("Received SIGTERM");
Denis Vlasenkoe175ff22006-09-26 17:41:00 +0000511 if (client_config.release_on_quit)
512 perform_release();
Mike Frysinger7031f622006-05-08 03:20:50 +0000513 return 0;
514 }
515 } else if (retval == -1 && errno == EINTR) {
516 /* a signal was caught */
517 } else {
518 /* An error occured */
Denis Vlasenko3538b9a2006-09-06 18:36:50 +0000519 bb_perror_msg("select");
Mike Frysinger7031f622006-05-08 03:20:50 +0000520 }
521
522 }
523 return 0;
524}