mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Workaround for UEFI PXE boot problems.
This commit is contained in:
@@ -63,7 +63,7 @@ static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char
|
||||
static int prune_vendor_opts(struct dhcp_netid *netid);
|
||||
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
|
||||
struct dhcp_boot *find_boot(struct dhcp_netid *netid);
|
||||
|
||||
static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now);
|
||||
|
||||
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe, struct in_addr fallback)
|
||||
@@ -851,6 +851,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)))
|
||||
{
|
||||
struct dhcp_context *tmp;
|
||||
int workaround = 0;
|
||||
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if ((tmp->flags & CONTEXT_PROXY) &&
|
||||
@@ -878,10 +879,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
clear_packet(mess, end);
|
||||
|
||||
/* Provide the bootfile here, for gPXE, and in case we have no menu items
|
||||
and set discovery_control = 8 */
|
||||
if (boot)
|
||||
/* Only do workaround for replies to 4011 */
|
||||
if (!pxe)
|
||||
mess->siaddr = tmp->local;
|
||||
else
|
||||
workaround = pxe_uefi_workaround(pxearch, tagif_netid, mess, tmp->local, now);
|
||||
|
||||
if (!workaround && boot)
|
||||
{
|
||||
/* Provide the bootfile here, for gPXE, and in case we have no menu items
|
||||
and set discovery_control = 8 */
|
||||
if (boot->next_server.s_addr)
|
||||
mess->siaddr = boot->next_server;
|
||||
else if (boot->tftp_sname)
|
||||
@@ -896,7 +903,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
|
||||
pxe_misc(mess, end, uuid);
|
||||
prune_vendor_opts(tagif_netid);
|
||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
if (!workaround)
|
||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
|
||||
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
@@ -1975,6 +1983,52 @@ static int prune_vendor_opts(struct dhcp_netid *netid)
|
||||
return force;
|
||||
}
|
||||
|
||||
|
||||
/* Many UEFI PXE implementations have badly broken menu code.
|
||||
If there's exactly one relevant menu item, we abandon the menu system,
|
||||
and jamb the data direct into the DHCP file, siaddr and sname fields.
|
||||
Note that in this case, we have to assume that layer zero would be requested
|
||||
by the client PXE stack. */
|
||||
static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now)
|
||||
{
|
||||
struct pxe_service *service, *found;
|
||||
|
||||
/* Only workaround UEFI archs. */
|
||||
if (pxe_arch != 6 && pxe_arch != 7 && pxe_arch != 8 && pxe_arch != 9)
|
||||
return 0;
|
||||
|
||||
for (found = NULL, service = daemon->pxe_services; service; service = service->next)
|
||||
if (pxe_arch == service->CSA && match_netid(service->netid, netid, 1))
|
||||
{
|
||||
if (found)
|
||||
return 0; /* More than one relevant menu item */
|
||||
|
||||
found = service;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return 0; /* No relevant menu items. */
|
||||
|
||||
if (found->sname)
|
||||
{
|
||||
mess->siaddr = a_record_from_hosts(found->sname, now);
|
||||
snprintf((char *)mess->sname, sizeof(mess->sname), "%s", found->sname);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (found->server.s_addr != 0)
|
||||
mess->siaddr = found->server;
|
||||
else
|
||||
mess->siaddr = local;
|
||||
|
||||
inet_ntop(AF_INET, &mess->siaddr, (char *)mess->sname, INET_ADDRSTRLEN);
|
||||
}
|
||||
|
||||
snprintf((char *)mess->file, sizeof(mess->file), "%s.0", found->basename);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now)
|
||||
{
|
||||
#define NUM_OPTS 4
|
||||
@@ -2509,7 +2563,8 @@ static void do_options(struct dhcp_context *context,
|
||||
if (context && pxe_arch != -1)
|
||||
{
|
||||
pxe_misc(mess, end, uuid);
|
||||
config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
|
||||
if (!pxe_uefi_workaround(pxe_arch, tagif, mess, context->local, now))
|
||||
config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
|
||||
}
|
||||
|
||||
if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&
|
||||
|
||||
Reference in New Issue
Block a user