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
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
efi_pxe_probe(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,
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
116 bool
efi_pxe_match_booted_interface(const EFI_MAC_ADDRESS * mac,UINT32 addrsz)117 efi_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