diff options
author | Mike Frysinger <vapier@gentoo.org> | 2006-04-27 02:03:03 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2006-04-27 02:03:03 +0000 |
commit | ee3e57db0d309247a3a6160f1d32e74ef9e15fec (patch) | |
tree | 41e83634364c95fc24fe94096792fcaead242f1c | |
parent | 2f5f59189ee80bd70426902e10bbea517a8e7f8b (diff) | |
download | busybox-w32-ee3e57db0d309247a3a6160f1d32e74ef9e15fec.tar.gz busybox-w32-ee3e57db0d309247a3a6160f1d32e74ef9e15fec.tar.bz2 busybox-w32-ee3e57db0d309247a3a6160f1d32e74ef9e15fec.zip |
Giuseppe Ciotta writes: add -t, --retries=NUM to show_usage()
-rw-r--r-- | networking/udhcp/dhcpc.c | 573 |
1 files changed, 573 insertions, 0 deletions
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c new file mode 100644 index 000000000..7878e8eea --- /dev/null +++ b/networking/udhcp/dhcpc.c | |||
@@ -0,0 +1,573 @@ | |||
1 | /* dhcpc.c | ||
2 | * | ||
3 | * udhcp DHCP client | ||
4 | * | ||
5 | * Russ Dill <Russ.Dill@asu.edu> July 2001 | ||
6 | * | ||
7 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. | ||
8 | */ | ||
9 | |||
10 | #include <sys/time.h> | ||
11 | #include <sys/file.h> | ||
12 | #include <unistd.h> | ||
13 | #include <getopt.h> | ||
14 | #include <stdlib.h> | ||
15 | #include <sys/socket.h> | ||
16 | #include <netinet/in.h> | ||
17 | #include <arpa/inet.h> | ||
18 | #include <signal.h> | ||
19 | #include <time.h> | ||
20 | #include <string.h> | ||
21 | #include <sys/ioctl.h> | ||
22 | #include <net/if.h> | ||
23 | #include <errno.h> | ||
24 | |||
25 | #include "common.h" | ||
26 | #include "dhcpd.h" | ||
27 | #include "dhcpc.h" | ||
28 | #include "options.h" | ||
29 | #include "clientpacket.h" | ||
30 | #include "clientsocket.h" | ||
31 | #include "script.h" | ||
32 | #include "socket.h" | ||
33 | #include "signalpipe.h" | ||
34 | |||
35 | static int state; | ||
36 | static unsigned long requested_ip; /* = 0 */ | ||
37 | static unsigned long server_addr; | ||
38 | static unsigned long timeout; | ||
39 | static int packet_num; /* = 0 */ | ||
40 | static int fd = -1; | ||
41 | |||
42 | #define LISTEN_NONE 0 | ||
43 | #define LISTEN_KERNEL 1 | ||
44 | #define LISTEN_RAW 2 | ||
45 | static int listen_mode; | ||
46 | |||
47 | struct client_config_t client_config = { | ||
48 | /* Default options. */ | ||
49 | .abort_if_no_lease = 0, | ||
50 | .foreground = 0, | ||
51 | .quit_after_lease = 0, | ||
52 | .background_if_no_lease = 0, | ||
53 | .interface = "eth0", | ||
54 | .pidfile = NULL, | ||
55 | .script = DEFAULT_SCRIPT, | ||
56 | .clientid = NULL, | ||
57 | .vendorclass = NULL, | ||
58 | .hostname = NULL, | ||
59 | .fqdn = NULL, | ||
60 | .ifindex = 0, | ||
61 | .retries = 3, | ||
62 | .timeout = 3, | ||
63 | .arp = "\0\0\0\0\0\0", /* appease gcc-3.0 */ | ||
64 | }; | ||
65 | |||
66 | #ifndef IN_BUSYBOX | ||
67 | static void ATTRIBUTE_NORETURN show_usage(void) | ||
68 | { | ||
69 | printf( | ||
70 | "Usage: udhcpc [OPTIONS]\n\n" | ||
71 | " -c, --clientid=CLIENTID Set client identifier - type is first char\n" | ||
72 | " -C, --clientid-none Suppress default client identifier\n" | ||
73 | " -V, --vendorclass=CLASSID Set vendor class identifier\n" | ||
74 | " -H, --hostname=HOSTNAME Client hostname\n" | ||
75 | " -h Alias for -H\n" | ||
76 | " -F, --fqdn=FQDN Client fully qualified domain name\n" | ||
77 | " -f, --foreground Do not fork after getting lease\n" | ||
78 | " -b, --background Fork to background if lease cannot be\n" | ||
79 | " immediately negotiated.\n" | ||
80 | " -i, --interface=INTERFACE Interface to use (default: eth0)\n" | ||
81 | " -n, --now Exit with failure if lease cannot be\n" | ||
82 | " immediately negotiated.\n" | ||
83 | " -p, --pidfile=file Store process ID of daemon in file\n" | ||
84 | " -q, --quit Quit after obtaining lease\n" | ||
85 | " -r, --request=IP IP address to request (default: none)\n" | ||
86 | " -s, --script=file Run file at dhcp events (default:\n" | ||
87 | " " DEFAULT_SCRIPT ")\n" | ||
88 | " -T, --timeout=seconds Try to get the lease for the amount of\n" | ||
89 | " seconds (default: 3)\n" | ||
90 | " -t, --retries=NUM Send up to NUM request packets\n" | ||
91 | " -v, --version Display version\n" | ||
92 | ); | ||
93 | exit(0); | ||
94 | } | ||
95 | #else | ||
96 | #define show_usage bb_show_usage | ||
97 | extern void show_usage(void) ATTRIBUTE_NORETURN; | ||
98 | #endif | ||
99 | |||
100 | |||
101 | /* just a little helper */ | ||
102 | static void change_mode(int new_mode) | ||
103 | { | ||
104 | DEBUG(LOG_INFO, "entering %s listen mode", | ||
105 | new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none"); | ||
106 | if (fd >= 0) close(fd); | ||
107 | fd = -1; | ||
108 | listen_mode = new_mode; | ||
109 | } | ||
110 | |||
111 | |||
112 | /* perform a renew */ | ||
113 | static void perform_renew(void) | ||
114 | { | ||
115 | LOG(LOG_INFO, "Performing a DHCP renew"); | ||
116 | switch (state) { | ||
117 | case BOUND: | ||
118 | change_mode(LISTEN_KERNEL); | ||
119 | case RENEWING: | ||
120 | case REBINDING: | ||
121 | state = RENEW_REQUESTED; | ||
122 | break; | ||
123 | case RENEW_REQUESTED: /* impatient are we? fine, square 1 */ | ||
124 | run_script(NULL, "deconfig"); | ||
125 | case REQUESTING: | ||
126 | case RELEASED: | ||
127 | change_mode(LISTEN_RAW); | ||
128 | state = INIT_SELECTING; | ||
129 | break; | ||
130 | case INIT_SELECTING: | ||
131 | break; | ||
132 | } | ||
133 | |||
134 | /* start things over */ | ||
135 | packet_num = 0; | ||
136 | |||
137 | /* Kill any timeouts because the user wants this to hurry along */ | ||
138 | timeout = 0; | ||
139 | } | ||
140 | |||
141 | |||
142 | /* perform a release */ | ||
143 | static void perform_release(void) | ||
144 | { | ||
145 | char buffer[16]; | ||
146 | struct in_addr temp_addr; | ||
147 | |||
148 | /* send release packet */ | ||
149 | if (state == BOUND || state == RENEWING || state == REBINDING) { | ||
150 | temp_addr.s_addr = server_addr; | ||
151 | sprintf(buffer, "%s", inet_ntoa(temp_addr)); | ||
152 | temp_addr.s_addr = requested_ip; | ||
153 | LOG(LOG_INFO, "Unicasting a release of %s to %s", | ||
154 | inet_ntoa(temp_addr), buffer); | ||
155 | send_release(server_addr, requested_ip); /* unicast */ | ||
156 | run_script(NULL, "deconfig"); | ||
157 | } | ||
158 | LOG(LOG_INFO, "Entering released state"); | ||
159 | |||
160 | change_mode(LISTEN_NONE); | ||
161 | state = RELEASED; | ||
162 | timeout = 0x7fffffff; | ||
163 | } | ||
164 | |||
165 | |||
166 | static void client_background(void) | ||
167 | { | ||
168 | background(client_config.pidfile); | ||
169 | client_config.foreground = 1; /* Do not fork again. */ | ||
170 | client_config.background_if_no_lease = 0; | ||
171 | } | ||
172 | |||
173 | |||
174 | #ifdef COMBINED_BINARY | ||
175 | int udhcpc_main(int argc, char *argv[]) | ||
176 | #else | ||
177 | int main(int argc, char *argv[]) | ||
178 | #endif | ||
179 | { | ||
180 | uint8_t *temp, *message; | ||
181 | unsigned long t1 = 0, t2 = 0, xid = 0; | ||
182 | unsigned long start = 0, lease; | ||
183 | fd_set rfds; | ||
184 | int retval; | ||
185 | struct timeval tv; | ||
186 | int c, len; | ||
187 | struct dhcpMessage packet; | ||
188 | struct in_addr temp_addr; | ||
189 | long now; | ||
190 | int max_fd; | ||
191 | int sig; | ||
192 | int no_clientid = 0; | ||
193 | |||
194 | static const struct option arg_options[] = { | ||
195 | {"clientid", required_argument, 0, 'c'}, | ||
196 | {"clientid-none", no_argument, 0, 'C'}, | ||
197 | {"vendorclass", required_argument, 0, 'V'}, | ||
198 | {"foreground", no_argument, 0, 'f'}, | ||
199 | {"background", no_argument, 0, 'b'}, | ||
200 | {"hostname", required_argument, 0, 'H'}, | ||
201 | {"hostname", required_argument, 0, 'h'}, | ||
202 | {"fqdn", required_argument, 0, 'F'}, | ||
203 | {"interface", required_argument, 0, 'i'}, | ||
204 | {"now", no_argument, 0, 'n'}, | ||
205 | {"pidfile", required_argument, 0, 'p'}, | ||
206 | {"quit", no_argument, 0, 'q'}, | ||
207 | {"request", required_argument, 0, 'r'}, | ||
208 | {"script", required_argument, 0, 's'}, | ||
209 | {"timeout", required_argument, 0, 'T'}, | ||
210 | {"version", no_argument, 0, 'v'}, | ||
211 | {"retries", required_argument, 0, 't'}, | ||
212 | {0, 0, 0, 0} | ||
213 | }; | ||
214 | |||
215 | /* get options */ | ||
216 | while (1) { | ||
217 | int option_index = 0; | ||
218 | c = getopt_long(argc, argv, "c:CV:fbH:h:F:i:np:qr:s:T:t:v", arg_options, &option_index); | ||
219 | if (c == -1) break; | ||
220 | |||
221 | switch (c) { | ||
222 | case 'c': | ||
223 | if (no_clientid) show_usage(); | ||
224 | len = strlen(optarg) > 255 ? 255 : strlen(optarg); | ||
225 | free(client_config.clientid); | ||
226 | client_config.clientid = xmalloc(len + 2); | ||
227 | client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; | ||
228 | client_config.clientid[OPT_LEN] = len; | ||
229 | client_config.clientid[OPT_DATA] = '\0'; | ||
230 | strncpy((char*)client_config.clientid + OPT_DATA, optarg, len); | ||
231 | break; | ||
232 | case 'C': | ||
233 | if (client_config.clientid) show_usage(); | ||
234 | no_clientid = 1; | ||
235 | break; | ||
236 | case 'V': | ||
237 | len = strlen(optarg) > 255 ? 255 : strlen(optarg); | ||
238 | free(client_config.vendorclass); | ||
239 | client_config.vendorclass = xmalloc(len + 2); | ||
240 | client_config.vendorclass[OPT_CODE] = DHCP_VENDOR; | ||
241 | client_config.vendorclass[OPT_LEN] = len; | ||
242 | strncpy((char*)client_config.vendorclass + OPT_DATA, optarg, len); | ||
243 | break; | ||
244 | case 'f': | ||
245 | client_config.foreground = 1; | ||
246 | break; | ||
247 | case 'b': | ||
248 | client_config.background_if_no_lease = 1; | ||
249 | break; | ||
250 | case 'h': | ||
251 | case 'H': | ||
252 | len = strlen(optarg) > 255 ? 255 : strlen(optarg); | ||
253 | free(client_config.hostname); | ||
254 | client_config.hostname = xmalloc(len + 2); | ||
255 | client_config.hostname[OPT_CODE] = DHCP_HOST_NAME; | ||
256 | client_config.hostname[OPT_LEN] = len; | ||
257 | strncpy((char*)client_config.hostname + 2, optarg, len); | ||
258 | break; | ||
259 | case 'F': | ||
260 | len = strlen(optarg) > 255 ? 255 : strlen(optarg); | ||
261 | free(client_config.fqdn); | ||
262 | client_config.fqdn = xmalloc(len + 5); | ||
263 | client_config.fqdn[OPT_CODE] = DHCP_FQDN; | ||
264 | client_config.fqdn[OPT_LEN] = len + 3; | ||
265 | /* Flags: 0000NEOS | ||
266 | S: 1 => Client requests Server to update A RR in DNS as well as PTR | ||
267 | O: 1 => Server indicates to client that DNS has been updated regardless | ||
268 | E: 1 => Name data is DNS format, i.e. <4>host<6>domain<4>com<0> not "host.domain.com" | ||
269 | N: 1 => Client requests Server to not update DNS | ||
270 | */ | ||
271 | client_config.fqdn[OPT_LEN + 1] = 0x1; | ||
272 | client_config.fqdn[OPT_LEN + 2] = 0; | ||
273 | client_config.fqdn[OPT_LEN + 3] = 0; | ||
274 | strncpy((char*)client_config.fqdn + 5, optarg, len); | ||
275 | break; | ||
276 | case 'i': | ||
277 | client_config.interface = optarg; | ||
278 | break; | ||
279 | case 'n': | ||
280 | client_config.abort_if_no_lease = 1; | ||
281 | break; | ||
282 | case 'p': | ||
283 | client_config.pidfile = optarg; | ||
284 | break; | ||
285 | case 'q': | ||
286 | client_config.quit_after_lease = 1; | ||
287 | break; | ||
288 | case 'r': | ||
289 | requested_ip = inet_addr(optarg); | ||
290 | break; | ||
291 | case 's': | ||
292 | client_config.script = optarg; | ||
293 | break; | ||
294 | case 'T': | ||
295 | client_config.timeout = atoi(optarg); | ||
296 | break; | ||
297 | case 't': | ||
298 | client_config.retries = atoi(optarg); | ||
299 | break; | ||
300 | case 'v': | ||
301 | printf("udhcpcd, version %s\n\n", VERSION); | ||
302 | return 0; | ||
303 | break; | ||
304 | default: | ||
305 | show_usage(); | ||
306 | } | ||
307 | } | ||
308 | |||
309 | /* Start the log, sanitize fd's, and write a pid file */ | ||
310 | start_log_and_pid("udhcpc", client_config.pidfile); | ||
311 | |||
312 | if (read_interface(client_config.interface, &client_config.ifindex, | ||
313 | NULL, client_config.arp) < 0) | ||
314 | return 1; | ||
315 | |||
316 | /* if not set, and not suppressed, setup the default client ID */ | ||
317 | if (!client_config.clientid && !no_clientid) { | ||
318 | client_config.clientid = xmalloc(6 + 3); | ||
319 | client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; | ||
320 | client_config.clientid[OPT_LEN] = 7; | ||
321 | client_config.clientid[OPT_DATA] = 1; | ||
322 | memcpy(client_config.clientid + 3, client_config.arp, 6); | ||
323 | } | ||
324 | |||
325 | if (!client_config.vendorclass) { | ||
326 | client_config.vendorclass = xmalloc(sizeof("udhcp "VERSION) + 2); | ||
327 | client_config.vendorclass[OPT_CODE] = DHCP_VENDOR; | ||
328 | client_config.vendorclass[OPT_LEN] = sizeof("udhcp "VERSION) - 1; | ||
329 | client_config.vendorclass[OPT_DATA] = 1; | ||
330 | memcpy(&client_config.vendorclass[OPT_DATA], | ||
331 | "udhcp "VERSION, sizeof("udhcp "VERSION) - 1); | ||
332 | } | ||
333 | |||
334 | |||
335 | /* setup the signal pipe */ | ||
336 | udhcp_sp_setup(); | ||
337 | |||
338 | state = INIT_SELECTING; | ||
339 | run_script(NULL, "deconfig"); | ||
340 | change_mode(LISTEN_RAW); | ||
341 | |||
342 | for (;;) { | ||
343 | |||
344 | tv.tv_sec = timeout - uptime(); | ||
345 | tv.tv_usec = 0; | ||
346 | |||
347 | if (listen_mode != LISTEN_NONE && fd < 0) { | ||
348 | if (listen_mode == LISTEN_KERNEL) | ||
349 | fd = listen_socket(INADDR_ANY, CLIENT_PORT, client_config.interface); | ||
350 | else | ||
351 | fd = raw_socket(client_config.ifindex); | ||
352 | if (fd < 0) { | ||
353 | LOG(LOG_ERR, "FATAL: couldn't listen on socket, %m"); | ||
354 | return 0; | ||
355 | } | ||
356 | } | ||
357 | max_fd = udhcp_sp_fd_set(&rfds, fd); | ||
358 | |||
359 | if (tv.tv_sec > 0) { | ||
360 | DEBUG(LOG_INFO, "Waiting on select..."); | ||
361 | retval = select(max_fd + 1, &rfds, NULL, NULL, &tv); | ||
362 | } else retval = 0; /* If we already timed out, fall through */ | ||
363 | |||
364 | now = uptime(); | ||
365 | if (retval == 0) { | ||
366 | /* timeout dropped to zero */ | ||
367 | switch (state) { | ||
368 | case INIT_SELECTING: | ||
369 | if (packet_num < client_config.retries) { | ||
370 | if (packet_num == 0) | ||
371 | xid = random_xid(); | ||
372 | |||
373 | /* send discover packet */ | ||
374 | send_discover(xid, requested_ip); /* broadcast */ | ||
375 | |||
376 | timeout = now + client_config.timeout; | ||
377 | packet_num++; | ||
378 | } else { | ||
379 | run_script(NULL, "leasefail"); | ||
380 | if (client_config.background_if_no_lease) { | ||
381 | LOG(LOG_INFO, "No lease, forking to background."); | ||
382 | client_background(); | ||
383 | } else if (client_config.abort_if_no_lease) { | ||
384 | LOG(LOG_INFO, "No lease, failing."); | ||
385 | return 1; | ||
386 | } | ||
387 | /* wait to try again */ | ||
388 | packet_num = 0; | ||
389 | timeout = now + 60; | ||
390 | } | ||
391 | break; | ||
392 | case RENEW_REQUESTED: | ||
393 | case REQUESTING: | ||
394 | if (packet_num < client_config.retries) { | ||
395 | /* send request packet */ | ||
396 | if (state == RENEW_REQUESTED) | ||
397 | send_renew(xid, server_addr, requested_ip); /* unicast */ | ||
398 | else send_selecting(xid, server_addr, requested_ip); /* broadcast */ | ||
399 | |||
400 | timeout = now + ((packet_num == 2) ? 10 : 2); | ||
401 | packet_num++; | ||
402 | } else { | ||
403 | /* timed out, go back to init state */ | ||
404 | if (state == RENEW_REQUESTED) run_script(NULL, "deconfig"); | ||
405 | state = INIT_SELECTING; | ||
406 | timeout = now; | ||
407 | packet_num = 0; | ||
408 | change_mode(LISTEN_RAW); | ||
409 | } | ||
410 | break; | ||
411 | case BOUND: | ||
412 | /* Lease is starting to run out, time to enter renewing state */ | ||
413 | state = RENEWING; | ||
414 | change_mode(LISTEN_KERNEL); | ||
415 | DEBUG(LOG_INFO, "Entering renew state"); | ||
416 | /* fall right through */ | ||
417 | case RENEWING: | ||
418 | /* Either set a new T1, or enter REBINDING state */ | ||
419 | if ((t2 - t1) <= (lease / 14400 + 1)) { | ||
420 | /* timed out, enter rebinding state */ | ||
421 | state = REBINDING; | ||
422 | timeout = now + (t2 - t1); | ||
423 | DEBUG(LOG_INFO, "Entering rebinding state"); | ||
424 | } else { | ||
425 | /* send a request packet */ | ||
426 | send_renew(xid, server_addr, requested_ip); /* unicast */ | ||
427 | |||
428 | t1 = (t2 - t1) / 2 + t1; | ||
429 | timeout = t1 + start; | ||
430 | } | ||
431 | break; | ||
432 | case REBINDING: | ||
433 | /* Either set a new T2, or enter INIT state */ | ||
434 | if ((lease - t2) <= (lease / 14400 + 1)) { | ||
435 | /* timed out, enter init state */ | ||
436 | state = INIT_SELECTING; | ||
437 | LOG(LOG_INFO, "Lease lost, entering init state"); | ||
438 | run_script(NULL, "deconfig"); | ||
439 | timeout = now; | ||
440 | packet_num = 0; | ||
441 | change_mode(LISTEN_RAW); | ||
442 | } else { | ||
443 | /* send a request packet */ | ||
444 | send_renew(xid, 0, requested_ip); /* broadcast */ | ||
445 | |||
446 | t2 = (lease - t2) / 2 + t2; | ||
447 | timeout = t2 + start; | ||
448 | } | ||
449 | break; | ||
450 | case RELEASED: | ||
451 | /* yah, I know, *you* say it would never happen */ | ||
452 | timeout = 0x7fffffff; | ||
453 | break; | ||
454 | } | ||
455 | } else if (retval > 0 && listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds)) { | ||
456 | /* a packet is ready, read it */ | ||
457 | |||
458 | if (listen_mode == LISTEN_KERNEL) | ||
459 | len = get_packet(&packet, fd); | ||
460 | else len = get_raw_packet(&packet, fd); | ||
461 | |||
462 | if (len == -1 && errno != EINTR) { | ||
463 | DEBUG(LOG_INFO, "error on read, %m, reopening socket"); | ||
464 | change_mode(listen_mode); /* just close and reopen */ | ||
465 | } | ||
466 | if (len < 0) continue; | ||
467 | |||
468 | if (packet.xid != xid) { | ||
469 | DEBUG(LOG_INFO, "Ignoring XID %lx (our xid is %lx)", | ||
470 | (unsigned long) packet.xid, xid); | ||
471 | continue; | ||
472 | } | ||
473 | /* Ignore packets that aren't for us */ | ||
474 | if (memcmp(packet.chaddr, client_config.arp, 6)) { | ||
475 | DEBUG(LOG_INFO, "packet does not have our chaddr -- ignoring"); | ||
476 | continue; | ||
477 | } | ||
478 | |||
479 | if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) { | ||
480 | DEBUG(LOG_ERR, "couldnt get option from packet -- ignoring"); | ||
481 | continue; | ||
482 | } | ||
483 | |||
484 | switch (state) { | ||
485 | case INIT_SELECTING: | ||
486 | /* Must be a DHCPOFFER to one of our xid's */ | ||
487 | if (*message == DHCPOFFER) { | ||
488 | if ((temp = get_option(&packet, DHCP_SERVER_ID))) { | ||
489 | memcpy(&server_addr, temp, 4); | ||
490 | xid = packet.xid; | ||
491 | requested_ip = packet.yiaddr; | ||
492 | |||
493 | /* enter requesting state */ | ||
494 | state = REQUESTING; | ||
495 | timeout = now; | ||
496 | packet_num = 0; | ||
497 | } else { | ||
498 | DEBUG(LOG_ERR, "No server ID in message"); | ||
499 | } | ||
500 | } | ||
501 | break; | ||
502 | case RENEW_REQUESTED: | ||
503 | case REQUESTING: | ||
504 | case RENEWING: | ||
505 | case REBINDING: | ||
506 | if (*message == DHCPACK) { | ||
507 | if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) { | ||
508 | LOG(LOG_ERR, "No lease time with ACK, using 1 hour lease"); | ||
509 | lease = 60 * 60; | ||
510 | } else { | ||
511 | memcpy(&lease, temp, 4); | ||
512 | lease = ntohl(lease); | ||
513 | } | ||
514 | |||
515 | /* enter bound state */ | ||
516 | t1 = lease / 2; | ||
517 | |||
518 | /* little fixed point for n * .875 */ | ||
519 | t2 = (lease * 0x7) >> 3; | ||
520 | temp_addr.s_addr = packet.yiaddr; | ||
521 | LOG(LOG_INFO, "Lease of %s obtained, lease time %ld", | ||
522 | inet_ntoa(temp_addr), lease); | ||
523 | start = now; | ||
524 | timeout = t1 + start; | ||
525 | requested_ip = packet.yiaddr; | ||
526 | run_script(&packet, | ||
527 | ((state == RENEWING || state == REBINDING) ? "renew" : "bound")); | ||
528 | |||
529 | state = BOUND; | ||
530 | change_mode(LISTEN_NONE); | ||
531 | if (client_config.quit_after_lease) | ||
532 | return 0; | ||
533 | if (!client_config.foreground) | ||
534 | client_background(); | ||
535 | |||
536 | } else if (*message == DHCPNAK) { | ||
537 | /* return to init state */ | ||
538 | LOG(LOG_INFO, "Received DHCP NAK"); | ||
539 | run_script(&packet, "nak"); | ||
540 | if (state != REQUESTING) | ||
541 | run_script(NULL, "deconfig"); | ||
542 | state = INIT_SELECTING; | ||
543 | timeout = now; | ||
544 | requested_ip = 0; | ||
545 | packet_num = 0; | ||
546 | change_mode(LISTEN_RAW); | ||
547 | sleep(3); /* avoid excessive network traffic */ | ||
548 | } | ||
549 | break; | ||
550 | /* case BOUND, RELEASED: - ignore all packets */ | ||
551 | } | ||
552 | } else if (retval > 0 && (sig = udhcp_sp_read(&rfds))) { | ||
553 | switch (sig) { | ||
554 | case SIGUSR1: | ||
555 | perform_renew(); | ||
556 | break; | ||
557 | case SIGUSR2: | ||
558 | perform_release(); | ||
559 | break; | ||
560 | case SIGTERM: | ||
561 | LOG(LOG_INFO, "Received SIGTERM"); | ||
562 | return 0; | ||
563 | } | ||
564 | } else if (retval == -1 && errno == EINTR) { | ||
565 | /* a signal was caught */ | ||
566 | } else { | ||
567 | /* An error occured */ | ||
568 | DEBUG(LOG_ERR, "Error on select"); | ||
569 | } | ||
570 | |||
571 | } | ||
572 | return 0; | ||
573 | } | ||