1 /* vi: set sw=4 ts=4: */
3 * Russ Dill <Russ.Dill@asu.edu> July 2001
5 * Licensed under GPLv2, see file LICENSE in this source tree.
10 /* Find the oldest expired lease, NULL if there are no expired leases */
11 static struct dyn_lease
*oldest_expired_lease(void)
13 struct dyn_lease
*oldest_lease
= NULL
;
14 leasetime_t oldest_time
= time(NULL
);
17 /* 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
== 0 /* empty entry */
21 || g_leases
[i
].expires
< oldest_time
23 oldest_time
= g_leases
[i
].expires
;
24 oldest_lease
= &g_leases
[i
];
30 /* Clear out all leases with matching nonzero chaddr OR yiaddr.
31 * If chaddr == NULL, this is a conflict lease.
33 static void clear_leases(const uint8_t *chaddr
, uint32_t yiaddr
)
37 for (i
= 0; i
< server_config
.max_leases
; i
++) {
38 if ((chaddr
&& memcmp(g_leases
[i
].lease_mac
, chaddr
, 6) == 0)
39 || (yiaddr
&& g_leases
[i
].lease_nip
== yiaddr
)
41 memset(&g_leases
[i
], 0, sizeof(g_leases
[i
]));
46 /* Add a lease into the table, clearing out any old ones.
47 * If chaddr == NULL, this is a conflict lease.
49 struct dyn_lease
* FAST_FUNC
add_lease(
50 const uint8_t *chaddr
, uint32_t yiaddr
,
51 leasetime_t leasetime
,
52 const char *hostname
, int hostname_len
)
54 struct dyn_lease
*oldest
;
56 /* clean out any old ones */
57 clear_leases(chaddr
, yiaddr
);
59 oldest
= oldest_expired_lease();
62 memset(oldest
, 0, sizeof(*oldest
));
66 hostname_len
++; /* include NUL */
67 if (hostname_len
> sizeof(oldest
->hostname
))
68 hostname_len
= sizeof(oldest
->hostname
);
69 p
= safe_strncpy(oldest
->hostname
, hostname
, hostname_len
);
71 * Sanitization (s/bad_char/./g).
72 * The intent is not to allow only "DNS-valid" hostnames,
73 * but merely make dumpleases output safe for shells to use.
74 * We accept "0-9A-Za-z._-", all other chars turn to dots.
77 if (!isalnum(*p
) && *p
!= '-' && *p
!= '_')
83 memcpy(oldest
->lease_mac
, chaddr
, 6);
84 oldest
->lease_nip
= yiaddr
;
85 oldest
->expires
= time(NULL
) + leasetime
;
91 /* True if a lease has expired */
92 int FAST_FUNC
is_expired_lease(struct dyn_lease
*lease
)
94 return (lease
->expires
< (leasetime_t
) time(NULL
));
97 /* Find the first lease that matches MAC, NULL if no match */
98 struct dyn_lease
* FAST_FUNC
find_lease_by_mac(const uint8_t *mac
)
102 for (i
= 0; i
< server_config
.max_leases
; i
++)
103 if (memcmp(g_leases
[i
].lease_mac
, mac
, 6) == 0)
109 /* Find the first lease that matches IP, NULL is no match */
110 struct dyn_lease
* FAST_FUNC
find_lease_by_nip(uint32_t nip
)
114 for (i
= 0; i
< server_config
.max_leases
; i
++)
115 if (g_leases
[i
].lease_nip
== nip
)
121 /* Check if the IP is taken; if it is, add it to the lease table */
122 static int nobody_responds_to_arp(uint32_t nip
, const uint8_t *safe_mac
, unsigned arpping_ms
)
127 r
= arpping(nip
, safe_mac
,
128 server_config
.server_nip
,
129 server_config
.server_mac
,
130 server_config
.interface
,
136 bb_error_msg("%s belongs to someone, reserving it for %u seconds",
137 inet_ntoa(temp
), (unsigned)server_config
.conflict_time
);
138 add_lease(NULL
, nip
, server_config
.conflict_time
, NULL
, 0);
142 /* Find a new usable (we think) address */
143 uint32_t FAST_FUNC
find_free_or_expired_nip(const uint8_t *safe_mac
, unsigned arpping_ms
)
146 struct dyn_lease
*oldest_lease
= NULL
;
148 #if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC
152 /* hash hwaddr: use the SDBM hashing algorithm. Seems to give good
153 * dispersal even with similarly-valued "strings".
156 for (i
= 0; i
< 6; i
++)
157 hash
+= safe_mac
[i
] + (hash
<< 6) + (hash
<< 16) - hash
;
159 /* pick a seed based on hwaddr then iterate until we find a free address. */
160 addr
= server_config
.start_ip
161 + (hash
% (1 + server_config
.end_ip
- server_config
.start_ip
));
164 addr
= server_config
.start_ip
;
165 #define stop (server_config.end_ip + 1)
169 struct dyn_lease
*lease
;
171 /* ie, 192.168.55.0 */
172 if ((addr
& 0xff) == 0)
174 /* ie, 192.168.55.255 */
175 if ((addr
& 0xff) == 0xff)
178 /* skip our own address */
179 if (nip
== server_config
.server_nip
)
181 /* is this a static lease addr? */
182 if (is_nip_reserved(server_config
.static_leases
, nip
))
185 lease
= find_lease_by_nip(nip
);
187 //TODO: DHCP servers do not always sit on the same subnet as clients: should *ping*, not arp-ping!
188 if (nobody_responds_to_arp(nip
, safe_mac
, arpping_ms
))
191 if (!oldest_lease
|| lease
->expires
< oldest_lease
->expires
)
192 oldest_lease
= lease
;
197 #if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC
198 if (addr
> server_config
.end_ip
)
199 addr
= server_config
.start_ip
;
201 } while (addr
!= stop
);
204 && is_expired_lease(oldest_lease
)
205 && nobody_responds_to_arp(oldest_lease
->lease_nip
, safe_mac
, arpping_ms
)
207 return oldest_lease
->lease_nip
;