1 /* $NetBSD: efipxe.c,v 1.2 2018/11/15 23:52:33 jmcneill Exp $ */ 2 /* $OpenBSD: efipxe.c,v 1.3 2018/01/30 20:19:06 naddy Exp $ */ 3 4 /* 5 * Copyright (c) 2017 Patrick Wildt <patrick@blueri.se> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/queue.h> 21 22 #include "efiboot.h" 23 24 #include <netinet/in.h> 25 #include <netinet/in_systm.h> 26 #include <lib/libsa/bootp.h> /* for VM_RFC1048 */ 27 28 29 struct efipxeinfo { 30 TAILQ_ENTRY(efipxeinfo) list; 31 32 EFI_PXE_BASE_CODE *pxe; 33 EFI_SIMPLE_NETWORK *net; 34 EFI_MAC_ADDRESS mac; 35 UINT32 addrsz; 36 }; 37 TAILQ_HEAD(efipxeinfo_lh, efipxeinfo); 38 static struct efipxeinfo_lh efi_pxelist; 39 static int nefipxes; 40 41 void 42 efi_pxe_probe(void) 43 { 44 struct efipxeinfo *epi; 45 EFI_PXE_BASE_CODE *pxe; 46 EFI_DEVICE_PATH *dp; 47 EFI_SIMPLE_NETWORK *net; 48 EFI_HANDLE *handles; 49 EFI_STATUS status; 50 UINTN nhandles; 51 int i, depth; 52 bool found; 53 54 TAILQ_INIT(&efi_pxelist); 55 56 status = LibLocateHandle(ByProtocol, &PxeBaseCodeProtocol, NULL, 57 &nhandles, &handles); 58 if (EFI_ERROR(status)) 59 return; 60 61 for (i = 0; i < nhandles; i++) { 62 status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], 63 &DevicePathProtocol, (void **)&dp); 64 if (EFI_ERROR(status)) 65 continue; 66 67 depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH); 68 if (efi_device_path_ncmp(efi_bootdp, dp, depth)) 69 continue; 70 71 status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], 72 &PxeBaseCodeProtocol, (void **)&pxe); 73 if (EFI_ERROR(status)) 74 continue; 75 76 if (pxe->Mode == NULL || 77 (!pxe->Mode->DhcpAckReceived && !pxe->Mode->PxeReplyReceived)) 78 continue; 79 80 status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], 81 &SimpleNetworkProtocol, (void **)&net); 82 if (EFI_ERROR(status)) 83 continue; 84 85 if (net->Mode == NULL) 86 continue; 87 88 found = false; 89 TAILQ_FOREACH(epi, &efi_pxelist, list) { 90 if (net->Mode->HwAddressSize == epi->addrsz && 91 memcmp(net->Mode->CurrentAddress.Addr, epi->mac.Addr, 92 net->Mode->HwAddressSize) == 0) { 93 found = true; 94 break; 95 } 96 } 97 if (found) 98 continue; 99 100 epi = alloc(sizeof(*epi)); 101 if (epi == NULL) 102 continue; 103 104 memset(epi, 0, sizeof(*epi)); 105 epi->pxe = pxe; 106 epi->net = net; 107 epi->addrsz = net->Mode->HwAddressSize; 108 memcpy(epi->mac.Addr, net->Mode->CurrentAddress.Addr, epi->addrsz); 109 110 TAILQ_INSERT_TAIL(&efi_pxelist, epi, list); 111 nefipxes++; 112 } 113 } 114 115 bool 116 efi_pxe_match_booted_interface(const EFI_MAC_ADDRESS *mac, UINT32 addrsz) 117 { 118 const struct efipxeinfo *epi; 119 120 TAILQ_FOREACH(epi, &efi_pxelist, list) { 121 if (addrsz == epi->addrsz && 122 memcmp(mac->Addr, epi->mac.Addr, addrsz) == 0) 123 return true; 124 } 125 return false; 126 } 127