1/*
2 * leases.c -- tools to manage DHCP leases
3 * Russ Dill <Russ.Dill@asu.edu> July 2001
4 */
5
6#include <time.h>
7#include <string.h>
8#include <sys/socket.h>
9#include <netinet/in.h>
10#include <arpa/inet.h>
11
12#include "debug.h"
13#include "dhcpd.h"
14#include "files.h"
15#include "options.h"
16#include "leases.h"
17#include "arpping.h"
18
19#include <bcmnvram.h>
20
21int check_lan_ip(u_int32_t addr);
22
23unsigned char blank_chaddr[] = {[0 ... 15] = 0};
24struct dhcpOfferedAddr *static_lease;
25
26/* clear every lease out that chaddr OR yiaddr matches and is nonzero */
27void clear_lease(u_int8_t *chaddr, u_int32_t yiaddr)
28{
29	unsigned int i, j;
30
31	//added by Joey to handle static lease
32	static_lease = NULL;
33
34	for (j = 0; j < 16 && !chaddr[j]; j++);
35
36	for (i = 0; i < server_config.max_leases; i++)
37	{
38		// added by Joey to handle static lease
39		//if (memcmp(leases[i].chaddr, chaddr, 16)==0 && leases[i].expires==0xffffffff)
40		//	static_lease = &leases[i];
41
42		if ((j != 16 && !memcmp(leases[i].chaddr, chaddr, 16)) ||
43		    (yiaddr && leases[i].yiaddr == yiaddr))
44		{
45			if (leases[i].expires==0xffffffff) static_lease=&leases[i];
46			else memset(&(leases[i]), 0, sizeof(struct dhcpOfferedAddr));
47		}
48	}
49}
50
51
52/* add a lease into the table, clearing out any old ones */
53struct dhcpOfferedAddr *add_lease(u_int8_t *chaddr, u_int32_t yiaddr, unsigned long lease)
54{
55	struct dhcpOfferedAddr *oldest;
56
57	/* clean out any old ones */
58	clear_lease(chaddr, yiaddr);
59
60	// added by Joey to handle static lease
61	if (static_lease) return(static_lease);
62
63	oldest = oldest_expired_lease();
64
65	if (oldest) {
66		memcpy(oldest->chaddr, chaddr, 16);
67		oldest->yiaddr = yiaddr;
68		if (lease==0xffffffff)
69			oldest->expires = 0xffffffff;
70		else
71			oldest->expires = time(0) + lease;
72	}
73
74	return oldest;
75}
76
77
78/* true if a lease has expired */
79int lease_expired(struct dhcpOfferedAddr *lease)
80{
81	return (lease->expires < (unsigned long) time(0));
82}
83
84
85/* Find the oldest expired lease, NULL if there are no expired leases */
86struct dhcpOfferedAddr *oldest_expired_lease(void)
87{
88	struct dhcpOfferedAddr *oldest = NULL;
89	unsigned long oldest_lease = time(0);
90	unsigned int i;
91
92
93	for (i = 0; i < server_config.max_leases; i++)
94		if (oldest_lease > leases[i].expires) {
95			oldest_lease = leases[i].expires;
96			oldest = &(leases[i]);
97		}
98	return oldest;
99
100}
101
102
103/* Find the first lease that matches chaddr, NULL if no match */
104struct dhcpOfferedAddr *find_lease_by_chaddr(u_int8_t *chaddr)
105{
106	unsigned int i;
107
108	for (i = 0; i < server_config.max_leases; i++)
109		//JYWeng: 20030701 for palm: chaddr error after first 6 bytes
110		//if (!memcmp(leases[i].chaddr, chaddr, 16)) return &(leases[i]);
111		if (!memcmp(leases[i].chaddr, chaddr, 6)) return &(leases[i]);
112
113	return NULL;
114}
115
116
117/* Find the first lease that matches yiaddr, NULL is no match */
118struct dhcpOfferedAddr *find_lease_by_yiaddr(u_int32_t yiaddr)
119{
120	unsigned int i;
121
122	for (i = 0; i < server_config.max_leases; i++)
123		if (leases[i].yiaddr == yiaddr) return &(leases[i]);
124
125	return NULL;
126}
127
128
129/* find an assignable address, it check_expired is true, we check all the expired leases as well.
130 * Maybe this should try expired leases by age... */
131u_int32_t find_address(int check_expired)
132{
133	u_int32_t addr, ret;
134	struct dhcpOfferedAddr *lease = NULL;
135
136	addr = ntohl(server_config.start); /* addr is in host order here */
137	for (;addr <= ntohl(server_config.end); addr++) {
138
139		/* ie, 192.168.55.0 */
140		if (!(addr & 0xFF)) continue;
141
142		/* ie, 192.168.55.255 */
143		if ((addr & 0xFF) == 0xFF) continue;
144
145		/* lease is not taken */
146		ret = htonl(addr);
147		if ((!(lease = find_lease_by_yiaddr(ret)) ||
148				/* or it expired and we are checking for expired leases */
149				(check_expired  && lease_expired(lease))) &&
150				/* and it isn't on the network */
151				!check_ip(ret) &&
152				/* and different from LAN IP */
153				check_lan_ip(ret)) {
154			return ret;
155		}
156	}
157	return 0;
158}
159
160
161/* check is an IP is taken, if it is, add it to the lease table */
162int check_ip(u_int32_t addr)
163{
164	struct in_addr temp;
165
166	if (arpping(addr, server_config.server, server_config.arp, server_config.interface) == 0) {
167		temp.s_addr = addr;
168	 	LOG(LOG_INFO, "%s belongs to someone, reserving it for %ld seconds",
169	 		inet_ntoa(temp), server_config.conflict_time);
170		add_lease(blank_chaddr, addr, server_config.conflict_time);
171		return 1;
172	} else return 0;
173}
174
175/* check is an IP is used by LAN IP */
176int check_lan_ip(u_int32_t addr)
177{
178	struct in_addr temp;
179	temp.s_addr = addr;
180
181	if (nvram_match("lan_ipaddr_t", inet_ntoa(temp)))
182		return 0;
183	else
184		return 1;
185}
186