Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

efi_pxe.c 45KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687
  1. /*
  2. * Copyright (C) 2015 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 (at your option) 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. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <string.h>
  25. #include <errno.h>
  26. #include <ipxe/refcnt.h>
  27. #include <ipxe/list.h>
  28. #include <ipxe/netdevice.h>
  29. #include <ipxe/fakedhcp.h>
  30. #include <ipxe/process.h>
  31. #include <ipxe/uri.h>
  32. #include <ipxe/in.h>
  33. #include <ipxe/socket.h>
  34. #include <ipxe/tcpip.h>
  35. #include <ipxe/xferbuf.h>
  36. #include <ipxe/open.h>
  37. #include <ipxe/dhcppkt.h>
  38. #include <ipxe/udp.h>
  39. #include <ipxe/efi/efi.h>
  40. #include <ipxe/efi/efi_snp.h>
  41. #include <ipxe/efi/efi_pxe.h>
  42. #include <ipxe/efi/Protocol/PxeBaseCode.h>
  43. #include <ipxe/efi/Protocol/AppleNetBoot.h>
  44. #include <usr/ifmgmt.h>
  45. #include <config/general.h>
  46. /** @file
  47. *
  48. * EFI PXE base code protocol
  49. *
  50. */
  51. /* Downgrade user experience if configured to do so
  52. *
  53. * See comments in efi_snp.c
  54. */
  55. #ifdef EFI_DOWNGRADE_UX
  56. static EFI_GUID dummy_pxe_base_code_protocol_guid = {
  57. 0x70647523, 0x2320, 0x7477,
  58. { 0x66, 0x20, 0x23, 0x6d, 0x6f, 0x72, 0x6f, 0x6e }
  59. };
  60. #define efi_pxe_base_code_protocol_guid dummy_pxe_base_code_protocol_guid
  61. #endif
  62. /** A PXE base code */
  63. struct efi_pxe {
  64. /** Reference count */
  65. struct refcnt refcnt;
  66. /** Underlying network device */
  67. struct net_device *netdev;
  68. /** Name */
  69. const char *name;
  70. /** List of PXE base codes */
  71. struct list_head list;
  72. /** Installed handle */
  73. EFI_HANDLE handle;
  74. /** PXE base code protocol */
  75. EFI_PXE_BASE_CODE_PROTOCOL base;
  76. /** PXE base code mode */
  77. EFI_PXE_BASE_CODE_MODE mode;
  78. /** Apple NetBoot protocol */
  79. EFI_APPLE_NET_BOOT_PROTOCOL apple;
  80. /** TCP/IP network-layer protocol */
  81. struct tcpip_net_protocol *tcpip;
  82. /** Network-layer protocol */
  83. struct net_protocol *net;
  84. /** Data transfer buffer */
  85. struct xfer_buffer buf;
  86. /** (M)TFTP download interface */
  87. struct interface tftp;
  88. /** Block size (for TFTP) */
  89. size_t blksize;
  90. /** Overall return status */
  91. int rc;
  92. /** UDP interface */
  93. struct interface udp;
  94. /** List of received UDP packets */
  95. struct list_head queue;
  96. /** UDP interface closer process */
  97. struct process process;
  98. };
  99. /**
  100. * Free PXE base code
  101. *
  102. * @v refcnt Reference count
  103. */
  104. static void efi_pxe_free ( struct refcnt *refcnt ) {
  105. struct efi_pxe *pxe = container_of ( refcnt, struct efi_pxe, refcnt );
  106. netdev_put ( pxe->netdev );
  107. free ( pxe );
  108. }
  109. /** List of PXE base codes */
  110. static LIST_HEAD ( efi_pxes );
  111. /**
  112. * Locate PXE base code
  113. *
  114. * @v handle EFI handle
  115. * @ret pxe PXE base code, or NULL
  116. */
  117. static struct efi_pxe * efi_pxe_find ( EFI_HANDLE handle ) {
  118. struct efi_pxe *pxe;
  119. /* Locate base code */
  120. list_for_each_entry ( pxe, &efi_pxes, list ) {
  121. if ( pxe->handle == handle )
  122. return pxe;
  123. }
  124. return NULL;
  125. }
  126. /******************************************************************************
  127. *
  128. * IP addresses
  129. *
  130. ******************************************************************************
  131. */
  132. /**
  133. * An EFI socket address
  134. *
  135. */
  136. struct sockaddr_efi {
  137. /** Socket address family (part of struct @c sockaddr) */
  138. sa_family_t se_family;
  139. /** Flags (part of struct @c sockaddr_tcpip) */
  140. uint16_t se_flags;
  141. /** TCP/IP port (part of struct @c sockaddr_tcpip) */
  142. uint16_t se_port;
  143. /** Scope ID (part of struct @c sockaddr_tcpip)
  144. *
  145. * For link-local or multicast addresses, this is the network
  146. * device index.
  147. */
  148. uint16_t se_scope_id;
  149. /** IP address */
  150. EFI_IP_ADDRESS se_addr;
  151. /** Padding
  152. *
  153. * This ensures that a struct @c sockaddr_tcpip is large
  154. * enough to hold a socket address for any TCP/IP address
  155. * family.
  156. */
  157. char pad[ sizeof ( struct sockaddr ) -
  158. ( sizeof ( sa_family_t ) /* se_family */ +
  159. sizeof ( uint16_t ) /* se_flags */ +
  160. sizeof ( uint16_t ) /* se_port */ +
  161. sizeof ( uint16_t ) /* se_scope_id */ +
  162. sizeof ( EFI_IP_ADDRESS ) /* se_addr */ ) ];
  163. } __attribute__ (( packed, may_alias ));
  164. /**
  165. * Populate socket address from EFI IP address
  166. *
  167. * @v pxe PXE base code
  168. * @v ip EFI IP address
  169. * @v sa Socket address to fill in
  170. */
  171. static void efi_pxe_ip_sockaddr ( struct efi_pxe *pxe, EFI_IP_ADDRESS *ip,
  172. struct sockaddr *sa ) {
  173. union {
  174. struct sockaddr sa;
  175. struct sockaddr_efi se;
  176. } *sockaddr = container_of ( sa, typeof ( *sockaddr ), sa );
  177. /* Initialise socket address */
  178. memset ( sockaddr, 0, sizeof ( *sockaddr ) );
  179. sockaddr->sa.sa_family = pxe->tcpip->sa_family;
  180. memcpy ( &sockaddr->se.se_addr, ip, pxe->net->net_addr_len );
  181. sockaddr->se.se_scope_id = pxe->netdev->index;
  182. }
  183. /**
  184. * Transcribe EFI IP address (for debugging)
  185. *
  186. * @v pxe PXE base code
  187. * @v ip EFI IP address
  188. * @ret text Transcribed IP address
  189. */
  190. static const char * efi_pxe_ip_ntoa ( struct efi_pxe *pxe,
  191. EFI_IP_ADDRESS *ip ) {
  192. return pxe->net->ntoa ( ip );
  193. }
  194. /**
  195. * Populate local IP address
  196. *
  197. * @v pxe PXE base code
  198. * @ret rc Return status code
  199. */
  200. static int efi_pxe_ip ( struct efi_pxe *pxe ) {
  201. EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
  202. struct in_addr address;
  203. struct in_addr netmask;
  204. /* It's unclear which of the potentially many IPv6 addresses
  205. * is supposed to be used.
  206. */
  207. if ( mode->UsingIpv6 )
  208. return -ENOTSUP;
  209. /* Fetch IP address and subnet mask */
  210. fetch_ipv4_setting ( netdev_settings ( pxe->netdev ), &ip_setting,
  211. &address );
  212. fetch_ipv4_setting ( netdev_settings ( pxe->netdev ), &netmask_setting,
  213. &netmask );
  214. /* Populate IP address and subnet mask */
  215. memset ( &mode->StationIp, 0, sizeof ( mode->StationIp ) );
  216. memcpy ( &mode->StationIp, &address, sizeof ( address ) );
  217. memset ( &mode->SubnetMask, 0, sizeof ( mode->SubnetMask ) );
  218. memcpy ( &mode->SubnetMask, &netmask, sizeof ( netmask ) );
  219. return 0;
  220. }
  221. /**
  222. * Check if IP address matches filter
  223. *
  224. * @v pxe PXE base code
  225. * @v ip EFI IP address
  226. * @ret is_match IP address matches filter
  227. */
  228. static int efi_pxe_ip_filter ( struct efi_pxe *pxe, EFI_IP_ADDRESS *ip ) {
  229. EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
  230. EFI_PXE_BASE_CODE_IP_FILTER *filter = &mode->IpFilter;
  231. uint8_t filters = filter->Filters;
  232. union {
  233. EFI_IP_ADDRESS ip;
  234. struct in_addr in;
  235. struct in6_addr in6;
  236. } *u = container_of ( ip, typeof ( *u ), ip );
  237. size_t addr_len = pxe->net->net_addr_len;
  238. unsigned int i;
  239. /* Match everything, if applicable */
  240. if ( filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS )
  241. return 1;
  242. /* Match all multicasts, if applicable */
  243. if ( filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST ) {
  244. if ( mode->UsingIpv6 ) {
  245. if ( IN6_IS_ADDR_MULTICAST ( &u->in6 ) )
  246. return 1;
  247. } else {
  248. if ( IN_IS_MULTICAST ( u->in.s_addr ) )
  249. return 1;
  250. }
  251. }
  252. /* Match IPv4 broadcasts, if applicable */
  253. if ( filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST ) {
  254. if ( ( ! mode->UsingIpv6 ) &&
  255. ( u->in.s_addr == INADDR_BROADCAST ) )
  256. return 1;
  257. }
  258. /* Match station address, if applicable */
  259. if ( filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP ) {
  260. if ( memcmp ( ip, &mode->StationIp, addr_len ) == 0 )
  261. return 1;
  262. }
  263. /* Match explicit addresses, if applicable */
  264. for ( i = 0 ; i < filter->IpCnt ; i++ ) {
  265. if ( memcmp ( ip, &filter->IpList[i], addr_len ) == 0 )
  266. return 1;
  267. }
  268. return 0;
  269. }
  270. /******************************************************************************
  271. *
  272. * Data transfer buffer
  273. *
  274. ******************************************************************************
  275. */
  276. /**
  277. * Reallocate PXE data transfer buffer
  278. *
  279. * @v xferbuf Data transfer buffer
  280. * @v len New length (or zero to free buffer)
  281. * @ret rc Return status code
  282. */
  283. static int efi_pxe_buf_realloc ( struct xfer_buffer *xferbuf __unused,
  284. size_t len __unused ) {
  285. /* Can never reallocate: return EFI_BUFFER_TOO_SMALL */
  286. return -ERANGE;
  287. }
  288. /**
  289. * Write data to PXE data transfer buffer
  290. *
  291. * @v xferbuf Data transfer buffer
  292. * @v offset Starting offset
  293. * @v data Data to copy
  294. * @v len Length of data
  295. */
  296. static void efi_pxe_buf_write ( struct xfer_buffer *xferbuf, size_t offset,
  297. const void *data, size_t len ) {
  298. /* Copy data to buffer */
  299. memcpy ( ( xferbuf->data + offset ), data, len );
  300. }
  301. /** PXE data transfer buffer operations */
  302. static struct xfer_buffer_operations efi_pxe_buf_operations = {
  303. .realloc = efi_pxe_buf_realloc,
  304. .write = efi_pxe_buf_write,
  305. };
  306. /******************************************************************************
  307. *
  308. * (M)TFTP download interface
  309. *
  310. ******************************************************************************
  311. */
  312. /**
  313. * Close PXE (M)TFTP download interface
  314. *
  315. * @v pxe PXE base code
  316. * @v rc Reason for close
  317. */
  318. static void efi_pxe_tftp_close ( struct efi_pxe *pxe, int rc ) {
  319. /* Restart interface */
  320. intf_restart ( &pxe->tftp, rc );
  321. /* Record overall status */
  322. pxe->rc = rc;
  323. }
  324. /**
  325. * Check PXE (M)TFTP download flow control window
  326. *
  327. * @v pxe PXE base code
  328. * @ret len Length of window
  329. */
  330. static size_t efi_pxe_tftp_window ( struct efi_pxe *pxe ) {
  331. /* Return requested blocksize */
  332. return pxe->blksize;
  333. }
  334. /**
  335. * Receive new PXE (M)TFTP download data
  336. *
  337. * @v pxe PXE base code
  338. * @v iobuf I/O buffer
  339. * @v meta Transfer metadata
  340. * @ret rc Return status code
  341. */
  342. static int efi_pxe_tftp_deliver ( struct efi_pxe *pxe,
  343. struct io_buffer *iobuf,
  344. struct xfer_metadata *meta ) {
  345. int rc;
  346. /* Deliver to data transfer buffer */
  347. if ( ( rc = xferbuf_deliver ( &pxe->buf, iob_disown ( iobuf ),
  348. meta ) ) != 0 )
  349. goto err_deliver;
  350. return 0;
  351. err_deliver:
  352. efi_pxe_tftp_close ( pxe, rc );
  353. return rc;
  354. }
  355. /** PXE file data transfer interface operations */
  356. static struct interface_operation efi_pxe_tftp_operations[] = {
  357. INTF_OP ( xfer_deliver, struct efi_pxe *, efi_pxe_tftp_deliver ),
  358. INTF_OP ( xfer_window, struct efi_pxe *, efi_pxe_tftp_window ),
  359. INTF_OP ( intf_close, struct efi_pxe *, efi_pxe_tftp_close ),
  360. };
  361. /** PXE file data transfer interface descriptor */
  362. static struct interface_descriptor efi_pxe_tftp_desc =
  363. INTF_DESC ( struct efi_pxe, tftp, efi_pxe_tftp_operations );
  364. /**
  365. * Open (M)TFTP download interface
  366. *
  367. * @v pxe PXE base code
  368. * @v ip EFI IP address
  369. * @v filename Filename
  370. * @ret rc Return status code
  371. */
  372. static int efi_pxe_tftp_open ( struct efi_pxe *pxe, EFI_IP_ADDRESS *ip,
  373. const char *filename ) {
  374. struct sockaddr server;
  375. struct uri *uri;
  376. int rc;
  377. /* Parse server address and filename */
  378. efi_pxe_ip_sockaddr ( pxe, ip, &server );
  379. uri = pxe_uri ( &server, filename );
  380. if ( ! uri ) {
  381. DBGC ( pxe, "PXE %s could not parse %s:%s\n", pxe->name,
  382. efi_pxe_ip_ntoa ( pxe, ip ), filename );
  383. rc = -ENOTSUP;
  384. goto err_parse;
  385. }
  386. /* Open URI */
  387. if ( ( rc = xfer_open_uri ( &pxe->tftp, uri ) ) != 0 ) {
  388. DBGC ( pxe, "PXE %s could not open: %s\n",
  389. pxe->name, strerror ( rc ) );
  390. goto err_open;
  391. }
  392. err_open:
  393. uri_put ( uri );
  394. err_parse:
  395. return rc;
  396. }
  397. /******************************************************************************
  398. *
  399. * UDP interface
  400. *
  401. ******************************************************************************
  402. */
  403. /** EFI UDP pseudo-header */
  404. struct efi_pxe_udp_pseudo_header {
  405. /** Network-layer protocol */
  406. struct net_protocol *net;
  407. /** Destination port */
  408. uint16_t dest_port;
  409. /** Source port */
  410. uint16_t src_port;
  411. } __attribute__ (( packed ));
  412. /**
  413. * Close UDP interface
  414. *
  415. * @v pxe PXE base code
  416. * @v rc Reason for close
  417. */
  418. static void efi_pxe_udp_close ( struct efi_pxe *pxe, int rc ) {
  419. struct io_buffer *iobuf;
  420. struct io_buffer *tmp;
  421. /* Release our claim on SNP devices, if applicable */
  422. if ( process_running ( &pxe->process ) )
  423. efi_snp_release();
  424. /* Stop process */
  425. process_del ( &pxe->process );
  426. /* Restart UDP interface */
  427. intf_restart ( &pxe->udp, rc );
  428. /* Flush any received UDP packets */
  429. list_for_each_entry_safe ( iobuf, tmp, &pxe->queue, list ) {
  430. list_del ( &iobuf->list );
  431. free_iob ( iobuf );
  432. }
  433. }
  434. /**
  435. * Receive UDP packet
  436. *
  437. * @v pxe PXE base code
  438. * @v iobuf I/O buffer
  439. * @v meta Data transfer metadata
  440. * @ret rc Return status code
  441. */
  442. static int efi_pxe_udp_deliver ( struct efi_pxe *pxe, struct io_buffer *iobuf,
  443. struct xfer_metadata *meta ) {
  444. struct sockaddr_efi *se_src;
  445. struct sockaddr_efi *se_dest;
  446. struct tcpip_net_protocol *tcpip;
  447. struct net_protocol *net;
  448. struct efi_pxe_udp_pseudo_header *pshdr;
  449. size_t addr_len;
  450. size_t pshdr_len;
  451. int rc;
  452. /* Sanity checks */
  453. assert ( meta != NULL );
  454. se_src = ( ( struct sockaddr_efi * ) meta->src );
  455. assert ( se_src != NULL );
  456. se_dest = ( ( struct sockaddr_efi * ) meta->dest );
  457. assert ( se_dest != NULL );
  458. assert ( se_src->se_family == se_dest->se_family );
  459. /* Determine protocol */
  460. tcpip = tcpip_net_protocol ( se_src->se_family );
  461. if ( ! tcpip ) {
  462. rc = -ENOTSUP;
  463. goto err_unsupported;
  464. }
  465. net = tcpip->net_protocol;
  466. addr_len = net->net_addr_len;
  467. /* Construct pseudo-header */
  468. pshdr_len = ( sizeof ( *pshdr ) + ( 2 * addr_len ) );
  469. if ( ( rc = iob_ensure_headroom ( iobuf, pshdr_len ) ) != 0 )
  470. goto err_headroom;
  471. memcpy ( iob_push ( iobuf, addr_len ), &se_src->se_addr, addr_len );
  472. memcpy ( iob_push ( iobuf, addr_len ), &se_dest->se_addr, addr_len );
  473. pshdr = iob_push ( iobuf, sizeof ( *pshdr ) );
  474. pshdr->net = net;
  475. pshdr->dest_port = ntohs ( se_dest->se_port );
  476. pshdr->src_port = ntohs ( se_src->se_port );
  477. /* Add to queue */
  478. list_add_tail ( &iobuf->list, &pxe->queue );
  479. return 0;
  480. err_unsupported:
  481. err_headroom:
  482. free_iob ( iobuf );
  483. return rc;
  484. }
  485. /** PXE UDP interface operations */
  486. static struct interface_operation efi_pxe_udp_operations[] = {
  487. INTF_OP ( xfer_deliver, struct efi_pxe *, efi_pxe_udp_deliver ),
  488. INTF_OP ( intf_close, struct efi_pxe *, efi_pxe_udp_close ),
  489. };
  490. /** PXE UDP interface descriptor */
  491. static struct interface_descriptor efi_pxe_udp_desc =
  492. INTF_DESC ( struct efi_pxe, udp, efi_pxe_udp_operations );
  493. /**
  494. * Open UDP interface
  495. *
  496. * @v pxe PXE base code
  497. * @ret rc Return status code
  498. */
  499. static int efi_pxe_udp_open ( struct efi_pxe *pxe ) {
  500. int rc;
  501. /* If interface is already open, then cancel the scheduled close */
  502. if ( process_running ( &pxe->process ) ) {
  503. process_del ( &pxe->process );
  504. return 0;
  505. }
  506. /* Open promiscuous UDP interface */
  507. if ( ( rc = udp_open_promisc ( &pxe->udp ) ) != 0 ) {
  508. DBGC ( pxe, "PXE %s could not open UDP connection: %s\n",
  509. pxe->name, strerror ( rc ) );
  510. return rc;
  511. }
  512. /* Claim network devices */
  513. efi_snp_claim();
  514. return 0;
  515. }
  516. /**
  517. * Schedule close of UDP interface
  518. *
  519. * @v pxe PXE base code
  520. */
  521. static void efi_pxe_udp_schedule_close ( struct efi_pxe *pxe ) {
  522. /* The EFI PXE base code protocol does not provide any
  523. * explicit UDP open/close methods. To avoid the overhead of
  524. * reopening a socket for each read/write operation, we start
  525. * a process which will close the socket immediately if the
  526. * next call into iPXE is anything other than a UDP
  527. * read/write.
  528. */
  529. process_add ( &pxe->process );
  530. }
  531. /**
  532. * Scheduled close of UDP interface
  533. *
  534. * @v pxe PXE base code
  535. */
  536. static void efi_pxe_udp_scheduled_close ( struct efi_pxe *pxe ) {
  537. /* Close UDP interface */
  538. efi_pxe_udp_close ( pxe, 0 );
  539. }
  540. /** UDP close process descriptor */
  541. static struct process_descriptor efi_pxe_process_desc =
  542. PROC_DESC_ONCE ( struct efi_pxe, process, efi_pxe_udp_scheduled_close );
  543. /******************************************************************************
  544. *
  545. * Fake DHCP packets
  546. *
  547. ******************************************************************************
  548. */
  549. /**
  550. * Name fake DHCP packet
  551. *
  552. * @v pxe PXE base code
  553. * @v packet Packet
  554. * @ret name Name of packet
  555. */
  556. static const char * efi_pxe_fake_name ( struct efi_pxe *pxe,
  557. EFI_PXE_BASE_CODE_PACKET *packet ) {
  558. EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
  559. if ( packet == &mode->DhcpDiscover ) {
  560. return "DhcpDiscover";
  561. } else if ( packet == &mode->DhcpAck ) {
  562. return "DhcpAck";
  563. } else if ( packet == &mode->ProxyOffer ) {
  564. return "ProxyOffer";
  565. } else if ( packet == &mode->PxeDiscover ) {
  566. return "PxeDiscover";
  567. } else if ( packet == &mode->PxeReply ) {
  568. return "PxeReply";
  569. } else if ( packet == &mode->PxeBisReply ) {
  570. return "PxeBisReply";
  571. } else {
  572. return "<UNKNOWN>";
  573. }
  574. }
  575. /**
  576. * Construct fake DHCP packet and flag
  577. *
  578. * @v pxe PXE base code
  579. * @v fake Fake packet constructor
  580. * @v packet Packet to fill in
  581. * @ret exists Packet existence flag
  582. */
  583. static BOOLEAN efi_pxe_fake ( struct efi_pxe *pxe,
  584. int ( * fake ) ( struct net_device *netdev,
  585. void *data, size_t len ),
  586. EFI_PXE_BASE_CODE_PACKET *packet ) {
  587. EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
  588. struct dhcp_packet dhcppkt;
  589. struct dhcphdr *dhcphdr;
  590. unsigned int len;
  591. int rc;
  592. /* The fake packet constructors do not support IPv6 */
  593. if ( mode->UsingIpv6 )
  594. return FALSE;
  595. /* Attempt to construct packet */
  596. if ( ( rc = fake ( pxe->netdev, packet, sizeof ( *packet ) ) != 0 ) ) {
  597. DBGC ( pxe, "PXE %s could not fake %s: %s\n", pxe->name,
  598. efi_pxe_fake_name ( pxe, packet ), strerror ( rc ) );
  599. return FALSE;
  600. }
  601. /* The WDS bootstrap wdsmgfw.efi has a buggy DHCPv4 packet
  602. * parser which does not correctly handle DHCP padding bytes.
  603. * Specifically, if a padding byte (i.e. a zero) is
  604. * encountered, the parse will first increment the pointer by
  605. * one to skip over the padding byte but will then drop into
  606. * the code path for handling normal options, which increments
  607. * the pointer by two to skip over the (already-skipped) type
  608. * field and the (non-existent) length field.
  609. *
  610. * The upshot of this bug in WDS is that the parser will fail
  611. * with an error 0xc0000023 if the number of spare bytes after
  612. * the end of the options is not an exact multiple of three.
  613. *
  614. * Work around this buggy parser by adding an explicit
  615. * DHCP_END tag.
  616. */
  617. dhcphdr = container_of ( &packet->Dhcpv4.BootpOpcode,
  618. struct dhcphdr, op );
  619. dhcppkt_init ( &dhcppkt, dhcphdr, sizeof ( *packet ) );
  620. len = dhcppkt_len ( &dhcppkt );
  621. if ( len < sizeof ( *packet ) )
  622. packet->Raw[len] = DHCP_END;
  623. return TRUE;
  624. }
  625. /**
  626. * Construct fake DHCP packets
  627. *
  628. * @v pxe PXE base code
  629. */
  630. static void efi_pxe_fake_all ( struct efi_pxe *pxe ) {
  631. EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
  632. /* Construct fake packets */
  633. mode->DhcpDiscoverValid =
  634. efi_pxe_fake ( pxe, create_fakedhcpdiscover,
  635. &mode->DhcpDiscover );
  636. mode->DhcpAckReceived =
  637. efi_pxe_fake ( pxe, create_fakedhcpack,
  638. &mode->DhcpAck );
  639. mode->PxeReplyReceived =
  640. efi_pxe_fake ( pxe, create_fakepxebsack,
  641. &mode->PxeReply );
  642. }
  643. /******************************************************************************
  644. *
  645. * Base code protocol
  646. *
  647. ******************************************************************************
  648. */
  649. /**
  650. * Start PXE base code
  651. *
  652. * @v base PXE base code protocol
  653. * @v use_ipv6 Use IPv6
  654. * @ret efirc EFI status code
  655. */
  656. static EFI_STATUS EFIAPI efi_pxe_start ( EFI_PXE_BASE_CODE_PROTOCOL *base,
  657. BOOLEAN use_ipv6 ) {
  658. struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
  659. EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
  660. struct tcpip_net_protocol *ipv6 = tcpip_net_protocol ( AF_INET6 );
  661. sa_family_t family = ( use_ipv6 ? AF_INET6 : AF_INET );
  662. int rc;
  663. DBGC ( pxe, "PXE %s START %s\n", pxe->name, ( ipv6 ? "IPv6" : "IPv4" ));
  664. /* Initialise mode structure */
  665. memset ( mode, 0, sizeof ( *mode ) );
  666. mode->AutoArp = TRUE;
  667. mode->TTL = DEFAULT_TTL;
  668. mode->ToS = DEFAULT_ToS;
  669. mode->IpFilter.Filters =
  670. ( EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP |
  671. EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST |
  672. EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS |
  673. EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST );
  674. /* Check for IPv4/IPv6 support */
  675. mode->Ipv6Supported = ( ipv6 != NULL );
  676. mode->Ipv6Available = ( ipv6 != NULL );
  677. pxe->tcpip = tcpip_net_protocol ( family );
  678. if ( ! pxe->tcpip ) {
  679. DBGC ( pxe, "PXE %s has no support for %s\n",
  680. pxe->name, socket_family_name ( family ) );
  681. return EFI_UNSUPPORTED;
  682. }
  683. pxe->net = pxe->tcpip->net_protocol;
  684. mode->UsingIpv6 = use_ipv6;
  685. /* Populate station IP address */
  686. if ( ( rc = efi_pxe_ip ( pxe ) ) != 0 )
  687. return rc;
  688. /* Construct fake DHCP packets */
  689. efi_pxe_fake_all ( pxe );
  690. /* Record that base code is started */
  691. mode->Started = TRUE;
  692. DBGC ( pxe, "PXE %s using %s\n",
  693. pxe->name, pxe->net->ntoa ( &mode->StationIp ) );
  694. return 0;
  695. }
  696. /**
  697. * Stop PXE base code
  698. *
  699. * @v base PXE base code protocol
  700. * @ret efirc EFI status code
  701. */
  702. static EFI_STATUS EFIAPI efi_pxe_stop ( EFI_PXE_BASE_CODE_PROTOCOL *base ) {
  703. struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
  704. EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
  705. DBGC ( pxe, "PXE %s STOP\n", pxe->name );
  706. /* Record that base code is stopped */
  707. mode->Started = FALSE;
  708. /* Close TFTP */
  709. efi_pxe_tftp_close ( pxe, 0 );
  710. /* Close UDP */
  711. efi_pxe_udp_close ( pxe, 0 );
  712. return 0;
  713. }
  714. /**
  715. * Perform DHCP
  716. *
  717. * @v base PXE base code protocol
  718. * @v sort Offers should be sorted
  719. * @ret efirc EFI status code
  720. */
  721. static EFI_STATUS EFIAPI efi_pxe_dhcp ( EFI_PXE_BASE_CODE_PROTOCOL *base,
  722. BOOLEAN sort ) {
  723. struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
  724. struct net_device *netdev = pxe->netdev;
  725. int rc;
  726. DBGC ( pxe, "PXE %s DHCP %s\n",
  727. pxe->name, ( sort ? "sorted" : "unsorted" ) );
  728. /* Claim network devices */
  729. efi_snp_claim();
  730. /* Initiate configuration */
  731. if ( ( rc = netdev_configure_all ( netdev ) ) != 0 ) {
  732. DBGC ( pxe, "PXE %s could not initiate configuration: %s\n",
  733. pxe->name, strerror ( rc ) );
  734. goto err_configure;
  735. }
  736. /* Wait for configuration to complete (or time out) */
  737. while ( netdev_configuration_in_progress ( netdev ) )
  738. step();
  739. /* Report timeout if configuration failed */
  740. if ( ! netdev_configuration_ok ( netdev ) ) {
  741. rc = -ETIMEDOUT;
  742. goto err_timeout;
  743. }
  744. /* Update station IP address */
  745. if ( ( rc = efi_pxe_ip ( pxe ) ) != 0 )
  746. goto err_ip;
  747. /* Update faked DHCP packets */
  748. efi_pxe_fake_all ( pxe );
  749. err_ip:
  750. err_timeout:
  751. err_configure:
  752. efi_snp_release();
  753. return EFIRC ( rc );
  754. }
  755. /**
  756. * Perform boot server discovery
  757. *
  758. * @v base PXE base code protocol
  759. * @v type Boot server type
  760. * @v layer Boot server layer
  761. * @v bis Use boot integrity services
  762. * @v info Additional information
  763. * @ret efirc EFI status code
  764. */
  765. static EFI_STATUS EFIAPI
  766. efi_pxe_discover ( EFI_PXE_BASE_CODE_PROTOCOL *base, UINT16 type, UINT16 *layer,
  767. BOOLEAN bis, EFI_PXE_BASE_CODE_DISCOVER_INFO *info ) {
  768. struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
  769. EFI_IP_ADDRESS *ip;
  770. unsigned int i;
  771. DBGC ( pxe, "PXE %s DISCOVER type %d layer %d%s\n",
  772. pxe->name, type, *layer, ( bis ? " bis" : "" ) );
  773. if ( info ) {
  774. DBGC ( pxe, "%s%s%s%s %s",
  775. ( info->UseMCast ? " mcast" : "" ),
  776. ( info->UseBCast ? " bcast" : "" ),
  777. ( info->UseUCast ? " ucast" : "" ),
  778. ( info->MustUseList ? " list" : "" ),
  779. efi_pxe_ip_ntoa ( pxe, &info->ServerMCastIp ) );
  780. for ( i = 0 ; i < info->IpCnt ; i++ ) {
  781. ip = &info->SrvList[i].IpAddr;
  782. DBGC ( pxe, " %d%s:%s", info->SrvList[i].Type,
  783. ( info->SrvList[i].AcceptAnyResponse ?
  784. ":any" : "" ), efi_pxe_ip_ntoa ( pxe, ip ) );
  785. }
  786. }
  787. DBGC ( pxe, "\n" );
  788. /* Not used by any bootstrap I can find to test with */
  789. return EFI_UNSUPPORTED;
  790. }
  791. /**
  792. * Perform (M)TFTP
  793. *
  794. * @v base PXE base code protocol
  795. * @v opcode TFTP opcode
  796. * @v data Data buffer
  797. * @v overwrite Overwrite file
  798. * @v len Length of data buffer
  799. * @v blksize Block size
  800. * @v ip Server address
  801. * @v filename Filename
  802. * @v info Additional information
  803. * @v callback Pass packets to callback instead of data buffer
  804. * @ret efirc EFI status code
  805. */
  806. static EFI_STATUS EFIAPI
  807. efi_pxe_mtftp ( EFI_PXE_BASE_CODE_PROTOCOL *base,
  808. EFI_PXE_BASE_CODE_TFTP_OPCODE opcode, VOID *data,
  809. BOOLEAN overwrite, UINT64 *len, UINTN *blksize,
  810. EFI_IP_ADDRESS *ip, UINT8 *filename,
  811. EFI_PXE_BASE_CODE_MTFTP_INFO *info, BOOLEAN callback ) {
  812. struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
  813. int rc;
  814. DBGC ( pxe, "PXE %s MTFTP %d%s %p+%llx", pxe->name, opcode,
  815. ( overwrite ? " overwrite" : "" ), data, *len );
  816. if ( blksize )
  817. DBGC ( pxe, " blksize %zd", ( ( size_t ) *blksize ) );
  818. DBGC ( pxe, " %s:%s", efi_pxe_ip_ntoa ( pxe, ip ), filename );
  819. if ( info ) {
  820. DBGC ( pxe, " %s:%d:%d:%d:%d",
  821. efi_pxe_ip_ntoa ( pxe, &info->MCastIp ),
  822. info->CPort, info->SPort, info->ListenTimeout,
  823. info->TransmitTimeout );
  824. }
  825. DBGC ( pxe, "%s\n", ( callback ? " callback" : "" ) );
  826. /* Fail unless operation is supported */
  827. if ( ! ( ( opcode == EFI_PXE_BASE_CODE_TFTP_READ_FILE ) ||
  828. ( opcode == EFI_PXE_BASE_CODE_MTFTP_READ_FILE ) ) ) {
  829. DBGC ( pxe, "PXE %s unsupported MTFTP opcode %d\n",
  830. pxe->name, opcode );
  831. rc = -ENOTSUP;
  832. goto err_opcode;
  833. }
  834. /* Claim network devices */
  835. efi_snp_claim();
  836. /* Determine block size. Ignore the requested block size
  837. * unless we are using callbacks, since limiting HTTP to a
  838. * 512-byte TCP window is not sensible.
  839. */
  840. pxe->blksize = ( ( callback && blksize ) ? *blksize : -1UL );
  841. /* Initialise data transfer buffer */
  842. pxe->buf.data = data;
  843. pxe->buf.len = *len;
  844. /* Open download */
  845. if ( ( rc = efi_pxe_tftp_open ( pxe, ip,
  846. ( ( const char * ) filename ) ) ) != 0 )
  847. goto err_open;
  848. /* Wait for download to complete */
  849. pxe->rc = -EINPROGRESS;
  850. while ( pxe->rc == -EINPROGRESS )
  851. step();
  852. if ( ( rc = pxe->rc ) != 0 ) {
  853. DBGC ( pxe, "PXE %s download failed: %s\n",
  854. pxe->name, strerror ( rc ) );
  855. goto err_download;
  856. }
  857. err_download:
  858. efi_pxe_tftp_close ( pxe, rc );
  859. err_open:
  860. efi_snp_release();
  861. err_opcode:
  862. return EFIRC ( rc );
  863. }
  864. /**
  865. * Transmit UDP packet
  866. *
  867. * @v base PXE base code protocol
  868. * @v flags Operation flags
  869. * @v dest_ip Destination address
  870. * @v dest_port Destination port
  871. * @v gateway Gateway address
  872. * @v src_ip Source address
  873. * @v src_port Source port
  874. * @v hdr_len Header length
  875. * @v hdr Header data
  876. * @v len Length
  877. * @v data Data
  878. * @ret efirc EFI status code
  879. */
  880. static EFI_STATUS EFIAPI
  881. efi_pxe_udp_write ( EFI_PXE_BASE_CODE_PROTOCOL *base, UINT16 flags,
  882. EFI_IP_ADDRESS *dest_ip,
  883. EFI_PXE_BASE_CODE_UDP_PORT *dest_port,
  884. EFI_IP_ADDRESS *gateway, EFI_IP_ADDRESS *src_ip,
  885. EFI_PXE_BASE_CODE_UDP_PORT *src_port,
  886. UINTN *hdr_len, VOID *hdr, UINTN *len, VOID *data ) {
  887. struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
  888. EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
  889. struct io_buffer *iobuf;
  890. struct xfer_metadata meta;
  891. union {
  892. struct sockaddr_tcpip st;
  893. struct sockaddr sa;
  894. } dest;
  895. union {
  896. struct sockaddr_tcpip st;
  897. struct sockaddr sa;
  898. } src;
  899. int rc;
  900. DBGC2 ( pxe, "PXE %s UDP WRITE ", pxe->name );
  901. if ( src_ip )
  902. DBGC2 ( pxe, "%s", efi_pxe_ip_ntoa ( pxe, src_ip ) );
  903. DBGC2 ( pxe, ":" );
  904. if ( src_port &&
  905. ( ! ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT ) ) ) {
  906. DBGC2 ( pxe, "%d", *src_port );
  907. } else {
  908. DBGC2 ( pxe, "*" );
  909. }
  910. DBGC2 ( pxe, "->%s:%d", efi_pxe_ip_ntoa ( pxe, dest_ip ), *dest_port );
  911. if ( gateway )
  912. DBGC2 ( pxe, " via %s", efi_pxe_ip_ntoa ( pxe, gateway ) );
  913. if ( hdr_len )
  914. DBGC2 ( pxe, " %p+%zx", hdr, ( ( size_t ) *hdr_len ) );
  915. DBGC2 ( pxe, " %p+%zx", data, ( ( size_t ) *len ) );
  916. if ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT )
  917. DBGC2 ( pxe, " frag" );
  918. DBGC2 ( pxe, "\n" );
  919. /* Open UDP connection (if applicable) */
  920. if ( ( rc = efi_pxe_udp_open ( pxe ) ) != 0 )
  921. goto err_open;
  922. /* Construct destination address */
  923. efi_pxe_ip_sockaddr ( pxe, dest_ip, &dest.sa );
  924. dest.st.st_port = htons ( *dest_port );
  925. /* Construct source address */
  926. efi_pxe_ip_sockaddr ( pxe, ( src_ip ? src_ip : &mode->StationIp ),
  927. &src.sa );
  928. if ( src_port &&
  929. ( ! ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT ) ) ) {
  930. src.st.st_port = htons ( *src_port );
  931. } else {
  932. /* The API does not allow for a sensible concept of
  933. * binding to a local port, so just use a random value.
  934. */
  935. src.st.st_port = ( random() | htons ( 1024 ) );
  936. if ( src_port )
  937. *src_port = ntohs ( src.st.st_port );
  938. }
  939. /* Allocate I/O buffer */
  940. iobuf = xfer_alloc_iob ( &pxe->udp,
  941. ( *len + ( hdr_len ? *hdr_len : 0 ) ) );
  942. if ( ! iobuf ) {
  943. rc = -ENOMEM;
  944. goto err_alloc;
  945. }
  946. /* Populate I/O buffer */
  947. if ( hdr_len )
  948. memcpy ( iob_put ( iobuf, *hdr_len ), hdr, *hdr_len );
  949. memcpy ( iob_put ( iobuf, *len ), data, *len );
  950. /* Construct metadata */
  951. memset ( &meta, 0, sizeof ( meta ) );
  952. meta.src = &src.sa;
  953. meta.dest = &dest.sa;
  954. meta.netdev = pxe->netdev;
  955. /* Deliver I/O buffer */
  956. if ( ( rc = xfer_deliver ( &pxe->udp, iob_disown ( iobuf ),
  957. &meta ) ) != 0 ) {
  958. DBGC ( pxe, "PXE %s could not transmit: %s\n",
  959. pxe->name, strerror ( rc ) );
  960. goto err_deliver;
  961. }
  962. err_deliver:
  963. free_iob ( iobuf );
  964. err_alloc:
  965. efi_pxe_udp_schedule_close ( pxe );
  966. err_open:
  967. return EFIRC ( rc );
  968. }
  969. /**
  970. * Receive UDP packet
  971. *
  972. * @v base PXE base code protocol
  973. * @v flags Operation flags
  974. * @v dest_ip Destination address
  975. * @v dest_port Destination port
  976. * @v src_ip Source address
  977. * @v src_port Source port
  978. * @v hdr_len Header length
  979. * @v hdr Header data
  980. * @v len Length
  981. * @v data Data
  982. * @ret efirc EFI status code
  983. */
  984. static EFI_STATUS EFIAPI
  985. efi_pxe_udp_read ( EFI_PXE_BASE_CODE_PROTOCOL *base, UINT16 flags,
  986. EFI_IP_ADDRESS *dest_ip,
  987. EFI_PXE_BASE_CODE_UDP_PORT *dest_port,
  988. EFI_IP_ADDRESS *src_ip,
  989. EFI_PXE_BASE_CODE_UDP_PORT *src_port,
  990. UINTN *hdr_len, VOID *hdr, UINTN *len, VOID *data ) {
  991. struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
  992. struct io_buffer *iobuf;
  993. struct efi_pxe_udp_pseudo_header *pshdr;
  994. EFI_IP_ADDRESS *actual_dest_ip;
  995. EFI_IP_ADDRESS *actual_src_ip;
  996. size_t addr_len;
  997. size_t frag_len;
  998. int rc;
  999. DBGC2 ( pxe, "PXE %s UDP READ ", pxe->name );
  1000. if ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER ) {
  1001. DBGC2 ( pxe, "(filter)" );
  1002. } else if ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP ) {
  1003. DBGC2 ( pxe, "*" );
  1004. } else if ( dest_ip ) {
  1005. DBGC2 ( pxe, "%s", efi_pxe_ip_ntoa ( pxe, dest_ip ) );
  1006. }
  1007. DBGC2 ( pxe, ":" );
  1008. if ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT ) {
  1009. DBGC2 ( pxe, "*" );
  1010. } else if ( dest_port ) {
  1011. DBGC2 ( pxe, "%d", *dest_port );
  1012. } else {
  1013. DBGC2 ( pxe, "<NULL>" );
  1014. }
  1015. DBGC2 ( pxe, "<-" );
  1016. if ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP ) {
  1017. DBGC2 ( pxe, "*" );
  1018. } else if ( src_ip ) {
  1019. DBGC2 ( pxe, "%s", efi_pxe_ip_ntoa ( pxe, src_ip ) );
  1020. } else {
  1021. DBGC2 ( pxe, "<NULL>" );
  1022. }
  1023. DBGC2 ( pxe, ":" );
  1024. if ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT ) {
  1025. DBGC2 ( pxe, "*" );
  1026. } else if ( src_port ) {
  1027. DBGC2 ( pxe, "%d", *src_port );
  1028. } else {
  1029. DBGC2 ( pxe, "<NULL>" );
  1030. }
  1031. if ( hdr_len )
  1032. DBGC2 ( pxe, " %p+%zx", hdr, ( ( size_t ) *hdr_len ) );
  1033. DBGC2 ( pxe, " %p+%zx\n", data, ( ( size_t ) *len ) );
  1034. /* Open UDP connection (if applicable) */
  1035. if ( ( rc = efi_pxe_udp_open ( pxe ) ) != 0 )
  1036. goto err_open;
  1037. /* Try receiving a packet, if the queue is empty */
  1038. if ( list_empty ( &pxe->queue ) )
  1039. step();
  1040. /* Remove first packet from the queue */
  1041. iobuf = list_first_entry ( &pxe->queue, struct io_buffer, list );
  1042. if ( ! iobuf ) {
  1043. rc = -ETIMEDOUT; /* "no packet" */
  1044. goto err_empty;
  1045. }
  1046. list_del ( &iobuf->list );
  1047. /* Strip pseudo-header */
  1048. pshdr = iobuf->data;
  1049. addr_len = ( pshdr->net->net_addr_len );
  1050. iob_pull ( iobuf, sizeof ( *pshdr ) );
  1051. actual_dest_ip = iobuf->data;
  1052. iob_pull ( iobuf, addr_len );
  1053. actual_src_ip = iobuf->data;
  1054. iob_pull ( iobuf, addr_len );
  1055. DBGC2 ( pxe, "PXE %s UDP RX %s:%d", pxe->name,
  1056. pshdr->net->ntoa ( actual_dest_ip ), pshdr->dest_port );
  1057. DBGC2 ( pxe, "<-%s:%d len %#zx\n", pshdr->net->ntoa ( actual_src_ip ),
  1058. pshdr->src_port, iob_len ( iobuf ) );
  1059. /* Filter based on network-layer protocol */
  1060. if ( pshdr->net != pxe->net ) {
  1061. DBGC2 ( pxe, "PXE %s filtered out %s packet\n",
  1062. pxe->name, pshdr->net->name );
  1063. rc = -ETIMEDOUT; /* "no packet" */
  1064. goto err_filter;
  1065. }
  1066. /* Filter based on port numbers */
  1067. if ( ! ( ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT ) ||
  1068. ( dest_port && ( *dest_port == pshdr->dest_port ) ) ) ) {
  1069. DBGC2 ( pxe, "PXE %s filtered out destination port %d\n",
  1070. pxe->name, pshdr->dest_port );
  1071. rc = -ETIMEDOUT; /* "no packet" */
  1072. goto err_filter;
  1073. }
  1074. if ( ! ( ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT ) ||
  1075. ( src_port && ( *src_port == pshdr->src_port ) ) ) ) {
  1076. DBGC2 ( pxe, "PXE %s filtered out source port %d\n",
  1077. pxe->name, pshdr->src_port );
  1078. rc = -ETIMEDOUT; /* "no packet" */
  1079. goto err_filter;
  1080. }
  1081. /* Filter based on source IP address */
  1082. if ( ! ( ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP ) ||
  1083. ( src_ip &&
  1084. ( memcmp ( src_ip, actual_src_ip, addr_len ) == 0 ) ) ) ) {
  1085. DBGC2 ( pxe, "PXE %s filtered out source IP %s\n",
  1086. pxe->name, pshdr->net->ntoa ( actual_src_ip ) );
  1087. rc = -ETIMEDOUT; /* "no packet" */
  1088. goto err_filter;
  1089. }
  1090. /* Filter based on destination IP address */
  1091. if ( ! ( ( ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER ) &&
  1092. efi_pxe_ip_filter ( pxe, actual_dest_ip ) ) ||
  1093. ( ( ! ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER ) ) &&
  1094. ( ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP ) ||
  1095. ( dest_ip && ( memcmp ( dest_ip, actual_dest_ip,
  1096. addr_len ) == 0 ) ) ) ) ) ) {
  1097. DBGC2 ( pxe, "PXE %s filtered out destination IP %s\n",
  1098. pxe->name, pshdr->net->ntoa ( actual_dest_ip ) );
  1099. rc = -ETIMEDOUT; /* "no packet" */
  1100. goto err_filter;
  1101. }
  1102. /* Fill in addresses and port numbers */
  1103. if ( dest_ip )
  1104. memcpy ( dest_ip, actual_dest_ip, addr_len );
  1105. if ( dest_port )
  1106. *dest_port = pshdr->dest_port;
  1107. if ( src_ip )
  1108. memcpy ( src_ip, actual_src_ip, addr_len );
  1109. if ( src_port )
  1110. *src_port = pshdr->src_port;
  1111. /* Fill in header, if applicable */
  1112. if ( hdr_len ) {
  1113. frag_len = iob_len ( iobuf );
  1114. if ( frag_len > *hdr_len )
  1115. frag_len = *hdr_len;
  1116. memcpy ( hdr, iobuf->data, frag_len );
  1117. iob_pull ( iobuf, frag_len );
  1118. *hdr_len = frag_len;
  1119. }
  1120. /* Fill in data buffer */
  1121. frag_len = iob_len ( iobuf );
  1122. if ( frag_len > *len )
  1123. frag_len = *len;
  1124. memcpy ( data, iobuf->data, frag_len );
  1125. iob_pull ( iobuf, frag_len );
  1126. *len = frag_len;
  1127. /* Check for overflow */
  1128. if ( iob_len ( iobuf ) ) {
  1129. rc = -ERANGE;
  1130. goto err_too_short;
  1131. }
  1132. /* Success */
  1133. rc = 0;
  1134. err_too_short:
  1135. err_filter:
  1136. free_iob ( iobuf );
  1137. err_empty:
  1138. efi_pxe_udp_schedule_close ( pxe );
  1139. err_open:
  1140. return EFIRC ( rc );
  1141. }
  1142. /**
  1143. * Set receive filter
  1144. *
  1145. * @v base PXE base code protocol
  1146. * @v filter Receive filter
  1147. * @ret efirc EFI status code
  1148. */
  1149. static EFI_STATUS EFIAPI
  1150. efi_pxe_set_ip_filter ( EFI_PXE_BASE_CODE_PROTOCOL *base,
  1151. EFI_PXE_BASE_CODE_IP_FILTER *filter ) {
  1152. struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
  1153. EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
  1154. unsigned int i;
  1155. DBGC ( pxe, "PXE %s SET IP FILTER %02x",
  1156. pxe->name, filter->Filters );
  1157. for ( i = 0 ; i < filter->IpCnt ; i++ ) {
  1158. DBGC ( pxe, " %s",
  1159. efi_pxe_ip_ntoa ( pxe, &filter->IpList[i] ) );
  1160. }
  1161. DBGC ( pxe, "\n" );
  1162. /* Update filter */
  1163. memcpy ( &mode->IpFilter, filter, sizeof ( mode->IpFilter ) );
  1164. return 0;
  1165. }
  1166. /**
  1167. * Resolve MAC address
  1168. *
  1169. * @v base PXE base code protocol
  1170. * @v ip IP address
  1171. * @v mac MAC address to fill in
  1172. * @ret efirc EFI status code
  1173. */
  1174. static EFI_STATUS EFIAPI efi_pxe_arp ( EFI_PXE_BASE_CODE_PROTOCOL *base,
  1175. EFI_IP_ADDRESS *ip,
  1176. EFI_MAC_ADDRESS *mac ) {
  1177. struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
  1178. DBGC ( pxe, "PXE %s ARP %s %p\n",
  1179. pxe->name, efi_pxe_ip_ntoa ( pxe, ip ), mac );
  1180. /* Not used by any bootstrap I can find to test with */
  1181. return EFI_UNSUPPORTED;
  1182. }
  1183. /**
  1184. * Set parameters
  1185. *
  1186. * @v base PXE base code protocol
  1187. * @v autoarp Automatic ARP packet generation
  1188. * @v sendguid Send GUID as client hardware address
  1189. * @v ttl IP time to live
  1190. * @v tos IP type of service
  1191. * @v callback Make callbacks
  1192. * @ret efirc EFI status code
  1193. */
  1194. static EFI_STATUS EFIAPI
  1195. efi_pxe_set_parameters ( EFI_PXE_BASE_CODE_PROTOCOL *base,
  1196. BOOLEAN *autoarp, BOOLEAN *sendguid, UINT8 *ttl,
  1197. UINT8 *tos, BOOLEAN *callback ) {
  1198. struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
  1199. EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
  1200. DBGC ( pxe, "PXE %s SET PARAMETERS", pxe->name );
  1201. if ( autoarp )
  1202. DBGC ( pxe, " %s", ( *autoarp ? "autoarp" : "noautoarp" ) );
  1203. if ( sendguid )
  1204. DBGC ( pxe, " %s", ( *sendguid ? "sendguid" : "sendmac" ) );
  1205. if ( ttl )
  1206. DBGC ( pxe, " ttl %d", *ttl );
  1207. if ( tos )
  1208. DBGC ( pxe, " tos %d", *tos );
  1209. if ( callback ) {
  1210. DBGC ( pxe, " %s",
  1211. ( *callback ? "callback" : "nocallback" ) );
  1212. }
  1213. DBGC ( pxe, "\n" );
  1214. /* Update parameters */
  1215. if ( autoarp )
  1216. mode->AutoArp = *autoarp;
  1217. if ( sendguid )
  1218. mode->SendGUID = *sendguid;
  1219. if ( ttl )
  1220. mode->TTL = *ttl;
  1221. if ( tos )
  1222. mode->ToS = *tos;
  1223. if ( callback )
  1224. mode->MakeCallbacks = *callback;
  1225. return 0;
  1226. }
  1227. /**
  1228. * Set IP address
  1229. *
  1230. * @v base PXE base code protocol
  1231. * @v ip IP address
  1232. * @v netmask Subnet mask
  1233. * @ret efirc EFI status code
  1234. */
  1235. static EFI_STATUS EFIAPI
  1236. efi_pxe_set_station_ip ( EFI_PXE_BASE_CODE_PROTOCOL *base,
  1237. EFI_IP_ADDRESS *ip, EFI_IP_ADDRESS *netmask ) {
  1238. struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
  1239. EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
  1240. DBGC ( pxe, "PXE %s SET STATION IP ", pxe->name );
  1241. if ( ip )
  1242. DBGC ( pxe, "%s", efi_pxe_ip_ntoa ( pxe, ip ) );
  1243. if ( netmask )
  1244. DBGC ( pxe, "/%s", efi_pxe_ip_ntoa ( pxe, netmask ) );
  1245. DBGC ( pxe, "\n" );
  1246. /* Update IP address and netmask */
  1247. if ( ip )
  1248. memcpy ( &mode->StationIp, ip, sizeof ( mode->StationIp ) );
  1249. if ( netmask )
  1250. memcpy ( &mode->SubnetMask, netmask, sizeof (mode->SubnetMask));
  1251. return 0;
  1252. }
  1253. /**
  1254. * Update cached DHCP packets
  1255. *
  1256. * @v base PXE base code protocol
  1257. * @v dhcpdisc_ok DHCPDISCOVER is valid
  1258. * @v dhcpack_ok DHCPACK received
  1259. * @v proxyoffer_ok ProxyDHCPOFFER received
  1260. * @v pxebsdisc_ok PxeBsDISCOVER valid
  1261. * @v pxebsack_ok PxeBsACK received
  1262. * @v pxebsbis_ok PxeBsBIS received
  1263. * @v dhcpdisc DHCPDISCOVER packet
  1264. * @v dhcpack DHCPACK packet
  1265. * @v proxyoffer ProxyDHCPOFFER packet
  1266. * @v pxebsdisc PxeBsDISCOVER packet
  1267. * @v pxebsack PxeBsACK packet
  1268. * @v pxebsbis PxeBsBIS packet
  1269. * @ret efirc EFI status code
  1270. */
  1271. static EFI_STATUS EFIAPI
  1272. efi_pxe_set_packets ( EFI_PXE_BASE_CODE_PROTOCOL *base, BOOLEAN *dhcpdisc_ok,
  1273. BOOLEAN *dhcpack_ok, BOOLEAN *proxyoffer_ok,
  1274. BOOLEAN *pxebsdisc_ok, BOOLEAN *pxebsack_ok,
  1275. BOOLEAN *pxebsbis_ok, EFI_PXE_BASE_CODE_PACKET *dhcpdisc,
  1276. EFI_PXE_BASE_CODE_PACKET *dhcpack,
  1277. EFI_PXE_BASE_CODE_PACKET *proxyoffer,
  1278. EFI_PXE_BASE_CODE_PACKET *pxebsdisc,
  1279. EFI_PXE_BASE_CODE_PACKET *pxebsack,
  1280. EFI_PXE_BASE_CODE_PACKET *pxebsbis ) {
  1281. struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
  1282. EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
  1283. DBGC ( pxe, "PXE %s SET PACKETS\n", pxe->name );
  1284. /* Update fake packet flags */
  1285. if ( dhcpdisc_ok )
  1286. mode->DhcpDiscoverValid = *dhcpdisc_ok;
  1287. if ( dhcpack_ok )
  1288. mode->DhcpAckReceived = *dhcpack_ok;
  1289. if ( proxyoffer_ok )
  1290. mode->ProxyOfferReceived = *proxyoffer_ok;
  1291. if ( pxebsdisc_ok )
  1292. mode->PxeDiscoverValid = *pxebsdisc_ok;
  1293. if ( pxebsack_ok )
  1294. mode->PxeReplyReceived = *pxebsack_ok;
  1295. if ( pxebsbis_ok )
  1296. mode->PxeBisReplyReceived = *pxebsbis_ok;
  1297. /* Update fake packet contents */
  1298. if ( dhcpdisc )
  1299. memcpy ( &mode->DhcpDiscover, dhcpdisc, sizeof ( *dhcpdisc ) );
  1300. if ( dhcpack )
  1301. memcpy ( &mode->DhcpAck, dhcpack, sizeof ( *dhcpack ) );
  1302. if ( proxyoffer )
  1303. memcpy ( &mode->ProxyOffer, proxyoffer, sizeof ( *proxyoffer ));
  1304. if ( pxebsdisc )
  1305. memcpy ( &mode->PxeDiscover, pxebsdisc, sizeof ( *pxebsdisc ) );
  1306. if ( pxebsack )
  1307. memcpy ( &mode->PxeReply, pxebsack, sizeof ( *pxebsack ) );
  1308. if ( pxebsbis )
  1309. memcpy ( &mode->PxeBisReply, pxebsbis, sizeof ( *pxebsbis ) );
  1310. return 0;
  1311. }
  1312. /** PXE base code protocol */
  1313. static EFI_PXE_BASE_CODE_PROTOCOL efi_pxe_base_code_protocol = {
  1314. .Revision = EFI_PXE_BASE_CODE_PROTOCOL_REVISION,
  1315. .Start = efi_pxe_start,
  1316. .Stop = efi_pxe_stop,
  1317. .Dhcp = efi_pxe_dhcp,
  1318. .Discover = efi_pxe_discover,
  1319. .Mtftp = efi_pxe_mtftp,
  1320. .UdpWrite = efi_pxe_udp_write,
  1321. .UdpRead = efi_pxe_udp_read,
  1322. .SetIpFilter = efi_pxe_set_ip_filter,
  1323. .Arp = efi_pxe_arp,
  1324. .SetParameters = efi_pxe_set_parameters,
  1325. .SetStationIp = efi_pxe_set_station_ip,
  1326. .SetPackets = efi_pxe_set_packets,
  1327. };
  1328. /******************************************************************************
  1329. *
  1330. * Apple NetBoot protocol
  1331. *
  1332. ******************************************************************************
  1333. */
  1334. /**
  1335. * Get DHCP/BSDP response
  1336. *
  1337. * @v packet Packet
  1338. * @v len Length of data buffer
  1339. * @v data Data buffer
  1340. * @ret efirc EFI status code
  1341. */
  1342. static EFI_STATUS EFIAPI
  1343. efi_apple_get_response ( EFI_PXE_BASE_CODE_PACKET *packet, UINTN *len,
  1344. VOID *data ) {
  1345. /* Check length */
  1346. if ( *len < sizeof ( *packet ) ) {
  1347. *len = sizeof ( *packet );
  1348. return EFI_BUFFER_TOO_SMALL;
  1349. }
  1350. /* Copy packet */
  1351. memcpy ( data, packet, sizeof ( *packet ) );
  1352. *len = sizeof ( *packet );
  1353. return EFI_SUCCESS;
  1354. }
  1355. /**
  1356. * Get DHCP response
  1357. *
  1358. * @v apple Apple NetBoot protocol
  1359. * @v len Length of data buffer
  1360. * @v data Data buffer
  1361. * @ret efirc EFI status code
  1362. */
  1363. static EFI_STATUS EFIAPI
  1364. efi_apple_get_dhcp_response ( EFI_APPLE_NET_BOOT_PROTOCOL *apple,
  1365. UINTN *len, VOID *data ) {
  1366. struct efi_pxe *pxe = container_of ( apple, struct efi_pxe, apple );
  1367. return efi_apple_get_response ( &pxe->mode.DhcpAck, len, data );
  1368. }
  1369. /**
  1370. * Get BSDP response
  1371. *
  1372. * @v apple Apple NetBoot protocol
  1373. * @v len Length of data buffer
  1374. * @v data Data buffer
  1375. * @ret efirc EFI status code
  1376. */
  1377. static EFI_STATUS EFIAPI
  1378. efi_apple_get_bsdp_response ( EFI_APPLE_NET_BOOT_PROTOCOL *apple,
  1379. UINTN *len, VOID *data ) {
  1380. struct efi_pxe *pxe = container_of ( apple, struct efi_pxe, apple );
  1381. return efi_apple_get_response ( &pxe->mode.PxeReply, len, data );
  1382. }
  1383. /** Apple NetBoot protocol */
  1384. static EFI_APPLE_NET_BOOT_PROTOCOL efi_apple_net_boot_protocol = {
  1385. .GetDhcpResponse = efi_apple_get_dhcp_response,
  1386. .GetBsdpResponse = efi_apple_get_bsdp_response,
  1387. };
  1388. /******************************************************************************
  1389. *
  1390. * Installer
  1391. *
  1392. ******************************************************************************
  1393. */
  1394. /**
  1395. * Install PXE base code protocol
  1396. *
  1397. * @v handle EFI handle
  1398. * @v netdev Underlying network device
  1399. * @ret rc Return status code
  1400. */
  1401. int efi_pxe_install ( EFI_HANDLE handle, struct net_device *netdev ) {
  1402. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  1403. struct tcpip_net_protocol *ipv6 = tcpip_net_protocol ( AF_INET6 );
  1404. struct efi_pxe *pxe;
  1405. struct in_addr ip;
  1406. BOOLEAN use_ipv6;
  1407. EFI_STATUS efirc;
  1408. int rc;
  1409. /* Allocate and initialise structure */
  1410. pxe = zalloc ( sizeof ( *pxe ) );
  1411. if ( ! pxe ) {
  1412. rc = -ENOMEM;
  1413. goto err_alloc;
  1414. }
  1415. ref_init ( &pxe->refcnt, efi_pxe_free );
  1416. pxe->netdev = netdev_get ( netdev );
  1417. pxe->name = netdev->name;
  1418. pxe->handle = handle;
  1419. memcpy ( &pxe->base, &efi_pxe_base_code_protocol, sizeof ( pxe->base ));
  1420. pxe->base.Mode = &pxe->mode;
  1421. memcpy ( &pxe->apple, &efi_apple_net_boot_protocol,
  1422. sizeof ( pxe->apple ) );
  1423. pxe->buf.op = &efi_pxe_buf_operations;
  1424. intf_init ( &pxe->tftp, &efi_pxe_tftp_desc, &pxe->refcnt );
  1425. intf_init ( &pxe->udp, &efi_pxe_udp_desc, &pxe->refcnt );
  1426. INIT_LIST_HEAD ( &pxe->queue );
  1427. process_init_stopped ( &pxe->process, &efi_pxe_process_desc,
  1428. &pxe->refcnt );
  1429. /* Crude heuristic: assume that we prefer to use IPv4 if we
  1430. * have an IPv4 address for the network device, otherwise
  1431. * prefer IPv6 (if available).
  1432. */
  1433. fetch_ipv4_setting ( netdev_settings ( netdev ), &ip_setting, &ip );
  1434. use_ipv6 = ( ip.s_addr ? FALSE : ( ipv6 != NULL ) );
  1435. /* Start base code */
  1436. efi_pxe_start ( &pxe->base, use_ipv6 );
  1437. /* Install PXE base code protocol */
  1438. if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
  1439. &handle,
  1440. &efi_pxe_base_code_protocol_guid, &pxe->base,
  1441. &efi_apple_net_boot_protocol_guid, &pxe->apple,
  1442. NULL ) ) != 0 ) {
  1443. rc = -EEFI ( efirc );
  1444. DBGC ( pxe, "PXE %s could not install base code protocol: %s\n",
  1445. pxe->name, strerror ( rc ) );
  1446. goto err_install_protocol;
  1447. }
  1448. /* Transfer reference to list and return */
  1449. list_add_tail ( &pxe->list, &efi_pxes );
  1450. DBGC ( pxe, "PXE %s installed for %s\n",
  1451. pxe->name, efi_handle_name ( handle ) );
  1452. return 0;
  1453. bs->UninstallMultipleProtocolInterfaces (
  1454. handle,
  1455. &efi_pxe_base_code_protocol_guid, &pxe->base,
  1456. &efi_apple_net_boot_protocol_guid, &pxe->apple,
  1457. NULL );
  1458. err_install_protocol:
  1459. ref_put ( &pxe->refcnt );
  1460. err_alloc:
  1461. return rc;
  1462. }
  1463. /**
  1464. * Uninstall PXE base code protocol
  1465. *
  1466. * @v handle EFI handle
  1467. */
  1468. void efi_pxe_uninstall ( EFI_HANDLE handle ) {
  1469. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  1470. struct efi_pxe *pxe;
  1471. /* Locate PXE base code */
  1472. pxe = efi_pxe_find ( handle );
  1473. if ( ! handle ) {
  1474. DBG ( "PXE could not find base code for %s\n",
  1475. efi_handle_name ( handle ) );
  1476. return;
  1477. }
  1478. /* Stop base code */
  1479. efi_pxe_stop ( &pxe->base );
  1480. /* Uninstall PXE base code protocol */
  1481. bs->UninstallMultipleProtocolInterfaces (
  1482. handle,
  1483. &efi_pxe_base_code_protocol_guid, &pxe->base,
  1484. &efi_apple_net_boot_protocol_guid, &pxe->apple,
  1485. NULL );
  1486. /* Remove from list and drop list's reference */
  1487. list_del ( &pxe->list );
  1488. ref_put ( &pxe->refcnt );
  1489. }