diff options
-rw-r--r-- | networking/udhcp/Kbuild.src | 2 | ||||
-rw-r--r-- | networking/udhcp/arpping.c | 1 | ||||
-rw-r--r-- | networking/udhcp/dhcpd.c | 222 | ||||
-rw-r--r-- | networking/udhcp/dhcpd.h | 14 | ||||
-rw-r--r-- | networking/udhcp/leases.c | 211 | ||||
-rw-r--r-- | networking/udhcp/static_leases.c | 22 |
6 files changed, 219 insertions, 253 deletions
diff --git a/networking/udhcp/Kbuild.src b/networking/udhcp/Kbuild.src index bfa776860..5ea77df06 100644 --- a/networking/udhcp/Kbuild.src +++ b/networking/udhcp/Kbuild.src @@ -13,7 +13,7 @@ lib-$(CONFIG_UDHCPC) += common.o packet.o signalpipe.o socket.o lib-$(CONFIG_UDHCPD) += common.o packet.o signalpipe.o socket.o lib-$(CONFIG_UDHCPC) += dhcpc.o -lib-$(CONFIG_UDHCPD) += dhcpd.o arpping.o leases.o static_leases.o +lib-$(CONFIG_UDHCPD) += dhcpd.o arpping.o lib-$(CONFIG_DUMPLEASES) += dumpleases.o lib-$(CONFIG_DHCPRELAY) += dhcprelay.o diff --git a/networking/udhcp/arpping.c b/networking/udhcp/arpping.c index c98027316..215d023ce 100644 --- a/networking/udhcp/arpping.c +++ b/networking/udhcp/arpping.c @@ -9,7 +9,6 @@ #include <net/if_arp.h> #include "common.h" -#include "dhcpd.h" struct arpMsg { /* Ethernet header */ diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index b625756f9..56116d01f 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c @@ -39,6 +39,10 @@ #include "dhcpc.h" #include "dhcpd.h" +/* globals */ +struct dyn_lease *g_leases; +/* struct server_config_t server_config is in bb_common_bufsiz1 */ + /* Takes the address of the pointer to the static_leases linked list, * address to a 6 byte mac address, * 4 byte IP address */ @@ -72,6 +76,17 @@ static uint32_t get_static_nip_by_mac(struct static_lease *st_lease, void *mac) return 0; } +static int is_nip_reserved(struct static_lease *st_lease, uint32_t nip) +{ + while (st_lease) { + if (st_lease->nip == nip) + return 1; + st_lease = st_lease->next; + } + + return 0; +} + #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 /* Print out static leases just to check what's going on */ /* Takes the address of the pointer to the static_leases linked list */ @@ -96,6 +111,209 @@ static void log_static_leases(struct static_lease **st_lease_pp) # define log_static_leases(st_lease_pp) ((void)0) #endif +/* Find the oldest expired lease, NULL if there are no expired leases */ +static struct dyn_lease *oldest_expired_lease(void) +{ + struct dyn_lease *oldest_lease = NULL; + leasetime_t oldest_time = time(NULL); + unsigned i; + + /* Unexpired leases have g_leases[i].expires >= current time + * and therefore can't ever match */ + for (i = 0; i < server_config.max_leases; i++) { + if (g_leases[i].expires == 0 /* empty entry */ + || g_leases[i].expires < oldest_time + ) { + oldest_time = g_leases[i].expires; + oldest_lease = &g_leases[i]; + } + } + return oldest_lease; +} + +/* Clear out all leases with matching nonzero chaddr OR yiaddr. + * If chaddr == NULL, this is a conflict lease. + */ +static void clear_leases(const uint8_t *chaddr, uint32_t yiaddr) +{ + unsigned i; + + for (i = 0; i < server_config.max_leases; i++) { + if ((chaddr && memcmp(g_leases[i].lease_mac, chaddr, 6) == 0) + || (yiaddr && g_leases[i].lease_nip == yiaddr) + ) { + memset(&g_leases[i], 0, sizeof(g_leases[i])); + } + } +} + +/* Add a lease into the table, clearing out any old ones. + * If chaddr == NULL, this is a conflict lease. + */ +static struct dyn_lease *add_lease( + const uint8_t *chaddr, uint32_t yiaddr, + leasetime_t leasetime, + const char *hostname, int hostname_len) +{ + struct dyn_lease *oldest; + + /* clean out any old ones */ + clear_leases(chaddr, yiaddr); + + oldest = oldest_expired_lease(); + + if (oldest) { + memset(oldest, 0, sizeof(*oldest)); + if (hostname) { + char *p; + + hostname_len++; /* include NUL */ + if (hostname_len > sizeof(oldest->hostname)) + hostname_len = sizeof(oldest->hostname); + p = safe_strncpy(oldest->hostname, hostname, hostname_len); + /* + * Sanitization (s/bad_char/./g). + * The intent is not to allow only "DNS-valid" hostnames, + * but merely make dumpleases output safe for shells to use. + * We accept "0-9A-Za-z._-", all other chars turn to dots. + */ + while (*p) { + if (!isalnum(*p) && *p != '-' && *p != '_') + *p = '.'; + p++; + } + } + if (chaddr) + memcpy(oldest->lease_mac, chaddr, 6); + oldest->lease_nip = yiaddr; + oldest->expires = time(NULL) + leasetime; + } + + return oldest; +} + +/* True if a lease has expired */ +static int is_expired_lease(struct dyn_lease *lease) +{ + return (lease->expires < (leasetime_t) time(NULL)); +} + +/* Find the first lease that matches MAC, NULL if no match */ +static struct dyn_lease *find_lease_by_mac(const uint8_t *mac) +{ + unsigned i; + + for (i = 0; i < server_config.max_leases; i++) + if (memcmp(g_leases[i].lease_mac, mac, 6) == 0) + return &g_leases[i]; + + return NULL; +} + +/* Find the first lease that matches IP, NULL is no match */ +static struct dyn_lease *find_lease_by_nip(uint32_t nip) +{ + unsigned i; + + for (i = 0; i < server_config.max_leases; i++) + if (g_leases[i].lease_nip == nip) + return &g_leases[i]; + + return NULL; +} + +/* Check if the IP is taken; if it is, add it to the lease table */ +static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac, unsigned arpping_ms) +{ + struct in_addr temp; + int r; + + r = arpping(nip, safe_mac, + server_config.server_nip, + server_config.server_mac, + server_config.interface, + arpping_ms); + if (r) + return r; + + temp.s_addr = nip; + bb_error_msg("%s belongs to someone, reserving it for %u seconds", + inet_ntoa(temp), (unsigned)server_config.conflict_time); + add_lease(NULL, nip, server_config.conflict_time, NULL, 0); + return 0; +} + +/* Find a new usable (we think) address */ +static uint32_t find_free_or_expired_nip(const uint8_t *safe_mac, unsigned arpping_ms) +{ + uint32_t addr; + struct dyn_lease *oldest_lease = NULL; + +#if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC + uint32_t stop; + unsigned i, hash; + + /* hash hwaddr: use the SDBM hashing algorithm. Seems to give good + * dispersal even with similarly-valued "strings". + */ + hash = 0; + for (i = 0; i < 6; i++) + hash += safe_mac[i] + (hash << 6) + (hash << 16) - hash; + + /* pick a seed based on hwaddr then iterate until we find a free address. */ + addr = server_config.start_ip + + (hash % (1 + server_config.end_ip - server_config.start_ip)); + stop = addr; +#else + addr = server_config.start_ip; +#define stop (server_config.end_ip + 1) +#endif + do { + uint32_t nip; + struct dyn_lease *lease; + + /* ie, 192.168.55.0 */ + if ((addr & 0xff) == 0) + goto next_addr; + /* ie, 192.168.55.255 */ + if ((addr & 0xff) == 0xff) + goto next_addr; + nip = htonl(addr); + /* skip our own address */ + if (nip == server_config.server_nip) + goto next_addr; + /* is this a static lease addr? */ + if (is_nip_reserved(server_config.static_leases, nip)) + goto next_addr; + + lease = find_lease_by_nip(nip); + if (!lease) { +//TODO: DHCP servers do not always sit on the same subnet as clients: should *ping*, not arp-ping! + if (nobody_responds_to_arp(nip, safe_mac, arpping_ms)) + return nip; + } else { + if (!oldest_lease || lease->expires < oldest_lease->expires) + oldest_lease = lease; + } + + next_addr: + addr++; +#if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC + if (addr > server_config.end_ip) + addr = server_config.start_ip; +#endif + } while (addr != stop); + + if (oldest_lease + && is_expired_lease(oldest_lease) + && nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac, arpping_ms) + ) { + return oldest_lease->lease_nip; + } + + return 0; +} + /* On these functions, make sure your datatype matches */ static int FAST_FUNC read_str(const char *line, void *arg) { @@ -568,10 +786,6 @@ static NOINLINE void send_inform(struct dhcp_packet *oldpacket) send_packet(&packet, /*force_bcast:*/ 0); } -/* globals */ -struct dyn_lease *g_leases; -/* struct server_config_t server_config is in bb_common_bufsiz1 */ - int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int udhcpd_main(int argc UNUSED_PARAM, char **argv) { diff --git a/networking/udhcp/dhcpd.h b/networking/udhcp/dhcpd.h index b8d94a763..b8f96b029 100644 --- a/networking/udhcp/dhcpd.h +++ b/networking/udhcp/dhcpd.h @@ -90,20 +90,6 @@ struct dyn_lease { /* total size is a multiply of 4 */ } PACKED; -extern struct dyn_lease *g_leases; - -struct dyn_lease *add_lease( - const uint8_t *chaddr, uint32_t yiaddr, - leasetime_t leasetime, - const char *hostname, int hostname_len - ) FAST_FUNC; -int is_expired_lease(struct dyn_lease *lease) FAST_FUNC; -struct dyn_lease *find_lease_by_mac(const uint8_t *mac) FAST_FUNC; -struct dyn_lease *find_lease_by_nip(uint32_t nip) FAST_FUNC; -uint32_t find_free_or_expired_nip(const uint8_t *safe_mac, unsigned arpping_ms) FAST_FUNC; - -int is_nip_reserved(struct static_lease *st_lease, uint32_t nip) FAST_FUNC; - POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/networking/udhcp/leases.c b/networking/udhcp/leases.c deleted file mode 100644 index 6642e396d..000000000 --- a/networking/udhcp/leases.c +++ /dev/null @@ -1,211 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Russ Dill <Russ.Dill@asu.edu> July 2001 - * - * Licensed under GPLv2, see file LICENSE in this source tree. - */ -#include "common.h" -#include "dhcpd.h" - -/* Find the oldest expired lease, NULL if there are no expired leases */ -static struct dyn_lease *oldest_expired_lease(void) -{ - struct dyn_lease *oldest_lease = NULL; - leasetime_t oldest_time = time(NULL); - unsigned i; - - /* Unexpired leases have g_leases[i].expires >= current time - * and therefore can't ever match */ - for (i = 0; i < server_config.max_leases; i++) { - if (g_leases[i].expires == 0 /* empty entry */ - || g_leases[i].expires < oldest_time - ) { - oldest_time = g_leases[i].expires; - oldest_lease = &g_leases[i]; - } - } - return oldest_lease; -} - -/* Clear out all leases with matching nonzero chaddr OR yiaddr. - * If chaddr == NULL, this is a conflict lease. - */ -static void clear_leases(const uint8_t *chaddr, uint32_t yiaddr) -{ - unsigned i; - - for (i = 0; i < server_config.max_leases; i++) { - if ((chaddr && memcmp(g_leases[i].lease_mac, chaddr, 6) == 0) - || (yiaddr && g_leases[i].lease_nip == yiaddr) - ) { - memset(&g_leases[i], 0, sizeof(g_leases[i])); - } - } -} - -/* Add a lease into the table, clearing out any old ones. - * If chaddr == NULL, this is a conflict lease. - */ -struct dyn_lease* FAST_FUNC add_lease( - const uint8_t *chaddr, uint32_t yiaddr, - leasetime_t leasetime, - const char *hostname, int hostname_len) -{ - struct dyn_lease *oldest; - - /* clean out any old ones */ - clear_leases(chaddr, yiaddr); - - oldest = oldest_expired_lease(); - - if (oldest) { - memset(oldest, 0, sizeof(*oldest)); - if (hostname) { - char *p; - - hostname_len++; /* include NUL */ - if (hostname_len > sizeof(oldest->hostname)) - hostname_len = sizeof(oldest->hostname); - p = safe_strncpy(oldest->hostname, hostname, hostname_len); - /* - * Sanitization (s/bad_char/./g). - * The intent is not to allow only "DNS-valid" hostnames, - * but merely make dumpleases output safe for shells to use. - * We accept "0-9A-Za-z._-", all other chars turn to dots. - */ - while (*p) { - if (!isalnum(*p) && *p != '-' && *p != '_') - *p = '.'; - p++; - } - } - if (chaddr) - memcpy(oldest->lease_mac, chaddr, 6); - oldest->lease_nip = yiaddr; - oldest->expires = time(NULL) + leasetime; - } - - return oldest; -} - -/* True if a lease has expired */ -int FAST_FUNC is_expired_lease(struct dyn_lease *lease) -{ - return (lease->expires < (leasetime_t) time(NULL)); -} - -/* Find the first lease that matches MAC, NULL if no match */ -struct dyn_lease* FAST_FUNC find_lease_by_mac(const uint8_t *mac) -{ - unsigned i; - - for (i = 0; i < server_config.max_leases; i++) - if (memcmp(g_leases[i].lease_mac, mac, 6) == 0) - return &g_leases[i]; - - return NULL; -} - -/* Find the first lease that matches IP, NULL is no match */ -struct dyn_lease* FAST_FUNC find_lease_by_nip(uint32_t nip) -{ - unsigned i; - - for (i = 0; i < server_config.max_leases; i++) - if (g_leases[i].lease_nip == nip) - return &g_leases[i]; - - return NULL; -} - -/* Check if the IP is taken; if it is, add it to the lease table */ -static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac, unsigned arpping_ms) -{ - struct in_addr temp; - int r; - - r = arpping(nip, safe_mac, - server_config.server_nip, - server_config.server_mac, - server_config.interface, - arpping_ms); - if (r) - return r; - - temp.s_addr = nip; - bb_error_msg("%s belongs to someone, reserving it for %u seconds", - inet_ntoa(temp), (unsigned)server_config.conflict_time); - add_lease(NULL, nip, server_config.conflict_time, NULL, 0); - return 0; -} - -/* Find a new usable (we think) address */ -uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac, unsigned arpping_ms) -{ - uint32_t addr; - struct dyn_lease *oldest_lease = NULL; - -#if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC - uint32_t stop; - unsigned i, hash; - - /* hash hwaddr: use the SDBM hashing algorithm. Seems to give good - * dispersal even with similarly-valued "strings". - */ - hash = 0; - for (i = 0; i < 6; i++) - hash += safe_mac[i] + (hash << 6) + (hash << 16) - hash; - - /* pick a seed based on hwaddr then iterate until we find a free address. */ - addr = server_config.start_ip - + (hash % (1 + server_config.end_ip - server_config.start_ip)); - stop = addr; -#else - addr = server_config.start_ip; -#define stop (server_config.end_ip + 1) -#endif - do { - uint32_t nip; - struct dyn_lease *lease; - - /* ie, 192.168.55.0 */ - if ((addr & 0xff) == 0) - goto next_addr; - /* ie, 192.168.55.255 */ - if ((addr & 0xff) == 0xff) - goto next_addr; - nip = htonl(addr); - /* skip our own address */ - if (nip == server_config.server_nip) - goto next_addr; - /* is this a static lease addr? */ - if (is_nip_reserved(server_config.static_leases, nip)) - goto next_addr; - - lease = find_lease_by_nip(nip); - if (!lease) { -//TODO: DHCP servers do not always sit on the same subnet as clients: should *ping*, not arp-ping! - if (nobody_responds_to_arp(nip, safe_mac, arpping_ms)) - return nip; - } else { - if (!oldest_lease || lease->expires < oldest_lease->expires) - oldest_lease = lease; - } - - next_addr: - addr++; -#if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC - if (addr > server_config.end_ip) - addr = server_config.start_ip; -#endif - } while (addr != stop); - - if (oldest_lease - && is_expired_lease(oldest_lease) - && nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac, arpping_ms) - ) { - return oldest_lease->lease_nip; - } - - return 0; -} diff --git a/networking/udhcp/static_leases.c b/networking/udhcp/static_leases.c deleted file mode 100644 index 3be7a5228..000000000 --- a/networking/udhcp/static_leases.c +++ /dev/null @@ -1,22 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Storing and retrieving data for static leases - * - * Wade Berrier <wberrier@myrealbox.com> September 2004 - * - * Licensed under GPLv2, see file LICENSE in this source tree. - */ -#include "common.h" -#include "dhcpd.h" - -/* Check to see if an IP is reserved as a static IP */ -int FAST_FUNC is_nip_reserved(struct static_lease *st_lease, uint32_t nip) -{ - while (st_lease) { - if (st_lease->nip == nip) - return 1; - st_lease = st_lease->next; - } - - return 0; -} |