]>
Commit | Line | Data |
---|---|---|
d7837182 TL |
1 | /* dhcp.c |
2 | ||
b88e8e15 | 3 | DHCP Protocol engine. */ |
d7837182 TL |
4 | |
5 | /* | |
b88e8e15 TL |
6 | * Copyright (c) 1995, 1996 The Internet Software Consortium. |
7 | * All rights reserved. | |
d7837182 TL |
8 | * |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of The Internet Software Consortium nor the names | |
19 | * of its contributors may be used to endorse or promote products derived | |
20 | * from this software without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND | |
23 | * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
24 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
26 | * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR | |
27 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
29 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
30 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
31 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
32 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
33 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
34 | * SUCH DAMAGE. | |
35 | * | |
36 | * This software has been written for the Internet Software Consortium | |
37 | * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie | |
38 | * Enterprises. To learn more about the Internet Software Consortium, | |
39 | * see ``http://www.vix.com/isc''. To learn more about Vixie | |
40 | * Enterprises, see ``http://www.vix.com''. | |
41 | */ | |
42 | ||
43 | #ifndef lint | |
44 | static char copyright[] = | |
20581a0b | 45 | "@(#) Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; |
d7837182 TL |
46 | #endif /* not lint */ |
47 | ||
48 | #include "dhcpd.h" | |
49 | ||
d3e5a892 | 50 | static unsigned char dhcp_message [256]; |
b88e8e15 | 51 | |
d7837182 TL |
52 | void dhcp (packet) |
53 | struct packet *packet; | |
54 | { | |
3a581108 TL |
55 | if (!locate_network (packet)) |
56 | return; | |
57 | ||
ed8bcd8f TL |
58 | switch (packet -> packet_type) { |
59 | case DHCPDISCOVER: | |
60 | dhcpdiscover (packet); | |
61 | break; | |
97ca1699 | 62 | |
ed8bcd8f TL |
63 | case DHCPREQUEST: |
64 | dhcprequest (packet); | |
65 | break; | |
97ca1699 | 66 | |
ed8bcd8f TL |
67 | case DHCPRELEASE: |
68 | dhcprelease (packet); | |
69 | break; | |
97ca1699 | 70 | |
b88e8e15 TL |
71 | case DHCPDECLINE: |
72 | dhcpdecline (packet); | |
73 | break; | |
74 | ||
75 | case DHCPINFORM: | |
76 | dhcpinform (packet); | |
77 | break; | |
78 | ||
ed8bcd8f TL |
79 | default: |
80 | break; | |
97ca1699 | 81 | } |
ed8bcd8f | 82 | } |
97ca1699 | 83 | |
ed8bcd8f TL |
84 | void dhcpdiscover (packet) |
85 | struct packet *packet; | |
86 | { | |
15c00bba | 87 | struct lease *lease = find_lease (packet, packet -> shared_network); |
7a049f2c | 88 | struct host_decl *hp; |
97ca1699 | 89 | |
a69f4fd3 | 90 | note ("DHCPDISCOVER from %s via %s", |
f9a32ee9 TL |
91 | print_hw_addr (packet -> raw -> htype, |
92 | packet -> raw -> hlen, | |
a69f4fd3 TL |
93 | packet -> raw -> chaddr), |
94 | packet -> raw -> giaddr.s_addr | |
95 | ? inet_ntoa (packet -> raw -> giaddr) | |
96 | : packet -> interface -> name); | |
a8b53b42 | 97 | |
15c00bba TL |
98 | /* Sourceless packets don't make sense here. */ |
99 | if (!packet -> shared_network) { | |
100 | note ("Packet from unknown subnet: %s", | |
101 | inet_ntoa (packet -> raw -> giaddr)); | |
102 | return; | |
103 | } | |
104 | ||
97ca1699 TL |
105 | /* If we didn't find a lease, try to allocate one... */ |
106 | if (!lease) { | |
7a049f2c | 107 | lease = packet -> shared_network -> last_lease; |
97ca1699 TL |
108 | |
109 | /* If there are no leases in that subnet that have | |
110 | expired, we have nothing to offer this client. */ | |
faf4a8de | 111 | if (!lease || lease -> ends > cur_time) { |
97ca1699 | 112 | note ("no free leases on subnet %s", |
7a049f2c | 113 | packet -> shared_network -> name); |
97ca1699 TL |
114 | return; |
115 | } | |
7a049f2c TL |
116 | |
117 | /* Try to find a host_decl that matches the client | |
118 | identifier or hardware address on the packet, and | |
119 | has no fixed IP address. If there is one, hang | |
120 | it off the lease so that its option definitions | |
121 | can be used. */ | |
122 | if (((packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len | |
123 | != 0) && | |
124 | ((hp = find_hosts_by_uid | |
125 | (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].data, | |
126 | packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len)) | |
127 | != (struct host_decl *)0)) || | |
128 | ((hp = find_hosts_by_haddr (packet -> raw -> htype, | |
129 | packet -> raw -> chaddr, | |
130 | packet -> raw -> hlen)) | |
131 | != (struct host_decl *)0)) { | |
132 | for (; hp; hp = hp -> n_ipaddr) { | |
133 | if (!hp -> fixed_addr) { | |
134 | lease -> host = hp; | |
135 | break; | |
136 | } | |
137 | } | |
138 | } else { | |
139 | lease -> host = (struct host_decl *)0; | |
140 | } | |
97ca1699 TL |
141 | } |
142 | ||
ed8bcd8f TL |
143 | ack_lease (packet, lease, DHCPOFFER, cur_time + 120); |
144 | } | |
145 | ||
146 | void dhcprequest (packet) | |
147 | struct packet *packet; | |
148 | { | |
15c00bba | 149 | struct lease *lease; |
b88e8e15 | 150 | struct iaddr cip; |
7a049f2c | 151 | struct subnet *subnet; |
b88e8e15 | 152 | |
b88e8e15 TL |
153 | if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) { |
154 | cip.len = 4; | |
155 | memcpy (cip.iabuf, | |
156 | packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data, | |
157 | 4); | |
a8b53b42 TL |
158 | } else { |
159 | cip.len = 4; | |
160 | memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4); | |
161 | } | |
162 | ||
15c00bba TL |
163 | /* Find the lease that matches the address requested by the |
164 | client. */ | |
165 | subnet = find_subnet (cip); | |
166 | lease = find_lease (packet, (subnet | |
167 | ? subnet -> shared_network | |
168 | : (struct shared_network *)0)); | |
169 | ||
a69f4fd3 | 170 | note ("DHCPREQUEST for %s from %s via %s", |
7a049f2c TL |
171 | piaddr (cip), |
172 | print_hw_addr (packet -> raw -> htype, | |
173 | packet -> raw -> hlen, | |
a69f4fd3 TL |
174 | packet -> raw -> chaddr), |
175 | packet -> raw -> giaddr.s_addr | |
176 | ? inet_ntoa (packet -> raw -> giaddr) | |
177 | : packet -> interface -> name); | |
178 | ||
a8b53b42 | 179 | |
15c00bba TL |
180 | /* If a client on a given network wants to request a lease on |
181 | an address on a different network, NAK it. If the Requested | |
182 | Address option was used, the protocol says that it must have | |
183 | been broadcast, so we can trust the source network information. | |
184 | ||
185 | If ciaddr was specified and Requested Address was not, then | |
186 | we really only know for sure what network a packet came from | |
187 | if it came through a BOOTP gateway - if it came through an | |
188 | IP router, we'll just have to assume that it's cool. | |
189 | ||
190 | This violates the protocol spec in the case that the client | |
191 | is in the REBINDING state and broadcasts a DHCPREQUEST on | |
192 | the local wire. We're supposed to check ciaddr for | |
193 | validity in that case, but if the packet was unicast | |
194 | through a router from a client in the RENEWING state, it | |
195 | would look exactly the same to us and it would be very | |
196 | bad to send a DHCPNAK. I think we just have to live with | |
197 | this. */ | |
198 | if ((packet -> raw -> ciaddr.s_addr && | |
199 | packet -> raw -> giaddr.s_addr) || | |
200 | packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) { | |
201 | ||
202 | /* If we don't know where it came from but we do know | |
203 | where it claims to have come from, it didn't come | |
204 | from there. Fry it. */ | |
205 | if (!packet -> shared_network) { | |
206 | subnet = find_subnet (cip); | |
207 | if (subnet) { | |
208 | nak_lease (packet, &cip); | |
209 | return; | |
210 | } | |
b88e8e15 | 211 | } |
15c00bba TL |
212 | |
213 | /* If we do know where it came from and we don't know | |
214 | where it claims to have come from, same deal - fry it. */ | |
7a049f2c TL |
215 | subnet = find_grouped_subnet (packet -> shared_network, cip); |
216 | if (!subnet) { | |
a8b53b42 | 217 | nak_lease (packet, &cip); |
b88e8e15 TL |
218 | return; |
219 | } | |
220 | } | |
ed8bcd8f | 221 | |
d01578b7 TL |
222 | /* If we own the lease that the client is asking for, |
223 | and it's already been assigned to the client, ack it. */ | |
224 | if (lease && | |
225 | ((lease -> uid_len && lease -> uid_len == | |
226 | packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len && | |
227 | !memcmp (packet -> options | |
228 | [DHO_DHCP_CLIENT_IDENTIFIER].data, | |
229 | lease -> uid, lease -> uid_len)) || | |
230 | (lease -> hardware_addr.hlen == packet -> raw -> hlen && | |
231 | lease -> hardware_addr.htype == packet -> raw -> htype && | |
232 | !memcmp (lease -> hardware_addr.haddr, | |
233 | packet -> raw -> chaddr, | |
234 | packet -> raw -> hlen)))) { | |
235 | ack_lease (packet, lease, DHCPACK, 0); | |
236 | return; | |
237 | } | |
7a049f2c | 238 | |
d01578b7 TL |
239 | /* Otherwise, if we have a lease for this client, |
240 | release it, and in any case don't reply to the | |
241 | DHCPREQUEST. */ | |
242 | if (packet -> options [DHO_DHCP_SERVER_IDENTIFIER].len | |
243 | && memcmp (packet -> | |
244 | options [DHO_DHCP_SERVER_IDENTIFIER].data, | |
245 | server_identifier.iabuf, | |
246 | server_identifier.len)) { | |
247 | if (lease) | |
248 | release_lease (lease); | |
249 | return; | |
ed8bcd8f | 250 | } |
ed8bcd8f TL |
251 | } |
252 | ||
253 | void dhcprelease (packet) | |
254 | struct packet *packet; | |
255 | { | |
15c00bba | 256 | struct lease *lease = find_lease (packet, packet -> shared_network); |
ed8bcd8f | 257 | |
a69f4fd3 | 258 | note ("DHCPRELEASE of %s from %s via %s", |
7a049f2c | 259 | inet_ntoa (packet -> raw -> ciaddr), |
f9a32ee9 TL |
260 | print_hw_addr (packet -> raw -> htype, |
261 | packet -> raw -> hlen, | |
a69f4fd3 TL |
262 | packet -> raw -> chaddr), |
263 | packet -> raw -> giaddr.s_addr | |
264 | ? inet_ntoa (packet -> raw -> giaddr) | |
265 | : packet -> interface -> name); | |
266 | ||
a8b53b42 | 267 | |
b88e8e15 | 268 | /* If we found a lease, release it. */ |
ed8bcd8f TL |
269 | if (lease) { |
270 | release_lease (lease); | |
271 | } | |
272 | } | |
273 | ||
b88e8e15 TL |
274 | void dhcpdecline (packet) |
275 | struct packet *packet; | |
276 | { | |
15c00bba | 277 | struct lease *lease = find_lease (packet, packet -> shared_network); |
a8b53b42 TL |
278 | struct iaddr cip; |
279 | ||
280 | if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) { | |
281 | cip.len = 4; | |
282 | memcpy (cip.iabuf, | |
283 | packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data, | |
284 | 4); | |
285 | } else { | |
286 | cip.len = 0; | |
287 | } | |
288 | ||
a69f4fd3 | 289 | note ("DHCPDECLINE on %s from %s via %s", |
7a049f2c | 290 | piaddr (cip), |
f9a32ee9 TL |
291 | print_hw_addr (packet -> raw -> htype, |
292 | packet -> raw -> hlen, | |
a69f4fd3 TL |
293 | packet -> raw -> chaddr), |
294 | packet -> raw -> giaddr.s_addr | |
295 | ? inet_ntoa (packet -> raw -> giaddr) | |
296 | : packet -> interface -> name); | |
297 | ||
b88e8e15 TL |
298 | |
299 | /* If we found a lease, mark it as unusable and complain. */ | |
300 | if (lease) { | |
301 | abandon_lease (lease); | |
302 | } | |
303 | } | |
304 | ||
305 | void dhcpinform (packet) | |
306 | struct packet *packet; | |
307 | { | |
7a049f2c | 308 | note ("DHCPINFORM from %s", |
f9a32ee9 | 309 | inet_ntoa (packet -> raw -> ciaddr)); |
b88e8e15 TL |
310 | } |
311 | ||
a8b53b42 | 312 | void nak_lease (packet, cip) |
ed8bcd8f | 313 | struct packet *packet; |
a8b53b42 | 314 | struct iaddr *cip; |
ed8bcd8f TL |
315 | { |
316 | struct sockaddr_in to; | |
317 | int result; | |
318 | struct dhcp_packet raw; | |
319 | unsigned char nak = DHCPNAK; | |
320 | struct packet outgoing; | |
fde927d2 | 321 | struct hardware hto; |
ed8bcd8f TL |
322 | |
323 | struct tree_cache *options [256]; | |
324 | struct tree_cache dhcpnak_tree; | |
b88e8e15 | 325 | struct tree_cache dhcpmsg_tree; |
ed8bcd8f TL |
326 | |
327 | memset (options, 0, sizeof options); | |
328 | memset (&outgoing, 0, sizeof outgoing); | |
329 | memset (&raw, 0, sizeof raw); | |
330 | outgoing.raw = &raw; | |
331 | ||
332 | /* Set DHCP_MESSAGE_TYPE to DHCPNAK */ | |
333 | options [DHO_DHCP_MESSAGE_TYPE] = &dhcpnak_tree; | |
334 | options [DHO_DHCP_MESSAGE_TYPE] -> value = &nak; | |
335 | options [DHO_DHCP_MESSAGE_TYPE] -> len = sizeof nak; | |
336 | options [DHO_DHCP_MESSAGE_TYPE] -> buf_size = sizeof nak; | |
337 | options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF; | |
338 | options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0; | |
339 | ||
b88e8e15 TL |
340 | /* Set DHCP_MESSAGE to whatever the message is */ |
341 | options [DHO_DHCP_MESSAGE] = &dhcpmsg_tree; | |
342 | options [DHO_DHCP_MESSAGE] -> value = dhcp_message; | |
343 | options [DHO_DHCP_MESSAGE] -> len = strlen (dhcp_message); | |
344 | options [DHO_DHCP_MESSAGE] -> buf_size = strlen (dhcp_message); | |
345 | options [DHO_DHCP_MESSAGE] -> timeout = 0xFFFFFFFF; | |
346 | options [DHO_DHCP_MESSAGE] -> tree = (struct tree *)0; | |
347 | ||
348 | /* Do not use the client's requested parameter list. */ | |
349 | packet -> options [DHO_DHCP_PARAMETER_REQUEST_LIST].len = 0; | |
350 | packet -> options [DHO_DHCP_PARAMETER_REQUEST_LIST].data = | |
351 | (unsigned char *)0; | |
352 | ||
ed8bcd8f TL |
353 | /* Set up the option buffer... */ |
354 | cons_options (packet, &outgoing, options, 0); | |
355 | ||
b88e8e15 | 356 | /* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/ |
7a049f2c | 357 | memcpy (&raw.siaddr, server_identifier.iabuf, 4); |
ed8bcd8f | 358 | raw.giaddr = packet -> raw -> giaddr; |
b88e8e15 TL |
359 | memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr); |
360 | raw.hlen = packet -> raw -> hlen; | |
361 | raw.htype = packet -> raw -> htype; | |
ed8bcd8f TL |
362 | |
363 | raw.xid = packet -> raw -> xid; | |
364 | raw.secs = packet -> raw -> secs; | |
b88e8e15 | 365 | raw.flags = packet -> raw -> flags | htons (BOOTP_BROADCAST); |
ed8bcd8f TL |
366 | raw.hops = packet -> raw -> hops; |
367 | raw.op = BOOTREPLY; | |
368 | ||
7a049f2c | 369 | /* Report what we're sending... */ |
a69f4fd3 | 370 | note ("DHCPNAK on %s to %s via %s", |
7a049f2c TL |
371 | piaddr (*cip), |
372 | print_hw_addr (packet -> raw -> htype, | |
373 | packet -> raw -> hlen, | |
a69f4fd3 TL |
374 | packet -> raw -> chaddr), |
375 | packet -> raw -> giaddr.s_addr | |
376 | ? inet_ntoa (packet -> raw -> giaddr) | |
377 | : packet -> interface -> name); | |
378 | ||
379 | ||
7a049f2c TL |
380 | |
381 | #ifdef DEBUG_PACKET | |
382 | dump_packet (packet); | |
383 | dump_raw ((unsigned char *)packet -> raw, packet -> packet_length); | |
384 | dump_packet (&outgoing); | |
385 | dump_raw ((unsigned char *)&raw, outgoing.packet_length); | |
386 | #endif | |
387 | ||
388 | hto.htype = packet -> raw -> htype; | |
389 | hto.hlen = packet -> raw -> hlen; | |
390 | memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen); | |
391 | ||
392 | /* Set up the common stuff... */ | |
393 | to.sin_family = AF_INET; | |
394 | #ifdef HAVE_SA_LEN | |
395 | to.sin_len = sizeof to; | |
396 | #endif | |
397 | memset (to.sin_zero, 0, sizeof to.sin_zero); | |
398 | ||
b88e8e15 TL |
399 | /* If this was gatewayed, send it back to the gateway. |
400 | Otherwise, broadcast it on the local network. */ | |
401 | if (raw.giaddr.s_addr) { | |
ed8bcd8f | 402 | to.sin_addr = raw.giaddr; |
b88e8e15 | 403 | to.sin_port = server_port; |
7a049f2c | 404 | |
8ec97099 TL |
405 | if (outgoing.packet_length < BOOTP_MIN_LEN) |
406 | outgoing.packet_length = BOOTP_MIN_LEN; | |
407 | ||
7a049f2c TL |
408 | #ifdef USE_FALLBACK |
409 | result = send_fallback (&fallback_interface, | |
410 | packet, &raw, outgoing.packet_length, | |
411 | raw.siaddr, &to, &hto); | |
412 | if (result < 0) | |
413 | warn ("send_fallback: %m"); | |
414 | return; | |
415 | #endif | |
b88e8e15 | 416 | } else { |
fde927d2 | 417 | to.sin_addr.s_addr = htonl (INADDR_BROADCAST); |
a8b53b42 | 418 | to.sin_port = packet->client_port; |
b88e8e15 | 419 | } |
ed8bcd8f | 420 | |
ed8bcd8f | 421 | errno = 0; |
fde927d2 TL |
422 | result = send_packet (packet -> interface, |
423 | packet, &raw, outgoing.packet_length, | |
7a049f2c | 424 | raw.siaddr, &to, (struct hardware *)0); |
ed8bcd8f | 425 | if (result < 0) |
7a049f2c | 426 | warn ("send_packet: %m"); |
ed8bcd8f TL |
427 | } |
428 | ||
429 | void ack_lease (packet, lease, offer, when) | |
430 | struct packet *packet; | |
431 | struct lease *lease; | |
432 | unsigned char offer; | |
433 | TIME when; | |
434 | { | |
435 | struct lease lt; | |
436 | TIME lease_time; | |
437 | ||
438 | int bufs = 0; | |
439 | struct packet outgoing; | |
440 | struct dhcp_packet raw; | |
441 | struct tree_cache *options [256]; | |
442 | struct sockaddr_in to; | |
fde927d2 | 443 | struct hardware hto; |
ed8bcd8f TL |
444 | int result; |
445 | ||
446 | struct tree_cache dhcpoffer_tree; | |
447 | unsigned char lease_time_buf [4]; | |
448 | struct tree_cache lease_time_tree; | |
449 | struct tree_cache server_id_tree; | |
b88e8e15 TL |
450 | struct tree_cache vendor_class_tree; |
451 | struct tree_cache user_class_tree; | |
452 | ||
453 | struct class *vendor_class, *user_class; | |
454 | char *filename; | |
7a049f2c | 455 | char *server_name; |
b88e8e15 TL |
456 | int i; |
457 | ||
458 | if (packet -> options [DHO_DHCP_CLASS_IDENTIFIER].len) { | |
459 | vendor_class = | |
460 | find_class (0, | |
461 | packet -> | |
462 | options [DHO_DHCP_CLASS_IDENTIFIER].data, | |
463 | packet -> | |
464 | options [DHO_DHCP_CLASS_IDENTIFIER].len); | |
465 | } else { | |
466 | vendor_class = (struct class *)0; | |
467 | } | |
468 | ||
469 | if (packet -> options [DHO_DHCP_USER_CLASS_ID].len) { | |
470 | user_class = | |
471 | find_class (0, | |
472 | packet -> | |
473 | options [DHO_DHCP_USER_CLASS_ID].data, | |
474 | packet -> | |
475 | options [DHO_DHCP_USER_CLASS_ID].len); | |
476 | } else { | |
477 | user_class = (struct class *)0; | |
478 | } | |
479 | ||
7a049f2c TL |
480 | /* Choose a filename; first from the host_decl, if any, then from |
481 | the user class, then from the vendor class. */ | |
acf6cfe3 | 482 | if (lease -> host && lease -> host -> filename) |
7a049f2c TL |
483 | filename = lease -> host -> filename; |
484 | else if (user_class && user_class -> filename) | |
b88e8e15 TL |
485 | filename = user_class -> filename; |
486 | else if (vendor_class && vendor_class -> filename) | |
487 | filename = vendor_class -> filename; | |
488 | else filename = (char *)0; | |
ed8bcd8f | 489 | |
7a049f2c | 490 | /* Choose a server name as above. */ |
acf6cfe3 | 491 | if (lease -> host && lease -> host -> server_name) |
7a049f2c TL |
492 | server_name = lease -> host -> server_name; |
493 | else if (user_class && user_class -> server_name) | |
494 | server_name = user_class -> server_name; | |
495 | else if (vendor_class && vendor_class -> server_name) | |
496 | server_name = vendor_class -> server_name; | |
497 | else server_name = (char *)0; | |
498 | ||
97ca1699 TL |
499 | /* At this point, we have a lease that we can offer the client. |
500 | Now we construct a lease structure that contains what we want, | |
501 | and call supersede_lease to do the right thing with it. */ | |
502 | ||
503 | memset (<, 0, sizeof lt); | |
504 | ||
505 | /* Use the ip address of the lease that we finally found in | |
506 | the database. */ | |
507 | lt.ip_addr = lease -> ip_addr; | |
508 | ||
509 | /* Start now. */ | |
510 | lt.starts = cur_time; | |
511 | ||
7a049f2c TL |
512 | /* Figure out how long a lease to assign. If this is a |
513 | dynamic BOOTP lease, its duration must be infinite. */ | |
514 | if (offer) { | |
515 | if (packet -> options [DHO_DHCP_LEASE_TIME].len == 4) { | |
516 | lease_time = getULong | |
517 | (packet -> options [DHO_DHCP_LEASE_TIME].data); | |
518 | ||
519 | /* Don't let the client ask for a longer lease than | |
520 | is supported for this subnet or host. */ | |
521 | if (lease -> host && lease -> host -> max_lease_time) { | |
522 | if (lease_time > | |
523 | lease -> host -> max_lease_time) | |
524 | lease_time = (lease -> host -> | |
525 | max_lease_time); | |
526 | } else { | |
527 | if (lease_time > | |
528 | lease -> subnet -> max_lease_time) | |
529 | lease_time = (lease -> subnet -> | |
530 | max_lease_time); | |
531 | } | |
532 | } else { | |
533 | if (lease -> host | |
534 | && lease -> host -> default_lease_time) | |
535 | lease_time = (lease -> host -> | |
536 | default_lease_time); | |
537 | else | |
538 | lease_time = (lease -> subnet -> | |
539 | default_lease_time); | |
540 | } | |
541 | ||
542 | lt.offered_expiry = cur_time + lease_time; | |
543 | if (when) | |
544 | lt.ends = when; | |
545 | else | |
546 | lt.ends = lt.offered_expiry; | |
547 | } else { | |
548 | lt.offered_expiry = lt.ends = MAX_TIME; | |
549 | lt.flags = BOOTP_LEASE; | |
550 | } | |
97ca1699 TL |
551 | |
552 | lt.timestamp = cur_time; | |
553 | ||
554 | /* Record the uid, if given... */ | |
555 | if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len) { | |
556 | lt.uid_len = | |
557 | packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len; | |
558 | lt.uid = packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].data; | |
559 | packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].data = | |
560 | (unsigned char *)0; | |
561 | packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len = 0; | |
562 | } | |
563 | ||
564 | /* Record the hardware address, if given... */ | |
565 | lt.hardware_addr.hlen = packet -> raw -> hlen; | |
566 | lt.hardware_addr.htype = packet -> raw -> htype; | |
567 | memcpy (lt.hardware_addr.haddr, packet -> raw -> chaddr, | |
568 | packet -> raw -> hlen); | |
569 | ||
7a049f2c TL |
570 | lt.host = lease -> host; |
571 | lt.subnet = lease -> subnet; | |
572 | lt.shared_network = lease -> shared_network; | |
97ca1699 TL |
573 | |
574 | /* Record the transaction id... */ | |
575 | lt.xid = packet -> raw -> xid; | |
576 | ||
7a049f2c TL |
577 | /* Don't call supersede_lease on a mocked-up lease. */ |
578 | if (lease -> flags & STATIC_LEASE) | |
579 | ; | |
580 | else | |
1358b874 | 581 | /* Install the new information about this lease in the database. |
7a049f2c TL |
582 | If this is a DHCPACK or a dynamic BOOTREPLY and we can't write |
583 | the lease, don't ACK it (or BOOTREPLY it) either. */ | |
584 | if (!(supersede_lease (lease, <, !offer || offer == DHCPACK) | |
585 | || (offer && offer != DHCPACK))) | |
586 | return; | |
97ca1699 TL |
587 | |
588 | /* Send a response to the client... */ | |
685963dc TL |
589 | |
590 | memset (&outgoing, 0, sizeof outgoing); | |
591 | memset (&raw, 0, sizeof raw); | |
592 | outgoing.raw = &raw; | |
593 | ||
594 | /* Copy in the filename if given; otherwise, flag the filename | |
595 | buffer as available for options. */ | |
b88e8e15 TL |
596 | if (filename) |
597 | strncpy (raw.file, filename, sizeof raw.file); | |
598 | else | |
599 | bufs |= 1; | |
685963dc TL |
600 | |
601 | /* Copy in the server name if given; otherwise, flag the | |
602 | server_name buffer as available for options. */ | |
7a049f2c TL |
603 | if (server_name) |
604 | strncpy (raw.sname, server_name, sizeof raw.sname); | |
605 | else | |
606 | bufs |= 2; /* XXX */ | |
685963dc TL |
607 | |
608 | memcpy (raw.chaddr, packet -> raw -> chaddr, packet -> raw -> hlen); | |
609 | raw.hlen = packet -> raw -> hlen; | |
610 | raw.htype = packet -> raw -> htype; | |
611 | ||
612 | /* Start out with the subnet options... */ | |
7a049f2c TL |
613 | memcpy (options, lease -> subnet -> options, sizeof options); |
614 | ||
615 | /* Vendor and user classes are only supported for DHCP clients. */ | |
616 | if (offer) { | |
617 | /* If we have a vendor class, install those options, | |
618 | superseding any subnet options. */ | |
619 | if (vendor_class) { | |
620 | for (i = 0; i < 256; i++) | |
621 | if (vendor_class -> options [i]) | |
622 | options [i] = | |
623 | vendor_class -> options [i]; | |
624 | } | |
685963dc | 625 | |
7a049f2c TL |
626 | /* If we have a user class, install those options, |
627 | superseding any subnet and vendor class options. */ | |
628 | if (user_class) { | |
629 | for (i = 0; i < 256; i++) | |
630 | if (user_class -> options [i]) | |
631 | options [i] = | |
632 | user_class -> options [i]; | |
633 | } | |
b88e8e15 | 634 | |
b88e8e15 TL |
635 | } |
636 | ||
7a049f2c TL |
637 | /* If we have a host_decl structure, install the associated |
638 | options, superseding anything that's in the way. */ | |
639 | if (lease -> host) { | |
640 | for (i = 0; i < 256; i++) | |
641 | if (lease -> host -> options [i]) | |
642 | options [i] = lease -> host -> options [i]; | |
b88e8e15 TL |
643 | } |
644 | ||
7a049f2c TL |
645 | /* Now, if appropriate, put in DHCP-specific options that |
646 | override those. */ | |
647 | if (offer) { | |
648 | options [DHO_DHCP_MESSAGE_TYPE] = &dhcpoffer_tree; | |
649 | options [DHO_DHCP_MESSAGE_TYPE] -> value = &offer; | |
650 | options [DHO_DHCP_MESSAGE_TYPE] -> len = sizeof offer; | |
651 | options [DHO_DHCP_MESSAGE_TYPE] -> buf_size = sizeof offer; | |
652 | options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF; | |
653 | options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0; | |
654 | ||
655 | options [DHO_DHCP_SERVER_IDENTIFIER] = &server_id_tree; | |
656 | options [DHO_DHCP_SERVER_IDENTIFIER] -> | |
657 | value = server_identifier.iabuf; | |
658 | options [DHO_DHCP_SERVER_IDENTIFIER] -> | |
659 | len = server_identifier.len; | |
660 | options [DHO_DHCP_SERVER_IDENTIFIER] -> | |
661 | buf_size = server_identifier.len; | |
662 | options [DHO_DHCP_SERVER_IDENTIFIER] -> | |
663 | timeout = 0xFFFFFFFF; | |
664 | options [DHO_DHCP_SERVER_IDENTIFIER] -> | |
665 | tree = (struct tree *)0; | |
666 | ||
667 | /* Sanity check the lease time. */ | |
668 | if ((lease->offered_expiry - cur_time) < 0) | |
669 | putULong (lease_time_buf, | |
670 | lease -> subnet -> default_lease_time); | |
671 | else if (lease -> offered_expiry - cur_time > | |
672 | lease -> subnet -> max_lease_time) | |
673 | putULong (lease_time_buf, | |
674 | lease -> subnet -> max_lease_time); | |
675 | else | |
676 | putULong (lease_time_buf, | |
677 | lease -> offered_expiry - cur_time); | |
b88e8e15 | 678 | |
20581a0b | 679 | putULong (lease_time_buf, lease -> offered_expiry - cur_time); |
7a049f2c TL |
680 | options [DHO_DHCP_LEASE_TIME] = &lease_time_tree; |
681 | options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf; | |
682 | options [DHO_DHCP_LEASE_TIME] -> len = sizeof lease_time_buf; | |
683 | options [DHO_DHCP_LEASE_TIME] -> | |
684 | buf_size = sizeof lease_time_buf; | |
685 | options [DHO_DHCP_LEASE_TIME] -> timeout = 0xFFFFFFFF; | |
686 | options [DHO_DHCP_LEASE_TIME] -> tree = (struct tree *)0; | |
687 | ||
688 | /* If we used the vendor class the client specified, we | |
689 | have to return it. */ | |
690 | if (vendor_class) { | |
691 | options [DHO_DHCP_CLASS_IDENTIFIER] = | |
692 | &vendor_class_tree; | |
693 | options [DHO_DHCP_CLASS_IDENTIFIER] -> | |
694 | value = (unsigned char *)vendor_class -> name; | |
695 | options [DHO_DHCP_CLASS_IDENTIFIER] -> | |
696 | len = strlen (vendor_class -> name); | |
697 | options [DHO_DHCP_CLASS_IDENTIFIER] -> | |
698 | buf_size = strlen (vendor_class -> name); | |
699 | options [DHO_DHCP_CLASS_IDENTIFIER] -> | |
700 | timeout = 0xFFFFFFFF; | |
701 | options [DHO_DHCP_CLASS_IDENTIFIER] -> | |
702 | tree = (struct tree *)0; | |
703 | } | |
a8b53b42 | 704 | |
7a049f2c TL |
705 | /* If we used the user class the client specified, we |
706 | have to return it. */ | |
707 | if (user_class) { | |
708 | options [DHO_DHCP_USER_CLASS_ID] = &user_class_tree; | |
709 | options [DHO_DHCP_USER_CLASS_ID] -> | |
710 | value = (unsigned char *)user_class -> name; | |
711 | options [DHO_DHCP_USER_CLASS_ID] -> | |
712 | len = strlen (user_class -> name); | |
713 | options [DHO_DHCP_USER_CLASS_ID] -> | |
714 | buf_size = strlen (user_class -> name); | |
715 | options [DHO_DHCP_USER_CLASS_ID] -> | |
716 | timeout = 0xFFFFFFFF; | |
717 | options [DHO_DHCP_USER_CLASS_ID] -> | |
718 | tree = (struct tree *)0; | |
719 | } | |
720 | } | |
685963dc TL |
721 | |
722 | cons_options (packet, &outgoing, options, bufs); | |
8ec97099 TL |
723 | if (!offer && outgoing.packet_length < BOOTP_MIN_LEN) |
724 | outgoing.packet_length = BOOTP_MIN_LEN; | |
685963dc TL |
725 | |
726 | raw.ciaddr = packet -> raw -> ciaddr; | |
727 | memcpy (&raw.yiaddr, lease -> ip_addr.iabuf, 4); | |
7a049f2c TL |
728 | if (lease -> subnet -> interface_address.len) |
729 | memcpy (&raw.siaddr, | |
730 | lease -> subnet -> interface_address.iabuf, 4); | |
731 | else | |
732 | memcpy (&raw.siaddr, server_identifier.iabuf, 4); | |
733 | ||
685963dc TL |
734 | raw.giaddr = packet -> raw -> giaddr; |
735 | ||
736 | raw.xid = packet -> raw -> xid; | |
737 | raw.secs = packet -> raw -> secs; | |
738 | raw.flags = packet -> raw -> flags; | |
739 | raw.hops = packet -> raw -> hops; | |
740 | raw.op = BOOTREPLY; | |
741 | ||
7a049f2c | 742 | /* Say what we're doing... */ |
a69f4fd3 | 743 | note ("%s on %s to %s via %s", |
7a049f2c TL |
744 | (offer |
745 | ? (offer == DHCPACK ? "DHCPACK" : "DHCPOFFER") | |
746 | : "BOOTREPLY"), | |
747 | piaddr (lease -> ip_addr), | |
748 | print_hw_addr (packet -> raw -> htype, | |
749 | packet -> raw -> hlen, | |
a69f4fd3 TL |
750 | packet -> raw -> chaddr), |
751 | packet -> raw -> giaddr.s_addr | |
752 | ? inet_ntoa (packet -> raw -> giaddr) | |
753 | : packet -> interface -> name); | |
7a049f2c TL |
754 | |
755 | /* Set up the hardware address... */ | |
756 | hto.htype = packet -> raw -> htype; | |
757 | hto.hlen = packet -> raw -> hlen; | |
758 | memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen); | |
759 | ||
760 | to.sin_family = AF_INET; | |
761 | #ifdef HAVE_SA_LEN | |
762 | to.sin_len = sizeof to; | |
763 | #endif | |
764 | memset (to.sin_zero, 0, sizeof to.sin_zero); | |
765 | ||
766 | #ifdef DEBUG_PACKET | |
767 | dump_packet (packet); | |
768 | dump_raw ((unsigned char *)packet -> raw, packet -> packet_length); | |
769 | dump_packet (&outgoing); | |
770 | dump_raw ((unsigned char *)&raw, outgoing.packet_length); | |
771 | #endif | |
772 | ||
ed8bcd8f | 773 | /* If this was gatewayed, send it back to the gateway... */ |
b88e8e15 | 774 | if (raw.giaddr.s_addr) { |
ed8bcd8f | 775 | to.sin_addr = raw.giaddr; |
b88e8e15 | 776 | to.sin_port = server_port; |
8ec97099 TL |
777 | |
778 | if (outgoing.packet_length < BOOTP_MIN_LEN) | |
779 | outgoing.packet_length = BOOTP_MIN_LEN; | |
780 | ||
7a049f2c TL |
781 | #ifdef USE_FALLBACK |
782 | result = send_fallback (&fallback_interface, | |
783 | packet, &raw, outgoing.packet_length, | |
784 | raw.siaddr, &to, &hto); | |
785 | if (result < 0) | |
786 | warn ("send_fallback: %m"); | |
787 | return; | |
788 | #endif | |
b88e8e15 | 789 | |
1a4b272f TL |
790 | /* If it comes from a client who already knows its address and |
791 | is not requesting a broadcast response, sent it directly to | |
792 | that client. */ | |
793 | } else if (raw.ciaddr.s_addr && offer == DHCPACK && | |
794 | !(raw.flags & BOOTP_BROADCAST)) { | |
ed8bcd8f | 795 | to.sin_addr = packet -> raw -> ciaddr; |
b88e8e15 TL |
796 | to.sin_port = htons (ntohs (server_port) + 1); /* XXX */ |
797 | ||
e2cb6d53 TL |
798 | #ifdef USE_FALLBACK |
799 | result = send_fallback (&fallback_interface, | |
800 | packet, &raw, outgoing.packet_length, | |
801 | raw.siaddr, &to, &hto); | |
802 | if (result < 0) | |
803 | warn ("send_fallback: %m"); | |
804 | return; | |
805 | #endif | |
806 | ||
ed8bcd8f | 807 | /* Otherwise, broadcast it on the local network. */ |
b88e8e15 | 808 | } else { |
fde927d2 | 809 | to.sin_addr.s_addr = htonl (INADDR_BROADCAST); |
b88e8e15 TL |
810 | to.sin_port = htons (ntohs (server_port) + 1); /* XXX */ |
811 | } | |
ed8bcd8f | 812 | |
fde927d2 TL |
813 | |
814 | result = send_packet (packet -> interface, | |
815 | packet, &raw, outgoing.packet_length, | |
7a049f2c | 816 | raw.siaddr, &to, &hto); |
685963dc | 817 | if (result < 0) |
a8b53b42 | 818 | warn ("sendpkt: %m"); |
d7837182 | 819 | } |
ed8bcd8f | 820 | |
15c00bba | 821 | struct lease *find_lease (packet, share) |
ed8bcd8f | 822 | struct packet *packet; |
15c00bba | 823 | struct shared_network *share; |
ed8bcd8f | 824 | { |
7a049f2c TL |
825 | struct lease *uid_lease, *ip_lease, *hw_lease; |
826 | struct lease *lease = (struct lease *)0; | |
ed8bcd8f | 827 | struct iaddr cip; |
e29c53f6 | 828 | struct host_decl *hp, *host = (struct host_decl *)0; |
7a049f2c | 829 | struct lease *fixed_lease; |
ed8bcd8f | 830 | |
7a049f2c TL |
831 | /* Try to find a host or lease that's been assigned to the |
832 | specified unique client identifier. */ | |
833 | if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len) { | |
834 | /* First, try to find a fixed host entry for the specified | |
835 | client identifier... */ | |
836 | hp = find_hosts_by_uid (packet -> options | |
837 | [DHO_DHCP_CLIENT_IDENTIFIER].data, | |
838 | packet -> options | |
839 | [DHO_DHCP_CLIENT_IDENTIFIER].len); | |
840 | if (hp) { | |
841 | host = hp; | |
15c00bba | 842 | fixed_lease = mockup_lease (packet, share, hp); |
b6b1cadf | 843 | uid_lease = (struct lease *)0; |
45023390 | 844 | } else { |
7a049f2c TL |
845 | uid_lease = find_lease_by_uid |
846 | (packet -> options | |
847 | [DHO_DHCP_CLIENT_IDENTIFIER].data, | |
848 | packet -> options | |
849 | [DHO_DHCP_CLIENT_IDENTIFIER].len); | |
45023390 TL |
850 | fixed_lease = (struct lease *)0; |
851 | } | |
7a049f2c | 852 | } else { |
ed8bcd8f | 853 | uid_lease = (struct lease *)0; |
7a049f2c TL |
854 | fixed_lease = (struct lease *)0; |
855 | } | |
856 | ||
857 | /* If we didn't find a fixed lease using the uid, try doing | |
858 | it with the hardware address... */ | |
859 | if (!fixed_lease) { | |
860 | hp = find_hosts_by_haddr (packet -> raw -> htype, | |
861 | packet -> raw -> chaddr, | |
862 | packet -> raw -> hlen); | |
863 | if (hp) { | |
864 | host = hp; /* Save it for later. */ | |
15c00bba | 865 | fixed_lease = mockup_lease (packet, share, hp); |
7a049f2c TL |
866 | } |
867 | } | |
ed8bcd8f TL |
868 | |
869 | /* Try to find a lease that's been attached to the client's | |
870 | hardware address... */ | |
871 | hw_lease = find_lease_by_hw_addr (packet -> raw -> chaddr, | |
872 | packet -> raw -> hlen); | |
873 | ||
874 | /* Try to find a lease that's been allocated to the client's | |
875 | IP address. */ | |
876 | if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len && | |
877 | packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len | |
878 | <= sizeof cip.iabuf) { | |
879 | cip.len = packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len; | |
880 | memcpy (cip.iabuf, | |
881 | packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data, | |
882 | packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len); | |
b6b1cadf TL |
883 | ip_lease = find_lease_by_ip_addr (cip); |
884 | } else if (packet -> raw -> ciaddr.s_addr) { | |
885 | cip.len = packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len; | |
ed8bcd8f TL |
886 | memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4); |
887 | ip_lease = find_lease_by_ip_addr (cip); | |
888 | } else | |
889 | ip_lease = (struct lease *)0; | |
890 | ||
f8cd781e TL |
891 | /* Toss ip_lease if it hasn't yet expired and the uid doesn't |
892 | match */ | |
893 | if (ip_lease && | |
894 | ip_lease -> ends >= cur_time && | |
895 | ip_lease -> uid && ip_lease != uid_lease) | |
896 | ip_lease = (struct lease *)0; | |
897 | ||
898 | /* Toss hw_lease if it hasn't yet expired and the uid doesn't | |
899 | match, except that if the hardware address matches and the | |
900 | client is now doing dynamic BOOTP (and thus hasn't provided | |
901 | a uid) we let the client get away with it. */ | |
902 | if (hw_lease && | |
903 | hw_lease -> ends >= cur_time && | |
904 | hw_lease -> uid && hw_lease != uid_lease && | |
905 | (packet -> packet_type != 0 || | |
906 | !(lease -> flags & DYNAMIC_BOOTP_OK))) | |
907 | hw_lease = (struct lease *)0; | |
908 | ||
ed8bcd8f TL |
909 | /* Toss extra pointers to the same lease... */ |
910 | if (ip_lease == hw_lease) | |
911 | ip_lease = (struct lease *)0; | |
912 | if (hw_lease == uid_lease) | |
913 | hw_lease = (struct lease *)0; | |
914 | if (ip_lease == uid_lease) | |
915 | ip_lease = (struct lease *)0; | |
916 | ||
917 | /* If we got an ip address lease, make sure it isn't assigned to | |
918 | some *other* client! If it was assigned to this client, we'd | |
919 | have zeroed it out above, so the only way we can take it at this | |
920 | point is if some other client had it but it's timed out, or if no | |
921 | other client has ever had it. */ | |
922 | if (ip_lease && | |
923 | ip_lease -> ends >= cur_time) | |
924 | ip_lease = (struct lease *)0; | |
925 | ||
b88e8e15 TL |
926 | /* If we've already eliminated the lease, it wasn't there to |
927 | begin with. If we have come up with a matching lease, | |
928 | set the message to bad network in case we have to throw it out. */ | |
929 | if (!ip_lease && !hw_lease && !uid_lease) { | |
930 | strcpy (dhcp_message, "requested address not available"); | |
931 | } else { | |
932 | strcpy (dhcp_message, "requested address on bad subnet"); | |
933 | } | |
934 | ||
7a049f2c TL |
935 | /* Now eliminate leases that are on the wrong network... */ |
936 | if (ip_lease && | |
15c00bba | 937 | (share != ip_lease -> shared_network)) { |
ed8bcd8f TL |
938 | release_lease (ip_lease); |
939 | ip_lease = (struct lease *)0; | |
940 | } | |
7a049f2c | 941 | if (uid_lease && |
15c00bba | 942 | (share != uid_lease -> shared_network)) { |
ed8bcd8f TL |
943 | release_lease (uid_lease); |
944 | uid_lease = (struct lease *)0; | |
945 | } | |
7a049f2c | 946 | if (hw_lease && |
15c00bba | 947 | (share != hw_lease -> shared_network)) { |
ed8bcd8f TL |
948 | release_lease (hw_lease); |
949 | hw_lease = (struct lease *)0; | |
950 | } | |
951 | ||
7a049f2c | 952 | /* At this point, if fixed_lease is nonzero, we can assign it to |
ed8bcd8f | 953 | this client. */ |
7a049f2c TL |
954 | if (fixed_lease) |
955 | lease = fixed_lease; | |
956 | ||
957 | /* If we got a lease that matched the ip address and don't have | |
958 | a better offer, use that; otherwise, release it. */ | |
959 | if (ip_lease) { | |
960 | if (lease) { | |
961 | release_lease (ip_lease); | |
962 | } else { | |
963 | lease = ip_lease; | |
964 | lease -> host = (struct host_decl *)0; | |
965 | } | |
966 | } | |
ed8bcd8f TL |
967 | |
968 | /* If we got a lease that matched the client identifier, we may want | |
969 | to use it, but if we already have a lease we like, we must free | |
970 | the lease that matched the client identifier. */ | |
971 | if (uid_lease) { | |
972 | if (lease) { | |
973 | release_lease (uid_lease); | |
7a049f2c | 974 | } else { |
ed8bcd8f | 975 | lease = uid_lease; |
7a049f2c TL |
976 | lease -> host = (struct host_decl *)0; |
977 | } | |
ed8bcd8f TL |
978 | } |
979 | ||
980 | /* The lease that matched the hardware address is treated likewise. */ | |
981 | if (hw_lease) { | |
982 | if (lease) { | |
983 | release_lease (hw_lease); | |
7a049f2c | 984 | } else { |
ed8bcd8f | 985 | lease = hw_lease; |
7a049f2c TL |
986 | lease -> host = (struct host_decl *)0; |
987 | } | |
988 | } | |
989 | ||
990 | /* If we found a host_decl but no matching address, try to | |
991 | find a host_decl that has no address, and if there is one, | |
992 | hang it off the lease so that we can use the supplied | |
993 | options. */ | |
994 | if (lease && host && !lease -> host) { | |
995 | for (; host; host = host -> n_ipaddr) { | |
996 | if (!host -> fixed_addr) { | |
997 | lease -> host = host; | |
998 | break; | |
999 | } | |
1000 | } | |
ed8bcd8f TL |
1001 | } |
1002 | ||
1003 | return lease; | |
1004 | } | |
7a049f2c TL |
1005 | |
1006 | /* Search the provided host_decl structure list for an address that's on | |
1007 | the specified shared network. If one is found, mock up and return a | |
1008 | lease structure for it; otherwise return the null pointer. */ | |
1009 | ||
15c00bba | 1010 | struct lease *mockup_lease (packet, share, hp) |
7a049f2c | 1011 | struct packet *packet; |
15c00bba | 1012 | struct shared_network *share; |
7a049f2c TL |
1013 | struct host_decl *hp; |
1014 | { | |
1015 | static struct lease mock; | |
1016 | ||
15c00bba | 1017 | mock.subnet = find_host_for_network (&hp, &mock.ip_addr, share); |
7a049f2c TL |
1018 | if (!mock.subnet) |
1019 | return (struct lease *)0; | |
1020 | mock.next = mock.prev = (struct lease *)0; | |
1021 | mock.shared_network = mock.subnet -> shared_network; | |
1022 | mock.host = hp; | |
1023 | mock.uid_len = 0; | |
d01578b7 | 1024 | mock.hardware_addr = hp -> interface; |
7a049f2c TL |
1025 | mock.uid = (unsigned char *)0; |
1026 | mock.starts = mock.timestamp = mock.ends = MIN_TIME; | |
1027 | mock.flags = STATIC_LEASE; | |
1028 | return &mock; | |
1029 | } |