From: Andrei Borzenkov <arvidj...@gmail.com> Even though we were parsing some DHCP options sent by the server, so far we are only using the BOOTP 2-way handshake, even when talking to a DHCP server.
Change this by actually sending out DHCP DISCOVER packets instead of the generic (mostly empty) BOOTP BOOTREQUEST packets. A pure BOOTP server would ignore the extra DHCP options in the DISCOVER packet and would just reply with a BOOTREPLY packet, which we also handle in the code. Signed-off-by: Andre Przywara <andre.przyw...@arm.com> Reviewed-by: Daniel Kiper <daniel.ki...@oracle.com> --- grub-core/net/bootp.c | 120 +++++++++++++++++++++++++++++++++++++++++- include/grub/net.h | 2 + 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c index d0482a7d5..63763aaab 100644 --- a/grub-core/net/bootp.c +++ b/grub-core/net/bootp.c @@ -25,6 +25,48 @@ #include <grub/net/udp.h> #include <grub/datetime.h> +struct grub_dhcp_discover_options +{ + grub_uint8_t magic[4]; + struct + { + grub_uint8_t code; + grub_uint8_t len; + grub_uint8_t data; + } GRUB_PACKED message_type; + grub_uint8_t end; +} GRUB_PACKED; + +struct grub_dhcp_request_options +{ + grub_uint8_t magic[4]; + struct + { + grub_uint8_t code; + grub_uint8_t len; + grub_uint8_t data; + } GRUB_PACKED message_type; + struct + { + grub_uint8_t type; + grub_uint8_t len; + grub_uint32_t data; + } GRUB_PACKED server_identifier; + struct + { + grub_uint8_t type; + grub_uint8_t len; + grub_uint32_t data; + } GRUB_PACKED requested_ip; + struct + { + grub_uint8_t type; + grub_uint8_t len; + grub_uint8_t data[7]; + } GRUB_PACKED parameter_request; + grub_uint8_t end; +} GRUB_PACKED; + enum { GRUB_DHCP_OPT_OVERLOAD_FILE = 1, @@ -43,6 +85,8 @@ enum GRUB_DHCP_MESSAGE_INFORM, }; +#define GRUB_BOOTP_MAX_OPTIONS_SIZE 64 + /* Max timeout when waiting for BOOTP/DHCP reply */ #define GRUB_DHCP_MAX_PACKET_TIMEOUT 32 @@ -386,6 +430,64 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) grub_net_network_level_address_t target; grub_net_link_level_address_t ll_target; + static struct grub_dhcp_discover_options discover_options = + { + { + GRUB_NET_BOOTP_RFC1048_MAGIC_0, + GRUB_NET_BOOTP_RFC1048_MAGIC_1, + GRUB_NET_BOOTP_RFC1048_MAGIC_2, + GRUB_NET_BOOTP_RFC1048_MAGIC_3, + }, + { + GRUB_NET_DHCP_MESSAGE_TYPE, + sizeof (discover_options.message_type.data), + GRUB_DHCP_MESSAGE_DISCOVER, + }, + GRUB_NET_BOOTP_END, + }; + + static struct grub_dhcp_request_options request_options = + { + { + GRUB_NET_BOOTP_RFC1048_MAGIC_0, + GRUB_NET_BOOTP_RFC1048_MAGIC_1, + GRUB_NET_BOOTP_RFC1048_MAGIC_2, + GRUB_NET_BOOTP_RFC1048_MAGIC_3, + }, + { + GRUB_NET_DHCP_MESSAGE_TYPE, + sizeof (request_options.message_type.data), + GRUB_DHCP_MESSAGE_REQUEST, + }, + { + GRUB_NET_DHCP_SERVER_IDENTIFIER, + sizeof (request_options.server_identifier.data), + 0, + }, + { + GRUB_NET_DHCP_REQUESTED_IP_ADDRESS, + sizeof (request_options.requested_ip.data), + 0, + }, + { + GRUB_NET_DHCP_PARAMETER_REQUEST_LIST, + sizeof (request_options.parameter_request.data), + { + GRUB_NET_BOOTP_NETMASK, + GRUB_NET_BOOTP_ROUTER, + GRUB_NET_BOOTP_DNS, + GRUB_NET_BOOTP_DOMAIN, + GRUB_NET_BOOTP_HOSTNAME, + GRUB_NET_BOOTP_ROOT_PATH, + GRUB_NET_BOOTP_EXTENSIONS_PATH, + }, + }, + GRUB_NET_BOOTP_END, + }; + + COMPILE_TIME_ASSERT (sizeof (discover_options) <= GRUB_BOOTP_MAX_OPTIONS_SIZE); + COMPILE_TIME_ASSERT (sizeof (request_options) <= GRUB_BOOTP_MAX_OPTIONS_SIZE); + nb = grub_netbuff_alloc (sizeof (*pack) + GRUB_BOOTP_MAX_OPTIONS_SIZE + 128); if (!nb) return grub_errno; @@ -399,6 +501,19 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) goto out; grub_memset (nb->data, 0, GRUB_BOOTP_MAX_OPTIONS_SIZE); + if (!iface->srv_id) + { + grub_memcpy (nb->data, &discover_options, sizeof (discover_options)); + } + else + { + struct grub_dhcp_request_options *ro = (struct grub_dhcp_request_options *) nb->data; + + grub_memcpy (nb->data, &request_options, sizeof (request_options)); + /* my_ip and srv_id are stored in network order so do not need conversion. */ + grub_set_unaligned32 (&ro->server_identifier.data, iface->srv_id); + grub_set_unaligned32 (&ro->requested_ip.data, iface->my_ip); + } err = grub_netbuff_push (nb, sizeof (*pack)); if (err) @@ -416,7 +531,10 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) t = 0; } pack->seconds = grub_cpu_to_be16 (t); - pack->ident = grub_cpu_to_be32 (t); + if (!iface->srv_id) + iface->xid = pack->ident = grub_cpu_to_be32 (t); + else + pack->ident = iface->xid; grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, 6); diff --git a/include/grub/net.h b/include/grub/net.h index 68a9f1311..4a9069a14 100644 --- a/include/grub/net.h +++ b/include/grub/net.h @@ -462,9 +462,11 @@ enum GRUB_NET_BOOTP_DOMAIN = 0x0f, GRUB_NET_BOOTP_ROOT_PATH = 0x11, GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12, + GRUB_NET_DHCP_REQUESTED_IP_ADDRESS = 50, GRUB_NET_DHCP_OVERLOAD = 52, GRUB_NET_DHCP_MESSAGE_TYPE = 53, GRUB_NET_DHCP_SERVER_IDENTIFIER = 54, + GRUB_NET_DHCP_PARAMETER_REQUEST_LIST = 55, GRUB_NET_DHCP_TFTP_SERVER_NAME = 66, GRUB_NET_DHCP_BOOTFILE_NAME = 67, GRUB_NET_BOOTP_END = 0xff -- 2.17.1 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel