Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

pxe_export.c 42KB

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