Annotation of /trunk/mkinitrd-magellan/busybox/networking/udhcp/leases.c
Parent Directory | Revision Log
Revision 984 -
(hide annotations)
(download)
Sun May 30 11:32:42 2010 UTC (14 years ago) by niro
File MIME type: text/plain
File size: 4356 byte(s)
Sun May 30 11:32:42 2010 UTC (14 years ago) by niro
File MIME type: text/plain
File size: 4356 byte(s)
-updated to busybox-1.16.1 and enabled blkid/uuid support in default config
1 | niro | 532 | /* vi: set sw=4 ts=4: */ |
2 | /* | ||
3 | * leases.c -- tools to manage DHCP leases | ||
4 | * Russ Dill <Russ.Dill@asu.edu> July 2001 | ||
5 | niro | 984 | * |
6 | * Licensed under GPLv2, see file LICENSE in this tarball for details. | ||
7 | niro | 532 | */ |
8 | |||
9 | #include "common.h" | ||
10 | #include "dhcpd.h" | ||
11 | |||
12 | |||
13 | niro | 816 | /* Find the oldest expired lease, NULL if there are no expired leases */ |
14 | niro | 984 | static struct dyn_lease *oldest_expired_lease(void) |
15 | niro | 816 | { |
16 | niro | 984 | struct dyn_lease *oldest_lease = NULL; |
17 | leasetime_t oldest_time = time(NULL); | ||
18 | niro | 816 | unsigned i; |
19 | niro | 532 | |
20 | niro | 984 | /* Unexpired leases have g_leases[i].expires >= current time |
21 | * and therefore can't ever match */ | ||
22 | for (i = 0; i < server_config.max_leases; i++) { | ||
23 | if (g_leases[i].expires < oldest_time) { | ||
24 | oldest_time = g_leases[i].expires; | ||
25 | oldest_lease = &g_leases[i]; | ||
26 | niro | 816 | } |
27 | niro | 984 | } |
28 | return oldest_lease; | ||
29 | niro | 816 | } |
30 | |||
31 | |||
32 | niro | 984 | /* Clear every lease out that chaddr OR yiaddr matches and is nonzero */ |
33 | niro | 816 | static void clear_lease(const uint8_t *chaddr, uint32_t yiaddr) |
34 | niro | 532 | { |
35 | niro | 816 | unsigned i, j; |
36 | niro | 532 | |
37 | niro | 816 | for (j = 0; j < 16 && !chaddr[j]; j++) |
38 | continue; | ||
39 | niro | 532 | |
40 | niro | 984 | for (i = 0; i < server_config.max_leases; i++) { |
41 | if ((j != 16 && memcmp(g_leases[i].lease_mac, chaddr, 6) == 0) | ||
42 | || (yiaddr && g_leases[i].lease_nip == yiaddr) | ||
43 | niro | 816 | ) { |
44 | niro | 984 | memset(&g_leases[i], 0, sizeof(g_leases[i])); |
45 | niro | 532 | } |
46 | niro | 984 | } |
47 | niro | 532 | } |
48 | |||
49 | |||
50 | niro | 984 | /* Add a lease into the table, clearing out any old ones */ |
51 | struct dyn_lease* FAST_FUNC add_lease( | ||
52 | const uint8_t *chaddr, uint32_t yiaddr, | ||
53 | leasetime_t leasetime, | ||
54 | const char *hostname, int hostname_len) | ||
55 | niro | 532 | { |
56 | niro | 984 | struct dyn_lease *oldest; |
57 | niro | 532 | |
58 | /* clean out any old ones */ | ||
59 | clear_lease(chaddr, yiaddr); | ||
60 | |||
61 | oldest = oldest_expired_lease(); | ||
62 | |||
63 | if (oldest) { | ||
64 | niro | 984 | oldest->hostname[0] = '\0'; |
65 | if (hostname) { | ||
66 | char *p; | ||
67 | if (hostname_len > sizeof(oldest->hostname)) | ||
68 | hostname_len = sizeof(oldest->hostname); | ||
69 | p = safe_strncpy(oldest->hostname, hostname, hostname_len); | ||
70 | /* sanitization (s/non-ASCII/^/g) */ | ||
71 | while (*p) { | ||
72 | if (*p < ' ' || *p > 126) | ||
73 | *p = '^'; | ||
74 | p++; | ||
75 | } | ||
76 | } | ||
77 | memcpy(oldest->lease_mac, chaddr, 6); | ||
78 | oldest->lease_nip = yiaddr; | ||
79 | oldest->expires = time(NULL) + leasetime; | ||
80 | niro | 532 | } |
81 | |||
82 | return oldest; | ||
83 | } | ||
84 | |||
85 | |||
86 | niro | 984 | /* True if a lease has expired */ |
87 | int FAST_FUNC is_expired_lease(struct dyn_lease *lease) | ||
88 | niro | 532 | { |
89 | niro | 984 | return (lease->expires < (leasetime_t) time(NULL)); |
90 | niro | 532 | } |
91 | |||
92 | |||
93 | niro | 984 | /* Find the first lease that matches MAC, NULL if no match */ |
94 | struct dyn_lease* FAST_FUNC find_lease_by_mac(const uint8_t *mac) | ||
95 | niro | 532 | { |
96 | niro | 816 | unsigned i; |
97 | niro | 532 | |
98 | for (i = 0; i < server_config.max_leases; i++) | ||
99 | niro | 984 | if (memcmp(g_leases[i].lease_mac, mac, 6) == 0) |
100 | return &g_leases[i]; | ||
101 | niro | 532 | |
102 | return NULL; | ||
103 | } | ||
104 | |||
105 | |||
106 | niro | 984 | /* Find the first lease that matches IP, NULL is no match */ |
107 | struct dyn_lease* FAST_FUNC find_lease_by_nip(uint32_t nip) | ||
108 | niro | 532 | { |
109 | niro | 816 | unsigned i; |
110 | niro | 532 | |
111 | for (i = 0; i < server_config.max_leases; i++) | ||
112 | niro | 984 | if (g_leases[i].lease_nip == nip) |
113 | return &g_leases[i]; | ||
114 | niro | 532 | |
115 | return NULL; | ||
116 | } | ||
117 | |||
118 | |||
119 | niro | 984 | /* Check if the IP is taken; if it is, add it to the lease table */ |
120 | static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac) | ||
121 | niro | 532 | { |
122 | niro | 816 | /* 16 zero bytes */ |
123 | static const uint8_t blank_chaddr[16] = { 0 }; | ||
124 | /* = { 0 } helps gcc to put it in rodata, not bss */ | ||
125 | |||
126 | niro | 532 | struct in_addr temp; |
127 | niro | 816 | int r; |
128 | niro | 532 | |
129 | niro | 984 | r = arpping(nip, safe_mac, |
130 | server_config.server_nip, | ||
131 | server_config.server_mac, | ||
132 | server_config.interface); | ||
133 | niro | 816 | if (r) |
134 | return r; | ||
135 | |||
136 | niro | 984 | temp.s_addr = nip; |
137 | niro | 816 | bb_info_msg("%s belongs to someone, reserving it for %u seconds", |
138 | inet_ntoa(temp), (unsigned)server_config.conflict_time); | ||
139 | niro | 984 | add_lease(blank_chaddr, nip, server_config.conflict_time, NULL, 0); |
140 | niro | 816 | return 0; |
141 | niro | 532 | } |
142 | |||
143 | |||
144 | niro | 984 | /* Find a new usable (we think) address */ |
145 | uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac) | ||
146 | niro | 532 | { |
147 | niro | 984 | uint32_t addr; |
148 | struct dyn_lease *oldest_lease = NULL; | ||
149 | niro | 532 | |
150 | niro | 816 | addr = server_config.start_ip; /* addr is in host order here */ |
151 | for (; addr <= server_config.end_ip; addr++) { | ||
152 | niro | 984 | uint32_t nip; |
153 | struct dyn_lease *lease; | ||
154 | |||
155 | niro | 532 | /* ie, 192.168.55.0 */ |
156 | niro | 984 | if ((addr & 0xff) == 0) |
157 | niro | 816 | continue; |
158 | niro | 532 | /* ie, 192.168.55.255 */ |
159 | niro | 984 | if ((addr & 0xff) == 0xff) |
160 | niro | 816 | continue; |
161 | niro | 984 | nip = htonl(addr); |
162 | /* is this a static lease addr? */ | ||
163 | if (is_nip_reserved(server_config.static_leases, nip)) | ||
164 | continue; | ||
165 | |||
166 | lease = find_lease_by_nip(nip); | ||
167 | if (!lease) { | ||
168 | if (nobody_responds_to_arp(nip, safe_mac)) | ||
169 | return nip; | ||
170 | } else { | ||
171 | if (!oldest_lease || lease->expires < oldest_lease->expires) | ||
172 | oldest_lease = lease; | ||
173 | niro | 532 | } |
174 | } | ||
175 | niro | 984 | |
176 | if (oldest_lease && is_expired_lease(oldest_lease) | ||
177 | && nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac) | ||
178 | ) { | ||
179 | return oldest_lease->lease_nip; | ||
180 | } | ||
181 | |||
182 | niro | 532 | return 0; |
183 | } |