Provide individually cached constructed copies of DHCP packets via
[people/pcmattman/gpxe.git] / src / interface / pxe / pxe_preboot.c
1 /** @file
2  *
3  * PXE Preboot API
4  *
5  */
6
7 /* PXE API interface for Etherboot.
8  *
9  * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2 of the
14  * License, or any later version.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 #include <stdint.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <gpxe/uaccess.h>
30 #include <gpxe/dhcp.h>
31 #include <gpxe/device.h>
32 #include <gpxe/netdevice.h>
33 #include <gpxe/isapnp.h>
34 #include <gpxe/init.h>
35 #include <gpxe/if_ether.h>
36 #include <basemem_packet.h>
37 #include "pxe.h"
38 #include "pxe_call.h"
39
40 /* Avoid dragging in isapnp.o unnecessarily */
41 uint16_t isapnp_read_port;
42
43 /** Zero-based versions of PXENV_GET_CACHED_INFO::PacketType */
44 enum pxe_cached_info_indices {
45         CACHED_INFO_DHCPDISCOVER = ( PXENV_PACKET_TYPE_DHCP_DISCOVER - 1 ),
46         CACHED_INFO_DHCPACK = ( PXENV_PACKET_TYPE_DHCP_ACK - 1 ),
47         CACHED_INFO_BINL = ( PXENV_PACKET_TYPE_CACHED_REPLY - 1 ),
48         NUM_CACHED_INFOS
49 };
50
51 /** A cached DHCP packet */
52 union pxe_cached_info {
53         struct dhcphdr dhcphdr;
54         char raw[ETH_FRAME_LEN];
55 };
56
57 /* The case in which the caller doesn't supply a buffer is really
58  * awkward to support given that we have multiple sources of options,
59  * and that we don't actually store the DHCP packets.  (We may not
60  * even have performed DHCP; we may have obtained all configuration
61  * from non-volatile stored options or from the command line.)
62  *
63  * Some NBPs rely on the buffers we provide being persistent, so we
64  * can't just use the temporary packet buffer.  4.5kB of base memory
65  * always wasted just because some clients are too lazy to provide
66  * their own buffers...
67  */
68 static union pxe_cached_info __bss16_array ( cached_info, [NUM_CACHED_INFOS] );
69 #define cached_info __use_data16 ( cached_info )
70
71 /**
72  * UNLOAD BASE CODE STACK
73  *
74  * @v None                              -
75  * @ret ...
76  *
77  */
78 PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) {
79         DBG ( "PXENV_UNLOAD_STACK" );
80
81         unload_stack->Status = PXENV_STATUS_SUCCESS;
82         return PXENV_EXIT_SUCCESS;
83 }
84
85 /* PXENV_GET_CACHED_INFO
86  *
87  * Status: working
88  */
89 PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
90                                      *get_cached_info ) {
91         struct dhcp_packet dhcppkt;
92         int ( * dhcp_packet_creator ) ( struct net_device *, int,
93                                         struct dhcp_option_block *, void *,
94                                         size_t, struct dhcp_packet * );
95         unsigned int idx;
96         unsigned int msgtype;
97         size_t len;
98         userptr_t buffer;
99         int rc;
100
101         DBG ( "PXENV_GET_CACHED_INFO %d", get_cached_info->PacketType );
102
103         DBG ( " to %04x:%04x+%x", get_cached_info->Buffer.segment,
104               get_cached_info->Buffer.offset, get_cached_info->BufferSize );
105
106         /* Sanity check */
107         idx = ( get_cached_info->PacketType - 1 );
108         if ( idx >= ( sizeof ( cached_info ) / sizeof ( cached_info[0] ) ) ) {
109                 DBG ( " bad PacketType" );
110                 goto err;
111         }
112
113         /* Construct cached version of packet, if not already constructed. */
114         if ( ! cached_info[idx].dhcphdr.op ) {
115                 /* Construct DHCP packet */
116                 if ( get_cached_info->PacketType ==
117                      PXENV_PACKET_TYPE_DHCP_DISCOVER ) {
118                         dhcp_packet_creator = create_dhcp_request;
119                         msgtype = DHCPDISCOVER;
120                 } else {
121                         dhcp_packet_creator = create_dhcp_response;
122                         msgtype = DHCPACK;
123                 }
124                 if ( ( rc = dhcp_packet_creator ( pxe_netdev, msgtype,
125                                                   NULL, &cached_info[idx],
126                                                   sizeof ( cached_info[idx] ),
127                                                   &dhcppkt ) ) != 0 ) {
128                         DBG ( " failed to build packet" );
129                         goto err;
130                 }
131         }
132
133         len = get_cached_info->BufferSize;
134         if ( len == 0 ) {
135                 /* Point client at our cached buffer.
136                  *
137                  * To add to the fun, Intel decided at some point in
138                  * the evolution of the PXE specification to add the
139                  * BufferLimit field, which we are meant to fill in
140                  * with the length of our packet buffer, so that the
141                  * caller can safely modify the boot server reply
142                  * packet stored therein.  However, this field was not
143                  * present in earlier versions of the PXE spec, and
144                  * there is at least one PXE NBP (Altiris) which
145                  * allocates only exactly enough space for this
146                  * earlier, shorter version of the structure.  If we
147                  * actually fill in the BufferLimit field, we
148                  * therefore risk trashing random areas of the
149                  * caller's memory.  If we *don't* fill it in, then
150                  * the caller is at liberty to assume that whatever
151                  * random value happened to be in that location
152                  * represents the length of the buffer we've just
153                  * passed back to it.
154                  *
155                  * Since older PXE stacks won't fill this field in
156                  * anyway, it's probably safe to assume that no
157                  * callers actually rely on it, so we choose to not
158                  * fill it in.
159                  */
160                 get_cached_info->Buffer.segment = rm_ds;
161                 get_cached_info->Buffer.offset =
162                         ( unsigned ) ( & __from_data16 ( cached_info[idx] ) );
163                 get_cached_info->BufferSize = sizeof ( cached_info[idx] );
164                 DBG ( " returning %04x:%04x+%04x['%x']",
165                       get_cached_info->Buffer.segment,
166                       get_cached_info->Buffer.offset,
167                       get_cached_info->BufferSize,
168                       get_cached_info->BufferLimit );
169         } else {
170                 /* Copy packet to client buffer */
171                 if ( len < sizeof ( cached_info[idx] ) ) {
172                         DBG ( " buffer too short" );
173                         goto err;
174                 }
175                 buffer = real_to_user ( get_cached_info->Buffer.segment,
176                                         get_cached_info->Buffer.offset );
177                 copy_to_user ( buffer, 0, &cached_info[idx],
178                                sizeof ( cached_info[idx] ) );
179                 get_cached_info->BufferSize = sizeof ( cached_info[idx] );
180         }
181
182         get_cached_info->Status = PXENV_STATUS_SUCCESS;
183         return PXENV_EXIT_SUCCESS;
184
185  err:
186         get_cached_info->Status = PXENV_STATUS_OUT_OF_RESOURCES;
187         return PXENV_EXIT_FAILURE;
188 }
189
190 /* PXENV_RESTART_TFTP
191  *
192  * Status: working
193  */
194 PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
195                                   *restart_tftp ) {
196         PXENV_EXIT_t tftp_exit;
197
198         DBG ( "PXENV_RESTART_TFTP " );
199
200         /* This is a bug-for-bug compatibility hack needed in order to
201          * work with Microsoft Remote Installation Services (RIS).
202          * The filename used in a call to PXENV_RESTART_TFTP must be
203          * returned as the DHCP filename in subsequent calls to
204          * PXENV_GET_CACHED_INFO.
205          */
206         memcpy ( cached_info[CACHED_INFO_DHCPACK].dhcphdr.file,
207                  restart_tftp->FileName,
208                  sizeof ( cached_info[CACHED_INFO_DHCPACK].dhcphdr.file ) );
209         memcpy ( cached_info[CACHED_INFO_BINL].dhcphdr.file,
210                  restart_tftp->FileName,
211                  sizeof ( cached_info[CACHED_INFO_BINL].dhcphdr.file ) );
212
213         /* Words cannot describe the complete mismatch between the PXE
214          * specification and any possible version of reality...
215          */
216         restart_tftp->Buffer = PXE_LOAD_PHYS; /* Fixed by spec, apparently */
217         restart_tftp->BufferSize = ( 0xa0000 - PXE_LOAD_PHYS ); /* Near enough */
218         tftp_exit = pxenv_tftp_read_file ( restart_tftp );
219         if ( tftp_exit != PXENV_EXIT_SUCCESS )
220                 return tftp_exit;
221
222         /* Fire up the new NBP */
223         restart_tftp->Status = pxe_start_nbp();
224
225         /* Not sure what "SUCCESS" actually means, since we can only
226          * return if the new NBP failed to boot...
227          */
228         return PXENV_EXIT_SUCCESS;
229 }
230
231 /* PXENV_START_UNDI
232  *
233  * Status: working
234  */
235 PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
236         unsigned int bus_type;
237         unsigned int location;
238         struct net_device *netdev;
239
240         DBG ( "PXENV_START_UNDI %04x:%04x:%04x",
241               start_undi->AX, start_undi->BX, start_undi->DX );
242
243         /* Determine bus type and location.  Use a heuristic to decide
244          * whether we are PCI or ISAPnP
245          */
246         if ( ( start_undi->DX >= ISAPNP_READ_PORT_MIN ) &&
247              ( start_undi->DX <= ISAPNP_READ_PORT_MAX ) &&
248              ( start_undi->BX >= ISAPNP_CSN_MIN ) &&
249              ( start_undi->BX <= ISAPNP_CSN_MAX ) ) {
250                 bus_type = BUS_TYPE_ISAPNP;
251                 location = start_undi->BX;
252                 /* Record ISAPnP read port for use by isapnp.c */
253                 isapnp_read_port = start_undi->DX;
254         } else {
255                 bus_type = BUS_TYPE_PCI;
256                 location = start_undi->AX;
257         }
258
259         /* Probe for devices, etc. */
260         startup();
261
262         /* Look for a matching net device */
263         netdev = find_netdev_by_location ( bus_type, location );
264         if ( ! netdev ) {
265                 DBG ( " no net device found" );
266                 start_undi->Status = PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC;
267                 return PXENV_EXIT_FAILURE;
268         }
269         DBG ( " using netdev %s", netdev->name );
270
271         /* Save as PXE net device */
272         pxe_set_netdev ( netdev );
273
274         /* Hook INT 1A */
275         pxe_hook_int1a();
276
277         start_undi->Status = PXENV_STATUS_SUCCESS;
278         return PXENV_EXIT_SUCCESS;
279 }
280
281 /* PXENV_STOP_UNDI
282  *
283  * Status: working
284  */
285 PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) {
286         DBG ( "PXENV_STOP_UNDI" );
287
288         /* Unhook INT 1A */
289         pxe_unhook_int1a();
290
291         /* Clear PXE net device */
292         pxe_set_netdev ( NULL );
293
294         /* Prepare for unload */
295         shutdown();
296
297         stop_undi->Status = PXENV_STATUS_SUCCESS;
298         return PXENV_EXIT_SUCCESS;
299 }
300
301 /* PXENV_START_BASE
302  *
303  * Status: won't implement (requires major structural changes)
304  */
305 PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base ) {
306         DBG ( "PXENV_START_BASE" );
307
308         start_base->Status = PXENV_STATUS_UNSUPPORTED;
309         return PXENV_EXIT_FAILURE;
310 }
311
312 /* PXENV_STOP_BASE
313  *
314  * Status: working
315  */
316 PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ) {
317         DBG ( "PXENV_STOP_BASE" );
318
319         /* The only time we will be called is when the NBP is trying
320          * to shut down the PXE stack.  There's nothing we need to do
321          * in this call.
322          */
323
324         stop_base->Status = PXENV_STATUS_SUCCESS;
325         return PXENV_EXIT_SUCCESS;
326 }