aboutsummaryrefslogtreecommitdiff
path: root/networking/udhcp/dhcpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/udhcp/dhcpc.c')
-rw-r--r--networking/udhcp/dhcpc.c127
1 files changed, 54 insertions, 73 deletions
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index bbcbd1fca..a818c1875 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -1266,7 +1266,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1266 uint32_t xid = xid; /* for compiler */ 1266 uint32_t xid = xid; /* for compiler */
1267 int packet_num; 1267 int packet_num;
1268 int timeout; /* must be signed */ 1268 int timeout; /* must be signed */
1269 unsigned already_waited_sec; 1269 int lease_remaining; /* must be signed */
1270 unsigned opt; 1270 unsigned opt;
1271 IF_FEATURE_UDHCPC_ARPING(unsigned arpping_ms;) 1271 IF_FEATURE_UDHCPC_ARPING(unsigned arpping_ms;)
1272 int retval; 1272 int retval;
@@ -1411,18 +1411,15 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1411 change_listen_mode(LISTEN_RAW); 1411 change_listen_mode(LISTEN_RAW);
1412 packet_num = 0; 1412 packet_num = 0;
1413 timeout = 0; 1413 timeout = 0;
1414 already_waited_sec = 0; 1414 lease_remaining = 0;
1415 1415
1416 /* Main event loop. select() waits on signal pipe and possibly 1416 /* Main event loop. select() waits on signal pipe and possibly
1417 * on sockfd. 1417 * on sockfd.
1418 * "continue" statements in code below jump to the top of the loop. 1418 * "continue" statements in code below jump to the top of the loop.
1419 */ 1419 */
1420 for (;;) { 1420 for (;;) {
1421 int tv;
1422 struct pollfd pfds[2]; 1421 struct pollfd pfds[2];
1423 struct dhcp_packet packet; 1422 struct dhcp_packet packet;
1424 /* silence "uninitialized!" warning */
1425 unsigned timestamp_before_wait = timestamp_before_wait;
1426 1423
1427 //bb_error_msg("sockfd:%d, listen_mode:%d", client_data.sockfd, client_data.listen_mode); 1424 //bb_error_msg("sockfd:%d, listen_mode:%d", client_data.sockfd, client_data.listen_mode);
1428 1425
@@ -1435,17 +1432,24 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1435 1432
1436 udhcp_sp_fd_set(pfds, client_data.sockfd); 1433 udhcp_sp_fd_set(pfds, client_data.sockfd);
1437 1434
1438 tv = timeout - already_waited_sec;
1439 retval = 0; 1435 retval = 0;
1440 /* If we already timed out, fall through with retval = 0, else... */ 1436 /* If we already timed out, fall through with retval = 0, else... */
1441 if (tv > 0) { 1437 if (timeout > 0) {
1442 log1("waiting %u seconds", tv); 1438 unsigned diff;
1443 timestamp_before_wait = (unsigned)monotonic_sec(); 1439
1444 retval = poll(pfds, 2, tv < INT_MAX/1000 ? tv * 1000 : INT_MAX); 1440 if (timeout > INT_MAX/1000)
1441 timeout = INT_MAX/1000;
1442 log1("waiting %u seconds", timeout);
1443 diff = (unsigned)monotonic_sec();
1444 retval = poll(pfds, 2, timeout * 1000);
1445 if (retval < 0) { 1445 if (retval < 0) {
1446 /* EINTR? A signal was caught, don't panic */ 1446 /* EINTR? A signal was caught, don't panic */
1447 if (errno == EINTR) { 1447 if (errno == EINTR) {
1448 already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; 1448 diff = (unsigned)monotonic_sec() - diff;
1449 lease_remaining -= diff;
1450 if (lease_remaining < 0)
1451 lease_remaining = 0;
1452 timeout -= diff;
1449 continue; 1453 continue;
1450 } 1454 }
1451 /* Else: an error occurred, panic! */ 1455 /* Else: an error occurred, panic! */
@@ -1472,9 +1476,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1472 if (clientid_mac_ptr) 1476 if (clientid_mac_ptr)
1473 memcpy(clientid_mac_ptr, client_data.client_mac, 6); 1477 memcpy(clientid_mac_ptr, client_data.client_mac, 6);
1474 1478
1475 /* We will restart the wait in any case */
1476 already_waited_sec = 0;
1477
1478 switch (client_data.state) { 1479 switch (client_data.state) {
1479 case INIT_SELECTING: 1480 case INIT_SELECTING:
1480 if (!discover_retries || packet_num < discover_retries) { 1481 if (!discover_retries || packet_num < discover_retries) {
@@ -1536,7 +1537,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1536 case RENEW_REQUESTED: /* manual (SIGUSR1) renew */ 1537 case RENEW_REQUESTED: /* manual (SIGUSR1) renew */
1537 case_RENEW_REQUESTED: 1538 case_RENEW_REQUESTED:
1538 case RENEWING: 1539 case RENEWING:
1539 if (timeout >= 60) { 1540 if (packet_num < 3) {
1541 packet_num++;
1540 /* send an unicast renew request */ 1542 /* send an unicast renew request */
1541 /* Sometimes observed to fail (EADDRNOTAVAIL) to bind 1543 /* Sometimes observed to fail (EADDRNOTAVAIL) to bind
1542 * a new UDP socket for sending inside send_renew. 1544 * a new UDP socket for sending inside send_renew.
@@ -1547,14 +1549,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1547 * into INIT_SELECTING state. 1549 * into INIT_SELECTING state.
1548 */ 1550 */
1549 if (send_renew(xid, server_addr, requested_ip) >= 0) { 1551 if (send_renew(xid, server_addr, requested_ip) >= 0) {
1550 timeout >>= 1; 1552 timeout = discover_timeout;
1551//TODO: the timeout to receive an answer for our renew should not be selected 1553 /* ^^^ used to be = lease_remaining / 2 - WAY too long */
1552//with "timeout = lease_seconds / 2; ...; timeout = timeout / 2": it is often huge.
1553//Waiting e.g. 4*3600 seconds for a reply does not make sense
1554//(if reply isn't coming, we keep an open socket for hours),
1555//it should be something like 10 seconds.
1556//Also, it's probably best to try sending renew in kernel mode a few (3-5) times
1557//and fall back to raw mode if it does not work.
1558 continue; 1554 continue;
1559 } 1555 }
1560 /* else: error sending. 1556 /* else: error sending.
@@ -1563,6 +1559,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1563 * which wasn't reachable (and probably did not exist). 1559 * which wasn't reachable (and probably did not exist).
1564 */ 1560 */
1565 } 1561 }
1562//TODO: if 3 renew's failed (no reply) but remaining lease is large,
1563//it might make sense to make a large pause (~1 hour?) and try later?
1566 /* Timed out or error, enter rebinding state */ 1564 /* Timed out or error, enter rebinding state */
1567 log1s("entering rebinding state"); 1565 log1s("entering rebinding state");
1568 client_data.state = REBINDING; 1566 client_data.state = REBINDING;
@@ -1572,10 +1570,10 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1572 change_listen_mode(LISTEN_RAW); 1570 change_listen_mode(LISTEN_RAW);
1573 /* Lease is *really* about to run out, 1571 /* Lease is *really* about to run out,
1574 * try to find DHCP server using broadcast */ 1572 * try to find DHCP server using broadcast */
1575 if (timeout > 0) { 1573 if (lease_remaining > 0) {
1576 /* send a broadcast renew request */ 1574 /* send a broadcast renew request */
1577 send_renew(xid, 0 /*INADDR_ANY*/, requested_ip); 1575 send_renew(xid, 0 /*INADDR_ANY*/, requested_ip);
1578 timeout >>= 1; 1576 timeout = discover_timeout;
1579 continue; 1577 continue;
1580 } 1578 }
1581 /* Timed out, enter init state */ 1579 /* Timed out, enter init state */
@@ -1583,7 +1581,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1583 udhcp_run_script(NULL, "deconfig"); 1581 udhcp_run_script(NULL, "deconfig");
1584 client_data.state = INIT_SELECTING; 1582 client_data.state = INIT_SELECTING;
1585 client_data.first_secs = 0; /* make secs field count from 0 */ 1583 client_data.first_secs = 0; /* make secs field count from 0 */
1586 /*timeout = 0; - already is */ 1584 timeout = 0;
1587 packet_num = 0; 1585 packet_num = 0;
1588 continue; 1586 continue;
1589 /* case RELEASED: */ 1587 /* case RELEASED: */
@@ -1599,21 +1597,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1599 switch (udhcp_sp_read()) { 1597 switch (udhcp_sp_read()) {
1600 case SIGUSR1: 1598 case SIGUSR1:
1601 client_data.first_secs = 0; /* make secs field count from 0 */ 1599 client_data.first_secs = 0; /* make secs field count from 0 */
1602 already_waited_sec = 0;
1603 perform_renew(); 1600 perform_renew();
1604 if (client_data.state == RENEW_REQUESTED) { 1601 if (client_data.state == RENEW_REQUESTED)
1605 /* We might be either on the same network
1606 * (in which case renew might work),
1607 * or we might be on a completely different one
1608 * (in which case renew won't ever succeed).
1609 * For the second case, must make sure timeout
1610 * is not too big, or else we can send
1611 * futile renew requests for hours.
1612 */
1613 if (timeout > 60)
1614 timeout = 60;
1615 goto case_RENEW_REQUESTED; 1602 goto case_RENEW_REQUESTED;
1616 }
1617 /* Start things over */ 1603 /* Start things over */
1618 packet_num = 0; 1604 packet_num = 0;
1619 /* Kill any timeouts, user wants this to hurry along */ 1605 /* Kill any timeouts, user wants this to hurry along */
@@ -1646,10 +1632,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1646 sleep(discover_timeout); /* 3 seconds by default */ 1632 sleep(discover_timeout); /* 3 seconds by default */
1647 change_listen_mode(client_data.listen_mode); /* just close and reopen */ 1633 change_listen_mode(client_data.listen_mode); /* just close and reopen */
1648 } 1634 }
1649 /* If this packet will turn out to be unrelated/bogus,
1650 * we will go back and wait for next one.
1651 * Be sure timeout is properly decreased. */
1652 already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
1653 if (len < 0) 1635 if (len < 0)
1654 continue; 1636 continue;
1655 } 1637 }
@@ -1722,7 +1704,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1722 client_data.state = REQUESTING; 1704 client_data.state = REQUESTING;
1723 timeout = 0; 1705 timeout = 0;
1724 packet_num = 0; 1706 packet_num = 0;
1725 already_waited_sec = 0;
1726 } 1707 }
1727 continue; 1708 continue;
1728 case REQUESTING: 1709 case REQUESTING:
@@ -1731,28 +1712,38 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1731 case REBINDING: 1712 case REBINDING:
1732 if (*message == DHCPACK) { 1713 if (*message == DHCPACK) {
1733 unsigned start; 1714 unsigned start;
1734 uint32_t lease_seconds;
1735 struct in_addr temp_addr; 1715 struct in_addr temp_addr;
1736 char server_str[sizeof("255.255.255.255")]; 1716 char server_str[sizeof("255.255.255.255")];
1737 uint8_t *temp; 1717 uint8_t *temp;
1738 1718
1719 temp_addr.s_addr = server_addr;
1720 strcpy(server_str, inet_ntoa(temp_addr));
1721 temp_addr.s_addr = packet.yiaddr;
1722
1739 temp = udhcp_get_option32(&packet, DHCP_LEASE_TIME); 1723 temp = udhcp_get_option32(&packet, DHCP_LEASE_TIME);
1740 if (!temp) { 1724 if (!temp) {
1741 bb_simple_info_msg("no lease time with ACK, using 1 hour lease"); 1725 lease_remaining = 60 * 60;
1742 lease_seconds = 60 * 60;
1743 } else { 1726 } else {
1727 uint32_t lease;
1744 /* it IS unaligned sometimes, don't "optimize" */ 1728 /* it IS unaligned sometimes, don't "optimize" */
1745 move_from_unaligned32(lease_seconds, temp); 1729 move_from_unaligned32(lease, temp);
1746 lease_seconds = ntohl(lease_seconds); 1730 lease_remaining = ntohl(lease);
1747 /* paranoia: must not be too small and not prone to overflows */
1748 /* timeout > 60 - ensures at least one unicast renew attempt */
1749 if (lease_seconds < 2 * 61)
1750 lease_seconds = 2 * 61;
1751 //if (lease_seconds > 0x7fffffff)
1752 // lease_seconds = 0x7fffffff;
1753 //^^^not necessary since "timeout = lease_seconds / 2"
1754 //does not overflow even for 0xffffffff.
1755 } 1731 }
1732 /* Log message _before_ we sanitize lease */
1733 bb_info_msg("lease of %s obtained from %s, lease time %u%s",
1734 inet_ntoa(temp_addr), server_str, (unsigned)lease_remaining,
1735 temp ? "" : " (default)"
1736 );
1737 /* paranoia: must not be too small and not prone to overflows */
1738 /* NB: 60s leases _are_ used in real world
1739 * (temporary IPs while ISP modem initializes)
1740 * do not break this case by bumplit it up.
1741 */
1742 if (lease_remaining < 0) /* signed overflow? */
1743 lease_remaining = INT_MAX;
1744 if (lease_remaining < 30)
1745 lease_remaining = 30;
1746 requested_ip = packet.yiaddr;
1756#if ENABLE_FEATURE_UDHCPC_ARPING 1747#if ENABLE_FEATURE_UDHCPC_ARPING
1757 if (opt & OPT_a) { 1748 if (opt & OPT_a) {
1758/* RFC 2131 3.1 paragraph 5: 1749/* RFC 2131 3.1 paragraph 5:
@@ -1764,7 +1755,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1764 * address is already in use (e.g., through the use of ARP), 1755 * address is already in use (e.g., through the use of ARP),
1765 * the client MUST send a DHCPDECLINE message to the server and restarts 1756 * the client MUST send a DHCPDECLINE message to the server and restarts
1766 * the configuration process..." */ 1757 * the configuration process..." */
1767 if (!arpping(packet.yiaddr, 1758 if (!arpping(requested_ip,
1768 NULL, 1759 NULL,
1769 (uint32_t) 0, 1760 (uint32_t) 0,
1770 client_data.client_mac, 1761 client_data.client_mac,
@@ -1783,27 +1774,18 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1783 requested_ip = 0; 1774 requested_ip = 0;
1784 timeout = tryagain_timeout; 1775 timeout = tryagain_timeout;
1785 packet_num = 0; 1776 packet_num = 0;
1786 already_waited_sec = 0;
1787 continue; /* back to main loop */ 1777 continue; /* back to main loop */
1788 } 1778 }
1789 } 1779 }
1790#endif 1780#endif
1791 /* enter bound state */
1792 temp_addr.s_addr = server_addr;
1793 strcpy(server_str, inet_ntoa(temp_addr));
1794 temp_addr.s_addr = packet.yiaddr;
1795 bb_info_msg("lease of %s obtained from %s, lease time %u",
1796 inet_ntoa(temp_addr), server_str, (unsigned)lease_seconds);
1797 requested_ip = packet.yiaddr;
1798 1781
1782 /* enter bound state */
1799 start = monotonic_sec(); 1783 start = monotonic_sec();
1800 udhcp_run_script(&packet, client_data.state == REQUESTING ? "bound" : "renew"); 1784 udhcp_run_script(&packet, client_data.state == REQUESTING ? "bound" : "renew");
1801 already_waited_sec = (unsigned)monotonic_sec() - start; 1785 timeout = (unsigned)lease_remaining / 2;
1802 timeout = lease_seconds / 2; 1786//TODO: why / 2?
1803 if ((unsigned)timeout < already_waited_sec) { 1787 timeout -= (unsigned)monotonic_sec() - start;
1804 /* Something went wrong. Back to discover state */ 1788 packet_num = 0;
1805 timeout = already_waited_sec = 0;
1806 }
1807 1789
1808 client_data.state = BOUND; 1790 client_data.state = BOUND;
1809 change_listen_mode(LISTEN_NONE); 1791 change_listen_mode(LISTEN_NONE);
@@ -1856,7 +1838,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1856 requested_ip = 0; 1838 requested_ip = 0;
1857 timeout = 0; 1839 timeout = 0;
1858 packet_num = 0; 1840 packet_num = 0;
1859 already_waited_sec = 0;
1860 } 1841 }
1861 continue; 1842 continue;
1862 /* case BOUND: - ignore all packets */ 1843 /* case BOUND: - ignore all packets */