On Thu, Apr 21, 2016 at 10:36 AM, chen zhihui <[email protected]> wrote:
> From: chenzhihui <[email protected]> > > 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 <[email protected]> > Tested-by: Jerome Forissier <[email protected]> > --- > 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))) > option->data needs to be cast to (char *) if the patch is applied on master. > + 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); > Same here. > + 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 > > Thanks, -- Jerome
_______________________________________________ Grub-devel mailing list [email protected] https://lists.gnu.org/mailman/listinfo/grub-devel
