d478880a30912dca95c114d6b68b95932df43888
[oweals/busybox.git] / networking / udhcp / leases.c
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 "dhcpd.h"
13 #include "files.h"
14 #include "options.h"
15 #include "leases.h"
16 #include "arpping.h"
17 #include "common.h"
18
19
20 uint8_t blank_chaddr[] = {[0 ... 15] = 0};
21
22 /* clear every lease out that chaddr OR yiaddr matches and is nonzero */
23 void clear_lease(uint8_t *chaddr, uint32_t yiaddr)
24 {
25         unsigned int i, j;
26
27         for (j = 0; j < 16 && !chaddr[j]; j++);
28
29         for (i = 0; i < server_config.max_leases; i++)
30                 if ((j != 16 && !memcmp(leases[i].chaddr, chaddr, 16)) ||
31                     (yiaddr && leases[i].yiaddr == yiaddr)) {
32                         memset(&(leases[i]), 0, sizeof(struct dhcpOfferedAddr));
33                 }
34 }
35
36
37 /* add a lease into the table, clearing out any old ones */
38 struct dhcpOfferedAddr *add_lease(uint8_t *chaddr, uint32_t yiaddr, unsigned long lease)
39 {
40         struct dhcpOfferedAddr *oldest;
41
42         /* clean out any old ones */
43         clear_lease(chaddr, yiaddr);
44
45         oldest = oldest_expired_lease();
46
47         if (oldest) {
48                 memcpy(oldest->chaddr, chaddr, 16);
49                 oldest->yiaddr = yiaddr;
50                 oldest->expires = time(0) + lease;
51         }
52
53         return oldest;
54 }
55
56
57 /* true if a lease has expired */
58 int lease_expired(struct dhcpOfferedAddr *lease)
59 {
60         return (lease->expires < (unsigned long) time(0));
61 }
62
63
64 /* Find the oldest expired lease, NULL if there are no expired leases */
65 struct dhcpOfferedAddr *oldest_expired_lease(void)
66 {
67         struct dhcpOfferedAddr *oldest = NULL;
68         unsigned long oldest_lease = time(0);
69         unsigned int i;
70
71
72         for (i = 0; i < server_config.max_leases; i++)
73                 if (oldest_lease > leases[i].expires) {
74                         oldest_lease = leases[i].expires;
75                         oldest = &(leases[i]);
76                 }
77         return oldest;
78
79 }
80
81
82 /* Find the first lease that matches chaddr, NULL if no match */
83 struct dhcpOfferedAddr *find_lease_by_chaddr(uint8_t *chaddr)
84 {
85         unsigned int i;
86
87         for (i = 0; i < server_config.max_leases; i++)
88                 if (!memcmp(leases[i].chaddr, chaddr, 16)) return &(leases[i]);
89
90         return NULL;
91 }
92
93
94 /* Find the first lease that matches yiaddr, NULL is no match */
95 struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr)
96 {
97         unsigned int i;
98
99         for (i = 0; i < server_config.max_leases; i++)
100                 if (leases[i].yiaddr == yiaddr) return &(leases[i]);
101
102         return NULL;
103 }
104
105
106 /* check is an IP is taken, if it is, add it to the lease table */
107 static int check_ip(uint32_t addr)
108 {
109         struct in_addr temp;
110
111         if (arpping(addr, server_config.server, server_config.arp, server_config.interface) == 0) {
112                 temp.s_addr = addr;
113                 LOG(LOG_INFO, "%s belongs to someone, reserving it for %ld seconds",
114                         inet_ntoa(temp), server_config.conflict_time);
115                 add_lease(blank_chaddr, addr, server_config.conflict_time);
116                 return 1;
117         } else return 0;
118 }
119
120
121 /* find an assignable address, it check_expired is true, we check all the expired leases as well.
122  * Maybe this should try expired leases by age... */
123 uint32_t find_address(int check_expired)
124 {
125         uint32_t addr, ret;
126         struct dhcpOfferedAddr *lease = NULL;
127
128         addr = ntohl(server_config.start); /* addr is in host order here */
129         for (;addr <= ntohl(server_config.end); addr++) {
130
131                 /* ie, 192.168.55.0 */
132                 if (!(addr & 0xFF)) continue;
133
134                 /* ie, 192.168.55.255 */
135                 if ((addr & 0xFF) == 0xFF) continue;
136
137                 /* lease is not taken */
138                 ret = htonl(addr);
139                 if ((!(lease = find_lease_by_yiaddr(ret)) ||
140
141                      /* or it expired and we are checking for expired leases */
142                      (check_expired  && lease_expired(lease))) &&
143
144                      /* and it isn't on the network */
145                      !check_ip(ret)) {
146                         return ret;
147                         break;
148                 }
149         }
150         return 0;
151 }