1/* $NetBSD: efipxe.c,v 1.3 2023/07/24 08:30:42 rin 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 29struct 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}; 37TAILQ_HEAD(efipxeinfo_lh, efipxeinfo); 38static struct efipxeinfo_lh efi_pxelist; 39static int nefipxes; 40 41void 42efi_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, 68 MESSAGING_DEVICE_PATH); 69 if (efi_device_path_ncmp(efi_bootdp, dp, depth)) 70 continue; 71 72 status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], 73 &PxeBaseCodeProtocol, (void **)&pxe); 74 if (EFI_ERROR(status)) 75 continue; 76 77 if (pxe->Mode == NULL || 78 (!pxe->Mode->DhcpAckReceived && !pxe->Mode->PxeReplyReceived)) 79 continue; 80 81 status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], 82 &SimpleNetworkProtocol, (void **)&net); 83 if (EFI_ERROR(status)) 84 continue; 85 86 if (net->Mode == NULL) 87 continue; 88 89 found = false; 90 TAILQ_FOREACH(epi, &efi_pxelist, list) { 91 if (net->Mode->HwAddressSize == epi->addrsz && 92 memcmp(net->Mode->CurrentAddress.Addr, epi->mac.Addr, 93 net->Mode->HwAddressSize) == 0) { 94 found = true; 95 break; 96 } 97 } 98 if (found) 99 continue; 100 101 epi = alloc(sizeof(*epi)); 102 if (epi == NULL) 103 continue; 104 105 memset(epi, 0, sizeof(*epi)); 106 epi->pxe = pxe; 107 epi->net = net; 108 epi->addrsz = net->Mode->HwAddressSize; 109 memcpy(epi->mac.Addr, net->Mode->CurrentAddress.Addr, epi->addrsz); 110 111 TAILQ_INSERT_TAIL(&efi_pxelist, epi, list); 112 nefipxes++; 113 } 114} 115 116bool 117efi_pxe_match_booted_interface(const EFI_MAC_ADDRESS *mac, UINT32 addrsz) 118{ 119 const struct efipxeinfo *epi; 120 121 TAILQ_FOREACH(epi, &efi_pxelist, list) { 122 if (addrsz == epi->addrsz && 123 memcmp(mac->Addr, epi->mac.Addr, addrsz) == 0) 124 return true; 125 } 126 return false; 127} 128