net/dhcp: Allow overloading legacy bootfile and name field
DHCP specifies a special dummy option OVERLOAD, to allow DHCP options to spill over into the (legacy) BOOTFILE and SNAME fields. Parse and handle this option properly. Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
parent
4c44bbd835
commit
bd21d6465e
2 changed files with 59 additions and 1 deletions
|
@ -25,11 +25,19 @@
|
|||
#include <grub/net/udp.h>
|
||||
#include <grub/datetime.h>
|
||||
|
||||
enum
|
||||
{
|
||||
GRUB_DHCP_OPT_OVERLOAD_FILE = 1,
|
||||
GRUB_DHCP_OPT_OVERLOAD_SNAME = 2,
|
||||
};
|
||||
|
||||
static const void *
|
||||
find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
|
||||
grub_uint8_t opt_code, grub_uint8_t *opt_len)
|
||||
{
|
||||
const grub_uint8_t *ptr;
|
||||
grub_uint8_t overload = 0;
|
||||
int end = 0;
|
||||
grub_size_t i;
|
||||
|
||||
if (opt_len)
|
||||
|
@ -54,6 +62,7 @@ find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
|
|||
size -= sizeof (*bp);
|
||||
i = sizeof (grub_uint32_t);
|
||||
|
||||
again:
|
||||
while (i < size)
|
||||
{
|
||||
grub_uint8_t tagtype;
|
||||
|
@ -67,7 +76,10 @@ find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
|
|||
|
||||
/* End tag. */
|
||||
if (tagtype == GRUB_NET_BOOTP_END)
|
||||
break;
|
||||
{
|
||||
end = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= size)
|
||||
return NULL;
|
||||
|
@ -84,9 +96,54 @@ find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
|
|||
return &ptr[i];
|
||||
}
|
||||
|
||||
if (tagtype == GRUB_NET_DHCP_OVERLOAD && taglength == 1)
|
||||
overload = ptr[i];
|
||||
|
||||
i += taglength;
|
||||
}
|
||||
|
||||
if (!end)
|
||||
return NULL;
|
||||
|
||||
/* RFC2131, 4.1, 23ff:
|
||||
* If the options in a DHCP message extend into the 'sname' and 'file'
|
||||
* fields, the 'option overload' option MUST appear in the 'options'
|
||||
* field, with value 1, 2 or 3, as specified in RFC 1533. If the
|
||||
* 'option overload' option is present in the 'options' field, the
|
||||
* options in the 'options' field MUST be terminated by an 'end' option,
|
||||
* and MAY contain one or more 'pad' options to fill the options field.
|
||||
* The options in the 'sname' and 'file' fields (if in use as indicated
|
||||
* by the 'options overload' option) MUST begin with the first octet of
|
||||
* the field, MUST be terminated by an 'end' option, and MUST be
|
||||
* followed by 'pad' options to fill the remainder of the field. Any
|
||||
* individual option in the 'options', 'sname' and 'file' fields MUST be
|
||||
* entirely contained in that field. The options in the 'options' field
|
||||
* MUST be interpreted first, so that any 'option overload' options may
|
||||
* be interpreted. The 'file' field MUST be interpreted next (if the
|
||||
* 'option overload' option indicates that the 'file' field contains
|
||||
* DHCP options), followed by the 'sname' field.
|
||||
*
|
||||
* FIXME: We do not explicitly check for trailing 'pad' options here.
|
||||
*/
|
||||
end = 0;
|
||||
if (overload & GRUB_DHCP_OPT_OVERLOAD_FILE)
|
||||
{
|
||||
overload &= ~GRUB_DHCP_OPT_OVERLOAD_FILE;
|
||||
ptr = (grub_uint8_t *) &bp->boot_file[0];
|
||||
size = sizeof (bp->boot_file);
|
||||
i = 0;
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (overload & GRUB_DHCP_OPT_OVERLOAD_SNAME)
|
||||
{
|
||||
overload &= ~GRUB_DHCP_OPT_OVERLOAD_SNAME;
|
||||
ptr = (grub_uint8_t *) &bp->server_name[0];
|
||||
size = sizeof (bp->server_name);
|
||||
i = 0;
|
||||
goto again;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -457,6 +457,7 @@ enum
|
|||
GRUB_NET_BOOTP_DOMAIN = 0x0f,
|
||||
GRUB_NET_BOOTP_ROOT_PATH = 0x11,
|
||||
GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12,
|
||||
GRUB_NET_DHCP_OVERLOAD = 52,
|
||||
GRUB_NET_BOOTP_END = 0xff
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue