revert between 56095 -> 55830 in arch
[AROS.git] / workbench / network / stacks / AROSTCP / dhcp / server / bootp.c
blobce3a0695238451062905eeeefdcd9f203f218006
1 /* bootp.c
3 BOOTP Protocol support. */
5 /*
6 * Copyright (c) 2004-2005 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
35 #ifndef lint
36 static char copyright[] =
37 "$Id$ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
38 #endif /* not lint */
40 #include "dhcpd.h"
42 #if defined (TRACING)
43 # define send_packet trace_packet_send
44 #endif
46 void bootp (packet)
47 struct packet *packet;
49 int result;
50 struct host_decl *hp = (struct host_decl *)0;
51 struct host_decl *host = (struct host_decl *)0;
52 struct packet outgoing;
53 struct dhcp_packet raw;
54 struct sockaddr_in to;
55 struct in_addr from;
56 struct hardware hto;
57 struct option_state *options = (struct option_state *)0;
58 struct lease *lease = (struct lease *)0;
59 unsigned i;
60 struct data_string d1;
61 struct option_cache *oc;
62 char msgbuf [1024];
63 int ignorep;
64 int peer_has_leases = 0;
66 if (packet -> raw -> op != BOOTREQUEST)
67 return;
69 /* %Audit% This is log output. %2004.06.17,Safe%
70 * If we truncate we hope the user can get a hint from the log.
72 snprintf (msgbuf, sizeof msgbuf, "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);
80 if (!locate_network (packet)) {
81 log_info ("%s: network unknown", msgbuf);
82 return;
85 find_lease (&lease, packet, packet -> shared_network,
86 0, 0, (struct lease *)0, MDL);
88 if (lease && lease->host)
89 host_reference(&hp, lease->host, MDL);
91 if (!lease || ((lease->flags & STATIC_LEASE) == 0)) {
92 struct host_decl *h;
93 /* We didn't find an applicable fixed-address host
94 declaration. Just in case we may be able to dynamically
95 assign an address, see if there's a host declaration
96 that doesn't have an ip address associated with it. */
98 if (!hp)
99 find_hosts_by_haddr(&hp, packet->raw->htype,
100 packet->raw->chaddr,
101 packet->raw->hlen, MDL);
103 for (h = hp; h; h = h -> n_ipaddr) {
104 if (!h -> fixed_addr) {
105 host_reference(&host, h, MDL);
106 break;
110 if (hp)
111 host_dereference(&hp, MDL);
113 if (host) {
114 host_reference(&hp, host, MDL);
115 host_dereference(&host, MDL);
118 /* Allocate a lease if we have not yet found one. */
119 if (!lease)
120 allocate_lease (&lease, packet,
121 packet -> shared_network -> pools,
122 &peer_has_leases);
124 if (lease)
125 ack_lease (packet, lease, 0, 0, msgbuf, 0, hp);
126 else
127 log_info ("%s: BOOTP from dynamic client and no "
128 "dynamic leases", msgbuf);
130 goto out;
133 /* Run the executable statements to compute the client and server
134 options. */
135 option_state_allocate (&options, MDL);
137 /* Execute the subnet statements. */
138 execute_statements_in_scope ((struct binding_value **)0,
139 packet, lease, (struct client_state *)0,
140 packet -> options, options,
141 &lease -> scope, lease -> subnet -> group,
142 (struct group *)0);
144 /* Execute statements from class scopes. */
145 for (i = packet -> class_count; i > 0; i--) {
146 execute_statements_in_scope
147 ((struct binding_value **)0,
148 packet, lease, (struct client_state *)0,
149 packet -> options, options,
150 &lease -> scope, packet -> classes [i - 1] -> group,
151 lease -> subnet -> group);
154 /* Execute the host statements. */
155 execute_statements_in_scope ((struct binding_value **)0,
156 packet, lease, (struct client_state *)0,
157 packet -> options, options,
158 &lease -> scope,
159 hp -> group, lease -> subnet -> group);
161 /* Drop the request if it's not allowed for this client. */
162 if ((oc = lookup_option (&server_universe, options, SV_ALLOW_BOOTP)) &&
163 !evaluate_boolean_option_cache (&ignorep, packet, lease,
164 (struct client_state *)0,
165 packet -> options, options,
166 &lease -> scope, oc, MDL)) {
167 if (!ignorep)
168 log_info ("%s: bootp disallowed", msgbuf);
169 goto out;
172 if ((oc = lookup_option (&server_universe,
173 options, SV_ALLOW_BOOTING)) &&
174 !evaluate_boolean_option_cache (&ignorep, packet, lease,
175 (struct client_state *)0,
176 packet -> options, options,
177 &lease -> scope, oc, MDL)) {
178 if (!ignorep)
179 log_info ("%s: booting disallowed", msgbuf);
180 goto out;
183 /* Set up the outgoing packet... */
184 memset (&outgoing, 0, sizeof outgoing);
185 memset (&raw, 0, sizeof raw);
186 outgoing.raw = &raw;
188 /* If we didn't get a known vendor magic number on the way in,
189 just copy the input options to the output. */
190 if (!packet -> options_valid &&
191 !(evaluate_boolean_option_cache
192 (&ignorep, packet, lease, (struct client_state *)0,
193 packet -> options, options, &lease -> scope,
194 lookup_option (&server_universe, options,
195 SV_ALWAYS_REPLY_RFC1048), MDL))) {
196 memcpy (outgoing.raw -> options,
197 packet -> raw -> options, DHCP_OPTION_LEN);
198 outgoing.packet_length = BOOTP_MIN_LEN;
199 } else {
201 /* Use the subnet mask from the subnet declaration if no other
202 mask has been provided. */
204 oc = (struct option_cache *)0;
205 i = DHO_SUBNET_MASK;
206 if (!lookup_option (&dhcp_universe, options, i)) {
207 if (option_cache_allocate (&oc, MDL)) {
208 if (make_const_data
209 (&oc -> expression,
210 lease -> subnet -> netmask.iabuf,
211 lease -> subnet -> netmask.len,
212 0, 0, MDL)) {
213 oc -> option =
214 dhcp_universe.options [i];
215 save_option (&dhcp_universe,
216 options, oc);
218 option_cache_dereference (&oc, MDL);
222 /* Pack the options into the buffer. Unlike DHCP, we
223 can't pack options into the filename and server
224 name buffers. */
226 outgoing.packet_length =
227 cons_options (packet, outgoing.raw, lease,
228 (struct client_state *)0, 0,
229 packet -> options, options,
230 &lease -> scope,
231 0, 0, 1, (struct data_string *)0,
232 (const char *)0);
233 if (outgoing.packet_length < BOOTP_MIN_LEN)
234 outgoing.packet_length = BOOTP_MIN_LEN;
237 /* Take the fields that we care about... */
238 raw.op = BOOTREPLY;
239 raw.htype = packet -> raw -> htype;
240 raw.hlen = packet -> raw -> hlen;
241 memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
242 raw.hops = packet -> raw -> hops;
243 raw.xid = packet -> raw -> xid;
244 raw.secs = packet -> raw -> secs;
245 raw.flags = packet -> raw -> flags;
246 raw.ciaddr = packet -> raw -> ciaddr;
248 /* yiaddr is an ipv4 address, it must be 4 octets. */
249 memcpy (&raw.yiaddr, lease->ip_addr.iabuf, 4);
251 /* If we're always supposed to broadcast to this client, set
252 the broadcast bit in the bootp flags field. */
253 if ((oc = lookup_option (&server_universe,
254 options, SV_ALWAYS_BROADCAST)) &&
255 evaluate_boolean_option_cache (&ignorep, packet, lease,
256 (struct client_state *)0,
257 packet -> options, options,
258 &lease -> scope, oc, MDL))
259 raw.flags |= htons (BOOTP_BROADCAST);
261 /* Figure out the address of the next server. */
262 memset (&d1, 0, sizeof d1);
263 oc = lookup_option (&server_universe, options, SV_NEXT_SERVER);
264 if (oc &&
265 evaluate_option_cache (&d1, packet, lease,
266 (struct client_state *)0,
267 packet -> options, options,
268 &lease -> scope, oc, MDL)) {
269 /* If there was more than one answer, take the first. */
270 if (d1.len >= 4 && d1.data)
271 memcpy (&raw.siaddr, d1.data, 4);
272 data_string_forget (&d1, MDL);
273 } else {
274 if (lease -> subnet -> shared_network -> interface)
275 raw.siaddr = (lease -> subnet -> shared_network ->
276 interface -> primary_address);
277 else
278 raw.siaddr = packet -> interface -> primary_address;
281 raw.giaddr = packet -> raw -> giaddr;
283 /* Figure out the filename. */
284 oc = lookup_option (&server_universe, options, SV_FILENAME);
285 if (oc &&
286 evaluate_option_cache (&d1, packet, lease,
287 (struct client_state *)0,
288 packet -> options, options,
289 &lease -> scope, oc, MDL)) {
290 memcpy (raw.file, d1.data,
291 d1.len > sizeof raw.file ? sizeof raw.file : d1.len);
292 if (sizeof raw.file > d1.len)
293 memset (&raw.file [d1.len],
294 0, (sizeof raw.file) - d1.len);
295 data_string_forget (&d1, MDL);
296 } else
297 memcpy (raw.file, packet -> raw -> file, sizeof raw.file);
299 /* Choose a server name as above. */
300 oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
301 if (oc &&
302 evaluate_option_cache (&d1, packet, lease,
303 (struct client_state *)0,
304 packet -> options, options,
305 &lease -> scope, oc, MDL)) {
306 memcpy (raw.sname, d1.data,
307 d1.len > sizeof raw.sname ? sizeof raw.sname : d1.len);
308 if (sizeof raw.sname > d1.len)
309 memset (&raw.sname [d1.len],
310 0, (sizeof raw.sname) - d1.len);
311 data_string_forget (&d1, MDL);
314 /* Execute the commit statements, if there are any. */
315 execute_statements ((struct binding_value **)0,
316 packet, lease, (struct client_state *)0,
317 packet -> options,
318 options, &lease -> scope, lease -> on_commit);
320 /* We're done with the option state. */
321 option_state_dereference (&options, MDL);
323 /* Set up the hardware destination address... */
324 hto.hbuf [0] = packet -> raw -> htype;
325 hto.hlen = packet -> raw -> hlen + 1;
326 memcpy (&hto.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen);
328 from = packet -> interface -> primary_address;
330 /* Report what we're doing... */
331 log_info ("%s", msgbuf);
332 log_info ("BOOTREPLY for %s to %s (%s) via %s",
333 piaddr (lease->ip_addr), hp -> name,
334 print_hw_addr (packet -> raw -> htype,
335 packet -> raw -> hlen,
336 packet -> raw -> chaddr),
337 packet -> raw -> giaddr.s_addr
338 ? inet_ntoa (packet -> raw -> giaddr)
339 : packet -> interface -> name);
341 /* Set up the parts of the address that are in common. */
342 to.sin_family = AF_INET;
343 #ifdef HAVE_SA_LEN
344 to.sin_len = sizeof to;
345 #endif
346 memset (to.sin_zero, 0, sizeof to.sin_zero);
348 /* If this was gatewayed, send it back to the gateway... */
349 if (raw.giaddr.s_addr) {
350 to.sin_addr = raw.giaddr;
351 to.sin_port = local_port;
353 if (fallback_interface) {
354 result = send_packet (fallback_interface,
355 (struct packet *)0,
356 &raw, outgoing.packet_length,
357 from, &to, &hto);
358 goto out;
361 /* If it comes from a client that already knows its address
362 and is not requesting a broadcast response, and we can
363 unicast to a client without using the ARP protocol, sent it
364 directly to that client. */
365 } else if (!(raw.flags & htons (BOOTP_BROADCAST)) &&
366 can_unicast_without_arp (packet -> interface)) {
367 to.sin_addr = raw.yiaddr;
368 to.sin_port = remote_port;
370 /* Otherwise, broadcast it on the local network. */
371 } else {
372 to.sin_addr = limited_broadcast;
373 to.sin_port = remote_port; /* XXX */
376 errno = 0;
377 result = send_packet (packet -> interface,
378 packet, &raw, outgoing.packet_length,
379 from, &to, &hto);
380 out:
381 if (options)
382 option_state_dereference (&options, MDL);
383 if (lease)
384 lease_dereference (&lease, MDL);
385 if (hp)
386 host_dereference (&hp, MDL);
387 if (host)
388 host_dereference (&host, MDL);