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