[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] efinet: get bootstrap info from proxy offer packet
From: |
chen zhihui |
Subject: |
[PATCH] efinet: get bootstrap info from proxy offer packet |
Date: |
Thu, 21 Apr 2016 08:36:37 +0000 |
From: chenzhihui <address@hidden>
Bootstrap server ip address and boot file name maybe come from
a separate proxy DHCP server, check the proxy_offer packet if
failed with dhcp_ack packet.
Signed-off-by: chenzhihui <address@hidden>
Tested-by: Jerome Forissier <address@hidden>
---
grub-core/net/bootp.c | 170 ++++++++++++++++++++++++++++++++++++-
grub-core/net/drivers/efi/efinet.c | 23 ++++-
include/grub/net.h | 10 +++
3 files changed, 200 insertions(+), 3 deletions(-)
diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
index 4fdeac3..52f4051 100644
--- a/grub-core/net/bootp.c
+++ b/grub-core/net/bootp.c
@@ -186,7 +186,7 @@ grub_net_configure_by_dhcp_ack (const char *name,
}
#endif
- if (size > OFFSET_OF (boot_file, bp))
+ if (size > OFFSET_OF (boot_file, bp) && bp->boot_file[0])
grub_env_set_net_property (name, "boot_file", bp->boot_file,
sizeof (bp->boot_file));
if (is_def)
@@ -233,7 +233,7 @@ grub_net_configure_by_dhcp_ack (const char *name,
}
}
- if (size > OFFSET_OF (boot_file, bp) && path)
+ if (size > OFFSET_OF (boot_file, bp) && bp->boot_file[0] && path)
{
*path = grub_strndup (bp->boot_file, sizeof (bp->boot_file));
grub_print_error ();
@@ -263,6 +263,172 @@ grub_net_configure_by_dhcp_ack (const char *name,
return inter;
}
+struct dhcp4_packet_option {
+ grub_uint8_t code;
+ grub_uint8_t length;
+ grub_uint8_t data[0];
+};
+
+/*
+ * Get specified option from DHCP extension data
+ *
+ * from PxeBcDhcp.c of UEFI
+ *
+ */
+static struct dhcp4_packet_option *
+dhcp_proxy_extension_option (const grub_uint8_t *buf,
+ grub_size_t size,
+ grub_uint8_t code)
+{
+ struct dhcp4_packet_option *option = (struct dhcp4_packet_option *)buf;
+ grub_size_t offset = 0;
+
+ while (offset < size && option->code != GRUB_NET_BOOTP_END) {
+ if (option->code == code)
+ return option;
+
+ if (option->code == GRUB_NET_BOOTP_PAD)
+ offset++;
+ else
+ offset += option->length + 2;
+
+ option = (struct dhcp4_packet_option *)(buf + offset);
+ }
+
+ return NULL;
+}
+
+#define PXE_CLASS_ID "PXEClient"
+
+static int
+proxy_offer_is_valid(const struct grub_net_bootp_packet *bp,
+ grub_size_t size)
+{
+ const grub_uint8_t *buf;
+ grub_uint32_t option_size;
+ struct dhcp4_packet_option *option;
+
+ if (size <= OFFSET_OF (vendor, bp) + sizeof (grub_uint32_t))
+ return 0;
+
+ if (bp->vendor[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0
+ || bp->vendor[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1
+ || bp->vendor[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2
+ || bp->vendor[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3)
+ return 0;
+
+ buf = bp->vendor + sizeof (grub_uint32_t);
+ option_size = size - OFFSET_OF(vendor, bp) - sizeof (grub_uint32_t);
+ option = dhcp_proxy_extension_option(buf, option_size,
GRUB_NET_DHCP_CLASS_ID);
+ if (option == NULL)
+ return 0;
+
+ if (option->length < grub_strlen(PXE_CLASS_ID))
+ return 0;
+
+ if (grub_strncmp(option->data, PXE_CLASS_ID, grub_strlen(PXE_CLASS_ID)))
+ return 0;
+
+ return 1;
+}
+
+void
+grub_net_configure_by_proxy_offer (const struct grub_net_bootp_packet *bp,
+ grub_size_t size,
+ char **device,
+ char **path)
+{
+ const grub_uint8_t *buf = bp->vendor + sizeof (grub_uint32_t);
+ grub_uint32_t option_size =
+ size - OFFSET_OF(vendor, bp) - sizeof (grub_uint32_t);
+ struct dhcp4_packet_option *option;
+
+ if (device == NULL)
+ return;
+
+ if (!proxy_offer_is_valid(bp, size))
+ return;
+
+ if (!*device && bp->server_ip)
+ {
+ *device = grub_xasprintf ("tftp,%d.%d.%d.%d",
+ ((grub_uint8_t *) &bp->server_ip)[0],
+ ((grub_uint8_t *) &bp->server_ip)[1],
+ ((grub_uint8_t *) &bp->server_ip)[2],
+ ((grub_uint8_t *) &bp->server_ip)[3]);
+ grub_print_error ();
+ }
+
+ option = dhcp_proxy_extension_option(buf,
+ option_size, GRUB_NET_DHCP_OVERLOAD);
+
+ if ((option == NULL || option->data[0] == 1) && !*device &&
bp->server_name[0])
+ {
+ *device = grub_xasprintf ("tftp,%s", bp->server_name);
+ grub_print_error ();
+ }
+
+ if (!*device)
+ {
+ option = dhcp_proxy_extension_option(buf,
+ option_size, GRUB_NET_DHCP_SERVER_ID);
+
+ if (option) {
+ *device = grub_xasprintf("tftp,%d.%d.%d.%d",
+ option->data[0],
+ option->data[1],
+ option->data[2],
+ option->data[3]);
+ grub_print_error ();
+ }
+ }
+
+ if (*device && grub_net_default_server == NULL)
+ grub_net_default_server = grub_strdup((*device) + 5);
+
+ if (path && !*path) {
+ option = dhcp_proxy_extension_option(buf,
+ option_size, GRUB_NET_DHCP_OVERLOAD);
+
+ if (option == NULL || option->data[0] == 2)
+ {
+ *path = grub_strndup (bp->boot_file, sizeof
(bp->boot_file));
+ grub_print_error ();
+
+ if (*path)
+ {
+ char *slash;
+
+ slash = grub_strrchr (*path, '/');
+ if (slash)
+ *slash = 0;
+ else
+ **path = 0;
+ }
+ }
+ else
+ {
+ option = dhcp_proxy_extension_option(buf,
+ option_size, GRUB_NET_DHCP_BOOTFILE);
+ if (option) {
+ *path = grub_strndup (option->data,
option->length);
+ grub_print_error ();
+
+ if (*path)
+ {
+ char *slash;
+
+ slash = grub_strrchr (*path, '/');
+ if (slash)
+ *slash = 0;
+ else
+ **path = 0;
+ }
+ }
+ }
+ }
+}
+
void
grub_net_process_dhcp (struct grub_net_buff *nb,
struct grub_net_card *card)
diff --git a/grub-core/net/drivers/efi/efinet.c
b/grub-core/net/drivers/efi/efinet.c
index 5388f95..ef0ccd9 100644
--- a/grub-core/net/drivers/efi/efinet.c
+++ b/grub-core/net/drivers/efi/efinet.c
@@ -338,6 +338,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char
**device,
FOR_NET_CARDS (card)
{
grub_efi_device_path_t *cdp;
+ struct grub_net_network_level_interface *inter;
struct grub_efi_pxe *pxe;
struct grub_efi_pxe_mode *pxe_mode;
if (card->driver != &efidriver)
@@ -378,11 +379,31 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char
**device,
if (! pxe)
continue;
pxe_mode = pxe->mode;
- grub_net_configure_by_dhcp_ack (card->name, card, 0,
+ inter = grub_net_configure_by_dhcp_ack (card->name, card, 0,
(struct grub_net_bootp_packet *)
&pxe_mode->dhcp_ack,
sizeof (pxe_mode->dhcp_ack),
1, device, path);
+
+ /*
+ * Bootstrap server ip address and file name maybe
+ * come from a separate proxy DHCP server,
+ * so check the proxy_offer DHCP packet
+ *
+ */
+ if (inter && *path == NULL) {
+ if (*device) {
+ grub_free(*device);
+ *device = NULL;
+ }
+
+ grub_net_configure_by_proxy_offer(
+ (struct grub_net_bootp_packet
*)&pxe_mode->proxy_offer,
+ sizeof (pxe_mode->proxy_offer),
+ device,
+ path);
+ }
+
return;
}
}
diff --git a/include/grub/net.h b/include/grub/net.h
index b62643a..f107a23 100644
--- a/include/grub/net.h
+++ b/include/grub/net.h
@@ -433,6 +433,10 @@ enum
GRUB_NET_BOOTP_DOMAIN = 0x0f,
GRUB_NET_BOOTP_ROOT_PATH = 0x11,
GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12,
+ GRUB_NET_DHCP_OVERLOAD = 0x34,
+ GRUB_NET_DHCP_SERVER_ID = 0x36,
+ GRUB_NET_DHCP_CLASS_ID = 0x3c,
+ GRUB_NET_DHCP_BOOTFILE = 0x43,
GRUB_NET_BOOTP_END = 0xff
};
@@ -444,6 +448,12 @@ grub_net_configure_by_dhcp_ack (const char *name,
grub_size_t size,
int is_def, char **device, char **path);
+void
+grub_net_configure_by_proxy_offer (const struct grub_net_bootp_packet *bp,
+ grub_size_t size,
+ char **device,
+ char **path);
+
grub_err_t
grub_net_add_ipv4_local (struct grub_net_network_level_interface *inf,
int mask);
--
1.9.1
- [PATCH] efinet: get bootstrap info from proxy offer packet,
chen zhihui <=