Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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