net/dhcp: Actually send out DHCPv4 DISCOVER and REQUEST messages

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.przywara@arm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
Andrei Borzenkov 2019-03-07 15:14:15 +00:00 committed by Vincent Batts
parent ada2f6d40c
commit 723c3174e4
2 changed files with 123 additions and 18 deletions

View file

@ -35,14 +35,52 @@
#error "unknown bootp architecture" #error "unknown bootp architecture"
#endif #endif
static grub_uint8_t dhcp_option_header[] = {GRUB_NET_BOOTP_RFC1048_MAGIC_0,
GRUB_NET_BOOTP_RFC1048_MAGIC_1,
GRUB_NET_BOOTP_RFC1048_MAGIC_2,
GRUB_NET_BOOTP_RFC1048_MAGIC_3};
static grub_uint8_t grub_userclass[] = {0x4D, 0x06, 0x05, 'G', 'R', 'U', 'B', '2'}; static grub_uint8_t grub_userclass[] = {0x4D, 0x06, 0x05, 'G', 'R', 'U', 'B', '2'};
static grub_uint8_t grub_dhcpdiscover[] = {0x35, 0x01, 0x01}; static grub_uint8_t grub_dhcpdiscover[] = {0x35, 0x01, 0x01};
static grub_uint8_t grub_dhcptime[] = {0x33, 0x04, 0x00, 0x00, 0x0e, 0x10}; static grub_uint8_t grub_dhcptime[] = {0x33, 0x04, 0x00, 0x00, 0x0e, 0x10};
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 enum
{ {
GRUB_DHCP_OPT_OVERLOAD_FILE = 1, GRUB_DHCP_OPT_OVERLOAD_FILE = 1,
@ -61,9 +99,6 @@ enum
GRUB_DHCP_MESSAGE_INFORM, GRUB_DHCP_MESSAGE_INFORM,
}; };
/* Max timeout when waiting for BOOTP/DHCP reply */
#define GRUB_DHCP_MAX_PACKET_TIMEOUT 32
#define GRUB_BOOTP_MAX_OPTIONS_SIZE 64 #define GRUB_BOOTP_MAX_OPTIONS_SIZE 64
/* Max timeout when waiting for BOOTP/DHCP reply */ /* Max timeout when waiting for BOOTP/DHCP reply */
@ -405,35 +440,102 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface)
grub_net_link_level_address_t ll_target; grub_net_link_level_address_t ll_target;
grub_uint8_t *offset; grub_uint8_t *offset;
nb = grub_netbuff_alloc (sizeof (*pack) + sizeof(dhcp_option_header) static struct grub_dhcp_discover_options discover_options =
+ sizeof(grub_userclass) {
{
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) + sizeof(grub_userclass)
+ sizeof(grub_dhcpdiscover) + sizeof(grub_dhcpdiscover)
+ sizeof(grub_dhcptime) + sizeof(grub_dhcptime)
+ GRUB_BOOTP_MAX_OPTIONS_SIZE + 128); + GRUB_BOOTP_MAX_OPTIONS_SIZE + 128);
if (!nb) if (!nb)
return grub_errno; return grub_errno;
err = grub_netbuff_reserve (nb, sizeof (*pack) + sizeof(dhcp_option_header) err = grub_netbuff_reserve (nb, sizeof (*pack) + sizeof(grub_userclass)
+ sizeof(grub_userclass)
+ sizeof(grub_dhcpdiscover) + sizeof(grub_dhcpdiscover)
+ sizeof(grub_dhcptime) + sizeof(grub_dhcptime)
+ GRUB_BOOTP_MAX_OPTIONS_SIZE + 128); + GRUB_BOOTP_MAX_OPTIONS_SIZE + 128);
if (err) if (err)
goto out; goto out;
err = grub_netbuff_push (nb, sizeof(dhcp_option_header) err = grub_netbuff_push (nb, sizeof(grub_userclass)
+ sizeof(grub_userclass)
+ sizeof(grub_dhcpdiscover) + sizeof(grub_dhcpdiscover)
+ sizeof(grub_dhcptime) + sizeof(grub_dhcptime)
+ GRUB_BOOTP_MAX_OPTIONS_SIZE); + GRUB_BOOTP_MAX_OPTIONS_SIZE);
if (err) if (err)
goto out; goto out;
grub_memset (nb->data, 0, sizeof(dhcp_option_header) grub_memset (nb->data, 0, sizeof(grub_userclass)
+ sizeof(grub_userclass)
+ sizeof(grub_dhcpdiscover) + sizeof(grub_dhcpdiscover)
+ sizeof(grub_dhcptime) + sizeof(grub_dhcptime)
+ GRUB_BOOTP_MAX_OPTIONS_SIZE); + 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)); err = grub_netbuff_push (nb, sizeof (*pack));
if (err) if (err)
@ -451,12 +553,13 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface)
t = 0; t = 0;
} }
pack->seconds = grub_cpu_to_be16 (t); 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); grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, 6);
offset = (grub_uint8_t *)&pack->vendor; offset = (grub_uint8_t *)&pack->vendor;
grub_memcpy (offset, dhcp_option_header, sizeof(dhcp_option_header));
offset += sizeof(dhcp_option_header);
grub_memcpy (offset, grub_dhcpdiscover, sizeof(grub_dhcpdiscover)); grub_memcpy (offset, grub_dhcpdiscover, sizeof(grub_dhcpdiscover));
offset += sizeof(grub_dhcpdiscover); offset += sizeof(grub_dhcpdiscover);
grub_memcpy (offset, grub_userclass, sizeof(grub_userclass)); grub_memcpy (offset, grub_userclass, sizeof(grub_userclass));

View file

@ -463,9 +463,11 @@ enum
GRUB_NET_BOOTP_DOMAIN = 0x0f, GRUB_NET_BOOTP_DOMAIN = 0x0f,
GRUB_NET_BOOTP_ROOT_PATH = 0x11, GRUB_NET_BOOTP_ROOT_PATH = 0x11,
GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12, GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12,
GRUB_NET_DHCP_REQUESTED_IP_ADDRESS = 50,
GRUB_NET_DHCP_OVERLOAD = 52, GRUB_NET_DHCP_OVERLOAD = 52,
GRUB_NET_DHCP_MESSAGE_TYPE = 53, GRUB_NET_DHCP_MESSAGE_TYPE = 53,
GRUB_NET_DHCP_SERVER_IDENTIFIER = 54, GRUB_NET_DHCP_SERVER_IDENTIFIER = 54,
GRUB_NET_DHCP_PARAMETER_REQUEST_LIST = 55,
GRUB_NET_DHCP_TFTP_SERVER_NAME = 66, GRUB_NET_DHCP_TFTP_SERVER_NAME = 66,
GRUB_NET_DHCP_BOOTFILE_NAME = 67, GRUB_NET_DHCP_BOOTFILE_NAME = 67,
GRUB_NET_BOOTP_END = 0xff GRUB_NET_BOOTP_END = 0xff