]> git.ipfire.org Git - thirdparty/dhcp.git/blob - server/bootp.c
Release DHCP lease before assigning it to BOOTP client, so as to avoid unnecessary...
[thirdparty/dhcp.git] / server / bootp.c
1 /* bootp.c
2
3 BOOTP Protocol support. */
4
5 /*
6 * Copyright (c) 1995, 1996 The Internet Software Consortium.
7 * All rights reserved.
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[] =
45 "@(#) Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
46 #endif /* not lint */
47
48 #include "dhcpd.h"
49
50 void bootp (packet)
51 struct packet *packet;
52 {
53 int result;
54 struct host_decl *hp;
55 struct host_decl *host = (struct host_decl *)0;
56 struct packet outgoing;
57 struct dhcp_packet raw;
58 struct sockaddr_in to;
59 struct hardware hto;
60 struct tree_cache *options [256];
61 struct subnet *subnet;
62 struct lease *lease;
63 struct iaddr ip_address;
64 int i;
65
66 note ("BOOTREQUEST from %s via %s",
67 print_hw_addr (packet -> raw -> htype,
68 packet -> raw -> hlen,
69 packet -> raw -> chaddr),
70 packet -> raw -> giaddr.s_addr
71 ? inet_ntoa (packet -> raw -> giaddr)
72 : packet -> interface -> name);
73
74
75
76 locate_network (packet);
77
78 hp = find_hosts_by_haddr (packet -> raw -> htype,
79 packet -> raw -> chaddr,
80 packet -> raw -> hlen);
81
82 lease = find_lease (packet, packet -> shared_network);
83
84 /* Find an IP address in the host_decl that matches the
85 specified network. */
86 if (hp && packet -> shared_network)
87 subnet = find_host_for_network (&hp, &ip_address,
88 packet -> shared_network);
89 else
90 subnet = (struct subnet *)0;
91
92 if (!subnet) {
93 /* We didn't find an applicable host declaration.
94 Just in case we may be able to dynamically assign
95 an address, see if there's a host declaration
96 that doesn't have an ip address associated with it. */
97 if (hp) {
98 for (; hp; hp = hp -> n_ipaddr) {
99 if (!hp -> fixed_addr) {
100 host = hp;
101 }
102 }
103 }
104
105 /* If the packet is from a host we don't know and there
106 are no dynamic bootp addresses on the network it came
107 in on, drop it on the floor. */
108 if (!(packet -> shared_network &&
109 packet -> shared_network -> dynamic_bootp)) {
110 lose:
111 note ("No applicable record for BOOTP host %s",
112 print_hw_addr (packet -> raw -> htype,
113 packet -> raw -> hlen,
114 packet -> raw -> chaddr));
115 return;
116 }
117
118 /* If a lease has already been assigned to this client
119 and it's still okay to use dynamic bootp on
120 that lease, reassign it. */
121 if (lease) {
122 /* If this lease can be used for dynamic bootp,
123 do so. */
124 if ((lease -> flags & DYNAMIC_BOOTP_OK)) {
125
126 /* If it's not a DYNAMIC_BOOTP lease,
127 release it before reassigning it
128 so that we don't get a lease
129 conflict. */
130 if (!(lease -> flags & BOOTP_LEASE))
131 release_lease (lease);
132
133 lease -> host = host;
134 ack_lease (packet, lease, 0, 0);
135 return;
136 }
137
138 /* If dynamic BOOTP is no longer allowed for
139 this lease, set it free. */
140 release_lease (lease);
141 }
142
143 /* At this point, if we don't know the network from which
144 the packet came, lose it. */
145 if (!packet -> shared_network)
146 goto lose;
147
148 /* If there are dynamic bootp addresses that might be
149 available, try to snag one. */
150 for (lease =
151 packet -> shared_network -> last_lease;
152 lease && lease -> ends <= cur_time;
153 lease = lease -> prev) {
154 if ((lease -> flags & DYNAMIC_BOOTP_OK)) {
155 lease -> host = host;
156 ack_lease (packet, lease, 0, 0);
157 return;
158 }
159 }
160 goto lose;
161 }
162
163 /* If we don't have a fixed address for it, drop it. */
164 if (!subnet) {
165 note ("No fixed address for BOOTP host %s (%s)",
166 print_hw_addr (packet -> raw -> htype,
167 packet -> raw -> hlen,
168 packet -> raw -> chaddr),
169 hp -> name);
170 return;
171 }
172
173 /* Set up the outgoing packet... */
174 memset (&outgoing, 0, sizeof outgoing);
175 memset (&raw, 0, sizeof raw);
176 outgoing.raw = &raw;
177
178 /* Come up with a list of options that we want to send to this
179 client. Start with the per-subnet options, and then override
180 those with client-specific options. */
181
182 memcpy (options, subnet -> options, sizeof options);
183
184 for (i = 0; i < 256; i++) {
185 if (hp -> options [i])
186 options [i] = hp -> options [i];
187 }
188
189 /* Pack the options into the buffer. Unlike DHCP, we can't
190 pack options into the filename and server name buffers. */
191
192 cons_options (packet, &outgoing, options, 0);
193
194
195 /* Take the fields that we care about... */
196 raw.op = BOOTREPLY;
197 raw.htype = packet -> raw -> htype;
198 raw.hlen = packet -> raw -> hlen;
199 memcpy (raw.chaddr, packet -> raw -> chaddr, raw.hlen);
200 memset (&raw.chaddr [raw.hlen], 0,
201 (sizeof raw.chaddr) - raw.hlen);
202 raw.hops = packet -> raw -> hops;
203 raw.xid = packet -> raw -> xid;
204 raw.secs = packet -> raw -> secs;
205 raw.flags = 0;
206 raw.ciaddr = packet -> raw -> ciaddr;
207 memcpy (&raw.yiaddr, ip_address.iabuf, sizeof raw.yiaddr);
208
209 if (subnet -> interface_address.len)
210 memcpy (&raw.siaddr, subnet -> interface_address.iabuf, 4);
211 else
212 memcpy (&raw.siaddr, server_identifier.iabuf, 4);
213
214 raw.giaddr = packet -> raw -> giaddr;
215 if (hp -> server_name) {
216 strncpy (raw.sname, hp -> server_name,
217 (sizeof raw.sname) - 1);
218 raw.sname [(sizeof raw.sname) - 1] = 0;
219 }
220 if (hp -> filename) {
221 strncpy (raw.file, hp -> filename,
222 (sizeof raw.file) - 1);
223 raw.file [(sizeof raw.file) - 1] = 0;
224 }
225
226 /* Set up the hardware destination address... */
227 hto.htype = packet -> raw -> htype;
228 hto.hlen = packet -> raw -> hlen;
229 memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
230
231 /* Report what we're doing... */
232 note ("BOOTREPLY for %s to %s via %s",
233 inet_ntoa (raw.yiaddr),
234 print_hw_addr (packet -> raw -> htype,
235 packet -> raw -> hlen,
236 packet -> raw -> chaddr),
237 packet -> raw -> giaddr.s_addr
238 ? inet_ntoa (packet -> raw -> giaddr)
239 : packet -> interface -> name);
240
241 /* Set up the parts of the address that are in common. */
242 to.sin_family = AF_INET;
243 #ifdef HAVE_SA_LEN
244 to.sin_len = sizeof to;
245 #endif
246 memset (to.sin_zero, 0, sizeof to.sin_zero);
247
248 /* If this was gatewayed, send it back to the gateway... */
249 if (raw.giaddr.s_addr) {
250 to.sin_addr = raw.giaddr;
251 to.sin_port = server_port;
252
253 #ifdef USE_FALLBACK
254 result = send_fallback (&fallback_interface,
255 (struct packet *)0,
256 &raw, outgoing.packet_length,
257 raw.siaddr, &to, &hto);
258 if (result < 0)
259 warn ("send_fallback: %m");
260 return;
261 #endif
262 /* Otherwise, broadcast it on the local network. */
263 } else {
264 to.sin_addr.s_addr = INADDR_BROADCAST;
265 to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
266 }
267
268 errno = 0;
269 result = send_packet (packet -> interface,
270 packet, &raw, outgoing.packet_length,
271 raw.siaddr, &to, &hto);
272 if (result < 0)
273 warn ("send_packet: %m");
274 }