diff options
Diffstat (limited to 'networking/udhcp/dhcpc.c')
-rw-r--r-- | networking/udhcp/dhcpc.c | 170 |
1 files changed, 71 insertions, 99 deletions
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index bbcbd1fca..6666cbce6 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -1027,7 +1027,6 @@ static int udhcp_raw_socket(int ifindex) | |||
1027 | * SOCK_DGRAM: remove link-layer headers on input (SOCK_RAW keeps them) | 1027 | * SOCK_DGRAM: remove link-layer headers on input (SOCK_RAW keeps them) |
1028 | * ETH_P_IP: want to receive only packets with IPv4 eth type | 1028 | * ETH_P_IP: want to receive only packets with IPv4 eth type |
1029 | */ | 1029 | */ |
1030 | log3("got raw socket fd %d", fd); | ||
1031 | 1030 | ||
1032 | memset(&sock, 0, sizeof(sock)); /* let's be deterministic */ | 1031 | memset(&sock, 0, sizeof(sock)); /* let's be deterministic */ |
1033 | sock.sll_family = AF_PACKET; | 1032 | sock.sll_family = AF_PACKET; |
@@ -1122,29 +1121,6 @@ static void change_listen_mode(int new_mode) | |||
1122 | /* else LISTEN_NONE: client_data.sockfd stays closed */ | 1121 | /* else LISTEN_NONE: client_data.sockfd stays closed */ |
1123 | } | 1122 | } |
1124 | 1123 | ||
1125 | /* Called only on SIGUSR1 */ | ||
1126 | static void perform_renew(void) | ||
1127 | { | ||
1128 | bb_simple_info_msg("performing DHCP renew"); | ||
1129 | switch (client_data.state) { | ||
1130 | case BOUND: | ||
1131 | change_listen_mode(LISTEN_KERNEL); | ||
1132 | case RENEWING: | ||
1133 | case REBINDING: | ||
1134 | client_data.state = RENEW_REQUESTED; | ||
1135 | break; | ||
1136 | case RENEW_REQUESTED: /* impatient are we? fine, square 1 */ | ||
1137 | udhcp_run_script(NULL, "deconfig"); | ||
1138 | case REQUESTING: | ||
1139 | case RELEASED: | ||
1140 | change_listen_mode(LISTEN_RAW); | ||
1141 | client_data.state = INIT_SELECTING; | ||
1142 | break; | ||
1143 | case INIT_SELECTING: | ||
1144 | break; | ||
1145 | } | ||
1146 | } | ||
1147 | |||
1148 | static void perform_release(uint32_t server_addr, uint32_t requested_ip) | 1124 | static void perform_release(uint32_t server_addr, uint32_t requested_ip) |
1149 | { | 1125 | { |
1150 | char buffer[sizeof("255.255.255.255")]; | 1126 | char buffer[sizeof("255.255.255.255")]; |
@@ -1247,7 +1223,6 @@ static void client_background(void) | |||
1247 | //usage: "\n USR1 Renew lease" | 1223 | //usage: "\n USR1 Renew lease" |
1248 | //usage: "\n USR2 Release lease" | 1224 | //usage: "\n USR2 Release lease" |
1249 | 1225 | ||
1250 | |||
1251 | int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1226 | int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1252 | int udhcpc_main(int argc UNUSED_PARAM, char **argv) | 1227 | int udhcpc_main(int argc UNUSED_PARAM, char **argv) |
1253 | { | 1228 | { |
@@ -1266,7 +1241,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1266 | uint32_t xid = xid; /* for compiler */ | 1241 | uint32_t xid = xid; /* for compiler */ |
1267 | int packet_num; | 1242 | int packet_num; |
1268 | int timeout; /* must be signed */ | 1243 | int timeout; /* must be signed */ |
1269 | unsigned already_waited_sec; | 1244 | int lease_remaining; /* must be signed */ |
1270 | unsigned opt; | 1245 | unsigned opt; |
1271 | IF_FEATURE_UDHCPC_ARPING(unsigned arpping_ms;) | 1246 | IF_FEATURE_UDHCPC_ARPING(unsigned arpping_ms;) |
1272 | int retval; | 1247 | int retval; |
@@ -1411,18 +1386,15 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1411 | change_listen_mode(LISTEN_RAW); | 1386 | change_listen_mode(LISTEN_RAW); |
1412 | packet_num = 0; | 1387 | packet_num = 0; |
1413 | timeout = 0; | 1388 | timeout = 0; |
1414 | already_waited_sec = 0; | 1389 | lease_remaining = 0; |
1415 | 1390 | ||
1416 | /* Main event loop. select() waits on signal pipe and possibly | 1391 | /* Main event loop. select() waits on signal pipe and possibly |
1417 | * on sockfd. | 1392 | * on sockfd. |
1418 | * "continue" statements in code below jump to the top of the loop. | 1393 | * "continue" statements in code below jump to the top of the loop. |
1419 | */ | 1394 | */ |
1420 | for (;;) { | 1395 | for (;;) { |
1421 | int tv; | ||
1422 | struct pollfd pfds[2]; | 1396 | struct pollfd pfds[2]; |
1423 | struct dhcp_packet packet; | 1397 | struct dhcp_packet packet; |
1424 | /* silence "uninitialized!" warning */ | ||
1425 | unsigned timestamp_before_wait = timestamp_before_wait; | ||
1426 | 1398 | ||
1427 | //bb_error_msg("sockfd:%d, listen_mode:%d", client_data.sockfd, client_data.listen_mode); | 1399 | //bb_error_msg("sockfd:%d, listen_mode:%d", client_data.sockfd, client_data.listen_mode); |
1428 | 1400 | ||
@@ -1435,17 +1407,24 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1435 | 1407 | ||
1436 | udhcp_sp_fd_set(pfds, client_data.sockfd); | 1408 | udhcp_sp_fd_set(pfds, client_data.sockfd); |
1437 | 1409 | ||
1438 | tv = timeout - already_waited_sec; | ||
1439 | retval = 0; | 1410 | retval = 0; |
1440 | /* If we already timed out, fall through with retval = 0, else... */ | 1411 | /* If we already timed out, fall through with retval = 0, else... */ |
1441 | if (tv > 0) { | 1412 | if (timeout > 0) { |
1442 | log1("waiting %u seconds", tv); | 1413 | unsigned diff; |
1443 | timestamp_before_wait = (unsigned)monotonic_sec(); | 1414 | |
1444 | retval = poll(pfds, 2, tv < INT_MAX/1000 ? tv * 1000 : INT_MAX); | 1415 | if (timeout > INT_MAX/1000) |
1416 | timeout = INT_MAX/1000; | ||
1417 | log1("waiting %u seconds", timeout); | ||
1418 | diff = (unsigned)monotonic_sec(); | ||
1419 | retval = poll(pfds, 2, timeout * 1000); | ||
1445 | if (retval < 0) { | 1420 | if (retval < 0) { |
1446 | /* EINTR? A signal was caught, don't panic */ | 1421 | /* EINTR? A signal was caught, don't panic */ |
1447 | if (errno == EINTR) { | 1422 | if (errno == EINTR) { |
1448 | already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; | 1423 | diff = (unsigned)monotonic_sec() - diff; |
1424 | lease_remaining -= diff; | ||
1425 | if (lease_remaining < 0) | ||
1426 | lease_remaining = 0; | ||
1427 | timeout -= diff; | ||
1449 | continue; | 1428 | continue; |
1450 | } | 1429 | } |
1451 | /* Else: an error occurred, panic! */ | 1430 | /* Else: an error occurred, panic! */ |
@@ -1472,9 +1451,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1472 | if (clientid_mac_ptr) | 1451 | if (clientid_mac_ptr) |
1473 | memcpy(clientid_mac_ptr, client_data.client_mac, 6); | 1452 | memcpy(clientid_mac_ptr, client_data.client_mac, 6); |
1474 | 1453 | ||
1475 | /* We will restart the wait in any case */ | ||
1476 | already_waited_sec = 0; | ||
1477 | |||
1478 | switch (client_data.state) { | 1454 | switch (client_data.state) { |
1479 | case INIT_SELECTING: | 1455 | case INIT_SELECTING: |
1480 | if (!discover_retries || packet_num < discover_retries) { | 1456 | if (!discover_retries || packet_num < discover_retries) { |
@@ -1536,7 +1512,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1536 | case RENEW_REQUESTED: /* manual (SIGUSR1) renew */ | 1512 | case RENEW_REQUESTED: /* manual (SIGUSR1) renew */ |
1537 | case_RENEW_REQUESTED: | 1513 | case_RENEW_REQUESTED: |
1538 | case RENEWING: | 1514 | case RENEWING: |
1539 | if (timeout >= 60) { | 1515 | if (packet_num < 3) { |
1516 | packet_num++; | ||
1540 | /* send an unicast renew request */ | 1517 | /* send an unicast renew request */ |
1541 | /* Sometimes observed to fail (EADDRNOTAVAIL) to bind | 1518 | /* Sometimes observed to fail (EADDRNOTAVAIL) to bind |
1542 | * a new UDP socket for sending inside send_renew. | 1519 | * a new UDP socket for sending inside send_renew. |
@@ -1547,14 +1524,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1547 | * into INIT_SELECTING state. | 1524 | * into INIT_SELECTING state. |
1548 | */ | 1525 | */ |
1549 | if (send_renew(xid, server_addr, requested_ip) >= 0) { | 1526 | if (send_renew(xid, server_addr, requested_ip) >= 0) { |
1550 | timeout >>= 1; | 1527 | timeout = discover_timeout; |
1551 | //TODO: the timeout to receive an answer for our renew should not be selected | 1528 | /* ^^^ 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; | 1529 | continue; |
1559 | } | 1530 | } |
1560 | /* else: error sending. | 1531 | /* else: error sending. |
@@ -1563,6 +1534,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1563 | * which wasn't reachable (and probably did not exist). | 1534 | * which wasn't reachable (and probably did not exist). |
1564 | */ | 1535 | */ |
1565 | } | 1536 | } |
1537 | //TODO: if 3 renew's failed (no reply) but remaining lease is large, | ||
1538 | //it might make sense to make a large pause (~1 hour?) and try later? | ||
1566 | /* Timed out or error, enter rebinding state */ | 1539 | /* Timed out or error, enter rebinding state */ |
1567 | log1s("entering rebinding state"); | 1540 | log1s("entering rebinding state"); |
1568 | client_data.state = REBINDING; | 1541 | client_data.state = REBINDING; |
@@ -1572,10 +1545,10 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1572 | change_listen_mode(LISTEN_RAW); | 1545 | change_listen_mode(LISTEN_RAW); |
1573 | /* Lease is *really* about to run out, | 1546 | /* Lease is *really* about to run out, |
1574 | * try to find DHCP server using broadcast */ | 1547 | * try to find DHCP server using broadcast */ |
1575 | if (timeout > 0) { | 1548 | if (lease_remaining > 0) { |
1576 | /* send a broadcast renew request */ | 1549 | /* send a broadcast renew request */ |
1577 | send_renew(xid, 0 /*INADDR_ANY*/, requested_ip); | 1550 | send_renew(xid, 0 /*INADDR_ANY*/, requested_ip); |
1578 | timeout >>= 1; | 1551 | timeout = discover_timeout; |
1579 | continue; | 1552 | continue; |
1580 | } | 1553 | } |
1581 | /* Timed out, enter init state */ | 1554 | /* Timed out, enter init state */ |
@@ -1583,7 +1556,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1583 | udhcp_run_script(NULL, "deconfig"); | 1556 | udhcp_run_script(NULL, "deconfig"); |
1584 | client_data.state = INIT_SELECTING; | 1557 | client_data.state = INIT_SELECTING; |
1585 | client_data.first_secs = 0; /* make secs field count from 0 */ | 1558 | client_data.first_secs = 0; /* make secs field count from 0 */ |
1586 | /*timeout = 0; - already is */ | 1559 | timeout = 0; |
1587 | packet_num = 0; | 1560 | packet_num = 0; |
1588 | continue; | 1561 | continue; |
1589 | /* case RELEASED: */ | 1562 | /* case RELEASED: */ |
@@ -1599,22 +1572,26 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1599 | switch (udhcp_sp_read()) { | 1572 | switch (udhcp_sp_read()) { |
1600 | case SIGUSR1: | 1573 | case SIGUSR1: |
1601 | client_data.first_secs = 0; /* make secs field count from 0 */ | 1574 | client_data.first_secs = 0; /* make secs field count from 0 */ |
1602 | already_waited_sec = 0; | 1575 | bb_simple_info_msg("performing DHCP renew"); |
1603 | perform_renew(); | 1576 | |
1604 | if (client_data.state == RENEW_REQUESTED) { | 1577 | switch (client_data.state) { |
1605 | /* We might be either on the same network | 1578 | /* Try to renew/rebind */ |
1606 | * (in which case renew might work), | 1579 | case BOUND: |
1607 | * or we might be on a completely different one | 1580 | case RENEWING: |
1608 | * (in which case renew won't ever succeed). | 1581 | case REBINDING: |
1609 | * For the second case, must make sure timeout | 1582 | change_listen_mode(LISTEN_KERNEL); |
1610 | * is not too big, or else we can send | 1583 | client_data.state = RENEW_REQUESTED; |
1611 | * futile renew requests for hours. | ||
1612 | */ | ||
1613 | if (timeout > 60) | ||
1614 | timeout = 60; | ||
1615 | goto case_RENEW_REQUESTED; | 1584 | goto case_RENEW_REQUESTED; |
1616 | } | 1585 | |
1617 | /* Start things over */ | 1586 | /* Start things over */ |
1587 | case RENEW_REQUESTED: /* two or more SIGUSR1 received */ | ||
1588 | udhcp_run_script(NULL, "deconfig"); | ||
1589 | /* case REQUESTING: break; */ | ||
1590 | /* case RELEASED: break; */ | ||
1591 | /* case INIT_SELECTING: break; */ | ||
1592 | } | ||
1593 | change_listen_mode(LISTEN_RAW); | ||
1594 | client_data.state = INIT_SELECTING; | ||
1618 | packet_num = 0; | 1595 | packet_num = 0; |
1619 | /* Kill any timeouts, user wants this to hurry along */ | 1596 | /* Kill any timeouts, user wants this to hurry along */ |
1620 | timeout = 0; | 1597 | timeout = 0; |
@@ -1646,10 +1623,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1646 | sleep(discover_timeout); /* 3 seconds by default */ | 1623 | sleep(discover_timeout); /* 3 seconds by default */ |
1647 | change_listen_mode(client_data.listen_mode); /* just close and reopen */ | 1624 | change_listen_mode(client_data.listen_mode); /* just close and reopen */ |
1648 | } | 1625 | } |
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) | 1626 | if (len < 0) |
1654 | continue; | 1627 | continue; |
1655 | } | 1628 | } |
@@ -1722,7 +1695,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1722 | client_data.state = REQUESTING; | 1695 | client_data.state = REQUESTING; |
1723 | timeout = 0; | 1696 | timeout = 0; |
1724 | packet_num = 0; | 1697 | packet_num = 0; |
1725 | already_waited_sec = 0; | ||
1726 | } | 1698 | } |
1727 | continue; | 1699 | continue; |
1728 | case REQUESTING: | 1700 | case REQUESTING: |
@@ -1731,28 +1703,38 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1731 | case REBINDING: | 1703 | case REBINDING: |
1732 | if (*message == DHCPACK) { | 1704 | if (*message == DHCPACK) { |
1733 | unsigned start; | 1705 | unsigned start; |
1734 | uint32_t lease_seconds; | ||
1735 | struct in_addr temp_addr; | 1706 | struct in_addr temp_addr; |
1736 | char server_str[sizeof("255.255.255.255")]; | 1707 | char server_str[sizeof("255.255.255.255")]; |
1737 | uint8_t *temp; | 1708 | uint8_t *temp; |
1738 | 1709 | ||
1710 | temp_addr.s_addr = server_addr; | ||
1711 | strcpy(server_str, inet_ntoa(temp_addr)); | ||
1712 | temp_addr.s_addr = packet.yiaddr; | ||
1713 | |||
1739 | temp = udhcp_get_option32(&packet, DHCP_LEASE_TIME); | 1714 | temp = udhcp_get_option32(&packet, DHCP_LEASE_TIME); |
1740 | if (!temp) { | 1715 | if (!temp) { |
1741 | bb_simple_info_msg("no lease time with ACK, using 1 hour lease"); | 1716 | lease_remaining = 60 * 60; |
1742 | lease_seconds = 60 * 60; | ||
1743 | } else { | 1717 | } else { |
1718 | uint32_t lease; | ||
1744 | /* it IS unaligned sometimes, don't "optimize" */ | 1719 | /* it IS unaligned sometimes, don't "optimize" */ |
1745 | move_from_unaligned32(lease_seconds, temp); | 1720 | move_from_unaligned32(lease, temp); |
1746 | lease_seconds = ntohl(lease_seconds); | 1721 | 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 | } | 1722 | } |
1723 | /* Log message _before_ we sanitize lease */ | ||
1724 | bb_info_msg("lease of %s obtained from %s, lease time %u%s", | ||
1725 | inet_ntoa(temp_addr), server_str, (unsigned)lease_remaining, | ||
1726 | temp ? "" : " (default)" | ||
1727 | ); | ||
1728 | /* paranoia: must not be too small and not prone to overflows */ | ||
1729 | /* NB: 60s leases _are_ used in real world | ||
1730 | * (temporary IPs while ISP modem initializes) | ||
1731 | * do not break this case by bumping it up. | ||
1732 | */ | ||
1733 | if (lease_remaining < 0) /* signed overflow? */ | ||
1734 | lease_remaining = INT_MAX; | ||
1735 | if (lease_remaining < 30) | ||
1736 | lease_remaining = 30; | ||
1737 | requested_ip = packet.yiaddr; | ||
1756 | #if ENABLE_FEATURE_UDHCPC_ARPING | 1738 | #if ENABLE_FEATURE_UDHCPC_ARPING |
1757 | if (opt & OPT_a) { | 1739 | if (opt & OPT_a) { |
1758 | /* RFC 2131 3.1 paragraph 5: | 1740 | /* RFC 2131 3.1 paragraph 5: |
@@ -1764,7 +1746,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1764 | * address is already in use (e.g., through the use of ARP), | 1746 | * 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 | 1747 | * the client MUST send a DHCPDECLINE message to the server and restarts |
1766 | * the configuration process..." */ | 1748 | * the configuration process..." */ |
1767 | if (!arpping(packet.yiaddr, | 1749 | if (!arpping(requested_ip, |
1768 | NULL, | 1750 | NULL, |
1769 | (uint32_t) 0, | 1751 | (uint32_t) 0, |
1770 | client_data.client_mac, | 1752 | client_data.client_mac, |
@@ -1783,27 +1765,18 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1783 | requested_ip = 0; | 1765 | requested_ip = 0; |
1784 | timeout = tryagain_timeout; | 1766 | timeout = tryagain_timeout; |
1785 | packet_num = 0; | 1767 | packet_num = 0; |
1786 | already_waited_sec = 0; | ||
1787 | continue; /* back to main loop */ | 1768 | continue; /* back to main loop */ |
1788 | } | 1769 | } |
1789 | } | 1770 | } |
1790 | #endif | 1771 | #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 | 1772 | ||
1773 | /* enter bound state */ | ||
1799 | start = monotonic_sec(); | 1774 | start = monotonic_sec(); |
1800 | udhcp_run_script(&packet, client_data.state == REQUESTING ? "bound" : "renew"); | 1775 | udhcp_run_script(&packet, client_data.state == REQUESTING ? "bound" : "renew"); |
1801 | already_waited_sec = (unsigned)monotonic_sec() - start; | 1776 | timeout = (unsigned)lease_remaining / 2; |
1802 | timeout = lease_seconds / 2; | 1777 | //TODO: why / 2? |
1803 | if ((unsigned)timeout < already_waited_sec) { | 1778 | timeout -= (unsigned)monotonic_sec() - start; |
1804 | /* Something went wrong. Back to discover state */ | 1779 | packet_num = 0; |
1805 | timeout = already_waited_sec = 0; | ||
1806 | } | ||
1807 | 1780 | ||
1808 | client_data.state = BOUND; | 1781 | client_data.state = BOUND; |
1809 | change_listen_mode(LISTEN_NONE); | 1782 | change_listen_mode(LISTEN_NONE); |
@@ -1856,7 +1829,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1856 | requested_ip = 0; | 1829 | requested_ip = 0; |
1857 | timeout = 0; | 1830 | timeout = 0; |
1858 | packet_num = 0; | 1831 | packet_num = 0; |
1859 | already_waited_sec = 0; | ||
1860 | } | 1832 | } |
1861 | continue; | 1833 | continue; |
1862 | /* case BOUND: - ignore all packets */ | 1834 | /* case BOUND: - ignore all packets */ |