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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  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. /* Forcibly enable interrupts at this point, to work around
  181. * callers that never call PXENV_UNDI_OPEN before attempting
  182. * to use the UNDI API.
  183. */
  184. netdev_irq ( pxe_netdev, 1 );
  185. /* Identify network-layer protocol */
  186. switch ( undi_transmit->Protocol ) {
  187. case P_IP: net_protocol = &ipv4_protocol; break;
  188. case P_ARP: net_protocol = &arp_protocol; break;
  189. case P_RARP: net_protocol = &rarp_protocol; break;
  190. case P_UNKNOWN:
  191. net_protocol = NULL;
  192. ll_hlen = 0;
  193. break;
  194. default:
  195. undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
  196. return PXENV_EXIT_FAILURE;
  197. }
  198. DBG ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) );
  199. /* Calculate total packet length */
  200. copy_from_real ( &tbd, undi_transmit->TBD.segment,
  201. undi_transmit->TBD.offset, sizeof ( tbd ) );
  202. len = tbd.ImmedLength;
  203. DBG ( " %d", tbd.ImmedLength );
  204. for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
  205. datablk = &tbd.DataBlock[i];
  206. len += datablk->TDDataLen;
  207. DBG ( "+%d", datablk->TDDataLen );
  208. }
  209. /* Allocate and fill I/O buffer */
  210. iobuf = alloc_iob ( ll_hlen + len );
  211. if ( ! iobuf ) {
  212. undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES;
  213. return PXENV_EXIT_FAILURE;
  214. }
  215. iob_reserve ( iobuf, ll_hlen );
  216. copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment,
  217. tbd.Xmit.offset, tbd.ImmedLength );
  218. for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
  219. datablk = &tbd.DataBlock[i];
  220. copy_from_real ( iob_put ( iobuf, datablk->TDDataLen ),
  221. datablk->TDDataPtr.segment,
  222. datablk->TDDataPtr.offset,
  223. datablk->TDDataLen );
  224. }
  225. /* Add link-layer header, if required to do so */
  226. if ( net_protocol != NULL ) {
  227. /* Calculate destination address */
  228. if ( undi_transmit->XmitFlag == XMT_DESTADDR ) {
  229. copy_from_real ( destaddr,
  230. undi_transmit->DestAddr.segment,
  231. undi_transmit->DestAddr.offset,
  232. ll_protocol->ll_addr_len );
  233. ll_dest = destaddr;
  234. } else {
  235. DBG ( " BCAST" );
  236. ll_dest = ll_protocol->ll_broadcast;
  237. }
  238. /* Add link-layer header */
  239. if ( ( rc = ll_protocol->push ( pxe_netdev, iobuf, ll_dest,
  240. pxe_netdev->ll_addr,
  241. net_protocol->net_proto ))!=0){
  242. free_iob ( iobuf );
  243. undi_transmit->Status = PXENV_STATUS ( rc );
  244. return PXENV_EXIT_FAILURE;
  245. }
  246. }
  247. /* Transmit packet */
  248. if ( ( rc = netdev_tx ( pxe_netdev, iobuf ) ) != 0 ) {
  249. undi_transmit->Status = PXENV_STATUS ( rc );
  250. return PXENV_EXIT_FAILURE;
  251. }
  252. /* Flag transmission as in-progress */
  253. undi_tx_count++;
  254. undi_transmit->Status = PXENV_STATUS_SUCCESS;
  255. return PXENV_EXIT_SUCCESS;
  256. }
  257. /* PXENV_UNDI_SET_MCAST_ADDRESS
  258. *
  259. * Status: stub (no PXE multicast support)
  260. */
  261. PXENV_EXIT_t
  262. pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS
  263. *undi_set_mcast_address ) {
  264. DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" );
  265. undi_set_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
  266. return PXENV_EXIT_FAILURE;
  267. }
  268. /* PXENV_UNDI_SET_STATION_ADDRESS
  269. *
  270. * Status: working
  271. */
  272. PXENV_EXIT_t
  273. pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS
  274. *undi_set_station_address ) {
  275. DBG ( "PXENV_UNDI_SET_STATION_ADDRESS" );
  276. /* If adapter is open, the change will have no effect; return
  277. * an error
  278. */
  279. if ( pxe_netdev->state & NETDEV_OPEN ) {
  280. undi_set_station_address->Status =
  281. PXENV_STATUS_UNDI_INVALID_STATE;
  282. return PXENV_EXIT_FAILURE;
  283. }
  284. /* Update MAC address */
  285. memcpy ( pxe_netdev->ll_addr,
  286. &undi_set_station_address->StationAddress,
  287. pxe_netdev->ll_protocol->ll_addr_len );
  288. undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
  289. return PXENV_EXIT_SUCCESS;
  290. }
  291. /* PXENV_UNDI_SET_PACKET_FILTER
  292. *
  293. * Status: won't implement (would require driver API changes for no
  294. * real benefit)
  295. */
  296. PXENV_EXIT_t
  297. pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER
  298. *undi_set_packet_filter ) {
  299. DBG ( "PXENV_UNDI_SET_PACKET_FILTER" );
  300. /* Pretend that we succeeded, otherwise the 3Com DOS UNDI
  301. * driver refuses to load. (We ignore the filter value in the
  302. * PXENV_UNDI_OPEN call anyway.)
  303. */
  304. DBG ( " %02x", undi_set_packet_filter->filter );
  305. undi_set_packet_filter->Status = PXENV_STATUS_SUCCESS;
  306. return PXENV_EXIT_SUCCESS;
  307. }
  308. /* PXENV_UNDI_GET_INFORMATION
  309. *
  310. * Status: working
  311. */
  312. PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
  313. *undi_get_information ) {
  314. struct device *dev = pxe_netdev->dev;
  315. struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
  316. DBG ( "PXENV_UNDI_GET_INFORMATION" );
  317. undi_get_information->BaseIo = dev->desc.ioaddr;
  318. undi_get_information->IntNumber = dev->desc.irq;
  319. /* Cheat: assume all cards can cope with this */
  320. undi_get_information->MaxTranUnit = ETH_MAX_MTU;
  321. undi_get_information->HwType = ntohs ( ll_protocol->ll_proto );
  322. undi_get_information->HwAddrLen = ll_protocol->ll_addr_len;
  323. /* Cheat: assume card is always configured with its permanent
  324. * node address. This is a valid assumption within Etherboot
  325. * at the time of writing.
  326. */
  327. memcpy ( &undi_get_information->CurrentNodeAddress,
  328. pxe_netdev->ll_addr,
  329. sizeof ( undi_get_information->CurrentNodeAddress ) );
  330. memcpy ( &undi_get_information->PermNodeAddress,
  331. pxe_netdev->ll_addr,
  332. sizeof ( undi_get_information->PermNodeAddress ) );
  333. undi_get_information->ROMAddress = 0;
  334. /* nic.rom_info->rom_segment; */
  335. /* We only provide the ability to receive or transmit a single
  336. * packet at a time. This is a bootloader, not an OS.
  337. */
  338. undi_get_information->RxBufCt = 1;
  339. undi_get_information->TxBufCt = 1;
  340. undi_get_information->Status = PXENV_STATUS_SUCCESS;
  341. return PXENV_EXIT_SUCCESS;
  342. }
  343. /* PXENV_UNDI_GET_STATISTICS
  344. *
  345. * Status: working
  346. */
  347. PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
  348. *undi_get_statistics ) {
  349. DBG ( "PXENV_UNDI_GET_STATISTICS" );
  350. undi_get_statistics->XmtGoodFrames = pxe_netdev->tx_stats.good;
  351. undi_get_statistics->RcvGoodFrames = pxe_netdev->rx_stats.good;
  352. undi_get_statistics->RcvCRCErrors = pxe_netdev->rx_stats.bad;
  353. undi_get_statistics->RcvResourceErrors = pxe_netdev->rx_stats.bad;
  354. undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
  355. return PXENV_EXIT_SUCCESS;
  356. }
  357. /* PXENV_UNDI_CLEAR_STATISTICS
  358. *
  359. * Status: working
  360. */
  361. PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS
  362. *undi_clear_statistics ) {
  363. DBG ( "PXENV_UNDI_CLEAR_STATISTICS" );
  364. memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) );
  365. memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) );
  366. undi_clear_statistics->Status = PXENV_STATUS_SUCCESS;
  367. return PXENV_EXIT_SUCCESS;
  368. }
  369. /* PXENV_UNDI_INITIATE_DIAGS
  370. *
  371. * Status: won't implement (would require driver API changes for no
  372. * real benefit)
  373. */
  374. PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS
  375. *undi_initiate_diags ) {
  376. DBG ( "PXENV_UNDI_INITIATE_DIAGS" );
  377. undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
  378. return PXENV_EXIT_FAILURE;
  379. }
  380. /* PXENV_UNDI_FORCE_INTERRUPT
  381. *
  382. * Status: won't implement (would require driver API changes for no
  383. * perceptible benefit)
  384. */
  385. PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT
  386. *undi_force_interrupt ) {
  387. DBG ( "PXENV_UNDI_FORCE_INTERRUPT" );
  388. undi_force_interrupt->Status = PXENV_STATUS_UNSUPPORTED;
  389. return PXENV_EXIT_FAILURE;
  390. }
  391. /* PXENV_UNDI_GET_MCAST_ADDRESS
  392. *
  393. * Status: stub (no PXE multicast support)
  394. */
  395. PXENV_EXIT_t
  396. pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS
  397. *undi_get_mcast_address ) {
  398. DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS" );
  399. undi_get_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
  400. return PXENV_EXIT_FAILURE;
  401. }
  402. /* PXENV_UNDI_GET_NIC_TYPE
  403. *
  404. * Status: working
  405. */
  406. PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
  407. *undi_get_nic_type ) {
  408. struct device *dev = pxe_netdev->dev;
  409. DBG ( "PXENV_UNDI_GET_NIC_TYPE" );
  410. memset ( &undi_get_nic_type->info, 0,
  411. sizeof ( undi_get_nic_type->info ) );
  412. switch ( dev->desc.bus_type ) {
  413. case BUS_TYPE_PCI: {
  414. struct pci_nic_info *info = &undi_get_nic_type->info.pci;
  415. undi_get_nic_type->NicType = PCI_NIC;
  416. info->Vendor_ID = dev->desc.vendor;
  417. info->Dev_ID = dev->desc.device;
  418. info->Base_Class = PCI_BASE_CLASS ( dev->desc.class );
  419. info->Sub_Class = PCI_SUB_CLASS ( dev->desc.class );
  420. info->Prog_Intf = PCI_PROG_INTF ( dev->desc.class );
  421. info->BusDevFunc = dev->desc.location;
  422. /* Cheat: remaining fields are probably unnecessary,
  423. * and would require adding extra code to pci.c.
  424. */
  425. undi_get_nic_type->info.pci.SubVendor_ID = 0xffff;
  426. undi_get_nic_type->info.pci.SubDevice_ID = 0xffff;
  427. break; }
  428. case BUS_TYPE_ISAPNP: {
  429. struct pnp_nic_info *info = &undi_get_nic_type->info.pnp;
  430. undi_get_nic_type->NicType = PnP_NIC;
  431. info->EISA_Dev_ID = ( ( dev->desc.vendor << 16 ) |
  432. dev->desc.device );
  433. info->CardSelNum = dev->desc.location;
  434. /* Cheat: remaining fields are probably unnecessary,
  435. * and would require adding extra code to isapnp.c.
  436. */
  437. break; }
  438. default:
  439. undi_get_nic_type->Status = PXENV_STATUS_FAILURE;
  440. return PXENV_EXIT_FAILURE;
  441. }
  442. undi_get_nic_type->Status = PXENV_STATUS_SUCCESS;
  443. return PXENV_EXIT_SUCCESS;
  444. }
  445. /* PXENV_UNDI_GET_IFACE_INFO
  446. *
  447. * Status: working
  448. */
  449. PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
  450. *undi_get_iface_info ) {
  451. DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
  452. /* Just hand back some info, doesn't really matter what it is.
  453. * Most PXE stacks seem to take this approach.
  454. */
  455. snprintf ( ( char * ) undi_get_iface_info->IfaceType,
  456. sizeof ( undi_get_iface_info->IfaceType ), "DIX+802.3" );
  457. undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
  458. undi_get_iface_info->ServiceFlags =
  459. ( SUPPORTED_BROADCAST | SUPPORTED_MULTICAST |
  460. SUPPORTED_SET_STATION_ADDRESS | SUPPORTED_RESET |
  461. SUPPORTED_OPEN_CLOSE | SUPPORTED_IRQ );
  462. memset ( undi_get_iface_info->Reserved, 0,
  463. sizeof(undi_get_iface_info->Reserved) );
  464. undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
  465. return PXENV_EXIT_SUCCESS;
  466. }
  467. /* PXENV_UNDI_GET_STATE
  468. *
  469. * Status: impossible
  470. */
  471. PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
  472. *undi_get_state ) {
  473. DBG ( "PXENV_UNDI_GET_STATE" );
  474. undi_get_state->Status = PXENV_STATUS_UNSUPPORTED;
  475. return PXENV_EXIT_FAILURE;
  476. };
  477. /* PXENV_UNDI_ISR
  478. *
  479. * Status: working
  480. */
  481. PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
  482. struct io_buffer *iobuf;
  483. size_t len;
  484. struct ll_protocol *ll_protocol;
  485. const void *ll_dest;
  486. const void *ll_source;
  487. uint16_t net_proto;
  488. size_t ll_hlen;
  489. struct net_protocol *net_protocol;
  490. unsigned int prottype;
  491. int rc;
  492. DBG ( "PXENV_UNDI_ISR" );
  493. /* Just in case some idiot actually looks at these fields when
  494. * we weren't meant to fill them in...
  495. */
  496. undi_isr->BufferLength = 0;
  497. undi_isr->FrameLength = 0;
  498. undi_isr->FrameHeaderLength = 0;
  499. undi_isr->ProtType = 0;
  500. undi_isr->PktType = 0;
  501. switch ( undi_isr->FuncFlag ) {
  502. case PXENV_UNDI_ISR_IN_START :
  503. DBG ( " START" );
  504. /* Call poll(). This should acknowledge the device
  505. * interrupt and queue up any received packet.
  506. */
  507. netdev_poll ( pxe_netdev );
  508. /* Disable interrupts to avoid interrupt storm */
  509. netdev_irq ( pxe_netdev, 0 );
  510. /* Always say it was ours for the sake of simplicity */
  511. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
  512. break;
  513. case PXENV_UNDI_ISR_IN_PROCESS :
  514. DBG ( " PROCESS" );
  515. /* Fall through */
  516. case PXENV_UNDI_ISR_IN_GET_NEXT :
  517. DBG ( " GET_NEXT" );
  518. /* Some dumb NBPs (e.g. emBoot's winBoot/i) never call
  519. * PXENV_UNDI_ISR with FuncFlag=PXENV_UNDI_ISR_START;
  520. * they just sit in a tight polling loop merrily
  521. * violating the PXE spec with repeated calls to
  522. * PXENV_UNDI_ISR_IN_PROCESS. Force extra polls to
  523. * cope with these out-of-spec clients.
  524. */
  525. netdev_poll ( pxe_netdev );
  526. /* If we have not yet marked a TX as complete, and the
  527. * netdev TX queue is empty, report the TX completion.
  528. */
  529. if ( undi_tx_count && list_empty ( &pxe_netdev->tx_queue ) ) {
  530. DBG ( " TXC" );
  531. undi_tx_count--;
  532. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_TRANSMIT;
  533. break;
  534. }
  535. /* Remove first packet from netdev RX queue */
  536. iobuf = netdev_rx_dequeue ( pxe_netdev );
  537. if ( ! iobuf ) {
  538. DBG ( " DONE" );
  539. /* No more packets remaining */
  540. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
  541. /* Re-enable interrupts */
  542. netdev_irq ( pxe_netdev, 1 );
  543. break;
  544. }
  545. /* Copy packet to base memory buffer */
  546. len = iob_len ( iobuf );
  547. DBG ( " RX %zd", len );
  548. if ( len > sizeof ( basemem_packet ) ) {
  549. /* Should never happen */
  550. len = sizeof ( basemem_packet );
  551. }
  552. memcpy ( basemem_packet, iobuf->data, len );
  553. /* Strip link-layer header */
  554. ll_protocol = pxe_netdev->ll_protocol;
  555. if ( ( rc = ll_protocol->pull ( pxe_netdev, iobuf, &ll_dest,
  556. &ll_source, &net_proto )) !=0){
  557. /* Assume unknown net_proto and no ll_source */
  558. net_proto = 0;
  559. ll_source = NULL;
  560. }
  561. ll_hlen = ( len - iob_len ( iobuf ) );
  562. /* Determine network-layer protocol */
  563. switch ( net_proto ) {
  564. case htons ( ETH_P_IP ):
  565. net_protocol = &ipv4_protocol;
  566. prottype = P_IP;
  567. break;
  568. case htons ( ETH_P_ARP ):
  569. net_protocol = &arp_protocol;
  570. prottype = P_ARP;
  571. break;
  572. case htons ( ETH_P_RARP ):
  573. net_protocol = &rarp_protocol;
  574. prottype = P_RARP;
  575. break;
  576. default:
  577. net_protocol = NULL;
  578. prottype = P_UNKNOWN;
  579. break;
  580. }
  581. DBG ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) );
  582. /* Fill in UNDI_ISR structure */
  583. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
  584. undi_isr->BufferLength = len;
  585. undi_isr->FrameLength = len;
  586. undi_isr->FrameHeaderLength = ll_hlen;
  587. undi_isr->Frame.segment = rm_ds;
  588. undi_isr->Frame.offset = __from_data16 ( basemem_packet );
  589. undi_isr->ProtType = prottype;
  590. undi_isr->PktType = XMT_DESTADDR;
  591. /* Free packet */
  592. free_iob ( iobuf );
  593. break;
  594. default :
  595. DBG ( " INVALID(%04x)", undi_isr->FuncFlag );
  596. /* Should never happen */
  597. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
  598. undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
  599. return PXENV_EXIT_FAILURE;
  600. }
  601. undi_isr->Status = PXENV_STATUS_SUCCESS;
  602. return PXENV_EXIT_SUCCESS;
  603. }