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

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