You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

pxe_export.c 42KB

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