diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-04 00:51:38 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-04 00:56:58 +0200 |
commit | a85740c8afe6942beff90fec345403b37b2a9092 (patch) | |
tree | 23781137d927ccfb0595b20bc8922b243334a81f /networking/udhcp/dhcpd.c | |
parent | d2ae66cb3e5c79ffdbde553fa6cce64f9218e14d (diff) | |
download | busybox-w32-a85740c8afe6942beff90fec345403b37b2a9092.tar.gz busybox-w32-a85740c8afe6942beff90fec345403b37b2a9092.tar.bz2 busybox-w32-a85740c8afe6942beff90fec345403b37b2a9092.zip |
dhcp: merge leases.c and static_leases.c into dhcpd.c
function old new delta
send_offer 292 461 +169
udhcpd_main 1531 1588 +57
read_leases 330 332 +2
add_lease 314 312 -2
find_lease_by_mac 68 - -68
find_free_or_expired_nip 174 - -174
------------------------------------------------------------------------------
(add/remove: 0/4 grow/shrink: 3/1 up/down: 228/-244) Total: -16 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/udhcp/dhcpd.c')
-rw-r--r-- | networking/udhcp/dhcpd.c | 222 |
1 files changed, 218 insertions, 4 deletions
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 @@ | |||
39 | #include "dhcpc.h" | 39 | #include "dhcpc.h" |
40 | #include "dhcpd.h" | 40 | #include "dhcpd.h" |
41 | 41 | ||
42 | /* globals */ | ||
43 | struct dyn_lease *g_leases; | ||
44 | /* struct server_config_t server_config is in bb_common_bufsiz1 */ | ||
45 | |||
42 | /* Takes the address of the pointer to the static_leases linked list, | 46 | /* Takes the address of the pointer to the static_leases linked list, |
43 | * address to a 6 byte mac address, | 47 | * address to a 6 byte mac address, |
44 | * 4 byte IP address */ | 48 | * 4 byte IP address */ |
@@ -72,6 +76,17 @@ static uint32_t get_static_nip_by_mac(struct static_lease *st_lease, void *mac) | |||
72 | return 0; | 76 | return 0; |
73 | } | 77 | } |
74 | 78 | ||
79 | static int is_nip_reserved(struct static_lease *st_lease, uint32_t nip) | ||
80 | { | ||
81 | while (st_lease) { | ||
82 | if (st_lease->nip == nip) | ||
83 | return 1; | ||
84 | st_lease = st_lease->next; | ||
85 | } | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
75 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 | 90 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 |
76 | /* Print out static leases just to check what's going on */ | 91 | /* Print out static leases just to check what's going on */ |
77 | /* Takes the address of the pointer to the static_leases linked list */ | 92 | /* 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) | |||
96 | # define log_static_leases(st_lease_pp) ((void)0) | 111 | # define log_static_leases(st_lease_pp) ((void)0) |
97 | #endif | 112 | #endif |
98 | 113 | ||
114 | /* Find the oldest expired lease, NULL if there are no expired leases */ | ||
115 | static struct dyn_lease *oldest_expired_lease(void) | ||
116 | { | ||
117 | struct dyn_lease *oldest_lease = NULL; | ||
118 | leasetime_t oldest_time = time(NULL); | ||
119 | unsigned i; | ||
120 | |||
121 | /* Unexpired leases have g_leases[i].expires >= current time | ||
122 | * and therefore can't ever match */ | ||
123 | for (i = 0; i < server_config.max_leases; i++) { | ||
124 | if (g_leases[i].expires == 0 /* empty entry */ | ||
125 | || g_leases[i].expires < oldest_time | ||
126 | ) { | ||
127 | oldest_time = g_leases[i].expires; | ||
128 | oldest_lease = &g_leases[i]; | ||
129 | } | ||
130 | } | ||
131 | return oldest_lease; | ||
132 | } | ||
133 | |||
134 | /* Clear out all leases with matching nonzero chaddr OR yiaddr. | ||
135 | * If chaddr == NULL, this is a conflict lease. | ||
136 | */ | ||
137 | static void clear_leases(const uint8_t *chaddr, uint32_t yiaddr) | ||
138 | { | ||
139 | unsigned i; | ||
140 | |||
141 | for (i = 0; i < server_config.max_leases; i++) { | ||
142 | if ((chaddr && memcmp(g_leases[i].lease_mac, chaddr, 6) == 0) | ||
143 | || (yiaddr && g_leases[i].lease_nip == yiaddr) | ||
144 | ) { | ||
145 | memset(&g_leases[i], 0, sizeof(g_leases[i])); | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | /* Add a lease into the table, clearing out any old ones. | ||
151 | * If chaddr == NULL, this is a conflict lease. | ||
152 | */ | ||
153 | static struct dyn_lease *add_lease( | ||
154 | const uint8_t *chaddr, uint32_t yiaddr, | ||
155 | leasetime_t leasetime, | ||
156 | const char *hostname, int hostname_len) | ||
157 | { | ||
158 | struct dyn_lease *oldest; | ||
159 | |||
160 | /* clean out any old ones */ | ||
161 | clear_leases(chaddr, yiaddr); | ||
162 | |||
163 | oldest = oldest_expired_lease(); | ||
164 | |||
165 | if (oldest) { | ||
166 | memset(oldest, 0, sizeof(*oldest)); | ||
167 | if (hostname) { | ||
168 | char *p; | ||
169 | |||
170 | hostname_len++; /* include NUL */ | ||
171 | if (hostname_len > sizeof(oldest->hostname)) | ||
172 | hostname_len = sizeof(oldest->hostname); | ||
173 | p = safe_strncpy(oldest->hostname, hostname, hostname_len); | ||
174 | /* | ||
175 | * Sanitization (s/bad_char/./g). | ||
176 | * The intent is not to allow only "DNS-valid" hostnames, | ||
177 | * but merely make dumpleases output safe for shells to use. | ||
178 | * We accept "0-9A-Za-z._-", all other chars turn to dots. | ||
179 | */ | ||
180 | while (*p) { | ||
181 | if (!isalnum(*p) && *p != '-' && *p != '_') | ||
182 | *p = '.'; | ||
183 | p++; | ||
184 | } | ||
185 | } | ||
186 | if (chaddr) | ||
187 | memcpy(oldest->lease_mac, chaddr, 6); | ||
188 | oldest->lease_nip = yiaddr; | ||
189 | oldest->expires = time(NULL) + leasetime; | ||
190 | } | ||
191 | |||
192 | return oldest; | ||
193 | } | ||
194 | |||
195 | /* True if a lease has expired */ | ||
196 | static int is_expired_lease(struct dyn_lease *lease) | ||
197 | { | ||
198 | return (lease->expires < (leasetime_t) time(NULL)); | ||
199 | } | ||
200 | |||
201 | /* Find the first lease that matches MAC, NULL if no match */ | ||
202 | static struct dyn_lease *find_lease_by_mac(const uint8_t *mac) | ||
203 | { | ||
204 | unsigned i; | ||
205 | |||
206 | for (i = 0; i < server_config.max_leases; i++) | ||
207 | if (memcmp(g_leases[i].lease_mac, mac, 6) == 0) | ||
208 | return &g_leases[i]; | ||
209 | |||
210 | return NULL; | ||
211 | } | ||
212 | |||
213 | /* Find the first lease that matches IP, NULL is no match */ | ||
214 | static struct dyn_lease *find_lease_by_nip(uint32_t nip) | ||
215 | { | ||
216 | unsigned i; | ||
217 | |||
218 | for (i = 0; i < server_config.max_leases; i++) | ||
219 | if (g_leases[i].lease_nip == nip) | ||
220 | return &g_leases[i]; | ||
221 | |||
222 | return NULL; | ||
223 | } | ||
224 | |||
225 | /* Check if the IP is taken; if it is, add it to the lease table */ | ||
226 | static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac, unsigned arpping_ms) | ||
227 | { | ||
228 | struct in_addr temp; | ||
229 | int r; | ||
230 | |||
231 | r = arpping(nip, safe_mac, | ||
232 | server_config.server_nip, | ||
233 | server_config.server_mac, | ||
234 | server_config.interface, | ||
235 | arpping_ms); | ||
236 | if (r) | ||
237 | return r; | ||
238 | |||
239 | temp.s_addr = nip; | ||
240 | bb_error_msg("%s belongs to someone, reserving it for %u seconds", | ||
241 | inet_ntoa(temp), (unsigned)server_config.conflict_time); | ||
242 | add_lease(NULL, nip, server_config.conflict_time, NULL, 0); | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | /* Find a new usable (we think) address */ | ||
247 | static uint32_t find_free_or_expired_nip(const uint8_t *safe_mac, unsigned arpping_ms) | ||
248 | { | ||
249 | uint32_t addr; | ||
250 | struct dyn_lease *oldest_lease = NULL; | ||
251 | |||
252 | #if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC | ||
253 | uint32_t stop; | ||
254 | unsigned i, hash; | ||
255 | |||
256 | /* hash hwaddr: use the SDBM hashing algorithm. Seems to give good | ||
257 | * dispersal even with similarly-valued "strings". | ||
258 | */ | ||
259 | hash = 0; | ||
260 | for (i = 0; i < 6; i++) | ||
261 | hash += safe_mac[i] + (hash << 6) + (hash << 16) - hash; | ||
262 | |||
263 | /* pick a seed based on hwaddr then iterate until we find a free address. */ | ||
264 | addr = server_config.start_ip | ||
265 | + (hash % (1 + server_config.end_ip - server_config.start_ip)); | ||
266 | stop = addr; | ||
267 | #else | ||
268 | addr = server_config.start_ip; | ||
269 | #define stop (server_config.end_ip + 1) | ||
270 | #endif | ||
271 | do { | ||
272 | uint32_t nip; | ||
273 | struct dyn_lease *lease; | ||
274 | |||
275 | /* ie, 192.168.55.0 */ | ||
276 | if ((addr & 0xff) == 0) | ||
277 | goto next_addr; | ||
278 | /* ie, 192.168.55.255 */ | ||
279 | if ((addr & 0xff) == 0xff) | ||
280 | goto next_addr; | ||
281 | nip = htonl(addr); | ||
282 | /* skip our own address */ | ||
283 | if (nip == server_config.server_nip) | ||
284 | goto next_addr; | ||
285 | /* is this a static lease addr? */ | ||
286 | if (is_nip_reserved(server_config.static_leases, nip)) | ||
287 | goto next_addr; | ||
288 | |||
289 | lease = find_lease_by_nip(nip); | ||
290 | if (!lease) { | ||
291 | //TODO: DHCP servers do not always sit on the same subnet as clients: should *ping*, not arp-ping! | ||
292 | if (nobody_responds_to_arp(nip, safe_mac, arpping_ms)) | ||
293 | return nip; | ||
294 | } else { | ||
295 | if (!oldest_lease || lease->expires < oldest_lease->expires) | ||
296 | oldest_lease = lease; | ||
297 | } | ||
298 | |||
299 | next_addr: | ||
300 | addr++; | ||
301 | #if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC | ||
302 | if (addr > server_config.end_ip) | ||
303 | addr = server_config.start_ip; | ||
304 | #endif | ||
305 | } while (addr != stop); | ||
306 | |||
307 | if (oldest_lease | ||
308 | && is_expired_lease(oldest_lease) | ||
309 | && nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac, arpping_ms) | ||
310 | ) { | ||
311 | return oldest_lease->lease_nip; | ||
312 | } | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
99 | /* On these functions, make sure your datatype matches */ | 317 | /* On these functions, make sure your datatype matches */ |
100 | static int FAST_FUNC read_str(const char *line, void *arg) | 318 | static int FAST_FUNC read_str(const char *line, void *arg) |
101 | { | 319 | { |
@@ -568,10 +786,6 @@ static NOINLINE void send_inform(struct dhcp_packet *oldpacket) | |||
568 | send_packet(&packet, /*force_bcast:*/ 0); | 786 | send_packet(&packet, /*force_bcast:*/ 0); |
569 | } | 787 | } |
570 | 788 | ||
571 | /* globals */ | ||
572 | struct dyn_lease *g_leases; | ||
573 | /* struct server_config_t server_config is in bb_common_bufsiz1 */ | ||
574 | |||
575 | int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 789 | int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
576 | int udhcpd_main(int argc UNUSED_PARAM, char **argv) | 790 | int udhcpd_main(int argc UNUSED_PARAM, char **argv) |
577 | { | 791 | { |