diff --git a/include/platform.h b/include/platform.h index 0e0ccaf90..21224fabf 100644 --- a/include/platform.h +++ b/include/platform.h @@ -135,7 +135,18 @@ #define SWAP_LE64(x) (x) #endif +/* ---- Unaligned access ------------------------------------ */ + +/* parameter is supposed to be an uint32_t* ptr */ +#if defined(i386) || defined(__x86_64__) /* + other arches? */ +#define get_unaligned_u32p(u32p) (*(u32p)) +#else +/* performs reasonably well (gcc usually inlines memcpy here) */ +#define get_unaligned_u32p(u32p) ({ uint32_t __t; memcpy(&__t, (u32p), 4); __t; }) +#endif + /* ---- Networking ------------------------------------------ */ + #ifndef __APPLE__ # include # ifndef __socklen_t_defined @@ -146,6 +157,7 @@ typedef int socklen_t; #endif /* ---- Compiler dependent settings ------------------------- */ + #if (defined __digital__ && defined __unix__) || defined __APPLE__ # undef HAVE_MNTENT_H # undef HAVE_SYS_STATFS_H @@ -163,9 +175,10 @@ __extension__ typedef unsigned long long __u64; #endif /*----- Kernel versioning ------------------------------------*/ + #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) -/* ---- miscellaneous --------------------------------------- */ +/* ---- Miscellaneous --------------------------------------- */ #if defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ < 5 && \ !defined(__dietlibc__) && \ diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index fef8632f6..f1aa36fe6 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -18,9 +18,6 @@ #include "options.h" -static int timeout; /* = 0. Must be signed */ -static uint32_t requested_ip; /* = 0 */ -static uint32_t server_addr; static int sockfd = -1; #define LISTEN_NONE 0 @@ -28,6 +25,14 @@ static int sockfd = -1; #define LISTEN_RAW 2 static smallint listen_mode; +#define INIT_SELECTING 0 +#define REQUESTING 1 +#define BOUND 2 +#define RENEWING 3 +#define REBINDING 4 +#define INIT_REBOOT 5 +#define RENEW_REQUESTED 6 +#define RELEASED 7 static smallint state; /* struct client_config_t client_config is in bb_common_bufsiz1 */ @@ -71,7 +76,7 @@ static void perform_renew(void) /* perform a release */ -static void perform_release(void) +static void perform_release(uint32_t requested_ip, uint32_t server_addr) { char buffer[sizeof("255.255.255.255")]; struct in_addr temp_addr; @@ -90,7 +95,6 @@ static void perform_release(void) change_listen_mode(LISTEN_NONE); state = RELEASED; - timeout = INT_MAX; } @@ -140,9 +144,12 @@ int udhcpc_main(int argc ATTRIBUTE_UNUSED, char **argv) int tryagain_timeout = 20; int discover_timeout = 3; int discover_retries = 3; + uint32_t server_addr = server_addr; /* for compiler */ + uint32_t requested_ip = 0; uint32_t xid = 0; uint32_t lease_seconds = 0; /* can be given as 32-bit quantity */ int packet_num; + int timeout; /* must be signed */ unsigned already_waited_sec; unsigned opt; int max_fd; @@ -332,6 +339,7 @@ int udhcpc_main(int argc ATTRIBUTE_UNUSED, char **argv) udhcp_run_script(NULL, "deconfig"); change_listen_mode(LISTEN_RAW); packet_num = 0; + timeout = 0; already_waited_sec = 0; /* Main event loop. select() waits on signal pipe and possibly @@ -510,8 +518,8 @@ int udhcpc_main(int argc ATTRIBUTE_UNUSED, char **argv) continue; /* still selecting - this server looks bad */ } - /* can be misaligned, thus memcpy */ - memcpy(&server_addr, temp, 4); + /* it IS unaligned sometimes, don't "optimize" */ + server_addr = get_unaligned_u32p((uint32_t*)temp); xid = packet.xid; requested_ip = packet.yiaddr; @@ -535,7 +543,9 @@ int udhcpc_main(int argc ATTRIBUTE_UNUSED, char **argv) /* can be misaligned, thus memcpy */ memcpy(&lease_seconds, temp, 4); lease_seconds = ntohl(lease_seconds); - lease_seconds &= 0x0fffffff; /* paranoia: must not be negative */ + lease_seconds &= 0x0fffffff; /* paranoia: must not be prone to overflows */ + if (lease_seconds < 10) /* and not too small */ + lease_seconds = 10; } #if ENABLE_FEATURE_UDHCPC_ARPING if (opt & OPT_a) { @@ -576,7 +586,7 @@ int udhcpc_main(int argc ATTRIBUTE_UNUSED, char **argv) change_listen_mode(LISTEN_NONE); if (client_config.quit_after_lease) { if (client_config.release_on_quit) - perform_release(); + perform_release(requested_ip, server_addr); goto ret0; } if (!client_config.foreground) @@ -618,12 +628,13 @@ int udhcpc_main(int argc ATTRIBUTE_UNUSED, char **argv) timeout = 0; break; case SIGUSR2: - perform_release(); + perform_release(requested_ip, server_addr); + timeout = INT_MAX; break; case SIGTERM: bb_info_msg("Received SIGTERM"); if (client_config.release_on_quit) - perform_release(); + perform_release(requested_ip, server_addr); goto ret0; } } diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h index 9331466e1..97d3b3c9d 100644 --- a/networking/udhcp/dhcpc.h +++ b/networking/udhcp/dhcpc.h @@ -8,15 +8,6 @@ # pragma GCC visibility push(hidden) #endif -#define INIT_SELECTING 0 -#define REQUESTING 1 -#define BOUND 2 -#define RENEWING 3 -#define REBINDING 4 -#define INIT_REBOOT 5 -#define RENEW_REQUESTED 6 -#define RELEASED 7 - struct client_config_t { /* TODO: combine flag fields into single "unsigned opt" */ /* (can be set directly to the result of getopt32) */