Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

pxe_undi.c 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. /** @file
  2. *
  3. * PXE UNDI API
  4. *
  5. */
  6. /*
  7. * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License as
  11. * published by the Free Software Foundation; either version 2 of the
  12. * License, or any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful, but
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22. */
  23. #include <stdint.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <byteswap.h>
  27. #include <basemem_packet.h>
  28. #include <gpxe/netdevice.h>
  29. #include <gpxe/iobuf.h>
  30. #include <gpxe/device.h>
  31. #include <gpxe/pci.h>
  32. #include <gpxe/if_ether.h>
  33. #include <gpxe/ip.h>
  34. #include <gpxe/arp.h>
  35. #include <gpxe/rarp.h>
  36. #include "pxe.h"
  37. /**
  38. * Count of outstanding transmitted packets
  39. *
  40. * This is incremented each time PXENV_UNDI_TRANSMIT is called, and
  41. * decremented each time that PXENV_UNDI_ISR is called with the TX
  42. * queue empty, stopping when the count reaches zero. This allows us
  43. * to provide a pessimistic approximation of TX completion events to
  44. * the PXE NBP simply by monitoring the netdev's TX queue.
  45. */
  46. static int undi_tx_count = 0;
  47. struct net_device *pxe_netdev = NULL;
  48. /**
  49. * Set network device as current PXE network device
  50. *
  51. * @v netdev Network device, or NULL
  52. */
  53. void pxe_set_netdev ( struct net_device *netdev ) {
  54. if ( pxe_netdev )
  55. netdev_put ( pxe_netdev );
  56. pxe_netdev = NULL;
  57. if ( netdev )
  58. pxe_netdev = netdev_get ( netdev );
  59. }
  60. /**
  61. * Open PXE network device
  62. *
  63. * @ret rc Return status code
  64. */
  65. static int pxe_netdev_open ( void ) {
  66. int rc;
  67. if ( ( rc = netdev_open ( pxe_netdev ) ) != 0 )
  68. return rc;
  69. netdev_irq ( pxe_netdev, 1 );
  70. return 0;
  71. }
  72. /**
  73. * Close PXE network device
  74. *
  75. */
  76. static void pxe_netdev_close ( void ) {
  77. netdev_irq ( pxe_netdev, 0 );
  78. netdev_close ( pxe_netdev );
  79. undi_tx_count = 0;
  80. }
  81. /* PXENV_UNDI_STARTUP
  82. *
  83. * Status: working
  84. */
  85. PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) {
  86. DBG ( "PXENV_UNDI_STARTUP" );
  87. undi_startup->Status = PXENV_STATUS_SUCCESS;
  88. return PXENV_EXIT_SUCCESS;
  89. }
  90. /* PXENV_UNDI_CLEANUP
  91. *
  92. * Status: working
  93. */
  94. PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) {
  95. DBG ( "PXENV_UNDI_CLEANUP" );
  96. pxe_netdev_close();
  97. undi_cleanup->Status = PXENV_STATUS_SUCCESS;
  98. return PXENV_EXIT_SUCCESS;
  99. }
  100. /* PXENV_UNDI_INITIALIZE
  101. *
  102. * Status: working
  103. */
  104. PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE
  105. *undi_initialize ) {
  106. DBG ( "PXENV_UNDI_INITIALIZE" );
  107. undi_initialize->Status = PXENV_STATUS_SUCCESS;
  108. return PXENV_EXIT_SUCCESS;
  109. }
  110. /* PXENV_UNDI_RESET_ADAPTER
  111. *
  112. * Status: working
  113. */
  114. PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET
  115. *undi_reset_adapter ) {
  116. int rc;
  117. DBG ( "PXENV_UNDI_RESET_ADAPTER" );
  118. pxe_netdev_close();
  119. if ( ( rc = pxe_netdev_open() ) != 0 ) {
  120. undi_reset_adapter->Status = PXENV_STATUS ( rc );
  121. return PXENV_EXIT_FAILURE;
  122. }
  123. undi_reset_adapter->Status = PXENV_STATUS_SUCCESS;
  124. return PXENV_EXIT_SUCCESS;
  125. }
  126. /* PXENV_UNDI_SHUTDOWN
  127. *
  128. * Status: working
  129. */
  130. PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN
  131. *undi_shutdown ) {
  132. DBG ( "PXENV_UNDI_SHUTDOWN" );
  133. pxe_netdev_close();
  134. undi_shutdown->Status = PXENV_STATUS_SUCCESS;
  135. return PXENV_EXIT_SUCCESS;
  136. }
  137. /* PXENV_UNDI_OPEN
  138. *
  139. * Status: working
  140. */
  141. PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) {
  142. int rc;
  143. DBG ( "PXENV_UNDI_OPEN" );
  144. if ( ( rc = pxe_netdev_open() ) != 0 ) {
  145. undi_open->Status = PXENV_STATUS ( rc );
  146. return PXENV_EXIT_FAILURE;
  147. }
  148. undi_open->Status = PXENV_STATUS_SUCCESS;
  149. return PXENV_EXIT_SUCCESS;
  150. }
  151. /* PXENV_UNDI_CLOSE
  152. *
  153. * Status: working
  154. */
  155. PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) {
  156. DBG ( "PXENV_UNDI_CLOSE" );
  157. pxe_netdev_close();
  158. undi_close->Status = PXENV_STATUS_SUCCESS;
  159. return PXENV_EXIT_SUCCESS;
  160. }
  161. /* PXENV_UNDI_TRANSMIT
  162. *
  163. * Status: working
  164. */
  165. PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
  166. *undi_transmit ) {
  167. struct s_PXENV_UNDI_TBD tbd;
  168. struct DataBlk *datablk;
  169. struct io_buffer *iobuf;
  170. struct net_protocol *net_protocol;
  171. char destaddr[MAX_LL_ADDR_LEN];
  172. const void *ll_dest;
  173. size_t ll_hlen = pxe_netdev->ll_protocol->ll_header_len;
  174. size_t len;
  175. unsigned int i;
  176. int rc;
  177. DBG ( "PXENV_UNDI_TRANSMIT" );
  178. /* Identify network-layer protocol */
  179. switch ( undi_transmit->Protocol ) {
  180. case P_IP: net_protocol = &ipv4_protocol; break;
  181. case P_ARP: net_protocol = &arp_protocol; break;
  182. case P_RARP: net_protocol = &rarp_protocol; break;
  183. case P_UNKNOWN:
  184. net_protocol = NULL;
  185. ll_hlen = 0;
  186. break;
  187. default:
  188. undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
  189. return PXENV_EXIT_FAILURE;
  190. }
  191. DBG ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) );
  192. /* Calculate total packet length */
  193. copy_from_real ( &tbd, undi_transmit->TBD.segment,
  194. undi_transmit->TBD.offset, sizeof ( tbd ) );
  195. len = tbd.ImmedLength;
  196. DBG ( " %d", tbd.ImmedLength );
  197. for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
  198. datablk = &tbd.DataBlock[i];
  199. len += datablk->TDDataLen;
  200. DBG ( "+%d", datablk->TDDataLen );
  201. }
  202. /* Allocate and fill I/O buffer */
  203. iobuf = alloc_iob ( ll_hlen + len );
  204. if ( ! iobuf ) {
  205. undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES;
  206. return PXENV_EXIT_FAILURE;
  207. }
  208. iob_reserve ( iobuf, ll_hlen );
  209. copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment,
  210. tbd.Xmit.offset, tbd.ImmedLength );
  211. for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
  212. datablk = &tbd.DataBlock[i];
  213. copy_from_real ( iob_put ( iobuf, datablk->TDDataLen ),
  214. datablk->TDDataPtr.segment,
  215. datablk->TDDataPtr.offset,
  216. datablk->TDDataLen );
  217. }
  218. /* Add link-layer header, if required to do so */
  219. if ( net_protocol != NULL ) {
  220. /* Calculate destination address */
  221. if ( undi_transmit->XmitFlag == XMT_DESTADDR ) {
  222. copy_from_real ( destaddr,
  223. undi_transmit->DestAddr.segment,
  224. undi_transmit->DestAddr.offset,
  225. pxe_netdev->ll_protocol->ll_addr_len );
  226. ll_dest = destaddr;
  227. } else {
  228. DBG ( " BCAST" );
  229. ll_dest = pxe_netdev->ll_protocol->ll_broadcast;
  230. }
  231. /* Add link-layer header */
  232. if ( ( rc = pxe_netdev->ll_protocol->push ( iobuf, pxe_netdev,
  233. net_protocol,
  234. ll_dest )) != 0 ){
  235. free_iob ( iobuf );
  236. undi_transmit->Status = PXENV_STATUS ( rc );
  237. return PXENV_EXIT_FAILURE;
  238. }
  239. }
  240. /* Transmit packet */
  241. if ( ( rc = netdev_tx ( pxe_netdev, iobuf ) ) != 0 ) {
  242. undi_transmit->Status = PXENV_STATUS ( rc );
  243. return PXENV_EXIT_FAILURE;
  244. }
  245. /* Flag transmission as in-progress */
  246. undi_tx_count++;
  247. undi_transmit->Status = PXENV_STATUS_SUCCESS;
  248. return PXENV_EXIT_SUCCESS;
  249. }
  250. /* PXENV_UNDI_SET_MCAST_ADDRESS
  251. *
  252. * Status: stub (no PXE multicast support)
  253. */
  254. PXENV_EXIT_t
  255. pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS
  256. *undi_set_mcast_address ) {
  257. DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" );
  258. undi_set_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
  259. return PXENV_EXIT_FAILURE;
  260. }
  261. /* PXENV_UNDI_SET_STATION_ADDRESS
  262. *
  263. * Status: working
  264. */
  265. PXENV_EXIT_t
  266. pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS
  267. *undi_set_station_address ) {
  268. DBG ( "PXENV_UNDI_SET_STATION_ADDRESS" );
  269. /* If adapter is open, the change will have no effect; return
  270. * an error
  271. */
  272. if ( pxe_netdev->state & NETDEV_OPEN ) {
  273. undi_set_station_address->Status =
  274. PXENV_STATUS_UNDI_INVALID_STATE;
  275. return PXENV_EXIT_FAILURE;
  276. }
  277. /* Update MAC address */
  278. memcpy ( pxe_netdev->ll_addr,
  279. &undi_set_station_address->StationAddress,
  280. pxe_netdev->ll_protocol->ll_addr_len );
  281. undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
  282. return PXENV_EXIT_SUCCESS;
  283. }
  284. /* PXENV_UNDI_SET_PACKET_FILTER
  285. *
  286. * Status: won't implement (would require driver API changes for no
  287. * real benefit)
  288. */
  289. PXENV_EXIT_t
  290. pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER
  291. *undi_set_packet_filter ) {
  292. DBG ( "PXENV_UNDI_SET_PACKET_FILTER" );
  293. undi_set_packet_filter->Status = PXENV_STATUS_UNSUPPORTED;
  294. return PXENV_EXIT_FAILURE;
  295. }
  296. /* PXENV_UNDI_GET_INFORMATION
  297. *
  298. * Status: working
  299. */
  300. PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
  301. *undi_get_information ) {
  302. struct device *dev = pxe_netdev->dev;
  303. struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
  304. DBG ( "PXENV_UNDI_GET_INFORMATION" );
  305. undi_get_information->BaseIo = dev->desc.ioaddr;
  306. undi_get_information->IntNumber = dev->desc.irq;
  307. /* Cheat: assume all cards can cope with this */
  308. undi_get_information->MaxTranUnit = ETH_MAX_MTU;
  309. undi_get_information->HwType = ntohs ( ll_protocol->ll_proto );
  310. undi_get_information->HwAddrLen = ll_protocol->ll_addr_len;
  311. /* Cheat: assume card is always configured with its permanent
  312. * node address. This is a valid assumption within Etherboot
  313. * at the time of writing.
  314. */
  315. memcpy ( &undi_get_information->CurrentNodeAddress,
  316. pxe_netdev->ll_addr,
  317. sizeof ( undi_get_information->CurrentNodeAddress ) );
  318. memcpy ( &undi_get_information->PermNodeAddress,
  319. pxe_netdev->ll_addr,
  320. sizeof ( undi_get_information->PermNodeAddress ) );
  321. undi_get_information->ROMAddress = 0;
  322. /* nic.rom_info->rom_segment; */
  323. /* We only provide the ability to receive or transmit a single
  324. * packet at a time. This is a bootloader, not an OS.
  325. */
  326. undi_get_information->RxBufCt = 1;
  327. undi_get_information->TxBufCt = 1;
  328. undi_get_information->Status = PXENV_STATUS_SUCCESS;
  329. return PXENV_EXIT_SUCCESS;
  330. }
  331. /* PXENV_UNDI_GET_STATISTICS
  332. *
  333. * Status: working
  334. */
  335. PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
  336. *undi_get_statistics ) {
  337. DBG ( "PXENV_UNDI_GET_STATISTICS" );
  338. undi_get_statistics->XmtGoodFrames = pxe_netdev->stats.tx_ok;
  339. undi_get_statistics->RcvGoodFrames = pxe_netdev->stats.rx_ok;
  340. undi_get_statistics->RcvCRCErrors = pxe_netdev->stats.rx_err;
  341. undi_get_statistics->RcvResourceErrors = pxe_netdev->stats.rx_err;
  342. undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
  343. return PXENV_EXIT_SUCCESS;
  344. }
  345. /* PXENV_UNDI_CLEAR_STATISTICS
  346. *
  347. * Status: working
  348. */
  349. PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS
  350. *undi_clear_statistics ) {
  351. DBG ( "PXENV_UNDI_CLEAR_STATISTICS" );
  352. memset ( &pxe_netdev->stats, 0, sizeof ( pxe_netdev->stats ) );
  353. undi_clear_statistics->Status = PXENV_STATUS_SUCCESS;
  354. return PXENV_EXIT_SUCCESS;
  355. }
  356. /* PXENV_UNDI_INITIATE_DIAGS
  357. *
  358. * Status: won't implement (would require driver API changes for no
  359. * real benefit)
  360. */
  361. PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS
  362. *undi_initiate_diags ) {
  363. DBG ( "PXENV_UNDI_INITIATE_DIAGS" );
  364. undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
  365. return PXENV_EXIT_FAILURE;
  366. }
  367. /* PXENV_UNDI_FORCE_INTERRUPT
  368. *
  369. * Status: won't implement (would require driver API changes for no
  370. * perceptible benefit)
  371. */
  372. PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT
  373. *undi_force_interrupt ) {
  374. DBG ( "PXENV_UNDI_FORCE_INTERRUPT" );
  375. undi_force_interrupt->Status = PXENV_STATUS_UNSUPPORTED;
  376. return PXENV_EXIT_FAILURE;
  377. }
  378. /* PXENV_UNDI_GET_MCAST_ADDRESS
  379. *
  380. * Status: stub (no PXE multicast support)
  381. */
  382. PXENV_EXIT_t
  383. pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS
  384. *undi_get_mcast_address ) {
  385. DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS" );
  386. undi_get_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
  387. return PXENV_EXIT_FAILURE;
  388. }
  389. /* PXENV_UNDI_GET_NIC_TYPE
  390. *
  391. * Status: working
  392. */
  393. PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
  394. *undi_get_nic_type ) {
  395. struct device *dev = pxe_netdev->dev;
  396. DBG ( "PXENV_UNDI_GET_NIC_TYPE" );
  397. memset ( &undi_get_nic_type->info, 0,
  398. sizeof ( undi_get_nic_type->info ) );
  399. switch ( dev->desc.bus_type ) {
  400. case BUS_TYPE_PCI: {
  401. struct pci_nic_info *info = &undi_get_nic_type->info.pci;
  402. undi_get_nic_type->NicType = PCI_NIC;
  403. info->Vendor_ID = dev->desc.vendor;
  404. info->Dev_ID = dev->desc.device;
  405. info->Base_Class = PCI_BASE_CLASS ( dev->desc.class );
  406. info->Sub_Class = PCI_SUB_CLASS ( dev->desc.class );
  407. info->Prog_Intf = PCI_PROG_INTF ( dev->desc.class );
  408. info->BusDevFunc = dev->desc.location;
  409. /* Cheat: remaining fields are probably unnecessary,
  410. * and would require adding extra code to pci.c.
  411. */
  412. undi_get_nic_type->info.pci.SubVendor_ID = 0xffff;
  413. undi_get_nic_type->info.pci.SubDevice_ID = 0xffff;
  414. break; }
  415. case BUS_TYPE_ISAPNP: {
  416. struct pnp_nic_info *info = &undi_get_nic_type->info.pnp;
  417. undi_get_nic_type->NicType = PnP_NIC;
  418. info->EISA_Dev_ID = ( ( dev->desc.vendor << 16 ) |
  419. dev->desc.device );
  420. info->CardSelNum = dev->desc.location;
  421. /* Cheat: remaining fields are probably unnecessary,
  422. * and would require adding extra code to isapnp.c.
  423. */
  424. break; }
  425. default:
  426. undi_get_nic_type->Status = PXENV_STATUS_FAILURE;
  427. return PXENV_EXIT_FAILURE;
  428. }
  429. undi_get_nic_type->Status = PXENV_STATUS_SUCCESS;
  430. return PXENV_EXIT_SUCCESS;
  431. }
  432. /* PXENV_UNDI_GET_IFACE_INFO
  433. *
  434. * Status: working
  435. */
  436. PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
  437. *undi_get_iface_info ) {
  438. DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
  439. /* Just hand back some info, doesn't really matter what it is.
  440. * Most PXE stacks seem to take this approach.
  441. */
  442. snprintf ( ( char * ) undi_get_iface_info->IfaceType,
  443. sizeof ( undi_get_iface_info->IfaceType ), "gPXE" );
  444. undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
  445. undi_get_iface_info->ServiceFlags = 0;
  446. memset ( undi_get_iface_info->Reserved, 0,
  447. sizeof(undi_get_iface_info->Reserved) );
  448. undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
  449. return PXENV_EXIT_SUCCESS;
  450. }
  451. /* PXENV_UNDI_GET_STATE
  452. *
  453. * Status: impossible
  454. */
  455. PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
  456. *undi_get_state ) {
  457. DBG ( "PXENV_UNDI_GET_STATE" );
  458. undi_get_state->Status = PXENV_STATUS_UNSUPPORTED;
  459. return PXENV_EXIT_FAILURE;
  460. };
  461. /* PXENV_UNDI_ISR
  462. *
  463. * Status: working
  464. */
  465. PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
  466. struct io_buffer *iobuf;
  467. size_t len;
  468. struct ll_protocol *ll_protocol;
  469. const void *ll_source;
  470. uint16_t net_proto;
  471. size_t ll_hlen;
  472. struct net_protocol *net_protocol;
  473. unsigned int prottype;
  474. int rc;
  475. DBG ( "PXENV_UNDI_ISR" );
  476. /* Just in case some idiot actually looks at these fields when
  477. * we weren't meant to fill them in...
  478. */
  479. undi_isr->BufferLength = 0;
  480. undi_isr->FrameLength = 0;
  481. undi_isr->FrameHeaderLength = 0;
  482. undi_isr->ProtType = 0;
  483. undi_isr->PktType = 0;
  484. switch ( undi_isr->FuncFlag ) {
  485. case PXENV_UNDI_ISR_IN_START :
  486. DBG ( " START" );
  487. /* Call poll(). This should acknowledge the device
  488. * interrupt and queue up any received packet.
  489. */
  490. netdev_poll ( pxe_netdev );
  491. /* Disable interrupts to avoid interrupt storm */
  492. netdev_irq ( pxe_netdev, 0 );
  493. /* Always say it was ours for the sake of simplicity */
  494. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
  495. break;
  496. case PXENV_UNDI_ISR_IN_PROCESS :
  497. DBG ( " PROCESS" );
  498. /* Fall through */
  499. case PXENV_UNDI_ISR_IN_GET_NEXT :
  500. DBG ( " GET_NEXT" );
  501. /* Some dumb NBPs (e.g. emBoot's winBoot/i) never call
  502. * PXENV_UNDI_ISR with FuncFlag=PXENV_UNDI_ISR_START;
  503. * they just sit in a tight polling loop merrily
  504. * violating the PXE spec with repeated calls to
  505. * PXENV_UNDI_ISR_IN_PROCESS. Force extra polls to
  506. * cope with these out-of-spec clients.
  507. */
  508. netdev_poll ( pxe_netdev );
  509. /* If we have not yet marked a TX as complete, and the
  510. * netdev TX queue is empty, report the TX completion.
  511. */
  512. if ( undi_tx_count && list_empty ( &pxe_netdev->tx_queue ) ) {
  513. DBG ( " TXC" );
  514. undi_tx_count--;
  515. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_TRANSMIT;
  516. break;
  517. }
  518. /* Remove first packet from netdev RX queue */
  519. iobuf = netdev_rx_dequeue ( pxe_netdev );
  520. if ( ! iobuf ) {
  521. DBG ( " DONE" );
  522. /* No more packets remaining */
  523. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
  524. /* Re-enable interrupts */
  525. netdev_irq ( pxe_netdev, 1 );
  526. break;
  527. }
  528. /* Copy packet to base memory buffer */
  529. len = iob_len ( iobuf );
  530. DBG ( " RX %zd", len );
  531. if ( len > sizeof ( basemem_packet ) ) {
  532. /* Should never happen */
  533. len = sizeof ( basemem_packet );
  534. }
  535. memcpy ( basemem_packet, iobuf->data, len );
  536. /* Strip link-layer header */
  537. ll_protocol = pxe_netdev->ll_protocol;
  538. if ( ( rc = ll_protocol->pull ( iobuf, pxe_netdev,
  539. &net_proto,
  540. &ll_source ) ) != 0 ) {
  541. /* Assume unknown net_proto and no ll_source */
  542. net_proto = 0;
  543. ll_source = NULL;
  544. }
  545. ll_hlen = ( len - iob_len ( iobuf ) );
  546. /* Determine network-layer protocol */
  547. switch ( net_proto ) {
  548. case htons ( ETH_P_IP ):
  549. net_protocol = &ipv4_protocol;
  550. prottype = P_IP;
  551. break;
  552. case htons ( ETH_P_ARP ):
  553. net_protocol = &arp_protocol;
  554. prottype = P_ARP;
  555. break;
  556. case htons ( ETH_P_RARP ):
  557. net_protocol = &rarp_protocol;
  558. prottype = P_RARP;
  559. break;
  560. default:
  561. net_protocol = NULL;
  562. prottype = P_UNKNOWN;
  563. break;
  564. }
  565. DBG ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) );
  566. /* Fill in UNDI_ISR structure */
  567. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
  568. undi_isr->BufferLength = len;
  569. undi_isr->FrameLength = len;
  570. undi_isr->FrameHeaderLength = ll_hlen;
  571. undi_isr->Frame.segment = rm_ds;
  572. undi_isr->Frame.offset = __from_data16 ( basemem_packet );
  573. undi_isr->ProtType = prottype;
  574. undi_isr->PktType = XMT_DESTADDR;
  575. /* Free packet */
  576. free_iob ( iobuf );
  577. break;
  578. default :
  579. DBG ( " INVALID(%04x)", undi_isr->FuncFlag );
  580. /* Should never happen */
  581. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
  582. undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
  583. return PXENV_EXIT_FAILURE;
  584. }
  585. undi_isr->Status = PXENV_STATUS_SUCCESS;
  586. return PXENV_EXIT_SUCCESS;
  587. }