]>
git.ipfire.org Git - thirdparty/dhcp.git/blob - server/bootp.c
3 BOOTP Protocol support. */
6 * Copyright (c) 1995, 1996, 1997, 1998, 1999
7 * The Internet Software Consortium. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
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''.
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";
51 struct packet
*packet
;
55 struct host_decl
*host
= (struct host_decl
*)0;
56 struct packet outgoing
;
57 struct dhcp_packet raw
;
58 struct sockaddr_in to
;
61 struct option_state options
;
62 struct subnet
*subnet
;
64 struct iaddr ip_address
;
66 struct data_string d1
;
67 struct option_cache
*oc
;
70 if (packet
-> raw
-> op
!= BOOTREQUEST
)
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
);
83 if (!locate_network (packet
)) {
84 note ("%s: network unknown", msgbuf
);
88 hp
= find_hosts_by_haddr (packet
-> raw
-> htype
,
89 packet
-> raw
-> chaddr
,
90 packet
-> raw
-> hlen
);
92 lease
= find_lease (packet
, packet
-> shared_network
, 0);
94 /* Find an IP address in the host_decl that matches the
97 subnet
= find_host_for_network (&hp
, &ip_address
,
98 packet
-> shared_network
);
100 subnet
= (struct subnet
*)0;
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. */
108 for (; hp
; hp
= hp
-> n_ipaddr
) {
109 if (!hp
-> fixed_addr
) {
116 /* If a lease has already been assigned to this client,
119 ack_lease (packet
, lease
, 0, 0, msgbuf
);
123 /* Otherwise, try to allocate one. */
124 lease
= allocate_lease (packet
,
125 packet
-> shared_network
-> pools
, 0);
127 lease
-> host
= host
;
128 ack_lease (packet
, lease
, 0, 0, msgbuf
);
131 note ("%s: no available leases", msgbuf
);
135 /* Run the executable statements to compute the client and server
138 memset (&options
, 0, sizeof options
);
140 /* Execute the subnet statements. */
141 execute_statements_in_scope (packet
, &options
, &options
,
142 lease
-> subnet
-> group
,
145 /* Execute the host statements. */
146 execute_statements_in_scope (packet
, &options
, &options
, hp
-> group
,
147 lease
-> subnet
-> group
);
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
,
153 note ("%s: bootp disallowed", msgbuf
);
157 if (evaluate_boolean_option_cache (packet
, &options
,
158 lookup_option (options
.dhcp_hash
,
159 SV_ALLOW_BOOTING
))) {
160 note ("%s: booting disallowed", msgbuf
);
164 /* Set up the outgoing packet... */
165 memset (&outgoing
, 0, sizeof outgoing
);
166 memset (&raw
, 0, sizeof raw
);
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
;
176 /* Pack the options into the buffer. Unlike DHCP, we
177 can't pack options into the filename and server
180 outgoing
.packet_length
=
181 cons_options (packet
, outgoing
.raw
, 0,
182 &options
, (struct agent_options
*)0,
184 if (outgoing
.packet_length
< BOOTP_MIN_LEN
)
185 outgoing
.packet_length
= BOOTP_MIN_LEN
;
188 /* Take the fields that we care about... */
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
;
197 raw
.ciaddr
= packet
-> raw
-> ciaddr
;
198 memcpy (&raw
.yiaddr
, ip_address
.iabuf
, sizeof raw
.yiaddr
);
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
);
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");
212 raw
.giaddr
= packet
-> raw
-> giaddr
;
214 /* Figure out the filename. */
215 oc
= lookup_option (options
.dhcp_hash
, SV_FILENAME
);
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");
225 memcpy (raw
.file
, packet
-> raw
-> file
, sizeof raw
.file
);
227 /* Choose a server name as above. */
228 oc
= lookup_option (options
.dhcp_hash
, SV_SERVER_NAME
);
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");
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
);
244 from
= packet
-> interface
-> primary_address
;
246 /* Report what we're doing... */
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
);
257 /* Set up the parts of the address that are in common. */
258 to
.sin_family
= AF_INET
;
260 to
.sin_len
= sizeof to
;
262 memset (to
.sin_zero
, 0, sizeof to
.sin_zero
);
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
;
269 if (fallback_interface
) {
270 result
= send_packet (fallback_interface
,
272 &raw
, outgoing
.packet_length
,
275 warn ("send_packet: %m");
278 /* Otherwise, broadcast it on the local network. */
280 to
.sin_addr
.s_addr
= INADDR_BROADCAST
;
281 to
.sin_port
= remote_port
; /* XXX */
285 result
= send_packet (packet
-> interface
,
286 packet
, &raw
, outgoing
.packet_length
,
289 warn ("send_packet: %m");