Skip to content

Commit

Permalink
Add support for proxy dhcp based on old patch in grub mailing list
Browse files Browse the repository at this point in the history
  • Loading branch information
miray-tf committed Nov 22, 2019
1 parent 38a8279 commit 9f2092f
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 11 deletions.
175 changes: 168 additions & 7 deletions grub-core/net/bootp.c 100644 → 100755
Expand Up @@ -213,6 +213,165 @@ find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,

#define OFFSET_OF(x, y) ((grub_size_t)((grub_uint8_t *)((y)->x) - (grub_uint8_t *)(y)))

void
grub_net_process_dhcp_ack (struct grub_net_network_level_interface *inter,
const struct grub_net_bootp_packet *bp,
grub_size_t size,
int is_def, char **device, char **path)
{
int mask = -1;
char server_ip[sizeof ("xxx.xxx.xxx.xxx")];
const grub_uint8_t *opt;
grub_uint8_t opt_len, overload = 0;
const char *boot_file = 0, *server_name = 0;
grub_size_t boot_file_len, server_name_len;


opt = find_dhcp_option (bp, size, GRUB_NET_DHCP_OVERLOAD, &opt_len);
if (opt && opt_len == 1)
overload = *opt;

opt = find_dhcp_option (bp, size, GRUB_NET_DHCP_TFTP_SERVER_NAME, &opt_len);
if (opt && opt_len)
{
server_name = (const char *) opt;
server_name_len = opt_len;
}
else if (size > OFFSET_OF (server_name, bp) && !(overload & GRUB_DHCP_OPT_OVERLOAD_SNAME) &&
bp->server_name[0])
{
server_name = bp->server_name;
server_name_len = sizeof (bp->server_name);
}

opt = find_dhcp_option (bp, size, GRUB_NET_DHCP_BOOTFILE_NAME, &opt_len);
if (opt && opt_len)
{
boot_file = (const char *) opt;
boot_file_len = opt_len;
}
else if (size > OFFSET_OF (boot_file, bp) && !(overload && GRUB_DHCP_OPT_OVERLOAD_FILE) &&
bp->boot_file[0])
{
boot_file = bp->boot_file;
boot_file_len = sizeof (bp->boot_file);
}

if (bp->server_ip)
{
grub_snprintf (server_ip, sizeof (server_ip), "%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_env_set_net_property (inter->name, "next_server", server_ip, sizeof (server_ip));
grub_print_error ();
}

if (device && !*device && bp->server_ip)
{
*device = grub_xasprintf ("tftp,%s", server_ip);
grub_print_error ();
}

if (server_name)
{
grub_env_set_net_property (inter->name, "dhcp_server_name", server_name, server_name_len);
if (is_def && !grub_net_default_server)
{
grub_net_default_server = grub_strdup (server_name);
grub_print_error ();
}
if (device && !*device)
{
*device = grub_xasprintf ("tftp,%s", server_name);
grub_print_error ();
}
}

if (boot_file)
{
grub_env_set_net_property (inter->name, "boot_file", boot_file, boot_file_len);
if (path)
{
*path = grub_strndup (boot_file, boot_file_len);
grub_print_error ();
if (*path)
{
char *slash;
slash = grub_strrchr (*path, '/');
if (slash)
*slash = 0;
else
**path = 0;
}
}
}

opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_NETMASK, &opt_len);
if (opt && opt_len == 4)
{
int i;
for (i = 0; i < 32; i++)
if (!(opt[i / 8] & (1 << (7 - (i % 8)))))
break;
mask = i;
}
grub_net_add_ipv4_local (inter, mask);

/* We do not implement dead gateway detection and the first entry SHOULD
be preferred one */
opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_ROUTER, &opt_len);
if (opt && opt_len && !(opt_len & 3))
{
grub_net_network_level_netaddress_t target;
grub_net_network_level_address_t gw;
char *rname;

target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
target.ipv4.base = 0;
target.ipv4.masksize = 0;
gw.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
gw.ipv4 = grub_get_unaligned32 (opt);
rname = grub_xasprintf ("%s:default", inter->name);
if (rname)
grub_net_add_route_gw (rname, target, gw, 0);
grub_free (rname);
}

opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_DNS, &opt_len);
if (opt && opt_len && !(opt_len & 3))
{
int i;
for (i = 0; i < opt_len / 4; i++)
{
struct grub_net_network_level_address s;

s.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
s.ipv4 = grub_get_unaligned32 (opt);
s.option = DNS_OPTION_PREFER_IPV4;
grub_net_add_dns_server (&s);
opt += 4;
}
}

opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_HOSTNAME, &opt_len);
if (opt && opt_len)
grub_env_set_net_property (inter->name, "hostname", (const char *) opt, opt_len);

opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_DOMAIN, &opt_len);
if (opt && opt_len)
grub_env_set_net_property (inter->name, "domain", (const char *) opt, opt_len);

opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_ROOT_PATH, &opt_len);
if (opt && opt_len)
grub_env_set_net_property (inter->name, "rootpath", (const char *) opt, opt_len);

opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_EXTENSIONS_PATH, &opt_len);
if (opt && opt_len)
grub_env_set_net_property (inter->name, "extensionspath", (const char *) opt, opt_len);
}

struct grub_net_network_level_interface *
grub_net_configure_by_dhcp_ack (const char *name,
struct grub_net_card *card,
Expand All @@ -224,12 +383,7 @@ grub_net_configure_by_dhcp_ack (const char *name,
grub_net_network_level_address_t addr;
grub_net_link_level_address_t hwaddr;
struct grub_net_network_level_interface *inter;
int mask = -1;
char server_ip[sizeof ("xxx.xxx.xxx.xxx")];
const grub_uint8_t *opt;
grub_uint8_t opt_len, overload = 0;
const char *boot_file = 0, *server_name = 0;
grub_size_t boot_file_len, server_name_len;

addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
addr.ipv4 = bp->your_ip;
Expand All @@ -248,6 +402,7 @@ grub_net_configure_by_dhcp_ack (const char *name,
if (!inter)
return 0;

#if 0
opt = find_dhcp_option (bp, size, GRUB_NET_DHCP_OVERLOAD, &opt_len);

This comment has been minimized.

Copy link
@martinezjavier

martinezjavier Jun 2, 2021

why are you disabling this code ?

if (opt && opt_len == 1)
overload = *opt;
Expand Down Expand Up @@ -288,7 +443,8 @@ grub_net_configure_by_dhcp_ack (const char *name,
grub_env_set_net_property (name, "next_server", server_ip, sizeof (server_ip));
grub_print_error ();
}

#endif

if (is_def)
grub_net_default_server = 0;
if (is_def && !grub_net_default_server && bp->server_ip)
Expand All @@ -303,7 +459,8 @@ grub_net_configure_by_dhcp_ack (const char *name,
grub_env_export ("net_default_interface");
}

if (device && !*device && bp->server_ip)
#if 0

This comment has been minimized.

Copy link
@martinezjavier

martinezjavier Jun 2, 2021

and this ?

if (device && !*device && bp->server_ip)
{
*device = grub_xasprintf ("tftp,%s", server_ip);
grub_print_error ();
Expand Down Expand Up @@ -405,6 +562,10 @@ grub_net_configure_by_dhcp_ack (const char *name,
opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_EXTENSIONS_PATH, &opt_len);
if (opt && opt_len)
grub_env_set_net_property (name, "extensionspath", (const char *) opt, opt_len);
#endif

grub_net_process_dhcp_ack (inter, bp, size, is_def, device, path);

This comment has been minimized.

Copy link
@martinezjavier

martinezjavier Jun 2, 2021

ah, because the options are set in this function instead, right? In that case I think that would be better to just remove all the find_dhcp_option() calls and tftp env var set instead of just guarding in #if 0's, to make more clear that you are moving that logic to grub_net_process_dhcp_ack().

This comment has been minimized.

Copy link
@miray-tf

miray-tf Jun 2, 2021

Author

Yes, that functionality is moved to grub_net_process_dhcp_ack().
I'll have to clean that up before sending that upstream.
I left it in here because it makes it easier to spot changes in upstream when I rebase this code to a newer GRUB version.

This comment has been minimized.

Copy link
@martinezjavier

martinezjavier Jun 2, 2021

Got it. Makes sense.



inter->dhcp_ack = grub_malloc (size);
if (inter->dhcp_ack)
Expand Down
11 changes: 10 additions & 1 deletion grub-core/net/drivers/efi/efinet.c
Expand Up @@ -330,6 +330,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
{
struct grub_net_card *card;
grub_efi_device_path_t *dp;
struct grub_net_network_level_interface *inter;

dp = grub_efi_get_device_path (hnd);
if (! dp)
Expand Down Expand Up @@ -378,11 +379,19 @@ 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);

/* Boot server PXE options add and override boot file/server */
if (pxe_mode->proxy_offer_received)
grub_net_process_dhcp_ack (inter,
(struct grub_net_bootp_packet *)
&pxe_mode->proxy_offer,
sizeof (pxe_mode->proxy_offer),
1, device, path);
return;
}
}
Expand Down
11 changes: 10 additions & 1 deletion grub-core/net/drivers/i386/pc/pxe.c
Expand Up @@ -359,15 +359,24 @@ static void
grub_pc_net_config_real (char **device, char **path)
{
struct grub_net_bootp_packet *bp;
struct grub_net_network_level_interface *inter;

bp = grub_pxe_get_cached (GRUB_PXENV_PACKET_TYPE_DHCP_ACK);

if (!bp)
return;
grub_net_configure_by_dhcp_ack ("pxe", &grub_pxe_card, 0,
inter = grub_net_configure_by_dhcp_ack ("pxe", &grub_pxe_card, 0,
bp, GRUB_PXE_BOOTP_SIZE,
1, device, path);


/* Boot server PXE options add and override boot file/server */
bp = grub_pxe_get_cached (GRUB_PXENV_PACKET_TYPE_CACHED_REPLY);


if (bp)
grub_net_process_dhcp_ack (inter, bp, GRUB_PXE_BOOTP_SIZE,
1, device, path);
}

static struct grub_preboot *fini_hnd;
Expand Down
25 changes: 23 additions & 2 deletions include/grub/efi/api.h
Expand Up @@ -575,7 +575,7 @@ typedef grub_efi_uintn_t grub_efi_tpl_t;
typedef grub_uint8_t grub_efi_mac_address_t[32];
typedef grub_uint8_t grub_efi_ipv4_address_t[4];
typedef grub_uint16_t grub_efi_ipv6_address_t[8];
typedef grub_uint8_t grub_efi_ip_address_t[8] __attribute__ ((aligned(4)));
typedef grub_uint8_t grub_efi_ip_address_t[16] __attribute__ ((aligned(4)));
typedef grub_efi_uint64_t grub_efi_physical_address_t;
typedef grub_efi_uint64_t grub_efi_virtual_address_t;

Expand Down Expand Up @@ -1454,12 +1454,33 @@ typedef grub_uint8_t grub_efi_pxe_packet_t[1472];

typedef struct grub_efi_pxe_mode
{
grub_uint8_t unused[52];
grub_uint8_t started;
grub_uint8_t ipv6_available;
grub_uint8_t ipv6_supported;
grub_uint8_t using_ipv6;
grub_uint8_t bis_supported;
grub_uint8_t bis_detected;
grub_uint8_t auto_arp;
grub_uint8_t send_guid;
grub_uint8_t dhcp_discover_valid;
grub_uint8_t dhcp_ack_received;
grub_uint8_t proxy_offer_received;
grub_uint8_t pxe_discover_valid;
grub_uint8_t pxe_reply_received;
grub_uint8_t pxe_bis_reply_received;
grub_uint8_t icmp_error_received;
grub_uint8_t tftp_error_received;
grub_uint8_t make_callbacks;
grub_uint8_t ttl;
grub_uint8_t tos;
grub_efi_ip_address_t station_ip;
grub_efi_ip_address_t subnet_mask;
grub_efi_pxe_packet_t dhcp_discover;
grub_efi_pxe_packet_t dhcp_ack;
grub_efi_pxe_packet_t proxy_offer;
grub_efi_pxe_packet_t pxe_discover;
grub_efi_pxe_packet_t pxe_reply;
grub_efi_pxe_packet_t pxe_bis_reply;
} grub_efi_pxe_mode_t;

typedef struct grub_efi_pxe
Expand Down
6 changes: 6 additions & 0 deletions include/grub/net.h
Expand Up @@ -480,6 +480,12 @@ grub_net_configure_by_dhcp_ack (const char *name,
grub_size_t size,
int is_def, char **device, char **path);

void
grub_net_process_dhcp_ack (struct grub_net_network_level_interface *inter,
const struct grub_net_bootp_packet *bp,
grub_size_t size,
int is_def, char **device, char **path);

grub_err_t
grub_net_add_ipv4_local (struct grub_net_network_level_interface *inf,
int mask);
Expand Down

0 comments on commit 9f2092f

Please sign in to comment.