diff options
Diffstat (limited to 'networking/udhcp/dhcpc.c')
-rw-r--r-- | networking/udhcp/dhcpc.c | 127 |
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 */ |