]> git.ipfire.org Git - thirdparty/dhcp.git/blob - server/bootp.c
Add pool support.
[thirdparty/dhcp.git] / server / bootp.c
1 /* bootp.c
2
3 BOOTP Protocol support. */
4
5 /*
6 * Copyright (c) 1995, 1996, 1997, 1998 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 "$Id: bootp.c,v 1.34 1998/11/09 02:45:59 mellon Exp $ 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 in_addr from;
60 struct hardware hto;
61 struct option_state options;
62 struct subnet *subnet;
63 struct lease *lease;
64 struct iaddr ip_address;
65 int i;
66 struct data_string d1;
67 struct option_cache *oc;
68
69 if (packet -> raw -> op != BOOTREQUEST)
70 return;
71
72 note ("BOOTREQUEST from %s via %s",
73 print_hw_addr (packet -> raw -> htype,
74 packet -> raw -> hlen,
75 packet -> raw -> chaddr),
76 packet -> raw -> giaddr.s_addr
77 ? inet_ntoa (packet -> raw -> giaddr)
78 : packet -> interface -> name);
79
80
81
82 if (!locate_network (packet))
83 return;
84
85 hp = find_hosts_by_haddr (packet -> raw -> htype,
86 packet -> raw -> chaddr,
87 packet -> raw -> hlen);
88
89 lease = find_lease (packet, packet -> shared_network, 0);
90
91 /* Find an IP address in the host_decl that matches the
92 specified network. */
93 if (hp)
94 subnet = find_host_for_network (&hp, &ip_address,
95 packet -> shared_network);
96 else
97 subnet = (struct subnet *)0;
98
99 if (!subnet) {
100 /* We didn't find an applicable host declaration.
101 Just in case we may be able to dynamically assign
102 an address, see if there's a host declaration
103 that doesn't have an ip address associated with it. */
104 if (hp) {
105 for (; hp; hp = hp -> n_ipaddr) {
106 if (!hp -> fixed_addr) {
107 host = hp;
108 break;
109 }
110 }
111 }
112
113 /* If a lease has already been assigned to this client,
114 use it. */
115 if (lease) {
116 ack_lease (packet, lease, 0, 0);
117 return;
118 }
119
120 /* Otherwise, try to allocate one. */
121 lease = allocate_lease (packet,
122 packet -> shared_network -> pools, 0);
123 if (lease) {
124 lease -> host = host;
125 ack_lease (packet, lease, 0, 0);
126 return;
127 }
128 note ("No available leases for BOOTP client %s",
129 print_hw_addr (packet -> raw -> htype,
130 packet -> raw -> hlen,
131 packet -> raw -> chaddr));
132 return;
133 }
134
135 /* Run the executable statements to compute the client and server
136 options. */
137
138 memset (&options, 0, sizeof options);
139
140 /* Execute the subnet statements. */
141 execute_statements_in_scope (packet, &options,
142 lease -> subnet -> group,
143 (struct group *)0);
144
145 /* Execute the host statements. */
146 execute_statements_in_scope (packet, &options, hp -> group,
147 lease -> subnet -> group);
148
149 /* Drop the request if it's not allowed for this client. */
150 if (evaluate_boolean_option_cache (packet, &options,
151 lookup_option (options.dhcp_hash,
152 SV_ALLOW_BOOTP))) {
153 note ("Ignoring BOOTP client %s",
154 print_hw_addr (packet -> raw -> htype,
155 packet -> raw -> hlen,
156 packet -> raw -> chaddr));
157 return;
158 }
159
160 if (evaluate_boolean_option_cache (packet, &options,
161 lookup_option (options.dhcp_hash,
162 SV_ALLOW_BOOTP))) {
163 note ("Declining to boot client %s",
164 lease -> host -> name
165 ? lease -> host -> name
166 : print_hw_addr (packet -> raw -> htype,
167 packet -> raw -> hlen,
168 packet -> raw -> chaddr));
169 return;
170 }
171
172 /* Set up the outgoing packet... */
173 memset (&outgoing, 0, sizeof outgoing);
174 memset (&raw, 0, sizeof raw);
175 outgoing.raw = &raw;
176
177 /* If we didn't get a known vendor magic number on the way in,
178 just copy the input options to the output. */
179 if (!packet -> options_valid) {
180 memcpy (outgoing.raw -> options,
181 packet -> raw -> options, DHCP_OPTION_LEN);
182 outgoing.packet_length = BOOTP_MIN_LEN;
183 } else {
184 /* Pack the options into the buffer. Unlike DHCP, we
185 can't pack options into the filename and server
186 name buffers. */
187
188 outgoing.packet_length =
189 cons_options (packet, outgoing.raw, 0,
190 &options, (struct agent_options *)0,
191 0, 0, 1);
192 if (outgoing.packet_length < BOOTP_MIN_LEN)
193 outgoing.packet_length = BOOTP_MIN_LEN;
194 }
195
196 /* Take the fields that we care about... */
197 raw.op = BOOTREPLY;
198 raw.htype = packet -> raw -> htype;
199 raw.hlen = packet -> raw -> hlen;
200 memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
201 raw.hops = packet -> raw -> hops;
202 raw.xid = packet -> raw -> xid;
203 raw.secs = packet -> raw -> secs;
204 raw.flags = 0;
205 raw.ciaddr = packet -> raw -> ciaddr;
206 memcpy (&raw.yiaddr, ip_address.iabuf, sizeof raw.yiaddr);
207
208 /* Figure out the address of the next server. */
209 raw.siaddr = lease -> shared_network -> interface -> primary_address;
210 oc = lookup_option (options.dhcp_hash, SV_NEXT_SERVER);
211 if (oc &&
212 evaluate_option_cache (&d1, packet, &options, oc)) {
213 /* If there was more than one answer, take the first. */
214 if (d1.len >= 4 && d1.data)
215 memcpy (&raw.siaddr, d1.data, 4);
216 data_string_forget (&d1, "bootrequest");
217 }
218
219 raw.giaddr = packet -> raw -> giaddr;
220
221 /* Figure out the filename. */
222 oc = lookup_option (options.dhcp_hash, SV_FILENAME);
223 if (oc &&
224 evaluate_option_cache (&d1, packet, &options, oc)) {
225 memcpy (raw.file, d1.data,
226 d1.len > sizeof raw.file ? sizeof raw.file : d1.len);
227 if (sizeof raw.file > d1.len)
228 memset (&raw.file [d1.len],
229 0, (sizeof raw.file) - d1.len);
230 data_string_forget (&d1, "bootrequest");
231 }
232
233 /* Choose a server name as above. */
234 oc = lookup_option (options.dhcp_hash, SV_SERVER_NAME);
235 if (oc &&
236 evaluate_option_cache (&d1, packet, &options, oc)) {
237 memcpy (raw.sname, d1.data,
238 d1.len > sizeof raw.sname ? sizeof raw.sname : d1.len);
239 if (sizeof raw.sname > d1.len)
240 memset (&raw.sname [d1.len],
241 0, (sizeof raw.sname) - d1.len);
242 data_string_forget (&d1, "bootrequest");
243 }
244
245 /* Set up the hardware destination address... */
246 hto.htype = packet -> raw -> htype;
247 hto.hlen = packet -> raw -> hlen;
248 memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
249
250 from = packet -> interface -> primary_address;
251
252 /* Report what we're doing... */
253 note ("BOOTREPLY for %s to %s (%s) via %s",
254 piaddr (ip_address), hp -> name,
255 print_hw_addr (packet -> raw -> htype,
256 packet -> raw -> hlen,
257 packet -> raw -> chaddr),
258 packet -> raw -> giaddr.s_addr
259 ? inet_ntoa (packet -> raw -> giaddr)
260 : packet -> interface -> name);
261
262 /* Set up the parts of the address that are in common. */
263 to.sin_family = AF_INET;
264 #ifdef HAVE_SA_LEN
265 to.sin_len = sizeof to;
266 #endif
267 memset (to.sin_zero, 0, sizeof to.sin_zero);
268
269 /* If this was gatewayed, send it back to the gateway... */
270 if (raw.giaddr.s_addr) {
271 to.sin_addr = raw.giaddr;
272 to.sin_port = local_port;
273
274 #ifdef USE_FALLBACK
275 result = send_fallback (&fallback_interface,
276 (struct packet *)0,
277 &raw, outgoing.packet_length,
278 from, &to, &hto);
279 if (result < 0)
280 warn ("send_fallback: %m");
281 return;
282 #endif
283 /* Otherwise, broadcast it on the local network. */
284 } else {
285 to.sin_addr.s_addr = INADDR_BROADCAST;
286 to.sin_port = remote_port; /* XXX */
287 }
288
289 errno = 0;
290 result = send_packet (packet -> interface,
291 packet, &raw, outgoing.packet_length,
292 from, &to, &hto);
293 if (result < 0)
294 warn ("send_packet: %m");
295 }