aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--networking/udhcp/dhcpc.c299
1 files changed, 151 insertions, 148 deletions
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index fca5c2a03..077098f42 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -307,7 +307,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
307 /* Goes to stdout (unless NOMMU) and possibly syslog */ 307 /* Goes to stdout (unless NOMMU) and possibly syslog */
308 bb_info_msg("%s (v"BB_VER") started", applet_name); 308 bb_info_msg("%s (v"BB_VER") started", applet_name);
309 309
310 /* if not set, and not suppressed, setup the default client ID */ 310 /* If not set, and not suppressed, set up the default client ID */
311 if (!client_config.clientid && !(opt & OPT_C)) { 311 if (!client_config.clientid && !(opt & OPT_C)) {
312 client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7); 312 client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);
313 client_config.clientid[OPT_DATA] = 1; 313 client_config.clientid[OPT_DATA] = 1;
@@ -317,7 +317,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
317 if (!client_config.vendorclass) 317 if (!client_config.vendorclass)
318 client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, "udhcp "BB_VER, 0); 318 client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, "udhcp "BB_VER, 0);
319 319
320 /* setup the signal pipe */ 320 /* Set up the signal pipe */
321 udhcp_sp_setup(); 321 udhcp_sp_setup();
322 322
323 state = INIT_SELECTING; 323 state = INIT_SELECTING;
@@ -467,19 +467,45 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
467 /* yah, I know, *you* say it would never happen */ 467 /* yah, I know, *you* say it would never happen */
468 timeout = INT_MAX; 468 timeout = INT_MAX;
469 continue; /* back to main loop */ 469 continue; /* back to main loop */
470 } /* if select timed out */
471
472 /* select() didn't timeout, something happened */
473
474 /* Is it a signal? */
475 /* note: udhcp_sp_read checks FD_ISSET before reading */
476 switch (udhcp_sp_read(&rfds)) {
477 case SIGUSR1:
478 perform_renew();
479 /* Start things over */
480 packet_num = 0;
481 /* Kill any timeouts because the user wants this to hurry along */
482 timeout = 0;
483 continue;
484 case SIGUSR2:
485 perform_release(requested_ip, server_addr);
486 timeout = INT_MAX;
487 continue;
488 case SIGTERM:
489 bb_info_msg("Received SIGTERM");
490 if (opt & OPT_R) /* release on quit */
491 perform_release(requested_ip, server_addr);
492 goto ret0;
470 } 493 }
471 494
472 /* select() didn't timeout, something did happen. */
473 /* Is it a packet? */ 495 /* Is it a packet? */
474 if (listen_mode != LISTEN_NONE && FD_ISSET(sockfd, &rfds)) { 496 if (listen_mode == LISTEN_NONE || !FD_ISSET(sockfd, &rfds))
497 continue; /* no */
498
499 {
475 int len; 500 int len;
476 /* A packet is ready, read it */
477 501
502 /* A packet is ready, read it */
478 if (listen_mode == LISTEN_KERNEL) 503 if (listen_mode == LISTEN_KERNEL)
479 len = udhcp_recv_kernel_packet(&packet, sockfd); 504 len = udhcp_recv_kernel_packet(&packet, sockfd);
480 else 505 else
481 len = udhcp_recv_raw_packet(&packet, sockfd); 506 len = udhcp_recv_raw_packet(&packet, sockfd);
482 if (len == -1) { /* error is severe, reopen socket */ 507 if (len == -1) {
508 /* Error is severe, reopen socket */
483 bb_info_msg("Read error: %s, reopening socket", strerror(errno)); 509 bb_info_msg("Read error: %s, reopening socket", strerror(errno));
484 sleep(discover_timeout); /* 3 seconds by default */ 510 sleep(discover_timeout); /* 3 seconds by default */
485 change_listen_mode(listen_mode); /* just close and reopen */ 511 change_listen_mode(listen_mode); /* just close and reopen */
@@ -490,70 +516,71 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
490 already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; 516 already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
491 if (len < 0) 517 if (len < 0)
492 continue; 518 continue;
519 }
493 520
494 if (packet.xid != xid) { 521 if (packet.xid != xid) {
495 log1("xid %x (our is %x), ignoring packet", 522 log1("xid %x (our is %x), ignoring packet",
496 (unsigned)packet.xid, (unsigned)xid); 523 (unsigned)packet.xid, (unsigned)xid);
497 continue; 524 continue;
498 } 525 }
499 526
500 /* Ignore packets that aren't for us */ 527 /* Ignore packets that aren't for us */
501 if (packet.hlen != 6 528 if (packet.hlen != 6
502 || memcmp(packet.chaddr, client_config.client_mac, 6) 529 || memcmp(packet.chaddr, client_config.client_mac, 6)
503 ) { 530 ) {
504//FIXME: need to also check that last 10 bytes are zero 531//FIXME: need to also check that last 10 bytes are zero
505 log1("chaddr does not match, ignoring packet"); // log2? 532 log1("chaddr does not match, ignoring packet"); // log2?
506 continue; 533 continue;
507 } 534 }
508 535
509 message = get_option(&packet, DHCP_MESSAGE_TYPE); 536 message = get_option(&packet, DHCP_MESSAGE_TYPE);
510 if (message == NULL) { 537 if (message == NULL) {
511 bb_error_msg("no message type option, ignoring packet"); 538 bb_error_msg("no message type option, ignoring packet");
512 continue; 539 continue;
513 } 540 }
514 541
515 switch (state) { 542 switch (state) {
516 case INIT_SELECTING: 543 case INIT_SELECTING:
517 /* Must be a DHCPOFFER to one of our xid's */ 544 /* Must be a DHCPOFFER to one of our xid's */
518 if (*message == DHCPOFFER) { 545 if (*message == DHCPOFFER) {
519 /* TODO: why we don't just fetch server's IP from IP header? */ 546 /* TODO: why we don't just fetch server's IP from IP header? */
520 temp = get_option(&packet, DHCP_SERVER_ID); 547 temp = get_option(&packet, DHCP_SERVER_ID);
521 if (!temp) { 548 if (!temp) {
522 bb_error_msg("no server ID in message"); 549 bb_error_msg("no server ID in message");
523 continue; 550 continue;
524 /* still selecting - this server looks bad */ 551 /* still selecting - this server looks bad */
525 } 552 }
553 /* it IS unaligned sometimes, don't "optimize" */
554 move_from_unaligned32(server_addr, temp);
555 xid = packet.xid;
556 requested_ip = packet.yiaddr;
557
558 /* enter requesting state */
559 state = REQUESTING;
560 timeout = 0;
561 packet_num = 0;
562 already_waited_sec = 0;
563 }
564 continue;
565 case RENEW_REQUESTED:
566 case REQUESTING:
567 case RENEWING:
568 case REBINDING:
569 if (*message == DHCPACK) {
570 temp = get_option(&packet, DHCP_LEASE_TIME);
571 if (!temp) {
572 bb_error_msg("no lease time with ACK, using 1 hour lease");
573 lease_seconds = 60 * 60;
574 } else {
526 /* it IS unaligned sometimes, don't "optimize" */ 575 /* it IS unaligned sometimes, don't "optimize" */
527 move_from_unaligned32(server_addr, temp); 576 move_from_unaligned32(lease_seconds, temp);
528 xid = packet.xid; 577 lease_seconds = ntohl(lease_seconds);
529 requested_ip = packet.yiaddr; 578 lease_seconds &= 0x0fffffff; /* paranoia: must not be prone to overflows */
530 579 if (lease_seconds < 10) /* and not too small */
531 /* enter requesting state */ 580 lease_seconds = 10;
532 state = REQUESTING;
533 timeout = 0;
534 packet_num = 0;
535 already_waited_sec = 0;
536 } 581 }
537 continue;
538 case RENEW_REQUESTED:
539 case REQUESTING:
540 case RENEWING:
541 case REBINDING:
542 if (*message == DHCPACK) {
543 temp = get_option(&packet, DHCP_LEASE_TIME);
544 if (!temp) {
545 bb_error_msg("no lease time with ACK, using 1 hour lease");
546 lease_seconds = 60 * 60;
547 } else {
548 /* it IS unaligned sometimes, don't "optimize" */
549 move_from_unaligned32(lease_seconds, temp);
550 lease_seconds = ntohl(lease_seconds);
551 lease_seconds &= 0x0fffffff; /* paranoia: must not be prone to overflows */
552 if (lease_seconds < 10) /* and not too small */
553 lease_seconds = 10;
554 }
555#if ENABLE_FEATURE_UDHCPC_ARPING 582#if ENABLE_FEATURE_UDHCPC_ARPING
556 if (opt & OPT_a) { 583 if (opt & OPT_a) {
557/* RFC 2131 3.1 paragraph 5: 584/* RFC 2131 3.1 paragraph 5:
558 * "The client receives the DHCPACK message with configuration 585 * "The client receives the DHCPACK message with configuration
559 * parameters. The client SHOULD perform a final check on the 586 * parameters. The client SHOULD perform a final check on the
@@ -563,100 +590,76 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
563 * address is already in use (e.g., through the use of ARP), 590 * address is already in use (e.g., through the use of ARP),
564 * the client MUST send a DHCPDECLINE message to the server and restarts 591 * the client MUST send a DHCPDECLINE message to the server and restarts
565 * the configuration process..." */ 592 * the configuration process..." */
566 if (!arpping(packet.yiaddr, 593 if (!arpping(packet.yiaddr,
567 NULL, 594 NULL,
568 (uint32_t) 0, 595 (uint32_t) 0,
569 client_config.client_mac, 596 client_config.client_mac,
570 client_config.interface) 597 client_config.interface)
571 ) { 598 ) {
572 bb_info_msg("Offered address is in use " 599 bb_info_msg("Offered address is in use "
573 "(got ARP reply), declining"); 600 "(got ARP reply), declining");
574 send_decline(xid, server_addr, packet.yiaddr); 601 send_decline(xid, server_addr, packet.yiaddr);
575 602
576 if (state != REQUESTING) 603 if (state != REQUESTING)
577 udhcp_run_script(NULL, "deconfig"); 604 udhcp_run_script(NULL, "deconfig");
578 change_listen_mode(LISTEN_RAW); 605 change_listen_mode(LISTEN_RAW);
579 state = INIT_SELECTING; 606 state = INIT_SELECTING;
580 requested_ip = 0; 607 requested_ip = 0;
581 timeout = tryagain_timeout; 608 timeout = tryagain_timeout;
582 packet_num = 0; 609 packet_num = 0;
583 already_waited_sec = 0; 610 already_waited_sec = 0;
584 continue; /* back to main loop */ 611 continue; /* back to main loop */
585 }
586 }
587#endif
588 /* enter bound state */
589 timeout = lease_seconds / 2;
590 {
591 struct in_addr temp_addr;
592 temp_addr.s_addr = packet.yiaddr;
593 bb_info_msg("Lease of %s obtained, lease time %u",
594 inet_ntoa(temp_addr), (unsigned)lease_seconds);
595 }
596 requested_ip = packet.yiaddr;
597 udhcp_run_script(&packet,
598 ((state == RENEWING || state == REBINDING) ? "renew" : "bound"));
599
600 state = BOUND;
601 change_listen_mode(LISTEN_NONE);
602 if (opt & OPT_q) { /* quit after lease */
603 if (opt & OPT_R) /* release on quit */
604 perform_release(requested_ip, server_addr);
605 goto ret0;
606 }
607#if BB_MMU /* NOMMU case backgrounded earlier */
608 if (!(opt & OPT_f)) {
609 client_background();
610 /* do not background again! */
611 opt = ((opt & ~OPT_b) | OPT_f);
612 } 612 }
613 }
613#endif 614#endif
614 already_waited_sec = 0; 615 /* enter bound state */
615 continue; /* back to main loop */ 616 timeout = lease_seconds / 2;
617 {
618 struct in_addr temp_addr;
619 temp_addr.s_addr = packet.yiaddr;
620 bb_info_msg("Lease of %s obtained, lease time %u",
621 inet_ntoa(temp_addr), (unsigned)lease_seconds);
616 } 622 }
617 if (*message == DHCPNAK) { 623 requested_ip = packet.yiaddr;
618 /* return to init state */ 624 udhcp_run_script(&packet,
619 bb_info_msg("Received DHCP NAK"); 625 ((state == RENEWING || state == REBINDING) ? "renew" : "bound"));
620 udhcp_run_script(&packet, "nak"); 626
621 if (state != REQUESTING) 627 state = BOUND;
622 udhcp_run_script(NULL, "deconfig"); 628 change_listen_mode(LISTEN_NONE);
623 change_listen_mode(LISTEN_RAW); 629 if (opt & OPT_q) { /* quit after lease */
624 sleep(3); /* avoid excessive network traffic */ 630 if (opt & OPT_R) /* release on quit */
625 state = INIT_SELECTING; 631 perform_release(requested_ip, server_addr);
626 requested_ip = 0; 632 goto ret0;
627 timeout = 0;
628 packet_num = 0;
629 already_waited_sec = 0;
630 } 633 }
631 continue; 634#if BB_MMU /* NOMMU case backgrounded earlier */
632 /* case BOUND, RELEASED: - ignore all packets */ 635 if (!(opt & OPT_f)) {
636 client_background();
637 /* do not background again! */
638 opt = ((opt & ~OPT_b) | OPT_f);
639 }
640#endif
641 already_waited_sec = 0;
642 continue; /* back to main loop */
633 } 643 }
634 continue; /* back to main loop */ 644 if (*message == DHCPNAK) {
635 } 645 /* return to init state */
636 646 bb_info_msg("Received DHCP NAK");
637 /* select() didn't timeout, something did happen. 647 udhcp_run_script(&packet, "nak");
638 * But it wasn't a packet. It's a signal pipe then. */ 648 if (state != REQUESTING)
639 { 649 udhcp_run_script(NULL, "deconfig");
640 int signo = udhcp_sp_read(&rfds); 650 change_listen_mode(LISTEN_RAW);
641 switch (signo) { 651 sleep(3); /* avoid excessive network traffic */
642 case SIGUSR1: 652 state = INIT_SELECTING;
643 perform_renew(); 653 requested_ip = 0;
644 /* start things over */
645 packet_num = 0;
646 /* Kill any timeouts because the user wants this to hurry along */
647 timeout = 0; 654 timeout = 0;
648 break; 655 packet_num = 0;
649 case SIGUSR2: 656 already_waited_sec = 0;
650 perform_release(requested_ip, server_addr);
651 timeout = INT_MAX;
652 break;
653 case SIGTERM:
654 bb_info_msg("Received SIGTERM");
655 if (opt & OPT_R) /* release on quit */
656 perform_release(requested_ip, server_addr);
657 goto ret0;
658 } 657 }
658 continue;
659 /* case BOUND: - ignore all packets */
660 /* case RELEASED: - ignore all packets */
659 } 661 }
662 /* back to main loop */
660 } /* for (;;) - main loop ends */ 663 } /* for (;;) - main loop ends */
661 664
662 ret0: 665 ret0: