]>
git.ipfire.org Git - thirdparty/dhcp.git/blob - server/bootp.c
3 BOOTP Protocol support. */
6 * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
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.34 1998/11/09 02:45:59 mellon Exp $ Copyright (c) 1995, 1996 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
;
69 if (packet
-> raw
-> op
!= BOOTREQUEST
)
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
);
82 if (!locate_network (packet
))
85 hp
= find_hosts_by_haddr (packet
-> raw
-> htype
,
86 packet
-> raw
-> chaddr
,
87 packet
-> raw
-> hlen
);
89 lease
= find_lease (packet
, packet
-> shared_network
, 0);
91 /* Find an IP address in the host_decl that matches the
94 subnet
= find_host_for_network (&hp
, &ip_address
,
95 packet
-> shared_network
);
97 subnet
= (struct subnet
*)0;
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. */
105 for (; hp
; hp
= hp
-> n_ipaddr
) {
106 if (!hp
-> fixed_addr
) {
113 /* If a lease has already been assigned to this client,
116 ack_lease (packet
, lease
, 0, 0);
120 /* Otherwise, try to allocate one. */
121 lease
= allocate_lease (packet
,
122 packet
-> shared_network
-> pools
, 0);
124 lease
-> host
= host
;
125 ack_lease (packet
, lease
, 0, 0);
128 note ("No available leases for BOOTP client %s",
129 print_hw_addr (packet
-> raw
-> htype
,
130 packet
-> raw
-> hlen
,
131 packet
-> raw
-> chaddr
));
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
,
142 lease
-> subnet
-> group
,
145 /* Execute the host statements. */
146 execute_statements_in_scope (packet
, &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 ("Ignoring BOOTP client %s",
154 print_hw_addr (packet
-> raw
-> htype
,
155 packet
-> raw
-> hlen
,
156 packet
-> raw
-> chaddr
));
160 if (evaluate_boolean_option_cache (packet
, &options
,
161 lookup_option (options
.dhcp_hash
,
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
));
172 /* Set up the outgoing packet... */
173 memset (&outgoing
, 0, sizeof outgoing
);
174 memset (&raw
, 0, sizeof raw
);
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
;
184 /* Pack the options into the buffer. Unlike DHCP, we
185 can't pack options into the filename and server
188 outgoing
.packet_length
=
189 cons_options (packet
, outgoing
.raw
, 0,
190 &options
, (struct agent_options
*)0,
192 if (outgoing
.packet_length
< BOOTP_MIN_LEN
)
193 outgoing
.packet_length
= BOOTP_MIN_LEN
;
196 /* Take the fields that we care about... */
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
;
205 raw
.ciaddr
= packet
-> raw
-> ciaddr
;
206 memcpy (&raw
.yiaddr
, ip_address
.iabuf
, sizeof raw
.yiaddr
);
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
);
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");
219 raw
.giaddr
= packet
-> raw
-> giaddr
;
221 /* Figure out the filename. */
222 oc
= lookup_option (options
.dhcp_hash
, SV_FILENAME
);
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");
233 /* Choose a server name as above. */
234 oc
= lookup_option (options
.dhcp_hash
, SV_SERVER_NAME
);
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");
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
);
250 from
= packet
-> interface
-> primary_address
;
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
);
262 /* Set up the parts of the address that are in common. */
263 to
.sin_family
= AF_INET
;
265 to
.sin_len
= sizeof to
;
267 memset (to
.sin_zero
, 0, sizeof to
.sin_zero
);
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
;
275 result
= send_fallback (&fallback_interface
,
277 &raw
, outgoing
.packet_length
,
280 warn ("send_fallback: %m");
283 /* Otherwise, broadcast it on the local network. */
285 to
.sin_addr
.s_addr
= INADDR_BROADCAST
;
286 to
.sin_port
= remote_port
; /* XXX */
290 result
= send_packet (packet
-> interface
,
291 packet
, &raw
, outgoing
.packet_length
,
294 warn ("send_packet: %m");