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