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 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);
|
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);
|
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 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)
|
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)))
|
if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)))
|
||||||
{
|
{
|
||||||
struct dhcp_context *tmp;
|
struct dhcp_context *tmp;
|
||||||
|
int workaround = 0;
|
||||||
|
|
||||||
for (tmp = context; tmp; tmp = tmp->current)
|
for (tmp = context; tmp; tmp = tmp->current)
|
||||||
if ((tmp->flags & CONTEXT_PROXY) &&
|
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);
|
clear_packet(mess, end);
|
||||||
|
|
||||||
/* Provide the bootfile here, for gPXE, and in case we have no menu items
|
/* Only do workaround for replies to 4011 */
|
||||||
and set discovery_control = 8 */
|
if (!pxe)
|
||||||
if (boot)
|
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)
|
if (boot->next_server.s_addr)
|
||||||
mess->siaddr = boot->next_server;
|
mess->siaddr = boot->next_server;
|
||||||
else if (boot->tftp_sname)
|
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));
|
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
|
||||||
pxe_misc(mess, end, uuid);
|
pxe_misc(mess, end, uuid);
|
||||||
prune_vendor_opts(tagif_netid);
|
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_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
|
||||||
log_tags(tagif_netid, ntohl(mess->xid));
|
log_tags(tagif_netid, ntohl(mess->xid));
|
||||||
@@ -1975,6 +1983,52 @@ static int prune_vendor_opts(struct dhcp_netid *netid)
|
|||||||
return force;
|
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)
|
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now)
|
||||||
{
|
{
|
||||||
#define NUM_OPTS 4
|
#define NUM_OPTS 4
|
||||||
@@ -2509,7 +2563,8 @@ static void do_options(struct dhcp_context *context,
|
|||||||
if (context && pxe_arch != -1)
|
if (context && pxe_arch != -1)
|
||||||
{
|
{
|
||||||
pxe_misc(mess, end, uuid);
|
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)) &&
|
if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&
|
||||||
|
|||||||
Reference in New Issue
Block a user