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 31KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080
  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., 51 Franklin Street, Fifth Floor, Boston, MA
  22. * 02110-1301, USA.
  23. */
  24. FILE_LICENCE ( GPL2_OR_LATER );
  25. #include <stdint.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <byteswap.h>
  29. #include <basemem_packet.h>
  30. #include <ipxe/netdevice.h>
  31. #include <ipxe/iobuf.h>
  32. #include <ipxe/device.h>
  33. #include <ipxe/pci.h>
  34. #include <ipxe/if_ether.h>
  35. #include <ipxe/ip.h>
  36. #include <ipxe/arp.h>
  37. #include <ipxe/rarp.h>
  38. #include <ipxe/profile.h>
  39. #include "pxe.h"
  40. /**
  41. * Count of outstanding transmitted packets
  42. *
  43. * This is incremented each time PXENV_UNDI_TRANSMIT is called, and
  44. * decremented each time that PXENV_UNDI_ISR is called with the TX
  45. * queue empty, stopping when the count reaches zero. This allows us
  46. * to provide a pessimistic approximation of TX completion events to
  47. * the PXE NBP simply by monitoring the netdev's TX queue.
  48. */
  49. static int undi_tx_count = 0;
  50. struct net_device *pxe_netdev = NULL;
  51. /** Transmit profiler */
  52. static struct profiler undi_tx_profiler __profiler = { .name = "undi.tx" };
  53. /**
  54. * Set network device as current PXE network device
  55. *
  56. * @v netdev Network device, or NULL
  57. */
  58. void pxe_set_netdev ( struct net_device *netdev ) {
  59. if ( pxe_netdev ) {
  60. netdev_rx_unfreeze ( pxe_netdev );
  61. netdev_put ( pxe_netdev );
  62. }
  63. pxe_netdev = NULL;
  64. if ( netdev )
  65. pxe_netdev = netdev_get ( netdev );
  66. }
  67. /**
  68. * Open PXE network device
  69. *
  70. * @ret rc Return status code
  71. */
  72. static int pxe_netdev_open ( void ) {
  73. int rc;
  74. assert ( pxe_netdev != NULL );
  75. if ( ( rc = netdev_open ( pxe_netdev ) ) != 0 )
  76. return rc;
  77. netdev_rx_freeze ( pxe_netdev );
  78. netdev_irq ( pxe_netdev, 1 );
  79. return 0;
  80. }
  81. /**
  82. * Close PXE network device
  83. *
  84. */
  85. static void pxe_netdev_close ( void ) {
  86. assert ( pxe_netdev != NULL );
  87. netdev_rx_unfreeze ( pxe_netdev );
  88. netdev_irq ( pxe_netdev, 0 );
  89. netdev_close ( pxe_netdev );
  90. undi_tx_count = 0;
  91. }
  92. /**
  93. * Dump multicast address list
  94. *
  95. * @v mcast PXE multicast address list
  96. */
  97. static void pxe_dump_mcast_list ( struct s_PXENV_UNDI_MCAST_ADDRESS *mcast ) {
  98. struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
  99. unsigned int i;
  100. for ( i = 0 ; i < mcast->MCastAddrCount ; i++ ) {
  101. DBGC ( &pxe_netdev, " %s",
  102. ll_protocol->ntoa ( mcast->McastAddr[i] ) );
  103. }
  104. }
  105. /* PXENV_UNDI_STARTUP
  106. *
  107. * Status: working
  108. */
  109. static PXENV_EXIT_t
  110. pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) {
  111. DBGC ( &pxe_netdev, "PXENV_UNDI_STARTUP\n" );
  112. /* Sanity check */
  113. if ( ! pxe_netdev ) {
  114. DBGC ( &pxe_netdev, "PXENV_UNDI_STARTUP called with no "
  115. "network device\n" );
  116. undi_startup->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  117. return PXENV_EXIT_FAILURE;
  118. }
  119. undi_startup->Status = PXENV_STATUS_SUCCESS;
  120. return PXENV_EXIT_SUCCESS;
  121. }
  122. /* PXENV_UNDI_CLEANUP
  123. *
  124. * Status: working
  125. */
  126. static PXENV_EXIT_t
  127. pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) {
  128. DBGC ( &pxe_netdev, "PXENV_UNDI_CLEANUP\n" );
  129. /* Sanity check */
  130. if ( ! pxe_netdev ) {
  131. DBGC ( &pxe_netdev, "PXENV_UNDI_CLEANUP called with no "
  132. "network device\n" );
  133. undi_cleanup->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  134. return PXENV_EXIT_FAILURE;
  135. }
  136. /* Close network device */
  137. pxe_netdev_close();
  138. undi_cleanup->Status = PXENV_STATUS_SUCCESS;
  139. return PXENV_EXIT_SUCCESS;
  140. }
  141. /* PXENV_UNDI_INITIALIZE
  142. *
  143. * Status: working
  144. */
  145. static PXENV_EXIT_t
  146. pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE *undi_initialize ) {
  147. DBGC ( &pxe_netdev, "PXENV_UNDI_INITIALIZE protocolini %08x\n",
  148. undi_initialize->ProtocolIni );
  149. /* Sanity check */
  150. if ( ! pxe_netdev ) {
  151. DBGC ( &pxe_netdev, "PXENV_UNDI_INITIALIZE called with no "
  152. "network device\n" );
  153. undi_initialize->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  154. return PXENV_EXIT_FAILURE;
  155. }
  156. undi_initialize->Status = PXENV_STATUS_SUCCESS;
  157. return PXENV_EXIT_SUCCESS;
  158. }
  159. /* PXENV_UNDI_RESET_ADAPTER
  160. *
  161. * Status: working
  162. */
  163. static PXENV_EXIT_t
  164. pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET *undi_reset_adapter ) {
  165. int rc;
  166. DBGC ( &pxe_netdev, "PXENV_UNDI_RESET_ADAPTER" );
  167. pxe_dump_mcast_list ( &undi_reset_adapter->R_Mcast_Buf );
  168. DBGC ( &pxe_netdev, "\n" );
  169. /* Sanity check */
  170. if ( ! pxe_netdev ) {
  171. DBGC ( &pxe_netdev, "PXENV_UNDI_RESET_ADAPTER called with no "
  172. "network device\n" );
  173. undi_reset_adapter->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  174. return PXENV_EXIT_FAILURE;
  175. }
  176. /* Close and reopen network device */
  177. pxe_netdev_close();
  178. if ( ( rc = pxe_netdev_open() ) != 0 ) {
  179. DBGC ( &pxe_netdev, "PXENV_UNDI_RESET_ADAPTER could not "
  180. "reopen %s: %s\n", pxe_netdev->name, strerror ( rc ) );
  181. undi_reset_adapter->Status = PXENV_STATUS ( rc );
  182. return PXENV_EXIT_FAILURE;
  183. }
  184. undi_reset_adapter->Status = PXENV_STATUS_SUCCESS;
  185. return PXENV_EXIT_SUCCESS;
  186. }
  187. /* PXENV_UNDI_SHUTDOWN
  188. *
  189. * Status: working
  190. */
  191. static PXENV_EXIT_t
  192. pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN *undi_shutdown ) {
  193. DBGC ( &pxe_netdev, "PXENV_UNDI_SHUTDOWN\n" );
  194. /* Sanity check */
  195. if ( ! pxe_netdev ) {
  196. DBGC ( &pxe_netdev, "PXENV_UNDI_SHUTDOWN called with no "
  197. "network device\n" );
  198. undi_shutdown->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  199. return PXENV_EXIT_FAILURE;
  200. }
  201. /* Close network device */
  202. pxe_netdev_close();
  203. undi_shutdown->Status = PXENV_STATUS_SUCCESS;
  204. return PXENV_EXIT_SUCCESS;
  205. }
  206. /* PXENV_UNDI_OPEN
  207. *
  208. * Status: working
  209. */
  210. static PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) {
  211. int rc;
  212. DBGC ( &pxe_netdev, "PXENV_UNDI_OPEN flag %04x filter %04x",
  213. undi_open->OpenFlag, undi_open->PktFilter );
  214. pxe_dump_mcast_list ( &undi_open->R_Mcast_Buf );
  215. DBGC ( &pxe_netdev, "\n" );
  216. /* Sanity check */
  217. if ( ! pxe_netdev ) {
  218. DBGC ( &pxe_netdev, "PXENV_UNDI_OPEN called with no "
  219. "network device\n" );
  220. undi_open->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  221. return PXENV_EXIT_FAILURE;
  222. }
  223. /* Open network device */
  224. if ( ( rc = pxe_netdev_open() ) != 0 ) {
  225. DBGC ( &pxe_netdev, "PXENV_UNDI_OPEN could not open %s: %s\n",
  226. pxe_netdev->name, strerror ( rc ) );
  227. undi_open->Status = PXENV_STATUS ( rc );
  228. return PXENV_EXIT_FAILURE;
  229. }
  230. undi_open->Status = PXENV_STATUS_SUCCESS;
  231. return PXENV_EXIT_SUCCESS;
  232. }
  233. /* PXENV_UNDI_CLOSE
  234. *
  235. * Status: working
  236. */
  237. static PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) {
  238. DBGC ( &pxe_netdev, "PXENV_UNDI_CLOSE\n" );
  239. /* Sanity check */
  240. if ( ! pxe_netdev ) {
  241. DBGC ( &pxe_netdev, "PXENV_UNDI_CLOSE called with no "
  242. "network device\n" );
  243. undi_close->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  244. return PXENV_EXIT_FAILURE;
  245. }
  246. /* Close network device */
  247. pxe_netdev_close();
  248. undi_close->Status = PXENV_STATUS_SUCCESS;
  249. return PXENV_EXIT_SUCCESS;
  250. }
  251. /* PXENV_UNDI_TRANSMIT
  252. *
  253. * Status: working
  254. */
  255. static PXENV_EXIT_t
  256. pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT *undi_transmit ) {
  257. struct s_PXENV_UNDI_TBD tbd;
  258. struct DataBlk *datablk;
  259. struct io_buffer *iobuf;
  260. struct net_protocol *net_protocol;
  261. struct ll_protocol *ll_protocol;
  262. char destaddr[MAX_LL_ADDR_LEN];
  263. const void *ll_dest;
  264. size_t len;
  265. unsigned int i;
  266. int rc;
  267. /* Start profiling */
  268. profile_start ( &undi_tx_profiler );
  269. /* Sanity check */
  270. if ( ! pxe_netdev ) {
  271. DBGC ( &pxe_netdev, "PXENV_UNDI_TRANSMIT called with no "
  272. "network device\n" );
  273. undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  274. return PXENV_EXIT_FAILURE;
  275. }
  276. DBGC2 ( &pxe_netdev, "PXENV_UNDI_TRANSMIT" );
  277. /* Forcibly enable interrupts and freeze receive queue
  278. * processing at this point, to work around callers that never
  279. * call PXENV_UNDI_OPEN before attempting to use the UNDI API.
  280. */
  281. if ( ! netdev_rx_frozen ( pxe_netdev ) ) {
  282. netdev_rx_freeze ( pxe_netdev );
  283. netdev_irq ( pxe_netdev, 1 );
  284. }
  285. /* Identify network-layer protocol */
  286. switch ( undi_transmit->Protocol ) {
  287. case P_IP: net_protocol = &ipv4_protocol; break;
  288. case P_ARP: net_protocol = &arp_protocol; break;
  289. case P_RARP: net_protocol = &rarp_protocol; break;
  290. case P_UNKNOWN:
  291. net_protocol = NULL;
  292. break;
  293. default:
  294. DBGC2 ( &pxe_netdev, " %02x invalid protocol\n",
  295. undi_transmit->Protocol );
  296. undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
  297. return PXENV_EXIT_FAILURE;
  298. }
  299. DBGC2 ( &pxe_netdev, " %s",
  300. ( net_protocol ? net_protocol->name : "RAW" ) );
  301. /* Calculate total packet length */
  302. copy_from_real ( &tbd, undi_transmit->TBD.segment,
  303. undi_transmit->TBD.offset, sizeof ( tbd ) );
  304. len = tbd.ImmedLength;
  305. DBGC2 ( &pxe_netdev, " %04x:%04x+%x", tbd.Xmit.segment, tbd.Xmit.offset,
  306. tbd.ImmedLength );
  307. for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
  308. datablk = &tbd.DataBlock[i];
  309. len += datablk->TDDataLen;
  310. DBGC2 ( &pxe_netdev, " %04x:%04x+%x",
  311. datablk->TDDataPtr.segment, datablk->TDDataPtr.offset,
  312. datablk->TDDataLen );
  313. }
  314. /* Allocate and fill I/O buffer */
  315. iobuf = alloc_iob ( MAX_LL_HEADER_LEN +
  316. ( ( len > IOB_ZLEN ) ? len : IOB_ZLEN ) );
  317. if ( ! iobuf ) {
  318. DBGC2 ( &pxe_netdev, " could not allocate iobuf\n" );
  319. undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES;
  320. return PXENV_EXIT_FAILURE;
  321. }
  322. iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
  323. copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment,
  324. tbd.Xmit.offset, tbd.ImmedLength );
  325. for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
  326. datablk = &tbd.DataBlock[i];
  327. copy_from_real ( iob_put ( iobuf, datablk->TDDataLen ),
  328. datablk->TDDataPtr.segment,
  329. datablk->TDDataPtr.offset,
  330. datablk->TDDataLen );
  331. }
  332. /* Add link-layer header, if required to do so */
  333. if ( net_protocol != NULL ) {
  334. /* Calculate destination address */
  335. ll_protocol = pxe_netdev->ll_protocol;
  336. if ( undi_transmit->XmitFlag == XMT_DESTADDR ) {
  337. copy_from_real ( destaddr,
  338. undi_transmit->DestAddr.segment,
  339. undi_transmit->DestAddr.offset,
  340. ll_protocol->ll_addr_len );
  341. ll_dest = destaddr;
  342. DBGC2 ( &pxe_netdev, " DEST %s",
  343. ll_protocol->ntoa ( ll_dest ) );
  344. } else {
  345. ll_dest = pxe_netdev->ll_broadcast;
  346. DBGC2 ( &pxe_netdev, " BCAST" );
  347. }
  348. /* Add link-layer header */
  349. if ( ( rc = ll_protocol->push ( pxe_netdev, iobuf, ll_dest,
  350. pxe_netdev->ll_addr,
  351. net_protocol->net_proto ))!=0){
  352. DBGC2 ( &pxe_netdev, " could not add link-layer "
  353. "header: %s\n", strerror ( rc ) );
  354. free_iob ( iobuf );
  355. undi_transmit->Status = PXENV_STATUS ( rc );
  356. return PXENV_EXIT_FAILURE;
  357. }
  358. }
  359. /* Flag transmission as in-progress. Do this before starting
  360. * to transmit the packet, because the ISR may trigger before
  361. * we return from netdev_tx().
  362. */
  363. undi_tx_count++;
  364. /* Transmit packet */
  365. DBGC2 ( &pxe_netdev, "\n" );
  366. if ( ( rc = netdev_tx ( pxe_netdev, iobuf ) ) != 0 ) {
  367. DBGC2 ( &pxe_netdev, "PXENV_UNDI_TRANSMIT could not transmit: "
  368. "%s\n", strerror ( rc ) );
  369. undi_tx_count--;
  370. undi_transmit->Status = PXENV_STATUS ( rc );
  371. return PXENV_EXIT_FAILURE;
  372. }
  373. profile_stop ( &undi_tx_profiler );
  374. undi_transmit->Status = PXENV_STATUS_SUCCESS;
  375. return PXENV_EXIT_SUCCESS;
  376. }
  377. /* PXENV_UNDI_SET_MCAST_ADDRESS
  378. *
  379. * Status: working (for NICs that support receive-all-multicast)
  380. */
  381. static PXENV_EXIT_t
  382. pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS
  383. *undi_set_mcast_address ) {
  384. DBGC ( &pxe_netdev, "PXENV_UNDI_SET_MCAST_ADDRESS" );
  385. pxe_dump_mcast_list ( &undi_set_mcast_address->R_Mcast_Buf );
  386. DBGC ( &pxe_netdev, "\n" );
  387. /* Sanity check */
  388. if ( ! pxe_netdev ) {
  389. DBGC ( &pxe_netdev, "PXENV_UNDI_SET_MCAST_ADDRESS called with "
  390. "no network device\n" );
  391. undi_set_mcast_address->Status =
  392. PXENV_STATUS_UNDI_INVALID_STATE;
  393. return PXENV_EXIT_FAILURE;
  394. }
  395. undi_set_mcast_address->Status = PXENV_STATUS_SUCCESS;
  396. return PXENV_EXIT_SUCCESS;
  397. }
  398. /* PXENV_UNDI_SET_STATION_ADDRESS
  399. *
  400. * Status: working
  401. */
  402. static PXENV_EXIT_t
  403. pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS
  404. *undi_set_station_address ) {
  405. struct ll_protocol *ll_protocol;
  406. /* Sanity check */
  407. if ( ! pxe_netdev ) {
  408. DBGC ( &pxe_netdev, "PXENV_UNDI_SET_STATION_ADDRESS called "
  409. "with no network device\n" );
  410. undi_set_station_address->Status =
  411. PXENV_STATUS_UNDI_INVALID_STATE;
  412. return PXENV_EXIT_FAILURE;
  413. }
  414. ll_protocol = pxe_netdev->ll_protocol;
  415. DBGC ( &pxe_netdev, "PXENV_UNDI_SET_STATION_ADDRESS %s",
  416. ll_protocol->ntoa ( undi_set_station_address->StationAddress ) );
  417. /* If adapter is open, the change will have no effect; return
  418. * an error
  419. */
  420. if ( netdev_is_open ( pxe_netdev ) ) {
  421. DBGC ( &pxe_netdev, " failed: netdev is open\n" );
  422. undi_set_station_address->Status =
  423. PXENV_STATUS_UNDI_INVALID_STATE;
  424. return PXENV_EXIT_FAILURE;
  425. }
  426. /* Update MAC address */
  427. memcpy ( pxe_netdev->ll_addr,
  428. &undi_set_station_address->StationAddress,
  429. ll_protocol->ll_addr_len );
  430. DBGC ( &pxe_netdev, "\n" );
  431. undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
  432. return PXENV_EXIT_SUCCESS;
  433. }
  434. /* PXENV_UNDI_SET_PACKET_FILTER
  435. *
  436. * Status: won't implement (would require driver API changes for no
  437. * real benefit)
  438. */
  439. static PXENV_EXIT_t
  440. pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER
  441. *undi_set_packet_filter ) {
  442. DBGC ( &pxe_netdev, "PXENV_UNDI_SET_PACKET_FILTER %02x\n",
  443. undi_set_packet_filter->filter );
  444. /* Sanity check */
  445. if ( ! pxe_netdev ) {
  446. DBGC ( &pxe_netdev, "PXENV_UNDI_SET_PACKET_FILTER called with "
  447. "no network device\n" );
  448. undi_set_packet_filter->Status =
  449. PXENV_STATUS_UNDI_INVALID_STATE;
  450. return PXENV_EXIT_FAILURE;
  451. }
  452. /* Pretend that we succeeded, otherwise the 3Com DOS UNDI
  453. * driver refuses to load. (We ignore the filter value in the
  454. * PXENV_UNDI_OPEN call anyway.)
  455. */
  456. undi_set_packet_filter->Status = PXENV_STATUS_SUCCESS;
  457. return PXENV_EXIT_SUCCESS;
  458. }
  459. /* PXENV_UNDI_GET_INFORMATION
  460. *
  461. * Status: working
  462. */
  463. static PXENV_EXIT_t
  464. pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
  465. *undi_get_information ) {
  466. struct device *dev;
  467. struct ll_protocol *ll_protocol;
  468. /* Sanity check */
  469. if ( ! pxe_netdev ) {
  470. DBGC ( &pxe_netdev, "PXENV_UNDI_GET_INFORMATION called with no "
  471. "network device\n" );
  472. undi_get_information->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  473. return PXENV_EXIT_FAILURE;
  474. }
  475. DBGC ( &pxe_netdev, "PXENV_UNDI_GET_INFORMATION" );
  476. /* Fill in information */
  477. dev = pxe_netdev->dev;
  478. ll_protocol = pxe_netdev->ll_protocol;
  479. undi_get_information->BaseIo = dev->desc.ioaddr;
  480. undi_get_information->IntNumber =
  481. ( netdev_irq_supported ( pxe_netdev ) ? dev->desc.irq : 0 );
  482. /* Cheat: assume all cards can cope with this */
  483. undi_get_information->MaxTranUnit = ETH_MAX_MTU;
  484. undi_get_information->HwType = ntohs ( ll_protocol->ll_proto );
  485. undi_get_information->HwAddrLen = ll_protocol->ll_addr_len;
  486. assert ( ll_protocol->ll_addr_len <=
  487. sizeof ( undi_get_information->CurrentNodeAddress ) );
  488. memcpy ( &undi_get_information->CurrentNodeAddress,
  489. pxe_netdev->ll_addr,
  490. sizeof ( undi_get_information->CurrentNodeAddress ) );
  491. ll_protocol->init_addr ( pxe_netdev->hw_addr,
  492. &undi_get_information->PermNodeAddress );
  493. undi_get_information->ROMAddress = 0;
  494. /* nic.rom_info->rom_segment; */
  495. /* We only provide the ability to receive or transmit a single
  496. * packet at a time. This is a bootloader, not an OS.
  497. */
  498. undi_get_information->RxBufCt = 1;
  499. undi_get_information->TxBufCt = 1;
  500. DBGC ( &pxe_netdev, " io %04x irq %d mtu %d %s %s\n",
  501. undi_get_information->BaseIo, undi_get_information->IntNumber,
  502. undi_get_information->MaxTranUnit, ll_protocol->name,
  503. ll_protocol->ntoa ( &undi_get_information->CurrentNodeAddress ));
  504. undi_get_information->Status = PXENV_STATUS_SUCCESS;
  505. return PXENV_EXIT_SUCCESS;
  506. }
  507. /* PXENV_UNDI_GET_STATISTICS
  508. *
  509. * Status: working
  510. */
  511. static PXENV_EXIT_t
  512. pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
  513. *undi_get_statistics ) {
  514. /* Sanity check */
  515. if ( ! pxe_netdev ) {
  516. DBGC ( &pxe_netdev, "PXENV_UNDI_GET_STATISTICS called with no "
  517. "network device\n" );
  518. undi_get_statistics->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  519. return PXENV_EXIT_FAILURE;
  520. }
  521. DBGC ( &pxe_netdev, "PXENV_UNDI_GET_STATISTICS" );
  522. /* Report statistics */
  523. undi_get_statistics->XmtGoodFrames = pxe_netdev->tx_stats.good;
  524. undi_get_statistics->RcvGoodFrames = pxe_netdev->rx_stats.good;
  525. undi_get_statistics->RcvCRCErrors = pxe_netdev->rx_stats.bad;
  526. undi_get_statistics->RcvResourceErrors = pxe_netdev->rx_stats.bad;
  527. DBGC ( &pxe_netdev, " txok %d rxok %d rxcrc %d rxrsrc %d\n",
  528. undi_get_statistics->XmtGoodFrames,
  529. undi_get_statistics->RcvGoodFrames,
  530. undi_get_statistics->RcvCRCErrors,
  531. undi_get_statistics->RcvResourceErrors );
  532. undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
  533. return PXENV_EXIT_SUCCESS;
  534. }
  535. /* PXENV_UNDI_CLEAR_STATISTICS
  536. *
  537. * Status: working
  538. */
  539. static PXENV_EXIT_t
  540. pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS
  541. *undi_clear_statistics ) {
  542. DBGC ( &pxe_netdev, "PXENV_UNDI_CLEAR_STATISTICS\n" );
  543. /* Sanity check */
  544. if ( ! pxe_netdev ) {
  545. DBGC ( &pxe_netdev, "PXENV_UNDI_CLEAR_STATISTICS called with "
  546. "no network device\n" );
  547. undi_clear_statistics->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  548. return PXENV_EXIT_FAILURE;
  549. }
  550. /* Clear statistics */
  551. memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) );
  552. memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) );
  553. undi_clear_statistics->Status = PXENV_STATUS_SUCCESS;
  554. return PXENV_EXIT_SUCCESS;
  555. }
  556. /* PXENV_UNDI_INITIATE_DIAGS
  557. *
  558. * Status: won't implement (would require driver API changes for no
  559. * real benefit)
  560. */
  561. static PXENV_EXIT_t
  562. pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS
  563. *undi_initiate_diags ) {
  564. DBGC ( &pxe_netdev, "PXENV_UNDI_INITIATE_DIAGS failed: unsupported\n" );
  565. /* Sanity check */
  566. if ( ! pxe_netdev ) {
  567. DBGC ( &pxe_netdev, "PXENV_UNDI_INITIATE_DIAGS called with no "
  568. "network device\n" );
  569. undi_initiate_diags->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  570. return PXENV_EXIT_FAILURE;
  571. }
  572. undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
  573. return PXENV_EXIT_FAILURE;
  574. }
  575. /* PXENV_UNDI_FORCE_INTERRUPT
  576. *
  577. * Status: won't implement (would require driver API changes for no
  578. * perceptible benefit)
  579. */
  580. static PXENV_EXIT_t
  581. pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT
  582. *undi_force_interrupt ) {
  583. DBGC ( &pxe_netdev,
  584. "PXENV_UNDI_FORCE_INTERRUPT failed: unsupported\n" );
  585. /* Sanity check */
  586. if ( ! pxe_netdev ) {
  587. DBGC ( &pxe_netdev, "PXENV_UNDI_FORCE_INTERRUPT called with no "
  588. "network device\n" );
  589. undi_force_interrupt->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  590. return PXENV_EXIT_FAILURE;
  591. }
  592. undi_force_interrupt->Status = PXENV_STATUS_UNSUPPORTED;
  593. return PXENV_EXIT_FAILURE;
  594. }
  595. /* PXENV_UNDI_GET_MCAST_ADDRESS
  596. *
  597. * Status: working
  598. */
  599. static PXENV_EXIT_t
  600. pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS
  601. *undi_get_mcast_address ) {
  602. struct ll_protocol *ll_protocol;
  603. struct in_addr ip = { .s_addr = undi_get_mcast_address->InetAddr };
  604. int rc;
  605. /* Sanity check */
  606. if ( ! pxe_netdev ) {
  607. DBGC ( &pxe_netdev, "PXENV_UNDI_GET_MCAST_ADDRESS called with "
  608. "no network device\n" );
  609. undi_get_mcast_address->Status =
  610. PXENV_STATUS_UNDI_INVALID_STATE;
  611. return PXENV_EXIT_FAILURE;
  612. }
  613. DBGC ( &pxe_netdev, "PXENV_UNDI_GET_MCAST_ADDRESS %s",
  614. inet_ntoa ( ip ) );
  615. /* Hash address using the network device's link-layer protocol */
  616. ll_protocol = pxe_netdev->ll_protocol;
  617. if ( ( rc = ll_protocol->mc_hash ( AF_INET, &ip,
  618. undi_get_mcast_address->MediaAddr ))!=0){
  619. DBGC ( &pxe_netdev, " failed: %s\n", strerror ( rc ) );
  620. undi_get_mcast_address->Status = PXENV_STATUS ( rc );
  621. return PXENV_EXIT_FAILURE;
  622. }
  623. DBGC ( &pxe_netdev, "=>%s\n",
  624. ll_protocol->ntoa ( undi_get_mcast_address->MediaAddr ) );
  625. undi_get_mcast_address->Status = PXENV_STATUS_SUCCESS;
  626. return PXENV_EXIT_SUCCESS;
  627. }
  628. /* PXENV_UNDI_GET_NIC_TYPE
  629. *
  630. * Status: working
  631. */
  632. static PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
  633. *undi_get_nic_type ) {
  634. struct device *dev;
  635. /* Sanity check */
  636. if ( ! pxe_netdev ) {
  637. DBGC ( &pxe_netdev, "PXENV_UNDI_GET_NIC_TYPE called with "
  638. "no network device\n" );
  639. undi_get_nic_type->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  640. return PXENV_EXIT_FAILURE;
  641. }
  642. DBGC ( &pxe_netdev, "PXENV_UNDI_GET_NIC_TYPE" );
  643. /* Fill in information */
  644. memset ( &undi_get_nic_type->info, 0,
  645. sizeof ( undi_get_nic_type->info ) );
  646. dev = pxe_netdev->dev;
  647. switch ( dev->desc.bus_type ) {
  648. case BUS_TYPE_PCI: {
  649. struct pci_nic_info *info = &undi_get_nic_type->info.pci;
  650. undi_get_nic_type->NicType = PCI_NIC;
  651. info->Vendor_ID = dev->desc.vendor;
  652. info->Dev_ID = dev->desc.device;
  653. info->Base_Class = PCI_BASE_CLASS ( dev->desc.class );
  654. info->Sub_Class = PCI_SUB_CLASS ( dev->desc.class );
  655. info->Prog_Intf = PCI_PROG_INTF ( dev->desc.class );
  656. info->BusDevFunc = dev->desc.location;
  657. /* Earlier versions of the PXE specification do not
  658. * have the SubVendor_ID and SubDevice_ID fields. It
  659. * is possible that some NBPs will not provide space
  660. * for them, and so we must not fill them in.
  661. */
  662. DBGC ( &pxe_netdev, " PCI %02x:%02x.%x %04x:%04x "
  663. "('%04x:%04x') %02x%02x%02x rev %02x\n",
  664. PCI_BUS ( info->BusDevFunc ),
  665. PCI_SLOT ( info->BusDevFunc ),
  666. PCI_FUNC ( info->BusDevFunc ), info->Vendor_ID,
  667. info->Dev_ID, info->SubVendor_ID, info->SubDevice_ID,
  668. info->Base_Class, info->Sub_Class, info->Prog_Intf,
  669. info->Rev );
  670. break; }
  671. case BUS_TYPE_ISAPNP: {
  672. struct pnp_nic_info *info = &undi_get_nic_type->info.pnp;
  673. undi_get_nic_type->NicType = PnP_NIC;
  674. info->EISA_Dev_ID = ( ( dev->desc.vendor << 16 ) |
  675. dev->desc.device );
  676. info->CardSelNum = dev->desc.location;
  677. /* Cheat: remaining fields are probably unnecessary,
  678. * and would require adding extra code to isapnp.c.
  679. */
  680. DBGC ( &pxe_netdev, " ISAPnP CSN %04x %08x %02x%02x%02x\n",
  681. info->CardSelNum, info->EISA_Dev_ID,
  682. info->Base_Class, info->Sub_Class, info->Prog_Intf );
  683. break; }
  684. default:
  685. DBGC ( &pxe_netdev, " failed: unknown bus type\n" );
  686. undi_get_nic_type->Status = PXENV_STATUS_FAILURE;
  687. return PXENV_EXIT_FAILURE;
  688. }
  689. undi_get_nic_type->Status = PXENV_STATUS_SUCCESS;
  690. return PXENV_EXIT_SUCCESS;
  691. }
  692. /* PXENV_UNDI_GET_IFACE_INFO
  693. *
  694. * Status: working
  695. */
  696. static PXENV_EXIT_t
  697. pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
  698. *undi_get_iface_info ) {
  699. /* Sanity check */
  700. if ( ! pxe_netdev ) {
  701. DBGC ( &pxe_netdev, "PXENV_UNDI_GET_IFACE_INFO called with "
  702. "no network device\n" );
  703. undi_get_iface_info->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  704. return PXENV_EXIT_FAILURE;
  705. }
  706. DBGC ( &pxe_netdev, "PXENV_UNDI_GET_IFACE_INFO" );
  707. /* Just hand back some info, doesn't really matter what it is.
  708. * Most PXE stacks seem to take this approach.
  709. */
  710. snprintf ( ( char * ) undi_get_iface_info->IfaceType,
  711. sizeof ( undi_get_iface_info->IfaceType ), "DIX+802.3" );
  712. undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
  713. undi_get_iface_info->ServiceFlags =
  714. ( SUPPORTED_BROADCAST | SUPPORTED_MULTICAST |
  715. SUPPORTED_SET_STATION_ADDRESS | SUPPORTED_RESET |
  716. SUPPORTED_OPEN_CLOSE );
  717. if ( netdev_irq_supported ( pxe_netdev ) )
  718. undi_get_iface_info->ServiceFlags |= SUPPORTED_IRQ;
  719. memset ( undi_get_iface_info->Reserved, 0,
  720. sizeof(undi_get_iface_info->Reserved) );
  721. DBGC ( &pxe_netdev, " %s %dbps flags %08x\n",
  722. undi_get_iface_info->IfaceType, undi_get_iface_info->LinkSpeed,
  723. undi_get_iface_info->ServiceFlags );
  724. undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
  725. return PXENV_EXIT_SUCCESS;
  726. }
  727. /* PXENV_UNDI_GET_STATE
  728. *
  729. * Status: impossible due to opcode collision
  730. */
  731. /* PXENV_UNDI_ISR
  732. *
  733. * Status: working
  734. */
  735. static PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
  736. struct io_buffer *iobuf;
  737. size_t len;
  738. struct ll_protocol *ll_protocol;
  739. const void *ll_dest;
  740. const void *ll_source;
  741. uint16_t net_proto;
  742. unsigned int flags;
  743. size_t ll_hlen;
  744. struct net_protocol *net_protocol;
  745. unsigned int prottype;
  746. int rc;
  747. /* Use a different debug colour, since UNDI ISR messages are
  748. * likely to be interspersed amongst other UNDI messages.
  749. */
  750. /* Sanity check */
  751. if ( ! pxe_netdev ) {
  752. DBGC ( &pxenv_undi_isr, "PXENV_UNDI_ISR called with "
  753. "no network device\n" );
  754. undi_isr->Status = PXENV_STATUS_UNDI_INVALID_STATE;
  755. return PXENV_EXIT_FAILURE;
  756. }
  757. DBGC2 ( &pxenv_undi_isr, "PXENV_UNDI_ISR" );
  758. /* Just in case some idiot actually looks at these fields when
  759. * we weren't meant to fill them in...
  760. */
  761. undi_isr->BufferLength = 0;
  762. undi_isr->FrameLength = 0;
  763. undi_isr->FrameHeaderLength = 0;
  764. undi_isr->ProtType = 0;
  765. undi_isr->PktType = 0;
  766. switch ( undi_isr->FuncFlag ) {
  767. case PXENV_UNDI_ISR_IN_START :
  768. DBGC2 ( &pxenv_undi_isr, " START" );
  769. /* Call poll(). This should acknowledge the device
  770. * interrupt and queue up any received packet.
  771. */
  772. net_poll();
  773. /* A 100% accurate determination of "OURS" vs "NOT
  774. * OURS" is difficult to achieve without invasive and
  775. * unpleasant changes to the driver model. We settle
  776. * for always returning "OURS" if interrupts are
  777. * currently enabled.
  778. *
  779. * Returning "NOT OURS" when interrupts are disabled
  780. * allows us to avoid a potential interrupt storm when
  781. * we are on a shared interrupt line; if we were to
  782. * always return "OURS" then the other device's ISR
  783. * may never be called.
  784. */
  785. if ( netdev_irq_enabled ( pxe_netdev ) ) {
  786. DBGC2 ( &pxenv_undi_isr, " OURS" );
  787. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
  788. } else {
  789. DBGC2 ( &pxenv_undi_isr, " NOT OURS" );
  790. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_NOT_OURS;
  791. }
  792. /* Disable interrupts */
  793. netdev_irq ( pxe_netdev, 0 );
  794. break;
  795. case PXENV_UNDI_ISR_IN_PROCESS :
  796. case PXENV_UNDI_ISR_IN_GET_NEXT :
  797. DBGC2 ( &pxenv_undi_isr, " %s",
  798. ( ( undi_isr->FuncFlag == PXENV_UNDI_ISR_IN_PROCESS ) ?
  799. "PROCESS" : "GET_NEXT" ) );
  800. /* Some dumb NBPs (e.g. emBoot's winBoot/i) never call
  801. * PXENV_UNDI_ISR with FuncFlag=PXENV_UNDI_ISR_START;
  802. * they just sit in a tight polling loop merrily
  803. * violating the PXE spec with repeated calls to
  804. * PXENV_UNDI_ISR_IN_PROCESS. Force extra polls to
  805. * cope with these out-of-spec clients.
  806. */
  807. net_poll();
  808. /* If we have not yet marked a TX as complete, and the
  809. * netdev TX queue is empty, report the TX completion.
  810. */
  811. if ( undi_tx_count && list_empty ( &pxe_netdev->tx_queue ) ) {
  812. DBGC2 ( &pxenv_undi_isr, " TXC" );
  813. undi_tx_count--;
  814. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_TRANSMIT;
  815. break;
  816. }
  817. /* Remove first packet from netdev RX queue */
  818. iobuf = netdev_rx_dequeue ( pxe_netdev );
  819. if ( ! iobuf ) {
  820. DBGC2 ( &pxenv_undi_isr, " DONE" );
  821. /* No more packets remaining */
  822. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
  823. /* Re-enable interrupts */
  824. netdev_irq ( pxe_netdev, 1 );
  825. break;
  826. }
  827. /* Copy packet to base memory buffer */
  828. len = iob_len ( iobuf );
  829. DBGC2 ( &pxenv_undi_isr, " RX" );
  830. if ( len > sizeof ( basemem_packet ) ) {
  831. /* Should never happen */
  832. DBGC2 ( &pxenv_undi_isr, " overlength (%zx)", len );
  833. len = sizeof ( basemem_packet );
  834. }
  835. memcpy ( basemem_packet, iobuf->data, len );
  836. /* Strip link-layer header */
  837. ll_protocol = pxe_netdev->ll_protocol;
  838. if ( ( rc = ll_protocol->pull ( pxe_netdev, iobuf, &ll_dest,
  839. &ll_source, &net_proto,
  840. &flags ) ) != 0 ) {
  841. /* Assume unknown net_proto and no ll_source */
  842. net_proto = 0;
  843. ll_source = NULL;
  844. }
  845. ll_hlen = ( len - iob_len ( iobuf ) );
  846. /* Determine network-layer protocol */
  847. switch ( net_proto ) {
  848. case htons ( ETH_P_IP ):
  849. net_protocol = &ipv4_protocol;
  850. prottype = P_IP;
  851. break;
  852. case htons ( ETH_P_ARP ):
  853. net_protocol = &arp_protocol;
  854. prottype = P_ARP;
  855. break;
  856. case htons ( ETH_P_RARP ):
  857. net_protocol = &rarp_protocol;
  858. prottype = P_RARP;
  859. break;
  860. default:
  861. net_protocol = NULL;
  862. prottype = P_UNKNOWN;
  863. break;
  864. }
  865. /* Fill in UNDI_ISR structure */
  866. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
  867. undi_isr->BufferLength = len;
  868. undi_isr->FrameLength = len;
  869. undi_isr->FrameHeaderLength = ll_hlen;
  870. undi_isr->Frame.segment = rm_ds;
  871. undi_isr->Frame.offset = __from_data16 ( basemem_packet );
  872. undi_isr->ProtType = prottype;
  873. if ( flags & LL_BROADCAST ) {
  874. undi_isr->PktType = P_BROADCAST;
  875. } else if ( flags & LL_MULTICAST ) {
  876. undi_isr->PktType = P_MULTICAST;
  877. } else {
  878. undi_isr->PktType = P_DIRECTED;
  879. }
  880. DBGC2 ( &pxenv_undi_isr, " %04x:%04x+%x(%x) %s hlen %d",
  881. undi_isr->Frame.segment, undi_isr->Frame.offset,
  882. undi_isr->BufferLength, undi_isr->FrameLength,
  883. ( net_protocol ? net_protocol->name : "RAW" ),
  884. undi_isr->FrameHeaderLength );
  885. /* Free packet */
  886. free_iob ( iobuf );
  887. break;
  888. default :
  889. DBGC2 ( &pxenv_undi_isr, " INVALID(%04x)\n",
  890. undi_isr->FuncFlag );
  891. /* Should never happen */
  892. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
  893. undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
  894. return PXENV_EXIT_FAILURE;
  895. }
  896. DBGC2 ( &pxenv_undi_isr, "\n" );
  897. undi_isr->Status = PXENV_STATUS_SUCCESS;
  898. return PXENV_EXIT_SUCCESS;
  899. }
  900. /** PXE UNDI API */
  901. struct pxe_api_call pxe_undi_api[] __pxe_api_call = {
  902. PXE_API_CALL ( PXENV_UNDI_STARTUP, pxenv_undi_startup,
  903. struct s_PXENV_UNDI_STARTUP ),
  904. PXE_API_CALL ( PXENV_UNDI_CLEANUP, pxenv_undi_cleanup,
  905. struct s_PXENV_UNDI_CLEANUP ),
  906. PXE_API_CALL ( PXENV_UNDI_INITIALIZE, pxenv_undi_initialize,
  907. struct s_PXENV_UNDI_INITIALIZE ),
  908. PXE_API_CALL ( PXENV_UNDI_RESET_ADAPTER, pxenv_undi_reset_adapter,
  909. struct s_PXENV_UNDI_RESET ),
  910. PXE_API_CALL ( PXENV_UNDI_SHUTDOWN, pxenv_undi_shutdown,
  911. struct s_PXENV_UNDI_SHUTDOWN ),
  912. PXE_API_CALL ( PXENV_UNDI_OPEN, pxenv_undi_open,
  913. struct s_PXENV_UNDI_OPEN ),
  914. PXE_API_CALL ( PXENV_UNDI_CLOSE, pxenv_undi_close,
  915. struct s_PXENV_UNDI_CLOSE ),
  916. PXE_API_CALL ( PXENV_UNDI_TRANSMIT, pxenv_undi_transmit,
  917. struct s_PXENV_UNDI_TRANSMIT ),
  918. PXE_API_CALL ( PXENV_UNDI_SET_MCAST_ADDRESS,
  919. pxenv_undi_set_mcast_address,
  920. struct s_PXENV_UNDI_SET_MCAST_ADDRESS ),
  921. PXE_API_CALL ( PXENV_UNDI_SET_STATION_ADDRESS,
  922. pxenv_undi_set_station_address,
  923. struct s_PXENV_UNDI_SET_STATION_ADDRESS ),
  924. PXE_API_CALL ( PXENV_UNDI_SET_PACKET_FILTER,
  925. pxenv_undi_set_packet_filter,
  926. struct s_PXENV_UNDI_SET_PACKET_FILTER ),
  927. PXE_API_CALL ( PXENV_UNDI_GET_INFORMATION, pxenv_undi_get_information,
  928. struct s_PXENV_UNDI_GET_INFORMATION ),
  929. PXE_API_CALL ( PXENV_UNDI_GET_STATISTICS, pxenv_undi_get_statistics,
  930. struct s_PXENV_UNDI_GET_STATISTICS ),
  931. PXE_API_CALL ( PXENV_UNDI_CLEAR_STATISTICS, pxenv_undi_clear_statistics,
  932. struct s_PXENV_UNDI_CLEAR_STATISTICS ),
  933. PXE_API_CALL ( PXENV_UNDI_INITIATE_DIAGS, pxenv_undi_initiate_diags,
  934. struct s_PXENV_UNDI_INITIATE_DIAGS ),
  935. PXE_API_CALL ( PXENV_UNDI_FORCE_INTERRUPT, pxenv_undi_force_interrupt,
  936. struct s_PXENV_UNDI_FORCE_INTERRUPT ),
  937. PXE_API_CALL ( PXENV_UNDI_GET_MCAST_ADDRESS,
  938. pxenv_undi_get_mcast_address,
  939. struct s_PXENV_UNDI_GET_MCAST_ADDRESS ),
  940. PXE_API_CALL ( PXENV_UNDI_GET_NIC_TYPE, pxenv_undi_get_nic_type,
  941. struct s_PXENV_UNDI_GET_NIC_TYPE ),
  942. PXE_API_CALL ( PXENV_UNDI_GET_IFACE_INFO, pxenv_undi_get_iface_info,
  943. struct s_PXENV_UNDI_GET_IFACE_INFO ),
  944. PXE_API_CALL ( PXENV_UNDI_ISR, pxenv_undi_isr,
  945. struct s_PXENV_UNDI_ISR ),
  946. };