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

pxe_undi.c 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  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 <gpxe/shutdown.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. /**
  49. * Open PXE network device
  50. *
  51. * @ret rc Return status code
  52. */
  53. static int pxe_netdev_open ( void ) {
  54. return netdev_open ( pxe_netdev );
  55. }
  56. /**
  57. * Close PXE network device
  58. *
  59. */
  60. static void pxe_netdev_close ( void ) {
  61. netdev_close ( pxe_netdev );
  62. undi_tx_count = 0;
  63. }
  64. /* PXENV_UNDI_STARTUP
  65. *
  66. * Status: working
  67. */
  68. PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) {
  69. DBG ( "PXENV_UNDI_STARTUP" );
  70. undi_startup->Status = PXENV_STATUS_SUCCESS;
  71. return PXENV_EXIT_SUCCESS;
  72. }
  73. /* PXENV_UNDI_CLEANUP
  74. *
  75. * Status: working
  76. */
  77. PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) {
  78. DBG ( "PXENV_UNDI_CLEANUP" );
  79. pxe_netdev_close();
  80. undi_cleanup->Status = PXENV_STATUS_SUCCESS;
  81. return PXENV_EXIT_SUCCESS;
  82. }
  83. /* PXENV_UNDI_INITIALIZE
  84. *
  85. * Status: working
  86. */
  87. PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE
  88. *undi_initialize ) {
  89. DBG ( "PXENV_UNDI_INITIALIZE" );
  90. undi_initialize->Status = PXENV_STATUS_SUCCESS;
  91. return PXENV_EXIT_SUCCESS;
  92. }
  93. /* PXENV_UNDI_RESET_ADAPTER
  94. *
  95. * Status: working
  96. */
  97. PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET
  98. *undi_reset_adapter ) {
  99. int rc;
  100. DBG ( "PXENV_UNDI_RESET_ADAPTER" );
  101. pxe_netdev_close();
  102. if ( ( rc = pxe_netdev_open() ) != 0 ) {
  103. undi_reset_adapter->Status = PXENV_STATUS ( rc );
  104. return PXENV_EXIT_FAILURE;
  105. }
  106. undi_reset_adapter->Status = PXENV_STATUS_SUCCESS;
  107. return PXENV_EXIT_SUCCESS;
  108. }
  109. /* PXENV_UNDI_SHUTDOWN
  110. *
  111. * Status: working
  112. */
  113. PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN
  114. *undi_shutdown ) {
  115. DBG ( "PXENV_UNDI_SHUTDOWN" );
  116. pxe_netdev_close();
  117. undi_shutdown->Status = PXENV_STATUS_SUCCESS;
  118. return PXENV_EXIT_SUCCESS;
  119. }
  120. /* PXENV_UNDI_OPEN
  121. *
  122. * Status: working
  123. */
  124. PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) {
  125. int rc;
  126. DBG ( "PXENV_UNDI_OPEN" );
  127. if ( ( rc = pxe_netdev_open() ) != 0 ) {
  128. undi_open->Status = PXENV_STATUS ( rc );
  129. return PXENV_EXIT_FAILURE;
  130. }
  131. undi_open->Status = PXENV_STATUS_SUCCESS;
  132. return PXENV_EXIT_SUCCESS;
  133. }
  134. /* PXENV_UNDI_CLOSE
  135. *
  136. * Status: working
  137. */
  138. PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) {
  139. DBG ( "PXENV_UNDI_CLOSE" );
  140. pxe_netdev_close();
  141. undi_close->Status = PXENV_STATUS_SUCCESS;
  142. return PXENV_EXIT_SUCCESS;
  143. }
  144. /* PXENV_UNDI_TRANSMIT
  145. *
  146. * Status: working
  147. */
  148. PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
  149. *undi_transmit ) {
  150. struct s_PXENV_UNDI_TBD tbd;
  151. struct DataBlk *datablk;
  152. struct io_buffer *iobuf;
  153. struct net_protocol *net_protocol;
  154. char destaddr[MAX_LL_ADDR_LEN];
  155. const void *ll_dest;
  156. size_t len;
  157. unsigned int i;
  158. int rc;
  159. DBG ( "PXENV_UNDI_TRANSMIT" );
  160. /* Identify network-layer protocol */
  161. switch ( undi_transmit->Protocol ) {
  162. case P_IP: net_protocol = &ipv4_protocol; break;
  163. case P_ARP: net_protocol = &arp_protocol; break;
  164. case P_RARP: net_protocol = &rarp_protocol; break;
  165. case P_UNKNOWN: net_protocol = NULL; break;
  166. default:
  167. undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
  168. return PXENV_EXIT_FAILURE;
  169. }
  170. /* Calculate total packet length */
  171. copy_from_real ( &tbd, undi_transmit->TBD.segment,
  172. undi_transmit->TBD.offset, sizeof ( tbd ) );
  173. len = tbd.ImmedLength;
  174. for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
  175. datablk = &tbd.DataBlock[i];
  176. len += datablk->TDDataLen;
  177. }
  178. /* Allocate and fill I/O buffer */
  179. iobuf = alloc_iob ( len );
  180. if ( ! iobuf ) {
  181. undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES;
  182. return PXENV_EXIT_FAILURE;
  183. }
  184. copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment,
  185. tbd.Xmit.offset, tbd.ImmedLength );
  186. for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
  187. datablk = &tbd.DataBlock[i];
  188. copy_from_real ( iob_put ( iobuf, datablk->TDDataLen ),
  189. datablk->TDDataPtr.segment,
  190. datablk->TDDataPtr.offset,
  191. datablk->TDDataLen );
  192. }
  193. /* Transmit packet */
  194. if ( net_protocol == NULL ) {
  195. /* Link-layer header already present */
  196. rc = netdev_tx ( pxe_netdev, iobuf );
  197. } else {
  198. /* Calculate destination address */
  199. if ( undi_transmit->XmitFlag == XMT_DESTADDR ) {
  200. copy_from_real ( destaddr,
  201. undi_transmit->DestAddr.segment,
  202. undi_transmit->DestAddr.offset,
  203. pxe_netdev->ll_protocol->ll_addr_len );
  204. ll_dest = destaddr;
  205. } else {
  206. ll_dest = pxe_netdev->ll_protocol->ll_broadcast;
  207. }
  208. rc = net_tx ( iobuf, pxe_netdev, net_protocol, ll_dest );
  209. }
  210. /* Flag transmission as in-progress */
  211. undi_tx_count++;
  212. undi_transmit->Status = PXENV_STATUS ( rc );
  213. return ( ( rc == 0 ) ? PXENV_EXIT_SUCCESS : PXENV_EXIT_FAILURE );
  214. }
  215. /* PXENV_UNDI_SET_MCAST_ADDRESS
  216. *
  217. * Status: stub (no PXE multicast support)
  218. */
  219. PXENV_EXIT_t
  220. pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS
  221. *undi_set_mcast_address ) {
  222. DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" );
  223. undi_set_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
  224. return PXENV_EXIT_FAILURE;
  225. }
  226. /* PXENV_UNDI_SET_STATION_ADDRESS
  227. *
  228. * Status: working
  229. */
  230. PXENV_EXIT_t
  231. pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS
  232. *undi_set_station_address ) {
  233. DBG ( "PXENV_UNDI_SET_STATION_ADDRESS" );
  234. /* If adapter is open, the change will have no effect; return
  235. * an error
  236. */
  237. if ( pxe_netdev->state & NETDEV_OPEN ) {
  238. undi_set_station_address->Status =
  239. PXENV_STATUS_UNDI_INVALID_STATE;
  240. return PXENV_EXIT_FAILURE;
  241. }
  242. /* Update MAC address */
  243. memcpy ( pxe_netdev->ll_addr,
  244. &undi_set_station_address->StationAddress,
  245. pxe_netdev->ll_protocol->ll_addr_len );
  246. undi_set_station_address = PXENV_STATUS_SUCCESS;
  247. return PXENV_EXIT_SUCCESS;
  248. }
  249. /* PXENV_UNDI_SET_PACKET_FILTER
  250. *
  251. * Status: won't implement (would require driver API changes for no
  252. * real benefit)
  253. */
  254. PXENV_EXIT_t
  255. pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER
  256. *undi_set_packet_filter ) {
  257. DBG ( "PXENV_UNDI_SET_PACKET_FILTER" );
  258. undi_set_packet_filter->Status = PXENV_STATUS_UNSUPPORTED;
  259. return PXENV_EXIT_FAILURE;
  260. }
  261. /* PXENV_UNDI_GET_INFORMATION
  262. *
  263. * Status: working
  264. */
  265. PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
  266. *undi_get_information ) {
  267. struct device *dev = pxe_netdev->dev;
  268. struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
  269. DBG ( "PXENV_UNDI_GET_INFORMATION" );
  270. undi_get_information->BaseIo = dev->desc.ioaddr;
  271. undi_get_information->IntNumber = dev->desc.irq;
  272. /* Cheat: assume all cards can cope with this */
  273. undi_get_information->MaxTranUnit = ETH_MAX_MTU;
  274. undi_get_information->HwType = ntohs ( ll_protocol->ll_proto );
  275. undi_get_information->HwAddrLen = ll_protocol->ll_addr_len;
  276. /* Cheat: assume card is always configured with its permanent
  277. * node address. This is a valid assumption within Etherboot
  278. * at the time of writing.
  279. */
  280. memcpy ( &undi_get_information->CurrentNodeAddress,
  281. pxe_netdev->ll_addr,
  282. sizeof ( undi_get_information->CurrentNodeAddress ) );
  283. memcpy ( &undi_get_information->PermNodeAddress,
  284. pxe_netdev->ll_addr,
  285. sizeof ( undi_get_information->PermNodeAddress ) );
  286. undi_get_information->ROMAddress = 0;
  287. /* nic.rom_info->rom_segment; */
  288. /* We only provide the ability to receive or transmit a single
  289. * packet at a time. This is a bootloader, not an OS.
  290. */
  291. undi_get_information->RxBufCt = 1;
  292. undi_get_information->TxBufCt = 1;
  293. undi_get_information->Status = PXENV_STATUS_SUCCESS;
  294. return PXENV_EXIT_SUCCESS;
  295. }
  296. /* PXENV_UNDI_GET_STATISTICS
  297. *
  298. * Status: working
  299. */
  300. PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
  301. *undi_get_statistics ) {
  302. DBG ( "PXENV_UNDI_GET_STATISTICS" );
  303. undi_get_statistics->XmtGoodFrames = pxe_netdev->stats.tx_count;
  304. undi_get_statistics->RcvGoodFrames = pxe_netdev->stats.rx_count;
  305. undi_get_statistics->RcvCRCErrors = 0;
  306. undi_get_statistics->RcvResourceErrors = 0;
  307. undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
  308. return PXENV_EXIT_SUCCESS;
  309. }
  310. /* PXENV_UNDI_CLEAR_STATISTICS
  311. *
  312. * Status: working
  313. */
  314. PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS
  315. *undi_clear_statistics ) {
  316. DBG ( "PXENV_UNDI_CLEAR_STATISTICS" );
  317. memset ( &pxe_netdev->stats, 0, sizeof ( pxe_netdev->stats ) );
  318. undi_clear_statistics->Status = PXENV_STATUS_SUCCESS;
  319. return PXENV_EXIT_SUCCESS;
  320. }
  321. /* PXENV_UNDI_INITIATE_DIAGS
  322. *
  323. * Status: won't implement (would require driver API changes for no
  324. * real benefit)
  325. */
  326. PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS
  327. *undi_initiate_diags ) {
  328. DBG ( "PXENV_UNDI_INITIATE_DIAGS" );
  329. undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
  330. return PXENV_EXIT_FAILURE;
  331. }
  332. /* PXENV_UNDI_FORCE_INTERRUPT
  333. *
  334. * Status: working
  335. */
  336. PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT
  337. *undi_force_interrupt ) {
  338. DBG ( "PXENV_UNDI_FORCE_INTERRUPT" );
  339. #if 0
  340. eth_irq ( FORCE );
  341. #endif
  342. undi_force_interrupt->Status = PXENV_STATUS_SUCCESS;
  343. return PXENV_EXIT_SUCCESS;
  344. }
  345. /* PXENV_UNDI_GET_MCAST_ADDRESS
  346. *
  347. * Status: stub (no PXE multicast support)
  348. */
  349. PXENV_EXIT_t
  350. pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS
  351. *undi_get_mcast_address ) {
  352. DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS" );
  353. undi_get_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
  354. return PXENV_EXIT_FAILURE;
  355. }
  356. /* PXENV_UNDI_GET_NIC_TYPE
  357. *
  358. * Status: working
  359. */
  360. PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
  361. *undi_get_nic_type ) {
  362. struct device *dev = pxe_netdev->dev;
  363. DBG ( "PXENV_UNDI_GET_NIC_TYPE" );
  364. memset ( &undi_get_nic_type->info, 0,
  365. sizeof ( undi_get_nic_type->info ) );
  366. switch ( dev->desc.bus_type ) {
  367. case BUS_TYPE_PCI: {
  368. struct pci_nic_info *info = &undi_get_nic_type->info.pci;
  369. undi_get_nic_type->NicType = PCI_NIC;
  370. info->Vendor_ID = dev->desc.vendor;
  371. info->Dev_ID = dev->desc.device;
  372. info->Base_Class = PCI_BASE_CLASS ( dev->desc.class );
  373. info->Sub_Class = PCI_SUB_CLASS ( dev->desc.class );
  374. info->Prog_Intf = PCI_PROG_INTF ( dev->desc.class );
  375. info->BusDevFunc = dev->desc.location;
  376. /* Cheat: remaining fields are probably unnecessary,
  377. * and would require adding extra code to pci.c.
  378. */
  379. undi_get_nic_type->info.pci.SubVendor_ID = 0xffff;
  380. undi_get_nic_type->info.pci.SubDevice_ID = 0xffff;
  381. break; }
  382. case BUS_TYPE_ISAPNP: {
  383. struct pnp_nic_info *info = &undi_get_nic_type->info.pnp;
  384. undi_get_nic_type->NicType = PnP_NIC;
  385. info->EISA_Dev_ID = ( ( dev->desc.vendor << 16 ) |
  386. dev->desc.device );
  387. info->CardSelNum = dev->desc.location;
  388. /* Cheat: remaining fields are probably unnecessary,
  389. * and would require adding extra code to isapnp.c.
  390. */
  391. break; }
  392. default:
  393. undi_get_nic_type->Status = PXENV_STATUS_FAILURE;
  394. return PXENV_EXIT_FAILURE;
  395. }
  396. undi_get_nic_type->Status = PXENV_STATUS_SUCCESS;
  397. return PXENV_EXIT_SUCCESS;
  398. }
  399. /* PXENV_UNDI_GET_IFACE_INFO
  400. *
  401. * Status: working
  402. */
  403. PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
  404. *undi_get_iface_info ) {
  405. DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
  406. /* Just hand back some info, doesn't really matter what it is.
  407. * Most PXE stacks seem to take this approach.
  408. */
  409. snprintf ( ( char * ) undi_get_iface_info->IfaceType,
  410. sizeof ( undi_get_iface_info->IfaceType ), "Etherboot" );
  411. undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
  412. undi_get_iface_info->ServiceFlags = 0;
  413. memset ( undi_get_iface_info->Reserved, 0,
  414. sizeof(undi_get_iface_info->Reserved) );
  415. undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
  416. return PXENV_EXIT_SUCCESS;
  417. }
  418. /* PXENV_UNDI_GET_STATE
  419. *
  420. * Status: impossible
  421. */
  422. PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
  423. *undi_get_state ) {
  424. DBG ( "PXENV_UNDI_GET_STATE" );
  425. undi_get_state->Status = PXENV_STATUS_UNSUPPORTED;
  426. return PXENV_EXIT_FAILURE;
  427. };
  428. /* PXENV_UNDI_ISR
  429. *
  430. * Status: working
  431. */
  432. PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
  433. struct io_buffer *iobuf;
  434. size_t len;
  435. DBG ( "PXENV_UNDI_ISR" );
  436. /* Just in case some idiot actually looks at these fields when
  437. * we weren't meant to fill them in...
  438. */
  439. undi_isr->BufferLength = 0;
  440. undi_isr->FrameLength = 0;
  441. undi_isr->FrameHeaderLength = 0;
  442. undi_isr->ProtType = 0;
  443. undi_isr->PktType = 0;
  444. switch ( undi_isr->FuncFlag ) {
  445. case PXENV_UNDI_ISR_IN_START :
  446. DBG ( " START" );
  447. /* Call poll(). This should acknowledge the device
  448. * interrupt and queue up any received packet.
  449. */
  450. if ( netdev_poll ( pxe_netdev, -1U ) ) {
  451. /* Packet waiting in queue */
  452. DBG ( " OURS" );
  453. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
  454. } else {
  455. DBG ( " NOT_OURS" );
  456. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_NOT_OURS;
  457. }
  458. break;
  459. case PXENV_UNDI_ISR_IN_PROCESS :
  460. case PXENV_UNDI_ISR_IN_GET_NEXT :
  461. DBG ( " PROCESS/GET_NEXT" );
  462. /* If we have not yet marked a TX as complete, and the
  463. * netdev TX queue is empty, report the TX completion.
  464. */
  465. if ( undi_tx_count && list_empty ( &pxe_netdev->tx_queue ) ) {
  466. undi_tx_count--;
  467. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_TRANSMIT;
  468. break;
  469. }
  470. /* Remove first packet from netdev RX queue */
  471. iobuf = netdev_rx_dequeue ( pxe_netdev );
  472. if ( ! iobuf ) {
  473. /* No more packets remaining */
  474. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
  475. break;
  476. }
  477. /* Copy packet to base memory buffer */
  478. len = iob_len ( iobuf );
  479. DBG ( " RECEIVE %zd", len );
  480. if ( len > sizeof ( basemem_packet ) ) {
  481. /* Should never happen */
  482. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
  483. undi_isr->Status = PXENV_STATUS_OUT_OF_RESOURCES;
  484. return PXENV_EXIT_FAILURE;
  485. }
  486. memcpy ( basemem_packet, iobuf->data, len );
  487. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
  488. undi_isr->BufferLength = len;
  489. undi_isr->FrameLength = len;
  490. undi_isr->FrameHeaderLength =
  491. pxe_netdev->ll_protocol->ll_header_len;
  492. undi_isr->Frame.segment = rm_ds;
  493. undi_isr->Frame.offset =
  494. ( ( unsigned ) & __from_data16 ( basemem_packet ) );
  495. /* Probably ought to fill in packet type */
  496. undi_isr->ProtType = P_UNKNOWN;
  497. undi_isr->PktType = XMT_DESTADDR;
  498. break;
  499. default :
  500. DBG ( " INVALID(%04x)", undi_isr->FuncFlag );
  501. /* Should never happen */
  502. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
  503. undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
  504. return PXENV_EXIT_FAILURE;
  505. }
  506. undi_isr->Status = PXENV_STATUS_SUCCESS;
  507. return PXENV_EXIT_SUCCESS;
  508. }