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

Reply via email to