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.

efi_snp.c 34KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  1. /*
  2. * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. */
  19. FILE_LICENCE ( GPL2_OR_LATER );
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <errno.h>
  23. #include <assert.h>
  24. #include <byteswap.h>
  25. #include <ipxe/netdevice.h>
  26. #include <ipxe/iobuf.h>
  27. #include <ipxe/in.h>
  28. #include <ipxe/version.h>
  29. #include <ipxe/efi/efi.h>
  30. #include <ipxe/efi/efi_driver.h>
  31. #include <ipxe/efi/efi_strings.h>
  32. #include <ipxe/efi/efi_snp.h>
  33. #include <usr/autoboot.h>
  34. /** EFI simple network protocol GUID */
  35. static EFI_GUID efi_simple_network_protocol_guid
  36. = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
  37. /** EFI device path protocol GUID */
  38. static EFI_GUID efi_device_path_protocol_guid
  39. = EFI_DEVICE_PATH_PROTOCOL_GUID;
  40. /** EFI network interface identifier GUID */
  41. static EFI_GUID efi_nii_protocol_guid
  42. = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID;
  43. /** EFI network interface identifier GUID (extra special version) */
  44. static EFI_GUID efi_nii31_protocol_guid = {
  45. /* At some point, it seems that someone decided to change the
  46. * GUID. Current EFI builds ignore the older GUID, older EFI
  47. * builds ignore the newer GUID, so we have to expose both.
  48. */
  49. 0x1ACED566, 0x76ED, 0x4218,
  50. { 0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 }
  51. };
  52. /** EFI component name protocol GUID */
  53. static EFI_GUID efi_component_name2_protocol_guid
  54. = EFI_COMPONENT_NAME2_PROTOCOL_GUID;
  55. /** EFI load file protocol GUID */
  56. static EFI_GUID efi_load_file_protocol_guid
  57. = EFI_LOAD_FILE_PROTOCOL_GUID;
  58. /** List of SNP devices */
  59. static LIST_HEAD ( efi_snp_devices );
  60. /** Network devices are currently claimed for use by iPXE */
  61. static int efi_snp_claimed;
  62. /**
  63. * Set EFI SNP mode state
  64. *
  65. * @v snp SNP interface
  66. */
  67. static void efi_snp_set_state ( struct efi_snp_device *snpdev ) {
  68. struct net_device *netdev = snpdev->netdev;
  69. EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
  70. /* Calculate state */
  71. if ( ! snpdev->started ) {
  72. /* Start() method not called; report as Stopped */
  73. mode->State = EfiSimpleNetworkStopped;
  74. } else if ( ! netdev_is_open ( netdev ) ) {
  75. /* Network device not opened; report as Started */
  76. mode->State = EfiSimpleNetworkStarted;
  77. } else if ( efi_snp_claimed ) {
  78. /* Network device opened but claimed for use by iPXE; report
  79. * as Started to inhibit receive polling.
  80. */
  81. mode->State = EfiSimpleNetworkStarted;
  82. } else {
  83. /* Network device opened and available for use via SNP; report
  84. * as Initialized.
  85. */
  86. mode->State = EfiSimpleNetworkInitialized;
  87. }
  88. }
  89. /**
  90. * Set EFI SNP mode based on iPXE net device parameters
  91. *
  92. * @v snp SNP interface
  93. */
  94. static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) {
  95. struct net_device *netdev = snpdev->netdev;
  96. EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
  97. struct ll_protocol *ll_protocol = netdev->ll_protocol;
  98. unsigned int ll_addr_len = ll_protocol->ll_addr_len;
  99. mode->HwAddressSize = ll_addr_len;
  100. mode->MediaHeaderSize = ll_protocol->ll_header_len;
  101. mode->MaxPacketSize = netdev->max_pkt_len;
  102. mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
  103. EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
  104. EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST );
  105. assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) );
  106. memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len );
  107. memcpy ( &mode->BroadcastAddress, netdev->ll_broadcast, ll_addr_len );
  108. ll_protocol->init_addr ( netdev->hw_addr, &mode->PermanentAddress );
  109. mode->IfType = ntohs ( ll_protocol->ll_proto );
  110. mode->MacAddressChangeable = TRUE;
  111. mode->MediaPresentSupported = TRUE;
  112. mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
  113. }
  114. /**
  115. * Poll net device and count received packets
  116. *
  117. * @v snpdev SNP device
  118. */
  119. static void efi_snp_poll ( struct efi_snp_device *snpdev ) {
  120. struct io_buffer *iobuf;
  121. unsigned int before = 0;
  122. unsigned int after = 0;
  123. unsigned int arrived;
  124. /* We have to report packet arrivals, and this is the easiest
  125. * way to fake it.
  126. */
  127. list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
  128. before++;
  129. netdev_poll ( snpdev->netdev );
  130. list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
  131. after++;
  132. arrived = ( after - before );
  133. snpdev->rx_count_interrupts += arrived;
  134. snpdev->rx_count_events += arrived;
  135. }
  136. /**
  137. * Change SNP state from "stopped" to "started"
  138. *
  139. * @v snp SNP interface
  140. * @ret efirc EFI status code
  141. */
  142. static EFI_STATUS EFIAPI
  143. efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
  144. struct efi_snp_device *snpdev =
  145. container_of ( snp, struct efi_snp_device, snp );
  146. DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev );
  147. /* Fail if net device is currently claimed for use by iPXE */
  148. if ( efi_snp_claimed )
  149. return EFI_NOT_READY;
  150. snpdev->started = 1;
  151. efi_snp_set_state ( snpdev );
  152. return 0;
  153. }
  154. /**
  155. * Change SNP state from "started" to "stopped"
  156. *
  157. * @v snp SNP interface
  158. * @ret efirc EFI status code
  159. */
  160. static EFI_STATUS EFIAPI
  161. efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
  162. struct efi_snp_device *snpdev =
  163. container_of ( snp, struct efi_snp_device, snp );
  164. DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev );
  165. /* Fail if net device is currently claimed for use by iPXE */
  166. if ( efi_snp_claimed )
  167. return EFI_NOT_READY;
  168. snpdev->started = 0;
  169. efi_snp_set_state ( snpdev );
  170. return 0;
  171. }
  172. /**
  173. * Open the network device
  174. *
  175. * @v snp SNP interface
  176. * @v extra_rx_bufsize Extra RX buffer size, in bytes
  177. * @v extra_tx_bufsize Extra TX buffer size, in bytes
  178. * @ret efirc EFI status code
  179. */
  180. static EFI_STATUS EFIAPI
  181. efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
  182. UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) {
  183. struct efi_snp_device *snpdev =
  184. container_of ( snp, struct efi_snp_device, snp );
  185. int rc;
  186. DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n",
  187. snpdev, ( ( unsigned long ) extra_rx_bufsize ),
  188. ( ( unsigned long ) extra_tx_bufsize ) );
  189. /* Fail if net device is currently claimed for use by iPXE */
  190. if ( efi_snp_claimed )
  191. return EFI_NOT_READY;
  192. if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
  193. DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n",
  194. snpdev, snpdev->netdev->name, strerror ( rc ) );
  195. return EFIRC ( rc );
  196. }
  197. efi_snp_set_state ( snpdev );
  198. return 0;
  199. }
  200. /**
  201. * Reset the network device
  202. *
  203. * @v snp SNP interface
  204. * @v ext_verify Extended verification required
  205. * @ret efirc EFI status code
  206. */
  207. static EFI_STATUS EFIAPI
  208. efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) {
  209. struct efi_snp_device *snpdev =
  210. container_of ( snp, struct efi_snp_device, snp );
  211. int rc;
  212. DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
  213. snpdev, ( ext_verify ? "with" : "without" ) );
  214. /* Fail if net device is currently claimed for use by iPXE */
  215. if ( efi_snp_claimed )
  216. return EFI_NOT_READY;
  217. netdev_close ( snpdev->netdev );
  218. efi_snp_set_state ( snpdev );
  219. if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
  220. DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n",
  221. snpdev, snpdev->netdev->name, strerror ( rc ) );
  222. return EFIRC ( rc );
  223. }
  224. efi_snp_set_state ( snpdev );
  225. return 0;
  226. }
  227. /**
  228. * Shut down the network device
  229. *
  230. * @v snp SNP interface
  231. * @ret efirc EFI status code
  232. */
  233. static EFI_STATUS EFIAPI
  234. efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
  235. struct efi_snp_device *snpdev =
  236. container_of ( snp, struct efi_snp_device, snp );
  237. DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
  238. /* Fail if net device is currently claimed for use by iPXE */
  239. if ( efi_snp_claimed )
  240. return EFI_NOT_READY;
  241. netdev_close ( snpdev->netdev );
  242. efi_snp_set_state ( snpdev );
  243. return 0;
  244. }
  245. /**
  246. * Manage receive filters
  247. *
  248. * @v snp SNP interface
  249. * @v enable Receive filters to enable
  250. * @v disable Receive filters to disable
  251. * @v mcast_reset Reset multicast filters
  252. * @v mcast_count Number of multicast filters
  253. * @v mcast Multicast filters
  254. * @ret efirc EFI status code
  255. */
  256. static EFI_STATUS EFIAPI
  257. efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable,
  258. UINT32 disable, BOOLEAN mcast_reset,
  259. UINTN mcast_count, EFI_MAC_ADDRESS *mcast ) {
  260. struct efi_snp_device *snpdev =
  261. container_of ( snp, struct efi_snp_device, snp );
  262. unsigned int i;
  263. DBGC2 ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08x&~%08x%s %ld mcast\n",
  264. snpdev, enable, disable, ( mcast_reset ? " reset" : "" ),
  265. ( ( unsigned long ) mcast_count ) );
  266. for ( i = 0 ; i < mcast_count ; i++ ) {
  267. DBGC2_HDA ( snpdev, i, &mcast[i],
  268. snpdev->netdev->ll_protocol->ll_addr_len );
  269. }
  270. /* Fail if net device is currently claimed for use by iPXE */
  271. if ( efi_snp_claimed )
  272. return EFI_NOT_READY;
  273. /* Lie through our teeth, otherwise MNP refuses to accept us */
  274. return 0;
  275. }
  276. /**
  277. * Set station address
  278. *
  279. * @v snp SNP interface
  280. * @v reset Reset to permanent address
  281. * @v new New station address
  282. * @ret efirc EFI status code
  283. */
  284. static EFI_STATUS EFIAPI
  285. efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
  286. EFI_MAC_ADDRESS *new ) {
  287. struct efi_snp_device *snpdev =
  288. container_of ( snp, struct efi_snp_device, snp );
  289. struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
  290. DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
  291. ( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
  292. /* Fail if net device is currently claimed for use by iPXE */
  293. if ( efi_snp_claimed )
  294. return EFI_NOT_READY;
  295. /* Set the MAC address */
  296. if ( reset )
  297. new = &snpdev->mode.PermanentAddress;
  298. memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len );
  299. /* MAC address changes take effect only on netdev_open() */
  300. if ( netdev_is_open ( snpdev->netdev ) ) {
  301. DBGC ( snpdev, "SNPDEV %p MAC address changed while net "
  302. "device open\n", snpdev );
  303. }
  304. return 0;
  305. }
  306. /**
  307. * Get (or reset) statistics
  308. *
  309. * @v snp SNP interface
  310. * @v reset Reset statistics
  311. * @v stats_len Size of statistics table
  312. * @v stats Statistics table
  313. * @ret efirc EFI status code
  314. */
  315. static EFI_STATUS EFIAPI
  316. efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
  317. UINTN *stats_len, EFI_NETWORK_STATISTICS *stats ) {
  318. struct efi_snp_device *snpdev =
  319. container_of ( snp, struct efi_snp_device, snp );
  320. EFI_NETWORK_STATISTICS stats_buf;
  321. DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
  322. ( reset ? " reset" : "" ) );
  323. /* Fail if net device is currently claimed for use by iPXE */
  324. if ( efi_snp_claimed )
  325. return EFI_NOT_READY;
  326. /* Gather statistics */
  327. memset ( &stats_buf, 0, sizeof ( stats_buf ) );
  328. stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good;
  329. stats_buf.TxDroppedFrames = snpdev->netdev->tx_stats.bad;
  330. stats_buf.TxTotalFrames = ( snpdev->netdev->tx_stats.good +
  331. snpdev->netdev->tx_stats.bad );
  332. stats_buf.RxGoodFrames = snpdev->netdev->rx_stats.good;
  333. stats_buf.RxDroppedFrames = snpdev->netdev->rx_stats.bad;
  334. stats_buf.RxTotalFrames = ( snpdev->netdev->rx_stats.good +
  335. snpdev->netdev->rx_stats.bad );
  336. if ( *stats_len > sizeof ( stats_buf ) )
  337. *stats_len = sizeof ( stats_buf );
  338. if ( stats )
  339. memcpy ( stats, &stats_buf, *stats_len );
  340. /* Reset statistics if requested to do so */
  341. if ( reset ) {
  342. memset ( &snpdev->netdev->tx_stats, 0,
  343. sizeof ( snpdev->netdev->tx_stats ) );
  344. memset ( &snpdev->netdev->rx_stats, 0,
  345. sizeof ( snpdev->netdev->rx_stats ) );
  346. }
  347. return 0;
  348. }
  349. /**
  350. * Convert multicast IP address to MAC address
  351. *
  352. * @v snp SNP interface
  353. * @v ipv6 Address is IPv6
  354. * @v ip IP address
  355. * @v mac MAC address
  356. * @ret efirc EFI status code
  357. */
  358. static EFI_STATUS EFIAPI
  359. efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6,
  360. EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac ) {
  361. struct efi_snp_device *snpdev =
  362. container_of ( snp, struct efi_snp_device, snp );
  363. struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
  364. const char *ip_str;
  365. int rc;
  366. ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ :
  367. inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
  368. DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
  369. /* Fail if net device is currently claimed for use by iPXE */
  370. if ( efi_snp_claimed )
  371. return EFI_NOT_READY;
  372. /* Try to hash the address */
  373. if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ),
  374. ip, mac ) ) != 0 ) {
  375. DBGC ( snpdev, "SNPDEV %p could not hash %s: %s\n",
  376. snpdev, ip_str, strerror ( rc ) );
  377. return EFIRC ( rc );
  378. }
  379. return 0;
  380. }
  381. /**
  382. * Read or write non-volatile storage
  383. *
  384. * @v snp SNP interface
  385. * @v read Operation is a read
  386. * @v offset Starting offset within NVRAM
  387. * @v len Length of data buffer
  388. * @v data Data buffer
  389. * @ret efirc EFI status code
  390. */
  391. static EFI_STATUS EFIAPI
  392. efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read,
  393. UINTN offset, UINTN len, VOID *data ) {
  394. struct efi_snp_device *snpdev =
  395. container_of ( snp, struct efi_snp_device, snp );
  396. DBGC2 ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev,
  397. ( read ? "read" : "write" ), ( ( unsigned long ) offset ),
  398. ( ( unsigned long ) len ) );
  399. if ( ! read )
  400. DBGC2_HDA ( snpdev, offset, data, len );
  401. /* Fail if net device is currently claimed for use by iPXE */
  402. if ( efi_snp_claimed )
  403. return EFI_NOT_READY;
  404. return EFI_UNSUPPORTED;
  405. }
  406. /**
  407. * Read interrupt status and TX recycled buffer status
  408. *
  409. * @v snp SNP interface
  410. * @v interrupts Interrupt status, or NULL
  411. * @v txbufs Recycled transmit buffer address, or NULL
  412. * @ret efirc EFI status code
  413. */
  414. static EFI_STATUS EFIAPI
  415. efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
  416. UINT32 *interrupts, VOID **txbufs ) {
  417. struct efi_snp_device *snpdev =
  418. container_of ( snp, struct efi_snp_device, snp );
  419. DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev );
  420. /* Fail if net device is currently claimed for use by iPXE */
  421. if ( efi_snp_claimed )
  422. return EFI_NOT_READY;
  423. /* Poll the network device */
  424. efi_snp_poll ( snpdev );
  425. /* Interrupt status. In practice, this seems to be used only
  426. * to detect TX completions.
  427. */
  428. if ( interrupts ) {
  429. *interrupts = 0;
  430. /* Report TX completions once queue is empty; this
  431. * avoids having to add hooks in the net device layer.
  432. */
  433. if ( snpdev->tx_count_interrupts &&
  434. list_empty ( &snpdev->netdev->tx_queue ) ) {
  435. *interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
  436. snpdev->tx_count_interrupts--;
  437. }
  438. /* Report RX */
  439. if ( snpdev->rx_count_interrupts ) {
  440. *interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
  441. snpdev->rx_count_interrupts--;
  442. }
  443. DBGC2 ( snpdev, " INTS:%02x", *interrupts );
  444. }
  445. /* TX completions. It would be possible to design a more
  446. * idiotic scheme for this, but it would be a challenge.
  447. * According to the UEFI header file, txbufs will be filled in
  448. * with a list of "recycled transmit buffers" (i.e. completed
  449. * TX buffers). Observant readers may care to note that
  450. * *txbufs is a void pointer. Precisely how a list of
  451. * completed transmit buffers is meant to be represented as an
  452. * array of voids is left as an exercise for the reader.
  453. *
  454. * The only users of this interface (MnpDxe/MnpIo.c and
  455. * PxeBcDxe/Bc.c within the EFI dev kit) both just poll until
  456. * seeing a non-NULL result return in txbufs. This is valid
  457. * provided that they do not ever attempt to transmit more
  458. * than one packet concurrently (and that TX never times out).
  459. */
  460. if ( txbufs ) {
  461. if ( snpdev->tx_count_txbufs &&
  462. list_empty ( &snpdev->netdev->tx_queue ) ) {
  463. *txbufs = "Which idiot designed this API?";
  464. snpdev->tx_count_txbufs--;
  465. } else {
  466. *txbufs = NULL;
  467. }
  468. DBGC2 ( snpdev, " TX:%s", ( *txbufs ? "some" : "none" ) );
  469. }
  470. DBGC2 ( snpdev, "\n" );
  471. return 0;
  472. }
  473. /**
  474. * Start packet transmission
  475. *
  476. * @v snp SNP interface
  477. * @v ll_header_len Link-layer header length, if to be filled in
  478. * @v len Length of data buffer
  479. * @v data Data buffer
  480. * @v ll_src Link-layer source address, if specified
  481. * @v ll_dest Link-layer destination address, if specified
  482. * @v net_proto Network-layer protocol (in host order)
  483. * @ret efirc EFI status code
  484. */
  485. static EFI_STATUS EFIAPI
  486. efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
  487. UINTN ll_header_len, UINTN len, VOID *data,
  488. EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
  489. UINT16 *net_proto ) {
  490. struct efi_snp_device *snpdev =
  491. container_of ( snp, struct efi_snp_device, snp );
  492. struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
  493. struct io_buffer *iobuf;
  494. size_t payload_len;
  495. int rc;
  496. DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data,
  497. ( ( unsigned long ) len ) );
  498. if ( ll_header_len ) {
  499. if ( ll_src ) {
  500. DBGC2 ( snpdev, " src %s",
  501. ll_protocol->ntoa ( ll_src ) );
  502. }
  503. if ( ll_dest ) {
  504. DBGC2 ( snpdev, " dest %s",
  505. ll_protocol->ntoa ( ll_dest ) );
  506. }
  507. if ( net_proto ) {
  508. DBGC2 ( snpdev, " proto %04x", *net_proto );
  509. }
  510. }
  511. DBGC2 ( snpdev, "\n" );
  512. /* Fail if net device is currently claimed for use by iPXE */
  513. if ( efi_snp_claimed )
  514. return EFI_NOT_READY;
  515. /* Sanity checks */
  516. if ( ll_header_len ) {
  517. if ( ll_header_len != ll_protocol->ll_header_len ) {
  518. DBGC ( snpdev, "SNPDEV %p TX invalid header length "
  519. "%ld\n", snpdev,
  520. ( ( unsigned long ) ll_header_len ) );
  521. rc = -EINVAL;
  522. goto err_sanity;
  523. }
  524. if ( len < ll_header_len ) {
  525. DBGC ( snpdev, "SNPDEV %p invalid packet length %ld\n",
  526. snpdev, ( ( unsigned long ) len ) );
  527. rc = -EINVAL;
  528. goto err_sanity;
  529. }
  530. if ( ! ll_dest ) {
  531. DBGC ( snpdev, "SNPDEV %p TX missing destination "
  532. "address\n", snpdev );
  533. rc = -EINVAL;
  534. goto err_sanity;
  535. }
  536. if ( ! net_proto ) {
  537. DBGC ( snpdev, "SNPDEV %p TX missing network "
  538. "protocol\n", snpdev );
  539. rc = -EINVAL;
  540. goto err_sanity;
  541. }
  542. if ( ! ll_src )
  543. ll_src = &snpdev->mode.CurrentAddress;
  544. }
  545. /* Allocate buffer */
  546. payload_len = ( len - ll_protocol->ll_header_len );
  547. iobuf = alloc_iob ( MAX_LL_HEADER_LEN + ( ( payload_len > IOB_ZLEN ) ?
  548. payload_len : IOB_ZLEN ) );
  549. if ( ! iobuf ) {
  550. DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte "
  551. "buffer\n", snpdev, ( ( unsigned long ) len ) );
  552. rc = -ENOMEM;
  553. goto err_alloc_iob;
  554. }
  555. iob_reserve ( iobuf, ( MAX_LL_HEADER_LEN -
  556. ll_protocol->ll_header_len ) );
  557. memcpy ( iob_put ( iobuf, len ), data, len );
  558. /* Create link-layer header, if specified */
  559. if ( ll_header_len ) {
  560. iob_pull ( iobuf, ll_protocol->ll_header_len );
  561. if ( ( rc = ll_protocol->push ( snpdev->netdev,
  562. iobuf, ll_dest, ll_src,
  563. htons ( *net_proto ) )) != 0 ){
  564. DBGC ( snpdev, "SNPDEV %p TX could not construct "
  565. "header: %s\n", snpdev, strerror ( rc ) );
  566. goto err_ll_push;
  567. }
  568. }
  569. /* Transmit packet */
  570. if ( ( rc = netdev_tx ( snpdev->netdev, iob_disown ( iobuf ) ) ) != 0){
  571. DBGC ( snpdev, "SNPDEV %p TX could not transmit: %s\n",
  572. snpdev, strerror ( rc ) );
  573. goto err_tx;
  574. }
  575. /* Record transmission as outstanding */
  576. snpdev->tx_count_interrupts++;
  577. snpdev->tx_count_txbufs++;
  578. return 0;
  579. err_tx:
  580. err_ll_push:
  581. free_iob ( iobuf );
  582. err_alloc_iob:
  583. err_sanity:
  584. return EFIRC ( rc );
  585. }
  586. /**
  587. * Receive packet
  588. *
  589. * @v snp SNP interface
  590. * @v ll_header_len Link-layer header length, if to be filled in
  591. * @v len Length of data buffer
  592. * @v data Data buffer
  593. * @v ll_src Link-layer source address, if specified
  594. * @v ll_dest Link-layer destination address, if specified
  595. * @v net_proto Network-layer protocol (in host order)
  596. * @ret efirc EFI status code
  597. */
  598. static EFI_STATUS EFIAPI
  599. efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
  600. UINTN *ll_header_len, UINTN *len, VOID *data,
  601. EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
  602. UINT16 *net_proto ) {
  603. struct efi_snp_device *snpdev =
  604. container_of ( snp, struct efi_snp_device, snp );
  605. struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
  606. struct io_buffer *iobuf;
  607. const void *iob_ll_dest;
  608. const void *iob_ll_src;
  609. uint16_t iob_net_proto;
  610. unsigned int iob_flags;
  611. int rc;
  612. DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data,
  613. ( ( unsigned long ) *len ) );
  614. /* Fail if net device is currently claimed for use by iPXE */
  615. if ( efi_snp_claimed )
  616. return EFI_NOT_READY;
  617. /* Poll the network device */
  618. efi_snp_poll ( snpdev );
  619. /* Dequeue a packet, if one is available */
  620. iobuf = netdev_rx_dequeue ( snpdev->netdev );
  621. if ( ! iobuf ) {
  622. DBGC2 ( snpdev, "\n" );
  623. rc = -EAGAIN;
  624. goto out_no_packet;
  625. }
  626. DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) );
  627. /* Return packet to caller */
  628. memcpy ( data, iobuf->data, iob_len ( iobuf ) );
  629. *len = iob_len ( iobuf );
  630. /* Attempt to decode link-layer header */
  631. if ( ( rc = ll_protocol->pull ( snpdev->netdev, iobuf, &iob_ll_dest,
  632. &iob_ll_src, &iob_net_proto,
  633. &iob_flags ) ) != 0 ) {
  634. DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n",
  635. snpdev, strerror ( rc ) );
  636. goto out_bad_ll_header;
  637. }
  638. /* Return link-layer header parameters to caller, if required */
  639. if ( ll_header_len )
  640. *ll_header_len = ll_protocol->ll_header_len;
  641. if ( ll_src )
  642. memcpy ( ll_src, iob_ll_src, ll_protocol->ll_addr_len );
  643. if ( ll_dest )
  644. memcpy ( ll_dest, iob_ll_dest, ll_protocol->ll_addr_len );
  645. if ( net_proto )
  646. *net_proto = ntohs ( iob_net_proto );
  647. rc = 0;
  648. out_bad_ll_header:
  649. free_iob ( iobuf );
  650. out_no_packet:
  651. return EFIRC ( rc );
  652. }
  653. /**
  654. * Poll event
  655. *
  656. * @v event Event
  657. * @v context Event context
  658. */
  659. static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event,
  660. VOID *context ) {
  661. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  662. struct efi_snp_device *snpdev = context;
  663. DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev );
  664. /* Do nothing unless the net device is open */
  665. if ( ! netdev_is_open ( snpdev->netdev ) )
  666. return;
  667. /* Do nothing if net device is currently claimed for use by iPXE */
  668. if ( efi_snp_claimed )
  669. return;
  670. /* Poll the network device */
  671. efi_snp_poll ( snpdev );
  672. /* Fire event if packets have been received */
  673. if ( snpdev->rx_count_events != 0 ) {
  674. DBGC2 ( snpdev, "SNPDEV %p firing WaitForPacket event\n",
  675. snpdev );
  676. bs->SignalEvent ( event );
  677. snpdev->rx_count_events--;
  678. }
  679. }
  680. /** SNP interface */
  681. static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = {
  682. .Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION,
  683. .Start = efi_snp_start,
  684. .Stop = efi_snp_stop,
  685. .Initialize = efi_snp_initialize,
  686. .Reset = efi_snp_reset,
  687. .Shutdown = efi_snp_shutdown,
  688. .ReceiveFilters = efi_snp_receive_filters,
  689. .StationAddress = efi_snp_station_address,
  690. .Statistics = efi_snp_statistics,
  691. .MCastIpToMac = efi_snp_mcast_ip_to_mac,
  692. .NvData = efi_snp_nvdata,
  693. .GetStatus = efi_snp_get_status,
  694. .Transmit = efi_snp_transmit,
  695. .Receive = efi_snp_receive,
  696. };
  697. /******************************************************************************
  698. *
  699. * Component name protocol
  700. *
  701. ******************************************************************************
  702. */
  703. /**
  704. * Look up driver name
  705. *
  706. * @v name2 Component name protocol
  707. * @v language Language to use
  708. * @v driver_name Driver name to fill in
  709. * @ret efirc EFI status code
  710. */
  711. static EFI_STATUS EFIAPI
  712. efi_snp_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *name2,
  713. CHAR8 *language __unused, CHAR16 **driver_name ) {
  714. struct efi_snp_device *snpdev =
  715. container_of ( name2, struct efi_snp_device, name2 );
  716. *driver_name = snpdev->driver_name;
  717. return 0;
  718. }
  719. /**
  720. * Look up controller name
  721. *
  722. * @v name2 Component name protocol
  723. * @v device Device
  724. * @v child Child device, or NULL
  725. * @v language Language to use
  726. * @v driver_name Device name to fill in
  727. * @ret efirc EFI status code
  728. */
  729. static EFI_STATUS EFIAPI
  730. efi_snp_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *name2,
  731. EFI_HANDLE device __unused,
  732. EFI_HANDLE child __unused,
  733. CHAR8 *language __unused,
  734. CHAR16 **controller_name ) {
  735. struct efi_snp_device *snpdev =
  736. container_of ( name2, struct efi_snp_device, name2 );
  737. *controller_name = snpdev->controller_name;
  738. return 0;
  739. }
  740. /******************************************************************************
  741. *
  742. * Load file protocol
  743. *
  744. ******************************************************************************
  745. */
  746. /**
  747. * Load file
  748. *
  749. * @v loadfile Load file protocol
  750. * @v path File path
  751. * @v booting Loading as part of a boot attempt
  752. * @ret efirc EFI status code
  753. */
  754. static EFI_STATUS EFIAPI
  755. efi_snp_load_file ( EFI_LOAD_FILE_PROTOCOL *load_file,
  756. EFI_DEVICE_PATH_PROTOCOL *path __unused,
  757. BOOLEAN booting, UINTN *len __unused,
  758. VOID *data __unused ) {
  759. struct efi_snp_device *snpdev =
  760. container_of ( load_file, struct efi_snp_device, load_file );
  761. struct net_device *netdev = snpdev->netdev;
  762. /* Fail unless this is a boot attempt */
  763. if ( ! booting ) {
  764. DBGC ( snpdev, "SNPDEV %p cannot load non-boot file\n",
  765. snpdev );
  766. return EFI_UNSUPPORTED;
  767. }
  768. /* Claim network devices for use by iPXE */
  769. efi_snp_claim();
  770. /* Boot from network device */
  771. ipxe ( netdev );
  772. /* Release network devices for use via SNP */
  773. efi_snp_release();
  774. /* Assume boot process was aborted */
  775. return EFI_ABORTED;
  776. }
  777. /** Load file protocol */
  778. static EFI_LOAD_FILE_PROTOCOL efi_snp_load_file_protocol = {
  779. .LoadFile = efi_snp_load_file,
  780. };
  781. /******************************************************************************
  782. *
  783. * iPXE network driver
  784. *
  785. ******************************************************************************
  786. */
  787. /**
  788. * Locate SNP device corresponding to network device
  789. *
  790. * @v netdev Network device
  791. * @ret snp SNP device, or NULL if not found
  792. */
  793. static struct efi_snp_device * efi_snp_demux ( struct net_device *netdev ) {
  794. struct efi_snp_device *snpdev;
  795. list_for_each_entry ( snpdev, &efi_snp_devices, list ) {
  796. if ( snpdev->netdev == netdev )
  797. return snpdev;
  798. }
  799. return NULL;
  800. }
  801. /**
  802. * Create SNP device
  803. *
  804. * @v netdev Network device
  805. * @ret rc Return status code
  806. */
  807. static int efi_snp_probe ( struct net_device *netdev ) {
  808. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  809. struct efi_device *efidev;
  810. struct efi_snp_device *snpdev;
  811. EFI_DEVICE_PATH_PROTOCOL *path_end;
  812. MAC_ADDR_DEVICE_PATH *macpath;
  813. size_t path_prefix_len = 0;
  814. EFI_STATUS efirc;
  815. int rc;
  816. /* Find parent EFI device */
  817. efidev = efidev_parent ( netdev->dev );
  818. if ( ! efidev ) {
  819. DBG ( "SNP skipping non-EFI device %s\n", netdev->name );
  820. rc = 0;
  821. goto err_no_efidev;
  822. }
  823. /* Calculate device path prefix length */
  824. path_end = efi_devpath_end ( efidev->path );
  825. path_prefix_len = ( ( ( void * ) path_end ) -
  826. ( ( void * ) efidev->path ) );
  827. /* Allocate the SNP device */
  828. snpdev = zalloc ( sizeof ( *snpdev ) + path_prefix_len +
  829. sizeof ( *macpath ) );
  830. if ( ! snpdev ) {
  831. rc = -ENOMEM;
  832. goto err_alloc_snp;
  833. }
  834. snpdev->netdev = netdev_get ( netdev );
  835. snpdev->efidev = efidev;
  836. /* Sanity check */
  837. if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
  838. DBGC ( snpdev, "SNPDEV %p cannot support link-layer address "
  839. "length %d for %s\n", snpdev,
  840. netdev->ll_protocol->ll_addr_len, netdev->name );
  841. rc = -ENOTSUP;
  842. goto err_ll_addr_len;
  843. }
  844. /* Populate the SNP structure */
  845. memcpy ( &snpdev->snp, &efi_snp_device_snp, sizeof ( snpdev->snp ) );
  846. snpdev->snp.Mode = &snpdev->mode;
  847. if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY,
  848. efi_snp_wait_for_packet, snpdev,
  849. &snpdev->snp.WaitForPacket ) ) != 0 ){
  850. rc = -EEFI ( efirc );
  851. DBGC ( snpdev, "SNPDEV %p could not create event: %s\n",
  852. snpdev, strerror ( rc ) );
  853. goto err_create_event;
  854. }
  855. /* Populate the SNP mode structure */
  856. snpdev->mode.State = EfiSimpleNetworkStopped;
  857. efi_snp_set_mode ( snpdev );
  858. /* Populate the NII structure */
  859. snpdev->nii.Revision =
  860. EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
  861. strncpy ( snpdev->nii.StringId, "iPXE",
  862. sizeof ( snpdev->nii.StringId ) );
  863. /* Populate the component name structure */
  864. efi_snprintf ( snpdev->driver_name,
  865. ( sizeof ( snpdev->driver_name ) /
  866. sizeof ( snpdev->driver_name[0] ) ),
  867. "%s %s", product_short_name, netdev->dev->driver_name );
  868. efi_snprintf ( snpdev->controller_name,
  869. ( sizeof ( snpdev->controller_name ) /
  870. sizeof ( snpdev->controller_name[0] ) ),
  871. "%s %s (%s, %s)", product_short_name,
  872. netdev->dev->driver_name, netdev->dev->name,
  873. netdev_addr ( netdev ) );
  874. snpdev->name2.GetDriverName = efi_snp_get_driver_name;
  875. snpdev->name2.GetControllerName = efi_snp_get_controller_name;
  876. snpdev->name2.SupportedLanguages = "en";
  877. /* Populate the load file protocol structure */
  878. memcpy ( &snpdev->load_file, &efi_snp_load_file_protocol,
  879. sizeof ( snpdev->load_file ) );
  880. /* Populate the device name */
  881. efi_snprintf ( snpdev->name, ( sizeof ( snpdev->name ) /
  882. sizeof ( snpdev->name[0] ) ),
  883. "%s", netdev->name );
  884. /* Populate the device path */
  885. memcpy ( &snpdev->path, efidev->path, path_prefix_len );
  886. macpath = ( ( ( void * ) &snpdev->path ) + path_prefix_len );
  887. path_end = ( ( void * ) ( macpath + 1 ) );
  888. memset ( macpath, 0, sizeof ( *macpath ) );
  889. macpath->Header.Type = MESSAGING_DEVICE_PATH;
  890. macpath->Header.SubType = MSG_MAC_ADDR_DP;
  891. macpath->Header.Length[0] = sizeof ( *macpath );
  892. memcpy ( &macpath->MacAddress, netdev->ll_addr,
  893. sizeof ( macpath->MacAddress ) );
  894. macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto );
  895. memset ( path_end, 0, sizeof ( *path_end ) );
  896. path_end->Type = END_DEVICE_PATH_TYPE;
  897. path_end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
  898. path_end->Length[0] = sizeof ( *path_end );
  899. /* Install the SNP */
  900. if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
  901. &snpdev->handle,
  902. &efi_simple_network_protocol_guid, &snpdev->snp,
  903. &efi_device_path_protocol_guid, &snpdev->path,
  904. &efi_nii_protocol_guid, &snpdev->nii,
  905. &efi_nii31_protocol_guid, &snpdev->nii,
  906. &efi_component_name2_protocol_guid, &snpdev->name2,
  907. &efi_load_file_protocol_guid, &snpdev->load_file,
  908. NULL ) ) != 0 ) {
  909. rc = -EEFI ( efirc );
  910. DBGC ( snpdev, "SNPDEV %p could not install protocols: "
  911. "%s\n", snpdev, strerror ( rc ) );
  912. goto err_install_protocol_interface;
  913. }
  914. /* Add as child of EFI parent device */
  915. if ( ( rc = efidev_child_add ( efidev, snpdev->handle ) ) != 0 ) {
  916. DBGC ( snpdev, "SNPDEV %p could not become child of %p %s: "
  917. "%s\n", snpdev, efidev->device,
  918. efi_devpath_text ( efidev->path ), strerror ( rc ) );
  919. goto err_efidev_child_add;
  920. }
  921. /* Install HII */
  922. if ( ( rc = efi_snp_hii_install ( snpdev ) ) != 0 ) {
  923. DBGC ( snpdev, "SNPDEV %p could not install HII: %s\n",
  924. snpdev, strerror ( rc ) );
  925. goto err_hii_install;
  926. }
  927. /* Add to list of SNP devices */
  928. list_add ( &snpdev->list, &efi_snp_devices );
  929. DBGC ( snpdev, "SNPDEV %p installed for %s as device %p %s\n",
  930. snpdev, netdev->name, snpdev->handle,
  931. efi_devpath_text ( &snpdev->path ) );
  932. return 0;
  933. efi_snp_hii_uninstall ( snpdev );
  934. err_hii_install:
  935. efidev_child_del ( efidev, snpdev->handle );
  936. err_efidev_child_add:
  937. bs->UninstallMultipleProtocolInterfaces (
  938. snpdev->handle,
  939. &efi_simple_network_protocol_guid, &snpdev->snp,
  940. &efi_device_path_protocol_guid, &snpdev->path,
  941. &efi_nii_protocol_guid, &snpdev->nii,
  942. &efi_nii31_protocol_guid, &snpdev->nii,
  943. &efi_component_name2_protocol_guid, &snpdev->name2,
  944. &efi_load_file_protocol_guid, &snpdev->load_file,
  945. NULL );
  946. err_install_protocol_interface:
  947. bs->CloseEvent ( snpdev->snp.WaitForPacket );
  948. err_create_event:
  949. err_ll_addr_len:
  950. netdev_put ( netdev );
  951. free ( snpdev );
  952. err_alloc_snp:
  953. err_no_efidev:
  954. return rc;
  955. }
  956. /**
  957. * Handle SNP device or link state change
  958. *
  959. * @v netdev Network device
  960. */
  961. static void efi_snp_notify ( struct net_device *netdev ) {
  962. struct efi_snp_device *snpdev;
  963. /* Locate SNP device */
  964. snpdev = efi_snp_demux ( netdev );
  965. if ( ! snpdev ) {
  966. DBG ( "SNP skipping non-SNP device %s\n", netdev->name );
  967. return;
  968. }
  969. /* Update link state */
  970. snpdev->mode.MediaPresent =
  971. ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
  972. DBGC ( snpdev, "SNPDEV %p link is %s\n", snpdev,
  973. ( snpdev->mode.MediaPresent ? "up" : "down" ) );
  974. /* Update mode state */
  975. efi_snp_set_state ( snpdev );
  976. }
  977. /**
  978. * Destroy SNP device
  979. *
  980. * @v netdev Network device
  981. */
  982. static void efi_snp_remove ( struct net_device *netdev ) {
  983. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  984. struct efi_snp_device *snpdev;
  985. /* Locate SNP device */
  986. snpdev = efi_snp_demux ( netdev );
  987. if ( ! snpdev ) {
  988. DBG ( "SNP skipping non-SNP device %s\n", netdev->name );
  989. return;
  990. }
  991. /* Uninstall the SNP */
  992. efi_snp_hii_uninstall ( snpdev );
  993. efidev_child_del ( snpdev->efidev, snpdev->handle );
  994. list_del ( &snpdev->list );
  995. bs->UninstallMultipleProtocolInterfaces (
  996. snpdev->handle,
  997. &efi_simple_network_protocol_guid, &snpdev->snp,
  998. &efi_device_path_protocol_guid, &snpdev->path,
  999. &efi_nii_protocol_guid, &snpdev->nii,
  1000. &efi_nii31_protocol_guid, &snpdev->nii,
  1001. &efi_component_name2_protocol_guid, &snpdev->name2,
  1002. &efi_load_file_protocol_guid, &snpdev->load_file,
  1003. NULL );
  1004. bs->CloseEvent ( snpdev->snp.WaitForPacket );
  1005. netdev_put ( snpdev->netdev );
  1006. free ( snpdev );
  1007. }
  1008. /** SNP driver */
  1009. struct net_driver efi_snp_driver __net_driver = {
  1010. .name = "SNP",
  1011. .probe = efi_snp_probe,
  1012. .notify = efi_snp_notify,
  1013. .remove = efi_snp_remove,
  1014. };
  1015. /**
  1016. * Find SNP device by EFI device handle
  1017. *
  1018. * @v handle EFI device handle
  1019. * @ret snpdev SNP device, or NULL
  1020. */
  1021. struct efi_snp_device * find_snpdev ( EFI_HANDLE handle ) {
  1022. struct efi_snp_device *snpdev;
  1023. list_for_each_entry ( snpdev, &efi_snp_devices, list ) {
  1024. if ( snpdev->handle == handle )
  1025. return snpdev;
  1026. }
  1027. return NULL;
  1028. }
  1029. /**
  1030. * Get most recently opened SNP device
  1031. *
  1032. * @ret snpdev Most recently opened SNP device, or NULL
  1033. */
  1034. struct efi_snp_device * last_opened_snpdev ( void ) {
  1035. struct net_device *netdev;
  1036. netdev = last_opened_netdev();
  1037. if ( ! netdev )
  1038. return NULL;
  1039. return efi_snp_demux ( netdev );
  1040. }
  1041. /**
  1042. * Set SNP claimed/released state
  1043. *
  1044. * @v claimed Network devices are claimed for use by iPXE
  1045. */
  1046. void efi_snp_set_claimed ( int claimed ) {
  1047. struct efi_snp_device *snpdev;
  1048. /* Claim SNP devices */
  1049. efi_snp_claimed = claimed;
  1050. /* Update SNP mode state for each interface */
  1051. list_for_each_entry ( snpdev, &efi_snp_devices, list )
  1052. efi_snp_set_state ( snpdev );
  1053. }