Moved pxe_export.c to pxe.c, since the old pxe.c no longer exists.
[people/xl0/gpxe.git] / src / core / pxe.c
1 /* PXE API interface for Etherboot.
2  *
3  * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 /* Tags used in this file:
21  *
22  * FIXME : obvious
23  * PXESPEC : question over interpretation of the PXE spec.
24  */
25
26 #ifdef PXE_EXPORT
27
28 #include "etherboot.h"
29 #include "pxe.h"
30 #include "pxe_export.h"
31 #include "pxe_callbacks.h"
32 #include "dev.h"
33 #include "nic.h"
34 #include "pci.h"
35 #include "cpu.h"
36 #include "timer.h"
37
38 #undef DBG
39 #if TRACE_PXE
40 #define DBG(...) printf ( __VA_ARGS__ )
41 #else
42 #define DBG(...)
43 #endif
44
45 /* Not sure why this isn't a globally-used structure within Etherboot.
46  * (Because I didn't want to use packed to prevent gcc from aligning
47  * source however it liked. Also nstype is a u16, not a uint. - Ken)
48  */
49 typedef struct {
50         char dest[ETH_ALEN];
51         char source[ETH_ALEN];
52         unsigned int nstype;
53 } media_header_t;
54 static const char broadcast_mac[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
55
56 /* Global pointer to currently installed PXE stack */
57 pxe_stack_t *pxe_stack = NULL;
58
59 /* Various startup/shutdown routines.  The startup/shutdown call
60  * sequence is incredibly badly defined in the Intel PXE spec, for
61  * example:
62  *
63  *   PXENV_UNDI_INITIALIZE says that the parameters used to initialize
64  *   the adaptor should be those supplied to the most recent
65  *   PXENV_UNDI_STARTUP call.  PXENV_UNDI_STARTUP takes no parameters.
66  *
67  *   PXENV_UNDI_CLEANUP says that the rest of the API will not be
68  *   available after making this call.  Figure 3-3 ("Early UNDI API
69  *   usage") shows a call to PXENV_UNDI_CLEANUP being followed by a
70  *   call to the supposedly now unavailable PXENV_STOP_UNDI.
71  *
72  *   PXENV_UNLOAD_BASE_STACK talks about freeing up the memory
73  *   occupied by the PXE stack.  Figure 4-3 ("PXE IPL") shows a call
74  *   to PXENV_STOP_UNDI being made after the call to
75  *   PXENV_UNLOAD_BASE_STACK, by which time the entire PXE stack
76  *   should have been freed (and, potentially, zeroed).
77  *
78  *   Nothing, anywhere, seems to mention who's responsible for freeing
79  *   up the base memory allocated for the stack segment.  It's not
80  *   even clear whether or not this is expected to be in free base
81  *   memory rather than claimed base memory.
82  *
83  * Consequently, we adopt a rather defensive strategy, designed to
84  * work with any conceivable sequence of initialisation or shutdown
85  * calls.  We have only two things that we care about:
86  *
87  *   1. Have we hooked INT 1A and INT 15,E820(etc.)?
88  *   2. Is the NIC initialised?
89  *
90  * The NIC should never be initialised without the vectors being
91  * hooked, similarly the vectors should never be unhooked with the NIC
92  * still initialised.  We do, however, want to be able to have the
93  * vectors hooked with the NIC shutdown.  We therefore have three
94  * possible states:
95  *
96  *   1. Ready to unload: interrupts unhooked, NIC shutdown.
97  *   2. Midway: interrupts hooked, NIC shutdown.
98  *   3. Fully ready: interrupts hooked, NIC initialised.
99  *
100  * We provide the three states CAN_UNLOAD, MIDWAY and READY to define
101  * these, and the call pxe_ensure_state() to ensure that the stack is
102  * in the specified state.  All our PXE API call implementations
103  * should use this call to ensure that the state is as required for
104  * that PXE API call.  This enables us to cope with whatever the
105  * end-user's interpretation of the PXE spec may be.  It even allows
106  * for someone calling e.g. PXENV_START_UNDI followed by
107  * PXENV_UDP_WRITE, without bothering with any of the intervening
108  * calls.
109  *
110  * pxe_ensure_state() returns 1 for success, 0 for failure.  In the
111  * event of failure (which can arise from e.g. asking for state READY
112  * when we don't know where our NIC is), the error code
113  * PXENV_STATUS_UNDI_INVALID_STATE should be returned to the user.
114  * The macros ENSURE_XXX() can be used to achieve this without lots of
115  * duplicated code.
116  */
117
118 /* pxe_[un]hook_stack are architecture-specific and provided in
119  * pxe_callbacks.c
120  */
121
122 int pxe_initialise_nic ( void ) {
123         if ( pxe_stack->state >= READY ) return 1;
124
125 #warning "device probing mechanism has completely changed"
126 #if 0
127
128         /* Check if NIC is initialised.  dev.disable is set to 0
129          * when disable() is called, so we use this.
130          */
131         if ( dev.disable ) {
132                 /* NIC may have been initialised independently
133                  * (e.g. when we set up the stack prior to calling the
134                  * NBP).
135                  */
136                 pxe_stack->state = READY;
137                 return 1;
138         }
139
140         /* If we already have a NIC defined, reuse that one with
141          * PROBE_AWAKE.  If one was specifed via PXENV_START_UNDI, try
142          * that one first.  Otherwise, set PROBE_FIRST.
143          */
144
145         if ( dev.state.pci.dev.use_specified == 1 ) {
146                 dev.how_probe = PROBE_NEXT;
147                 DBG ( " initialising NIC specified via START_UNDI" );
148         } else if ( dev.state.pci.dev.driver ) {
149                 DBG ( " reinitialising NIC" );
150                 dev.how_probe = PROBE_AWAKE;
151         } else {
152                 DBG ( " probing for any NIC" );
153                 dev.how_probe = PROBE_FIRST;
154         }
155
156         /* Call probe routine to bring up the NIC */
157         if ( eth_probe ( &dev ) != PROBE_WORKED ) {
158                 DBG ( " failed" );
159                 return 0;
160         }
161 #endif
162         
163
164         pxe_stack->state = READY;
165         return 1;
166 }
167
168 int pxe_shutdown_nic ( void ) {
169         if ( pxe_stack->state <= MIDWAY ) return 1;
170
171         eth_irq ( DISABLE );
172         disable ( &dev );
173         pxe_stack->state = MIDWAY;
174         return 1;
175 }
176
177 int ensure_pxe_state ( pxe_stack_state_t wanted ) {
178         int success = 1;
179
180         if ( ! pxe_stack ) return 0;
181         if ( wanted >= MIDWAY )
182                 success = success & hook_pxe_stack();
183         if ( wanted > MIDWAY ) {
184                 success = success & pxe_initialise_nic();
185         } else {
186                 success = success & pxe_shutdown_nic();
187         }
188         if ( wanted < MIDWAY )
189                 success = success & unhook_pxe_stack();
190         return success;
191 }
192
193 #define ENSURE_CAN_UNLOAD(structure) if ( ! ensure_pxe_state(CAN_UNLOAD) ) { \
194                         structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
195                         return PXENV_EXIT_FAILURE; }
196 #define ENSURE_MIDWAY(structure) if ( ! ensure_pxe_state(MIDWAY) ) { \
197                         structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
198                         return PXENV_EXIT_FAILURE; }
199 #define ENSURE_READY(structure) if ( ! ensure_pxe_state(READY) ) { \
200                         structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
201                         return PXENV_EXIT_FAILURE; }
202
203 /*****************************************************************************
204  *
205  * Actual PXE API calls
206  *
207  *****************************************************************************/
208
209 /* PXENV_START_UNDI
210  *
211  * Status: working
212  */
213 PXENV_EXIT_t pxenv_start_undi ( t_PXENV_START_UNDI *start_undi ) {
214         unsigned char bus, devfn;
215
216         DBG ( "PXENV_START_UNDI" );
217         ENSURE_MIDWAY(start_undi);
218
219         /* Record PCI bus & devfn passed by caller, so we know which
220          * NIC they want to use.
221          *
222          * If they don't match our already-existing NIC structure, set
223          * values to ensure that the specified NIC is used at the next
224          * call to pxe_intialise_nic().
225          */
226         bus = ( start_undi->ax >> 8 ) & 0xff;
227         devfn = start_undi->ax & 0xff;
228
229 #warning "device probing mechanism has completely changed"
230 #if 0
231         if ( ( pci->dev.driver == NULL ) ||
232              ( pci->dev.bus != bus ) || ( pci->dev.devfn != devfn ) ) {
233                 /* This is quite a bit of a hack and relies on
234                  * knowledge of the internal operation of Etherboot's
235                  * probe mechanism.
236                  */
237                 DBG ( " set PCI %hhx:%hhx.%hhx",
238                       bus, PCI_SLOT(devfn), PCI_FUNC(devfn) );
239                 dev->type = BOOT_NIC;
240                 dev->to_probe = PROBE_PCI;
241                 memset ( &dev->state, 0, sizeof(dev->state) );
242                 pci->advance = 1;
243                 pci->dev.use_specified = 1;
244                 pci->dev.bus = bus;
245                 pci->dev.devfn = devfn;
246         }
247 #endif
248
249         start_undi->Status = PXENV_STATUS_SUCCESS;
250         return PXENV_EXIT_SUCCESS;
251 }
252
253 /* PXENV_UNDI_STARTUP
254  *
255  * Status: working
256  */
257 PXENV_EXIT_t pxenv_undi_startup ( t_PXENV_UNDI_STARTUP *undi_startup ) {
258         DBG ( "PXENV_UNDI_STARTUP" );
259         ENSURE_MIDWAY(undi_startup);
260
261         undi_startup->Status = PXENV_STATUS_SUCCESS;
262         return PXENV_EXIT_SUCCESS;
263 }
264
265 /* PXENV_UNDI_CLEANUP
266  *
267  * Status: working
268  */
269 PXENV_EXIT_t pxenv_undi_cleanup ( t_PXENV_UNDI_CLEANUP *undi_cleanup ) {
270         DBG ( "PXENV_UNDI_CLEANUP" );
271         ENSURE_CAN_UNLOAD ( undi_cleanup );
272
273         undi_cleanup->Status = PXENV_STATUS_SUCCESS;
274         return PXENV_EXIT_SUCCESS;
275 }
276
277 /* PXENV_UNDI_INITIALIZE
278  *
279  * Status: working
280  */
281 PXENV_EXIT_t pxenv_undi_initialize ( t_PXENV_UNDI_INITIALIZE
282                                      *undi_initialize ) {
283         DBG ( "PXENV_UNDI_INITIALIZE" );
284         ENSURE_MIDWAY ( undi_initialize );
285
286         undi_initialize->Status = PXENV_STATUS_SUCCESS;
287         return PXENV_EXIT_SUCCESS;
288 }
289
290 /* PXENV_UNDI_RESET_ADAPTER
291  *
292  * Status: working
293  */
294 PXENV_EXIT_t pxenv_undi_reset_adapter ( t_PXENV_UNDI_RESET_ADAPTER
295                                         *undi_reset_adapter ) {
296         DBG ( "PXENV_UNDI_RESET_ADAPTER" );
297
298         ENSURE_MIDWAY ( undi_reset_adapter );
299         ENSURE_READY ( undi_reset_adapter );
300
301         undi_reset_adapter->Status = PXENV_STATUS_SUCCESS;
302         return PXENV_EXIT_SUCCESS;
303 }
304
305 /* PXENV_UNDI_SHUTDOWN
306  *
307  * Status: working
308  */
309 PXENV_EXIT_t pxenv_undi_shutdown ( t_PXENV_UNDI_SHUTDOWN *undi_shutdown ) {
310         DBG ( "PXENV_UNDI_SHUTDOWN" );
311         ENSURE_MIDWAY ( undi_shutdown );
312
313         undi_shutdown->Status = PXENV_STATUS_SUCCESS;
314         return PXENV_EXIT_SUCCESS;
315 }
316
317 /* PXENV_UNDI_OPEN
318  *
319  * Status: working
320  */
321 PXENV_EXIT_t pxenv_undi_open ( t_PXENV_UNDI_OPEN *undi_open ) {
322         DBG ( "PXENV_UNDI_OPEN" );
323         ENSURE_READY ( undi_open );
324
325         /* PXESPEC: This is where we choose to enable interrupts.
326          * Can't actually find where we're meant to in the PXE spec,
327          * but this should work.
328          */
329         eth_irq ( ENABLE );
330
331         undi_open->Status = PXENV_STATUS_SUCCESS;
332         return PXENV_EXIT_SUCCESS;
333 }
334
335 /* PXENV_UNDI_CLOSE
336  *
337  * Status: working
338  */
339 PXENV_EXIT_t pxenv_undi_close ( t_PXENV_UNDI_CLOSE *undi_close ) {
340         DBG ( "PXENV_UNDI_CLOSE" );
341         ENSURE_MIDWAY ( undi_close );
342
343         undi_close->Status = PXENV_STATUS_SUCCESS;
344         return PXENV_EXIT_SUCCESS;
345 }
346
347 /* PXENV_UNDI_TRANSMIT
348  *
349  * Status: working
350  */
351 PXENV_EXIT_t pxenv_undi_transmit ( t_PXENV_UNDI_TRANSMIT *undi_transmit ) {
352         t_PXENV_UNDI_TBD *tbd;
353         const char *dest;
354         unsigned int type;
355         unsigned int length;
356         const char *data;
357         media_header_t *media_header;
358
359         DBG ( "PXENV_UNDI_TRANSMIT" );
360         ENSURE_READY ( undi_transmit );
361
362         /* We support only the "immediate" portion of the TBD.  Who
363          * knows what Intel's "engineers" were smoking when they came
364          * up with the array of transmit data blocks...
365          */
366         tbd = SEGOFF16_TO_PTR ( undi_transmit->TBD );
367         if ( tbd->DataBlkCount > 0 ) {
368                 undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
369                 return PXENV_EXIT_FAILURE;
370         }
371         data = SEGOFF16_TO_PTR ( tbd->Xmit );
372         length = tbd->ImmedLength;
373
374         /* If destination is broadcast, we need to supply the MAC address */
375         if ( undi_transmit->XmitFlag == XMT_BROADCAST ) {
376                 dest = broadcast_mac;
377         } else {
378                 dest = SEGOFF16_TO_PTR ( undi_transmit->DestAddr );
379         }
380
381         /* We can't properly support P_UNKNOWN without rewriting all
382          * the driver transmit() methods, so we cheat: if P_UNKNOWN is
383          * specified we rip the destination address and type out of
384          * the pre-assembled packet, then skip over the header.
385          */
386         switch ( undi_transmit->Protocol ) {
387         case P_IP:      type = IP;      break;
388         case P_ARP:     type = ARP;     break;
389         case P_RARP:    type = RARP;    break;
390         case P_UNKNOWN:
391                 media_header = (media_header_t*)data;
392                 dest = media_header->dest;
393                 type = ntohs ( media_header->nstype );
394                 data += ETH_HLEN;
395                 length -= ETH_HLEN;
396                 break;
397         default:
398                 undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
399                 return PXENV_EXIT_FAILURE;
400         }
401
402         /* Send the packet */
403         eth_transmit ( dest, type, length, data );
404         
405         undi_transmit->Status = PXENV_STATUS_SUCCESS;
406         return PXENV_EXIT_SUCCESS;
407 }
408
409 /* PXENV_UNDI_SET_MCAST_ADDRESS
410  *
411  * Status: stub (no PXE multicast support)
412  */
413 PXENV_EXIT_t pxenv_undi_set_mcast_address ( t_PXENV_UNDI_SET_MCAST_ADDRESS
414                                             *undi_set_mcast_address ) {
415         DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" );
416         /* ENSURE_READY ( undi_set_mcast_address ); */
417         undi_set_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
418         return PXENV_EXIT_FAILURE;
419 }
420
421 /* PXENV_UNDI_SET_STATION_ADDRESS
422  *
423  * Status: working (deliberately incomplete)
424  */
425 PXENV_EXIT_t pxenv_undi_set_station_address ( t_PXENV_UNDI_SET_STATION_ADDRESS
426                                               *undi_set_station_address ) {
427         DBG ( "PXENV_UNDI_SET_STATION_ADDRESS" );
428         ENSURE_READY ( undi_set_station_address );
429
430         /* We don't offer a facility to set the MAC address; this
431          * would require adding extra code to all the Etherboot
432          * drivers, for very little benefit.  If we're setting it to
433          * the current value anyway then return success, otherwise
434          * return UNSUPPORTED.
435          */
436         if ( memcmp ( nic.node_addr,
437                       &undi_set_station_address->StationAddress,
438                       ETH_ALEN ) == 0 ) {
439                 undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
440                 return PXENV_EXIT_SUCCESS;
441         }
442         undi_set_station_address->Status = PXENV_STATUS_UNSUPPORTED;
443         return PXENV_EXIT_FAILURE;
444 }
445
446 /* PXENV_UNDI_SET_PACKET_FILTER
447  *
448  * Status: won't implement (would require driver API changes for no
449  * real benefit)
450  */
451 PXENV_EXIT_t pxenv_undi_set_packet_filter ( t_PXENV_UNDI_SET_PACKET_FILTER
452                                             *undi_set_packet_filter ) {
453         DBG ( "PXENV_UNDI_SET_PACKET_FILTER" );
454         /* ENSURE_READY ( undi_set_packet_filter ); */
455         undi_set_packet_filter->Status = PXENV_STATUS_UNSUPPORTED;
456         return PXENV_EXIT_FAILURE;
457 }
458
459 /* PXENV_UNDI_GET_INFORMATION
460  *
461  * Status: working
462  */
463 PXENV_EXIT_t pxenv_undi_get_information ( t_PXENV_UNDI_GET_INFORMATION
464                                           *undi_get_information ) {
465         DBG ( "PXENV_UNDI_GET_INFORMATION" );
466         ENSURE_READY ( undi_get_information );
467
468         undi_get_information->BaseIo = nic.ioaddr;
469         undi_get_information->IntNumber = nic.irqno;
470         /* Cheat: assume all cards can cope with this */
471         undi_get_information->MaxTranUnit = ETH_MAX_MTU;
472         /* Cheat: we only ever have Ethernet cards */
473         undi_get_information->HwType = ETHER_TYPE;
474         undi_get_information->HwAddrLen = ETH_ALEN;
475         /* Cheat: assume card is always configured with its permanent
476          * node address.  This is a valid assumption within Etherboot
477          * at the time of writing.
478          */
479         memcpy ( &undi_get_information->CurrentNodeAddress, nic.node_addr,
480                  ETH_ALEN );
481         memcpy ( &undi_get_information->PermNodeAddress, nic.node_addr,
482                  ETH_ALEN );
483         undi_get_information->ROMAddress = 0;
484                 /* nic.rom_info->rom_segment; */
485         /* We only provide the ability to receive or transmit a single
486          * packet at a time.  This is a bootloader, not an OS.
487          */
488         undi_get_information->RxBufCt = 1;
489         undi_get_information->TxBufCt = 1;
490         undi_get_information->Status = PXENV_STATUS_SUCCESS;
491         return PXENV_EXIT_SUCCESS;
492 }
493
494 /* PXENV_UNDI_GET_STATISTICS
495  *
496  * Status: won't implement (would require driver API changes for no
497  * real benefit)
498  */
499 PXENV_EXIT_t pxenv_undi_get_statistics ( t_PXENV_UNDI_GET_STATISTICS
500                                          *undi_get_statistics ) {
501         DBG ( "PXENV_UNDI_GET_STATISTICS" );
502         /* ENSURE_READY ( undi_get_statistics ); */
503         undi_get_statistics->Status = PXENV_STATUS_UNSUPPORTED;
504         return PXENV_EXIT_FAILURE;
505 }
506
507 /* PXENV_UNDI_CLEAR_STATISTICS
508  *
509  * Status: won't implement (would require driver API changes for no
510  * real benefit)
511  */
512 PXENV_EXIT_t pxenv_undi_clear_statistics ( t_PXENV_UNDI_CLEAR_STATISTICS
513                                            *undi_clear_statistics ) {
514         DBG ( "PXENV_UNDI_CLEAR_STATISTICS" );
515         /* ENSURE_READY ( undi_clear_statistics ); */
516         undi_clear_statistics->Status = PXENV_STATUS_UNSUPPORTED;
517         return PXENV_EXIT_FAILURE;
518 }
519
520 /* PXENV_UNDI_INITIATE_DIAGS
521  *
522  * Status: won't implement (would require driver API changes for no
523  * real benefit)
524  */
525 PXENV_EXIT_t pxenv_undi_initiate_diags ( t_PXENV_UNDI_INITIATE_DIAGS
526                                          *undi_initiate_diags ) {
527         DBG ( "PXENV_UNDI_INITIATE_DIAGS" );
528         /* ENSURE_READY ( undi_initiate_diags ); */
529         undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
530         return PXENV_EXIT_FAILURE;
531 }
532
533 /* PXENV_UNDI_FORCE_INTERRUPT
534  *
535  * Status: working
536  */
537 PXENV_EXIT_t pxenv_undi_force_interrupt ( t_PXENV_UNDI_FORCE_INTERRUPT
538                                           *undi_force_interrupt ) {
539         DBG ( "PXENV_UNDI_FORCE_INTERRUPT" );
540         ENSURE_READY ( undi_force_interrupt );
541
542         eth_irq ( FORCE );
543         undi_force_interrupt->Status = PXENV_STATUS_SUCCESS;
544         return PXENV_EXIT_SUCCESS;
545 }
546
547 /* PXENV_UNDI_GET_MCAST_ADDRESS
548  *
549  * Status: stub (no PXE multicast support)
550  */
551 PXENV_EXIT_t pxenv_undi_get_mcast_address ( t_PXENV_UNDI_GET_MCAST_ADDRESS
552                                             *undi_get_mcast_address ) {
553         DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS" );
554         /* ENSURE_READY ( undi_get_mcast_address ); */
555         undi_get_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
556         return PXENV_EXIT_FAILURE;
557 }
558
559 /* PXENV_UNDI_GET_NIC_TYPE
560  *
561  * Status: working
562  */
563 PXENV_EXIT_t pxenv_undi_get_nic_type ( t_PXENV_UNDI_GET_NIC_TYPE
564                                        *undi_get_nic_type ) {
565 #warning "device probing mechanism has changed completely"
566
567 #if 0
568         struct dev *dev = &dev;
569         
570         DBG ( "PXENV_UNDI_GET_NIC_TYPE" );
571         ENSURE_READY ( undi_get_nic_type );
572         
573         if ( dev->to_probe == PROBE_PCI ) {
574                 struct pci_device *pci = &dev->state.pci.dev;
575
576                 undi_get_nic_type->NicType = PCI_NIC;
577                 undi_get_nic_type->info.pci.Vendor_ID = pci->vendor;
578                 undi_get_nic_type->info.pci.Dev_ID = pci->dev_id;
579                 undi_get_nic_type->info.pci.Base_Class = pci->class >> 8;
580                 undi_get_nic_type->info.pci.Sub_Class = pci->class & 0xff;
581                 undi_get_nic_type->info.pci.BusDevFunc =
582                         ( pci->bus << 8 ) | pci->devfn;
583                 /* Cheat: these fields are probably unnecessary, and
584                  * would require adding extra code to pci.c.
585                  */
586                 undi_get_nic_type->info.pci.Prog_Intf = 0;
587                 undi_get_nic_type->info.pci.Rev = 0;
588                 undi_get_nic_type->info.pci.SubVendor_ID = 0xffff;
589                 undi_get_nic_type->info.pci.SubDevice_ID = 0xffff;
590         } else if ( dev->to_probe == PROBE_ISA ) {
591                 /* const struct isa_driver *isa = dev->state.isa.driver; */
592
593                 undi_get_nic_type->NicType = PnP_NIC;
594                 /* Don't think anything fills these fields in, and
595                  * probably no-one will ever be interested in them.
596                  */
597                 undi_get_nic_type->info.pnp.EISA_Dev_ID = 0;
598                 undi_get_nic_type->info.pnp.Base_Class = 0;
599                 undi_get_nic_type->info.pnp.Sub_Class = 0;
600                 undi_get_nic_type->info.pnp.Prog_Intf = 0;
601                 undi_get_nic_type->info.pnp.CardSelNum = 0;
602         } else {
603                 /* PXESPEC: There doesn't seem to be an "unknown type"
604                  * defined.
605                  */
606                 undi_get_nic_type->NicType = 0;
607         }
608         undi_get_nic_type->Status = PXENV_STATUS_SUCCESS;
609         return PXENV_EXIT_SUCCESS;
610
611 #endif
612 }
613
614 /* PXENV_UNDI_GET_IFACE_INFO
615  *
616  * Status: working
617  */
618 PXENV_EXIT_t pxenv_undi_get_iface_info ( t_PXENV_UNDI_GET_IFACE_INFO
619                                          *undi_get_iface_info ) {
620         DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
621         ENSURE_READY ( undi_get_iface_info );
622
623         /* Just hand back some info, doesn't really matter what it is.
624          * Most PXE stacks seem to take this approach.
625          */
626         sprintf ( undi_get_iface_info->IfaceType, "Etherboot" );
627         undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
628         undi_get_iface_info->ServiceFlags = 0;
629         memset ( undi_get_iface_info->Reserved, 0,
630                  sizeof(undi_get_iface_info->Reserved) );
631         undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
632         return PXENV_EXIT_SUCCESS;
633 }
634
635 /* PXENV_UNDI_ISR
636  *
637  * Status: working
638  */
639 PXENV_EXIT_t pxenv_undi_isr ( t_PXENV_UNDI_ISR *undi_isr ) {
640         media_header_t *media_header = (media_header_t*)nic.packet;
641
642         DBG ( "PXENV_UNDI_ISR" );
643         /* We can't call ENSURE_READY, because this could be being
644          * called as part of an interrupt service routine.  Instead,
645          * we should simply die if we're not READY.
646          */
647         if ( ( pxe_stack == NULL ) || ( pxe_stack->state < READY ) ) {
648                 undi_isr->Status = PXENV_STATUS_UNDI_INVALID_STATE;
649                 return PXENV_EXIT_FAILURE;
650         }
651         
652         /* Just in case some idiot actually looks at these fields when
653          * we weren't meant to fill them in...
654          */
655         undi_isr->BufferLength = 0;
656         undi_isr->FrameLength = 0;
657         undi_isr->FrameHeaderLength = 0;
658         undi_isr->ProtType = 0;
659         undi_isr->PktType = 0;
660
661         switch ( undi_isr->FuncFlag ) {
662         case PXENV_UNDI_ISR_IN_START :
663                 /* Is there a packet waiting?  If so, disable
664                  * interrupts on the NIC and return "it's ours".  Do
665                  * *not* necessarily acknowledge the interrupt; this
666                  * can happen later when eth_poll(1) is called.  As
667                  * long as the interrupt is masked off so that it
668                  * doesn't immediately retrigger the 8259A then all
669                  * should be well.
670                  */
671                 DBG ( " START" );
672                 if ( eth_poll ( 0 ) ) {
673                         DBG ( " OURS" );
674                         eth_irq ( DISABLE );
675                         undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
676                 } else {
677                         DBG ( " NOT_OURS" );
678                         undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_NOT_OURS;
679                 }
680                 break;
681         case PXENV_UNDI_ISR_IN_PROCESS :
682                 /* Call poll(), return packet.  If no packet, return "done".
683                  */
684                 DBG ( " PROCESS" );
685                 if ( eth_poll ( 1 ) ) {
686                         DBG ( " RECEIVE %d", nic.packetlen );
687                         if ( nic.packetlen > sizeof(pxe_stack->packet) ) {
688                                 /* Should never happen */
689                                 undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
690                                 undi_isr->Status =
691                                         PXENV_STATUS_OUT_OF_RESOURCES;
692                                 return PXENV_EXIT_FAILURE;
693                         }
694                         undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
695                         undi_isr->BufferLength = nic.packetlen;
696                         undi_isr->FrameLength = nic.packetlen;
697                         undi_isr->FrameHeaderLength = ETH_HLEN;
698                         memcpy ( pxe_stack->packet, nic.packet, nic.packetlen);
699                         PTR_TO_SEGOFF16 ( pxe_stack->packet, undi_isr->Frame );
700                         switch ( ntohs(media_header->nstype) ) {
701                         case IP :       undi_isr->ProtType = P_IP;      break;
702                         case ARP :      undi_isr->ProtType = P_ARP;     break;
703                         case RARP :     undi_isr->ProtType = P_RARP;    break;
704                         default :       undi_isr->ProtType = P_UNKNOWN;
705                         }
706                         if ( memcmp ( media_header->dest, broadcast_mac,
707                                       sizeof(broadcast_mac) ) ) {
708                                 undi_isr->PktType = XMT_BROADCAST;
709                         } else {
710                                 undi_isr->PktType = XMT_DESTADDR;
711                         }
712                         break;
713                 } else {
714                         /* No break - fall through to IN_GET_NEXT */
715                 }
716         case PXENV_UNDI_ISR_IN_GET_NEXT :
717                 /* We only ever return one frame at a time */
718                 DBG ( " GET_NEXT DONE" );
719                 /* Re-enable interrupts */
720                 eth_irq ( ENABLE );
721                 /* Force an interrupt if there's a packet still
722                  * waiting, since we only handle one packet per
723                  * interrupt.
724                  */
725                 if ( eth_poll ( 0 ) ) {
726                         DBG ( " (RETRIGGER)" );
727                         eth_irq ( FORCE );
728                 }
729                 undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
730                 break;
731         default :
732                 /* Should never happen */
733                 undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
734                 undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
735                 return PXENV_EXIT_FAILURE;
736         }
737
738         undi_isr->Status = PXENV_STATUS_SUCCESS;
739         return PXENV_EXIT_SUCCESS;
740 }
741
742 /* PXENV_STOP_UNDI
743  *
744  * Status: working
745  */
746 PXENV_EXIT_t pxenv_stop_undi ( t_PXENV_STOP_UNDI *stop_undi ) {
747         DBG ( "PXENV_STOP_UNDI" );
748
749         if ( ! ensure_pxe_state(CAN_UNLOAD) ) {
750                 stop_undi->Status = PXENV_STATUS_KEEP_UNDI;
751                 return PXENV_EXIT_FAILURE;
752         }
753
754         stop_undi->Status = PXENV_STATUS_SUCCESS;
755         return PXENV_EXIT_SUCCESS;
756 }
757
758 /* PXENV_TFTP_OPEN
759  *
760  * Status: working
761  */
762 PXENV_EXIT_t pxenv_tftp_open ( t_PXENV_TFTP_OPEN *tftp_open ) {
763         struct sockaddr_in tftp_server;
764         struct tftpreq_info_t request;
765         struct tftpblk_info_t block;
766
767         DBG ( "PXENV_TFTP_OPEN" );
768         ENSURE_READY ( tftp_open );
769
770         /* Set server address and port */
771         tftp_server.sin_addr.s_addr = tftp_open->ServerIPAddress
772                 ? tftp_open->ServerIPAddress
773                 : arptable[ARP_SERVER].ipaddr.s_addr;
774         tftp_server.sin_port = ntohs ( tftp_open->TFTPPort );
775 #ifdef WORK_AROUND_BPBATCH_BUG        
776         /* Force use of port 69; BpBatch tries to use port 4 for some         
777         * bizarre reason.         */        
778         tftp_server.sin_port = TFTP_PORT;
779 #endif
780         /* Ignore gateway address; we can route properly */
781         /* Fill in request structure */
782         request.server = &tftp_server;
783         request.name = tftp_open->FileName;
784         request.blksize = tftp_open->PacketSize;
785         DBG ( " %@:%d/%s (%d)", tftp_open->ServerIPAddress,
786               tftp_open->TFTPPort, request.name, request.blksize );
787         if ( !request.blksize ) request.blksize = TFTP_DEFAULTSIZE_PACKET;
788         /* Make request and get first packet */
789         if ( !tftp_block ( &request, &block ) ) {
790                 tftp_open->Status = PXENV_STATUS_TFTP_FILE_NOT_FOUND;
791                 return PXENV_EXIT_FAILURE;
792         }
793         /* Fill in PacketSize */
794         tftp_open->PacketSize = request.blksize;
795         /* Store first block for later retrieval by TFTP_READ */
796         pxe_stack->tftpdata.magic_cookie = PXE_TFTP_MAGIC_COOKIE;
797         pxe_stack->tftpdata.len = block.len;
798         pxe_stack->tftpdata.eof = block.eof;
799         memcpy ( pxe_stack->tftpdata.data, block.data, block.len );
800
801         tftp_open->Status = PXENV_STATUS_SUCCESS;
802         return PXENV_EXIT_SUCCESS;
803 }
804
805 /* PXENV_TFTP_CLOSE
806  *
807  * Status: working
808  */
809 PXENV_EXIT_t pxenv_tftp_close ( t_PXENV_TFTP_CLOSE *tftp_close ) {
810         DBG ( "PXENV_TFTP_CLOSE" );
811         ENSURE_READY ( tftp_close );
812         tftp_close->Status = PXENV_STATUS_SUCCESS;
813         return PXENV_EXIT_SUCCESS;
814 }
815
816 /* PXENV_TFTP_READ
817  *
818  * Status: working
819  */
820 PXENV_EXIT_t pxenv_tftp_read ( t_PXENV_TFTP_READ *tftp_read ) {
821         struct tftpblk_info_t block;
822
823         DBG ( "PXENV_TFTP_READ" );
824         ENSURE_READY ( tftp_read );
825
826         /* Do we have a block pending */
827         if ( pxe_stack->tftpdata.magic_cookie == PXE_TFTP_MAGIC_COOKIE ) {
828                 block.data = pxe_stack->tftpdata.data;
829                 block.len = pxe_stack->tftpdata.len;
830                 block.eof = pxe_stack->tftpdata.eof;
831                 block.block = 1; /* Will be the first block */
832                 pxe_stack->tftpdata.magic_cookie = 0;
833         } else {
834                 if ( !tftp_block ( NULL, &block ) ) {
835                         tftp_read->Status = PXENV_STATUS_TFTP_FILE_NOT_FOUND;
836                         return PXENV_EXIT_FAILURE;
837                 }
838         }
839
840         /* Return data */
841         tftp_read->PacketNumber = block.block;
842         tftp_read->BufferSize = block.len;
843         memcpy ( SEGOFF16_TO_PTR(tftp_read->Buffer), block.data, block.len );
844         DBG ( " %d to %hx:%hx", block.len, tftp_read->Buffer.segment,
845               tftp_read->Buffer.offset );
846  
847         tftp_read->Status = PXENV_STATUS_SUCCESS;
848         return PXENV_EXIT_SUCCESS;
849 }
850
851 /* PXENV_TFTP_READ_FILE
852  *
853  * Status: working
854  */
855
856 int pxe_tftp_read_block ( unsigned char *data, unsigned int block __unused,
857                           unsigned int len, int eof ) {
858         if ( pxe_stack->readfile.buffer ) {
859                 if ( pxe_stack->readfile.offset + len >=
860                      pxe_stack->readfile.bufferlen ) return -1;
861                 memcpy ( pxe_stack->readfile.buffer +
862                          pxe_stack->readfile.offset, data, len );
863         }
864         pxe_stack->readfile.offset += len;
865         return eof ? 0 : 1;
866 }
867
868 PXENV_EXIT_t pxenv_tftp_read_file ( t_PXENV_TFTP_READ_FILE *tftp_read_file ) {
869         struct sockaddr_in tftp_server;
870         int rc;
871
872         DBG ( "PXENV_TFTP_READ_FILE %s to [%x,%x)", tftp_read_file->FileName,
873               tftp_read_file->Buffer,
874               tftp_read_file->Buffer + tftp_read_file->BufferSize );
875         ENSURE_READY ( tftp_read_file );
876
877         /* inserted by Klaus Wittemeier */
878         /* KERNEL_BUF stores the name of the last required file */
879         /* This is a fix to make Microsoft Remote Install Services work (RIS) */
880         memcpy(KERNEL_BUF, tftp_read_file->FileName, sizeof(KERNEL_BUF));
881         /* end of insertion */
882
883         /* Set server address and port */
884         tftp_server.sin_addr.s_addr = tftp_read_file->ServerIPAddress
885                 ? tftp_read_file->ServerIPAddress
886                 : arptable[ARP_SERVER].ipaddr.s_addr;
887         tftp_server.sin_port = ntohs ( tftp_read_file->TFTPSrvPort );
888
889         pxe_stack->readfile.buffer = phys_to_virt ( tftp_read_file->Buffer );
890         pxe_stack->readfile.bufferlen = tftp_read_file->BufferSize;
891         pxe_stack->readfile.offset = 0;
892
893         rc = tftp ( NULL, &tftp_server, tftp_read_file->FileName,
894                     pxe_tftp_read_block );
895         if ( rc ) {
896                 tftp_read_file->Status = PXENV_STATUS_FAILURE;
897                 return PXENV_EXIT_FAILURE;
898         }
899         tftp_read_file->Status = PXENV_STATUS_SUCCESS;
900         return PXENV_EXIT_SUCCESS;
901 }
902
903 /* PXENV_TFTP_GET_FSIZE
904  *
905  * Status: working, though ugly (we actually read the whole file,
906  * because it's too ugly to make Etherboot request the tsize option
907  * and hand it to us).
908  */
909 PXENV_EXIT_t pxenv_tftp_get_fsize ( t_PXENV_TFTP_GET_FSIZE *tftp_get_fsize ) {
910         int rc;
911
912         DBG ( "PXENV_TFTP_GET_FSIZE" );
913         ENSURE_READY ( tftp_get_fsize );
914
915         pxe_stack->readfile.buffer = NULL;
916         pxe_stack->readfile.bufferlen = 0;
917         pxe_stack->readfile.offset = 0;
918
919 #warning "Rewrite pxenv_tftp_get_fsize, please"
920         if ( rc ) {
921                 tftp_get_fsize->FileSize = 0;
922                 tftp_get_fsize->Status = PXENV_STATUS_FAILURE;
923                 return PXENV_EXIT_FAILURE;
924         }
925         tftp_get_fsize->FileSize = pxe_stack->readfile.offset;
926         tftp_get_fsize->Status = PXENV_STATUS_SUCCESS;
927         return PXENV_EXIT_SUCCESS;
928 }
929
930 /* PXENV_UDP_OPEN
931  *
932  * Status: working
933  */
934 PXENV_EXIT_t pxenv_udp_open ( t_PXENV_UDP_OPEN *udp_open ) {
935         DBG ( "PXENV_UDP_OPEN" );
936         ENSURE_READY ( udp_open );
937
938         if ( udp_open->src_ip &&
939              udp_open->src_ip != arptable[ARP_CLIENT].ipaddr.s_addr ) {
940                 /* Overwrite our IP address */
941                 DBG ( " with new IP %@", udp_open->src_ip );
942                 arptable[ARP_CLIENT].ipaddr.s_addr = udp_open->src_ip;
943         }
944
945         udp_open->Status = PXENV_STATUS_SUCCESS;
946         return PXENV_EXIT_SUCCESS;
947 }
948
949 /* PXENV_UDP_CLOSE
950  *
951  * Status: working
952  */
953 PXENV_EXIT_t pxenv_udp_close ( t_PXENV_UDP_CLOSE *udp_close ) {
954         DBG ( "PXENV_UDP_CLOSE" );
955         ENSURE_READY ( udp_close );
956         udp_close->Status = PXENV_STATUS_SUCCESS;
957         return PXENV_EXIT_SUCCESS;
958 }
959
960 /* PXENV_UDP_READ
961  *
962  * Status: working
963  */
964 int await_pxe_udp ( int ival __unused, void *ptr,
965                     unsigned short ptype __unused,
966                     struct iphdr *ip, struct udphdr *udp,
967                     struct tcphdr *tcp __unused ) {
968         t_PXENV_UDP_READ *udp_read = (t_PXENV_UDP_READ*)ptr;
969         uint16_t d_port;
970         size_t size;
971
972         /* Ignore non-UDP packets */
973         if ( !udp ) {
974                 DBG ( " non-UDP" );
975                 return 0;
976         }
977         
978         /* Check dest_ip */
979         if ( udp_read->dest_ip && ( udp_read->dest_ip != ip->dest.s_addr ) ) {
980                 DBG ( " wrong dest IP (got %@, wanted %@)",
981                       ip->dest.s_addr, udp_read->dest_ip );
982                 return 0;
983         }
984
985         /* Check dest_port */
986         d_port = ntohs ( udp_read->d_port );
987         if ( d_port && ( d_port != ntohs(udp->dest) ) ) {
988                 DBG ( " wrong dest port (got %d, wanted %d)",
989                       ntohs(udp->dest), d_port );
990                 return 0;
991         }
992
993         /* Copy packet to buffer and fill in information */
994         udp_read->src_ip = ip->src.s_addr;
995         udp_read->s_port = udp->src; /* Both in network order */
996         size = ntohs(udp->len) - sizeof(*udp);
997         /* Workaround: NTLDR expects us to fill these in, even though
998          * PXESPEC clearly defines them as input parameters.
999          */
1000         udp_read->dest_ip = ip->dest.s_addr;
1001         udp_read->d_port = udp->dest;
1002         DBG ( " %@:%d->%@:%d (%d)",
1003               udp_read->src_ip, ntohs(udp_read->s_port),
1004               udp_read->dest_ip, ntohs(udp_read->d_port), size );
1005         if ( udp_read->buffer_size < size ) {
1006                 /* PXESPEC: what error code should we actually return? */
1007                 DBG ( " buffer too small (%d)", udp_read->buffer_size );
1008                 udp_read->Status = PXENV_STATUS_OUT_OF_RESOURCES;
1009                 return 0;
1010         }
1011         memcpy ( SEGOFF16_TO_PTR ( udp_read->buffer ), &udp->payload, size );
1012         udp_read->buffer_size = size;
1013
1014         return 1;
1015 }
1016
1017 PXENV_EXIT_t pxenv_udp_read ( t_PXENV_UDP_READ *udp_read ) {
1018         DBG ( "PXENV_UDP_READ" );
1019         ENSURE_READY ( udp_read );
1020
1021         /* Use await_reply with a timeout of zero */
1022         /* Allow await_reply to change Status if necessary */
1023         udp_read->Status = PXENV_STATUS_FAILURE;
1024         if ( ! await_reply ( await_pxe_udp, 0, udp_read, 0 ) ) {
1025                 return PXENV_EXIT_FAILURE;
1026         }
1027
1028         udp_read->Status = PXENV_STATUS_SUCCESS;
1029         return PXENV_EXIT_SUCCESS;
1030 }
1031
1032 /* PXENV_UDP_WRITE
1033  *
1034  * Status: working
1035  */
1036 PXENV_EXIT_t pxenv_udp_write ( t_PXENV_UDP_WRITE *udp_write ) {
1037         uint16_t src_port;
1038         uint16_t dst_port;
1039         struct udppacket *packet = (struct udppacket *)nic.packet;
1040         int packet_size;
1041
1042         DBG ( "PXENV_UDP_WRITE" );
1043         ENSURE_READY ( udp_write );
1044
1045         /* PXE spec says source port is 2069 if not specified */
1046         src_port = ntohs(udp_write->src_port);
1047         if ( src_port == 0 ) src_port = 2069;
1048         dst_port = ntohs(udp_write->dst_port);
1049         DBG ( " %d->%@:%d (%d)", src_port, udp_write->ip, dst_port,
1050               udp_write->buffer_size );
1051         
1052         /* FIXME: we ignore the gateway specified, since we're
1053          * confident of being able to do our own routing.  We should
1054          * probably allow for multiple gateways.
1055          */
1056         
1057         /* Copy payload to packet buffer */
1058         packet_size = ( (void*)&packet->payload - (void*)packet )
1059                 + udp_write->buffer_size;
1060         if ( packet_size > ETH_FRAME_LEN ) {
1061                 udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
1062                 return PXENV_EXIT_FAILURE;
1063         }
1064         memcpy ( &packet->payload, SEGOFF16_TO_PTR(udp_write->buffer),
1065                  udp_write->buffer_size );
1066
1067         /* Transmit packet */
1068         if ( ! udp_transmit ( udp_write->ip, src_port, dst_port,
1069                               packet_size, packet ) ) {
1070                 udp_write->Status = PXENV_STATUS_FAILURE;
1071                 return PXENV_EXIT_FAILURE;
1072         }
1073
1074         udp_write->Status = PXENV_STATUS_SUCCESS;
1075         return PXENV_EXIT_SUCCESS;
1076 }
1077
1078 /* PXENV_UNLOAD_STACK
1079  *
1080  * Status: working
1081  */
1082 PXENV_EXIT_t pxenv_unload_stack ( t_PXENV_UNLOAD_STACK *unload_stack ) {
1083         int success;
1084
1085         DBG ( "PXENV_UNLOAD_STACK" );
1086         success = ensure_pxe_state ( CAN_UNLOAD );
1087
1088         /* We need to call cleanup() at some point.  The network card
1089          * has already been disabled by ENSURE_CAN_UNLOAD(), but for
1090          * the sake of completeness we should call the console_fini()
1091          * etc. that are part of cleanup().
1092          *
1093          * There seems to be a lack of consensus on which is the final
1094          * PXE API call to make, but it's a fairly safe bet that all
1095          * the potential shutdown sequences will include a call to
1096          * PXENV_UNLOAD_STACK at some point, so we may as well do it
1097          * here.
1098          */
1099         cleanup();
1100
1101         if ( ! success ) {
1102                 unload_stack->Status = PXENV_STATUS_KEEP_ALL;
1103                 return PXENV_EXIT_FAILURE;
1104         }
1105
1106         unload_stack->Status = PXENV_STATUS_SUCCESS;
1107         return PXENV_EXIT_SUCCESS;
1108 }
1109
1110 /* PXENV_GET_CACHED_INFO
1111  *
1112  * Status: working
1113  */
1114 PXENV_EXIT_t pxenv_get_cached_info ( t_PXENV_GET_CACHED_INFO
1115                                      *get_cached_info ) {
1116         BOOTPLAYER *cached_info = &pxe_stack->cached_info;
1117         DBG ( "PXENV_GET_CACHED_INFO %d", get_cached_info->PacketType );
1118         ENSURE_READY ( get_cached_info );
1119
1120         /* Fill in cached_info structure in our pxe_stack */
1121
1122         /* I don't think there's actually any way we can be called in
1123          * the middle of a DHCP request... 
1124          */
1125         cached_info->opcode = BOOTP_REP;
1126         /* We only have Ethernet drivers */
1127         cached_info->Hardware = ETHER_TYPE;
1128         cached_info->Hardlen = ETH_ALEN;
1129         /* PXESPEC: "Client sets" says the spec, but who's filling in
1130          * this structure?  It ain't the client.
1131          */
1132         cached_info->Gatehops = 0;
1133         cached_info->ident = 0;
1134         cached_info->seconds = 0;
1135         cached_info->Flags = BOOTP_BCAST;
1136         /* PXESPEC: What do 'Client' and 'Your' IP address refer to? */
1137         cached_info->cip = arptable[ARP_CLIENT].ipaddr.s_addr;
1138         cached_info->yip = arptable[ARP_CLIENT].ipaddr.s_addr;
1139         cached_info->sip = arptable[ARP_SERVER].ipaddr.s_addr;
1140         /* PXESPEC: Does "GIP" mean "Gateway" or "Relay agent"? */
1141         cached_info->gip = arptable[ARP_GATEWAY].ipaddr.s_addr;
1142         memcpy ( cached_info->CAddr, arptable[ARP_CLIENT].node, ETH_ALEN );
1143         /* Nullify server name */
1144         cached_info->Sname[0] = '\0';
1145         memcpy ( cached_info->bootfile, KERNEL_BUF,
1146                  sizeof(cached_info->bootfile) );
1147         /* Copy DHCP vendor options */
1148         memcpy ( &cached_info->vendor.d, BOOTP_DATA_ADDR->bootp_reply.bp_vend,
1149                  sizeof(cached_info->vendor.d) );
1150         
1151         /* Copy to user-specified buffer, or set pointer to our buffer */
1152         get_cached_info->BufferLimit = sizeof(*cached_info);
1153         /* PXESPEC: says to test for Buffer == NULL *and* BufferSize =
1154          * 0, but what are we supposed to do with a null buffer of
1155          * non-zero size?!
1156          */
1157         if ( IS_NULL_SEGOFF16 ( get_cached_info->Buffer ) ) {
1158                 /* Point back to our buffer */
1159                 PTR_TO_SEGOFF16 ( cached_info, get_cached_info->Buffer );
1160                 get_cached_info->BufferSize = sizeof(*cached_info);
1161         } else {
1162                 /* Copy to user buffer */
1163                 size_t size = sizeof(*cached_info);
1164                 void *buffer = SEGOFF16_TO_PTR ( get_cached_info->Buffer );
1165                 if ( get_cached_info->BufferSize < size )
1166                         size = get_cached_info->BufferSize;
1167                 DBG ( " to %x", virt_to_phys ( buffer ) );
1168                 memcpy ( buffer, cached_info, size );
1169                 /* PXESPEC: Should we return an error if the user
1170                  * buffer is too small?  We do return the actual size
1171                  * of the buffer via BufferLimit, so the user does
1172                  * have a way to detect this already.
1173                  */
1174         }
1175
1176         get_cached_info->Status = PXENV_STATUS_SUCCESS;
1177         return PXENV_EXIT_SUCCESS;
1178 }
1179
1180 /* PXENV_RESTART_TFTP
1181  *
1182  * Status: working
1183  */
1184 PXENV_EXIT_t pxenv_restart_tftp ( t_PXENV_RESTART_TFTP *restart_tftp ) {
1185         PXENV_EXIT_t tftp_exit;
1186
1187         DBG ( "PXENV_RESTART_TFTP" );
1188         ENSURE_READY ( restart_tftp );
1189
1190         /* Words cannot describe the complete mismatch between the PXE
1191          * specification and any possible version of reality...
1192          */
1193         restart_tftp->Buffer = PXE_LOAD_ADDRESS; /* Fixed by spec, apparently */
1194         restart_tftp->BufferSize = get_free_base_memory() - PXE_LOAD_ADDRESS; /* Near enough */
1195         DBG ( "(" );
1196         tftp_exit = pxe_api_call ( PXENV_TFTP_READ_FILE, (t_PXENV_ANY*)restart_tftp );
1197         DBG ( ")" );
1198         if ( tftp_exit != PXENV_EXIT_SUCCESS ) return tftp_exit;
1199
1200         /* Fire up the new NBP */
1201         restart_tftp->Status = xstartpxe();
1202
1203         /* Not sure what "SUCCESS" actually means, since we can only
1204          * return if the new NBP failed to boot...
1205          */
1206         return PXENV_EXIT_SUCCESS;
1207 }
1208
1209 /* PXENV_START_BASE
1210  *
1211  * Status: won't implement (requires major structural changes)
1212  */
1213 PXENV_EXIT_t pxenv_start_base ( t_PXENV_START_BASE *start_base ) {
1214         DBG ( "PXENV_START_BASE" );
1215         /* ENSURE_READY ( start_base ); */
1216         start_base->Status = PXENV_STATUS_UNSUPPORTED;
1217         return PXENV_EXIT_FAILURE;
1218 }
1219
1220 /* PXENV_STOP_BASE
1221  *
1222  * Status: working
1223  */
1224 PXENV_EXIT_t pxenv_stop_base ( t_PXENV_STOP_BASE *stop_base ) {
1225         DBG ( "PXENV_STOP_BASE" );
1226
1227         /* The only time we will be called is when the NBP is trying
1228          * to shut down the PXE stack.  There's nothing we need to do
1229          * in this call.
1230          */
1231
1232         stop_base->Status = PXENV_STATUS_SUCCESS;
1233         return PXENV_EXIT_SUCCESS;
1234 }
1235
1236 /* PXENV_UNDI_LOADER
1237  *
1238  * Status: working
1239  *
1240  * NOTE: This is not a genuine PXE API call; the loader has a separate
1241  * entry point.  However, to simplify the mapping of the PXE API to
1242  * the internal Etherboot API, both are directed through the same
1243  * interface.
1244  */
1245 PXENV_EXIT_t pxenv_undi_loader ( undi_loader_t *loader ) {
1246         uint32_t loader_phys = virt_to_phys ( loader );
1247
1248         DBG ( "PXENV_UNDI_LOADER" );
1249         
1250         /* Set UNDI DS as our real-mode stack */
1251         use_undi_ds_for_rm_stack ( loader->undi_ds );
1252
1253         /* FIXME: These lines are borrowed from main.c.  There should
1254          * probably be a single initialise() function that does all
1255          * this, but it's currently split interestingly between main()
1256          * and main_loop()...
1257          */
1258
1259
1260         /* CHECKME: Our init functions have probably already been
1261            called by the ROM prefix's call to setup(), haven't
1262            they? */
1263
1264
1265
1266         /* We have relocated; the loader pointer is now invalid */
1267         loader = phys_to_virt ( loader_phys );
1268
1269         /* Install PXE stack to area specified by NBP */
1270         install_pxe_stack ( VIRTUAL ( loader->undi_cs, 0 ) );
1271         
1272         /* Call pxenv_start_undi to set parameters.  Why the hell PXE
1273          * requires these parameters to be provided twice is beyond
1274          * the wit of any sane man.  Don't worry if it fails; the NBP
1275          * should call PXENV_START_UNDI separately anyway.
1276          */
1277         pxenv_start_undi ( &loader->start_undi );
1278         /* Unhook stack; the loader is not meant to hook int 1a etc,
1279          * but the call the pxenv_start_undi will cause it to happen.
1280          */
1281         ENSURE_CAN_UNLOAD ( loader );
1282
1283         /* Fill in addresses of !PXE and PXENV+ structures */
1284         PTR_TO_SEGOFF16 ( &pxe_stack->pxe, loader->pxe_ptr );
1285         PTR_TO_SEGOFF16 ( &pxe_stack->pxenv, loader->pxenv_ptr );
1286         
1287         loader->Status = PXENV_STATUS_SUCCESS;
1288         return PXENV_EXIT_SUCCESS;
1289 }
1290
1291 /* API call dispatcher
1292  *
1293  * Status: complete
1294  */
1295 PXENV_EXIT_t pxe_api_call ( int opcode, t_PXENV_ANY *params ) {
1296         PXENV_EXIT_t ret = PXENV_EXIT_FAILURE;
1297
1298         /* Set default status in case child routine fails to do so */
1299         params->Status = PXENV_STATUS_FAILURE;
1300
1301         DBG ( "[" );
1302
1303         /* Hand off to relevant API routine */
1304         switch ( opcode ) {
1305         case PXENV_START_UNDI:
1306                 ret = pxenv_start_undi ( &params->start_undi );
1307                 break;
1308         case PXENV_UNDI_STARTUP:
1309                 ret = pxenv_undi_startup ( &params->undi_startup );
1310                 break;
1311         case PXENV_UNDI_CLEANUP:
1312                 ret = pxenv_undi_cleanup ( &params->undi_cleanup );
1313                 break;
1314         case PXENV_UNDI_INITIALIZE:
1315                 ret = pxenv_undi_initialize ( &params->undi_initialize );
1316                 break;
1317         case PXENV_UNDI_RESET_ADAPTER:
1318                 ret = pxenv_undi_reset_adapter ( &params->undi_reset_adapter );
1319                 break;
1320         case PXENV_UNDI_SHUTDOWN:
1321                 ret = pxenv_undi_shutdown ( &params->undi_shutdown );
1322                 break;
1323         case PXENV_UNDI_OPEN:
1324                 ret = pxenv_undi_open ( &params->undi_open );
1325                 break;
1326         case PXENV_UNDI_CLOSE:
1327                 ret = pxenv_undi_close ( &params->undi_close );
1328                 break;
1329         case PXENV_UNDI_TRANSMIT:
1330                 ret = pxenv_undi_transmit ( &params->undi_transmit );
1331                 break;
1332         case PXENV_UNDI_SET_MCAST_ADDRESS:
1333                 ret = pxenv_undi_set_mcast_address (
1334                                              &params->undi_set_mcast_address );
1335                 break;
1336         case PXENV_UNDI_SET_STATION_ADDRESS:
1337                 ret = pxenv_undi_set_station_address (
1338                                            &params->undi_set_station_address );
1339                 break;
1340         case PXENV_UNDI_SET_PACKET_FILTER:
1341                 ret = pxenv_undi_set_packet_filter (
1342                                              &params->undi_set_packet_filter );
1343                 break;
1344         case PXENV_UNDI_GET_INFORMATION:
1345                 ret = pxenv_undi_get_information (
1346                                                &params->undi_get_information );
1347                 break;
1348         case PXENV_UNDI_GET_STATISTICS:
1349                 ret = pxenv_undi_get_statistics (
1350                                                 &params->undi_get_statistics );
1351                 break;
1352         case PXENV_UNDI_CLEAR_STATISTICS:
1353                 ret = pxenv_undi_clear_statistics (
1354                                               &params->undi_clear_statistics );
1355                 break;
1356         case PXENV_UNDI_INITIATE_DIAGS:
1357                 ret = pxenv_undi_initiate_diags (
1358                                                 &params->undi_initiate_diags );
1359                 break;
1360         case PXENV_UNDI_FORCE_INTERRUPT:
1361                 ret = pxenv_undi_force_interrupt (
1362                                                &params->undi_force_interrupt );
1363                 break;
1364         case PXENV_UNDI_GET_MCAST_ADDRESS:
1365                 ret = pxenv_undi_get_mcast_address (
1366                                              &params->undi_get_mcast_address );
1367                 break;
1368         case PXENV_UNDI_GET_NIC_TYPE:
1369                 ret = pxenv_undi_get_nic_type ( &params->undi_get_nic_type );
1370                 break;
1371         case PXENV_UNDI_GET_IFACE_INFO:
1372                 ret = pxenv_undi_get_iface_info (
1373                                                 &params->undi_get_iface_info );
1374                 break;
1375         case PXENV_UNDI_ISR:
1376                 ret = pxenv_undi_isr ( &params->undi_isr );
1377                 break;
1378         case PXENV_STOP_UNDI:
1379                 ret = pxenv_stop_undi ( &params->stop_undi );
1380                 break;
1381         case PXENV_TFTP_OPEN:
1382                 ret = pxenv_tftp_open ( &params->tftp_open );
1383                 break;
1384         case PXENV_TFTP_CLOSE:
1385                 ret = pxenv_tftp_close ( &params->tftp_close );
1386                 break;
1387         case PXENV_TFTP_READ:
1388                 ret = pxenv_tftp_read ( &params->tftp_read );
1389                 break;
1390         case PXENV_TFTP_READ_FILE:
1391                 ret = pxenv_tftp_read_file ( &params->tftp_read_file );
1392                 break;
1393         case PXENV_TFTP_GET_FSIZE:
1394                 ret = pxenv_tftp_get_fsize ( &params->tftp_get_fsize );
1395                 break;
1396         case PXENV_UDP_OPEN:
1397                 ret = pxenv_udp_open ( &params->udp_open );
1398                 break;
1399         case PXENV_UDP_CLOSE:
1400                 ret = pxenv_udp_close ( &params->udp_close );
1401                 break;
1402         case PXENV_UDP_READ:
1403                 ret = pxenv_udp_read ( &params->udp_read );
1404                 break;
1405         case PXENV_UDP_WRITE:
1406                 ret = pxenv_udp_write ( &params->udp_write );
1407                 break;
1408         case PXENV_UNLOAD_STACK:
1409                 ret = pxenv_unload_stack ( &params->unload_stack );
1410                 break;
1411         case PXENV_GET_CACHED_INFO:
1412                 ret = pxenv_get_cached_info ( &params->get_cached_info );
1413                 break;
1414         case PXENV_RESTART_TFTP:
1415                 ret = pxenv_restart_tftp ( &params->restart_tftp );
1416                 break;
1417         case PXENV_START_BASE:
1418                 ret = pxenv_start_base ( &params->start_base );
1419                 break;
1420         case PXENV_STOP_BASE:
1421                 ret = pxenv_stop_base ( &params->stop_base );
1422                 break;
1423         case PXENV_UNDI_LOADER:
1424                 ret = pxenv_undi_loader ( &params->loader );
1425                 break;
1426                 
1427         default:
1428                 DBG ( "PXENV_UNKNOWN_%hx", opcode );
1429                 params->Status = PXENV_STATUS_UNSUPPORTED;
1430                 ret = PXENV_EXIT_FAILURE;
1431                 break;
1432         }
1433
1434         if ( params->Status != PXENV_STATUS_SUCCESS ) {
1435                 DBG ( " %hx", params->Status );
1436         }
1437         if ( ret != PXENV_EXIT_SUCCESS ) {
1438                 DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
1439         }
1440         DBG ( "]" );
1441
1442         return ret;
1443 }
1444
1445 #endif /* PXE_EXPORT */