[Dnsmasq-discuss] ProxyDHCP with UEFI systems

Michael Kuron michael-lists at physcip.uni-stuttgart.de
Sat Oct 31 10:39:00 GMT 2015


As it turns out, UEFI does support PXE menus, but the implementations are rather buggy in that regard. VMware often does not render the menu on the screen, but you can blindly select the menu entry using the arrow keys and boot it with the return key. A recent Asus laptop renders the menu, but ignores the TFTP server IP specified in the PXE service and instead tries to open a TFTP connection to the DHCP server’s IP. There probably are some fully-working implementations out there as well.
Below is a patch that combines the work from my previous emails with this new discovery. It always redirects to port 4011. If only one service is specified, it puts that into the siaddr and file fields directly, which should work for all UEFI implementations. If more than one service is specified, it sends a menu, which might reveal bugs in the UEFI implementation. All of this is backwards compatible with BIOS because the port 4011 redirect is part of the PXE spec.

How can I submit this patch for inclusion in dnsmasq?


diff --git a/src/rfc2131.c b/src/rfc2131.c
index 9f69ed5..bdc0f78 100644
--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -824,7 +824,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 	  else
 	    mess->siaddr = context->local; 
 	  
-	  snprintf((char *)mess->file, sizeof(mess->file), "%s.%d", service->basename, layer);
+	  if (service->CSA == 6 || service->CSA == 7 || service->CSA == 8 || service->CSA == 9)
+	    snprintf((char *)mess->file, sizeof(mess->file), "%s.efi", service->basename);
+	  else
+	    snprintf((char *)mess->file, sizeof(mess->file), "%s.%d", service->basename, layer);
 	  option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
 	  option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
 	  pxe_misc(mess, end, uuid);
@@ -859,6 +862,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 	      
 	      if (tmp)
 		{
+		  int num_services = 0;
 		  struct dhcp_boot *boot;
 		  
 		  if (tmp->netid.net)
@@ -890,13 +894,42 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 		      if (boot->file)
 			strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
 		    }
+		  else
+		    {
+				struct pxe_service *service;
+				for (service = daemon->pxe_services; service; service = service->next)
+					if (pxearch == service->CSA && match_netid(service->netid, netid, 1))
+						++num_services;
+				
+				if (num_services == 1 && pxe)
+				{
+					for (service = daemon->pxe_services; service; service = service->next)
+						if (pxearch == service->CSA && match_netid(service->netid, netid, 1))
+					{
+						if (service->sname)
+							mess->siaddr = a_record_from_hosts(service->sname, now);
+						else if (service->server.s_addr != 0)
+							mess->siaddr = service->server; 
+						else
+							mess->siaddr = tmp->local;
+						
+						if (service->CSA == 0)
+							snprintf((char *)mess->file, sizeof(mess->file), "%s.0", service->basename);
+						else if (service->CSA == 6 || service->CSA == 7 || service->CSA == 8 || service->CSA == 9)
+							snprintf((char *)mess->file, sizeof(mess->file), "%s.efi", service->basename);
+						else
+							strncpy((char *)mess->file, service->basename, sizeof(mess->file)-1);
+					}
+				}
+		    }
 		  
 		  option_put(mess, end, OPTION_MESSAGE_TYPE, 1, 
 			     mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
 		  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 (num_services != 1 && pxe)
+		    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));




More information about the Dnsmasq-discuss mailing list