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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. /** @file
  2. *
  3. * PXE UNDI API
  4. *
  5. */
  6. /*
  7. * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License as
  11. * published by the Free Software Foundation; either version 2 of the
  12. * License, or any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful, but
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER );
  24. #include <stdint.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <byteswap.h>
  28. #include <basemem_packet.h>
  29. #include <ipxe/netdevice.h>
  30. #include <ipxe/iobuf.h>
  31. #include <ipxe/device.h>
  32. #include <ipxe/pci.h>
  33. #include <ipxe/if_ether.h>
  34. #include <ipxe/ip.h>
  35. #include <ipxe/arp.h>
  36. #include <ipxe/rarp.h>
  37. #include "pxe.h"
  38. /**
  39. * Count of outstanding transmitted packets
  40. *
  41. * This is incremented each time PXENV_UNDI_TRANSMIT is called, and
  42. * decremented each time that PXENV_UNDI_ISR is called with the TX
  43. * queue empty, stopping when the count reaches zero. This allows us
  44. * to provide a pessimistic approximation of TX completion events to
  45. * the PXE NBP simply by monitoring the netdev's TX queue.
  46. */
  47. static int undi_tx_count = 0;
  48. struct net_device *pxe_netdev = NULL;
  49. /**
  50. * Set network device as current PXE network device
  51. *
  52. * @v netdev Network device, or NULL
  53. */
  54. void pxe_set_netdev ( struct net_device *netdev ) {
  55. if ( pxe_netdev )
  56. netdev_put ( pxe_netdev );
  57. pxe_netdev = NULL;
  58. if ( netdev )
  59. pxe_netdev = netdev_get ( netdev );
  60. }
  61. /**
  62. * Open PXE network device
  63. *
  64. * @ret rc Return status code
  65. */
  66. static int pxe_netdev_open ( void ) {
  67. int rc;
  68. if ( ( rc = netdev_open ( pxe_netdev ) ) != 0 )
  69. return rc;
  70. netdev_irq ( pxe_netdev, 1 );
  71. return 0;
  72. }
  73. /**
  74. * Close PXE network device
  75. *
  76. */
  77. static void pxe_netdev_close ( void ) {
  78. netdev_irq ( pxe_netdev, 0 );
  79. netdev_close ( pxe_netdev );
  80. undi_tx_count = 0;
  81. }
  82. /**
  83. * Dump multicast address list
  84. *
  85. * @v mcast PXE multicast address list
  86. */
  87. static void pxe_dump_mcast_list ( struct s_PXENV_UNDI_MCAST_ADDRESS *mcast ) {
  88. struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
  89. unsigned int i;
  90. for ( i = 0 ; i < mcast->MCastAddrCount ; i++ ) {
  91. DBG ( " %s", ll_protocol->ntoa ( mcast->McastAddr[i] ) );
  92. }
  93. }
  94. /* PXENV_UNDI_STARTUP
  95. *
  96. * Status: working
  97. */
  98. PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) {
  99. DBG ( "PXENV_UNDI_STARTUP\n" );
  100. undi_startup->Status = PXENV_STATUS_SUCCESS;
  101. return PXENV_EXIT_SUCCESS;
  102. }
  103. /* PXENV_UNDI_CLEANUP
  104. *
  105. * Status: working
  106. */
  107. PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) {
  108. DBG ( "PXENV_UNDI_CLEANUP\n" );
  109. pxe_netdev_close();
  110. undi_cleanup->Status = PXENV_STATUS_SUCCESS;
  111. return PXENV_EXIT_SUCCESS;
  112. }
  113. /* PXENV_UNDI_INITIALIZE
  114. *
  115. * Status: working
  116. */
  117. PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE
  118. *undi_initialize ) {
  119. DBG ( "PXENV_UNDI_INITIALIZE protocolini %08x\n",
  120. undi_initialize->ProtocolIni );
  121. undi_initialize->Status = PXENV_STATUS_SUCCESS;
  122. return PXENV_EXIT_SUCCESS;
  123. }
  124. /* PXENV_UNDI_RESET_ADAPTER
  125. *
  126. * Status: working
  127. */
  128. PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET
  129. *undi_reset_adapter ) {
  130. int rc;
  131. DBG ( "PXENV_UNDI_RESET_ADAPTER" );
  132. pxe_dump_mcast_list ( &undi_reset_adapter->R_Mcast_Buf );
  133. DBG ( "\n" );
  134. pxe_netdev_close();
  135. if ( ( rc = pxe_netdev_open() ) != 0 ) {
  136. DBG ( "PXENV_UNDI_RESET_ADAPTER could not reopen %s: %s\n",
  137. pxe_netdev->name, strerror ( rc ) );
  138. undi_reset_adapter->Status = PXENV_STATUS ( rc );
  139. return PXENV_EXIT_FAILURE;
  140. }
  141. undi_reset_adapter->Status = PXENV_STATUS_SUCCESS;
  142. return PXENV_EXIT_SUCCESS;
  143. }
  144. /* PXENV_UNDI_SHUTDOWN
  145. *
  146. * Status: working
  147. */
  148. PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN
  149. *undi_shutdown ) {
  150. DBG ( "PXENV_UNDI_SHUTDOWN\n" );
  151. pxe_netdev_close();
  152. undi_shutdown->Status = PXENV_STATUS_SUCCESS;
  153. return PXENV_EXIT_SUCCESS;
  154. }
  155. /* PXENV_UNDI_OPEN
  156. *
  157. * Status: working
  158. */
  159. PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) {
  160. int rc;
  161. DBG ( "PXENV_UNDI_OPEN flag %04x filter %04x",
  162. undi_open->OpenFlag, undi_open->PktFilter );
  163. pxe_dump_mcast_list ( &undi_open->R_Mcast_Buf );
  164. DBG ( "\n" );
  165. if ( ( rc = pxe_netdev_open() ) != 0 ) {
  166. DBG ( "PXENV_UNDI_OPEN could not open %s: %s\n",
  167. pxe_netdev->name, strerror ( rc ) );
  168. undi_open->Status = PXENV_STATUS ( rc );
  169. return PXENV_EXIT_FAILURE;
  170. }
  171. undi_open->Status = PXENV_STATUS_SUCCESS;
  172. return PXENV_EXIT_SUCCESS;
  173. }
  174. /* PXENV_UNDI_CLOSE
  175. *
  176. * Status: working
  177. */
  178. PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) {
  179. DBG ( "PXENV_UNDI_CLOSE\n" );
  180. pxe_netdev_close();
  181. undi_close->Status = PXENV_STATUS_SUCCESS;
  182. return PXENV_EXIT_SUCCESS;
  183. }
  184. /* PXENV_UNDI_TRANSMIT
  185. *
  186. * Status: working
  187. */
  188. PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
  189. *undi_transmit ) {
  190. struct s_PXENV_UNDI_TBD tbd;
  191. struct DataBlk *datablk;
  192. struct io_buffer *iobuf;
  193. struct net_protocol *net_protocol;
  194. struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
  195. char destaddr[MAX_LL_ADDR_LEN];
  196. const void *ll_dest;
  197. size_t ll_hlen = ll_protocol->ll_header_len;
  198. size_t len;
  199. unsigned int i;
  200. int rc;
  201. DBG2 ( "PXENV_UNDI_TRANSMIT" );
  202. /* Forcibly enable interrupts at this point, to work around
  203. * callers that never call PXENV_UNDI_OPEN before attempting
  204. * to use the UNDI API.
  205. */
  206. netdev_irq ( pxe_netdev, 1 );
  207. /* Identify network-layer protocol */
  208. switch ( undi_transmit->Protocol ) {
  209. case P_IP: net_protocol = &ipv4_protocol; break;
  210. case P_ARP: net_protocol = &arp_protocol; break;
  211. case P_RARP: net_protocol = &rarp_protocol; break;
  212. case P_UNKNOWN:
  213. net_protocol = NULL;
  214. ll_hlen = 0;
  215. break;
  216. default:
  217. DBG2 ( " %02x invalid protocol\n", undi_transmit->Protocol );
  218. undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
  219. return PXENV_EXIT_FAILURE;
  220. }
  221. DBG2 ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) );
  222. /* Calculate total packet length */
  223. copy_from_real ( &tbd, undi_transmit->TBD.segment,
  224. undi_transmit->TBD.offset, sizeof ( tbd ) );
  225. len = tbd.ImmedLength;
  226. DBG2 ( " %04x:%04x+%x", tbd.Xmit.segment, tbd.Xmit.offset,
  227. tbd.ImmedLength );
  228. for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
  229. datablk = &tbd.DataBlock[i];
  230. len += datablk->TDDataLen;
  231. DBG2 ( " %04x:%04x+%x", datablk->TDDataPtr.segment,
  232. datablk->TDDataPtr.offset, datablk->TDDataLen );
  233. }
  234. /* Allocate and fill I/O buffer */
  235. iobuf = alloc_iob ( ll_hlen + len );
  236. if ( ! iobuf ) {
  237. DBG2 ( " could not allocate iobuf\n" );
  238. undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES;
  239. return PXENV_EXIT_FAILURE;
  240. }
  241. iob_reserve ( iobuf, ll_hlen );
  242. copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment,
  243. tbd.Xmit.offset, tbd.ImmedLength );
  244. for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
  245. datablk = &tbd.DataBlock[i];
  246. copy_from_real ( iob_put ( iobuf, datablk->TDDataLen ),
  247. datablk->TDDataPtr.segment,
  248. datablk->TDDataPtr.offset,
  249. datablk->TDDataLen );
  250. }
  251. /* Add link-layer header, if required to do so */
  252. if ( net_protocol != NULL ) {
  253. /* Calculate destination address */
  254. if ( undi_transmit->XmitFlag == XMT_DESTADDR ) {
  255. copy_from_real ( destaddr,
  256. undi_transmit->DestAddr.segment,
  257. undi_transmit->DestAddr.offset,
  258. ll_protocol->ll_addr_len );
  259. ll_dest = destaddr;
  260. DBG2 ( " DEST %s", ll_protocol->ntoa ( ll_dest ) );
  261. } else {
  262. ll_dest = pxe_netdev->ll_broadcast;
  263. DBG2 ( " BCAST" );
  264. }
  265. /* Add link-layer header */
  266. if ( ( rc = ll_protocol->push ( pxe_netdev, iobuf, ll_dest,
  267. pxe_netdev->ll_addr,
  268. net_protocol->net_proto ))!=0){
  269. DBG2 ( " could not add link-layer header: %s\n",
  270. strerror ( rc ) );
  271. free_iob ( iobuf );
  272. undi_transmit->Status = PXENV_STATUS ( rc );
  273. return PXENV_EXIT_FAILURE;
  274. }
  275. }
  276. /* Flag transmission as in-progress. Do this before starting
  277. * to transmit the packet, because the ISR may trigger before
  278. * we return from netdev_tx().
  279. */
  280. undi_tx_count++;
  281. /* Transmit packet */
  282. DBG2 ( "\n" );
  283. if ( ( rc = netdev_tx ( pxe_netdev, iobuf ) ) != 0 ) {
  284. DBG2 ( "PXENV_UNDI_TRANSMIT could not transmit: %s\n",
  285. strerror ( rc ) );
  286. undi_tx_count--;
  287. undi_transmit->Status = PXENV_STATUS ( rc );
  288. return PXENV_EXIT_FAILURE;
  289. }
  290. undi_transmit->Status = PXENV_STATUS_SUCCESS;
  291. return PXENV_EXIT_SUCCESS;
  292. }
  293. /* PXENV_UNDI_SET_MCAST_ADDRESS
  294. *
  295. * Status: working (for NICs that support receive-all-multicast)
  296. */
  297. PXENV_EXIT_t
  298. pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS
  299. *undi_set_mcast_address ) {
  300. DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" );
  301. pxe_dump_mcast_list ( &undi_set_mcast_address->R_Mcast_Buf );
  302. DBG ( "\n" );
  303. undi_set_mcast_address->Status = PXENV_STATUS_SUCCESS;
  304. return PXENV_EXIT_SUCCESS;
  305. }
  306. /* PXENV_UNDI_SET_STATION_ADDRESS
  307. *
  308. * Status: working
  309. */
  310. PXENV_EXIT_t
  311. pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS
  312. *undi_set_station_address ) {
  313. struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
  314. DBG ( "PXENV_UNDI_SET_STATION_ADDRESS %s",
  315. ll_protocol->ntoa ( undi_set_station_address->StationAddress ) );
  316. /* If adapter is open, the change will have no effect; return
  317. * an error
  318. */
  319. if ( netdev_is_open ( pxe_netdev ) ) {
  320. DBG ( " failed: netdev is open\n" );
  321. undi_set_station_address->Status =
  322. PXENV_STATUS_UNDI_INVALID_STATE;
  323. return PXENV_EXIT_FAILURE;
  324. }
  325. /* Update MAC address */
  326. memcpy ( pxe_netdev->ll_addr,
  327. &undi_set_station_address->StationAddress,
  328. ll_protocol->ll_addr_len );
  329. DBG ( "\n" );
  330. undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
  331. return PXENV_EXIT_SUCCESS;
  332. }
  333. /* PXENV_UNDI_SET_PACKET_FILTER
  334. *
  335. * Status: won't implement (would require driver API changes for no
  336. * real benefit)
  337. */
  338. PXENV_EXIT_t
  339. pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER
  340. *undi_set_packet_filter ) {
  341. DBG ( "PXENV_UNDI_SET_PACKET_FILTER %02x\n",
  342. undi_set_packet_filter->filter );
  343. /* Pretend that we succeeded, otherwise the 3Com DOS UNDI
  344. * driver refuses to load. (We ignore the filter value in the
  345. * PXENV_UNDI_OPEN call anyway.)
  346. */
  347. undi_set_packet_filter->Status = PXENV_STATUS_SUCCESS;
  348. return PXENV_EXIT_SUCCESS;
  349. }
  350. /* PXENV_UNDI_GET_INFORMATION
  351. *
  352. * Status: working
  353. */
  354. PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
  355. *undi_get_information ) {
  356. struct device *dev = pxe_netdev->dev;
  357. struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
  358. size_t ll_addr_len = ll_protocol->ll_addr_len;
  359. DBG ( "PXENV_UNDI_GET_INFORMATION" );
  360. undi_get_information->BaseIo = dev->desc.ioaddr;
  361. undi_get_information->IntNumber = dev->desc.irq;
  362. /* Cheat: assume all cards can cope with this */
  363. undi_get_information->MaxTranUnit = ETH_MAX_MTU;
  364. undi_get_information->HwType = ntohs ( ll_protocol->ll_proto );
  365. undi_get_information->HwAddrLen = ll_addr_len;
  366. assert ( ll_addr_len <=
  367. sizeof ( undi_get_information->CurrentNodeAddress ) );
  368. memcpy ( &undi_get_information->CurrentNodeAddress,
  369. pxe_netdev->ll_addr,
  370. sizeof ( undi_get_information->CurrentNodeAddress ) );
  371. ll_protocol->init_addr ( pxe_netdev->hw_addr,
  372. &undi_get_information->PermNodeAddress );
  373. undi_get_information->ROMAddress = 0;
  374. /* nic.rom_info->rom_segment; */
  375. /* We only provide the ability to receive or transmit a single
  376. * packet at a time. This is a bootloader, not an OS.
  377. */
  378. undi_get_information->RxBufCt = 1;
  379. undi_get_information->TxBufCt = 1;
  380. DBG ( " io %04x irq %d mtu %d %s %s\n",
  381. undi_get_information->BaseIo, undi_get_information->IntNumber,
  382. undi_get_information->MaxTranUnit, ll_protocol->name,
  383. ll_protocol->ntoa ( &undi_get_information->CurrentNodeAddress ));
  384. undi_get_information->Status = PXENV_STATUS_SUCCESS;
  385. return PXENV_EXIT_SUCCESS;
  386. }
  387. /* PXENV_UNDI_GET_STATISTICS
  388. *
  389. * Status: working
  390. */
  391. PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
  392. *undi_get_statistics ) {
  393. DBG ( "PXENV_UNDI_GET_STATISTICS" );
  394. undi_get_statistics->XmtGoodFrames = pxe_netdev->tx_stats.good;
  395. undi_get_statistics->RcvGoodFrames = pxe_netdev->rx_stats.good;
  396. undi_get_statistics->RcvCRCErrors = pxe_netdev->rx_stats.bad;
  397. undi_get_statistics->RcvResourceErrors = pxe_netdev->rx_stats.bad;
  398. DBG ( " txok %d rxok %d rxcrc %d rxrsrc %d\n",
  399. undi_get_statistics->XmtGoodFrames,
  400. undi_get_statistics->RcvGoodFrames,
  401. undi_get_statistics->RcvCRCErrors,
  402. undi_get_statistics->RcvResourceErrors );
  403. undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
  404. return PXENV_EXIT_SUCCESS;
  405. }
  406. /* PXENV_UNDI_CLEAR_STATISTICS
  407. *
  408. * Status: working
  409. */
  410. PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS
  411. *undi_clear_statistics ) {
  412. DBG ( "PXENV_UNDI_CLEAR_STATISTICS\n" );
  413. memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) );
  414. memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) );
  415. undi_clear_statistics->Status = PXENV_STATUS_SUCCESS;
  416. return PXENV_EXIT_SUCCESS;
  417. }
  418. /* PXENV_UNDI_INITIATE_DIAGS
  419. *
  420. * Status: won't implement (would require driver API changes for no
  421. * real benefit)
  422. */
  423. PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS
  424. *undi_initiate_diags ) {
  425. DBG ( "PXENV_UNDI_INITIATE_DIAGS failed: unsupported\n" );
  426. undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
  427. return PXENV_EXIT_FAILURE;
  428. }
  429. /* PXENV_UNDI_FORCE_INTERRUPT
  430. *
  431. * Status: won't implement (would require driver API changes for no
  432. * perceptible benefit)
  433. */
  434. PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT
  435. *undi_force_interrupt ) {
  436. DBG ( "PXENV_UNDI_FORCE_INTERRUPT failed: unsupported\n" );
  437. undi_force_interrupt->Status = PXENV_STATUS_UNSUPPORTED;
  438. return PXENV_EXIT_FAILURE;
  439. }
  440. /* PXENV_UNDI_GET_MCAST_ADDRESS
  441. *
  442. * Status: working
  443. */
  444. PXENV_EXIT_t
  445. pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS
  446. *undi_get_mcast_address ) {
  447. struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
  448. struct in_addr ip = { .s_addr = undi_get_mcast_address->InetAddr };
  449. int rc;
  450. DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS %s", inet_ntoa ( ip ) );
  451. if ( ( rc = ll_protocol->mc_hash ( AF_INET, &ip,
  452. undi_get_mcast_address->MediaAddr ))!=0){
  453. DBG ( " failed: %s\n", strerror ( rc ) );
  454. undi_get_mcast_address->Status = PXENV_STATUS ( rc );
  455. return PXENV_EXIT_FAILURE;
  456. }
  457. DBG ( "=>%s\n",
  458. ll_protocol->ntoa ( undi_get_mcast_address->MediaAddr ) );
  459. undi_get_mcast_address->Status = PXENV_STATUS_SUCCESS;
  460. return PXENV_EXIT_SUCCESS;
  461. }
  462. /* PXENV_UNDI_GET_NIC_TYPE
  463. *
  464. * Status: working
  465. */
  466. PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
  467. *undi_get_nic_type ) {
  468. struct device *dev = pxe_netdev->dev;
  469. DBG ( "PXENV_UNDI_GET_NIC_TYPE" );
  470. memset ( &undi_get_nic_type->info, 0,
  471. sizeof ( undi_get_nic_type->info ) );
  472. switch ( dev->desc.bus_type ) {
  473. case BUS_TYPE_PCI: {
  474. struct pci_nic_info *info = &undi_get_nic_type->info.pci;
  475. undi_get_nic_type->NicType = PCI_NIC;
  476. info->Vendor_ID = dev->desc.vendor;
  477. info->Dev_ID = dev->desc.device;
  478. info->Base_Class = PCI_BASE_CLASS ( dev->desc.class );
  479. info->Sub_Class = PCI_SUB_CLASS ( dev->desc.class );
  480. info->Prog_Intf = PCI_PROG_INTF ( dev->desc.class );
  481. info->BusDevFunc = dev->desc.location;
  482. /* Cheat: remaining fields are probably unnecessary,
  483. * and would require adding extra code to pci.c.
  484. */
  485. undi_get_nic_type->info.pci.SubVendor_ID = 0xffff;
  486. undi_get_nic_type->info.pci.SubDevice_ID = 0xffff;
  487. DBG ( " PCI %02x:%02x.%x %04x:%04x (%04x:%04x) %02x%02x%02x "
  488. "rev %02x\n", PCI_BUS ( info->BusDevFunc ),
  489. PCI_SLOT ( info->BusDevFunc ),
  490. PCI_FUNC ( info->BusDevFunc ), info->Vendor_ID,
  491. info->Dev_ID, info->SubVendor_ID, info->SubDevice_ID,
  492. info->Base_Class, info->Sub_Class, info->Prog_Intf,
  493. info->Rev );
  494. break; }
  495. case BUS_TYPE_ISAPNP: {
  496. struct pnp_nic_info *info = &undi_get_nic_type->info.pnp;
  497. undi_get_nic_type->NicType = PnP_NIC;
  498. info->EISA_Dev_ID = ( ( dev->desc.vendor << 16 ) |
  499. dev->desc.device );
  500. info->CardSelNum = dev->desc.location;
  501. /* Cheat: remaining fields are probably unnecessary,
  502. * and would require adding extra code to isapnp.c.
  503. */
  504. DBG ( " ISAPnP CSN %04x %08x %02x%02x%02x\n",
  505. info->CardSelNum, info->EISA_Dev_ID,
  506. info->Base_Class, info->Sub_Class, info->Prog_Intf );
  507. break; }
  508. default:
  509. DBG ( " failed: unknown bus type\n" );
  510. undi_get_nic_type->Status = PXENV_STATUS_FAILURE;
  511. return PXENV_EXIT_FAILURE;
  512. }
  513. undi_get_nic_type->Status = PXENV_STATUS_SUCCESS;
  514. return PXENV_EXIT_SUCCESS;
  515. }
  516. /* PXENV_UNDI_GET_IFACE_INFO
  517. *
  518. * Status: working
  519. */
  520. PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
  521. *undi_get_iface_info ) {
  522. DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
  523. /* Just hand back some info, doesn't really matter what it is.
  524. * Most PXE stacks seem to take this approach.
  525. */
  526. snprintf ( ( char * ) undi_get_iface_info->IfaceType,
  527. sizeof ( undi_get_iface_info->IfaceType ), "DIX+802.3" );
  528. undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
  529. undi_get_iface_info->ServiceFlags =
  530. ( SUPPORTED_BROADCAST | SUPPORTED_MULTICAST |
  531. SUPPORTED_SET_STATION_ADDRESS | SUPPORTED_RESET |
  532. SUPPORTED_OPEN_CLOSE | SUPPORTED_IRQ );
  533. memset ( undi_get_iface_info->Reserved, 0,
  534. sizeof(undi_get_iface_info->Reserved) );
  535. DBG ( " %s %dbps flags %08x\n", undi_get_iface_info->IfaceType,
  536. undi_get_iface_info->LinkSpeed,
  537. undi_get_iface_info->ServiceFlags );
  538. undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
  539. return PXENV_EXIT_SUCCESS;
  540. }
  541. /* PXENV_UNDI_GET_STATE
  542. *
  543. * Status: impossible
  544. */
  545. PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
  546. *undi_get_state ) {
  547. DBG ( "PXENV_UNDI_GET_STATE failed: unsupported\n" );
  548. undi_get_state->Status = PXENV_STATUS_UNSUPPORTED;
  549. return PXENV_EXIT_FAILURE;
  550. };
  551. /* PXENV_UNDI_ISR
  552. *
  553. * Status: working
  554. */
  555. PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
  556. struct io_buffer *iobuf;
  557. size_t len;
  558. struct ll_protocol *ll_protocol;
  559. const void *ll_dest;
  560. const void *ll_source;
  561. uint16_t net_proto;
  562. size_t ll_hlen;
  563. struct net_protocol *net_protocol;
  564. unsigned int prottype;
  565. int rc;
  566. /* Use coloured debug, since UNDI ISR messages are likely to
  567. * be interspersed amongst other UNDI messages.
  568. */
  569. DBGC2 ( &pxenv_undi_isr, "PXENV_UNDI_ISR" );
  570. /* Just in case some idiot actually looks at these fields when
  571. * we weren't meant to fill them in...
  572. */
  573. undi_isr->BufferLength = 0;
  574. undi_isr->FrameLength = 0;
  575. undi_isr->FrameHeaderLength = 0;
  576. undi_isr->ProtType = 0;
  577. undi_isr->PktType = 0;
  578. switch ( undi_isr->FuncFlag ) {
  579. case PXENV_UNDI_ISR_IN_START :
  580. DBGC2 ( &pxenv_undi_isr, " START" );
  581. /* Call poll(). This should acknowledge the device
  582. * interrupt and queue up any received packet.
  583. */
  584. netdev_poll ( pxe_netdev );
  585. /* A 100% accurate determination of "OURS" vs "NOT
  586. * OURS" is difficult to achieve without invasive and
  587. * unpleasant changes to the driver model. We settle
  588. * for always returning "OURS" if interrupts are
  589. * currently enabled.
  590. *
  591. * Returning "NOT OURS" when interrupts are disabled
  592. * allows us to avoid a potential interrupt storm when
  593. * we are on a shared interrupt line; if we were to
  594. * always return "OURS" then the other device's ISR
  595. * may never be called.
  596. */
  597. if ( netdev_irq_enabled ( pxe_netdev ) ) {
  598. DBGC2 ( &pxenv_undi_isr, " OURS" );
  599. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
  600. } else {
  601. DBGC2 ( &pxenv_undi_isr, " NOT OURS" );
  602. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_NOT_OURS;
  603. }
  604. /* Disable interrupts */
  605. netdev_irq ( pxe_netdev, 0 );
  606. break;
  607. case PXENV_UNDI_ISR_IN_PROCESS :
  608. case PXENV_UNDI_ISR_IN_GET_NEXT :
  609. DBGC2 ( &pxenv_undi_isr, " %s",
  610. ( ( undi_isr->FuncFlag == PXENV_UNDI_ISR_IN_PROCESS ) ?
  611. "PROCESS" : "GET_NEXT" ) );
  612. /* Some dumb NBPs (e.g. emBoot's winBoot/i) never call
  613. * PXENV_UNDI_ISR with FuncFlag=PXENV_UNDI_ISR_START;
  614. * they just sit in a tight polling loop merrily
  615. * violating the PXE spec with repeated calls to
  616. * PXENV_UNDI_ISR_IN_PROCESS. Force extra polls to
  617. * cope with these out-of-spec clients.
  618. */
  619. netdev_poll ( pxe_netdev );
  620. /* If we have not yet marked a TX as complete, and the
  621. * netdev TX queue is empty, report the TX completion.
  622. */
  623. if ( undi_tx_count && list_empty ( &pxe_netdev->tx_queue ) ) {
  624. DBGC2 ( &pxenv_undi_isr, " TXC" );
  625. undi_tx_count--;
  626. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_TRANSMIT;
  627. break;
  628. }
  629. /* Remove first packet from netdev RX queue */
  630. iobuf = netdev_rx_dequeue ( pxe_netdev );
  631. if ( ! iobuf ) {
  632. DBGC2 ( &pxenv_undi_isr, " DONE" );
  633. /* No more packets remaining */
  634. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
  635. /* Re-enable interrupts */
  636. netdev_irq ( pxe_netdev, 1 );
  637. break;
  638. }
  639. /* Copy packet to base memory buffer */
  640. len = iob_len ( iobuf );
  641. DBGC2 ( &pxenv_undi_isr, " RX" );
  642. if ( len > sizeof ( basemem_packet ) ) {
  643. /* Should never happen */
  644. DBGC2 ( &pxenv_undi_isr, " overlength (%zx)", len );
  645. len = sizeof ( basemem_packet );
  646. }
  647. memcpy ( basemem_packet, iobuf->data, len );
  648. /* Strip link-layer header */
  649. ll_protocol = pxe_netdev->ll_protocol;
  650. if ( ( rc = ll_protocol->pull ( pxe_netdev, iobuf, &ll_dest,
  651. &ll_source, &net_proto )) !=0){
  652. /* Assume unknown net_proto and no ll_source */
  653. net_proto = 0;
  654. ll_source = NULL;
  655. }
  656. ll_hlen = ( len - iob_len ( iobuf ) );
  657. /* Determine network-layer protocol */
  658. switch ( net_proto ) {
  659. case htons ( ETH_P_IP ):
  660. net_protocol = &ipv4_protocol;
  661. prottype = P_IP;
  662. break;
  663. case htons ( ETH_P_ARP ):
  664. net_protocol = &arp_protocol;
  665. prottype = P_ARP;
  666. break;
  667. case htons ( ETH_P_RARP ):
  668. net_protocol = &rarp_protocol;
  669. prottype = P_RARP;
  670. break;
  671. default:
  672. net_protocol = NULL;
  673. prottype = P_UNKNOWN;
  674. break;
  675. }
  676. /* Fill in UNDI_ISR structure */
  677. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
  678. undi_isr->BufferLength = len;
  679. undi_isr->FrameLength = len;
  680. undi_isr->FrameHeaderLength = ll_hlen;
  681. undi_isr->Frame.segment = rm_ds;
  682. undi_isr->Frame.offset = __from_data16 ( basemem_packet );
  683. undi_isr->ProtType = prottype;
  684. undi_isr->PktType = XMT_DESTADDR;
  685. DBGC2 ( &pxenv_undi_isr, " %04x:%04x+%x(%x) %s hlen %d",
  686. undi_isr->Frame.segment, undi_isr->Frame.offset,
  687. undi_isr->BufferLength, undi_isr->FrameLength,
  688. ( net_protocol ? net_protocol->name : "RAW" ),
  689. undi_isr->FrameHeaderLength );
  690. /* Free packet */
  691. free_iob ( iobuf );
  692. break;
  693. default :
  694. DBGC2 ( &pxenv_undi_isr, " INVALID(%04x)\n",
  695. undi_isr->FuncFlag );
  696. /* Should never happen */
  697. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
  698. undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
  699. return PXENV_EXIT_FAILURE;
  700. }
  701. DBGC2 ( &pxenv_undi_isr, "\n" );
  702. undi_isr->Status = PXENV_STATUS_SUCCESS;
  703. return PXENV_EXIT_SUCCESS;
  704. }